From 824cc490c54d9a488c561965770abec09a32c0a5 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Wed, 12 Feb 2020 10:48:14 -0800 Subject: [PATCH] Assigned package ids to overlays last Before overlays could reference internal resources, overlays were added to AssetManagers before shared libraries. Overlays are now loaded as shared libraries so they must be assigned package ids after non-overlay shared libraries so enabling and disabling overlays does not affect the package ids of the non-overlay shared libraries. Since overlays are added to the end of the AssetManager by ResourcesManager, enabling and disabling overlays will not change the assets cookie of shared libraries loaded through ResourcesManager, but it will change the apk assets cookie or overlays added through AssetManager#addAssetPathAsSharedLibrary. The package ids of shared libraries added through AssetManager#addAssetPathAsSharedLibrary will not be affected by overlays since overlay package ids are assigned last. Bug: 146685730 Test: CtsHostsideWebViewTests Change-Id: If7ea17d51b18769bf2465e29af3ae6a71004d06c --- libs/androidfw/AssetManager2.cpp | 25 ++++++--- .../include/androidfw/AssetManager2.h | 6 +- libs/androidfw/tests/AssetManager2_test.cpp | 56 ++++++++++++++----- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 803828fc16c57..eaf452b5fa711 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -88,13 +88,24 @@ void AssetManager2::BuildDynamicRefTable() { // A mapping from apk assets path to the runtime package id of its first loaded package. std::unordered_map apk_assets_package_ids; + // Overlay resources are not directly referenced by an application so their resource ids + // can change throughout the application's lifetime. Assign overlay package ids last. + std::vector sorted_apk_assets(apk_assets_); + std::stable_partition(sorted_apk_assets.begin(), sorted_apk_assets.end(), [](const ApkAssets* a) { + return !a->IsOverlay(); + }); + + // The assets cookie must map to the position of the apk assets in the unsorted apk assets list. + std::unordered_map apk_assets_cookies; + apk_assets_cookies.reserve(apk_assets_.size()); + for (size_t i = 0, n = apk_assets_.size(); i < n; i++) { + apk_assets_cookies[apk_assets_[i]] = static_cast(i); + } + // 0x01 is reserved for the android package. int next_package_id = 0x02; - const size_t apk_assets_count = apk_assets_.size(); - for (size_t i = 0; i < apk_assets_count; i++) { - const ApkAssets* apk_assets = apk_assets_[i]; + for (const ApkAssets* apk_assets : sorted_apk_assets) { const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc(); - for (const std::unique_ptr& package : loaded_arsc->GetPackages()) { // Get the package ID or assign one if a shared library. int package_id; @@ -126,7 +137,7 @@ void AssetManager2::BuildDynamicRefTable() { PackageGroup& target_package_group = package_groups_[target_idx]; - // Create a special dynamic reference table for the overlay to rewite references to + // Create a special dynamic reference table for the overlay to rewrite references to // overlay resources as references to the target resources they overlay. auto overlay_table = std::make_shared( loaded_idmap->GetOverlayDynamicRefTable(target_package_id)); @@ -136,7 +147,7 @@ void AssetManager2::BuildDynamicRefTable() { target_package_group.overlays_.push_back( ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id, overlay_table.get()), - static_cast(i)}); + apk_assets_cookies[apk_assets]}); } } @@ -148,7 +159,7 @@ void AssetManager2::BuildDynamicRefTable() { // Add the package and to the set of packages with the same ID. package_group->packages_.push_back(ConfiguredPackage{package.get(), {}}); - package_group->cookies_.push_back(static_cast(i)); + package_group->cookies_.push_back(apk_assets_cookies[apk_assets]); // Add the package name -> build time ID mappings. for (const DynamicPackageEntry& entry : package->GetDynamicPackageMap()) { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 00cbbcad56e68..e21abade99a4d 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. std::shared_ptr GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const; + // Retrieve the assigned package id of the package if loaded into this AssetManager + uint8_t GetAssignedPackageId(const LoadedPackage* package) const; + // Returns a string representation of the overlayable API of a package. bool GetOverlayablesToString(const android::StringPiece& package_name, std::string* out) const; @@ -368,9 +371,6 @@ class AssetManager2 { // been seen while traversing bag parents. const ResolvedBag* GetBag(uint32_t resid, std::vector& child_resids); - // Retrieve the assigned package id of the package if loaded into this AssetManager - uint8_t GetAssignedPackageId(const LoadedPackage* package) const; - // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. std::vector apk_assets_; diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 6054fa3338bd7..8c255d16fe1f3 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -17,9 +17,9 @@ #include "androidfw/AssetManager2.h" #include "androidfw/AssetManager.h" -#include "android-base/logging.h" - #include "TestHelpers.h" +#include "android-base/file.h" +#include "android-base/logging.h" #include "androidfw/ResourceUtils.h" #include "data/appaslib/R.h" #include "data/basic/R.h" @@ -45,37 +45,43 @@ namespace android { class AssetManager2Test : public ::testing::Test { public: void SetUp() override { - basic_assets_ = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk"); + // Move to the test data directory so the idmap can locate the overlay APK. + std::string original_path = base::GetExecutableDirectory(); + chdir(GetTestDataPath().c_str()); + + basic_assets_ = ApkAssets::Load("basic/basic.apk"); ASSERT_NE(nullptr, basic_assets_); - basic_de_fr_assets_ = ApkAssets::Load(GetTestDataPath() + "/basic/basic_de_fr.apk"); + basic_de_fr_assets_ = ApkAssets::Load("basic/basic_de_fr.apk"); ASSERT_NE(nullptr, basic_de_fr_assets_); - style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk"); + style_assets_ = ApkAssets::Load("styles/styles.apk"); ASSERT_NE(nullptr, style_assets_); - lib_one_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_one/lib_one.apk"); + lib_one_assets_ = ApkAssets::Load("lib_one/lib_one.apk"); ASSERT_NE(nullptr, lib_one_assets_); - lib_two_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_two/lib_two.apk"); + lib_two_assets_ = ApkAssets::Load("lib_two/lib_two.apk"); ASSERT_NE(nullptr, lib_two_assets_); - libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk"); + libclient_assets_ = ApkAssets::Load("libclient/libclient.apk"); ASSERT_NE(nullptr, libclient_assets_); - appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk", - PROPERTY_DYNAMIC); + appaslib_assets_ = ApkAssets::Load("appaslib/appaslib.apk", PROPERTY_DYNAMIC); ASSERT_NE(nullptr, appaslib_assets_); - system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", - PROPERTY_SYSTEM); + system_assets_ = ApkAssets::Load("system/system.apk", PROPERTY_SYSTEM); ASSERT_NE(nullptr, system_assets_); - app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk"); + app_assets_ = ApkAssets::Load("app/app.apk"); ASSERT_THAT(app_assets_, NotNull()); - overlayable_assets_ = ApkAssets::Load(GetTestDataPath() + "/overlayable/overlayable.apk"); + overlay_assets_ = ApkAssets::LoadOverlay("overlay/overlay.idmap"); + ASSERT_NE(nullptr, overlay_assets_); + + overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk"); ASSERT_THAT(overlayable_assets_, NotNull()); + chdir(original_path.c_str()); } protected: @@ -88,6 +94,7 @@ class AssetManager2Test : public ::testing::Test { std::unique_ptr appaslib_assets_; std::unique_ptr system_assets_; std::unique_ptr app_assets_; + std::unique_ptr overlay_assets_; std::unique_ptr overlayable_assets_; }; @@ -216,6 +223,26 @@ TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) { EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data); } +TEST_F(AssetManager2Test, AssignsOverlayPackageIdLast) { + AssetManager2 assetmanager; + assetmanager.SetApkAssets( + {overlayable_assets_.get(), overlay_assets_.get(), lib_one_assets_.get()}); + + auto apk_assets = assetmanager.GetApkAssets(); + ASSERT_EQ(3, apk_assets.size()); + ASSERT_EQ(overlayable_assets_.get(), apk_assets[0]); + ASSERT_EQ(overlay_assets_.get(), apk_assets[1]); + ASSERT_EQ(lib_one_assets_.get(), apk_assets[2]); + + auto get_first_package_id = [&assetmanager](const ApkAssets* apkAssets) -> uint8_t { + return assetmanager.GetAssignedPackageId(apkAssets->GetLoadedArsc()->GetPackages()[0].get()); + }; + + ASSERT_EQ(get_first_package_id(overlayable_assets_.get()), 0x7f); + ASSERT_EQ(get_first_package_id(overlay_assets_.get()), 0x03); + ASSERT_EQ(get_first_package_id(lib_one_assets_.get()), 0x02); +} + TEST_F(AssetManager2Test, GetSharedLibraryResourceName) { AssetManager2 assetmanager; assetmanager.SetApkAssets({lib_one_assets_.get()}); @@ -751,7 +778,6 @@ TEST_F(AssetManager2Test, GetOverlayablesToString) { ASSERT_EQ(api.find("not_overlayable"), std::string::npos); ASSERT_NE(api.find("resource='com.android.overlayable:string/overlayable2' overlayable='OverlayableResources1' actor='overlay://theme' policy='0x0000000a'\n"), std::string::npos); - } } // namespace android