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 --- libs/androidfw/ResourceUtils.cpp | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'libs/androidfw/ResourceUtils.cpp') 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 -- 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/ResourceUtils.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