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; DynamicPackageEntry(std::string && package_name,int package_id)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 GetFlagsForEntryIndexTypeSpec64 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. GetTypeStringPool()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. GetKeyStringPool()106 inline const ResStringPool* GetKeyStringPool() const { 107 return &key_string_pool_; 108 } 109 GetPackageName()110 inline const std::string& GetPackageName() const { 111 return package_name_; 112 } 113 GetPackageId()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. IsDynamic()119 inline bool IsDynamic() const { 120 return dynamic_; 121 } 122 123 // Returns true if this package originates from a system provided resource. IsSystem()124 inline bool IsSystem() const { 125 return system_; 126 } 127 128 // Returns true if this package is from an overlay ApkAssets. IsOverlay()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. GetDynamicPackageMap()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. GetTypeSpecByTypeIndex(uint8_t type_index)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> ForEachTypeSpec(Func f)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. GetStringPool()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. GetPackages()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. IsSystem()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