blob: 1fb5bd3a2a8a63e45dcdb46ea9b2bc23a0f6245d [file] [log] [blame]
Andreas Gampe3de3e562018-11-14 08:42:48 -08001/*
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>
Andreas Gampe51bb99d2019-03-26 11:38:36 -070022#include <unordered_set>
Andreas Gampe3de3e562018-11-14 08:42:48 -080023
24#include <android-base/logging.h>
25
26namespace android {
27namespace apex {
28
29class 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.
Nikita Ioffec7c27842019-03-26 19:35:15 +000036 std::string mount_point; // Path this apex is mounted on.
37 std::string device_name; // Name of the dm verity device.
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000038 // 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;
Nikita Ioffe78d2bce2020-05-02 01:28:30 +010041 // Whenever apex file specified in full_path was deleted.
42 bool deleted;
Andreas Gampe3de3e562018-11-14 08:42:48 -080043
Andreas Gampe7149e2f2019-02-07 11:44:04 -080044 MountedApexData() {}
Nikita Ioffec7c27842019-03-26 19:35:15 +000045 MountedApexData(const std::string& loop_name, const std::string& full_path,
46 const std::string& mount_point,
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000047 const std::string& device_name,
48 const std::string& hashtree_loop_name)
Nikita Ioffec7c27842019-03-26 19:35:15 +000049 : loop_name(loop_name),
50 full_path(full_path),
51 mount_point(mount_point),
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000052 device_name(device_name),
53 hashtree_loop_name(hashtree_loop_name) {}
Andreas Gampe3de3e562018-11-14 08:42:48 -080054
55 inline bool operator<(const MountedApexData& rhs) const {
Andreas Gampe7149e2f2019-02-07 11:44:04 -080056 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 }
Nikita Ioffec7c27842019-03-26 19:35:15 +000062 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 }
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000074 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;
Andreas Gampe3de3e562018-11-14 08:42:48 -080081 }
82 };
83
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
Andreas Gampe51bb99d2019-03-26 11:38:36 -070096 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 }
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +0000109 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 }
Andreas Gampe51bb99d2019-03-26 11:38:36 -0700113 }
114 }
115 }
116
Andreas Gampe3de3e562018-11-14 08:42:48 -0800117 template <typename... 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();
Andreas Gampe51bb99d2019-03-26 11:38:36 -0700133 CheckUniqueLoopDm();
Andreas Gampe3de3e562018-11-14 08:42:48 -0800134 }
135
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
Andreas Gampedeece7e2018-12-13 11:24:51 -0800153 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;
Andreas Gampe4510d492018-12-12 15:56:05 -0800163 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;
Andreas Gampedeece7e2018-12-13 11:24:51 -0800167 }
168 }
169 return;
170 }
171 }
172
173 LOG(FATAL) << "Did not find " << package << " " << full_path;
174 }
175
Andreas Gampe3de3e562018-11-14 08:42:48 -0800176 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>
187 inline void ForallMountedApexes(const std::string& package,
Andreas Gampe7149e2f2019-02-07 11:44:04 -0800188 const T& handler) const {
Andreas Gampe3de3e562018-11-14 08:42:48 -0800189 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
Andreas Gampe0fa59af2018-11-16 11:12:11 -0800198 template <typename T>
Andreas Gampe7149e2f2019-02-07 11:44:04 -0800199 inline void ForallMountedApexes(const T& handler) const {
Andreas Gampe0fa59af2018-11-16 11:12:11 -0800200 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
Jooyung Han7dca50c2019-04-12 04:52:42 +0900207 void PopulateFromMounts();
208
Andreas Gampe3de3e562018-11-14 08:42:48 -0800209 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: Eventually 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_