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 <utils/RefBase.h>
21 
22 #include <array>
23 #include <limits>
24 #include <set>
25 #include <span>
26 #include <unordered_map>
27 
28 #include "android-base/function_ref.h"
29 #include "android-base/macros.h"
30 #include "androidfw/ApkAssets.h"
31 #include "androidfw/Asset.h"
32 #include "androidfw/AssetManager.h"
33 #include "androidfw/ResourceTypes.h"
34 #include "androidfw/Util.h"
35 
36 namespace android {
37 
38 class Theme;
39 
40 using ApkAssetsCookie = int32_t;
41 
42 enum : ApkAssetsCookie {
43   kInvalidCookie = -1,
44 };
45 
46 // Holds a bag that has been merged with its parent, if one exists.
47 struct ResolvedBag {
48   // A single key-value entry in a bag.
49   struct Entry {
50     // The key, as described in ResTable_map::name.
51     uint32_t key;
52 
53     Res_value value;
54 
55     // The resource ID of the origin style associated with the given entry.
56     uint32_t style;
57 
58     // Which ApkAssets this entry came from.
59     ApkAssetsCookie cookie;
60 
61     ResStringPool* key_pool;
62     ResStringPool* type_pool;
63   };
64 
65   // Denotes the configuration axis that this bag varies with.
66   // If a configuration changes with respect to one of these axis,
67   // the bag should be reloaded.
68   uint32_t type_spec_flags;
69 
70   // The number of entries in this bag. Access them by indexing into `entries`.
71   uint32_t entry_count;
72 
73   // The array of entries for this bag. An empty array is a neat trick to force alignment
74   // of the Entry structs that follow this structure and avoids a bunch of casts.
75   Entry entries[0];
76 };
77 
78 struct FindEntryResult;
79 
80 // AssetManager2 is the main entry point for accessing assets and resources.
81 // AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
82 class AssetManager2 {
83   friend Theme;
84 
85  public:
86   struct ResourceName {
87     const char* package = nullptr;
88     size_t package_len = 0u;
89 
90     const char* type = nullptr;
91     const char16_t* type16 = nullptr;
92     size_t type_len = 0u;
93 
94     const char* entry = nullptr;
95     const char16_t* entry16 = nullptr;
96     size_t entry_len = 0u;
97   };
98 
99   using ApkAssetsPtr = sp<const ApkAssets>;
100   using ApkAssetsWPtr = wp<const ApkAssets>;
101   using ApkAssetsList = std::span<const ApkAssetsPtr>;
102 
103   AssetManager2();
104   explicit AssetManager2(AssetManager2&& other) = default;
105   AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration);
106 
107   struct ScopedOperation {
108     DISALLOW_COPY_AND_ASSIGN(ScopedOperation);
109     friend AssetManager2;
110     const AssetManager2& am_;
111     ScopedOperation(const AssetManager2& am);
112 
113    public:
114     ~ScopedOperation();
115   };
116 
117   [[nodiscard]] ScopedOperation StartOperation() const;
118 
119   // Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets
120   // are not owned by the AssetManager, and must have a longer lifetime.
121   //
122   // Only pass invalidate_caches=false when it is known that the structure
123   // change in ApkAssets is due to a safe addition of resources with completely
124   // new resource IDs.
125   bool SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches = true);
126   bool SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets, bool invalidate_caches = true);
127   // This one is an optimization - it skips all calculations for applying the currently set
128   // configuration, expecting a configuration update later with a forced refresh.
129   void PresetApkAssets(ApkAssetsList apk_assets);
130 
131   const ApkAssetsPtr& GetApkAssets(ApkAssetsCookie cookie) const;
GetApkAssetsCount()132   int GetApkAssetsCount() const {
133     return int(apk_assets_.size());
134   }
135 
136   // Returns the string pool for the given asset cookie.
137   // Use the string pool returned here with a valid Res_value object of type Res_value::TYPE_STRING.
138   const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const;
139 
140   // Returns the DynamicRefTable for the given package ID.
141   // This may be nullptr if the APK represented by `cookie` has no resource table.
142   const DynamicRefTable* GetDynamicRefTableForPackage(uint32_t package_id) const;
143 
144   // Returns the DynamicRefTable for the ApkAssets represented by the cookie.
145   // This may be nullptr if the APK represented by `cookie` has no resource table.
146   std::shared_ptr<const DynamicRefTable> GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const;
147 
148   // Retrieve the assigned package id of the package if loaded into this AssetManager
149   uint8_t GetAssignedPackageId(const LoadedPackage* package) const;
150 
151   // Returns a string representation of the overlayable API of a package.
152   bool GetOverlayablesToString(android::StringPiece package_name, std::string* out) const;
153 
154   const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage(
155       uint32_t package_id) const;
156 
157   // Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped).
158   bool ContainsAllocatedTable() const;
159 
160   // Sets/resets the configuration for this AssetManager. This will cause all
161   // caches that are related to the configuration change to be invalidated.
162   void SetConfigurations(std::vector<ResTable_config> configurations, bool force_refresh = false);
163 
GetConfigurations()164   inline const std::vector<ResTable_config>& GetConfigurations() const {
165     return configurations_;
166   }
167 
SetDefaultLocale(uint32_t default_locale)168   inline void SetDefaultLocale(uint32_t default_locale) {
169     default_locale_ = default_locale;
170   }
171 
172   // Returns all configurations for which there are resources defined, or an I/O error if reading
173   // resource data failed.
174   //
175   // This includes resource configurations in all the ApkAssets set for this AssetManager.
176   // If `exclude_system` is set to true, resource configurations from system APKs
177   // ('android' package, other libraries) will be excluded from the list.
178   // If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
179   // will be excluded from the list.
180   base::expected<std::set<ResTable_config>, IOError> GetResourceConfigurations(
181       bool exclude_system = false, bool exclude_mipmap = false) const;
182 
183   // Returns all the locales for which there are resources defined. This includes resource
184   // locales in all the ApkAssets set for this AssetManager.
185   // If `exclude_system` is set to true, resource locales from system APKs
186   // ('android' package, other libraries) will be excluded from the list.
187   // If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
188   // and de-duped in the resulting list.
189   std::set<std::string> GetResourceLocales(bool exclude_system = false,
190                                            bool merge_equivalent_languages = false) const;
191 
192   // Searches the set of APKs loaded by this AssetManager and opens the first one found located
193   // in the assets/ directory.
194   // `mode` controls how the file is opened.
195   //
196   // NOTE: The loaded APKs are searched in reverse order.
197   std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode) const;
198 
199   // Opens a file within the assets/ directory of the APK specified by `cookie`.
200   // `mode` controls how the file is opened.
201   std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
202                               Asset::AccessMode mode) const;
203 
204   // Opens the directory specified by `dirname`. The result is an AssetDir that is the combination
205   // of all directories matching `dirname` under the assets/ directory of every ApkAssets loaded.
206   // The entries are sorted by their ASCII name.
207   std::unique_ptr<AssetDir> OpenDir(const std::string& dirname) const;
208 
209   // Searches the set of APKs loaded by this AssetManager and opens the first one found.
210   // `mode` controls how the file is opened.
211   // `out_cookie` is populated with the cookie of the APK this file was found in.
212   //
213   // NOTE: The loaded APKs are searched in reverse order.
214   std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
215                                       ApkAssetsCookie* out_cookie = nullptr) const;
216 
217   // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
218   // This is typically used to open a specific AndroidManifest.xml, or a binary XML file
219   // referenced by a resource lookup with GetResource().
220   std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
221                                       Asset::AccessMode mode) const;
222 
223   // Returns the resource id of parent style of the specified theme.
224   //
225   // Returns a null error if the name is missing/corrupt, or an I/O error if reading resource data
226   // failed.
227   base::expected<uint32_t, NullOrIOError> GetParentThemeResourceId(uint32_t resid) const;
228 
229   // Returns the resource name of the specified resource ID.
230   //
231   // Utf8 strings are preferred, and only if they are unavailable are the Utf16 variants populated.
232   //
233   // Returns a null error if the name is missing/corrupt, or an I/O error if reading resource data
234   // failed.
235   base::expected<ResourceName, NullOrIOError> GetResourceName(uint32_t resid) const;
236 
237   // Finds the resource ID assigned to `resource_name`.
238   //
239   // `resource_name` must be of the form '[package:][type/]entry'.
240   // If no package is specified in `resource_name`, then `fallback_package` is used as the package.
241   // If no type is specified in `resource_name`, then `fallback_type` is used as the type.
242   //
243   // Returns a null error if no resource by that name was found, or an I/O error if reading resource
244   // data failed.
245   base::expected<uint32_t, NullOrIOError> GetResourceId(
246       const std::string& resource_name, const std::string& fallback_type = {},
247       const std::string& fallback_package = {}) const;
248 
249   struct SelectedValue {
250     friend AssetManager2;
251     friend Theme;
252     SelectedValue() = default;
SelectedValueSelectedValue253     SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry)
254         : cookie(entry.cookie),
255           data(entry.value.data),
256           type(entry.value.dataType),
257           flags(bag->type_spec_flags),
258           resid(0U),
259           config() {
260     }
261 
262     // The cookie representing the ApkAssets in which the value resides.
263     ApkAssetsCookie cookie = kInvalidCookie;
264 
265     // The data for this value, as interpreted according to `type`.
266     Res_value::data_type data;
267 
268     // Type of the data value.
269     uint8_t type;
270 
271     // The bitmask of configuration axis that this resource varies with.
272     // See ResTable_config::CONFIG_*.
273     uint32_t flags;
274 
275     // The resource ID from which this value was resolved.
276     uint32_t resid;
277 
278     // The configuration for which the resolved value was defined.
279     ResTable_config config;
280 
281    private:
SelectedValueSelectedValue282     SelectedValue(uint8_t value_type, Res_value::data_type value_data, ApkAssetsCookie cookie,
283                   uint32_t type_flags, uint32_t resid, const ResTable_config& config) :
284                   cookie(cookie), data(value_data), type(value_type), flags(type_flags),
285                   resid(resid), config(config) {};
286   };
287 
288   // Retrieves the best matching resource value with ID `resid`.
289   //
290   // If `may_be_bag` is false, this function logs if the resource was a map/bag type and returns a
291   // null result. If `density_override` is non-zero, the configuration to match against is
292   // overridden with that density.
293   //
294   // Returns a null error if a best match could not be found, or an I/O error if reading resource
295   // data failed.
296   base::expected<SelectedValue, NullOrIOError> GetResource(uint32_t resid, bool may_be_bag = false,
297                                                            uint16_t density_override = 0U) const;
298 
299   // Resolves the resource referenced in `value` if the type is Res_value::TYPE_REFERENCE.
300   //
301   // If the data type is not Res_value::TYPE_REFERENCE, no work is done. Configuration flags of the
302   // values pointed to by the reference are OR'd into `value.flags`. If `cache_value` is true, then
303   // the resolved value will be cached and used when attempting to resolve the resource id specified
304   // in `value`.
305   //
306   // Returns a null error if the resource could not be resolved, or an I/O error if reading
307   // resource data failed.
308   base::expected<std::monostate, NullOrIOError> ResolveReference(SelectedValue& value,
309                                                                  bool cache_value = false) const;
310 
311   // Retrieves the best matching bag/map resource with ID `resid`.
312   //
313   // This method will resolve all parent references for this bag and merge keys with the child.
314   // To iterate over the keys, use the following idiom:
315   //
316   //  base::expected<const ResolvedBag*, NullOrIOError> bag = asset_manager->GetBag(id);
317   //  if (bag.has_value()) {
318   //    for (auto iter = begin(*bag); iter != end(*bag); ++iter) {
319   //      ...
320   //    }
321   //  }
322   //
323   // Returns a null error if a best match could not be found, or an I/O error if reading resource
324   // data failed.
325   base::expected<const ResolvedBag*, NullOrIOError> GetBag(uint32_t resid) const;
326 
327   // Retrieves the best matching bag/map resource of the resource referenced in `value`.
328   //
329   // If `value.type` is not Res_value::TYPE_REFERENCE, a null result is returned.
330   // Configuration flags of the bag pointed to by the reference are OR'd into `value.flags`.
331   //
332   // Returns a null error if a best match could not be found, or an I/O error if reading resource
333   // data failed.
334   base::expected<const ResolvedBag*, NullOrIOError> ResolveBag(SelectedValue& value) const;
335 
336   // Returns the android::ResTable_typeSpec flags of the resource ID.
337   //
338   // Returns a null error if the resource could not be resolved, or an I/O error if reading
339   // resource data failed.
340   base::expected<uint32_t, NullOrIOError> GetResourceTypeSpecFlags(uint32_t resid) const;
341 
342   base::expected<const std::vector<uint32_t>*, NullOrIOError> GetBagResIdStack(
343       uint32_t resid) const;
344 
345   // Resets the resource resolution structures in preparation for the next resource retrieval.
346   void ResetResourceResolution() const;
347 
348   // Enables or disables resource resolution logging. Clears stored steps when disabled.
349   void SetResourceResolutionLoggingEnabled(bool enabled);
350 
351   // Returns formatted log of last resource resolution path, or empty if no resource has been
352   // resolved yet.
353   std::string GetLastResourceResolution() const;
354 
355   // Creates a new Theme from this AssetManager.
356   std::unique_ptr<Theme> NewTheme();
357 
358   void ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
359                       package_property_t excluded_property_flags = 0U) const;
360 
361   void DumpToLog() const;
362 
363  private:
364   DISALLOW_COPY_AND_ASSIGN(AssetManager2);
365 
366   // A collection of configurations and their associated ResTable_type that match the current
367   // AssetManager configuration.
368   struct FilteredConfigGroup {
369       std::vector<const TypeSpec::TypeEntry*> type_entries;
370   };
371 
372   // Represents an single package.
373   struct ConfiguredPackage {
374       // A pointer to the immutable, loaded package info.
375       const LoadedPackage* loaded_package_;
376 
377       // A mutable AssetManager-specific list of configurations that match the AssetManager's
378       // current configuration. This is used as an optimization to avoid checking every single
379       // candidate configuration when looking up resources.
380       ByteBucketArray<FilteredConfigGroup> filtered_configs_;
381   };
382 
383   // Represents a Runtime Resource Overlay that overlays resources in the logical package.
384   struct ConfiguredOverlay {
385       // The set of package groups that overlay this package group.
386       IdmapResMap overlay_res_maps_;
387 
388       // The cookie of the overlay assets.
389       ApkAssetsCookie cookie;
390   };
391 
392   // Represents a logical package, which can be made up of many individual packages. Each package
393   // in a PackageGroup shares the same package name and package ID.
394   struct PackageGroup {
395       // The set of packages that make-up this group.
396       std::vector<ConfiguredPackage> packages_;
397 
398       // The cookies associated with each package in the group. They share the same order as
399       // packages_.
400       std::vector<ApkAssetsCookie> cookies_;
401 
402       // Runtime Resource Overlays that overlay resources in this package group.
403       std::vector<ConfiguredOverlay> overlays_;
404 
405       // A library reference table that contains build-package ID to runtime-package ID mappings.
406       std::shared_ptr<DynamicRefTable> dynamic_ref_table = std::make_shared<DynamicRefTable>();
407   };
408 
409   // Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
410   // Res_value, or a complex map/bag type. Returns a null result if a best entry cannot be found.
411   //
412   // `density_override` overrides the density of the current configuration when doing a search.
413   //
414   // When `stop_at_first_match` is true, the first match found is selected and the search
415   // terminates. This is useful for methods that just look up the name of a resource and don't
416   // care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
417   // and should not be used.
418   //
419   // When `ignore_configuration` is true, FindEntry will return always select the first entry in
420   // for the type seen regardless of its configuration.
421   //
422   // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
423   // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
424   base::expected<FindEntryResult, NullOrIOError> FindEntry(uint32_t resid,
425                                                            uint16_t density_override,
426                                                            bool stop_at_first_match,
427                                                            bool ignore_configuration) const;
428 
429   base::expected<FindEntryResult, NullOrIOError> FindEntryInternal(
430       const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx,
431       const ResTable_config& desired_config, bool stop_at_first_match,
432       bool ignore_configuration) const;
433 
434   // Assigns package IDs to all shared library ApkAssets.
435   // Should be called whenever the ApkAssets are changed.
436   void BuildDynamicRefTable(ApkAssetsList assets);
437 
438   // Purge all resources that are cached and vary by the configuration axis denoted by the
439   // bitmask `diff`.
440   void InvalidateCaches(uint32_t diff);
441 
442   // Triggers the re-construction of lists of types that match the set configuration.
443   // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
444   void RebuildFilterList();
445 
446   // Retrieves the APK paths of overlays that overlay non-system packages.
447   std::set<ApkAssetsPtr> GetNonSystemOverlays() const;
448 
449   // AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
450   // been seen while traversing bag parents.
451   base::expected<const ResolvedBag*, NullOrIOError> GetBag(
452       uint32_t resid, std::vector<uint32_t>& child_resids) const;
453 
454   // Finish an operation that was running with the current asset manager, and clean up the
455   // promoted apk assets when the last operation ends.
456   void FinishOperation() const;
457 
458   // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
459   // have a longer lifetime.
460   // The second pair element is the promoted version of the assets, that is held for the duration
461   // of the currently running operation. FinishOperation() clears all promoted assets to make sure
462   // they can be released when the system needs that.
463   mutable std::vector<std::pair<ApkAssetsWPtr, ApkAssetsPtr>> apk_assets_;
464 
465   // DynamicRefTables for shared library package resolution.
466   // These are ordered according to apk_assets_. The mappings may change depending on what is
467   // in apk_assets_, therefore they must be stored in the AssetManager and not in the
468   // immutable ApkAssets class.
469   std::vector<PackageGroup> package_groups_;
470 
471   // An array mapping package ID to index into package_groups. This keeps the lookup fast
472   // without taking too much memory.
473   std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_;
474 
475   uint32_t default_locale_;
476 
477   // The current configurations set for this AssetManager. When this changes, cached resources
478   // may need to be purged.
479   std::vector<ResTable_config> configurations_;
480 
481   // Cached set of bags. These are cached because they can inherit keys from parent bags,
482   // which involves some calculation.
483   mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
484 
485   // Cached set of bag resid stacks for each bag. These are cached because they might be requested
486   // a number of times for each view during View inspection.
487   mutable std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
488 
489   // Cached set of resolved resource values.
490   mutable std::unordered_map<uint32_t, SelectedValue> cached_resolved_values_;
491 
492   // Tracking the number of the started operations running with the current AssetManager.
493   // Finishing the last one clears all promoted apk assets.
494   mutable int number_of_running_scoped_operations_ = 0;
495 
496   // Whether or not to save resource resolution steps
497   bool resource_resolution_logging_enabled_ = false;
498 
499   struct Resolution {
500     struct Step {
501       enum class Type {
502         INITIAL,
503         BETTER_MATCH,
504         OVERLAID,
505         OVERLAID_INLINE,
506         SKIPPED,
507         NO_ENTRY,
508       };
509 
510       // Marks what kind of override this step was.
511       Type type;
512 
513       ApkAssetsCookie cookie = kInvalidCookie;
514 
515       // Built name of configuration for this step.
516       String8 config_name;
517     };
518 
519     // Last resolved resource ID.
520     uint32_t resid;
521 
522     // Last resolved resource result cookie.
523     ApkAssetsCookie cookie = kInvalidCookie;
524 
525     // Last resolved resource type.
526     StringPoolRef type_string_ref;
527 
528     // Last resolved resource entry.
529     StringPoolRef entry_string_ref;
530 
531     // Steps taken to resolve last resource.
532     std::vector<Step> steps;
533 
534     // The configuration name of the best resource found.
535     String8 best_config_name;
536 
537     // The package name of the best resource found.
538     String8 best_package_name;
539   };
540 
541   // Record of the last resolved resource's resolution path.
542   mutable Resolution last_resolution_;
543 };
544 
545 class Theme {
546   friend class AssetManager2;
547 
548  public:
549   ~Theme();
550 
551   // Applies the style identified by `resid` to this theme.
552   //
553   // This can be called multiple times with different styles. By default, any theme attributes that
554   // are already defined before this call are not overridden. If `force` is set to true, this
555   // behavior is changed and all theme attributes from the style at `resid` are applied.
556   //
557   // Returns a null error if the style could not be applied, or an I/O error if reading resource
558   // data failed.
559   base::expected<std::monostate, NullOrIOError> ApplyStyle(uint32_t resid, bool force = false);
560 
561   // Clears the existing theme, sets the new asset manager to use for this theme, and applies the
562   // styles in `style_ids` through repeated invocations of `ApplyStyle`.
563   void Rebase(AssetManager2* am, const uint32_t* style_ids, const uint8_t* force,
564               size_t style_count);
565 
566   // Sets this Theme to be a copy of `source` if `source` has the same AssetManager as this Theme.
567   //
568   // If `source` does not have the same AssetManager as this theme, only attributes from ApkAssets
569   // loaded into both AssetManagers will be copied to this theme.
570   //
571   // Returns an I/O error if reading resource data failed.
572   base::expected<std::monostate, IOError> SetTo(const Theme& source);
573 
574   void Clear();
575 
576   // Retrieves the value of attribute ID `resid` in the theme.
577   //
578   // NOTE: This function does not do reference traversal. If you want to follow references to other
579   // resources to get the "real" value to use, you need to call ResolveReference() after this
580   // function.
581   std::optional<AssetManager2::SelectedValue> GetAttribute(uint32_t resid) const;
582 
583   // This is like AssetManager2::ResolveReference(), but also takes care of resolving attribute
584   // references to the theme.
585   base::expected<std::monostate, NullOrIOError> ResolveAttributeReference(
586       AssetManager2::SelectedValue& value) const;
587 
GetAssetManager()588   AssetManager2* GetAssetManager() {
589     return asset_manager_;
590   }
591 
GetAssetManager()592   const AssetManager2* GetAssetManager() const {
593     return asset_manager_;
594   }
595 
596   // Returns a bit mask of configuration changes that will impact this
597   // theme (and thus require completely reloading it).
GetChangingConfigurations()598   uint32_t GetChangingConfigurations() const {
599     return type_spec_flags_;
600   }
601 
602   void Dump() const;
603 
604   struct Entry;
605  private:
606   DISALLOW_COPY_AND_ASSIGN(Theme);
607 
608   explicit Theme(AssetManager2* asset_manager);
609 
610   AssetManager2* asset_manager_ = nullptr;
611   uint32_t type_spec_flags_ = 0u;
612 
613   std::vector<uint32_t> keys_;
614   std::vector<Entry> entries_;
615 };
616 
begin(const ResolvedBag * bag)617 inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) {
618   return bag->entries;
619 }
620 
end(const ResolvedBag * bag)621 inline const ResolvedBag::Entry* end(const ResolvedBag* bag) {
622   return bag->entries + bag->entry_count;
623 }
624 
625 }  // namespace android
626 
627 #endif /* ANDROIDFW_ASSETMANAGER2_H_ */
628