Home | History | Annotate | Download | only in androidfw
      1 /*
      2  * Copyright (C) 2016 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 LOADEDARSC_H_
     18 #define LOADEDARSC_H_
     19 
     20 #include <memory>
     21 #include <set>
     22 #include <vector>
     23 
     24 #include "android-base/macros.h"
     25 
     26 #include "androidfw/ByteBucketArray.h"
     27 #include "androidfw/Chunk.h"
     28 #include "androidfw/Idmap.h"
     29 #include "androidfw/ResourceTypes.h"
     30 #include "androidfw/Util.h"
     31 
     32 namespace android {
     33 
     34 class DynamicPackageEntry {
     35  public:
     36   DynamicPackageEntry() = default;
     37   DynamicPackageEntry(std::string&& package_name, int package_id)
     38       : package_name(std::move(package_name)), package_id(package_id) {}
     39 
     40   std::string package_name;
     41   int package_id = 0;
     42 };
     43 
     44 // TypeSpec is going to be immediately proceeded by
     45 // an array of Type structs, all in the same block of memory.
     46 struct TypeSpec {
     47   // Pointer to the mmapped data where flags are kept.
     48   // Flags denote whether the resource entry is public
     49   // and under which configurations it varies.
     50   const ResTable_typeSpec* type_spec;
     51 
     52   // Pointer to the mmapped data where the IDMAP mappings for this type
     53   // exist. May be nullptr if no IDMAP exists.
     54   const IdmapEntry_header* idmap_entries;
     55 
     56   // The number of types that follow this struct.
     57   // There is a type for each configuration that entries are defined for.
     58   size_t type_count;
     59 
     60   // Trick to easily access a variable number of Type structs
     61   // proceeding this struct, and to ensure their alignment.
     62   const ResTable_type* types[0];
     63 
     64   inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
     65     if (entry_index >= dtohl(type_spec->entryCount)) {
     66       return 0u;
     67     }
     68 
     69     const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
     70     return flags[entry_index];
     71   }
     72 };
     73 
     74 // TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
     75 // ResTable_type pointers.
     76 // TypeSpecPtr is a managed pointer that knows how to delete itself.
     77 using TypeSpecPtr = util::unique_cptr<TypeSpec>;
     78 
     79 class LoadedPackage {
     80  public:
     81   static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
     82                                                    const LoadedIdmap* loaded_idmap, bool system,
     83                                                    bool load_as_shared_library);
     84 
     85   ~LoadedPackage();
     86 
     87   // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
     88   // the underlying ResStringPool API expects this. For now this is acceptable, but since
     89   // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
     90   // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
     91   // for patching the correct package ID to the resource ID.
     92   uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
     93 
     94   static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
     95 
     96   static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
     97 
     98   static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
     99 
    100   // Returns the string pool where type names are stored.
    101   inline const ResStringPool* GetTypeStringPool() const {
    102     return &type_string_pool_;
    103   }
    104 
    105   // Returns the string pool where the names of resource entries are stored.
    106   inline const ResStringPool* GetKeyStringPool() const {
    107     return &key_string_pool_;
    108   }
    109 
    110   inline const std::string& GetPackageName() const {
    111     return package_name_;
    112   }
    113 
    114   inline int GetPackageId() const {
    115     return package_id_;
    116   }
    117 
    118   // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
    119   inline bool IsDynamic() const {
    120     return dynamic_;
    121   }
    122 
    123   // Returns true if this package originates from a system provided resource.
    124   inline bool IsSystem() const {
    125     return system_;
    126   }
    127 
    128   // Returns true if this package is from an overlay ApkAssets.
    129   inline bool IsOverlay() const {
    130     return overlay_;
    131   }
    132 
    133   // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
    134   // package could have been assigned a different package ID than what this LoadedPackage was
    135   // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
    136   inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
    137     return dynamic_package_map_;
    138   }
    139 
    140   // Populates a set of ResTable_config structs, possibly excluding configurations defined for
    141   // the mipmap type.
    142   void CollectConfigurations(bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
    143 
    144   // Populates a set of strings representing locales.
    145   // If `canonicalize` is set to true, each locale is transformed into its canonical format
    146   // before being inserted into the set. This may cause some equivalent locales to de-dupe.
    147   void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
    148 
    149   // type_idx is TT - 1 from 0xPPTTEEEE.
    150   inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const {
    151     // If the type IDs are offset in this package, we need to take that into account when searching
    152     // for a type.
    153     return type_specs_[type_index - type_id_offset_].get();
    154   }
    155 
    156   template <typename Func>
    157   void ForEachTypeSpec(Func f) const {
    158     for (size_t i = 0; i < type_specs_.size(); i++) {
    159       const TypeSpecPtr& ptr = type_specs_[i];
    160       if (ptr != nullptr) {
    161         uint8_t type_id = ptr->type_spec->id;
    162         if (ptr->idmap_entries != nullptr) {
    163           type_id = ptr->idmap_entries->target_type_id;
    164         }
    165         f(ptr.get(), type_id - 1);
    166       }
    167     }
    168   }
    169 
    170  private:
    171   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
    172 
    173   LoadedPackage();
    174 
    175   ResStringPool type_string_pool_;
    176   ResStringPool key_string_pool_;
    177   std::string package_name_;
    178   int package_id_ = -1;
    179   int type_id_offset_ = 0;
    180   bool dynamic_ = false;
    181   bool system_ = false;
    182   bool overlay_ = false;
    183 
    184   ByteBucketArray<TypeSpecPtr> type_specs_;
    185   std::vector<DynamicPackageEntry> dynamic_package_map_;
    186 };
    187 
    188 // Read-only view into a resource table. This class validates all data
    189 // when loading, including offsets and lengths.
    190 class LoadedArsc {
    191  public:
    192   // Load a resource table from memory pointed to by `data` of size `len`.
    193   // The lifetime of `data` must out-live the LoadedArsc returned from this method.
    194   // If `system` is set to true, the LoadedArsc is considered as a system provided resource.
    195   // If `load_as_shared_library` is set to true, the application package (0x7f) is treated
    196   // as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an
    197   // ID.
    198   static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data,
    199                                                 const LoadedIdmap* loaded_idmap = nullptr,
    200                                                 bool system = false,
    201                                                 bool load_as_shared_library = false);
    202 
    203   // Create an empty LoadedArsc. This is used when an APK has no resources.arsc.
    204   static std::unique_ptr<const LoadedArsc> CreateEmpty();
    205 
    206   // Returns the string pool where all string resource values
    207   // (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
    208   inline const ResStringPool* GetStringPool() const {
    209     return &global_string_pool_;
    210   }
    211 
    212   // Gets a pointer to the package with the specified package ID, or nullptr if no such package
    213   // exists.
    214   const LoadedPackage* GetPackageById(uint8_t package_id) const;
    215 
    216   // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
    217   inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
    218     return packages_;
    219   }
    220 
    221   // Returns true if this is a system provided resource.
    222   inline bool IsSystem() const {
    223     return system_;
    224   }
    225 
    226  private:
    227   DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
    228 
    229   LoadedArsc() = default;
    230   bool LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library);
    231 
    232   ResStringPool global_string_pool_;
    233   std::vector<std::unique_ptr<const LoadedPackage>> packages_;
    234   bool system_ = false;
    235 };
    236 
    237 }  // namespace android
    238 
    239 #endif /* LOADEDARSC_H_ */
    240