blob: 3d2fb556cf591c08a3c1fdaefe2d92296d9cd1d0 [file] [log] [blame]
Adam Lesinski59e04c62016-02-04 15:59:23 -08001/*
2 * Copyright (C) 2016 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
Adam Lesinski93190b72017-11-03 15:20:17 -070017#include <cinttypes>
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018#include <vector>
19
Adam Lesinski93190b72017-11-03 15:20:17 -070020#include "android-base/stringprintf.h"
Adam Lesinskid5083f62017-01-16 15:07:21 -080021#include "androidfw/StringPiece.h"
22
Adam Lesinski59e04c62016-02-04 15:59:23 -080023#include "Debug.h"
24#include "Diagnostics.h"
25#include "Flags.h"
Adam Lesinski00451162017-10-03 07:44:08 -070026#include "format/Container.h"
Adam Lesinski46708052017-09-29 14:49:15 -070027#include "format/binary/BinaryResourceParser.h"
28#include "format/proto/ProtoDeserialize.h"
Adam Lesinski00451162017-10-03 07:44:08 -070029#include "io/FileStream.h"
Adam Lesinski64587af2016-02-18 18:33:06 -080030#include "io/ZipArchive.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080031#include "process/IResourceTableConsumer.h"
Adam Lesinski93190b72017-11-03 15:20:17 -070032#include "text/Printer.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080033#include "util/Files.h"
Adam Lesinskid5083f62017-01-16 15:07:21 -080034
Adam Lesinski93190b72017-11-03 15:20:17 -070035using ::aapt::text::Printer;
Adam Lesinski4ffea042017-08-10 15:37:28 -070036using ::android::StringPiece;
Adam Lesinski93190b72017-11-03 15:20:17 -070037using ::android::base::StringPrintf;
Adam Lesinski59e04c62016-02-04 15:59:23 -080038
Adam Lesinski59e04c62016-02-04 15:59:23 -080039namespace aapt {
40
Adam Lesinski00451162017-10-03 07:44:08 -070041static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
42 switch (type) {
43 case ResourceFile::Type::kPng:
44 return "PNG";
45 case ResourceFile::Type::kBinaryXml:
46 return "BINARY_XML";
47 case ResourceFile::Type::kProtoXml:
48 return "PROTO_XML";
49 default:
50 break;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 }
Adam Lesinski00451162017-10-03 07:44:08 -070052 return "UNKNOWN";
Adam Lesinski59e04c62016-02-04 15:59:23 -080053}
54
Adam Lesinski00451162017-10-03 07:44:08 -070055static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
Adam Lesinski93190b72017-11-03 15:20:17 -070056 size_t len, Printer* printer) {
57 printer->Print("Resource: ");
58 printer->Println(file.name.to_string());
59
60 printer->Print("Config: ");
61 printer->Println(file.config.to_string());
62
63 printer->Print("Source: ");
64 printer->Println(file.source.to_string());
65
66 printer->Print("Type: ");
67 printer->Println(ResourceFileTypeToString(file.type));
68
69 printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
Adam Lesinski00451162017-10-03 07:44:08 -070070}
71
Adam Lesinski71be7052017-12-12 16:48:07 -080072static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
73 const DebugPrintTableOptions& print_options) {
Adam Lesinski93190b72017-11-03 15:20:17 -070074 // Use a smaller buffer so that there is less latency for dumping to stdout.
75 constexpr size_t kStdOutBufferSize = 1024u;
76 io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
77 Printer printer(&fout);
78
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 std::string err;
Adam Lesinskid0f492d2017-04-03 18:12:45 -070080 std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070081 if (zip) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070082 ResourceTable table;
Adam Lesinskie59f0d82017-10-13 09:36:53 -070083 if (io::IFile* file = zip->FindFile("resources.pb")) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070084 std::unique_ptr<io::IData> data = file->OpenAsData();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070085 if (data == nullptr) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -070086 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010087 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070088 }
Adam Lesinski64587af2016-02-18 18:33:06 -080089
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 pb::ResourceTable pb_table;
91 if (!pb_table.ParseFromArray(data->data(), data->size())) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -070092 context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010093 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094 }
Adam Lesinski64587af2016-02-18 18:33:06 -080095
Adam Lesinski8780eb62017-10-31 17:44:39 -070096 if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070097 context->GetDiagnostics()->Error(DiagMessage(file_path)
98 << "failed to parse table: " << err);
99 return false;
100 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700101
102 printer.Println("Proto APK");
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700103 } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
104 std::unique_ptr<io::IData> data = file->OpenAsData();
105 if (!data) {
106 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
107 return false;
108 }
109
Adam Lesinski8780eb62017-10-31 17:44:39 -0700110 BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path),
111 data->data(), data->size());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700112 if (!parser.Parse()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100113 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700114 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700115
116 printer.Println("Binary APK");
Adam Lesinski64587af2016-02-18 18:33:06 -0800117 }
118
Adam Lesinski93190b72017-11-03 15:20:17 -0700119 Debug::PrintTable(table, print_options, &printer);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700120 return true;
121 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700122
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700123 err.clear();
124
Adam Lesinski00451162017-10-03 07:44:08 -0700125 io::FileInputStream input(file_path);
126 if (input.HadError()) {
127 context->GetDiagnostics()->Error(DiagMessage(file_path)
128 << "failed to open file: " << input.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700129 return false;
130 }
131
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700132 // Try as a compiled file.
Adam Lesinski00451162017-10-03 07:44:08 -0700133 ContainerReader reader(&input);
134 if (reader.HadError()) {
135 context->GetDiagnostics()->Error(DiagMessage(file_path)
136 << "failed to read container: " << reader.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700137 return false;
138 }
139
Adam Lesinski93190b72017-11-03 15:20:17 -0700140 printer.Println("AAPT2 Container (APC)");
Adam Lesinski00451162017-10-03 07:44:08 -0700141 ContainerReaderEntry* entry;
142 while ((entry = reader.Next()) != nullptr) {
143 if (entry->Type() == ContainerEntryType::kResTable) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700144 printer.Println("kResTable");
145
Adam Lesinski00451162017-10-03 07:44:08 -0700146 pb::ResourceTable pb_table;
147 if (!entry->GetResTable(&pb_table)) {
148 context->GetDiagnostics()->Error(DiagMessage(file_path)
149 << "failed to parse proto table: " << entry->GetError());
150 continue;
151 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800152
Adam Lesinski00451162017-10-03 07:44:08 -0700153 ResourceTable table;
154 err.clear();
Adam Lesinski8780eb62017-10-31 17:44:39 -0700155 if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) {
Adam Lesinski00451162017-10-03 07:44:08 -0700156 context->GetDiagnostics()->Error(DiagMessage(file_path)
157 << "failed to parse table: " << err);
158 continue;
159 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160
Adam Lesinski93190b72017-11-03 15:20:17 -0700161 printer.Indent();
162 Debug::PrintTable(table, print_options, &printer);
163 printer.Undent();
Adam Lesinski00451162017-10-03 07:44:08 -0700164 } else if (entry->Type() == ContainerEntryType::kResFile) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700165 printer.Println("kResFile");
Adam Lesinski00451162017-10-03 07:44:08 -0700166 pb::internal::CompiledFile pb_compiled_file;
167 off64_t offset;
168 size_t length;
169 if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
170 context->GetDiagnostics()->Error(
171 DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
172 continue;
173 }
174
175 ResourceFile file;
176 std::string error;
177 if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
178 context->GetDiagnostics()->Warn(DiagMessage(file_path)
179 << "failed to parse compiled file: " << error);
180 continue;
181 }
182
Adam Lesinski93190b72017-11-03 15:20:17 -0700183 printer.Indent();
184 DumpCompiledFile(file, Source(file_path), offset, length, &printer);
185 printer.Undent();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 }
187 }
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100188 return true;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800189}
190
Adam Lesinski00451162017-10-03 07:44:08 -0700191namespace {
192
Adam Lesinski59e04c62016-02-04 15:59:23 -0800193class DumpContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194 public:
Adam Lesinskib522f042017-04-21 16:57:59 -0700195 PackageType GetPackageType() override {
196 // Doesn't matter.
197 return PackageType::kApp;
198 }
199
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700200 IDiagnostics* GetDiagnostics() override {
201 return &diagnostics_;
202 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800203
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 NameMangler* GetNameMangler() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700205 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700206 return nullptr;
207 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800208
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 const std::string& GetCompilationPackage() override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 static std::string empty;
211 return empty;
212 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800213
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700214 uint8_t GetPackageId() override {
215 return 0;
216 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800217
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 SymbolTable* GetExternalSymbols() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700219 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700220 return nullptr;
221 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800222
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700223 bool IsVerbose() override {
224 return verbose_;
225 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800226
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700227 void SetVerbose(bool val) {
228 verbose_ = val;
229 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800230
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700231 int GetMinSdkVersion() override {
232 return 0;
233 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -0700234
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 StdErrDiagnostics diagnostics_;
237 bool verbose_ = false;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800238};
239
Adam Lesinski00451162017-10-03 07:44:08 -0700240} // namespace
241
242// Entry point for dump command.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700243int Dump(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700244 bool verbose = false;
Adam Lesinski71be7052017-12-12 16:48:07 -0800245 bool no_values = false;
246 Flags flags = Flags()
247 .OptionalSwitch("--no-values",
248 "Suppresses output of values when displaying resource tables.",
249 &no_values)
250 .OptionalSwitch("-v", "increase verbosity of output", &verbose);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700251 if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700252 return 1;
253 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800254
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700255 DumpContext context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700256 context.SetVerbose(verbose);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800257
Adam Lesinski71be7052017-12-12 16:48:07 -0800258 DebugPrintTableOptions dump_table_options;
259 dump_table_options.show_sources = true;
260 dump_table_options.show_values = !no_values;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700261 for (const std::string& arg : flags.GetArgs()) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800262 if (!TryDumpFile(&context, arg, dump_table_options)) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100263 return 1;
264 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700265 }
266 return 0;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800267}
268
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269} // namespace aapt