| /* | |
| * 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 <functional> | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <tuple> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include "Resource.h" | |
| #include "ResourceValues.h" | |
| #include "android-base/macros.h" | |
| #include "androidfw/ConfigDescription.h" | |
| #include "androidfw/IDiagnostics.h" | |
| #include "androidfw/Source.h" | |
| #include "androidfw/StringPiece.h" | |
| #include "androidfw/StringPool.h" | |
| #include "io/File.h" | |
| using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; | |
| namespace aapt { | |
| // The Public status of a resource. | |
| struct Visibility { | |
| enum class Level { | |
| kUndefined, | |
| kPrivate, | |
| kPublic, | |
| }; | |
| Level level = Level::kUndefined; | |
| android::Source source; | |
| std::string comment; | |
| // Indicates that the resource id may change across builds and that the public R.java identifier | |
| // for this resource should not be final. This is set to `true` for resources in `staging-group` | |
| // tags. | |
| bool staged_api = false; | |
| }; | |
| // Represents <add-resource> in an overlay. | |
| struct AllowNew { | |
| android::Source source; | |
| std::string comment; | |
| }; | |
| // Represents the staged resource id of a finalized resource. | |
| struct StagedId { | |
| ResourceId id; | |
| android::Source source; | |
| }; | |
| struct Overlayable { | |
| Overlayable() = default; | |
| Overlayable(android::StringPiece name, android::StringPiece actor) : name(name), actor(actor) { | |
| } | |
| Overlayable(android::StringPiece name, android::StringPiece actor, const android::Source& source) | |
| : name(name), actor(actor), source(source) { | |
| } | |
| static const char* kActorScheme; | |
| std::string name; | |
| std::string actor; | |
| android::Source source; | |
| }; | |
| // Represents a declaration that a resource is overlayable at runtime. | |
| struct OverlayableItem { | |
| explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable) | |
| : overlayable(overlayable) {} | |
| std::shared_ptr<Overlayable> overlayable; | |
| PolicyFlags policies = PolicyFlags::NONE; | |
| std::string comment; | |
| android::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> value; | |
| // Whether the value uses read/write feature flags | |
| bool uses_readwrite_feature_flags = false; | |
| ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product) | |
| : config(config), product(product) { | |
| } | |
| 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). | |
| std::optional<ResourceId> id; | |
| // Whether this resource is public (and must maintain the same entry ID across builds). | |
| Visibility visibility; | |
| std::optional<AllowNew> allow_new; | |
| // The declarations of this resource as overlayable for RROs | |
| std::optional<OverlayableItem> overlayable_item; | |
| // The staged resource id for a finalized resource. | |
| std::optional<StagedId> staged_id; | |
| // The resource's values for each configuration. | |
| std::vector<std::unique_ptr<ResourceConfigValue>> values; | |
| // The resource's values that are behind disabled flags. | |
| std::vector<std::unique_ptr<ResourceConfigValue>> flag_disabled_values; | |
| explicit ResourceEntry(android::StringPiece name) : name(name) { | |
| } | |
| ResourceConfigValue* FindValue(const android::ConfigDescription& config, | |
| android::StringPiece product = {}); | |
| const ResourceConfigValue* FindValue(const android::ConfigDescription& config, | |
| android::StringPiece product = {}) const; | |
| ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config, | |
| android::StringPiece product); | |
| std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config); | |
| // Either returns the existing ResourceConfigValue in the disabled list with the given flag, | |
| // config, and product or creates a new one and returns that. In either case the returned value | |
| // does not have the flag set on the value so it must be set by the caller. | |
| ResourceConfigValue* FindOrCreateFlagDisabledValue(const FeatureFlagAttribute& flag, | |
| const android::ConfigDescription& config, | |
| android::StringPiece product = {}); | |
| template <typename Func> | |
| std::vector<ResourceConfigValue*> FindValuesIf(Func f) { | |
| std::vector<ResourceConfigValue*> 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 ResourceNamedType named_type; | |
| // 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<std::unique_ptr<ResourceEntry>> entries; | |
| explicit ResourceTableType(const ResourceNamedTypeRef& type) | |
| : named_type(type.ToResourceNamedType()) { | |
| } | |
| ResourceEntry* CreateEntry(android::StringPiece name); | |
| ResourceEntry* FindEntry(android::StringPiece name) const; | |
| ResourceEntry* FindOrCreateEntry(android::StringPiece name); | |
| private: | |
| DISALLOW_COPY_AND_ASSIGN(ResourceTableType); | |
| }; | |
| class ResourceTablePackage { | |
| public: | |
| std::string name; | |
| std::vector<std::unique_ptr<ResourceTableType>> types; | |
| explicit ResourceTablePackage(android::StringPiece name) : name(name) { | |
| } | |
| ResourceTablePackage() = default; | |
| ResourceTableType* FindTypeWithDefaultName(const ResourceType type) const; | |
| ResourceTableType* FindType(const ResourceNamedTypeRef& type) const; | |
| ResourceTableType* FindOrCreateType(const ResourceNamedTypeRef& type); | |
| private: | |
| DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage); | |
| }; | |
| struct ResourceTableEntryView { | |
| std::string name; | |
| std::optional<uint16_t> id; | |
| Visibility visibility; | |
| std::optional<AllowNew> allow_new; | |
| std::optional<OverlayableItem> overlayable_item; | |
| std::optional<StagedId> staged_id; | |
| std::vector<const ResourceConfigValue*> values; | |
| std::vector<const ResourceConfigValue*> flag_disabled_values; | |
| const ResourceConfigValue* FindValue(const android::ConfigDescription& config, | |
| android::StringPiece product = {}) const; | |
| const ResourceConfigValue* FindFlagDisabledValue(const FeatureFlagAttribute& flag, | |
| const android::ConfigDescription& config, | |
| android::StringPiece product = {}) const; | |
| }; | |
| struct ResourceTableTypeView { | |
| ResourceNamedType named_type; | |
| std::optional<uint8_t> id; | |
| Visibility::Level visibility_level = Visibility::Level::kUndefined; | |
| // Entries sorted in ascending entry id order. If ids have not been assigned, the entries are | |
| // sorted lexicographically. | |
| std::vector<ResourceTableEntryView> entries; | |
| }; | |
| struct ResourceTablePackageView { | |
| std::string name; | |
| std::optional<uint8_t> id; | |
| // Types sorted in ascending type id order. If ids have not been assigned, the types are sorted by | |
| // their declaration order in the ResourceType enum. | |
| std::vector<ResourceTableTypeView> types; | |
| }; | |
| struct ResourceTableViewOptions { | |
| bool create_alias_entries = false; | |
| }; | |
| struct ResourceTableView { | |
| // Packages sorted in ascending package id order. If ids have not been assigned, the packages are | |
| // sorted lexicographically. | |
| std::vector<ResourceTablePackageView> packages; | |
| }; | |
| enum class OnIdConflict { | |
| // If the resource entry already exists but has a different resource id, the resource value will | |
| // not be added to the table. | |
| ERROR, | |
| // If the resource entry already exists but has a different resource id, create a new resource | |
| // with this resource name and id combination. | |
| CREATE_ENTRY, | |
| }; | |
| struct NewResource { | |
| ResourceName name; | |
| std::unique_ptr<Value> value; | |
| android::ConfigDescription config; | |
| std::string product; | |
| std::optional<std::pair<ResourceId, OnIdConflict>> id; | |
| std::optional<Visibility> visibility; | |
| std::optional<OverlayableItem> overlayable; | |
| std::optional<AllowNew> allow_new; | |
| std::optional<StagedId> staged_id; | |
| bool allow_mangled = false; | |
| bool uses_readwrite_feature_flags = false; | |
| }; | |
| struct NewResourceBuilder { | |
| explicit NewResourceBuilder(const ResourceNameRef& name); | |
| explicit NewResourceBuilder(const std::string& name); | |
| NewResourceBuilder& SetValue(std::unique_ptr<Value> value, android::ConfigDescription config = {}, | |
| std::string product = {}); | |
| NewResourceBuilder& SetId(ResourceId id, OnIdConflict on_conflict = OnIdConflict::ERROR); | |
| NewResourceBuilder& SetVisibility(Visibility id); | |
| NewResourceBuilder& SetOverlayable(OverlayableItem overlayable); | |
| NewResourceBuilder& SetAllowNew(AllowNew allow_new); | |
| NewResourceBuilder& SetStagedId(StagedId id); | |
| NewResourceBuilder& SetAllowMangled(bool allow_mangled); | |
| NewResourceBuilder& SetUsesReadWriteFeatureFlags(bool uses_feature_flags); | |
| NewResource Build(); | |
| private: | |
| NewResource res_; | |
| }; | |
| // The container and index for all resources defined for an app. | |
| class ResourceTable { | |
| public: | |
| enum class Validation { | |
| kEnabled, | |
| kDisabled, | |
| }; | |
| enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew }; | |
| ResourceTable() = default; | |
| explicit ResourceTable(Validation validation); | |
| bool AddResource(NewResource&& res, android::IDiagnostics* diag); | |
| // Retrieves a sorted a view of the packages, types, and entries sorted in ascending resource id | |
| // order. | |
| ResourceTableView GetPartitionedView(const ResourceTableViewOptions& options = {}) const; | |
| using ReferencedPackages = std::map<uint8_t, std::string>; | |
| const ReferencedPackages& GetReferencedPackages() const { | |
| return included_packages_; | |
| } | |
| struct SearchResult { | |
| ResourceTablePackage* package; | |
| ResourceTableType* type; | |
| ResourceEntry* entry; | |
| }; | |
| std::optional<SearchResult> FindResource(const ResourceNameRef& name) const; | |
| std::optional<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const; | |
| bool RemoveResource(const ResourceNameRef& name, ResourceId id) 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(android::StringPiece name) const; | |
| ResourceTablePackage* FindOrCreatePackage(android::StringPiece name); | |
| std::unique_ptr<ResourceTable> Clone() const; | |
| // When a collision of resources occurs, these methods decide which value to keep. | |
| static CollisionResult ResolveFlagCollision(FlagStatus existing, FlagStatus incoming); | |
| static CollisionResult ResolveValueCollision(Value* existing, Value* incoming); | |
| // 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. | |
| android::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<std::unique_ptr<ResourceTablePackage>> 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. | |
| ReferencedPackages included_packages_; | |
| private: | |
| DISALLOW_COPY_AND_ASSIGN(ResourceTable); | |
| Validation validation_ = Validation::kEnabled; | |
| }; | |
| } // namespace aapt | |
| #endif // AAPT_RESOURCE_TABLE_H |