• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #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