AssetManager2.h revision da431a22da38f9c4085b5d71ed9a9c6122c6a5a6
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 ANDROIDFW_ASSETMANAGER2_H_ 18#define ANDROIDFW_ASSETMANAGER2_H_ 19 20#include "android-base/macros.h" 21 22#include <array> 23#include <limits> 24#include <unordered_map> 25 26#include "androidfw/ApkAssets.h" 27#include "androidfw/Asset.h" 28#include "androidfw/AssetManager.h" 29#include "androidfw/ResourceTypes.h" 30#include "androidfw/Util.h" 31 32namespace android { 33 34class Theme; 35 36using ApkAssetsCookie = int32_t; 37 38enum : ApkAssetsCookie { 39 kInvalidCookie = -1, 40}; 41 42// Holds a bag that has been merged with its parent, if one exists. 43struct ResolvedBag { 44 // A single key-value entry in a bag. 45 struct Entry { 46 // The key, as described in ResTable_map::name. 47 uint32_t key; 48 49 Res_value value; 50 51 // Which ApkAssets this entry came from. 52 ApkAssetsCookie cookie; 53 54 ResStringPool* key_pool; 55 ResStringPool* type_pool; 56 }; 57 58 // Denotes the configuration axis that this bag varies with. 59 // If a configuration changes with respect to one of these axis, 60 // the bag should be reloaded. 61 uint32_t type_spec_flags; 62 63 // The number of entries in this bag. Access them by indexing into `entries`. 64 uint32_t entry_count; 65 66 // The array of entries for this bag. An empty array is a neat trick to force alignment 67 // of the Entry structs that follow this structure and avoids a bunch of casts. 68 Entry entries[0]; 69}; 70 71// AssetManager2 is the main entry point for accessing assets and resources. 72// AssetManager2 provides caching of resources retrieved via the underlying 73// ApkAssets. 74class AssetManager2 : public ::AAssetManager { 75 public: 76 struct ResourceName { 77 const char* package = nullptr; 78 size_t package_len = 0u; 79 80 const char* type = nullptr; 81 const char16_t* type16 = nullptr; 82 size_t type_len = 0u; 83 84 const char* entry = nullptr; 85 const char16_t* entry16 = nullptr; 86 size_t entry_len = 0u; 87 }; 88 89 AssetManager2(); 90 91 // Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets 92 // are not owned by the AssetManager, and must have a longer lifetime. 93 // 94 // Only pass invalidate_caches=false when it is known that the structure 95 // change in ApkAssets is due to a safe addition of resources with completely 96 // new resource IDs. 97 bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true); 98 99 inline const std::vector<const ApkAssets*> GetApkAssets() const { return apk_assets_; } 100 101 // Returns the string pool for the given asset cookie. 102 // Use the string pool returned here with a valid Res_value object of 103 // type Res_value::TYPE_STRING. 104 const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const; 105 106 // Returns the DynamicRefTable for the given package ID. 107 const DynamicRefTable* GetDynamicRefTableForPackage(uint32_t package_id) const; 108 109 // Sets/resets the configuration for this AssetManager. This will cause all 110 // caches that are related to the configuration change to be invalidated. 111 void SetConfiguration(const ResTable_config& configuration); 112 113 inline const ResTable_config& GetConfiguration() const { return configuration_; } 114 115 // Searches the set of APKs loaded by this AssetManager and opens the first one found located 116 // in the assets/ directory. 117 // `mode` controls how the file is opened. 118 // 119 // NOTE: The loaded APKs are searched in reverse order. 120 std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode); 121 122 // Opens a file within the assets/ directory of the APK specified by `cookie`. 123 // `mode` controls how the file is opened. 124 std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie, 125 Asset::AccessMode mode); 126 127 // Searches the set of APKs loaded by this AssetManager and opens the first one found. 128 // `mode` controls how the file is opened. 129 // `out_cookie` is populated with the cookie of the APK this file was found in. 130 // 131 // NOTE: The loaded APKs are searched in reverse order. 132 std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode, 133 ApkAssetsCookie* out_cookie = nullptr); 134 135 // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened. 136 // This is typically used to open a specific AndroidManifest.xml, or a binary XML file 137 // referenced by a resource lookup with GetResource(). 138 std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie, 139 Asset::AccessMode mode); 140 141 // Populates the `out_name` parameter with resource name information. 142 // Utf8 strings are preferred, and only if they are unavailable are 143 // the Utf16 variants populated. 144 // Returns false if the resource was not found or the name was missing/corrupt. 145 bool GetResourceName(uint32_t resid, ResourceName* out_name); 146 147 // Populates `out_flags` with the bitmask of configuration axis that this resource varies with. 148 // See ResTable_config for the list of configuration axis. 149 // Returns false if the resource was not found. 150 bool GetResourceFlags(uint32_t resid, uint32_t* out_flags); 151 152 // Retrieves the best matching resource with ID `resid`. The resource value is filled into 153 // `out_value` and the configuration for the selected value is populated in `out_selected_config`. 154 // `out_flags` holds the same flags as retrieved with GetResourceFlags(). 155 // If `density_override` is non-zero, the configuration to match against is overridden with that 156 // density. 157 // 158 // Returns a valid cookie if the resource was found. If the resource was not found, or if the 159 // resource was a map/bag type, then kInvalidCookie is returned. If `may_be_bag` is false, 160 // this function logs if the resource was a map/bag type before returning kInvalidCookie. 161 ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override, 162 Res_value* out_value, ResTable_config* out_selected_config, 163 uint32_t* out_flags); 164 165 // Retrieves the best matching bag/map resource with ID `resid`. 166 // This method will resolve all parent references for this bag and merge keys with the child. 167 // To iterate over the keys, use the following idiom: 168 // 169 // const AssetManager2::ResolvedBag* bag = asset_manager->GetBag(id); 170 // if (bag != nullptr) { 171 // for (auto iter = begin(bag); iter != end(bag); ++iter) { 172 // ... 173 // } 174 // } 175 const ResolvedBag* GetBag(uint32_t resid); 176 177 // Creates a new Theme from this AssetManager. 178 std::unique_ptr<Theme> NewTheme(); 179 180 void DumpToLog() const; 181 182 private: 183 DISALLOW_COPY_AND_ASSIGN(AssetManager2); 184 185 // Finds the best entry for `resid` amongst all the ApkAssets. The entry can be a simple 186 // Res_value, or a complex map/bag type. 187 // 188 // `density_override` overrides the density of the current configuration when doing a search. 189 // 190 // When `stop_at_first_match` is true, the first match found is selected and the search 191 // terminates. This is useful for methods that just look up the name of a resource and don't 192 // care about the value. In this case, the value of `out_flags` is incomplete and should not 193 // be used. 194 // 195 // `out_flags` stores the resulting bitmask of configuration axis with which the resource 196 // value varies. 197 ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match, 198 LoadedArscEntry* out_entry, ResTable_config* out_selected_config, 199 uint32_t* out_flags); 200 201 // Assigns package IDs to all shared library ApkAssets. 202 // Should be called whenever the ApkAssets are changed. 203 void BuildDynamicRefTable(); 204 205 // Purge all resources that are cached and vary by the configuration axis denoted by the 206 // bitmask `diff`. 207 void InvalidateCaches(uint32_t diff); 208 209 // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must 210 // have a longer lifetime. 211 std::vector<const ApkAssets*> apk_assets_; 212 213 struct PackageGroup { 214 std::vector<const LoadedPackage*> packages_; 215 std::vector<ApkAssetsCookie> cookies_; 216 DynamicRefTable dynamic_ref_table; 217 }; 218 219 // DynamicRefTables for shared library package resolution. 220 // These are ordered according to apk_assets_. The mappings may change depending on what is 221 // in apk_assets_, therefore they must be stored in the AssetManager and not in the 222 // immutable ApkAssets class. 223 std::vector<PackageGroup> package_groups_; 224 225 // An array mapping package ID to index into package_groups. This keeps the lookup fast 226 // without taking too much memory. 227 std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_; 228 229 // The current configuration set for this AssetManager. When this changes, cached resources 230 // may need to be purged. 231 ResTable_config configuration_; 232 233 // Cached set of bags. These are cached because they can inherit keys from parent bags, 234 // which involves some calculation. 235 std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_; 236}; 237 238class Theme { 239 friend class AssetManager2; 240 241 public: 242 // Applies the style identified by `resid` to this theme. This can be called 243 // multiple times with different styles. By default, any theme attributes that 244 // are already defined before this call are not overridden. If `force` is set 245 // to true, this behavior is changed and all theme attributes from the style at 246 // `resid` are applied. 247 // Returns false if the style failed to apply. 248 bool ApplyStyle(uint32_t resid, bool force = false); 249 250 // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme. 251 // Returns false if the AssetManagers of the Themes were not compatible. 252 bool SetTo(const Theme& o); 253 254 void Clear(); 255 256 inline const AssetManager2* GetAssetManager() const { return asset_manager_; } 257 258 // Returns a bit mask of configuration changes that will impact this 259 // theme (and thus require completely reloading it). 260 inline uint32_t GetChangingConfigurations() const { return type_spec_flags_; } 261 262 // Retrieve a value in the theme. If the theme defines this value, 263 // returns an asset cookie indicating which ApkAssets it came from 264 // and populates `out_value` with the value. If `out_flags` is non-null, 265 // populates it with a bitmask of the configuration axis the resource 266 // varies with. 267 // 268 // If the attribute is not found, returns kInvalidCookie. 269 // 270 // NOTE: This function does not do reference traversal. If you want 271 // to follow references to other resources to get the "real" value to 272 // use, you need to call ResolveReference() after this function. 273 ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value, 274 uint32_t* out_flags = nullptr) const; 275 276 // This is like AssetManager2::ResolveReference(), but also takes 277 // care of resolving attribute references to the theme. 278 ApkAssetsCookie ResolveAttributeReference(Res_value* in_out_value, ApkAssetsCookie src_cookie, 279 uint32_t* out_last_ref = nullptr, 280 uint32_t* in_out_type_spec_flags = nullptr, 281 ResTable_config* out_selected_config = nullptr) const; 282 283 private: 284 DISALLOW_COPY_AND_ASSIGN(Theme); 285 286 // Called by AssetManager2. 287 explicit inline Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {} 288 289 struct Entry { 290 ApkAssetsCookie cookie; 291 uint32_t type_spec_flags; 292 Res_value value; 293 }; 294 295 struct Type { 296 // Use uint32_t for fewer cycles when loading from memory. 297 uint32_t entry_count; 298 uint32_t entry_capacity; 299 Entry entries[0]; 300 }; 301 302 static constexpr const size_t kPackageCount = std::numeric_limits<uint8_t>::max() + 1; 303 static constexpr const size_t kTypeCount = std::numeric_limits<uint8_t>::max() + 1; 304 305 struct Package { 306 // Each element of Type will be a dynamically sized object 307 // allocated to have the entries stored contiguously with the Type. 308 std::array<util::unique_cptr<Type>, kTypeCount> types; 309 }; 310 311 AssetManager2* asset_manager_; 312 uint32_t type_spec_flags_ = 0u; 313 std::array<std::unique_ptr<Package>, kPackageCount> packages_; 314}; 315 316inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) { return bag->entries; } 317 318inline const ResolvedBag::Entry* end(const ResolvedBag* bag) { 319 return bag->entries + bag->entry_count; 320} 321 322} // namespace android 323 324#endif /* ANDROIDFW_ASSETMANAGER2_H_ */ 325