Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3c1a4a9 authored by David Chaloupka's avatar David Chaloupka
Browse files

Handle multiple packages of same name in 'aapt2 convert'

aapt2 currently looks-up packages only by package name and then verifies
whether the package ID has the expected value. For pre-L we need to be able
to handle resource tables having packages of same package name but
different IDs.

Note that this CL fixes only proto->binary conversion but many other aapt2
commands are still affected. This is because many transformations still
consider package name as sufficient identifier of a package.

Bug: 72143207
Test: Manual
Change-Id: Id8a920d6cd15bec747d3124270f5bcb7f48924cf
parent 588a06f5
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -47,6 +47,13 @@ static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const Stri
  return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
}

template <typename T>
static bool less_than_struct_with_name_and_id(const std::unique_ptr<T>& lhs,
                                              const std::pair<StringPiece, Maybe<uint8_t>>& rhs) {
  int name_cmp = lhs->name.compare(0, lhs->name.size(), rhs.first.data(), rhs.first.size());
  return name_cmp < 0 || (name_cmp == 0 && lhs->id < rhs.second);
}

ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) const {
  const auto last = packages.end();
  auto iter = std::lower_bound(packages.begin(), last, name,
@@ -79,6 +86,22 @@ ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Mayb
  return package;
}

ResourceTablePackage* ResourceTable::CreatePackageAllowingDuplicateNames(const StringPiece& name,
                                                                         const Maybe<uint8_t> id) {
  const auto last = packages.end();
  auto iter = std::lower_bound(packages.begin(), last, std::make_pair(name, id),
                               less_than_struct_with_name_and_id<ResourceTablePackage>);

  if (iter != last && name == (*iter)->name && id == (*iter)->id) {
    return iter->get();
  }

  std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
  new_package->name = name.to_string();
  new_package->id = id;
  return packages.emplace(iter, std::move(new_package))->get();
}

ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) {
  const auto last = packages.end();
  auto iter = std::lower_bound(packages.begin(), last, name,
+7 −1
Original line number Diff line number Diff line
@@ -229,6 +229,11 @@ class ResourceTable {

  ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {});

  // Attempts to find a package having the specified name and ID. If not found, a new package
  // of the specified parameters is created and returned.
  ResourceTablePackage* CreatePackageAllowingDuplicateNames(const android::StringPiece& name,
                                                            const Maybe<uint8_t> id);

  std::unique_ptr<ResourceTable> Clone() const;

  // The string pool used by this resource table. Values that reference strings must use
@@ -239,7 +244,8 @@ class ResourceTable {
  // destroyed.
  StringPool string_pool;

  // The list of packages in this table, sorted alphabetically by package name.
  // The list of packages in this table, sorted alphabetically by package name and increasing
  // package ID (missing ID being the lowest).
  std::vector<std::unique_ptr<ResourceTablePackage>> packages;

  // Set of dynamic packages that this table may reference. Their package names get encoded
+2 −1
Original line number Diff line number Diff line
@@ -380,7 +380,8 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr

  std::map<ResourceId, ResourceNameRef> id_index;

  ResourceTablePackage* pkg = out_table->CreatePackage(pb_package.package_name(), id);
  ResourceTablePackage* pkg =
      out_table->CreatePackageAllowingDuplicateNames(pb_package.package_name(), id);
  for (const pb::Type& pb_type : pb_package.type()) {
    const ResourceType* res_type = ParseResourceType(pb_type.name());
    if (res_type == nullptr) {