xref: /aosp_15_r20/system/apex/apexd/apex_database.h (revision 33f3758387333dbd2962d7edbd98681940d895da)
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