diff options
Diffstat (limited to 'libs')
20 files changed, 610 insertions, 1068 deletions
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 70d52164ff74..251b2e773cfb 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -145,7 +145,6 @@ cc_test { "tests/TypeWrappers_test.cpp", "tests/ZipUtils_test.cpp", ], - static_libs: ["libgmock"], target: { android: { srcs: [ @@ -172,7 +171,6 @@ cc_benchmark { // Actual benchmarks. "tests/AssetManager2_bench.cpp", - "tests/AttributeResolution_bench.cpp", "tests/SparseEntry_bench.cpp", "tests/Theme_bench.cpp", ], diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index a558ff7ccfc1..415d3e36adf9 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -36,31 +36,6 @@ 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; - - // The configuration for which the resulting entry was defined. This is already swapped to host - // endianness. - ResTable_config config; - - // The bitmask of configuration axis with which the resource value varies. - uint32_t type_flags; - - // The dynamic package ID map for the package from which this resource came from. - const DynamicRefTable* dynamic_ref_table; - - // 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; - - // The string pool reference to the entry's name. This uses a different string pool than - // the global string pool, but this is hidden from the caller. - StringPoolRef entry_string_ref; -}; - AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } @@ -69,7 +44,6 @@ bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets bool invalidate_caches) { apk_assets_ = apk_assets; BuildDynamicRefTable(); - RebuildFilterList(); if (invalidate_caches) { InvalidateCaches(static_cast<uint32_t>(-1)); } @@ -105,7 +79,7 @@ void AssetManager2::BuildDynamicRefTable() { 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->packages_.push_back(package.get()); package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i)); // Add the package name -> build time ID mappings. @@ -120,7 +94,7 @@ void AssetManager2::BuildDynamicRefTable() { // Now assign the runtime IDs so that we have a build-time to runtime ID map. const auto package_groups_end = package_groups_.end(); for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) { - const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName(); + const std::string& package_name = iter->packages_[0]->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); @@ -134,20 +108,17 @@ void AssetManager2::DumpToLog() const { std::string list; for (size_t i = 0; i < package_ids_.size(); i++) { if (package_ids_[i] != 0xff) { - base::StringAppendF(&list, "%02x -> %d, ", (int)i, package_ids_[i]); + base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]); } } LOG(INFO) << "Package ID map: " << list; - for (const auto& package_group : package_groups_) { - list = ""; - for (const auto& package : package_group.packages_) { - base::StringAppendF(&list, "%s(%02x), ", package.loaded_package_->GetPackageName().c_str(), - package.loaded_package_->GetPackageId()); - } - LOG(INFO) << base::StringPrintf("PG (%02x): ", - package_group.dynamic_ref_table.mAssignedPackageId) - << list; + for (const auto& package_group: package_groups_) { + list = ""; + for (const auto& package : package_group.packages_) { + base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId()); + } + LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list; } } @@ -186,54 +157,52 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) { configuration_ = configuration; if (diff) { - RebuildFilterList(); InvalidateCaches(static_cast<uint32_t>(diff)); } } std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system, - bool exclude_mipmap) const { + bool exclude_mipmap) { ATRACE_CALL(); std::set<ResTable_config> configurations; for (const PackageGroup& package_group : package_groups_) { - for (const ConfiguredPackage& package : package_group.packages_) { - if (exclude_system && package.loaded_package_->IsSystem()) { + for (const LoadedPackage* package : package_group.packages_) { + if (exclude_system && package->IsSystem()) { continue; } - package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations); + package->CollectConfigurations(exclude_mipmap, &configurations); } } return configurations; } std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system, - bool merge_equivalent_languages) const { + bool merge_equivalent_languages) { ATRACE_CALL(); std::set<std::string> locales; for (const PackageGroup& package_group : package_groups_) { - for (const ConfiguredPackage& package : package_group.packages_) { - if (exclude_system && package.loaded_package_->IsSystem()) { + for (const LoadedPackage* package : package_group.packages_) { + if (exclude_system && package->IsSystem()) { continue; } - package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales); + package->CollectLocales(merge_equivalent_languages, &locales); } } return locales; } -std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, - Asset::AccessMode mode) const { +std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) { const std::string new_path = "assets/" + filename; return OpenNonAsset(new_path, mode); } std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie, - Asset::AccessMode mode) const { + Asset::AccessMode mode) { const std::string new_path = "assets/" + filename; return OpenNonAsset(new_path, cookie, mode); } -std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const { +std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) { ATRACE_CALL(); std::string full_path = "assets/" + dirname; @@ -267,7 +236,7 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con // is inconsistent for split APKs. std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, Asset::AccessMode mode, - ApkAssetsCookie* out_cookie) const { + ApkAssetsCookie* out_cookie) { ATRACE_CALL(); for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) { std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode); @@ -286,8 +255,7 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, } std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, - ApkAssetsCookie cookie, - Asset::AccessMode mode) const { + ApkAssetsCookie cookie, Asset::AccessMode mode) { ATRACE_CALL(); if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) { return {}; @@ -296,13 +264,14 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, } ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override, - bool /*stop_at_first_match*/, - FindEntryResult* out_entry) const { + bool stop_at_first_match, FindEntryResult* out_entry) { + ATRACE_CALL(); + // Might use this if density_override != 0. ResTable_config density_override_config; // Select our configuration or generate a density override configuration. - const ResTable_config* desired_config = &configuration_; + ResTable_config* desired_config = &configuration_; if (density_override != 0 && density_override != configuration_.density) { density_override_config = configuration_; density_override_config.density = density_override; @@ -316,135 +285,53 @@ 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 uint16_t entry_id = get_entry_id(resid); - const uint8_t package_idx = package_ids_[package_id]; - if (package_idx == 0xff) { + const uint8_t idx = package_ids_[package_id]; + if (idx == 0xff) { LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid); return kInvalidCookie; } - const PackageGroup& package_group = package_groups_[package_idx]; - const size_t package_count = package_group.packages_.size(); - + FindEntryResult best_entry; ApkAssetsCookie best_cookie = kInvalidCookie; - const LoadedPackage* best_package = nullptr; - const ResTable_type* best_type = nullptr; - const ResTable_config* best_config = nullptr; - ResTable_config best_config_copy; - uint32_t best_offset = 0u; - uint32_t type_flags = 0u; - - // 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 = desired_config == &configuration_; - - 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_; - ApkAssetsCookie cookie = package_group.cookies_[pi]; - - // If the type IDs are offset in this package, we need to take that into account when searching - // for a type. - const TypeSpec* type_spec = loaded_package->GetTypeSpecByTypeIndex(type_idx); - if (UNLIKELY(type_spec == nullptr)) { + uint32_t cumulated_flags = 0u; + + const PackageGroup& package_group = package_groups_[idx]; + const size_t package_count = package_group.packages_.size(); + FindEntryResult current_entry; + for (size_t i = 0; i < package_count; i++) { + const LoadedPackage* loaded_package = package_group.packages_[i]; + if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, ¤t_entry)) { continue; } - uint16_t local_entry_idx = entry_idx; + cumulated_flags |= current_entry.type_flags; - // 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(); - - const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; - if (use_fast_path) { - const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations; - const size_t type_count = candidate_configs.size(); - for (uint32_t i = 0; i < type_count; i++) { - const ResTable_config& this_config = candidate_configs[i]; - - // We can skip calling ResTable_config::match() because we know that all candidate - // configurations that do NOT match have been filtered-out. - if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || - (package_is_overlay && this_config.compare(*best_config) == 0)) { - // The configuration matches and is better than the previous selection. - // Find the entry value if it exists for this configuration. - const ResTable_type* type_chunk = filtered_group.types[i]; - const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx); - if (offset == ResTable_type::NO_ENTRY) { - continue; - } - - best_cookie = cookie; - best_package = loaded_package; - best_type = type_chunk; - best_config = &this_config; - best_offset = offset; - } - } - } else { - // This is the slower path, which doesn't use the filtered list of configurations. - // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness - // and fill in any new fields that did not exist when the APK was compiled. - // Furthermore when selecting configurations we can't just record the pointer to the - // ResTable_config, we must copy it. - const auto iter_end = type_spec->types + type_spec->type_count; - for (auto iter = type_spec->types; iter != iter_end; ++iter) { - ResTable_config this_config; - this_config.copyFromDtoH((*iter)->config); - - if (this_config.match(*desired_config)) { - if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || - (package_is_overlay && this_config.compare(*best_config) == 0)) { - // 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); - if (offset == ResTable_type::NO_ENTRY) { - continue; - } - - best_cookie = cookie; - best_package = loaded_package; - best_type = *iter; - best_config_copy = this_config; - best_config = &best_config_copy; - best_offset = offset; - } - } + const ResTable_config* current_config = current_entry.config; + const ResTable_config* best_config = best_entry.config; + if (best_cookie == kInvalidCookie || + current_config->isBetterThan(*best_config, desired_config) || + (loaded_package->IsOverlay() && current_config->compare(*best_config) == 0)) { + best_entry = current_entry; + best_cookie = package_group.cookies_[i]; + if (stop_at_first_match) { + break; } } } - if (UNLIKELY(best_cookie == kInvalidCookie)) { + if (best_cookie == kInvalidCookie) { return kInvalidCookie; } - const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset); - if (UNLIKELY(best_entry == nullptr)) { - return kInvalidCookie; - } - - out_entry->entry = best_entry; - out_entry->config = *best_config; - out_entry->type_flags = type_flags; - 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 = best_entry; out_entry->dynamic_ref_table = &package_group.dynamic_ref_table; + out_entry->type_flags = cumulated_flags; return best_cookie; } -bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { +bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) { ATRACE_CALL(); FindEntryResult entry; @@ -454,8 +341,7 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons return false; } - const LoadedPackage* package = - apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); + const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid); if (package == nullptr) { return false; } @@ -483,7 +369,7 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons return true; } -bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const { +bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) { FindEntryResult entry; ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry); @@ -497,7 +383,7 @@ bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override, Res_value* out_value, ResTable_config* out_selected_config, - uint32_t* out_flags) const { + uint32_t* out_flags) { ATRACE_CALL(); FindEntryResult entry; @@ -516,7 +402,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, // Create a reference since we can't represent this complex type as a Res_value. out_value->dataType = Res_value::TYPE_REFERENCE; out_value->data = resid; - *out_selected_config = entry.config; + *out_selected_config = *entry.config; *out_flags = entry.type_flags; return cookie; } @@ -528,7 +414,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, // Convert the package ID to the runtime assigned package ID. entry.dynamic_ref_table->lookupResourceValue(out_value); - *out_selected_config = entry.config; + *out_selected_config = *entry.config; *out_flags = entry.type_flags; return cookie; } @@ -536,14 +422,16 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value, ResTable_config* in_out_selected_config, uint32_t* in_out_flags, - uint32_t* out_last_reference) const { + uint32_t* out_last_reference) { ATRACE_CALL(); constexpr const int kMaxIterations = 20; for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE && in_out_value->data != 0u && iteration < kMaxIterations; iteration++) { - *out_last_reference = in_out_value->data; + if (out_last_reference != nullptr) { + *out_last_reference = in_out_value->data; + } uint32_t new_flags = 0u; cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/, in_out_value, in_out_selected_config, &new_flags); @@ -604,8 +492,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Attributes, arrays, etc don't have a resource id as the name. They specify // other data, which would be wrong to change via a lookup. if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { - LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, - resid); + LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid); return nullptr; } } @@ -637,8 +524,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { const ResolvedBag* parent_bag = GetBag(parent_resid); if (parent_bag == nullptr) { // Failed to get the parent that should exist. - LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, - resid); + LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, resid); return nullptr; } @@ -657,8 +543,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { uint32_t child_key = dtohl(map_entry->name.ident); if (!is_internal_resid(child_key)) { if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) { - LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, - resid); + LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid); return nullptr; } } @@ -697,8 +582,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { uint32_t new_key = dtohl(map_entry->name.ident); if (!is_internal_resid(new_key)) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { - LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, - resid); + LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid); return nullptr; } } @@ -754,7 +638,7 @@ static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) { uint32_t AssetManager2::GetResourceId(const std::string& resource_name, const std::string& fallback_type, - const std::string& fallback_package) const { + const std::string& fallback_package) { StringPiece package_name, type, entry; if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) { return 0u; @@ -786,8 +670,7 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name, const static std::u16string kAttrPrivate16 = u"^attr-private"; for (const PackageGroup& package_group : package_groups_) { - for (const ConfiguredPackage& package_impl : package_group.packages_) { - const LoadedPackage* package = package_impl.loaded_package_; + for (const LoadedPackage* package : package_group.packages_) { if (package_name != package->GetPackageName()) { // All packages in the same group are expected to have the same package name. break; @@ -809,32 +692,6 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name, return 0u; } -void AssetManager2::RebuildFilterList() { - for (PackageGroup& group : package_groups_) { - for (ConfiguredPackage& impl : group.packages_) { - // Destroy it. - impl.filtered_configs_.~ByteBucketArray(); - - // Re-create it. - new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>(); - - // Create the filters here. - impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec* spec, uint8_t type_index) { - FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_index); - const auto iter_end = spec->types + spec->type_count; - for (auto iter = spec->types; iter != iter_end; ++iter) { - ResTable_config this_config; - this_config.copyFromDtoH((*iter)->config); - if (this_config.match(configuration_)) { - group.configurations.push_back(this_config); - group.types.push_back(*iter); - } - } - }); - } - } -} - void AssetManager2::InvalidateCaches(uint32_t diff) { if (diff == 0xffffffffu) { // Everything must go. @@ -1015,7 +872,7 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value, ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value, ResTable_config* in_out_selected_config, uint32_t* in_out_type_spec_flags, - uint32_t* out_last_ref) const { + uint32_t* out_last_ref) { if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) { uint32_t new_flags; cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags); diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp index f912af4f7190..60e3845d98a9 100644 --- a/libs/androidfw/AttributeResolution.cpp +++ b/libs/androidfw/AttributeResolution.cpp @@ -20,18 +20,13 @@ #include <log/log.h> -#include "androidfw/AssetManager2.h" #include "androidfw/AttributeFinder.h" +#include "androidfw/ResourceTypes.h" constexpr bool kDebugStyles = false; namespace android { -// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0. -static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) { - return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1); -} - class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> { public: @@ -49,53 +44,58 @@ class XmlAttributeFinder }; class BagAttributeFinder - : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> { + : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { public: - BagAttributeFinder(const ResolvedBag* bag) - : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr, - bag != nullptr ? bag->entries + bag->entry_count : nullptr) { - } + BagAttributeFinder(const ResTable::bag_entry* start, + const ResTable::bag_entry* end) + : BackTrackingAttributeFinder(start, end) {} - inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const { - return entry->key; + inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const { + return entry->map.name.ident; } }; -bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, - uint32_t* src_values, size_t src_values_length, uint32_t* attrs, - size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) { +bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, + uint32_t def_style_res, uint32_t* src_values, + size_t src_values_length, uint32_t* attrs, + size_t attrs_length, uint32_t* out_values, + uint32_t* out_indices) { if (kDebugStyles) { ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, def_style_attr, def_style_res); } - AssetManager2* assetmanager = theme->GetAssetManager(); + const ResTable& res = theme->getResTable(); ResTable_config config; Res_value value; int indices_idx = 0; // Load default style from attribute, if specified... - uint32_t def_style_flags = 0u; + uint32_t def_style_bag_type_set_flags = 0; if (def_style_attr != 0) { Res_value value; - if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) { + if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { if (value.dataType == Res_value::TYPE_REFERENCE) { def_style_res = value.data; } } } - // Retrieve the default style bag, if requested. - const ResolvedBag* default_style_bag = nullptr; - if (def_style_res != 0) { - default_style_bag = assetmanager->GetBag(def_style_res); - if (default_style_bag != nullptr) { - def_style_flags |= default_style_bag->type_spec_flags; - } - } + // Now lock down the resource object and start pulling stuff from it. + res.lock(); - BagAttributeFinder def_style_attr_finder(default_style_bag); + // Retrieve the default style bag, if requested. + const ResTable::bag_entry* def_style_start = nullptr; + uint32_t def_style_type_set_flags = 0; + ssize_t bag_off = def_style_res != 0 + ? res.getBagLocked(def_style_res, &def_style_start, + &def_style_type_set_flags) + : -1; + def_style_type_set_flags |= def_style_bag_type_set_flags; + const ResTable::bag_entry* const def_style_end = + def_style_start + (bag_off >= 0 ? bag_off : 0); + BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end); // Now iterate through all of the attributes that the client has requested, // filling in each with whatever data we can find. @@ -106,7 +106,7 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident); } - ApkAssetsCookie cookie = kInvalidCookie; + ssize_t block = -1; uint32_t type_set_flags = 0; value.dataType = Res_value::TYPE_NULL; @@ -122,14 +122,15 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, value.dataType = Res_value::TYPE_ATTRIBUTE; value.data = src_values[ii]; if (kDebugStyles) { - ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data); + ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, + value.data); } } else { - const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident); - if (entry != def_style_attr_finder.end()) { - cookie = entry->cookie; - type_set_flags = def_style_flags; - value = entry->value; + const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); + if (def_style_entry != def_style_end) { + block = def_style_entry->stringBlock; + type_set_flags = def_style_type_set_flags; + value = def_style_entry->map.value; if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } @@ -139,26 +140,22 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. - ApkAssetsCookie new_cookie = - theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid); - if (new_cookie != kInvalidCookie) { - cookie = new_cookie; - } + ssize_t new_block = + theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); + if (new_block >= 0) block = new_block; if (kDebugStyles) { ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); } } else if (value.data != Res_value::DATA_NULL_EMPTY) { - // If we still don't have a value for this attribute, try to find it in the theme! - ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags); - if (new_cookie != kInvalidCookie) { + // If we still don't have a value for this attribute, try to find + // it in the theme! + ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); + if (new_block >= 0) { if (kDebugStyles) { ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } - new_cookie = - assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid); - if (new_cookie != kInvalidCookie) { - cookie = new_cookie; - } + new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); + if (new_block >= 0) block = new_block; if (kDebugStyles) { ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } @@ -172,7 +169,7 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, } value.dataType = Res_value::TYPE_NULL; value.data = Res_value::DATA_NULL_UNDEFINED; - cookie = kInvalidCookie; + block = -1; } if (kDebugStyles) { @@ -182,7 +179,9 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, // Write the final value back to Java. out_values[STYLE_TYPE] = value.dataType; out_values[STYLE_DATA] = value.data; - out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie); + out_values[STYLE_ASSET_COOKIE] = + block != -1 ? static_cast<uint32_t>(res.getTableCookie(block)) + : static_cast<uint32_t>(-1); out_values[STYLE_RESOURCE_ID] = resid; out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; @@ -196,80 +195,90 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, out_values += STYLE_NUM_ENTRIES; } + res.unlock(); + if (out_indices != nullptr) { out_indices[0] = indices_idx; } return true; } -void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, - uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length, +void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, + uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) { if (kDebugStyles) { - ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme, - def_style_attr, def_style_resid, xml_parser); + ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", + theme, def_style_attr, def_style_res, xml_parser); } - AssetManager2* assetmanager = theme->GetAssetManager(); + const ResTable& res = theme->getResTable(); ResTable_config config; Res_value value; int indices_idx = 0; // Load default style from attribute, if specified... - uint32_t def_style_flags = 0u; + uint32_t def_style_bag_type_set_flags = 0; if (def_style_attr != 0) { Res_value value; - if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) { + if (theme->getAttribute(def_style_attr, &value, + &def_style_bag_type_set_flags) >= 0) { if (value.dataType == Res_value::TYPE_REFERENCE) { - def_style_resid = value.data; + def_style_res = value.data; } } } - // Retrieve the style resource ID associated with the current XML tag's style attribute. - uint32_t style_resid = 0u; - uint32_t style_flags = 0u; + // Retrieve the style class associated with the current XML tag. + int style = 0; + uint32_t style_bag_type_set_flags = 0; if (xml_parser != nullptr) { ssize_t idx = xml_parser->indexOfStyle(); if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) { if (value.dataType == value.TYPE_ATTRIBUTE) { - // Resolve the attribute with out theme. - if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) { + if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { value.dataType = Res_value::TYPE_NULL; } } - if (value.dataType == value.TYPE_REFERENCE) { - style_resid = value.data; + style = value.data; } } } - // Retrieve the default style bag, if requested. - const ResolvedBag* default_style_bag = nullptr; - if (def_style_resid != 0) { - default_style_bag = assetmanager->GetBag(def_style_resid); - if (default_style_bag != nullptr) { - def_style_flags |= default_style_bag->type_spec_flags; - } - } + // Now lock down the resource object and start pulling stuff from it. + res.lock(); - BagAttributeFinder def_style_attr_finder(default_style_bag); + // Retrieve the default style bag, if requested. + const ResTable::bag_entry* def_style_attr_start = nullptr; + uint32_t def_style_type_set_flags = 0; + ssize_t bag_off = def_style_res != 0 + ? res.getBagLocked(def_style_res, &def_style_attr_start, + &def_style_type_set_flags) + : -1; + def_style_type_set_flags |= def_style_bag_type_set_flags; + const ResTable::bag_entry* const def_style_attr_end = + def_style_attr_start + (bag_off >= 0 ? bag_off : 0); + BagAttributeFinder def_style_attr_finder(def_style_attr_start, + def_style_attr_end); // Retrieve the style class bag, if requested. - const ResolvedBag* xml_style_bag = nullptr; - if (style_resid != 0) { - xml_style_bag = assetmanager->GetBag(style_resid); - if (xml_style_bag != nullptr) { - style_flags |= xml_style_bag->type_spec_flags; - } - } - - BagAttributeFinder xml_style_attr_finder(xml_style_bag); + const ResTable::bag_entry* style_attr_start = nullptr; + uint32_t style_type_set_flags = 0; + bag_off = + style != 0 + ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags) + : -1; + style_type_set_flags |= style_bag_type_set_flags; + const ResTable::bag_entry* const style_attr_end = + style_attr_start + (bag_off >= 0 ? bag_off : 0); + BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end); // Retrieve the XML attributes, if requested. + static const ssize_t kXmlBlock = 0x10000000; XmlAttributeFinder xml_attr_finder(xml_parser); + const size_t xml_attr_end = + xml_parser != nullptr ? xml_parser->getAttributeCount() : 0; // Now iterate through all of the attributes that the client has requested, // filling in each with whatever data we can find. @@ -280,8 +289,8 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident); } - ApkAssetsCookie cookie = kInvalidCookie; - uint32_t type_set_flags = 0u; + ssize_t block = kXmlBlock; + uint32_t type_set_flags = 0; value.dataType = Res_value::TYPE_NULL; value.data = Res_value::DATA_NULL_UNDEFINED; @@ -293,7 +302,7 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, // Walk through the xml attributes looking for the requested attribute. const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident); - if (xml_attr_idx != xml_attr_finder.end()) { + if (xml_attr_idx != xml_attr_end) { // We found the attribute we were looking for. xml_parser->getAttributeValue(xml_attr_idx, &value); if (kDebugStyles) { @@ -303,12 +312,12 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { // Walk through the style class values looking for the requested attribute. - const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident); - if (entry != xml_style_attr_finder.end()) { + const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); + if (style_attr_entry != style_attr_end) { // We found the attribute we were looking for. - cookie = entry->cookie; - type_set_flags = style_flags; - value = entry->value; + block = style_attr_entry->stringBlock; + type_set_flags = style_type_set_flags; + value = style_attr_entry->map.value; if (kDebugStyles) { ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); } @@ -317,25 +326,25 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { // Walk through the default style values looking for the requested attribute. - const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident); - if (entry != def_style_attr_finder.end()) { + const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); + if (def_style_attr_entry != def_style_attr_end) { // We found the attribute we were looking for. - cookie = entry->cookie; - type_set_flags = def_style_flags; - value = entry->value; + block = def_style_attr_entry->stringBlock; + type_set_flags = style_type_set_flags; + value = def_style_attr_entry->map.value; if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } - uint32_t resid = 0u; + uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. - ApkAssetsCookie new_cookie = - theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid); - if (new_cookie != kInvalidCookie) { - cookie = new_cookie; + ssize_t new_block = + theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); + if (new_block >= 0) { + block = new_block; } if (kDebugStyles) { @@ -343,15 +352,14 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, } } else if (value.data != Res_value::DATA_NULL_EMPTY) { // If we still don't have a value for this attribute, try to find it in the theme! - ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags); - if (new_cookie != kInvalidCookie) { + ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); + if (new_block >= 0) { if (kDebugStyles) { ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } - new_cookie = - assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid); - if (new_cookie != kInvalidCookie) { - cookie = new_cookie; + new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); + if (new_block >= 0) { + block = new_block; } if (kDebugStyles) { @@ -367,7 +375,7 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, } value.dataType = Res_value::TYPE_NULL; value.data = Res_value::DATA_NULL_UNDEFINED; - cookie = kInvalidCookie; + block = kXmlBlock; } if (kDebugStyles) { @@ -377,7 +385,9 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, // Write the final value back to Java. out_values[STYLE_TYPE] = value.dataType; out_values[STYLE_DATA] = value.data; - out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie); + out_values[STYLE_ASSET_COOKIE] = + block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block)) + : static_cast<uint32_t>(-1); out_values[STYLE_RESOURCE_ID] = resid; out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; @@ -392,28 +402,36 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, out_values += STYLE_NUM_ENTRIES; } + res.unlock(); + // out_indices must NOT be nullptr. out_indices[0] = indices_idx; } -bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs, - size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) { +bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, + uint32_t* attrs, size_t attrs_length, + uint32_t* out_values, uint32_t* out_indices) { ResTable_config config; Res_value value; int indices_idx = 0; + // Now lock down the resource object and start pulling stuff from it. + res->lock(); + // Retrieve the XML attributes, if requested. const size_t xml_attr_count = xml_parser->getAttributeCount(); size_t ix = 0; uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix); + static const ssize_t kXmlBlock = 0x10000000; + // Now iterate through all of the attributes that the client has requested, // filling in each with whatever data we can find. for (size_t ii = 0; ii < attrs_length; ii++) { const uint32_t cur_ident = attrs[ii]; - ApkAssetsCookie cookie = kInvalidCookie; - uint32_t type_set_flags = 0u; + ssize_t block = kXmlBlock; + uint32_t type_set_flags = 0; value.dataType = Res_value::TYPE_NULL; value.data = Res_value::DATA_NULL_UNDEFINED; @@ -432,27 +450,28 @@ bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, u cur_xml_attr = xml_parser->getAttributeNameResID(ix); } - uint32_t resid = 0u; + uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. - ApkAssetsCookie new_cookie = - assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid); - if (new_cookie != kInvalidCookie) { - cookie = new_cookie; - } + // printf("Resolving attribute reference\n"); + ssize_t new_block = res->resolveReference(&value, block, &resid, + &type_set_flags, &config); + if (new_block >= 0) block = new_block; } // Deal with the special @null value -- it turns back to TYPE_NULL. if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { value.dataType = Res_value::TYPE_NULL; value.data = Res_value::DATA_NULL_UNDEFINED; - cookie = kInvalidCookie; + block = kXmlBlock; } // Write the final value back to Java. out_values[STYLE_TYPE] = value.dataType; out_values[STYLE_DATA] = value.data; - out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie); + out_values[STYLE_ASSET_COOKIE] = + block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block)) + : static_cast<uint32_t>(-1); out_values[STYLE_RESOURCE_ID] = resid; out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; @@ -466,6 +485,8 @@ bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, u out_values += STYLE_NUM_ENTRIES; } + res->unlock(); + if (out_indices != nullptr) { out_indices[0] = indices_idx; } diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index 1d2c597c4c8c..28548e27baf0 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -44,6 +44,44 @@ namespace android { constexpr const static int kAppPackageId = 0x7f; +// Element of a TypeSpec array. See TypeSpec. +struct Type { + // The configuration for which this type defines entries. + // This is already converted to host endianness. + ResTable_config configuration; + + // Pointer to the mmapped data where entry definitions are kept. + const ResTable_type* type; +}; + +// TypeSpec is going to be immediately proceeded by +// an array of Type structs, all in the same block of memory. +struct TypeSpec { + // Pointer to the mmapped data where flags are kept. + // Flags denote whether the resource entry is public + // and under which configurations it varies. + const ResTable_typeSpec* type_spec; + + // Pointer to the mmapped data where the IDMAP mappings for this type + // exist. May be nullptr if no IDMAP exists. + const IdmapEntry_header* idmap_entries; + + // The number of types that follow this struct. + // There is a type for each configuration + // that entries are defined for. + size_t type_count; + + // Trick to easily access a variable number of Type structs + // proceeding this struct, and to ensure their alignment. + const Type types[0]; +}; + +// TypeSpecPtr points to the block of memory that holds +// a TypeSpec struct, followed by an array of Type structs. +// TypeSpecPtr is a managed pointer that knows how to delete +// itself. +using TypeSpecPtr = util::unique_cptr<TypeSpec>; + namespace { // Builder that helps accumulate Type structs and then create a single @@ -57,22 +95,21 @@ class TypeSpecPtrBuilder { } void AddType(const ResTable_type* type) { - types_.push_back(type); + ResTable_config config; + config.copyFromDtoH(type->config); + types_.push_back(Type{config, type}); } TypeSpecPtr Build() { // Check for overflow. - using ElementType = const ResTable_type*; - if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) < - types_.size()) { + if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) { return {}; } - TypeSpec* type_spec = - (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(ElementType))); + TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type))); type_spec->type_spec = header_; type_spec->idmap_entries = idmap_header_; type_spec->type_count = types_.size(); - memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType)); + memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type)); return TypeSpecPtr(type_spec); } @@ -81,7 +118,7 @@ class TypeSpecPtrBuilder { const ResTable_typeSpec* header_; const IdmapEntry_header* idmap_header_; - std::vector<const ResTable_type*> types_; + std::vector<Type> types_; }; } // namespace @@ -125,17 +162,18 @@ static bool VerifyResTableType(const ResTable_type* header) { return true; } -static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) { +static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset, + size_t entry_idx) { // Check that the offset is aligned. if (entry_offset & 0x03) { - LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned."; + LOG(ERROR) << "Entry offset at index " << entry_idx << " is not 4-byte aligned."; return false; } // Check that the offset doesn't overflow. if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) { // Overflow in offset. - LOG(ERROR) << "Entry at offset " << entry_offset << " is too large."; + LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large."; return false; } @@ -143,7 +181,7 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset entry_offset += dtohl(type->entriesStart); if (entry_offset > chunk_size - sizeof(ResTable_entry)) { - LOG(ERROR) << "Entry at offset " << entry_offset + LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large. No room for ResTable_entry."; return false; } @@ -153,13 +191,13 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset const size_t entry_size = dtohs(entry->size); if (entry_size < sizeof(*entry)) { - LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset + LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx << " is too small."; return false; } if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) { - LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset + LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx << " is too large."; return false; } @@ -167,7 +205,7 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset if (entry_size < sizeof(ResTable_map_entry)) { // There needs to be room for one Res_value struct. if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) { - LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset + LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << entry_idx << " for type " << (int)type->id << "."; return false; } @@ -176,12 +214,12 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size); const size_t value_size = dtohs(value->size); if (value_size < sizeof(Res_value)) { - LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small."; + LOG(ERROR) << "Res_value at index " << entry_idx << " is too small."; return false; } if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) { - LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset + LOG(ERROR) << "Res_value size " << value_size << " at index " << entry_idx << " is too large."; return false; } @@ -190,76 +228,119 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset const size_t map_entry_count = dtohl(map->count); size_t map_entries_start = entry_offset + entry_size; if (map_entries_start & 0x03) { - LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset."; + LOG(ERROR) << "Map entries at index " << entry_idx << " start at unaligned offset."; return false; } // Each entry is sizeof(ResTable_map) big. if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) { - LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << "."; + LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << entry_idx << "."; return false; } } return true; } -const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk, - uint16_t entry_index) { - uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index); - if (entry_offset == ResTable_type::NO_ENTRY) { - return nullptr; - } - return GetEntryFromOffset(type_chunk, entry_offset); -} - -uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) { - // The configuration matches and is better than the previous selection. - // Find the entry value if it exists for this configuration. - const size_t entry_count = dtohl(type_chunk->entryCount); - const size_t offsets_offset = dtohs(type_chunk->header.headerSize); +bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx, + const ResTable_config& config, FindEntryResult* out_entry) const { + const ResTable_config* best_config = nullptr; + const ResTable_type* best_type = nullptr; + uint32_t best_offset = 0; + + for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) { + const Type* type = &type_spec_ptr->types[i]; + const ResTable_type* type_chunk = type->type; + + if (type->configuration.match(config) && + (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) { + // The configuration matches and is better than the previous selection. + // Find the entry value if it exists for this configuration. + const size_t entry_count = dtohl(type_chunk->entryCount); + const size_t offsets_offset = dtohs(type_chunk->header.headerSize); + + // Check if there is the desired entry in this type. + + if (type_chunk->flags & ResTable_type::FLAG_SPARSE) { + // This is encoded as a sparse map, so perform a binary search. + const ResTable_sparseTypeEntry* sparse_indices = + reinterpret_cast<const ResTable_sparseTypeEntry*>( + reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); + const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count; + const ResTable_sparseTypeEntry* result = + std::lower_bound(sparse_indices, sparse_indices_end, entry_idx, + [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) { + return dtohs(entry.idx) < entry_idx; + }); + + if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) { + // No entry found. + continue; + } - // Check if there is the desired entry in this type. + // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as + // the real offset divided by 4. + best_offset = uint32_t{dtohs(result->offset)} * 4u; + } else { + if (entry_idx >= entry_count) { + // This entry cannot be here. + continue; + } - if (type_chunk->flags & ResTable_type::FLAG_SPARSE) { - // This is encoded as a sparse map, so perform a binary search. - const ResTable_sparseTypeEntry* sparse_indices = - reinterpret_cast<const ResTable_sparseTypeEntry*>( + const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); - const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count; - const ResTable_sparseTypeEntry* result = - std::lower_bound(sparse_indices, sparse_indices_end, entry_index, - [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) { - return dtohs(entry.idx) < entry_idx; - }); - - if (result == sparse_indices_end || dtohs(result->idx) != entry_index) { - // No entry found. - return ResTable_type::NO_ENTRY; + const uint32_t offset = dtohl(entry_offsets[entry_idx]); + if (offset == ResTable_type::NO_ENTRY) { + continue; + } + + // There is an entry for this resource, record it. + best_offset = offset; + } + + best_config = &type->configuration; + best_type = type_chunk; } + } - // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as - // the real offset divided by 4. - return uint32_t{dtohs(result->offset)} * 4u; + if (best_type == nullptr) { + return false; } - // This type is encoded as a dense array. - if (entry_index >= entry_count) { - // This entry cannot be here. - return ResTable_type::NO_ENTRY; + if (UNLIKELY(!VerifyResTableEntry(best_type, best_offset, entry_idx))) { + return false; } - const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( - reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); - return dtohl(entry_offsets[entry_index]); + const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>( + reinterpret_cast<const uint8_t*>(best_type) + best_offset + dtohl(best_type->entriesStart)); + + const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec_ptr->type_spec + 1); + out_entry->type_flags = dtohl(flags[entry_idx]); + out_entry->entry = best_entry; + out_entry->config = best_config; + out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1); + out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index)); + return true; } -const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk, - uint32_t offset) { - if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) { - return nullptr; +bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config, + FindEntryResult* out_entry) const { + ATRACE_CALL(); + + // If the type IDs are offset in this package, we need to take that into account when searching + // for a type. + const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_]; + if (UNLIKELY(ptr == nullptr)) { + return false; } - return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) + - offset + dtohl(type_chunk->entriesStart)); + + // If there is an IDMAP supplied with this package, translate the entry ID. + if (ptr->idmap_entries != nullptr) { + if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) { + // There is no mapping, so the resource is not meant to be in this overlay package. + return false; + } + } + return FindEntry(ptr, entry_idx, config, out_entry); } void LoadedPackage::CollectConfigurations(bool exclude_mipmap, @@ -267,7 +348,7 @@ void LoadedPackage::CollectConfigurations(bool exclude_mipmap, const static std::u16string kMipMap = u"mipmap"; const size_t type_count = type_specs_.size(); for (size_t i = 0; i < type_count; i++) { - const TypeSpecPtr& type_spec = type_specs_[i]; + const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i]; if (type_spec != nullptr) { if (exclude_mipmap) { const int type_idx = type_spec->type_spec->id - 1; @@ -288,11 +369,8 @@ void LoadedPackage::CollectConfigurations(bool exclude_mipmap, } } - const auto iter_end = type_spec->types + type_spec->type_count; - for (auto iter = type_spec->types; iter != iter_end; ++iter) { - ResTable_config config; - config.copyFromDtoH((*iter)->config); - out_configs->insert(config); + for (size_t j = 0; j < type_spec->type_count; j++) { + out_configs->insert(type_spec->types[j].configuration); } } } @@ -302,12 +380,10 @@ void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out char temp_locale[RESTABLE_MAX_LOCALE_LEN]; const size_t type_count = type_specs_.size(); for (size_t i = 0; i < type_count; i++) { - const TypeSpecPtr& type_spec = type_specs_[i]; + const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i]; if (type_spec != nullptr) { - const auto iter_end = type_spec->types + type_spec->type_count; - for (auto iter = type_spec->types; iter != iter_end; ++iter) { - ResTable_config configuration; - configuration.copyFromDtoH((*iter)->config); + for (size_t j = 0; j < type_spec->type_count; j++) { + const ResTable_config& configuration = type_spec->types[j].configuration; if (configuration.locale != 0) { configuration.getBcp47Locale(temp_locale, canonicalize); std::string locale(temp_locale); @@ -335,17 +411,17 @@ uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name, return 0u; } - const auto iter_end = type_spec->types + type_spec->type_count; - for (auto iter = type_spec->types; iter != iter_end; ++iter) { - const ResTable_type* type = *iter; - size_t entry_count = dtohl(type->entryCount); + for (size_t ti = 0; ti < type_spec->type_count; ti++) { + const Type* type = &type_spec->types[ti]; + size_t entry_count = dtohl(type->type->entryCount); for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) { const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( - reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize)); + reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize)); const uint32_t offset = dtohl(entry_offsets[entry_idx]); if (offset != ResTable_type::NO_ENTRY) { - const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>( - reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset); + const ResTable_entry* entry = + reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) + + dtohl(type->type->entriesStart) + offset); if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) { // The package ID will be overridden by the caller (due to runtime assignment of package // IDs for shared libraries). @@ -357,7 +433,8 @@ uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name, return 0u; } -const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const { +const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { + const uint8_t package_id = get_package_id(resid); for (const auto& loaded_package : packages_) { if (loaded_package->GetPackageId() == package_id) { return loaded_package.get(); @@ -605,6 +682,26 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, return std::move(loaded_package); } +bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, + FindEntryResult* out_entry) const { + ATRACE_CALL(); + + const uint8_t package_id = get_package_id(resid); + const uint8_t type_id = get_type_id(resid); + const uint16_t entry_id = get_entry_id(resid); + + if (UNLIKELY(type_id == 0)) { + LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid); + return false; + } + + for (const auto& loaded_package : packages_) { + if (loaded_package->GetPackageId() == package_id) { + return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry); + } + } + return false; +} bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library) { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index ef08897d997a..b033137b4764 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -69,8 +69,6 @@ struct ResolvedBag { Entry entries[0]; }; -struct FindEntryResult; - // AssetManager2 is the main entry point for accessing assets and resources. // AssetManager2 provides caching of resources retrieved via the underlying ApkAssets. class AssetManager2 { @@ -129,7 +127,7 @@ class AssetManager2 { // If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap' // will be excluded from the list. std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false, - bool exclude_mipmap = false) const; + bool exclude_mipmap = false); // Returns all the locales for which there are resources defined. This includes resource // locales in all the ApkAssets set for this AssetManager. @@ -138,24 +136,24 @@ class AssetManager2 { // If `merge_equivalent_languages` is set to true, resource locales will be canonicalized // and de-duped in the resulting list. std::set<std::string> GetResourceLocales(bool exclude_system = false, - bool merge_equivalent_languages = false) const; + bool merge_equivalent_languages = false); // Searches the set of APKs loaded by this AssetManager and opens the first one found located // in the assets/ directory. // `mode` controls how the file is opened. // // NOTE: The loaded APKs are searched in reverse order. - std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode) const; + std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode); // Opens a file within the assets/ directory of the APK specified by `cookie`. // `mode` controls how the file is opened. std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie, - Asset::AccessMode mode) const; + Asset::AccessMode mode); // Opens the directory specified by `dirname`. The result is an AssetDir that is the combination // of all directories matching `dirname` under the assets/ directory of every ApkAssets loaded. // The entries are sorted by their ASCII name. - std::unique_ptr<AssetDir> OpenDir(const std::string& dirname) const; + std::unique_ptr<AssetDir> OpenDir(const std::string& dirname); // Searches the set of APKs loaded by this AssetManager and opens the first one found. // `mode` controls how the file is opened. @@ -163,24 +161,24 @@ class AssetManager2 { // // NOTE: The loaded APKs are searched in reverse order. std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode, - ApkAssetsCookie* out_cookie = nullptr) const; + ApkAssetsCookie* out_cookie = nullptr); // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened. // This is typically used to open a specific AndroidManifest.xml, or a binary XML file // referenced by a resource lookup with GetResource(). std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie, - Asset::AccessMode mode) const; + Asset::AccessMode mode); // Populates the `out_name` parameter with resource name information. // Utf8 strings are preferred, and only if they are unavailable are // the Utf16 variants populated. // Returns false if the resource was not found or the name was missing/corrupt. - bool GetResourceName(uint32_t resid, ResourceName* out_name) const; + bool GetResourceName(uint32_t resid, ResourceName* out_name); // Populates `out_flags` with the bitmask of configuration axis that this resource varies with. // See ResTable_config for the list of configuration axis. // Returns false if the resource was not found. - bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const; + bool GetResourceFlags(uint32_t resid, uint32_t* out_flags); // Finds the resource ID assigned to `resource_name`. // `resource_name` must be of the form '[package:][type/]entry'. @@ -188,7 +186,7 @@ class AssetManager2 { // If no type is specified in `resource_name`, then `fallback_type` is used as the type. // Returns 0x0 if no resource by that name was found. uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {}, - const std::string& fallback_package = {}) const; + const std::string& fallback_package = {}); // Retrieves the best matching resource with ID `resid`. The resource value is filled into // `out_value` and the configuration for the selected value is populated in `out_selected_config`. @@ -201,7 +199,7 @@ class AssetManager2 { // this function logs if the resource was a map/bag type before returning kInvalidCookie. ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override, Res_value* out_value, ResTable_config* out_selected_config, - uint32_t* out_flags) const; + uint32_t* out_flags); // Resolves the resource reference in `in_out_value` if the data type is // Res_value::TYPE_REFERENCE. @@ -217,7 +215,7 @@ class AssetManager2 { // it was not found. ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value, ResTable_config* in_out_selected_config, uint32_t* in_out_flags, - uint32_t* out_last_reference) const; + uint32_t* out_last_reference); // Retrieves the best matching bag/map resource with ID `resid`. // This method will resolve all parent references for this bag and merge keys with the child. @@ -235,9 +233,9 @@ class AssetManager2 { std::unique_ptr<Theme> NewTheme(); template <typename Func> - void ForEachPackage(Func func) const { + void ForEachPackage(Func func) { for (const PackageGroup& package_group : package_groups_) { - func(package_group.packages_.front().loaded_package_->GetPackageName(), + func(package_group.packages_.front()->GetPackageName(), package_group.dynamic_ref_table.mAssignedPackageId); } } @@ -262,7 +260,7 @@ class AssetManager2 { // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds. ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match, - FindEntryResult* out_entry) const; + FindEntryResult* out_entry); // Assigns package IDs to all shared library ApkAssets. // Should be called whenever the ApkAssets are changed. @@ -272,43 +270,13 @@ class AssetManager2 { // bitmask `diff`. void InvalidateCaches(uint32_t diff); - // Triggers the re-construction of lists of types that match the set configuration. - // This should always be called when mutating the AssetManager's configuration or ApkAssets set. - void RebuildFilterList(); - // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. std::vector<const ApkAssets*> apk_assets_; - // A collection of configurations and their associated ResTable_type that match the current - // AssetManager configuration. - struct FilteredConfigGroup { - std::vector<ResTable_config> configurations; - std::vector<const ResTable_type*> types; - }; - - // Represents an single package. - struct ConfiguredPackage { - // A pointer to the immutable, loaded package info. - const LoadedPackage* loaded_package_; - - // A mutable AssetManager-specific list of configurations that match the AssetManager's - // current configuration. This is used as an optimization to avoid checking every single - // candidate configuration when looking up resources. - ByteBucketArray<FilteredConfigGroup> filtered_configs_; - }; - - // Represents a logical package, which can be made up of many individual packages. Each package - // in a PackageGroup shares the same package name and package ID. struct PackageGroup { - // The set of packages that make-up this group. - std::vector<ConfiguredPackage> packages_; - - // The cookies associated with each package in the group. They share the same order as - // packages_. + std::vector<const LoadedPackage*> packages_; std::vector<ApkAssetsCookie> cookies_; - - // A library reference table that contains build-package ID to runtime-package ID mappings. DynamicRefTable dynamic_ref_table; }; @@ -382,7 +350,7 @@ class Theme { ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value, ResTable_config* in_out_selected_config = nullptr, uint32_t* in_out_type_spec_flags = nullptr, - uint32_t* out_last_ref = nullptr) const; + uint32_t* out_last_ref = nullptr); private: DISALLOW_COPY_AND_ASSIGN(Theme); diff --git a/libs/androidfw/include/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h index 03fad4947dfe..f281921824e7 100644 --- a/libs/androidfw/include/androidfw/AttributeFinder.h +++ b/libs/androidfw/include/androidfw/AttributeFinder.h @@ -58,7 +58,6 @@ class BackTrackingAttributeFinder { BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end); Iterator Find(uint32_t attr); - inline Iterator end(); private: void JumpToClosestAttribute(uint32_t package_id); @@ -202,11 +201,6 @@ Iterator BackTrackingAttributeFinder<Derived, Iterator>::Find(uint32_t attr) { return end_; } -template <typename Derived, typename Iterator> -Iterator BackTrackingAttributeFinder<Derived, Iterator>::end() { - return end_; -} - } // namespace android #endif // ANDROIDFW_ATTRIBUTE_FINDER_H diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h index 35ef98d8c704..69b760414846 100644 --- a/libs/androidfw/include/androidfw/AttributeResolution.h +++ b/libs/androidfw/include/androidfw/AttributeResolution.h @@ -17,8 +17,7 @@ #ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H #define ANDROIDFW_ATTRIBUTERESOLUTION_H -#include "androidfw/AssetManager2.h" -#include "androidfw/ResourceTypes.h" +#include <androidfw/ResourceTypes.h> namespace android { @@ -43,19 +42,19 @@ enum { // `out_values` must NOT be nullptr. // `out_indices` may be nullptr. -bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid, +bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, uint32_t* src_values, size_t src_values_length, uint32_t* attrs, size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); // `out_values` must NOT be nullptr. // `out_indices` is NOT optional and must NOT be nullptr. -void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, - uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length, +void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, + uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); // `out_values` must NOT be nullptr. // `out_indices` may be nullptr. -bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs, +bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs, size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); } // namespace android diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 35ae5fcd9e7b..965e2dbd2fb2 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -41,40 +41,32 @@ class DynamicPackageEntry { int package_id = 0; }; -// TypeSpec is going to be immediately proceeded by -// an array of Type structs, all in the same block of memory. -struct TypeSpec { - // Pointer to the mmapped data where flags are kept. - // Flags denote whether the resource entry is public - // and under which configurations it varies. - const ResTable_typeSpec* type_spec; - - // Pointer to the mmapped data where the IDMAP mappings for this type - // exist. May be nullptr if no IDMAP exists. - const IdmapEntry_header* idmap_entries; - - // The number of types that follow this struct. - // There is a type for each configuration that entries are defined for. - size_t type_count; - - // Trick to easily access a variable number of Type structs - // proceeding this struct, and to ensure their alignment. - const ResTable_type* types[0]; - - inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const { - if (entry_index >= dtohl(type_spec->entryCount)) { - return 0u; - } - - const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1); - return flags[entry_index]; - } +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 = nullptr; + + // The configuration for which the resulting entry was defined. + const ResTable_config* config = nullptr; + + // Stores the resulting bitmask of configuration axis with which the resource value varies. + uint32_t type_flags = 0u; + + // The dynamic package ID map for the package from which this resource came from. + const DynamicRefTable* dynamic_ref_table = nullptr; + + // 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; + + // The string pool reference to the entry's name. This uses a different string pool than + // the global string pool, but this is hidden from the caller. + StringPoolRef entry_string_ref; }; -// TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of -// ResTable_type pointers. -// TypeSpecPtr is a managed pointer that knows how to delete itself. -using TypeSpecPtr = util::unique_cptr<TypeSpec>; +struct TypeSpec; +class LoadedArsc; class LoadedPackage { public: @@ -84,6 +76,9 @@ class LoadedPackage { ~LoadedPackage(); + bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config, + FindEntryResult* out_entry) const; + // Finds the entry with the specified type name and entry name. The names are in UTF-16 because // the underlying ResStringPool API expects this. For now this is acceptable, but since // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change. @@ -91,12 +86,6 @@ class LoadedPackage { // for patching the correct package ID to the resource ID. uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const; - static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index); - - static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index); - - static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset); - // Returns the string pool where type names are stored. inline const ResStringPool* GetTypeStringPool() const { return &type_string_pool_; @@ -146,32 +135,14 @@ class LoadedPackage { // before being inserted into the set. This may cause some equivalent locales to de-dupe. void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const; - // type_idx is TT - 1 from 0xPPTTEEEE. - inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const { - // If the type IDs are offset in this package, we need to take that into account when searching - // for a type. - return type_specs_[type_index - type_id_offset_].get(); - } - - template <typename Func> - void ForEachTypeSpec(Func f) const { - for (size_t i = 0; i < type_specs_.size(); i++) { - const TypeSpecPtr& ptr = type_specs_[i]; - if (ptr != nullptr) { - uint8_t type_id = ptr->type_spec->id; - if (ptr->idmap_entries != nullptr) { - type_id = ptr->idmap_entries->target_type_id; - } - f(ptr.get(), type_id - 1); - } - } - } - private: DISALLOW_COPY_AND_ASSIGN(LoadedPackage); LoadedPackage(); + bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx, + const ResTable_config& config, FindEntryResult* out_entry) const; + ResStringPool type_string_pool_; ResStringPool key_string_pool_; std::string package_name_; @@ -181,7 +152,7 @@ class LoadedPackage { bool system_ = false; bool overlay_ = false; - ByteBucketArray<TypeSpecPtr> type_specs_; + ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_; std::vector<DynamicPackageEntry> dynamic_package_map_; }; @@ -209,20 +180,25 @@ class LoadedArsc { return &global_string_pool_; } - // Gets a pointer to the package with the specified package ID, or nullptr if no such package - // exists. - const LoadedPackage* GetPackageById(uint8_t package_id) const; + // Finds the resource with ID `resid` with the best value for configuration `config`. + // The parameter `out_entry` will be filled with the resulting resource entry. + // The resource entry can be a simple entry (ResTable_entry) or a complex bag + // (ResTable_entry_map). + bool FindEntry(uint32_t resid, const ResTable_config& config, FindEntryResult* out_entry) const; - // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc. - inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const { - return packages_; - } + // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist. + const LoadedPackage* GetPackageForId(uint32_t resid) const; // Returns true if this is a system provided resource. inline bool IsSystem() const { return system_; } + // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc. + inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const { + return packages_; + } + private: DISALLOW_COPY_AND_ASSIGN(LoadedArsc); diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h deleted file mode 100644 index 64924f433245..000000000000 --- a/libs/androidfw/include/androidfw/MutexGuard.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROIDFW_MUTEXGUARD_H -#define ANDROIDFW_MUTEXGUARD_H - -#include <mutex> -#include <type_traits> - -#include "android-base/macros.h" - -namespace android { - -template <typename T> -class ScopedLock; - -// Owns the guarded object and protects access to it via a mutex. -// The guarded object is inaccessible via this class. -// The mutex is locked and the object accessed via the ScopedLock<T> class. -// -// NOTE: The template parameter T should not be a raw pointer, since ownership -// is ambiguous and error-prone. Instead use an std::unique_ptr<>. -// -// Example use: -// -// Guarded<std::string> shared_string("hello"); -// { -// ScopedLock<std::string> locked_string(shared_string); -// *locked_string += " world"; -// } -// -template <typename T> -class Guarded { - static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer"); - - public: - explicit Guarded() : guarded_() { - } - - template <typename U = T> - explicit Guarded(const T& guarded, - typename std::enable_if<std::is_copy_constructible<U>::value>::type = void()) - : guarded_(guarded) { - } - - template <typename U = T> - explicit Guarded(T&& guarded, - typename std::enable_if<std::is_move_constructible<U>::value>::type = void()) - : guarded_(std::move(guarded)) { - } - - private: - friend class ScopedLock<T>; - - DISALLOW_COPY_AND_ASSIGN(Guarded); - - std::mutex lock_; - T guarded_; -}; - -template <typename T> -class ScopedLock { - public: - explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) { - } - - T& operator*() { - return guarded_; - } - - T* operator->() { - return &guarded_; - } - - T* get() { - return &guarded_; - } - - private: - DISALLOW_COPY_AND_ASSIGN(ScopedLock); - - std::lock_guard<std::mutex> lock_; - T& guarded_; -}; - -} // namespace android - -#endif // ANDROIDFW_MUTEXGUARD_H diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp index e2b9f0040989..6c43a67e602f 100644 --- a/libs/androidfw/tests/ApkAssets_test.cpp +++ b/libs/androidfw/tests/ApkAssets_test.cpp @@ -26,56 +26,58 @@ using ::android::base::unique_fd; using ::com::android::basic::R; -using ::testing::Eq; -using ::testing::Ge; -using ::testing::NotNull; -using ::testing::SizeIs; -using ::testing::StrEq; namespace android { TEST(ApkAssetsTest, LoadApk) { std::unique_ptr<const ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk"); - ASSERT_THAT(loaded_apk, NotNull()); + ASSERT_NE(nullptr, loaded_apk); const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc(); - ASSERT_THAT(loaded_arsc, NotNull()); - ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull()); - ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull()); + ASSERT_NE(nullptr, loaded_arsc); + + const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000); + ASSERT_NE(nullptr, loaded_package); + + std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml"); + ASSERT_NE(nullptr, asset); } TEST(ApkAssetsTest, LoadApkFromFd) { const std::string path = GetTestDataPath() + "/basic/basic.apk"; unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY)); - ASSERT_THAT(fd.get(), Ge(0)); + ASSERT_GE(fd.get(), 0); std::unique_ptr<const ApkAssets> loaded_apk = ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/); - ASSERT_THAT(loaded_apk, NotNull()); + ASSERT_NE(nullptr, loaded_apk); const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc(); - ASSERT_THAT(loaded_arsc, NotNull()); - ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull()); - ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull()); + ASSERT_NE(nullptr, loaded_arsc); + + const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000); + ASSERT_NE(nullptr, loaded_package); + + std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml"); + ASSERT_NE(nullptr, asset); } TEST(ApkAssetsTest, LoadApkAsSharedLibrary) { std::unique_ptr<const ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk"); - ASSERT_THAT(loaded_apk, NotNull()); - + ASSERT_NE(nullptr, loaded_apk); const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc(); - ASSERT_THAT(loaded_arsc, NotNull()); - ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u)); + ASSERT_NE(nullptr, loaded_arsc); + ASSERT_EQ(1u, loaded_arsc->GetPackages().size()); EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic()); loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk"); - ASSERT_THAT(loaded_apk, NotNull()); + ASSERT_NE(nullptr, loaded_apk); loaded_arsc = loaded_apk->GetLoadedArsc(); - ASSERT_THAT(loaded_arsc, NotNull()); - ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u)); + ASSERT_NE(nullptr, loaded_arsc); + ASSERT_EQ(1u, loaded_arsc->GetPackages().size()); EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic()); } @@ -84,22 +86,19 @@ TEST(ApkAssetsTest, LoadApkWithIdmap) { ResTable target_table; const std::string target_path = GetTestDataPath() + "/basic/basic.apk"; ASSERT_TRUE(ReadFileFromZipToString(target_path, "resources.arsc", &contents)); - ASSERT_THAT(target_table.add(contents.data(), contents.size(), 0, true /*copyData*/), - Eq(NO_ERROR)); + ASSERT_EQ(NO_ERROR, target_table.add(contents.data(), contents.size(), 0, true /*copyData*/)); ResTable overlay_table; const std::string overlay_path = GetTestDataPath() + "/overlay/overlay.apk"; ASSERT_TRUE(ReadFileFromZipToString(overlay_path, "resources.arsc", &contents)); - ASSERT_THAT(overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/), - Eq(NO_ERROR)); + ASSERT_EQ(NO_ERROR, overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/)); util::unique_cptr<void> idmap_data; void* temp_data; size_t idmap_len; - ASSERT_THAT(target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(), - overlay_path.c_str(), &temp_data, &idmap_len), - Eq(NO_ERROR)); + ASSERT_EQ(NO_ERROR, target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(), + overlay_path.c_str(), &temp_data, &idmap_len)); idmap_data.reset(temp_data); TemporaryFile tf; @@ -109,30 +108,37 @@ TEST(ApkAssetsTest, LoadApkWithIdmap) { // Open something so that the destructor of TemporaryFile closes a valid fd. tf.fd = open("/dev/null", O_WRONLY); - ASSERT_THAT(ApkAssets::LoadOverlay(tf.path), NotNull()); + std::unique_ptr<const ApkAssets> loaded_overlay_apk = ApkAssets::LoadOverlay(tf.path); + ASSERT_NE(nullptr, loaded_overlay_apk); } TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) { std::unique_ptr<const ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk"); - ASSERT_THAT(loaded_apk, NotNull()); + ASSERT_NE(nullptr, loaded_apk); - { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); } + { + std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER); + ASSERT_NE(nullptr, assets); + } - { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); } + { + std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER); + ASSERT_NE(nullptr, assets); + } } TEST(ApkAssetsTest, OpenUncompressedAssetFd) { std::unique_ptr<const ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk"); - ASSERT_THAT(loaded_apk, NotNull()); + ASSERT_NE(nullptr, loaded_apk); auto asset = loaded_apk->Open("assets/uncompressed.txt", Asset::ACCESS_UNKNOWN); - ASSERT_THAT(asset, NotNull()); + ASSERT_NE(nullptr, asset); off64_t start, length; unique_fd fd(asset->openFileDescriptor(&start, &length)); - ASSERT_THAT(fd.get(), Ge(0)); + EXPECT_GE(fd.get(), 0); lseek64(fd.get(), start, SEEK_SET); @@ -140,7 +146,7 @@ TEST(ApkAssetsTest, OpenUncompressedAssetFd) { buffer.resize(length); ASSERT_TRUE(base::ReadFully(fd.get(), &*buffer.begin(), length)); - EXPECT_THAT(buffer, StrEq("This should be uncompressed.\n\n")); + EXPECT_EQ("This should be uncompressed.\n\n", buffer); } } // namespace android diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp index 437e14772964..85e8f25394e9 100644 --- a/libs/androidfw/tests/AssetManager2_bench.cpp +++ b/libs/androidfw/tests/AssetManager2_bench.cpp @@ -81,18 +81,17 @@ static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) { } BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld); -static void BM_AssetManagerGetResource(benchmark::State& state, uint32_t resid) { - GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid, state); +static void BM_AssetManagerGetResource(benchmark::State& state) { + GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, + basic::R::integer::number1, state); } -BENCHMARK_CAPTURE(BM_AssetManagerGetResource, number1, basic::R::integer::number1); -BENCHMARK_CAPTURE(BM_AssetManagerGetResource, deep_ref, basic::R::integer::deep_ref); +BENCHMARK(BM_AssetManagerGetResource); -static void BM_AssetManagerGetResourceOld(benchmark::State& state, uint32_t resid) { - GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid, - state); +static void BM_AssetManagerGetResourceOld(benchmark::State& state) { + GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, + basic::R::integer::number1, state); } -BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, number1, basic::R::integer::number1); -BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, deep_ref, basic::R::integer::deep_ref); +BENCHMARK(BM_AssetManagerGetResourceOld); static void BM_AssetManagerGetLibraryResource(benchmark::State& state) { GetResourceBenchmark( @@ -197,7 +196,7 @@ BENCHMARK(BM_AssetManagerGetResourceLocales); static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) { AssetManager assets; if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/, - true /*isSystemAssets*/)) { + false /*isSystemAssets*/)) { state.SkipWithError("Failed to load assets"); return; } @@ -212,44 +211,4 @@ static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) { } BENCHMARK(BM_AssetManagerGetResourceLocalesOld); -static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) { - std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath); - if (apk == nullptr) { - state.SkipWithError("Failed to load assets"); - return; - } - - AssetManager2 assets; - assets.SetApkAssets({apk.get()}); - - ResTable_config config; - memset(&config, 0, sizeof(config)); - - while (state.KeepRunning()) { - config.sdkVersion = ~config.sdkVersion; - assets.SetConfiguration(config); - } -} -BENCHMARK(BM_AssetManagerSetConfigurationFramework); - -static void BM_AssetManagerSetConfigurationFrameworkOld(benchmark::State& state) { - AssetManager assets; - if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/, - true /*isSystemAssets*/)) { - state.SkipWithError("Failed to load assets"); - return; - } - - const ResTable& table = assets.getResources(true); - - ResTable_config config; - memset(&config, 0, sizeof(config)); - - while (state.KeepRunning()) { - config.sdkVersion = ~config.sdkVersion; - assets.setConfiguration(config); - } -} -BENCHMARK(BM_AssetManagerSetConfigurationFrameworkOld); - } // namespace android diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp deleted file mode 100644 index fa300c50218a..000000000000 --- a/libs/androidfw/tests/AttributeResolution_bench.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "benchmark/benchmark.h" - -//#include "android-base/stringprintf.h" -#include "androidfw/ApkAssets.h" -#include "androidfw/AssetManager.h" -#include "androidfw/AssetManager2.h" -#include "androidfw/AttributeResolution.h" -#include "androidfw/ResourceTypes.h" - -#include "BenchmarkHelpers.h" -#include "data/basic/R.h" -#include "data/styles/R.h" - -namespace app = com::android::app; -namespace basic = com::android::basic; - -namespace android { - -constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk"; -constexpr const static uint32_t Theme_Material_Light = 0x01030237u; - -static void BM_ApplyStyle(benchmark::State& state) { - std::unique_ptr<const ApkAssets> styles_apk = - ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk"); - if (styles_apk == nullptr) { - state.SkipWithError("failed to load assets"); - return; - } - - AssetManager2 assetmanager; - assetmanager.SetApkAssets({styles_apk.get()}); - - std::unique_ptr<Asset> asset = - assetmanager.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER); - if (asset == nullptr) { - state.SkipWithError("failed to load layout"); - return; - } - - ResXMLTree xml_tree; - if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) { - state.SkipWithError("corrupt xml layout"); - return; - } - - // Skip to the first tag. - while (xml_tree.next() != ResXMLParser::START_TAG) { - } - - std::unique_ptr<Theme> theme = assetmanager.NewTheme(); - theme->ApplyStyle(app::R::style::StyleTwo); - - std::array<uint32_t, 6> attrs{{app::R::attr::attr_one, app::R::attr::attr_two, - app::R::attr::attr_three, app::R::attr::attr_four, - app::R::attr::attr_five, app::R::attr::attr_empty}}; - std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; - std::array<uint32_t, attrs.size() + 1> indices; - - while (state.KeepRunning()) { - ApplyStyle(theme.get(), &xml_tree, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(), - attrs.size(), values.data(), indices.data()); - } -} -BENCHMARK(BM_ApplyStyle); - -static void BM_ApplyStyleFramework(benchmark::State& state) { - std::unique_ptr<const ApkAssets> framework_apk = ApkAssets::Load(kFrameworkPath); - if (framework_apk == nullptr) { - state.SkipWithError("failed to load framework assets"); - return; - } - - std::unique_ptr<const ApkAssets> basic_apk = - ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk"); - if (basic_apk == nullptr) { - state.SkipWithError("failed to load assets"); - return; - } - - AssetManager2 assetmanager; - assetmanager.SetApkAssets({framework_apk.get(), basic_apk.get()}); - - ResTable_config device_config; - memset(&device_config, 0, sizeof(device_config)); - device_config.language[0] = 'e'; - device_config.language[1] = 'n'; - device_config.country[0] = 'U'; - device_config.country[1] = 'S'; - device_config.orientation = ResTable_config::ORIENTATION_PORT; - device_config.smallestScreenWidthDp = 700; - device_config.screenWidthDp = 700; - device_config.screenHeightDp = 1024; - device_config.sdkVersion = 27; - - Res_value value; - ResTable_config config; - uint32_t flags = 0u; - ApkAssetsCookie cookie = - assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/, - 0u /*density_override*/, &value, &config, &flags); - if (cookie == kInvalidCookie) { - state.SkipWithError("failed to find R.layout.layout"); - return; - } - - size_t len = 0u; - const char* layout_path = - assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len); - if (layout_path == nullptr || len == 0u) { - state.SkipWithError("failed to lookup layout path"); - return; - } - - std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset( - StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER); - if (asset == nullptr) { - state.SkipWithError("failed to load layout"); - return; - } - - ResXMLTree xml_tree; - if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) { - state.SkipWithError("corrupt xml layout"); - return; - } - - // Skip to the first tag. - while (xml_tree.next() != ResXMLParser::START_TAG) { - } - - std::unique_ptr<Theme> theme = assetmanager.NewTheme(); - theme->ApplyStyle(Theme_Material_Light); - - std::array<uint32_t, 92> attrs{ - {0x0101000e, 0x01010034, 0x01010095, 0x01010096, 0x01010097, 0x01010098, 0x01010099, - 0x0101009a, 0x0101009b, 0x010100ab, 0x010100af, 0x010100b0, 0x010100b1, 0x0101011f, - 0x01010120, 0x0101013f, 0x01010140, 0x0101014e, 0x0101014f, 0x01010150, 0x01010151, - 0x01010152, 0x01010153, 0x01010154, 0x01010155, 0x01010156, 0x01010157, 0x01010158, - 0x01010159, 0x0101015a, 0x0101015b, 0x0101015c, 0x0101015d, 0x0101015e, 0x0101015f, - 0x01010160, 0x01010161, 0x01010162, 0x01010163, 0x01010164, 0x01010165, 0x01010166, - 0x01010167, 0x01010168, 0x01010169, 0x0101016a, 0x0101016b, 0x0101016c, 0x0101016d, - 0x0101016e, 0x0101016f, 0x01010170, 0x01010171, 0x01010217, 0x01010218, 0x0101021d, - 0x01010220, 0x01010223, 0x01010224, 0x01010264, 0x01010265, 0x01010266, 0x010102c5, - 0x010102c6, 0x010102c7, 0x01010314, 0x01010315, 0x01010316, 0x0101035e, 0x0101035f, - 0x01010362, 0x01010374, 0x0101038c, 0x01010392, 0x01010393, 0x010103ac, 0x0101045d, - 0x010104b6, 0x010104b7, 0x010104d6, 0x010104d7, 0x010104dd, 0x010104de, 0x010104df, - 0x01010535, 0x01010536, 0x01010537, 0x01010538, 0x01010546, 0x01010567, 0x011100c9, - 0x011100ca}}; - - std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; - std::array<uint32_t, attrs.size() + 1> indices; - while (state.KeepRunning()) { - ApplyStyle(theme.get(), &xml_tree, 0x01010084u /*def_style_attr*/, 0u /*def_style_res*/, - attrs.data(), attrs.size(), values.data(), indices.data()); - } -} -BENCHMARK(BM_ApplyStyleFramework); - -} // namespace android diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp index cc3053798e7b..2d73ce8f8ee3 100644 --- a/libs/androidfw/tests/AttributeResolution_test.cpp +++ b/libs/androidfw/tests/AttributeResolution_test.cpp @@ -21,7 +21,6 @@ #include "android-base/file.h" #include "android-base/logging.h" #include "android-base/macros.h" -#include "androidfw/AssetManager2.h" #include "TestHelpers.h" #include "data/styles/R.h" @@ -33,14 +32,15 @@ namespace android { class AttributeResolutionTest : public ::testing::Test { public: virtual void SetUp() override { - styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk"); - ASSERT_NE(nullptr, styles_assets_); - assetmanager_.SetApkAssets({styles_assets_.get()}); + std::string contents; + ASSERT_TRUE(ReadFileFromZipToString( + GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents)); + ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(), + 1 /*cookie*/, true /*copyData*/)); } protected: - std::unique_ptr<const ApkAssets> styles_assets_; - AssetManager2 assetmanager_; + ResTable table_; }; class AttributeResolutionXmlTest : public AttributeResolutionTest { @@ -48,12 +48,13 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest { virtual void SetUp() override { AttributeResolutionTest::SetUp(); - std::unique_ptr<Asset> asset = - assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER); - ASSERT_NE(nullptr, asset); + std::string contents; + ASSERT_TRUE( + ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", + "res/layout/layout.xml", &contents)); - ASSERT_EQ(NO_ERROR, - xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/)); + ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(), + true /*copyData*/)); // Skip to the first tag. while (xml_parser_.next() != ResXMLParser::START_TAG) { @@ -65,14 +66,14 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest { }; TEST_F(AttributeResolutionTest, Theme) { - std::unique_ptr<Theme> theme = assetmanager_.NewTheme(); - ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo)); + ResTable::Theme theme(table_); + ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; - ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/, + ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/, nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(), attrs.size(), values.data(), nullptr /*out_indices*/)); @@ -125,8 +126,8 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) { R::attr::attr_four, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; - ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(), - values.data(), nullptr /*out_indices*/)); + ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(), + nullptr /*out_indices*/)); uint32_t* values_cursor = values.data(); EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); @@ -170,15 +171,15 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) { } TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { - std::unique_ptr<Theme> theme = assetmanager_.NewTheme(); - ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo)); + ResTable::Theme theme(table_); + ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; std::array<uint32_t, attrs.size() + 1> indices; - ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(), + ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(), attrs.size(), values.data(), indices.data()); const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC; diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp index faddfe599af4..7149beef797f 100644 --- a/libs/androidfw/tests/BenchmarkHelpers.cpp +++ b/libs/androidfw/tests/BenchmarkHelpers.cpp @@ -33,21 +33,19 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab } } - // Make sure to force creation of the ResTable first, or else the configuration doesn't get set. - const ResTable& table = assetmanager.getResources(true); if (config != nullptr) { assetmanager.setConfiguration(*config); } + const ResTable& table = assetmanager.getResources(true); + Res_value value; ResTable_config selected_config; uint32_t flags; - uint32_t last_ref = 0u; while (state.KeepRunning()) { - ssize_t block = table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags, - &selected_config); - table.resolveReference(&value, block, &last_ref, &flags, &selected_config); + table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags, + &selected_config); } } @@ -74,12 +72,10 @@ void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_ Res_value value; ResTable_config selected_config; uint32_t flags; - uint32_t last_id = 0u; while (state.KeepRunning()) { - ApkAssetsCookie cookie = assetmanager.GetResource( - resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags); - assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id); + assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value, + &selected_config, &flags); } } diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index bedebd66cb2f..37ddafb14fd3 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -16,8 +16,6 @@ #include "androidfw/LoadedArsc.h" -#include "androidfw/ResourceUtils.h" - #include "TestHelpers.h" #include "data/basic/R.h" #include "data/libclient/R.h" @@ -29,13 +27,6 @@ namespace basic = com::android::basic; namespace libclient = com::android::libclient; namespace sparse = com::android::sparse; -using ::testing::Eq; -using ::testing::Ge; -using ::testing::IsNull; -using ::testing::NotNull; -using ::testing::SizeIs; -using ::testing::StrEq; - namespace android { TEST(LoadedArscTest, LoadSinglePackageArsc) { @@ -44,24 +35,39 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) { &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); - ASSERT_THAT(loaded_arsc, NotNull()); + ASSERT_NE(nullptr, loaded_arsc); + + const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages(); + ASSERT_EQ(1u, packages.size()); + EXPECT_EQ(std::string("com.android.app"), packages[0]->GetPackageName()); + EXPECT_EQ(0x7f, packages[0]->GetPackageId()); + + ResTable_config config; + memset(&config, 0, sizeof(config)); + config.sdkVersion = 24; + + FindEntryResult entry; - const LoadedPackage* package = - loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one)); - ASSERT_THAT(package, NotNull()); - EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app")); - EXPECT_THAT(package->GetPackageId(), Eq(0x7f)); + ASSERT_TRUE(loaded_arsc->FindEntry(app::R::string::string_one, config, &entry)); + ASSERT_NE(nullptr, entry.entry); +} - const uint8_t type_index = get_type_id(app::R::string::string_one) - 1; - const uint16_t entry_index = get_entry_id(app::R::string::string_one); +TEST(LoadedArscTest, FindDefaultEntry) { + std::string contents; + ASSERT_TRUE( + ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents)); - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_count, Ge(1u)); + std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); + ASSERT_NE(nullptr, loaded_arsc); - const ResTable_type* type = type_spec->types[0]; - ASSERT_THAT(type, NotNull()); - ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull()); + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + desired_config.language[0] = 'd'; + desired_config.language[1] = 'e'; + + FindEntryResult entry; + ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry)); + ASSERT_NE(nullptr, entry.entry); } TEST(LoadedArscTest, LoadSparseEntryApp) { @@ -70,22 +76,15 @@ TEST(LoadedArscTest, LoadSparseEntryApp) { &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); - ASSERT_THAT(loaded_arsc, NotNull()); - - const LoadedPackage* package = - loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9)); - ASSERT_THAT(package, NotNull()); + ASSERT_NE(nullptr, loaded_arsc); - const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1; - const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9); + ResTable_config config; + memset(&config, 0, sizeof(config)); + config.sdkVersion = 26; - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_count, Ge(1u)); - - const ResTable_type* type = type_spec->types[0]; - ASSERT_THAT(type, NotNull()); - ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull()); + FindEntryResult entry; + ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry)); + ASSERT_NE(nullptr, entry.entry); } TEST(LoadedArscTest, LoadSharedLibrary) { @@ -94,13 +93,14 @@ TEST(LoadedArscTest, LoadSharedLibrary) { &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); - ASSERT_THAT(loaded_arsc, NotNull()); + ASSERT_NE(nullptr, loaded_arsc); const auto& packages = loaded_arsc->GetPackages(); - ASSERT_THAT(packages, SizeIs(1u)); + ASSERT_EQ(1u, packages.size()); + EXPECT_TRUE(packages[0]->IsDynamic()); - EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one")); - EXPECT_THAT(packages[0]->GetPackageId(), Eq(0)); + EXPECT_EQ(std::string("com.android.lib_one"), packages[0]->GetPackageName()); + EXPECT_EQ(0, packages[0]->GetPackageId()); const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap(); @@ -114,23 +114,25 @@ TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) { "resources.arsc", &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); - ASSERT_THAT(loaded_arsc, NotNull()); + ASSERT_NE(nullptr, loaded_arsc); const auto& packages = loaded_arsc->GetPackages(); - ASSERT_THAT(packages, SizeIs(1u)); + ASSERT_EQ(1u, packages.size()); + EXPECT_FALSE(packages[0]->IsDynamic()); - EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient")); - EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f)); + EXPECT_EQ(std::string("com.android.libclient"), packages[0]->GetPackageName()); + EXPECT_EQ(0x7f, packages[0]->GetPackageId()); const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap(); // The library has two dependencies. - ASSERT_THAT(dynamic_pkg_map, SizeIs(2u)); - EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one")); - EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02)); + ASSERT_EQ(2u, dynamic_pkg_map.size()); - EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two")); - EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03)); + EXPECT_EQ(std::string("com.android.lib_one"), dynamic_pkg_map[0].package_name); + EXPECT_EQ(0x02, dynamic_pkg_map[0].package_id); + + EXPECT_EQ(std::string("com.android.lib_two"), dynamic_pkg_map[1].package_name); + EXPECT_EQ(0x03, dynamic_pkg_map[1].package_id); } TEST(LoadedArscTest, LoadAppAsSharedLibrary) { @@ -141,12 +143,13 @@ TEST(LoadedArscTest, LoadAppAsSharedLibrary) { std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/, true /*load_as_shared_library*/); - ASSERT_THAT(loaded_arsc, NotNull()); + ASSERT_NE(nullptr, loaded_arsc); const auto& packages = loaded_arsc->GetPackages(); - ASSERT_THAT(packages, SizeIs(1u)); + ASSERT_EQ(1u, packages.size()); + EXPECT_TRUE(packages[0]->IsDynamic()); - EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f)); + EXPECT_EQ(0x7f, packages[0]->GetPackageId()); } TEST(LoadedArscTest, LoadFeatureSplit) { @@ -154,27 +157,21 @@ TEST(LoadedArscTest, LoadFeatureSplit) { ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc", &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); - ASSERT_THAT(loaded_arsc, NotNull()); + ASSERT_NE(nullptr, loaded_arsc); - const LoadedPackage* package = - loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3)); - ASSERT_THAT(package, NotNull()); + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); - uint8_t type_index = get_type_id(basic::R::string::test3) - 1; - uint8_t entry_index = get_entry_id(basic::R::string::test3); - - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_count, Ge(1u)); - ASSERT_THAT(type_spec->types[0], NotNull()); + FindEntryResult entry; + ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry)); size_t len; - const char16_t* type_name16 = - package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len); - ASSERT_THAT(type_name16, NotNull()); - EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string")); + const char16_t* type_name16 = entry.type_string_ref.string16(&len); + ASSERT_NE(nullptr, type_name16); + ASSERT_NE(0u, len); - ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull()); + std::string type_name = util::Utf16ToUtf8(StringPiece16(type_name16, len)); + EXPECT_EQ(std::string("string"), type_name); } class MockLoadedIdmap : public LoadedIdmap { @@ -202,33 +199,23 @@ class MockLoadedIdmap : public LoadedIdmap { }; TEST(LoadedArscTest, LoadOverlay) { - std::string contents; + std::string contents, overlay_contents; + ASSERT_TRUE( + ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents)); ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc", - &contents)); + &overlay_contents)); MockLoadedIdmap loaded_idmap; std::unique_ptr<const LoadedArsc> loaded_arsc = - LoadedArsc::Load(StringPiece(contents), &loaded_idmap); - ASSERT_THAT(loaded_arsc, NotNull()); - - const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u); - ASSERT_THAT(package, NotNull()); - - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_count, Ge(1u)); - ASSERT_THAT(type_spec->types[0], NotNull()); - - // The entry being overlaid doesn't exist at the original entry index. - ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull()); - - // Since this is an overlay, the actual entry ID must be mapped. - ASSERT_THAT(type_spec->idmap_entries, NotNull()); - uint16_t target_entry_id = 0u; - ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id)); - ASSERT_THAT(target_entry_id, Eq(0x0u)); - ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull()); + LoadedArsc::Load(StringPiece(overlay_contents), &loaded_idmap); + ASSERT_NE(nullptr, loaded_arsc); + + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + + FindEntryResult entry; + ASSERT_TRUE(loaded_arsc->FindEntry(0x08030001u, desired_config, &entry)); } // structs with size fields (like Res_value, ResTable_entry) should be diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index df0c642f4565..43a995536d89 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -20,7 +20,6 @@ #include <string> #include "androidfw/ResourceTypes.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "CommonHelpers.h" diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h index b7e814fea079..94a2a14ced87 100644 --- a/libs/androidfw/tests/data/basic/R.h +++ b/libs/androidfw/tests/data/basic/R.h @@ -34,7 +34,6 @@ struct R { struct layout { enum : uint32_t { main = 0x7f020000, - layoutt = 0x7f020001, }; }; @@ -56,7 +55,6 @@ struct R { number2 = 0x7f040001, ref1 = 0x7f040002, ref2 = 0x7f040003, - deep_ref = 0x7f040004, // From feature number3 = 0x80030000, diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk Binary files differindex 1733b6a16546..18ef75e91ded 100644 --- a/libs/androidfw/tests/data/basic/basic.apk +++ b/libs/androidfw/tests/data/basic/basic.apk diff --git a/libs/androidfw/tests/data/basic/res/layout/layout.xml b/libs/androidfw/tests/data/basic/res/layout/layout.xml deleted file mode 100644 index 045ede454bca..000000000000 --- a/libs/androidfw/tests/data/basic/res/layout/layout.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<Button xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/ok" - android:layout_width="0sp" - android:layout_height="fill_parent" - android:layout_weight="1" - android:layout_marginStart="2dip" - android:layout_marginEnd="2dip" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textStyle="bold" - android:text="@android:string/ok" />
\ No newline at end of file diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml index b3435629265b..6c474596b5cd 100644 --- a/libs/androidfw/tests/data/basic/res/values/values.xml +++ b/libs/androidfw/tests/data/basic/res/values/values.xml @@ -22,7 +22,6 @@ <attr name="attr2" format="reference|integer" /> <public type="layout" name="main" id="0x7f020000" /> - <public type="layout" name="layout" id="0x7f020001" /> <public type="string" name="test1" id="0x7f030000" /> <string name="test1">test1</string> @@ -44,18 +43,6 @@ <public type="integer" name="ref2" id="0x7f040003" /> <integer name="ref2">12000</integer> - <public type="integer" name="deep_ref" id="0x7f040004" /> - <integer name="deep_ref">@integer/deep_ref_1</integer> - <integer name="deep_ref_1">@integer/deep_ref_2</integer> - <integer name="deep_ref_2">@integer/deep_ref_3</integer> - <integer name="deep_ref_3">@integer/deep_ref_4</integer> - <integer name="deep_ref_4">@integer/deep_ref_5</integer> - <integer name="deep_ref_5">@integer/deep_ref_6</integer> - <integer name="deep_ref_6">@integer/deep_ref_7</integer> - <integer name="deep_ref_7">@integer/deep_ref_8</integer> - <integer name="deep_ref_8">@integer/deep_ref_9</integer> - <integer name="deep_ref_9">100</integer> - <public type="style" name="Theme1" id="0x7f050000" /> <style name="Theme1"> <item name="com.android.basic:attr1">100</item> |