Loading libs/androidfw/AssetManager2.cpp +26 −3 Original line number Diff line number Diff line Loading @@ -992,6 +992,11 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { return bag; } static bool compare_bag_entries(const ResolvedBag::Entry& entry1, const ResolvedBag::Entry& entry2) { return entry1.key < entry2.key; } const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) { auto cached_iter = cached_bags_.find(resid); if (cached_iter != cached_bags_.end()) { Loading Loading @@ -1027,13 +1032,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids.push_back(resid); uint32_t parent_resid = dtohl(map->parent.ident); if (parent_resid == 0 || std::find(child_resids.begin(), child_resids.end(), parent_resid) if (parent_resid == 0U || std::find(child_resids.begin(), child_resids.end(), parent_resid) != child_resids.end()) { // There is no parent or that a circular dependency exist, meaning there is nothing to // inherit and we can do a simple copy of the entries in the map. // There is no parent or a circular dependency exist, meaning there is nothing to inherit and // we can do a simple copy of the entries in the map. const size_t entry_count = map_entry_end - map_entry; util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>( malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))}; bool sort_entries = false; ResolvedBag::Entry* new_entry = new_bag->entries; for (; map_entry != map_entry_end; ++map_entry) { uint32_t new_key = dtohl(map_entry->name.ident); Loading @@ -1059,8 +1066,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& new_entry->value.data, new_key); return nullptr; } sort_entries = sort_entries || (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key)); ++new_entry; } if (sort_entries) { std::sort(new_bag->entries, new_bag->entries + entry_count, compare_bag_entries); } new_bag->type_spec_flags = entry.type_flags; new_bag->entry_count = static_cast<uint32_t>(entry_count); ResolvedBag* result = new_bag.get(); Loading Loading @@ -1091,6 +1105,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count; // The keys are expected to be in sorted order. Merge the two bags. bool sort_entries = false; while (map_entry != map_entry_end && parent_entry != parent_entry_end) { uint32_t child_key = dtohl(map_entry->name.ident); if (!is_internal_resid(child_key)) { Loading Loading @@ -1123,6 +1138,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& memcpy(new_entry, parent_entry, sizeof(*new_entry)); } sort_entries = sort_entries || (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key)); if (child_key >= parent_entry->key) { // Move to the next parent entry if we used it or it was overridden. ++parent_entry; Loading Loading @@ -1153,6 +1170,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& new_entry->value.dataType, new_entry->value.data, new_key); return nullptr; } sort_entries = sort_entries || (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key)); ++map_entry; ++new_entry; } Loading @@ -1172,6 +1191,10 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))))); } if (sort_entries) { std::sort(new_bag->entries, new_bag->entries + actual_count, compare_bag_entries); } // Combine flags from the parent and our own bag. new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags; new_bag->entry_count = static_cast<uint32_t>(actual_count); Loading libs/androidfw/tests/AssetManager2_test.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,27 @@ TEST_F(AssetManager2Test, FindsBagResourceFromSharedLibrary) { EXPECT_EQ(0x03, get_package_id(bag->entries[1].key)); } TEST_F(AssetManager2Test, FindsBagResourceFromMultipleSharedLibraries) { AssetManager2 assetmanager; // libclient is built with lib_one and then lib_two in order. // Reverse the order to test that proper package ID re-assignment is happening. assetmanager.SetApkAssets( {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()}); const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib); ASSERT_NE(nullptr, bag); ASSERT_EQ(bag->entry_count, 2u); // First attribute comes from lib_two. EXPECT_EQ(2, bag->entries[0].cookie); EXPECT_EQ(0x02, get_package_id(bag->entries[0].key)); // The next two attributes come from lib_one. EXPECT_EQ(2, bag->entries[1].cookie); EXPECT_EQ(0x03, get_package_id(bag->entries[1].key)); } TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) { AssetManager2 assetmanager; Loading libs/androidfw/tests/data/lib_two/R.h +9 −3 Original line number Diff line number Diff line Loading @@ -30,16 +30,22 @@ struct R { }; }; struct integer { enum : uint32_t { bar = 0x02020000, // default }; }; struct string { enum : uint32_t { LibraryString = 0x02020000, // default foo = 0x02020001, // default LibraryString = 0x02030000, // default foo = 0x02030001, // default }; }; struct style { enum : uint32_t { Theme = 0x02030000, // default Theme = 0x02040000, // default }; }; }; Loading libs/androidfw/tests/data/lib_two/lib_two.apk +160 B (1.55 KiB) File changed.No diff preview for this file type. View original file View changed file libs/androidfw/tests/data/lib_two/res/values/values.xml +7 −4 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ <public type="attr" name="attr3" id="0x00010000" /> <attr name="attr3" format="integer" /> <public type="string" name="LibraryString" id="0x00020000" /> <public type="integer" name="bar" id="0x00020000" /> <integer name="bar">1337</integer> <public type="string" name="LibraryString" id="0x00030000" /> <string name="LibraryString">Hi from library two</string> <public type="string" name="foo" id="0x00020001" /> <public type="string" name="foo" id="0x00030001" /> <string name="foo">Foo from lib_two</string> <public type="style" name="Theme" id="0x02030000" /> <public type="style" name="Theme" id="0x00040000" /> <style name="Theme"> <item name="com.android.lib_two:attr3">800</item> <item name="com.android.lib_two:attr3">@integer/bar</item> </style> </resources> Loading
libs/androidfw/AssetManager2.cpp +26 −3 Original line number Diff line number Diff line Loading @@ -992,6 +992,11 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { return bag; } static bool compare_bag_entries(const ResolvedBag::Entry& entry1, const ResolvedBag::Entry& entry2) { return entry1.key < entry2.key; } const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) { auto cached_iter = cached_bags_.find(resid); if (cached_iter != cached_bags_.end()) { Loading Loading @@ -1027,13 +1032,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids.push_back(resid); uint32_t parent_resid = dtohl(map->parent.ident); if (parent_resid == 0 || std::find(child_resids.begin(), child_resids.end(), parent_resid) if (parent_resid == 0U || std::find(child_resids.begin(), child_resids.end(), parent_resid) != child_resids.end()) { // There is no parent or that a circular dependency exist, meaning there is nothing to // inherit and we can do a simple copy of the entries in the map. // There is no parent or a circular dependency exist, meaning there is nothing to inherit and // we can do a simple copy of the entries in the map. const size_t entry_count = map_entry_end - map_entry; util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>( malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))}; bool sort_entries = false; ResolvedBag::Entry* new_entry = new_bag->entries; for (; map_entry != map_entry_end; ++map_entry) { uint32_t new_key = dtohl(map_entry->name.ident); Loading @@ -1059,8 +1066,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& new_entry->value.data, new_key); return nullptr; } sort_entries = sort_entries || (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key)); ++new_entry; } if (sort_entries) { std::sort(new_bag->entries, new_bag->entries + entry_count, compare_bag_entries); } new_bag->type_spec_flags = entry.type_flags; new_bag->entry_count = static_cast<uint32_t>(entry_count); ResolvedBag* result = new_bag.get(); Loading Loading @@ -1091,6 +1105,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count; // The keys are expected to be in sorted order. Merge the two bags. bool sort_entries = false; while (map_entry != map_entry_end && parent_entry != parent_entry_end) { uint32_t child_key = dtohl(map_entry->name.ident); if (!is_internal_resid(child_key)) { Loading Loading @@ -1123,6 +1138,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& memcpy(new_entry, parent_entry, sizeof(*new_entry)); } sort_entries = sort_entries || (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key)); if (child_key >= parent_entry->key) { // Move to the next parent entry if we used it or it was overridden. ++parent_entry; Loading Loading @@ -1153,6 +1170,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& new_entry->value.dataType, new_entry->value.data, new_key); return nullptr; } sort_entries = sort_entries || (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key)); ++map_entry; ++new_entry; } Loading @@ -1172,6 +1191,10 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))))); } if (sort_entries) { std::sort(new_bag->entries, new_bag->entries + actual_count, compare_bag_entries); } // Combine flags from the parent and our own bag. new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags; new_bag->entry_count = static_cast<uint32_t>(actual_count); Loading
libs/androidfw/tests/AssetManager2_test.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,27 @@ TEST_F(AssetManager2Test, FindsBagResourceFromSharedLibrary) { EXPECT_EQ(0x03, get_package_id(bag->entries[1].key)); } TEST_F(AssetManager2Test, FindsBagResourceFromMultipleSharedLibraries) { AssetManager2 assetmanager; // libclient is built with lib_one and then lib_two in order. // Reverse the order to test that proper package ID re-assignment is happening. assetmanager.SetApkAssets( {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()}); const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib); ASSERT_NE(nullptr, bag); ASSERT_EQ(bag->entry_count, 2u); // First attribute comes from lib_two. EXPECT_EQ(2, bag->entries[0].cookie); EXPECT_EQ(0x02, get_package_id(bag->entries[0].key)); // The next two attributes come from lib_one. EXPECT_EQ(2, bag->entries[1].cookie); EXPECT_EQ(0x03, get_package_id(bag->entries[1].key)); } TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) { AssetManager2 assetmanager; Loading
libs/androidfw/tests/data/lib_two/R.h +9 −3 Original line number Diff line number Diff line Loading @@ -30,16 +30,22 @@ struct R { }; }; struct integer { enum : uint32_t { bar = 0x02020000, // default }; }; struct string { enum : uint32_t { LibraryString = 0x02020000, // default foo = 0x02020001, // default LibraryString = 0x02030000, // default foo = 0x02030001, // default }; }; struct style { enum : uint32_t { Theme = 0x02030000, // default Theme = 0x02040000, // default }; }; }; Loading
libs/androidfw/tests/data/lib_two/lib_two.apk +160 B (1.55 KiB) File changed.No diff preview for this file type. View original file View changed file
libs/androidfw/tests/data/lib_two/res/values/values.xml +7 −4 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ <public type="attr" name="attr3" id="0x00010000" /> <attr name="attr3" format="integer" /> <public type="string" name="LibraryString" id="0x00020000" /> <public type="integer" name="bar" id="0x00020000" /> <integer name="bar">1337</integer> <public type="string" name="LibraryString" id="0x00030000" /> <string name="LibraryString">Hi from library two</string> <public type="string" name="foo" id="0x00020001" /> <public type="string" name="foo" id="0x00030001" /> <string name="foo">Foo from lib_two</string> <public type="style" name="Theme" id="0x02030000" /> <public type="style" name="Theme" id="0x00040000" /> <style name="Theme"> <item name="com.android.lib_two:attr3">800</item> <item name="com.android.lib_two:attr3">@integer/bar</item> </style> </resources>