1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker * Copyright (C) 2019 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 #include "apex_file_repository.h"
18*33f37583SAndroid Build Coastguard Worker
19*33f37583SAndroid Build Coastguard Worker #include <android-base/file.h>
20*33f37583SAndroid Build Coastguard Worker #include <android-base/properties.h>
21*33f37583SAndroid Build Coastguard Worker #include <android-base/result.h>
22*33f37583SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
23*33f37583SAndroid Build Coastguard Worker #include <android-base/strings.h>
24*33f37583SAndroid Build Coastguard Worker #include <microdroid/metadata.h>
25*33f37583SAndroid Build Coastguard Worker
26*33f37583SAndroid Build Coastguard Worker #include <cstdint>
27*33f37583SAndroid Build Coastguard Worker #include <filesystem>
28*33f37583SAndroid Build Coastguard Worker #include <unordered_map>
29*33f37583SAndroid Build Coastguard Worker
30*33f37583SAndroid Build Coastguard Worker #include "apex_blocklist.h"
31*33f37583SAndroid Build Coastguard Worker #include "apex_constants.h"
32*33f37583SAndroid Build Coastguard Worker #include "apex_file.h"
33*33f37583SAndroid Build Coastguard Worker #include "apexd_brand_new_verifier.h"
34*33f37583SAndroid Build Coastguard Worker #include "apexd_utils.h"
35*33f37583SAndroid Build Coastguard Worker #include "apexd_vendor_apex.h"
36*33f37583SAndroid Build Coastguard Worker #include "apexd_verity.h"
37*33f37583SAndroid Build Coastguard Worker
38*33f37583SAndroid Build Coastguard Worker using android::base::EndsWith;
39*33f37583SAndroid Build Coastguard Worker using android::base::Error;
40*33f37583SAndroid Build Coastguard Worker using android::base::GetProperty;
41*33f37583SAndroid Build Coastguard Worker using android::base::Result;
42*33f37583SAndroid Build Coastguard Worker using ::apex::proto::ApexBlocklist;
43*33f37583SAndroid Build Coastguard Worker
44*33f37583SAndroid Build Coastguard Worker namespace android {
45*33f37583SAndroid Build Coastguard Worker namespace apex {
46*33f37583SAndroid Build Coastguard Worker
ConsumeApexPackageSuffix(const std::string & path)47*33f37583SAndroid Build Coastguard Worker std::string ConsumeApexPackageSuffix(const std::string& path) {
48*33f37583SAndroid Build Coastguard Worker std::string_view path_view(path);
49*33f37583SAndroid Build Coastguard Worker android::base::ConsumeSuffix(&path_view, kApexPackageSuffix);
50*33f37583SAndroid Build Coastguard Worker android::base::ConsumeSuffix(&path_view, kCompressedApexPackageSuffix);
51*33f37583SAndroid Build Coastguard Worker return std::string(path_view);
52*33f37583SAndroid Build Coastguard Worker }
53*33f37583SAndroid Build Coastguard Worker
GetApexSelectFilenameFromProp(const std::vector<std::string> & prefixes,const std::string & apex_name)54*33f37583SAndroid Build Coastguard Worker std::string GetApexSelectFilenameFromProp(
55*33f37583SAndroid Build Coastguard Worker const std::vector<std::string>& prefixes, const std::string& apex_name) {
56*33f37583SAndroid Build Coastguard Worker for (const std::string& prefix : prefixes) {
57*33f37583SAndroid Build Coastguard Worker const std::string& filename = GetProperty(prefix + apex_name, "");
58*33f37583SAndroid Build Coastguard Worker if (filename != "") {
59*33f37583SAndroid Build Coastguard Worker return ConsumeApexPackageSuffix(filename);
60*33f37583SAndroid Build Coastguard Worker }
61*33f37583SAndroid Build Coastguard Worker }
62*33f37583SAndroid Build Coastguard Worker return "";
63*33f37583SAndroid Build Coastguard Worker }
64*33f37583SAndroid Build Coastguard Worker
ScanBuiltInDir(const std::string & dir,ApexPartition partition)65*33f37583SAndroid Build Coastguard Worker Result<void> ApexFileRepository::ScanBuiltInDir(const std::string& dir,
66*33f37583SAndroid Build Coastguard Worker ApexPartition partition) {
67*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Scanning " << dir << " for pre-installed ApexFiles";
68*33f37583SAndroid Build Coastguard Worker if (access(dir.c_str(), F_OK) != 0 && errno == ENOENT) {
69*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << dir << " does not exist. Skipping";
70*33f37583SAndroid Build Coastguard Worker return {};
71*33f37583SAndroid Build Coastguard Worker }
72*33f37583SAndroid Build Coastguard Worker
73*33f37583SAndroid Build Coastguard Worker Result<std::vector<std::string>> all_apex_files = FindFilesBySuffix(
74*33f37583SAndroid Build Coastguard Worker dir, {kApexPackageSuffix, kCompressedApexPackageSuffix});
75*33f37583SAndroid Build Coastguard Worker if (!all_apex_files.ok()) {
76*33f37583SAndroid Build Coastguard Worker return all_apex_files.error();
77*33f37583SAndroid Build Coastguard Worker }
78*33f37583SAndroid Build Coastguard Worker
79*33f37583SAndroid Build Coastguard Worker // TODO(b/179248390): scan parallelly if possible
80*33f37583SAndroid Build Coastguard Worker for (const auto& file : *all_apex_files) {
81*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Found pre-installed APEX " << file;
82*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(file);
83*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
84*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to open " << file << " : " << apex_file.error();
85*33f37583SAndroid Build Coastguard Worker }
86*33f37583SAndroid Build Coastguard Worker
87*33f37583SAndroid Build Coastguard Worker const std::string& name = apex_file->GetManifest().name();
88*33f37583SAndroid Build Coastguard Worker
89*33f37583SAndroid Build Coastguard Worker // Check if this APEX name is treated as a multi-install APEX.
90*33f37583SAndroid Build Coastguard Worker //
91*33f37583SAndroid Build Coastguard Worker // Note: apexd is a oneshot service which runs at boot, but can be restarted
92*33f37583SAndroid Build Coastguard Worker // when needed (such as staging an APEX update). If a multi-install select
93*33f37583SAndroid Build Coastguard Worker // property changes between boot and when apexd restarts, the LOG messages
94*33f37583SAndroid Build Coastguard Worker // below will report the version that will be activated on next reboot,
95*33f37583SAndroid Build Coastguard Worker // which may differ from the currently-active version.
96*33f37583SAndroid Build Coastguard Worker std::string select_filename = GetApexSelectFilenameFromProp(
97*33f37583SAndroid Build Coastguard Worker multi_install_select_prop_prefixes_, name);
98*33f37583SAndroid Build Coastguard Worker if (!select_filename.empty()) {
99*33f37583SAndroid Build Coastguard Worker std::string path;
100*33f37583SAndroid Build Coastguard Worker if (!android::base::Realpath(apex_file->GetPath(), &path)) {
101*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Unable to resolve realpath of APEX with path "
102*33f37583SAndroid Build Coastguard Worker << apex_file->GetPath();
103*33f37583SAndroid Build Coastguard Worker continue;
104*33f37583SAndroid Build Coastguard Worker }
105*33f37583SAndroid Build Coastguard Worker if (enforce_multi_install_partition_ &&
106*33f37583SAndroid Build Coastguard Worker partition != ApexPartition::Vendor &&
107*33f37583SAndroid Build Coastguard Worker partition != ApexPartition::Odm) {
108*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Multi-install APEX " << path
109*33f37583SAndroid Build Coastguard Worker << " can only be preinstalled on /{odm,vendor}/apex/.";
110*33f37583SAndroid Build Coastguard Worker continue;
111*33f37583SAndroid Build Coastguard Worker }
112*33f37583SAndroid Build Coastguard Worker
113*33f37583SAndroid Build Coastguard Worker auto& keys = multi_install_public_keys_[name];
114*33f37583SAndroid Build Coastguard Worker keys.insert(apex_file->GetBundledPublicKey());
115*33f37583SAndroid Build Coastguard Worker if (keys.size() > 1) {
116*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Multi-install APEXes for " << name
117*33f37583SAndroid Build Coastguard Worker << " have different public keys.";
118*33f37583SAndroid Build Coastguard Worker // If any versions of a multi-installed APEX differ in public key,
119*33f37583SAndroid Build Coastguard Worker // then no version should be installed.
120*33f37583SAndroid Build Coastguard Worker if (auto it = pre_installed_store_.find(name);
121*33f37583SAndroid Build Coastguard Worker it != pre_installed_store_.end()) {
122*33f37583SAndroid Build Coastguard Worker pre_installed_store_.erase(it);
123*33f37583SAndroid Build Coastguard Worker partition_store_.erase(name);
124*33f37583SAndroid Build Coastguard Worker }
125*33f37583SAndroid Build Coastguard Worker continue;
126*33f37583SAndroid Build Coastguard Worker }
127*33f37583SAndroid Build Coastguard Worker
128*33f37583SAndroid Build Coastguard Worker if (ConsumeApexPackageSuffix(android::base::Basename(path)) ==
129*33f37583SAndroid Build Coastguard Worker select_filename) {
130*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Found APEX at path " << path << " for multi-install APEX "
131*33f37583SAndroid Build Coastguard Worker << name;
132*33f37583SAndroid Build Coastguard Worker // Add the APEX file to the store if its filename matches the property.
133*33f37583SAndroid Build Coastguard Worker pre_installed_store_.emplace(name, std::move(*apex_file));
134*33f37583SAndroid Build Coastguard Worker partition_store_.emplace(name, partition);
135*33f37583SAndroid Build Coastguard Worker } else {
136*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Skipping APEX at path " << path
137*33f37583SAndroid Build Coastguard Worker << " because it does not match expected multi-install"
138*33f37583SAndroid Build Coastguard Worker << " APEX property for " << name;
139*33f37583SAndroid Build Coastguard Worker }
140*33f37583SAndroid Build Coastguard Worker
141*33f37583SAndroid Build Coastguard Worker continue;
142*33f37583SAndroid Build Coastguard Worker }
143*33f37583SAndroid Build Coastguard Worker
144*33f37583SAndroid Build Coastguard Worker auto it = pre_installed_store_.find(name);
145*33f37583SAndroid Build Coastguard Worker if (it == pre_installed_store_.end()) {
146*33f37583SAndroid Build Coastguard Worker pre_installed_store_.emplace(name, std::move(*apex_file));
147*33f37583SAndroid Build Coastguard Worker partition_store_.emplace(name, partition);
148*33f37583SAndroid Build Coastguard Worker } else if (it->second.GetPath() != apex_file->GetPath()) {
149*33f37583SAndroid Build Coastguard Worker LOG(FATAL) << "Found two apex packages " << it->second.GetPath()
150*33f37583SAndroid Build Coastguard Worker << " and " << apex_file->GetPath()
151*33f37583SAndroid Build Coastguard Worker << " with the same module name " << name;
152*33f37583SAndroid Build Coastguard Worker } else if (it->second.GetBundledPublicKey() !=
153*33f37583SAndroid Build Coastguard Worker apex_file->GetBundledPublicKey()) {
154*33f37583SAndroid Build Coastguard Worker LOG(FATAL) << "Public key of apex package " << it->second.GetPath()
155*33f37583SAndroid Build Coastguard Worker << " (" << name << ") has unexpectedly changed";
156*33f37583SAndroid Build Coastguard Worker }
157*33f37583SAndroid Build Coastguard Worker }
158*33f37583SAndroid Build Coastguard Worker multi_install_public_keys_.clear();
159*33f37583SAndroid Build Coastguard Worker return {};
160*33f37583SAndroid Build Coastguard Worker }
161*33f37583SAndroid Build Coastguard Worker
GetInstance()162*33f37583SAndroid Build Coastguard Worker ApexFileRepository& ApexFileRepository::GetInstance() {
163*33f37583SAndroid Build Coastguard Worker static ApexFileRepository instance;
164*33f37583SAndroid Build Coastguard Worker return instance;
165*33f37583SAndroid Build Coastguard Worker }
166*33f37583SAndroid Build Coastguard Worker
AddPreInstalledApex(const std::unordered_map<ApexPartition,std::string> & partition_to_prebuilt_dirs)167*33f37583SAndroid Build Coastguard Worker android::base::Result<void> ApexFileRepository::AddPreInstalledApex(
168*33f37583SAndroid Build Coastguard Worker const std::unordered_map<ApexPartition, std::string>&
169*33f37583SAndroid Build Coastguard Worker partition_to_prebuilt_dirs) {
170*33f37583SAndroid Build Coastguard Worker for (const auto& [partition, dir] : partition_to_prebuilt_dirs) {
171*33f37583SAndroid Build Coastguard Worker if (auto result = ScanBuiltInDir(dir, partition); !result.ok()) {
172*33f37583SAndroid Build Coastguard Worker return result.error();
173*33f37583SAndroid Build Coastguard Worker }
174*33f37583SAndroid Build Coastguard Worker }
175*33f37583SAndroid Build Coastguard Worker return {};
176*33f37583SAndroid Build Coastguard Worker }
177*33f37583SAndroid Build Coastguard Worker
AddBlockApex(const std::string & metadata_partition)178*33f37583SAndroid Build Coastguard Worker Result<int> ApexFileRepository::AddBlockApex(
179*33f37583SAndroid Build Coastguard Worker const std::string& metadata_partition) {
180*33f37583SAndroid Build Coastguard Worker CHECK(!block_disk_path_.has_value())
181*33f37583SAndroid Build Coastguard Worker << "AddBlockApex() can't be called twice.";
182*33f37583SAndroid Build Coastguard Worker
183*33f37583SAndroid Build Coastguard Worker auto metadata_ready = WaitForFile(metadata_partition, kBlockApexWaitTime);
184*33f37583SAndroid Build Coastguard Worker if (!metadata_ready.ok()) {
185*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Error waiting for metadata_partition : "
186*33f37583SAndroid Build Coastguard Worker << metadata_ready.error();
187*33f37583SAndroid Build Coastguard Worker return {};
188*33f37583SAndroid Build Coastguard Worker }
189*33f37583SAndroid Build Coastguard Worker
190*33f37583SAndroid Build Coastguard Worker // TODO(b/185069443) consider moving the logic to find disk_path from
191*33f37583SAndroid Build Coastguard Worker // metadata_partition to its own library
192*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Scanning " << metadata_partition << " for host apexes";
193*33f37583SAndroid Build Coastguard Worker if (access(metadata_partition.c_str(), F_OK) != 0 && errno == ENOENT) {
194*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << metadata_partition << " does not exist. Skipping";
195*33f37583SAndroid Build Coastguard Worker return {};
196*33f37583SAndroid Build Coastguard Worker }
197*33f37583SAndroid Build Coastguard Worker
198*33f37583SAndroid Build Coastguard Worker std::string metadata_realpath;
199*33f37583SAndroid Build Coastguard Worker if (!android::base::Realpath(metadata_partition, &metadata_realpath)) {
200*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Can't get realpath of " << metadata_partition
201*33f37583SAndroid Build Coastguard Worker << ". Skipping";
202*33f37583SAndroid Build Coastguard Worker return {};
203*33f37583SAndroid Build Coastguard Worker }
204*33f37583SAndroid Build Coastguard Worker
205*33f37583SAndroid Build Coastguard Worker std::string_view metadata_path_view(metadata_realpath);
206*33f37583SAndroid Build Coastguard Worker if (!android::base::ConsumeSuffix(&metadata_path_view, "1")) {
207*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << metadata_realpath << " is not a first partition. Skipping";
208*33f37583SAndroid Build Coastguard Worker return {};
209*33f37583SAndroid Build Coastguard Worker }
210*33f37583SAndroid Build Coastguard Worker
211*33f37583SAndroid Build Coastguard Worker block_disk_path_ = std::string(metadata_path_view);
212*33f37583SAndroid Build Coastguard Worker
213*33f37583SAndroid Build Coastguard Worker // Read the payload metadata.
214*33f37583SAndroid Build Coastguard Worker // "metadata" can be overridden by microdroid_manager. To ensure that
215*33f37583SAndroid Build Coastguard Worker // "microdroid" is started with the same/unmodified set of host APEXes,
216*33f37583SAndroid Build Coastguard Worker // microdroid stores APEXes' pubkeys in its encrypted instance disk. Next
217*33f37583SAndroid Build Coastguard Worker // time, microdroid checks if there's pubkeys in the instance disk and use
218*33f37583SAndroid Build Coastguard Worker // them to activate APEXes. Microdroid_manager passes pubkeys in instance.img
219*33f37583SAndroid Build Coastguard Worker // via the following file.
220*33f37583SAndroid Build Coastguard Worker if (auto exists = PathExists("/apex/vm-payload-metadata");
221*33f37583SAndroid Build Coastguard Worker exists.ok() && *exists) {
222*33f37583SAndroid Build Coastguard Worker metadata_realpath = "/apex/vm-payload-metadata";
223*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Overriding metadata to " << metadata_realpath;
224*33f37583SAndroid Build Coastguard Worker }
225*33f37583SAndroid Build Coastguard Worker auto metadata = android::microdroid::ReadMetadata(metadata_realpath);
226*33f37583SAndroid Build Coastguard Worker if (!metadata.ok()) {
227*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to load metadata from " << metadata_realpath
228*33f37583SAndroid Build Coastguard Worker << ". Skipping: " << metadata.error();
229*33f37583SAndroid Build Coastguard Worker return {};
230*33f37583SAndroid Build Coastguard Worker }
231*33f37583SAndroid Build Coastguard Worker
232*33f37583SAndroid Build Coastguard Worker int ret = 0;
233*33f37583SAndroid Build Coastguard Worker
234*33f37583SAndroid Build Coastguard Worker // subsequent partitions are APEX archives.
235*33f37583SAndroid Build Coastguard Worker static constexpr const int kFirstApexPartition = 2;
236*33f37583SAndroid Build Coastguard Worker for (int i = 0; i < metadata->apexes_size(); i++) {
237*33f37583SAndroid Build Coastguard Worker const auto& apex_config = metadata->apexes(i);
238*33f37583SAndroid Build Coastguard Worker
239*33f37583SAndroid Build Coastguard Worker const std::string apex_path =
240*33f37583SAndroid Build Coastguard Worker *block_disk_path_ + std::to_string(i + kFirstApexPartition);
241*33f37583SAndroid Build Coastguard Worker
242*33f37583SAndroid Build Coastguard Worker auto apex_ready = WaitForFile(apex_path, kBlockApexWaitTime);
243*33f37583SAndroid Build Coastguard Worker if (!apex_ready.ok()) {
244*33f37583SAndroid Build Coastguard Worker return Error() << "Error waiting for apex file : " << apex_ready.error();
245*33f37583SAndroid Build Coastguard Worker }
246*33f37583SAndroid Build Coastguard Worker
247*33f37583SAndroid Build Coastguard Worker auto apex_file = ApexFile::Open(apex_path);
248*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
249*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to open " << apex_path << " : "
250*33f37583SAndroid Build Coastguard Worker << apex_file.error();
251*33f37583SAndroid Build Coastguard Worker }
252*33f37583SAndroid Build Coastguard Worker
253*33f37583SAndroid Build Coastguard Worker // When metadata specifies the public key of the apex, it should match the
254*33f37583SAndroid Build Coastguard Worker // bundled key. Otherwise we accept it.
255*33f37583SAndroid Build Coastguard Worker if (apex_config.public_key() != "" &&
256*33f37583SAndroid Build Coastguard Worker apex_config.public_key() != apex_file->GetBundledPublicKey()) {
257*33f37583SAndroid Build Coastguard Worker return Error() << "public key doesn't match: " << apex_path;
258*33f37583SAndroid Build Coastguard Worker }
259*33f37583SAndroid Build Coastguard Worker
260*33f37583SAndroid Build Coastguard Worker const std::string& name = apex_file->GetManifest().name();
261*33f37583SAndroid Build Coastguard Worker
262*33f37583SAndroid Build Coastguard Worker // When metadata specifies the manifest name and version of the apex, it
263*33f37583SAndroid Build Coastguard Worker // should match what we see in the manifest.
264*33f37583SAndroid Build Coastguard Worker if (apex_config.manifest_name() != "" &&
265*33f37583SAndroid Build Coastguard Worker apex_config.manifest_name() != name) {
266*33f37583SAndroid Build Coastguard Worker return Error() << "manifest name doesn't match: " << apex_path;
267*33f37583SAndroid Build Coastguard Worker }
268*33f37583SAndroid Build Coastguard Worker
269*33f37583SAndroid Build Coastguard Worker if (apex_config.manifest_version() != 0 &&
270*33f37583SAndroid Build Coastguard Worker apex_config.manifest_version() != apex_file->GetManifest().version()) {
271*33f37583SAndroid Build Coastguard Worker return Error() << "manifest version doesn't match: " << apex_path;
272*33f37583SAndroid Build Coastguard Worker }
273*33f37583SAndroid Build Coastguard Worker
274*33f37583SAndroid Build Coastguard Worker BlockApexOverride overrides;
275*33f37583SAndroid Build Coastguard Worker
276*33f37583SAndroid Build Coastguard Worker // A block device doesn't have an inherent timestamp, so it is carried in
277*33f37583SAndroid Build Coastguard Worker // the metadata.
278*33f37583SAndroid Build Coastguard Worker if (int64_t last_update_seconds = apex_config.last_update_seconds();
279*33f37583SAndroid Build Coastguard Worker last_update_seconds != 0) {
280*33f37583SAndroid Build Coastguard Worker overrides.last_update_seconds = last_update_seconds;
281*33f37583SAndroid Build Coastguard Worker }
282*33f37583SAndroid Build Coastguard Worker
283*33f37583SAndroid Build Coastguard Worker // When metadata specifies the root digest of the apex, it should be used
284*33f37583SAndroid Build Coastguard Worker // when activating the apex. So we need to keep it.
285*33f37583SAndroid Build Coastguard Worker if (auto root_digest = apex_config.root_digest(); root_digest != "") {
286*33f37583SAndroid Build Coastguard Worker overrides.block_apex_root_digest =
287*33f37583SAndroid Build Coastguard Worker BytesToHex(reinterpret_cast<const uint8_t*>(root_digest.data()),
288*33f37583SAndroid Build Coastguard Worker root_digest.size());
289*33f37583SAndroid Build Coastguard Worker }
290*33f37583SAndroid Build Coastguard Worker
291*33f37583SAndroid Build Coastguard Worker if (overrides.last_update_seconds.has_value() ||
292*33f37583SAndroid Build Coastguard Worker overrides.block_apex_root_digest.has_value()) {
293*33f37583SAndroid Build Coastguard Worker block_apex_overrides_.emplace(apex_path, std::move(overrides));
294*33f37583SAndroid Build Coastguard Worker }
295*33f37583SAndroid Build Coastguard Worker
296*33f37583SAndroid Build Coastguard Worker // Depending on whether the APEX was a factory version in the host or not,
297*33f37583SAndroid Build Coastguard Worker // put it to different stores.
298*33f37583SAndroid Build Coastguard Worker auto& store = apex_config.is_factory() ? pre_installed_store_ : data_store_;
299*33f37583SAndroid Build Coastguard Worker // We want "uniqueness" in each store.
300*33f37583SAndroid Build Coastguard Worker if (auto it = store.find(name); it != store.end()) {
301*33f37583SAndroid Build Coastguard Worker return Error() << "duplicate of " << name << " found in "
302*33f37583SAndroid Build Coastguard Worker << it->second.GetPath();
303*33f37583SAndroid Build Coastguard Worker }
304*33f37583SAndroid Build Coastguard Worker store.emplace(name, std::move(*apex_file));
305*33f37583SAndroid Build Coastguard Worker // NOTE: We consider block APEXes are SYSTEM. APEX Config should be extended
306*33f37583SAndroid Build Coastguard Worker // to support non-system block APEXes.
307*33f37583SAndroid Build Coastguard Worker partition_store_.emplace(name, ApexPartition::System);
308*33f37583SAndroid Build Coastguard Worker
309*33f37583SAndroid Build Coastguard Worker ret++;
310*33f37583SAndroid Build Coastguard Worker }
311*33f37583SAndroid Build Coastguard Worker return {ret};
312*33f37583SAndroid Build Coastguard Worker }
313*33f37583SAndroid Build Coastguard Worker
314*33f37583SAndroid Build Coastguard Worker // TODO(b/179497746): AddDataApex should not concern with filtering out invalid
315*33f37583SAndroid Build Coastguard Worker // apex.
AddDataApex(const std::string & data_dir)316*33f37583SAndroid Build Coastguard Worker Result<void> ApexFileRepository::AddDataApex(const std::string& data_dir) {
317*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Scanning " << data_dir << " for data ApexFiles";
318*33f37583SAndroid Build Coastguard Worker if (access(data_dir.c_str(), F_OK) != 0 && errno == ENOENT) {
319*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << data_dir << " does not exist. Skipping";
320*33f37583SAndroid Build Coastguard Worker return {};
321*33f37583SAndroid Build Coastguard Worker }
322*33f37583SAndroid Build Coastguard Worker
323*33f37583SAndroid Build Coastguard Worker Result<std::vector<std::string>> active_apex =
324*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(data_dir, {kApexPackageSuffix});
325*33f37583SAndroid Build Coastguard Worker if (!active_apex.ok()) {
326*33f37583SAndroid Build Coastguard Worker return active_apex.error();
327*33f37583SAndroid Build Coastguard Worker }
328*33f37583SAndroid Build Coastguard Worker
329*33f37583SAndroid Build Coastguard Worker // TODO(b/179248390): scan parallelly if possible
330*33f37583SAndroid Build Coastguard Worker for (const auto& file : *active_apex) {
331*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Found updated apex " << file;
332*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(file);
333*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
334*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open " << file << " : " << apex_file.error();
335*33f37583SAndroid Build Coastguard Worker continue;
336*33f37583SAndroid Build Coastguard Worker }
337*33f37583SAndroid Build Coastguard Worker
338*33f37583SAndroid Build Coastguard Worker const std::string& name = apex_file->GetManifest().name();
339*33f37583SAndroid Build Coastguard Worker auto preinstalled = pre_installed_store_.find(name);
340*33f37583SAndroid Build Coastguard Worker if (preinstalled != pre_installed_store_.end()) {
341*33f37583SAndroid Build Coastguard Worker if (preinstalled->second.GetBundledPublicKey() !=
342*33f37583SAndroid Build Coastguard Worker apex_file->GetBundledPublicKey()) {
343*33f37583SAndroid Build Coastguard Worker // Ignore data apex if public key doesn't match with pre-installed apex
344*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Skipping " << file
345*33f37583SAndroid Build Coastguard Worker << " : public key doesn't match pre-installed one";
346*33f37583SAndroid Build Coastguard Worker continue;
347*33f37583SAndroid Build Coastguard Worker }
348*33f37583SAndroid Build Coastguard Worker } else if (ApexFileRepository::IsBrandNewApexEnabled()) {
349*33f37583SAndroid Build Coastguard Worker auto verified_partition =
350*33f37583SAndroid Build Coastguard Worker VerifyBrandNewPackageAgainstPreinstalled(*apex_file);
351*33f37583SAndroid Build Coastguard Worker if (!verified_partition.ok()) {
352*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Skipping " << file << " : "
353*33f37583SAndroid Build Coastguard Worker << verified_partition.error();
354*33f37583SAndroid Build Coastguard Worker continue;
355*33f37583SAndroid Build Coastguard Worker }
356*33f37583SAndroid Build Coastguard Worker // Stores partition for already-verified brand-new APEX.
357*33f37583SAndroid Build Coastguard Worker partition_store_.emplace(name, *verified_partition);
358*33f37583SAndroid Build Coastguard Worker } else {
359*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Skipping " << file << " : no preinstalled apex";
360*33f37583SAndroid Build Coastguard Worker // Ignore data apex without corresponding pre-installed apex
361*33f37583SAndroid Build Coastguard Worker continue;
362*33f37583SAndroid Build Coastguard Worker }
363*33f37583SAndroid Build Coastguard Worker
364*33f37583SAndroid Build Coastguard Worker std::string select_filename = GetApexSelectFilenameFromProp(
365*33f37583SAndroid Build Coastguard Worker multi_install_select_prop_prefixes_, name);
366*33f37583SAndroid Build Coastguard Worker if (!select_filename.empty()) {
367*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "APEX " << name << " is a multi-installed APEX."
368*33f37583SAndroid Build Coastguard Worker << " Any updated version in /data will always overwrite"
369*33f37583SAndroid Build Coastguard Worker << " the multi-installed preinstalled version, if possible.";
370*33f37583SAndroid Build Coastguard Worker }
371*33f37583SAndroid Build Coastguard Worker
372*33f37583SAndroid Build Coastguard Worker if (EndsWith(apex_file->GetPath(), kDecompressedApexPackageSuffix)) {
373*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Skipping " << file
374*33f37583SAndroid Build Coastguard Worker << " : Non-decompressed APEX should not have "
375*33f37583SAndroid Build Coastguard Worker << kDecompressedApexPackageSuffix << " suffix";
376*33f37583SAndroid Build Coastguard Worker continue;
377*33f37583SAndroid Build Coastguard Worker }
378*33f37583SAndroid Build Coastguard Worker
379*33f37583SAndroid Build Coastguard Worker auto it = data_store_.find(name);
380*33f37583SAndroid Build Coastguard Worker if (it == data_store_.end()) {
381*33f37583SAndroid Build Coastguard Worker data_store_.emplace(name, std::move(*apex_file));
382*33f37583SAndroid Build Coastguard Worker continue;
383*33f37583SAndroid Build Coastguard Worker }
384*33f37583SAndroid Build Coastguard Worker
385*33f37583SAndroid Build Coastguard Worker const auto& existing_version = it->second.GetManifest().version();
386*33f37583SAndroid Build Coastguard Worker const auto new_version = apex_file->GetManifest().version();
387*33f37583SAndroid Build Coastguard Worker // If multiple data apexs are preset, select the one with highest version
388*33f37583SAndroid Build Coastguard Worker bool prioritize_higher_version = new_version > existing_version;
389*33f37583SAndroid Build Coastguard Worker // For same version, non-decompressed apex gets priority
390*33f37583SAndroid Build Coastguard Worker if (prioritize_higher_version) {
391*33f37583SAndroid Build Coastguard Worker it->second = std::move(*apex_file);
392*33f37583SAndroid Build Coastguard Worker }
393*33f37583SAndroid Build Coastguard Worker }
394*33f37583SAndroid Build Coastguard Worker return {};
395*33f37583SAndroid Build Coastguard Worker }
396*33f37583SAndroid Build Coastguard Worker
AddBrandNewApexCredentialAndBlocklist(const std::unordered_map<ApexPartition,std::string> & partition_to_dir_map)397*33f37583SAndroid Build Coastguard Worker Result<void> ApexFileRepository::AddBrandNewApexCredentialAndBlocklist(
398*33f37583SAndroid Build Coastguard Worker const std::unordered_map<ApexPartition, std::string>&
399*33f37583SAndroid Build Coastguard Worker partition_to_dir_map) {
400*33f37583SAndroid Build Coastguard Worker for (const auto& [partition, dir] : partition_to_dir_map) {
401*33f37583SAndroid Build Coastguard Worker LOG(INFO)
402*33f37583SAndroid Build Coastguard Worker << "Scanning " << dir
403*33f37583SAndroid Build Coastguard Worker << " for pre-installed public keys and blocklists of brand-new APEX";
404*33f37583SAndroid Build Coastguard Worker if (access(dir.c_str(), F_OK) != 0 && errno == ENOENT) {
405*33f37583SAndroid Build Coastguard Worker continue;
406*33f37583SAndroid Build Coastguard Worker }
407*33f37583SAndroid Build Coastguard Worker
408*33f37583SAndroid Build Coastguard Worker std::vector<std::string> all_credential_files =
409*33f37583SAndroid Build Coastguard Worker OR_RETURN(FindFilesBySuffix(dir, {kBrandNewApexPublicKeySuffix}));
410*33f37583SAndroid Build Coastguard Worker for (const std::string& credential_path : all_credential_files) {
411*33f37583SAndroid Build Coastguard Worker std::string content;
412*33f37583SAndroid Build Coastguard Worker CHECK(android::base::ReadFileToString(credential_path, &content));
413*33f37583SAndroid Build Coastguard Worker const auto& [it, inserted] =
414*33f37583SAndroid Build Coastguard Worker brand_new_apex_pubkeys_.emplace(content, partition);
415*33f37583SAndroid Build Coastguard Worker CHECK(inserted || it->second == partition)
416*33f37583SAndroid Build Coastguard Worker << "Duplicate public keys are found in different partitions.";
417*33f37583SAndroid Build Coastguard Worker }
418*33f37583SAndroid Build Coastguard Worker
419*33f37583SAndroid Build Coastguard Worker const std::string& blocklist_path =
420*33f37583SAndroid Build Coastguard Worker std::filesystem::path(dir) / kBrandNewApexBlocklistFileName;
421*33f37583SAndroid Build Coastguard Worker const auto blocklist_exists = OR_RETURN(PathExists(blocklist_path));
422*33f37583SAndroid Build Coastguard Worker if (!blocklist_exists) {
423*33f37583SAndroid Build Coastguard Worker continue;
424*33f37583SAndroid Build Coastguard Worker }
425*33f37583SAndroid Build Coastguard Worker
426*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, int64_t> apex_name_to_version;
427*33f37583SAndroid Build Coastguard Worker ApexBlocklist blocklist = OR_RETURN(ReadBlocklist(blocklist_path));
428*33f37583SAndroid Build Coastguard Worker for (const auto& block_item : blocklist.blocked_apex()) {
429*33f37583SAndroid Build Coastguard Worker const auto& [it, inserted] =
430*33f37583SAndroid Build Coastguard Worker apex_name_to_version.emplace(block_item.name(), block_item.version());
431*33f37583SAndroid Build Coastguard Worker CHECK(inserted) << "Duplicate APEX names are found in blocklist.";
432*33f37583SAndroid Build Coastguard Worker }
433*33f37583SAndroid Build Coastguard Worker brand_new_apex_blocked_version_.emplace(partition, apex_name_to_version);
434*33f37583SAndroid Build Coastguard Worker }
435*33f37583SAndroid Build Coastguard Worker return {};
436*33f37583SAndroid Build Coastguard Worker }
437*33f37583SAndroid Build Coastguard Worker
GetPartition(const ApexFile & apex) const438*33f37583SAndroid Build Coastguard Worker Result<ApexPartition> ApexFileRepository::GetPartition(
439*33f37583SAndroid Build Coastguard Worker const ApexFile& apex) const {
440*33f37583SAndroid Build Coastguard Worker const std::string& name = apex.GetManifest().name();
441*33f37583SAndroid Build Coastguard Worker auto it = partition_store_.find(name);
442*33f37583SAndroid Build Coastguard Worker if (it != partition_store_.end()) {
443*33f37583SAndroid Build Coastguard Worker return it->second;
444*33f37583SAndroid Build Coastguard Worker }
445*33f37583SAndroid Build Coastguard Worker
446*33f37583SAndroid Build Coastguard Worker // Supports staged but not-yet-activated brand-new APEX.
447*33f37583SAndroid Build Coastguard Worker if (!ApexFileRepository::IsBrandNewApexEnabled()) {
448*33f37583SAndroid Build Coastguard Worker return Error() << "No preinstalled data found for package " << name;
449*33f37583SAndroid Build Coastguard Worker }
450*33f37583SAndroid Build Coastguard Worker return VerifyBrandNewPackageAgainstPreinstalled(apex);
451*33f37583SAndroid Build Coastguard Worker }
452*33f37583SAndroid Build Coastguard Worker
453*33f37583SAndroid Build Coastguard Worker // TODO(b/179497746): remove this method when we add api for fetching ApexFile
454*33f37583SAndroid Build Coastguard Worker // by name
GetPublicKey(const std::string & name) const455*33f37583SAndroid Build Coastguard Worker Result<const std::string> ApexFileRepository::GetPublicKey(
456*33f37583SAndroid Build Coastguard Worker const std::string& name) const {
457*33f37583SAndroid Build Coastguard Worker auto it = pre_installed_store_.find(name);
458*33f37583SAndroid Build Coastguard Worker if (it == pre_installed_store_.end()) {
459*33f37583SAndroid Build Coastguard Worker // Special casing for APEXes backed by block devices, i.e. APEXes in VM.
460*33f37583SAndroid Build Coastguard Worker // Inside a VM, we fall back to find the key from data_store_. This is
461*33f37583SAndroid Build Coastguard Worker // because an APEX is put to either pre_installed_store_ or data_store,
462*33f37583SAndroid Build Coastguard Worker // depending on whether it was a factory APEX or not in the host.
463*33f37583SAndroid Build Coastguard Worker it = data_store_.find(name);
464*33f37583SAndroid Build Coastguard Worker if (it != data_store_.end() && IsBlockApex(it->second)) {
465*33f37583SAndroid Build Coastguard Worker return it->second.GetBundledPublicKey();
466*33f37583SAndroid Build Coastguard Worker }
467*33f37583SAndroid Build Coastguard Worker return Error() << "No preinstalled apex found for package " << name;
468*33f37583SAndroid Build Coastguard Worker }
469*33f37583SAndroid Build Coastguard Worker return it->second.GetBundledPublicKey();
470*33f37583SAndroid Build Coastguard Worker }
471*33f37583SAndroid Build Coastguard Worker
472*33f37583SAndroid Build Coastguard Worker // TODO(b/179497746): remove this method when we add api for fetching ApexFile
473*33f37583SAndroid Build Coastguard Worker // by name
GetPreinstalledPath(const std::string & name) const474*33f37583SAndroid Build Coastguard Worker Result<const std::string> ApexFileRepository::GetPreinstalledPath(
475*33f37583SAndroid Build Coastguard Worker const std::string& name) const {
476*33f37583SAndroid Build Coastguard Worker auto it = pre_installed_store_.find(name);
477*33f37583SAndroid Build Coastguard Worker if (it == pre_installed_store_.end()) {
478*33f37583SAndroid Build Coastguard Worker return Error() << "No preinstalled data found for package " << name;
479*33f37583SAndroid Build Coastguard Worker }
480*33f37583SAndroid Build Coastguard Worker return it->second.GetPath();
481*33f37583SAndroid Build Coastguard Worker }
482*33f37583SAndroid Build Coastguard Worker
483*33f37583SAndroid Build Coastguard Worker // TODO(b/179497746): remove this method when we add api for fetching ApexFile
484*33f37583SAndroid Build Coastguard Worker // by name
GetDataPath(const std::string & name) const485*33f37583SAndroid Build Coastguard Worker Result<const std::string> ApexFileRepository::GetDataPath(
486*33f37583SAndroid Build Coastguard Worker const std::string& name) const {
487*33f37583SAndroid Build Coastguard Worker auto it = data_store_.find(name);
488*33f37583SAndroid Build Coastguard Worker if (it == data_store_.end()) {
489*33f37583SAndroid Build Coastguard Worker return Error() << "No data apex found for package " << name;
490*33f37583SAndroid Build Coastguard Worker }
491*33f37583SAndroid Build Coastguard Worker return it->second.GetPath();
492*33f37583SAndroid Build Coastguard Worker }
493*33f37583SAndroid Build Coastguard Worker
GetBlockApexRootDigest(const std::string & path) const494*33f37583SAndroid Build Coastguard Worker std::optional<std::string> ApexFileRepository::GetBlockApexRootDigest(
495*33f37583SAndroid Build Coastguard Worker const std::string& path) const {
496*33f37583SAndroid Build Coastguard Worker auto it = block_apex_overrides_.find(path);
497*33f37583SAndroid Build Coastguard Worker if (it == block_apex_overrides_.end()) {
498*33f37583SAndroid Build Coastguard Worker return std::nullopt;
499*33f37583SAndroid Build Coastguard Worker }
500*33f37583SAndroid Build Coastguard Worker return it->second.block_apex_root_digest;
501*33f37583SAndroid Build Coastguard Worker }
502*33f37583SAndroid Build Coastguard Worker
GetBlockApexLastUpdateSeconds(const std::string & path) const503*33f37583SAndroid Build Coastguard Worker std::optional<int64_t> ApexFileRepository::GetBlockApexLastUpdateSeconds(
504*33f37583SAndroid Build Coastguard Worker const std::string& path) const {
505*33f37583SAndroid Build Coastguard Worker auto it = block_apex_overrides_.find(path);
506*33f37583SAndroid Build Coastguard Worker if (it == block_apex_overrides_.end()) {
507*33f37583SAndroid Build Coastguard Worker return std::nullopt;
508*33f37583SAndroid Build Coastguard Worker }
509*33f37583SAndroid Build Coastguard Worker return it->second.last_update_seconds;
510*33f37583SAndroid Build Coastguard Worker }
511*33f37583SAndroid Build Coastguard Worker
HasPreInstalledVersion(const std::string & name) const512*33f37583SAndroid Build Coastguard Worker bool ApexFileRepository::HasPreInstalledVersion(const std::string& name) const {
513*33f37583SAndroid Build Coastguard Worker return pre_installed_store_.find(name) != pre_installed_store_.end();
514*33f37583SAndroid Build Coastguard Worker }
515*33f37583SAndroid Build Coastguard Worker
HasDataVersion(const std::string & name) const516*33f37583SAndroid Build Coastguard Worker bool ApexFileRepository::HasDataVersion(const std::string& name) const {
517*33f37583SAndroid Build Coastguard Worker return data_store_.find(name) != data_store_.end();
518*33f37583SAndroid Build Coastguard Worker }
519*33f37583SAndroid Build Coastguard Worker
520*33f37583SAndroid Build Coastguard Worker // ApexFile is considered a decompressed APEX if it is located in decompression
521*33f37583SAndroid Build Coastguard Worker // dir
IsDecompressedApex(const ApexFile & apex) const522*33f37583SAndroid Build Coastguard Worker bool ApexFileRepository::IsDecompressedApex(const ApexFile& apex) const {
523*33f37583SAndroid Build Coastguard Worker return apex.GetPath().starts_with(decompression_dir_);
524*33f37583SAndroid Build Coastguard Worker }
525*33f37583SAndroid Build Coastguard Worker
IsPreInstalledApex(const ApexFile & apex) const526*33f37583SAndroid Build Coastguard Worker bool ApexFileRepository::IsPreInstalledApex(const ApexFile& apex) const {
527*33f37583SAndroid Build Coastguard Worker auto it = pre_installed_store_.find(apex.GetManifest().name());
528*33f37583SAndroid Build Coastguard Worker if (it == pre_installed_store_.end()) {
529*33f37583SAndroid Build Coastguard Worker return false;
530*33f37583SAndroid Build Coastguard Worker }
531*33f37583SAndroid Build Coastguard Worker return it->second.GetPath() == apex.GetPath() || IsDecompressedApex(apex);
532*33f37583SAndroid Build Coastguard Worker }
533*33f37583SAndroid Build Coastguard Worker
IsBlockApex(const ApexFile & apex) const534*33f37583SAndroid Build Coastguard Worker bool ApexFileRepository::IsBlockApex(const ApexFile& apex) const {
535*33f37583SAndroid Build Coastguard Worker return block_disk_path_.has_value() &&
536*33f37583SAndroid Build Coastguard Worker apex.GetPath().starts_with(*block_disk_path_);
537*33f37583SAndroid Build Coastguard Worker }
538*33f37583SAndroid Build Coastguard Worker
GetPreInstalledApexFiles() const539*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> ApexFileRepository::GetPreInstalledApexFiles() const {
540*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> result;
541*33f37583SAndroid Build Coastguard Worker result.reserve(pre_installed_store_.size());
542*33f37583SAndroid Build Coastguard Worker for (const auto& it : pre_installed_store_) {
543*33f37583SAndroid Build Coastguard Worker result.emplace_back(std::cref(it.second));
544*33f37583SAndroid Build Coastguard Worker }
545*33f37583SAndroid Build Coastguard Worker return result;
546*33f37583SAndroid Build Coastguard Worker }
547*33f37583SAndroid Build Coastguard Worker
GetDataApexFiles() const548*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> ApexFileRepository::GetDataApexFiles() const {
549*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> result;
550*33f37583SAndroid Build Coastguard Worker result.reserve(data_store_.size());
551*33f37583SAndroid Build Coastguard Worker for (const auto& it : data_store_) {
552*33f37583SAndroid Build Coastguard Worker result.emplace_back(std::cref(it.second));
553*33f37583SAndroid Build Coastguard Worker }
554*33f37583SAndroid Build Coastguard Worker return result;
555*33f37583SAndroid Build Coastguard Worker }
556*33f37583SAndroid Build Coastguard Worker
557*33f37583SAndroid Build Coastguard Worker std::optional<ApexPartition>
GetBrandNewApexPublicKeyPartition(const std::string & public_key) const558*33f37583SAndroid Build Coastguard Worker ApexFileRepository::GetBrandNewApexPublicKeyPartition(
559*33f37583SAndroid Build Coastguard Worker const std::string& public_key) const {
560*33f37583SAndroid Build Coastguard Worker auto it = brand_new_apex_pubkeys_.find(public_key);
561*33f37583SAndroid Build Coastguard Worker if (it == brand_new_apex_pubkeys_.end()) {
562*33f37583SAndroid Build Coastguard Worker return std::nullopt;
563*33f37583SAndroid Build Coastguard Worker }
564*33f37583SAndroid Build Coastguard Worker return it->second;
565*33f37583SAndroid Build Coastguard Worker }
566*33f37583SAndroid Build Coastguard Worker
GetBrandNewApexBlockedVersion(ApexPartition partition,const std::string & apex_name) const567*33f37583SAndroid Build Coastguard Worker std::optional<int64_t> ApexFileRepository::GetBrandNewApexBlockedVersion(
568*33f37583SAndroid Build Coastguard Worker ApexPartition partition, const std::string& apex_name) const {
569*33f37583SAndroid Build Coastguard Worker auto it = brand_new_apex_blocked_version_.find(partition);
570*33f37583SAndroid Build Coastguard Worker if (it == brand_new_apex_blocked_version_.end()) {
571*33f37583SAndroid Build Coastguard Worker return std::nullopt;
572*33f37583SAndroid Build Coastguard Worker }
573*33f37583SAndroid Build Coastguard Worker const auto& apex_name_to_version = it->second;
574*33f37583SAndroid Build Coastguard Worker auto itt = apex_name_to_version.find(apex_name);
575*33f37583SAndroid Build Coastguard Worker if (itt == apex_name_to_version.end()) {
576*33f37583SAndroid Build Coastguard Worker return std::nullopt;
577*33f37583SAndroid Build Coastguard Worker }
578*33f37583SAndroid Build Coastguard Worker return itt->second;
579*33f37583SAndroid Build Coastguard Worker }
580*33f37583SAndroid Build Coastguard Worker
581*33f37583SAndroid Build Coastguard Worker // Group pre-installed APEX and data APEX by name
582*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, std::vector<ApexFileRef>>
AllApexFilesByName() const583*33f37583SAndroid Build Coastguard Worker ApexFileRepository::AllApexFilesByName() const {
584*33f37583SAndroid Build Coastguard Worker // Collect all apex files
585*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> all_apex_files;
586*33f37583SAndroid Build Coastguard Worker auto pre_installed_apexs = GetPreInstalledApexFiles();
587*33f37583SAndroid Build Coastguard Worker auto data_apexs = GetDataApexFiles();
588*33f37583SAndroid Build Coastguard Worker std::move(pre_installed_apexs.begin(), pre_installed_apexs.end(),
589*33f37583SAndroid Build Coastguard Worker std::back_inserter(all_apex_files));
590*33f37583SAndroid Build Coastguard Worker std::move(data_apexs.begin(), data_apexs.end(),
591*33f37583SAndroid Build Coastguard Worker std::back_inserter(all_apex_files));
592*33f37583SAndroid Build Coastguard Worker
593*33f37583SAndroid Build Coastguard Worker // Group them by name
594*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, std::vector<ApexFileRef>> result;
595*33f37583SAndroid Build Coastguard Worker for (const auto& apex_file_ref : all_apex_files) {
596*33f37583SAndroid Build Coastguard Worker const ApexFile& apex_file = apex_file_ref.get();
597*33f37583SAndroid Build Coastguard Worker const std::string& package_name = apex_file.GetManifest().name();
598*33f37583SAndroid Build Coastguard Worker if (result.find(package_name) == result.end()) {
599*33f37583SAndroid Build Coastguard Worker result[package_name] = std::vector<ApexFileRef>{};
600*33f37583SAndroid Build Coastguard Worker }
601*33f37583SAndroid Build Coastguard Worker result[package_name].emplace_back(apex_file_ref);
602*33f37583SAndroid Build Coastguard Worker }
603*33f37583SAndroid Build Coastguard Worker
604*33f37583SAndroid Build Coastguard Worker return result;
605*33f37583SAndroid Build Coastguard Worker }
606*33f37583SAndroid Build Coastguard Worker
GetDataApex(const std::string & name) const607*33f37583SAndroid Build Coastguard Worker ApexFileRef ApexFileRepository::GetDataApex(const std::string& name) const {
608*33f37583SAndroid Build Coastguard Worker auto it = data_store_.find(name);
609*33f37583SAndroid Build Coastguard Worker CHECK(it != data_store_.end());
610*33f37583SAndroid Build Coastguard Worker return std::cref(it->second);
611*33f37583SAndroid Build Coastguard Worker }
612*33f37583SAndroid Build Coastguard Worker
GetPreInstalledApex(const std::string & name) const613*33f37583SAndroid Build Coastguard Worker ApexFileRef ApexFileRepository::GetPreInstalledApex(
614*33f37583SAndroid Build Coastguard Worker const std::string& name) const {
615*33f37583SAndroid Build Coastguard Worker auto it = pre_installed_store_.find(name);
616*33f37583SAndroid Build Coastguard Worker CHECK(it != pre_installed_store_.end());
617*33f37583SAndroid Build Coastguard Worker return std::cref(it->second);
618*33f37583SAndroid Build Coastguard Worker }
619*33f37583SAndroid Build Coastguard Worker
620*33f37583SAndroid Build Coastguard Worker } // namespace apex
621*33f37583SAndroid Build Coastguard Worker } // namespace android
622