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