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

Commit 1a8a6907 authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Loosen loading apk format requirements"

parents 14590e6d 83a37adf
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
    }

    std::string error;
    table = util::make_unique<ResourceTable>();
    table = util::make_unique<ResourceTable>(/** validate_resources **/ false);
    if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
      diag->Error(DiagMessage(source)
                  << "failed to deserialize " << kProtoResourceTablePath << ": " << error);
@@ -120,7 +120,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(

  io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
  if (table_file != nullptr) {
    table = util::make_unique<ResourceTable>();
    table = util::make_unique<ResourceTable>(/** validate_resources **/ false);
    std::unique_ptr<io::IData> data = table_file->OpenAsData();
    if (data == nullptr) {
      diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
+2 −0
Original line number Diff line number Diff line
@@ -96,6 +96,8 @@ StringPiece to_string(ResourceType type) {
      return "styleable";
    case ResourceType::kTransition:
      return "transition";
    case ResourceType::kUnknown:
      return "unknown";
    case ResourceType::kXml:
      return "xml";
  }
+5 −0
Original line number Diff line number Diff line
@@ -66,6 +66,11 @@ enum class ResourceType {
  kStyle,
  kStyleable,
  kTransition,

  // Not a parsed type. It is only used when loading resource tables that may have modified type
  // names
  kUnknown,

  kXml,
};

+117 −54
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "androidfw/ResourceTypes.h"

#include "ConfigDescription.h"
#include "Debug.h"
#include "NameMangler.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
@@ -38,8 +39,9 @@ using ::android::base::StringPrintf;

namespace aapt {

static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
  return lhs->type < rhs;
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);
}

template <typename T>
@@ -51,7 +53,7 @@ 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);
  return name_cmp < 0 || (name_cmp == 0 && rhs.second && lhs->id < rhs.second);
}

ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) const {
@@ -115,42 +117,52 @@ ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name
  return packages.emplace(iter, std::move(new_package))->get();
}

ResourceTableType* ResourceTablePackage::FindType(ResourceType type) {
ResourceTableType* ResourceTablePackage::FindType(ResourceType type, const Maybe<uint8_t> id) {
  const auto last = types.end();
  auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
  if (iter != last && (*iter)->type == type) {
  auto iter = std::lower_bound(types.begin(), last, std::make_pair(type, id),
                               less_than_type_and_id);
  if (iter != last && (*iter)->type == type && (!id || id == (*iter)->id)) {
    return iter->get();
  }
  return nullptr;
}

ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type,
                                                          const Maybe<uint8_t> id) {
  const auto last = types.end();
  auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
  if (iter != last && (*iter)->type == type) {
  auto iter = std::lower_bound(types.begin(), last, std::make_pair(type, id),
                               less_than_type_and_id);
  if (iter != last && (*iter)->type == type && (!id || id == (*iter)->id)) {
    return iter->get();
  }
  return types.emplace(iter, new ResourceTableType(type))->get();

  auto new_type = new ResourceTableType(type);
  new_type->id = id;
  return types.emplace(iter, std::move(new_type))->get();
}

ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) {
ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name, const Maybe<uint8_t> id) {
  const auto last = entries.end();
  auto iter =
      std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
  if (iter != last && name == (*iter)->name) {
  auto iter = std::lower_bound(entries.begin(), last, std::make_pair(name, id),
      less_than_struct_with_name_and_id<ResourceEntry>);
  if (iter != last && name == (*iter)->name && (!id || id == (*iter)->id)) {
    return iter->get();
  }
  return nullptr;
}

ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) {
ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name,
                                                    const Maybe<uint8_t> id) {
  auto last = entries.end();
  auto iter =
      std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
  if (iter != last && name == (*iter)->name) {
  auto iter = std::lower_bound(entries.begin(), last, std::make_pair(name, id),
                               less_than_struct_with_name_and_id<ResourceEntry>);
  if (iter != last && name == (*iter)->name && (!id || id == (*iter)->id)) {
    return iter->get();
  }
  return entries.emplace(iter, new ResourceEntry(name))->get();

  auto new_entry = new ResourceEntry(name);
  new_entry->id = id;
  return entries.emplace(iter, std::move(new_entry))->get();
}

ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
@@ -302,9 +314,15 @@ ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* exist
    // Keep the existing attribute.
    return CollisionResult::kKeepOriginal;
  }

  return CollisionResult::kConflict;
}

ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /** existing **/,
                                                              Value* /** incoming **/) {
  return CollisionResult::kKeepBoth;
}

