From b3ae42e9762a826b1591ab932a6a092ad3e6c3a7 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 16 Oct 2018 12:48:38 -0700 Subject: Copy common resources between styles The docuemntation of setTo states that the resources two styles from different AssetManagers have in common will be set in the destination theme. This change adds this functionality. The package ids of the attributes, the package ids of reference values, and the cookie of attribute values have to be rewritten to match the destination AssetManager. This change can later be made more generic if rewriting references between packages is needed elsewhere. Bug: 115897657 Test: libandroidfw_tests and manual test of app specified in the bug Change-Id: Iee999ea2cc8473168cac11aaf3c34e14c958e5ae --- libs/androidfw/AssetManager2.cpp | 243 +++++++++++++++++++++++++++++++++++---- 1 file changed, 221 insertions(+), 22 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 04cc5bb30ade..288ba32c47a6 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "android-base/logging.h" #include "android-base/stringprintf.h" @@ -869,6 +870,17 @@ void AssetManager2::InvalidateCaches(uint32_t diff) { } } +uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) { + for (auto& package_group : package_groups_) { + for (auto& package2 : package_group.packages_) { + if (package2.loaded_package_ == package) { + return package_group.dynamic_ref_table.mAssignedPackageId; + } + } + } + return 0; +} + std::unique_ptr AssetManager2::NewTheme() { return std::unique_ptr(new Theme(this)); } @@ -1054,44 +1066,231 @@ void Theme::Clear() { } } -bool Theme::SetTo(const Theme& o) { +void Theme::SetTo(const Theme& o) { if (this == &o) { - return true; + return; } type_spec_flags_ = o.type_spec_flags_; - const bool copy_only_system = asset_manager_ != o.asset_manager_; + if (asset_manager_ == o.asset_manager_) { + // The theme comes from the same asset manager so all theme data can be copied exactly + for (size_t p = 0; p < packages_.size(); p++) { + const Package *package = o.packages_[p].get(); + if (package == nullptr) { + // The other theme doesn't have this package, clear ours. + packages_[p].reset(); + continue; + } + + if (packages_[p] == nullptr) { + // The other theme has this package, but we don't. Make one. + packages_[p].reset(new Package()); + } - for (size_t p = 0; p < packages_.size(); p++) { - const Package* package = o.packages_[p].get(); - if (package == nullptr || (copy_only_system && p != 0x01)) { - // The other theme doesn't have this package, clear ours. - packages_[p].reset(); - continue; + for (size_t t = 0; t < package->types.size(); t++) { + const ThemeType *type = package->types[t].get(); + if (type == nullptr) { + // The other theme doesn't have this type, clear ours. + packages_[p]->types[t].reset(); + continue; + } + + // Create a new type and update it to theirs. + const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry)); + void *copied_data = malloc(type_alloc_size); + memcpy(copied_data, type, type_alloc_size); + packages_[p]->types[t].reset(reinterpret_cast(copied_data)); + } + } + } else { + std::map src_to_dest_asset_cookies; + typedef std::map SourceToDestinationRuntimePackageMap; + std::map src_asset_cookie_id_map; + + // Determine which ApkAssets are loaded in both theme AssetManagers + std::vector src_assets = o.asset_manager_->GetApkAssets(); + for (size_t i = 0; i < src_assets.size(); i++) { + const ApkAssets* src_asset = src_assets[i]; + + std::vector dest_assets = asset_manager_->GetApkAssets(); + for (size_t j = 0; j < dest_assets.size(); j++) { + const ApkAssets* dest_asset = dest_assets[j]; + + // Map the runtime package of the source apk asset to the destination apk asset + if (src_asset->GetPath() == dest_asset->GetPath()) { + const std::vector>& src_packages = + src_asset->GetLoadedArsc()->GetPackages(); + const std::vector>& dest_packages = + dest_asset->GetLoadedArsc()->GetPackages(); + + SourceToDestinationRuntimePackageMap package_map; + + // The source and destination package should have the same number of packages loaded in + // the same order. + const size_t N = src_packages.size(); + CHECK(N == dest_packages.size()) + << " LoadedArsc " << src_asset->GetPath() << " differs number of packages."; + for (size_t p = 0; p < N; p++) { + auto& src_package = src_packages[p]; + auto& dest_package = dest_packages[p]; + CHECK(src_package->GetPackageName() == dest_package->GetPackageName()) + << " Package " << src_package->GetPackageName() << " differs in load order."; + + int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get()); + int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get()); + package_map[src_package_id] = dest_package_id; + } + + src_to_dest_asset_cookies.insert(std::pair(i, j)); + src_asset_cookie_id_map.insert( + std::pair(i, package_map)); + break; + } + } + } + + // Reset the data in the destination theme + for (size_t p = 0; p < packages_.size(); p++) { + if (packages_[p] != nullptr) { + packages_[p].reset(); + } + } + + for (size_t p = 0; p < packages_.size(); p++) { + const Package *package = o.packages_[p].get(); + if (package == nullptr) { + continue; + } + + for (size_t t = 0; t < package->types.size(); t++) { + const ThemeType *type = package->types[t].get(); + if (type == nullptr) { + continue; + } + + for (size_t e = 0; e < type->entry_count; e++) { + const ThemeEntry &entry = type->entries[e]; + if (entry.value.dataType == Res_value::TYPE_NULL && + entry.value.data != Res_value::DATA_NULL_EMPTY) { + continue; + } + + // The package id of the attribute needs to be rewritten to the package id of the value in + // the destination + int attribute_dest_package_id = p; + if (attribute_dest_package_id != 0x01) { + // Find the cookie of the attribute resource id + FindEntryResult attribute_entry_result; + ApkAssetsCookie attribute_cookie = + o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false, + &attribute_entry_result); + + // Determine the package id of the attribute in the destination AssetManager + auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie); + if (attribute_package_map == src_asset_cookie_id_map.end()) { + continue; + } + auto attribute_dest_package = attribute_package_map->second.find( + attribute_dest_package_id); + if (attribute_dest_package == attribute_package_map->second.end()) { + continue; + } + attribute_dest_package_id = attribute_dest_package->second; + } + + // If the attribute value represents an attribute or reference, the package id of the + // value needs to be rewritten to the package id of the value in the destination + uint32_t attribue_data = entry.value.data; + if (entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE + || entry.value.dataType == Res_value::TYPE_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_REFERENCE) { + + // Determine the package id of the reference in the destination AssetManager + auto value_package_map = src_asset_cookie_id_map.find(entry.cookie); + if (value_package_map == src_asset_cookie_id_map.end()) { + continue; + } + + auto value_dest_package = value_package_map->second.find( + get_package_id(entry.value.data)); + if (value_dest_package == value_package_map->second.end()) { + continue; + } + + attribue_data = fix_package_id(entry.value.data, value_dest_package->second); + } + + // Lazily instantiate the destination package + std::unique_ptr& dest_package = packages_[attribute_dest_package_id]; + if (dest_package == nullptr) { + dest_package.reset(new Package()); + } + + // Lazily instantiate and resize the destination type + util::unique_cptr& dest_type = dest_package->types[t]; + if (dest_type == nullptr || dest_type->entry_count < type->entry_count) { + const size_t type_alloc_size = sizeof(ThemeType) + + (type->entry_count * sizeof(ThemeEntry)); + void* dest_data = malloc(type_alloc_size); + memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry)); + + // Copy the existing destination type values if the type is resized + if (dest_type != nullptr) { + memcpy(dest_data, type, sizeof(ThemeType) + + (dest_type->entry_count * sizeof(ThemeEntry))); + } + + dest_type.reset(reinterpret_cast(dest_data)); + dest_type->entry_count = type->entry_count; + } + + // Find the cookie of the value in the destination + auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie); + if (value_dest_cookie == src_to_dest_asset_cookies.end()) { + continue; + } + + dest_type->entries[e].cookie = value_dest_cookie->second; + dest_type->entries[e].value.dataType = entry.value.dataType; + dest_type->entries[e].value.data = attribue_data; + dest_type->entries[e].type_spec_flags = entry.type_spec_flags; + } + } } + } +} + +void Theme::Dump() const { + base::ScopedLogSeverity _log(base::INFO); + LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_); - if (packages_[p] == nullptr) { - // The other theme has this package, but we don't. Make one. - packages_[p].reset(new Package()); + for (int p = 0; p < packages_.size(); p++) { + auto& package = packages_[p]; + if (package == nullptr) { + continue; } - for (size_t t = 0; t < package->types.size(); t++) { - const ThemeType* type = package->types[t].get(); + for (int t = 0; t < package->types.size(); t++) { + auto& type = package->types[t]; if (type == nullptr) { - // The other theme doesn't have this type, clear ours. - packages_[p]->types[t].reset(); continue; } - // Create a new type and update it to theirs. - const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry)); - void* copied_data = malloc(type_alloc_size); - memcpy(copied_data, type, type_alloc_size); - packages_[p]->types[t].reset(reinterpret_cast(copied_data)); + for (int e = 0; e < type->entry_count; e++) { + auto& entry = type->entries[e]; + if (entry.value.dataType == Res_value::TYPE_NULL && + entry.value.data != Res_value::DATA_NULL_EMPTY) { + continue; + } + + LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)", + make_resid(p, t, e), entry.value.data, + entry.value.dataType, entry.cookie); + } } } - return true; } } // namespace android -- cgit v1.2.3-59-g8ed1b From 5db396d5cc780ecf13cdfd25c8af15a220065f14 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Mon, 5 Nov 2018 15:56:15 -0800 Subject: Only resolve non-dynamic resource references Only resolve non-dynamic references and attributes if the package is loaded as a library or if a shared library is attempting to retrieve its own resources. Bug: 116486668 Bug: 116620612 Test: libandroidfw_tests & manual test of broken apps & atest FieldsClassificationTest#testGetAlgorith Change-Id: Icb827796a65072a39452dbe577d5e18f085ea4e2 --- libs/androidfw/AssetManager2.cpp | 7 ++++ libs/androidfw/ResourceTypes.cpp | 32 ++++++++++----- libs/androidfw/tests/DynamicRefTable_test.cpp | 58 +++++++++++++++++++++++---- 3 files changed, 78 insertions(+), 19 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 288ba32c47a6..9e6948878b1d 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -162,6 +162,13 @@ void AssetManager2::DumpToLog() const { LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list; + + for (size_t i = 0; i < 256; i++) { + if (package_group.dynamic_ref_table.mLookupTable[i] != 0) { + LOG(INFO) << base::StringPrintf(" e[0x%02x] -> 0x%02x", (uint8_t) i, + package_group.dynamic_ref_table.mLookupTable[i]); + } + } } } diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index dc4a0a706bae..388548b174f9 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -6998,18 +6998,28 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { } status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { - uint8_t resolvedType; - - if (value->dataType == Res_value::TYPE_ATTRIBUTE - || value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) { - resolvedType = Res_value::TYPE_ATTRIBUTE; - - } else if (value->dataType == Res_value::TYPE_REFERENCE - || value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) { - resolvedType = Res_value::TYPE_REFERENCE; + uint8_t resolvedType = Res_value::TYPE_REFERENCE; + switch (value->dataType) { + case Res_value::TYPE_ATTRIBUTE: + resolvedType = Res_value::TYPE_ATTRIBUTE; + // fallthrough + case Res_value::TYPE_REFERENCE: + // Only resolve non-dynamic references and attributes if the package is loaded as a + // library or if a shared library is attempting to retrieve its own resource + if (!(mAppAsLib || (Res_GETPACKAGE(value->data) + 1) == 0)) { + return NO_ERROR; + } - } else { - return NO_ERROR; + // If the package is loaded as shared library, the resource reference + // also need to be fixed. + break; + case Res_value::TYPE_DYNAMIC_ATTRIBUTE: + resolvedType = Res_value::TYPE_ATTRIBUTE; + // fallthrough + case Res_value::TYPE_DYNAMIC_REFERENCE: + break; + default: + return NO_ERROR; } status_t err = lookupResourceId(&value->data); diff --git a/libs/androidfw/tests/DynamicRefTable_test.cpp b/libs/androidfw/tests/DynamicRefTable_test.cpp index df44e343b2b4..5acc46a3c0d9 100644 --- a/libs/androidfw/tests/DynamicRefTable_test.cpp +++ b/libs/androidfw/tests/DynamicRefTable_test.cpp @@ -40,6 +40,26 @@ TEST(DynamicRefTableTest, LookupSharedLibSelfReferences) { EXPECT_EQ(value2.data, 0x02010000); }; +TEST(DynamicRefTableTest, LookupSharedLibSelfAttributes) { + // Shared library + DynamicRefTable shared_table(0x03, /* appAsLib */ false); + shared_table.addMapping(0x00, 0x03); + Res_value value; + value.dataType = Res_value::TYPE_ATTRIBUTE; + value.data = 0x00010000; + ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR); + EXPECT_EQ(value.data, 0x03010000); + + // App loaded as a shared library + DynamicRefTable shared_app_table(0x04, /* appAsLib */ true); + shared_app_table.addMapping(0x7f, 0x04); + Res_value value2; + value2.dataType = Res_value::TYPE_ATTRIBUTE; + value2.data = 0x7f010000; + ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR); + EXPECT_EQ(value2.data, 0x04010000); +}; + TEST(DynamicRefTableTest, LookupDynamicReferences) { // Shared library DynamicRefTable shared_table(0x2, /* appAsLib */ false); @@ -51,24 +71,46 @@ TEST(DynamicRefTableTest, LookupDynamicReferences) { ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR); EXPECT_EQ(value.data, 0x05010000); - // App loaded as a shared library + // Regular application + DynamicRefTable app_table(0x7f, /* appAsLib */ false); + app_table.addMapping(0x03, 0x05); + Res_value value3; + value3.dataType = Res_value::TYPE_DYNAMIC_REFERENCE; + value3.data = 0x03010000; + ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR); + EXPECT_EQ(value3.data, 0x05010000); +}; + +TEST(DynamicRefTableTest, LookupDynamicAttributes) { +// App loaded as a shared library DynamicRefTable shared_app_table(0x2, /* appAsLib */ true); shared_app_table.addMapping(0x03, 0x05); shared_app_table.addMapping(0x7f, 0x2); Res_value value2; - value2.dataType = Res_value::TYPE_DYNAMIC_REFERENCE; + value2.dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE; value2.data = 0x03010000; ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR); EXPECT_EQ(value2.data, 0x05010000); +} +TEST(DynamicRefTableTest, DoNotLookupNonDynamicReferences) { // Regular application DynamicRefTable app_table(0x7f, /* appAsLib */ false); - app_table.addMapping(0x03, 0x05); - Res_value value3; - value3.dataType = Res_value::TYPE_REFERENCE; - value3.data = 0x03010000; - ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR); - EXPECT_EQ(value3.data, 0x05010000); + Res_value value; + value.dataType = Res_value::TYPE_REFERENCE; + value.data = 0x03010000; + ASSERT_EQ(app_table.lookupResourceValue(&value), NO_ERROR); + EXPECT_EQ(value.data, 0x03010000); +}; + +TEST(DynamicRefTableTest, DoNotLookupNonDynamicAttributes) { + // App with custom package id + DynamicRefTable custom_app_table(0x8f, /* appAsLib */ false); + Res_value value2; + value2.dataType = Res_value::TYPE_ATTRIBUTE; + value2.data = 0x03010000; + ASSERT_EQ(custom_app_table.lookupResourceValue(&value2), NO_ERROR); + EXPECT_EQ(value2.data, 0x03010000); }; } // namespace android \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From d42a670ee59618e98078079b554f2652035eb1e2 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Thu, 15 Nov 2018 15:48:28 -0800 Subject: Add style value to ResolvedBag in AssetManager2. Bug: 117176857 Test: updated AssetManager2Test.MergesStylesWithParentFromSingleApkAssets Change-Id: I2b79eea8e43431a932756b267b91eb4423c968a5 --- libs/androidfw/AssetManager2.cpp | 3 +++ libs/androidfw/AttributeResolution.cpp | 4 ++-- libs/androidfw/include/androidfw/AssetManager2.h | 3 +++ libs/androidfw/tests/AssetManager2_test.cpp | 6 ++++++ 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 9e6948878b1d..85e72cccc703 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -637,6 +637,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector& new_entry->key = new_key; new_entry->key_pool = nullptr; new_entry->type_pool = nullptr; + new_entry->style = resid; new_entry->value.copyFrom_dtoh(map_entry->value); status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value); if (err != NO_ERROR) { @@ -695,6 +696,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector& new_entry->key_pool = nullptr; new_entry->type_pool = nullptr; new_entry->value.copyFrom_dtoh(map_entry->value); + new_entry->style = resid; status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value); if (err != NO_ERROR) { LOG(ERROR) << base::StringPrintf( @@ -731,6 +733,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector& new_entry->key_pool = nullptr; new_entry->type_pool = nullptr; new_entry->value.copyFrom_dtoh(map_entry->value); + new_entry->style = resid; status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value); if (err != NO_ERROR) { LOG(ERROR) << base::StringPrintf("Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp index f912af4f7190..57e3491895e6 100644 --- a/libs/androidfw/AttributeResolution.cpp +++ b/libs/androidfw/AttributeResolution.cpp @@ -310,7 +310,8 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, type_set_flags = style_flags; value = entry->value; if (kDebugStyles) { - ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); + ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data, + entry->style); } } } @@ -388,7 +389,6 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, // out_indices must NOT be nullptr. out_indices[indices_idx] = ii; } - out_values += STYLE_NUM_ENTRIES; } diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 5312b062473a..0d492984d41d 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -49,6 +49,9 @@ struct ResolvedBag { Res_value value; + // The resource ID of the origin style associated with the given entry. + uint32_t style; + // Which ApkAssets this entry came from. ApkAssetsCookie cookie; diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index f1cc569f7d4e..5449a54d08de 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -298,11 +298,13 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) { EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[0].value.dataType); EXPECT_EQ(1u, bag_two->entries[0].value.data); EXPECT_EQ(0, bag_two->entries[0].cookie); + EXPECT_EQ(app::R::style::StyleOne, bag_two->entries[0].style); // attr_two should be overridden from StyleOne by StyleTwo. EXPECT_EQ(app::R::attr::attr_two, bag_two->entries[1].key); EXPECT_EQ(Res_value::TYPE_STRING, bag_two->entries[1].value.dataType); EXPECT_EQ(0, bag_two->entries[1].cookie); + EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[1].style); EXPECT_EQ(std::string("string"), GetStringFromPool(assetmanager.GetStringPoolForCookie(0), bag_two->entries[1].value.data)); @@ -312,21 +314,25 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) { EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, bag_two->entries[2].value.dataType); EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[2].value.data); EXPECT_EQ(0, bag_two->entries[2].cookie); + EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[2].style); EXPECT_EQ(app::R::attr::attr_five, bag_two->entries[3].key); EXPECT_EQ(Res_value::TYPE_REFERENCE, bag_two->entries[3].value.dataType); EXPECT_EQ(app::R::string::string_one, bag_two->entries[3].value.data); EXPECT_EQ(0, bag_two->entries[3].cookie); + EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[3].style); EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[4].key); EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType); EXPECT_EQ(3u, bag_two->entries[4].value.data); EXPECT_EQ(0, bag_two->entries[4].cookie); + EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[4].style); EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key); EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data); EXPECT_EQ(0, bag_two->entries[5].cookie); + EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[5].style); } TEST_F(AssetManager2Test, MergeStylesCircularDependency) { -- cgit v1.2.3-59-g8ed1b From b85d9b2a32949d0cfd6a78701da6597a7aec39d0 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Mon, 19 Nov 2018 12:11:38 -0800 Subject: Fix copying null reference across themes When themes have two different AssetManagers, we only copy attributes that exist in both the themes. If the value of the attribute or reference is equal to 0 (a null reference but not using the TYPE_NULL type), do not attempt to fix the package id of that null reference. Bug: 119522708 Test: manual test of broken app Change-Id: Id615d5a47b7f121b08bbba885d106b9cd3f54afc --- libs/androidfw/AssetManager2.cpp | 51 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 9e6948878b1d..37717a83ccc7 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -1183,8 +1183,32 @@ void Theme::SetTo(const Theme& o) { continue; } - // The package id of the attribute needs to be rewritten to the package id of the value in - // the destination + // If the attribute value represents an attribute or reference, the package id of the + // value needs to be rewritten to the package id of the value in the destination + uint32_t attribue_data = entry.value.data; + if ((entry.value.dataType == Res_value::TYPE_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_REFERENCE + || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) + && attribue_data != 0x0) { + + // Determine the package id of the reference in the destination AssetManager + auto value_package_map = src_asset_cookie_id_map.find(entry.cookie); + if (value_package_map == src_asset_cookie_id_map.end()) { + continue; + } + + auto value_dest_package = value_package_map->second.find( + get_package_id(entry.value.data)); + if (value_dest_package == value_package_map->second.end()) { + continue; + } + + attribue_data = fix_package_id(entry.value.data, value_dest_package->second); + } + + // The package id of the attribute needs to be rewritten to the package id of the + // attribute in the destination int attribute_dest_package_id = p; if (attribute_dest_package_id != 0x01) { // Find the cookie of the attribute resource id @@ -1206,29 +1230,6 @@ void Theme::SetTo(const Theme& o) { attribute_dest_package_id = attribute_dest_package->second; } - // If the attribute value represents an attribute or reference, the package id of the - // value needs to be rewritten to the package id of the value in the destination - uint32_t attribue_data = entry.value.data; - if (entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE - || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE - || entry.value.dataType == Res_value::TYPE_ATTRIBUTE - || entry.value.dataType == Res_value::TYPE_REFERENCE) { - - // Determine the package id of the reference in the destination AssetManager - auto value_package_map = src_asset_cookie_id_map.find(entry.cookie); - if (value_package_map == src_asset_cookie_id_map.end()) { - continue; - } - - auto value_dest_package = value_package_map->second.find( - get_package_id(entry.value.data)); - if (value_dest_package == value_package_map->second.end()) { - continue; - } - - attribue_data = fix_package_id(entry.value.data, value_dest_package->second); - } - // Lazily instantiate the destination package std::unique_ptr& dest_package = packages_[attribute_dest_package_id]; if (dest_package == nullptr) { -- cgit v1.2.3-59-g8ed1b From 449a54fb6bdbe8401d4f7291df46d4d980622ba7 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 30 Nov 2018 15:22:31 -0800 Subject: Do not include system overlay data when excluded Do not include configurations or locales from overlays overriding system resources when exclude_system is specified in GetResourceConfigurations or GetResourceLocales. Bug: 120083032 Test: run cts -m CtsContentTestCases -t android.content.res.cts.AssetManagerTest#testGetNonSystemLocales Change-Id: I4ba3b07d3bb9ac72b196ff7ed4d1e853b51f7eea --- libs/androidfw/AssetManager2.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 7ab12b1b3167..ad9ec02648b1 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -217,10 +217,19 @@ std::set AssetManager2::GetResourceConfigurations(bool exclude_ ATRACE_NAME("AssetManager::GetResourceConfigurations"); std::set configurations; for (const PackageGroup& package_group : package_groups_) { + bool found_system_package = false; for (const ConfiguredPackage& package : package_group.packages_) { if (exclude_system && package.loaded_package_->IsSystem()) { + found_system_package = true; continue; } + + if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) { + // Overlays must appear after the target package to take effect. Any overlay found in the + // same package as a system package is able to overlay system resources. + continue; + } + package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations); } } @@ -232,10 +241,19 @@ std::set AssetManager2::GetResourceLocales(bool exclude_system, ATRACE_NAME("AssetManager::GetResourceLocales"); std::set locales; for (const PackageGroup& package_group : package_groups_) { + bool found_system_package = false; for (const ConfiguredPackage& package : package_group.packages_) { if (exclude_system && package.loaded_package_->IsSystem()) { + found_system_package = true; continue; } + + if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) { + // Overlays must appear after the target package to take effect. Any overlay found in the + // same package as a system package is able to overlay system resources. + continue; + } + package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales); } } -- cgit v1.2.3-59-g8ed1b From 2f3669b767129bc8739bb03e80abc65eb54a3471 Mon Sep 17 00:00:00 2001 From: Winson Date: Fri, 11 Jan 2019 11:28:34 -0800 Subject: Add function to return path for last resolved resource After an AssetManager.FindEntry call is made, either directly or from any of the resource entry calls, a stack of the steps taken to resolve the resource is saved. Those steps can be retrieved as a log later on by calling AssetManager.GetLastResourceResolution, which returns a formatted string of the resource ID/name and path taken, including the configs and package names of each step. Logging and the saving of the steps to memory can be enabled/disabled with the @hide .setResourceResolutionLoggingEnabled() method on AssetManager. Bug: 122374289 Test: cases for single and multi ApkAssets loaded Test: case for no resolution made Test: made test app to display log on device Test: added debugging call to source and ran through on-device apps Change-Id: I6a32b8d4020c3f8510032ff7f431510089fff43f --- core/java/android/content/res/AssetManager.java | 34 ++++ core/java/android/content/res/Resources.java | 24 ++- core/java/android/content/res/ResourcesImpl.java | 7 + core/jni/android_util_AssetManager.cpp | 55 +++--- libs/androidfw/AssetManager2.cpp | 207 +++++++++++++++++------ libs/androidfw/ResourceUtils.cpp | 61 +++++++ libs/androidfw/include/androidfw/AssetManager2.h | 50 ++++++ libs/androidfw/include/androidfw/ResourceUtils.h | 12 ++ libs/androidfw/tests/AssetManager2_test.cpp | 107 ++++++++++++ 9 files changed, 471 insertions(+), 86 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index f1a4db25cd14..9e0a9ba0dc7b 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -732,6 +732,38 @@ public final class AssetManager implements AutoCloseable { } } + /** + * Enable resource resolution logging to track the steps taken to resolve the last resource + * entry retrieved. Stores the configuration and package names for each step. + * + * Default disabled. + * + * @param enabled Boolean indicating whether to enable or disable logging. + * + * @hide + */ + public void setResourceResolutionLoggingEnabled(boolean enabled) { + synchronized (this) { + ensureValidLocked(); + nativeSetResourceResolutionLoggingEnabled(mObject, enabled); + } + } + + /** + * Retrieve the last resource resolution path logged. + * + * @return Formatted string containing last resource ID/name and steps taken to resolve final + * entry, including configuration and package names. + * + * @hide + */ + public @Nullable String getLastResourceResolution() { + synchronized (this) { + ensureValidLocked(); + return nativeGetLastResourceResolution(mObject); + } + } + CharSequence getPooledStringForCookie(int cookie, int id) { // Cookies map to ApkAssets starting at 1. return getApkAssets()[cookie - 1].getStringFromPool(id); @@ -1383,6 +1415,8 @@ public final class AssetManager implements AutoCloseable { private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); + private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); + private static native @Nullable String nativeGetLastResourceResolution(long ptr); // Style attribute retrieval native methods. private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 365ceac68ee1..c4b315ec90c8 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -2010,22 +2010,36 @@ public class Resources { public String getResourceTypeName(@AnyRes int resid) throws NotFoundException { return mResourcesImpl.getResourceTypeName(resid); } - + /** * Return the entry name for a given resource identifier. - * + * * @param resid The resource identifier whose entry name is to be * retrieved. - * + * * @return A string holding the entry name of the resource. - * + * * @throws NotFoundException Throws NotFoundException if the given ID does not exist. - * + * * @see #getResourceName */ public String getResourceEntryName(@AnyRes int resid) throws NotFoundException { return mResourcesImpl.getResourceEntryName(resid); } + + /** + * Return formatted log of the last retrieved resource's resolution path. + * + * @return A string holding a formatted log of the steps taken to resolve the last resource. + * + * @throws NotFoundException Throws NotFoundException if there hasn't been a resource + * resolved yet. + * + * @hide + */ + public String getLastResourceResolution() throws NotFoundException { + return mResourcesImpl.getLastResourceResolution(); + } /** * Parse a series of {@link android.R.styleable#Extra <extra>} tags from diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 2ad4f625ef8c..77796d9ebdf5 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -298,6 +298,13 @@ public class ResourcesImpl { + Integer.toHexString(resid)); } + @NonNull + String getLastResourceResolution() throws NotFoundException { + String str = mAssets.getLastResourceResolution(); + if (str != null) return str; + throw new NotFoundException("Associated AssetManager hasn't resolved a resource"); + } + @NonNull CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { PluralRules rule = getPluralRule(); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 7b564ae162ce..4101c04162af 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -44,6 +44,8 @@ #include "androidfw/MutexGuard.h" #include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" +#include "androidfw/ResourceUtils.h" + #include "core_jni_helpers.h" #include "jni.h" #include "nativehelper/JNIHelp.h" @@ -975,34 +977,7 @@ static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, j return nullptr; } - std::string result; - if (name.package != nullptr) { - result.append(name.package, name.package_len); - } - - if (name.type != nullptr || name.type16 != nullptr) { - if (!result.empty()) { - result += ":"; - } - - if (name.type != nullptr) { - result.append(name.type, name.type_len); - } else { - result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len)); - } - } - - if (name.entry != nullptr || name.entry16 != nullptr) { - if (!result.empty()) { - result += "/"; - } - - if (name.entry != nullptr) { - result.append(name.entry, name.entry_len); - } else { - result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len)); - } - } + std::string result = ToFormattedResourceString(&name); return env->NewStringUTF(result.c_str()); } @@ -1049,6 +1024,26 @@ static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong p return nullptr; } +static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/, + jclass /*clazz*/, + jlong ptr, + jboolean enabled) { + ScopedLock assetmanager(AssetManagerFromLong(ptr)); + assetmanager->SetResourceResolutionLoggingEnabled(enabled); +} + +static jstring NativeGetLastResourceResolution(JNIEnv* env, + jclass /*clazz*/, + jlong ptr) { + ScopedLock assetmanager(AssetManagerFromLong(ptr)); + std::string resolution = assetmanager->GetLastResourceResolution(); + if (resolution.empty()) { + return nullptr; + } else { + return env->NewStringUTF(resolution.c_str()); + } +} + static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr, jboolean exclude_system) { ScopedLock assetmanager(AssetManagerFromLong(ptr)); @@ -1452,6 +1447,10 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName}, {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName}, {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName}, + {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V", + (void*) NativeSetResourceResolutionLoggingEnabled}, + {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;", + (void*) NativeGetLastResourceResolution}, {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales}, {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;", (void*)NativeGetSizeConfigurations}, diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index ad9ec02648b1..3c35d9b33fc8 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -20,8 +20,9 @@ #include #include -#include #include +#include +#include #include "android-base/logging.h" #include "android-base/stringprintf.h" @@ -372,6 +373,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri uint32_t best_offset = 0u; uint32_t type_flags = 0u; + Resolution::Step::Type resolution_type; + std::vector resolution_steps; + // If desired_config is the same as the set configuration, then we can use our filtered list // and we don't need to match the configurations, since they already matched. const bool use_fast_path = desired_config == &configuration_; @@ -403,8 +407,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // 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 FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; const std::vector& candidate_configs = filtered_group.configurations; const size_t type_count = candidate_configs.size(); for (uint32_t i = 0; i < type_count; i++) { @@ -412,21 +416,34 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // 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; - } + if (best_config == nullptr) { + resolution_type = Resolution::Step::Type::INITIAL; + } else if (this_config.isBetterThan(*best_config, desired_config)) { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } else if (package_is_overlay && this_config.compare(*best_config) == 0) { + resolution_type = Resolution::Step::Type::OVERLAID; + } else { + continue; + } + + // The configuration matches and is better than the previous selection. + // Find the entry value if it exists for this configuration. + const ResTable_type* type = filtered_group.types[i]; + const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx); + 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; + best_cookie = cookie; + best_package = loaded_package; + best_type = type; + best_config = &this_config; + best_offset = offset; + + if (resource_resolution_logging_enabled_) { + resolution_steps.push_back(Resolution::Step{resolution_type, + this_config.toString(), + &loaded_package->GetPackageName()}); } } } else { @@ -440,23 +457,38 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri 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; - } + if (!this_config.match(*desired_config)) { + continue; + } - best_cookie = cookie; - best_package = loaded_package; - best_type = *iter; - best_config_copy = this_config; - best_config = &best_config_copy; - best_offset = offset; - } + if (best_config == nullptr) { + resolution_type = Resolution::Step::Type::INITIAL; + } else if (this_config.isBetterThan(*best_config, desired_config)) { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } else if (package_is_overlay && this_config.compare(*best_config) == 0) { + resolution_type = Resolution::Step::Type::OVERLAID; + } else { + continue; + } + + // 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; + + if (resource_resolution_logging_enabled_) { + resolution_steps.push_back(Resolution::Step{resolution_type, + this_config.toString(), + &loaded_package->GetPackageName()}); } } } @@ -478,9 +510,95 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri out_entry->entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); out_entry->dynamic_ref_table = &package_group.dynamic_ref_table; + + if (resource_resolution_logging_enabled_) { + last_resolution.resid = resid; + last_resolution.cookie = best_cookie; + last_resolution.steps = resolution_steps; + + // Cache only the type/entry refs since that's all that's needed to build name + last_resolution.type_string_ref = + StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1); + last_resolution.entry_string_ref = + StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); + } + return best_cookie; } +void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) { + resource_resolution_logging_enabled_ = enabled; + + if (!enabled) { + last_resolution.cookie = kInvalidCookie; + last_resolution.resid = 0; + last_resolution.steps.clear(); + last_resolution.type_string_ref = StringPoolRef(); + last_resolution.entry_string_ref = StringPoolRef(); + } +} + +std::string AssetManager2::GetLastResourceResolution() const { + if (!resource_resolution_logging_enabled_) { + LOG(ERROR) << "Must enable resource resolution logging before getting path."; + return std::string(); + } + + auto cookie = last_resolution.cookie; + if (cookie == kInvalidCookie) { + LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path."; + return std::string(); + } + + uint32_t resid = last_resolution.resid; + std::vector& steps = last_resolution.steps; + + ResourceName resource_name; + std::string resource_name_string; + + const LoadedPackage* package = + apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); + + if (package != nullptr) { + ToResourceName(last_resolution.type_string_ref, + last_resolution.entry_string_ref, + package, + &resource_name); + resource_name_string = ToFormattedResourceString(&resource_name); + } + + std::stringstream log_stream; + log_stream << base::StringPrintf("Resolution for 0x%08x ", resid) + << resource_name_string + << "\n\tFor config -" + << configuration_.toString(); + + std::string prefix; + for (Resolution::Step step : steps) { + switch (step.type) { + case Resolution::Step::Type::INITIAL: + prefix = "Found initial"; + break; + case Resolution::Step::Type::BETTER_MATCH: + prefix = "Found better"; + break; + case Resolution::Step::Type::OVERLAID: + prefix = "Overlaid"; + break; + } + + if (!prefix.empty()) { + log_stream << "\n\t" << prefix << ": " << *step.package_name; + + if (!step.config_name.isEmpty()) { + log_stream << " -" << step.config_name; + } + } + } + + return log_stream.str(); +} + bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; ApkAssetsCookie cookie = @@ -495,27 +613,10 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons return false; } - out_name->package = package->GetPackageName().data(); - out_name->package_len = package->GetPackageName().size(); - - out_name->type = entry.type_string_ref.string8(&out_name->type_len); - out_name->type16 = nullptr; - if (out_name->type == nullptr) { - out_name->type16 = entry.type_string_ref.string16(&out_name->type_len); - if (out_name->type16 == nullptr) { - return false; - } - } - - out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len); - out_name->entry16 = nullptr; - if (out_name->entry == nullptr) { - out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len); - if (out_name->entry16 == nullptr) { - return false; - } - } - return true; + return ToResourceName(entry.type_string_ref, + entry.entry_string_ref, + package, + out_name); } bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const { diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp index d63feb01ef83..645984d85c34 100644 --- a/libs/androidfw/ResourceUtils.cpp +++ b/libs/androidfw/ResourceUtils.cpp @@ -48,4 +48,65 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin !(has_type_separator && out_type->empty()); } +bool ToResourceName(StringPoolRef& type_string_ref, + StringPoolRef& entry_string_ref, + const LoadedPackage* package, + AssetManager2::ResourceName* out_name) { + out_name->package = package->GetPackageName().data(); + out_name->package_len = package->GetPackageName().size(); + + out_name->type = type_string_ref.string8(&out_name->type_len); + out_name->type16 = nullptr; + if (out_name->type == nullptr) { + out_name->type16 = type_string_ref.string16(&out_name->type_len); + if (out_name->type16 == nullptr) { + return false; + } + } + + out_name->entry = entry_string_ref.string8(&out_name->entry_len); + out_name->entry16 = nullptr; + if (out_name->entry == nullptr) { + out_name->entry16 = entry_string_ref.string16(&out_name->entry_len); + if (out_name->entry16 == nullptr) { + return false; + } + } + + return true; +} + +std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) { + std::string result; + if (resource_name->package != nullptr) { + result.append(resource_name->package, resource_name->package_len); + } + + if (resource_name->type != nullptr || resource_name->type16 != nullptr) { + if (!result.empty()) { + result += ":"; + } + + if (resource_name->type != nullptr) { + result.append(resource_name->type, resource_name->type_len); + } else { + result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len)); + } + } + + if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) { + if (!result.empty()) { + result += "/"; + } + + if (resource_name->entry != nullptr) { + result.append(resource_name->entry, resource_name->entry_len); + } else { + result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len)); + } + } + + return result; +} + } // namespace android diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 0d492984d41d..f29769b834d1 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -229,6 +229,14 @@ class AssetManager2 { ResTable_config* in_out_selected_config, uint32_t* in_out_flags, uint32_t* out_last_reference) const; + // Enables or disables resource resolution logging. Clears stored steps when + // disabled. + void SetResourceResolutionLoggingEnabled(bool enabled); + + // Returns formatted log of last resource resolution path, or empty if no + // resource has been resolved yet. + std::string GetLastResourceResolution() const; + // 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. // To iterate over the keys, use the following idiom: @@ -346,6 +354,48 @@ class AssetManager2 { // Cached set of bags. These are cached because they can inherit keys from parent bags, // which involves some calculation. std::unordered_map> cached_bags_; + + // Whether or not to save resource resolution steps + bool resource_resolution_logging_enabled_ = false; + + struct Resolution { + + struct Step { + + enum class Type { + INITIAL, + BETTER_MATCH, + OVERLAID + }; + + // Marks what kind of override this step was. + Type type; + + // Built name of configuration for this step. + String8 config_name; + + // Marks the package name of the better resource found in this step. + const std::string* package_name; + }; + + // Last resolved resource ID. + uint32_t resid; + + // Last resolved resource result cookie. + ApkAssetsCookie cookie = kInvalidCookie; + + // Last resolved resource type. + StringPoolRef type_string_ref; + + // Last resolved resource entry. + StringPoolRef entry_string_ref; + + // Steps taken to resolve last resource. + std::vector steps; + }; + + // Record of the last resolved resource's resolution path. + mutable Resolution last_resolution; }; class Theme { diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h index d94779bf5225..eb6eb8e66175 100644 --- a/libs/androidfw/include/androidfw/ResourceUtils.h +++ b/libs/androidfw/include/androidfw/ResourceUtils.h @@ -17,6 +17,7 @@ #ifndef ANDROIDFW_RESOURCEUTILS_H #define ANDROIDFW_RESOURCEUTILS_H +#include "androidfw/AssetManager2.h" #include "androidfw/StringPiece.h" namespace android { @@ -27,6 +28,17 @@ namespace android { bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type, StringPiece* out_entry); +// Convert a type_string_ref, entry_string_ref, and package +// to AssetManager2::ResourceName. Useful for getting +// resource name without re-running AssetManager2::FindEntry searches. +bool ToResourceName(StringPoolRef& type_string_ref, + StringPoolRef& entry_string_ref, + const LoadedPackage* package, + AssetManager2::ResourceName* out_name); + +// Formats a ResourceName to "package:type/entry_name". +std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name); + inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) { return (resid & 0x00ffffffu) | (static_cast(package_id) << 24); } diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 5449a54d08de..105dcd209bf7 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -586,4 +586,111 @@ TEST_F(AssetManager2Test, OpenDirFromManyApks) { EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory)); } +TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) { + ResTable_config desired_config; + + AssetManager2 assetmanager; + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + assetmanager.SetResourceResolutionLoggingEnabled(false); + + Res_value value; + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("", result); +} + +TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) { + ResTable_config desired_config; + + AssetManager2 assetmanager; + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("", result); +} + +TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + desired_config.language[0] = 'd'; + desired_config.language[1] = 'e'; + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + + Res_value value; + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result); +} + +TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + desired_config.language[0] = 'd'; + desired_config.language[1] = 'e'; + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()}); + + Res_value value = Res_value(); + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result); +} + +TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + + Res_value value = Res_value(); + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto resultEnabled = assetmanager.GetLastResourceResolution(); + ASSERT_NE("", resultEnabled); + + assetmanager.SetResourceResolutionLoggingEnabled(false); + + auto resultDisabled = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("", resultDisabled); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 741e96ff07326292744ee5bc437ba7171f7c3f56 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Wed, 23 Jan 2019 16:56:51 -0800 Subject: Fix GetResourceName for shared libraries GetResourceName used GetPAckageById which only works when the compile time package id is eqal to the runtime package id. This change resolves resource names correctly using the ruuntime package id. Bug: 79666085 Test: libandroidfw_tests Change-Id: Ic60cb2416329c5cb34e925991cd689ca7574b483 --- libs/androidfw/AssetManager2.cpp | 20 +++++++++++++++----- libs/androidfw/ResourceUtils.cpp | 10 +++++----- libs/androidfw/include/androidfw/ResourceUtils.h | 11 +++++------ libs/androidfw/tests/AssetManager2_test.cpp | 10 ++++++++++ 4 files changed, 35 insertions(+), 16 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 3c35d9b33fc8..20303eba6667 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -562,7 +562,7 @@ std::string AssetManager2::GetLastResourceResolution() const { if (package != nullptr) { ToResourceName(last_resolution.type_string_ref, last_resolution.entry_string_ref, - package, + package->GetPackageName(), &resource_name); resource_name_string = ToFormattedResourceString(&resource_name); } @@ -607,15 +607,25 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons return false; } - const LoadedPackage* package = - apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); - if (package == nullptr) { + const uint8_t package_idx = package_ids_[get_package_id(resid)]; + if (package_idx == 0xff) { + LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", + get_package_id(resid), resid); + return false; + } + + const PackageGroup& package_group = package_groups_[package_idx]; + auto cookie_iter = std::find(package_group.cookies_.begin(), + package_group.cookies_.end(), cookie); + if (cookie_iter == package_group.cookies_.end()) { return false; } + long package_pos = std::distance(package_group.cookies_.begin(), cookie_iter); + const LoadedPackage* package = package_group.packages_[package_pos].loaded_package_; return ToResourceName(entry.type_string_ref, entry.entry_string_ref, - package, + package->GetPackageName(), out_name); } diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp index 645984d85c34..c63dff8f9104 100644 --- a/libs/androidfw/ResourceUtils.cpp +++ b/libs/androidfw/ResourceUtils.cpp @@ -48,12 +48,12 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin !(has_type_separator && out_type->empty()); } -bool ToResourceName(StringPoolRef& type_string_ref, - StringPoolRef& entry_string_ref, - const LoadedPackage* package, +bool ToResourceName(const StringPoolRef& type_string_ref, + const StringPoolRef& entry_string_ref, + const StringPiece& package_name, AssetManager2::ResourceName* out_name) { - out_name->package = package->GetPackageName().data(); - out_name->package_len = package->GetPackageName().size(); + out_name->package = package_name.data(); + out_name->package_len = package_name.size(); out_name->type = type_string_ref.string8(&out_name->type_len); out_name->type16 = nullptr; diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h index eb6eb8e66175..e649940cdde1 100644 --- a/libs/androidfw/include/androidfw/ResourceUtils.h +++ b/libs/androidfw/include/androidfw/ResourceUtils.h @@ -28,12 +28,11 @@ namespace android { bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type, StringPiece* out_entry); -// Convert a type_string_ref, entry_string_ref, and package -// to AssetManager2::ResourceName. Useful for getting -// resource name without re-running AssetManager2::FindEntry searches. -bool ToResourceName(StringPoolRef& type_string_ref, - StringPoolRef& entry_string_ref, - const LoadedPackage* package, +// Convert a type_string_ref, entry_string_ref, and package to AssetManager2::ResourceName. +// Useful for getting resource name without re-running AssetManager2::FindEntry searches. +bool ToResourceName(const StringPoolRef& type_string_ref, + const StringPoolRef& entry_string_ref, + const StringPiece& package_name, AssetManager2::ResourceName* out_name); // Formats a ResourceName to "package:type/entry_name". diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 105dcd209bf7..447fdf5d306a 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -210,6 +210,16 @@ TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) { EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data); } +TEST_F(AssetManager2Test, GetSharedLibraryResourceName) { + AssetManager2 assetmanager; + assetmanager.SetApkAssets({lib_one_assets_.get()}); + + AssetManager2::ResourceName name; + ASSERT_TRUE(assetmanager.GetResourceName(lib_one::R::string::foo, &name)); + std::string formatted_name = ToFormattedResourceString(&name); + ASSERT_EQ(formatted_name, "com.android.lib_one:string/foo"); +} + TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) { AssetManager2 assetmanager; assetmanager.SetApkAssets({basic_assets_.get()}); -- cgit v1.2.3-59-g8ed1b From 8f004c85a0859b6fad16f26ac0fce7b2dc3db3b1 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Thu, 17 Jan 2019 17:20:10 -0800 Subject: Add helper methods for View attribute debugging Adding abilities to debug: - Attribute resolution stack (which resources are looked at when resolving an attribute) - Attribute value source (where did each attribute value get defined) - Get explicit style id (if a view had it set via style="...") This feature will be behind Settings.Global flag that Android Studio will set to the debugged application package ID. Bug: 111439551 Test: atest CtsViewTestCases:android.view.cts.ViewStyleTest Change-Id: Ib6f9fc81000bb867b5b94a68953c99b0bc802d6c --- api/current.txt | 6 + core/java/android/app/ActivityThread.java | 22 +++- core/java/android/content/res/AssetManager.java | 10 ++ core/java/android/content/res/Resources.java | 62 +++++++++ core/java/android/content/res/ResourcesImpl.java | 26 ++++ core/java/android/provider/Settings.java | 8 ++ core/java/android/view/View.java | 144 ++++++++++++++++++++- core/java/android/widget/TextView.java | 2 + core/jni/android_util_AssetManager.cpp | 41 ++++++ core/proto/android/providers/settings/global.proto | 2 + .../src/android/provider/SettingsBackupTest.java | 1 + libs/androidfw/AssetManager2.cpp | 22 +++- libs/androidfw/include/androidfw/AssetManager2.h | 6 + .../providers/settings/SettingsProtoDumpUtil.java | 3 + .../android/server/am/CoreSettingsObserver.java | 2 + 15 files changed, 347 insertions(+), 10 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/api/current.txt b/api/current.txt index 3461eff49d1a..f6f68e15eeb7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12355,8 +12355,10 @@ package android.content.res { public final class Resources.Theme { method public void applyStyle(int, boolean); method public void dump(int, String, String); + method public int[] getAttributeResolutionStack(@AttrRes int, @StyleRes int, @StyleRes int); method public int getChangingConfigurations(); method public android.graphics.drawable.Drawable getDrawable(@DrawableRes int) throws android.content.res.Resources.NotFoundException; + method @StyleRes public int getExplicitStyle(@Nullable android.util.AttributeSet); method public android.content.res.Resources getResources(); method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]); method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException; @@ -50326,6 +50328,8 @@ package android.view { method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getAlpha(); method public android.view.animation.Animation getAnimation(); method public android.os.IBinder getApplicationWindowToken(); + method @NonNull public java.util.List getAttributeResolutionStack(); + method @NonNull public java.util.Map getAttributeSourceResourceMap(); method @android.view.ViewDebug.ExportedProperty @Nullable public String[] getAutofillHints(); method public final android.view.autofill.AutofillId getAutofillId(); method public int getAutofillType(); @@ -50356,6 +50360,7 @@ package android.view { method public void getDrawingRect(android.graphics.Rect); method public long getDrawingTime(); method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getElevation(); + method @StyleRes public int getExplicitStyle(); method @android.view.ViewDebug.ExportedProperty public boolean getFilterTouchesWhenObscured(); method @android.view.ViewDebug.ExportedProperty public boolean getFitsSystemWindows(); method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.NOT_FOCUSABLE, to="NOT_FOCUSABLE"), @android.view.ViewDebug.IntToString(from=android.view.View.FOCUSABLE, to="FOCUSABLE"), @android.view.ViewDebug.IntToString(from=android.view.View.FOCUSABLE_AUTO, to="FOCUSABLE_AUTO")}, category="focus") public int getFocusable(); @@ -50650,6 +50655,7 @@ package android.view { method public static int resolveSizeAndState(int, int, int); method public boolean restoreDefaultFocus(); method public void restoreHierarchyState(android.util.SparseArray); + method public final void saveAttributeDataForStyleable(@NonNull android.content.Context, @NonNull int[], @Nullable android.util.AttributeSet, @NonNull android.content.res.TypedArray, int, int); method public void saveHierarchyState(android.util.SparseArray); method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long); method public void scrollBy(int, int); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 21d66e567a81..cc419b8d837a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4565,16 +4565,25 @@ public final class ActivityThread extends ClientTransactionHandler { } private void onCoreSettingsChange() { - boolean debugViewAttributes = - mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0; - if (debugViewAttributes != View.mDebugViewAttributes) { - View.mDebugViewAttributes = debugViewAttributes; - + if (updateDebugViewAttributeState()) { // request all activities to relaunch for the changes to take place relaunchAllActivities(); } } + private boolean updateDebugViewAttributeState() { + boolean previousState = View.sDebugViewAttributes; + + View.sDebugViewAttributesApplicationPackage = mCoreSettings.getString( + Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, ""); + String currentPackage = (mBoundApplication != null && mBoundApplication.appInfo != null) + ? mBoundApplication.appInfo.packageName : ""; + View.sDebugViewAttributes = + mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0 + || View.sDebugViewAttributesApplicationPackage.equals(currentPackage); + return previousState != View.sDebugViewAttributes; + } + private void relaunchAllActivities() { for (Map.Entry entry : mActivities.entrySet()) { final Activity activity = entry.getValue().activity; @@ -5950,8 +5959,7 @@ public final class ActivityThread extends ClientTransactionHandler { // true : use 24 hour format. DateFormat.set24HourTimePref(is24Hr); - View.mDebugViewAttributes = - mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0; + updateDebugViewAttributeState(); StrictMode.initThreadDefaults(data.appInfo); StrictMode.initVmDefaults(data.appInfo); diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 9e0a9ba0dc7b..faf17e011b23 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1051,6 +1051,14 @@ public final class AssetManager implements AutoCloseable { } } + int[] getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, + @StyleRes int defStyleRes, @StyleRes int xmlStyle) { + synchronized (this) { + return nativeAttributeResolutionStack( + mObject, themePtr, xmlStyle, defStyleAttr, defStyleRes); + } + } + @UnsupportedAppUsage boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, @@ -1419,6 +1427,8 @@ public final class AssetManager implements AutoCloseable { private static native @Nullable String nativeGetLastResourceResolution(long ptr); // Style attribute retrieval native methods. + private static native int[] nativeAttributeResolutionStack(long ptr, long themePtr, + @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes); private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 59db49e0d37e..a2ae994f7b0f 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1725,6 +1725,68 @@ public class Resources { public void rebase() { mThemeImpl.rebase(); } + + /** + * Returns the resource ID for the style specified using {@code style="..."} in the + * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not + * specified or otherwise not applicable. + *

