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 #include <unordered_map> 24 #include <unordered_set> 25 26 #include "android-base/macros.h" 27 28 #include "androidfw/ByteBucketArray.h" 29 #include "androidfw/Chunk.h" 30 #include "androidfw/Idmap.h" 31 #include "androidfw/ResourceTypes.h" 32 #include "androidfw/Util.h" 33 34 namespace android { 35 36 class DynamicPackageEntry { 37 public: 38 DynamicPackageEntry() = default; DynamicPackageEntry(std::string && package_name,int package_id)39 DynamicPackageEntry(std::string&& package_name, int package_id) 40 : package_name(std::move(package_name)), package_id(package_id) {} 41 42 std::string package_name; 43 int package_id = 0; 44 }; 45 46 // TypeSpec is going to be immediately proceeded by 47 // an array of Type structs, all in the same block of memory. 48 struct TypeSpec { 49 // Pointer to the mmapped data where flags are kept. 50 // Flags denote whether the resource entry is public 51 // and under which configurations it varies. 52 const ResTable_typeSpec* type_spec; 53 54 // Pointer to the mmapped data where the IDMAP mappings for this type 55 // exist. May be nullptr if no IDMAP exists. 56 const IdmapEntry_header* idmap_entries; 57 58 // The number of types that follow this struct. 59 // There is a type for each configuration that entries are defined for. 60 size_t type_count; 61 62 // Trick to easily access a variable number of Type structs 63 // proceeding this struct, and to ensure their alignment. 64 const ResTable_type* types[0]; 65 GetFlagsForEntryIndexTypeSpec66 inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const { 67 if (entry_index >= dtohl(type_spec->entryCount)) { 68 return 0u; 69 } 70 71 const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1); 72 return flags[entry_index]; 73 } 74 }; 75 76 // TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of 77 // ResTable_type pointers. 78 // TypeSpecPtr is a managed pointer that knows how to delete itself. 79 using TypeSpecPtr = util::unique_cptr<TypeSpec>; 80 81 struct OverlayableInfo { 82 std::string name; 83 std::string actor; 84 uint32_t policy_flags; 85 }; 86 87 class LoadedPackage { 88 public: 89 class iterator { 90 public: 91 iterator& operator=(const iterator& rhs) { 92 loadedPackage_ = rhs.loadedPackage_; 93 typeIndex_ = rhs.typeIndex_; 94 entryIndex_ = rhs.entryIndex_; 95 return *this; 96 } 97 98 bool operator==(const iterator& rhs) const { 99 return loadedPackage_ == rhs.loadedPackage_ && 100 typeIndex_ == rhs.typeIndex_ && 101 entryIndex_ == rhs.entryIndex_; 102 } 103 104 bool operator!=(const iterator& rhs) const { 105 return !(*this == rhs); 106 } 107 108 iterator operator++(int) { 109 size_t prevTypeIndex_ = typeIndex_; 110 size_t prevEntryIndex_ = entryIndex_; 111 operator++(); 112 return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_); 113 } 114 115 iterator& operator++(); 116 117 uint32_t operator*() const; 118 119 private: 120 friend class LoadedPackage; 121 122 iterator(const LoadedPackage* lp, size_t ti, size_t ei); 123 124 const LoadedPackage* loadedPackage_; 125 size_t typeIndex_; 126 size_t entryIndex_; 127 const size_t typeIndexEnd_; // STL style end, so one past the last element 128 }; 129 begin()130 iterator begin() const { 131 return iterator(this, 0, 0); 132 } 133 end()134 iterator end() const { 135 return iterator(this, resource_ids_.size() + 1, 0); 136 } 137 138 static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk, 139 const LoadedIdmap* loaded_idmap, bool system, 140 bool load_as_shared_library); 141 142 ~LoadedPackage(); 143 144 // Finds the entry with the specified type name and entry name. The names are in UTF-16 because 145 // the underlying ResStringPool API expects this. For now this is acceptable, but since 146 // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change. 147 // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible 148 // for patching the correct package ID to the resource ID. 149 uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const; 150 151 static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index); 152 153 static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index); 154 155 static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset); 156 157 // Returns the string pool where type names are stored. GetTypeStringPool()158 inline const ResStringPool* GetTypeStringPool() const { 159 return &type_string_pool_; 160 } 161 162 // Returns the string pool where the names of resource entries are stored. GetKeyStringPool()163 inline const ResStringPool* GetKeyStringPool() const { 164 return &key_string_pool_; 165 } 166 GetPackageName()167 inline const std::string& GetPackageName() const { 168 return package_name_; 169 } 170 GetPackageId()171 inline int GetPackageId() const { 172 return package_id_; 173 } 174 175 // Returns true if this package is dynamic (shared library) and needs to have an ID assigned. IsDynamic()176 inline bool IsDynamic() const { 177 return dynamic_; 178 } 179 180 // Returns true if this package originates from a system provided resource. IsSystem()181 inline bool IsSystem() const { 182 return system_; 183 } 184 185 // Returns true if this package is from an overlay ApkAssets. IsOverlay()186 inline bool IsOverlay() const { 187 return overlay_; 188 } 189 190 // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a 191 // package could have been assigned a different package ID than what this LoadedPackage was 192 // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime. GetDynamicPackageMap()193 inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const { 194 return dynamic_package_map_; 195 } 196 197 // Populates a set of ResTable_config structs, possibly excluding configurations defined for 198 // the mipmap type. 199 void CollectConfigurations(bool exclude_mipmap, std::set<ResTable_config>* out_configs) const; 200 201 // Populates a set of strings representing locales. 202 // If `canonicalize` is set to true, each locale is transformed into its canonical format 203 // before being inserted into the set. This may cause some equivalent locales to de-dupe. 204 void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const; 205 206 // type_idx is TT - 1 from 0xPPTTEEEE. GetTypeSpecByTypeIndex(uint8_t type_index)207 inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const { 208 // If the type IDs are offset in this package, we need to take that into account when searching 209 // for a type. 210 return type_specs_[type_index - type_id_offset_].get(); 211 } 212 213 template <typename Func> ForEachTypeSpec(Func f)214 void ForEachTypeSpec(Func f) const { 215 for (size_t i = 0; i < type_specs_.size(); i++) { 216 const TypeSpecPtr& ptr = type_specs_[i]; 217 if (ptr != nullptr) { 218 uint8_t type_id = ptr->type_spec->id; 219 if (ptr->idmap_entries != nullptr) { 220 type_id = ptr->idmap_entries->target_type_id; 221 } 222 f(ptr.get(), type_id - 1); 223 } 224 } 225 } 226 227 // Retrieves the overlayable properties of the specified resource. If the resource is not 228 // overlayable, this will return a null pointer. GetOverlayableInfo(uint32_t resid)229 const OverlayableInfo* GetOverlayableInfo(uint32_t resid) const { 230 for (const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>& overlayable_info_ids 231 : overlayable_infos_) { 232 if (overlayable_info_ids.second.find(resid) != overlayable_info_ids.second.end()) { 233 return &overlayable_info_ids.first; 234 } 235 } 236 return nullptr; 237 } 238 239 // Retrieves whether or not the package defines overlayable resources. 240 // TODO(123905379): Remove this when the enforcement of overlayable is turned on for all APK and 241 // not just those that defined overlayable resources. DefinesOverlayable()242 bool DefinesOverlayable() const { 243 return defines_overlayable_; 244 } 245 GetOverlayableMap()246 const std::unordered_map<std::string, std::string>& GetOverlayableMap() const { 247 return overlayable_map_; 248 } 249 250 private: 251 DISALLOW_COPY_AND_ASSIGN(LoadedPackage); 252 253 LoadedPackage(); 254 255 ResStringPool type_string_pool_; 256 ResStringPool key_string_pool_; 257 std::string package_name_; 258 int package_id_ = -1; 259 int type_id_offset_ = 0; 260 bool dynamic_ = false; 261 bool system_ = false; 262 bool overlay_ = false; 263 bool defines_overlayable_ = false; 264 265 ByteBucketArray<TypeSpecPtr> type_specs_; 266 ByteBucketArray<uint32_t> resource_ids_; 267 std::vector<DynamicPackageEntry> dynamic_package_map_; 268 std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_; 269 std::unordered_map<std::string, std::string> overlayable_map_; 270 }; 271 272 // Read-only view into a resource table. This class validates all data 273 // when loading, including offsets and lengths. 274 class LoadedArsc { 275 public: 276 // Load a resource table from memory pointed to by `data` of size `len`. 277 // The lifetime of `data` must out-live the LoadedArsc returned from this method. 278 // If `system` is set to true, the LoadedArsc is considered as a system provided resource. 279 // If `load_as_shared_library` is set to true, the application package (0x7f) is treated 280 // as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an 281 // ID. 282 static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data, 283 const LoadedIdmap* loaded_idmap = nullptr, 284 bool system = false, 285 bool load_as_shared_library = false); 286 287 // Create an empty LoadedArsc. This is used when an APK has no resources.arsc. 288 static std::unique_ptr<const LoadedArsc> CreateEmpty(); 289 290 // Returns the string pool where all string resource values 291 // (Res_value::dataType == Res_value::TYPE_STRING) are indexed. GetStringPool()292 inline const ResStringPool* GetStringPool() const { 293 return &global_string_pool_; 294 } 295 296 // Gets a pointer to the package with the specified package ID, or nullptr if no such package 297 // exists. 298 const LoadedPackage* GetPackageById(uint8_t package_id) const; 299 300 // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc. GetPackages()301 inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const { 302 return packages_; 303 } 304 305 // Returns true if this is a system provided resource. IsSystem()306 inline bool IsSystem() const { 307 return system_; 308 } 309 310 private: 311 DISALLOW_COPY_AND_ASSIGN(LoadedArsc); 312 313 LoadedArsc() = default; 314 bool LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library); 315 316 ResStringPool global_string_pool_; 317 std::vector<std::unique_ptr<const LoadedPackage>> packages_; 318 bool system_ = false; 319 }; 320 321 } // namespace android 322 323 #endif /* LOADEDARSC_H_ */ 324