Home | History | Annotate | Download | only in aapt2
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef AAPT_RESOURCE_TABLE_H
     18 #define AAPT_RESOURCE_TABLE_H
     19 
     20 #include "ConfigDescription.h"
     21 #include "Diagnostics.h"
     22 #include "Resource.h"
     23 #include "ResourceValues.h"
     24 #include "Source.h"
     25 #include "StringPool.h"
     26 #include "io/File.h"
     27 
     28 #include "android-base/macros.h"
     29 #include "androidfw/StringPiece.h"
     30 
     31 #include <functional>
     32 #include <map>
     33 #include <memory>
     34 #include <string>
     35 #include <tuple>
     36 #include <unordered_map>
     37 #include <vector>
     38 
     39 namespace aapt {
     40 
     41 // The Public status of a resource.
     42 struct Visibility {
     43   enum class Level {
     44     kUndefined,
     45     kPrivate,
     46     kPublic,
     47   };
     48 
     49   Level level = Level::kUndefined;
     50   Source source;
     51   std::string comment;
     52 };
     53 
     54 // Represents <add-resource> in an overlay.
     55 struct AllowNew {
     56   Source source;
     57   std::string comment;
     58 };
     59 
     60 // The policy dictating whether an entry is overlayable at runtime by RROs.
     61 struct Overlayable {
     62   Source source;
     63   std::string comment;
     64 };
     65 
     66 class ResourceConfigValue {
     67  public:
     68   // The configuration for which this value is defined.
     69   const ConfigDescription config;
     70 
     71   // The product for which this value is defined.
     72   const std::string product;
     73 
     74   // The actual Value.
     75   std::unique_ptr<Value> value;
     76 
     77   ResourceConfigValue(const ConfigDescription& config, const android::StringPiece& product)
     78       : config(config), product(product.to_string()) {}
     79 
     80  private:
     81   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
     82 };
     83 
     84 // Represents a resource entry, which may have varying values for each defined configuration.
     85 class ResourceEntry {
     86  public:
     87   // The name of the resource. Immutable, as this determines the order of this resource
     88   // when doing lookups.
     89   const std::string name;
     90 
     91   // The entry ID for this resource (the EEEE in 0xPPTTEEEE).
     92   Maybe<uint16_t> id;
     93 
     94   // Whether this resource is public (and must maintain the same entry ID across builds).
     95   Visibility visibility;
     96 
     97   Maybe<AllowNew> allow_new;
     98 
     99   Maybe<Overlayable> overlayable;
    100 
    101   // The resource's values for each configuration.
    102   std::vector<std::unique_ptr<ResourceConfigValue>> values;
    103 
    104   explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
    105 
    106   ResourceConfigValue* FindValue(const ConfigDescription& config);
    107 
    108   ResourceConfigValue* FindValue(const ConfigDescription& config,
    109                                  const android::StringPiece& product);
    110 
    111   ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config,
    112                                          const android::StringPiece& product);
    113   std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config);
    114 
    115   template <typename Func>
    116   std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
    117     std::vector<ResourceConfigValue*> results;
    118     for (auto& config_value : values) {
    119       if (f(config_value.get())) {
    120         results.push_back(config_value.get());
    121       }
    122     }
    123     return results;
    124   }
    125 
    126   bool HasDefaultValue() const;
    127 
    128  private:
    129   DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
    130 };
    131 
    132 // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries.
    133 class ResourceTableType {
    134  public:
    135   // The logical type of resource (string, drawable, layout, etc.).
    136   const ResourceType type;
    137 
    138   // The type ID for this resource (the TT in 0xPPTTEEEE).
    139   Maybe<uint8_t> id;
    140 
    141   // Whether this type is public (and must maintain the same type ID across builds).
    142   Visibility::Level visibility_level = Visibility::Level::kUndefined;
    143 
    144   // List of resources for this type.
    145   std::vector<std::unique_ptr<ResourceEntry>> entries;
    146 
    147   explicit ResourceTableType(const ResourceType type) : type(type) {}
    148 
    149   ResourceEntry* FindEntry(const android::StringPiece& name);
    150   ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
    151 
    152  private:
    153   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
    154 };
    155 
    156 class ResourceTablePackage {
    157  public:
    158   std::string name;
    159 
    160   // The package ID (the PP in 0xPPTTEEEE).
    161   Maybe<uint8_t> id;
    162 
    163   std::vector<std::unique_ptr<ResourceTableType>> types;
    164 
    165   ResourceTablePackage() = default;
    166   ResourceTableType* FindType(ResourceType type);
    167   ResourceTableType* FindOrCreateType(const ResourceType type);
    168 
    169  private:
    170   DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
    171 };
    172 
    173 // The container and index for all resources defined for an app.
    174 class ResourceTable {
    175  public:
    176   ResourceTable() = default;
    177 
    178   enum class CollisionResult { kKeepOriginal, kConflict, kTakeNew };
    179 
    180   using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>;
    181 
    182   // When a collision of resources occurs, this method decides which value to keep.
    183   static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
    184 
    185   bool AddResource(const ResourceNameRef& name, const ConfigDescription& config,
    186                    const android::StringPiece& product, std::unique_ptr<Value> value,
    187                    IDiagnostics* diag);
    188 
    189   bool AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
    190                          const ConfigDescription& config, const android::StringPiece& product,
    191                          std::unique_ptr<Value> value, IDiagnostics* diag);
    192 
    193   bool AddFileReference(const ResourceNameRef& name, const ConfigDescription& config,
    194                         const Source& source, const android::StringPiece& path, IDiagnostics* diag);
    195 
    196   bool AddFileReferenceMangled(const ResourceNameRef& name, const ConfigDescription& config,
    197                                const Source& source, const android::StringPiece& path,
    198                                io::IFile* file, IDiagnostics* diag);
    199 
    200   // Same as AddResource, but doesn't verify the validity of the name. This is used
    201   // when loading resources from an existing binary resource table that may have mangled names.
    202   bool AddResourceMangled(const ResourceNameRef& name, const ConfigDescription& config,
    203                           const android::StringPiece& product, std::unique_ptr<Value> value,
    204                           IDiagnostics* diag);
    205 
    206   bool AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
    207                                 const ConfigDescription& config,
    208                                 const android::StringPiece& product, std::unique_ptr<Value> value,
    209                                 IDiagnostics* diag);
    210 
    211   bool SetVisibility(const ResourceNameRef& name, const Visibility& visibility, IDiagnostics* diag);
    212   bool SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
    213                             IDiagnostics* diag);
    214   bool SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
    215                            const ResourceId& res_id, IDiagnostics* diag);
    216   bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
    217                                   const ResourceId& res_id, IDiagnostics* diag);
    218 
    219   bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
    220                       IDiagnostics* diag);
    221   bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
    222                              IDiagnostics* diag);
    223 
    224   bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
    225   bool SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new,
    226                           IDiagnostics* diag);
    227 
    228   struct SearchResult {
    229     ResourceTablePackage* package;
    230     ResourceTableType* type;
    231     ResourceEntry* entry;
    232   };
    233 
    234   Maybe<SearchResult> FindResource(const ResourceNameRef& name) const;
    235 
    236   // Returns the package struct with the given name, or nullptr if such a package does not
    237   // exist. The empty string is a valid package and typically is used to represent the
    238   // 'current' package before it is known to the ResourceTable.
    239   ResourceTablePackage* FindPackage(const android::StringPiece& name) const;
    240 
    241   ResourceTablePackage* FindPackageById(uint8_t id) const;
    242 
    243   ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {});
    244 
    245   // Attempts to find a package having the specified name and ID. If not found, a new package
    246   // of the specified parameters is created and returned.
    247   ResourceTablePackage* CreatePackageAllowingDuplicateNames(const android::StringPiece& name,
    248                                                             const Maybe<uint8_t> id);
    249 
    250   std::unique_ptr<ResourceTable> Clone() const;
    251 
    252   // The string pool used by this resource table. Values that reference strings must use
    253   // this pool to create their strings.
    254   // NOTE: `string_pool` must come before `packages` so that it is destroyed after.
    255   // When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
    256   // they decrement a refCount, which would cause invalid memory access if the pool was already
    257   // destroyed.
    258   StringPool string_pool;
    259 
    260   // The list of packages in this table, sorted alphabetically by package name and increasing
    261   // package ID (missing ID being the lowest).
    262   std::vector<std::unique_ptr<ResourceTablePackage>> packages;
    263 
    264   // Set of dynamic packages that this table may reference. Their package names get encoded
    265   // into the resources.arsc along with their compile-time assigned IDs.
    266   std::map<size_t, std::string> included_packages_;
    267 
    268  private:
    269   // The function type that validates a symbol name. Returns a non-empty StringPiece representing
    270   // the offending character (which may be more than one byte in UTF-8). Returns an empty string
    271   // if the name was valid.
    272   using NameValidator = android::StringPiece(const android::StringPiece&);
    273 
    274   ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name);
    275 
    276   bool ValidateName(NameValidator validator, const ResourceNameRef& name, const Source& source,
    277                     IDiagnostics* diag);
    278 
    279   bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
    280                        const ConfigDescription& config, const android::StringPiece& product,
    281                        std::unique_ptr<Value> value, NameValidator name_validator,
    282                        const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag);
    283 
    284   bool AddFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config,
    285                             const Source& source, const android::StringPiece& path, io::IFile* file,
    286                             NameValidator name_validator, IDiagnostics* diag);
    287 
    288   bool SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility,
    289                          const ResourceId& res_id, NameValidator name_validator,
    290                          IDiagnostics* diag);
    291 
    292   bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
    293                        NameValidator name_validator, IDiagnostics* diag);
    294 
    295   bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
    296                           NameValidator name_validator, IDiagnostics* diag);
    297 
    298   bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
    299                           const Visibility& symbol, NameValidator name_validator,
    300                           IDiagnostics* diag);
    301 
    302   DISALLOW_COPY_AND_ASSIGN(ResourceTable);
    303 };
    304 
    305 }  // namespace aapt
    306 
    307 #endif  // AAPT_RESOURCE_TABLE_H
    308