1*33f37583SAndroid Build Coastguard Worker /* 2*33f37583SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*33f37583SAndroid Build Coastguard Worker * 4*33f37583SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*33f37583SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*33f37583SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*33f37583SAndroid Build Coastguard Worker * 8*33f37583SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*33f37583SAndroid Build Coastguard Worker * 10*33f37583SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*33f37583SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*33f37583SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*33f37583SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*33f37583SAndroid Build Coastguard Worker * limitations under the License. 15*33f37583SAndroid Build Coastguard Worker */ 16*33f37583SAndroid Build Coastguard Worker 17*33f37583SAndroid Build Coastguard Worker #ifndef ANDROID_APEXD_APEX_DATABASE_H_ 18*33f37583SAndroid Build Coastguard Worker #define ANDROID_APEXD_APEX_DATABASE_H_ 19*33f37583SAndroid Build Coastguard Worker 20*33f37583SAndroid Build Coastguard Worker #include <android-base/logging.h> 21*33f37583SAndroid Build Coastguard Worker #include <android-base/result.h> 22*33f37583SAndroid Build Coastguard Worker #include <android-base/thread_annotations.h> 23*33f37583SAndroid Build Coastguard Worker 24*33f37583SAndroid Build Coastguard Worker #include <map> 25*33f37583SAndroid Build Coastguard Worker #include <mutex> 26*33f37583SAndroid Build Coastguard Worker #include <optional> 27*33f37583SAndroid Build Coastguard Worker #include <set> 28*33f37583SAndroid Build Coastguard Worker #include <string> 29*33f37583SAndroid Build Coastguard Worker #include <unordered_set> 30*33f37583SAndroid Build Coastguard Worker 31*33f37583SAndroid Build Coastguard Worker namespace android { 32*33f37583SAndroid Build Coastguard Worker namespace apex { 33*33f37583SAndroid Build Coastguard Worker 34*33f37583SAndroid Build Coastguard Worker class MountedApexDatabase { 35*33f37583SAndroid Build Coastguard Worker public: 36*33f37583SAndroid Build Coastguard Worker // Stores associated low-level data for a mounted APEX. To conserve memory, 37*33f37583SAndroid Build Coastguard Worker // the APEX file isn't stored, but must be opened to retrieve specific data. 38*33f37583SAndroid Build Coastguard Worker struct MountedApexData { 39*33f37583SAndroid Build Coastguard Worker int version = 0; // APEX version for this mount 40*33f37583SAndroid Build Coastguard Worker std::string loop_name; // Loop device used (fs path). 41*33f37583SAndroid Build Coastguard Worker std::string full_path; // Full path to the apex file. 42*33f37583SAndroid Build Coastguard Worker std::string mount_point; // Path this apex is mounted on. 43*33f37583SAndroid Build Coastguard Worker std::string device_name; // Name of the dm verity device. 44*33f37583SAndroid Build Coastguard Worker // Whenever apex file specified in full_path was deleted. 45*33f37583SAndroid Build Coastguard Worker bool deleted = false; 46*33f37583SAndroid Build Coastguard Worker 47*33f37583SAndroid Build Coastguard Worker MountedApexData() = default; MountedApexDataMountedApexData48*33f37583SAndroid Build Coastguard Worker MountedApexData(int version, const std::string& loop_name, 49*33f37583SAndroid Build Coastguard Worker const std::string& full_path, 50*33f37583SAndroid Build Coastguard Worker const std::string& mount_point, 51*33f37583SAndroid Build Coastguard Worker const std::string& device_name) 52*33f37583SAndroid Build Coastguard Worker : version(version), 53*33f37583SAndroid Build Coastguard Worker loop_name(loop_name), 54*33f37583SAndroid Build Coastguard Worker full_path(full_path), 55*33f37583SAndroid Build Coastguard Worker mount_point(mount_point), 56*33f37583SAndroid Build Coastguard Worker device_name(device_name), 57*33f37583SAndroid Build Coastguard Worker deleted(false) {} 58*33f37583SAndroid Build Coastguard Worker 59*33f37583SAndroid Build Coastguard Worker inline auto operator<=>(const MountedApexData& rhs) const = default; 60*33f37583SAndroid Build Coastguard Worker }; 61*33f37583SAndroid Build Coastguard Worker 62*33f37583SAndroid Build Coastguard Worker template <typename... Args> AddMountedApexLocked(const std::string & package,Args &&...args)63*33f37583SAndroid Build Coastguard Worker inline void AddMountedApexLocked(const std::string& package, Args&&... args) 64*33f37583SAndroid Build Coastguard Worker REQUIRES(mounted_apexes_mutex_) { 65*33f37583SAndroid Build Coastguard Worker auto it = mounted_apexes_.find(package); 66*33f37583SAndroid Build Coastguard Worker if (it == mounted_apexes_.end()) { 67*33f37583SAndroid Build Coastguard Worker auto insert_it = 68*33f37583SAndroid Build Coastguard Worker mounted_apexes_.emplace(package, std::set<MountedApexData>()); 69*33f37583SAndroid Build Coastguard Worker CHECK(insert_it.second); 70*33f37583SAndroid Build Coastguard Worker it = insert_it.first; 71*33f37583SAndroid Build Coastguard Worker } 72*33f37583SAndroid Build Coastguard Worker 73*33f37583SAndroid Build Coastguard Worker auto check_it = 74*33f37583SAndroid Build Coastguard Worker it->second.emplace(MountedApexData(std::forward<Args>(args)...)); 75*33f37583SAndroid Build Coastguard Worker CHECK(check_it.second); 76*33f37583SAndroid Build Coastguard Worker 77*33f37583SAndroid Build Coastguard Worker CheckUniqueLoopDm(); 78*33f37583SAndroid Build Coastguard Worker } 79*33f37583SAndroid Build Coastguard Worker 80*33f37583SAndroid Build Coastguard Worker template <typename... Args> AddMountedApex(const std::string & package,Args &&...args)81*33f37583SAndroid Build Coastguard Worker inline void AddMountedApex(const std::string& package, Args&&... args) 82*33f37583SAndroid Build Coastguard Worker REQUIRES(!mounted_apexes_mutex_) { 83*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mounted_apexes_mutex_); 84*33f37583SAndroid Build Coastguard Worker AddMountedApexLocked(package, args...); 85*33f37583SAndroid Build Coastguard Worker } 86*33f37583SAndroid Build Coastguard Worker RemoveMountedApex(const std::string & package,const std::string & full_path)87*33f37583SAndroid Build Coastguard Worker inline void RemoveMountedApex(const std::string& package, 88*33f37583SAndroid Build Coastguard Worker const std::string& full_path) 89*33f37583SAndroid Build Coastguard Worker REQUIRES(!mounted_apexes_mutex_) { 90*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mounted_apexes_mutex_); 91*33f37583SAndroid Build Coastguard Worker auto it = mounted_apexes_.find(package); 92*33f37583SAndroid Build Coastguard Worker if (it == mounted_apexes_.end()) { 93*33f37583SAndroid Build Coastguard Worker return; 94*33f37583SAndroid Build Coastguard Worker } 95*33f37583SAndroid Build Coastguard Worker 96*33f37583SAndroid Build Coastguard Worker auto& pkg_set = it->second; 97*33f37583SAndroid Build Coastguard Worker 98*33f37583SAndroid Build Coastguard Worker for (auto pkg_it = pkg_set.begin(); pkg_it != pkg_set.end(); ++pkg_it) { 99*33f37583SAndroid Build Coastguard Worker if (pkg_it->full_path == full_path) { 100*33f37583SAndroid Build Coastguard Worker pkg_set.erase(pkg_it); 101*33f37583SAndroid Build Coastguard Worker return; 102*33f37583SAndroid Build Coastguard Worker } 103*33f37583SAndroid Build Coastguard Worker } 104*33f37583SAndroid Build Coastguard Worker } 105*33f37583SAndroid Build Coastguard Worker 106*33f37583SAndroid Build Coastguard Worker // Invoke handler if the passed package is the latest DoIfLatest(const std::string & package,const std::string & full_path,const std::function<base::Result<void> ()> & handler)107*33f37583SAndroid Build Coastguard Worker inline base::Result<void> DoIfLatest( 108*33f37583SAndroid Build Coastguard Worker const std::string& package, const std::string& full_path, 109*33f37583SAndroid Build Coastguard Worker const std::function<base::Result<void>()>& handler) 110*33f37583SAndroid Build Coastguard Worker REQUIRES(!mounted_apexes_mutex_) { 111*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mounted_apexes_mutex_); 112*33f37583SAndroid Build Coastguard Worker auto it = mounted_apexes_.find(package); 113*33f37583SAndroid Build Coastguard Worker CHECK(it != mounted_apexes_.end()); 114*33f37583SAndroid Build Coastguard Worker CHECK(!it->second.empty()); 115*33f37583SAndroid Build Coastguard Worker 116*33f37583SAndroid Build Coastguard Worker auto latest = it->second.rbegin(); 117*33f37583SAndroid Build Coastguard Worker if (latest->full_path == full_path) { 118*33f37583SAndroid Build Coastguard Worker return handler(); 119*33f37583SAndroid Build Coastguard Worker } 120*33f37583SAndroid Build Coastguard Worker return {}; 121*33f37583SAndroid Build Coastguard Worker } 122*33f37583SAndroid Build Coastguard Worker 123*33f37583SAndroid Build Coastguard Worker template <typename T> ForallMountedApexes(const std::string & package,const T & handler)124*33f37583SAndroid Build Coastguard Worker inline void ForallMountedApexes(const std::string& package, 125*33f37583SAndroid Build Coastguard Worker const T& handler) const 126*33f37583SAndroid Build Coastguard Worker REQUIRES(!mounted_apexes_mutex_) { 127*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mounted_apexes_mutex_); 128*33f37583SAndroid Build Coastguard Worker auto outer_it = mounted_apexes_.find(package); 129*33f37583SAndroid Build Coastguard Worker if (outer_it == mounted_apexes_.end()) { 130*33f37583SAndroid Build Coastguard Worker return; 131*33f37583SAndroid Build Coastguard Worker } 132*33f37583SAndroid Build Coastguard Worker for (auto it = outer_it->second.rbegin(), end = outer_it->second.rend(); 133*33f37583SAndroid Build Coastguard Worker it != end; it++) { 134*33f37583SAndroid Build Coastguard Worker bool latest = (it == outer_it->second.rbegin()); 135*33f37583SAndroid Build Coastguard Worker handler(*it, latest); 136*33f37583SAndroid Build Coastguard Worker } 137*33f37583SAndroid Build Coastguard Worker } 138*33f37583SAndroid Build Coastguard Worker 139*33f37583SAndroid Build Coastguard Worker template <typename T> ForallMountedApexes(const T & handler)140*33f37583SAndroid Build Coastguard Worker inline void ForallMountedApexes(const T& handler) const 141*33f37583SAndroid Build Coastguard Worker REQUIRES(!mounted_apexes_mutex_) { 142*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mounted_apexes_mutex_); 143*33f37583SAndroid Build Coastguard Worker for (const auto& pkg : mounted_apexes_) { 144*33f37583SAndroid Build Coastguard Worker for (auto it = pkg.second.rbegin(), end = pkg.second.rend(); it != end; 145*33f37583SAndroid Build Coastguard Worker it++) { 146*33f37583SAndroid Build Coastguard Worker bool latest = (it == pkg.second.rbegin()); 147*33f37583SAndroid Build Coastguard Worker handler(pkg.first, *it, latest); 148*33f37583SAndroid Build Coastguard Worker } 149*33f37583SAndroid Build Coastguard Worker } 150*33f37583SAndroid Build Coastguard Worker } 151*33f37583SAndroid Build Coastguard Worker GetLatestMountedApex(const std::string & package)152*33f37583SAndroid Build Coastguard Worker inline std::optional<MountedApexData> GetLatestMountedApex( 153*33f37583SAndroid Build Coastguard Worker const std::string& package) REQUIRES(!mounted_apexes_mutex_) { 154*33f37583SAndroid Build Coastguard Worker std::optional<MountedApexData> ret; 155*33f37583SAndroid Build Coastguard Worker ForallMountedApexes(package, 156*33f37583SAndroid Build Coastguard Worker [&ret](const MountedApexData& data, bool latest) { 157*33f37583SAndroid Build Coastguard Worker if (latest) { 158*33f37583SAndroid Build Coastguard Worker ret.emplace(data); 159*33f37583SAndroid Build Coastguard Worker } 160*33f37583SAndroid Build Coastguard Worker }); 161*33f37583SAndroid Build Coastguard Worker return ret; 162*33f37583SAndroid Build Coastguard Worker } 163*33f37583SAndroid Build Coastguard Worker 164*33f37583SAndroid Build Coastguard Worker void PopulateFromMounts(const std::vector<std::string>& data_dirs); 165*33f37583SAndroid Build Coastguard Worker 166*33f37583SAndroid Build Coastguard Worker // Resets state of the database. Should only be used in testing. Reset()167*33f37583SAndroid Build Coastguard Worker inline void Reset() REQUIRES(!mounted_apexes_mutex_) { 168*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mounted_apexes_mutex_); 169*33f37583SAndroid Build Coastguard Worker mounted_apexes_.clear(); 170*33f37583SAndroid Build Coastguard Worker } 171*33f37583SAndroid Build Coastguard Worker 172*33f37583SAndroid Build Coastguard Worker private: 173*33f37583SAndroid Build Coastguard Worker // A map from package name to mounted apexes. 174*33f37583SAndroid Build Coastguard Worker // Note: using std::maps to 175*33f37583SAndroid Build Coastguard Worker // a) so we do not have to worry about iterator invalidation. 176*33f37583SAndroid Build Coastguard Worker // b) do not have to const_cast (over std::set) 177*33f37583SAndroid Build Coastguard Worker // TODO(b/158467745): This structure (and functions) need to be guarded by 178*33f37583SAndroid Build Coastguard Worker // locks. 179*33f37583SAndroid Build Coastguard Worker std::map<std::string, std::set<MountedApexData>> mounted_apexes_ 180*33f37583SAndroid Build Coastguard Worker GUARDED_BY(mounted_apexes_mutex_); 181*33f37583SAndroid Build Coastguard Worker 182*33f37583SAndroid Build Coastguard Worker // To fix thread safety negative capability warning 183*33f37583SAndroid Build Coastguard Worker class Mutex : public std::mutex { 184*33f37583SAndroid Build Coastguard Worker public: 185*33f37583SAndroid Build Coastguard Worker // for negative capabilities 186*33f37583SAndroid Build Coastguard Worker const Mutex& operator!() const { return *this; } 187*33f37583SAndroid Build Coastguard Worker }; 188*33f37583SAndroid Build Coastguard Worker mutable Mutex mounted_apexes_mutex_; 189*33f37583SAndroid Build Coastguard Worker CheckUniqueLoopDm()190*33f37583SAndroid Build Coastguard Worker inline void CheckUniqueLoopDm() REQUIRES(mounted_apexes_mutex_) { 191*33f37583SAndroid Build Coastguard Worker std::unordered_set<std::string> loop_devices; 192*33f37583SAndroid Build Coastguard Worker std::unordered_set<std::string> dm_devices; 193*33f37583SAndroid Build Coastguard Worker for (const auto& apex_set : mounted_apexes_) { 194*33f37583SAndroid Build Coastguard Worker for (const auto& mount : apex_set.second) { 195*33f37583SAndroid Build Coastguard Worker if (mount.loop_name != "") { 196*33f37583SAndroid Build Coastguard Worker CHECK(loop_devices.insert(mount.loop_name).second) 197*33f37583SAndroid Build Coastguard Worker << "Duplicate loop device: " << mount.loop_name; 198*33f37583SAndroid Build Coastguard Worker } 199*33f37583SAndroid Build Coastguard Worker if (mount.device_name != "") { 200*33f37583SAndroid Build Coastguard Worker CHECK(dm_devices.insert(mount.device_name).second) 201*33f37583SAndroid Build Coastguard Worker << "Duplicate dm device: " << mount.device_name; 202*33f37583SAndroid Build Coastguard Worker } 203*33f37583SAndroid Build Coastguard Worker } 204*33f37583SAndroid Build Coastguard Worker } 205*33f37583SAndroid Build Coastguard Worker } 206*33f37583SAndroid Build Coastguard Worker }; 207*33f37583SAndroid Build Coastguard Worker 208*33f37583SAndroid Build Coastguard Worker } // namespace apex 209*33f37583SAndroid Build Coastguard Worker } // namespace android 210*33f37583SAndroid Build Coastguard Worker 211*33f37583SAndroid Build Coastguard Worker #endif // ANDROID_APEXD_APEX_DATABASE_H_ 212