Dump XML files in aapt2 dump

Test: manual
Change-Id: Id7f656c1385f6d1fec8eaa993c8e2b36bb1ae5b0
This commit is contained in:
Adam Lesinski
2018-02-13 16:44:10 -08:00
parent 97661735aa
commit da9eba300b
3 changed files with 116 additions and 37 deletions

View File

@@ -414,59 +414,70 @@ class XmlPrinter : public xml::ConstVisitor {
public:
using xml::ConstVisitor::Visit;
XmlPrinter(Printer* printer) : printer_(printer) {
}
void Visit(const xml::Element* el) override {
const size_t previous_size = prefix_.size();
for (const xml::NamespaceDecl& decl : el->namespace_decls) {
std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri
<< " (line=" << decl.line_number << ")\n";
prefix_ += " ";
printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
decl.line_number));
printer_->Indent();
}
std::cerr << prefix_ << "E: ";
printer_->Print("E: ");
if (!el->namespace_uri.empty()) {
std::cerr << el->namespace_uri << ":";
printer_->Print(el->namespace_uri);
printer_->Print(":");
}
std::cerr << el->name << " (line=" << el->line_number << ")\n";
printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
printer_->Indent();
for (const xml::Attribute& attr : el->attributes) {
std::cerr << prefix_ << " A: ";
printer_->Print("A: ");
if (!attr.namespace_uri.empty()) {
std::cerr << attr.namespace_uri << ":";
printer_->Print(attr.namespace_uri);
printer_->Print(":");
}
std::cerr << attr.name;
printer_->Print(attr.name);
if (attr.compiled_attribute) {
std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
<< ")";
printer_->Print("(");
printer_->Print(
attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
printer_->Print(")");
}
std::cerr << "=";
printer_->Print("=");
if (attr.compiled_value != nullptr) {
std::cerr << *attr.compiled_value;
attr.compiled_value->PrettyPrint(printer_);
} else {
std::cerr << attr.value;
printer_->Print(attr.value);
}
std::cerr << "\n";
printer_->Println();
}
prefix_ += " ";
printer_->Indent();
xml::ConstVisitor::Visit(el);
prefix_.resize(previous_size);
printer_->Undent();
printer_->Undent();
for (size_t i = 0; i < el->namespace_decls.size(); i++) {
printer_->Undent();
}
}
void Visit(const xml::Text* text) override {
std::cerr << prefix_ << "T: '" << text->text << "'\n";
printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
}
private:
std::string prefix_;
Printer* printer_;
};
} // namespace
void Debug::DumpXml(const xml::XmlResource& doc) {
XmlPrinter printer;
doc.root->Accept(&printer);
void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
XmlPrinter xml_visitor(printer);
doc.root->Accept(&xml_visitor);
}
} // namespace aapt

View File

@@ -37,7 +37,7 @@ struct Debug {
text::Printer* printer);
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);
static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
};
} // namespace aapt

View File

@@ -38,6 +38,13 @@ using ::android::base::StringPrintf;
namespace aapt {
struct DumpOptions {
DebugPrintTableOptions print_options;
// The path to a file within an APK to dump.
Maybe<std::string> file_to_dump_path;
};
static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
switch (type) {
case ResourceFile::Type::kPng:
@@ -69,8 +76,52 @@ 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<xml::XmlResource> doc;
if (proto) {
std::unique_ptr<io::InputStream> 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<io::IData> 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 DebugPrintTableOptions& print_options) {
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);
@@ -80,7 +131,10 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
if (zip) {
ResourceTable table;
bool proto = false;
if (io::IFile* file = zip->FindFile("resources.pb")) {
proto = true;
std::unique_ptr<io::IData> data = file->OpenAsData();
if (data == nullptr) {
context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
@@ -98,8 +152,6 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
<< "failed to parse table: " << err);
return false;
}
printer.Println("Proto APK");
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
@@ -112,12 +164,26 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
if (!parser.Parse()) {
return false;
}
printer.Println("Binary APK");
}
Debug::PrintTable(table, print_options, &printer);
return true;
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();
@@ -159,7 +225,7 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
}
printer.Indent();
Debug::PrintTable(table, print_options, &printer);
Debug::PrintTable(table, options.print_options, &printer);
printer.Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
printer.Println("kResFile");
@@ -243,10 +309,13 @@ class DumpContext : public IAaptContext {
int Dump(const std::vector<StringPiece>& args) {
bool verbose = false;
bool no_values = false;
DumpOptions options;
Flags flags = Flags()
.OptionalSwitch("--no-values",
"Suppresses output of values when displaying resource tables.",
&no_values)
.OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
&options.file_to_dump_path)
.OptionalSwitch("-v", "increase verbosity of output", &verbose);
if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
return 1;
@@ -255,11 +324,10 @@ int Dump(const std::vector<StringPiece>& args) {
DumpContext context;
context.SetVerbose(verbose);
DebugPrintTableOptions dump_table_options;
dump_table_options.show_sources = true;
dump_table_options.show_values = !no_values;
options.print_options.show_sources = true;
options.print_options.show_values = !no_values;
for (const std::string& arg : flags.GetArgs()) {
if (!TryDumpFile(&context, arg, dump_table_options)) {
if (!TryDumpFile(&context, arg, options)) {
return 1;
}
}