Add encoding of name and actor overlayable fields
Encode the actor and name attributes of <overlayable> elements in the overlayable chunks. Two chunks cannot have the same name. Bug: 110869880 Bug: 119390855 Test: aapt2_tests and libandroidfw_tests Change-Id: I0ed95efef640b3927046b6155d1840f0d96030dd
This commit is contained in:
@@ -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 {};
|
||||
|
||||
@@ -78,6 +78,8 @@ struct TypeSpec {
|
||||
using TypeSpecPtr = util::unique_cptr<TypeSpec>;
|
||||
|
||||
struct OverlayableInfo {
|
||||
std::string name;
|
||||
std::string actor;
|
||||
uint32_t policy_flags;
|
||||
};
|
||||
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
for (auto& overlayable_pair : overlayable_chunks) {
|
||||
std::string name = overlayable_pair.first;
|
||||
OverlayableChunk& overlayable = overlayable_pair.second;
|
||||
|
||||
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++;
|
||||
// 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;
|
||||
}
|
||||
strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
|
||||
util::Utf8ToUtf16(name));
|
||||
|
||||
policy_writer.Finish();
|
||||
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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user