blob: e9e1c322f915682cae26a10249b6f0853484f277 [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.
Andreas Gampe3de3e562018-11-14 08:42:48 -080038
Andreas Gampe7149e2f2019-02-07 11:44:04 -080039 MountedApexData() {}
Nikita Ioffec7c27842019-03-26 19:35:15 +000040 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) {}
Andreas Gampe3de3e562018-11-14 08:42:48 -080047
48 inline bool operator<(const MountedApexData& rhs) const {
Andreas Gampe7149e2f2019-02-07 11:44:04 -080049 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 }
Nikita Ioffec7c27842019-03-26 19:35:15 +000055 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;
Andreas Gampe3de3e562018-11-14 08:42:48 -080068 }
69 };
70
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
Andreas Gampe51bb99d2019-03-26 11:38:36 -070083 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
Andreas Gampe3de3e562018-11-14 08:42:48 -0800100 template <typename... 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();
Andreas Gampe51bb99d2019-03-26 11:38:36 -0700116 CheckUniqueLoopDm();
Andreas Gampe3de3e562018-11-14 08:42:48 -0800117 }
118
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
Andreas Gampedeece7e2018-12-13 11:24:51 -0800136 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;
Andreas Gampe4510d492018-12-12 15:56:05 -0800146 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;
Andreas Gampedeece7e2018-12-13 11:24:51 -0800150 }
151 }
152 return;
153 }
154 }
155
156 LOG(FATAL) << "Did not find " << package << " " << full_path;
157 }
158
Andreas Gampe3de3e562018-11-14 08:42:48 -0800159 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>
170 inline void ForallMountedApexes(const std::string& package,
Andreas Gampe7149e2f2019-02-07 11:44:04 -0800171 const T& handler) const {
Andreas Gampe3de3e562018-11-14 08:42:48 -0800172 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
Andreas Gampe0fa59af2018-11-16 11:12:11 -0800181 template <typename T>
Andreas Gampe7149e2f2019-02-07 11:44:04 -0800182 inline void ForallMountedApexes(const T& handler) const {
Andreas Gampe0fa59af2018-11-16 11:12:11 -0800183 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
Jooyung Han451cc342019-04-12 04:52:42 +0900190 void PopulateFromMounts();
191
Andreas Gampe3de3e562018-11-14 08:42:48 -0800192 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_