Merge "Add actor and name parsing for overlayable"

This commit is contained in:
Ryan Mitchell
2018-12-19 17:31:50 +00:00
committed by Android (Google) Code Review
19 changed files with 570 additions and 329 deletions

View File

@@ -623,7 +623,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
}
// Add the pairing of overlayable properties to resource ids to the package
OverlayableInfo overlayable_info;
OverlayableInfo overlayable_info{};
overlayable_info.policy_flags = policy_header->policy_flags;
loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
break;

View File

@@ -99,7 +99,7 @@ struct ParsedResource {
ResourceId id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
bool allow_new = false;
Maybe<Overlayable> overlayable;
Maybe<OverlayableItem> overlayable_item;
std::string comment;
std::unique_ptr<Value> value;
@@ -133,8 +133,8 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
}
}
if (res->overlayable) {
if (!table->SetOverlayable(res->name, res->overlayable.value(), diag)) {
if (res->overlayable_item) {
if (!table->SetOverlayable(res->name, res->overlayable_item.value(), diag)) {
return false;
}
}
@@ -1059,92 +1059,119 @@ bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out
bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
diag_->Warn(DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config
<< "' for <overlayable> tag");
<< "ignoring configuration '" << out_resource->config
<< "' for <overlayable> tag");
}
Maybe<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name");
if (!overlayable_name) {
diag_->Error(DiagMessage(out_resource->source)
<< "<overlayable> tag must have a 'name' attribute");
return false;
}
const std::string kActorUriScheme =
android::base::StringPrintf("%s://", Overlayable::kActorScheme);
Maybe<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor");
if (overlayable_actor && !util::StartsWith(overlayable_actor.value(), kActorUriScheme)) {
diag_->Error(DiagMessage(out_resource->source)
<< "specified <overlayable> tag 'actor' attribute must use the scheme '"
<< Overlayable::kActorScheme << "'");
return false;
}
// Create a overlayable entry grouping that represents this <overlayable>
auto overlayable = std::make_shared<Overlayable>(
overlayable_name.value(), (overlayable_actor) ? overlayable_actor.value() : "",
out_resource->source);
bool error = false;
std::string comment;
Overlayable::PolicyFlags current_policies = Overlayable::Policy::kNone;
OverlayableItem::PolicyFlags current_policies = OverlayableItem::Policy::kNone;
const size_t start_depth = parser->depth();
while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
xml::XmlPullParser::Event event = parser->event();
if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth) {
// Break the loop when exiting the overlayable element
// Break the loop when exiting the <overlayable>
break;
} else if (event == xml::XmlPullParser::Event::kEndElement
&& parser->depth() == start_depth + 1) {
// Clear the current policies when exiting the policy element
current_policies = Overlayable::Policy::kNone;
// Clear the current policies when exiting the <policy> tags
current_policies = OverlayableItem::Policy::kNone;
continue;
} else if (event == xml::XmlPullParser::Event::kComment) {
// Get the comment of individual item elements
// Retrieve the comment of individual <item> tags
comment = parser->comment();
continue;
} else if (event != xml::XmlPullParser::Event::kStartElement) {
// Skip to the next element
// Skip to the start of the next element
continue;
}
const Source item_source = source_.WithLine(parser->line_number());
const Source element_source = source_.WithLine(parser->line_number());
const std::string& element_name = parser->element_name();
const std::string& element_namespace = parser->element_namespace();
if (element_namespace.empty() && element_name == "item") {
// Items specify the name and type of resource that should be overlayable
Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
diag_->Error(DiagMessage(item_source)
<< "<item> within an <overlayable> tag must have a 'name' attribute");
Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
if (!item_name) {
diag_->Error(DiagMessage(element_source)
<< "<item> within an <overlayable> must have a 'name' attribute");
error = true;
continue;
}
Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
diag_->Error(DiagMessage(item_source)
<< "<item> within an <overlayable> tag must have a 'type' attribute");
Maybe<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type");
if (!item_type) {
diag_->Error(DiagMessage(element_source)
<< "<item> within an <overlayable> must have a 'type' attribute");
error = true;
continue;
}
const ResourceType* type = ParseResourceType(maybe_type.value());
const ResourceType* type = ParseResourceType(item_type.value());
if (type == nullptr) {
diag_->Error(DiagMessage(item_source)
<< "invalid resource type '" << maybe_type.value()
diag_->Error(DiagMessage(element_source)
<< "invalid resource type '" << item_type.value()
<< "' in <item> within an <overlayable>");
error = true;
continue;
}
ParsedResource child_resource;
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies = current_policies;
overlayable_item.comment = comment;
overlayable_item.source = element_source;
ParsedResource child_resource{};
child_resource.name.type = *type;
child_resource.name.entry = maybe_name.value().to_string();
child_resource.overlayable = Overlayable{current_policies, item_source, comment};
child_resource.name.entry = item_name.value().to_string();
child_resource.overlayable_item = overlayable_item;
out_resource->child_resources.push_back(std::move(child_resource));
} else if (element_namespace.empty() && element_name == "policy") {
if (current_policies != Overlayable::Policy::kNone) {
if (current_policies != OverlayableItem::Policy::kNone) {
// If the policy list is not empty, then we are currently inside a policy element
diag_->Error(DiagMessage(item_source) << "<policy> blocks cannot be recursively nested");
diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested");
error = true;
break;
} else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
// Parse the polices separated by vertical bar characters to allow for specifying multiple
// policies
// policies. Items within the policy tag will have the specified policy.
for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
StringPiece trimmed_part = util::TrimWhitespace(part);
if (trimmed_part == "public") {
current_policies |= Overlayable::Policy::kPublic;
current_policies |= OverlayableItem::Policy::kPublic;
} else if (trimmed_part == "product") {
current_policies |= Overlayable::Policy::kProduct;
current_policies |= OverlayableItem::Policy::kProduct;
} else if (trimmed_part == "product_services") {
current_policies |= Overlayable::Policy::kProductServices;
current_policies |= OverlayableItem::Policy::kProductServices;
} else if (trimmed_part == "system") {
current_policies |= Overlayable::Policy::kSystem;
current_policies |= OverlayableItem::Policy::kSystem;
} else if (trimmed_part == "vendor") {
current_policies |= Overlayable::Policy::kVendor;
current_policies |= OverlayableItem::Policy::kVendor;
} else {
diag_->Error(DiagMessage(item_source)
diag_->Error(DiagMessage(element_source)
<< "<policy> has unsupported type '" << trimmed_part << "'");
error = true;
continue;
@@ -1152,11 +1179,13 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
}
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
diag_->Error(DiagMessage(item_source) << "invalid element <" << element_name << "> "
diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
<< " in <overlayable>");
error = true;
break;
}
comment.clear();
}
return !error;

View File

@@ -892,11 +892,8 @@ TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
}
TEST_F(ResourceParserTest, ParseOverlayable) {
std::string input = R"(<overlayable />)";
EXPECT_TRUE(TestParse(input));
input = R"(
<overlayable>
std::string input = R"(
<overlayable name="Name" actor="overlay://theme">
<item type="string" name="foo" />
<item type="drawable" name="bar" />
</overlayable>)";
@@ -905,24 +902,35 @@ TEST_F(ResourceParserTest, ParseOverlayable) {
auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
EXPECT_THAT(search_result.value().entry->overlayable.value().policies,
Eq(Overlayable::Policy::kNone));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
EXPECT_THAT(search_result.value().entry->overlayable.value().policies,
Eq(Overlayable::Policy::kNone));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
}
TEST_F(ResourceParserTest, ParseOverlayableRequiresName) {
EXPECT_FALSE(TestParse(R"(<overlayable actor="overlay://theme" />)"));
EXPECT_TRUE(TestParse(R"(<overlayable name="Name" />)"));
EXPECT_TRUE(TestParse(R"(<overlayable name="Name" actor="overlay://theme" />)"));
}
TEST_F(ResourceParserTest, ParseOverlayableBadActorFail) {
EXPECT_FALSE(TestParse(R"(<overlayable name="Name" actor="overley://theme" />)"));
}
TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
std::string input = R"(<overlayable />)";
EXPECT_TRUE(TestParse(input));
input = R"(
<overlayable>
std::string input = R"(
<overlayable name="Name">
<item type="string" name="foo" />
<policy type="product">
<item type="string" name="bar" />
@@ -945,49 +953,55 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
Overlayable& overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kNone));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kProduct));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kProductServices));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices));
search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kSystem));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem));
search_result = table_.FindResource(test::ParseNameOrDie("string/fuz"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kVendor));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor));
search_result = table_.FindResource(test::ParseNameOrDie("string/faz"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kPublic));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
}
TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
std::string input = R"(
<overlayable>
<overlayable name="Name">
<policy type="illegal_policy">
<item type="string" name="foo" />
</policy>
@@ -995,7 +1009,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<policy type="product">
<item name="foo" />
</policy>
@@ -1003,7 +1017,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<policy type="vendor">
<item type="string" />
</policy>
@@ -1013,7 +1027,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
std::string input = R"(
<overlayable>
<overlayable name="Name">
<policy type="vendor|product_services">
<item type="string" name="foo" />
</policy>
@@ -1026,39 +1040,59 @@ TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
Overlayable& overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kVendor
| Overlayable::Policy::kProductServices));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor
| OverlayableItem::Policy::kProductServices));
search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kProduct
| Overlayable::Policy::kSystem));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
| OverlayableItem::Policy::kSystem));
}
TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
std::string input = R"(
<overlayable>
<overlayable name="Name">
<item type="string" name="foo" />
<item type="string" name="foo" />
</overlayable>)";
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<item type="string" name="foo" />
</overlayable>
<overlayable>
<overlayable name="Name">
<item type="string" name="foo" />
</overlayable>)";
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<item type="string" name="foo" />
</overlayable>
<overlayable name="Other">
<item type="string" name="foo" />
</overlayable>)";
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable name="Name" actor="overlay://my.actor.one">
<item type="string" name="foo" />
</overlayable>
<overlayable name="Other" actor="overlay://my.actor.two">
<item type="string" name="foo" />
</overlayable>)";
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable name="Name">
<policy type="product">
<item type="string" name="foo" />
<item type="string" name="foo" />
@@ -1067,7 +1101,7 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<policy type="product">
<item type="string" name="foo" />
</policy>
@@ -1076,7 +1110,7 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<policy type="product">
<item type="string" name="foo" />
</policy>
@@ -1087,13 +1121,13 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
EXPECT_FALSE(TestParse(input));
input = R"(
<overlayable>
<overlayable name="Name">
<policy type="product">
<item type="string" name="foo" />
</policy>
</overlayable>
<overlayable>
<overlayable name="Name">
<policy type="product">
<item type="string" name="foo" />
</policy>
@@ -1103,7 +1137,7 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
TEST_F(ResourceParserTest, NestPolicyInOverlayableError) {
std::string input = R"(
<overlayable>
<overlayable name="Name">
<policy type="vendor|product">
<policy type="product_services">
<item type="string" name="foo" />

View File

@@ -40,6 +40,8 @@ using ::android::base::StringPrintf;
namespace aapt {
const char* Overlayable::kActorScheme = "overlay";
static bool less_than_type_and_id(const std::unique_ptr<ResourceTableType>& lhs,
const std::pair<ResourceType, Maybe<uint8_t>>& rhs) {
return lhs->type < rhs.first || (lhs->type == rhs.first && rhs.second && lhs->id < rhs.second);
@@ -625,17 +627,18 @@ bool ResourceTable::SetAllowNewImpl(const ResourceNameRef& name, const AllowNew&
return true;
}
bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable,
IDiagnostics* diag) {
return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
}
bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
const Overlayable& overlayable, IDiagnostics* diag) {
const OverlayableItem& overlayable, IDiagnostics* diag) {
return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
}
bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name,
const OverlayableItem& overlayable,
NameValidator name_validator, IDiagnostics *diag) {
CHECK(diag != nullptr);
@@ -647,14 +650,15 @@ bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overla
ResourceTableType* type = package->FindOrCreateType(name.type);
ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
if (entry->overlayable) {
if (entry->overlayable_item) {
diag->Error(DiagMessage(overlayable.source)
<< "duplicate overlayable declaration for resource '" << name << "'");
diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here");
<< "duplicate overlayable declaration for resource '" << name << "'");
diag->Error(DiagMessage(entry->overlayable_item.value().source)
<< "previous declaration here");
return false;
}
entry->overlayable = overlayable;
entry->overlayable_item = overlayable;
return true;
}
@@ -690,7 +694,7 @@ std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
new_entry->id = entry->id;
new_entry->visibility = entry->visibility;
new_entry->allow_new = entry->allow_new;
new_entry->overlayable = entry->overlayable;
new_entry->overlayable_item = entry->overlayable_item;
for (const auto& config_value : entry->values) {
ResourceConfigValue* new_value =

View File

@@ -57,10 +57,27 @@ struct AllowNew {
std::string comment;
};
// Represents a declaration that a resource is overlayable at runtime.
struct Overlayable {
Overlayable() = default;
Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
: name(name.to_string()), actor(actor.to_string()) {}
Overlayable(const android::StringPiece& name, const android::StringPiece& actor,
const Source& source)
: name(name.to_string()), actor(actor.to_string()), source(source ){}
static const char* kActorScheme;
std::string name;
std::string actor;
Source source;
};
// Represents a declaration that a resource is overlayable at runtime.
struct OverlayableItem {
explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable)
: overlayable(overlayable) {}
// Represents the types overlays that are allowed to overlay the resource.
typedef uint32_t PolicyFlags;
enum Policy : uint32_t {
kNone = 0x00,
@@ -80,11 +97,10 @@ struct Overlayable {
kProductServices = 0x10
};
typedef uint32_t PolicyFlags;
std::shared_ptr<Overlayable> overlayable;
PolicyFlags policies = Policy::kNone;
Source source;
std::string comment;
Source source;
};
class ResourceConfigValue {
@@ -121,7 +137,7 @@ class ResourceEntry {
Maybe<AllowNew> allow_new;
// The declarations of this resource as overlayable for RROs
Maybe<Overlayable> overlayable;
Maybe<OverlayableItem> overlayable_item;
// The resource's values for each configuration.
std::vector<std::unique_ptr<ResourceConfigValue>> values;
@@ -251,9 +267,9 @@ class ResourceTable {
bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
const ResourceId& res_id, IDiagnostics* diag);
bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
bool SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable,
IDiagnostics *diag);
bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
bool SetOverlayableMangled(const ResourceNameRef& name, const OverlayableItem& overlayable,
IDiagnostics* diag);
bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
@@ -328,7 +344,7 @@ class ResourceTable {
bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
NameValidator name_validator, IDiagnostics* diag);
bool SetOverlayableImpl(const ResourceNameRef &name, const Overlayable &overlayable,
bool SetOverlayableImpl(const ResourceNameRef &name, const OverlayableItem& overlayable,
NameValidator name_validator, IDiagnostics *diag);
bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,

View File

@@ -244,48 +244,90 @@ TEST(ResourceTableTest, SetAllowNew) {
TEST(ResourceTableTest, SetOverlayable) {
ResourceTable table;
Overlayable overlayable{};
overlayable.policies |= Overlayable::Policy::kProduct;
overlayable.policies |= Overlayable::Policy::kProductServices;
overlayable.comment = "comment";
auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme",
Source("res/values/overlayable.xml", 40));
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
overlayable_item.comment = "comment";
overlayable_item.source = Source("res/values/overlayable.xml", 42);
const ResourceName name = test::ParseNameOrDie("android:string/foo");
ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
ASSERT_TRUE(table.SetOverlayable(name, overlayable_item, test::GetDiagnostics()));
Maybe<ResourceTable::SearchResult> search_result = table.FindResource(name);
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
ASSERT_TRUE(search_result.value().entry->overlayable_item);
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
ASSERT_THAT(result_overlayable.comment, StrEq("comment"));
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProduct
| Overlayable::Policy::kProductServices));
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40);
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
| OverlayableItem::Policy::kProductServices));
ASSERT_THAT(result_overlayable_item.comment, StrEq("comment"));
EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
EXPECT_THAT(result_overlayable_item.source.line, 42);
}
TEST(ResourceTableTest, AddDuplicateOverlayableSamePolicyFail) {
TEST(ResourceTableTest, SetMultipleOverlayableResources) {
ResourceTable table;
const ResourceName foo = test::ParseNameOrDie("android:string/foo");
auto group = std::make_shared<Overlayable>("Name", "overlay://theme");
OverlayableItem overlayable(group);
overlayable.policies = OverlayableItem::Policy::kProduct;
ASSERT_TRUE(table.SetOverlayable(foo, overlayable, test::GetDiagnostics()));
const ResourceName bar = test::ParseNameOrDie("android:string/bar");
OverlayableItem overlayable2(group);
overlayable2.policies = OverlayableItem::Policy::kProduct;
ASSERT_TRUE(table.SetOverlayable(bar, overlayable2, test::GetDiagnostics()));
const ResourceName baz = test::ParseNameOrDie("android:string/baz");
OverlayableItem overlayable3(group);
overlayable3.policies = OverlayableItem::Policy::kVendor;
ASSERT_TRUE(table.SetOverlayable(baz, overlayable3, test::GetDiagnostics()));
}
TEST(ResourceTableTest, SetOverlayableDifferentResourcesDifferentName) {
ResourceTable table;
const ResourceName foo = test::ParseNameOrDie("android:string/foo");
OverlayableItem overlayable_item(std::make_shared<Overlayable>("Name", "overlay://theme"));
overlayable_item.policies = OverlayableItem::Policy::kProduct;
ASSERT_TRUE(table.SetOverlayable(foo, overlayable_item, test::GetDiagnostics()));
const ResourceName bar = test::ParseNameOrDie("android:string/bar");
OverlayableItem overlayable_item2(std::make_shared<Overlayable>("Name2", "overlay://theme"));
overlayable_item2.policies = OverlayableItem::Policy::kProduct;
ASSERT_TRUE(table.SetOverlayable(bar, overlayable_item2, test::GetDiagnostics()));
}
TEST(ResourceTableTest, SetOverlayableSameResourcesFail) {
ResourceTable table;
const ResourceName name = test::ParseNameOrDie("android:string/foo");
Overlayable overlayable{};
overlayable.policies = Overlayable::Policy::kProduct;
ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme");
OverlayableItem overlayable_item(overlayable);
ASSERT_TRUE(table.SetOverlayable(name, overlayable_item, test::GetDiagnostics()));
Overlayable overlayable2{};
overlayable2.policies = Overlayable::Policy::kProduct;
ASSERT_FALSE(table.SetOverlayable(name, overlayable2, test::GetDiagnostics()));
OverlayableItem overlayable_item2(overlayable);
ASSERT_FALSE(table.SetOverlayable(name, overlayable_item2, test::GetDiagnostics()));
}
TEST(ResourceTableTest, AddDuplicateOverlayableDifferentPolicyFail) {
TEST(ResourceTableTest, SetOverlayableSameResourcesDifferentNameFail) {
ResourceTable table;
const ResourceName name = test::ParseNameOrDie("android:string/foo");
Overlayable overlayable{};
overlayable.policies = Overlayable::Policy::kProduct;
ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme");
OverlayableItem overlayable_item(overlayable);
ASSERT_TRUE(table.SetOverlayable(name, overlayable_item, test::GetDiagnostics()));
Overlayable overlayable2{};
overlayable2.policies = Overlayable::Policy::kVendor;
ASSERT_FALSE(table.SetOverlayable(name, overlayable2, test::GetDiagnostics()));
auto overlayable2 = std::make_shared<Overlayable>("Other", "overlay://theme");
OverlayableItem overlayable_item2(overlayable2);
ASSERT_FALSE(table.SetOverlayable(name, overlayable_item2, test::GetDiagnostics()));
}
TEST(ResourceTableTest, AllowDuplictaeResourcesNames) {

View File

@@ -49,6 +49,9 @@ message ResourceTable {
// Resource definitions corresponding to an Android package.
repeated Package package = 2;
// The <overlayable> declarations within the resource table.
repeated Overlayable overlayable = 3;
}
// A package ID in the range [0x00, 0xff].
@@ -133,8 +136,20 @@ message AllowNew {
string comment = 2;
}
// Represents a declaration that a resource is overayable at runtime.
// Represents a set of overlayable resources.
message Overlayable {
// The name of the <overlyabale>.
string name = 1;
// The location of the <overlyabale> declaration in the source.
Source source = 2;
// The component responsible for enabling and disabling overlays targeting this <overlayable>.
string actor = 3;
}
// Represents an overlayable <item> declaration within an <overlayable> tag.
message OverlayableItem {
enum Policy {
PUBLIC = 0;
SYSTEM = 1;
@@ -143,14 +158,18 @@ message Overlayable {
PRODUCT_SERVICES = 4;
}
// Where this declaration was defined in source.
// The location of the <item> declaration in source.
Source source = 1;
// Any comment associated with the declaration.
string comment = 2;
// The policy defined in the overlayable declaration.
// The policy defined by the enclosing <policy> tag of this <item>.
repeated Policy policy = 3;
// The index into overlayable list that points to the <overlayable> tag that contains
// this <item>.
uint32 overlayable_idx = 4;
}
// An entry ID in the range [0x0000, 0xffff].
@@ -180,7 +199,7 @@ message Entry {
AllowNew allow_new = 4;
// Whether this resource can be overlaid by a runtime resource overlay (RRO).
Overlayable overlayable = 5;
OverlayableItem overlayable_item = 5;
// The set of values defined for this entry, each corresponding to a different
// configuration/variant.

View File

@@ -434,6 +434,8 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
return false;
}
auto overlayable = std::make_shared<Overlayable>();
ResChunkPullParser parser(GetChunkData(chunk),
GetChunkDataLen(chunk));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
@@ -441,25 +443,25 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
const ResTable_overlayable_policy_header* policy_header =
ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
Overlayable::PolicyFlags policies = Overlayable::Policy::kNone;
OverlayableItem::PolicyFlags policies = OverlayableItem::Policy::kNone;
if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) {
policies |= Overlayable::Policy::kPublic;
policies |= OverlayableItem::Policy::kPublic;
}
if (policy_header->policy_flags
& ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) {
policies |= Overlayable::Policy::kSystem;
policies |= OverlayableItem::Policy::kSystem;
}
if (policy_header->policy_flags
& ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) {
policies |= Overlayable::Policy::kVendor;
policies |= OverlayableItem::Policy::kVendor;
}
if (policy_header->policy_flags
& ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
policies |= Overlayable::Policy::kProduct;
policies |= OverlayableItem::Policy::kProduct;
}
if (policy_header->policy_flags
& ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) {
policies |= Overlayable::Policy::kProductServices;
policies |= OverlayableItem::Policy::kProductServices;
}
const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
@@ -478,10 +480,10 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
return false;
}
Overlayable overlayable{};
overlayable.source = source_.WithLine(0);
overlayable.policies = policies;
if (!table_->SetOverlayable(iter->second, overlayable, diag_)) {
OverlayableItem overlayable_item(overlayable);
overlayable_item.source = source_.WithLine(0);
overlayable_item.policies = policies;
if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) {
return false;
}
}

View File

@@ -429,29 +429,29 @@ class PackageFlattener {
CHECK(bool(type->id)) << "type must have an ID set when flattening <overlayable>";
for (auto& entry : type->entries) {
CHECK(bool(type->id)) << "entry must have an ID set when flattening <overlayable>";
if (!entry->overlayable) {
if (!entry->overlayable_item) {
continue;
}
Overlayable overlayable = entry->overlayable.value();
uint32_t policy_flags = Overlayable::Policy::kNone;
if (overlayable.policies & Overlayable::Policy::kPublic) {
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 & Overlayable::Policy::kSystem) {
if (overlayable.policies & OverlayableItem::Policy::kSystem) {
policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
}
if (overlayable.policies & Overlayable::Policy::kVendor) {
if (overlayable.policies & OverlayableItem::Policy::kVendor) {
policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
}
if (overlayable.policies & Overlayable::Policy::kProduct) {
if (overlayable.policies & OverlayableItem::Policy::kProduct) {
policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
}
if (overlayable.policies & Overlayable::Policy::kProductServices) {
if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
}
if (overlayable.policies == Overlayable::Policy::kNone) {
if (overlayable.policies == OverlayableItem::Policy::kNone) {
// Encode overlayable entries defined without a policy as publicly overlayable
policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
}

View File

@@ -628,17 +628,17 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) {
}
TEST_F(TableFlattenerTest, FlattenOverlayable) {
Overlayable overlayable{};
overlayable.policies |= Overlayable::Policy::kProduct;
overlayable.policies |= Overlayable::Policy::kSystem;
overlayable.policies |= Overlayable::Policy::kVendor;
OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
overlayable_item.policies |= OverlayableItem::Policy::kSystem;
overlayable_item.policies |= OverlayableItem::Policy::kVendor;
std::string name = "com.app.test:integer/overlayable";
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
.AddSimple(name, ResourceId(0x7f020000))
.SetOverlayable(name, overlayable)
.SetOverlayable(name, overlayable_item)
.Build();
ResourceTable output_table;
@@ -647,45 +647,46 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) {
auto search_result = output_table.FindResource(test::ParseNameOrDie(name));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kSystem
| Overlayable::Policy::kVendor
| Overlayable::Policy::kProduct);
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(result_overlayable_item.policies, OverlayableItem::Policy::kSystem
| OverlayableItem::Policy::kVendor
| OverlayableItem::Policy::kProduct);
}
TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
std::string name_zero = "com.app.test:integer/overlayable_zero";
Overlayable overlayable_zero{};
overlayable_zero.policies |= Overlayable::Policy::kProduct;
overlayable_zero.policies |= Overlayable::Policy::kSystem;
overlayable_zero.policies |= Overlayable::Policy::kProductServices;
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;
std::string name_one = "com.app.test:integer/overlayable_one";
Overlayable overlayable_one{};
overlayable_one.policies |= Overlayable::Policy::kPublic;
overlayable_one.policies |= Overlayable::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;
std::string name_two = "com.app.test:integer/overlayable_two";
Overlayable overlayable_two{};
overlayable_two.policies |= Overlayable::Policy::kProduct;
overlayable_two.policies |= Overlayable::Policy::kSystem;
overlayable_two.policies |= Overlayable::Policy::kVendor;
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;
std::string name_three = "com.app.test:integer/overlayable_three";
Overlayable overlayable_three{};
std::string name_three = "com.app.test:integer/overlayable_three_item";
OverlayableItem overlayable_three_item(overlayable);
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
.AddSimple(name_zero, ResourceId(0x7f020000))
.SetOverlayable(name_zero, overlayable_zero)
.SetOverlayable(name_zero, overlayable_zero_item)
.AddSimple(name_one, ResourceId(0x7f020001))
.SetOverlayable(name_one, overlayable_one)
.SetOverlayable(name_one, overlayable_one_item)
.AddSimple(name_two, ResourceId(0x7f020002))
.SetOverlayable(name_two, overlayable_two)
.SetOverlayable(name_two, overlayable_two_item)
.AddSimple(name_three, ResourceId(0x7f020003))
.SetOverlayable(name_three, overlayable_three)
.SetOverlayable(name_three, overlayable_three_item)
.Build();
ResourceTable output_table;
@@ -694,35 +695,35 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
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);
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kSystem
| Overlayable::Policy::kProduct
| Overlayable::Policy::kProductServices);
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(overlayable_item.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);
result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kPublic
| Overlayable::Policy::kProductServices);
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
| 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);
result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kSystem
| Overlayable::Policy::kProduct
| Overlayable::Policy::kVendor);
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(overlayable_item.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);
result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kPublic);
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);
}
} // namespace aapt

