xref: /aosp_15_r20/frameworks/base/cmds/idmap2/libidmap2/Idmap.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2018 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 #include "idmap2/Idmap.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
20*d57664e9SAndroid Build Coastguard Worker #include <cassert>
21*d57664e9SAndroid Build Coastguard Worker #include <istream>
22*d57664e9SAndroid Build Coastguard Worker #include <iterator>
23*d57664e9SAndroid Build Coastguard Worker #include <limits>
24*d57664e9SAndroid Build Coastguard Worker #include <memory>
25*d57664e9SAndroid Build Coastguard Worker #include <string>
26*d57664e9SAndroid Build Coastguard Worker #include <utility>
27*d57664e9SAndroid Build Coastguard Worker 
28*d57664e9SAndroid Build Coastguard Worker #include "android-base/format.h"
29*d57664e9SAndroid Build Coastguard Worker #include "android-base/macros.h"
30*d57664e9SAndroid Build Coastguard Worker #include "androidfw/AssetManager2.h"
31*d57664e9SAndroid Build Coastguard Worker #include "idmap2/ResourceMapping.h"
32*d57664e9SAndroid Build Coastguard Worker #include "idmap2/ResourceUtils.h"
33*d57664e9SAndroid Build Coastguard Worker #include "idmap2/Result.h"
34*d57664e9SAndroid Build Coastguard Worker #include "idmap2/SysTrace.h"
35*d57664e9SAndroid Build Coastguard Worker 
36*d57664e9SAndroid Build Coastguard Worker namespace android::idmap2 {
37*d57664e9SAndroid Build Coastguard Worker 
38*d57664e9SAndroid Build Coastguard Worker namespace {
39*d57664e9SAndroid Build Coastguard Worker 
Read8(std::istream & stream,uint8_t * out)40*d57664e9SAndroid Build Coastguard Worker bool WARN_UNUSED Read8(std::istream& stream, uint8_t* out) {
41*d57664e9SAndroid Build Coastguard Worker   uint8_t value;
42*d57664e9SAndroid Build Coastguard Worker   if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint8_t))) {
43*d57664e9SAndroid Build Coastguard Worker     *out = value;
44*d57664e9SAndroid Build Coastguard Worker     return true;
45*d57664e9SAndroid Build Coastguard Worker   }
46*d57664e9SAndroid Build Coastguard Worker   return false;
47*d57664e9SAndroid Build Coastguard Worker }
48*d57664e9SAndroid Build Coastguard Worker 
Read16(std::istream & stream,uint16_t * out)49*d57664e9SAndroid Build Coastguard Worker bool WARN_UNUSED Read16(std::istream& stream, uint16_t* out) {
50*d57664e9SAndroid Build Coastguard Worker   uint16_t value;
51*d57664e9SAndroid Build Coastguard Worker   if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint16_t))) {
52*d57664e9SAndroid Build Coastguard Worker     *out = dtohs(value);
53*d57664e9SAndroid Build Coastguard Worker     return true;
54*d57664e9SAndroid Build Coastguard Worker   }
55*d57664e9SAndroid Build Coastguard Worker   return false;
56*d57664e9SAndroid Build Coastguard Worker }
57*d57664e9SAndroid Build Coastguard Worker 
Read32(std::istream & stream,uint32_t * out)58*d57664e9SAndroid Build Coastguard Worker bool WARN_UNUSED Read32(std::istream& stream, uint32_t* out) {
59*d57664e9SAndroid Build Coastguard Worker   uint32_t value;
60*d57664e9SAndroid Build Coastguard Worker   if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
61*d57664e9SAndroid Build Coastguard Worker     *out = dtohl(value);
62*d57664e9SAndroid Build Coastguard Worker     return true;
63*d57664e9SAndroid Build Coastguard Worker   }
64*d57664e9SAndroid Build Coastguard Worker   return false;
65*d57664e9SAndroid Build Coastguard Worker }
66*d57664e9SAndroid Build Coastguard Worker 
ReadString(std::istream & stream,std::string * out)67*d57664e9SAndroid Build Coastguard Worker bool WARN_UNUSED ReadString(std::istream& stream, std::string* out) {
68*d57664e9SAndroid Build Coastguard Worker   uint32_t size;
69*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &size)) {
70*d57664e9SAndroid Build Coastguard Worker     return false;
71*d57664e9SAndroid Build Coastguard Worker   }
72*d57664e9SAndroid Build Coastguard Worker   if (size == 0) {
73*d57664e9SAndroid Build Coastguard Worker     *out = "";
74*d57664e9SAndroid Build Coastguard Worker     return true;
75*d57664e9SAndroid Build Coastguard Worker   }
76*d57664e9SAndroid Build Coastguard Worker   std::string buf(size, '\0');
77*d57664e9SAndroid Build Coastguard Worker   if (!stream.read(buf.data(), size)) {
78*d57664e9SAndroid Build Coastguard Worker     return false;
79*d57664e9SAndroid Build Coastguard Worker   }
80*d57664e9SAndroid Build Coastguard Worker   uint32_t padding_size = CalculatePadding(size);
81*d57664e9SAndroid Build Coastguard Worker   if (padding_size != 0 && !stream.seekg(padding_size, std::ios_base::cur)) {
82*d57664e9SAndroid Build Coastguard Worker     return false;
83*d57664e9SAndroid Build Coastguard Worker   }
84*d57664e9SAndroid Build Coastguard Worker   *out = std::move(buf);
85*d57664e9SAndroid Build Coastguard Worker   return true;
86*d57664e9SAndroid Build Coastguard Worker }
87*d57664e9SAndroid Build Coastguard Worker 
88*d57664e9SAndroid Build Coastguard Worker }  // namespace
89*d57664e9SAndroid Build Coastguard Worker 
FromBinaryStream(std::istream & stream)90*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
91*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
92*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_)) {
93*d57664e9SAndroid Build Coastguard Worker     return nullptr;
94*d57664e9SAndroid Build Coastguard Worker   }
95*d57664e9SAndroid Build Coastguard Worker 
96*d57664e9SAndroid Build Coastguard Worker   if (idmap_header->magic_ != kIdmapMagic || idmap_header->version_ != kIdmapCurrentVersion) {
97*d57664e9SAndroid Build Coastguard Worker     // Do not continue parsing if the file is not a current version idmap.
98*d57664e9SAndroid Build Coastguard Worker     return nullptr;
99*d57664e9SAndroid Build Coastguard Worker   }
100*d57664e9SAndroid Build Coastguard Worker 
101*d57664e9SAndroid Build Coastguard Worker   uint32_t enforce_overlayable;
102*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) ||
103*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &idmap_header->fulfilled_policies_) ||
104*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &enforce_overlayable) || !ReadString(stream, &idmap_header->target_path_) ||
105*d57664e9SAndroid Build Coastguard Worker       !ReadString(stream, &idmap_header->overlay_path_) ||
106*d57664e9SAndroid Build Coastguard Worker       !ReadString(stream, &idmap_header->overlay_name_) ||
107*d57664e9SAndroid Build Coastguard Worker       !ReadString(stream, &idmap_header->debug_info_)) {
108*d57664e9SAndroid Build Coastguard Worker     return nullptr;
109*d57664e9SAndroid Build Coastguard Worker   }
110*d57664e9SAndroid Build Coastguard Worker 
111*d57664e9SAndroid Build Coastguard Worker   idmap_header->enforce_overlayable_ = enforce_overlayable != 0U;
112*d57664e9SAndroid Build Coastguard Worker   return std::move(idmap_header);
113*d57664e9SAndroid Build Coastguard Worker }
114*d57664e9SAndroid Build Coastguard Worker 
IsUpToDate(const TargetResourceContainer & target,const OverlayResourceContainer & overlay,const std::string & overlay_name,PolicyBitmask fulfilled_policies,bool enforce_overlayable) const115*d57664e9SAndroid Build Coastguard Worker Result<Unit> IdmapHeader::IsUpToDate(const TargetResourceContainer& target,
116*d57664e9SAndroid Build Coastguard Worker                                      const OverlayResourceContainer& overlay,
117*d57664e9SAndroid Build Coastguard Worker                                      const std::string& overlay_name,
118*d57664e9SAndroid Build Coastguard Worker                                      PolicyBitmask fulfilled_policies,
119*d57664e9SAndroid Build Coastguard Worker                                      bool enforce_overlayable) const {
120*d57664e9SAndroid Build Coastguard Worker   const Result<uint32_t> target_crc = target.GetCrc();
121*d57664e9SAndroid Build Coastguard Worker   if (!target_crc) {
122*d57664e9SAndroid Build Coastguard Worker     return Error("failed to get target crc");
123*d57664e9SAndroid Build Coastguard Worker   }
124*d57664e9SAndroid Build Coastguard Worker 
125*d57664e9SAndroid Build Coastguard Worker   const Result<uint32_t> overlay_crc = overlay.GetCrc();
126*d57664e9SAndroid Build Coastguard Worker   if (!overlay_crc) {
127*d57664e9SAndroid Build Coastguard Worker     return Error("failed to get overlay crc");
128*d57664e9SAndroid Build Coastguard Worker   }
129*d57664e9SAndroid Build Coastguard Worker 
130*d57664e9SAndroid Build Coastguard Worker   return IsUpToDate(target.GetPath(), overlay.GetPath(), overlay_name, *target_crc, *overlay_crc,
131*d57664e9SAndroid Build Coastguard Worker                     fulfilled_policies, enforce_overlayable);
132*d57664e9SAndroid Build Coastguard Worker }
133*d57664e9SAndroid Build Coastguard Worker 
IsUpToDate(const std::string & target_path,const std::string & overlay_path,const std::string & overlay_name,uint32_t target_crc,uint32_t overlay_crc,PolicyBitmask fulfilled_policies,bool enforce_overlayable) const134*d57664e9SAndroid Build Coastguard Worker Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
135*d57664e9SAndroid Build Coastguard Worker                                      const std::string& overlay_path,
136*d57664e9SAndroid Build Coastguard Worker                                      const std::string& overlay_name, uint32_t target_crc,
137*d57664e9SAndroid Build Coastguard Worker                                      uint32_t overlay_crc, PolicyBitmask fulfilled_policies,
138*d57664e9SAndroid Build Coastguard Worker                                      bool enforce_overlayable) const {
139*d57664e9SAndroid Build Coastguard Worker   if (magic_ != kIdmapMagic) {
140*d57664e9SAndroid Build Coastguard Worker     return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
141*d57664e9SAndroid Build Coastguard Worker   }
142*d57664e9SAndroid Build Coastguard Worker 
143*d57664e9SAndroid Build Coastguard Worker   if (version_ != kIdmapCurrentVersion) {
144*d57664e9SAndroid Build Coastguard Worker     return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion);
145*d57664e9SAndroid Build Coastguard Worker   }
146*d57664e9SAndroid Build Coastguard Worker 
147*d57664e9SAndroid Build Coastguard Worker   if (target_crc_ != target_crc) {
148*d57664e9SAndroid Build Coastguard Worker     return Error("bad target crc: idmap version 0x%08x, file system version 0x%08x", target_crc_,
149*d57664e9SAndroid Build Coastguard Worker                  target_crc);
150*d57664e9SAndroid Build Coastguard Worker   }
151*d57664e9SAndroid Build Coastguard Worker 
152*d57664e9SAndroid Build Coastguard Worker   if (overlay_crc_ != overlay_crc) {
153*d57664e9SAndroid Build Coastguard Worker     return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
154*d57664e9SAndroid Build Coastguard Worker                  overlay_crc);
155*d57664e9SAndroid Build Coastguard Worker   }
156*d57664e9SAndroid Build Coastguard Worker 
157*d57664e9SAndroid Build Coastguard Worker   if (fulfilled_policies_ != fulfilled_policies) {
158*d57664e9SAndroid Build Coastguard Worker     return Error("bad fulfilled policies: idmap version 0x%08x, file system version 0x%08x",
159*d57664e9SAndroid Build Coastguard Worker                  fulfilled_policies, fulfilled_policies_);
160*d57664e9SAndroid Build Coastguard Worker   }
161*d57664e9SAndroid Build Coastguard Worker 
162*d57664e9SAndroid Build Coastguard Worker   if (enforce_overlayable != enforce_overlayable_) {
163*d57664e9SAndroid Build Coastguard Worker     return Error("bad enforce overlayable: idmap version %s, file system version %s",
164*d57664e9SAndroid Build Coastguard Worker                  enforce_overlayable ? "true" : "false", enforce_overlayable_ ? "true" : "false");
165*d57664e9SAndroid Build Coastguard Worker   }
166*d57664e9SAndroid Build Coastguard Worker 
167*d57664e9SAndroid Build Coastguard Worker   if (target_path != target_path_) {
168*d57664e9SAndroid Build Coastguard Worker     return Error("bad target path: idmap version %s, file system version %s", target_path.c_str(),
169*d57664e9SAndroid Build Coastguard Worker                  target_path_.c_str());
170*d57664e9SAndroid Build Coastguard Worker   }
171*d57664e9SAndroid Build Coastguard Worker 
172*d57664e9SAndroid Build Coastguard Worker   if (overlay_path != overlay_path_) {
173*d57664e9SAndroid Build Coastguard Worker     return Error("bad overlay path: idmap version %s, file system version %s", overlay_path.c_str(),
174*d57664e9SAndroid Build Coastguard Worker                  overlay_path_.c_str());
175*d57664e9SAndroid Build Coastguard Worker   }
176*d57664e9SAndroid Build Coastguard Worker 
177*d57664e9SAndroid Build Coastguard Worker   if (overlay_name != overlay_name_) {
178*d57664e9SAndroid Build Coastguard Worker     return Error("bad overlay name: idmap version %s, file system version %s", overlay_name.c_str(),
179*d57664e9SAndroid Build Coastguard Worker                  overlay_name_.c_str());
180*d57664e9SAndroid Build Coastguard Worker   }
181*d57664e9SAndroid Build Coastguard Worker 
182*d57664e9SAndroid Build Coastguard Worker   return Unit{};
183*d57664e9SAndroid Build Coastguard Worker }
184*d57664e9SAndroid Build Coastguard Worker 
FromBinaryStream(std::istream & stream)185*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
186*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header());
187*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &idmap_data_header->target_entry_count) ||
188*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &idmap_data_header->target_entry_inline_count) ||
189*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &idmap_data_header->target_entry_inline_value_count) ||
190*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &idmap_data_header->config_count) ||
191*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &idmap_data_header->overlay_entry_count) ||
192*d57664e9SAndroid Build Coastguard Worker       !Read32(stream, &idmap_data_header->string_pool_index_offset)) {
193*d57664e9SAndroid Build Coastguard Worker     return nullptr;
194*d57664e9SAndroid Build Coastguard Worker   }
195*d57664e9SAndroid Build Coastguard Worker 
196*d57664e9SAndroid Build Coastguard Worker   return std::move(idmap_data_header);
197*d57664e9SAndroid Build Coastguard Worker }
198*d57664e9SAndroid Build Coastguard Worker 
FromBinaryStream(std::istream & stream)199*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& stream) {
200*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<IdmapData> data(new IdmapData());
201*d57664e9SAndroid Build Coastguard Worker   data->header_ = IdmapData::Header::FromBinaryStream(stream);
202*d57664e9SAndroid Build Coastguard Worker   if (!data->header_) {
203*d57664e9SAndroid Build Coastguard Worker     return nullptr;
204*d57664e9SAndroid Build Coastguard Worker   }
205*d57664e9SAndroid Build Coastguard Worker 
206*d57664e9SAndroid Build Coastguard Worker   // Read the mapping of target resource id to overlay resource value.
207*d57664e9SAndroid Build Coastguard Worker   data->target_entries_.resize(data->header_->GetTargetEntryCount());
208*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) {
209*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &data->target_entries_[i].target_id)) {
210*d57664e9SAndroid Build Coastguard Worker       return nullptr;
211*d57664e9SAndroid Build Coastguard Worker     }
212*d57664e9SAndroid Build Coastguard Worker   }
213*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) {
214*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &data->target_entries_[i].overlay_id)) {
215*d57664e9SAndroid Build Coastguard Worker       return nullptr;
216*d57664e9SAndroid Build Coastguard Worker     }
217*d57664e9SAndroid Build Coastguard Worker   }
218*d57664e9SAndroid Build Coastguard Worker 
219*d57664e9SAndroid Build Coastguard Worker   // Read the mapping of target resource id to inline overlay values.
220*d57664e9SAndroid Build Coastguard Worker   struct TargetInlineEntryHeader {
221*d57664e9SAndroid Build Coastguard Worker     ResourceId target_id;
222*d57664e9SAndroid Build Coastguard Worker     uint32_t values_offset;
223*d57664e9SAndroid Build Coastguard Worker     uint32_t values_count;
224*d57664e9SAndroid Build Coastguard Worker   };
225*d57664e9SAndroid Build Coastguard Worker   std::vector<TargetInlineEntryHeader> target_inline_entries(
226*d57664e9SAndroid Build Coastguard Worker       data->header_->GetTargetInlineEntryCount());
227*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
228*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &target_inline_entries[i].target_id)) {
229*d57664e9SAndroid Build Coastguard Worker       return nullptr;
230*d57664e9SAndroid Build Coastguard Worker     }
231*d57664e9SAndroid Build Coastguard Worker   }
232*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
233*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &target_inline_entries[i].values_offset) ||
234*d57664e9SAndroid Build Coastguard Worker         !Read32(stream, &target_inline_entries[i].values_count)) {
235*d57664e9SAndroid Build Coastguard Worker       return nullptr;
236*d57664e9SAndroid Build Coastguard Worker     }
237*d57664e9SAndroid Build Coastguard Worker   }
238*d57664e9SAndroid Build Coastguard Worker 
239*d57664e9SAndroid Build Coastguard Worker   // Read the inline overlay resource values
240*d57664e9SAndroid Build Coastguard Worker   struct TargetValueHeader {
241*d57664e9SAndroid Build Coastguard Worker     uint32_t config_index;
242*d57664e9SAndroid Build Coastguard Worker     DataType data_type;
243*d57664e9SAndroid Build Coastguard Worker     DataValue data_value;
244*d57664e9SAndroid Build Coastguard Worker   };
245*d57664e9SAndroid Build Coastguard Worker   std::vector<TargetValueHeader> target_values(data->header_->GetTargetInlineEntryValueCount());
246*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
247*d57664e9SAndroid Build Coastguard Worker     auto& value = target_values[i];
248*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &value.config_index)) {
249*d57664e9SAndroid Build Coastguard Worker       return nullptr;
250*d57664e9SAndroid Build Coastguard Worker     }
251*d57664e9SAndroid Build Coastguard Worker     // skip the padding
252*d57664e9SAndroid Build Coastguard Worker     stream.seekg(3, std::ios::cur);
253*d57664e9SAndroid Build Coastguard Worker     if (!Read8(stream, &value.data_type) || !Read32(stream, &value.data_value)) {
254*d57664e9SAndroid Build Coastguard Worker       return nullptr;
255*d57664e9SAndroid Build Coastguard Worker     }
256*d57664e9SAndroid Build Coastguard Worker   }
257*d57664e9SAndroid Build Coastguard Worker 
258*d57664e9SAndroid Build Coastguard Worker   // Read the configurations
259*d57664e9SAndroid Build Coastguard Worker   std::vector<ConfigDescription> configurations(data->header_->GetConfigCount());
260*d57664e9SAndroid Build Coastguard Worker   if (!configurations.empty()) {
261*d57664e9SAndroid Build Coastguard Worker     if (!stream.read(reinterpret_cast<char*>(&configurations.front()),
262*d57664e9SAndroid Build Coastguard Worker                      sizeof(configurations.front()) * configurations.size())) {
263*d57664e9SAndroid Build Coastguard Worker       return nullptr;
264*d57664e9SAndroid Build Coastguard Worker     }
265*d57664e9SAndroid Build Coastguard Worker   }
266*d57664e9SAndroid Build Coastguard Worker 
267*d57664e9SAndroid Build Coastguard Worker   // Construct complete target inline entries
268*d57664e9SAndroid Build Coastguard Worker   data->target_inline_entries_.reserve(target_inline_entries.size());
269*d57664e9SAndroid Build Coastguard Worker   for (auto&& entry_header : target_inline_entries) {
270*d57664e9SAndroid Build Coastguard Worker     TargetInlineEntry& entry = data->target_inline_entries_.emplace_back();
271*d57664e9SAndroid Build Coastguard Worker     entry.target_id = entry_header.target_id;
272*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < entry_header.values_count; i++) {
273*d57664e9SAndroid Build Coastguard Worker       const auto& value_header = target_values[entry_header.values_offset + i];
274*d57664e9SAndroid Build Coastguard Worker       const auto& config = configurations[value_header.config_index];
275*d57664e9SAndroid Build Coastguard Worker       auto& value = entry.values[config];
276*d57664e9SAndroid Build Coastguard Worker       value.data_type = value_header.data_type;
277*d57664e9SAndroid Build Coastguard Worker       value.data_value = value_header.data_value;
278*d57664e9SAndroid Build Coastguard Worker     }
279*d57664e9SAndroid Build Coastguard Worker   }
280*d57664e9SAndroid Build Coastguard Worker 
281*d57664e9SAndroid Build Coastguard Worker   // Read the mapping of overlay resource id to target resource id.
282*d57664e9SAndroid Build Coastguard Worker   data->overlay_entries_.resize(data->header_->GetOverlayEntryCount());
283*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) {
284*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &data->overlay_entries_[i].overlay_id)) {
285*d57664e9SAndroid Build Coastguard Worker       return nullptr;
286*d57664e9SAndroid Build Coastguard Worker     }
287*d57664e9SAndroid Build Coastguard Worker   }
288*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) {
289*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &data->overlay_entries_[i].target_id)) {
290*d57664e9SAndroid Build Coastguard Worker       return nullptr;
291*d57664e9SAndroid Build Coastguard Worker     }
292*d57664e9SAndroid Build Coastguard Worker   }
293*d57664e9SAndroid Build Coastguard Worker 
294*d57664e9SAndroid Build Coastguard Worker   // Read raw string pool bytes.
295*d57664e9SAndroid Build Coastguard Worker   if (!ReadString(stream, &data->string_pool_data_)) {
296*d57664e9SAndroid Build Coastguard Worker     return nullptr;
297*d57664e9SAndroid Build Coastguard Worker   }
298*d57664e9SAndroid Build Coastguard Worker   return std::move(data);
299*d57664e9SAndroid Build Coastguard Worker }
300*d57664e9SAndroid Build Coastguard Worker 
CanonicalIdmapPathFor(std::string_view absolute_dir,std::string_view absolute_apk_path)301*d57664e9SAndroid Build Coastguard Worker std::string Idmap::CanonicalIdmapPathFor(std::string_view absolute_dir,
302*d57664e9SAndroid Build Coastguard Worker                                          std::string_view absolute_apk_path) {
303*d57664e9SAndroid Build Coastguard Worker   assert(absolute_dir.size() > 0 && absolute_dir[0] == "/");
304*d57664e9SAndroid Build Coastguard Worker   assert(absolute_apk_path.size() > 0 && absolute_apk_path[0] == "/");
305*d57664e9SAndroid Build Coastguard Worker   std::string copy(absolute_apk_path.begin() + 1, absolute_apk_path.end());
306*d57664e9SAndroid Build Coastguard Worker   replace(copy.begin(), copy.end(), '/', '@');
307*d57664e9SAndroid Build Coastguard Worker   return fmt::format("{}/{}@idmap", absolute_dir, copy);
308*d57664e9SAndroid Build Coastguard Worker }
309*d57664e9SAndroid Build Coastguard Worker 
FromBinaryStream(std::istream & stream)310*d57664e9SAndroid Build Coastguard Worker Result<std::unique_ptr<const Idmap>> Idmap::FromBinaryStream(std::istream& stream) {
311*d57664e9SAndroid Build Coastguard Worker   SYSTRACE << "Idmap::FromBinaryStream";
312*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<Idmap> idmap(new Idmap());
313*d57664e9SAndroid Build Coastguard Worker 
314*d57664e9SAndroid Build Coastguard Worker   idmap->header_ = IdmapHeader::FromBinaryStream(stream);
315*d57664e9SAndroid Build Coastguard Worker   if (!idmap->header_) {
316*d57664e9SAndroid Build Coastguard Worker     return Error("failed to parse idmap header");
317*d57664e9SAndroid Build Coastguard Worker   }
318*d57664e9SAndroid Build Coastguard Worker 
319*d57664e9SAndroid Build Coastguard Worker   // idmap version 0x01 does not specify the number of data blocks that follow
320*d57664e9SAndroid Build Coastguard Worker   // the idmap header; assume exactly one data block
321*d57664e9SAndroid Build Coastguard Worker   for (int i = 0; i < 1; i++) {
322*d57664e9SAndroid Build Coastguard Worker     std::unique_ptr<const IdmapData> data = IdmapData::FromBinaryStream(stream);
323*d57664e9SAndroid Build Coastguard Worker     if (!data) {
324*d57664e9SAndroid Build Coastguard Worker       return Error("failed to parse data block %d", i);
325*d57664e9SAndroid Build Coastguard Worker     }
326*d57664e9SAndroid Build Coastguard Worker     idmap->data_.push_back(std::move(data));
327*d57664e9SAndroid Build Coastguard Worker   }
328*d57664e9SAndroid Build Coastguard Worker 
329*d57664e9SAndroid Build Coastguard Worker   return {std::move(idmap)};
330*d57664e9SAndroid Build Coastguard Worker }
331*d57664e9SAndroid Build Coastguard Worker 
FromResourceMapping(const ResourceMapping & resource_mapping)332*d57664e9SAndroid Build Coastguard Worker Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
333*d57664e9SAndroid Build Coastguard Worker     const ResourceMapping& resource_mapping) {
334*d57664e9SAndroid Build Coastguard Worker   if (resource_mapping.GetTargetToOverlayMap().empty()) {
335*d57664e9SAndroid Build Coastguard Worker     return Error("no resources were overlaid");
336*d57664e9SAndroid Build Coastguard Worker   }
337*d57664e9SAndroid Build Coastguard Worker 
338*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<IdmapData> data(new IdmapData());
339*d57664e9SAndroid Build Coastguard Worker   data->string_pool_data_ = std::string(resource_mapping.GetStringPoolData());
340*d57664e9SAndroid Build Coastguard Worker   uint32_t inline_value_count = 0;
341*d57664e9SAndroid Build Coastguard Worker   std::set<std::string_view> config_set;
342*d57664e9SAndroid Build Coastguard Worker   for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
343*d57664e9SAndroid Build Coastguard Worker     if (auto overlay_resource = std::get_if<ResourceId>(&mapping.second)) {
344*d57664e9SAndroid Build Coastguard Worker       data->target_entries_.push_back({mapping.first, *overlay_resource});
345*d57664e9SAndroid Build Coastguard Worker     } else {
346*d57664e9SAndroid Build Coastguard Worker       std::map<ConfigDescription, TargetValue> values;
347*d57664e9SAndroid Build Coastguard Worker       for (const auto& [config, value] : std::get<ConfigMap>(mapping.second)) {
348*d57664e9SAndroid Build Coastguard Worker         config_set.insert(config);
349*d57664e9SAndroid Build Coastguard Worker         ConfigDescription cd;
350*d57664e9SAndroid Build Coastguard Worker         if (!ConfigDescription::Parse(config, &cd)) {
351*d57664e9SAndroid Build Coastguard Worker           return Error("failed to parse configuration string '%s'", config.c_str());
352*d57664e9SAndroid Build Coastguard Worker         }
353*d57664e9SAndroid Build Coastguard Worker         values[cd] = value;
354*d57664e9SAndroid Build Coastguard Worker         inline_value_count++;
355*d57664e9SAndroid Build Coastguard Worker       }
356*d57664e9SAndroid Build Coastguard Worker       data->target_inline_entries_.push_back({mapping.first, std::move(values)});
357*d57664e9SAndroid Build Coastguard Worker     }
358*d57664e9SAndroid Build Coastguard Worker   }
359*d57664e9SAndroid Build Coastguard Worker 
360*d57664e9SAndroid Build Coastguard Worker   for (const auto& mapping : resource_mapping.GetOverlayToTargetMap()) {
361*d57664e9SAndroid Build Coastguard Worker     data->overlay_entries_.emplace_back(IdmapData::OverlayEntry{mapping.first, mapping.second});
362*d57664e9SAndroid Build Coastguard Worker   }
363*d57664e9SAndroid Build Coastguard Worker 
364*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header());
365*d57664e9SAndroid Build Coastguard Worker   data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size());
366*d57664e9SAndroid Build Coastguard Worker   data_header->target_entry_inline_count =
367*d57664e9SAndroid Build Coastguard Worker       static_cast<uint32_t>(data->target_inline_entries_.size());
368*d57664e9SAndroid Build Coastguard Worker   data_header->target_entry_inline_value_count = inline_value_count;
369*d57664e9SAndroid Build Coastguard Worker   data_header->config_count = config_set.size();
370*d57664e9SAndroid Build Coastguard Worker   data_header->overlay_entry_count = static_cast<uint32_t>(data->overlay_entries_.size());
371*d57664e9SAndroid Build Coastguard Worker   data_header->string_pool_index_offset = resource_mapping.GetStringPoolOffset();
372*d57664e9SAndroid Build Coastguard Worker   data->header_ = std::move(data_header);
373*d57664e9SAndroid Build Coastguard Worker   return {std::move(data)};
374*d57664e9SAndroid Build Coastguard Worker }
375*d57664e9SAndroid Build Coastguard Worker 
FromContainers(const TargetResourceContainer & target,const OverlayResourceContainer & overlay,const std::string & overlay_name,const PolicyBitmask & fulfilled_policies,bool enforce_overlayable)376*d57664e9SAndroid Build Coastguard Worker Result<std::unique_ptr<const Idmap>> Idmap::FromContainers(const TargetResourceContainer& target,
377*d57664e9SAndroid Build Coastguard Worker                                                            const OverlayResourceContainer& overlay,
378*d57664e9SAndroid Build Coastguard Worker                                                            const std::string& overlay_name,
379*d57664e9SAndroid Build Coastguard Worker                                                            const PolicyBitmask& fulfilled_policies,
380*d57664e9SAndroid Build Coastguard Worker                                                            bool enforce_overlayable) {
381*d57664e9SAndroid Build Coastguard Worker   SYSTRACE << "Idmap::FromApkAssets";
382*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<IdmapHeader> header(new IdmapHeader());
383*d57664e9SAndroid Build Coastguard Worker   header->magic_ = kIdmapMagic;
384*d57664e9SAndroid Build Coastguard Worker   header->version_ = kIdmapCurrentVersion;
385*d57664e9SAndroid Build Coastguard Worker 
386*d57664e9SAndroid Build Coastguard Worker   const auto target_crc = target.GetCrc();
387*d57664e9SAndroid Build Coastguard Worker   if (!target_crc) {
388*d57664e9SAndroid Build Coastguard Worker     return Error(target_crc.GetError(), "failed to get zip CRC for '%s'", target.GetPath().data());
389*d57664e9SAndroid Build Coastguard Worker   }
390*d57664e9SAndroid Build Coastguard Worker   header->target_crc_ = *target_crc;
391*d57664e9SAndroid Build Coastguard Worker 
392*d57664e9SAndroid Build Coastguard Worker   const auto overlay_crc = overlay.GetCrc();
393*d57664e9SAndroid Build Coastguard Worker   if (!overlay_crc) {
394*d57664e9SAndroid Build Coastguard Worker     return Error(overlay_crc.GetError(), "failed to get zip CRC for '%s'",
395*d57664e9SAndroid Build Coastguard Worker                  overlay.GetPath().data());
396*d57664e9SAndroid Build Coastguard Worker   }
397*d57664e9SAndroid Build Coastguard Worker   header->overlay_crc_ = *overlay_crc;
398*d57664e9SAndroid Build Coastguard Worker 
399*d57664e9SAndroid Build Coastguard Worker   header->fulfilled_policies_ = fulfilled_policies;
400*d57664e9SAndroid Build Coastguard Worker   header->enforce_overlayable_ = enforce_overlayable;
401*d57664e9SAndroid Build Coastguard Worker   header->target_path_ = target.GetPath();
402*d57664e9SAndroid Build Coastguard Worker   header->overlay_path_ = overlay.GetPath();
403*d57664e9SAndroid Build Coastguard Worker   header->overlay_name_ = overlay_name;
404*d57664e9SAndroid Build Coastguard Worker 
405*d57664e9SAndroid Build Coastguard Worker   auto info = overlay.FindOverlayInfo(overlay_name);
406*d57664e9SAndroid Build Coastguard Worker   if (!info) {
407*d57664e9SAndroid Build Coastguard Worker     return Error(info.GetError(), "failed to get overlay info for '%s'", overlay.GetPath().data());
408*d57664e9SAndroid Build Coastguard Worker   }
409*d57664e9SAndroid Build Coastguard Worker 
410*d57664e9SAndroid Build Coastguard Worker   LogInfo log_info;
411*d57664e9SAndroid Build Coastguard Worker   auto resource_mapping = ResourceMapping::FromContainers(
412*d57664e9SAndroid Build Coastguard Worker       target, overlay, *info, fulfilled_policies, enforce_overlayable, log_info);
413*d57664e9SAndroid Build Coastguard Worker   if (!resource_mapping) {
414*d57664e9SAndroid Build Coastguard Worker     return Error(resource_mapping.GetError(), "failed to generate resource map for '%s'",
415*d57664e9SAndroid Build Coastguard Worker                  overlay.GetPath().data());
416*d57664e9SAndroid Build Coastguard Worker   }
417*d57664e9SAndroid Build Coastguard Worker 
418*d57664e9SAndroid Build Coastguard Worker   auto idmap_data = IdmapData::FromResourceMapping(*resource_mapping);
419*d57664e9SAndroid Build Coastguard Worker   if (!idmap_data) {
420*d57664e9SAndroid Build Coastguard Worker     return idmap_data.GetError();
421*d57664e9SAndroid Build Coastguard Worker   }
422*d57664e9SAndroid Build Coastguard Worker 
423*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<Idmap> idmap(new Idmap());
424*d57664e9SAndroid Build Coastguard Worker   header->debug_info_ = log_info.GetString();
425*d57664e9SAndroid Build Coastguard Worker   idmap->header_ = std::move(header);
426*d57664e9SAndroid Build Coastguard Worker   idmap->data_.push_back(std::move(*idmap_data));
427*d57664e9SAndroid Build Coastguard Worker 
428*d57664e9SAndroid Build Coastguard Worker   return {std::move(idmap)};
429*d57664e9SAndroid Build Coastguard Worker }
430*d57664e9SAndroid Build Coastguard Worker 
accept(Visitor * v) const431*d57664e9SAndroid Build Coastguard Worker void IdmapHeader::accept(Visitor* v) const {
432*d57664e9SAndroid Build Coastguard Worker   assert(v != nullptr);
433*d57664e9SAndroid Build Coastguard Worker   v->visit(*this);
434*d57664e9SAndroid Build Coastguard Worker }
435*d57664e9SAndroid Build Coastguard Worker 
accept(Visitor * v) const436*d57664e9SAndroid Build Coastguard Worker void IdmapData::Header::accept(Visitor* v) const {
437*d57664e9SAndroid Build Coastguard Worker   assert(v != nullptr);
438*d57664e9SAndroid Build Coastguard Worker   v->visit(*this);
439*d57664e9SAndroid Build Coastguard Worker }
440*d57664e9SAndroid Build Coastguard Worker 
accept(Visitor * v) const441*d57664e9SAndroid Build Coastguard Worker void IdmapData::accept(Visitor* v) const {
442*d57664e9SAndroid Build Coastguard Worker   assert(v != nullptr);
443*d57664e9SAndroid Build Coastguard Worker   header_->accept(v);
444*d57664e9SAndroid Build Coastguard Worker   v->visit(*this);
445*d57664e9SAndroid Build Coastguard Worker }
446*d57664e9SAndroid Build Coastguard Worker 
accept(Visitor * v) const447*d57664e9SAndroid Build Coastguard Worker void Idmap::accept(Visitor* v) const {
448*d57664e9SAndroid Build Coastguard Worker   assert(v != nullptr);
449*d57664e9SAndroid Build Coastguard Worker   header_->accept(v);
450*d57664e9SAndroid Build Coastguard Worker   v->visit(*this);
451*d57664e9SAndroid Build Coastguard Worker   auto end = data_.cend();
452*d57664e9SAndroid Build Coastguard Worker   for (auto iter = data_.cbegin(); iter != end; ++iter) {
453*d57664e9SAndroid Build Coastguard Worker     (*iter)->accept(v);
454*d57664e9SAndroid Build Coastguard Worker   }
455*d57664e9SAndroid Build Coastguard Worker }
456*d57664e9SAndroid Build Coastguard Worker 
457*d57664e9SAndroid Build Coastguard Worker }  // namespace android::idmap2
458