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