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