• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // The apk assets only contain the overlayable declarations information.
101   PROPERTY_ONLY_OVERLAYABLES = 1U << 5U,
102 
103   // Optimize the resource lookups by name via an in-memory lookup table.
104   PROPERTY_OPTIMIZE_NAME_LOOKUPS = 1U << 6U,
105 };
106 
107 struct OverlayableInfo {
108   std::string_view name;
109   std::string_view actor;
110   uint32_t policy_flags;
111 };
112 
113 class LoadedPackage {
114  public:
115   class iterator {
116    public:
117     iterator& operator=(const iterator& rhs) {
118       loadedPackage_ = rhs.loadedPackage_;
119       typeIndex_ = rhs.typeIndex_;
120       entryIndex_ = rhs.entryIndex_;
121       return *this;
122     }
123 
124     bool operator==(const iterator& rhs) const {
125       return loadedPackage_ == rhs.loadedPackage_ &&
126              typeIndex_ == rhs.typeIndex_ &&
127              entryIndex_ == rhs.entryIndex_;
128     }
129 
130     bool operator!=(const iterator& rhs) const {
131       return !(*this == rhs);
132     }
133 
134     iterator operator++(int) {
135       size_t prevTypeIndex_ = typeIndex_;
136       size_t prevEntryIndex_ = entryIndex_;
137       operator++();
138       return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_);
139     }
140 
141     iterator& operator++();
142 
143     uint32_t operator*() const;
144 
145    private:
146     friend class LoadedPackage;
147 
148     iterator(const LoadedPackage* lp, size_t ti, size_t ei);
149 
150     const LoadedPackage* loadedPackage_;
151     size_t typeIndex_;
152     size_t entryIndex_;
153     const size_t typeIndexEnd_;  // STL style end, so one past the last element
154   };
155 
begin()156   iterator begin() const {
157     return iterator(this, 0, 0);
158   }
159 
end()160   iterator end() const {
161     return iterator(this, resource_ids_.size() + 1, 0);
162   }
163 
164   static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
165                                                    package_property_t property_flags);
166 
167   // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
168   // the underlying ResStringPool API expects this. For now this is acceptable, but since
169   // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
170   // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
171   // for patching the correct package ID to the resource ID.
172   base::expected<uint32_t, NullOrIOError> FindEntryByName(const std::u16string& type_name,
173                                                           const std::u16string& entry_name) const;
174 
175   static base::expected<incfs::verified_map_ptr<ResTable_entry>, NullOrIOError>
176       GetEntry(incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index);
177 
178   static base::expected<uint32_t, NullOrIOError> GetEntryOffset(
179       incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index);
180 
181   static base::expected<incfs::verified_map_ptr<ResTable_entry>, NullOrIOError>
182       GetEntryFromOffset(incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset);
183 
184   // Returns the string pool where type names are stored.
GetTypeStringPool()185   const ResStringPool* GetTypeStringPool() const {
186     return &type_string_pool_;
187   }
188 
189   // Returns the string pool where the names of resource entries are stored.
GetKeyStringPool()190   const ResStringPool* GetKeyStringPool() const {
191     return &key_string_pool_;
192   }
193 
GetPackageName()194   const std::string& GetPackageName() const {
195     return package_name_;
196   }
197 
GetPackageId()198   int GetPackageId() const {
199     return package_id_;
200   }
201 
202   // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
IsDynamic()203   bool IsDynamic() const {
204     return (property_flags_ & PROPERTY_DYNAMIC) != 0;
205   }
206 
207   // Returns true if this package is a Runtime Resource Overlay.
IsOverlay()208   bool IsOverlay() const {
209     return (property_flags_ & PROPERTY_OVERLAY) != 0;
210   }
211 
212   // Returns true if this package originates from a system provided resource.
IsSystem()213   bool IsSystem() const {
214     return (property_flags_ & PROPERTY_SYSTEM) != 0;
215   }
216 
217   // Returns true if this package is a custom loader and should behave like an overlay.
IsCustomLoader()218   bool IsCustomLoader() const {
219     return (property_flags_ & PROPERTY_LOADER) != 0;
220   }
221 
GetPropertyFlags()222   package_property_t GetPropertyFlags() const {
223     return property_flags_;
224   }
225 
226   // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
227   // package could have been assigned a different package ID than what this LoadedPackage was
228   // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
GetDynamicPackageMap()229   const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
230     return dynamic_package_map_;
231   }
232 
233   // Populates a set of ResTable_config structs, possibly excluding configurations defined for
234   // the mipmap type.
235   base::expected<std::monostate, IOError> CollectConfigurations(
236       bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
237 
238   // Populates a set of strings representing locales.
239   // If `canonicalize` is set to true, each locale is transformed into its canonical format
240   // before being inserted into the set. This may cause some equivalent locales to de-dupe.
241   using Locales = std::set<std::string, std::less<>>;
242   void CollectLocales(bool canonicalize, Locales* out_locales) const;
243 
244   // type_idx is TT - 1 from 0xPPTTEEEE.
GetTypeSpecByTypeIndex(uint8_t type_index)245   inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const {
246     // If the type IDs are offset in this package, we need to take that into account when searching
247     // for a type.
248     const auto& type_spec = type_specs_.find(type_index + 1 - type_id_offset_);
249     if (type_spec == type_specs_.end()) {
250       return nullptr;
251     }
252     return &type_spec->second;
253   }
254 
255   template <typename Func>
ForEachTypeSpec(Func f)256   void ForEachTypeSpec(Func f) const {
257     for (const auto& type_spec : type_specs_) {
258       f(type_spec.second, type_spec.first);
259     }
260   }
261 
262   // Retrieves the overlayable properties of the specified resource. If the resource is not
263   // overlayable, this will return a null pointer.
GetOverlayableInfo(uint32_t resid)264   const OverlayableInfo* GetOverlayableInfo(uint32_t resid) const {
265     for (const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>& overlayable_info_ids
266         : overlayable_infos_) {
267       if (overlayable_info_ids.second.find(resid) != overlayable_info_ids.second.end()) {
268         return &overlayable_info_ids.first;
269       }
270     }
271     return nullptr;
272   }
273 
274   // Retrieves whether or not the package defines overlayable resources.
275   // TODO(123905379): Remove this when the enforcement of overlayable is turned on for all APK and
276   // not just those that defined overlayable resources.
DefinesOverlayable()277   bool DefinesOverlayable() const {
278     return defines_overlayable_;
279   }
280 
GetOverlayableMap()281   const std::unordered_map<std::string, std::string>& GetOverlayableMap() const {
282     return overlayable_map_;
283   }
284 
GetAliasResourceIdMap()285   const std::vector<std::pair<uint32_t, uint32_t>>& GetAliasResourceIdMap() const {
286     return alias_id_map_;
287   }
288 
289  private:
290   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
291 
292   explicit LoadedPackage(bool optimize_name_lookups = false)
type_string_pool_(optimize_name_lookups)293       : type_string_pool_(optimize_name_lookups), key_string_pool_(optimize_name_lookups) {
294   }
295 
296   ResStringPool type_string_pool_;
297   ResStringPool key_string_pool_;
298   std::string package_name_;
299   bool defines_overlayable_ = false;
300   int package_id_ = -1;
301   int type_id_offset_ = 0;
302   package_property_t property_flags_ = 0U;
303 
304   std::unordered_map<uint8_t, TypeSpec> type_specs_;
305   ByteBucketArray<uint32_t> resource_ids_;
306   std::vector<DynamicPackageEntry> dynamic_package_map_;
307   std::vector<std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
308   std::vector<std::pair<uint32_t, uint32_t>> alias_id_map_;
309 
310   // A map of overlayable name to actor
311   std::unordered_map<std::string, std::string> overlayable_map_;
312 };
313 
314 // Read-only view into a resource table. This class validates all data
315 // when loading, including offsets and lengths.
316 class LoadedArsc {
317  public:
318   // Load a resource table from memory pointed to by `data` of size `len`.
319   // The lifetime of `data` must out-live the LoadedArsc returned from this method.
320 
321   static std::unique_ptr<LoadedArsc> Load(incfs::map_ptr<void> data,
322                                           size_t length,
323                                           const LoadedIdmap* loaded_idmap = nullptr,
324                                           package_property_t property_flags = 0U);
325 
326   static std::unique_ptr<LoadedArsc> Load(const LoadedIdmap* loaded_idmap = nullptr);
327 
328   // Create an empty LoadedArsc. This is used when an APK has no resources.arsc.
329   static std::unique_ptr<LoadedArsc> CreateEmpty();
330 
331   // Returns the string pool where all string resource values
332   // (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
GetStringPool()333   inline const ResStringPool* GetStringPool() const {
334     return global_string_pool_.get();
335   }
336 
337   // Gets a pointer to the package with the specified package ID, or nullptr if no such package
338   // exists.
339   const LoadedPackage* GetPackageById(uint8_t package_id) const;
340 
341   // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
GetPackages()342   inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
343     return packages_;
344   }
345 
346  private:
347   DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
348 
349   LoadedArsc() = default;
350   bool LoadTable(
351       const Chunk& chunk, const LoadedIdmap* loaded_idmap, package_property_t property_flags);
352   bool LoadStringPool(const LoadedIdmap* loaded_idmap);
353 
354   std::unique_ptr<ResStringPool> global_string_pool_ = util::make_unique<ResStringPool>();
355   std::vector<std::unique_ptr<const LoadedPackage>> packages_;
356 };
357 
358 }  // namespace android
359 
360 #endif /* LOADEDARSC_H_ */
361