• 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(const std::string & decompression_dir,bool ignore_duplicate_apex_definitions)55   explicit ApexFileRepository(const std::string& decompression_dir,
56                               bool ignore_duplicate_apex_definitions)
57       : ignore_duplicate_apex_definitions_(ignore_duplicate_apex_definitions),
58         decompression_dir_(decompression_dir){};
59 
~ApexFileRepository()60   ~ApexFileRepository() {
61     pre_installed_store_.clear();
62     data_store_.clear();
63   };
64 
65   // Returns a singletone instance of this class.
66   static ApexFileRepository& GetInstance();
67 
68   // Populate instance by collecting pre-installed apex files from the given
69   // |prebuilt_dirs|.
70   // Note: this call is **not thread safe** and is expected to be performed in a
71   // single thread during initialization of apexd. After initialization is
72   // finished, all queries to the instance are thread safe.
73   android::base::Result<void> AddPreInstalledApex(
74       const std::vector<std::string>& prebuilt_dirs);
75 
76   // Populate instance by collecting host-provided apex files via
77   // |metadata_partition|. Host can provide its apexes to a VM instance via the
78   // virtual disk image which has partitions: (see
79   // /packages/modules/Virtualization/microdroid for the details)
80   //  - metadata partition(/dev/block/vd*1) should be accessed by
81   //  setting the system property apexd.payload_metadata.prop. On microdroid,
82   //  this is /dev/block/by-name/payload-metadata.
83   //  - each subsequence partition(/dev/block/vd*{2,3,..}) represents an APEX
84   //  archive.
85   // It will fail if there is more than one apex with the same name in
86   // pre-installed and block apexes. Note: this call is **not thread safe** and
87   // is expected to be performed in a single thread during initialization of
88   // apexd. After initialization is finished, all queries to the instance are
89   // thread safe.
90   // This will return the number of block apexes that were added.
91   android::base::Result<int> AddBlockApex(
92       const std::string& metadata_partition);
93 
94   // Populate instance by collecting data apex files from the given |data_dir|.
95   // Note: this call is **not thread safe** and is expected to be performed in a
96   // single thread during initialization of apexd. After initialization is
97   // finished, all queries to the instance are thread safe.
98   android::base::Result<void> AddDataApex(const std::string& data_dir);
99 
100   // Returns trusted public key for an apex with the given |name|.
101   android::base::Result<const std::string> GetPublicKey(
102       const std::string& name) const;
103 
104   // Returns path to the pre-installed version of an apex with the given |name|.
105   android::base::Result<const std::string> GetPreinstalledPath(
106       const std::string& name) const;
107 
108   // Returns path to the data version of an apex with the given |name|.
109   android::base::Result<const std::string> GetDataPath(
110       const std::string& name) const;
111 
112   // Returns root digest of an apex with the given |path| for block apexes.
113   std::optional<std::string> GetBlockApexRootDigest(
114       const std::string& path) const;
115 
116   // Returns timestamp to be used for the block apex of the given |path|.
117   std::optional<int64_t> GetBlockApexLastUpdateSeconds(
118       const std::string& path) const;
119 
120   // Checks whether there is a pre-installed version of an apex with the given
121   // |name|.
122   bool HasPreInstalledVersion(const std::string& name) const;
123 
124   // Checks whether there is a data version of an apex with the given |name|.
125   bool HasDataVersion(const std::string& name) const;
126 
127   // Checks if given |apex| is pre-installed.
128   bool IsPreInstalledApex(const ApexFile& apex) const;
129 
130   // Checks if given |apex| is decompressed from a pre-installed APEX
131   bool IsDecompressedApex(const ApexFile& apex) const;
132 
133   // Checks if given |apex| is loaded from block device.
134   bool IsBlockApex(const ApexFile& apex) const;
135 
136   // Returns reference to all pre-installed APEX on device
137   std::vector<ApexFileRef> GetPreInstalledApexFiles() const;
138 
139   // Returns reference to all data APEX on device
140   std::vector<ApexFileRef> GetDataApexFiles() const;
141 
142   // Group all ApexFiles on device by their package name
143   std::unordered_map<std::string, std::vector<ApexFileRef>> AllApexFilesByName()
144       const;
145 
146   // Returns a pre-installed version of apex with the given name. Caller is
147   // expected to check if there is a pre-installed apex with the given name
148   // using |HasPreinstalledVersion| function.
149   ApexFileRef GetPreInstalledApex(const std::string& name) const;
150   // Returns a data version of apex with the given name. Caller is
151   // expected to check if there is a data apex with the given name
152   // using |HasDataVersion| function.
153   ApexFileRef GetDataApex(const std::string& name) const;
154 
155   // Clears ApexFileRepostiry.
156   // Only use in tests.
157   void Reset(const std::string& decompression_dir = kApexDecompressedDir) {
158     pre_installed_store_.clear();
159     data_store_.clear();
160     block_apex_overrides_.clear();
161     decompression_dir_ = decompression_dir;
162     block_disk_path_.reset();
163   }
164 
165  private:
166   // Non-copyable && non-moveable.
167   ApexFileRepository(const ApexFileRepository&) = delete;
168   ApexFileRepository& operator=(const ApexFileRepository&) = delete;
169   ApexFileRepository& operator=(ApexFileRepository&&) = delete;
170   ApexFileRepository(ApexFileRepository&&) = delete;
171 
172   // Scans apexes in the given directory and adds collected data into
173   // |pre_installed_store_|.
174   android::base::Result<void> ScanBuiltInDir(const std::string& dir);
175 
176   std::unordered_map<std::string, ApexFile> pre_installed_store_, data_store_;
177 
178   // Multi-installed APEX name -> all encountered public keys for this APEX.
179   std::unordered_map<std::string, std::unordered_set<std::string>>
180       multi_install_public_keys_;
181 
182   // Prefixes used when looking for multi-installed APEX sysprops.
183   // Order matters: the first non-empty prop value is returned.
184   std::vector<std::string> multi_install_select_prop_prefixes_ =
185       kMultiApexSelectPrefix;
186 
187   // Allows multi-install APEXes outside of expected partitions.
188   // Only set false in tests.
189   bool enforce_multi_install_partition_ = true;
190 
191   // Ignore duplicate vendor APEX definitions, normally a duplicate definition
192   // is considered an error.
193   bool ignore_duplicate_apex_definitions_ = false;
194 
195   // Decompression directory which will be used to determine if apex is
196   // decompressed or not
197   std::string decompression_dir_;
198 
199   // Disk path where block apexes are read from. AddBlockApex() sets this.
200   std::optional<std::string> block_disk_path_;
201 
202   // Information from the metadata for block apexes, overriding the file data.
203   struct BlockApexOverride {
204     // Root digest for the APEX. When specified in block apex config, it
205     // should be used/checked when activating the apex to avoid
206     // TOCTOU(time-of-check to time-of-use).
207     std::optional<std::string> block_apex_root_digest;
208     // The last update time of the APEX.
209     std::optional<int64_t> last_update_seconds;
210   };
211 
212   // Use "path" as key instead of APEX name because there can be multiple
213   // versions of sharedlibs APEXes.
214   std::unordered_map<std::string, BlockApexOverride> block_apex_overrides_;
215 };
216 
217 }  // namespace apex
218 }  // namespace android
219