summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/Android.bp2
-rw-r--r--libs/androidfw/AssetManager2.cpp279
-rw-r--r--libs/androidfw/AttributeResolution.cpp263
-rw-r--r--libs/androidfw/LoadedArsc.cpp263
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h66
-rw-r--r--libs/androidfw/include/androidfw/AttributeFinder.h6
-rw-r--r--libs/androidfw/include/androidfw/AttributeResolution.h11
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h110
-rw-r--r--libs/androidfw/include/androidfw/MutexGuard.h101
-rw-r--r--libs/androidfw/tests/ApkAssets_test.cpp78
-rw-r--r--libs/androidfw/tests/AssetManager2_bench.cpp59
-rw-r--r--libs/androidfw/tests/AttributeResolution_bench.cpp175
-rw-r--r--libs/androidfw/tests/AttributeResolution_test.cpp39
-rw-r--r--libs/androidfw/tests/BenchmarkHelpers.cpp16
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp169
-rw-r--r--libs/androidfw/tests/TestHelpers.h1
-rw-r--r--libs/androidfw/tests/data/basic/R.h2
-rw-r--r--libs/androidfw/tests/data/basic/basic.apkbin5260 -> 3124 bytes
-rw-r--r--libs/androidfw/tests/data/basic/res/layout/layout.xml25
-rw-r--r--libs/androidfw/tests/data/basic/res/values/values.xml13
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, &current_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
index 1733b6a16546..18ef75e91ded 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
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>