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