• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 using android::StringPiece;
31 
32 namespace aapt {
33 
DumpCompiledFile(const pb::CompiledFile & pb_file,const void * data,size_t len,const Source & source,IAaptContext * context)34 void 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 
TryDumpFile(IAaptContext * context,const std::string & file_path)48 void 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 
145 class DumpContext : public IAaptContext {
146  public:
GetPackageType()147   PackageType GetPackageType() override {
148     // Doesn't matter.
149     return PackageType::kApp;
150   }
151 
GetDiagnostics()152   IDiagnostics* GetDiagnostics() override {
153     return &diagnostics_;
154   }
155 
GetNameMangler()156   NameMangler* GetNameMangler() override {
157     abort();
158     return nullptr;
159   }
160 
GetCompilationPackage()161   const std::string& GetCompilationPackage() override {
162     static std::string empty;
163     return empty;
164   }
165 
GetPackageId()166   uint8_t GetPackageId() override {
167     return 0;
168   }
169 
GetExternalSymbols()170   SymbolTable* GetExternalSymbols() override {
171     abort();
172     return nullptr;
173   }
174 
IsVerbose()175   bool IsVerbose() override {
176     return verbose_;
177   }
178 
SetVerbose(bool val)179   void SetVerbose(bool val) {
180     verbose_ = val;
181   }
182 
GetMinSdkVersion()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  */
Dump(const std::vector<StringPiece> & args)195 int 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