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