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