Reorder style items in shared libraries

AssetManager2.cpp expects style attribute IDs to be in sorted order when
applying a style (see AssetManager2::GetBag). Shared libraries have a
package ID of 0x00, which will mean any attribute defined in a shared
library will be put before all other attributes. Once the attribute ID
is looked up in the dynamic ref table, the package ID is no longer 0x00,
which means this ID is no longer in sorted order. This messes up the
logic in AssetManager2::GetBag, and results in some style attributes
getting dropped from shared libraries.

This change modifies how aapt2 sorts the style entries, sorting entries
with dynamic IDs after entries with the android framework ID. This means
the entries will still be in sorted order when the IDs are looked up.

Bug: 147674078
Test: TableFlattenerTest.FlattenSharedLibraryWithStyle
Change-Id: Ic4f4004b6d9cecde9325dcdb37f71138857f8236
This commit is contained in:
Clark DuVall
2020-01-16 11:28:13 -08:00
parent 2bb9f65c87
commit 18b15bb3a6
2 changed files with 54 additions and 1 deletions

View File

@@ -59,10 +59,22 @@ static void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) {
dst[i] = 0;
}
static bool cmp_style_ids(ResourceId a, ResourceId b) {
// If one of a and b is from the framework package (package ID 0x01), and the
// other is a dynamic ID (package ID 0x00), then put the dynamic ID after the
// framework ID. This ensures that when AssetManager resolves the dynamic IDs,
// they will be in sorted order as expected by AssetManager.
if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) ||
(a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) {
return b < a;
}
return a < b;
}
static bool cmp_style_entries(const Style::Entry& a, const Style::Entry& b) {
if (a.key.id) {
if (b.key.id) {
return a.key.id.value() < b.key.id.value();
return cmp_style_ids(a.key.id.value(), b.key.id.value());
}
return true;
} else if (!b.key.id) {

View File

@@ -431,6 +431,47 @@ TEST_F(TableFlattenerTest, FlattenSharedLibrary) {
EXPECT_EQ("lib", iter->second);
}
TEST_F(TableFlattenerTest, FlattenSharedLibraryWithStyle) {
std::unique_ptr<IAaptContext> context =
test::ContextBuilder().SetCompilationPackage("lib").SetPackageId(0x00).Build();
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("lib", 0x00)
.AddValue("lib:style/Theme",
ResourceId(0x00030001),
test::StyleBuilder()
.AddItem("lib:attr/bar", ResourceId(0x00010002),
ResourceUtils::TryParseInt("2"))
.AddItem("lib:attr/foo", ResourceId(0x00010001),
ResourceUtils::TryParseInt("1"))
.AddItem("android:attr/bar", ResourceId(0x01010002),
ResourceUtils::TryParseInt("4"))
.AddItem("android:attr/foo", ResourceId(0x01010001),
ResourceUtils::TryParseInt("3"))
.Build())
.Build();
ResourceTable result;
ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
Maybe<ResourceTable::SearchResult> search_result =
result.FindResource(test::ParseNameOrDie("lib:style/Theme"));
ASSERT_TRUE(search_result);
EXPECT_EQ(0x00u, search_result.value().package->id.value());
EXPECT_EQ(0x03u, search_result.value().type->id.value());
EXPECT_EQ(0x01u, search_result.value().entry->id.value());
ASSERT_EQ(1u, search_result.value().entry->values.size());
Value* value = search_result.value().entry->values[0]->value.get();
Style* style = ValueCast<Style>(value);
ASSERT_TRUE(style);
ASSERT_EQ(4u, style->entries.size());
// Ensure the attributes from the shared library come after the items from
// android.
EXPECT_EQ(0x01010001, style->entries[0].key.id.value());
EXPECT_EQ(0x01010002, style->entries[1].key.id.value());
EXPECT_EQ(0x00010001, style->entries[2].key.id.value());
EXPECT_EQ(0x00010002, style->entries[3].key.id.value());
}
TEST_F(TableFlattenerTest, FlattenTableReferencingSharedLibraries) {
std::unique_ptr<IAaptContext> context =
test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x7f).Build();