diff options
| author | 2019-01-15 19:34:30 +0000 | |
|---|---|---|
| committer | 2019-01-15 19:34:30 +0000 | |
| commit | cf9dd94323e0bf4934281582a1851e60f1fa36ac (patch) | |
| tree | 1a7a160c3f03987d1929a6c23717f0ffb78bd040 | |
| parent | edb5e1a1b8e6791f85040a6b602d5c7929260be7 (diff) | |
| parent | ef5673a4c4021ca27b40e48020203928d71c95a8 (diff) | |
Merge "Add encoding of name and actor overlayable fields"
| -rw-r--r-- | libs/androidfw/LoadedArsc.cpp | 15 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/LoadedArsc.h | 2 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 6 | ||||
| -rw-r--r-- | libs/androidfw/tests/LoadedArsc_test.cpp | 8 | ||||
| -rw-r--r-- | libs/androidfw/tests/data/overlayable/overlayable.apk | bin | 1387 -> 5523 bytes | |||
| -rw-r--r-- | libs/androidfw/tests/data/overlayable/res/values/overlayable.xml | 6 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/BinaryResourceParser.cpp | 26 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/TableFlattener.cpp | 170 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/TableFlattener_test.cpp | 110 |
9 files changed, 250 insertions, 93 deletions
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index 5a267804ddf1..70ce9bc705ef 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -593,7 +593,12 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, return {}; } - // Iterate over the overlayable policy chunks + std::string name; + util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name); + std::string actor; + util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &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()) { const Chunk overlayable_child_chunk = overlayable_iter.Next(); @@ -613,7 +618,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, return {}; } - // Retrieve all the ids belonging to this policy + // Retrieve all the resource ids belonging to this policy chunk std::unordered_set<uint32_t> ids; const auto ids_begin = reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr()); @@ -622,8 +627,10 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, ids.insert(dtohl(id_iter->ident)); } - // Add the pairing of overlayable properties to resource ids to the package + // Add the pairing of overlayable properties and resource ids to the package OverlayableInfo overlayable_info{}; + overlayable_info.name = name; + overlayable_info.actor = actor; overlayable_info.policy_flags = policy_header->policy_flags; loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids)); break; @@ -636,7 +643,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, } if (overlayable_iter.HadError()) { - LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s", + LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s", overlayable_iter.GetLastError().c_str()); if (overlayable_iter.HadFatalError()) { return {}; diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 8c5c3b7d3858..be62f30617bf 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -78,6 +78,8 @@ struct TypeSpec { using TypeSpecPtr = util::unique_cptr<TypeSpec>; struct OverlayableInfo { + std::string name; + std::string actor; uint32_t policy_flags; }; diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 9b05d1f64e08..6b9ebd3e8d12 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1611,6 +1611,12 @@ struct ResTable_lib_entry struct ResTable_overlayable_header { struct ResChunk_header header; + + // The name of the overlayable set of resources that overlays target. + uint16_t name[256]; + + // The component responsible for enabling and disabling overlays targeting this chunk. + uint16_t actor[256]; }; /** diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index 22d587a7f5c4..2e386a083185 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -294,22 +294,30 @@ TEST(LoadedArscTest, LoadOverlayable) { info = package->GetOverlayableInfo(overlayable::R::string::overlayable1); ASSERT_THAT(info, NotNull()); + EXPECT_THAT(info->name, Eq("OverlayableResources1")); + EXPECT_THAT(info->actor, Eq("overlay://theme")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable2); ASSERT_THAT(info, NotNull()); + EXPECT_THAT(info->name, Eq("OverlayableResources1")); + EXPECT_THAT(info->actor, Eq("overlay://theme")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable3); ASSERT_THAT(info, NotNull()); + EXPECT_THAT(info->name, Eq("OverlayableResources2")); + EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable4); + EXPECT_THAT(info->name, Eq("OverlayableResources1")); + EXPECT_THAT(info->actor, Eq("overlay://theme")); ASSERT_THAT(info, NotNull()); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC)); } diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk Binary files differindex 85ab4be7a2e5..863474794d00 100644 --- a/libs/androidfw/tests/data/overlayable/overlayable.apk +++ b/libs/androidfw/tests/data/overlayable/overlayable.apk diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml index 11aa7354901d..dba7b08628f1 100644 --- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml +++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml @@ -15,7 +15,7 @@ --> <resources> -<overlayable> +<overlayable name="OverlayableResources1" actor="overlay://theme"> <!-- Any overlay can overlay the value of @string/overlayable1 --> <item type="string" name="overlayable1" /> @@ -31,9 +31,9 @@ </policy> </overlayable> -<overlayable> +<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable"> <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of - @string/overlayable3 --> + @string/overlayable3 --> <policy type="product_services|vendor|product"> <item type="string" name="overlayable3" /> </policy> diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index c496ff0e159b..7d4c6f348403 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -42,6 +42,19 @@ namespace aapt { namespace { +static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) { + size_t utf16_len = strnlen16(src, len); + if (utf16_len == 0) { + return {}; + } + std::u16string dst; + dst.resize(utf16_len); + for (size_t i = 0; i < utf16_len; i++) { + dst[i] = util::DeviceToHost16(src[i]); + } + return dst; +} + // Visitor that converts a reference's resource ID to a resource name, given a mapping from // resource ID to resource name. class ReferenceIdToNameVisitor : public DescendingValueVisitor { @@ -176,12 +189,8 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) { } // Extract the package name. - size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name)); - std::u16string package_name; - package_name.resize(len); - for (size_t i = 0; i < len; i++) { - package_name[i] = util::DeviceToHost16(package_header->name[i]); - } + std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name, + arraysize(package_header->name)); ResourceTablePackage* package = table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id)); @@ -435,6 +444,11 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { } auto overlayable = std::make_shared<Overlayable>(); + overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name, + arraysize(header->name))); + overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor, + arraysize(header->name))); + overlayable->source = source_.WithLine(0); ResChunkPullParser parser(GetChunkData(chunk), GetChunkDataLen(chunk)); diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 931d57b1c08a..c4ecbafc008b 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -217,9 +217,10 @@ class MapFlattenVisitor : public ValueVisitor { size_t entry_count_ = 0; }; -struct PolicyChunk { - uint32_t policy_flags; - std::set<ResourceId> ids; +struct OverlayableChunk { + std::string actor; + Source source; + std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids; }; class PackageFlattener { @@ -421,8 +422,9 @@ class PackageFlattener { return sorted_entries; } - void FlattenOverlayable(BigBuffer* buffer) { - std::vector<PolicyChunk> policies; + bool FlattenOverlayable(BigBuffer* buffer) { + std::set<ResourceId> seen_ids; + std::map<std::string, OverlayableChunk> overlayable_chunks; CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>"; for (auto& type : package_->types) { @@ -433,79 +435,119 @@ class PackageFlattener { continue; } - OverlayableItem& overlayable = entry->overlayable_item.value(); - uint32_t policy_flags = OverlayableItem::Policy::kNone; - if (overlayable.policies & OverlayableItem::Policy::kPublic) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - if (overlayable.policies & OverlayableItem::Policy::kSystem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; - } - if (overlayable.policies & OverlayableItem::Policy::kVendor) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; - } - if (overlayable.policies & OverlayableItem::Policy::kProduct) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; - } - if (overlayable.policies & OverlayableItem::Policy::kProductServices) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION; + OverlayableItem& item = entry->overlayable_item.value(); + + // Resource ids should only appear once in the resource table + ResourceId id = android::make_resid(package_->id.value(), type->id.value(), + entry->id.value()); + CHECK(seen_ids.find(id) == seen_ids.end()) + << "multiple overlayable definitions found for resource " + << ResourceName(package_->name, type->type, entry->name).to_string(); + seen_ids.insert(id); + + // Find the overlayable chunk with the specified name + OverlayableChunk* overlayable_chunk = nullptr; + auto iter = overlayable_chunks.find(item.overlayable->name); + if (iter == overlayable_chunks.end()) { + OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source}; + overlayable_chunk = + &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second; + } else { + OverlayableChunk& chunk = iter->second; + if (!(chunk.source == item.overlayable->source)) { + // The name of an overlayable set of resources must be unique + context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source) + << "duplicate overlayable name" + << item.overlayable->name << "'"); + context_->GetDiagnostics()->Error(DiagMessage(chunk.source) + << "previous declaration here"); + return false; + } + + CHECK(chunk.actor == item.overlayable->actor); + overlayable_chunk = &chunk; } - if (overlayable.policies == OverlayableItem::Policy::kNone) { + uint32_t policy_flags = 0; + if (item.policies == OverlayableItem::Policy::kNone) { // Encode overlayable entries defined without a policy as publicly overlayable policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - - // Find the overlayable policy chunk with the same policies as the entry - PolicyChunk* policy_chunk = nullptr; - for (PolicyChunk& policy : policies) { - if (policy.policy_flags == policy_flags) { - policy_chunk = &policy; - break; + } else { + if (item.policies & OverlayableItem::Policy::kPublic) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; + } + if (item.policies & OverlayableItem::Policy::kSystem) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kVendor) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kProduct) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kProductServices) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION; } } - // Create a new policy chunk if an existing one with the same policy cannot be found - if (policy_chunk == nullptr) { - PolicyChunk p; - p.policy_flags = policy_flags; - policies.push_back(p); - policy_chunk = &policies.back(); + auto policy = overlayable_chunk->policy_ids.find(policy_flags); + if (policy != overlayable_chunk->policy_ids.end()) { + policy->second.insert(id); + } else { + overlayable_chunk->policy_ids.insert( + std::make_pair(policy_flags, std::set<ResourceId>{id})); } - - policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(), - entry->id.value())); } } - if (policies.empty()) { - // Only write the overlayable chunk if the APK has overlayable entries - return; - } - - ChunkWriter writer(buffer); - writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE); - - // Write each policy block for the overlayable - for (PolicyChunk& policy : policies) { - ChunkWriter policy_writer(buffer); - ResTable_overlayable_policy_header* policy_type = - policy_writer.StartChunk<ResTable_overlayable_policy_header>( - RES_TABLE_OVERLAYABLE_POLICY_TYPE); - policy_type->policy_flags = util::HostToDevice32(policy.policy_flags); - policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size())); - - // Write the ids after the policy header - ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size()); - for (const ResourceId& id : policy.ids) { - id_block->ident = util::HostToDevice32(id.id); - id_block++; + for (auto& overlayable_pair : overlayable_chunks) { + std::string name = overlayable_pair.first; + OverlayableChunk& overlayable = overlayable_pair.second; + + // Write the header of the overlayable chunk + ChunkWriter overlayable_writer(buffer); + auto* overlayable_type = + overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE); + if (name.size() >= arraysize(overlayable_type->name)) { + diag_->Error(DiagMessage() << "overlayable name '" << name + << "' exceeds maximum length (" + << arraysize(overlayable_type->name) + << " utf16 characters)"); + return false; } - - policy_writer.Finish(); + strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name), + util::Utf8ToUtf16(name)); + + if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) { + diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor + << "' exceeds maximum length (" + << arraysize(overlayable_type->actor) + << " utf16 characters)"); + return false; + } + strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor), + util::Utf8ToUtf16(overlayable.actor)); + + // Write each policy block for the overlayable + for (auto& policy_ids : overlayable.policy_ids) { + ChunkWriter policy_writer(buffer); + auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>( + RES_TABLE_OVERLAYABLE_POLICY_TYPE); + policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)); + policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>( + policy_ids.second.size())); + // Write the ids after the policy header + auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size()); + for (const ResourceId& id : policy_ids.second) { + id_block->ident = util::HostToDevice32(id.id); + id_block++; + } + policy_writer.Finish(); + } + overlayable_writer.Finish(); } - writer.Finish(); + return true; } bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries, diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index a5fb6fd6d7aa..18fecf60c977 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -657,36 +657,36 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) { TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme"); std::string name_zero = "com.app.test:integer/overlayable_zero_item"; - OverlayableItem overlayable_zero_item(overlayable); - overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem; - overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices; + OverlayableItem overlayable_item_zero(overlayable); + overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices; std::string name_one = "com.app.test:integer/overlayable_one_item"; - OverlayableItem overlayable_one_item(overlayable); - overlayable_one_item.policies |= OverlayableItem::Policy::kPublic; - overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices; + OverlayableItem overlayable_item_one(overlayable); + overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices; std::string name_two = "com.app.test:integer/overlayable_two_item"; - OverlayableItem overlayable_two_item(overlayable); - overlayable_two_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_two_item.policies |= OverlayableItem::Policy::kSystem; - overlayable_two_item.policies |= OverlayableItem::Policy::kVendor; + OverlayableItem overlayable_item_two(overlayable); + overlayable_item_two.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; std::string name_three = "com.app.test:integer/overlayable_three_item"; - OverlayableItem overlayable_three_item(overlayable); + OverlayableItem overlayable_item_three(overlayable); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple(name_zero, ResourceId(0x7f020000)) - .SetOverlayable(name_zero, overlayable_zero_item) + .SetOverlayable(name_zero, overlayable_item_zero) .AddSimple(name_one, ResourceId(0x7f020001)) - .SetOverlayable(name_one, overlayable_one_item) + .SetOverlayable(name_one, overlayable_item_one) .AddSimple(name_two, ResourceId(0x7f020002)) - .SetOverlayable(name_two, overlayable_two_item) + .SetOverlayable(name_two, overlayable_item_two) .AddSimple(name_three, ResourceId(0x7f020003)) - .SetOverlayable(name_three, overlayable_three_item) + .SetOverlayable(name_three, overlayable_item_three) .Build(); ResourceTable output_table; @@ -724,6 +724,84 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(overlayable_item.overlayable->name, "TestName"); + EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme"); + EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); +} + +TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { + auto group = std::make_shared<Overlayable>("TestName", "overlay://theme"); + std::string name_zero = "com.app.test:integer/overlayable_zero"; + OverlayableItem overlayable_item_zero(group); + overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices; + + auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization"); + std::string name_one = "com.app.test:integer/overlayable_one"; + OverlayableItem overlayable_item_one(group_one); + overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices; + + std::string name_two = "com.app.test:integer/overlayable_two"; + OverlayableItem overlayable_item_two(group); + overlayable_item_two.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; + + std::string name_three = "com.app.test:integer/overlayable_three"; + OverlayableItem overlayable_item_three(group_one); + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .SetPackageId("com.app.test", 0x7f) + .AddSimple(name_zero, ResourceId(0x7f020000)) + .SetOverlayable(name_zero, overlayable_item_zero) + .AddSimple(name_one, ResourceId(0x7f020001)) + .SetOverlayable(name_one, overlayable_item_one) + .AddSimple(name_two, ResourceId(0x7f020002)) + .SetOverlayable(name_two, overlayable_item_two) + .AddSimple(name_three, ResourceId(0x7f020003)) + .SetOverlayable(name_three, overlayable_item_three) + .Build(); + ResourceTable output_table; + ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table)); + auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem + | OverlayableItem::Policy::kProduct + | OverlayableItem::Policy::kProductServices); + search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic + | OverlayableItem::Policy::kProductServices); + search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem + | OverlayableItem::Policy::kProduct + | OverlayableItem::Policy::kVendor); + search_result = output_table.FindResource(test::ParseNameOrDie(name_three)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic); } } // namespace aapt |