+ * Each {@link android.view.View} can have an explicit style specified in the layout file. + * This style is used first during the {@link android.view.View} attribute resolution, then + * if an attribute is not defined there the resource system looks at default style and theme + * as fallbacks. + * + * @param set The base set of attribute values. + * + * @return The resource ID for the style specified using {@code style="..."} in the + * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise + * if not specified or otherwise not applicable. + */ + @StyleRes + public int getExplicitStyle(@Nullable AttributeSet set) { + if (set == null) { + return ID_NULL; + } + int styleAttr = set.getStyleAttribute(); + if (styleAttr == ID_NULL) { + return ID_NULL; + } + String styleAttrType = getResources().getResourceTypeName(styleAttr); + if ("attr".equals(styleAttrType)) { + TypedValue explicitStyle = new TypedValue(); + boolean resolved = resolveAttribute(styleAttr, explicitStyle, true); + if (resolved) { + return explicitStyle.resourceId; + } + } else if ("style".equals(styleAttrType)) { + return styleAttr; + } + return ID_NULL; + } + + /** + * Returns the ordered list of resource ID that are considered when resolving attribute + * values when making an equivalent call to + * {@link #obtainStyledAttributes(AttributeSet, int[], int, int)} . The list will include + * a set of explicit styles ({@code explicitStyleRes} and it will include the default styles + * ({@code defStyleAttr} and {@code defStyleRes}). + * + * @param defStyleAttr An attribute in the current theme that contains a + * reference to a style resource that supplies + * defaults values for the TypedArray. Can be + * 0 to not look for defaults. + * @param defStyleRes A resource identifier of a style resource that + * supplies default values for the TypedArray, + * used only if defStyleAttr is 0 or can not be found + * in the theme. Can be 0 to not look for defaults. + * @param explicitStyleRes A resource identifier of an explicit style resource. + * @return ordered list of resource ID that are considered when resolving attribute values. + */ + public int[] getAttributeResolutionStack(@AttrRes int defStyleAttr, + @StyleRes int defStyleRes, @StyleRes int explicitStyleRes) { + return mThemeImpl.getAttributeResolutionStack( + defStyleAttr, defStyleRes, explicitStyleRes); + } } static class ThemeKey implements Cloneable { diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 98980799a365..da064c956fcc 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -1488,6 +1488,32 @@ public class ResourcesImpl { } } } + + /** + * Returns the ordered list of resource ID that are considered when resolving attribute + * values when making an equivalent call to + * {@link #obtainStyledAttributes(Resources.Theme, AttributeSet, int[], int, int)}. The list + * will include a set of explicit styles ({@code explicitStyleRes} and it will include the + * default styles ({@code defStyleAttr} and {@code defStyleRes}). + * + * @param defStyleAttr An attribute in the current theme that contains a + * reference to a style resource that supplies + * defaults values for the TypedArray. Can be + * 0 to not look for defaults. + * @param defStyleRes A resource identifier of a style resource that + * supplies default values for the TypedArray, + * used only if defStyleAttr is 0 or can not be found + * in the theme. Can be 0 to not look for defaults. + * @param explicitStyleRes A resource identifier of an explicit style resource. + * @return ordered list of resource ID that are considered when resolving attribute values. + */ + public int[] getAttributeResolutionStack(@AttrRes int defStyleAttr, + @StyleRes int defStyleRes, @StyleRes int explicitStyleRes) { + synchronized (mKey) { + return mAssets.getAttributeResolutionStack( + mTheme, defStyleAttr, defStyleRes, explicitStyleRes); + } + } } private static class LookupStack { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a8976aa56241..e95d60465371 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9299,6 +9299,13 @@ public final class Settings { */ public static final String DEBUG_VIEW_ATTRIBUTES = "debug_view_attributes"; + /** + * Which application package is allowed to save View attribute data. + * @hide + */ + public static final String DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE = + "debug_view_attributes_application_package"; + /** * Whether assisted GPS should be enabled or not. * @hide @@ -14022,6 +14029,7 @@ public final class Settings { INSTANT_APP_SETTINGS.add(TRANSITION_ANIMATION_SCALE); INSTANT_APP_SETTINGS.add(ANIMATOR_DURATION_SCALE); INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES); + INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE); INSTANT_APP_SETTINGS.add(WTF_IS_FATAL); INSTANT_APP_SETTINGS.add(SEND_ACTION_APP_ERROR); INSTANT_APP_SETTINGS.add(ZEN_MODE); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 04ffa33d0e22..e56861e39a98 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -35,6 +35,7 @@ import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; +import android.annotation.StyleRes; import android.annotation.TestApi; import android.annotation.UiThread; import android.annotation.UnsupportedAppUsage; @@ -91,6 +92,7 @@ import android.util.LongSparseLongArray; import android.util.Pools.SynchronizedPool; import android.util.Property; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.StateSet; import android.util.SuperNotCalledException; import android.util.TypedValue; @@ -820,7 +822,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ - public static boolean mDebugViewAttributes = false; + public static boolean sDebugViewAttributes = false; + + /** + * When set to this application package view will save its attribute data. + * + * @hide + */ + public static String sDebugViewAttributesApplicationPackage; /** * Used to mark a View that has no ID. @@ -5078,6 +5087,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @LayoutRes private int mSourceLayoutId = ID_NULL; + @Nullable + private SparseIntArray mAttributeSourceResId; + + @Nullable + private int[] mAttributeResolutionStack; + + @StyleRes + private int mExplicitStyle; + /** * Cached reference to the {@link ContentCaptureSession}, is reset on {@link #invalidate()}. */ @@ -5253,7 +5271,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); - if (mDebugViewAttributes) { + retrieveExplicitStyle(context.getTheme(), attrs); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, + defStyleAttr, defStyleRes); + + if (sDebugViewAttributes) { saveAttributeData(attrs, a); } @@ -5914,6 +5936,84 @@ public class View implements Drawable.Callback, KeyEvent.Callback, computeOpaqueFlags(); } + /** + * Returns the ordered list of resource ID that are considered when resolving attribute values + * for this {@link View}. The list will include layout resource ID if the View is inflated from + * XML. It will also include a set of explicit styles if specified in XML using + * {@code style="..."}. Finally, it will include the default styles resolved from the theme. + * + *

+ * Note: this method will only return actual values if the view attribute debugging + * is enabled in Android developer options. + * + * @return ordered list of resource ID that are considered when resolving attribute values for + * this {@link View}. + */ + @NonNull + public List getAttributeResolutionStack() { + ArrayList stack = new ArrayList<>(); + if (!sDebugViewAttributes) { + return stack; + } + if (mSourceLayoutId != ID_NULL) { + stack.add(mSourceLayoutId); + } + for (int i = 0; i < mAttributeResolutionStack.length; i++) { + stack.add(mAttributeResolutionStack[i]); + } + return stack; + } + + /** + * Returns the mapping of attribute resource ID to source resource ID where the attribute value + * was set. Source resource ID can either be a layout resource ID, if the value was set in XML + * within the View tag, or a style resource ID, if the attribute was set in a style. The source + * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. + * + *

+ * Note: this method will only return actual values if the view attribute debugging + * is enabled in Android developer options. + * + * @return mapping of attribute resource ID to source resource ID where the attribute value + * was set. + */ + @NonNull + public Map getAttributeSourceResourceMap() { + HashMap map = new HashMap<>(); + if (!sDebugViewAttributes) { + return map; + } + for (int i = 0; i < mAttributeSourceResId.size(); i++) { + map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); + } + return map; + } + + /** + * Returns the resource ID for the style specified using {@code style="..."} in the + * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not + * specified or otherwise not applicable. + *

+ * Each {@link View} can have an explicit style specified in the layout file. + * This style is used first during the {@link View} attribute resolution, then if an attribute + * is not defined there the resource system looks at default style and theme as fallbacks. + * + *

+ * Note: this method will only return actual values if the view attribute debugging + * is enabled in Android developer options. + * + * @return The resource ID for the style specified using {@code style="..."} in the + * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise + * if not specified or otherwise not applicable. + */ + @StyleRes + public int getExplicitStyle() { + if (!sDebugViewAttributes) { + return ID_NULL; + } + return mExplicitStyle; + } + /** * An implementation of OnClickListener that attempts to lazily load a * named click handling method from a parent or ancestor context. @@ -6000,6 +6100,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mAttributeMap; } + private void retrieveExplicitStyle(@NonNull Resources.Theme theme, + @Nullable AttributeSet attrs) { + if (!sDebugViewAttributes) { + return; + } + mExplicitStyle = theme.getExplicitStyle(attrs); + } + + /** + * Stores debugging information about attributes. This should be called in a constructor by + * every custom {@link View} that uses a custom styleable. + * @param context Context under which this view is created. + * @param styleable A reference to styleable array R.styleable.Foo + * @param attrs AttributeSet used to construct this view. + * @param t Resolved {@link TypedArray} returned by a call to + * {@link Resources#obtainAttributes(AttributeSet, int[])}. + * @param defStyleAttr Default style attribute passed into the view constructor. + * @param defStyleRes Default style resource passed into the view constructor. + */ + public final void saveAttributeDataForStyleable(@NonNull Context context, + @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, + int defStyleAttr, int defStyleRes) { + if (!sDebugViewAttributes) { + return; + } + + mAttributeResolutionStack = context.getTheme().getAttributeResolutionStack( + defStyleAttr, defStyleRes, mExplicitStyle); + + if (mAttributeSourceResId == null) { + mAttributeSourceResId = new SparseIntArray(); + } + + final int indexCount = t.getIndexCount(); + for (int j = 0; j < indexCount; ++j) { + final int index = t.getIndex(j); + mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); + } + } + private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); final int indexCount = t.getIndexCount(); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 659b71f51588..3da450d75133 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1055,6 +1055,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int inputType = EditorInfo.TYPE_NULL; a = theme.obtainStyledAttributes( attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TextView, attrs, a, + defStyleAttr, defStyleRes); int firstBaselineToTopHeight = -1; int lastBaselineToBottomHeight = -1; int lineHeight = -1; diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 4101c04162af..d493ddfaae13 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1105,6 +1105,46 @@ static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, j return array; } +static jintArray NativeAttributeResolutionStack( + JNIEnv* env, jclass /*clazz*/, jlong ptr, + jlong theme_ptr, jint xml_style_res, + jint def_style_attr, jint def_style_resid) { + + ScopedLock assetmanager(AssetManagerFromLong(ptr)); + Theme* theme = reinterpret_cast(theme_ptr); + CHECK(theme->GetAssetManager() == &(*assetmanager)); + (void) assetmanager; + + // Load default style from attribute, if specified... + uint32_t def_style_flags = 0u; + if (def_style_attr != 0) { + Res_value value; + if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) { + if (value.dataType == Res_value::TYPE_REFERENCE) { + def_style_resid = value.data; + } + } + } + + auto style_stack = assetmanager->GetBagResIdStack(xml_style_res); + auto def_style_stack = assetmanager->GetBagResIdStack(def_style_resid); + + jintArray array = env->NewIntArray(style_stack.size() + def_style_stack.size()); + if (env->ExceptionCheck()) { + return nullptr; + } + + for (uint32_t i = 0; i < style_stack.size(); i++) { + jint attr_resid = style_stack[i]; + env->SetIntArrayRegion(array, i, 1, &attr_resid); + } + for (uint32_t i = 0; i < def_style_stack.size(); i++) { + jint attr_resid = def_style_stack[i]; + env->SetIntArrayRegion(array, style_stack.size() + i, 1, &attr_resid); + } + return array; +} + static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr, jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr, jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) { @@ -1456,6 +1496,7 @@ static const JNINativeMethod gAssetManagerMethods[] = { (void*)NativeGetSizeConfigurations}, // Style attribute related methods. + {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack}, {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle}, {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs}, {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes}, diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index a160451ecfed..d5776534bb90 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -259,6 +259,8 @@ message GlobalSettingsProto { optional SettingProto app = 1; // Whether views are allowed to save their attribute data. optional SettingProto view_attributes = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Which application package is allowed to save view attribute data. + optional SettingProto view_attributes_application_package = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Debug debug = 37; diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 2cb925aa9549..ec57f793f15f 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -210,6 +210,7 @@ public class SettingsBackupTest { Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, Settings.Global.DEBUG_APP, Settings.Global.DEBUG_VIEW_ATTRIBUTES, + Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, Settings.Global.DEFAULT_DNS_SERVER, Settings.Global.DEFAULT_INSTALL_LOCATION, Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA, diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 20303eba6667..81afd937d85e 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -704,9 +704,29 @@ ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_valu return cookie; } +const std::vector AssetManager2::GetBagResIdStack(uint32_t resid) { + auto cached_iter = cached_bag_resid_stacks_.find(resid); + if (cached_iter != cached_bag_resid_stacks_.end()) { + return cached_iter->second; + } else { + auto found_resids = std::vector(); + GetBag(resid, found_resids); + // Cache style stacks if they are not already cached. + cached_bag_resid_stacks_[resid] = found_resids; + return found_resids; + } +} + const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { auto found_resids = std::vector(); - return GetBag(resid, found_resids); + auto bag = GetBag(resid, found_resids); + + // Cache style stacks if they are not already cached. + auto cached_iter = cached_bag_resid_stacks_.find(resid); + if (cached_iter == cached_bag_resid_stacks_.end()) { + cached_bag_resid_stacks_[resid] = found_resids; + } + return bag; } const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector& child_resids) { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index f29769b834d1..d862182d8960 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -237,6 +237,8 @@ class AssetManager2 { // resource has been resolved yet. std::string GetLastResourceResolution() const; + const std::vector GetBagResIdStack(uint32_t resid); + // 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. // To iterate over the keys, use the following idiom: @@ -355,6 +357,10 @@ class AssetManager2 { // which involves some calculation. std::unordered_map> cached_bags_; + // Cached set of bag resid stacks for each bag. These are cached because they might be requested + // a number of times for each view during View inspection. + std::unordered_map> cached_bag_resid_stacks_; + // Whether or not to save resource resolution steps bool resource_resolution_logging_enabled_ = false; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index fad93cbf83da..6152b8cbd562 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -457,6 +457,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.DEBUG_VIEW_ATTRIBUTES, GlobalSettingsProto.Debug.VIEW_ATTRIBUTES); + dumpSetting(s, p, + Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, + GlobalSettingsProto.Debug.VIEW_ATTRIBUTES_APPLICATION_PACKAGE); p.end(debugToken); final long defaultToken = p.start(GlobalSettingsProto.DEFAULT); diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 360d2960f61a..01946247bd12 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -55,6 +55,8 @@ final class CoreSettingsObserver extends ContentObserver { // add other system settings here... sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class); + sGlobalSettingToTypeMap.put( + Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, String.class); sGlobalSettingToTypeMap.put( Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE, String.class); sGlobalSettingToTypeMap.put( -- cgit v1.2.3-59-g8ed1b From c92c4dd6c6442d0876261ec3e634937f16edb3c5 Mon Sep 17 00:00:00 2001 From: MÃ¥rten Kongstad Date: Tue, 5 Feb 2019 01:29:59 +0100 Subject: Surface info in Java AssetManager Add a new, hidden method to AssetManager to extract a mapping overlayable name -> overlayable actor for all blocks in a package. [This will eventually be used to check if the caller of the OMS AIDL API is the registered actor for a given overlay.] Also, teach AssetManager2 to not accept packages that re-use the same overlayable name. [Such packages have always been ill-formed.] Bug: 123894537 Test: make libandroidfw_tests Change-Id: I1117fd3503f04fe4c73eb7114901e022508f4d9e --- core/java/android/content/res/AssetManager.java | 14 ++++++ core/jni/android_util_AssetManager.cpp | 60 ++++++++++++++++++++++++ libs/androidfw/AssetManager2.cpp | 21 +++++++++ libs/androidfw/LoadedArsc.cpp | 7 +++ libs/androidfw/include/androidfw/AssetManager2.h | 3 ++ libs/androidfw/include/androidfw/LoadedArsc.h | 6 +++ libs/androidfw/tests/AssetManager2_test.cpp | 20 ++++++++ libs/androidfw/tests/LoadedArsc_test.cpp | 20 +++++++- 8 files changed, 150 insertions(+), 1 deletion(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index faf17e011b23..49b4cb01c6a6 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -47,6 +47,7 @@ import java.nio.channels.FileLock; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Map; /** * Provides access to an application's raw asset files; see {@link Resources} @@ -1345,6 +1346,17 @@ public final class AssetManager implements AutoCloseable { } } + /** + * @hide + */ + @GuardedBy("this") + public @Nullable Map getOverlayableMap(String packageName) { + synchronized (this) { + ensureValidLocked(); + return nativeGetOverlayableMap(mObject, packageName); + } + } + @GuardedBy("this") private void incRefsLocked(long id) { if (DEBUG_REFS) { @@ -1462,6 +1474,8 @@ public final class AssetManager implements AutoCloseable { private static native void nativeVerifySystemIdmaps(); private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); + private static native @Nullable Map nativeGetOverlayableMap(long ptr, + @NonNull String packageName); // Global debug native methods. /** diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index d493ddfaae13..a212f47c0104 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -104,6 +104,12 @@ static struct configuration_offsets_t { jfieldID mScreenHeightDpOffset; } gConfigurationOffsets; +static struct arraymap_offsets_t { + jclass classObject; + jmethodID constructor; + jmethodID put; +} gArrayMapOffsets; + jclass g_stringClass = nullptr; // ---------------------------------------------------------------------------- @@ -326,6 +332,50 @@ static Guarded& AssetManagerFromLong(jlong ptr) { return *AssetManagerForNdkAssetManager(reinterpret_cast(ptr)); } +static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr, + jstring package_name) { + ScopedLock assetmanager(AssetManagerFromLong(ptr)); + const ScopedUtfChars package_name_utf8(env, package_name); + CHECK(package_name_utf8.c_str() != nullptr); + const std::string std_package_name(package_name_utf8.c_str()); + const std::unordered_map* map = nullptr; + + assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) { + if (this_package_name == std_package_name) { + map = assetmanager->GetOverlayableMapForPackage(package_id); + } + }); + + if (map == nullptr) { + return nullptr; + } + + jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor); + if (array_map == nullptr) { + return nullptr; + } + + for (const auto& iter : *map) { + jstring name = env->NewStringUTF(iter.first.c_str()); + if (env->ExceptionCheck()) { + return nullptr; + } + + jstring actor = env->NewStringUTF(iter.second.c_str()); + if (env->ExceptionCheck()) { + env->DeleteLocalRef(name); + return nullptr; + } + + env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor); + + env->DeleteLocalRef(name); + env->DeleteLocalRef(actor); + } + + return array_map; +} + static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr asset, jlongArray out_offsets) { off64_t start_offset, length; @@ -1524,6 +1574,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps}, {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;", (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, + {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;", + (void*)NativeGetOverlayableMap}, // Global management/debug methods. {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount}, @@ -1575,6 +1627,14 @@ int register_android_content_AssetManager(JNIEnv* env) { gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I"); + jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap"); + gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass); + gArrayMapOffsets.constructor = + GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "", "()V"); + gArrayMapOffsets.put = + GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods)); } diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 81afd937d85e..66d8542553d2 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -203,6 +203,27 @@ const DynamicRefTable* AssetManager2::GetDynamicRefTableForCookie(ApkAssetsCooki return nullptr; } +const std::unordered_map* + AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const { + + if (package_id >= package_ids_.size()) { + return nullptr; + } + + const size_t idx = package_ids_[package_id]; + if (idx == 0xff) { + return nullptr; + } + + const PackageGroup& package_group = package_groups_[idx]; + if (package_group.packages_.size() == 0) { + return nullptr; + } + + const auto loaded_package = package_group.packages_[0].loaded_package_; + return &loaded_package->GetOverlayableMap(); +} + void AssetManager2::SetConfiguration(const ResTable_config& configuration) { const int diff = configuration_.diff(configuration); configuration_ = configuration; diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index bdd47061054a..72873abc6a42 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -598,6 +598,13 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, std::string actor; util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor); + if (loaded_package->overlayable_map_.find(name) != + loaded_package->overlayable_map_.end()) { + LOG(ERROR) << "Multiple blocks with the same name '" << name << "'."; + return {}; + } + loaded_package->overlayable_map_.emplace(name, actor); + // Iterate over the overlayable policy chunks contained within the overlayable chunk data ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size()); while (overlayable_iter.HasNext()) { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index d862182d8960..fc5aa9c7f1b9 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -124,6 +124,9 @@ class AssetManager2 { // This may be nullptr if the APK represented by `cookie` has no resource table. const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const; + const std::unordered_map* + GetOverlayableMapForPackage(uint32_t package_id) const; + // Sets/resets the configuration for this AssetManager. This will cause all // caches that are related to the configuration change to be invalidated. void SetConfiguration(const ResTable_config& configuration); diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index b5f4006dbb00..950f5413f550 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "android-base/macros.h" @@ -242,6 +243,10 @@ class LoadedPackage { return defines_overlayable_; } + const std::unordered_map& GetOverlayableMap() const { + return overlayable_map_; + } + private: DISALLOW_COPY_AND_ASSIGN(LoadedPackage); @@ -261,6 +266,7 @@ class LoadedPackage { ByteBucketArray resource_ids_; std::vector dynamic_package_map_; std::vector>> overlayable_infos_; + std::unordered_map overlayable_map_; }; // Read-only view into a resource table. This class validates all data diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 447fdf5d306a..40c8e46e4d84 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -71,6 +71,9 @@ class AssetManager2Test : public ::testing::Test { app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk"); ASSERT_THAT(app_assets_, NotNull()); + + overlayable_assets_ = ApkAssets::Load(GetTestDataPath() + "/overlayable/overlayable.apk"); + ASSERT_THAT(overlayable_assets_, NotNull()); } protected: @@ -83,6 +86,7 @@ class AssetManager2Test : public ::testing::Test { std::unique_ptr appaslib_assets_; std::unique_ptr system_assets_; std::unique_ptr app_assets_; + std::unique_ptr overlayable_assets_; }; TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) { @@ -703,4 +707,20 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) { EXPECT_EQ("", resultDisabled); } +TEST_F(AssetManager2Test, GetOverlayableMap) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({overlayable_assets_.get()}); + + const auto map = assetmanager.GetOverlayableMapForPackage(0x7f); + ASSERT_NE(nullptr, map); + ASSERT_EQ(2, map->size()); + ASSERT_EQ(map->at("OverlayableResources1"), "overlay://theme"); + ASSERT_EQ(map->at("OverlayableResources2"), "overlay://com.android.overlayable"); +} + } // namespace android diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index b8d3c6bf92fb..d58e8d20c8aa 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -331,7 +331,7 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) { const std::vector>& packages = loaded_arsc->GetPackages(); ASSERT_EQ(1u, packages.size()); - EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName()); + ASSERT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName()); const auto& loaded_package = packages[0]; auto iter = loaded_package->begin(); @@ -369,6 +369,24 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) { ASSERT_EQ(end, iter); } +TEST(LoadedArscTest, GetOverlayableMap) { + std::string contents; + ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk", + "resources.arsc", &contents)); + + std::unique_ptr loaded_arsc = LoadedArsc::Load(StringPiece(contents)); + ASSERT_NE(nullptr, loaded_arsc); + + const std::vector>& packages = loaded_arsc->GetPackages(); + ASSERT_EQ(1u, packages.size()); + ASSERT_EQ(std::string("com.android.overlayable"), packages[0]->GetPackageName()); + + const auto map = packages[0]->GetOverlayableMap(); + ASSERT_EQ(2, map.size()); + ASSERT_EQ(map.at("OverlayableResources1"), "overlay://theme"); + ASSERT_EQ(map.at("OverlayableResources2"), "overlay://com.android.overlayable"); +} + // structs with size fields (like Res_value, ResTable_entry) should be // backwards and forwards compatible (aka checking the size field against // sizeof(Res_value) might not be backwards compatible. -- cgit v1.2.3-59-g8ed1b From a55dc2ed6bf2b4e6ad0ab2d1ae501bf7ec4c1e15 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Thu, 24 Jan 2019 10:58:23 -0800 Subject: Fix long paths on Windows util::mkdirs iteratively creates each directory of a specified path. For windows, Calling mkdir on only the drive letter or on the extended path prefix (\?\\) will result in an error. Start after the long path prefix and the drive letter. This also changes AAPT2 to use AssetMaanager2 to retrieve symbols from the symbol table. AssetManager2's zip library uses _wopen to open windows files. Bug:123251200 Test: aapt2_tests.exe Change-Id: I26169d83b22d441485de3c49d63a6c4ed710e292 --- core/jni/android_util_AssetManager.cpp | 7 +- libs/androidfw/AssetManager2.cpp | 64 +++++---- libs/androidfw/include/androidfw/AssetManager2.h | 14 +- tools/aapt2/ResourceUtils.cpp | 36 +++++ tools/aapt2/ResourceUtils.h | 7 + tools/aapt2/cmd/Link.cpp | 36 ++--- tools/aapt2/process/SymbolTable.cpp | 160 +++++++++++++---------- tools/aapt2/process/SymbolTable.h | 10 +- tools/aapt2/process/SymbolTable_test.cpp | 72 ++++++---- tools/aapt2/test/Fixture.cpp | 10 +- tools/aapt2/test/Fixture.h | 3 +- tools/aapt2/util/Files.cpp | 21 ++- tools/aapt2/util/Files_test.cpp | 36 +++++ 13 files changed, 311 insertions(+), 165 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index a212f47c0104..af2d41399016 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -343,7 +343,9 @@ static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr, assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) { if (this_package_name == std_package_name) { map = assetmanager->GetOverlayableMapForPackage(package_id); + return false; } + return true; }); if (map == nullptr) { @@ -521,15 +523,16 @@ static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/ return nullptr; } - assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) { + assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool { jstring jpackage_name = env->NewStringUTF(package_name.c_str()); if (jpackage_name == nullptr) { // An exception is pending. - return; + return false; } env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast(package_id), jpackage_name); + return true; }); return sparse_array; } diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 66d8542553d2..d7b84ff1060d 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -356,6 +356,7 @@ std::unique_ptr AssetManager2::OpenNonAsset(const std::string& filename, ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override, bool /*stop_at_first_match*/, + bool ignore_configuration, FindEntryResult* out_entry) const { // Might use this if density_override != 0. ResTable_config density_override_config; @@ -399,7 +400,7 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // 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_; + const bool use_fast_path = !ignore_configuration && desired_config == &configuration_; for (size_t pi = 0; pi < package_count; pi++) { const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi]; @@ -475,21 +476,23 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // 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); + ResTable_config this_config{}; - if (!this_config.match(*desired_config)) { - continue; - } + if (!ignore_configuration) { + this_config.copyFromDtoH((*iter)->config); + if (!this_config.match(*desired_config)) { + continue; + } - if (best_config == nullptr) { - resolution_type = Resolution::Step::Type::INITIAL; - } else if (this_config.isBetterThan(*best_config, desired_config)) { - resolution_type = Resolution::Step::Type::BETTER_MATCH; - } else if (package_is_overlay && this_config.compare(*best_config) == 0) { - resolution_type = Resolution::Step::Type::OVERLAID; - } else { - continue; + if (best_config == nullptr) { + resolution_type = Resolution::Step::Type::INITIAL; + } else if (this_config.isBetterThan(*best_config, desired_config)) { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } else if (package_is_overlay && this_config.compare(*best_config) == 0) { + resolution_type = Resolution::Step::Type::OVERLAID; + } else { + continue; + } } // The configuration matches and is better than the previous selection. @@ -506,6 +509,11 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri best_config = &best_config_copy; best_offset = offset; + if (ignore_configuration) { + // Any configuration will suffice, so break. + break; + } + if (resource_resolution_logging_enabled_) { resolution_steps.push_back(Resolution::Step{resolution_type, this_config.toString(), @@ -622,8 +630,9 @@ std::string AssetManager2::GetLastResourceResolution() const { bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; - ApkAssetsCookie cookie = - FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry); + ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, + true /* stop_at_first_match */, + true /* ignore_configuration */, &entry); if (cookie == kInvalidCookie) { return false; } @@ -652,13 +661,14 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const { FindEntryResult entry; - ApkAssetsCookie cookie = - FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry); + ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, + false /* stop_at_first_match */, + true /* ignore_configuration */, &entry); if (cookie != kInvalidCookie) { *out_flags = entry.type_flags; - return cookie; + return true; } - return kInvalidCookie; + return false; } ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, @@ -666,8 +676,8 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, ResTable_config* out_selected_config, uint32_t* out_flags) const { FindEntryResult entry; - ApkAssetsCookie cookie = - FindEntry(resid, density_override, false /* stop_at_first_match */, &entry); + ApkAssetsCookie cookie = FindEntry(resid, density_override, false /* stop_at_first_match */, + false /* ignore_configuration */, &entry); if (cookie == kInvalidCookie) { return kInvalidCookie; } @@ -759,8 +769,10 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector& } FindEntryResult entry; - ApkAssetsCookie cookie = - FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry); + ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, + false /* stop_at_first_match */, + false /* ignore_configuration */, + &entry); if (cookie == kInvalidCookie) { return nullptr; } @@ -1387,7 +1399,9 @@ void Theme::SetTo(const Theme& o) { // Find the cookie of the attribute resource id FindEntryResult attribute_entry_result; ApkAssetsCookie attribute_cookie = - o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false, + o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , + true /* stop_at_first_match */, + true /* ignore_configuration */, &attribute_entry_result); // Determine the package id of the attribute in the destination AssetManager diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index fc5aa9c7f1b9..1e2b36cb1703 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -257,11 +257,12 @@ class AssetManager2 { // Creates a new Theme from this AssetManager. std::unique_ptr NewTheme(); - template - void ForEachPackage(Func func) const { + void ForEachPackage(const std::function func) const { for (const PackageGroup& package_group : package_groups_) { - func(package_group.packages_.front().loaded_package_->GetPackageName(), - package_group.dynamic_ref_table.mAssignedPackageId); + if (!func(package_group.packages_.front().loaded_package_->GetPackageName(), + package_group.dynamic_ref_table.mAssignedPackageId)) { + return; + } } } @@ -282,10 +283,13 @@ class AssetManager2 { // care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete // and should not be used. // + // When `ignore_configuration` is true, FindEntry will return always select the first entry in + // for the type seen regardless of its configuration. + // // 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; + bool ignore_configuration, FindEntryResult* out_entry) const; // Assigns package IDs to all shared library ApkAssets. // Should be called whenever the ApkAssets are changed. diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 0032960ff93e..ffc1a92a88b0 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -44,6 +44,7 @@ constexpr int32_t kNonBreakingSpace = 0xa0; Maybe ToResourceName( const android::ResTable::resource_name& name_in) { + // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2 ResourceName name_out; if (!name_in.package) { return {}; @@ -79,6 +80,41 @@ Maybe ToResourceName( return name_out; } +Maybe ToResourceName(const android::AssetManager2::ResourceName& name_in) { + ResourceName name_out; + if (!name_in.package) { + return {}; + } + + name_out.package = std::string(name_in.package, name_in.package_len); + + const ResourceType* type; + if (name_in.type16) { + type = ParseResourceType( + util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len))); + } else if (name_in.type) { + type = ParseResourceType(StringPiece(name_in.type, name_in.type_len)); + } else { + return {}; + } + + if (!type) { + return {}; + } + + name_out.type = *type; + + if (name_in.entry16) { + name_out.entry = + util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len)); + } else if (name_in.entry) { + name_out.entry = std::string(name_in.entry, name_in.entry_len); + } else { + return {}; + } + return name_out; +} + bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref, bool* out_private) { if (str.empty()) { diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h index e282fd58d261..a8a312005e4e 100644 --- a/tools/aapt2/ResourceUtils.h +++ b/tools/aapt2/ResourceUtils.h @@ -20,6 +20,7 @@ #include #include +#include "androidfw/AssetManager2.h" #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" @@ -77,6 +78,12 @@ bool IsAttributeReference(const android::StringPiece& str); Maybe ToResourceName( const android::ResTable::resource_name& name); +/** + * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct. + */ +Maybe ToResourceName( + const android::AssetManager2::ResourceName& name_in); + /** * Returns a boolean value if the string is equal to TRUE, true, True, FALSE, * false, or False. diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 22edd2f2055a..a7b8d2535e79 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -717,28 +717,20 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path, return true; } -static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) { +static android::ApkAssetsCookie FindFrameworkAssetManagerCookie( + const android::AssetManager2& assets) { using namespace android; // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so // we're looking for the first attribute resource in the system package. - const ResTable& table = assets.getResources(true); - Res_value val; - ssize_t idx = table.getResource(0x01010000, &val, true); - if (idx != NO_ERROR) { - // Try as a bag. - const ResTable::bag_entry* entry; - ssize_t cnt = table.lockBag(0x01010000, &entry); - if (cnt >= 0) { - idx = entry->stringBlock; - } - table.unlockBag(entry); - } - - if (idx < 0) { - return 0; - } - return table.getTableCookie(idx); + Res_value val{}; + ResTable_config config{}; + uint32_t type_spec_flags; + ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */, + 0 /** density_override */, &val, &config, + &type_spec_flags); + + return idx; } class Linker { @@ -750,17 +742,17 @@ class Linker { file_collection_(util::make_unique()) { } - void ExtractCompileSdkVersions(android::AssetManager* assets) { + void ExtractCompileSdkVersions(android::AssetManager2* assets) { using namespace android; - int32_t cookie = FindFrameworkAssetManagerCookie(*assets); - if (cookie == 0) { + android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets); + if (cookie == android::kInvalidCookie) { // No Framework assets loaded. Not a failure. return; } std::unique_ptr manifest( - assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER)); + assets->OpenNonAsset(kAndroidManifestPath, cookie, Asset::AccessMode::ACCESS_BUFFER)); if (manifest == nullptr) { // No errors. return; diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp index a844a43698e5..78e00746f6cb 100644 --- a/tools/aapt2/process/SymbolTable.cpp +++ b/tools/aapt2/process/SymbolTable.cpp @@ -20,9 +20,11 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" -#include "androidfw/AssetManager.h" +#include "androidfw/Asset.h" +#include "androidfw/AssetManager2.h" #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" +#include "androidfw/ResourceUtils.h" #include "NameMangler.h" #include "Resource.h" @@ -30,6 +32,7 @@ #include "ValueVisitor.h" #include "util/Util.h" +using ::android::ApkAssets; using ::android::ConfigDescription; using ::android::StringPiece; using ::android::StringPiece16; @@ -214,51 +217,75 @@ std::unique_ptr ResourceTableSymbolSource::FindByName( } bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) { - int32_t cookie = 0; - return assets_.addAssetPath(android::String8(path.data(), path.size()), &cookie); + if (std::unique_ptr apk = ApkAssets::Load(path.data())) { + apk_assets_.push_back(std::move(apk)); + + std::vector apk_assets; + for (const std::unique_ptr& apk_asset : apk_assets_) { + apk_assets.push_back(apk_asset.get()); + } + + asset_manager_.SetApkAssets(apk_assets, true /* invalidate_caches */, + false /* filter_incompatible_configs */); + return true; + } + return false; } std::map AssetManagerSymbolSource::GetAssignedPackageIds() const { std::map package_map; - const android::ResTable& table = assets_.getResources(false); - const size_t package_count = table.getBasePackageCount(); - for (size_t i = 0; i < package_count; i++) { - package_map[table.getBasePackageId(i)] = - util::Utf16ToUtf8(android::StringPiece16(table.getBasePackageName(i).string())); - } + asset_manager_.ForEachPackage([&package_map](const std::string& name, uint8_t id) -> bool { + package_map.insert(std::make_pair(id, name)); + return true; + }); + return package_map; } bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId) const { - return assets_.getResources(false).isPackageDynamic(packageId); + if (packageId == 0) { + return true; + } + + for (const std::unique_ptr& assets : apk_assets_) { + for (const std::unique_ptr& loaded_package + : assets->GetLoadedArsc()->GetPackages()) { + if (packageId == loaded_package->GetPackageId() && loaded_package->IsDynamic()) { + return true; + } + } + } + + return false; } static std::unique_ptr LookupAttributeInTable( - const android::ResTable& table, ResourceId id) { - // Try as a bag. - const android::ResTable::bag_entry* entry; - ssize_t count = table.lockBag(id.id, &entry); - if (count < 0) { - table.unlockBag(entry); + android::AssetManager2& am, ResourceId id) { + if (am.GetApkAssets().empty()) { + return {}; + } + + const android::ResolvedBag* bag = am.GetBag(id.id); + if (bag == nullptr) { return nullptr; } // We found a resource. std::unique_ptr s = util::make_unique(id); - // Check to see if it is an attribute. - for (size_t i = 0; i < (size_t)count; i++) { - if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) { - s->attribute = std::make_shared(entry[i].map.value.data); + const size_t count = bag->entry_count; + for (uint32_t i = 0; i < count; i++) { + if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) { + s->attribute = std::make_shared(bag->entries[i].value.data); break; } } if (s->attribute) { - for (size_t i = 0; i < (size_t)count; i++) { - const android::ResTable_map& map_entry = entry[i].map; - if (Res_INTERNALID(map_entry.name.ident)) { - switch (map_entry.name.ident) { + for (size_t i = 0; i < count; i++) { + const android::ResolvedBag::Entry& map_entry = bag->entries[i]; + if (Res_INTERNALID(map_entry.key)) { + switch (map_entry.key) { case android::ResTable_map::ATTR_MIN: s->attribute->min_int = static_cast(map_entry.value.data); break; @@ -269,74 +296,65 @@ static std::unique_ptr LookupAttributeInTable( continue; } - android::ResTable::resource_name entry_name; - if (!table.getResourceName(map_entry.name.ident, false, &entry_name)) { - table.unlockBag(entry); + android::AssetManager2::ResourceName name; + if (!am.GetResourceName(map_entry.key, &name)) { return nullptr; } - Maybe parsed_name = ResourceUtils::ToResourceName(entry_name); + Maybe parsed_name = ResourceUtils::ToResourceName(name); if (!parsed_name) { return nullptr; } Attribute::Symbol symbol; symbol.symbol.name = parsed_name.value(); - symbol.symbol.id = ResourceId(map_entry.name.ident); + symbol.symbol.id = ResourceId(map_entry.key); symbol.value = map_entry.value.data; s->attribute->symbols.push_back(std::move(symbol)); } } - table.unlockBag(entry); + return s; } std::unique_ptr AssetManagerSymbolSource::FindByName( const ResourceName& name) { - const android::ResTable& table = assets_.getResources(false); - - const std::u16string package16 = util::Utf8ToUtf16(name.package); - const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type)); - const std::u16string entry16 = util::Utf8ToUtf16(name.entry); - const std::u16string mangled_entry16 = - util::Utf8ToUtf16(NameMangler::MangleEntry(name.package, name.entry)); + const std::string mangled_entry = NameMangler::MangleEntry(name.package, name.entry); + bool found = false; + ResourceId res_id = 0; uint32_t type_spec_flags; - ResourceId res_id; // There can be mangled resources embedded within other packages. Here we will // look into each package and look-up the mangled name until we find the resource. - const size_t count = table.getBasePackageCount(); - for (size_t i = 0; i < count; i++) { - const android::String16 package_name = table.getBasePackageName(i); - StringPiece16 real_package16 = package16; - StringPiece16 real_entry16 = entry16; - std::u16string scratch_entry16; - if (StringPiece16(package_name) != package16) { - real_entry16 = mangled_entry16; - real_package16 = package_name.string(); + asset_manager_.ForEachPackage([&](const std::string& package_name, uint8_t id) -> bool { + ResourceName real_name(name.package, name.type, name.entry); + + if (package_name != name.package) { + real_name.entry = mangled_entry; + real_name.package = package_name; } - type_spec_flags = 0; - res_id = table.identifierForName(real_entry16.data(), real_entry16.size(), type16.data(), - type16.size(), real_package16.data(), real_package16.size(), - &type_spec_flags); - if (res_id.is_valid()) { - break; + res_id = asset_manager_.GetResourceId(real_name.to_string()); + if (res_id.is_valid() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) { + found = true; + return false; } - } - if (!res_id.is_valid()) { + return true; + }); + + if (!found) { return {}; } std::unique_ptr s; if (name.type == ResourceType::kAttr) { - s = LookupAttributeInTable(table, res_id); + s = LookupAttributeInTable(asset_manager_, res_id); } else { s = util::make_unique(); s->id = res_id; - s->is_dynamic = table.isResourceDynamic(res_id.id); + s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id()); } if (s) { @@ -346,13 +364,13 @@ std::unique_ptr AssetManagerSymbolSource::FindByName( return {}; } -static Maybe GetResourceName(const android::ResTable& table, +static Maybe GetResourceName(android::AssetManager2& am, ResourceId id) { - android::ResTable::resource_name res_name = {}; - if (!table.getResourceName(id.id, true, &res_name)) { + android::AssetManager2::ResourceName name; + if (!am.GetResourceName(id.id, &name)) { return {}; } - return ResourceUtils::ToResourceName(res_name); + return ResourceUtils::ToResourceName(name); } std::unique_ptr AssetManagerSymbolSource::FindById( @@ -361,22 +379,30 @@ std::unique_ptr AssetManagerSymbolSource::FindById( // Exit early and avoid the error logs from AssetManager. return {}; } - const android::ResTable& table = assets_.getResources(false); - Maybe maybe_name = GetResourceName(table, id); + + if (apk_assets_.empty()) { + return {}; + } + + Maybe maybe_name = GetResourceName(asset_manager_, id); if (!maybe_name) { return {}; } + uint32_t type_spec_flags = 0; - table.getResourceFlags(id.id, &type_spec_flags); + if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) { + return {}; + } + ResourceName& name = maybe_name.value(); std::unique_ptr s; - if (maybe_name.value().type == ResourceType::kAttr) { - s = LookupAttributeInTable(table, id); + if (name.type == ResourceType::kAttr) { + s = LookupAttributeInTable(asset_manager_, id); } else { s = util::make_unique(); s->id = id; - s->is_dynamic = table.isResourceDynamic(id.id); + s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id()); } if (s) { diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h index 2d8bd02a3799..6997cd6714a8 100644 --- a/tools/aapt2/process/SymbolTable.h +++ b/tools/aapt2/process/SymbolTable.h @@ -22,7 +22,8 @@ #include #include "android-base/macros.h" -#include "androidfw/AssetManager.h" +#include "androidfw/Asset.h" +#include "androidfw/AssetManager2.h" #include "utils/JenkinsHash.h" #include "utils/LruCache.h" @@ -201,12 +202,13 @@ class AssetManagerSymbolSource : public ISymbolSource { std::unique_ptr FindByReference( const Reference& ref) override; - android::AssetManager* GetAssetManager() { - return &assets_; + android::AssetManager2* GetAssetManager() { + return &asset_manager_; } private: - android::AssetManager assets_; + android::AssetManager2 asset_manager_; + std::vector> apk_assets_; DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource); }; diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp index 1f59d7034300..ddc210189793 100644 --- a/tools/aapt2/process/SymbolTable_test.cpp +++ b/tools/aapt2/process/SymbolTable_test.cpp @@ -76,40 +76,54 @@ TEST(SymbolTableTest, FindByName) { EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull()); } -TEST(SymbolTableTest, FindByNameWhenSymbolIsMangledInResTable) { +using SymbolTableTestFixture = CommandTestFixture; +TEST_F(SymbolTableTestFixture, FindByNameWhenSymbolIsMangledInResTable) { using namespace android; - - std::unique_ptr context = - test::ContextBuilder() - .SetCompilationPackage("com.android.app") - .SetPackageId(0x7f) - .SetPackageType(PackageType::kApp) - .SetMinSdkVersion(SDK_LOLLIPOP_MR1) - .SetNameManglerPolicy(NameManglerPolicy{"com.android.app"}) - .Build(); - - // Create a ResourceTable with a mangled resource, simulating a static library being merged into - // the main application package. - std::unique_ptr table = - test::ResourceTableBuilder() - .AddSimple("com.android.app:id/" + NameMangler::MangleEntry("com.android.lib", "foo"), - ResourceId(0x7f020000)) - .AddSimple("com.android.app:id/bar", ResourceId(0x7f020001)) - .Build(); - - BigBuffer buffer(1024u); - TableFlattener flattener({}, &buffer); - ASSERT_TRUE(flattener.Consume(context.get(), table.get())); - - std::unique_ptr data = util::Copy(buffer); + StdErrDiagnostics diag; + + // Create a static library. + const std::string static_lib_compiled_files_dir = GetTestPath("static-lib-compiled"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), + R"( + + + )", + static_lib_compiled_files_dir, &diag)); + + const std::string static_lib_apk = GetTestPath("static_lib.apk"); + std::vector link_args = { + "--manifest", GetDefaultManifest("com.android.lib"), + "--min-sdk-version", "22", + "--static-lib", + "-o", static_lib_apk, + }; + ASSERT_TRUE(Link(link_args, static_lib_compiled_files_dir, &diag)); + + // Merge the static library into the main application package. The static library resources will + // be mangled with the library package name. + const std::string app_compiled_files_dir = GetTestPath("app-compiled"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), + R"( + + + )", + app_compiled_files_dir, &diag)); + + const std::string out_apk = GetTestPath("out.apk"); + link_args = { + "--manifest", GetDefaultManifest("com.android.app"), + "--min-sdk-version", "22", + "-o", out_apk, + static_lib_apk + }; + ASSERT_TRUE(Link(link_args, app_compiled_files_dir, &diag)); // Construct the test AssetManager. auto asset_manager_source = util::make_unique(); - ResTable& res_table = const_cast( - asset_manager_source->GetAssetManager()->getResources(false /*required*/)); - ASSERT_THAT(res_table.add(data.get(), buffer.size()), Eq(NO_ERROR)); + asset_manager_source->AddAssetPath(out_apk); - SymbolTable symbol_table(context->GetNameMangler()); + NameMangler name_mangler(NameManglerPolicy{"com.android.app"}); + SymbolTable symbol_table(&name_mangler); symbol_table.AppendSource(std::move(asset_manager_source)); EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull()); diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp index 3fcdfb70a524..a51b4a4649f1 100644 --- a/tools/aapt2/test/Fixture.cpp +++ b/tools/aapt2/test/Fixture.cpp @@ -37,6 +37,8 @@ using testing::Ne; namespace aapt { +const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test"; + void ClearDirectory(const android::StringPiece& path) { const std::string root_dir = path.to_string(); std::unique_ptr dir(opendir(root_dir.data()), closedir); @@ -124,12 +126,12 @@ bool CommandTestFixture::Link(const std::vector& args, return LinkCommand(diag).Execute(link_args, &std::cerr) == 0; } -std::string CommandTestFixture::GetDefaultManifest() { +std::string CommandTestFixture::GetDefaultManifest(const char* package_name) { const std::string manifest_file = GetTestPath("AndroidManifest.xml"); - CHECK(WriteFile(manifest_file, R"( + CHECK(WriteFile(manifest_file, android::base::StringPrintf(R"( - )")); + package="%s"> + )", package_name))); return manifest_file; } diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h index 3079c757f61a..fce2aebfecaa 100644 --- a/tools/aapt2/test/Fixture.h +++ b/tools/aapt2/test/Fixture.h @@ -81,7 +81,7 @@ class CommandTestFixture : public TestDirectoryFixture { IDiagnostics* diag); // Creates a minimal android manifest within the test directory and returns the file path. - std::string GetDefaultManifest(); + std::string GetDefaultManifest(const char* package_name = kDefaultPackageName); // Returns pointer to data inside APK files std::unique_ptr OpenFileAsData(LoadedApk* apk, @@ -91,6 +91,7 @@ class CommandTestFixture : public TestDirectoryFixture { void AssertLoadXml(LoadedApk* apk, const io::IData* data, android::ResXMLTree* out_tree); + static const char* kDefaultPackageName; private: DISALLOW_COPY_AND_ASSIGN(CommandTestFixture); }; diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index 604b2575daa1..5d57de6a9fb1 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -102,12 +102,21 @@ FileType GetFileType(const std::string& path) { #endif bool mkdirs(const std::string& path) { - #ifdef _WIN32 - // Start after the drive path if present. Calling mkdir with only the drive will cause an error. - size_t current_pos = 1u; - if (path.size() >= 3 && path[1] == ':' && - (path[2] == '\\' || path[2] == '/')) { - current_pos = 3u; + #ifdef _WIN32 + // Start after the long path prefix if present. + bool require_drive = false; + size_t current_pos = 0u; + if (util::StartsWith(path, R"(\\?\)")) { + require_drive = true; + current_pos = 4u; + } + + // Start after the drive path if present. + if (path.size() >= 3 && path[current_pos + 1] == ':' && + (path[current_pos + 2] == '\\' || path[current_pos + 2] == '/')) { + current_pos += 3u; + } else if (require_drive) { + return false; } #else // Start after the first character so that we don't consume the root '/'. diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp index 202cc261ad89..6c380808c0df 100644 --- a/tools/aapt2/util/Files_test.cpp +++ b/tools/aapt2/util/Files_test.cpp @@ -19,6 +19,7 @@ #include #include "android-base/stringprintf.h" +#include "android-base/utf8.h" #include "test/Test.h" @@ -65,5 +66,40 @@ TEST_F(FilesTest, AppendPathWithLeadingOrTrailingSeparators) { EXPECT_EQ(expected_path_, base); } +#ifdef _WIN32 +TEST_F(FilesTest, WindowsMkdirsLongPath) { + // Creating directory paths longer than the Windows maximum path length (260 charatcers) should + // succeed. + const std::string kDirName = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + const size_t kRecursiveDepth = 10u; + + // Recursively create the test file path and clean up the created directories after the files have + // been created. + std::function CreateResursiveDirs = + [&kDirName, &CreateResursiveDirs](std::string current_path, const size_t n) -> void { + AppendPath(¤t_path, kDirName); + + if (n == 0) { + ASSERT_TRUE(file::mkdirs(current_path)) << "Failed to create path " << current_path; + } else { + CreateResursiveDirs(current_path, n - 1); + } + + // Clean up the created directories. + _rmdir(current_path.data()); + }; + + CreateResursiveDirs( + android::base::StringPrintf(R"(\\?\%s)", android::base::GetExecutableDirectory().data()), + kRecursiveDepth); +} + +TEST_F(FilesTest, WindowsMkdirsLongPathMissingDrive) { + ASSERT_FALSE(file::mkdirs(R"(\\?\local\path\to\file)")); + ASSERT_FALSE(file::mkdirs(R"(\\?\:local\path\to\file)")); + ASSERT_FALSE(file::mkdirs(R"(\\?\\local\path\to\file)")); +} +#endif + } // namespace files } // namespace aapt -- cgit v1.2.3-59-g8ed1b From 2fe2347e1e422748a188285f3ccc50e7894a0896 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Wed, 27 Feb 2019 09:43:01 -0800 Subject: Add ANDROID_LOG to supress android specific logs AAPT2 uses AssetManager2 as the implmentation of its symbol table. When generating the the R.java, AAPT2 adds information about styleables in the comments. If the first symbol table checked by the delegate is an AssetManager2 symbol table and it does not contain the styleable attribute being searched for, a bogus error is printed and the resource is found in a later symbol table. Bug: 126596328 Test: m -j Settings && diffed generated java files Change-Id: If86a9d62fd72317525dffa862be1267621f93afd --- libs/androidfw/AssetManager2.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index d7b84ff1060d..117d05e837ef 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -35,6 +35,12 @@ #endif #endif +#ifdef __ANDROID__ +#define ANDROID_LOG(x) LOG(x) +#else +#define ANDROID_LOG(x) std::stringstream() +#endif + #include "androidfw/ResourceUtils.h" namespace android { @@ -380,7 +386,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri const uint8_t package_idx = package_ids_[package_id]; if (package_idx == 0xff) { - LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid); + ANDROID_LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", + package_id, resid); return kInvalidCookie; } -- cgit v1.2.3-59-g8ed1b From 2c4d874d72588cefe36acf19eded4b09c24cad2d Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Mon, 4 Mar 2019 09:41:00 -0800 Subject: Invalidate style stack resids Style resid stacks should also be invalidated when invalidating AssetManager caches. Bug:117176857 Test: manual Change-Id: I28224597adf4b0af8326bd788eab289e4ba60418 --- libs/androidfw/AssetManager2.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 117d05e837ef..d74f27cca200 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -1052,6 +1052,8 @@ void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) { } void AssetManager2::InvalidateCaches(uint32_t diff) { + cached_bag_resid_stacks_.clear(); + if (diff == 0xffffffffu) { // Everything must go. cached_bags_.clear(); -- cgit v1.2.3-59-g8ed1b From dbf343becb8c80ca70fab681aed8a71789b94a91 Mon Sep 17 00:00:00 2001 From: MÃ¥rten Kongstad Date: Thu, 21 Feb 2019 07:54:18 +0100 Subject: RRO: remove ability to overlay assets Target packages use to opt-in to RRO. While this works for resources, it does not support assets. For security reasons, remove the ability to overlay assets via RRO for now: a future change may extend to include assets. Test: atest OverlayDeviceTests Bug: 120867881 Change-Id: Ie0b6897f0586ea8b9d75f357e216904e25d4dc7b --- .../overlaytests/device/assets/package-name.txt | 1 + .../com/android/overlaytest/OverlayBaseTest.java | 32 ++++++++++++++++++++++ .../device/test-apps/AppOverlayOne/assets/foo.txt | 1 + .../AppOverlayOne/assets/package-name.txt | 1 + .../device/test-apps/AppOverlayTwo/assets/bar.txt | 1 + .../AppOverlayTwo/assets/package-name.txt | 1 + libs/androidfw/AssetManager2.cpp | 10 +++++++ libs/androidfw/include/androidfw/ApkAssets.h | 4 +++ 8 files changed, 51 insertions(+) create mode 100644 core/tests/overlaytests/device/assets/package-name.txt create mode 100644 core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt create mode 100644 core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt create mode 100644 core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt create mode 100644 core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/core/tests/overlaytests/device/assets/package-name.txt b/core/tests/overlaytests/device/assets/package-name.txt new file mode 100644 index 000000000000..809443818f06 --- /dev/null +++ b/core/tests/overlaytests/device/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java index 91fcdbbb18ce..f86743a2fdbc 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java @@ -17,9 +17,12 @@ package com.android.overlaytest; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.UiAutomation; +import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -30,6 +33,8 @@ import android.util.Xml; import androidx.test.InstrumentationRegistry; +import com.android.internal.util.ArrayUtils; + import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -291,6 +296,33 @@ public abstract class OverlayBaseTest { assertEquals(getExpected(no, so, mo), actual); } + @Test + public void testAssetsNotPossibleToOverlay() throws Throwable { + final AssetManager am = mResources.getAssets(); + + // AssetManager#list will include assets from all loaded non-overlay + // APKs, including the framework; framework-res.apk contains at least + // assets/{images,webkit}. Rather than checking the list, verify that + // assets only present in overlays are never part of the list. + String[] files = am.list(""); + assertTrue(ArrayUtils.contains(files, "package-name.txt")); + assertFalse(ArrayUtils.contains(files, "foo.txt")); + assertFalse(ArrayUtils.contains(files, "bar.txt")); + + String contents = null; + try (InputStream is = am.open("package-name.txt")) { + final BufferedReader reader = new BufferedReader( + new InputStreamReader(is, StandardCharsets.UTF_8)); + StringBuilder str = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + str.append(line); + } + contents = str.toString(); + } + assertEquals("com.android.overlaytest", contents); + } + /* * testMatrix* tests * diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt new file mode 100644 index 000000000000..257cc5642cb1 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt @@ -0,0 +1 @@ +foo diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt new file mode 100644 index 000000000000..087cb96b767f --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_one diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt new file mode 100644 index 000000000000..5716ca5987cb --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt @@ -0,0 +1 @@ +bar diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt new file mode 100644 index 000000000000..13185654df21 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_two diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index d74f27cca200..951970464bfe 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -310,6 +310,9 @@ std::unique_ptr AssetManager2::OpenDir(const std::string& dirname) con // Start from the back. for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) { const ApkAssets* apk_assets = *iter; + if (apk_assets->IsOverlay()) { + continue; + } auto func = [&](const StringPiece& name, FileType type) { AssetDir::FileInfo info; @@ -336,6 +339,13 @@ std::unique_ptr AssetManager2::OpenNonAsset(const std::string& filename, Asset::AccessMode mode, ApkAssetsCookie* out_cookie) const { for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) { + // Prevent RRO from modifying assets and other entries accessed by file + // path. Explicitly asking for a path in a given package (denoted by a + // cookie) is still OK. + if (apk_assets_[i]->IsOverlay()) { + continue; + } + std::unique_ptr asset = apk_assets_[i]->Open(filename, mode); if (asset) { if (out_cookie != nullptr) { diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index db2d0382bcf6..35bbb5804df4 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -80,6 +80,10 @@ class ApkAssets { return loaded_arsc_.get(); } + inline bool IsOverlay() const { + return idmap_asset_.get() != nullptr; + } + private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); -- cgit v1.2.3-59-g8ed1b From 93bca97e7ce1f3a7938d6ce5af5f6f325ab66f89 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 8 Mar 2019 17:26:28 -0800 Subject: Allow non-references to be copied between AssetManagers Hard-coded values in styles can be copied between AssetManagers even if the source package is not present in the destination AssetManager. Only references and strings should be prevented from being copied over because they would be invalid in the destination AssetManager. Bug:126400561 Test: manual Change-Id: I970a3e961763b2c003c15b950d864a9a0b615022 --- libs/androidfw/AssetManager2.cpp | 68 ++++++++++--------- libs/androidfw/tests/Theme_test.cpp | 73 +++++++++++++++------ libs/androidfw/tests/data/styles/R.h | 1 + libs/androidfw/tests/data/styles/build | 4 +- .../tests/data/styles/res/values/styles.xml | 10 +++ libs/androidfw/tests/data/styles/styles.apk | Bin 2550 -> 2774 bytes 6 files changed, 105 insertions(+), 51 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 951970464bfe..1b515ad41e68 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -1319,7 +1319,7 @@ void Theme::SetTo(const Theme& o) { typedef std::map SourceToDestinationRuntimePackageMap; std::map src_asset_cookie_id_map; - // Determine which ApkAssets are loaded in both theme AssetManagers + // Determine which ApkAssets are loaded in both theme AssetManagers. std::vector src_assets = o.asset_manager_->GetApkAssets(); for (size_t i = 0; i < src_assets.size(); i++) { const ApkAssets* src_asset = src_assets[i]; @@ -1328,7 +1328,7 @@ void Theme::SetTo(const Theme& o) { for (size_t j = 0; j < dest_assets.size(); j++) { const ApkAssets* dest_asset = dest_assets[j]; - // Map the runtime package of the source apk asset to the destination apk asset + // Map the runtime package of the source apk asset to the destination apk asset. if (src_asset->GetPath() == dest_asset->GetPath()) { const std::vector>& src_packages = src_asset->GetLoadedArsc()->GetPackages(); @@ -1353,15 +1353,14 @@ void Theme::SetTo(const Theme& o) { package_map[src_package_id] = dest_package_id; } - src_to_dest_asset_cookies.insert(std::pair(i, j)); - src_asset_cookie_id_map.insert( - std::pair(i, package_map)); + src_to_dest_asset_cookies.insert(std::make_pair(i, j)); + src_asset_cookie_id_map.insert(std::make_pair(i, package_map)); break; } } } - // Reset the data in the destination theme + // Reset the data in the destination theme. for (size_t p = 0; p < packages_.size(); p++) { if (packages_[p] != nullptr) { packages_[p].reset(); @@ -1387,16 +1386,17 @@ void Theme::SetTo(const Theme& o) { continue; } + bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_REFERENCE + || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) + && entry.value.data != 0x0; + // If the attribute value represents an attribute or reference, the package id of the - // value needs to be rewritten to the package id of the value in the destination - uint32_t attribue_data = entry.value.data; - if ((entry.value.dataType == Res_value::TYPE_ATTRIBUTE - || entry.value.dataType == Res_value::TYPE_REFERENCE - || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE - || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) - && attribue_data != 0x0) { - - // Determine the package id of the reference in the destination AssetManager + // value needs to be rewritten to the package id of the value in the destination. + uint32_t attribute_data = entry.value.data; + if (is_reference) { + // Determine the package id of the reference in the destination AssetManager. auto value_package_map = src_asset_cookie_id_map.find(entry.cookie); if (value_package_map == src_asset_cookie_id_map.end()) { continue; @@ -1408,14 +1408,28 @@ void Theme::SetTo(const Theme& o) { continue; } - attribue_data = fix_package_id(entry.value.data, value_dest_package->second); + attribute_data = fix_package_id(entry.value.data, value_dest_package->second); + } + + // Find the cookie of the value in the destination. If the source apk is not loaded in the + // destination, only copy resources that do not reference resources in the source. + ApkAssetsCookie data_dest_cookie; + auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie); + if (value_dest_cookie != src_to_dest_asset_cookies.end()) { + data_dest_cookie = value_dest_cookie->second; + } else { + if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) { + continue; + } else { + data_dest_cookie = 0x0; + } } // The package id of the attribute needs to be rewritten to the package id of the - // attribute in the destination + // attribute in the destination. int attribute_dest_package_id = p; if (attribute_dest_package_id != 0x01) { - // Find the cookie of the attribute resource id + // Find the cookie of the attribute resource id in the source AssetManager FindEntryResult attribute_entry_result; ApkAssetsCookie attribute_cookie = o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , @@ -1423,7 +1437,7 @@ void Theme::SetTo(const Theme& o) { true /* ignore_configuration */, &attribute_entry_result); - // Determine the package id of the attribute in the destination AssetManager + // Determine the package id of the attribute in the destination AssetManager. auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie); if (attribute_package_map == src_asset_cookie_id_map.end()) { continue; @@ -1436,13 +1450,13 @@ void Theme::SetTo(const Theme& o) { attribute_dest_package_id = attribute_dest_package->second; } - // Lazily instantiate the destination package + // Lazily instantiate the destination package. std::unique_ptr& dest_package = packages_[attribute_dest_package_id]; if (dest_package == nullptr) { dest_package.reset(new Package()); } - // Lazily instantiate and resize the destination type + // Lazily instantiate and resize the destination type. util::unique_cptr& dest_type = dest_package->types[t]; if (dest_type == nullptr || dest_type->entry_count < type->entry_count) { const size_t type_alloc_size = sizeof(ThemeType) @@ -1450,7 +1464,7 @@ void Theme::SetTo(const Theme& o) { void* dest_data = malloc(type_alloc_size); memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry)); - // Copy the existing destination type values if the type is resized + // Copy the existing destination type values if the type is resized. if (dest_type != nullptr) { memcpy(dest_data, type, sizeof(ThemeType) + (dest_type->entry_count * sizeof(ThemeEntry))); @@ -1460,15 +1474,9 @@ void Theme::SetTo(const Theme& o) { dest_type->entry_count = type->entry_count; } - // Find the cookie of the value in the destination - auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie); - if (value_dest_cookie == src_to_dest_asset_cookies.end()) { - continue; - } - - dest_type->entries[e].cookie = value_dest_cookie->second; + dest_type->entries[e].cookie = data_dest_cookie; dest_type->entries[e].value.dataType = entry.value.dataType; - dest_type->entries[e].value.data = attribue_data; + dest_type->entries[e].value.data = attribute_data; dest_type->entries[e].type_spec_flags = entry.type_spec_flags; } } diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp index 2c39ceead123..be5ecd94a588 100644 --- a/libs/androidfw/tests/Theme_test.cpp +++ b/libs/androidfw/tests/Theme_test.cpp @@ -282,48 +282,81 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) { } TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) { - AssetManager2 assetmanager_one; - assetmanager_one.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(), + AssetManager2 assetmanager_dst; + assetmanager_dst.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(), libclient_assets_.get()}); - AssetManager2 assetmanager_two; - assetmanager_two.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(), + AssetManager2 assetmanager_src; + assetmanager_src.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(), style_assets_.get()}); - auto theme_one = assetmanager_one.NewTheme(); - ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne)); + auto theme_dst = assetmanager_dst.NewTheme(); + ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne)); - auto theme_two = assetmanager_two.NewTheme(); - ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One)); - ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo)); - ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03), + auto theme_src = assetmanager_src.NewTheme(); + ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One)); + ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo)); + ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03), false /*force*/)); - ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02), + ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02), false /*force*/)); - theme_one->SetTo(*theme_two); + theme_dst->SetTo(*theme_src); Res_value value; uint32_t flags; - // System resources (present in destination asset manager) - EXPECT_EQ(0, theme_one->GetAttribute(R::attr::foreground, &value, &flags)); + // System resources (present in destination asset manager). + EXPECT_EQ(0, theme_dst->GetAttribute(R::attr::foreground, &value, &flags)); // The cookie of the style asset is 3 in the source and 2 in the destination. - // Check that the cookie has been rewritten to the destination values - EXPECT_EQ(2, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags)); + // Check that the cookie has been rewritten to the destination values. + EXPECT_EQ(2, theme_dst->GetAttribute(app::R::attr::attr_one, &value, &flags)); // The cookie of the lib_one asset is 2 in the source and 1 in the destination. // The package id of the lib_one package is 0x03 in the source and 0x02 in the destination - // Check that the cookie and packages have been rewritten to the destination values - EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value, + // Check that the cookie and packages have been rewritten to the destination values. + EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value, &flags)); - EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value, + EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value, &flags)); // attr2 references an attribute in lib_one. Check that the resolution of the attribute value is - // correct after the value of attr2 had its package id rewritten to the destination package id + // correct after the value of attr2 had its package id rewritten to the destination package id. EXPECT_EQ(700, value.data); } +TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) { + AssetManager2 assetmanager_dst; + assetmanager_dst.SetApkAssets({system_assets_.get()}); + + AssetManager2 assetmanager_src; + assetmanager_src.SetApkAssets({system_assets_.get(), style_assets_.get()}); + + auto theme_dst = assetmanager_dst.NewTheme(); + auto theme_src = assetmanager_src.NewTheme(); + ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven)); + theme_dst->SetTo(*theme_src); + + Res_value value; + uint32_t flags; + + // Allow inline resource values to be copied even if the source apk asset is not present in the + // destination. + EXPECT_EQ(0, theme_dst->GetAttribute(0x0101021b /* android:versionCode */, &value, &flags)); + + // Do not copy strings since the data is an index into the values string pool of the source apk + // asset. + EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010001 /* android:label */, &value, &flags)); + + // Do not copy values that reference another resource if the resource is not present in the + // destination. + EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010002 /* android:icon */, &value, &flags)); + EXPECT_EQ(-1, theme_dst->GetAttribute(0x010100d1 /* android:tag */, &value, &flags)); + + // Allow @empty to and @null to be copied. + EXPECT_EQ(0, theme_dst->GetAttribute(0x010100d0 /* android:id */, &value, &flags)); + EXPECT_EQ(0, theme_dst->GetAttribute(0x01010000 /* android:theme */, &value, &flags)); +} + } // namespace android diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h index 538a84717176..f11486fe924a 100644 --- a/libs/androidfw/tests/data/styles/R.h +++ b/libs/androidfw/tests/data/styles/R.h @@ -51,6 +51,7 @@ struct R { StyleFour = 0x7f020003u, StyleFive = 0x7f020004u, StyleSix = 0x7f020005u, + StyleSeven = 0x7f020006u, }; }; }; diff --git a/libs/androidfw/tests/data/styles/build b/libs/androidfw/tests/data/styles/build index 1ef8e6e19208..7b7c1f7aa962 100755 --- a/libs/androidfw/tests/data/styles/build +++ b/libs/androidfw/tests/data/styles/build @@ -2,5 +2,7 @@ set -e +PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar + aapt2 compile -o compiled.flata --dir res -aapt2 link -o styles.apk --manifest AndroidManifest.xml compiled.flata +aapt2 link -o styles.apk --manifest AndroidManifest.xml -I $PATH_TO_FRAMEWORK_RES compiled.flata diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml index 1a231768dade..06774a8a6005 100644 --- a/libs/androidfw/tests/data/styles/res/values/styles.xml +++ b/libs/androidfw/tests/data/styles/res/values/styles.xml @@ -79,4 +79,14 @@ 3 + + + diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk index cd5c7a1c6c12..92e9bf90101e 100644 Binary files a/libs/androidfw/tests/data/styles/styles.apk and b/libs/androidfw/tests/data/styles/styles.apk differ -- cgit v1.2.3-59-g8ed1b From 4487398e0dca180c0a3223cd23949861440702db Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 20 May 2019 15:22:22 -0700 Subject: Remove obtainStyledAttribute and AssetManager2::GetBag tracing These traces are small and noisy, so they hurt performance more than they help. This reverts commit c37457799be3db0590a5d94832b2fef5f64ef439. Test: m Bug: 132721345 Change-Id: I9ef719f54f2bc8a54f23e88f46d74e35417a6519 (cherry picked from commit 3509b624feecbcb8be850f9e1f397cdd7aeea5e2) --- core/java/android/content/res/ResourcesImpl.java | 7 ++----- libs/androidfw/AssetManager2.cpp | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'libs/androidfw/AssetManager2.cpp') diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 633966c38786..794be9e202be 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -1390,11 +1390,9 @@ public class ResourcesImpl { @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { - Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "obtainStyledAttributes"); - TypedArray array; synchronized (mKey) { final int len = attrs.length; - array = TypedArray.obtain(wrapper.getResources(), len); + final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); // XXX note that for now we only work with compiled XML files. // To support generic XML files we will need to manually parse @@ -1405,9 +1403,8 @@ public class ResourcesImpl { array.mDataAddress, array.mIndicesAddress); array.mTheme = wrapper; array.mXml = parser; + return array; } - Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - return array; } @NonNull diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 1b515ad41e68..d20aecaaf0f6 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -778,8 +778,6 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { } const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector& child_resids) { - ATRACE_NAME("AssetManager::GetBag"); - auto cached_iter = cached_bags_.find(resid); if (cached_iter != cached_bags_.end()) { return cached_iter->second.get(); -- cgit v1.2.3-59-g8ed1b