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