static StringPiece ResourceNameValidator(const StringPiece& name) {
  if (!IsValidResourceEntryName(name)) {
    return name;
@@ -321,15 +339,17 @@ bool ResourceTable::AddResource(const ResourceNameRef& name,
                                const StringPiece& product,
                                std::unique_ptr<Value> value,
                                IDiagnostics* diag) {
  return AddResourceImpl(name, {}, config, product, std::move(value), ResourceNameValidator,
                         ResolveValueCollision, diag);
  return AddResourceImpl(name, ResourceId{}, config, product, std::move(value),
                         (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
                         (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}

bool ResourceTable::AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
                                      const ConfigDescription& config, const StringPiece& product,
                                      std::unique_ptr<Value> value, IDiagnostics* diag) {
  return AddResourceImpl(name, res_id, config, product, std::move(value), ResourceNameValidator,
                         ResolveValueCollision, diag);
  return AddResourceImpl(name, res_id, config, product, std::move(value),
                         (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
                         (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}

bool ResourceTable::AddFileReference(const ResourceNameRef& name,
@@ -337,14 +357,18 @@ bool ResourceTable::AddFileReference(const ResourceNameRef& name,
                                     const Source& source,
                                     const StringPiece& path,
                                     IDiagnostics* diag) {
  return AddFileReferenceImpl(name, config, source, path, nullptr, ResourceNameValidator, diag);
  return AddFileReferenceImpl(name, config, source, path, nullptr,
                              (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
                              diag);
}

bool ResourceTable::AddFileReferenceMangled(const ResourceNameRef& name,
                                            const ConfigDescription& config, const Source& source,
                                            const StringPiece& path, io::IFile* file,
                                            IDiagnostics* diag) {
  return AddFileReferenceImpl(name, config, source, path, file, SkipNameValidator, diag);
  return AddFileReferenceImpl(name, config, source, path, file,
                              (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
                              diag);
}

bool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name,
@@ -363,7 +387,7 @@ bool ResourceTable::AddResourceMangled(const ResourceNameRef& name, const Config
                                       const StringPiece& product, std::unique_ptr<Value> value,
                                       IDiagnostics* diag) {
  return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipNameValidator,
                         ResolveValueCollision, diag);
                         (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}

bool ResourceTable::AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
@@ -371,7 +395,7 @@ bool ResourceTable::AddResourceWithIdMangled(const ResourceNameRef& name, const
                                             const StringPiece& product,
                                             std::unique_ptr<Value> value, IDiagnostics* diag) {
  return AddResourceImpl(name, id, config, product, std::move(value), SkipNameValidator,
                         ResolveValueCollision, diag);
                         (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}

bool ResourceTable::ValidateName(NameValidator name_validator, const ResourceNameRef& name,
@@ -398,24 +422,38 @@ bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceI
    return false;
  }

  // Check for package names appearing twice with two different package ids
  ResourceTablePackage* package = FindOrCreatePackage(name.package);
  if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
    diag->Error(DiagMessage(source) << "trying to add resource '" << name << "' with ID " << res_id
    diag->Error(DiagMessage(source)
                    << "trying to add resource '" << name << "' with ID " << res_id
                    << " but package '" << package->name << "' already has ID "
                    << StringPrintf("%02x", package->id.value()));
    return false;
  }

  ResourceTableType* type = package->FindOrCreateType(name.type);
  if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
  // Whether or not to error on duplicate resources
  bool check_id = validate_resources_ && res_id.is_valid_dynamic();
  // Whether or not to create a duplicate resource if the id does not match
  bool use_id = !validate_resources_ && res_id.is_valid_dynamic();

  ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
                                                                        : Maybe<uint8_t>());

  // Check for types appearing twice with two different type ids
  if (check_id && type->id && type->id.value() != res_id.type_id()) {
    diag->Error(DiagMessage(source)
                << "trying to add resource '" << name << "' with ID " << res_id << " but type '"
                << type->type << "' already has ID " << StringPrintf("%02x", type->id.value()));
                    << "trying to add resource '" << name << "' with ID " << res_id
                    << " but type '" << type->type << "' already has ID "
                    << StringPrintf("%02x", type->id.value()));
    return false;
  }

  ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
  if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
  ResourceEntry* entry = type->FindOrCreateEntry(name.entry, use_id ? res_id.entry_id()
                                                                    : Maybe<uint8_t>());

  // Check for entries appearing twice with two different entry ids
  if (check_id && entry->id && entry->id.value() != res_id.entry_id()) {
    diag->Error(DiagMessage(source)
                    << "trying to add resource '" << name << "' with ID " << res_id
                    << " but resource already has ID "
@@ -424,11 +462,17 @@ bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceI
  }

  ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
  if (config_value->value == nullptr) {
  if (!config_value->value) {
    // Resource does not exist, add it now.
    config_value->value = std::move(value);
  } else {
    switch (conflict_resolver(config_value->value.get(), value.get())) {
      case CollisionResult::kKeepBoth:
        // Insert the value ignoring for duplicate configurations
        entry->values.push_back(util::make_unique<ResourceConfigValue>(config, product));
        entry->values.back()->value = std::move(value);
        break;

      case CollisionResult::kTakeNew:
        // Take the incoming value.
        config_value->value = std::move(value);
@@ -450,17 +494,22 @@ bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceI
    type->id = res_id.type_id();
    entry->id = res_id.entry_id();
  }

  return true;
}

bool ResourceTable::GetValidateResources() {
  return validate_resources_;
}

bool ResourceTable::SetVisibility(const ResourceNameRef& name, const Visibility& visibility,
                                  IDiagnostics* diag) {
  return SetVisibilityImpl(name, visibility, ResourceId{}, ResourceNameValidator, diag);
  return SetVisibilityImpl(name, visibility, {}, ResourceNameValidator, diag);
}

bool ResourceTable::SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
                                         IDiagnostics* diag) {
  return SetVisibilityImpl(name, visibility, ResourceId{}, SkipNameValidator, diag);
  return SetVisibilityImpl(name, visibility, {}, SkipNameValidator, diag);
}

bool ResourceTable::SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
@@ -484,24 +533,38 @@ bool ResourceTable::SetVisibilityImpl(const ResourceNameRef& name, const Visibil
    return false;
  }

  // Check for package names appearing twice with two different package ids
  ResourceTablePackage* package = FindOrCreatePackage(name.package);
  if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
    diag->Error(DiagMessage(source) << "trying to add resource '" << name << "' with ID " << res_id
    diag->Error(DiagMessage(source)
                    << "trying to add resource '" << name << "' with ID " << res_id
                    << " but package '" << package->name << "' already has ID "
                    << StringPrintf("%02x", package->id.value()));
    return false;
  }

  ResourceTableType* type = package->FindOrCreateType(name.type);
  if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
  // Whether or not to error on duplicate resources
  bool check_id = validate_resources_ && res_id.is_valid_dynamic();
  // Whether or not to create a duplicate resource if the id does not match
  bool use_id = !validate_resources_ && res_id.is_valid_dynamic();

  ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
                                                                        : Maybe<uint8_t>());

  // Check for types appearing twice with two different type ids
  if (check_id && type->id && type->id.value() != res_id.type_id()) {
    diag->Error(DiagMessage(source)
                << "trying to add resource '" << name << "' with ID " << res_id << " but type '"
                << type->type << "' already has ID " << StringPrintf("%02x", type->id.value()));
                    << "trying to add resource '" << name << "' with ID " << res_id
                    << " but type '" << type->type << "' already has ID "
                    << StringPrintf("%02x", type->id.value()));
    return false;
  }

  ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
  if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
  ResourceEntry* entry = type->FindOrCreateEntry(name.entry, use_id ? res_id.entry_id()
                                                                    : Maybe<uint8_t>());

  // Check for entries appearing twice with two different entry ids
  if (check_id && entry->id && entry->id.value() != res_id.entry_id()) {
    diag->Error(DiagMessage(source)
                    << "trying to add resource '" << name << "' with ID " << res_id
                    << " but resource already has ID "
+16 −5
Original line number Diff line number Diff line
@@ -146,8 +146,9 @@ class ResourceTableType {

  explicit ResourceTableType(const ResourceType type) : type(type) {}

  ResourceEntry* FindEntry(const android::StringPiece& name);
  ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
  ResourceEntry* FindEntry(const android::StringPiece& name, Maybe<uint8_t> id = Maybe<uint8_t>());
  ResourceEntry* FindOrCreateEntry(const android::StringPiece& name,
                                   Maybe<uint8_t> id = Maybe<uint8_t>());

 private:
  DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
@@ -163,8 +164,9 @@ class ResourceTablePackage {
  std::vector<std::unique_ptr<ResourceTableType>> types;

  ResourceTablePackage() = default;
  ResourceTableType* FindType(ResourceType type);
  ResourceTableType* FindOrCreateType(const ResourceType type);
  ResourceTableType* FindType(ResourceType type, Maybe<uint8_t> id = Maybe<uint8_t>());
  ResourceTableType* FindOrCreateType(const ResourceType type,
                                      Maybe<uint8_t> id = Maybe<uint8_t>());

 private:
  DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
@@ -174,14 +176,18 @@ class ResourceTablePackage {
class ResourceTable {
 public:
  ResourceTable() = default;
  explicit ResourceTable(bool validate_resources) : validate_resources_(validate_resources) {}

  enum class CollisionResult { kKeepOriginal, kConflict, kTakeNew };
  enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew };

  using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>;

  // When a collision of resources occurs, this method decides which value to keep.
  static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);

  // When a collision of resources occurs, this method keeps both values
  static CollisionResult IgnoreCollision(Value* existing, Value* incoming);

  bool AddResource(const ResourceNameRef& name, const ConfigDescription& config,
                   const android::StringPiece& product, std::unique_ptr<Value> value,
                   IDiagnostics* diag);
@@ -208,6 +214,8 @@ class ResourceTable {
                                const android::StringPiece& product, std::unique_ptr<Value> value,
                                IDiagnostics* diag);

  bool GetValidateResources();

  bool SetVisibility(const ResourceNameRef& name, const Visibility& visibility, IDiagnostics* diag);
  bool SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
                            IDiagnostics* diag);
@@ -299,6 +307,9 @@ class ResourceTable {
                          const Visibility& symbol, NameValidator name_validator,
                          IDiagnostics* diag);

  // Controls whether the table validates resource names and prevents duplicate resource names
  bool validate_resources_ = true;

  DISALLOW_COPY_AND_ASSIGN(ResourceTable);
};

Loading