• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 #pragma once
18 
19 #include <android-base/result.h>
20 
21 #include <functional>
22 #include <optional>
23 #include <string>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <vector>
27 
28 #include "apex_constants.h"
29 #include "apex_file.h"
30 
31 namespace android {
32 namespace apex {
33 
34 using ApexFileRef = std::reference_wrapper<const android::apex::ApexFile>;
35 
36 // This class serves as a ApexFile repository for all apexes on device. It also
37 // provides information about the ApexFiles it hosts, such as which are
38 // pre-installed and which are data. Such information can be used, for example,
39 // to verify validity of an apex before trying to mount it.
40 //
41 // It's expected to have a single instance of this class in a process that
42 // mounts apexes (e.g. apexd, otapreopt_chroot).
43 class ApexFileRepository final {
44  public:
45   // c-tors and d-tor are exposed for testing.
46   explicit ApexFileRepository(
47       const std::string& decompression_dir = kApexDecompressedDir)
decompression_dir_(decompression_dir)48       : decompression_dir_(decompression_dir){};
ApexFileRepository(bool enforce_multi_install_partition,const std::vector<std::string> & multi_install_select_prop_prefixes)49   explicit ApexFileRepository(
50       bool enforce_multi_install_partition,
51       const std::vector<std::string>& multi_install_select_prop_prefixes)
52       : multi_install_select_prop_prefixes_(multi_install_select_prop_prefixes),
53         enforce_multi_install_partition_(enforce_multi_install_partition){};
54 
~ApexFileRepository()55   ~ApexFileRepository() {
56     pre_installed_store_.clear();
57     data_store_.clear();
58   };
59 
60   // Returns a singletone instance of this class.
61   static ApexFileRepository& GetInstance();
62 
63   // Populate instance by collecting pre-installed apex files from the given
64   // |prebuilt_dirs|.
65   // Note: this call is **not thread safe** and is expected to be performed in a
66   // single thread during initialization of apexd. After initialization is
67   // finished, all queries to the instance are thread safe.
68   android::base::Result<void> AddPreInstalledApex(
69       const std::vector<std::string>& prebuilt_dirs);
70 
71   // Populate instance by collecting host-provided apex files via
72   // |metadata_partition|. Host can provide its apexes to a VM instance via the
73   // virtual disk image which has partitions: (see
74   // /packages/modules/Virtualization/microdroid for the details)
75   //  - metadata partition(/dev/block/vd*1) should be accessed by
76   //  setting the system property apexd.payload_metadata.prop. On microdroid,
77   //  this is /dev/block/by-name/payload-metadata.
78   //  - each subsequence partition(/dev/block/vd*{2,3,..}) represents an APEX
79   //  archive.
80   // It will fail if there is more than one apex with the same name in
81   // pre-installed and block apexes. Note: this call is **not thread safe** and
82   // is expected to be performed in a single thread during initialization of
83   // apexd. After initialization is finished, all queries to the instance are
84   // thread safe.
85   // This will return the number of block apexes that were added.
86   android::base::Result<int> AddBlockApex(
87       const std::string& metadata_partition);
88 
89   // Populate instance by collecting data apex files from the given |data_dir|.
90   // Note: this call is **not thread safe** and is expected to be performed in a
91   // single thread during initialization of apexd. After initialization is
92   // finished, all queries to the instance are thread safe.
93   android::base::Result<void> AddDataApex(const std::string& data_dir);
94 
95   // Returns trusted public key for an apex with the given |name|.
96   android::base::Result<const std::string> GetPublicKey(
97       const std::string& name) const;
98 
99   // Returns path to the pre-installed version of an apex with the given |name|.
100   android::base::Result<const std::string> GetPreinstalledPath(
101       const std::string& name) const;
102 
103   // Returns path to the data version of an apex with the given |name|.
104   android::base::Result<const std::string> GetDataPath(
105       const std::string& name) const;
106 
107   // Returns root digest of an apex with the given |path| for block apexes.
108   std::optional<std::string> GetBlockApexRootDigest(
109       const std::string& path) const;
110 
111   // Returns timestamp to be used for the block apex of the given |path|.
112   std::optional<int64_t> GetBlockApexLastUpdateSeconds(
113       const std::string& path) const;
114 
115   // Checks whether there is a pre-installed version of an apex with the given
116   // |name|.
117   bool HasPreInstalledVersion(const std::string& name) const;
118 
119   // Checks whether there is a data version of an apex with the given |name|.
120   bool HasDataVersion(const std::string& name) const;
121 
122   // Checks if given |apex| is pre-installed.
123   bool IsPreInstalledApex(const ApexFile& apex) const;
124 
125   // Checks if given |apex| is decompressed from a pre-installed APEX
126   bool IsDecompressedApex(const ApexFile& apex) const;
127 
128   // Checks if given |apex| is loaded from block device.
129   bool IsBlockApex(const ApexFile& apex) const;
130 
131   // Returns reference to all pre-installed APEX on device
132   std::vector<ApexFileRef> GetPreInstalledApexFiles() const;
133 
134   // Returns reference to all data APEX on device
135   std::vector<ApexFileRef> GetDataApexFiles() const;
136 
137   // Group all ApexFiles on device by their package name
138   std::unordered_map<std::string, std::vector<ApexFileRef>> AllApexFilesByName()
139       const;
140 
141   // Returns a pre-installed version of apex with the given name. Caller is
142   // expected to check if there is a pre-installed apex with the given name
143   // using |HasPreinstalledVersion| function.
144   ApexFileRef GetPreInstalledApex(const std::string& name) const;
145   // Returns a data version of apex with the given name. Caller is
146   // expected to check if there is a data apex with the given name
147   // using |HasDataVersion| function.
148   ApexFileRef GetDataApex(const std::string& name) const;
149 
150   // Clears ApexFileRepostiry.
151   // Only use in tests.
152   void Reset(const std::string& decompression_dir = kApexDecompressedDir) {
153     pre_installed_store_.clear();
154     data_store_.clear();
155     block_apex_overrides_.clear();
156     decompression_dir_ = decompression_dir;
157     block_disk_path_.reset();
158   }
159 
160  private:
161   // Non-copyable && non-moveable.
162   ApexFileRepository(const ApexFileRepository&) = delete;
163   ApexFileRepository& operator=(const ApexFileRepository&) = delete;
164   ApexFileRepository& operator=(ApexFileRepository&&) = delete;
165   ApexFileRepository(ApexFileRepository&&) = delete;
166 
167   // Scans apexes in the given directory and adds collected data into
168   // |pre_installed_store_|.
169   android::base::Result<void> ScanBuiltInDir(const std::string& dir);
170 
171   std::unordered_map<std::string, ApexFile> pre_installed_store_, data_store_;
172 
173   // Multi-installed APEX name -> all encountered public keys for this APEX.
174   std::unordered_map<std::string, std::unordered_set<std::string>>
175       multi_install_public_keys_;
176 
177   // Prefixes used when looking for multi-installed APEX sysprops.
178   // Order matters: the first non-empty prop value is returned.
179   std::vector<std::string> multi_install_select_prop_prefixes_ = {
180       // Check persist props first, to allow users to override bootconfig.
181       kMultiApexSelectPersistPrefix,
182       kMultiApexSelectBootconfigPrefix,
183   };
184 
185   // Allows multi-install APEXes outside of expected partitions.
186   // Only set false in tests.
187   bool enforce_multi_install_partition_ = true;
188 
189   // Decompression directory which will be used to determine if apex is
190   // decompressed or not
191   std::string decompression_dir_;
192 
193   // Disk path where block apexes are read from. AddBlockApex() sets this.
194   std::optional<std::string> block_disk_path_;
195 
196   // Information from the metadata for block apexes, overriding the file data.
197   struct BlockApexOverride {
198     // Root digest for the APEX. When specified in block apex config, it
199     // should be used/checked when activating the apex to avoid
200     // TOCTOU(time-of-check to time-of-use).
201     std::optional<std::string> block_apex_root_digest;
202     // The last update time of the APEX.
203     std::optional<int64_t> last_update_seconds;
204   };
205 
206   // Use "path" as key instead of APEX name because there can be multiple
207   // versions of sharedlibs APEXes.
208   std::unordered_map<std::string, BlockApexOverride> block_apex_overrides_;
209 };
210 
211 }  // namespace apex
212 }  // namespace android
213