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