• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #pragma once
18 
19 #include <memory>
20 #include <string>
21 #include <unordered_map>
22 #include <variant>
23 
24 #include "android-base/macros.h"
25 #include "android-base/unique_fd.h"
26 #include "androidfw/ConfigDescription.h"
27 #include "androidfw/ResourceTypes.h"
28 #include "androidfw/StringPiece.h"
29 #include "androidfw/misc.h"
30 #include "utils/ByteOrder.h"
31 
32 namespace android {
33 
34 // An enum that tracks more states than just 'up to date' or 'not' for a resources container:
35 // there are several cases where we know for sure that the object can't change and won't get
36 // out of date. Reporting those states to the managed layer allows it to stop checking here
37 // completely, speeding up the cache lookups by dozens of milliseconds.
38 enum class UpToDate : int { False, True, Always };
39 
40 // Combines two UpToDate values, and only accesses the second one if it matters to the result.
41 template <class Getter>
combine(UpToDate first,Getter secondGetter)42 UpToDate combine(UpToDate first, Getter secondGetter) {
43   switch (first) {
44     case UpToDate::False:
45       return UpToDate::False;
46     case UpToDate::True: {
47       const auto second = secondGetter();
48       return second == UpToDate::False ? UpToDate::False : UpToDate::True;
49     }
50     case UpToDate::Always:
51       return secondGetter();
52   }
53 }
54 
fromBool(bool value)55 inline UpToDate fromBool(bool value) {
56   return value ? UpToDate::True : UpToDate::False;
57 }
58 
59 class LoadedIdmap;
60 class IdmapResMap;
61 struct Idmap_header;
62 struct Idmap_constraints;
63 struct Idmap_data_header;
64 struct Idmap_target_entry_inline;
65 struct Idmap_target_entry_inline_value;
66 
67 // LINT.IfChange
68 constexpr int32_t kOverlayConstraintTypeDisplayId = 0;
69 constexpr int32_t kOverlayConstraintTypeDeviceId = 1;
70 // LINT.ThenChange(../../../../core/java/android/content/om/OverlayConstraint.java)
71 
72 struct Idmap_constraint {
73   // Constraint type can be kOverlayConstraintTypeDisplayId or kOverlayConstraintTypeDeviceId
74   const uint32_t constraint_type;
75   const uint32_t constraint_value;
76 };
77 struct Idmap_constraints {
78   const uint32_t constraint_count = 0;
79   const Idmap_constraint* constraint_entries = nullptr;
80 };
81 struct Idmap_target_entries {
82   const uint32_t* target_id = nullptr;
83   const uint32_t* overlay_id = nullptr;
84 };
85 struct Idmap_target_inline_entries {
86   const uint32_t* target_id = nullptr;
87   const Idmap_target_entry_inline* entry = nullptr;
88 };
89 struct Idmap_overlay_entries {
90   const uint32_t* overlay_id = nullptr;
91   const uint32_t* target_id = nullptr;
92 };
93 
94 // A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
95 // table and additionally allows for loading strings from the idmap string pool. The idmap string
96 // pool strings are offset after the end of the overlay resource table string pool entries so
97 // queries for strings defined inline in the idmap do not conflict with queries for overlay
98 // resource table strings.
99 class OverlayStringPool : public ResStringPool {
100  public:
101   virtual ~OverlayStringPool();
102   base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const override;
103   base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const override;
104   size_t size() const override;
105 
106   explicit OverlayStringPool(const LoadedIdmap* loaded_idmap);
107  private:
108     const Idmap_data_header* data_header_;
109     const ResStringPool* idmap_string_pool_;
110 };
111 
112 // A dynamic reference table for loaded overlay packages that rewrites the resource id of overlay
113 // resources to the resource id of corresponding target resources.
114 class OverlayDynamicRefTable : public DynamicRefTable {
115  public:
116   ~OverlayDynamicRefTable() override = default;
117   status_t lookupResourceId(uint32_t* resId) const override;
118 
119  private:
120   explicit OverlayDynamicRefTable(const Idmap_data_header* data_header,
121                                   Idmap_overlay_entries entries,
122                                   uint8_t target_assigned_package_id);
123 
124   // Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target
125   // resource.
126   status_t lookupResourceIdNoRewrite(uint32_t* resId) const;
127 
128   const Idmap_data_header* data_header_;
129   Idmap_overlay_entries entries_;
130   uint8_t target_assigned_package_id_;
131 
132   friend LoadedIdmap;
133   friend IdmapResMap;
134 };
135 
136 // A mapping of target resource ids to a values or resource ids that should overlay the target.
137 class IdmapResMap {
138  public:
139   // Represents the result of a idmap lookup. The result can be one of three possibilities:
140   // 1) The result is a resource id which represents the overlay resource that should act as an
141   //    alias of the target resource.
142   // 2) The result is a table entry which overlays the type and value of the target resource.
143   // 3) The result is neither and the target resource is not overlaid.
144   class Result {
145    public:
146     Result() = default;
Result(uint32_t value)147     explicit Result(uint32_t value) : data_(value) {};
Result(std::map<ConfigDescription,Res_value> value)148     explicit Result(std::map<ConfigDescription, Res_value> value) : data_(std::move(value)) {
149     }
150 
151     // Returns `true` if the resource is overlaid.
152     explicit operator bool() const {
153       return std::get_if<std::monostate>(&data_) == nullptr;
154     }
155 
IsResourceId()156     bool IsResourceId() const {
157       return std::get_if<uint32_t>(&data_) != nullptr;
158     }
159 
GetResourceId()160     uint32_t GetResourceId() const {
161       return std::get<uint32_t>(data_);
162     }
163 
IsInlineValue()164     bool IsInlineValue() const {
165       return std::get_if<2>(&data_) != nullptr;
166     }
167 
GetInlineValue()168     const std::map<ConfigDescription, Res_value>& GetInlineValue() const {
169       return std::get<2>(data_);
170     }
171 
172    private:
173       std::variant<std::monostate, uint32_t,
174           std::map<ConfigDescription, Res_value> > data_;
175   };
176 
177   // Looks up the value that overlays the target resource id.
178   Result Lookup(uint32_t target_res_id) const;
179 
GetOverlayDynamicRefTable()180   inline const OverlayDynamicRefTable* GetOverlayDynamicRefTable() const {
181     return overlay_ref_table_;
182   }
183 
GetConstraints()184   inline Idmap_constraints GetConstraints() const {
185     return constraints_;
186   }
187 
188  private:
189   explicit IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints,
190                        Idmap_target_entries entries, Idmap_target_inline_entries inline_entries,
191                        const Idmap_target_entry_inline_value* inline_entry_values,
192                        const ConfigDescription* configs, uint8_t target_assigned_package_id,
193                        const OverlayDynamicRefTable* overlay_ref_table);
194 
195   const Idmap_data_header* data_header_;
196   Idmap_constraints constraints_;
197   Idmap_target_entries entries_;
198   Idmap_target_inline_entries inline_entries_;
199   const Idmap_target_entry_inline_value* inline_entry_values_;
200   const ConfigDescription* configurations_;
201   const uint8_t target_assigned_package_id_;
202   const OverlayDynamicRefTable* overlay_ref_table_;
203 
204   friend LoadedIdmap;
205 };
206 
207 // Represents a loaded/parsed IDMAP for a Runtime Resource Overlay (RRO).
208 // An RRO and its target APK have different resource IDs assigned to their resources.
209 // An IDMAP is a generated mapping between the resource IDs of the RRO and the target APK.
210 // A LoadedIdmap can be set alongside the overlay's LoadedArsc to allow the overlay ApkAssets to
211 // masquerade as the target ApkAssets resources.
212 class LoadedIdmap {
213  public:
214   // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
215   static std::unique_ptr<LoadedIdmap> Load(StringPiece idmap_path, StringPiece idmap_data);
216 
217   // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
OverlayApkPath()218   std::string_view OverlayApkPath() const {
219     return overlay_apk_path_;
220   }
221 
222   // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
TargetApkPath()223   std::string_view TargetApkPath() const {
224     return target_apk_path_;
225   }
226 
227   // Returns a mapping from target resource ids to overlay values.
GetTargetResourcesMap(uint8_t target_assigned_package_id,const OverlayDynamicRefTable * overlay_ref_table)228   IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
229                                     const OverlayDynamicRefTable* overlay_ref_table) const {
230     return IdmapResMap(data_header_, constraints_, target_entries_, target_inline_entries_,
231                        inline_entry_values_, configurations_, target_assigned_package_id,
232                        overlay_ref_table);
233   }
234 
235   // Returns a dynamic reference table for a loaded overlay package.
GetOverlayDynamicRefTable(uint8_t target_assigned_package_id)236   OverlayDynamicRefTable GetOverlayDynamicRefTable(uint8_t target_assigned_package_id) const {
237     return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
238   }
239 
240   // Returns whether the idmap file on disk has not been modified since the construction of this
241   // LoadedIdmap.
242   UpToDate IsUpToDate() const;
243 
GetConstraints()244   inline const Idmap_constraints GetConstraints() const {
245     return constraints_;
246   }
247 
248  protected:
249   // Exposed as protected so that tests can subclass and mock this class out.
250   LoadedIdmap() = default;
251 
252   const Idmap_header* header_;
253   const Idmap_data_header* data_header_;
254   Idmap_constraints constraints_;
255   Idmap_target_entries target_entries_;
256   Idmap_target_inline_entries target_inline_entries_;
257   const Idmap_target_entry_inline_value* inline_entry_values_;
258   const ConfigDescription* configurations_;
259   const Idmap_overlay_entries overlay_entries_;
260   const std::unique_ptr<ResStringPool> string_pool_;
261 
262   android::base::unique_fd idmap_fd_;
263   std::string_view overlay_apk_path_;
264   std::string_view target_apk_path_;
265   ModDate idmap_last_mod_time_;
266 
267  private:
268   DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
269 
270   explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
271                        const Idmap_data_header* data_header, const Idmap_constraints& constraints,
272                        Idmap_target_entries target_entries,
273                        Idmap_target_inline_entries target_inline_entries,
274                        const Idmap_target_entry_inline_value* inline_entry_values_,
275                        const ConfigDescription* configs, Idmap_overlay_entries overlay_entries,
276                        std::unique_ptr<ResStringPool>&& string_pool,
277                        std::string_view overlay_apk_path, std::string_view target_apk_path);
278 
279   friend OverlayStringPool;
280 };
281 
282 }  // namespace android
283