summaryrefslogtreecommitdiff
path: root/tools/aapt2/ResourceTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt2/ResourceTable.cpp')
-rw-r--r--tools/aapt2/ResourceTable.cpp139
1 files changed, 98 insertions, 41 deletions
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index cff98728c325..27f7bdd83c9e 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -47,11 +47,6 @@ bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType
}
template <typename T>
-bool less_than_type_and_id(const T& lhs, const std::pair<ResourceType, Maybe<uint8_t>>& rhs) {
- return lhs.id != rhs.second ? lhs.id < rhs.second : lhs.type < rhs.first;
-}
-
-template <typename T>
bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
}
@@ -80,12 +75,6 @@ bool less_than_struct_with_name_and_id(const T& lhs,
return lhs.name.compare(0, lhs.name.size(), rhs.first.data(), rhs.first.size()) < 0;
}
-template <typename T, typename U>
-bool less_than_struct_with_name_and_id_pointer(const T* lhs,
- const std::pair<std::string_view, Maybe<U>>& rhs) {
- return less_than_struct_with_name_and_id(*lhs, rhs);
-}
-
template <typename T, typename Func, typename Elements>
T* FindElementsRunAction(const android::StringPiece& name, Elements& entries, Func action) {
const auto iter =
@@ -307,51 +296,115 @@ ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* exist
return CollisionResult::kConflict;
}
+template <typename T, typename Comparer>
+struct SortedVectorInserter : public Comparer {
+ std::pair<bool, typename std::vector<T>::iterator> LowerBound(std::vector<T>& el,
+ const T& value) {
+ auto it = std::lower_bound(el.begin(), el.end(), value, [&](auto& lhs, auto& rhs) {
+ return Comparer::operator()(lhs, rhs);
+ });
+ bool found =
+ it != el.end() && !Comparer::operator()(*it, value) && !Comparer::operator()(value, *it);
+ return std::make_pair(found, it);
+ }
+
+ T* Insert(std::vector<T>& el, T&& value) {
+ auto [found, it] = LowerBound(el, value);
+ if (found) {
+ return &*it;
+ }
+ return &*el.insert(it, std::move(value));
+ }
+};
+
+struct PackageViewComparer {
+ bool operator()(const ResourceTablePackageView& lhs, const ResourceTablePackageView& rhs) {
+ return less_than_struct_with_name_and_id<ResourceTablePackageView, uint8_t>(
+ lhs, std::make_pair(rhs.name, rhs.id));
+ }
+};
+
+struct TypeViewComparer {
+ bool operator()(const ResourceTableTypeView& lhs, const ResourceTableTypeView& rhs) {
+ return lhs.id != rhs.id ? lhs.id < rhs.id : lhs.type < rhs.type;
+ }
+};
+
+struct EntryViewComparer {
+ bool operator()(const ResourceEntry* lhs, const ResourceEntry* rhs) {
+ return less_than_struct_with_name_and_id<ResourceEntry, ResourceId>(
+ *lhs, std::make_pair(rhs->name, rhs->id));
+ }
+};
+
ResourceTableView ResourceTable::GetPartitionedView() const {
ResourceTableView view;
+ SortedVectorInserter<ResourceTablePackageView, PackageViewComparer> package_inserter;
+ SortedVectorInserter<ResourceTableTypeView, TypeViewComparer> type_inserter;
+ SortedVectorInserter<const ResourceEntry*, EntryViewComparer> entry_inserter;
+
for (const auto& package : packages) {
for (const auto& type : package->types) {
for (const auto& entry : type->entries) {
- std::pair<std::string_view, Maybe<uint8_t>> package_key(package->name, {});
- std::pair<std::string_view, Maybe<ResourceId>> entry_key(entry->name, {});
- std::pair<ResourceType, Maybe<uint8_t>> type_key(type->type, {});
- if (entry->id) {
- // If the entry has a defined id, use the id to determine insertion position.
- package_key.second = entry->id.value().package_id();
- type_key.second = entry->id.value().type_id();
- entry_key.second = entry->id.value();
- }
+ ResourceTablePackageView new_package{
+ package->name, entry->id ? entry->id.value().package_id() : Maybe<uint8_t>{}};
+ auto view_package = package_inserter.Insert(view.packages, std::move(new_package));
- auto package_it =
- std::lower_bound(view.packages.begin(), view.packages.end(), package_key,
- less_than_struct_with_name_and_id<ResourceTablePackageView, uint8_t>);
- if (package_it == view.packages.end() || package_it->name != package_key.first ||
- package_it->id != package_key.second) {
- ResourceTablePackageView new_package{std::string(package_key.first), package_key.second};
- package_it = view.packages.insert(package_it, new_package);
- }
-
- auto type_it = std::lower_bound(package_it->types.begin(), package_it->types.end(),
- type_key, less_than_type_and_id<ResourceTableTypeView>);
- if (type_it == package_it->types.end() || type_key.first != type_it->type ||
- type_it->id != type_key.second) {
- ResourceTableTypeView new_type{type_key.first, type_key.second};
- type_it = package_it->types.insert(type_it, new_type);
- }
+ ResourceTableTypeView new_type{type->type,
+ entry->id ? entry->id.value().type_id() : Maybe<uint8_t>{}};
+ auto view_type = type_inserter.Insert(view_package->types, std::move(new_type));
if (entry->visibility.level == Visibility::Level::kPublic) {
// Only mark the type visibility level as public, it doesn't care about being private.
- type_it->visibility_level = Visibility::Level::kPublic;
+ view_type->visibility_level = Visibility::Level::kPublic;
}
- auto entry_it =
- std::lower_bound(type_it->entries.begin(), type_it->entries.end(), entry_key,
- less_than_struct_with_name_and_id_pointer<ResourceEntry, ResourceId>);
- type_it->entries.insert(entry_it, entry.get());
+ entry_inserter.Insert(view_type->entries, entry.get());
+ }
+ }
+ }
+
+ // The android runtime does not support querying resources when the there are multiple type ids
+ // for the same resource type within the same package. For this reason, if there are types with
+ // multiple type ids, each type needs to exist in its own package in order to be queried by name.
+ std::vector<ResourceTablePackageView> new_packages;
+ for (auto& package : view.packages) {
+ // If a new package was already created for a different type within this package, then
+ // we can reuse those packages for other types that need to be extracted from this package.
+ // `start_index` is the index of the first newly created package that can be reused.
+ const size_t start_index = new_packages.size();
+ std::map<ResourceType, size_t> type_new_package_index;
+ for (auto type_it = package.types.begin(); type_it != package.types.end();) {
+ auto& type = *type_it;
+ auto type_index_iter = type_new_package_index.find(type.type);
+ if (type_index_iter == type_new_package_index.end()) {
+ // First occurrence of the resource type in this package. Keep it in this package.
+ type_new_package_index.insert(type_index_iter, std::make_pair(type.type, start_index));
+ ++type_it;
+ continue;
}
+
+ // The resource type has already been seen for this package, so this type must be extracted to
+ // a new separate package.
+ const size_t index = type_index_iter->second;
+ if (new_packages.size() == index) {
+ new_packages.emplace_back(ResourceTablePackageView{package.name, package.id});
+ type_new_package_index[type.type] = index + 1;
+ }
+
+ // Move the type into a new package
+ auto& other_package = new_packages[index];
+ type_inserter.Insert(other_package.types, std::move(type));
+ type_it = package.types.erase(type_it);
}
}
+ for (auto& new_package : new_packages) {
+ // Insert newly created packages after their original packages
+ auto [_, it] = package_inserter.LowerBound(view.packages, new_package);
+ view.packages.insert(++it, std::move(new_package));
+ }
+
return view;
}
@@ -424,6 +477,10 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
// This symbol definition takes precedence, replace.
entry->visibility = res.visibility.value();
}
+
+ if (res.visibility->staged_api) {
+ entry->visibility.staged_api = entry->visibility.staged_api;
+ }
}
if (res.overlayable.has_value()) {