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