summaryrefslogtreecommitdiff
path: root/libs/androidfw/AssetManager2.cpp
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
committerXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
commit628590d7ec80e10a3fc24b1c18a1afb55cca10a8 (patch)
tree4b1c3f52d86d7fb53afbe9e9438468588fa489f8 /libs/androidfw/AssetManager2.cpp
parentb11b8ec3aec8bb42f2c07e1c5ac7942da293baa8 (diff)
parentd2d3a20624d968199353ccf6ddbae6f3ac39c9af (diff)
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507 Merged-In: I3d92a6de21a938f6b352ec26dc23420c0fe02b27 Change-Id: Ifdb80563ef042738778ebb8a7581a97c4e3d96e2
Diffstat (limited to 'libs/androidfw/AssetManager2.cpp')
-rw-r--r--libs/androidfw/AssetManager2.cpp497
1 files changed, 364 insertions, 133 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index d20aecaaf0f6..b9765ea7212c 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -22,10 +22,11 @@
#include <iterator>
#include <map>
#include <set>
-#include <sstream>
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
+#include "androidfw/ResourceUtils.h"
+#include "androidfw/Util.h"
#include "utils/ByteOrder.h"
#include "utils/Trace.h"
@@ -35,21 +36,13 @@
#endif
#endif
-#ifdef __ANDROID__
-#define ANDROID_LOG(x) LOG(x)
-#else
-#define ANDROID_LOG(x) std::stringstream()
-#endif
-
-#include "androidfw/ResourceUtils.h"
-
namespace android {
struct FindEntryResult {
// A pointer to the resource table entry for this resource.
// If the size of the entry is > sizeof(ResTable_entry), it can be cast to
// a ResTable_map_entry and processed as a bag/map.
- const ResTable_entry* entry;
+ ResTable_entry_handle entry;
// The configuration for which the resulting entry was defined. This is already swapped to host
// endianness.
@@ -61,6 +54,9 @@ struct FindEntryResult {
// The dynamic package ID map for the package from which this resource came from.
const DynamicRefTable* dynamic_ref_table;
+ // The package name of the resource.
+ const std::string* package_name;
+
// The string pool reference to the type's name. This uses a different string pool than
// the global string pool, but this is hidden from the caller.
StringPoolRef type_string_ref;
@@ -89,12 +85,27 @@ void AssetManager2::BuildDynamicRefTable() {
package_groups_.clear();
package_ids_.fill(0xff);
+ // A mapping from apk assets path to the runtime package id of its first loaded package.
+ std::unordered_map<std::string, uint8_t> apk_assets_package_ids;
+
+ // Overlay resources are not directly referenced by an application so their resource ids
+ // can change throughout the application's lifetime. Assign overlay package ids last.
+ std::vector<const ApkAssets*> sorted_apk_assets(apk_assets_);
+ std::stable_partition(sorted_apk_assets.begin(), sorted_apk_assets.end(), [](const ApkAssets* a) {
+ return !a->IsOverlay();
+ });
+
+ // The assets cookie must map to the position of the apk assets in the unsorted apk assets list.
+ std::unordered_map<const ApkAssets*, ApkAssetsCookie> apk_assets_cookies;
+ apk_assets_cookies.reserve(apk_assets_.size());
+ for (size_t i = 0, n = apk_assets_.size(); i < n; i++) {
+ apk_assets_cookies[apk_assets_[i]] = static_cast<ApkAssetsCookie>(i);
+ }
+
// 0x01 is reserved for the android package.
int next_package_id = 0x02;
- const size_t apk_assets_count = apk_assets_.size();
- for (size_t i = 0; i < apk_assets_count; i++) {
- const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();
-
+ for (const ApkAssets* apk_assets : sorted_apk_assets) {
+ const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
for (const std::unique_ptr<const LoadedPackage>& package : loaded_arsc->GetPackages()) {
// Get the package ID or assign one if a shared library.
int package_id;
@@ -109,22 +120,55 @@ void AssetManager2::BuildDynamicRefTable() {
if (idx == 0xff) {
package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
package_groups_.push_back({});
- DynamicRefTable& ref_table = package_groups_.back().dynamic_ref_table;
- ref_table.mAssignedPackageId = package_id;
- ref_table.mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
+
+ if (apk_assets->IsOverlay()) {
+ // The target package must precede the overlay package in the apk assets paths in order
+ // to take effect.
+ const auto& loaded_idmap = apk_assets->GetLoadedIdmap();
+ auto target_package_iter = apk_assets_package_ids.find(loaded_idmap->TargetApkPath());
+ if (target_package_iter == apk_assets_package_ids.end()) {
+ LOG(INFO) << "failed to find target package for overlay "
+ << loaded_idmap->OverlayApkPath();
+ } else {
+ const uint8_t target_package_id = target_package_iter->second;
+ const uint8_t target_idx = package_ids_[target_package_id];
+ CHECK(target_idx != 0xff) << "overlay added to apk_assets_package_ids but does not"
+ << " have an assigned package group";
+
+ PackageGroup& target_package_group = package_groups_[target_idx];
+
+ // Create a special dynamic reference table for the overlay to rewrite references to
+ // overlay resources as references to the target resources they overlay.
+ auto overlay_table = std::make_shared<OverlayDynamicRefTable>(
+ loaded_idmap->GetOverlayDynamicRefTable(target_package_id));
+ package_groups_.back().dynamic_ref_table = overlay_table;
+
+ // Add the overlay resource map to the target package's set of overlays.
+ target_package_group.overlays_.push_back(
+ ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
+ overlay_table.get()),
+ apk_assets_cookies[apk_assets]});
+ }
+ }
+
+ DynamicRefTable* ref_table = package_groups_.back().dynamic_ref_table.get();
+ ref_table->mAssignedPackageId = package_id;
+ ref_table->mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
}
PackageGroup* package_group = &package_groups_[idx];
// Add the package and to the set of packages with the same ID.
package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
- package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));
+ package_group->cookies_.push_back(apk_assets_cookies[apk_assets]);
// Add the package name -> build time ID mappings.
for (const DynamicPackageEntry& entry : package->GetDynamicPackageMap()) {
String16 package_name(entry.package_name.c_str(), entry.package_name.size());
- package_group->dynamic_ref_table.mEntries.replaceValueFor(
+ package_group->dynamic_ref_table->mEntries.replaceValueFor(
package_name, static_cast<uint8_t>(entry.package_id));
}
+
+ apk_assets_package_ids.insert(std::make_pair(apk_assets->GetPath(), package_id));
}
}
@@ -133,8 +177,8 @@ void AssetManager2::BuildDynamicRefTable() {
for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
- iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
- iter->dynamic_ref_table.mAssignedPackageId);
+ iter2->dynamic_ref_table->addMapping(String16(package_name.c_str(), package_name.size()),
+ iter->dynamic_ref_table->mAssignedPackageId);
}
}
}
@@ -167,13 +211,13 @@ void AssetManager2::DumpToLog() const {
(loaded_package->IsDynamic() ? " dynamic" : ""));
}
LOG(INFO) << base::StringPrintf("PG (%02x): ",
- package_group.dynamic_ref_table.mAssignedPackageId)
+ package_group.dynamic_ref_table->mAssignedPackageId)
<< list;
for (size_t i = 0; i < 256; i++) {
- if (package_group.dynamic_ref_table.mLookupTable[i] != 0) {
+ if (package_group.dynamic_ref_table->mLookupTable[i] != 0) {
LOG(INFO) << base::StringPrintf(" e[0x%02x] -> 0x%02x", (uint8_t) i,
- package_group.dynamic_ref_table.mLookupTable[i]);
+ package_group.dynamic_ref_table->mLookupTable[i]);
}
}
}
@@ -195,14 +239,15 @@ const DynamicRefTable* AssetManager2::GetDynamicRefTableForPackage(uint32_t pack
if (idx == 0xff) {
return nullptr;
}
- return &package_groups_[idx].dynamic_ref_table;
+ return package_groups_[idx].dynamic_ref_table.get();
}
-const DynamicRefTable* AssetManager2::GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const {
+std::shared_ptr<const DynamicRefTable> AssetManager2::GetDynamicRefTableForCookie(
+ ApkAssetsCookie cookie) const {
for (const PackageGroup& package_group : package_groups_) {
for (const ApkAssetsCookie& package_cookie : package_group.cookies_) {
if (package_cookie == cookie) {
- return &package_group.dynamic_ref_table;
+ return package_group.dynamic_ref_table;
}
}
}
@@ -230,6 +275,67 @@ const std::unordered_map<std::string, std::string>*
return &loaded_package->GetOverlayableMap();
}
+bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_name,
+ std::string* out) const {
+ uint8_t package_id = 0U;
+ for (const auto& apk_assets : apk_assets_) {
+ const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
+ if (loaded_arsc == nullptr) {
+ continue;
+ }
+
+ const auto& loaded_packages = loaded_arsc->GetPackages();
+ if (loaded_packages.empty()) {
+ continue;
+ }
+
+ const auto& loaded_package = loaded_packages[0];
+ if (loaded_package->GetPackageName() == package_name) {
+ package_id = GetAssignedPackageId(loaded_package.get());
+ break;
+ }
+ }
+
+ if (package_id == 0U) {
+ ANDROID_LOG(ERROR) << base::StringPrintf("No package with name '%s", package_name.data());
+ return false;
+ }
+
+ const size_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
+ return false;
+ }
+
+ std::string output;
+ for (const ConfiguredPackage& package : package_groups_[idx].packages_) {
+ const LoadedPackage* loaded_package = package.loaded_package_;
+ for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) {
+ const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it);
+ if (info != nullptr) {
+ ResourceName res_name;
+ if (!GetResourceName(*it, &res_name)) {
+ ANDROID_LOG(ERROR) << base::StringPrintf(
+ "Unable to retrieve name of overlayable resource 0x%08x", *it);
+ return false;
+ }
+
+ const std::string name = ToFormattedResourceString(&res_name);
+ output.append(base::StringPrintf(
+ "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
+ name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
+ }
+ }
+ }
+
+ *out = std::move(output);
+ return true;
+}
+
+bool AssetManager2::ContainsAllocatedTable() const {
+ return std::find_if(apk_assets_.begin(), apk_assets_.end(),
+ std::mem_fn(&ApkAssets::IsTableAllocated)) != apk_assets_.end();
+}
+
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
const int diff = configuration_.diff(configuration);
configuration_ = configuration;
@@ -240,21 +346,45 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
}
}
+std::set<std::string> AssetManager2::GetNonSystemOverlayPaths() const {
+ std::set<std::string> non_system_overlays;
+ for (const PackageGroup& package_group : package_groups_) {
+ bool found_system_package = false;
+ for (const ConfiguredPackage& package : package_group.packages_) {
+ if (package.loaded_package_->IsSystem()) {
+ found_system_package = true;
+ break;
+ }
+ }
+
+ if (!found_system_package) {
+ for (const ConfiguredOverlay& overlay : package_group.overlays_) {
+ non_system_overlays.insert(apk_assets_[overlay.cookie]->GetPath());
+ }
+ }
+ }
+
+ return non_system_overlays;
+}
+
std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
bool exclude_mipmap) const {
ATRACE_NAME("AssetManager::GetResourceConfigurations");
+ const auto non_system_overlays =
+ (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
+
std::set<ResTable_config> configurations;
for (const PackageGroup& package_group : package_groups_) {
- bool found_system_package = false;
- for (const ConfiguredPackage& package : package_group.packages_) {
+ for (size_t i = 0; i < package_group.packages_.size(); i++) {
+ const ConfiguredPackage& package = package_group.packages_[i];
if (exclude_system && package.loaded_package_->IsSystem()) {
- found_system_package = true;
continue;
}
- if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) {
- // Overlays must appear after the target package to take effect. Any overlay found in the
- // same package as a system package is able to overlay system resources.
+ auto apk_assets = apk_assets_[package_group.cookies_[i]];
+ if (exclude_system && apk_assets->IsOverlay()
+ && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) {
+ // Exclude overlays that target system resources.
continue;
}
@@ -268,17 +398,20 @@ std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
bool merge_equivalent_languages) const {
ATRACE_NAME("AssetManager::GetResourceLocales");
std::set<std::string> locales;
+ const auto non_system_overlays =
+ (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
+
for (const PackageGroup& package_group : package_groups_) {
- bool found_system_package = false;
- for (const ConfiguredPackage& package : package_group.packages_) {
+ for (size_t i = 0; i < package_group.packages_.size(); i++) {
+ const ConfiguredPackage& package = package_group.packages_[i];
if (exclude_system && package.loaded_package_->IsSystem()) {
- found_system_package = true;
continue;
}
- if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) {
- // Overlays must appear after the target package to take effect. Any overlay found in the
- // same package as a system package is able to overlay system resources.
+ auto apk_assets = apk_assets_[package_group.cookies_[i]];
+ if (exclude_system && apk_assets->IsOverlay()
+ && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) {
+ // Exclude overlays that target system resources.
continue;
}
@@ -322,7 +455,7 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con
files->add(info);
};
- if (!apk_assets->ForEachFile(full_path, func)) {
+ if (!apk_assets->GetAssetsProvider()->ForEachFile(full_path, func)) {
return {};
}
}
@@ -346,7 +479,7 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
continue;
}
- std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
+ std::unique_ptr<Asset> asset = apk_assets_[i]->GetAssetsProvider()->Open(filename, mode);
if (asset) {
if (out_cookie != nullptr) {
*out_cookie = i;
@@ -367,13 +500,19 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return {};
}
- return apk_assets_[cookie]->Open(filename, mode);
+ return apk_assets_[cookie]->GetAssetsProvider()->Open(filename, mode);
}
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
bool /*stop_at_first_match*/,
bool ignore_configuration,
FindEntryResult* out_entry) const {
+ if (resource_resolution_logging_enabled_) {
+ // Clear the last logged resource resolution.
+ ResetResourceResolution();
+ last_resolution_.resid = resid;
+ }
+
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -385,6 +524,7 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
desired_config = &density_override_config;
}
+ // Retrieve the package group from the package id of the resource id.
if (!is_valid_resid(resid)) {
LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
return kInvalidCookie;
@@ -393,8 +533,7 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
const uint32_t package_id = get_package_id(resid);
const uint8_t type_idx = get_type_id(resid) - 1;
const uint16_t entry_idx = get_entry_id(resid);
-
- const uint8_t package_idx = package_ids_[package_id];
+ uint8_t package_idx = package_ids_[package_id];
if (package_idx == 0xff) {
ANDROID_LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
package_id, resid);
@@ -402,8 +541,71 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
}
const PackageGroup& package_group = package_groups_[package_idx];
- const size_t package_count = package_group.packages_.size();
+ ApkAssetsCookie cookie = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
+ false /* stop_at_first_match */,
+ ignore_configuration, out_entry);
+ if (UNLIKELY(cookie == kInvalidCookie)) {
+ return kInvalidCookie;
+ }
+
+ if (!apk_assets_[cookie]->IsLoader()) {
+ for (const auto& id_map : package_group.overlays_) {
+ auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
+ if (!overlay_entry) {
+ // No id map entry exists for this target resource.
+ continue;
+ }
+
+ if (overlay_entry.IsTableEntry()) {
+ // The target resource is overlaid by an inline value not represented by a resource.
+ out_entry->entry = overlay_entry.GetTableEntry();
+ out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+ cookie = id_map.cookie;
+ continue;
+ }
+
+ FindEntryResult overlay_result;
+ ApkAssetsCookie overlay_cookie = FindEntry(overlay_entry.GetResourceId(), density_override,
+ false /* stop_at_first_match */,
+ ignore_configuration, &overlay_result);
+ if (UNLIKELY(overlay_cookie == kInvalidCookie)) {
+ continue;
+ }
+
+ if (!overlay_result.config.isBetterThan(out_entry->config, desired_config)
+ && overlay_result.config.compare(out_entry->config) != 0) {
+ // The configuration of the entry for the overlay must be equal to or better than the target
+ // configuration to be chosen as the better value.
+ continue;
+ }
+
+ cookie = overlay_cookie;
+ out_entry->entry = std::move(overlay_result.entry);
+ out_entry->config = overlay_result.config;
+ out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+ if (resource_resolution_logging_enabled_) {
+ last_resolution_.steps.push_back(
+ Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result.config.toString(),
+ overlay_result.package_name});
+ }
+ }
+ }
+ if (resource_resolution_logging_enabled_) {
+ last_resolution_.cookie = cookie;
+ last_resolution_.type_string_ref = out_entry->type_string_ref;
+ last_resolution_.entry_string_ref = out_entry->entry_string_ref;
+ }
+
+ return cookie;
+}
+
+ApkAssetsCookie AssetManager2::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,
+ FindEntryResult* out_entry) const {
ApkAssetsCookie best_cookie = kInvalidCookie;
const LoadedPackage* best_package = nullptr;
const ResTable_type* best_type = nullptr;
@@ -412,13 +614,14 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
uint32_t best_offset = 0u;
uint32_t type_flags = 0u;
- Resolution::Step::Type resolution_type;
+ Resolution::Step::Type resolution_type = Resolution::Step::Type::NO_ENTRY;
std::vector<Resolution::Step> resolution_steps;
// If desired_config is the same as the set configuration, then we can use our filtered list
// and we don't need to match the configurations, since they already matched.
- const bool use_fast_path = !ignore_configuration && desired_config == &configuration_;
+ const bool use_fast_path = !ignore_configuration && &desired_config == &configuration_;
+ const size_t package_count = package_group.packages_.size();
for (size_t pi = 0; pi < package_count; pi++) {
const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
@@ -431,20 +634,10 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
continue;
}
- uint16_t local_entry_idx = entry_idx;
-
- // If there is an IDMAP supplied with this package, translate the entry ID.
- if (type_spec->idmap_entries != nullptr) {
- if (!LoadedIdmap::Lookup(type_spec->idmap_entries, local_entry_idx, &local_entry_idx)) {
- // There is no mapping, so the resource is not meant to be in this overlay package.
- continue;
- }
- }
-
- type_flags |= type_spec->GetFlagsForEntryIndex(local_entry_idx);
-
- // If the package is an overlay, then even configurations that are the same MUST be chosen.
- const bool package_is_overlay = loaded_package->IsOverlay();
+ // If the package is an overlay or custom loader,
+ // then even configurations that are the same MUST be chosen.
+ const bool package_is_loader = loaded_package->IsCustomLoader();
+ type_flags |= type_spec->GetFlagsForEntryIndex(entry_idx);
if (use_fast_path) {
const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
@@ -457,19 +650,37 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// configurations that do NOT match have been filtered-out.
if (best_config == nullptr) {
resolution_type = Resolution::Step::Type::INITIAL;
- } else if (this_config.isBetterThan(*best_config, desired_config)) {
- resolution_type = Resolution::Step::Type::BETTER_MATCH;
- } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
- resolution_type = Resolution::Step::Type::OVERLAID;
+ } else if (this_config.isBetterThan(*best_config, &desired_config)) {
+ resolution_type = (package_is_loader) ? Resolution::Step::Type::BETTER_MATCH_LOADER
+ : Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_loader && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID_LOADER;
} else {
+ if (resource_resolution_logging_enabled_) {
+ resolution_type = (package_is_loader) ? Resolution::Step::Type::SKIPPED_LOADER
+ : Resolution::Step::Type::SKIPPED;
+ resolution_steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
+ }
continue;
}
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
const ResTable_type* type = filtered_group.types[i];
- const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx);
+ const uint32_t offset = LoadedPackage::GetEntryOffset(type, entry_idx);
if (offset == ResTable_type::NO_ENTRY) {
+ if (resource_resolution_logging_enabled_) {
+ if (package_is_loader) {
+ resolution_type = Resolution::Step::Type::NO_ENTRY_LOADER;
+ } else {
+ resolution_type = Resolution::Step::Type::NO_ENTRY;
+ }
+ resolution_steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
+ }
continue;
}
@@ -480,9 +691,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
best_offset = offset;
if (resource_resolution_logging_enabled_) {
- resolution_steps.push_back(Resolution::Step{resolution_type,
- this_config.toString(),
- &loaded_package->GetPackageName()});
+ last_resolution_.steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
}
}
} else {
@@ -497,16 +708,17 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
if (!ignore_configuration) {
this_config.copyFromDtoH((*iter)->config);
- if (!this_config.match(*desired_config)) {
+ if (!this_config.match(desired_config)) {
continue;
}
if (best_config == nullptr) {
resolution_type = Resolution::Step::Type::INITIAL;
- } else if (this_config.isBetterThan(*best_config, desired_config)) {
- resolution_type = Resolution::Step::Type::BETTER_MATCH;
- } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
- resolution_type = Resolution::Step::Type::OVERLAID;
+ } else if (this_config.isBetterThan(*best_config, &desired_config)) {
+ resolution_type = (package_is_loader) ? Resolution::Step::Type::BETTER_MATCH_LOADER
+ : Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_loader && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID_LOADER;
} else {
continue;
}
@@ -514,7 +726,7 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
- const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
+ const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, entry_idx);
if (offset == ResTable_type::NO_ENTRY) {
continue;
}
@@ -532,9 +744,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
}
if (resource_resolution_logging_enabled_) {
- resolution_steps.push_back(Resolution::Step{resolution_type,
- this_config.toString(),
- &loaded_package->GetPackageName()});
+ last_resolution_.steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
}
}
}
@@ -549,38 +761,30 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
return kInvalidCookie;
}
- out_entry->entry = best_entry;
+ out_entry->entry = ResTable_entry_handle::unmanaged(best_entry);
out_entry->config = *best_config;
out_entry->type_flags = type_flags;
+ out_entry->package_name = &best_package->GetPackageName();
out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
out_entry->entry_string_ref =
- StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
- out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
-
- if (resource_resolution_logging_enabled_) {
- last_resolution.resid = resid;
- last_resolution.cookie = best_cookie;
- last_resolution.steps = resolution_steps;
-
- // Cache only the type/entry refs since that's all that's needed to build name
- last_resolution.type_string_ref =
- StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
- last_resolution.entry_string_ref =
- StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
- }
+ StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+ out_entry->dynamic_ref_table = package_group.dynamic_ref_table.get();
return best_cookie;
}
+void AssetManager2::ResetResourceResolution() const {
+ last_resolution_.cookie = kInvalidCookie;
+ last_resolution_.resid = 0;
+ last_resolution_.steps.clear();
+ last_resolution_.type_string_ref = StringPoolRef();
+ last_resolution_.entry_string_ref = StringPoolRef();
+}
+
void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
resource_resolution_logging_enabled_ = enabled;
-
if (!enabled) {
- last_resolution.cookie = kInvalidCookie;
- last_resolution.resid = 0;
- last_resolution.steps.clear();
- last_resolution.type_string_ref = StringPoolRef();
- last_resolution.entry_string_ref = StringPoolRef();
+ ResetResourceResolution();
}
}
@@ -590,24 +794,24 @@ std::string AssetManager2::GetLastResourceResolution() const {
return std::string();
}
- auto cookie = last_resolution.cookie;
+ auto cookie = last_resolution_.cookie;
if (cookie == kInvalidCookie) {
LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
return std::string();
}
- uint32_t resid = last_resolution.resid;
- std::vector<Resolution::Step>& steps = last_resolution.steps;
+ uint32_t resid = last_resolution_.resid;
+ std::vector<Resolution::Step>& steps = last_resolution_.steps;
ResourceName resource_name;
std::string resource_name_string;
const LoadedPackage* package =
- apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+ apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
if (package != nullptr) {
- ToResourceName(last_resolution.type_string_ref,
- last_resolution.entry_string_ref,
+ ToResourceName(last_resolution_.type_string_ref,
+ last_resolution_.entry_string_ref,
package->GetPackageName(),
&resource_name);
resource_name_string = ToFormattedResourceString(&resource_name);
@@ -628,9 +832,27 @@ std::string AssetManager2::GetLastResourceResolution() const {
case Resolution::Step::Type::BETTER_MATCH:
prefix = "Found better";
break;
+ case Resolution::Step::Type::BETTER_MATCH_LOADER:
+ prefix = "Found better in loader";
+ break;
case Resolution::Step::Type::OVERLAID:
prefix = "Overlaid";
break;
+ case Resolution::Step::Type::OVERLAID_LOADER:
+ prefix = "Overlaid by loader";
+ break;
+ case Resolution::Step::Type::SKIPPED:
+ prefix = "Skipped";
+ break;
+ case Resolution::Step::Type::SKIPPED_LOADER:
+ prefix = "Skipped loader";
+ break;
+ case Resolution::Step::Type::NO_ENTRY:
+ prefix = "No entry";
+ break;
+ case Resolution::Step::Type::NO_ENTRY_LOADER:
+ prefix = "No entry for loader";
+ break;
}
if (!prefix.empty()) {
@@ -654,25 +876,9 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons
return false;
}
- const uint8_t package_idx = package_ids_[get_package_id(resid)];
- if (package_idx == 0xff) {
- LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
- get_package_id(resid), resid);
- return false;
- }
-
- const PackageGroup& package_group = package_groups_[package_idx];
- auto cookie_iter = std::find(package_group.cookies_.begin(),
- package_group.cookies_.end(), cookie);
- if (cookie_iter == package_group.cookies_.end()) {
- return false;
- }
-
- long package_pos = std::distance(package_group.cookies_.begin(), cookie_iter);
- const LoadedPackage* package = package_group.packages_[package_pos].loaded_package_;
return ToResourceName(entry.type_string_ref,
entry.entry_string_ref,
- package->GetPackageName(),
+ *entry.package_name,
out_name);
}
@@ -699,7 +905,8 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
return kInvalidCookie;
}
- if (dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
+ const ResTable_entry* table_entry = *entry.entry;
+ if (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX) {
if (!may_be_bag) {
LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
return kInvalidCookie;
@@ -714,7 +921,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
}
const Res_value* device_value = reinterpret_cast<const Res_value*>(
- reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
+ reinterpret_cast<const uint8_t*>(table_entry) + dtohs(table_entry->size));
out_value->copyFrom_dtoh(*device_value);
// Convert the package ID to the runtime assigned package ID.
@@ -777,6 +984,11 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
return bag;
}
+static bool compare_bag_entries(const ResolvedBag::Entry& entry1,
+ const ResolvedBag::Entry& entry2) {
+ return entry1.key < entry2.key;
+}
+
const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
auto cached_iter = cached_bags_.find(resid);
if (cached_iter != cached_bags_.end()) {
@@ -795,13 +1007,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
// Check that the size of the entry header is at least as big as
// the desired ResTable_map_entry. Also verify that the entry
// was intended to be a map.
- if (dtohs(entry.entry->size) < sizeof(ResTable_map_entry) ||
- (dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) == 0) {
+ const ResTable_entry* table_entry = *entry.entry;
+ if (dtohs(table_entry->size) < sizeof(ResTable_map_entry) ||
+ (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX) == 0) {
// Not a bag, nothing to do.
return nullptr;
}
- const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry.entry);
+ const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(table_entry);
const ResTable_map* map_entry =
reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size);
const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
@@ -811,13 +1024,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
child_resids.push_back(resid);
uint32_t parent_resid = dtohl(map->parent.ident);
- if (parent_resid == 0 || std::find(child_resids.begin(), child_resids.end(), parent_resid)
+ if (parent_resid == 0U || std::find(child_resids.begin(), child_resids.end(), parent_resid)
!= child_resids.end()) {
- // There is no parent or that a circular dependency exist, meaning there is nothing to
- // inherit and we can do a simple copy of the entries in the map.
+ // There is no parent or a circular dependency exist, meaning there is nothing to inherit and
+ // we can do a simple copy of the entries in the map.
const size_t entry_count = map_entry_end - map_entry;
util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
+
+ bool sort_entries = false;
ResolvedBag::Entry* new_entry = new_bag->entries;
for (; map_entry != map_entry_end; ++map_entry) {
uint32_t new_key = dtohl(map_entry->name.ident);
@@ -843,8 +1058,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
new_entry->value.data, new_key);
return nullptr;
}
+ sort_entries = sort_entries ||
+ (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
++new_entry;
}
+
+ if (sort_entries) {
+ std::sort(new_bag->entries, new_bag->entries + entry_count, compare_bag_entries);
+ }
+
new_bag->type_spec_flags = entry.type_flags;
new_bag->entry_count = static_cast<uint32_t>(entry_count);
ResolvedBag* result = new_bag.get();
@@ -875,6 +1097,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count;
// The keys are expected to be in sorted order. Merge the two bags.
+ bool sort_entries = false;
while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
uint32_t child_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(child_key)) {
@@ -907,6 +1130,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
memcpy(new_entry, parent_entry, sizeof(*new_entry));
}
+ sort_entries = sort_entries ||
+ (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
if (child_key >= parent_entry->key) {
// Move to the next parent entry if we used it or it was overridden.
++parent_entry;
@@ -937,6 +1162,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
new_entry->value.dataType, new_entry->value.data, new_key);
return nullptr;
}
+ sort_entries = sort_entries ||
+ (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
++map_entry;
++new_entry;
}
@@ -956,6 +1183,10 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))));
}
+ if (sort_entries) {
+ std::sort(new_bag->entries, new_bag->entries + actual_count, compare_bag_entries);
+ }
+
// Combine flags from the parent and our own bag.
new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags;
new_bag->entry_count = static_cast<uint32_t>(actual_count);
@@ -1026,7 +1257,7 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
}
if (resid != 0u) {
- return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId);
+ return fix_package_id(resid, package_group.dynamic_ref_table->mAssignedPackageId);
}
}
}
@@ -1079,11 +1310,11 @@ void AssetManager2::InvalidateCaches(uint32_t diff) {
}
}
-uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
+uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
for (auto& package_group : package_groups_) {
for (auto& package2 : package_group.packages_) {
if (package2.loaded_package_ == package) {
- return package_group.dynamic_ref_table.mAssignedPackageId;
+ return package_group.dynamic_ref_table->mAssignedPackageId;
}
}
}