blob: c7a35672dc903a008a8c83d028a51eff17dd638b [file] [log] [blame]
Ryan Mitchell833a1a62018-07-10 13:51:36 -07001/*
2 * Copyright (C) 2018 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#ifndef AAPT2_DUMP_H
18#define AAPT2_DUMP_H
19
Ryan Mitchell19b27092018-08-13 11:36:27 -070020#include <io/FileStream.h>
21#include <io/ZipArchive.h>
22
Ryan Mitchell833a1a62018-07-10 13:51:36 -070023#include "Command.h"
24#include "Debug.h"
Ryan Mitchell214846d2018-09-19 16:57:01 -070025#include "LoadedApk.h"
Ryan Mitchellfc225b22018-08-21 14:52:51 -070026#include "dump/DumpManifest.h"
Ryan Mitchell833a1a62018-07-10 13:51:36 -070027
28namespace aapt {
29
Ryan Mitchell214846d2018-09-19 16:57:01 -070030/**
31 * The base command for dumping information about apks. When the command is executed, the command
32 * performs the DumpApkCommand::Dump() operation on each apk provided as a file argument.
33 **/
34class DumpApkCommand : public Command {
35 public:
36 explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
37 : Command(name), printer_(printer), diag_(diag) {
Fabien Sanglard362da822019-03-14 11:39:39 -070038 SetDescription("Dump information about an APK or APC.");
Ryan Mitchell214846d2018-09-19 16:57:01 -070039 }
40
41 text::Printer* GetPrinter() {
42 return printer_;
43 }
44
45 IDiagnostics* GetDiagnostics() {
46 return diag_;
47 }
48
Ryan Mitchell4382e442021-07-14 12:53:01 -070049 std::optional<std::string> GetPackageName(LoadedApk* apk) {
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -070050 xml::Element* manifest_el = apk->GetManifest()->root.get();
51 if (!manifest_el) {
52 GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest.");
Ryan Mitchell4382e442021-07-14 12:53:01 -070053 return {};
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -070054 }
55
56 xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
57 if (!attr) {
58 GetDiagnostics()->Error(DiagMessage() << "No package name.");
Ryan Mitchell4382e442021-07-14 12:53:01 -070059 return {};
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -070060 }
61 return attr->value;
62 }
63
Ryan Mitchell214846d2018-09-19 16:57:01 -070064 /** Perform the dump operation on the apk. */
65 virtual int Dump(LoadedApk* apk) = 0;
66
67 int Action(const std::vector<std::string>& args) final {
68 if (args.size() < 1) {
69 diag_->Error(DiagMessage() << "No dump apk specified.");
70 return 1;
71 }
72
73 bool error = false;
74 for (auto apk : args) {
75 auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
76 if (!loaded_apk) {
77 error = true;
78 continue;
79 }
80
81 error |= Dump(loaded_apk.get());
82 }
83
84 return error;
85 }
86
87 private:
88 text::Printer* printer_;
89 IDiagnostics* diag_;
90};
91
92/** Command that prints contents of files generated from the compilation stage. */
Ryan Mitchell5d275512018-07-19 14:29:00 -070093class DumpAPCCommand : public Command {
Ryan Mitchell833a1a62018-07-10 13:51:36 -070094 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -070095 explicit DumpAPCCommand(text::Printer* printer, IDiagnostics* diag)
96 : Command("apc"), printer_(printer), diag_(diag) {
Ryan Mitchell5d275512018-07-19 14:29:00 -070097 SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation.");
Ryan Mitchell833a1a62018-07-10 13:51:36 -070098 AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
Ryan Mitchell5d275512018-07-19 14:29:00 -070099 &no_values_);
100 AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700101 }
102
103 int Action(const std::vector<std::string>& args) override;
104
105 private:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700106 text::Printer* printer_;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700107 IDiagnostics* diag_;
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700108 bool no_values_ = false;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700109 bool verbose_ = false;
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700110};
111
Ryan Mitchell214846d2018-09-19 16:57:01 -0700112/** Easter egg command shown when users enter "badger" instead of "badging". */
113class DumpBadgerCommand : public Command {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700114 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700115 explicit DumpBadgerCommand(text::Printer* printer) : Command("badger"), printer_(printer) {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700116 }
117
118 int Action(const std::vector<std::string>& args) override;
119
120 private:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700121 text::Printer* printer_;
122 const static char kBadgerData[2925];
Ryan Mitchell5d275512018-07-19 14:29:00 -0700123};
124
Ryan Mitchell214846d2018-09-19 16:57:01 -0700125class DumpBadgingCommand : public DumpApkCommand {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700126 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700127 explicit DumpBadgingCommand(text::Printer* printer, IDiagnostics* diag)
128 : DumpApkCommand("badging", printer, diag) {
129 SetDescription("Print information extracted from the manifest of the APK.");
130 AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
131 &options_.include_meta_data);
132 }
133
Iurii Makhnodcead622022-04-13 18:00:03 +0000134 void SetIncludeMetaData(bool value) {
135 options_.include_meta_data = value;
136 }
137
138 void SetOnlyPermissions(bool value) {
139 options_.only_permissions = value;
140 }
141
Ryan Mitchell214846d2018-09-19 16:57:01 -0700142 int Dump(LoadedApk* apk) override {
143 return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics());
144 }
145
146 private:
147 DumpManifestOptions options_;
148};
149
150class DumpConfigsCommand : public DumpApkCommand {
151 public:
152 explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag)
153 : DumpApkCommand("configurations", printer, diag) {
154 SetDescription("Print every configuration used by a resource in the APK.");
155 }
156
157 int Dump(LoadedApk* apk) override;
158};
159
160class DumpPackageNameCommand : public DumpApkCommand {
161 public:
162 explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag)
163 : DumpApkCommand("packagename", printer, diag) {
164 SetDescription("Print the package name of the APK.");
165 }
166
167 int Dump(LoadedApk* apk) override;
168};
169
170class DumpPermissionsCommand : public DumpApkCommand {
171 public:
172 explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag)
173 : DumpApkCommand("permissions", printer, diag) {
174 SetDescription("Print the permissions extracted from the manifest of the APK.");
175 }
176
177 int Dump(LoadedApk* apk) override {
178 DumpManifestOptions options;
179 options.only_permissions = true;
180 return DumpManifest(apk, options, GetPrinter(), GetDiagnostics());
181 }
182};
183
184class DumpStringsCommand : public DumpApkCommand {
185 public:
186 explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag)
187 : DumpApkCommand("strings", printer, diag) {
188 SetDescription("Print the contents of the resource table string pool in the APK.");
189 }
190
191 int Dump(LoadedApk* apk) override;
192};
193
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -0700194/** Prints the graph of parents of a style in an APK. */
195class DumpStyleParentCommand : public DumpApkCommand {
196 public:
197 explicit DumpStyleParentCommand(text::Printer* printer, IDiagnostics* diag)
198 : DumpApkCommand("styleparents", printer, diag) {
199 SetDescription("Print the parents of a style in an APK.");
200 AddRequiredFlag("--style", "The name of the style to print", &style_);
201 }
202
203 int Dump(LoadedApk* apk) override;
204
205 private:
206 std::string style_;
207};
208
Ryan Mitchell214846d2018-09-19 16:57:01 -0700209class DumpTableCommand : public DumpApkCommand {
210 public:
211 explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag)
212 : DumpApkCommand("resources", printer, diag) {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700213 SetDescription("Print the contents of the resource table from the APK.");
214 AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
215 &no_values_);
216 AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
217 }
218
Ryan Mitchell214846d2018-09-19 16:57:01 -0700219 int Dump(LoadedApk* apk) override;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700220
221 private:
Ryan Mitchell5d275512018-07-19 14:29:00 -0700222 bool no_values_ = false;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700223 bool verbose_ = false;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700224};
225
Ryan Mitchell214846d2018-09-19 16:57:01 -0700226class DumpXmlStringsCommand : public DumpApkCommand {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700227 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700228 explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag)
229 : DumpApkCommand("xmlstrings", printer, diag) {
230 SetDescription("Print the string pool of a compiled xml in an APK.");
231 AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
232 }
233
234 int Dump(LoadedApk* apk) override;
235
236 private:
237 std::vector<std::string> files_;
238};
239
Ryan Mitchell19b27092018-08-13 11:36:27 -0700240class DumpChunks : public DumpApkCommand {
241 public:
242 DumpChunks(text::Printer* printer, IDiagnostics* diag) : DumpApkCommand("chunks", printer, diag) {
243 SetDescription("Print the chunk information of the compiled resources.arsc in the APK.");
244 }
245
246 int Dump(LoadedApk* apk) override;
247};
248
249/** Prints the tree of a compiled xml in an APK. */
Ryan Mitchell214846d2018-09-19 16:57:01 -0700250class DumpXmlTreeCommand : public DumpApkCommand {
251 public:
252 explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag)
253 : DumpApkCommand("xmltree", printer, diag) {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700254 SetDescription("Print the tree of a compiled xml in an APK.");
255 AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
256 }
257
Ryan Mitchell214846d2018-09-19 16:57:01 -0700258 int Dump(LoadedApk* apk) override;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700259
260 private:
Ryan Mitchell5d275512018-07-19 14:29:00 -0700261 std::vector<std::string> files_;
262};
263
Mårten Kongstad1d3b64852019-09-17 13:02:32 +0200264class DumpOverlayableCommand : public DumpApkCommand {
265 public:
266 explicit DumpOverlayableCommand(text::Printer* printer, IDiagnostics* diag)
267 : DumpApkCommand("overlayable", printer, diag) {
268 SetDescription("Print the <overlayable> resources of an APK.");
269 }
270
271 int Dump(LoadedApk* apk) override;
272};
273
Todd Kennedy908b7fc2018-08-24 10:11:21 -0700274/** The default dump command. Performs no action because a subcommand is required. */
Ryan Mitchell5d275512018-07-19 14:29:00 -0700275class DumpCommand : public Command {
276 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700277 explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
278 : Command("dump", "d"), diag_(diag) {
279 AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
280 AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
281 AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(printer, diag_));
282 AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(printer, diag_));
283 AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(printer, diag_));
284 AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(printer, diag_));
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -0700285 AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700286 AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700287 AddOptionalSubcommand(util::make_unique<DumpChunks>(printer, diag_));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700288 AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_));
289 AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_));
Mårten Kongstad1d3b64852019-09-17 13:02:32 +0200290 AddOptionalSubcommand(util::make_unique<DumpOverlayableCommand>(printer, diag_));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700291 AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true);
Ryan Mitchell5d275512018-07-19 14:29:00 -0700292 }
293
Ryan Mitchell214846d2018-09-19 16:57:01 -0700294 int Action(const std::vector<std::string>& args) override {
295 if (args.size() == 0) {
296 diag_->Error(DiagMessage() << "no subcommand specified");
297 } else {
298 diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
299 }
300 Usage(&std::cerr);
301 return 1;
302 }
Ryan Mitchell5d275512018-07-19 14:29:00 -0700303
304 private:
305 IDiagnostics* diag_;
306};
307
Ryan Mitchell214846d2018-09-19 16:57:01 -0700308} // namespace aapt
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700309
Ryan Mitchell214846d2018-09-19 16:57:01 -0700310#endif // AAPT2_DUMP_H