/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef AAPT_RESOURCE_TABLE_H #define AAPT_RESOURCE_TABLE_H #include "Diagnostics.h" #include "Resource.h" #include "ResourceValues.h" #include "Source.h" #include "StringPool.h" #include "io/File.h" #include "android-base/macros.h" #include "androidfw/ConfigDescription.h" #include "androidfw/StringPiece.h" #include #include #include #include #include #include #include namespace aapt { // The Public status of a resource. struct Visibility { enum class Level { kUndefined, kPrivate, kPublic, }; Level level = Level::kUndefined; Source source; std::string comment; }; // Represents in an overlay. struct AllowNew { Source source; std::string comment; }; struct Overlayable { Overlayable() = default; Overlayable(const android::StringPiece& name, const android::StringPiece& actor) : name(name.to_string()), actor(actor.to_string()) {} Overlayable(const android::StringPiece& name, const android::StringPiece& actor, const Source& source) : name(name.to_string()), actor(actor.to_string()), source(source ){} static const char* kActorScheme; std::string name; std::string actor; Source source; }; // Represents a declaration that a resource is overlayable at runtime. struct OverlayableItem { explicit OverlayableItem(const std::shared_ptr& overlayable) : overlayable(overlayable) {} // Represents the types overlays that are allowed to overlay the resource. typedef uint32_t PolicyFlags; enum Policy : uint32_t { kNone = 0x00000000, // The resource can be overlaid by any overlay. kPublic = 0x00000001, // The resource can be overlaid by any overlay on the system partition. kSystem = 0x00000002, // The resource can be overlaid by any overlay on the vendor partition. kVendor = 0x00000004, // The resource can be overlaid by any overlay on the product partition. kProduct = 0x00000008, // The resource can be overlaid by any overlay signed with the same signature as its actor. kSignature = 0x00000010, // The resource can be overlaid by any overlay on the odm partition. kOdm = 0x00000020, // The resource can be overlaid by any overlay on the oem partition. kOem = 0x00000040, }; std::shared_ptr overlayable; PolicyFlags policies = Policy::kNone; std::string comment; Source source; }; class ResourceConfigValue { public: // The configuration for which this value is defined. const android::ConfigDescription config; // The product for which this value is defined. const std::string product; // The actual Value. std::unique_ptr value; ResourceConfigValue(const android::ConfigDescription& config, const android::StringPiece& product) : config(config), product(product.to_string()) {} private: DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue); }; // Represents a resource entry, which may have varying values for each defined configuration. class ResourceEntry { public: // The name of the resource. Immutable, as this determines the order of this resource // when doing lookups. const std::string name; // The entry ID for this resource (the EEEE in 0xPPTTEEEE). Maybe id; // Whether this resource is public (and must maintain the same entry ID across builds). Visibility visibility; Maybe allow_new; // The declarations of this resource as overlayable for RROs Maybe overlayable_item; // The resource's values for each configuration. std::vector> values; explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {} ResourceConfigValue* FindValue(const android::ConfigDescription& config); ResourceConfigValue* FindValue(const android::ConfigDescription& config, const android::StringPiece& product); ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config, const android::StringPiece& product); std::vector FindAllValues(const android::ConfigDescription& config); template std::vector FindValuesIf(Func f) { std::vector results; for (auto& config_value : values) { if (f(config_value.get())) { results.push_back(config_value.get()); } } return results; } bool HasDefaultValue() const; private: DISALLOW_COPY_AND_ASSIGN(ResourceEntry); }; // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries. class ResourceTableType { public: // The logical type of resource (string, drawable, layout, etc.). const ResourceType type; // The type ID for this resource (the TT in 0xPPTTEEEE). Maybe id; // Whether this type is public (and must maintain the same type ID across builds). Visibility::Level visibility_level = Visibility::Level::kUndefined; // List of resources for this type. std::vector> entries; explicit ResourceTableType(const ResourceType type) : type(type) {} ResourceEntry* FindEntry(const android::StringPiece& name, Maybe id = Maybe()); ResourceEntry* FindOrCreateEntry(const android::StringPiece& name, Maybe id = Maybe()); private: DISALLOW_COPY_AND_ASSIGN(ResourceTableType); }; class ResourceTablePackage { public: std::string name; // The package ID (the PP in 0xPPTTEEEE). Maybe id; std::vector> types; ResourceTablePackage() = default; ResourceTableType* FindType(ResourceType type, Maybe id = Maybe()); ResourceTableType* FindOrCreateType(const ResourceType type, Maybe id = Maybe()); private: DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage); }; // The container and index for all resources defined for an app. class ResourceTable { public: ResourceTable() = default; explicit ResourceTable(bool validate_resources) : validate_resources_(validate_resources) {} enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew }; using CollisionResolverFunc = std::function; // When a collision of resources occurs, this method decides which value to keep. static CollisionResult ResolveValueCollision(Value* existing, Value* incoming, bool overlay); // When a collision of resources occurs, this method keeps both values static CollisionResult IgnoreCollision(Value* existing, Value* incoming, bool overlay); bool AddResource(const ResourceNameRef& name, const android::ConfigDescription& config, const android::StringPiece& product, std::unique_ptr value, IDiagnostics* diag); bool AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id, const android::ConfigDescription& config, const android::StringPiece& product, std::unique_ptr value, IDiagnostics* diag); // Same as AddResource, but doesn't verify the validity of the name. This is used // when loading resources from an existing binary resource table that may have mangled names. bool AddResourceMangled(const ResourceNameRef& name, const android::ConfigDescription& config, const android::StringPiece& product, std::unique_ptr value, IDiagnostics* diag); bool AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id, const android::ConfigDescription& config, const android::StringPiece& product, std::unique_ptr value, IDiagnostics* diag); bool GetValidateResources(); bool SetVisibility(const ResourceNameRef& name, const Visibility& visibility, IDiagnostics* diag); bool SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility, const ResourceId& res_id, IDiagnostics* diag); bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility, const ResourceId& res_id, IDiagnostics* diag); bool SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable, IDiagnostics *diag); bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag); bool SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag); struct SearchResult { ResourceTablePackage* package; ResourceTableType* type; ResourceEntry* entry; }; Maybe FindResource(const ResourceNameRef& name) const; // Returns the package struct with the given name, or nullptr if such a package does not // exist. The empty string is a valid package and typically is used to represent the // 'current' package before it is known to the ResourceTable. ResourceTablePackage* FindPackage(const android::StringPiece& name) const; ResourceTablePackage* FindPackageById(uint8_t id) const; ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe 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 id); std::unique_ptr Clone() const; // The string pool used by this resource table. Values that reference strings must use // this pool to create their strings. // NOTE: `string_pool` must come before `packages` so that it is destroyed after. // When `string_pool` references are destroyed (as they will be when `packages` is destroyed), // they decrement a refCount, which would cause invalid memory access if the pool was already // destroyed. StringPool string_pool; // The list of packages in this table, sorted alphabetically by package name and increasing // package ID (missing ID being the lowest). std::vector> packages; // Set of dynamic packages that this table may reference. Their package names get encoded // into the resources.arsc along with their compile-time assigned IDs. std::map included_packages_; private: // The function type that validates a symbol name. Returns a non-empty StringPiece representing // the offending character (which may be more than one byte in UTF-8). Returns an empty string // if the name was valid. using NameValidator = android::StringPiece(const android::StringPiece&); ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name); bool ValidateName(NameValidator validator, const ResourceNameRef& name, const Source& source, IDiagnostics* diag); bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id, const android::ConfigDescription& config, const android::StringPiece& product, std::unique_ptr value, NameValidator name_validator, const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag); bool SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility, const ResourceId& res_id, NameValidator name_validator, IDiagnostics* diag); bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new, NameValidator name_validator, IDiagnostics* diag); bool SetOverlayableImpl(const ResourceNameRef &name, const OverlayableItem& overlayable, 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); }; } // namespace aapt #endif // AAPT_RESOURCE_TABLE_H