blob: 6c3eae11eab9e1f8e642000df7c232344f42e9e2 [file] [log] [blame]
Adam Lesinski8780eb62017-10-31 17:44:39 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ryan Mitchell833a1a62018-07-10 13:51:36 -070017#include "Convert.h"
18
Adam Lesinski8780eb62017-10-31 17:44:39 -070019#include <vector>
20
Jeremy Meyer56f36e82022-05-20 20:35:42 +000021#include "Diagnostics.h"
Adam Lesinski8780eb62017-10-31 17:44:39 -070022#include "LoadedApk.h"
23#include "ValueVisitor.h"
Iurii Makhno054e4332022-10-12 16:03:03 +000024#include "android-base/file.h"
Iurii Makhno549938a2022-04-26 19:36:51 +000025#include "android-base/macros.h"
Iurii Makhno054e4332022-10-12 16:03:03 +000026#include "android-base/stringprintf.h"
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000027#include "androidfw/BigBufferStream.h"
Iurii Makhno549938a2022-04-26 19:36:51 +000028#include "androidfw/StringPiece.h"
Adam Lesinski8780eb62017-10-31 17:44:39 -070029#include "cmd/Util.h"
30#include "format/binary/TableFlattener.h"
31#include "format/binary/XmlFlattener.h"
32#include "format/proto/ProtoDeserialize.h"
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000033#include "format/proto/ProtoSerialize.h"
Adam Lesinski8780eb62017-10-31 17:44:39 -070034#include "io/Util.h"
35#include "process/IResourceTableConsumer.h"
36#include "process/SymbolTable.h"
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000037#include "util/Util.h"
Adam Lesinski8780eb62017-10-31 17:44:39 -070038
39using ::android::StringPiece;
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000040using ::android::base::StringPrintf;
Adam Lesinski8780eb62017-10-31 17:44:39 -070041using ::std::unique_ptr;
42using ::std::vector;
43
44namespace aapt {
45
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000046class IApkSerializer {
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000047 public:
Jeremy Meyer56f36e82022-05-20 20:35:42 +000048 IApkSerializer(IAaptContext* context, const android::Source& source)
49 : context_(context), source_(source) {
50 }
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000051
52 virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
Ryan Mitchell05aebf42018-10-09 15:08:41 -070053 IArchiveWriter* writer, uint32_t compression_flags) = 0;
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000054 virtual bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) = 0;
David Chaloupkab66db4e2018-01-15 12:35:41 +000055 virtual bool SerializeFile(FileReference* file, IArchiveWriter* writer) = 0;
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000056
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000057 virtual ~IApkSerializer() = default;
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000058
59 protected:
60 IAaptContext* context_;
Jeremy Meyer56f36e82022-05-20 20:35:42 +000061 android::Source source_;
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000062};
Adam Lesinski8780eb62017-10-31 17:44:39 -070063
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000064class BinaryApkSerializer : public IApkSerializer {
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000065 public:
Jeremy Meyer56f36e82022-05-20 20:35:42 +000066 BinaryApkSerializer(IAaptContext* context, const android::Source& source,
Ryan Mitchell479fa392019-01-02 17:15:39 -080067 const TableFlattenerOptions& table_flattener_options,
68 const XmlFlattenerOptions& xml_flattener_options)
69 : IApkSerializer(context, source),
70 table_flattener_options_(table_flattener_options),
Jeremy Meyer56f36e82022-05-20 20:35:42 +000071 xml_flattener_options_(xml_flattener_options) {
72 }
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000073
74 bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
Ryan Mitchell05aebf42018-10-09 15:08:41 -070075 IArchiveWriter* writer, uint32_t compression_flags) override {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000076 android::BigBuffer buffer(4096);
Ryan Mitchell479fa392019-01-02 17:15:39 -080077 xml_flattener_options_.use_utf16 = utf16;
78 XmlFlattener flattener(&buffer, xml_flattener_options_);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000079 if (!flattener.Consume(context_, xml)) {
80 return false;
81 }
82
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000083 android::BigBufferInputStream input_stream(&buffer);
Ryan Mitchell05aebf42018-10-09 15:08:41 -070084 return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000085 }
86
Pierre Lecesned8b4bea2017-11-10 23:50:17 +000087 bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000088 android::BigBuffer buffer(4096);
Ryan Mitchell479fa392019-01-02 17:15:39 -080089 TableFlattener table_flattener(table_flattener_options_, &buffer);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000090 if (!table_flattener.Consume(context_, table)) {
91 return false;
92 }
93
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000094 android::BigBufferInputStream input_stream(&buffer);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +000095 return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
96 ArchiveEntry::kAlign, writer);
97 }
98
David Chaloupkab66db4e2018-01-15 12:35:41 +000099 bool SerializeFile(FileReference* file, IArchiveWriter* writer) override {
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000100 if (file->type == ResourceFile::Type::kProtoXml) {
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +0000101 unique_ptr<android::InputStream> in = file->file->OpenInputStream();
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000102 if (in == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000103 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000104 << "failed to open file " << *file->path);
105 return false;
106 }
107
108 pb::XmlNode pb_node;
Ryan Mitchelle0eba7a2018-09-12 08:54:07 -0700109 io::ProtoInputStreamReader proto_reader(in.get());
110 if (!proto_reader.ReadMessage(&pb_node)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000111 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000112 << "failed to parse proto XML " << *file->path);
113 return false;
114 }
115
116 std::string error;
117 unique_ptr<xml::XmlResource> xml = DeserializeXmlResourceFromPb(pb_node, &error);
118 if (xml == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000119 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
120 << "failed to deserialize proto XML " << *file->path
121 << ": " << error);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000122 return false;
123 }
124
Ryan Mitchell05aebf42018-10-09 15:08:41 -0700125 if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
126 file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000127 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000128 << "failed to serialize to binary XML: " << *file->path);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000129 return false;
130 }
David Chaloupkab66db4e2018-01-15 12:35:41 +0000131
132 file->type = ResourceFile::Type::kBinaryXml;
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000133 } else {
Pierre Lecesned55bef72017-11-10 22:31:01 +0000134 if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000135 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Pierre Lecesned55bef72017-11-10 22:31:01 +0000136 << "failed to copy file " << *file->path);
137 return false;
138 }
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000139 }
140
141 return true;
142 }
143
144 private:
Ryan Mitchell479fa392019-01-02 17:15:39 -0800145 TableFlattenerOptions table_flattener_options_;
146 XmlFlattenerOptions xml_flattener_options_;
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000147
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000148 DISALLOW_COPY_AND_ASSIGN(BinaryApkSerializer);
149};
150
151class ProtoApkSerializer : public IApkSerializer {
152 public:
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000153 ProtoApkSerializer(IAaptContext* context, const android::Source& source)
154 : IApkSerializer(context, source) {
155 }
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000156
157 bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
Ryan Mitchell05aebf42018-10-09 15:08:41 -0700158 IArchiveWriter* writer, uint32_t compression_flags) override {
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000159 pb::XmlNode pb_node;
160 SerializeXmlResourceToPb(*xml, &pb_node);
Ryan Mitchell05aebf42018-10-09 15:08:41 -0700161 return io::CopyProtoToArchive(context_, &pb_node, path, compression_flags, writer);
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000162 }
163
164 bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
165 pb::ResourceTable pb_table;
Ryan Mitchella15c2a82018-03-26 11:05:31 -0700166 SerializeTableToPb(*table, &pb_table, context_->GetDiagnostics());
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000167 return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath,
168 ArchiveEntry::kCompress, writer);
169 }
170
David Chaloupkab66db4e2018-01-15 12:35:41 +0000171 bool SerializeFile(FileReference* file, IArchiveWriter* writer) override {
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000172 if (file->type == ResourceFile::Type::kBinaryXml) {
173 std::unique_ptr<io::IData> data = file->file->OpenAsData();
174 if (!data) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000175 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Ryan Mitchell90b7a082019-02-15 17:39:58 +0000176 << "failed to open file " << *file->path);
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000177 return false;
178 }
179
180 std::string error;
181 std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error);
182 if (xml == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000183 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
184 << "failed to parse binary XML: " << error);
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000185 return false;
186 }
187
Ryan Mitchell05aebf42018-10-09 15:08:41 -0700188 if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
189 file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000190 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000191 << "failed to serialize to proto XML: " << *file->path);
192 return false;
193 }
David Chaloupkab66db4e2018-01-15 12:35:41 +0000194
195 file->type = ResourceFile::Type::kProtoXml;
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000196 } else {
197 if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000198 context_->GetDiagnostics()->Error(android::DiagMessage(source_)
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000199 << "failed to copy file " << *file->path);
200 return false;
201 }
202 }
203
204 return true;
205 }
206
207 private:
208 DISALLOW_COPY_AND_ASSIGN(ProtoApkSerializer);
Pierre Lecesne7e8549d2017-11-10 01:22:12 +0000209};
210
Adam Lesinski8780eb62017-10-31 17:44:39 -0700211class Context : public IAaptContext {
212 public:
213 Context() : mangler_({}), symbols_(&mangler_) {
214 }
215
216 PackageType GetPackageType() override {
217 return PackageType::kApp;
218 }
219
220 SymbolTable* GetExternalSymbols() override {
221 return &symbols_;
222 }
223
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000224 android::IDiagnostics* GetDiagnostics() override {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700225 return &diag_;
226 }
227
228 const std::string& GetCompilationPackage() override {
229 return package_;
230 }
231
232 uint8_t GetPackageId() override {
233 // Nothing should call this.
234 UNIMPLEMENTED(FATAL) << "PackageID should not be necessary";
235 return 0;
236 }
237
238 NameMangler* GetNameMangler() override {
239 UNIMPLEMENTED(FATAL);
240 return nullptr;
241 }
242
243 bool IsVerbose() override {
244 return verbose_;
245 }
246
Yurii Zubrytskyidc3529e2024-08-09 10:55:05 -0700247 void SetVerbose(bool verbose) {
248 verbose_ = verbose;
249 }
250
Adam Lesinski8780eb62017-10-31 17:44:39 -0700251 int GetMinSdkVersion() override {
Iurii Makhno549938a2022-04-26 19:36:51 +0000252 return min_sdk_;
Adam Lesinski8780eb62017-10-31 17:44:39 -0700253 }
254
Udam Sainib228df32019-06-18 16:50:34 -0700255 const std::set<std::string>& GetSplitNameDependencies() override {
256 UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
257 static std::set<std::string> empty;
258 return empty;
259 }
260
Adam Lesinski8780eb62017-10-31 17:44:39 -0700261 bool verbose_ = false;
262 std::string package_;
Iurii Makhno549938a2022-04-26 19:36:51 +0000263 int32_t min_sdk_ = 0;
Adam Lesinski8780eb62017-10-31 17:44:39 -0700264
265 private:
266 DISALLOW_COPY_AND_ASSIGN(Context);
267
268 NameMangler mangler_;
269 SymbolTable symbols_;
270 StdErrDiagnostics diag_;
271};
272
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800273int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer,
Ryan Mitchell479fa392019-01-02 17:15:39 -0800274 ApkFormat output_format, TableFlattenerOptions table_flattener_options,
275 XmlFlattenerOptions xml_flattener_options) {
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800276 unique_ptr<IApkSerializer> serializer;
277 if (output_format == ApkFormat::kBinary) {
Ryan Mitchell479fa392019-01-02 17:15:39 -0800278 serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), table_flattener_options,
279 xml_flattener_options));
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800280 } else if (output_format == ApkFormat::kProto) {
281 serializer.reset(new ProtoApkSerializer(context, apk->GetSource()));
282 } else {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000283 context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800284 << "Cannot convert APK to unknown format");
285 return 1;
286 }
287
288 io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
289 if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/,
290 output_writer, (manifest != nullptr && manifest->WasCompressed())
Ryan Mitchell90b7a082019-02-15 17:39:58 +0000291 ? ArchiveEntry::kCompress : 0u)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000292 context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800293 << "failed to serialize AndroidManifest.xml");
294 return 1;
295 }
296
297 if (apk->GetResourceTable() != nullptr) {
298 // The table might be modified by below code.
299 auto converted_table = apk->GetResourceTable();
300
Winsonf54c9a12019-01-23 12:39:40 -0800301 std::unordered_set<std::string> files_written;
302
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800303 // Resources
304 for (const auto& package : converted_table->packages) {
305 for (const auto& type : package->types) {
306 for (const auto& entry : type->entries) {
307 for (const auto& config_value : entry->values) {
308 FileReference* file = ValueCast<FileReference>(config_value->value.get());
309 if (file != nullptr) {
310 if (file->file == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000311 context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800312 << "no file associated with " << *file);
313 return 1;
314 }
315
Winsonf54c9a12019-01-23 12:39:40 -0800316 // Only serialize if we haven't seen this file before
317 if (files_written.insert(*file->path).second) {
318 if (!serializer->SerializeFile(file, output_writer)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000319 context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
Ryan Mitchell90b7a082019-02-15 17:39:58 +0000320 << "failed to serialize file " << *file->path);
Winsonf54c9a12019-01-23 12:39:40 -0800321 return 1;
322 }
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800323 }
324 } // file
325 } // config_value
326 } // entry
327 } // type
328 } // package
329
330 // Converted resource table
331 if (!serializer->SerializeTable(converted_table, output_writer)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000332 context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800333 << "failed to serialize the resource table");
334 return 1;
335 }
336 }
337
338 // Other files
339 std::unique_ptr<io::IFileCollectionIterator> iterator = apk->GetFileCollection()->Iterator();
340 while (iterator->HasNext()) {
341 io::IFile* file = iterator->Next();
342 std::string path = file->GetSource().path;
343
344 // Manifest, resource table and resources have already been taken care of.
345 if (path == kAndroidManifestPath ||
346 path == kApkResourceTablePath ||
347 path == kProtoResourceTablePath ||
348 path.find("res/") == 0) {
349 continue;
350 }
351
352 if (!io::CopyFileToArchivePreserveCompression(context, file, path, output_writer)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000353 context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
354 << "failed to copy file " << path);
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800355 return 1;
356 }
357 }
358
359 return 0;
360}
361
Iurii Makhno054e4332022-10-12 16:03:03 +0000362bool ExtractResourceConfig(const std::string& path, IAaptContext* context,
363 TableFlattenerOptions& out_options) {
364 std::string content;
365 if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
366 context->GetDiagnostics()->Error(android::DiagMessage(path) << "failed reading config file");
367 return false;
368 }
369 std::unordered_set<ResourceName> resources_exclude_list;
370 bool result = ParseResourceConfig(content, context, resources_exclude_list,
branliuf1ed5232022-12-16 19:02:29 +0800371 out_options.name_collapse_exemptions,
372 out_options.path_shorten_exemptions);
Iurii Makhno054e4332022-10-12 16:03:03 +0000373 if (!result) {
374 return false;
375 }
376 if (!resources_exclude_list.empty()) {
377 context->GetDiagnostics()->Error(android::DiagMessage(path)
378 << "Unsupported '#remove' directive in resource config.");
379 return false;
380 }
381 return true;
382}
383
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700384const char* ConvertCommand::kOutputFormatProto = "proto";
385const char* ConvertCommand::kOutputFormatBinary = "binary";
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000386
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700387int ConvertCommand::Action(const std::vector<std::string>& args) {
388 if (args.size() != 1) {
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800389 std::cerr << "must supply a single APK\n";
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700390 Usage(&std::cerr);
391 return 1;
392 }
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000393
Adam Lesinski8780eb62017-10-31 17:44:39 -0700394 Context context;
Yurii Zubrytskyidc3529e2024-08-09 10:55:05 -0700395 context.SetVerbose(verbose_);
396
Yurii Zubrytskyia5775142022-11-02 17:49:49 -0700397 StringPiece path = args[0];
Adam Lesinski8780eb62017-10-31 17:44:39 -0700398 unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
399 if (apk == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000400 context.GetDiagnostics()->Error(android::DiagMessage(path) << "failed to load APK");
Adam Lesinski8780eb62017-10-31 17:44:39 -0700401 return 1;
402 }
403
Ryan Mitchell4382e442021-07-14 12:53:01 -0700404 auto app_info = ExtractAppInfoFromBinaryManifest(*apk->GetManifest(), context.GetDiagnostics());
Adam Lesinski8780eb62017-10-31 17:44:39 -0700405 if (!app_info) {
406 return 1;
407 }
408
409 context.package_ = app_info.value().package;
Iurii Makhno549938a2022-04-26 19:36:51 +0000410 context.min_sdk_ = app_info.value().min_sdk_version.value_or(0);
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800411 unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(context.GetDiagnostics(),
412 output_path_);
Adam Lesinski8780eb62017-10-31 17:44:39 -0700413 if (writer == nullptr) {
414 return 1;
415 }
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000416
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800417 ApkFormat format;
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700418 if (!output_format_ || output_format_.value() == ConvertCommand::kOutputFormatBinary) {
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800419 format = ApkFormat::kBinary;
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700420 } else if (output_format_.value() == ConvertCommand::kOutputFormatProto) {
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800421 format = ApkFormat::kProto;
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000422 } else {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000423 context.GetDiagnostics()->Error(android::DiagMessage(path)
424 << "Invalid value for flag --output-format: "
425 << output_format_.value());
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000426 return 1;
427 }
Iurii Makhnoda06e4d2022-08-24 14:17:32 +0000428 if (enable_sparse_encoding_) {
429 table_flattener_options_.sparse_entries = SparseEntriesMode::Enabled;
430 }
431 if (force_sparse_encoding_) {
432 table_flattener_options_.sparse_entries = SparseEntriesMode::Forced;
433 }
Rico Windec629dd2023-08-01 14:11:45 +0200434 table_flattener_options_.use_compact_entries = enable_compact_entries_;
Iurii Makhno054e4332022-10-12 16:03:03 +0000435 if (resources_config_path_) {
436 if (!ExtractResourceConfig(*resources_config_path_, &context, table_flattener_options_)) {
437 return 1;
438 }
439 }
Pierre Lecesned8b4bea2017-11-10 23:50:17 +0000440
Ryan Mitchell479fa392019-01-02 17:15:39 -0800441 return Convert(&context, apk.get(), writer.get(), format, table_flattener_options_,
442 xml_flattener_options_);
Adam Lesinski8780eb62017-10-31 17:44:39 -0700443}
444
445} // namespace aapt