1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <vector> 18 19#include "androidfw/StringPiece.h" 20 21#include "Debug.h" 22#include "Diagnostics.h" 23#include "Flags.h" 24#include "io/ZipArchive.h" 25#include "process/IResourceTableConsumer.h" 26#include "proto/ProtoSerialize.h" 27#include "unflatten/BinaryResourceParser.h" 28#include "util/Files.h" 29 30using android::StringPiece; 31 32namespace aapt { 33 34void DumpCompiledFile(const pb::CompiledFile& pb_file, const void* data, size_t len, 35 const Source& source, IAaptContext* context) { 36 std::unique_ptr<ResourceFile> file = 37 DeserializeCompiledFileFromPb(pb_file, source, context->GetDiagnostics()); 38 if (!file) { 39 context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file"); 40 return; 41 } 42 43 std::cout << "Resource: " << file->name << "\n" 44 << "Config: " << file->config << "\n" 45 << "Source: " << file->source << "\n"; 46} 47 48void TryDumpFile(IAaptContext* context, const std::string& file_path) { 49 std::unique_ptr<ResourceTable> table; 50 51 std::string err; 52 std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err); 53 if (zip) { 54 io::IFile* file = zip->FindFile("resources.arsc.flat"); 55 if (file) { 56 std::unique_ptr<io::IData> data = file->OpenAsData(); 57 if (!data) { 58 context->GetDiagnostics()->Error(DiagMessage(file_path) 59 << "failed to open resources.arsc.flat"); 60 return; 61 } 62 63 pb::ResourceTable pb_table; 64 if (!pb_table.ParseFromArray(data->data(), data->size())) { 65 context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.arsc.flat"); 66 return; 67 } 68 69 table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics()); 70 if (!table) { 71 return; 72 } 73 } 74 75 if (!table) { 76 file = zip->FindFile("resources.arsc"); 77 if (file) { 78 std::unique_ptr<io::IData> data = file->OpenAsData(); 79 if (!data) { 80 context->GetDiagnostics()->Error(DiagMessage(file_path) 81 << "failed to open resources.arsc"); 82 return; 83 } 84 85 table = util::make_unique<ResourceTable>(); 86 BinaryResourceParser parser(context, table.get(), Source(file_path), data->data(), 87 data->size()); 88 if (!parser.Parse()) { 89 return; 90 } 91 } 92 } 93 } 94 95 if (!table) { 96 Maybe<android::FileMap> file = file::MmapPath(file_path, &err); 97 if (!file) { 98 context->GetDiagnostics()->Error(DiagMessage(file_path) << err); 99 return; 100 } 101 102 android::FileMap* file_map = &file.value(); 103 104 // Try as a compiled table. 105 pb::ResourceTable pb_table; 106 if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) { 107 table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics()); 108 } 109 110 if (!table) { 111 // Try as a compiled file. 112 CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength()); 113 114 uint32_t num_files = 0; 115 if (!input.ReadLittleEndian32(&num_files)) { 116 return; 117 } 118 119 for (uint32_t i = 0; i < num_files; i++) { 120 pb::CompiledFile compiled_file; 121 if (!input.ReadCompiledFile(&compiled_file)) { 122 context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file"); 123 return; 124 } 125 126 uint64_t offset, len; 127 if (!input.ReadDataMetaData(&offset, &len)) { 128 context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data"); 129 return; 130 } 131 132 const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset; 133 DumpCompiledFile(compiled_file, data, len, Source(file_path), context); 134 } 135 } 136 } 137 138 if (table) { 139 DebugPrintTableOptions options; 140 options.show_sources = true; 141 Debug::PrintTable(table.get(), options); 142 } 143} 144 145class DumpContext : public IAaptContext { 146 public: 147 PackageType GetPackageType() override { 148 // Doesn't matter. 149 return PackageType::kApp; 150 } 151 152 IDiagnostics* GetDiagnostics() override { 153 return &diagnostics_; 154 } 155 156 NameMangler* GetNameMangler() override { 157 abort(); 158 return nullptr; 159 } 160 161 const std::string& GetCompilationPackage() override { 162 static std::string empty; 163 return empty; 164 } 165 166 uint8_t GetPackageId() override { 167 return 0; 168 } 169 170 SymbolTable* GetExternalSymbols() override { 171 abort(); 172 return nullptr; 173 } 174 175 bool IsVerbose() override { 176 return verbose_; 177 } 178 179 void SetVerbose(bool val) { 180 verbose_ = val; 181 } 182 183 int GetMinSdkVersion() override { 184 return 0; 185 } 186 187 private: 188 StdErrDiagnostics diagnostics_; 189 bool verbose_ = false; 190}; 191 192/** 193 * Entry point for dump command. 194 */ 195int Dump(const std::vector<StringPiece>& args) { 196 bool verbose = false; 197 Flags flags = Flags().OptionalSwitch("-v", "increase verbosity of output", &verbose); 198 if (!flags.Parse("aapt2 dump", args, &std::cerr)) { 199 return 1; 200 } 201 202 DumpContext context; 203 context.SetVerbose(verbose); 204 205 for (const std::string& arg : flags.GetArgs()) { 206 TryDumpFile(&context, arg); 207 } 208 return 0; 209} 210 211} // namespace aapt 212