1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_RESOURCES
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include "androidfw/Idmap.h"
20*d57664e9SAndroid Build Coastguard Worker
21*d57664e9SAndroid Build Coastguard Worker #include "android-base/file.h"
22*d57664e9SAndroid Build Coastguard Worker #include "android-base/logging.h"
23*d57664e9SAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
24*d57664e9SAndroid Build Coastguard Worker #include "android-base/utf8.h"
25*d57664e9SAndroid Build Coastguard Worker #include "androidfw/misc.h"
26*d57664e9SAndroid Build Coastguard Worker #include "androidfw/ResourceTypes.h"
27*d57664e9SAndroid Build Coastguard Worker #include "androidfw/Util.h"
28*d57664e9SAndroid Build Coastguard Worker #include "utils/ByteOrder.h"
29*d57664e9SAndroid Build Coastguard Worker #include "utils/Trace.h"
30*d57664e9SAndroid Build Coastguard Worker
31*d57664e9SAndroid Build Coastguard Worker #ifdef _WIN32
32*d57664e9SAndroid Build Coastguard Worker #ifdef ERROR
33*d57664e9SAndroid Build Coastguard Worker #undef ERROR
34*d57664e9SAndroid Build Coastguard Worker #endif
35*d57664e9SAndroid Build Coastguard Worker #endif
36*d57664e9SAndroid Build Coastguard Worker
37*d57664e9SAndroid Build Coastguard Worker using ::android::base::StringPrintf;
38*d57664e9SAndroid Build Coastguard Worker
39*d57664e9SAndroid Build Coastguard Worker namespace android {
40*d57664e9SAndroid Build Coastguard Worker
41*d57664e9SAndroid Build Coastguard Worker // See frameworks/base/cmds/idmap2/include/idmap2/Idmap.h for full idmap file format specification.
42*d57664e9SAndroid Build Coastguard Worker struct Idmap_header {
43*d57664e9SAndroid Build Coastguard Worker // Always 0x504D4449 ('IDMP')
44*d57664e9SAndroid Build Coastguard Worker uint32_t magic;
45*d57664e9SAndroid Build Coastguard Worker uint32_t version;
46*d57664e9SAndroid Build Coastguard Worker
47*d57664e9SAndroid Build Coastguard Worker uint32_t target_crc32;
48*d57664e9SAndroid Build Coastguard Worker uint32_t overlay_crc32;
49*d57664e9SAndroid Build Coastguard Worker
50*d57664e9SAndroid Build Coastguard Worker uint32_t fulfilled_policies;
51*d57664e9SAndroid Build Coastguard Worker uint32_t enforce_overlayable;
52*d57664e9SAndroid Build Coastguard Worker
53*d57664e9SAndroid Build Coastguard Worker // overlay_path, target_path, and other string values encoded in the idmap header and read and
54*d57664e9SAndroid Build Coastguard Worker // stored in separate structures. This allows the idmap header data to be casted to this struct
55*d57664e9SAndroid Build Coastguard Worker // without having to read/store each header entry separately.
56*d57664e9SAndroid Build Coastguard Worker };
57*d57664e9SAndroid Build Coastguard Worker
58*d57664e9SAndroid Build Coastguard Worker struct Idmap_data_header {
59*d57664e9SAndroid Build Coastguard Worker uint32_t target_entry_count;
60*d57664e9SAndroid Build Coastguard Worker uint32_t target_inline_entry_count;
61*d57664e9SAndroid Build Coastguard Worker uint32_t target_inline_entry_value_count;
62*d57664e9SAndroid Build Coastguard Worker uint32_t configuration_count;
63*d57664e9SAndroid Build Coastguard Worker uint32_t overlay_entry_count;
64*d57664e9SAndroid Build Coastguard Worker
65*d57664e9SAndroid Build Coastguard Worker uint32_t string_pool_index_offset;
66*d57664e9SAndroid Build Coastguard Worker };
67*d57664e9SAndroid Build Coastguard Worker
68*d57664e9SAndroid Build Coastguard Worker struct Idmap_target_entry_inline {
69*d57664e9SAndroid Build Coastguard Worker uint32_t start_value_index;
70*d57664e9SAndroid Build Coastguard Worker uint32_t value_count;
71*d57664e9SAndroid Build Coastguard Worker };
72*d57664e9SAndroid Build Coastguard Worker
73*d57664e9SAndroid Build Coastguard Worker struct Idmap_target_entry_inline_value {
74*d57664e9SAndroid Build Coastguard Worker uint32_t config_index;
75*d57664e9SAndroid Build Coastguard Worker Res_value value;
76*d57664e9SAndroid Build Coastguard Worker };
77*d57664e9SAndroid Build Coastguard Worker
convert_dev_target_id(uint32_t dev_target_id)78*d57664e9SAndroid Build Coastguard Worker static constexpr uint32_t convert_dev_target_id(uint32_t dev_target_id) {
79*d57664e9SAndroid Build Coastguard Worker return (0x00FFFFFFU & dtohl(dev_target_id));
80*d57664e9SAndroid Build Coastguard Worker }
81*d57664e9SAndroid Build Coastguard Worker
OverlayStringPool(const LoadedIdmap * loaded_idmap)82*d57664e9SAndroid Build Coastguard Worker OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap)
83*d57664e9SAndroid Build Coastguard Worker : data_header_(loaded_idmap->data_header_),
84*d57664e9SAndroid Build Coastguard Worker idmap_string_pool_(loaded_idmap->string_pool_.get()) { };
85*d57664e9SAndroid Build Coastguard Worker
~OverlayStringPool()86*d57664e9SAndroid Build Coastguard Worker OverlayStringPool::~OverlayStringPool() {
87*d57664e9SAndroid Build Coastguard Worker uninit();
88*d57664e9SAndroid Build Coastguard Worker }
89*d57664e9SAndroid Build Coastguard Worker
stringAt(size_t idx) const90*d57664e9SAndroid Build Coastguard Worker base::expected<StringPiece16, NullOrIOError> OverlayStringPool::stringAt(size_t idx) const {
91*d57664e9SAndroid Build Coastguard Worker const size_t offset = dtohl(data_header_->string_pool_index_offset);
92*d57664e9SAndroid Build Coastguard Worker if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
93*d57664e9SAndroid Build Coastguard Worker return idmap_string_pool_->stringAt(idx - offset);
94*d57664e9SAndroid Build Coastguard Worker }
95*d57664e9SAndroid Build Coastguard Worker
96*d57664e9SAndroid Build Coastguard Worker return ResStringPool::stringAt(idx);
97*d57664e9SAndroid Build Coastguard Worker }
98*d57664e9SAndroid Build Coastguard Worker
string8At(size_t idx) const99*d57664e9SAndroid Build Coastguard Worker base::expected<StringPiece, NullOrIOError> OverlayStringPool::string8At(size_t idx) const {
100*d57664e9SAndroid Build Coastguard Worker const size_t offset = dtohl(data_header_->string_pool_index_offset);
101*d57664e9SAndroid Build Coastguard Worker if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
102*d57664e9SAndroid Build Coastguard Worker return idmap_string_pool_->string8At(idx - offset);
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker
105*d57664e9SAndroid Build Coastguard Worker return ResStringPool::string8At(idx);
106*d57664e9SAndroid Build Coastguard Worker }
107*d57664e9SAndroid Build Coastguard Worker
size() const108*d57664e9SAndroid Build Coastguard Worker size_t OverlayStringPool::size() const {
109*d57664e9SAndroid Build Coastguard Worker return ResStringPool::size() + (idmap_string_pool_ != nullptr ? idmap_string_pool_->size() : 0U);
110*d57664e9SAndroid Build Coastguard Worker }
111*d57664e9SAndroid Build Coastguard Worker
OverlayDynamicRefTable(const Idmap_data_header * data_header,Idmap_overlay_entries entries,uint8_t target_assigned_package_id)112*d57664e9SAndroid Build Coastguard Worker OverlayDynamicRefTable::OverlayDynamicRefTable(const Idmap_data_header* data_header,
113*d57664e9SAndroid Build Coastguard Worker Idmap_overlay_entries entries,
114*d57664e9SAndroid Build Coastguard Worker uint8_t target_assigned_package_id)
115*d57664e9SAndroid Build Coastguard Worker : data_header_(data_header),
116*d57664e9SAndroid Build Coastguard Worker entries_(entries),
117*d57664e9SAndroid Build Coastguard Worker target_assigned_package_id_(target_assigned_package_id) {
118*d57664e9SAndroid Build Coastguard Worker }
119*d57664e9SAndroid Build Coastguard Worker
lookupResourceId(uint32_t * resId) const120*d57664e9SAndroid Build Coastguard Worker status_t OverlayDynamicRefTable::lookupResourceId(uint32_t* resId) const {
121*d57664e9SAndroid Build Coastguard Worker const auto count = dtohl(data_header_->overlay_entry_count);
122*d57664e9SAndroid Build Coastguard Worker const auto overlay_it_end = entries_.overlay_id + count;
123*d57664e9SAndroid Build Coastguard Worker const auto entry_it = std::lower_bound(entries_.overlay_id, overlay_it_end, *resId,
124*d57664e9SAndroid Build Coastguard Worker [](uint32_t dev_overlay_id, uint32_t overlay_id) {
125*d57664e9SAndroid Build Coastguard Worker return dtohl(dev_overlay_id) < overlay_id;
126*d57664e9SAndroid Build Coastguard Worker });
127*d57664e9SAndroid Build Coastguard Worker
128*d57664e9SAndroid Build Coastguard Worker if (entry_it == overlay_it_end || dtohl(*entry_it) != *resId) {
129*d57664e9SAndroid Build Coastguard Worker // A mapping for the target resource id could not be found.
130*d57664e9SAndroid Build Coastguard Worker return DynamicRefTable::lookupResourceId(resId);
131*d57664e9SAndroid Build Coastguard Worker }
132*d57664e9SAndroid Build Coastguard Worker
133*d57664e9SAndroid Build Coastguard Worker const auto index = entry_it - entries_.overlay_id;
134*d57664e9SAndroid Build Coastguard Worker *resId = convert_dev_target_id(entries_.target_id[index]) |
135*d57664e9SAndroid Build Coastguard Worker (((uint32_t)target_assigned_package_id_) << 24U);
136*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
137*d57664e9SAndroid Build Coastguard Worker }
138*d57664e9SAndroid Build Coastguard Worker
lookupResourceIdNoRewrite(uint32_t * resId) const139*d57664e9SAndroid Build Coastguard Worker status_t OverlayDynamicRefTable::lookupResourceIdNoRewrite(uint32_t* resId) const {
140*d57664e9SAndroid Build Coastguard Worker return DynamicRefTable::lookupResourceId(resId);
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker
IdmapResMap(const Idmap_data_header * data_header,Idmap_target_entries entries,Idmap_target_inline_entries inline_entries,const Idmap_target_entry_inline_value * inline_entry_values,const ConfigDescription * configs,uint8_t target_assigned_package_id,const OverlayDynamicRefTable * overlay_ref_table)143*d57664e9SAndroid Build Coastguard Worker IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
144*d57664e9SAndroid Build Coastguard Worker Idmap_target_inline_entries inline_entries,
145*d57664e9SAndroid Build Coastguard Worker const Idmap_target_entry_inline_value* inline_entry_values,
146*d57664e9SAndroid Build Coastguard Worker const ConfigDescription* configs, uint8_t target_assigned_package_id,
147*d57664e9SAndroid Build Coastguard Worker const OverlayDynamicRefTable* overlay_ref_table)
148*d57664e9SAndroid Build Coastguard Worker : data_header_(data_header),
149*d57664e9SAndroid Build Coastguard Worker entries_(entries),
150*d57664e9SAndroid Build Coastguard Worker inline_entries_(inline_entries),
151*d57664e9SAndroid Build Coastguard Worker inline_entry_values_(inline_entry_values),
152*d57664e9SAndroid Build Coastguard Worker configurations_(configs),
153*d57664e9SAndroid Build Coastguard Worker target_assigned_package_id_(target_assigned_package_id),
154*d57664e9SAndroid Build Coastguard Worker overlay_ref_table_(overlay_ref_table) {
155*d57664e9SAndroid Build Coastguard Worker }
156*d57664e9SAndroid Build Coastguard Worker
Lookup(uint32_t target_res_id) const157*d57664e9SAndroid Build Coastguard Worker IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
158*d57664e9SAndroid Build Coastguard Worker if ((target_res_id >> 24U) != target_assigned_package_id_) {
159*d57664e9SAndroid Build Coastguard Worker // The resource id must have the same package id as the target package.
160*d57664e9SAndroid Build Coastguard Worker return {};
161*d57664e9SAndroid Build Coastguard Worker }
162*d57664e9SAndroid Build Coastguard Worker
163*d57664e9SAndroid Build Coastguard Worker // The resource ids encoded within the idmap are build-time resource ids so do not consider the
164*d57664e9SAndroid Build Coastguard Worker // package id when determining if the resource in the target package is overlaid.
165*d57664e9SAndroid Build Coastguard Worker target_res_id &= 0x00FFFFFFU;
166*d57664e9SAndroid Build Coastguard Worker
167*d57664e9SAndroid Build Coastguard Worker // Check if the target resource is mapped to an overlay resource.
168*d57664e9SAndroid Build Coastguard Worker const auto target_end = entries_.target_id + dtohl(data_header_->target_entry_count);
169*d57664e9SAndroid Build Coastguard Worker auto target_it = std::lower_bound(entries_.target_id, target_end, target_res_id,
170*d57664e9SAndroid Build Coastguard Worker [](uint32_t dev_target_id, uint32_t target_id) {
171*d57664e9SAndroid Build Coastguard Worker return convert_dev_target_id(dev_target_id) < target_id;
172*d57664e9SAndroid Build Coastguard Worker });
173*d57664e9SAndroid Build Coastguard Worker
174*d57664e9SAndroid Build Coastguard Worker if (target_it != target_end && convert_dev_target_id(*target_it) == target_res_id) {
175*d57664e9SAndroid Build Coastguard Worker const auto index = target_it - entries_.target_id;
176*d57664e9SAndroid Build Coastguard Worker uint32_t overlay_resource_id = dtohl(entries_.overlay_id[index]);
177*d57664e9SAndroid Build Coastguard Worker // Lookup the resource without rewriting the overlay resource id back to the target resource id
178*d57664e9SAndroid Build Coastguard Worker // being looked up.
179*d57664e9SAndroid Build Coastguard Worker overlay_ref_table_->lookupResourceIdNoRewrite(&overlay_resource_id);
180*d57664e9SAndroid Build Coastguard Worker return Result(overlay_resource_id);
181*d57664e9SAndroid Build Coastguard Worker }
182*d57664e9SAndroid Build Coastguard Worker
183*d57664e9SAndroid Build Coastguard Worker // Check if the target resources is mapped to an inline table entry.
184*d57664e9SAndroid Build Coastguard Worker const auto inline_entry_target_end =
185*d57664e9SAndroid Build Coastguard Worker inline_entries_.target_id + dtohl(data_header_->target_inline_entry_count);
186*d57664e9SAndroid Build Coastguard Worker const auto inline_entry_target_it =
187*d57664e9SAndroid Build Coastguard Worker std::lower_bound(inline_entries_.target_id, inline_entry_target_end, target_res_id,
188*d57664e9SAndroid Build Coastguard Worker [](uint32_t dev_target_id, uint32_t target_id) {
189*d57664e9SAndroid Build Coastguard Worker return convert_dev_target_id(dev_target_id) < target_id;
190*d57664e9SAndroid Build Coastguard Worker });
191*d57664e9SAndroid Build Coastguard Worker
192*d57664e9SAndroid Build Coastguard Worker if (inline_entry_target_it != inline_entry_target_end &&
193*d57664e9SAndroid Build Coastguard Worker convert_dev_target_id(*inline_entry_target_it) == target_res_id) {
194*d57664e9SAndroid Build Coastguard Worker const auto index = inline_entry_target_it - inline_entries_.target_id;
195*d57664e9SAndroid Build Coastguard Worker std::map<ConfigDescription, Res_value> values_map;
196*d57664e9SAndroid Build Coastguard Worker const auto& inline_entry = inline_entries_.entry[index];
197*d57664e9SAndroid Build Coastguard Worker for (int i = 0; i < dtohl(inline_entry.value_count); i++) {
198*d57664e9SAndroid Build Coastguard Worker const auto& value = inline_entry_values_[dtohl(inline_entry.start_value_index) + i];
199*d57664e9SAndroid Build Coastguard Worker const auto& config = configurations_[dtohl(value.config_index)];
200*d57664e9SAndroid Build Coastguard Worker values_map[config] = value.value;
201*d57664e9SAndroid Build Coastguard Worker }
202*d57664e9SAndroid Build Coastguard Worker return Result(std::move(values_map));
203*d57664e9SAndroid Build Coastguard Worker }
204*d57664e9SAndroid Build Coastguard Worker return {};
205*d57664e9SAndroid Build Coastguard Worker }
206*d57664e9SAndroid Build Coastguard Worker
207*d57664e9SAndroid Build Coastguard Worker namespace {
208*d57664e9SAndroid Build Coastguard Worker template <typename T>
ReadType(const uint8_t ** in_out_data_ptr,size_t * in_out_size,const char * label,size_t count=1)209*d57664e9SAndroid Build Coastguard Worker const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const char* label,
210*d57664e9SAndroid Build Coastguard Worker size_t count = 1) {
211*d57664e9SAndroid Build Coastguard Worker if (!util::IsFourByteAligned(*in_out_data_ptr)) {
212*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Idmap " << label << " in " << __func__ << " is not word aligned.";
213*d57664e9SAndroid Build Coastguard Worker return {};
214*d57664e9SAndroid Build Coastguard Worker }
215*d57664e9SAndroid Build Coastguard Worker if ((*in_out_size / sizeof(T)) < count) {
216*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Idmap too small for the number of " << label << " in " << __func__
217*d57664e9SAndroid Build Coastguard Worker << " entries (" << count << ").";
218*d57664e9SAndroid Build Coastguard Worker return nullptr;
219*d57664e9SAndroid Build Coastguard Worker }
220*d57664e9SAndroid Build Coastguard Worker auto data_ptr = *in_out_data_ptr;
221*d57664e9SAndroid Build Coastguard Worker const size_t read_size = sizeof(T) * count;
222*d57664e9SAndroid Build Coastguard Worker *in_out_data_ptr += read_size;
223*d57664e9SAndroid Build Coastguard Worker *in_out_size -= read_size;
224*d57664e9SAndroid Build Coastguard Worker return reinterpret_cast<const T*>(data_ptr);
225*d57664e9SAndroid Build Coastguard Worker }
226*d57664e9SAndroid Build Coastguard Worker
ReadString(const uint8_t ** in_out_data_ptr,size_t * in_out_size,const char * label)227*d57664e9SAndroid Build Coastguard Worker std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size_t* in_out_size,
228*d57664e9SAndroid Build Coastguard Worker const char* label) {
229*d57664e9SAndroid Build Coastguard Worker const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label);
230*d57664e9SAndroid Build Coastguard Worker if (len == nullptr) {
231*d57664e9SAndroid Build Coastguard Worker return {};
232*d57664e9SAndroid Build Coastguard Worker }
233*d57664e9SAndroid Build Coastguard Worker const auto* data = ReadType<char>(in_out_data_ptr, in_out_size, label, *len);
234*d57664e9SAndroid Build Coastguard Worker if (data == nullptr) {
235*d57664e9SAndroid Build Coastguard Worker return {};
236*d57664e9SAndroid Build Coastguard Worker }
237*d57664e9SAndroid Build Coastguard Worker // Strings are padded to the next 4 byte boundary.
238*d57664e9SAndroid Build Coastguard Worker const uint32_t padding_size = (4U - ((size_t)*in_out_data_ptr & 0x3U)) % 4U;
239*d57664e9SAndroid Build Coastguard Worker for (uint32_t i = 0; i < padding_size; i++) {
240*d57664e9SAndroid Build Coastguard Worker if (**in_out_data_ptr != 0) {
241*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << " Idmap padding of " << label << " in " << __func__ << " is non-zero.";
242*d57664e9SAndroid Build Coastguard Worker return {};
243*d57664e9SAndroid Build Coastguard Worker }
244*d57664e9SAndroid Build Coastguard Worker *in_out_data_ptr += sizeof(uint8_t);
245*d57664e9SAndroid Build Coastguard Worker *in_out_size -= sizeof(uint8_t);
246*d57664e9SAndroid Build Coastguard Worker }
247*d57664e9SAndroid Build Coastguard Worker return std::string_view(data, *len);
248*d57664e9SAndroid Build Coastguard Worker }
249*d57664e9SAndroid Build Coastguard Worker } // namespace
250*d57664e9SAndroid Build Coastguard Worker
251*d57664e9SAndroid Build Coastguard Worker // O_PATH is a lightweight way of creating an FD, only exists on Linux
252*d57664e9SAndroid Build Coastguard Worker #ifndef O_PATH
253*d57664e9SAndroid Build Coastguard Worker #define O_PATH (0)
254*d57664e9SAndroid Build Coastguard Worker #endif
255*d57664e9SAndroid Build Coastguard Worker
LoadedIdmap(const std::string & idmap_path,const Idmap_header * header,const Idmap_data_header * data_header,Idmap_target_entries target_entries,Idmap_target_inline_entries target_inline_entries,const Idmap_target_entry_inline_value * inline_entry_values,const ConfigDescription * configs,Idmap_overlay_entries overlay_entries,std::unique_ptr<ResStringPool> && string_pool,std::string_view overlay_apk_path,std::string_view target_apk_path)256*d57664e9SAndroid Build Coastguard Worker LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
257*d57664e9SAndroid Build Coastguard Worker const Idmap_data_header* data_header, Idmap_target_entries target_entries,
258*d57664e9SAndroid Build Coastguard Worker Idmap_target_inline_entries target_inline_entries,
259*d57664e9SAndroid Build Coastguard Worker const Idmap_target_entry_inline_value* inline_entry_values,
260*d57664e9SAndroid Build Coastguard Worker const ConfigDescription* configs, Idmap_overlay_entries overlay_entries,
261*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<ResStringPool>&& string_pool,
262*d57664e9SAndroid Build Coastguard Worker std::string_view overlay_apk_path, std::string_view target_apk_path)
263*d57664e9SAndroid Build Coastguard Worker : header_(header),
264*d57664e9SAndroid Build Coastguard Worker data_header_(data_header),
265*d57664e9SAndroid Build Coastguard Worker target_entries_(target_entries),
266*d57664e9SAndroid Build Coastguard Worker target_inline_entries_(target_inline_entries),
267*d57664e9SAndroid Build Coastguard Worker inline_entry_values_(inline_entry_values),
268*d57664e9SAndroid Build Coastguard Worker configurations_(configs),
269*d57664e9SAndroid Build Coastguard Worker overlay_entries_(overlay_entries),
270*d57664e9SAndroid Build Coastguard Worker string_pool_(std::move(string_pool)),
271*d57664e9SAndroid Build Coastguard Worker idmap_fd_(
272*d57664e9SAndroid Build Coastguard Worker android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)),
273*d57664e9SAndroid Build Coastguard Worker overlay_apk_path_(overlay_apk_path),
274*d57664e9SAndroid Build Coastguard Worker target_apk_path_(target_apk_path),
275*d57664e9SAndroid Build Coastguard Worker idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {
276*d57664e9SAndroid Build Coastguard Worker }
277*d57664e9SAndroid Build Coastguard Worker
Load(StringPiece idmap_path,StringPiece idmap_data)278*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) {
279*d57664e9SAndroid Build Coastguard Worker ATRACE_CALL();
280*d57664e9SAndroid Build Coastguard Worker size_t data_size = idmap_data.size();
281*d57664e9SAndroid Build Coastguard Worker auto data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data());
282*d57664e9SAndroid Build Coastguard Worker
283*d57664e9SAndroid Build Coastguard Worker // Parse the idmap header
284*d57664e9SAndroid Build Coastguard Worker auto header = ReadType<Idmap_header>(&data_ptr, &data_size, "header");
285*d57664e9SAndroid Build Coastguard Worker if (header == nullptr) {
286*d57664e9SAndroid Build Coastguard Worker return {};
287*d57664e9SAndroid Build Coastguard Worker }
288*d57664e9SAndroid Build Coastguard Worker if (dtohl(header->magic) != kIdmapMagic) {
289*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << StringPrintf("Invalid Idmap file: bad magic value (was 0x%08x, expected 0x%08x)",
290*d57664e9SAndroid Build Coastguard Worker dtohl(header->magic), kIdmapMagic);
291*d57664e9SAndroid Build Coastguard Worker return {};
292*d57664e9SAndroid Build Coastguard Worker }
293*d57664e9SAndroid Build Coastguard Worker if (dtohl(header->version) != kIdmapCurrentVersion) {
294*d57664e9SAndroid Build Coastguard Worker // We are strict about versions because files with this format are generated at runtime and
295*d57664e9SAndroid Build Coastguard Worker // don't need backwards compatibility.
296*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << StringPrintf("Version mismatch in Idmap (was 0x%08x, expected 0x%08x)",
297*d57664e9SAndroid Build Coastguard Worker dtohl(header->version), kIdmapCurrentVersion);
298*d57664e9SAndroid Build Coastguard Worker return {};
299*d57664e9SAndroid Build Coastguard Worker }
300*d57664e9SAndroid Build Coastguard Worker std::optional<std::string_view> target_path = ReadString(&data_ptr, &data_size, "target path");
301*d57664e9SAndroid Build Coastguard Worker if (!target_path) {
302*d57664e9SAndroid Build Coastguard Worker return {};
303*d57664e9SAndroid Build Coastguard Worker }
304*d57664e9SAndroid Build Coastguard Worker std::optional<std::string_view> overlay_path = ReadString(&data_ptr, &data_size, "overlay path");
305*d57664e9SAndroid Build Coastguard Worker if (!overlay_path) {
306*d57664e9SAndroid Build Coastguard Worker return {};
307*d57664e9SAndroid Build Coastguard Worker }
308*d57664e9SAndroid Build Coastguard Worker if (!ReadString(&data_ptr, &data_size, "target name") ||
309*d57664e9SAndroid Build Coastguard Worker !ReadString(&data_ptr, &data_size, "debug info")) {
310*d57664e9SAndroid Build Coastguard Worker return {};
311*d57664e9SAndroid Build Coastguard Worker }
312*d57664e9SAndroid Build Coastguard Worker
313*d57664e9SAndroid Build Coastguard Worker // Parse the idmap data blocks. Currently idmap2 can only generate one data block.
314*d57664e9SAndroid Build Coastguard Worker auto data_header = ReadType<Idmap_data_header>(&data_ptr, &data_size, "data header");
315*d57664e9SAndroid Build Coastguard Worker if (data_header == nullptr) {
316*d57664e9SAndroid Build Coastguard Worker return {};
317*d57664e9SAndroid Build Coastguard Worker }
318*d57664e9SAndroid Build Coastguard Worker Idmap_target_entries target_entries{
319*d57664e9SAndroid Build Coastguard Worker .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "entries.target_id",
320*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->target_entry_count)),
321*d57664e9SAndroid Build Coastguard Worker .overlay_id = ReadType<uint32_t>(&data_ptr, &data_size, "entries.overlay_id",
322*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->target_entry_count)),
323*d57664e9SAndroid Build Coastguard Worker };
324*d57664e9SAndroid Build Coastguard Worker if (!target_entries.target_id || !target_entries.overlay_id) {
325*d57664e9SAndroid Build Coastguard Worker return {};
326*d57664e9SAndroid Build Coastguard Worker }
327*d57664e9SAndroid Build Coastguard Worker Idmap_target_inline_entries target_inline_entries{
328*d57664e9SAndroid Build Coastguard Worker .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "target inline.target_id",
329*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->target_inline_entry_count)),
330*d57664e9SAndroid Build Coastguard Worker .entry = ReadType<Idmap_target_entry_inline>(&data_ptr, &data_size, "target inline.entry",
331*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->target_inline_entry_count))};
332*d57664e9SAndroid Build Coastguard Worker if (!target_inline_entries.target_id || !target_inline_entries.entry) {
333*d57664e9SAndroid Build Coastguard Worker return {};
334*d57664e9SAndroid Build Coastguard Worker }
335*d57664e9SAndroid Build Coastguard Worker
336*d57664e9SAndroid Build Coastguard Worker auto target_inline_entry_values = ReadType<Idmap_target_entry_inline_value>(
337*d57664e9SAndroid Build Coastguard Worker &data_ptr, &data_size, "target inline values",
338*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->target_inline_entry_value_count));
339*d57664e9SAndroid Build Coastguard Worker if (target_inline_entry_values == nullptr) {
340*d57664e9SAndroid Build Coastguard Worker return {};
341*d57664e9SAndroid Build Coastguard Worker }
342*d57664e9SAndroid Build Coastguard Worker
343*d57664e9SAndroid Build Coastguard Worker auto configurations = ReadType<ConfigDescription>(
344*d57664e9SAndroid Build Coastguard Worker &data_ptr, &data_size, "configurations",
345*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->configuration_count));
346*d57664e9SAndroid Build Coastguard Worker if (configurations == nullptr) {
347*d57664e9SAndroid Build Coastguard Worker return {};
348*d57664e9SAndroid Build Coastguard Worker }
349*d57664e9SAndroid Build Coastguard Worker
350*d57664e9SAndroid Build Coastguard Worker Idmap_overlay_entries overlay_entries{
351*d57664e9SAndroid Build Coastguard Worker .overlay_id = ReadType<uint32_t>(&data_ptr, &data_size, "overlay entries.overlay_id",
352*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->overlay_entry_count)),
353*d57664e9SAndroid Build Coastguard Worker .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "overlay entries.target_id",
354*d57664e9SAndroid Build Coastguard Worker dtohl(data_header->overlay_entry_count)),
355*d57664e9SAndroid Build Coastguard Worker };
356*d57664e9SAndroid Build Coastguard Worker if (!overlay_entries.overlay_id || !overlay_entries.target_id) {
357*d57664e9SAndroid Build Coastguard Worker return {};
358*d57664e9SAndroid Build Coastguard Worker }
359*d57664e9SAndroid Build Coastguard Worker std::optional<std::string_view> string_pool = ReadString(&data_ptr, &data_size, "string pool");
360*d57664e9SAndroid Build Coastguard Worker if (!string_pool) {
361*d57664e9SAndroid Build Coastguard Worker return {};
362*d57664e9SAndroid Build Coastguard Worker }
363*d57664e9SAndroid Build Coastguard Worker auto idmap_string_pool = util::make_unique<ResStringPool>();
364*d57664e9SAndroid Build Coastguard Worker if (!string_pool->empty()) {
365*d57664e9SAndroid Build Coastguard Worker const status_t err = idmap_string_pool->setTo(string_pool->data(), string_pool->size());
366*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
367*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "idmap string pool corrupt.";
368*d57664e9SAndroid Build Coastguard Worker return {};
369*d57664e9SAndroid Build Coastguard Worker }
370*d57664e9SAndroid Build Coastguard Worker }
371*d57664e9SAndroid Build Coastguard Worker
372*d57664e9SAndroid Build Coastguard Worker if (data_size != 0) {
373*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "idmap parsed with " << data_size << "bytes remaining";
374*d57664e9SAndroid Build Coastguard Worker return {};
375*d57664e9SAndroid Build Coastguard Worker }
376*d57664e9SAndroid Build Coastguard Worker
377*d57664e9SAndroid Build Coastguard Worker // Can't use make_unique because LoadedIdmap constructor is private.
378*d57664e9SAndroid Build Coastguard Worker return std::unique_ptr<LoadedIdmap>(
379*d57664e9SAndroid Build Coastguard Worker new LoadedIdmap(std::string(idmap_path), header, data_header, target_entries,
380*d57664e9SAndroid Build Coastguard Worker target_inline_entries, target_inline_entry_values, configurations,
381*d57664e9SAndroid Build Coastguard Worker overlay_entries, std::move(idmap_string_pool), *overlay_path, *target_path));
382*d57664e9SAndroid Build Coastguard Worker }
383*d57664e9SAndroid Build Coastguard Worker
IsUpToDate() const384*d57664e9SAndroid Build Coastguard Worker bool LoadedIdmap::IsUpToDate() const {
385*d57664e9SAndroid Build Coastguard Worker return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get());
386*d57664e9SAndroid Build Coastguard Worker }
387*d57664e9SAndroid Build Coastguard Worker
388*d57664e9SAndroid Build Coastguard Worker } // namespace android
389