blob: bc7f5a86b0434b697fe2e129792657147625bee2 [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
72static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
Adam Lesinski93190b72017-11-03 15:20:17 -070073 // Use a smaller buffer so that there is less latency for dumping to stdout.
74 constexpr size_t kStdOutBufferSize = 1024u;
75 io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
76 Printer printer(&fout);
77
Adam Lesinski00451162017-10-03 07:44:08 -070078 DebugPrintTableOptions print_options;
79 print_options.show_sources = true;
80
Adam Lesinskicacb28f2016-10-19 12:18:14 -070081 std::string err;
Adam Lesinskid0f492d2017-04-03 18:12:45 -070082 std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083 if (zip) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070084 ResourceTable table;
Adam Lesinskie59f0d82017-10-13 09:36:53 -070085 if (io::IFile* file = zip->FindFile("resources.pb")) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070086 std::unique_ptr<io::IData> data = file->OpenAsData();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070087 if (data == nullptr) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -070088 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010089 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070090 }
Adam Lesinski64587af2016-02-18 18:33:06 -080091
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 pb::ResourceTable pb_table;
93 if (!pb_table.ParseFromArray(data->data(), data->size())) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -070094 context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010095 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070096 }
Adam Lesinski64587af2016-02-18 18:33:06 -080097
Adam Lesinski8780eb62017-10-31 17:44:39 -070098 if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070099 context->GetDiagnostics()->Error(DiagMessage(file_path)
100 << "failed to parse table: " << err);
101 return false;
102 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700103
104 printer.Println("Proto APK");
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700105 } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
106 std::unique_ptr<io::IData> data = file->OpenAsData();
107 if (!data) {
108 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
109 return false;
110 }
111
Adam Lesinski8780eb62017-10-31 17:44:39 -0700112 BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path),
113 data->data(), data->size());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700114 if (!parser.Parse()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100115 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700116 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700117
118 printer.Println("Binary APK");
Adam Lesinski64587af2016-02-18 18:33:06 -0800119 }
120
Adam Lesinski93190b72017-11-03 15:20:17 -0700121 Debug::PrintTable(table, print_options, &printer);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700122 return true;
123 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700124
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700125 err.clear();
126
Adam Lesinski00451162017-10-03 07:44:08 -0700127 io::FileInputStream input(file_path);
128 if (input.HadError()) {
129 context->GetDiagnostics()->Error(DiagMessage(file_path)
130 << "failed to open file: " << input.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700131 return false;
132 }
133
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700134 // Try as a compiled file.
Adam Lesinski00451162017-10-03 07:44:08 -0700135 ContainerReader reader(&input);
136 if (reader.HadError()) {
137 context->GetDiagnostics()->Error(DiagMessage(file_path)
138 << "failed to read container: " << reader.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700139 return false;
140 }
141
Adam Lesinski93190b72017-11-03 15:20:17 -0700142 printer.Println("AAPT2 Container (APC)");
Adam Lesinski00451162017-10-03 07:44:08 -0700143 ContainerReaderEntry* entry;
144 while ((entry = reader.Next()) != nullptr) {
145 if (entry->Type() == ContainerEntryType::kResTable) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700146 printer.Println("kResTable");
147
Adam Lesinski00451162017-10-03 07:44:08 -0700148 pb::ResourceTable pb_table;
149 if (!entry->GetResTable(&pb_table)) {
150 context->GetDiagnostics()->Error(DiagMessage(file_path)
151 << "failed to parse proto table: " << entry->GetError());
152 continue;
153 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800154
Adam Lesinski00451162017-10-03 07:44:08 -0700155 ResourceTable table;
156 err.clear();
Adam Lesinski8780eb62017-10-31 17:44:39 -0700157 if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) {
Adam Lesinski00451162017-10-03 07:44:08 -0700158 context->GetDiagnostics()->Error(DiagMessage(file_path)
159 << "failed to parse table: " << err);
160 continue;
161 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162
Adam Lesinski93190b72017-11-03 15:20:17 -0700163 printer.Indent();
164 Debug::PrintTable(table, print_options, &printer);
165 printer.Undent();
Adam Lesinski00451162017-10-03 07:44:08 -0700166 } else if (entry->Type() == ContainerEntryType::kResFile) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700167 printer.Println("kResFile");
Adam Lesinski00451162017-10-03 07:44:08 -0700168 pb::internal::CompiledFile pb_compiled_file;
169 off64_t offset;
170 size_t length;
171 if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
172 context->GetDiagnostics()->Error(
173 DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
174 continue;
175 }
176
177 ResourceFile file;
178 std::string error;
179 if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
180 context->GetDiagnostics()->Warn(DiagMessage(file_path)
181 << "failed to parse compiled file: " << error);
182 continue;
183 }
184
Adam Lesinski93190b72017-11-03 15:20:17 -0700185 printer.Indent();
186 DumpCompiledFile(file, Source(file_path), offset, length, &printer);
187 printer.Undent();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700188 }
189 }
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100190 return true;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800191}
192
Adam Lesinski00451162017-10-03 07:44:08 -0700193namespace {
194
Adam Lesinski59e04c62016-02-04 15:59:23 -0800195class DumpContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196 public:
Adam Lesinskib522f042017-04-21 16:57:59 -0700197 PackageType GetPackageType() override {
198 // Doesn't matter.
199 return PackageType::kApp;
200 }
201
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700202 IDiagnostics* GetDiagnostics() override {
203 return &diagnostics_;
204 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800205
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700206 NameMangler* GetNameMangler() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700207 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700208 return nullptr;
209 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800210
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211 const std::string& GetCompilationPackage() override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 static std::string empty;
213 return empty;
214 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800215
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700216 uint8_t GetPackageId() override {
217 return 0;
218 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800219
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 SymbolTable* GetExternalSymbols() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700221 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222 return nullptr;
223 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800224
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700225 bool IsVerbose() override {
226 return verbose_;
227 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800228
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700229 void SetVerbose(bool val) {
230 verbose_ = val;
231 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800232
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700233 int GetMinSdkVersion() override {
234 return 0;
235 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -0700236
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700237 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700238 StdErrDiagnostics diagnostics_;
239 bool verbose_ = false;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800240};
241
Adam Lesinski00451162017-10-03 07:44:08 -0700242} // namespace
243
244// Entry point for dump command.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700245int Dump(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700246 bool verbose = false;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700247 Flags flags = Flags().OptionalSwitch("-v", "increase verbosity of output", &verbose);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700248 if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700249 return 1;
250 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800251
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700252 DumpContext context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700253 context.SetVerbose(verbose);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800254
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700255 for (const std::string& arg : flags.GetArgs()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100256 if (!TryDumpFile(&context, arg)) {
257 return 1;
258 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259 }
260 return 0;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800261}
262
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700263} // namespace aapt