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