xref: /aosp_15_r20/frameworks/base/cmds/idmap2/libidmap2/FabricatedOverlay.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2021 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/FabricatedOverlay.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <sys/stat.h>   // umask
20*d57664e9SAndroid Build Coastguard Worker #include <sys/types.h>  // umask
21*d57664e9SAndroid Build Coastguard Worker 
22*d57664e9SAndroid Build Coastguard Worker #include <android-base/file.h>
23*d57664e9SAndroid Build Coastguard Worker #include <android-base/strings.h>
24*d57664e9SAndroid Build Coastguard Worker #include <androidfw/BigBuffer.h>
25*d57664e9SAndroid Build Coastguard Worker #include <androidfw/BigBufferStream.h>
26*d57664e9SAndroid Build Coastguard Worker #include <androidfw/FileStream.h>
27*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Image.h>
28*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Png.h>
29*d57664e9SAndroid Build Coastguard Worker #include <androidfw/ResourceUtils.h>
30*d57664e9SAndroid Build Coastguard Worker #include <androidfw/StringPiece.h>
31*d57664e9SAndroid Build Coastguard Worker #include <androidfw/StringPool.h>
32*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Streams.h>
33*d57664e9SAndroid Build Coastguard Worker #include <google/protobuf/io/coded_stream.h>
34*d57664e9SAndroid Build Coastguard Worker #include <google/protobuf/io/zero_copy_stream_impl.h>
35*d57664e9SAndroid Build Coastguard Worker #include <utils/ByteOrder.h>
36*d57664e9SAndroid Build Coastguard Worker #include <zlib.h>
37*d57664e9SAndroid Build Coastguard Worker 
38*d57664e9SAndroid Build Coastguard Worker #include <fstream>
39*d57664e9SAndroid Build Coastguard Worker #include <map>
40*d57664e9SAndroid Build Coastguard Worker #include <memory>
41*d57664e9SAndroid Build Coastguard Worker #include <string>
42*d57664e9SAndroid Build Coastguard Worker #include <utility>
43*d57664e9SAndroid Build Coastguard Worker #include <sys/utsname.h>
44*d57664e9SAndroid Build Coastguard Worker 
45*d57664e9SAndroid Build Coastguard Worker namespace android::idmap2 {
46*d57664e9SAndroid Build Coastguard Worker constexpr auto kBufferSize = 1024;
47*d57664e9SAndroid Build Coastguard Worker 
48*d57664e9SAndroid Build Coastguard Worker namespace {
Read32(std::istream & stream,uint32_t * out)49*d57664e9SAndroid Build Coastguard Worker bool Read32(std::istream& stream, uint32_t* out) {
50*d57664e9SAndroid Build Coastguard Worker   uint32_t value;
51*d57664e9SAndroid Build Coastguard Worker   if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
52*d57664e9SAndroid Build Coastguard Worker     *out = dtohl(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 
Write32(std::ostream & stream,uint32_t value)58*d57664e9SAndroid Build Coastguard Worker void Write32(std::ostream& stream, uint32_t value) {
59*d57664e9SAndroid Build Coastguard Worker   uint32_t x = htodl(value);
60*d57664e9SAndroid Build Coastguard Worker   stream.write(reinterpret_cast<char*>(&x), sizeof(uint32_t));
61*d57664e9SAndroid Build Coastguard Worker }
62*d57664e9SAndroid Build Coastguard Worker }  // namespace
63*d57664e9SAndroid Build Coastguard Worker 
FabricatedOverlay(pb::FabricatedOverlay && overlay,std::string && string_pool_data,std::vector<FabricatedOverlay::BinaryData> binary_files,off_t total_binary_bytes,std::optional<uint32_t> crc_from_disk)64*d57664e9SAndroid Build Coastguard Worker FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
65*d57664e9SAndroid Build Coastguard Worker                                      std::string&& string_pool_data,
66*d57664e9SAndroid Build Coastguard Worker                                      std::vector<FabricatedOverlay::BinaryData> binary_files,
67*d57664e9SAndroid Build Coastguard Worker                                      off_t total_binary_bytes,
68*d57664e9SAndroid Build Coastguard Worker                                      std::optional<uint32_t> crc_from_disk)
69*d57664e9SAndroid Build Coastguard Worker     : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)),
70*d57664e9SAndroid Build Coastguard Worker     string_pool_data_(std::move(string_pool_data)),
71*d57664e9SAndroid Build Coastguard Worker     binary_files_(std::move(binary_files)),
72*d57664e9SAndroid Build Coastguard Worker     total_binary_bytes_(total_binary_bytes),
73*d57664e9SAndroid Build Coastguard Worker     crc_from_disk_(crc_from_disk) {
74*d57664e9SAndroid Build Coastguard Worker }
75*d57664e9SAndroid Build Coastguard Worker 
Builder(const std::string & package_name,const std::string & name,const std::string & target_package_name)76*d57664e9SAndroid Build Coastguard Worker FabricatedOverlay::Builder::Builder(const std::string& package_name, const std::string& name,
77*d57664e9SAndroid Build Coastguard Worker                                     const std::string& target_package_name) {
78*d57664e9SAndroid Build Coastguard Worker   package_name_ = package_name;
79*d57664e9SAndroid Build Coastguard Worker   name_ = name;
80*d57664e9SAndroid Build Coastguard Worker   target_package_name_ = target_package_name;
81*d57664e9SAndroid Build Coastguard Worker }
82*d57664e9SAndroid Build Coastguard Worker 
SetOverlayable(const std::string & name)83*d57664e9SAndroid Build Coastguard Worker FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetOverlayable(const std::string& name) {
84*d57664e9SAndroid Build Coastguard Worker   target_overlayable_ = name;
85*d57664e9SAndroid Build Coastguard Worker   return *this;
86*d57664e9SAndroid Build Coastguard Worker }
87*d57664e9SAndroid Build Coastguard Worker 
SetResourceValue(const std::string & resource_name,uint8_t data_type,uint32_t data_value,const std::string & configuration)88*d57664e9SAndroid Build Coastguard Worker FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
89*d57664e9SAndroid Build Coastguard Worker     const std::string& resource_name, uint8_t data_type, uint32_t data_value,
90*d57664e9SAndroid Build Coastguard Worker     const std::string& configuration) {
91*d57664e9SAndroid Build Coastguard Worker   entries_.emplace_back(
92*d57664e9SAndroid Build Coastguard Worker       Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration, false});
93*d57664e9SAndroid Build Coastguard Worker   return *this;
94*d57664e9SAndroid Build Coastguard Worker }
95*d57664e9SAndroid Build Coastguard Worker 
SetResourceValue(const std::string & resource_name,uint8_t data_type,const std::string & data_string_value,const std::string & configuration)96*d57664e9SAndroid Build Coastguard Worker FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
97*d57664e9SAndroid Build Coastguard Worker     const std::string& resource_name, uint8_t data_type, const std::string& data_string_value,
98*d57664e9SAndroid Build Coastguard Worker     const std::string& configuration) {
99*d57664e9SAndroid Build Coastguard Worker   entries_.emplace_back(
100*d57664e9SAndroid Build Coastguard Worker       Entry{resource_name,
101*d57664e9SAndroid Build Coastguard Worker             data_type,
102*d57664e9SAndroid Build Coastguard Worker             0,
103*d57664e9SAndroid Build Coastguard Worker             data_string_value,
104*d57664e9SAndroid Build Coastguard Worker             std::nullopt,
105*d57664e9SAndroid Build Coastguard Worker             0,
106*d57664e9SAndroid Build Coastguard Worker             0,
107*d57664e9SAndroid Build Coastguard Worker             configuration,
108*d57664e9SAndroid Build Coastguard Worker             false});
109*d57664e9SAndroid Build Coastguard Worker   return *this;
110*d57664e9SAndroid Build Coastguard Worker }
111*d57664e9SAndroid Build Coastguard Worker 
SetResourceValue(const std::string & resource_name,std::optional<android::base::borrowed_fd> && binary_value,off64_t data_binary_offset,size_t data_binary_size,const std::string & configuration,bool nine_patch)112*d57664e9SAndroid Build Coastguard Worker FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
113*d57664e9SAndroid Build Coastguard Worker     const std::string& resource_name, std::optional<android::base::borrowed_fd>&& binary_value,
114*d57664e9SAndroid Build Coastguard Worker     off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration,
115*d57664e9SAndroid Build Coastguard Worker     bool nine_patch) {
116*d57664e9SAndroid Build Coastguard Worker   entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value,
117*d57664e9SAndroid Build Coastguard Worker                               data_binary_offset, data_binary_size, configuration, nine_patch});
118*d57664e9SAndroid Build Coastguard Worker   return *this;
119*d57664e9SAndroid Build Coastguard Worker }
120*d57664e9SAndroid Build Coastguard Worker 
buildBinaryData(pb::ResourceValue * pb_value,const TargetValue & value)121*d57664e9SAndroid Build Coastguard Worker static Result<FabricatedOverlay::BinaryData> buildBinaryData(
122*d57664e9SAndroid Build Coastguard Worker         pb::ResourceValue* pb_value, const TargetValue &value) {
123*d57664e9SAndroid Build Coastguard Worker   pb_value->set_data_type(Res_value::TYPE_STRING);
124*d57664e9SAndroid Build Coastguard Worker   size_t binary_size;
125*d57664e9SAndroid Build Coastguard Worker   off64_t binary_offset;
126*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<android::InputStream> binary_stream;
127*d57664e9SAndroid Build Coastguard Worker 
128*d57664e9SAndroid Build Coastguard Worker   if (value.nine_patch) {
129*d57664e9SAndroid Build Coastguard Worker     std::string file_contents;
130*d57664e9SAndroid Build Coastguard Worker     file_contents.resize(value.data_binary_size);
131*d57664e9SAndroid Build Coastguard Worker     if (!base::ReadFullyAtOffset(value.data_binary_value->get(), file_contents.data(),
132*d57664e9SAndroid Build Coastguard Worker                                  value.data_binary_size, value.data_binary_offset)) {
133*d57664e9SAndroid Build Coastguard Worker       return Error("Failed to read binary file data.");
134*d57664e9SAndroid Build Coastguard Worker     }
135*d57664e9SAndroid Build Coastguard Worker     const StringPiece content(file_contents.c_str(), file_contents.size());
136*d57664e9SAndroid Build Coastguard Worker     android::PngChunkFilter png_chunk_filter(content);
137*d57664e9SAndroid Build Coastguard Worker     android::AndroidLogDiagnostics diag;
138*d57664e9SAndroid Build Coastguard Worker     auto png = android::ReadPng(&png_chunk_filter, &diag);
139*d57664e9SAndroid Build Coastguard Worker     if (!png) {
140*d57664e9SAndroid Build Coastguard Worker       return Error("Error opening file as png");
141*d57664e9SAndroid Build Coastguard Worker     }
142*d57664e9SAndroid Build Coastguard Worker 
143*d57664e9SAndroid Build Coastguard Worker     std::string err;
144*d57664e9SAndroid Build Coastguard Worker     std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(png->rows.get(),
145*d57664e9SAndroid Build Coastguard Worker                                                               png->width, png->height,
146*d57664e9SAndroid Build Coastguard Worker                                                               &err);
147*d57664e9SAndroid Build Coastguard Worker     if (!nine_patch) {
148*d57664e9SAndroid Build Coastguard Worker       return Error("%s", err.c_str());
149*d57664e9SAndroid Build Coastguard Worker     }
150*d57664e9SAndroid Build Coastguard Worker 
151*d57664e9SAndroid Build Coastguard Worker     png->width -= 2;
152*d57664e9SAndroid Build Coastguard Worker     png->height -= 2;
153*d57664e9SAndroid Build Coastguard Worker     memmove(png->rows.get(), png->rows.get() + 1, png->height * sizeof(uint8_t**));
154*d57664e9SAndroid Build Coastguard Worker     for (int32_t h = 0; h < png->height; h++) {
155*d57664e9SAndroid Build Coastguard Worker       memmove(png->rows[h], png->rows[h] + 4, png->width * 4);
156*d57664e9SAndroid Build Coastguard Worker     }
157*d57664e9SAndroid Build Coastguard Worker 
158*d57664e9SAndroid Build Coastguard Worker     android::BigBuffer buffer(value.data_binary_size);
159*d57664e9SAndroid Build Coastguard Worker     android::BigBufferOutputStream buffer_output_stream(&buffer);
160*d57664e9SAndroid Build Coastguard Worker     if (!android::WritePng(png.get(), nine_patch.get(), &buffer_output_stream, {},
161*d57664e9SAndroid Build Coastguard Worker                            &diag, false)) {
162*d57664e9SAndroid Build Coastguard Worker       return Error("Error writing frro png");
163*d57664e9SAndroid Build Coastguard Worker     }
164*d57664e9SAndroid Build Coastguard Worker 
165*d57664e9SAndroid Build Coastguard Worker     binary_size = buffer.size();
166*d57664e9SAndroid Build Coastguard Worker     binary_offset = 0;
167*d57664e9SAndroid Build Coastguard Worker     android::BigBufferInputStream *buffer_input_stream
168*d57664e9SAndroid Build Coastguard Worker             = new android::BigBufferInputStream(std::move(buffer));
169*d57664e9SAndroid Build Coastguard Worker     binary_stream.reset(buffer_input_stream);
170*d57664e9SAndroid Build Coastguard Worker   } else {
171*d57664e9SAndroid Build Coastguard Worker     binary_size = value.data_binary_size;
172*d57664e9SAndroid Build Coastguard Worker     binary_offset = value.data_binary_offset;
173*d57664e9SAndroid Build Coastguard Worker     android::FileInputStream *fis
174*d57664e9SAndroid Build Coastguard Worker             = new android::FileInputStream(value.data_binary_value.value());
175*d57664e9SAndroid Build Coastguard Worker     binary_stream.reset(fis);
176*d57664e9SAndroid Build Coastguard Worker   }
177*d57664e9SAndroid Build Coastguard Worker 
178*d57664e9SAndroid Build Coastguard Worker   return FabricatedOverlay::BinaryData{
179*d57664e9SAndroid Build Coastguard Worker           std::move(binary_stream),
180*d57664e9SAndroid Build Coastguard Worker           binary_offset,
181*d57664e9SAndroid Build Coastguard Worker           binary_size};
182*d57664e9SAndroid Build Coastguard Worker }
183*d57664e9SAndroid Build Coastguard Worker 
Build()184*d57664e9SAndroid Build Coastguard Worker Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
185*d57664e9SAndroid Build Coastguard Worker   using ConfigMap = std::map<std::string, TargetValue, std::less<>>;
186*d57664e9SAndroid Build Coastguard Worker   using EntryMap = std::map<std::string, ConfigMap, std::less<>>;
187*d57664e9SAndroid Build Coastguard Worker   using TypeMap = std::map<std::string, EntryMap, std::less<>>;
188*d57664e9SAndroid Build Coastguard Worker   using PackageMap = std::map<std::string, TypeMap, std::less<>>;
189*d57664e9SAndroid Build Coastguard Worker   PackageMap package_map;
190*d57664e9SAndroid Build Coastguard Worker   android::StringPool string_pool;
191*d57664e9SAndroid Build Coastguard Worker   for (const auto& res_entry : entries_) {
192*d57664e9SAndroid Build Coastguard Worker     StringPiece package_substr;
193*d57664e9SAndroid Build Coastguard Worker     StringPiece type_name;
194*d57664e9SAndroid Build Coastguard Worker     StringPiece entry_name;
195*d57664e9SAndroid Build Coastguard Worker     if (!android::ExtractResourceName(StringPiece(res_entry.resource_name), &package_substr,
196*d57664e9SAndroid Build Coastguard Worker                                       &type_name, &entry_name)) {
197*d57664e9SAndroid Build Coastguard Worker       return Error("failed to parse resource name '%s'", res_entry.resource_name.c_str());
198*d57664e9SAndroid Build Coastguard Worker     }
199*d57664e9SAndroid Build Coastguard Worker 
200*d57664e9SAndroid Build Coastguard Worker     std::string_view package_name = package_substr.empty() ? target_package_name_ : package_substr;
201*d57664e9SAndroid Build Coastguard Worker     if (type_name.empty()) {
202*d57664e9SAndroid Build Coastguard Worker       return Error("resource name '%s' missing type name", res_entry.resource_name.c_str());
203*d57664e9SAndroid Build Coastguard Worker     }
204*d57664e9SAndroid Build Coastguard Worker 
205*d57664e9SAndroid Build Coastguard Worker     if (entry_name.empty()) {
206*d57664e9SAndroid Build Coastguard Worker       return Error("resource name '%s' missing entry name", res_entry.resource_name.c_str());
207*d57664e9SAndroid Build Coastguard Worker     }
208*d57664e9SAndroid Build Coastguard Worker 
209*d57664e9SAndroid Build Coastguard Worker     auto package = package_map.find(package_name);
210*d57664e9SAndroid Build Coastguard Worker     if (package == package_map.end()) {
211*d57664e9SAndroid Build Coastguard Worker       package = package_map
212*d57664e9SAndroid Build Coastguard Worker                     .insert(std::make_pair(package_name, TypeMap()))
213*d57664e9SAndroid Build Coastguard Worker                     .first;
214*d57664e9SAndroid Build Coastguard Worker     }
215*d57664e9SAndroid Build Coastguard Worker 
216*d57664e9SAndroid Build Coastguard Worker     auto type = package->second.find(type_name);
217*d57664e9SAndroid Build Coastguard Worker     if (type == package->second.end()) {
218*d57664e9SAndroid Build Coastguard Worker       type = package->second.insert(std::make_pair(type_name, EntryMap())).first;
219*d57664e9SAndroid Build Coastguard Worker     }
220*d57664e9SAndroid Build Coastguard Worker 
221*d57664e9SAndroid Build Coastguard Worker     auto entry = type->second.find(entry_name);
222*d57664e9SAndroid Build Coastguard Worker     if (entry == type->second.end()) {
223*d57664e9SAndroid Build Coastguard Worker       entry = type->second.insert(std::make_pair(entry_name, ConfigMap())).first;
224*d57664e9SAndroid Build Coastguard Worker     }
225*d57664e9SAndroid Build Coastguard Worker 
226*d57664e9SAndroid Build Coastguard Worker     auto value = entry->second.find(res_entry.configuration);
227*d57664e9SAndroid Build Coastguard Worker     if (value == entry->second.end()) {
228*d57664e9SAndroid Build Coastguard Worker       value = entry->second.insert(std::make_pair(res_entry.configuration, TargetValue())).first;
229*d57664e9SAndroid Build Coastguard Worker     }
230*d57664e9SAndroid Build Coastguard Worker 
231*d57664e9SAndroid Build Coastguard Worker     value->second = TargetValue{res_entry.data_type, res_entry.data_value,
232*d57664e9SAndroid Build Coastguard Worker                                 res_entry.data_string_value, res_entry.data_binary_value,
233*d57664e9SAndroid Build Coastguard Worker                                 res_entry.data_binary_offset, res_entry.data_binary_size,
234*d57664e9SAndroid Build Coastguard Worker                                 res_entry.nine_patch};
235*d57664e9SAndroid Build Coastguard Worker   }
236*d57664e9SAndroid Build Coastguard Worker 
237*d57664e9SAndroid Build Coastguard Worker   pb::FabricatedOverlay overlay_pb;
238*d57664e9SAndroid Build Coastguard Worker   overlay_pb.set_package_name(package_name_);
239*d57664e9SAndroid Build Coastguard Worker   overlay_pb.set_name(name_);
240*d57664e9SAndroid Build Coastguard Worker   overlay_pb.set_target_package_name(target_package_name_);
241*d57664e9SAndroid Build Coastguard Worker   overlay_pb.set_target_overlayable(target_overlayable_);
242*d57664e9SAndroid Build Coastguard Worker 
243*d57664e9SAndroid Build Coastguard Worker   std::vector<FabricatedOverlay::BinaryData> binary_files;
244*d57664e9SAndroid Build Coastguard Worker   size_t total_binary_bytes = 0;
245*d57664e9SAndroid Build Coastguard Worker   // 16 for the number of bytes in the frro file before the binary data
246*d57664e9SAndroid Build Coastguard Worker   const size_t FRRO_HEADER_SIZE = 16;
247*d57664e9SAndroid Build Coastguard Worker 
248*d57664e9SAndroid Build Coastguard Worker   for (auto& package : package_map) {
249*d57664e9SAndroid Build Coastguard Worker     auto package_pb = overlay_pb.add_packages();
250*d57664e9SAndroid Build Coastguard Worker     package_pb->set_name(package.first);
251*d57664e9SAndroid Build Coastguard Worker 
252*d57664e9SAndroid Build Coastguard Worker     for (auto& type : package.second) {
253*d57664e9SAndroid Build Coastguard Worker       auto type_pb = package_pb->add_types();
254*d57664e9SAndroid Build Coastguard Worker       type_pb->set_name(type.first);
255*d57664e9SAndroid Build Coastguard Worker 
256*d57664e9SAndroid Build Coastguard Worker       for (auto& entry : type.second) {
257*d57664e9SAndroid Build Coastguard Worker         for (const auto& value: entry.second) {
258*d57664e9SAndroid Build Coastguard Worker           auto entry_pb = type_pb->add_entries();
259*d57664e9SAndroid Build Coastguard Worker           entry_pb->set_name(entry.first);
260*d57664e9SAndroid Build Coastguard Worker           entry_pb->set_configuration(value.first);
261*d57664e9SAndroid Build Coastguard Worker           pb::ResourceValue* pb_value = entry_pb->mutable_res_value();
262*d57664e9SAndroid Build Coastguard Worker           pb_value->set_data_type(value.second.data_type);
263*d57664e9SAndroid Build Coastguard Worker           if (value.second.data_type == Res_value::TYPE_STRING) {
264*d57664e9SAndroid Build Coastguard Worker             auto ref = string_pool.MakeRef(value.second.data_string_value);
265*d57664e9SAndroid Build Coastguard Worker             pb_value->set_data_value(ref.index());
266*d57664e9SAndroid Build Coastguard Worker           } else if (value.second.data_binary_value.has_value()) {
267*d57664e9SAndroid Build Coastguard Worker             auto binary_data = buildBinaryData(pb_value, value.second);
268*d57664e9SAndroid Build Coastguard Worker             if (!binary_data) {
269*d57664e9SAndroid Build Coastguard Worker               return binary_data.GetError();
270*d57664e9SAndroid Build Coastguard Worker             }
271*d57664e9SAndroid Build Coastguard Worker             pb_value->set_data_type(Res_value::TYPE_STRING);
272*d57664e9SAndroid Build Coastguard Worker 
273*d57664e9SAndroid Build Coastguard Worker             std::string uri
274*d57664e9SAndroid Build Coastguard Worker                 = StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(),
275*d57664e9SAndroid Build Coastguard Worker                                static_cast<int> (FRRO_HEADER_SIZE + total_binary_bytes),
276*d57664e9SAndroid Build Coastguard Worker                                static_cast<int> (binary_data->size));
277*d57664e9SAndroid Build Coastguard Worker             total_binary_bytes += binary_data->size;
278*d57664e9SAndroid Build Coastguard Worker             binary_files.emplace_back(std::move(*binary_data));
279*d57664e9SAndroid Build Coastguard Worker             auto ref = string_pool.MakeRef(std::move(uri));
280*d57664e9SAndroid Build Coastguard Worker             pb_value->set_data_value(ref.index());
281*d57664e9SAndroid Build Coastguard Worker           } else {
282*d57664e9SAndroid Build Coastguard Worker             pb_value->set_data_value(value.second.data_value);
283*d57664e9SAndroid Build Coastguard Worker           }
284*d57664e9SAndroid Build Coastguard Worker         }
285*d57664e9SAndroid Build Coastguard Worker       }
286*d57664e9SAndroid Build Coastguard Worker     }
287*d57664e9SAndroid Build Coastguard Worker   }
288*d57664e9SAndroid Build Coastguard Worker   android::BigBuffer string_buffer(kBufferSize);
289*d57664e9SAndroid Build Coastguard Worker   android::StringPool::FlattenUtf8(&string_buffer, string_pool, nullptr);
290*d57664e9SAndroid Build Coastguard Worker   return FabricatedOverlay(std::move(overlay_pb), string_buffer.to_string(),
291*d57664e9SAndroid Build Coastguard Worker       std::move(binary_files), total_binary_bytes);
292*d57664e9SAndroid Build Coastguard Worker }
293*d57664e9SAndroid Build Coastguard Worker 
FromBinaryStream(std::istream & stream)294*d57664e9SAndroid Build Coastguard Worker Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stream) {
295*d57664e9SAndroid Build Coastguard Worker   uint32_t magic;
296*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &magic)) {
297*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to read fabricated overlay magic.");
298*d57664e9SAndroid Build Coastguard Worker   }
299*d57664e9SAndroid Build Coastguard Worker 
300*d57664e9SAndroid Build Coastguard Worker   if (magic != kFabricatedOverlayMagic) {
301*d57664e9SAndroid Build Coastguard Worker     return Error("Not a fabricated overlay file.");
302*d57664e9SAndroid Build Coastguard Worker   }
303*d57664e9SAndroid Build Coastguard Worker 
304*d57664e9SAndroid Build Coastguard Worker   uint32_t version;
305*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &version)) {
306*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to read fabricated overlay version.");
307*d57664e9SAndroid Build Coastguard Worker   }
308*d57664e9SAndroid Build Coastguard Worker 
309*d57664e9SAndroid Build Coastguard Worker   if (version < 1 || version > 3) {
310*d57664e9SAndroid Build Coastguard Worker     return Error("Invalid fabricated overlay version '%u'.", version);
311*d57664e9SAndroid Build Coastguard Worker   }
312*d57664e9SAndroid Build Coastguard Worker 
313*d57664e9SAndroid Build Coastguard Worker   uint32_t crc;
314*d57664e9SAndroid Build Coastguard Worker   if (!Read32(stream, &crc)) {
315*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to read fabricated overlay crc.");
316*d57664e9SAndroid Build Coastguard Worker   }
317*d57664e9SAndroid Build Coastguard Worker 
318*d57664e9SAndroid Build Coastguard Worker   pb::FabricatedOverlay overlay{};
319*d57664e9SAndroid Build Coastguard Worker   std::string sp_data;
320*d57664e9SAndroid Build Coastguard Worker   uint32_t total_binary_bytes;
321*d57664e9SAndroid Build Coastguard Worker   if (version == 3) {
322*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &total_binary_bytes)) {
323*d57664e9SAndroid Build Coastguard Worker       return Error("Failed read total binary bytes.");
324*d57664e9SAndroid Build Coastguard Worker     }
325*d57664e9SAndroid Build Coastguard Worker     stream.seekg(total_binary_bytes, std::istream::cur);
326*d57664e9SAndroid Build Coastguard Worker   }
327*d57664e9SAndroid Build Coastguard Worker   if (version >= 2) {
328*d57664e9SAndroid Build Coastguard Worker     uint32_t sp_size;
329*d57664e9SAndroid Build Coastguard Worker     if (!Read32(stream, &sp_size)) {
330*d57664e9SAndroid Build Coastguard Worker       return Error("Failed read string pool size.");
331*d57664e9SAndroid Build Coastguard Worker     }
332*d57664e9SAndroid Build Coastguard Worker     std::string buf(sp_size, '\0');
333*d57664e9SAndroid Build Coastguard Worker     if (!stream.read(buf.data(), sp_size)) {
334*d57664e9SAndroid Build Coastguard Worker       return Error("Failed to read string pool.");
335*d57664e9SAndroid Build Coastguard Worker     }
336*d57664e9SAndroid Build Coastguard Worker     sp_data = buf;
337*d57664e9SAndroid Build Coastguard Worker   }
338*d57664e9SAndroid Build Coastguard Worker   if (!overlay.ParseFromIstream(&stream)) {
339*d57664e9SAndroid Build Coastguard Worker     return Error("Failed read fabricated overlay proto.");
340*d57664e9SAndroid Build Coastguard Worker   }
341*d57664e9SAndroid Build Coastguard Worker 
342*d57664e9SAndroid Build Coastguard Worker   // If the proto version is the latest version, then the contents of the proto must be the same
343*d57664e9SAndroid Build Coastguard Worker   // when the proto is re-serialized; otherwise, the crc must be calculated because migrating the
344*d57664e9SAndroid Build Coastguard Worker   // proto to the latest version will likely change the contents of the fabricated overlay.
345*d57664e9SAndroid Build Coastguard Worker   return FabricatedOverlay(std::move(overlay), std::move(sp_data), {}, total_binary_bytes,
346*d57664e9SAndroid Build Coastguard Worker                            version == kFabricatedOverlayCurrentVersion
347*d57664e9SAndroid Build Coastguard Worker                                                    ? std::optional<uint32_t>(crc)
348*d57664e9SAndroid Build Coastguard Worker                                                    : std::nullopt);
349*d57664e9SAndroid Build Coastguard Worker }
350*d57664e9SAndroid Build Coastguard Worker 
InitializeData() const351*d57664e9SAndroid Build Coastguard Worker Result<FabricatedOverlay::SerializedData*> FabricatedOverlay::InitializeData() const {
352*d57664e9SAndroid Build Coastguard Worker   if (!data_.has_value()) {
353*d57664e9SAndroid Build Coastguard Worker     auto pb_size = overlay_pb_.ByteSizeLong();
354*d57664e9SAndroid Build Coastguard Worker     auto pb_data = std::unique_ptr<uint8_t[]>(new uint8_t[pb_size]);
355*d57664e9SAndroid Build Coastguard Worker 
356*d57664e9SAndroid Build Coastguard Worker     // Ensure serialization is deterministic
357*d57664e9SAndroid Build Coastguard Worker     google::protobuf::io::ArrayOutputStream array_stream(pb_data.get(), pb_size);
358*d57664e9SAndroid Build Coastguard Worker     google::protobuf::io::CodedOutputStream output_stream(&array_stream);
359*d57664e9SAndroid Build Coastguard Worker     output_stream.SetSerializationDeterministic(true);
360*d57664e9SAndroid Build Coastguard Worker     overlay_pb_.SerializeWithCachedSizes(&output_stream);
361*d57664e9SAndroid Build Coastguard Worker     if (output_stream.HadError() || pb_size != output_stream.ByteCount()) {
362*d57664e9SAndroid Build Coastguard Worker       return Error("Failed to serialize fabricated overlay.");
363*d57664e9SAndroid Build Coastguard Worker     }
364*d57664e9SAndroid Build Coastguard Worker 
365*d57664e9SAndroid Build Coastguard Worker     // Calculate the crc using the proto data and the version.
366*d57664e9SAndroid Build Coastguard Worker     uint32_t pb_crc = crc32(0L, Z_NULL, 0);
367*d57664e9SAndroid Build Coastguard Worker     pb_crc = crc32(pb_crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
368*d57664e9SAndroid Build Coastguard Worker                 sizeof(uint32_t));
369*d57664e9SAndroid Build Coastguard Worker     pb_crc = crc32(pb_crc, pb_data.get(), pb_size);
370*d57664e9SAndroid Build Coastguard Worker 
371*d57664e9SAndroid Build Coastguard Worker     data_ = SerializedData{std::move(pb_data), pb_size, pb_crc, string_pool_data_};
372*d57664e9SAndroid Build Coastguard Worker   }
373*d57664e9SAndroid Build Coastguard Worker   return &(*data_);
374*d57664e9SAndroid Build Coastguard Worker }
GetCrc() const375*d57664e9SAndroid Build Coastguard Worker Result<uint32_t> FabricatedOverlay::GetCrc() const {
376*d57664e9SAndroid Build Coastguard Worker   if (crc_from_disk_.has_value()) {
377*d57664e9SAndroid Build Coastguard Worker     return *crc_from_disk_;
378*d57664e9SAndroid Build Coastguard Worker   }
379*d57664e9SAndroid Build Coastguard Worker   auto data = InitializeData();
380*d57664e9SAndroid Build Coastguard Worker   if (!data) {
381*d57664e9SAndroid Build Coastguard Worker     return data.GetError();
382*d57664e9SAndroid Build Coastguard Worker   }
383*d57664e9SAndroid Build Coastguard Worker   return (*data)->pb_crc;
384*d57664e9SAndroid Build Coastguard Worker }
385*d57664e9SAndroid Build Coastguard Worker 
ToBinaryStream(std::ostream & stream) const386*d57664e9SAndroid Build Coastguard Worker Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
387*d57664e9SAndroid Build Coastguard Worker   auto data = InitializeData();
388*d57664e9SAndroid Build Coastguard Worker   if (!data) {
389*d57664e9SAndroid Build Coastguard Worker     return data.GetError();
390*d57664e9SAndroid Build Coastguard Worker   }
391*d57664e9SAndroid Build Coastguard Worker 
392*d57664e9SAndroid Build Coastguard Worker   Write32(stream, kFabricatedOverlayMagic);
393*d57664e9SAndroid Build Coastguard Worker   Write32(stream, kFabricatedOverlayCurrentVersion);
394*d57664e9SAndroid Build Coastguard Worker   Write32(stream, (*data)->pb_crc);
395*d57664e9SAndroid Build Coastguard Worker   Write32(stream, total_binary_bytes_);
396*d57664e9SAndroid Build Coastguard Worker   std::string file_contents;
397*d57664e9SAndroid Build Coastguard Worker   for (const FabricatedOverlay::BinaryData& bd : binary_files_) {
398*d57664e9SAndroid Build Coastguard Worker     file_contents.resize(bd.size);
399*d57664e9SAndroid Build Coastguard Worker     if (!bd.input_stream->ReadFullyAtOffset(file_contents.data(), bd.size, bd.offset)) {
400*d57664e9SAndroid Build Coastguard Worker       return Error("Failed to read binary file data.");
401*d57664e9SAndroid Build Coastguard Worker     }
402*d57664e9SAndroid Build Coastguard Worker     stream.write(file_contents.data(), file_contents.length());
403*d57664e9SAndroid Build Coastguard Worker   }
404*d57664e9SAndroid Build Coastguard Worker   Write32(stream, (*data)->sp_data.length());
405*d57664e9SAndroid Build Coastguard Worker   stream.write((*data)->sp_data.data(), (*data)->sp_data.length());
406*d57664e9SAndroid Build Coastguard Worker   if (stream.bad()) {
407*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to write string pool data.");
408*d57664e9SAndroid Build Coastguard Worker   }
409*d57664e9SAndroid Build Coastguard Worker   stream.write(reinterpret_cast<const char*>((*data)->pb_data.get()), (*data)->pb_data_size);
410*d57664e9SAndroid Build Coastguard Worker   if (stream.bad()) {
411*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to write serialized fabricated overlay.");
412*d57664e9SAndroid Build Coastguard Worker   }
413*d57664e9SAndroid Build Coastguard Worker 
414*d57664e9SAndroid Build Coastguard Worker   return Unit{};
415*d57664e9SAndroid Build Coastguard Worker }
416*d57664e9SAndroid Build Coastguard Worker 
417*d57664e9SAndroid Build Coastguard Worker using FabContainer = FabricatedOverlayContainer;
FabricatedOverlayContainer(FabricatedOverlay && overlay,std::string && path)418*d57664e9SAndroid Build Coastguard Worker FabContainer::FabricatedOverlayContainer(FabricatedOverlay&& overlay, std::string&& path)
419*d57664e9SAndroid Build Coastguard Worker     : overlay_(std::forward<FabricatedOverlay>(overlay)), path_(std::forward<std::string>(path)) {
420*d57664e9SAndroid Build Coastguard Worker }
421*d57664e9SAndroid Build Coastguard Worker 
422*d57664e9SAndroid Build Coastguard Worker FabContainer::~FabricatedOverlayContainer() = default;
423*d57664e9SAndroid Build Coastguard Worker 
FromPath(std::string path)424*d57664e9SAndroid Build Coastguard Worker Result<std::unique_ptr<FabContainer>> FabContainer::FromPath(std::string path) {
425*d57664e9SAndroid Build Coastguard Worker   std::fstream fin(path);
426*d57664e9SAndroid Build Coastguard Worker   auto overlay = FabricatedOverlay::FromBinaryStream(fin);
427*d57664e9SAndroid Build Coastguard Worker   if (!overlay) {
428*d57664e9SAndroid Build Coastguard Worker     return overlay.GetError();
429*d57664e9SAndroid Build Coastguard Worker   }
430*d57664e9SAndroid Build Coastguard Worker   return std::unique_ptr<FabContainer>(
431*d57664e9SAndroid Build Coastguard Worker       new FabricatedOverlayContainer(std::move(*overlay), std::move(path)));
432*d57664e9SAndroid Build Coastguard Worker }
433*d57664e9SAndroid Build Coastguard Worker 
FromOverlay(FabricatedOverlay && overlay)434*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<FabricatedOverlayContainer> FabContainer::FromOverlay(FabricatedOverlay&& overlay) {
435*d57664e9SAndroid Build Coastguard Worker   return std::unique_ptr<FabContainer>(
436*d57664e9SAndroid Build Coastguard Worker       new FabricatedOverlayContainer(std::move(overlay), {} /* path */));
437*d57664e9SAndroid Build Coastguard Worker }
438*d57664e9SAndroid Build Coastguard Worker 
GetManifestInfo() const439*d57664e9SAndroid Build Coastguard Worker OverlayManifestInfo FabContainer::GetManifestInfo() const {
440*d57664e9SAndroid Build Coastguard Worker   const pb::FabricatedOverlay& overlay_pb = overlay_.overlay_pb_;
441*d57664e9SAndroid Build Coastguard Worker   return OverlayManifestInfo{
442*d57664e9SAndroid Build Coastguard Worker       .package_name = overlay_pb.package_name(),
443*d57664e9SAndroid Build Coastguard Worker       .name = overlay_pb.name(),
444*d57664e9SAndroid Build Coastguard Worker       .target_package = overlay_pb.target_package_name(),
445*d57664e9SAndroid Build Coastguard Worker       .target_name = overlay_pb.target_overlayable(),
446*d57664e9SAndroid Build Coastguard Worker   };
447*d57664e9SAndroid Build Coastguard Worker }
448*d57664e9SAndroid Build Coastguard Worker 
FindOverlayInfo(const std::string & name) const449*d57664e9SAndroid Build Coastguard Worker Result<OverlayManifestInfo> FabContainer::FindOverlayInfo(const std::string& name) const {
450*d57664e9SAndroid Build Coastguard Worker   const OverlayManifestInfo info = GetManifestInfo();
451*d57664e9SAndroid Build Coastguard Worker   if (name != info.name) {
452*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to find name '%s' in fabricated overlay", name.c_str());
453*d57664e9SAndroid Build Coastguard Worker   }
454*d57664e9SAndroid Build Coastguard Worker   return info;
455*d57664e9SAndroid Build Coastguard Worker }
456*d57664e9SAndroid Build Coastguard Worker 
GetOverlayData(const OverlayManifestInfo & info) const457*d57664e9SAndroid Build Coastguard Worker Result<OverlayData> FabContainer::GetOverlayData(const OverlayManifestInfo& info) const {
458*d57664e9SAndroid Build Coastguard Worker   const pb::FabricatedOverlay& overlay_pb = overlay_.overlay_pb_;
459*d57664e9SAndroid Build Coastguard Worker   if (info.name != overlay_pb.name()) {
460*d57664e9SAndroid Build Coastguard Worker     return Error("Failed to find name '%s' in fabricated overlay", info.name.c_str());
461*d57664e9SAndroid Build Coastguard Worker   }
462*d57664e9SAndroid Build Coastguard Worker 
463*d57664e9SAndroid Build Coastguard Worker   OverlayData result{};
464*d57664e9SAndroid Build Coastguard Worker   for (const auto& package : overlay_pb.packages()) {
465*d57664e9SAndroid Build Coastguard Worker     for (const auto& type : package.types()) {
466*d57664e9SAndroid Build Coastguard Worker       for (const auto& entry : type.entries()) {
467*d57664e9SAndroid Build Coastguard Worker         auto name = base::StringPrintf("%s:%s/%s", package.name().c_str(), type.name().c_str(),
468*d57664e9SAndroid Build Coastguard Worker                                        entry.name().c_str());
469*d57664e9SAndroid Build Coastguard Worker         const auto& res_value = entry.res_value();
470*d57664e9SAndroid Build Coastguard Worker         result.pairs.emplace_back(OverlayData::Value{
471*d57664e9SAndroid Build Coastguard Worker             name, TargetValueWithConfig{.value = TargetValue{
472*d57664e9SAndroid Build Coastguard Worker                     .data_type = static_cast<uint8_t>(res_value.data_type()),
473*d57664e9SAndroid Build Coastguard Worker                     .data_value = res_value.data_value()}, .config = entry.configuration()}});
474*d57664e9SAndroid Build Coastguard Worker       }
475*d57664e9SAndroid Build Coastguard Worker     }
476*d57664e9SAndroid Build Coastguard Worker   }
477*d57664e9SAndroid Build Coastguard Worker   const uint32_t string_pool_data_length = overlay_.string_pool_data_.length();
478*d57664e9SAndroid Build Coastguard Worker   result.string_pool_data = OverlayData::InlineStringPoolData{
479*d57664e9SAndroid Build Coastguard Worker       .data = std::unique_ptr<uint8_t[]>(new uint8_t[string_pool_data_length]),
480*d57664e9SAndroid Build Coastguard Worker       .data_length = string_pool_data_length,
481*d57664e9SAndroid Build Coastguard Worker       .string_pool_offset = 0,
482*d57664e9SAndroid Build Coastguard Worker   };
483*d57664e9SAndroid Build Coastguard Worker   memcpy(result.string_pool_data->data.get(), overlay_.string_pool_data_.data(),
484*d57664e9SAndroid Build Coastguard Worker        string_pool_data_length);
485*d57664e9SAndroid Build Coastguard Worker   return result;
486*d57664e9SAndroid Build Coastguard Worker }
487*d57664e9SAndroid Build Coastguard Worker 
GetCrc() const488*d57664e9SAndroid Build Coastguard Worker Result<uint32_t> FabContainer::GetCrc() const {
489*d57664e9SAndroid Build Coastguard Worker   return overlay_.GetCrc();
490*d57664e9SAndroid Build Coastguard Worker }
491*d57664e9SAndroid Build Coastguard Worker 
GetPath() const492*d57664e9SAndroid Build Coastguard Worker const std::string& FabContainer::GetPath() const {
493*d57664e9SAndroid Build Coastguard Worker   return path_;
494*d57664e9SAndroid Build Coastguard Worker }
495*d57664e9SAndroid Build Coastguard Worker 
GetResourceName(ResourceId) const496*d57664e9SAndroid Build Coastguard Worker Result<std::string> FabContainer::GetResourceName(ResourceId /* id */) const {
497*d57664e9SAndroid Build Coastguard Worker   return Error("Fabricated overlay does not contain resources.");
498*d57664e9SAndroid Build Coastguard Worker }
499*d57664e9SAndroid Build Coastguard Worker 
500*d57664e9SAndroid Build Coastguard Worker }  // namespace android::idmap2
501