• 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 #ifndef IDMAP_H_
18 #define IDMAP_H_
19 
20 #include <memory>
21 #include <string>
22 #include <unordered_map>
23 #include <variant>
24 
25 #include "android-base/macros.h"
26 #include "android-base/unique_fd.h"
27 #include "androidfw/ConfigDescription.h"
28 #include "androidfw/StringPiece.h"
29 #include "androidfw/ResourceTypes.h"
30 #include "utils/ByteOrder.h"
31 
32 namespace android {
33 
34 class LoadedIdmap;
35 class IdmapResMap;
36 struct Idmap_header;
37 struct Idmap_data_header;
38 struct Idmap_target_entry;
39 struct Idmap_target_entry_inline;
40 struct Idmap_target_entry_inline_value;
41 struct Idmap_overlay_entry;
42 
43 // A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
44 // table and additionally allows for loading strings from the idmap string pool. The idmap string
45 // pool strings are offset after the end of the overlay resource table string pool entries so
46 // queries for strings defined inline in the idmap do not conflict with queries for overlay
47 // resource table strings.
48 class OverlayStringPool : public ResStringPool {
49  public:
50   virtual ~OverlayStringPool();
51   base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const override;
52   base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const override;
53   size_t size() const override;
54 
55   explicit OverlayStringPool(const LoadedIdmap* loaded_idmap);
56  private:
57     const Idmap_data_header* data_header_;
58     const ResStringPool* idmap_string_pool_;
59 };
60 
61 // A dynamic reference table for loaded overlay packages that rewrites the resource id of overlay
62 // resources to the resource id of corresponding target resources.
63 class OverlayDynamicRefTable : public DynamicRefTable {
64  public:
65   ~OverlayDynamicRefTable() override = default;
66   status_t lookupResourceId(uint32_t* resId) const override;
67 
68  private:
69   explicit OverlayDynamicRefTable(const Idmap_data_header* data_header,
70                                   const Idmap_overlay_entry* entries,
71                                   uint8_t target_assigned_package_id);
72 
73   // Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target
74   // resource.
75   status_t lookupResourceIdNoRewrite(uint32_t* resId) const;
76 
77   const Idmap_data_header* data_header_;
78   const Idmap_overlay_entry* entries_;
79   const int8_t target_assigned_package_id_;
80 
81   friend LoadedIdmap;
82   friend IdmapResMap;
83 };
84 
85 // A mapping of target resource ids to a values or resource ids that should overlay the target.
86 class IdmapResMap {
87  public:
88   // Represents the result of a idmap lookup. The result can be one of three possibilities:
89   // 1) The result is a resource id which represents the overlay resource that should act as an
90   //    alias of the target resource.
91   // 2) The result is a table entry which overlays the type and value of the target resource.
92   // 3) The result is neither and the target resource is not overlaid.
93   class Result {
94    public:
95     Result() = default;
Result(uint32_t value)96     explicit Result(uint32_t value) : data_(value) {};
Result(std::map<ConfigDescription,Res_value> value)97     explicit Result(std::map<ConfigDescription, Res_value> value) : data_(std::move(value)) {
98     }
99 
100     // Returns `true` if the resource is overlaid.
101     explicit operator bool() const {
102       return std::get_if<std::monostate>(&data_) == nullptr;
103     }
104 
IsResourceId()105     bool IsResourceId() const {
106       return std::get_if<uint32_t>(&data_) != nullptr;
107     }
108 
GetResourceId()109     uint32_t GetResourceId() const {
110       return std::get<uint32_t>(data_);
111     }
112 
IsInlineValue()113     bool IsInlineValue() const {
114       return std::get_if<2>(&data_) != nullptr;
115     }
116 
GetInlineValue()117     const std::map<ConfigDescription, Res_value>& GetInlineValue() const {
118       return std::get<2>(data_);
119     }
120 
121    private:
122       std::variant<std::monostate, uint32_t,
123           std::map<ConfigDescription, Res_value> > data_;
124   };
125 
126   // Looks up the value that overlays the target resource id.
127   Result Lookup(uint32_t target_res_id) const;
128 
GetOverlayDynamicRefTable()129   inline const OverlayDynamicRefTable* GetOverlayDynamicRefTable() const {
130     return overlay_ref_table_;
131   }
132 
133  private:
134   explicit IdmapResMap(const Idmap_data_header* data_header,
135                        const Idmap_target_entry* entries,
136                        const Idmap_target_entry_inline* inline_entries,
137                        const Idmap_target_entry_inline_value* inline_entry_values,
138                        const ConfigDescription* configs,
139                        uint8_t target_assigned_package_id,
140                        const OverlayDynamicRefTable* overlay_ref_table);
141 
142   const Idmap_data_header* data_header_;
143   const Idmap_target_entry* entries_;
144   const Idmap_target_entry_inline* inline_entries_;
145   const Idmap_target_entry_inline_value* inline_entry_values_;
146   const ConfigDescription* configurations_;
147   const uint8_t target_assigned_package_id_;
148   const OverlayDynamicRefTable* overlay_ref_table_;
149 
150   friend LoadedIdmap;
151 };
152 
153 // Represents a loaded/parsed IDMAP for a Runtime Resource Overlay (RRO).
154 // An RRO and its target APK have different resource IDs assigned to their resources.
155 // An IDMAP is a generated mapping between the resource IDs of the RRO and the target APK.
156 // A LoadedIdmap can be set alongside the overlay's LoadedArsc to allow the overlay ApkAssets to
157 // masquerade as the target ApkAssets resources.
158 class LoadedIdmap {
159  public:
160   // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
161   static std::unique_ptr<LoadedIdmap> Load(StringPiece idmap_path, StringPiece idmap_data);
162 
163   // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
OverlayApkPath()164   std::string_view OverlayApkPath() const {
165     return overlay_apk_path_;
166   }
167 
168   // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
TargetApkPath()169   std::string_view TargetApkPath() const {
170     return target_apk_path_;
171   }
172 
173   // Returns a mapping from target resource ids to overlay values.
GetTargetResourcesMap(uint8_t target_assigned_package_id,const OverlayDynamicRefTable * overlay_ref_table)174   const IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
175                                           const OverlayDynamicRefTable* overlay_ref_table) const {
176     return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_,
177                        configurations_, target_assigned_package_id, overlay_ref_table);
178   }
179 
180   // Returns a dynamic reference table for a loaded overlay package.
GetOverlayDynamicRefTable(uint8_t target_assigned_package_id)181   const OverlayDynamicRefTable GetOverlayDynamicRefTable(uint8_t target_assigned_package_id) const {
182     return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
183   }
184 
185   // Returns whether the idmap file on disk has not been modified since the construction of this
186   // LoadedIdmap.
187   bool IsUpToDate() const;
188 
189  protected:
190   // Exposed as protected so that tests can subclass and mock this class out.
191   LoadedIdmap() = default;
192 
193   const Idmap_header* header_;
194   const Idmap_data_header* data_header_;
195   const Idmap_target_entry* target_entries_;
196   const Idmap_target_entry_inline* target_inline_entries_;
197   const Idmap_target_entry_inline_value* inline_entry_values_;
198   const ConfigDescription* configurations_;
199   const Idmap_overlay_entry* overlay_entries_;
200   const std::unique_ptr<ResStringPool> string_pool_;
201 
202   android::base::unique_fd idmap_fd_;
203   std::string_view overlay_apk_path_;
204   std::string_view target_apk_path_;
205   time_t idmap_last_mod_time_;
206 
207  private:
208   DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
209 
210   explicit LoadedIdmap(const std::string& idmap_path,
211                        const Idmap_header* header,
212                        const Idmap_data_header* data_header,
213                        const Idmap_target_entry* target_entries,
214                        const Idmap_target_entry_inline* target_inline_entries,
215                        const Idmap_target_entry_inline_value* inline_entry_values_,
216                        const ConfigDescription* configs,
217                        const Idmap_overlay_entry* overlay_entries,
218                        std::unique_ptr<ResStringPool>&& string_pool,
219                        std::string_view overlay_apk_path,
220                        std::string_view target_apk_path);
221 
222   friend OverlayStringPool;
223 };
224 
225 }  // namespace android
226 
227 #endif  // IDMAP_H_
228