Prepare aapt2 for multiple ids per type
For the SDK finalization changes, aapt2 must be able to handle
resources of the same type having different type ids. The
ResourceTable data structure currently stores package ids and type ids
on ResourceTablePackage and ResourceTableType respectively. This
prevents resource entries of the same type from having different type
ids without having to create another ResourceTableType structure.
JavaClassGenerator assumes each type only appears once in the
ResourceTable and it would need to dedupe the types to ensure one class
containing all the resource types ids is generated. TableFlattener on
the other hand needs a separate ResourceTableType for each type/id
combination so that the types are flattened into separate
ResTable_types.
This change simplifies aapt2's ResourceTable data structure:
- Resource ids are stored exclusively on ResourceEntry structures
meaning multiple entries can have different type ids while being
stored in the same ResourceTableType. Classes like JavaClassGenerator
can simply iterate over a type to see all the resources of the type
regardless of what their type id is.
- ResourceTable::GetPartitionedView() retrieves a list of resources
sorted and partitioned by package id, type id, and entry id. Classes
like TableFlattener can use this view to get separate
ResourceTavleTypes for each different type id that a type has.
These changes will also make it easy to have a resource span multiple
type ids if it exhausts all of the entry ids in one type id.
The new NewResourcesBuilder replaces the numerous setter methods on
ResourceTable.
Bug: 183102797
Test: aapt2_tests
Change-Id: I60dbcb24143bb958333899cafa7d41faa226d203
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index d56994e..0bb044e 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -95,17 +95,17 @@
return false;
}
-static bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a,
- ResourceTablePackage* pkg_a, ResourceTableType* type_a,
- ResourceEntry* entry_a, ResourceConfigValue* config_value_a,
- LoadedApk* apk_b, ResourceTablePackage* pkg_b,
- ResourceTableType* type_b, ResourceEntry* entry_b,
- ResourceConfigValue* config_value_b) {
+static bool EmitResourceConfigValueDiff(
+ IAaptContext* context, LoadedApk* apk_a, const ResourceTablePackageView& pkg_a,
+ const ResourceTableTypeView& type_a, const ResourceEntry* entry_a,
+ const ResourceConfigValue* config_value_a, LoadedApk* apk_b,
+ const ResourceTablePackageView& pkg_b, const ResourceTableTypeView& type_b,
+ const ResourceEntry* entry_b, const ResourceConfigValue* config_value_b) {
Value* value_a = config_value_a->value.get();
Value* value_b = config_value_b->value.get();
if (!value_a->Equals(value_b)) {
std::stringstream str_stream;
- str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
+ str_stream << "value " << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
<< " config=" << config_value_a->config << " does not match:\n";
value_a->Print(&str_stream);
str_stream << "\n vs \n";
@@ -117,16 +117,17 @@
}
static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
- ResourceTablePackage* pkg_a, ResourceTableType* type_a,
- ResourceEntry* entry_a, LoadedApk* apk_b,
- ResourceTablePackage* pkg_b, ResourceTableType* type_b,
- ResourceEntry* entry_b) {
+ const ResourceTablePackageView& pkg_a,
+ const ResourceTableTypeView& type_a, const ResourceEntry* entry_a,
+ LoadedApk* apk_b, const ResourceTablePackageView& pkg_b,
+ const ResourceTableTypeView& type_b,
+ const ResourceEntry* entry_b) {
bool diff = false;
- for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
- ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config);
+ for (const std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
+ auto config_value_b = entry_b->FindValue(config_value_a->config);
if (!config_value_b) {
std::stringstream str_stream;
- str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
+ str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
<< " config=" << config_value_a->config;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
@@ -138,35 +139,47 @@
}
// Check for any newly added config values.
- for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
- ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config);
+ for (const std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
+ auto config_value_a = entry_a->FindValue(config_value_b->config);
if (!config_value_a) {
std::stringstream str_stream;
- str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name
+ str_stream << "new config " << pkg_b.name << ":" << type_b.type << "/" << entry_b->name
<< " config=" << config_value_b->config;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
}
}
- return false;
+ return diff;
}
static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
- ResourceTablePackage* pkg_a, ResourceTableType* type_a,
- LoadedApk* apk_b, ResourceTablePackage* pkg_b,
- ResourceTableType* type_b) {
+ const ResourceTablePackageView& pkg_a,
+ const ResourceTableTypeView& type_a, LoadedApk* apk_b,
+ const ResourceTablePackageView& pkg_b,
+ const ResourceTableTypeView& type_b) {
bool diff = false;
- for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) {
- ResourceEntry* entry_b = type_b->FindEntry(entry_a->name);
- if (!entry_b) {
+ auto entry_a_iter = type_a.entries.begin();
+ auto entry_b_iter = type_b.entries.begin();
+ while (entry_a_iter != type_a.entries.end() || entry_b_iter != type_b.entries.end()) {
+ if (entry_b_iter == type_b.entries.end()) {
+ // Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name;
+ str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << (*entry_a_iter)->name;
+ EmitDiffLine(apk_a->GetSource(), str_stream.str());
+ diff = true;
+ } else if (entry_a_iter == type_a.entries.end()) {
+ // Type B contains a type that type A does not have.
+ std::stringstream str_stream;
+ str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/"
+ << (*entry_b_iter)->name;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
} else {
+ const auto& entry_a = *entry_a_iter;
+ const auto& entry_b = *entry_a_iter;
if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) {
std::stringstream str_stream;
- str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
+ str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
<< " has different visibility (";
if (entry_b->visibility.level == Visibility::Level::kPublic) {
str_stream << "PUBLIC";
@@ -185,7 +198,7 @@
} else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
entry_b->id)) {
std::stringstream str_stream;
- str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
+ str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
<< " has different public ID (";
if (entry_b->id) {
str_stream << "0x" << std::hex << entry_b->id.value();
@@ -202,46 +215,43 @@
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
}
- diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b,
- type_b, entry_b);
- }
- }
-
- // Check for any newly added entries.
- for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) {
- ResourceEntry* entry_a = type_a->FindEntry(entry_b->name);
- if (!entry_a) {
- std::stringstream str_stream;
- str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name;
- EmitDiffLine(apk_b->GetSource(), str_stream.str());
- diff = true;
+ diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a, apk_b, pkg_b, type_b,
+ entry_b);
}
}
return diff;
}
static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
- ResourceTablePackage* pkg_a, LoadedApk* apk_b,
- ResourceTablePackage* pkg_b) {
+ const ResourceTablePackageView& pkg_a, LoadedApk* apk_b,
+ const ResourceTablePackageView& pkg_b) {
bool diff = false;
- for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) {
- ResourceTableType* type_b = pkg_b->FindType(type_a->type);
- if (!type_b) {
+ auto type_a_iter = pkg_a.types.begin();
+ auto type_b_iter = pkg_b.types.begin();
+ while (type_a_iter != pkg_a.types.end() || type_b_iter != pkg_b.types.end()) {
+ if (type_b_iter == pkg_b.types.end()) {
+ // Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a->name << ":" << type_a->type;
+ str_stream << "missing " << pkg_a.name << ":" << type_a_iter->type;
EmitDiffLine(apk_a->GetSource(), str_stream.str());
diff = true;
+ } else if (type_a_iter == pkg_a.types.end()) {
+ // Type B contains a type that type A does not have.
+ std::stringstream str_stream;
+ str_stream << "new type " << pkg_b.name << ":" << type_b_iter->type;
+ EmitDiffLine(apk_b->GetSource(), str_stream.str());
+ diff = true;
} else {
- if (type_a->visibility_level != type_b->visibility_level) {
+ if (type_a_iter->visibility_level != type_b_iter->visibility_level) {
std::stringstream str_stream;
- str_stream << pkg_a->name << ":" << type_a->type << " has different visibility (";
- if (type_b->visibility_level == Visibility::Level::kPublic) {
+ str_stream << pkg_a.name << ":" << type_a_iter->type << " has different visibility (";
+ if (type_b_iter->visibility_level == Visibility::Level::kPublic) {
str_stream << "PUBLIC";
} else {
str_stream << "PRIVATE";
}
str_stream << " vs ";
- if (type_a->visibility_level == Visibility::Level::kPublic) {
+ if (type_a_iter->visibility_level == Visibility::Level::kPublic) {
str_stream << "PUBLIC";
} else {
str_stream << "PRIVATE";
@@ -249,18 +259,18 @@
str_stream << ")";
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
- } else if (IsIdDiff(type_a->visibility_level, type_a->id, type_b->visibility_level,
- type_b->id)) {
+ } else if (IsIdDiff(type_a_iter->visibility_level, type_a_iter->id,
+ type_b_iter->visibility_level, type_b_iter->id)) {
std::stringstream str_stream;
- str_stream << pkg_a->name << ":" << type_a->type << " has different public ID (";
- if (type_b->id) {
- str_stream << "0x" << std::hex << type_b->id.value();
+ str_stream << pkg_a.name << ":" << type_a_iter->type << " has different public ID (";
+ if (type_b_iter->id) {
+ str_stream << "0x" << std::hex << type_b_iter->id.value();
} else {
str_stream << "none";
}
str_stream << " vs ";
- if (type_a->id) {
- str_stream << "0x " << std::hex << type_a->id.value();
+ if (type_a_iter->id) {
+ str_stream << "0x " << std::hex << type_a_iter->id.value();
} else {
str_stream << "none";
}
@@ -268,47 +278,44 @@
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
}
- diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b);
- }
- }
-
- // Check for any newly added types.
- for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) {
- ResourceTableType* type_a = pkg_a->FindType(type_b->type);
- if (!type_a) {
- std::stringstream str_stream;
- str_stream << "new type " << pkg_b->name << ":" << type_b->type;
- EmitDiffLine(apk_b->GetSource(), str_stream.str());
- diff = true;
+ diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, *type_a_iter, apk_b, pkg_b, *type_b_iter);
}
}
return diff;
}
static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
- ResourceTable* table_a = apk_a->GetResourceTable();
- ResourceTable* table_b = apk_b->GetResourceTable();
+ const auto table_a = apk_a->GetResourceTable()->GetPartitionedView();
+ const auto table_b = apk_b->GetResourceTable()->GetPartitionedView();
bool diff = false;
- for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) {
- ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name);
- if (!pkg_b) {
+ auto package_a_iter = table_a.packages.begin();
+ auto package_b_iter = table_b.packages.begin();
+ while (package_a_iter != table_a.packages.end() || package_b_iter != table_b.packages.end()) {
+ if (package_b_iter == table_b.packages.end()) {
+ // Table A contains a package that table B does not have.
std::stringstream str_stream;
- str_stream << "missing package " << pkg_a->name;
+ str_stream << "missing package " << package_a_iter->name;
+ EmitDiffLine(apk_a->GetSource(), str_stream.str());
+ diff = true;
+ } else if (package_a_iter == table_a.packages.end()) {
+ // Table B contains a package that table A does not have.
+ std::stringstream str_stream;
+ str_stream << "new package " << package_b_iter->name;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
} else {
- if (pkg_a->id != pkg_b->id) {
+ if (package_a_iter->id != package_b_iter->id) {
std::stringstream str_stream;
- str_stream << "package '" << pkg_a->name << "' has different id (";
- if (pkg_b->id) {
- str_stream << "0x" << std::hex << pkg_b->id.value();
+ str_stream << "package '" << package_a_iter->name << "' has different id (";
+ if (package_b_iter->id) {
+ str_stream << "0x" << std::hex << package_b_iter->id.value();
} else {
str_stream << "none";
}
str_stream << " vs ";
- if (pkg_a->id) {
- str_stream << "0x" << std::hex << pkg_a->id.value();
+ if (package_a_iter->id) {
+ str_stream << "0x" << std::hex << package_b_iter->id.value();
} else {
str_stream << "none";
}
@@ -316,20 +323,10 @@
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
}
- diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b);
+ diff |= EmitResourcePackageDiff(context, apk_a, *package_a_iter, apk_b, *package_b_iter);
}
}
- // Check for any newly added packages.
- for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) {
- ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name);
- if (!pkg_a) {
- std::stringstream str_stream;
- str_stream << "new package " << pkg_b->name;
- EmitDiffLine(apk_b->GetSource(), str_stream.str());
- diff = true;
- }
- }
return diff;
}