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