blob: ec320ecd2a3240e1fba9dd2d798a71899e8151fc [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
134 int Dump(LoadedApk* apk) override {
135 return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics());
136 }
137
138 private:
139 DumpManifestOptions options_;
140};
141
142class DumpConfigsCommand : public DumpApkCommand {
143 public:
144 explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag)
145 : DumpApkCommand("configurations", printer, diag) {
146 SetDescription("Print every configuration used by a resource in the APK.");
147 }
148
149 int Dump(LoadedApk* apk) override;
150};
151
152class DumpPackageNameCommand : public DumpApkCommand {
153 public:
154 explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag)
155 : DumpApkCommand("packagename", printer, diag) {
156 SetDescription("Print the package name of the APK.");
157 }
158
159 int Dump(LoadedApk* apk) override;
160};
161
162class DumpPermissionsCommand : public DumpApkCommand {
163 public:
164 explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag)
165 : DumpApkCommand("permissions", printer, diag) {
166 SetDescription("Print the permissions extracted from the manifest of the APK.");
167 }
168
169 int Dump(LoadedApk* apk) override {
170 DumpManifestOptions options;
171 options.only_permissions = true;
172 return DumpManifest(apk, options, GetPrinter(), GetDiagnostics());
173 }
174};
175
176class DumpStringsCommand : public DumpApkCommand {
177 public:
178 explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag)
179 : DumpApkCommand("strings", printer, diag) {
180 SetDescription("Print the contents of the resource table string pool in the APK.");
181 }
182
183 int Dump(LoadedApk* apk) override;
184};
185
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -0700186/** Prints the graph of parents of a style in an APK. */
187class DumpStyleParentCommand : public DumpApkCommand {
188 public:
189 explicit DumpStyleParentCommand(text::Printer* printer, IDiagnostics* diag)
190 : DumpApkCommand("styleparents", printer, diag) {
191 SetDescription("Print the parents of a style in an APK.");
192 AddRequiredFlag("--style", "The name of the style to print", &style_);
193 }
194
195 int Dump(LoadedApk* apk) override;
196
197 private:
198 std::string style_;
199};
200
Ryan Mitchell214846d2018-09-19 16:57:01 -0700201class DumpTableCommand : public DumpApkCommand {
202 public:
203 explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag)
204 : DumpApkCommand("resources", printer, diag) {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700205 SetDescription("Print the contents of the resource table from the APK.");
206 AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
207 &no_values_);
208 AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
209 }
210
Ryan Mitchell214846d2018-09-19 16:57:01 -0700211 int Dump(LoadedApk* apk) override;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700212
213 private:
Ryan Mitchell5d275512018-07-19 14:29:00 -0700214 bool no_values_ = false;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700215 bool verbose_ = false;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700216};
217
Ryan Mitchell214846d2018-09-19 16:57:01 -0700218class DumpXmlStringsCommand : public DumpApkCommand {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700219 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700220 explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag)
221 : DumpApkCommand("xmlstrings", printer, diag) {
222 SetDescription("Print the string pool of a compiled xml in an APK.");
223 AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
224 }
225
226 int Dump(LoadedApk* apk) override;
227
228 private:
229 std::vector<std::string> files_;
230};
231
Ryan Mitchell19b27092018-08-13 11:36:27 -0700232class DumpChunks : public DumpApkCommand {
233 public:
234 DumpChunks(text::Printer* printer, IDiagnostics* diag) : DumpApkCommand("chunks", printer, diag) {
235 SetDescription("Print the chunk information of the compiled resources.arsc in the APK.");
236 }
237
238 int Dump(LoadedApk* apk) override;
239};
240
241/** Prints the tree of a compiled xml in an APK. */
Ryan Mitchell214846d2018-09-19 16:57:01 -0700242class DumpXmlTreeCommand : public DumpApkCommand {
243 public:
244 explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag)
245 : DumpApkCommand("xmltree", printer, diag) {
Ryan Mitchell5d275512018-07-19 14:29:00 -0700246 SetDescription("Print the tree of a compiled xml in an APK.");
247 AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
248 }
249
Ryan Mitchell214846d2018-09-19 16:57:01 -0700250 int Dump(LoadedApk* apk) override;
Ryan Mitchell5d275512018-07-19 14:29:00 -0700251
252 private:
Ryan Mitchell5d275512018-07-19 14:29:00 -0700253 std::vector<std::string> files_;
254};
255
Mårten Kongstad1d3b64852019-09-17 13:02:32 +0200256class DumpOverlayableCommand : public DumpApkCommand {
257 public:
258 explicit DumpOverlayableCommand(text::Printer* printer, IDiagnostics* diag)
259 : DumpApkCommand("overlayable", printer, diag) {
260 SetDescription("Print the <overlayable> resources of an APK.");
261 }
262
263 int Dump(LoadedApk* apk) override;
264};
265
Todd Kennedy908b7fc2018-08-24 10:11:21 -0700266/** The default dump command. Performs no action because a subcommand is required. */
Ryan Mitchell5d275512018-07-19 14:29:00 -0700267class DumpCommand : public Command {
268 public:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700269 explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
270 : Command("dump", "d"), diag_(diag) {
271 AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
272 AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
273 AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(printer, diag_));
274 AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(printer, diag_));
275 AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(printer, diag_));
276 AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(printer, diag_));
Aurimas Liutikas13e6a1d2018-09-25 16:11:40 -0700277 AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700278 AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700279 AddOptionalSubcommand(util::make_unique<DumpChunks>(printer, diag_));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700280 AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_));
281 AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_));
Mårten Kongstad1d3b64852019-09-17 13:02:32 +0200282 AddOptionalSubcommand(util::make_unique<DumpOverlayableCommand>(printer, diag_));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700283 AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true);
Ryan Mitchell5d275512018-07-19 14:29:00 -0700284 }
285
Ryan Mitchell214846d2018-09-19 16:57:01 -0700286 int Action(const std::vector<std::string>& args) override {
287 if (args.size() == 0) {
288 diag_->Error(DiagMessage() << "no subcommand specified");
289 } else {
290 diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
291 }
292 Usage(&std::cerr);
293 return 1;
294 }
Ryan Mitchell5d275512018-07-19 14:29:00 -0700295
296 private:
297 IDiagnostics* diag_;
298};
299
Ryan Mitchell214846d2018-09-19 16:57:01 -0700300} // namespace aapt
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700301
Ryan Mitchell214846d2018-09-19 16:57:01 -0700302#endif // AAPT2_DUMP_H