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 MountedApexDataMountedApexData39 MountedApexData() {} MountedApexDataMountedApexData40 MountedApexData(const std::string& loop_name, const std::string& full_path, 41 const std::string& mount_point, 42 const std::string& device_name) 43 : loop_name(loop_name), 44 full_path(full_path), 45 mount_point(mount_point), 46 device_name(device_name) {} 47 48 inline bool operator<(const MountedApexData& rhs) const { 49 int compare_val = loop_name.compare(rhs.loop_name); 50 if (compare_val < 0) { 51 return true; 52 } else if (compare_val > 0) { 53 return false; 54 } 55 compare_val = full_path.compare(rhs.full_path); 56 if (compare_val < 0) { 57 return true; 58 } else if (compare_val > 0) { 59 return false; 60 } 61 compare_val = mount_point.compare(rhs.mount_point); 62 if (compare_val < 0) { 63 return true; 64 } else if (compare_val > 0) { 65 return false; 66 } 67 return device_name < rhs.device_name; 68 } 69 }; 70 CheckAtMostOneLatest()71 inline void CheckAtMostOneLatest() { 72 for (const auto& apex_set : mounted_apexes_) { 73 size_t count = 0; 74 for (const auto& pair : apex_set.second) { 75 if (pair.second) { 76 count++; 77 } 78 } 79 CHECK_LE(count, 1u) << apex_set.first; 80 } 81 } 82 CheckUniqueLoopDm()83 inline void CheckUniqueLoopDm() { 84 std::unordered_set<std::string> loop_devices; 85 std::unordered_set<std::string> dm_devices; 86 for (const auto& apex_set : mounted_apexes_) { 87 for (const auto& pair : apex_set.second) { 88 if (pair.first.loop_name != "") { 89 CHECK(loop_devices.insert(pair.first.loop_name).second) 90 << "Duplicate loop device: " << pair.first.loop_name; 91 } 92 if (pair.first.device_name != "") { 93 CHECK(dm_devices.insert(pair.first.device_name).second) 94 << "Duplicate dm device: " << pair.first.device_name; 95 } 96 } 97 } 98 } 99 100 template <typename... Args> AddMountedApex(const std::string & package,bool latest,Args &&...args)101 inline void AddMountedApex(const std::string& package, bool latest, 102 Args&&... args) { 103 auto it = mounted_apexes_.find(package); 104 if (it == mounted_apexes_.end()) { 105 auto insert_it = 106 mounted_apexes_.emplace(package, std::map<MountedApexData, bool>()); 107 CHECK(insert_it.second); 108 it = insert_it.first; 109 } 110 111 auto check_it = it->second.emplace( 112 MountedApexData(std::forward<Args>(args)...), latest); 113 CHECK(check_it.second); 114 115 CheckAtMostOneLatest(); 116 CheckUniqueLoopDm(); 117 } 118 RemoveMountedApex(const std::string & package,const std::string & full_path)119 inline void RemoveMountedApex(const std::string& package, 120 const std::string& full_path) { 121 auto it = mounted_apexes_.find(package); 122 if (it == mounted_apexes_.end()) { 123 return; 124 } 125 126 auto& pkg_map = it->second; 127 128 for (auto pkg_it = pkg_map.begin(); pkg_it != pkg_map.end(); ++pkg_it) { 129 if (pkg_it->first.full_path == full_path) { 130 pkg_map.erase(pkg_it); 131 return; 132 } 133 } 134 } 135 SetLatest(const std::string & package,const std::string & full_path)136 inline void SetLatest(const std::string& package, 137 const std::string& full_path) { 138 auto it = mounted_apexes_.find(package); 139 CHECK(it != mounted_apexes_.end()); 140 141 auto& pkg_map = it->second; 142 143 for (auto pkg_it = pkg_map.begin(); pkg_it != pkg_map.end(); ++pkg_it) { 144 if (pkg_it->first.full_path == full_path) { 145 pkg_it->second = true; 146 for (auto reset_it = pkg_map.begin(); reset_it != pkg_map.end(); 147 ++reset_it) { 148 if (reset_it != pkg_it) { 149 reset_it->second = false; 150 } 151 } 152 return; 153 } 154 } 155 156 LOG(FATAL) << "Did not find " << package << " " << full_path; 157 } 158 UnsetLatestForall(const std::string & package)159 inline void UnsetLatestForall(const std::string& package) { 160 auto it = mounted_apexes_.find(package); 161 if (it == mounted_apexes_.end()) { 162 return; 163 } 164 for (auto& data : it->second) { 165 data.second = false; 166 } 167 } 168 169 template <typename T> ForallMountedApexes(const std::string & package,const T & handler)170 inline void ForallMountedApexes(const std::string& package, 171 const T& handler) const { 172 auto it = mounted_apexes_.find(package); 173 if (it == mounted_apexes_.end()) { 174 return; 175 } 176 for (auto& pair : it->second) { 177 handler(pair.first, pair.second); 178 } 179 } 180 181 template <typename T> ForallMountedApexes(const T & handler)182 inline void ForallMountedApexes(const T& handler) const { 183 for (const auto& pkg : mounted_apexes_) { 184 for (const auto& pair : pkg.second) { 185 handler(pkg.first, pair.first, pair.second); 186 } 187 } 188 } 189 190 void PopulateFromMounts(); 191 192 private: 193 // A map from package name to mounted apexes. 194 // Note: using std::maps to 195 // a) so we do not have to worry about iterator invalidation. 196 // b) do not have to const_cast (over std::set) 197 // TODO: Eventually this structure (and functions) need to be guarded by 198 // locks. 199 std::map<std::string, std::map<MountedApexData, bool>> mounted_apexes_; 200 }; 201 202 } // namespace apex 203 } // namespace android 204 205 #endif // ANDROID_APEXD_APEX_DATABASE_H_ 206