1 /*
2 * Copyright (C) 2018 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 /*
18 * # idmap file format (current version)
19 *
20 * idmap := header data*
21 * header := magic version target_crc overlay_crc fulfilled_policies
22 * enforce_overlayable target_path overlay_path overlay_name
23 * debug_info
24 * data := data_header target_entries target_inline_entries
25 target_inline_entry_value* config* overlay_entries string_pool
26 * data_header := target_entry_count target_inline_entry_count
27 target_inline_entry_value_count config_count overlay_entry_count
28 * string_pool_index
29 * target_entries := target_id* overlay_id*
30 * target_inline_entries := target_id* target_inline_value_header*
31 * target_inline_value_header := start_value_index value_count
32 * target_inline_entry_value := config_index Res_value::size padding(1) Res_value::type
33 * Res_value::value
34 * config := target_id Res_value::size padding(1) Res_value::type
35 * Res_value::value
36 * overlay_entries := overlay_id* target_id*
37 *
38 * debug_info := string
39 * enforce_overlayable := <uint32_t>
40 * fulfilled_policies := <uint32_t>
41 * magic := <uint32_t>
42 * overlay_crc := <uint32_t>
43 * overlay_entry_count := <uint32_t>
44 * overlay_id := <uint32_t>
45 * overlay_package_id := <uint8_t>
46 * overlay_name := string
47 * overlay_path := string
48 * padding(n) := <uint8_t>[n]
49 * Res_value::size := <uint16_t>
50 * Res_value::type := <uint8_t>
51 * Res_value::value := <uint32_t>
52 * string := <uint32_t> <uint8_t>+ padding(n)
53 * string_pool := string
54 * string_pool_index := <uint32_t>
55 * string_pool_length := <uint32_t>
56 * target_crc := <uint32_t>
57 * target_entry_count := <uint32_t>
58 * target_inline_entry_count := <uint32_t>
59 * target_inline_entry_value_count := <uint32_t>
60 * config_count := <uint32_t>
61 * config_index := <uint32_t>
62 * start_value_index := <uint32_t>
63 * value_count := <uint32_t>
64 * target_id := <uint32_t>
65 * target_package_id := <uint8_t>
66 * target_path := string
67 * value_type := <uint8_t>
68 * value_data := <uint32_t>
69 * version := <uint32_t>
70 */
71
72 #ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
73 #define IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
74
75 #include <istream>
76 #include <memory>
77 #include <string>
78 #include <string_view>
79 #include <vector>
80
81 #include "android-base/macros.h"
82 #include "androidfw/ResourceTypes.h"
83 #include "androidfw/StringPiece.h"
84 #include "androidfw/ConfigDescription.h"
85 #include "idmap2/ResourceContainer.h"
86 #include "idmap2/ResourceMapping.h"
87
88 namespace android::idmap2 {
89
90 class Idmap;
91 class Visitor;
92
93 // magic number: all idmap files start with this
94 static constexpr const uint32_t kIdmapMagic = android::kIdmapMagic;
95
96 // current version of the idmap binary format; must be incremented when the format is changed
97 static constexpr const uint32_t kIdmapCurrentVersion = android::kIdmapCurrentVersion;
98
99 class IdmapHeader {
100 public:
101 static std::unique_ptr<const IdmapHeader> FromBinaryStream(std::istream& stream);
102
GetMagic()103 inline uint32_t GetMagic() const {
104 return magic_;
105 }
106
GetVersion()107 inline uint32_t GetVersion() const {
108 return version_;
109 }
110
GetTargetCrc()111 inline uint32_t GetTargetCrc() const {
112 return target_crc_;
113 }
114
GetOverlayCrc()115 inline uint32_t GetOverlayCrc() const {
116 return overlay_crc_;
117 }
118
GetFulfilledPolicies()119 inline uint32_t GetFulfilledPolicies() const {
120 return fulfilled_policies_;
121 }
122
GetEnforceOverlayable()123 bool GetEnforceOverlayable() const {
124 return enforce_overlayable_;
125 }
126
GetTargetPath()127 const std::string& GetTargetPath() const {
128 return target_path_;
129 }
130
GetOverlayPath()131 const std::string& GetOverlayPath() const {
132 return overlay_path_;
133 }
134
GetOverlayName()135 const std::string& GetOverlayName() const {
136 return overlay_name_;
137 }
138
GetDebugInfo()139 const std::string& GetDebugInfo() const {
140 return debug_info_;
141 }
142
143 // Invariant: anytime the idmap data encoding is changed, the idmap version
144 // field *must* be incremented. Because of this, we know that if the idmap
145 // header is up-to-date the entire file is up-to-date.
146 Result<Unit> IsUpToDate(const TargetResourceContainer& target,
147 const OverlayResourceContainer& overlay, const std::string& overlay_name,
148 PolicyBitmask fulfilled_policies, bool enforce_overlayable) const;
149
150 Result<Unit> IsUpToDate(const std::string& target_path, const std::string& overlay_path,
151 const std::string& overlay_name, uint32_t target_crc,
152 uint32_t overlay_crc, PolicyBitmask fulfilled_policies,
153 bool enforce_overlayable) const;
154
155 void accept(Visitor* v) const;
156
157 private:
158 IdmapHeader() = default;
159
160 uint32_t magic_;
161 uint32_t version_;
162 uint32_t target_crc_;
163 uint32_t overlay_crc_;
164 uint32_t fulfilled_policies_;
165 bool enforce_overlayable_;
166 std::string target_path_;
167 std::string overlay_path_;
168 std::string overlay_name_;
169 std::string debug_info_;
170
171 friend Idmap;
172 DISALLOW_COPY_AND_ASSIGN(IdmapHeader);
173 };
174 class IdmapData {
175 public:
176 class Header {
177 public:
178 static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream);
179
GetTargetEntryCount()180 [[nodiscard]] inline uint32_t GetTargetEntryCount() const {
181 return target_entry_count;
182 }
183
GetTargetInlineEntryCount()184 [[nodiscard]] inline uint32_t GetTargetInlineEntryCount() const {
185 return target_entry_inline_count;
186 }
187
GetTargetInlineEntryValueCount()188 [[nodiscard]] inline uint32_t GetTargetInlineEntryValueCount() const {
189 return target_entry_inline_value_count;
190 }
191
GetConfigCount()192 [[nodiscard]] inline uint32_t GetConfigCount() const {
193 return config_count;
194 }
195
GetOverlayEntryCount()196 [[nodiscard]] inline uint32_t GetOverlayEntryCount() const {
197 return overlay_entry_count;
198 }
199
GetStringPoolIndexOffset()200 [[nodiscard]] inline uint32_t GetStringPoolIndexOffset() const {
201 return string_pool_index_offset;
202 }
203
204 void accept(Visitor* v) const;
205
206 private:
207 uint32_t target_entry_count;
208 uint32_t target_entry_inline_count;
209 uint32_t target_entry_inline_value_count;
210 uint32_t config_count;
211 uint32_t overlay_entry_count;
212 uint32_t string_pool_index_offset;
213 Header() = default;
214
215 friend Idmap;
216 friend IdmapData;
217 DISALLOW_COPY_AND_ASSIGN(Header);
218 };
219
220 struct TargetEntry {
221 ResourceId target_id;
222 ResourceId overlay_id;
223 };
224
225 struct TargetInlineEntry {
226 ResourceId target_id;
227 std::map<ConfigDescription, TargetValue> values;
228 };
229
230 struct OverlayEntry {
231 ResourceId overlay_id;
232 ResourceId target_id;
233 };
234
235 static std::unique_ptr<const IdmapData> FromBinaryStream(std::istream& stream);
236
237 static Result<std::unique_ptr<const IdmapData>> FromResourceMapping(
238 const ResourceMapping& resource_mapping);
239
GetHeader()240 const std::unique_ptr<const Header>& GetHeader() const {
241 return header_;
242 }
243
GetTargetEntries()244 const std::vector<TargetEntry>& GetTargetEntries() const {
245 return target_entries_;
246 }
247
GetTargetInlineEntries()248 const std::vector<TargetInlineEntry>& GetTargetInlineEntries() const {
249 return target_inline_entries_;
250 }
251
GetOverlayEntries()252 [[nodiscard]] const std::vector<OverlayEntry>& GetOverlayEntries() const {
253 return overlay_entries_;
254 }
255
GetStringPoolData()256 [[nodiscard]] const std::string& GetStringPoolData() const {
257 return string_pool_data_;
258 }
259
260 void accept(Visitor* v) const;
261
262 private:
263 IdmapData() = default;
264
265 std::unique_ptr<const Header> header_;
266 std::vector<TargetEntry> target_entries_;
267 std::vector<TargetInlineEntry> target_inline_entries_;
268 std::vector<OverlayEntry> overlay_entries_;
269 std::string string_pool_data_;
270
271 friend Idmap;
272 DISALLOW_COPY_AND_ASSIGN(IdmapData);
273 };
274
275 class Idmap {
276 public:
277 static std::string CanonicalIdmapPathFor(std::string_view absolute_dir,
278 std::string_view absolute_apk_path);
279
280 static Result<std::unique_ptr<const Idmap>> FromBinaryStream(std::istream& stream);
281
282 // In the current version of idmap, the first package in each resources.arsc
283 // file is used; change this in the next version of idmap to use a named
284 // package instead; also update FromApkAssets to take additional parameters:
285 // the target and overlay package names
286 static Result<std::unique_ptr<const Idmap>> FromContainers(
287 const TargetResourceContainer& target, const OverlayResourceContainer& overlay,
288 const std::string& overlay_name, const PolicyBitmask& fulfilled_policies,
289 bool enforce_overlayable);
290
GetHeader()291 const std::unique_ptr<const IdmapHeader>& GetHeader() const {
292 return header_;
293 }
294
GetData()295 const std::vector<std::unique_ptr<const IdmapData>>& GetData() const {
296 return data_;
297 }
298
299 void accept(Visitor* v) const;
300
301 private:
302 Idmap() = default;
303
304 std::unique_ptr<const IdmapHeader> header_;
305 std::vector<std::unique_ptr<const IdmapData>> data_;
306
307 DISALLOW_COPY_AND_ASSIGN(Idmap);
308 };
309
310 class Visitor {
311 public:
312 virtual ~Visitor() = default;
313 virtual void visit(const Idmap& idmap) = 0;
314 virtual void visit(const IdmapHeader& header) = 0;
315 virtual void visit(const IdmapData& data) = 0;
316 virtual void visit(const IdmapData::Header& header) = 0;
317 };
318
CalculatePadding(size_t data_length)319 inline size_t CalculatePadding(size_t data_length) {
320 return (4 - (data_length % 4)) % 4;
321 }
322
323 } // namespace android::idmap2
324
325 #endif // IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
326