• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 #define ATRACE_TAG ATRACE_TAG_RESOURCES
18 
19 #include "androidfw/AssetManager2.h"
20 
21 #include <algorithm>
22 #include <iterator>
23 #include <map>
24 #include <set>
25 
26 #include "android-base/logging.h"
27 #include "android-base/stringprintf.h"
28 #include "androidfw/ResourceTypes.h"
29 #include "androidfw/ResourceUtils.h"
30 #include "androidfw/Util.h"
31 #include "utils/ByteOrder.h"
32 #include "utils/Trace.h"
33 
34 #ifdef _WIN32
35 #ifdef ERROR
36 #undef ERROR
37 #endif
38 #endif
39 
40 namespace android {
41 
42 namespace {
43 
44 using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>;
45 
GetEntryValue(incfs::verified_map_ptr<ResTable_entry> table_entry)46 base::expected<EntryValue, IOError> GetEntryValue(
47     incfs::verified_map_ptr<ResTable_entry> table_entry) {
48   const uint16_t entry_size = dtohs(table_entry->size);
49 
50   // Check if the entry represents a bag value.
51   if (entry_size >= sizeof(ResTable_map_entry) &&
52       (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX)) {
53     const auto map_entry = table_entry.convert<ResTable_map_entry>();
54     if (!map_entry) {
55       return base::unexpected(IOError::PAGES_MISSING);
56     }
57     return map_entry.verified();
58   }
59 
60   // The entry represents a non-bag value.
61   const auto entry_value = table_entry.offset(entry_size).convert<Res_value>();
62   if (!entry_value) {
63     return base::unexpected(IOError::PAGES_MISSING);
64   }
65   Res_value value;
66   value.copyFrom_dtoh(entry_value.value());
67   return value;
68 }
69 
70 } // namespace
71 
72 struct FindEntryResult {
73   // The cookie representing the ApkAssets in which the value resides.
74   ApkAssetsCookie cookie;
75 
76   // The value of the resource table entry. Either an android::Res_value for non-bag types or an
77   // incfs::verified_map_ptr<ResTable_map_entry> for bag types.
78   EntryValue entry;
79 
80   // The configuration for which the resulting entry was defined. This is already swapped to host
81   // endianness.
82   ResTable_config config;
83 
84   // The bitmask of configuration axis with which the resource value varies.
85   uint32_t type_flags;
86 
87   // The dynamic package ID map for the package from which this resource came from.
88   const DynamicRefTable* dynamic_ref_table;
89 
90   // The package name of the resource.
91   const std::string* package_name;
92 
93   // The string pool reference to the type's name. This uses a different string pool than
94   // the global string pool, but this is hidden from the caller.
95   StringPoolRef type_string_ref;
96 
97   // The string pool reference to the entry's name. This uses a different string pool than
98   // the global string pool, but this is hidden from the caller.
99   StringPoolRef entry_string_ref;
100 };
101 
AssetManager2()102 AssetManager2::AssetManager2() {
103   memset(&configuration_, 0, sizeof(configuration_));
104 }
105 
SetApkAssets(std::vector<const ApkAssets * > apk_assets,bool invalidate_caches)106 bool AssetManager2::SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches) {
107   apk_assets_ = std::move(apk_assets);
108   BuildDynamicRefTable();
109   RebuildFilterList();
110   if (invalidate_caches) {
111     InvalidateCaches(static_cast<uint32_t>(-1));
112   }
113   return true;
114 }
115 
BuildDynamicRefTable()116 void AssetManager2::BuildDynamicRefTable() {
117   package_groups_.clear();
118   package_ids_.fill(0xff);
119 
120   // A mapping from path of apk assets that could be target packages of overlays to the runtime
121   // package id of its first loaded package. Overlays currently can only override resources in the
122   // first package in the target resource table.
123   std::unordered_map<std::string, uint8_t> target_assets_package_ids;
124 
125   // Overlay resources are not directly referenced by an application so their resource ids
126   // can change throughout the application's lifetime. Assign overlay package ids last.
127   std::vector<const ApkAssets*> sorted_apk_assets(apk_assets_);
128   std::stable_partition(sorted_apk_assets.begin(), sorted_apk_assets.end(), [](const ApkAssets* a) {
129     return !a->IsOverlay();
130   });
131 
132   // The assets cookie must map to the position of the apk assets in the unsorted apk assets list.
133   std::unordered_map<const ApkAssets*, ApkAssetsCookie> apk_assets_cookies;
134   apk_assets_cookies.reserve(apk_assets_.size());
135   for (size_t i = 0, n = apk_assets_.size(); i < n; i++) {
136     apk_assets_cookies[apk_assets_[i]] = static_cast<ApkAssetsCookie>(i);
137   }
138 
139   // 0x01 is reserved for the android package.
140   int next_package_id = 0x02;
141   for (const ApkAssets* apk_assets : sorted_apk_assets) {
142     std::shared_ptr<OverlayDynamicRefTable> overlay_ref_table;
143     if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) {
144       // The target package must precede the overlay package in the apk assets paths in order
145       // to take effect.
146       auto iter = target_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
147       if (iter == target_assets_package_ids.end()) {
148          LOG(INFO) << "failed to find target package for overlay "
149                    << loaded_idmap->OverlayApkPath();
150       } else {
151         uint8_t target_package_id = iter->second;
152 
153         // Create a special dynamic reference table for the overlay to rewrite references to
154         // overlay resources as references to the target resources they overlay.
155         overlay_ref_table = std::make_shared<OverlayDynamicRefTable>(
156             loaded_idmap->GetOverlayDynamicRefTable(target_package_id));
157 
158         // Add the overlay resource map to the target package's set of overlays.
159         const uint8_t target_idx = package_ids_[target_package_id];
160         CHECK(target_idx != 0xff) << "overlay target '" << loaded_idmap->TargetApkPath()
161                                   << "'added to apk_assets_package_ids but does not have an"
162                                   << " assigned package group";
163 
164         PackageGroup& target_package_group = package_groups_[target_idx];
165         target_package_group.overlays_.push_back(
166             ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
167                                                                   overlay_ref_table.get()),
168                               apk_assets_cookies[apk_assets]});
169       }
170     }
171 
172     const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
173     for (const std::unique_ptr<const LoadedPackage>& package : loaded_arsc->GetPackages()) {
174       // Get the package ID or assign one if a shared library.
175       int package_id;
176       if (package->IsDynamic()) {
177         package_id = next_package_id++;
178       } else {
179         package_id = package->GetPackageId();
180       }
181 
182       uint8_t idx = package_ids_[package_id];
183       if (idx == 0xff) {
184         // Add the mapping for package ID to index if not present.
185         package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
186         PackageGroup& new_group = package_groups_.emplace_back();
187 
188         if (overlay_ref_table != nullptr) {
189           // If this package is from an overlay, use a dynamic reference table that can rewrite
190           // overlay resource ids to their corresponding target resource ids.
191           new_group.dynamic_ref_table = overlay_ref_table;
192         }
193 
194         DynamicRefTable* ref_table = new_group.dynamic_ref_table.get();
195         ref_table->mAssignedPackageId = package_id;
196         ref_table->mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
197       }
198 
199       // Add the package and to the set of packages with the same ID.
200       PackageGroup* package_group = &package_groups_[idx];
201       package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
202       package_group->cookies_.push_back(apk_assets_cookies[apk_assets]);
203 
204       // Add the package name -> build time ID mappings.
205       for (const DynamicPackageEntry& entry : package->GetDynamicPackageMap()) {
206         String16 package_name(entry.package_name.c_str(), entry.package_name.size());
207         package_group->dynamic_ref_table->mEntries.replaceValueFor(
208             package_name, static_cast<uint8_t>(entry.package_id));
209       }
210 
211       if (auto apk_assets_path = apk_assets->GetPath()) {
212         // Overlay target ApkAssets must have been created using path based load apis.
213         target_assets_package_ids.insert(std::make_pair(std::string(*apk_assets_path), package_id));
214       }
215     }
216   }
217 
218   // Now assign the runtime IDs so that we have a build-time to runtime ID map.
219   const auto package_groups_end = package_groups_.end();
220   for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
221     const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
222     for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
223       iter2->dynamic_ref_table->addMapping(String16(package_name.c_str(), package_name.size()),
224                                            iter->dynamic_ref_table->mAssignedPackageId);
225 
226       // Add the alias resources to the dynamic reference table of every package group. Since
227       // staging aliases can only be defined by the framework package (which is not a shared
228       // library), the compile-time package id of the framework is the same across all packages
229       // that compile against the framework.
230       for (const auto& package : iter->packages_) {
231         for (const auto& entry : package.loaded_package_->GetAliasResourceIdMap()) {
232           iter2->dynamic_ref_table->addAlias(entry.first, entry.second);
233         }
234       }
235     }
236   }
237 }
238 
DumpToLog() const239 void AssetManager2::DumpToLog() const {
240   LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
241 
242   std::string list;
243   for (const auto& apk_assets : apk_assets_) {
244     base::StringAppendF(&list, "%s,", apk_assets->GetDebugName().c_str());
245   }
246   LOG(INFO) << "ApkAssets: " << list;
247 
248   list = "";
249   for (size_t i = 0; i < package_ids_.size(); i++) {
250     if (package_ids_[i] != 0xff) {
251       base::StringAppendF(&list, "%02x -> %d, ", (int)i, package_ids_[i]);
252     }
253   }
254   LOG(INFO) << "Package ID map: " << list;
255 
256   for (const auto& package_group: package_groups_) {
257     list = "";
258     for (const auto& package : package_group.packages_) {
259       const LoadedPackage* loaded_package = package.loaded_package_;
260       base::StringAppendF(&list, "%s(%02x%s), ", loaded_package->GetPackageName().c_str(),
261                           loaded_package->GetPackageId(),
262                           (loaded_package->IsDynamic() ? " dynamic" : ""));
263     }
264     LOG(INFO) << base::StringPrintf("PG (%02x): ",
265                                     package_group.dynamic_ref_table->mAssignedPackageId)
266               << list;
267 
268     for (size_t i = 0; i < 256; i++) {
269       if (package_group.dynamic_ref_table->mLookupTable[i] != 0) {
270         LOG(INFO) << base::StringPrintf("    e[0x%02x] -> 0x%02x", (uint8_t) i,
271                                         package_group.dynamic_ref_table->mLookupTable[i]);
272       }
273     }
274   }
275 }
276 
GetStringPoolForCookie(ApkAssetsCookie cookie) const277 const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const {
278   if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
279     return nullptr;
280   }
281   return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
282 }
283 
GetDynamicRefTableForPackage(uint32_t package_id) const284 const DynamicRefTable* AssetManager2::GetDynamicRefTableForPackage(uint32_t package_id) const {
285   if (package_id >= package_ids_.size()) {
286     return nullptr;
287   }
288 
289   const size_t idx = package_ids_[package_id];
290   if (idx == 0xff) {
291     return nullptr;
292   }
293   return package_groups_[idx].dynamic_ref_table.get();
294 }
295 
GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const296 std::shared_ptr<const DynamicRefTable> AssetManager2::GetDynamicRefTableForCookie(
297     ApkAssetsCookie cookie) const {
298   for (const PackageGroup& package_group : package_groups_) {
299     for (const ApkAssetsCookie& package_cookie : package_group.cookies_) {
300       if (package_cookie == cookie) {
301         return package_group.dynamic_ref_table;
302       }
303     }
304   }
305   return nullptr;
306 }
307 
308 const std::unordered_map<std::string, std::string>*
GetOverlayableMapForPackage(uint32_t package_id) const309   AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const {
310 
311   if (package_id >= package_ids_.size()) {
312     return nullptr;
313   }
314 
315   const size_t idx = package_ids_[package_id];
316   if (idx == 0xff) {
317     return nullptr;
318   }
319 
320   const PackageGroup& package_group = package_groups_[idx];
321   if (package_group.packages_.empty()) {
322     return nullptr;
323   }
324 
325   const auto loaded_package = package_group.packages_[0].loaded_package_;
326   return &loaded_package->GetOverlayableMap();
327 }
328 
GetOverlayablesToString(const android::StringPiece & package_name,std::string * out) const329 bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_name,
330                                             std::string* out) const {
331   uint8_t package_id = 0U;
332   for (const auto& apk_assets : apk_assets_) {
333     const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
334     if (loaded_arsc == nullptr) {
335       continue;
336     }
337 
338     const auto& loaded_packages = loaded_arsc->GetPackages();
339     if (loaded_packages.empty()) {
340       continue;
341     }
342 
343     const auto& loaded_package = loaded_packages[0];
344     if (loaded_package->GetPackageName() == package_name) {
345       package_id = GetAssignedPackageId(loaded_package.get());
346       break;
347     }
348   }
349 
350   if (package_id == 0U) {
351     ANDROID_LOG(ERROR) << base::StringPrintf("No package with name '%s", package_name.data());
352     return false;
353   }
354 
355   const size_t idx = package_ids_[package_id];
356   if (idx == 0xff) {
357     return false;
358   }
359 
360   std::string output;
361   for (const ConfiguredPackage& package : package_groups_[idx].packages_) {
362     const LoadedPackage* loaded_package = package.loaded_package_;
363     for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) {
364       const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it);
365       if (info != nullptr) {
366         auto res_name = GetResourceName(*it);
367         if (!res_name.has_value()) {
368           ANDROID_LOG(ERROR) << base::StringPrintf(
369               "Unable to retrieve name of overlayable resource 0x%08x", *it);
370           return false;
371         }
372 
373         const std::string name = ToFormattedResourceString(*res_name);
374         output.append(base::StringPrintf(
375             "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
376             name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
377       }
378     }
379   }
380 
381   *out = std::move(output);
382   return true;
383 }
384 
ContainsAllocatedTable() const385 bool AssetManager2::ContainsAllocatedTable() const {
386   return std::find_if(apk_assets_.begin(), apk_assets_.end(),
387                       std::mem_fn(&ApkAssets::IsTableAllocated)) != apk_assets_.end();
388 }
389 
SetConfiguration(const ResTable_config & configuration)390 void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
391   const int diff = configuration_.diff(configuration);
392   configuration_ = configuration;
393 
394   if (diff) {
395     RebuildFilterList();
396     InvalidateCaches(static_cast<uint32_t>(diff));
397   }
398 }
399 
GetNonSystemOverlays() const400 std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const {
401   std::set<const ApkAssets*> non_system_overlays;
402   for (const PackageGroup& package_group : package_groups_) {
403     bool found_system_package = false;
404     for (const ConfiguredPackage& package : package_group.packages_) {
405       if (package.loaded_package_->IsSystem()) {
406         found_system_package = true;
407         break;
408       }
409     }
410 
411     if (!found_system_package) {
412       for (const ConfiguredOverlay& overlay : package_group.overlays_) {
413         non_system_overlays.insert(apk_assets_[overlay.cookie]);
414       }
415     }
416   }
417 
418   return non_system_overlays;
419 }
420 
GetResourceConfigurations(bool exclude_system,bool exclude_mipmap) const421 base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceConfigurations(
422     bool exclude_system, bool exclude_mipmap) const {
423   ATRACE_NAME("AssetManager::GetResourceConfigurations");
424   const auto non_system_overlays =
425       (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
426 
427   std::set<ResTable_config> configurations;
428   for (const PackageGroup& package_group : package_groups_) {
429     for (size_t i = 0; i < package_group.packages_.size(); i++) {
430       const ConfiguredPackage& package = package_group.packages_[i];
431       if (exclude_system && package.loaded_package_->IsSystem()) {
432         continue;
433       }
434 
435       auto apk_assets = apk_assets_[package_group.cookies_[i]];
436       if (exclude_system && apk_assets->IsOverlay() &&
437           non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
438         // Exclude overlays that target system resources.
439         continue;
440       }
441 
442       auto result = package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
443       if (UNLIKELY(!result.has_value())) {
444         return base::unexpected(result.error());
445       }
446     }
447   }
448   return configurations;
449 }
450 
GetResourceLocales(bool exclude_system,bool merge_equivalent_languages) const451 std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
452                                                         bool merge_equivalent_languages) const {
453   ATRACE_NAME("AssetManager::GetResourceLocales");
454   std::set<std::string> locales;
455   const auto non_system_overlays =
456       (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
457 
458   for (const PackageGroup& package_group : package_groups_) {
459     for (size_t i = 0; i < package_group.packages_.size(); i++) {
460       const ConfiguredPackage& package = package_group.packages_[i];
461       if (exclude_system && package.loaded_package_->IsSystem()) {
462         continue;
463       }
464 
465       auto apk_assets = apk_assets_[package_group.cookies_[i]];
466       if (exclude_system && apk_assets->IsOverlay() &&
467           non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
468         // Exclude overlays that target system resources.
469         continue;
470       }
471 
472       package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
473     }
474   }
475   return locales;
476 }
477 
Open(const std::string & filename,Asset::AccessMode mode) const478 std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename,
479                                            Asset::AccessMode mode) const {
480   const std::string new_path = "assets/" + filename;
481   return OpenNonAsset(new_path, mode);
482 }
483 
Open(const std::string & filename,ApkAssetsCookie cookie,Asset::AccessMode mode) const484 std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
485                                            Asset::AccessMode mode) const {
486   const std::string new_path = "assets/" + filename;
487   return OpenNonAsset(new_path, cookie, mode);
488 }
489 
OpenDir(const std::string & dirname) const490 std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
491   ATRACE_NAME("AssetManager::OpenDir");
492 
493   std::string full_path = "assets/" + dirname;
494   std::unique_ptr<SortedVector<AssetDir::FileInfo>> files =
495       util::make_unique<SortedVector<AssetDir::FileInfo>>();
496 
497   // Start from the back.
498   for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) {
499     const ApkAssets* apk_assets = *iter;
500     if (apk_assets->IsOverlay()) {
501       continue;
502     }
503 
504     auto func = [&](const StringPiece& name, FileType type) {
505       AssetDir::FileInfo info;
506       info.setFileName(String8(name.data(), name.size()));
507       info.setFileType(type);
508       info.setSourceName(String8(apk_assets->GetDebugName().c_str()));
509       files->add(info);
510     };
511 
512     if (!apk_assets->GetAssetsProvider()->ForEachFile(full_path, func)) {
513       return {};
514     }
515   }
516 
517   std::unique_ptr<AssetDir> asset_dir = util::make_unique<AssetDir>();
518   asset_dir->setFileList(files.release());
519   return asset_dir;
520 }
521 
522 // Search in reverse because that's how we used to do it and we need to preserve behaviour.
523 // This is unfortunate, because ClassLoaders delegate to the parent first, so the order
524 // is inconsistent for split APKs.
OpenNonAsset(const std::string & filename,Asset::AccessMode mode,ApkAssetsCookie * out_cookie) const525 std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
526                                                    Asset::AccessMode mode,
527                                                    ApkAssetsCookie* out_cookie) const {
528   for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
529     // Prevent RRO from modifying assets and other entries accessed by file
530     // path. Explicitly asking for a path in a given package (denoted by a
531     // cookie) is still OK.
532     if (apk_assets_[i]->IsOverlay()) {
533       continue;
534     }
535 
536     std::unique_ptr<Asset> asset = apk_assets_[i]->GetAssetsProvider()->Open(filename, mode);
537     if (asset) {
538       if (out_cookie != nullptr) {
539         *out_cookie = i;
540       }
541       return asset;
542     }
543   }
544 
545   if (out_cookie != nullptr) {
546     *out_cookie = kInvalidCookie;
547   }
548   return {};
549 }
550 
OpenNonAsset(const std::string & filename,ApkAssetsCookie cookie,Asset::AccessMode mode) const551 std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
552                                                    ApkAssetsCookie cookie,
553                                                    Asset::AccessMode mode) const {
554   if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
555     return {};
556   }
557   return apk_assets_[cookie]->GetAssetsProvider()->Open(filename, mode);
558 }
559 
FindEntry(uint32_t resid,uint16_t density_override,bool stop_at_first_match,bool ignore_configuration) const560 base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
561     uint32_t resid, uint16_t density_override, bool stop_at_first_match,
562     bool ignore_configuration) const {
563   const bool logging_enabled = resource_resolution_logging_enabled_;
564   if (UNLIKELY(logging_enabled)) {
565     // Clear the last logged resource resolution.
566     ResetResourceResolution();
567     last_resolution_.resid = resid;
568   }
569 
570   // Might use this if density_override != 0.
571   ResTable_config density_override_config;
572 
573   // Select our configuration or generate a density override configuration.
574   const ResTable_config* desired_config = &configuration_;
575   if (density_override != 0 && density_override != configuration_.density) {
576     density_override_config = configuration_;
577     density_override_config.density = density_override;
578     desired_config = &density_override_config;
579   }
580 
581   // Retrieve the package group from the package id of the resource id.
582   if (UNLIKELY(!is_valid_resid(resid))) {
583     LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
584     return base::unexpected(std::nullopt);
585   }
586 
587   const uint32_t package_id = get_package_id(resid);
588   const uint8_t type_idx = get_type_id(resid) - 1;
589   const uint16_t entry_idx = get_entry_id(resid);
590   uint8_t package_idx = package_ids_[package_id];
591   if (UNLIKELY(package_idx == 0xff)) {
592     ANDROID_LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
593                                              package_id, resid);
594     return base::unexpected(std::nullopt);
595   }
596 
597   const PackageGroup& package_group = package_groups_[package_idx];
598   auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
599                                   stop_at_first_match, ignore_configuration);
600   if (UNLIKELY(!result.has_value())) {
601     return base::unexpected(result.error());
602   }
603 
604   bool overlaid = false;
605   if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
606     for (const auto& id_map : package_group.overlays_) {
607       auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
608       if (!overlay_entry) {
609         // No id map entry exists for this target resource.
610         continue;
611       }
612       if (overlay_entry.IsInlineValue()) {
613         // The target resource is overlaid by an inline value not represented by a resource.
614         result->entry = overlay_entry.GetInlineValue();
615         result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
616         result->cookie = id_map.cookie;
617 
618         if (UNLIKELY(logging_enabled)) {
619           last_resolution_.steps.push_back(
620               Resolution::Step{Resolution::Step::Type::OVERLAID_INLINE, String8(), result->cookie});
621           if (auto path = apk_assets_[result->cookie]->GetPath()) {
622             const std::string overlay_path = path->data();
623             if (IsFabricatedOverlay(overlay_path)) {
624               // FRRO don't have package name so we use the creating package here.
625               String8 frro_name = String8("FRRO");
626               // Get the first part of it since the expected one should be like
627               // {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
628               // under /data/resource-cache/.
629               const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
630               const size_t end = name.find('-');
631               if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
632                 frro_name.append(base::StringPrintf(" created by %s",
633                                                     name.substr(0 /* pos */,
634                                                                 end).c_str()).c_str());
635               }
636               last_resolution_.best_package_name = frro_name;
637             } else {
638               last_resolution_.best_package_name = result->package_name->c_str();
639             }
640           }
641           overlaid = true;
642         }
643         continue;
644       }
645 
646       auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
647                                       false /* stop_at_first_match */,
648                                       false /* ignore_configuration */);
649       if (UNLIKELY(IsIOError(overlay_result))) {
650         return base::unexpected(overlay_result.error());
651       }
652       if (!overlay_result.has_value()) {
653         continue;
654       }
655 
656       if (!overlay_result->config.isBetterThan(result->config, desired_config)
657           && overlay_result->config.compare(result->config) != 0) {
658         // The configuration of the entry for the overlay must be equal to or better than the target
659         // configuration to be chosen as the better value.
660         continue;
661       }
662 
663       result->cookie = overlay_result->cookie;
664       result->entry = overlay_result->entry;
665       result->config = overlay_result->config;
666       result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
667 
668       if (UNLIKELY(logging_enabled)) {
669         last_resolution_.steps.push_back(
670             Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->config.toString(),
671                              overlay_result->cookie});
672         last_resolution_.best_package_name =
673             overlay_result->package_name->c_str();
674         overlaid = true;
675       }
676     }
677   }
678 
679   if (UNLIKELY(logging_enabled)) {
680     last_resolution_.cookie = result->cookie;
681     last_resolution_.type_string_ref = result->type_string_ref;
682     last_resolution_.entry_string_ref = result->entry_string_ref;
683     last_resolution_.best_config_name = result->config.toString();
684     if (!overlaid) {
685       last_resolution_.best_package_name = result->package_name->c_str();
686     }
687   }
688 
689   return result;
690 }
691 
FindEntryInternal(const PackageGroup & package_group,uint8_t type_idx,uint16_t entry_idx,const ResTable_config & desired_config,bool stop_at_first_match,bool ignore_configuration) const692 base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
693     const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx,
694     const ResTable_config& desired_config, bool stop_at_first_match,
695     bool ignore_configuration) const {
696   const bool logging_enabled = resource_resolution_logging_enabled_;
697   ApkAssetsCookie best_cookie = kInvalidCookie;
698   const LoadedPackage* best_package = nullptr;
699   incfs::verified_map_ptr<ResTable_type> best_type;
700   const ResTable_config* best_config = nullptr;
701   uint32_t best_offset = 0U;
702   uint32_t type_flags = 0U;
703 
704   // If `desired_config` is not the same as the set configuration or the caller will accept a value
705   // from any configuration, then we cannot use our filtered list of types since it only it contains
706   // types matched to the set configuration.
707   const bool use_filtered = !ignore_configuration && &desired_config == &configuration_;
708 
709   const size_t package_count = package_group.packages_.size();
710   for (size_t pi = 0; pi < package_count; pi++) {
711     const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
712     const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
713     const ApkAssetsCookie cookie = package_group.cookies_[pi];
714 
715     // If the type IDs are offset in this package, we need to take that into account when searching
716     // for a type.
717     const TypeSpec* type_spec = loaded_package->GetTypeSpecByTypeIndex(type_idx);
718     if (UNLIKELY(type_spec == nullptr)) {
719       continue;
720     }
721 
722     // Allow custom loader packages to overlay resource values with configurations equivalent to the
723     // current best configuration.
724     const bool package_is_loader = loaded_package->IsCustomLoader();
725 
726     auto entry_flags = type_spec->GetFlagsForEntryIndex(entry_idx);
727     if (UNLIKELY(!entry_flags.has_value())) {
728       return base::unexpected(entry_flags.error());
729     }
730     type_flags |= entry_flags.value();
731 
732     const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
733     const size_t type_entry_count = (use_filtered) ? filtered_group.type_entries.size()
734                                                    : type_spec->type_entries.size();
735     for (size_t i = 0; i < type_entry_count; i++) {
736       const TypeSpec::TypeEntry* type_entry = (use_filtered) ? filtered_group.type_entries[i]
737                                                              : &type_spec->type_entries[i];
738 
739       // We can skip calling ResTable_config::match() if the caller does not care for the
740       // configuration to match or if we're using the list of types that have already had their
741       // configuration matched.
742       const ResTable_config& this_config = type_entry->config;
743       if (!(use_filtered || ignore_configuration || this_config.match(desired_config))) {
744         continue;
745       }
746 
747       Resolution::Step::Type resolution_type;
748       if (best_config == nullptr) {
749         resolution_type = Resolution::Step::Type::INITIAL;
750       } else if (this_config.isBetterThan(*best_config, &desired_config)) {
751         resolution_type = Resolution::Step::Type::BETTER_MATCH;
752       } else if (package_is_loader && this_config.compare(*best_config) == 0) {
753         resolution_type = Resolution::Step::Type::OVERLAID;
754       } else {
755         if (UNLIKELY(logging_enabled)) {
756           last_resolution_.steps.push_back(Resolution::Step{Resolution::Step::Type::SKIPPED,
757                                                       this_config.toString(),
758                                                       cookie});
759         }
760         continue;
761       }
762 
763       // The configuration matches and is better than the previous selection.
764       // Find the entry value if it exists for this configuration.
765       const auto& type = type_entry->type;
766       const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
767       if (UNLIKELY(IsIOError(offset))) {
768         return base::unexpected(offset.error());
769       }
770 
771       if (!offset.has_value()) {
772         if (UNLIKELY(logging_enabled)) {
773           last_resolution_.steps.push_back(Resolution::Step{Resolution::Step::Type::NO_ENTRY,
774                                                       this_config.toString(),
775                                                       cookie});
776         }
777         continue;
778       }
779 
780       best_cookie = cookie;
781       best_package = loaded_package;
782       best_type = type;
783       best_config = &this_config;
784       best_offset = offset.value();
785 
786       if (UNLIKELY(logging_enabled)) {
787         last_resolution_.steps.push_back(Resolution::Step{resolution_type,
788                                                           this_config.toString(),
789                                                           cookie});
790       }
791 
792       // Any configuration will suffice, so break.
793       if (stop_at_first_match) {
794         break;
795       }
796     }
797   }
798 
799   if (UNLIKELY(best_cookie == kInvalidCookie)) {
800     return base::unexpected(std::nullopt);
801   }
802 
803   auto best_entry_result = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
804   if (!best_entry_result.has_value()) {
805     return base::unexpected(best_entry_result.error());
806   }
807 
808   const incfs::map_ptr<ResTable_entry> best_entry = *best_entry_result;
809   if (!best_entry) {
810     return base::unexpected(IOError::PAGES_MISSING);
811   }
812 
813   const auto entry = GetEntryValue(best_entry.verified());
814   if (!entry.has_value()) {
815     return base::unexpected(entry.error());
816   }
817 
818   return FindEntryResult{
819     .cookie = best_cookie,
820     .entry = *entry,
821     .config = *best_config,
822     .type_flags = type_flags,
823     .package_name = &best_package->GetPackageName(),
824     .type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1),
825     .entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(),
826                                       best_entry->key.index),
827     .dynamic_ref_table = package_group.dynamic_ref_table.get(),
828   };
829 }
830 
ResetResourceResolution() const831 void AssetManager2::ResetResourceResolution() const {
832   last_resolution_.cookie = kInvalidCookie;
833   last_resolution_.resid = 0;
834   last_resolution_.steps.clear();
835   last_resolution_.type_string_ref = StringPoolRef();
836   last_resolution_.entry_string_ref = StringPoolRef();
837   last_resolution_.best_config_name.clear();
838   last_resolution_.best_package_name.clear();
839 }
840 
SetResourceResolutionLoggingEnabled(bool enabled)841 void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
842   resource_resolution_logging_enabled_ = enabled;
843   if (!enabled) {
844     ResetResourceResolution();
845   }
846 }
847 
GetLastResourceResolution() const848 std::string AssetManager2::GetLastResourceResolution() const {
849   if (!resource_resolution_logging_enabled_) {
850     LOG(ERROR) << "Must enable resource resolution logging before getting path.";
851     return {};
852   }
853 
854   const ApkAssetsCookie cookie = last_resolution_.cookie;
855   if (cookie == kInvalidCookie) {
856     LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
857     return {};
858   }
859 
860   const uint32_t resid = last_resolution_.resid;
861   const auto package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
862 
863   std::string resource_name_string;
864   if (package != nullptr) {
865     auto resource_name = ToResourceName(last_resolution_.type_string_ref,
866                                         last_resolution_.entry_string_ref,
867                                         package->GetPackageName());
868     resource_name_string = resource_name.has_value() ?
869         ToFormattedResourceString(resource_name.value()) : "<unknown>";
870   }
871 
872   std::stringstream log_stream;
873   log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
874                                    "\tFor config - %s", resid, resource_name_string.c_str(),
875                                    configuration_.toString().c_str());
876 
877   for (const Resolution::Step& step : last_resolution_.steps) {
878     const static std::unordered_map<Resolution::Step::Type, const char*> kStepStrings = {
879         {Resolution::Step::Type::INITIAL,         "Found initial"},
880         {Resolution::Step::Type::BETTER_MATCH,    "Found better"},
881         {Resolution::Step::Type::OVERLAID,        "Overlaid"},
882         {Resolution::Step::Type::OVERLAID_INLINE, "Overlaid inline"},
883         {Resolution::Step::Type::SKIPPED,         "Skipped"},
884         {Resolution::Step::Type::NO_ENTRY,        "No entry"}
885     };
886 
887     const auto prefix = kStepStrings.find(step.type);
888     if (prefix == kStepStrings.end()) {
889       continue;
890     }
891 
892     log_stream << "\n\t" << prefix->second << ": " << apk_assets_[step.cookie]->GetDebugName();
893     if (!step.config_name.isEmpty()) {
894       log_stream << " - " << step.config_name;
895     }
896   }
897 
898   log_stream << "\nBest matching is from "
899              << (last_resolution_.best_config_name.isEmpty() ? "default"
900                                                    : last_resolution_.best_config_name)
901              << " configuration of " << last_resolution_.best_package_name;
902   return log_stream.str();
903 }
904 
GetParentThemeResourceId(uint32_t resid) const905 base::expected<uint32_t, NullOrIOError> AssetManager2::GetParentThemeResourceId(uint32_t resid)
906 const {
907   auto entry = FindEntry(resid, 0u /* density_override */,
908                          false /* stop_at_first_match */,
909                          false /* ignore_configuration */);
910   if (!entry.has_value()) {
911     return base::unexpected(entry.error());
912   }
913 
914   auto entry_map = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&entry->entry);
915   if (entry_map == nullptr) {
916     // Not a bag, nothing to do.
917     return base::unexpected(std::nullopt);
918   }
919 
920   auto map = *entry_map;
921   const uint32_t parent_resid = dtohl(map->parent.ident);
922 
923   return parent_resid;
924 }
925 
GetResourceName(uint32_t resid) const926 base::expected<AssetManager2::ResourceName, NullOrIOError> AssetManager2::GetResourceName(
927     uint32_t resid) const {
928   auto result = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */,
929                           true /* ignore_configuration */);
930   if (!result.has_value()) {
931     return base::unexpected(result.error());
932   }
933 
934   return ToResourceName(result->type_string_ref,
935                         result->entry_string_ref,
936                         *result->package_name);
937 }
938 
GetResourceTypeSpecFlags(uint32_t resid) const939 base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceTypeSpecFlags(
940     uint32_t resid) const {
941   auto result = FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */,
942                           true /* ignore_configuration */);
943   if (!result.has_value()) {
944     return base::unexpected(result.error());
945   }
946   return result->type_flags;
947 }
948 
GetResource(uint32_t resid,bool may_be_bag,uint16_t density_override) const949 base::expected<AssetManager2::SelectedValue, NullOrIOError> AssetManager2::GetResource(
950     uint32_t resid, bool may_be_bag, uint16_t density_override) const {
951   auto result = FindEntry(resid, density_override, false /* stop_at_first_match */,
952                           false /* ignore_configuration */);
953   if (!result.has_value()) {
954     return base::unexpected(result.error());
955   }
956 
957   auto result_map_entry = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&result->entry);
958   if (result_map_entry != nullptr) {
959     if (!may_be_bag) {
960       LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
961       return base::unexpected(std::nullopt);
962     }
963 
964     // Create a reference since we can't represent this complex type as a Res_value.
965     return SelectedValue(Res_value::TYPE_REFERENCE, resid, result->cookie, result->type_flags,
966                          resid, result->config);
967   }
968 
969   // Convert the package ID to the runtime assigned package ID.
970   Res_value value = std::get<Res_value>(result->entry);
971   result->dynamic_ref_table->lookupResourceValue(&value);
972 
973   return SelectedValue(value.dataType, value.data, result->cookie, result->type_flags,
974                        resid, result->config);
975 }
976 
ResolveReference(AssetManager2::SelectedValue & value,bool cache_value) const977 base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(
978     AssetManager2::SelectedValue& value, bool cache_value) const {
979   if (value.type != Res_value::TYPE_REFERENCE || value.data == 0U) {
980     // Not a reference. Nothing to do.
981     return {};
982   }
983 
984   const uint32_t original_flags = value.flags;
985   const uint32_t original_resid = value.data;
986   if (cache_value) {
987     auto cached_value = cached_resolved_values_.find(value.data);
988     if (cached_value != cached_resolved_values_.end()) {
989       value = cached_value->second;
990       value.flags |= original_flags;
991       return {};
992     }
993   }
994 
995   uint32_t combined_flags = 0U;
996   uint32_t resolve_resid = original_resid;
997   constexpr const uint32_t kMaxIterations = 20;
998   for (uint32_t i = 0U;; i++) {
999     auto result = GetResource(resolve_resid, true /*may_be_bag*/);
1000     if (!result.has_value()) {
1001       value.resid = resolve_resid;
1002       return base::unexpected(result.error());
1003     }
1004 
1005     // If resource resolution fails, the value should be set to the last reference that was able to
1006     // be resolved successfully.
1007     value = *result;
1008     value.flags |= combined_flags;
1009 
1010     if (result->type != Res_value::TYPE_REFERENCE ||
1011         result->data == Res_value::DATA_NULL_UNDEFINED ||
1012         result->data == resolve_resid || i == kMaxIterations) {
1013       // This reference can't be resolved, so exit now and let the caller deal with it.
1014       if (cache_value) {
1015         cached_resolved_values_[original_resid] = value;
1016       }
1017 
1018       // Above value is cached without original_flags to ensure they don't get included in future
1019       // queries that hit the cache
1020       value.flags |= original_flags;
1021       return {};
1022     }
1023 
1024     combined_flags = result->flags;
1025     resolve_resid = result->data;
1026   }
1027 }
1028 
GetBagResIdStack(uint32_t resid) const1029 const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) const {
1030   auto cached_iter = cached_bag_resid_stacks_.find(resid);
1031   if (cached_iter != cached_bag_resid_stacks_.end()) {
1032     return cached_iter->second;
1033   }
1034 
1035   std::vector<uint32_t> found_resids;
1036   GetBag(resid, found_resids);
1037   cached_bag_resid_stacks_.emplace(resid, found_resids);
1038   return found_resids;
1039 }
1040 
ResolveBag(AssetManager2::SelectedValue & value) const1041 base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
1042     AssetManager2::SelectedValue& value) const {
1043   if (UNLIKELY(value.type != Res_value::TYPE_REFERENCE)) {
1044     return base::unexpected(std::nullopt);
1045   }
1046 
1047   auto bag = GetBag(value.data);
1048   if (bag.has_value()) {
1049     value.flags |= (*bag)->type_spec_flags;
1050   }
1051   return bag;
1052 }
1053 
GetBag(uint32_t resid) const1054 base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
1055   std::vector<uint32_t> found_resids;
1056   const auto bag = GetBag(resid, found_resids);
1057   cached_bag_resid_stacks_.emplace(resid, found_resids);
1058   return bag;
1059 }
1060 
GetBag(uint32_t resid,std::vector<uint32_t> & child_resids) const1061 base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(
1062     uint32_t resid, std::vector<uint32_t>& child_resids) const {
1063   if (auto cached_iter = cached_bags_.find(resid); cached_iter != cached_bags_.end()) {
1064     return cached_iter->second.get();
1065   }
1066 
1067   auto entry = FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */,
1068                          false /* ignore_configuration */);
1069   if (!entry.has_value()) {
1070     return base::unexpected(entry.error());
1071   }
1072 
1073   auto entry_map = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&entry->entry);
1074   if (entry_map == nullptr) {
1075     // Not a bag, nothing to do.
1076     return base::unexpected(std::nullopt);
1077   }
1078 
1079   auto map = *entry_map;
1080   auto map_entry = map.offset(dtohs(map->size)).convert<ResTable_map>();
1081   const auto map_entry_end = map_entry + dtohl(map->count);
1082 
1083   // Keep track of ids that have already been seen to prevent infinite loops caused by circular
1084   // dependencies between bags.
1085   child_resids.push_back(resid);
1086 
1087   uint32_t parent_resid = dtohl(map->parent.ident);
1088   if (parent_resid == 0U ||
1089       std::find(child_resids.begin(), child_resids.end(), parent_resid) != child_resids.end()) {
1090     // There is no parent or a circular parental dependency exist, meaning there is nothing to
1091     // inherit and we can do a simple copy of the entries in the map.
1092     const size_t entry_count = map_entry_end - map_entry;
1093     util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
1094         malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
1095 
1096     bool sort_entries = false;
1097     for (auto new_entry = new_bag->entries; map_entry != map_entry_end; ++map_entry) {
1098       if (UNLIKELY(!map_entry)) {
1099         return base::unexpected(IOError::PAGES_MISSING);
1100       }
1101 
1102       uint32_t new_key = dtohl(map_entry->name.ident);
1103       if (!is_internal_resid(new_key)) {
1104         // Attributes, arrays, etc don't have a resource id as the name. They specify
1105         // other data, which would be wrong to change via a lookup.
1106         if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR)) {
1107           LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
1108                                            resid);
1109           return base::unexpected(std::nullopt);
1110         }
1111       }
1112 
1113       new_entry->cookie = entry->cookie;
1114       new_entry->key = new_key;
1115       new_entry->key_pool = nullptr;
1116       new_entry->type_pool = nullptr;
1117       new_entry->style = resid;
1118       new_entry->value.copyFrom_dtoh(map_entry->value);
1119       status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
1120       if (UNLIKELY(err != NO_ERROR)) {
1121         LOG(ERROR) << base::StringPrintf(
1122             "Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
1123             new_entry->value.data, new_key);
1124         return base::unexpected(std::nullopt);
1125       }
1126 
1127       sort_entries = sort_entries ||
1128           (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
1129       ++new_entry;
1130     }
1131 
1132     if (sort_entries) {
1133       std::sort(new_bag->entries, new_bag->entries + entry_count,
1134                 [](auto&& lhs, auto&& rhs) { return lhs.key < rhs.key; });
1135     }
1136 
1137     new_bag->type_spec_flags = entry->type_flags;
1138     new_bag->entry_count = static_cast<uint32_t>(entry_count);
1139     ResolvedBag* result = new_bag.get();
1140     cached_bags_[resid] = std::move(new_bag);
1141     return result;
1142   }
1143 
1144   // In case the parent is a dynamic reference, resolve it.
1145   entry->dynamic_ref_table->lookupResourceId(&parent_resid);
1146 
1147   // Get the parent and do a merge of the keys.
1148   const auto parent_bag = GetBag(parent_resid, child_resids);
1149   if (UNLIKELY(!parent_bag.has_value())) {
1150     // Failed to get the parent that should exist.
1151     LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
1152                                      resid);
1153     return base::unexpected(parent_bag.error());
1154   }
1155 
1156   // Create the max possible entries we can make. Once we construct the bag,
1157   // we will realloc to fit to size.
1158   const size_t max_count = (*parent_bag)->entry_count + dtohl(map->count);
1159   util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
1160       malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))))};
1161   ResolvedBag::Entry* new_entry = new_bag->entries;
1162 
1163   const ResolvedBag::Entry* parent_entry = (*parent_bag)->entries;
1164   const ResolvedBag::Entry* const parent_entry_end = parent_entry + (*parent_bag)->entry_count;
1165 
1166   // The keys are expected to be in sorted order. Merge the two bags.
1167   bool sort_entries = false;
1168   while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
1169     if (UNLIKELY(!map_entry)) {
1170       return base::unexpected(IOError::PAGES_MISSING);
1171     }
1172 
1173     uint32_t child_key = dtohl(map_entry->name.ident);
1174     if (!is_internal_resid(child_key)) {
1175       if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR)) {
1176         LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
1177                                          resid);
1178         return base::unexpected(std::nullopt);
1179       }
1180     }
1181 
1182     if (child_key <= parent_entry->key) {
1183       // Use the child key if it comes before the parent
1184       // or is equal to the parent (overrides).
1185       new_entry->cookie = entry->cookie;
1186       new_entry->key = child_key;
1187       new_entry->key_pool = nullptr;
1188       new_entry->type_pool = nullptr;
1189       new_entry->value.copyFrom_dtoh(map_entry->value);
1190       new_entry->style = resid;
1191       status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
1192       if (UNLIKELY(err != NO_ERROR)) {
1193         LOG(ERROR) << base::StringPrintf(
1194             "Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
1195             new_entry->value.data, child_key);
1196         return base::unexpected(std::nullopt);
1197       }
1198       ++map_entry;
1199     } else {
1200       // Take the parent entry as-is.
1201       memcpy(new_entry, parent_entry, sizeof(*new_entry));
1202     }
1203 
1204     sort_entries = sort_entries ||
1205         (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
1206     if (child_key >= parent_entry->key) {
1207       // Move to the next parent entry if we used it or it was overridden.
1208       ++parent_entry;
1209     }
1210     // Increment to the next entry to fill.
1211     ++new_entry;
1212   }
1213 
1214   // Finish the child entries if they exist.
1215   while (map_entry != map_entry_end) {
1216     if (UNLIKELY(!map_entry)) {
1217       return base::unexpected(IOError::PAGES_MISSING);
1218     }
1219 
1220     uint32_t new_key = dtohl(map_entry->name.ident);
1221     if (!is_internal_resid(new_key)) {
1222       if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR)) {
1223         LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
1224                                          resid);
1225         return base::unexpected(std::nullopt);
1226       }
1227     }
1228     new_entry->cookie = entry->cookie;
1229     new_entry->key = new_key;
1230     new_entry->key_pool = nullptr;
1231     new_entry->type_pool = nullptr;
1232     new_entry->value.copyFrom_dtoh(map_entry->value);
1233     new_entry->style = resid;
1234     status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
1235     if (UNLIKELY(err != NO_ERROR)) {
1236       LOG(ERROR) << base::StringPrintf("Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.",
1237                                        new_entry->value.dataType, new_entry->value.data, new_key);
1238       return base::unexpected(std::nullopt);
1239     }
1240     sort_entries = sort_entries ||
1241         (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
1242     ++map_entry;
1243     ++new_entry;
1244   }
1245 
1246   // Finish the parent entries if they exist.
1247   if (parent_entry != parent_entry_end) {
1248     // Take the rest of the parent entries as-is.
1249     const size_t num_entries_to_copy = parent_entry_end - parent_entry;
1250     memcpy(new_entry, parent_entry, num_entries_to_copy * sizeof(*new_entry));
1251     new_entry += num_entries_to_copy;
1252   }
1253 
1254   // Resize the resulting array to fit.
1255   const size_t actual_count = new_entry - new_bag->entries;
1256   if (actual_count != max_count) {
1257     new_bag.reset(reinterpret_cast<ResolvedBag*>(realloc(
1258         new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))));
1259   }
1260 
1261   if (sort_entries) {
1262     std::sort(new_bag->entries, new_bag->entries + actual_count,
1263               [](auto&& lhs, auto&& rhs) { return lhs.key < rhs.key; });
1264   }
1265 
1266   // Combine flags from the parent and our own bag.
1267   new_bag->type_spec_flags = entry->type_flags | (*parent_bag)->type_spec_flags;
1268   new_bag->entry_count = static_cast<uint32_t>(actual_count);
1269   ResolvedBag* result = new_bag.get();
1270   cached_bags_[resid] = std::move(new_bag);
1271   return result;
1272 }
1273 
Utf8ToUtf16(const StringPiece & str,std::u16string * out)1274 static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
1275   ssize_t len =
1276       utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false);
1277   if (len < 0) {
1278     return false;
1279   }
1280   out->resize(static_cast<size_t>(len));
1281   utf8_to_utf16(reinterpret_cast<const uint8_t*>(str.data()), str.size(), &*out->begin(),
1282                 static_cast<size_t>(len + 1));
1283   return true;
1284 }
1285 
GetResourceId(const std::string & resource_name,const std::string & fallback_type,const std::string & fallback_package) const1286 base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(
1287     const std::string& resource_name, const std::string& fallback_type,
1288     const std::string& fallback_package) const {
1289   StringPiece package_name, type, entry;
1290   if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
1291     return base::unexpected(std::nullopt);
1292   }
1293 
1294   if (entry.empty()) {
1295     return base::unexpected(std::nullopt);
1296   }
1297 
1298   if (package_name.empty()) {
1299     package_name = fallback_package;
1300   }
1301 
1302   if (type.empty()) {
1303     type = fallback_type;
1304   }
1305 
1306   std::u16string type16;
1307   if (!Utf8ToUtf16(type, &type16)) {
1308     return base::unexpected(std::nullopt);
1309   }
1310 
1311   std::u16string entry16;
1312   if (!Utf8ToUtf16(entry, &entry16)) {
1313     return base::unexpected(std::nullopt);
1314   }
1315 
1316   const StringPiece16 kAttr16 = u"attr";
1317   const static std::u16string kAttrPrivate16 = u"^attr-private";
1318 
1319   for (const PackageGroup& package_group : package_groups_) {
1320     for (const ConfiguredPackage& package_impl : package_group.packages_) {
1321       const LoadedPackage* package = package_impl.loaded_package_;
1322       if (package_name != package->GetPackageName()) {
1323         // All packages in the same group are expected to have the same package name.
1324         break;
1325       }
1326 
1327       base::expected<uint32_t, NullOrIOError> resid = package->FindEntryByName(type16, entry16);
1328       if (UNLIKELY(IsIOError(resid))) {
1329          return base::unexpected(resid.error());
1330        }
1331 
1332       if (!resid.has_value() && kAttr16 == type16) {
1333         // Private attributes in libraries (such as the framework) are sometimes encoded
1334         // under the type '^attr-private' in order to leave the ID space of public 'attr'
1335         // free for future additions. Check '^attr-private' for the same name.
1336         resid = package->FindEntryByName(kAttrPrivate16, entry16);
1337       }
1338 
1339       if (resid.has_value()) {
1340         return fix_package_id(*resid, package_group.dynamic_ref_table->mAssignedPackageId);
1341       }
1342     }
1343   }
1344   return base::unexpected(std::nullopt);
1345 }
1346 
RebuildFilterList()1347 void AssetManager2::RebuildFilterList() {
1348   for (PackageGroup& group : package_groups_) {
1349     for (ConfiguredPackage& impl : group.packages_) {
1350       // Destroy it.
1351       impl.filtered_configs_.~ByteBucketArray();
1352 
1353       // Re-create it.
1354       new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
1355 
1356       // Create the filters here.
1357       impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
1358         FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_id - 1);
1359         for (const auto& type_entry : type_spec.type_entries) {
1360           if (type_entry.config.match(configuration_)) {
1361             group.type_entries.push_back(&type_entry);
1362           }
1363         }
1364       });
1365     }
1366   }
1367 }
1368 
InvalidateCaches(uint32_t diff)1369 void AssetManager2::InvalidateCaches(uint32_t diff) {
1370   cached_bag_resid_stacks_.clear();
1371 
1372   if (diff == 0xffffffffu) {
1373     // Everything must go.
1374     cached_bags_.clear();
1375     return;
1376   }
1377 
1378   // Be more conservative with what gets purged. Only if the bag has other possible
1379   // variations with respect to what changed (diff) should we remove it.
1380   for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) {
1381     if (diff & iter->second->type_spec_flags) {
1382       iter = cached_bags_.erase(iter);
1383     } else {
1384       ++iter;
1385     }
1386   }
1387 
1388   cached_resolved_values_.clear();
1389 }
1390 
GetAssignedPackageId(const LoadedPackage * package) const1391 uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
1392   for (auto& package_group : package_groups_) {
1393     for (auto& package2 : package_group.packages_) {
1394       if (package2.loaded_package_ == package) {
1395         return package_group.dynamic_ref_table->mAssignedPackageId;
1396       }
1397     }
1398   }
1399   return 0;
1400 }
1401 
NewTheme()1402 std::unique_ptr<Theme> AssetManager2::NewTheme() {
1403   constexpr size_t kInitialReserveSize = 32;
1404   auto theme = std::unique_ptr<Theme>(new Theme(this));
1405   theme->entries_.reserve(kInitialReserveSize);
1406   return theme;
1407 }
1408 
Theme(AssetManager2 * asset_manager)1409 Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
1410 }
1411 
1412 Theme::~Theme() = default;
1413 
1414 struct Theme::Entry {
1415   uint32_t attr_res_id;
1416   ApkAssetsCookie cookie;
1417   uint32_t type_spec_flags;
1418   Res_value value;
1419 };
1420 
1421 namespace {
1422 struct ThemeEntryKeyComparer {
operator ()android::__anon8ac137490711::ThemeEntryKeyComparer1423   bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept {
1424     return entry.attr_res_id < attr_res_id;
1425   }
1426 };
1427 } // namespace
1428 
ApplyStyle(uint32_t resid,bool force)1429 base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
1430   ATRACE_NAME("Theme::ApplyStyle");
1431 
1432   auto bag = asset_manager_->GetBag(resid);
1433   if (!bag.has_value()) {
1434     return base::unexpected(bag.error());
1435   }
1436 
1437   // Merge the flags from this style.
1438   type_spec_flags_ |= (*bag)->type_spec_flags;
1439 
1440   for (auto it = begin(*bag); it != end(*bag); ++it) {
1441     const uint32_t attr_res_id = it->key;
1442 
1443     // If the resource ID passed in is not a style, the key can be some other identifier that is not
1444     // a resource ID. We should fail fast instead of operating with strange resource IDs.
1445     if (!is_valid_resid(attr_res_id)) {
1446       return base::unexpected(std::nullopt);
1447     }
1448 
1449     // DATA_NULL_EMPTY (@empty) is a valid resource value and DATA_NULL_UNDEFINED represents
1450     // an absence of a valid value.
1451     bool is_undefined = it->value.dataType == Res_value::TYPE_NULL &&
1452         it->value.data != Res_value::DATA_NULL_EMPTY;
1453     if (!force && is_undefined) {
1454       continue;
1455     }
1456 
1457     Theme::Entry new_entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
1458     auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
1459                                      ThemeEntryKeyComparer{});
1460     if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
1461       if (is_undefined) {
1462         // DATA_NULL_UNDEFINED clears the value of the attribute in the theme only when `force` is
1463         /// true.
1464         entries_.erase(entry_it);
1465       } else if (force) {
1466         *entry_it = new_entry;
1467       }
1468     } else {
1469       entries_.insert(entry_it, new_entry);
1470     }
1471   }
1472   return {};
1473 }
1474 
Rebase(AssetManager2 * am,const uint32_t * style_ids,const uint8_t * force,size_t style_count)1475 void Theme::Rebase(AssetManager2* am, const uint32_t* style_ids, const uint8_t* force,
1476                    size_t style_count) {
1477   ATRACE_NAME("Theme::Rebase");
1478   // Reset the entries without changing the vector capacity to prevent reallocations during
1479   // ApplyStyle.
1480   entries_.clear();
1481   asset_manager_ = am;
1482   for (size_t i = 0; i < style_count; i++) {
1483     ApplyStyle(style_ids[i], force[i]);
1484   }
1485 }
1486 
GetAttribute(uint32_t resid) const1487 std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
1488 
1489   constexpr const uint32_t kMaxIterations = 20;
1490   uint32_t type_spec_flags = 0u;
1491   for (uint32_t i = 0; i <= kMaxIterations; i++) {
1492     auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), resid,
1493                                      ThemeEntryKeyComparer{});
1494     if (entry_it == entries_.end() || entry_it->attr_res_id != resid) {
1495       return std::nullopt;
1496     }
1497 
1498     type_spec_flags |= entry_it->type_spec_flags;
1499     if (entry_it->value.dataType == Res_value::TYPE_ATTRIBUTE) {
1500       resid = entry_it->value.data;
1501       continue;
1502     }
1503 
1504     return AssetManager2::SelectedValue(entry_it->value.dataType, entry_it->value.data,
1505                                         entry_it->cookie, type_spec_flags, 0U /* resid */,
1506                                         {} /* config */);
1507   }
1508   return std::nullopt;
1509 }
1510 
ResolveAttributeReference(AssetManager2::SelectedValue & value) const1511 base::expected<std::monostate, NullOrIOError> Theme::ResolveAttributeReference(
1512       AssetManager2::SelectedValue& value) const {
1513   if (value.type != Res_value::TYPE_ATTRIBUTE) {
1514     return asset_manager_->ResolveReference(value);
1515   }
1516 
1517   std::optional<AssetManager2::SelectedValue> result = GetAttribute(value.data);
1518   if (!result.has_value()) {
1519     return base::unexpected(std::nullopt);
1520   }
1521 
1522   auto resolve_result = asset_manager_->ResolveReference(*result, true /* cache_value */);
1523   if (resolve_result.has_value()) {
1524     result->flags |= value.flags;
1525     value = *result;
1526   }
1527   return resolve_result;
1528 }
1529 
Clear()1530 void Theme::Clear() {
1531   entries_.clear();
1532 }
1533 
SetTo(const Theme & source)1534 base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
1535   if (this == &source) {
1536     return {};
1537   }
1538 
1539   type_spec_flags_ = source.type_spec_flags_;
1540 
1541   if (asset_manager_ == source.asset_manager_) {
1542     entries_ = source.entries_;
1543   } else {
1544     std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
1545     typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
1546     std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
1547 
1548     // Determine which ApkAssets are loaded in both theme AssetManagers.
1549     const auto src_assets = source.asset_manager_->GetApkAssets();
1550     for (size_t i = 0; i < src_assets.size(); i++) {
1551       const ApkAssets* src_asset = src_assets[i];
1552 
1553       const auto dest_assets = asset_manager_->GetApkAssets();
1554       for (size_t j = 0; j < dest_assets.size(); j++) {
1555         const ApkAssets* dest_asset = dest_assets[j];
1556         if (src_asset != dest_asset) {
1557           // ResourcesManager caches and reuses ApkAssets when the same apk must be present in
1558           // multiple AssetManagers. Two ApkAssets point to the same version of the same resources
1559           // if they are the same instance.
1560           continue;
1561         }
1562 
1563         // Map the package ids of the asset in the source AssetManager to the package ids of the
1564         // asset in th destination AssetManager.
1565         SourceToDestinationRuntimePackageMap package_map;
1566         for (const auto& loaded_package : src_asset->GetLoadedArsc()->GetPackages()) {
1567           const int src_package_id = source.asset_manager_->GetAssignedPackageId(
1568               loaded_package.get());
1569           const int dest_package_id = asset_manager_->GetAssignedPackageId(loaded_package.get());
1570           package_map[src_package_id] = dest_package_id;
1571         }
1572 
1573         src_to_dest_asset_cookies.insert(std::make_pair(i, j));
1574         src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
1575         break;
1576       }
1577     }
1578 
1579     // Reset the data in the destination theme.
1580     entries_.clear();
1581 
1582     for (const auto& entry : source.entries_) {
1583       bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
1584                            || entry.value.dataType == Res_value::TYPE_REFERENCE
1585                            || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
1586                            || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
1587                           && entry.value.data != 0x0;
1588 
1589       // If the attribute value represents an attribute or reference, the package id of the
1590       // value needs to be rewritten to the package id of the value in the destination.
1591       uint32_t attribute_data = entry.value.data;
1592       if (is_reference) {
1593         // Determine the package id of the reference in the destination AssetManager.
1594         auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
1595         if (value_package_map == src_asset_cookie_id_map.end()) {
1596           continue;
1597         }
1598 
1599         auto value_dest_package = value_package_map->second.find(
1600             get_package_id(entry.value.data));
1601         if (value_dest_package == value_package_map->second.end()) {
1602           continue;
1603         }
1604 
1605         attribute_data = fix_package_id(entry.value.data, value_dest_package->second);
1606       }
1607 
1608       // Find the cookie of the value in the destination. If the source apk is not loaded in the
1609       // destination, only copy resources that do not reference resources in the source.
1610       ApkAssetsCookie data_dest_cookie;
1611       auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
1612       if (value_dest_cookie != src_to_dest_asset_cookies.end()) {
1613         data_dest_cookie = value_dest_cookie->second;
1614       } else {
1615         if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) {
1616           continue;
1617         } else {
1618           data_dest_cookie = 0x0;
1619         }
1620       }
1621 
1622       // The package id of the attribute needs to be rewritten to the package id of the
1623       // attribute in the destination.
1624       int attribute_dest_package_id = get_package_id(entry.attr_res_id);
1625       if (attribute_dest_package_id != 0x01) {
1626         // Find the cookie of the attribute resource id in the source AssetManager
1627         base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
1628             source.asset_manager_->FindEntry(entry.attr_res_id, 0 /* density_override */ ,
1629                                              true /* stop_at_first_match */,
1630                                              true /* ignore_configuration */);
1631         if (UNLIKELY(IsIOError(attribute_entry_result))) {
1632           return base::unexpected(GetIOError(attribute_entry_result.error()));
1633         }
1634         if (!attribute_entry_result.has_value()) {
1635           continue;
1636         }
1637 
1638         // Determine the package id of the attribute in the destination AssetManager.
1639         auto attribute_package_map = src_asset_cookie_id_map.find(
1640             attribute_entry_result->cookie);
1641         if (attribute_package_map == src_asset_cookie_id_map.end()) {
1642           continue;
1643         }
1644         auto attribute_dest_package = attribute_package_map->second.find(
1645             attribute_dest_package_id);
1646         if (attribute_dest_package == attribute_package_map->second.end()) {
1647           continue;
1648         }
1649         attribute_dest_package_id = attribute_dest_package->second;
1650       }
1651 
1652       auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(entry.attr_res_id),
1653                                      get_entry_id(entry.attr_res_id));
1654       Theme::Entry new_entry{dest_attr_id, data_dest_cookie, entry.type_spec_flags,
1655                                             Res_value{.dataType = entry.value.dataType,
1656                                                       .data = attribute_data}};
1657 
1658       // Since the entries were cleared, the attribute resource id has yet been mapped to any value.
1659       auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), dest_attr_id,
1660                                        ThemeEntryKeyComparer{});
1661       entries_.insert(entry_it, new_entry);
1662     }
1663   }
1664   return {};
1665 }
1666 
Dump() const1667 void Theme::Dump() const {
1668   LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
1669   for (auto& entry : entries_) {
1670     LOG(INFO) << base::StringPrintf("  entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
1671                                     entry.attr_res_id, entry.value.data, entry.value.dataType,
1672                                     entry.cookie);
1673   }
1674 }
1675 
1676 }  // namespace android
1677