View File

@@ -373,9 +373,44 @@ static Visibility::Level DeserializeVisibilityFromPb(const pb::Visibility::Level
return Visibility::Level::kUndefined;
}
bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable,
const android::ResStringPool& src_pool,
OverlayableItem* out_overlayable, std::string* out_error) {
for (const int policy : pb_overlayable.policy()) {
switch (policy) {
case pb::OverlayableItem::PUBLIC:
out_overlayable->policies |= OverlayableItem::Policy::kPublic;
break;
case pb::OverlayableItem::SYSTEM:
out_overlayable->policies |= OverlayableItem::Policy::kSystem;
break;
case pb::OverlayableItem::VENDOR:
out_overlayable->policies |= OverlayableItem::Policy::kVendor;
break;
case pb::OverlayableItem::PRODUCT:
out_overlayable->policies |= OverlayableItem::Policy::kProduct;
break;
case pb::OverlayableItem::PRODUCT_SERVICES:
out_overlayable->policies |= OverlayableItem::Policy::kProductServices;
break;
default:
*out_error = "unknown overlayable policy";
return false;
}
}
if (pb_overlayable.has_source()) {
DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &out_overlayable->source);
}
out_overlayable->comment = pb_overlayable.comment();
return true;
}
static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
io::IFileCollection* files, ResourceTable* out_table,
std::string* out_error) {
io::IFileCollection* files,
const std::vector<std::shared_ptr<Overlayable>>& overlayables,
ResourceTable* out_table, std::string* out_error) {
Maybe<uint8_t> id;
if (pb_package.has_package_id()) {
id = static_cast<uint8_t>(pb_package.package_id().id());
@@ -437,39 +472,22 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
entry->allow_new = std::move(allow_new);
}
if (pb_entry.has_overlayable()) {
Overlayable overlayable{};
const pb::Overlayable& pb_overlayable = pb_entry.overlayable();
for (const int policy : pb_overlayable.policy()) {
switch (policy) {
case pb::Overlayable::PUBLIC:
overlayable.policies |= Overlayable::Policy::kPublic;
break;
case pb::Overlayable::SYSTEM:
overlayable.policies |= Overlayable::Policy::kSystem;
break;
case pb::Overlayable::VENDOR:
overlayable.policies |= Overlayable::Policy::kVendor;
break;
case pb::Overlayable::PRODUCT:
overlayable.policies |= Overlayable::Policy::kProduct;
break;
case pb::Overlayable::PRODUCT_SERVICES:
overlayable.policies |= Overlayable::Policy::kProductServices;
break;
default:
*out_error = "unknown overlayable policy";
return false;
}
if (pb_entry.has_overlayable_item()) {
// Find the overlayable to which this item belongs
pb::OverlayableItem pb_overlayable_item = pb_entry.overlayable_item();
if (pb_overlayable_item.overlayable_idx() >= overlayables.size()) {
*out_error = android::base::StringPrintf("invalid overlayable_idx value %d",
pb_overlayable_item.overlayable_idx());
return false;
}
if (pb_overlayable.has_source()) {
DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &overlayable.source);
OverlayableItem overlayable_item(overlayables[pb_overlayable_item.overlayable_idx()]);
if (!DeserializeOverlayableItemFromPb(pb_overlayable_item, src_pool, &overlayable_item,
out_error)) {
return false;
}
overlayable.comment = pb_overlayable.comment();
entry->overlayable = overlayable;
entry->overlayable_item = std::move(overlayable_item);
}
ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
@@ -522,8 +540,19 @@ bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollecti
}
}
// Deserialize the overlayable groups of the table
std::vector<std::shared_ptr<Overlayable>> overlayables;
for (const pb::Overlayable& pb_overlayable : pb_table.overlayable()) {
auto group = std::make_shared<Overlayable>(pb_overlayable.name(), pb_overlayable.actor());
if (pb_overlayable.has_source()) {
DeserializeSourceFromPb(pb_overlayable.source(), source_pool, &group->source);
}
overlayables.push_back(group);
}
for (const pb::Package& pb_package : pb_table.package()) {
if (!DeserializePackageFromPb(pb_package, source_pool, files, out_table, out_error)) {
if (!DeserializePackageFromPb(pb_package, source_pool, files, overlayables, out_table,
out_error)) {
return false;
}
}

View File

@@ -272,9 +272,57 @@ void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_
out_pb_config->set_sdk_version(config.sdkVersion);
}
static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item,
std::vector<Overlayable*>& serialized_overlayables,
StringPool* source_pool, pb::Entry* pb_entry,
pb::ResourceTable* pb_table) {
// Retrieve the index of the overlayable in the list of groups that have already been serialized.
size_t i;
for (i = 0 ; i < serialized_overlayables.size(); i++) {
if (overlayable_item.overlayable.get() == serialized_overlayables[i]) {
break;
}
}
// Serialize the overlayable if it has not been serialized already.
if (i == serialized_overlayables.size()) {
serialized_overlayables.push_back(overlayable_item.overlayable.get());
pb::Overlayable* pb_overlayable = pb_table->add_overlayable();
pb_overlayable->set_name(overlayable_item.overlayable->name);
pb_overlayable->set_actor(overlayable_item.overlayable->actor);
SerializeSourceToPb(overlayable_item.overlayable->source, source_pool,
pb_overlayable->mutable_source());
}
pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item();
pb_overlayable_item->set_overlayable_idx(i);
if (overlayable_item.policies & OverlayableItem::Policy::kPublic) {
pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC);
}
if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
}
if (overlayable_item.policies & OverlayableItem::Policy::kProductServices) {
pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT_SERVICES);
}
if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
}
if (overlayable_item.policies & OverlayableItem::Policy::kVendor) {
pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
}
SerializeSourceToPb(overlayable_item.source, source_pool,
pb_overlayable_item->mutable_source());
pb_overlayable_item->set_comment(overlayable_item.comment);
}
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
IDiagnostics* diag) {
StringPool source_pool;
std::vector<Overlayable*> overlayables;
for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) {
pb::Package* pb_package = out_table->add_package();
if (package->id) {
@@ -310,29 +358,9 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
pb_allow_new->set_comment(entry->allow_new.value().comment);
}
if (entry->overlayable) {
pb::Overlayable* pb_overlayable = pb_entry->mutable_overlayable();
Overlayable overlayable = entry->overlayable.value();
if (overlayable.policies & Overlayable::Policy::kPublic) {
pb_overlayable->add_policy(pb::Overlayable::PUBLIC);
}
if (overlayable.policies & Overlayable::Policy::kProduct) {
pb_overlayable->add_policy(pb::Overlayable::PRODUCT);
}
if (overlayable.policies & Overlayable::Policy::kProductServices) {
pb_overlayable->add_policy(pb::Overlayable::PRODUCT_SERVICES);
}
if (overlayable.policies & Overlayable::Policy::kSystem) {
pb_overlayable->add_policy(pb::Overlayable::SYSTEM);
}
if (overlayable.policies & Overlayable::Policy::kVendor) {
pb_overlayable->add_policy(pb::Overlayable::VENDOR);
}
SerializeSourceToPb(overlayable.source, &source_pool,
pb_overlayable->mutable_source());
pb_overlayable->set_comment(overlayable.comment);
if (entry->overlayable_item) {
SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, &source_pool,
pb_entry, out_table);
}
for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {

View File

@@ -93,8 +93,11 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
// Make an overlayable resource.
OverlayableItem overlayable_item(std::make_shared<Overlayable>(
"OverlayableName", "overlay://theme", Source("res/values/overlayable.xml", 40)));
overlayable_item.source = Source("res/values/overlayable.xml", 42);
ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
Overlayable{}, test::GetDiagnostics()));
overlayable_item, test::GetDiagnostics()));
pb::ResourceTable pb_table;
SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
@@ -160,9 +163,15 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable);
EXPECT_THAT(search_result.value().entry->overlayable.value().policies,
Eq(Overlayable::Policy::kNone));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("OverlayableName"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
EXPECT_THAT(result_overlayable_item.source.line, Eq(42));
}
TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
@@ -503,26 +512,31 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
}
TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
Overlayable overlayable_foo{};
overlayable_foo.policies |= Overlayable::Policy::kSystem;
overlayable_foo.policies |= Overlayable::Policy::kProduct;
OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>(
"CustomizableResources", "overlay://customization"));
overlayable_item_foo.policies |= OverlayableItem::Policy::kSystem;
overlayable_item_foo.policies |= OverlayableItem::Policy::kProduct;
Overlayable overlayable_bar{};
overlayable_bar.policies |= Overlayable::Policy::kProductServices;
overlayable_bar.policies |= Overlayable::Policy::kVendor;
OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
"TaskBar", "overlay://theme"));
overlayable_item_bar.policies |= OverlayableItem::Policy::kProductServices;
overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor;
Overlayable overlayable_baz{};
overlayable_baz.policies |= Overlayable::Policy::kPublic;
OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
"FontPack", "overlay://theme"));
overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic;
Overlayable overlayable_biz{};
OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
"Other", "overlay://customization"));
overlayable_item_biz.comment ="comment";
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetOverlayable("com.app.a:bool/foo", overlayable_foo)
.SetOverlayable("com.app.a:bool/bar", overlayable_bar)
.SetOverlayable("com.app.a:bool/baz", overlayable_baz)
.SetOverlayable("com.app.a:bool/biz", overlayable_biz)
.SetOverlayable("com.app.a:bool/foo", overlayable_item_foo)
.SetOverlayable("com.app.a:bool/bar", overlayable_item_bar)
.SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
.SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
.AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
.Build();
@@ -538,33 +552,41 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
Maybe<ResourceTable::SearchResult> search_result =
new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
Overlayable result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kSystem
| Overlayable::Policy::kProduct));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources"));
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization"));
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem
| OverlayableItem::Policy::kProduct));
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProductServices
| Overlayable::Policy::kVendor));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices
| OverlayableItem::Policy::kVendor));
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(result_overlayable.policies, Overlayable::Policy::kPublic);
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack"));
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(result_overlayable.policies, Overlayable::Policy::kNone);
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other"));
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
EXPECT_THAT(overlayable_item.comment, Eq("comment"));
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
ASSERT_TRUE(search_result);
ASSERT_FALSE(search_result.value().entry->overlayable);
ASSERT_FALSE(search_result.value().entry->overlayable_item);
}
} // namespace aapt

