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