diff options
Diffstat (limited to 'tools/aapt2/ResourceTable.cpp')
-rw-r--r-- | tools/aapt2/ResourceTable.cpp | 212 |
1 files changed, 145 insertions, 67 deletions
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index c2274d04cc8c..bc8a4d1f85b8 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -26,6 +26,7 @@ #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" +#include "Debug.h" #include "NameMangler.h" #include "ResourceValues.h" #include "ValueVisitor.h" @@ -39,8 +40,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> @@ -50,9 +52,9 @@ static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const Stri 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) { + const std::pair<StringPiece, Maybe<uint16_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 { @@ -116,42 +118,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<uint16_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<uint16_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) { @@ -303,9 +315,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; @@ -322,15 +340,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, @@ -338,14 +358,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, @@ -364,7 +388,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, @@ -372,7 +396,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, @@ -399,37 +423,57 @@ 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 - << " but package '" << package->name << "' already has ID " - << StringPrintf("%02x", package->id.value())); + 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<uint16_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 " - << ResourceId(package->id.value(), type->id.value(), entry->id.value())); + << "trying to add resource '" << name << "' with ID " << res_id + << " but resource already has ID " + << ResourceId(package->id.value(), type->id.value(), entry->id.value())); return false; } 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); @@ -451,17 +495,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, @@ -485,28 +534,42 @@ 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 - << " but package '" << package->name << "' already has ID " - << StringPrintf("%02x", package->id.value())); + 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<uint16_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 " - << ResourceId(package->id.value(), type->id.value(), entry->id.value())); + << "trying to add resource '" << name << "' with ID " << res_id + << " but resource already has ID " + << ResourceId(package->id.value(), type->id.value(), entry->id.value())); return false; } @@ -562,17 +625,17 @@ bool ResourceTable::SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& return true; } -bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, +bool ResourceTable::AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, IDiagnostics* diag) { - return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag); + return AddOverlayableImpl(name, overlayable, ResourceNameValidator, diag); } -bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name, +bool ResourceTable::AddOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable, IDiagnostics* diag) { - return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag); + return AddOverlayableImpl(name, overlayable, SkipNameValidator, diag); } -bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, +bool ResourceTable::AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, NameValidator name_validator, IDiagnostics* diag) { CHECK(diag != nullptr); @@ -583,13 +646,28 @@ bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overla ResourceTablePackage* package = FindOrCreatePackage(name.package); ResourceTableType* type = package->FindOrCreateType(name.type); ResourceEntry* entry = type->FindOrCreateEntry(name.entry); - if (entry->overlayable) { - diag->Error(DiagMessage(overlayable.source) - << "duplicate overlayable declaration for resource '" << name << "'"); - diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here"); - return false; + + for (auto& overlayable_declaration : entry->overlayable_declarations) { + // An overlayable resource cannot be declared twice with the same policy + if (overlayable.policy == overlayable_declaration.policy) { + diag->Error(DiagMessage(overlayable.source) + << "duplicate overlayable declaration for resource '" << name << "'"); + diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here"); + return false; + } + + // An overlayable resource cannot be declared once with a policy and without a policy because + // the policy becomes unused + if (!overlayable.policy || !overlayable_declaration.policy) { + diag->Error(DiagMessage(overlayable.source) + << "overlayable resource '" << name << "'" + << " declared once with a policy and once with no policy"); + diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here"); + return false; + } } - entry->overlayable = overlayable; + + entry->overlayable_declarations.push_back(overlayable); return true; } @@ -625,7 +703,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_declarations = entry->overlayable_declarations; for (const auto& config_value : entry->values) { ResourceConfigValue* new_value = |