View File

@@ -374,8 +374,8 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
}
// Ensure that definitions for values declared as overlayable exist
if (entry->overlayable && entry->values.empty()) {
context->GetDiagnostics()->Error(DiagMessage(entry->overlayable.value().source)
if (entry->overlayable_item && entry->values.empty()) {
context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_item.value().source)
<< "no definition for overlayable symbol '"
<< name << "'");
error = true;

View File

@@ -134,18 +134,18 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
dst_entry->allow_new = std::move(src_entry->allow_new);
}
if (src_entry->overlayable) {
if (dst_entry->overlayable) {
if (src_entry->overlayable_item) {
if (dst_entry->overlayable_item) {
// Do not allow a resource with an overlayable declaration to have that overlayable
// declaration redefined
context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable.value().source)
context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable_item.value().source)
<< "duplicate overlayable declaration for resource '"
<< src_entry->name << "'");
context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable.value().source)
context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable_item.value().source)
<< "previous declaration here");
return false;
} else {
dst_entry->overlayable = std::move(src_entry->overlayable);
dst_entry->overlayable_item = std::move(src_entry->overlayable_item);
}
}

View File

@@ -437,14 +437,16 @@ TEST_F(TableMergerTest, OverlaidStyleablesAndStylesShouldBeMerged) {
}
TEST_F(TableMergerTest, SetOverlayable) {
Overlayable overlayable{};
overlayable.policies |= Overlayable::Policy::kProduct;
overlayable.policies |= Overlayable::Policy::kVendor;
auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
"overlay://customization");
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
overlayable_item.policies |= OverlayableItem::Policy::kVendor;
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.SetOverlayable("bool/foo", overlayable)
.SetOverlayable("bool/foo", overlayable_item)
.Build();
std::unique_ptr<ResourceTable> table_b =
@@ -463,26 +465,30 @@ TEST_F(TableMergerTest, SetOverlayable) {
const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProduct
| Overlayable::Policy::kVendor));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
| OverlayableItem::Policy::kVendor));
}
TEST_F(TableMergerTest, SetOverlayableLater) {
auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
"overlay://customization");
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.AddSimple("bool/foo")
.Build();
Overlayable overlayable{};
overlayable.policies |= Overlayable::Policy::kPublic;
overlayable.policies |= Overlayable::Policy::kProductServices;
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= OverlayableItem::Policy::kPublic;
overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
std::unique_ptr<ResourceTable> table_b =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.SetOverlayable("bool/foo", overlayable)
.SetOverlayable("bool/foo", overlayable_item)
.Build();
ResourceTable final_table;
@@ -495,27 +501,33 @@ TEST_F(TableMergerTest, SetOverlayableLater) {
const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable);
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kPublic
| Overlayable::Policy::kProductServices));
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
| OverlayableItem::Policy::kProductServices));
}
TEST_F(TableMergerTest, SetOverlayableSamePolicesFail) {
Overlayable overlayable_first{};
overlayable_first.policies |= Overlayable::Policy::kProduct;
TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
"overlay://customization");
OverlayableItem overlayable_item_first(overlayable_first);
overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.SetOverlayable("bool/foo", overlayable_first)
.SetOverlayable("bool/foo", overlayable_item_first)
.Build();
Overlayable overlayable_second{};
overlayable_second.policies |= Overlayable::Policy::kProduct;
auto overlayable_second = std::make_shared<Overlayable>("ThemeResources",
"overlay://theme");
OverlayableItem overlayable_item_second(overlayable_second);
overlayable_item_second.policies |= OverlayableItem::Policy::kProduct;
std::unique_ptr<ResourceTable> table_b =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.SetOverlayable("bool/foo", overlayable_second)
.SetOverlayable("bool/foo", overlayable_item_second)
.Build();
ResourceTable final_table;
@@ -526,21 +538,24 @@ TEST_F(TableMergerTest, SetOverlayableSamePolicesFail) {
ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
}
TEST_F(TableMergerTest, SetOverlayableDifferentPolicesFail) {
Overlayable overlayable_first{};
overlayable_first.policies |= Overlayable::Policy::kVendor;
TEST_F(TableMergerTest, SameResourceSameNameFail) {
auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
"overlay://customization");
OverlayableItem overlayable_item_first(overlayable);
overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.SetOverlayable("bool/foo",overlayable_first)
.SetOverlayable("bool/foo", overlayable_item_first)
.Build();
Overlayable overlayable_second{};
overlayable_second.policies |= Overlayable::Policy::kProduct;
OverlayableItem overlayable_item_second(overlayable);
overlayable_item_second.policies |= OverlayableItem::Policy::kSystem;
std::unique_ptr<ResourceTable> table_b =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
.SetOverlayable("bool/foo", overlayable_second)
.SetOverlayable("bool/foo", overlayable_item_second)
.Build();
ResourceTable final_table;

View File

@@ -248,7 +248,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
if (!split_entry->id) {
split_entry->id = entry->id;
split_entry->visibility = entry->visibility;
split_entry->overlayable = entry->overlayable;
split_entry->overlayable_item = entry->overlayable_item;
}
// Copy the selected values into the new Split Entry.

View File

@@ -136,7 +136,7 @@ ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& na
}
ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(const StringPiece& name,
const Overlayable& overlayable) {
const OverlayableItem& overlayable) {
ResourceName res_name = ParseNameOrDie(name);
CHECK(table_->SetOverlayable(res_name, overlayable, GetDiagnostics()));

View File

@@ -74,7 +74,7 @@ class ResourceTableBuilder {
ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
Visibility::Level level, bool allow_new = false);
ResourceTableBuilder& SetOverlayable(const android::StringPiece& name,
const Overlayable& overlayable);
const OverlayableItem& overlayable);
StringPool* string_pool();
std::unique_ptr<ResourceTable> Build();