From 833a1a6c4a7b57431ae620fc83f4c17f6fbf6a06 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 10 Jul 2018 13:51:36 -0700 Subject: AAPT2: Refactor flags into commands Refactors the flag based command invocation into classes that make using subcommands easier. Test: manual tests of printing Change-Id: Ic8df6af0be30db552e32150afebecbfeec7e1075 --- tools/aapt2/Main.cpp | 180 +++++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 83 deletions(-) (limited to 'tools/aapt2/Main.cpp') diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 808b29cfd844..23903c9e05f3 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -29,6 +29,13 @@ #include "androidfw/StringPiece.h" #include "Diagnostics.h" +#include "cmd/Command.h" +#include "cmd/Compile.h" +#include "cmd/Convert.h" +#include "cmd/Diff.h" +#include "cmd/Dump.h" +#include "cmd/Link.h" +#include "cmd/Optimize.h" #include "util/Files.h" #include "util/Util.h" @@ -43,114 +50,121 @@ static const char* sMajorVersion = "2"; // Update minor version whenever a feature or flag is added. static const char* sMinorVersion = "19"; -static void PrintVersion() { - std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion, - sMinorVersion) - << std::endl; -} - -static void PrintUsage() { - std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|convert|version] ..." << std::endl; -} +/** Prints the version information of AAPT2. */ +class VersionCommand : public Command { + public: + explicit VersionCommand() : Command("version") { + SetDescription("Prints the version of aapt."); + } -extern int Compile(const std::vector& args, IDiagnostics* diagnostics); -extern int Link(const std::vector& args, IDiagnostics* diagnostics); -extern int Dump(const std::vector& args); -extern int Diff(const std::vector& args); -extern int Optimize(const std::vector& args); -extern int Convert(const std::vector& args); - -static int ExecuteCommand(const StringPiece& command, const std::vector& args, - IDiagnostics* diagnostics) { - if (command == "compile" || command == "c") { - return Compile(args, diagnostics); - } else if (command == "link" || command == "l") { - return Link(args, diagnostics); - } else if (command == "dump" || command == "d") { - return Dump(args); - } else if (command == "diff") { - return Diff(args); - } else if (command == "optimize") { - return Optimize(args); - } else if (command == "convert") { - return Convert(args); - } else if (command == "version") { - PrintVersion(); + int Action(const std::vector& /* args */) override { + std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion, + sMinorVersion) + << std::endl; return 0; } - diagnostics->Error(DiagMessage() << "unknown command '" << command << "'"); - return -1; -} +}; + +/** The main entry point of AAPT. */ +class MainCommand : public Command { + public: + explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) { + AddOptionalSubcommand(util::make_unique(diagnostics)); + AddOptionalSubcommand(util::make_unique(diagnostics)); + AddOptionalSubcommand(util::make_unique()); + AddOptionalSubcommand(util::make_unique()); + AddOptionalSubcommand(util::make_unique()); + AddOptionalSubcommand(util::make_unique()); + AddOptionalSubcommand(util::make_unique()); + } -static void RunDaemon(IDiagnostics* diagnostics) { - std::cout << "Ready" << std::endl; - - // Run in daemon mode. The first line of input is the command. This can be 'quit' which ends - // the daemon mode. Each subsequent line is a single parameter to the command. The end of a - // invocation is signaled by providing an empty line. At any point, an EOF signal or the - // command 'quit' will end the daemon mode. - while (true) { - std::vector raw_args; - for (std::string line; std::getline(std::cin, line) && !line.empty();) { - raw_args.push_back(line); + int Action(const std::vector& args) override { + if (args.size() == 0) { + diagnostics_->Error(DiagMessage() << "no subcommand specified"); + } else { + diagnostics_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'"); } - if (!std::cin) { - break; - } + Usage(&std::cerr); + return -1; + } - // An empty command does nothing. - if (raw_args.empty()) { - continue; - } + private: + IDiagnostics* diagnostics_; +}; - if (raw_args[0] == "quit") { - break; - } +/* + * Run in daemon mode. The first line of input is the command. This can be 'quit' which ends + * the daemon mode. Each subsequent line is a single parameter to the command. The end of a + * invocation is signaled by providing an empty line. At any point, an EOF signal or the + * command 'quit' will end the daemon mode. + */ +class DaemonCommand : public Command { + public: + explicit DaemonCommand(IDiagnostics* diagnostics) : Command("daemon", "m"), + diagnostics_(diagnostics) { + SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n" + "command. The end of an invocation is signaled by providing an empty line."); + } - std::vector args; - args.insert(args.end(), ++raw_args.begin(), raw_args.end()); - int ret = ExecuteCommand(raw_args[0], args, diagnostics); - if (ret != 0) { - std::cerr << "Error" << std::endl; + int Action(const std::vector& /* args */) override { + std::cout << "Ready" << std::endl; + + while (true) { + std::vector raw_args; + for (std::string line; std::getline(std::cin, line) && !line.empty();) { + raw_args.push_back(line); + } + + if (!std::cin) { + break; + } + + // An empty command does nothing. + if (raw_args.empty()) { + continue; + } + + // End the dameon + if (raw_args[0] == "quit") { + break; + } + + std::vector args; + args.insert(args.end(), raw_args.begin(), raw_args.end()); + if (MainCommand(diagnostics_).Execute(args, &std::cerr) != 0) { + std::cerr << "Error" << std::endl; + } + std::cerr << "Done" << std::endl; } - std::cerr << "Done" << std::endl; + std::cout << "Exiting daemon" << std::endl; + + return 0; } - std::cout << "Exiting daemon" << std::endl; -} + + private: + IDiagnostics* diagnostics_; +}; } // namespace aapt int MainImpl(int argc, char** argv) { - if (argc < 2) { - std::cerr << "no command specified\n"; - aapt::PrintUsage(); + if (argc < 1) { return -1; } - argv += 1; - argc -= 1; - - aapt::StdErrDiagnostics diagnostics; - // Collect the arguments starting after the program name and command name. std::vector args; for (int i = 1; i < argc; i++) { args.push_back(argv[i]); } - const StringPiece command(argv[0]); - if (command != "daemon" && command != "m") { - // Single execution. - const int result = aapt::ExecuteCommand(command, args, &diagnostics); - if (result < 0) { - aapt::PrintUsage(); - } - return result; - } + // Add the daemon subcommand here so it cannot be called while executing the daemon + aapt::StdErrDiagnostics diagnostics; + auto main_command = new aapt::MainCommand(&diagnostics); + main_command->AddOptionalSubcommand(aapt::util::make_unique(&diagnostics)); - aapt::RunDaemon(&diagnostics); - return 0; + return main_command->Execute(args, &std::cerr); } int main(int argc, char** argv) { -- cgit v1.2.3-59-g8ed1b From 5d2755129dae6ff6f0061da0abe634f44054b23e Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Thu, 19 Jul 2018 14:29:00 -0700 Subject: AAPT2: Reformatted dump command invocations Use with: aapt2 dump apc [apc] aapt2 dump configurations [apk] aapt2 dump strings [apk] aapt2 dump resources [apk] aapt2 dump xmlstrings [apk] --file [file] aapt2 dump xmltree [apk] --file [file] Will add permissions and badging in a later commit. Bug: 73351292 Test: Manual tests of the commands Change-Id: I97eec01222af14053a98bd70255f1bfecd16b1c4 --- tools/aapt2/Debug.cpp | 35 ++++ tools/aapt2/Debug.h | 1 + tools/aapt2/LoadedApk.cpp | 47 +++++ tools/aapt2/LoadedApk.h | 6 + tools/aapt2/Main.cpp | 2 +- tools/aapt2/cmd/Dump.cpp | 466 ++++++++++++++++++++++++++++------------------ tools/aapt2/cmd/Dump.h | 110 +++++++++-- 7 files changed, 469 insertions(+), 198 deletions(-) (limited to 'tools/aapt2/Main.cpp') diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index f064cb14248f..0a517ab8a2de 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -408,6 +408,41 @@ void Debug::DumpHex(const void* data, size_t len) { } } +void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) { + using namespace android; + + if (pool->getError() == NO_INIT) { + printer->Print("String pool is unitialized.\n"); + return; + } else if (pool->getError() != NO_ERROR) { + printer->Print("String pool is corrupt/invalid.\n"); + return; + } + + SortedVector uniqueStrings; + const size_t N = pool->size(); + for (size_t i=0; iisUTF8()) { + uniqueStrings.add(pool->string8At(i, &len)); + } else { + uniqueStrings.add(pool->stringAt(i, &len)); + } + } + + printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles " + "using %zd bytes:\n", uniqueStrings.size(), + pool->isUTF8() ? "UTF-8" : "UTF-16", + pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(), + pool->bytes())); + + const size_t NS = pool->size(); + for (size_t s=0; sstring8ObjectAt(s); + printer->Print(StringPrintf("String #%zd : %s\n", s, str.string())); + } +} + namespace { class XmlPrinter : public xml::ConstVisitor { diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h index 382707e1d4cd..a43197cacf7b 100644 --- a/tools/aapt2/Debug.h +++ b/tools/aapt2/Debug.h @@ -38,6 +38,7 @@ struct Debug { static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style); static void DumpHex(const void* data, size_t len); static void DumpXml(const xml::XmlResource& doc, text::Printer* printer); + static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer); }; } // namespace aapt diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index b32766be8d18..b6ee1ad83ce3 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -257,6 +257,53 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return true; } +std::unique_ptr LoadedApk::LoadXml(const std::string& file_path, + IDiagnostics* diag) { + io::IFile* file = apk_->FindFile(file_path); + if (file == nullptr) { + diag->Error(DiagMessage() << "failed to find file"); + return nullptr; + } + + std::unique_ptr doc; + if (format_ == ApkFormat::kProto) { + std::unique_ptr in = file->OpenInputStream(); + if (!in) { + diag->Error(DiagMessage() << "failed to open file"); + return nullptr; + } + + io::ZeroCopyInputAdaptor adaptor(in.get()); + pb::XmlNode pb_node; + if (!pb_node.ParseFromZeroCopyStream(&adaptor)) { + diag->Error(DiagMessage() << "failed to parse file as proto XML"); + return nullptr; + } + + std::string err; + doc = DeserializeXmlResourceFromPb(pb_node, &err); + if (!doc) { + diag->Error(DiagMessage() << "failed to deserialize proto XML: " << err); + return nullptr; + } + } else if (format_ == ApkFormat::kBinary) { + std::unique_ptr data = file->OpenAsData(); + if (!data) { + diag->Error(DiagMessage() << "failed to open file"); + return nullptr; + } + + std::string err; + doc = xml::Inflate(data->data(), data->size(), &err); + if (!doc) { + diag->Error(DiagMessage() << "failed to parse file as binary XML: " << err); + return nullptr; + } + } + + return doc; +} + ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) { if (apk->FindFile(kApkResourceTablePath) != nullptr) { return ApkFormat::kBinary; diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h index 41f879d0cdc3..dcb085aa2b0b 100644 --- a/tools/aapt2/LoadedApk.h +++ b/tools/aapt2/LoadedApk.h @@ -70,6 +70,10 @@ class LoadedApk { return apk_.get(); } + ApkFormat GetApkFormat() { + return format_; + } + const ResourceTable* GetResourceTable() const { return table_.get(); } @@ -106,6 +110,8 @@ class LoadedApk { const TableFlattenerOptions& options, FilterChain* filters, IArchiveWriter* writer, xml::XmlResource* manifest = nullptr); + /** Loads the file as an xml document. */ + std::unique_ptr LoadXml(const std::string& file_path, IDiagnostics* diag); private: DISALLOW_COPY_AND_ASSIGN(LoadedApk); diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 23903c9e05f3..37013c07ffef 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -71,7 +71,7 @@ class MainCommand : public Command { explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) { AddOptionalSubcommand(util::make_unique(diagnostics)); AddOptionalSubcommand(util::make_unique(diagnostics)); - AddOptionalSubcommand(util::make_unique()); + AddOptionalSubcommand(util::make_unique(diagnostics)); AddOptionalSubcommand(util::make_unique()); AddOptionalSubcommand(util::make_unique()); AddOptionalSubcommand(util::make_unique()); diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 6e9c80024ddd..b4311c56428b 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -24,8 +24,11 @@ #include "Debug.h" #include "Diagnostics.h" +#include "LoadedApk.h" +#include "Util.h" #include "format/Container.h" #include "format/binary/BinaryResourceParser.h" +#include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" #include "io/FileStream.h" #include "io/ZipArchive.h" @@ -70,184 +73,6 @@ static void DumpCompiledFile(const ResourceFile& file, const Source& source, off printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len)); } -static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto, - text::Printer* printer) { - std::unique_ptr doc; - if (proto) { - std::unique_ptr in = file->OpenInputStream(); - if (in == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to open file"); - return false; - } - - io::ZeroCopyInputAdaptor adaptor(in.get()); - pb::XmlNode pb_node; - if (!pb_node.ParseFromZeroCopyStream(&adaptor)) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML"); - return false; - } - - std::string err; - doc = DeserializeXmlResourceFromPb(pb_node, &err); - if (doc == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML"); - return false; - } - printer->Println("Proto XML"); - } else { - std::unique_ptr data = file->OpenAsData(); - if (data == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to open file"); - return false; - } - - std::string err; - doc = xml::Inflate(data->data(), data->size(), &err); - if (doc == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML"); - return false; - } - printer->Println("Binary XML"); - } - - Debug::DumpXml(*doc, printer); - return true; -} - -static bool TryDumpFile(IAaptContext* context, const std::string& file_path, - const DumpOptions& options) { - // Use a smaller buffer so that there is less latency for dumping to stdout. - constexpr size_t kStdOutBufferSize = 1024u; - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - std::string err; - std::unique_ptr zip = io::ZipFileCollection::Create(file_path, &err); - if (zip) { - ResourceTable table(/** validate_resources **/ false); - bool proto = false; - if (io::IFile* file = zip->FindFile("resources.pb")) { - proto = true; - - std::unique_ptr data = file->OpenAsData(); - if (data == nullptr) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb"); - return false; - } - - pb::ResourceTable pb_table; - if (!pb_table.ParseFromArray(data->data(), data->size())) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb"); - return false; - } - - if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse table: " << err); - return false; - } - } else if (io::IFile* file = zip->FindFile("resources.arsc")) { - std::unique_ptr data = file->OpenAsData(); - if (!data) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc"); - return false; - } - - BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path), - data->data(), data->size()); - if (!parser.Parse()) { - return false; - } - } - - if (!options.file_to_dump_path) { - if (proto) { - printer.Println("Proto APK"); - } else { - printer.Println("Binary APK"); - } - Debug::PrintTable(table, options.print_options, &printer); - return true; - } - - io::IFile* file = zip->FindFile(options.file_to_dump_path.value()); - if (file == nullptr) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "file '" << options.file_to_dump_path.value() - << "' not found in APK"); - return false; - } - return DumpXmlFile(context, file, proto, &printer); - } - - err.clear(); - - io::FileInputStream input(file_path); - if (input.HadError()) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to open file: " << input.GetError()); - return false; - } - - // Try as a compiled file. - ContainerReader reader(&input); - if (reader.HadError()) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to read container: " << reader.GetError()); - return false; - } - - printer.Println("AAPT2 Container (APC)"); - ContainerReaderEntry* entry; - while ((entry = reader.Next()) != nullptr) { - if (entry->Type() == ContainerEntryType::kResTable) { - printer.Println("kResTable"); - - pb::ResourceTable pb_table; - if (!entry->GetResTable(&pb_table)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse proto table: " << entry->GetError()); - continue; - } - - ResourceTable table; - err.clear(); - if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse table: " << err); - continue; - } - - printer.Indent(); - Debug::PrintTable(table, options.print_options, &printer); - printer.Undent(); - } else if (entry->Type() == ContainerEntryType::kResFile) { - printer.Println("kResFile"); - pb::internal::CompiledFile pb_compiled_file; - off64_t offset; - size_t length; - if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { - context->GetDiagnostics()->Error( - DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError()); - continue; - } - - ResourceFile file; - std::string error; - if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { - context->GetDiagnostics()->Warn(DiagMessage(file_path) - << "failed to parse compiled file: " << error); - continue; - } - - printer.Indent(); - DumpCompiledFile(file, Source(file_path), offset, length, &printer); - printer.Undent(); - } - } - return true; -} - namespace { class DumpContext : public IAaptContext { @@ -299,17 +124,290 @@ class DumpContext : public IAaptContext { } // namespace -int DumpCommand::Action(const std::vector& args) { +// Use a smaller buffer so that there is less latency for dumping to stdout. +constexpr size_t kStdOutBufferSize = 1024u; + +int DumpAPCCommand::Action(const std::vector& args) { + DumpContext context; + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump container specified."); + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + for (auto container : args) { + io::FileInputStream input(container); + if (input.HadError()) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to open file: " << input.GetError()); + return false; + } + + // Try as a compiled file. + ContainerReader reader(&input); + if (reader.HadError()) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to read container: " << reader.GetError()); + return false; + } + + printer.Println("AAPT2 Container (APC)"); + ContainerReaderEntry* entry; + std::string error; + while ((entry = reader.Next()) != nullptr) { + if (entry->Type() == ContainerEntryType::kResTable) { + printer.Println("kResTable"); + + pb::ResourceTable pb_table; + if (!entry->GetResTable(&pb_table)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse proto table: " + << entry->GetError()); + continue; + } + + ResourceTable table; + error.clear(); + if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse table: " << error); + continue; + } + + printer.Indent(); + Debug::PrintTable(table, print_options, &printer); + printer.Undent(); + } else if (entry->Type() == ContainerEntryType::kResFile) { + printer.Println("kResFile"); + pb::internal::CompiledFile pb_compiled_file; + off64_t offset; + size_t length; + if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { + context.GetDiagnostics()->Error( + DiagMessage(container) << "failed to parse compiled proto file: " + << entry->GetError()); + continue; + } + + ResourceFile file; + if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { + context.GetDiagnostics()->Warn(DiagMessage(container) + << "failed to parse compiled file: " << error); + continue; + } + + printer.Indent(); + DumpCompiledFile(file, Source(container), offset, length, &printer); + printer.Undent(); + } + } + } + + return 0; +} + +int DumpConfigsCommand::Action(const std::vector& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + // Comparison function used to order configurations + auto compare = [](ConfigDescription c1, ConfigDescription c2) -> bool { + return c1.compare(c2) < 0; + }; + + // Insert the configurations into a set in order to keep every configuarion seen + std::set configs(compare); + for (auto& package : loaded_apk->GetResourceTable()->packages) { + for (auto& type : package->types) { + for (auto& entry : type->entries) { + for (auto& value : entry->values) { + configs.insert(value->config); + } + } + } + } + + // Print the configurations in order + for (auto& config : configs) { + printer.Print(StringPrintf("%s\n", config.to_string().data())); + } + + return 0; +} + +int DumpStringsCommand::Action(const std::vector& args) { DumpContext context; - context.SetVerbose(verbose_); - options_.print_options.show_sources = true; - options_.print_options.show_values = !no_values_; - for (const std::string& arg : args) { - if (!TryDumpFile(&context, arg, options_)) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + for (auto apk : args) { + auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); + if (!loaded_apk) { + return 1; + } + + // Load the run-time xml string pool using the flattened data + BigBuffer buffer(4096); + StringPool::FlattenUtf8(&buffer, loaded_apk->GetResourceTable()->string_pool, + context.GetDiagnostics()); + auto data = buffer.to_string(); + android::ResStringPool pool(data.data(), data.size(), false); + Debug::DumpResStringPool(&pool, &printer); + } + + return 0; +} + +int DumpTableCommand::Action(const std::vector& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + + for (auto apk : args) { + auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); + if (!loaded_apk) { + return 1; + } + + if (loaded_apk->GetApkFormat()) { + printer.Println("Proto APK"); + } else { + printer.Println("Binary APK"); + } + + Debug::PrintTable(*loaded_apk->GetResourceTable(), print_options, &printer); + } + + return 0; +} + +int DumpXmlTreeCommand::Action(const std::vector& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified"); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + // Dump the xml tree of every passed in file + for (auto file : files_) { + auto xml = loaded_apk->LoadXml(file, diag_); + if (!xml) { return 1; } + + Debug::DumpXml(*xml, &printer); + } + + return 0; +} + +int DumpXmlStringsCommand::Action(const std::vector& args) { + DumpContext context; + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + // Dump the xml strings of every passed in file + for (auto xml_file : files_) { + android::ResXMLTree tree; + + if (loaded_apk->GetApkFormat() == kProto) { + auto xml = loaded_apk->LoadXml(xml_file, diag_); + if (!xml) { + return 1; + } + + // Flatten the xml document to get a binary representation of the proto xml file + BigBuffer buffer(4096); + XmlFlattenerOptions options = {}; + options.keep_raw_values = true; + XmlFlattener flattener(&buffer, options); + if (!flattener.Consume(&context, xml.get())) { + return 1; + } + + // Load the run-time xml tree using the flattened data + std::string data = buffer.to_string(); + tree.setTo(data.data(), data.size(), /** copyData */ true); + + } else if (loaded_apk->GetApkFormat() == kBinary) { + io::IFile* file = loaded_apk->GetFileCollection()->FindFile(xml_file); + if (!file) { + diag_->Error(DiagMessage(xml_file) << "file '" << xml_file << "' not found in APK"); + return 1; + } + + std::unique_ptr data = file->OpenAsData(); + if (!data) { + diag_->Error(DiagMessage() << "failed to open file"); + return 1; + } + + // Load the run-time xml tree from the file data + tree.setTo(data->data(), data->size(), /** copyData */ true); + } + + Debug::DumpResStringPool(&tree.getStrings(), &printer); } + return 0; } +/** Preform no action because a subcommand is required. */ +int DumpCommand::Action(const std::vector& args) { + if (args.size() == 0) { + diag_->Error(DiagMessage() << "no subcommand specified"); + } else { + diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'"); + } + + Usage(&std::cerr); + return 1; +} + } // namespace aapt diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 4893c8b76041..03a4fba133ba 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -22,33 +22,117 @@ namespace aapt { -struct DumpOptions { - DebugPrintTableOptions print_options; +/** Command the contents of files generated from the compilation stage. */ +class DumpAPCCommand : public Command { + public: + explicit DumpAPCCommand(IDiagnostics* diag) : Command("apc"), diag_(diag) { + SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation."); + AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", + &no_values_); + AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); + } - // The path to a file within an APK to dump. - Maybe file_to_dump_path; + int Action(const std::vector& args) override; + + private: + IDiagnostics* diag_; + bool verbose_ = false; + bool no_values_ = false; }; -class DumpCommand : public Command { +/** Prints every configuration used by a resource in an APK. */ +class DumpConfigsCommand : public Command { public: - DumpCommand() : Command("dump", "d") { - SetDescription("Prints resource and manifest information."); - AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", - &no_values_); - AddOptionalFlag("--file", "Dumps the specified file from the APK passed as arg.", - &options_.file_to_dump_path); - AddOptionalSwitch("-v", "increase verbosity of output", &verbose_); + explicit DumpConfigsCommand(IDiagnostics* diag) : Command("configurations"), diag_(diag) { + SetDescription("Print every configuration used by a resource in the APK."); } int Action(const std::vector& args) override; private: - DumpOptions options_; + IDiagnostics* diag_; +}; +/** Prints the contents of the resource table string pool in the APK. */ +class DumpStringsCommand : public Command { + public: + explicit DumpStringsCommand(IDiagnostics* diag) : Command("strings"), diag_(diag) { + SetDescription("Print the contents of the resource table string pool in the APK."); + } + + int Action(const std::vector& args) override; + + private: + IDiagnostics* diag_; +}; + +/** Prints the contents of the resource table from the APK. */ +class DumpTableCommand : public Command { + public: + explicit DumpTableCommand(IDiagnostics* diag) : Command("resources"), diag_(diag) { + SetDescription("Print the contents of the resource table from the APK."); + AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", + &no_values_); + AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); + } + + int Action(const std::vector& args) override; + + private: + IDiagnostics* diag_; bool verbose_ = false; bool no_values_ = false; }; +/** Prints the string pool of a compiled xml in an APK. */ +class DumpXmlStringsCommand : public Command { +public: + explicit DumpXmlStringsCommand(IDiagnostics* diag) : Command("xmlstrings"), diag_(diag) { + SetDescription("Print the string pool of a compiled xml in an APK."); + AddRequiredFlagList("--file", "A compiled xml file to print", &files_); + } + + int Action(const std::vector& args) override; + +private: + IDiagnostics* diag_; + std::vector files_; +}; + + +/** Prints the tree of a compiled xml in an APK. */ +class DumpXmlTreeCommand : public Command { + public: + explicit DumpXmlTreeCommand(IDiagnostics* diag) : Command("xmltree"), diag_(diag) { + SetDescription("Print the tree of a compiled xml in an APK."); + AddRequiredFlagList("--file", "A compiled xml file to print", &files_); + } + + int Action(const std::vector& args) override; + + private: + IDiagnostics* diag_; + std::vector files_; +}; + +/** The default dump command. Preforms no action because a subcommand is required. */ +class DumpCommand : public Command { + public: + explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) { + AddOptionalSubcommand(util::make_unique(diag_)); + AddOptionalSubcommand(util::make_unique(diag_)); + AddOptionalSubcommand(util::make_unique(diag_)); + AddOptionalSubcommand(util::make_unique(diag_)); + AddOptionalSubcommand(util::make_unique(diag_)); + AddOptionalSubcommand(util::make_unique(diag_)); + } + + int Action(const std::vector& args) override; + + private: + IDiagnostics* diag_; +}; + }// namespace aapt #endif //AAPT2_DUMP_H -- cgit v1.2.3-59-g8ed1b From 214846df59118ebe6b75706ea3505a8bb3b2f93c Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Wed, 19 Sep 2018 16:57:01 -0700 Subject: Created resuable DumpApkCommand and added "badger" This change refactors the dump commands to inherit from a base DumpApkCommand and adds a command that prints out an ASCII image of a badger if the user wrote "badger" instead of "badging". The command is hidden from the help menu. Bug: 73535002 Test: manual Change-Id: I9bdd8a7bbf6a4282c4933e5c478f6d1d8e32d99e --- tools/aapt2/Main.cpp | 28 ++- tools/aapt2/cmd/Command.cpp | 16 +- tools/aapt2/cmd/Command.h | 3 +- tools/aapt2/cmd/Dump.cpp | 440 ++++++++++++++++++++++---------------- tools/aapt2/cmd/Dump.h | 218 +++++++++++++------ tools/aapt2/dump/DumpManifest.cpp | 353 +++++++++++++----------------- tools/aapt2/dump/DumpManifest.h | 46 ++-- 7 files changed, 606 insertions(+), 498 deletions(-) (limited to 'tools/aapt2/Main.cpp') diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 37013c07ffef..adf85b0ea8e8 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -36,6 +36,7 @@ #include "cmd/Dump.h" #include "cmd/Link.h" #include "cmd/Optimize.h" +#include "io/FileStream.h" #include "util/Files.h" #include "util/Util.h" @@ -68,10 +69,11 @@ class VersionCommand : public Command { /** The main entry point of AAPT. */ class MainCommand : public Command { public: - explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) { + explicit MainCommand(text::Printer* printer, IDiagnostics* diagnostics) + : Command("aapt2"), diagnostics_(diagnostics) { AddOptionalSubcommand(util::make_unique(diagnostics)); AddOptionalSubcommand(util::make_unique(diagnostics)); - AddOptionalSubcommand(util::make_unique(diagnostics)); + AddOptionalSubcommand(util::make_unique(printer, diagnostics)); AddOptionalSubcommand(util::make_unique()); AddOptionalSubcommand(util::make_unique()); AddOptionalSubcommand(util::make_unique()); @@ -101,13 +103,14 @@ class MainCommand : public Command { */ class DaemonCommand : public Command { public: - explicit DaemonCommand(IDiagnostics* diagnostics) : Command("daemon", "m"), - diagnostics_(diagnostics) { + explicit DaemonCommand(io::FileOutputStream* out, IDiagnostics* diagnostics) + : Command("daemon", "m"), out_(out), diagnostics_(diagnostics) { SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n" "command. The end of an invocation is signaled by providing an empty line."); } int Action(const std::vector& /* args */) override { + text::Printer printer(out_); std::cout << "Ready" << std::endl; while (true) { @@ -132,7 +135,9 @@ class DaemonCommand : public Command { std::vector args; args.insert(args.end(), raw_args.begin(), raw_args.end()); - if (MainCommand(diagnostics_).Execute(args, &std::cerr) != 0) { + int result = MainCommand(&printer, diagnostics_).Execute(args, &std::cerr); + out_->Flush(); + if (result != 0) { std::cerr << "Error" << std::endl; } std::cerr << "Done" << std::endl; @@ -143,6 +148,7 @@ class DaemonCommand : public Command { } private: + io::FileOutputStream* out_; IDiagnostics* diagnostics_; }; @@ -159,11 +165,17 @@ int MainImpl(int argc, char** argv) { args.push_back(argv[i]); } - // Add the daemon subcommand here so it cannot be called while executing the daemon + // Use a smaller buffer so that there is less latency for printing to stdout. + constexpr size_t kStdOutBufferSize = 1024u; + aapt::io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + aapt::text::Printer printer(&fout); + aapt::StdErrDiagnostics diagnostics; - auto main_command = new aapt::MainCommand(&diagnostics); - main_command->AddOptionalSubcommand(aapt::util::make_unique(&diagnostics)); + auto main_command = new aapt::MainCommand(&printer, &diagnostics); + // Add the daemon subcommand here so it cannot be called while executing the daemon + main_command->AddOptionalSubcommand( + aapt::util::make_unique(&fout, &diagnostics)); return main_command->Execute(args, &std::cerr); } diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp index 09411b95bcfe..bdee5c9d4909 100644 --- a/tools/aapt2/cmd/Command.cpp +++ b/tools/aapt2/cmd/Command.cpp @@ -93,9 +93,13 @@ void Command::AddOptionalSwitch(const StringPiece& name, flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false}); } -void Command::AddOptionalSubcommand(std::unique_ptr&& subcommand) { +void Command::AddOptionalSubcommand(std::unique_ptr&& subcommand, bool experimental) { subcommand->fullname_ = name_ + " " + subcommand->name_; - subcommands_.push_back(std::move(subcommand)); + if (experimental) { + experimental_subcommands_.push_back(std::move(subcommand)); + } else { + subcommands_.push_back(std::move(subcommand)); + } } void Command::SetDescription(const android::StringPiece& description) { @@ -162,7 +166,7 @@ int Command::Execute(const std::vector& args, std::ostream for (size_t i = 0; i < args.size(); i++) { StringPiece arg = args[i]; if (*(arg.data()) != '-') { - // Continue parsing as the sub command if the first argument matches one of the subcommands + // Continue parsing as the subcommand if the first argument matches one of the subcommands if (i == 0) { for (auto& subcommand : subcommands_) { if (arg == subcommand->name_ || arg==subcommand->short_name_) { @@ -170,6 +174,12 @@ int Command::Execute(const std::vector& args, std::ostream std::vector(args.begin() + 1, args.end()), out_error); } } + for (auto& subcommand : experimental_subcommands_) { + if (arg == subcommand->name_ || arg==subcommand->short_name_) { + return subcommand->Execute( + std::vector(args.begin() + 1, args.end()), out_error); + } + } } file_args.push_back(arg.to_string()); diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h index 71dc6fe48da1..16949883d123 100644 --- a/tools/aapt2/cmd/Command.h +++ b/tools/aapt2/cmd/Command.h @@ -49,7 +49,7 @@ class Command { const android::StringPiece& description, std::unordered_set* value); void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description, bool* value); - void AddOptionalSubcommand(std::unique_ptr&& subcommand); + void AddOptionalSubcommand(std::unique_ptr&& subcommand, bool experimental = false); void SetDescription(const android::StringPiece& name); @@ -83,6 +83,7 @@ class Command { std::string fullname_; std::vector flags_; std::vector> subcommands_; + std::vector> experimental_subcommands_; }; } // namespace aapt diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index d80b5ea38bbd..06e4622d949a 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -125,9 +125,6 @@ class DumpContext : public IAaptContext { } // namespace -// Use a smaller buffer so that there is less latency for dumping to stdout. -constexpr size_t kStdOutBufferSize = 1024u; - int DumpAPCCommand::Action(const std::vector& args) { DumpContext context; DebugPrintTableOptions print_options; @@ -135,41 +132,41 @@ int DumpAPCCommand::Action(const std::vector& args) { print_options.show_values = !no_values_; if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump container specified."); + diag_->Error(DiagMessage() << "No dump container specified"); return 1; } - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - + bool error = false; for (auto container : args) { io::FileInputStream input(container); if (input.HadError()) { context.GetDiagnostics()->Error(DiagMessage(container) - << "failed to open file: " << input.GetError()); - return false; + << "failed to open file: " << input.GetError()); + error = true; + continue; } // Try as a compiled file. ContainerReader reader(&input); if (reader.HadError()) { context.GetDiagnostics()->Error(DiagMessage(container) - << "failed to read container: " << reader.GetError()); - return false; + << "failed to read container: " << reader.GetError()); + error = true; + continue; } - printer.Println("AAPT2 Container (APC)"); + printer_->Println("AAPT2 Container (APC)"); ContainerReaderEntry* entry; std::string error; while ((entry = reader.Next()) != nullptr) { if (entry->Type() == ContainerEntryType::kResTable) { - printer.Println("kResTable"); + printer_->Println("kResTable"); pb::ResourceTable pb_table; if (!entry->GetResTable(&pb_table)) { context.GetDiagnostics()->Error(DiagMessage(container) - << "failed to parse proto table: " - << entry->GetError()); + << "failed to parse proto table: " << entry->GetError()); + error = true; continue; } @@ -177,65 +174,61 @@ int DumpAPCCommand::Action(const std::vector& args) { error.clear(); if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) { context.GetDiagnostics()->Error(DiagMessage(container) - << "failed to parse table: " << error); + << "failed to parse table: " << error); + error = true; continue; } - printer.Indent(); - Debug::PrintTable(table, print_options, &printer); - printer.Undent(); + printer_->Indent(); + Debug::PrintTable(table, print_options, printer_); + printer_->Undent(); } else if (entry->Type() == ContainerEntryType::kResFile) { - printer.Println("kResFile"); + printer_->Println("kResFile"); pb::internal::CompiledFile pb_compiled_file; off64_t offset; size_t length; if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { - context.GetDiagnostics()->Error( - DiagMessage(container) << "failed to parse compiled proto file: " - << entry->GetError()); + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse compiled proto file: " + << entry->GetError()); + error = true; continue; } ResourceFile file; if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { context.GetDiagnostics()->Warn(DiagMessage(container) - << "failed to parse compiled file: " << error); + << "failed to parse compiled file: " << error); + error = true; continue; } - printer.Indent(); - DumpCompiledFile(file, Source(container), offset, length, &printer); - printer.Undent(); + printer_->Indent(); + DumpCompiledFile(file, Source(container), offset, length, printer_); + printer_->Undent(); } } } - return 0; + return (error) ? 1 : 0; } -int DumpConfigsCommand::Action(const std::vector& args) { - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); - return 1; - } - - auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); - if (!loaded_apk) { - return 1; - } +int DumpBadgerCommand::Action(const std::vector& args) { + printer_->Print(StringPrintf("%s", kBadgerData)); + printer_->Print("Did you mean \"aapt2 dump badging\"?\n"); + return 1; +} - ResourceTable* table = loaded_apk->GetResourceTable(); +int DumpConfigsCommand::Dump(LoadedApk* apk) { + ResourceTable* table = apk->GetResourceTable(); if (!table) { - diag_->Error(DiagMessage() << "Failed to retrieve resource table."); + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); return 1; } - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - // Comparison function used to order configurations auto compare = [](android::ConfigDescription c1, android::ConfigDescription c2) -> bool { - return c1.compare(c2) < 0; + return c1.compare(c2) < 0; }; // Insert the configurations into a set in order to keep every configuarion seen @@ -252,132 +245,75 @@ int DumpConfigsCommand::Action(const std::vector& args) { // Print the configurations in order for (auto& config : configs) { - printer.Print(StringPrintf("%s\n", config.to_string().data())); + GetPrinter()->Print(StringPrintf("%s\n", config.to_string().data())); } - return 0; } -int DumpStringsCommand::Action(const std::vector& args) { - DumpContext context; - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); +int DumpPackageNameCommand::Dump(LoadedApk* apk) { + xml::Element* manifest_el = apk->GetManifest()->root.get(); + if (!manifest_el) { + GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest"); return 1; } - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - for (auto apk : args) { - auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); - if (!loaded_apk) { - return 1; - } - - ResourceTable* table = loaded_apk->GetResourceTable(); - if (!table) { - diag_->Error(DiagMessage() << "Failed to retrieve resource table."); - return 1; - } - - // Load the run-time xml string pool using the flattened data - BigBuffer buffer(4096); - StringPool::FlattenUtf8(&buffer, table->string_pool, context.GetDiagnostics()); - auto data = buffer.to_string(); - android::ResStringPool pool(data.data(), data.size(), false); - Debug::DumpResStringPool(&pool, &printer); + xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); + if (!attr) { + GetDiagnostics()->Error(DiagMessage() << "No package name"); + return 1; } + GetPrinter()->Println(StringPrintf("%s", attr->value.c_str())); return 0; } -int DumpTableCommand::Action(const std::vector& args) { - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); +int DumpStringsCommand::Dump(LoadedApk* apk) { + ResourceTable* table = apk->GetResourceTable(); + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); return 1; } - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - DebugPrintTableOptions print_options; - print_options.show_sources = true; - print_options.show_values = !no_values_; - - for (auto apk : args) { - auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); - if (!loaded_apk) { - return 1; - } - - if (loaded_apk->GetApkFormat() == ApkFormat::kProto) { - printer.Println("Proto APK"); - } else { - printer.Println("Binary APK"); - } - - ResourceTable* table = loaded_apk->GetResourceTable(); - if (!table) { - diag_->Error(DiagMessage() << "Failed to retrieve resource table."); - return 1; - } - - Debug::PrintTable(*table, print_options, &printer); - } - + // Load the run-time xml string pool using the flattened data + BigBuffer buffer(4096); + StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics()); + auto data = buffer.to_string(); + android::ResStringPool pool(data.data(), data.size(), false); + Debug::DumpResStringPool(&pool, GetPrinter()); return 0; } -int DumpXmlTreeCommand::Action(const std::vector& args) { - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified"); - return 1; +int DumpTableCommand::Dump(LoadedApk* apk) { + if (apk->GetApkFormat() == ApkFormat::kProto) { + GetPrinter()->Println("Proto APK"); + } else { + GetPrinter()->Println("Binary APK"); } - auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); - if (!loaded_apk) { + ResourceTable* table = apk->GetResourceTable(); + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); return 1; } - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - // Dump the xml tree of every passed in file - for (auto file : files_) { - auto xml = loaded_apk->LoadXml(file, diag_); - if (!xml) { - return 1; - } - - Debug::DumpXml(*xml, &printer); - } - + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + Debug::PrintTable(*table, print_options, GetPrinter()); return 0; } -int DumpXmlStringsCommand::Action(const std::vector& args) { +int DumpXmlStringsCommand::Dump(LoadedApk* apk) { DumpContext context; - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); - return 1; - } - - auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); - if (!loaded_apk) { - return 1; - } - - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - // Dump the xml strings of every passed in file + bool error = false; for (auto xml_file : files_) { android::ResXMLTree tree; - if (loaded_apk->GetApkFormat() == ApkFormat::kProto) { - auto xml = loaded_apk->LoadXml(xml_file, diag_); + if (apk->GetApkFormat() == ApkFormat::kProto) { + auto xml = apk->LoadXml(xml_file, GetDiagnostics()); if (!xml) { - return 1; + error = true; + continue; } // Flatten the xml document to get a binary representation of the proto xml file @@ -386,76 +322,208 @@ int DumpXmlStringsCommand::Action(const std::vector& args) { options.keep_raw_values = true; XmlFlattener flattener(&buffer, options); if (!flattener.Consume(&context, xml.get())) { - return 1; + error = true; + continue; } // Load the run-time xml tree using the flattened data std::string data = buffer.to_string(); tree.setTo(data.data(), data.size(), /** copyData */ true); - } else if (loaded_apk->GetApkFormat() == ApkFormat::kBinary) { - io::IFile* file = loaded_apk->GetFileCollection()->FindFile(xml_file); + } else if (apk->GetApkFormat() == ApkFormat::kBinary) { + io::IFile* file = apk->GetFileCollection()->FindFile(xml_file); if (!file) { - diag_->Error(DiagMessage(xml_file) << "file '" << xml_file << "' not found in APK"); - return 1; + GetDiagnostics()->Error(DiagMessage(xml_file) + << "File '" << xml_file << "' not found in APK"); + error = true; + continue; } std::unique_ptr data = file->OpenAsData(); if (!data) { - diag_->Error(DiagMessage() << "failed to open file"); - return 1; + GetDiagnostics()->Error(DiagMessage() << "Failed to open " << xml_file); + error = true; + continue; } // Load the run-time xml tree from the file data tree.setTo(data->data(), data->size(), /** copyData */ true); + } else { + GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "Unknown APK format"); + error = true; + continue; } - Debug::DumpResStringPool(&tree.getStrings(), &printer); + Debug::DumpResStringPool(&tree.getStrings(), GetPrinter()); } - - return 0; + return (error) ? 1 : 0; } -int DumpPackageNameCommand::Action(const std::vector& args) { - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); - return 1; - } - - auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); - if (!loaded_apk) { - return 1; - } - - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - xml::Element* manifest_el = loaded_apk->GetManifest()->root.get(); - if (!manifest_el) { - diag_->Error(DiagMessage() << "No AndroidManifest."); - return 1; - } - - xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); - if (!attr) { - diag_->Error(DiagMessage() << "No package name."); - return 1; +int DumpXmlTreeCommand::Dump(LoadedApk* apk) { + for (auto file : files_) { + auto xml = apk->LoadXml(file, GetDiagnostics()); + if (!xml) { + return 1; + } + Debug::DumpXml(*xml, GetPrinter()); } - printer.Println(StringPrintf("%s", attr->value.c_str())); - return 0; } -/** Preform no action because a subcommand is required. */ -int DumpCommand::Action(const std::vector& args) { - if (args.size() == 0) { - diag_->Error(DiagMessage() << "no subcommand specified"); - } else { - diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'"); - } - - Usage(&std::cerr); - return 1; -} +const char DumpBadgerCommand::kBadgerData[2925] = { + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 86, 35, 40, 46, 46, + 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 62, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 81, 81, 81, 66, 96, 61, 61, 58, 46, + 46, 46, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, + 81, 81, 102, 59, 61, 59, 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 61, 59, 59, 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, + 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 58, + 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 47, 61, 59, 59, + 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 121, 81, 91, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 81, 81, 81, 109, 58, 59, 59, 59, + 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, + 81, 81, 81, 81, 59, 61, 59, 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 60, 81, 91, 59, 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, + 81, 76, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, + 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 93, 40, + 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 81, 68, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46, 46, 32, 46, + 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 81, 81, 81, 87, 46, 58, 61, + 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46, + 61, 59, 61, 61, 61, 59, 61, 61, 59, 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, + 81, 81, 81, 81, 69, 58, 59, 59, 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, + 32, 32, 32, 32, 58, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 61, 61, 46, 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, + 96, 32, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, + 81, 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 67, + 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 61, 59, 59, + 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 73, 108, 108, 62, 52, 81, + 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 59, 61, 61, 46, 46, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 46, 45, 57, 101, 43, 43, 61, + 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 97, + 46, 61, 108, 62, 126, 58, 106, 80, 96, 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 61, 61, 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, + 32, 32, 32, 32, 45, 46, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, + 58, 59, 59, 59, 59, 61, 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, + 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, + 99, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, + 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 58, + 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 81, 58, 59, 59, 59, + 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 87, 66, 33, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 45, 32, 46, 32, 32, 32, 32, 32, 46, + 32, 126, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 58, 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 40, 58, 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 59, + 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, + 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 87, 59, 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 102, 94, + 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 59, 59, 43, 63, 36, 81, + 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 59, 59, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, + 59, 59, 59, 59, 59, 59, 59, 43, 33, 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, + 58, 95, 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, + 59, 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 59, 58, + 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 59, 59, 59, 59, 59, 59, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, + 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, + 59, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, + 32, 32, 32, 32, 32, 61, 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, + 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, + 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 32, + 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 59, 59, 59, 59, + 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 58, 45, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10}; } // namespace aapt diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 9ec820d89596..cd215b00db22 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -19,14 +19,62 @@ #include "Command.h" #include "Debug.h" +#include "LoadedApk.h" #include "dump/DumpManifest.h" namespace aapt { -/** Command the contents of files generated from the compilation stage. */ +/** + * The base command for dumping information about apks. When the command is executed, the command + * performs the DumpApkCommand::Dump() operation on each apk provided as a file argument. + **/ +class DumpApkCommand : public Command { + public: + explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag) + : Command(name), printer_(printer), diag_(diag) { + } + + text::Printer* GetPrinter() { + return printer_; + } + + IDiagnostics* GetDiagnostics() { + return diag_; + } + + /** Perform the dump operation on the apk. */ + virtual int Dump(LoadedApk* apk) = 0; + + int Action(const std::vector& args) final { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + bool error = false; + for (auto apk : args) { + auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); + if (!loaded_apk) { + error = true; + continue; + } + + error |= Dump(loaded_apk.get()); + } + + return error; + } + + private: + text::Printer* printer_; + IDiagnostics* diag_; +}; + +/** Command that prints contents of files generated from the compilation stage. */ class DumpAPCCommand : public Command { public: - explicit DumpAPCCommand(IDiagnostics* diag) : Command("apc"), diag_(diag) { + explicit DumpAPCCommand(text::Printer* printer, IDiagnostics* diag) + : Command("apc"), printer_(printer), diag_(diag) { SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation."); AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", &no_values_); @@ -36,120 +84,162 @@ class DumpAPCCommand : public Command { int Action(const std::vector& args) override; private: + text::Printer* printer_; IDiagnostics* diag_; - bool verbose_ = false; bool no_values_ = false; + bool verbose_ = false; }; -/** Prints every configuration used by a resource in an APK. */ -class DumpConfigsCommand : public Command { +/** Easter egg command shown when users enter "badger" instead of "badging". */ +class DumpBadgerCommand : public Command { public: - explicit DumpConfigsCommand(IDiagnostics* diag) : Command("configurations"), diag_(diag) { - SetDescription("Print every configuration used by a resource in the APK."); + explicit DumpBadgerCommand(text::Printer* printer) : Command("badger"), printer_(printer) { } int Action(const std::vector& args) override; private: - IDiagnostics* diag_; + text::Printer* printer_; + const static char kBadgerData[2925]; }; -/** Prints the contents of the resource table string pool in the APK. */ -class DumpStringsCommand : public Command { - public: - explicit DumpStringsCommand(IDiagnostics* diag) : Command("strings"), diag_(diag) { - SetDescription("Print the contents of the resource table string pool in the APK."); - } +class DumpBadgingCommand : public DumpApkCommand { + public: + explicit DumpBadgingCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("badging", printer, diag) { + SetDescription("Print information extracted from the manifest of the APK."); + AddOptionalSwitch("--include-meta-data", "Include meta-data information.", + &options_.include_meta_data); + } + + int Dump(LoadedApk* apk) override { + return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics()); + } - int Action(const std::vector& args) override; + private: + DumpManifestOptions options_; +}; - private: - IDiagnostics* diag_; +class DumpConfigsCommand : public DumpApkCommand { + public: + explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("configurations", printer, diag) { + SetDescription("Print every configuration used by a resource in the APK."); + } + + int Dump(LoadedApk* apk) override; }; -/** Prints the contents of the resource table from the APK. */ -class DumpTableCommand : public Command { +class DumpPackageNameCommand : public DumpApkCommand { public: - explicit DumpTableCommand(IDiagnostics* diag) : Command("resources"), diag_(diag) { + explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("packagename", printer, diag) { + SetDescription("Print the package name of the APK."); + } + + int Dump(LoadedApk* apk) override; +}; + +class DumpPermissionsCommand : public DumpApkCommand { + public: + explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("permissions", printer, diag) { + SetDescription("Print the permissions extracted from the manifest of the APK."); + } + + int Dump(LoadedApk* apk) override { + DumpManifestOptions options; + options.only_permissions = true; + return DumpManifest(apk, options, GetPrinter(), GetDiagnostics()); + } +}; + +class DumpStringsCommand : public DumpApkCommand { + public: + explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("strings", printer, diag) { + SetDescription("Print the contents of the resource table string pool in the APK."); + } + + int Dump(LoadedApk* apk) override; +}; + +class DumpTableCommand : public DumpApkCommand { + public: + explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("resources", printer, diag) { SetDescription("Print the contents of the resource table from the APK."); AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", &no_values_); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); } - int Action(const std::vector& args) override; + int Dump(LoadedApk* apk) override; private: - IDiagnostics* diag_; - bool verbose_ = false; bool no_values_ = false; + bool verbose_ = false; }; -/** Prints the string pool of a compiled xml in an APK. */ -class DumpXmlStringsCommand : public Command { -public: - explicit DumpXmlStringsCommand(IDiagnostics* diag) : Command("xmlstrings"), diag_(diag) { - SetDescription("Print the string pool of a compiled xml in an APK."); - AddRequiredFlagList("--file", "A compiled xml file to print", &files_); - } - - int Action(const std::vector& args) override; - -private: - IDiagnostics* diag_; - std::vector files_; -}; - - -/** Prints the tree of a compiled xml in an APK. */ -class DumpXmlTreeCommand : public Command { +class DumpXmlStringsCommand : public DumpApkCommand { public: - explicit DumpXmlTreeCommand(IDiagnostics* diag) : Command("xmltree"), diag_(diag) { - SetDescription("Print the tree of a compiled xml in an APK."); + explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("xmlstrings", printer, diag) { + SetDescription("Print the string pool of a compiled xml in an APK."); AddRequiredFlagList("--file", "A compiled xml file to print", &files_); } - int Action(const std::vector& args) override; + int Dump(LoadedApk* apk) override; private: - IDiagnostics* diag_; std::vector files_; }; -/** Prints the contents of the resource table from the APK. */ -class DumpPackageNameCommand : public Command { +class DumpXmlTreeCommand : public DumpApkCommand { public: - explicit DumpPackageNameCommand(IDiagnostics* diag) : Command("packagename"), diag_(diag) { - SetDescription("Print the package name of the APK."); + explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("xmltree", printer, diag) { + SetDescription("Print the tree of a compiled xml in an APK."); + AddRequiredFlagList("--file", "A compiled xml file to print", &files_); } - int Action(const std::vector& args) override; + int Dump(LoadedApk* apk) override; private: - IDiagnostics* diag_; + std::vector files_; }; /** The default dump command. Performs no action because a subcommand is required. */ class DumpCommand : public Command { public: - explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) { - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); - AddOptionalSubcommand(util::make_unique(diag_)); + explicit DumpCommand(text::Printer* printer, IDiagnostics* diag) + : Command("dump", "d"), diag_(diag) { + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer, diag_)); + AddOptionalSubcommand(util::make_unique(printer), /* hidden */ true); } - int Action(const std::vector& args) override; + int Action(const std::vector& args) override { + if (args.size() == 0) { + diag_->Error(DiagMessage() << "no subcommand specified"); + } else { + diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'"); + } + Usage(&std::cerr); + return 1; + } private: IDiagnostics* diag_; }; -}// namespace aapt +} // namespace aapt -#endif //AAPT2_DUMP_H +#endif // AAPT2_DUMP_H diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp index c0e1dc682845..11a4074cd3cd 100644 --- a/tools/aapt2/dump/DumpManifest.cpp +++ b/tools/aapt2/dump/DumpManifest.cpp @@ -109,15 +109,8 @@ class CommonFeatureGroup; class ManifestExtractor { public: - struct Options { - /** Include meta information from elements in the output. */ - bool include_meta_data = false; - /** Only output permission information. */ - bool only_permissions = false; - }; - - explicit ManifestExtractor(LoadedApk* apk, ManifestExtractor::Options options) + explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options) : apk_(apk), options_(options) { } class Element { @@ -128,7 +121,7 @@ class ManifestExtractor { static std::unique_ptr Inflate(ManifestExtractor* extractor, xml::Element* el); /** Writes out the extracted contents of the element. */ - virtual void Print(text::Printer& printer) { } + virtual void Print(text::Printer* printer) { } /** Adds an element to the list of children of the element. */ void AddChild(std::unique_ptr& child) { children_.push_back(std::move(child)); } @@ -332,7 +325,7 @@ class ManifestExtractor { return config; } - bool Dump(text::Printer& printer, IDiagnostics* diag); + bool Dump(text::Printer* printer, IDiagnostics* diag); /** Recursively visit the xml element tree and return a processed badging element tree. */ std::unique_ptr Visit(xml::Element* element); @@ -378,7 +371,7 @@ class ManifestExtractor { } LoadedApk* const apk_; - const Options options_; + DumpManifestOptions& options_; private: std::unique_ptr commonFeatureGroup_ = util::make_unique(); @@ -450,40 +443,40 @@ class Manifest : public ManifestExtractor::Element { installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR)); } - void Print(text::Printer& printer) override { - printer.Print(StringPrintf("package: name='%s' ", package.data())); - printer.Print(StringPrintf("versionCode='%s' ", + void Print(text::Printer* printer) override { + printer->Print(StringPrintf("package: name='%s' ", package.data())); + printer->Print(StringPrintf("versionCode='%s' ", (versionCode > 0) ? std::to_string(versionCode).data() : "")); - printer.Print(StringPrintf("versionName='%s'", versionName.data())); + printer->Print(StringPrintf("versionName='%s'", versionName.data())); if (split) { - printer.Print(StringPrintf(" split='%s'", split->data())); + printer->Print(StringPrintf(" split='%s'", split->data())); } if (platformVersionName) { - printer.Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data())); + printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data())); } if (platformVersionCode) { - printer.Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data())); + printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data())); } if (compilesdkVersion) { - printer.Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion)); + printer->Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion)); } if (compilesdkVersionCodename) { - printer.Print(StringPrintf(" compileSdkVersionCodename='%s'", + printer->Print(StringPrintf(" compileSdkVersionCodename='%s'", compilesdkVersionCodename->data())); } - printer.Print("\n"); + printer->Print("\n"); if (installLocation) { switch (*installLocation) { case 0: - printer.Print("install-location:'auto'\n"); + printer->Print("install-location:'auto'\n"); break; case 1: - printer.Print("install-location:'internalOnly'\n"); + printer->Print("install-location:'internalOnly'\n"); break; case 2: - printer.Print("install-location:'preferExternal'\n"); + printer->Print("install-location:'preferExternal'\n"); break; default: break; @@ -544,15 +537,15 @@ class Application : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { // Print the labels for every locale for (auto p : locale_labels) { if (p.first.empty()) { - printer.Print(StringPrintf("application-label:'%s'\n", + printer->Print(StringPrintf("application-label:'%s'\n", android::ResTable::normalizeForOutput(p.second.data()) .c_str())); } else { - printer.Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(), + printer->Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(), android::ResTable::normalizeForOutput(p.second.data()) .c_str())); } @@ -560,26 +553,26 @@ class Application : public ManifestExtractor::Element { // Print the icon paths for every density for (auto p : density_icons) { - printer.Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data())); + printer->Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data())); } // Print the application info - printer.Print(StringPrintf("application: label='%s' ", + printer->Print(StringPrintf("application: label='%s' ", android::ResTable::normalizeForOutput(label.data()).c_str())); - printer.Print(StringPrintf("icon='%s'", icon.data())); + printer->Print(StringPrintf("icon='%s'", icon.data())); if (!banner.empty()) { - printer.Print(StringPrintf(" banner='%s'", banner.data())); + printer->Print(StringPrintf(" banner='%s'", banner.data())); } - printer.Print("\n"); + printer->Print("\n"); if (test_only != 0) { - printer.Print(StringPrintf("testOnly='%d'\n", test_only)); + printer->Print(StringPrintf("testOnly='%d'\n", test_only)); } if (is_game != 0) { - printer.Print("application-isGame\n"); + printer->Print("application-isGame\n"); } if (debuggable != 0) { - printer.Print("application-debuggable\n"); + printer->Print("application-debuggable\n"); } } }; @@ -614,19 +607,19 @@ class UsesSdkBadging : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (min_sdk) { - printer.Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk)); + printer->Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk)); } else if (min_sdk_name) { - printer.Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data())); + printer->Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data())); } if (max_sdk) { - printer.Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk)); + printer->Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk)); } if (target_sdk) { - printer.Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk)); + printer->Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk)); } else if (target_sdk_name) { - printer.Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data())); + printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data())); } } }; @@ -654,24 +647,24 @@ class UsesConfiguarion : public ManifestExtractor::Element { FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0); } - void Print(text::Printer& printer) override { - printer.Print("uses-configuration:"); + void Print(text::Printer* printer) override { + printer->Print("uses-configuration:"); if (req_touch_screen != 0) { - printer.Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen)); + printer->Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen)); } if (req_keyboard_type != 0) { - printer.Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type)); + printer->Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type)); } if (req_hard_keyboard != 0) { - printer.Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard)); + printer->Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard)); } if (req_navigation != 0) { - printer.Print(StringPrintf(" reqNavigation='%d'", req_navigation)); + printer->Print(StringPrintf(" reqNavigation='%d'", req_navigation)); } if (req_five_way_nav != 0) { - printer.Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav)); + printer->Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav)); } - printer.Print("\n"); + printer->Print("\n"); } }; @@ -715,7 +708,7 @@ class SupportsScreen : public ManifestExtractor::Element { } } - void PrintScreens(text::Printer& printer, int32_t target_sdk) { + void PrintScreens(text::Printer* printer, int32_t target_sdk) { int32_t small_screen_temp = small_screen; int32_t normal_screen_temp = normal_screen; int32_t large_screen_temp = large_screen; @@ -745,30 +738,30 @@ class SupportsScreen : public ManifestExtractor::Element { } // Print the formatted screen info - printer.Print("supports-screens:"); + printer->Print("supports-screens:"); if (small_screen_temp != 0) { - printer.Print(" 'small'"); + printer->Print(" 'small'"); } if (normal_screen_temp != 0) { - printer.Print(" 'normal'"); + printer->Print(" 'normal'"); } if (large_screen_temp != 0) { - printer.Print(" 'large'"); + printer->Print(" 'large'"); } if (xlarge_screen_temp != 0) { - printer.Print(" 'xlarge'"); + printer->Print(" 'xlarge'"); } - printer.Print("\n"); - printer.Print(StringPrintf("supports-any-density: '%s'\n", + printer->Print("\n"); + printer->Print(StringPrintf("supports-any-density: '%s'\n", (any_density_temp ) ? "true" : "false")); if (requires_smallest_width_dp > 0) { - printer.Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp)); + printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp)); } if (compatible_width_limit_dp > 0) { - printer.Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp)); + printer->Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp)); } if (largest_width_limit_dp > 0) { - printer.Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp)); + printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp)); } } }; @@ -784,20 +777,20 @@ class FeatureGroup : public ManifestExtractor::Element { label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), ""); } - virtual void PrintGroup(text::Printer& printer) { - printer.Print(StringPrintf("feature-group: label='%s'\n", label.data())); + virtual void PrintGroup(text::Printer* printer) { + printer->Print(StringPrintf("feature-group: label='%s'\n", label.data())); if (open_gles_version > 0) { - printer.Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version)); + printer->Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version)); } for (auto feature : features_) { - printer.Print(StringPrintf(" uses-feature%s: name='%s'", + printer->Print(StringPrintf(" uses-feature%s: name='%s'", (feature.second.required ? "" : "-not-required"), feature.first.data())); if (feature.second.version > 0) { - printer.Print(StringPrintf(" version='%d'", feature.second.version)); + printer->Print(StringPrintf(" version='%d'", feature.second.version)); } - printer.Print("\n"); + printer->Print("\n"); } } @@ -863,29 +856,29 @@ class FeatureGroup : public ManifestExtractor::Element { class CommonFeatureGroup : public FeatureGroup { public: CommonFeatureGroup() = default; - void PrintGroup(text::Printer& printer) override { + void PrintGroup(text::Printer* printer) override { FeatureGroup::PrintGroup(printer); // Also print the implied features for (auto feature : implied_features_) { if (features_.find(feature.first) == features_.end()) { const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : ""; - printer.Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data())); - printer.Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23, + printer->Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data())); + printer->Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23, feature.first.data())); // Print the reasons as a sentence size_t count = 0; for (auto reason : feature.second.reasons) { - printer.Print(reason); + printer->Print(reason); if (count + 2 < feature.second.reasons.size()) { - printer.Print(", "); + printer->Print(", "); } else if (count + 1 < feature.second.reasons.size()) { - printer.Print(", and "); + printer->Print(", and "); } count++; } - printer.Print("'\n"); + printer->Print("'\n"); } } } @@ -1070,35 +1063,35 @@ class UsesPermission : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (!name.empty()) { - printer.Print(StringPrintf("uses-permission: name='%s'", name.data())); + printer->Print(StringPrintf("uses-permission: name='%s'", name.data())); if (maxSdkVersion >= 0) { - printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion)); + printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion)); } if (!requiredFeature.empty()) { - printer.Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data())); + printer->Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data())); } if (!requiredNotFeature.empty()) { - printer.Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data())); + printer->Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data())); } - printer.Print("\n"); + printer->Print("\n"); if (required == 0) { - printer.Print(StringPrintf("optional-permission: name='%s'", name.data())); + printer->Print(StringPrintf("optional-permission: name='%s'", name.data())); if (maxSdkVersion >= 0) { - printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion)); + printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion)); } - printer.Print("\n"); + printer->Print("\n"); } } } - void PrintImplied(text::Printer& printer, const std::string& reason) { - printer.Print(StringPrintf("uses-implied-permission: name='%s'", name.data())); + void PrintImplied(text::Printer* printer, const std::string& reason) { + printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data())); if (maxSdkVersion >= 0) { - printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion)); + printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion)); } - printer.Print(StringPrintf(" reason='%s'\n", reason.data())); + printer->Print(StringPrintf(" reason='%s'\n", reason.data())); } }; @@ -1119,13 +1112,13 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (name) { - printer.Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data())); + printer->Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data())); if (maxSdkVersion) { - printer.Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion)); + printer->Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion)); } - printer.Print("\n"); + printer->Print("\n"); } } }; @@ -1140,9 +1133,9 @@ class Permission : public ManifestExtractor::Element { name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), ""); } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (extractor()->options_.only_permissions && !name.empty()) { - printer.Print(StringPrintf("permission: %s\n", name.data())); + printer->Print(StringPrintf("permission: %s\n", name.data())); } } }; @@ -1202,25 +1195,25 @@ class Activity : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { // Print whether the activity has the HOME category and a the MAIN action if (has_main_action && has_launcher_category) { - printer.Print("launchable-activity:"); + printer->Print("launchable-activity:"); if (!name.empty()) { - printer.Print(StringPrintf(" name='%s' ", name.data())); + printer->Print(StringPrintf(" name='%s' ", name.data())); } - printer.Print(StringPrintf(" label='%s' icon='%s'\n", + printer->Print(StringPrintf(" label='%s' icon='%s'\n", android::ResTable::normalizeForOutput(label.data()).c_str(), icon.data())); } // Print wether the activity has the HOME category and a the MAIN action if (has_leanback_launcher_category) { - printer.Print("leanback-launchable-activity:"); + printer->Print("leanback-launchable-activity:"); if (!name.empty()) { - printer.Print(StringPrintf(" name='%s' ", name.data())); + printer->Print(StringPrintf(" name='%s' ", name.data())); } - printer.Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n", + printer->Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n", android::ResTable::normalizeForOutput(label.data()).c_str(), icon.data(), banner.data())); } @@ -1319,9 +1312,9 @@ class UsesLibrary : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (!name.empty()) { - printer.Print(StringPrintf("uses-library%s:'%s'\n", + printer->Print(StringPrintf("uses-library%s:'%s'\n", (required == 0) ? "-not-required" : "", name.data())); } } @@ -1344,8 +1337,8 @@ class StaticLibrary : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { - printer.Print(StringPrintf( + void Print(text::Printer* printer) override { + printer->Print(StringPrintf( "static-library: name='%s' version='%d' versionMajor='%d'\n", name.data(), version, versionMajor)); } @@ -1380,14 +1373,14 @@ class UsesStaticLibrary : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { - printer.Print(StringPrintf( + void Print(text::Printer* printer) override { + printer->Print(StringPrintf( "uses-static-library: name='%s' version='%d' versionMajor='%d'", name.data(), version, versionMajor)); for (size_t i = 0; i < certDigests.size(); i++) { - printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data())); + printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data())); } - printer.Print("\n"); + printer->Print("\n"); } }; @@ -1412,21 +1405,21 @@ class MetaData : public ManifestExtractor::Element { resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR)); } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (extractor()->options_.include_meta_data && !name.empty()) { - printer.Print(StringPrintf("meta-data: name='%s' ", name.data())); + printer->Print(StringPrintf("meta-data: name='%s' ", name.data())); if (!value.empty()) { - printer.Print(StringPrintf("value='%s' ", value.data())); + printer->Print(StringPrintf("value='%s' ", value.data())); } else if (value_int) { - printer.Print(StringPrintf("value='%d' ", *value_int)); + printer->Print(StringPrintf("value='%d' ", *value_int)); } else { if (!resource.empty()) { - printer.Print(StringPrintf("resource='%s' ", resource.data())); + printer->Print(StringPrintf("resource='%s' ", resource.data())); } else if (resource_int) { - printer.Print(StringPrintf("resource='%d' ", *resource_int)); + printer->Print(StringPrintf("resource='%d' ", *resource_int)); } } - printer.Print("\n"); + printer->Print("\n"); } } }; @@ -1548,14 +1541,14 @@ class SupportsInput : public ManifestExtractor::Element { SupportsInput() = default; std::vector inputs; - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { const size_t size = inputs.size(); if (size > 0) { - printer.Print("supports-input: '"); + printer->Print("supports-input: '"); for (size_t i = 0; i < size; i++) { - printer.Print(StringPrintf("value='%s' ", inputs[i].data())); + printer->Print(StringPrintf("value='%s' ", inputs[i].data())); } - printer.Print("\n"); + printer->Print("\n"); } } }; @@ -1586,9 +1579,9 @@ class OriginalPackage : public ManifestExtractor::Element { name = GetAttributeString(FindAttribute(element, NAME_ATTR)); } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (name) { - printer.Print(StringPrintf("original-package:'%s'\n", name->data())); + printer->Print(StringPrintf("original-package:'%s'\n", name->data())); } } }; @@ -1605,9 +1598,9 @@ class PackageVerifier : public ManifestExtractor::Element { public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR)); } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (name && public_key) { - printer.Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n", + printer->Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n", name->data(), public_key->data())); } } @@ -1644,18 +1637,18 @@ class UsesPackage : public ManifestExtractor::Element { } } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (name) { if (packageType) { - printer.Print(StringPrintf( + printer->Print(StringPrintf( "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'", packageType->data(), name->data(), version, versionMajor)); for (size_t i = 0; i < certDigests.size(); i++) { - printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data())); + printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data())); } - printer.Print("\n"); + printer->Print("\n"); } else { - printer.Print(StringPrintf("uses-package:'%s'\n", name->data())); + printer->Print(StringPrintf("uses-package:'%s'\n", name->data())); } } } @@ -1700,8 +1693,8 @@ class Screen : public ManifestExtractor::Element { class CompatibleScreens : public ManifestExtractor::Element { public: CompatibleScreens() = default; - void Print(text::Printer& printer) override { - printer.Print("compatible-screens:"); + void Print(text::Printer* printer) override { + printer->Print("compatible-screens:"); bool first = true; ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){ @@ -1709,15 +1702,15 @@ class CompatibleScreens : public ManifestExtractor::Element { if (first) { first = false; } else { - printer.Print(","); + printer->Print(","); } if (screen->size && screen->density) { - printer.Print(StringPrintf("'%d/%d'", *screen->size, *screen->density)); + printer->Print(StringPrintf("'%d/%d'", *screen->size, *screen->density)); } } }); - printer.Print("\n"); + printer->Print("\n"); } }; @@ -1731,22 +1724,22 @@ class SupportsGlTexture : public ManifestExtractor::Element { name = GetAttributeString(FindAttribute(element, NAME_ATTR)); } - void Print(text::Printer& printer) override { + void Print(text::Printer* printer) override { if (name) { - printer.Print(StringPrintf("supports-gl-texture:'%s'\n", name->data())); + printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data())); } } }; /** Recursively prints the extracted badging element. */ -static void Print(ManifestExtractor::Element* el, text::Printer& printer) { +static void Print(ManifestExtractor::Element* el, text::Printer* printer) { el->Print(printer); for (auto &child : el->children()) { Print(child.get(), printer); } } -bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { +bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) { // Load the manifest std::unique_ptr doc = apk_->LoadXml("AndroidManifest.xml", diag); if (doc == nullptr) { @@ -1775,7 +1768,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { } } - printer.Print(StringPrintf("package: %s\n", manifest->package.data())); + printer->Print(StringPrintf("package: %s\n", manifest->package.data())); ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void { el->Print(printer); }); @@ -1992,7 +1985,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { // Print the components types if they are present auto PrintComponent = [&components, &printer](const std::string& component) -> void { if (components.find(component) != components.end()) { - printer.Print(StringPrintf("provides-component:'%s'\n", component.data())); + printer->Print(StringPrintf("provides-component:'%s'\n", component.data())); } }; @@ -2013,14 +2006,14 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { // Print presence of main activity if (components.find("main") != components.end()) { - printer.Print("main\n"); + printer->Print("main\n"); } // Print presence of activities, recivers, and services with no special components FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool { if (auto activity = ElementCast(el)) { if (!activity->has_component_) { - printer.Print("other-activities\n"); + printer->Print("other-activities\n"); return true; } } @@ -2030,7 +2023,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool { if (auto receiver = ElementCast(el)) { if (!receiver->has_component) { - printer.Print("other-receivers\n"); + printer->Print("other-receivers\n"); return true; } } @@ -2040,7 +2033,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool { if (auto service = ElementCast(el)) { if (!service->has_component) { - printer.Print("other-services\n"); + printer->Print("other-services\n"); return true; } } @@ -2062,22 +2055,22 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { } // Print all the unique locales of the apk - printer.Print("locales:"); + printer->Print("locales:"); for (auto& config : locales_) { if (config.first.empty()) { - printer.Print(" '--_--'"); + printer->Print(" '--_--'"); } else { - printer.Print(StringPrintf(" '%s'", config.first.data())); + printer->Print(StringPrintf(" '%s'", config.first.data())); } } - printer.Print("\n"); + printer->Print("\n"); // Print all the densities locales of the apk - printer.Print("densities:"); + printer->Print("densities:"); for (auto& config : densities_) { - printer.Print(StringPrintf(" '%d'", config.first)); + printer->Print(StringPrintf(" '%d'", config.first)); } - printer.Print("\n"); + printer->Print("\n"); // Print the supported architectures of the app std::set architectures; @@ -2131,7 +2124,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { } if (arch != architectures.end()) { - printer.Print(StringPrintf("native-code: '%s'\n", arch->data())); + printer->Print(StringPrintf("native-code: '%s'\n", arch->data())); architectures.erase(arch); output_alt_native_code = true; } @@ -2139,13 +2132,13 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) { if (architectures.size() > 0) { if (output_alt_native_code) { - printer.Print("alt-"); + printer->Print("alt-"); } - printer.Print("native-code:"); + printer->Print("native-code:"); for (auto& arch : architectures) { - printer.Print(StringPrintf(" '%s'", arch.data())); + printer->Print(StringPrintf(" '%s'", arch.data())); } - printer.Print("\n"); + printer->Print("\n"); } return true; @@ -2272,55 +2265,11 @@ std::unique_ptr ManifestExtractor::Visit(xml::Elemen return element; } -// Use a smaller buffer so that there is less latency for dumping to stdout. -constexpr size_t kStdOutBufferSize = 1024u; - -int DumpBadgingCommand::Action(const std::vector& args) { - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); - return 1; - } - - ManifestExtractor::Options options; - options.include_meta_data = include_metadata_; - - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - text::Printer printer(&fout); - for (auto apk : args) { - auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); - if (!loaded_apk) { - return 1; - } - - ManifestExtractor extractor(loaded_apk.get(), options); - extractor.Dump(printer, diag_); - } - - return 0; -} - -int DumpPermissionsCommand::Action(const std::vector& args) { - if (args.size() < 1) { - diag_->Error(DiagMessage() << "No dump apk specified."); - return 1; - } - - ManifestExtractor::Options options; - options.only_permissions = true; - - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - text::Printer printer(&fout); - for (auto apk : args) { - auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); - if (!loaded_apk) { - return 1; - } - - ManifestExtractor extractor(loaded_apk.get(), options); - extractor.Dump(printer, diag_); - } - return 0; +int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer, + IDiagnostics* diag) { + ManifestExtractor extractor(apk, options); + return extractor.Dump(printer, diag); } } // namespace aapt diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h index a70be53fa070..daf22ed57a84 100644 --- a/tools/aapt2/dump/DumpManifest.h +++ b/tools/aapt2/dump/DumpManifest.h @@ -17,45 +17,23 @@ #ifndef AAPT2_DUMP_MANIFEST_H #define AAPT2_DUMP_MANIFEST_H -#include -#include -#include - - -#include "cmd/Command.h" -#include "process/IResourceTableConsumer.h" +#include "Diagnostics.h" +#include "LoadedApk.h" #include "text/Printer.h" -#include "xml/XmlDom.h" namespace aapt { -class DumpBadgingCommand : public Command { - public: - explicit DumpBadgingCommand(IDiagnostics* diag) : Command("badging"), diag_(diag) { - SetDescription("Print information extracted from the manifest of the APK."); - AddOptionalSwitch("--include-meta-data", "Include meta-data information.", - &include_metadata_); - } - - int Action(const std::vector& args) override; - - private: - IDiagnostics* diag_; - bool include_metadata_ = false; +struct DumpManifestOptions { + /** Include meta information from elements in the output. */ + bool include_meta_data = false; + /** Only output permission information. */ + bool only_permissions = false; }; -class DumpPermissionsCommand : public Command { - public: - explicit DumpPermissionsCommand(IDiagnostics* diag) : Command("permissions"), diag_(diag) { - SetDescription("Print the permissions extracted from the manifest of the APK."); - } - - int Action(const std::vector& args) override; - - private: - IDiagnostics* diag_; -}; +/** Print information extracted from the manifest of the APK. */ +int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer, + IDiagnostics* diag); -}// namespace aapt +} // namespace aapt -#endif //AAPT2_DUMP_MANIFEST_H \ No newline at end of file +#endif // AAPT2_DUMP_MANIFEST_H \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From 2d34e76daceaac41a8c578d7fa02aca864019dbb Mon Sep 17 00:00:00 2001 From: Fabien Sanglard Date: Thu, 21 Feb 2019 15:13:29 -0800 Subject: Add --trace_folder to aapt2 Add a tracing API and instrument key functions in order to profile aapt2 bottleneck. The API allows to generate systrace fragment files. Impact on performance is neglibible with each Trace requiring less than 1us and the final Flush operation at the end of a command requiring around 40us. Bug: None Test: None Change-Id: I51b564d3694e9384679f43b878b32295527dddf6 --- tools/aapt2/Android.bp | 1 + tools/aapt2/Main.cpp | 7 +- tools/aapt2/ResourceTable.cpp | 2 + tools/aapt2/cmd/Command.cpp | 2 + tools/aapt2/cmd/Compile.cpp | 8 ++ tools/aapt2/cmd/Compile.h | 3 + tools/aapt2/cmd/Link.cpp | 22 ++++ tools/aapt2/cmd/Link.h | 4 + tools/aapt2/compile/Png.cpp | 2 + tools/aapt2/compile/PngCrunch.cpp | 4 + tools/aapt2/compile/XmlIdCollector.cpp | 2 + tools/aapt2/format/Container.cpp | 4 + tools/aapt2/format/binary/TableFlattener.cpp | 3 + tools/aapt2/io/Util.cpp | 6 ++ tools/aapt2/io/ZipArchive.cpp | 2 + tools/aapt2/link/AutoVersioner.cpp | 2 + tools/aapt2/link/ManifestFixer.cpp | 2 + tools/aapt2/link/ProductFilter.cpp | 2 + tools/aapt2/link/ReferenceLinker.cpp | 2 + tools/aapt2/link/ResourceExcluder.cpp | 2 + tools/aapt2/link/TableMerger.cpp | 2 + tools/aapt2/link/XmlReferenceLinker.cpp | 2 + tools/aapt2/optimize/ResourceDeduper.cpp | 2 + tools/aapt2/optimize/VersionCollapser.cpp | 2 + tools/aapt2/process/SymbolTable.cpp | 3 + tools/aapt2/split/TableSplitter.cpp | 2 + tools/aapt2/trace/TraceBuffer.cpp | 151 +++++++++++++++++++++++++++ tools/aapt2/trace/TraceBuffer.h | 64 ++++++++++++ tools/aapt2/xml/XmlDom.cpp | 2 + 29 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 tools/aapt2/trace/TraceBuffer.cpp create mode 100644 tools/aapt2/trace/TraceBuffer.h (limited to 'tools/aapt2/Main.cpp') diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index bc3a9a1c88c8..8bef221fe5ed 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -141,6 +141,7 @@ cc_library_host_static { "ResourceValues.cpp", "SdkConstants.cpp", "StringPool.cpp", + "trace/TraceBuffer.cpp", "xml/XmlActionExecutor.cpp", "xml/XmlDom.cpp", "xml/XmlPullParser.cpp", diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index adf85b0ea8e8..39eb9879f86d 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -37,6 +37,7 @@ #include "cmd/Link.h" #include "cmd/Optimize.h" #include "io/FileStream.h" +#include "trace/TraceBuffer.h" #include "util/Files.h" #include "util/Util.h" @@ -107,9 +108,12 @@ class DaemonCommand : public Command { : Command("daemon", "m"), out_(out), diagnostics_(diagnostics) { SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n" "command. The end of an invocation is signaled by providing an empty line."); + AddOptionalFlag("--trace_folder", "Generate systrace json trace fragment to specified folder.", + &trace_folder_); } - int Action(const std::vector& /* args */) override { + int Action(const std::vector& arguments) override { + TRACE_FLUSH_ARGS(trace_folder_ ? trace_folder_.value() : "", "daemon", arguments); text::Printer printer(out_); std::cout << "Ready" << std::endl; @@ -150,6 +154,7 @@ class DaemonCommand : public Command { private: io::FileOutputStream* out_; IDiagnostics* diagnostics_; + Maybe trace_folder_; }; } // namespace aapt diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index dbd0a0ca1799..7c0619f33851 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -30,6 +30,7 @@ #include "NameMangler.h" #include "ResourceValues.h" #include "ValueVisitor.h" +#include "trace/TraceBuffer.h" #include "text/Unicode.h" #include "util/Util.h" @@ -79,6 +80,7 @@ ResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) const { } ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Maybe id) { + TRACE_CALL(); ResourceTablePackage* package = FindOrCreatePackage(name); if (id && !package->id) { package->id = id; diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp index 4424a357c1dd..919b4c98fa8f 100644 --- a/tools/aapt2/cmd/Command.cpp +++ b/tools/aapt2/cmd/Command.cpp @@ -25,6 +25,7 @@ #include "android-base/utf8.h" #include "androidfw/StringPiece.h" +#include "trace/TraceBuffer.h" #include "util/Util.h" using android::base::StringPrintf; @@ -178,6 +179,7 @@ void Command::Usage(std::ostream* out) { } int Command::Execute(const std::vector& args, std::ostream* out_error) { + TRACE_NAME_ARGS("Command::Execute", args); std::vector file_args; for (size_t i = 0; i < args.size(); i++) { diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index bec6c6973613..42dc74c6db55 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -45,6 +45,7 @@ #include "io/StringStream.h" #include "io/Util.h" #include "io/ZipArchive.h" +#include "trace/TraceBuffer.h" #include "util/Files.h" #include "util/Maybe.h" #include "util/Util.h" @@ -141,6 +142,7 @@ static std::string BuildIntermediateContainerFilename(const ResourcePathData& da static bool CompileTable(IAaptContext* context, const CompileOptions& options, const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer, const std::string& output_path) { + TRACE_CALL(); ResourceTable table; { auto fin = file->OpenInputStream(); @@ -286,6 +288,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const ResourceFile& file, io::KnownSizeInputStream* in, IArchiveWriter* writer, IDiagnostics* diag) { + TRACE_CALL(); // Start the entry so we can write the header. if (!writer->StartEntry(output_path, 0)) { diag->Error(DiagMessage(output_path) << "failed to open file"); @@ -352,6 +355,7 @@ static bool IsValidFile(IAaptContext* context, const std::string& input_path) { static bool CompileXml(IAaptContext* context, const CompileOptions& options, const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer, const std::string& output_path) { + TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling XML"); } @@ -451,6 +455,7 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options, static bool CompilePng(IAaptContext* context, const CompileOptions& options, const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer, const std::string& output_path) { + TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling PNG"); } @@ -558,6 +563,7 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options, static bool CompileFile(IAaptContext* context, const CompileOptions& options, const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer, const std::string& output_path) { + TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling file"); } @@ -632,6 +638,7 @@ class CompileContext : public IAaptContext { int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, CompileOptions& options) { + TRACE_CALL(); bool error = false; // Iterate over the input files in a stable, platform-independent manner @@ -707,6 +714,7 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* } int CompileCommand::Action(const std::vector& args) { + TRACE_FLUSH(trace_folder_? trace_folder_.value() : "", "CompileCommand::Action"); CompileContext context(diagnostic_); context.SetVerbose(options_.verbose); diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h index 9b32cb3750a5..d3456b25da9a 100644 --- a/tools/aapt2/cmd/Compile.h +++ b/tools/aapt2/cmd/Compile.h @@ -60,6 +60,8 @@ class CompileCommand : public Command { "Sets the visibility of the compiled resources to the specified\n" "level. Accepted levels: public, private, default", &visibility_); AddOptionalSwitch("-v", "Enables verbose logging", &options_.verbose); + AddOptionalFlag("--trace-folder", "Generate systrace json trace fragment to specified folder.", + &trace_folder_); } int Action(const std::vector& args) override; @@ -68,6 +70,7 @@ class CompileCommand : public Command { IDiagnostics* diagnostic_; CompileOptions options_; Maybe visibility_; + Maybe trace_folder_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index a7b8d2535e79..f354bb610224 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -67,6 +67,7 @@ #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" #include "split/TableSplitter.h" +#include "trace/TraceBuffer.h" #include "util/Files.h" #include "xml/XmlDom.h" @@ -213,6 +214,7 @@ class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate { static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res, const StringPiece& path, bool keep_raw_values, bool utf16, OutputFormat format, IArchiveWriter* writer) { + TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage(path) << "writing to archive (keep_raw_values=" << (keep_raw_values ? "true" : "false") @@ -250,6 +252,7 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res, // Inflates an XML file from the source path. static std::unique_ptr LoadXml(const std::string& path, IDiagnostics* diag) { + TRACE_CALL(); FileInputStream fin(path); if (fin.HadError()) { diag->Error(DiagMessage(path) << "failed to load XML file: " << fin.GetError()); @@ -421,6 +424,7 @@ std::vector make_singleton_vec(T&& val) { std::vector> ResourceFileFlattener::LinkAndVersionXmlFile( ResourceTable* table, FileOperation* file_op) { + TRACE_CALL(); xml::XmlResource* doc = file_op->xml_to_flatten.get(); const Source& src = doc->file.source; @@ -489,6 +493,7 @@ static auto kDrawableVersions = std::map{ }; bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archive_writer) { + TRACE_CALL(); bool error = false; std::map, FileOperation> config_sorted_files; @@ -806,6 +811,7 @@ class Linker { // Creates a SymbolTable that loads symbols from the various APKs. // Pre-condition: context_->GetCompilationPackage() needs to be set. bool LoadSymbolsFromIncludePaths() { + TRACE_NAME("LoadSymbolsFromIncludePaths: #" + std::to_string(options_.include_paths.size())); auto asset_source = util::make_unique(); for (const std::string& path : options_.include_paths) { if (context_->IsVerbose()) { @@ -891,6 +897,7 @@ class Linker { } Maybe ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { + TRACE_CALL(); // Make sure the first element is with package attribute. xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get()); if (manifest_el == nullptr) { @@ -1041,6 +1048,7 @@ class Linker { } bool FlattenTable(ResourceTable* table, OutputFormat format, IArchiveWriter* writer) { + TRACE_CALL(); switch (format) { case OutputFormat::kApk: { BigBuffer buffer(1024); @@ -1114,6 +1122,7 @@ class Linker { } bool GenerateJavaClasses() { + TRACE_CALL(); // The set of packages whose R class to call in the main classes onResourcesLoaded callback. std::vector packages_to_callback; @@ -1197,6 +1206,7 @@ class Linker { } bool WriteManifestJavaFile(xml::XmlResource* manifest_xml) { + TRACE_CALL(); if (!options_.generate_java_class_path) { return true; } @@ -1254,6 +1264,7 @@ class Linker { } bool WriteProguardFile(const Maybe& out, const proguard::KeepSet& keep_set) { + TRACE_CALL(); if (!out) { return true; } @@ -1278,6 +1289,7 @@ class Linker { } bool MergeStaticLibrary(const std::string& input, bool override) { + TRACE_CALL(); if (context_->IsVerbose()) { context_->GetDiagnostics()->Note(DiagMessage() << "merging static library " << input); } @@ -1328,6 +1340,7 @@ class Linker { bool MergeExportedSymbols(const Source& source, const std::vector& exported_symbols) { + TRACE_CALL(); // Add the exports of this file to the table. for (const SourcedResourceName& exported_symbol : exported_symbols) { ResourceName res_name = exported_symbol.name; @@ -1353,6 +1366,7 @@ class Linker { } bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) { + TRACE_CALL(); if (context_->IsVerbose()) { context_->GetDiagnostics()->Note(DiagMessage() << "merging '" << compiled_file.name @@ -1371,6 +1385,7 @@ class Linker { // An io::IFileCollection is created from the ZIP file and added to the set of // io::IFileCollections that are open. bool MergeArchive(const std::string& input, bool override) { + TRACE_CALL(); if (context_->IsVerbose()) { context_->GetDiagnostics()->Note(DiagMessage() << "merging archive " << input); } @@ -1418,6 +1433,7 @@ class Linker { // All other file types are ignored. This is because these files could be coming from a zip, // where we could have other files like classes.dex. bool MergeFile(io::IFile* file, bool override) { + TRACE_CALL(); const Source& src = file->GetSource(); if (util::EndsWith(src.path, ".xml") || util::EndsWith(src.path, ".png")) { @@ -1458,6 +1474,7 @@ class Linker { while ((entry = reader.Next()) != nullptr) { if (entry->Type() == ContainerEntryType::kResTable) { + TRACE_NAME(std::string("Process ResTable:") + file->GetSource().path); pb::ResourceTable pb_table; if (!entry->GetResTable(&pb_table)) { context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to read resource table: " @@ -1478,6 +1495,7 @@ class Linker { return false; } } else if (entry->Type() == ContainerEntryType::kResFile) { + TRACE_NAME(std::string("Process ResFile") + file->GetSource().path); pb::internal::CompiledFile pb_compiled_file; off64_t offset; size_t len; @@ -1551,6 +1569,7 @@ class Linker { // to the IArchiveWriter. bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest, ResourceTable* table) { + TRACE_CALL(); const bool keep_raw_values = (context_->GetPackageType() == PackageType::kStaticLib) || options_.keep_raw_values; bool result = FlattenXml(context_, *manifest, kAndroidManifestPath, keep_raw_values, @@ -1632,6 +1651,7 @@ class Linker { } int Run(const std::vector& input_files) { + TRACE_CALL(); // Load the AndroidManifest.xml std::unique_ptr manifest_xml = LoadXml(options_.manifest_path, context_->GetDiagnostics()); @@ -1839,6 +1859,7 @@ class Linker { std::vector excluded_configs; for (auto& config_string : options_.exclude_configs_) { + TRACE_NAME("ConfigDescription::Parse"); ConfigDescription config_description; if (!ConfigDescription::Parse(config_string, &config_description)) { @@ -2038,6 +2059,7 @@ class Linker { }; int LinkCommand::Action(const std::vector& args) { + TRACE_FLUSH(trace_folder_ ? trace_folder_.value() : "", "LinkCommand::Action"); LinkContext context(diag_); // Expand all argument-files passed into the command line. These start with '@'. diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 1fc149ab41af..7c583858ee1d 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -25,6 +25,7 @@ #include "split/TableSplitter.h" #include "format/binary/TableFlattener.h" #include "link/ManifestFixer.h" +#include "trace/TraceBuffer.h" namespace aapt { @@ -277,6 +278,8 @@ class LinkCommand : public Command { "Do not allow overlays with different visibility levels.", &options_.strict_visibility); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); + AddOptionalFlag("--trace-folder", "Generate systrace json trace fragment to specified folder.", + &trace_folder_); } int Action(const std::vector& args) override; @@ -300,6 +303,7 @@ class LinkCommand : public Command { bool proto_format_ = false; Maybe stable_id_file_path_; std::vector split_args_; + Maybe trace_folder_; }; }// namespace aapt diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp index 33122dccb7de..d396d81d699a 100644 --- a/tools/aapt2/compile/Png.cpp +++ b/tools/aapt2/compile/Png.cpp @@ -27,6 +27,7 @@ #include "androidfw/ResourceTypes.h" #include "Source.h" +#include "trace/TraceBuffer.h" #include "util/BigBuffer.h" #include "util/Util.h" @@ -1233,6 +1234,7 @@ getout: bool Png::process(const Source& source, std::istream* input, BigBuffer* outBuffer, const PngOptions& options) { + TRACE_CALL(); png_byte signature[kPngSignatureSize]; // Read the PNG signature first. diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp index 0346a1982d8a..1f4ea44d9f86 100644 --- a/tools/aapt2/compile/PngCrunch.cpp +++ b/tools/aapt2/compile/PngCrunch.cpp @@ -27,6 +27,8 @@ #include "android-base/logging.h" #include "android-base/macros.h" +#include "trace/TraceBuffer.h" + namespace aapt { // Custom deleter that destroys libpng read and info structs. @@ -142,6 +144,7 @@ static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t } std::unique_ptr ReadPng(IAaptContext* context, const Source& source, io::InputStream* in) { + TRACE_CALL(); // Create a diagnostics that has the source information encoded. SourcePathDiagnostics source_diag(source, context->GetDiagnostics()); @@ -480,6 +483,7 @@ static void WriteNinePatch(png_structp write_ptr, png_infop write_info_ptr, bool WritePng(IAaptContext* context, const Image* image, const NinePatch* nine_patch, io::OutputStream* out, const PngOptions& options) { + TRACE_CALL(); // Create and initialize the write png_struct with the default error and // warning handlers. // The header version is also passed in to ensure that this was built against the same diff --git a/tools/aapt2/compile/XmlIdCollector.cpp b/tools/aapt2/compile/XmlIdCollector.cpp index 2199d003bccb..50541152f802 100644 --- a/tools/aapt2/compile/XmlIdCollector.cpp +++ b/tools/aapt2/compile/XmlIdCollector.cpp @@ -22,6 +22,7 @@ #include "ResourceUtils.h" #include "ResourceValues.h" #include "text/Unicode.h" +#include "trace/TraceBuffer.h" #include "xml/XmlDom.h" namespace aapt { @@ -72,6 +73,7 @@ struct IdCollector : public xml::Visitor { } // namespace bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) { + TRACE_CALL(); xmlRes->file.exported_symbols.clear(); SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics()); IdCollector collector(&xmlRes->file.exported_symbols, &source_diag); diff --git a/tools/aapt2/format/Container.cpp b/tools/aapt2/format/Container.cpp index d4b45717e015..f1890488276c 100644 --- a/tools/aapt2/format/Container.cpp +++ b/tools/aapt2/format/Container.cpp @@ -19,6 +19,8 @@ #include "android-base/scopeguard.h" #include "android-base/stringprintf.h" +#include "trace/TraceBuffer.h" + using ::android::base::StringPrintf; using ::google::protobuf::io::CodedInputStream; using ::google::protobuf::io::CodedOutputStream; @@ -171,6 +173,7 @@ ContainerEntryType ContainerReaderEntry::Type() const { } bool ContainerReaderEntry::GetResTable(pb::ResourceTable* out_table) { + TRACE_CALL(); CHECK(type_ == ContainerEntryType::kResTable) << "reading a kResTable when the type is kResFile"; if (length_ > std::numeric_limits::max()) { reader_->error_ = StringPrintf("entry length %zu is too large", length_); @@ -261,6 +264,7 @@ ContainerReader::ContainerReader(io::InputStream* in) total_entry_count_(0u), current_entry_count_(0u), entry_(this) { + TRACE_CALL(); ::google::protobuf::uint32 magic; if (!coded_in_.ReadLittleEndian32(&magic)) { std::ostringstream error; diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index d677317dc98d..aa578a2a6ff4 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -32,6 +32,7 @@ #include "ValueVisitor.h" #include "format/binary/ChunkWriter.h" #include "format/binary/ResourceTypeExtensions.h" +#include "trace/TraceBuffer.h" #include "util/BigBuffer.h" using namespace android; @@ -238,6 +239,7 @@ class PackageFlattener { } bool FlattenPackage(BigBuffer* buffer) { + TRACE_CALL(); ChunkWriter pkg_writer(buffer); ResTable_package* pkg_header = pkg_writer.StartChunk(RES_TABLE_PACKAGE_TYPE); pkg_header->id = util::HostToDevice32(package_->id.value()); @@ -710,6 +712,7 @@ class PackageFlattener { } // namespace bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_CALL(); // We must do this before writing the resources, since the string pool IDs may change. table->string_pool.Prune(); table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int { diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp index 97516322c4cb..ce6d9352180d 100644 --- a/tools/aapt2/io/Util.cpp +++ b/tools/aapt2/io/Util.cpp @@ -18,6 +18,8 @@ #include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "trace/TraceBuffer.h" + using ::android::StringPiece; using ::google::protobuf::io::ZeroCopyOutputStream; @@ -26,6 +28,7 @@ namespace io { bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std::string& out_path, uint32_t compression_flags, IArchiveWriter* writer) { + TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive"); } @@ -40,6 +43,7 @@ bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std: bool CopyFileToArchive(IAaptContext* context, io::IFile* file, const std::string& out_path, uint32_t compression_flags, IArchiveWriter* writer) { + TRACE_CALL(); std::unique_ptr data = file->OpenAsData(); if (!data) { context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "failed to open file"); @@ -57,6 +61,7 @@ bool CopyFileToArchivePreserveCompression(IAaptContext* context, io::IFile* file bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite* proto_msg, const std::string& out_path, uint32_t compression_flags, IArchiveWriter* writer) { + TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive"); } @@ -83,6 +88,7 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite* } bool Copy(OutputStream* out, InputStream* in) { + TRACE_CALL(); const void* in_buffer; size_t in_len; while (in->Next(&in_buffer, &in_len)) { diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp index 427dc92505d4..f6aaa1280a61 100644 --- a/tools/aapt2/io/ZipArchive.cpp +++ b/tools/aapt2/io/ZipArchive.cpp @@ -20,6 +20,7 @@ #include "ziparchive/zip_archive.h" #include "Source.h" +#include "trace/TraceBuffer.h" #include "util/Files.h" #include "util/Util.h" @@ -93,6 +94,7 @@ ZipFileCollection::ZipFileCollection() : handle_(nullptr) {} std::unique_ptr ZipFileCollection::Create( const StringPiece& path, std::string* out_error) { + TRACE_CALL(); constexpr static const int32_t kEmptyArchive = -6; std::unique_ptr collection = diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp index 960c7d46cc98..73b92542a755 100644 --- a/tools/aapt2/link/AutoVersioner.cpp +++ b/tools/aapt2/link/AutoVersioner.cpp @@ -23,6 +23,7 @@ #include "ResourceTable.h" #include "SdkConstants.h" #include "ValueVisitor.h" +#include "trace/TraceBuffer.h" using android::ConfigDescription; @@ -70,6 +71,7 @@ ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry, } bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_NAME("AutoVersioner::Consume"); for (auto& package : table->packages) { for (auto& type : package->types) { if (type->type != ResourceType::kStyle) { diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 582a5b869c65..b0a2055cafc8 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -21,6 +21,7 @@ #include "android-base/logging.h" #include "ResourceUtils.h" +#include "trace/TraceBuffer.h" #include "util/Util.h" #include "xml/XmlActionExecutor.h" #include "xml/XmlDom.h" @@ -451,6 +452,7 @@ static bool RenameManifestPackage(const StringPiece& package_override, xml::Elem } bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { + TRACE_CALL(); xml::Element* root = xml::FindRootElement(doc->root.get()); if (!root || !root->namespace_uri.empty() || root->name != "manifest") { context->GetDiagnostics()->Error(DiagMessage(doc->file.source) diff --git a/tools/aapt2/link/ProductFilter.cpp b/tools/aapt2/link/ProductFilter.cpp index c1a95ee1bcec..793740af3021 100644 --- a/tools/aapt2/link/ProductFilter.cpp +++ b/tools/aapt2/link/ProductFilter.cpp @@ -17,6 +17,7 @@ #include "link/Linkers.h" #include "ResourceTable.h" +#include "trace/TraceBuffer.h" namespace aapt { @@ -81,6 +82,7 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep( } bool ProductFilter::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_NAME("ProductFilter::Consume"); bool error = false; for (auto& pkg : table->packages) { for (auto& type : pkg->types) { diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp index c2340ba65e38..28f09aa48365 100644 --- a/tools/aapt2/link/ReferenceLinker.cpp +++ b/tools/aapt2/link/ReferenceLinker.cpp @@ -27,6 +27,7 @@ #include "link/Linkers.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" +#include "trace/TraceBuffer.h" #include "util/Util.h" #include "xml/XmlUtil.h" @@ -353,6 +354,7 @@ bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* referen } bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_NAME("ReferenceLinker::Consume"); EmptyDeclStack decl_stack; bool error = false; for (auto& package : table->packages) { diff --git a/tools/aapt2/link/ResourceExcluder.cpp b/tools/aapt2/link/ResourceExcluder.cpp index 2555995dfc8e..b3b9dc47fd84 100644 --- a/tools/aapt2/link/ResourceExcluder.cpp +++ b/tools/aapt2/link/ResourceExcluder.cpp @@ -20,6 +20,7 @@ #include "DominatorTree.h" #include "ResourceTable.h" +#include "trace/TraceBuffer.h" using android::ConfigDescription; @@ -65,6 +66,7 @@ void RemoveIfExcluded(std::set>& excluded_conf } // namespace bool ResourceExcluder::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_NAME("ResourceExcluder::Consume"); for (auto& package : table->packages) { for (auto& type : package->types) { for (auto& entry : type->entries) { diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index cc9fed554350..e9375176f26b 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -21,6 +21,7 @@ #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" +#include "trace/TraceBuffer.h" #include "ValueVisitor.h" #include "util/Util.h" @@ -38,6 +39,7 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table, } bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) { + TRACE_CALL(); // We allow adding new resources if this is not an overlay, or if the options allow overlays // to add new resources. return MergeImpl(src, table, overlay, options_.auto_add_overlay || !overlay /*allow_new*/); diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp index 160ff925f6cc..d68f7dd44c9f 100644 --- a/tools/aapt2/link/XmlReferenceLinker.cpp +++ b/tools/aapt2/link/XmlReferenceLinker.cpp @@ -25,6 +25,7 @@ #include "link/ReferenceLinker.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" +#include "trace/TraceBuffer.h" #include "util/Util.h" #include "xml/XmlDom.h" @@ -151,6 +152,7 @@ class XmlVisitor : public xml::PackageAwareVisitor { } // namespace bool XmlReferenceLinker::Consume(IAaptContext* context, xml::XmlResource* resource) { + TRACE_NAME("XmlReferenceLinker::Consume"); CallSite callsite{resource->file.name.package}; std::string out_name = resource->file.name.entry; diff --git a/tools/aapt2/optimize/ResourceDeduper.cpp b/tools/aapt2/optimize/ResourceDeduper.cpp index ee2dfbce7c06..78ebcb97b811 100644 --- a/tools/aapt2/optimize/ResourceDeduper.cpp +++ b/tools/aapt2/optimize/ResourceDeduper.cpp @@ -20,6 +20,7 @@ #include "DominatorTree.h" #include "ResourceTable.h" +#include "trace/TraceBuffer.h" using android::ConfigDescription; @@ -110,6 +111,7 @@ static void DedupeEntry(IAaptContext* context, ResourceEntry* entry) { } // namespace bool ResourceDeduper::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_CALL(); for (auto& package : table->packages) { for (auto& type : package->types) { for (auto& entry : type->entries) { diff --git a/tools/aapt2/optimize/VersionCollapser.cpp b/tools/aapt2/optimize/VersionCollapser.cpp index f9856047ac40..cd791bda250b 100644 --- a/tools/aapt2/optimize/VersionCollapser.cpp +++ b/tools/aapt2/optimize/VersionCollapser.cpp @@ -20,6 +20,7 @@ #include #include "ResourceTable.h" +#include "trace/TraceBuffer.h" using android::ConfigDescription; @@ -144,6 +145,7 @@ static void CollapseVersions(int min_sdk, ResourceEntry* entry) { } bool VersionCollapser::Consume(IAaptContext* context, ResourceTable* table) { + TRACE_NAME("VersionCollapser::Consume"); const int min_sdk = context->GetMinSdkVersion(); for (auto& package : table->packages) { for (auto& type : package->types) { diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp index 78e00746f6cb..61a8fbbb7f52 100644 --- a/tools/aapt2/process/SymbolTable.cpp +++ b/tools/aapt2/process/SymbolTable.cpp @@ -30,6 +30,7 @@ #include "Resource.h" #include "ResourceUtils.h" #include "ValueVisitor.h" +#include "trace/TraceBuffer.h" #include "util/Util.h" using ::android::ApkAssets; @@ -217,6 +218,7 @@ std::unique_ptr ResourceTableSymbolSource::FindByName( } bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) { + TRACE_CALL(); if (std::unique_ptr apk = ApkAssets::Load(path.data())) { apk_assets_.push_back(std::move(apk)); @@ -233,6 +235,7 @@ bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) { } std::map AssetManagerSymbolSource::GetAssignedPackageIds() const { + TRACE_CALL(); std::map package_map; asset_manager_.ForEachPackage([&package_map](const std::string& name, uint8_t id) -> bool { package_map.insert(std::make_pair(id, name)); diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp index 24cd5ba302ea..6a672717f38e 100644 --- a/tools/aapt2/split/TableSplitter.cpp +++ b/tools/aapt2/split/TableSplitter.cpp @@ -27,6 +27,7 @@ #include "androidfw/ConfigDescription.h" #include "ResourceTable.h" +#include "trace/TraceBuffer.h" #include "util/Util.h" using ::android::ConfigDescription; @@ -154,6 +155,7 @@ static void MarkNonPreferredDensitiesAsClaimed( } } bool TableSplitter::VerifySplitConstraints(IAaptContext* context) { + TRACE_CALL(); bool error = false; for (size_t i = 0; i < split_constraints_.size(); i++) { if (split_constraints_[i].configs.size() == 0) { diff --git a/tools/aapt2/trace/TraceBuffer.cpp b/tools/aapt2/trace/TraceBuffer.cpp new file mode 100644 index 000000000000..b4b31d9daf6e --- /dev/null +++ b/tools/aapt2/trace/TraceBuffer.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TraceBuffer.h" + +#include +#include +#include +#include + +#include + +#include "android-base/utf8.h" + +#include "util/Files.h" + +namespace aapt { +namespace tracebuffer { + +namespace { + +constexpr char kBegin = 'B'; +constexpr char kEnd = 'E'; + +struct TracePoint { + pid_t tid; + int64_t time; + std::string tag; + char type; +}; + +std::vector traces; + +int64_t GetTime() noexcept { + auto now = std::chrono::steady_clock::now(); + return std::chrono::duration_cast(now.time_since_epoch()).count(); +} + +} // namespace anonymous + +void AddWithTime(const std::string& tag, char type, int64_t time) noexcept { + TracePoint t = {getpid(), time, tag, type}; + traces.emplace_back(t); +} + +void Add(const std::string& tag, char type) noexcept { + AddWithTime(tag, type, GetTime()); +} + + + + +void Flush(const std::string& basePath) { + TRACE_CALL(); + if (basePath.empty()) { + return; + } + + std::stringstream s; + s << basePath << aapt::file::sDirSep << "report_aapt2_" << getpid() << ".json"; + FILE* f = android::base::utf8::fopen(s.str().c_str(), "a"); + if (f == nullptr) { + return; + } + + for(const TracePoint& trace : traces) { + fprintf(f, "{\"ts\" : \"%" PRIu64 "\", \"ph\" : \"%c\", \"tid\" : \"%d\" , \"pid\" : \"%d\", " + "\"name\" : \"%s\" },\n", trace.time, trace.type, 0, trace.tid, trace.tag.c_str()); + } + fclose(f); + traces.clear(); +} + +} // namespace tracebuffer + +void BeginTrace(const std::string& tag) { + tracebuffer::Add(tag, tracebuffer::kBegin); +} + +void EndTrace() { + tracebuffer::Add("", tracebuffer::kEnd); +} + +Trace::Trace(const std::string& tag) { + tracebuffer::Add(tag, tracebuffer::kBegin); +} + +Trace::Trace(const std::string& tag, const std::vector& args) { + std::stringstream s; + s << tag; + s << " "; + for (auto& arg : args) { + s << arg.to_string(); + s << " "; + } + tracebuffer::Add(s.str(), tracebuffer::kBegin); +} + +Trace::~Trace() { + tracebuffer::Add("", tracebuffer::kEnd); +} + +FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag) + : basepath_(basepath) { + tracebuffer::Add(tag, tracebuffer::kBegin); +} + +FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag, + const std::vector& args) : basepath_(basepath) { + std::stringstream s; + s << tag; + s << " "; + for (auto& arg : args) { + s << arg.to_string(); + s << " "; + } + tracebuffer::Add(s.str(), tracebuffer::kBegin); +} + +FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag, + const std::vector& args) : basepath_(basepath){ + std::stringstream s; + s << tag; + s << " "; + for (auto& arg : args) { + s << arg; + s << " "; + } + tracebuffer::Add(s.str(), tracebuffer::kBegin); +} + +FlushTrace::~FlushTrace() { + tracebuffer::Add("", tracebuffer::kEnd); + tracebuffer::Flush(basepath_); +} + +} // namespace aapt + diff --git a/tools/aapt2/trace/TraceBuffer.h b/tools/aapt2/trace/TraceBuffer.h new file mode 100644 index 000000000000..8618e0eeb731 --- /dev/null +++ b/tools/aapt2/trace/TraceBuffer.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAPT_TRACEBUFFER_H +#define AAPT_TRACEBUFFER_H + +#include +#include + +#include + +namespace aapt { + +// Record timestamps for beginning and end of a task and generate systrace json fragments. +// This is an in-process ftrace which has the advantage of being platform independent. +// These methods are NOT thread-safe since aapt2 is not multi-threaded. + +// Convenience RIAA object to automatically finish an event when object goes out of scope. +class Trace { +public: + Trace(const std::string& tag); + Trace(const std::string& tag, const std::vector& args); + ~Trace(); +}; + +// Manual markers. +void BeginTrace(const std::string& tag); +void EndTrace(); + +// A master trace is required to flush events to disk. Events are formatted in systrace +// json format. +class FlushTrace { +public: + explicit FlushTrace(const std::string& basepath, const std::string& tag); + explicit FlushTrace(const std::string& basepath, const std::string& tag, + const std::vector& args); + explicit FlushTrace(const std::string& basepath, const std::string& tag, + const std::vector& args); + ~FlushTrace(); +private: + std::string basepath_; +}; + +#define TRACE_CALL() Trace __t(__func__) +#define TRACE_NAME(tag) Trace __t(tag) +#define TRACE_NAME_ARGS(tag, args) Trace __t(tag, args) + +#define TRACE_FLUSH(basename, tag) FlushTrace __t(basename, tag) +#define TRACE_FLUSH_ARGS(basename, tag, args) FlushTrace __t(basename, tag, args) +} // namespace aapt +#endif //AAPT_TRACEBUFFER_H diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index acd07c2876c8..9a725fad8727 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -26,6 +26,7 @@ #include "android-base/logging.h" #include "ResourceUtils.h" +#include "trace/TraceBuffer.h" #include "XmlPullParser.h" #include "util/Util.h" @@ -264,6 +265,7 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo } std::unique_ptr Inflate(const void* data, size_t len, std::string* out_error) { + TRACE_CALL(); // We import the android namespace because on Windows NO_ERROR is a macro, not // an enum, which causes errors when qualifying it with android:: using namespace android; -- cgit v1.2.3-59-g8ed1b From 34039b26f554500450dd566d5710b9b17f155d6f Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Mon, 18 Mar 2019 08:57:47 -0700 Subject: Add build number to aapt2 version This changes adds the build id to the version printed by "aapt2 version". This change also adds a field to the ResourceTable proto that specifies the fingerprints of tools used to build the table. Bug: 123663089 Test: manual Change-Id: Ifaf33c1e506b68e9f1d921fdbeddf36485e65790 --- tools/aapt2/Android.bp | 1 + tools/aapt2/Main.cpp | 9 +-------- tools/aapt2/Resources.proto | 9 +++++++++ tools/aapt2/format/proto/ProtoSerialize.cpp | 3 +++ tools/aapt2/util/Util.cpp | 22 +++++++++++++++++++++- tools/aapt2/util/Util.h | 6 ++++++ 6 files changed, 41 insertions(+), 9 deletions(-) (limited to 'tools/aapt2/Main.cpp') diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index aca2be1da33d..326c88d47064 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -57,6 +57,7 @@ cc_defaults { "libbase", "libprotobuf-cpp-lite", "libz", + "libbuildversion", ], stl: "libc++_static", group_static_libs: true, diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 39eb9879f86d..213bdd2372ec 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -46,12 +46,6 @@ using ::android::base::StringPrintf; namespace aapt { -// DO NOT UPDATE, this is more of a marketing version. -static const char* sMajorVersion = "2"; - -// Update minor version whenever a feature or flag is added. -static const char* sMinorVersion = "19"; - /** Prints the version information of AAPT2. */ class VersionCommand : public Command { public: @@ -60,8 +54,7 @@ class VersionCommand : public Command { } int Action(const std::vector& /* args */) override { - std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion, - sMinorVersion) + std::cerr << StringPrintf("%s %s", util::GetToolName(), util::GetToolFingerprint().c_str()) << std::endl; return 0; } diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index a2fd7c664b04..ad068e3e0c46 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -41,6 +41,12 @@ message Source { SourcePosition position = 2; } +// The name and version fingerprint of a build tool. +message ToolFingerprint { + string tool = 1; + string version = 2; +} + // Top level message representing a resource table. message ResourceTable { // The string pool containing source paths referenced throughout the resource table. This does @@ -52,6 +58,9 @@ message ResourceTable { // The declarations within the resource table. repeated Overlayable overlayable = 3; + + // The version fingerprints of the tools that built the resource table. + repeated ToolFingerprint tool_fingerprint = 4; } // A package ID in the range [0x00, 0xff]. diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index eb2b1a2f35d3..6564e0b05641 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -321,6 +321,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, IDiagnostics* diag) { StringPool source_pool; + pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint(); + pb_fingerprint->set_tool(util::GetToolName()); + pb_fingerprint->set_version(util::GetToolFingerprint()); std::vector overlayables; for (const std::unique_ptr& package : table.packages) { diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index 59b7fff0f9e3..37ce65e4fe5b 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -21,13 +21,15 @@ #include #include +#include "android-base/stringprintf.h" #include "androidfw/StringPiece.h" -#include "utils/Unicode.h" +#include "build/version.h" #include "text/Unicode.h" #include "text/Utf8Iterator.h" #include "util/BigBuffer.h" #include "util/Maybe.h" +#include "utils/Unicode.h" using ::aapt::text::Utf8Iterator; using ::android::StringPiece; @@ -200,6 +202,24 @@ Maybe GetFullyQualifiedClassName(const StringPiece& package, return result; } +const char* GetToolName() { + static const char* const sToolName = "Android Asset Packaging Tool (aapt)"; + return sToolName; +} + +std::string GetToolFingerprint() { + // DO NOT UPDATE, this is more of a marketing version. + static const char* const sMajorVersion = "2"; + + // Update minor version whenever a feature or flag is added. + static const char* const sMinorVersion = "19"; + + // The build id of aapt2 binary. + static const std::string sBuildId = android::build::GetBuildNumber(); + + return android::base::StringPrintf("%s.%s-%s", sMajorVersion, sMinorVersion, sBuildId.c_str()); +} + static size_t ConsumeDigits(const char* start, const char* end) { const char* c = start; for (; c != end && *c >= '0' && *c <= '9'; c++) { diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index c6e8e6ef7619..a956957eace8 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -98,6 +98,12 @@ bool IsAndroidSplitName(const android::StringPiece& str); Maybe GetFullyQualifiedClassName(const android::StringPiece& package, const android::StringPiece& class_name); +// Retrieves the formatted name of aapt2. +const char* GetToolName(); + +// Retrieves the build fingerprint of aapt2. +std::string GetToolFingerprint(); + template typename std::enable_if::value, int>::type compare(const T& a, const T& b) { if (a < b) { -- cgit v1.2.3-59-g8ed1b