Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
Jeremy Meyer | b4f83ff | 2023-11-30 19:29:50 +0000 | [diff] [blame] | 20 | #include <androidfw/FileStream.h> |
Ryan Mitchell | 19b2709 | 2018-08-13 11:36:27 -0700 | [diff] [blame] | 21 | #include <io/ZipArchive.h> |
| 22 | |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 23 | #include "Command.h" |
| 24 | #include "Debug.h" |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 25 | #include "LoadedApk.h" |
Ryan Mitchell | fc225b2 | 2018-08-21 14:52:51 -0700 | [diff] [blame] | 26 | #include "dump/DumpManifest.h" |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 27 | |
| 28 | namespace aapt { |
| 29 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 30 | /** |
| 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 | **/ |
| 34 | class DumpApkCommand : public Command { |
| 35 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 36 | explicit DumpApkCommand(const std::string&& name, text::Printer* printer, |
| 37 | android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 38 | : Command(name), printer_(printer), diag_(diag) { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 39 | SetDescription("Dump information about an APK or APC."); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | text::Printer* GetPrinter() { |
| 43 | return printer_; |
| 44 | } |
| 45 | |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 46 | android::IDiagnostics* GetDiagnostics() { |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 47 | return diag_; |
| 48 | } |
| 49 | |
Ryan Mitchell | 4382e44 | 2021-07-14 12:53:01 -0700 | [diff] [blame] | 50 | std::optional<std::string> GetPackageName(LoadedApk* apk) { |
Aurimas Liutikas | 13e6a1d | 2018-09-25 16:11:40 -0700 | [diff] [blame] | 51 | xml::Element* manifest_el = apk->GetManifest()->root.get(); |
| 52 | if (!manifest_el) { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 53 | GetDiagnostics()->Error(android::DiagMessage() << "No AndroidManifest."); |
Ryan Mitchell | 4382e44 | 2021-07-14 12:53:01 -0700 | [diff] [blame] | 54 | return {}; |
Aurimas Liutikas | 13e6a1d | 2018-09-25 16:11:40 -0700 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); |
| 58 | if (!attr) { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 59 | GetDiagnostics()->Error(android::DiagMessage() << "No package name."); |
Ryan Mitchell | 4382e44 | 2021-07-14 12:53:01 -0700 | [diff] [blame] | 60 | return {}; |
Aurimas Liutikas | 13e6a1d | 2018-09-25 16:11:40 -0700 | [diff] [blame] | 61 | } |
| 62 | return attr->value; |
| 63 | } |
| 64 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 65 | /** Perform the dump operation on the apk. */ |
| 66 | virtual int Dump(LoadedApk* apk) = 0; |
| 67 | |
| 68 | int Action(const std::vector<std::string>& args) final { |
| 69 | if (args.size() < 1) { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 70 | diag_->Error(android::DiagMessage() << "No dump apk specified."); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 71 | return 1; |
| 72 | } |
| 73 | |
| 74 | bool error = false; |
| 75 | for (auto apk : args) { |
| 76 | auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); |
| 77 | if (!loaded_apk) { |
| 78 | error = true; |
| 79 | continue; |
| 80 | } |
| 81 | |
| 82 | error |= Dump(loaded_apk.get()); |
| 83 | } |
| 84 | |
| 85 | return error; |
| 86 | } |
| 87 | |
| 88 | private: |
| 89 | text::Printer* printer_; |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 90 | android::IDiagnostics* diag_; |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 91 | }; |
| 92 | |
| 93 | /** Command that prints contents of files generated from the compilation stage. */ |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 94 | class DumpAPCCommand : public Command { |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 95 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 96 | explicit DumpAPCCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 97 | : Command("apc"), printer_(printer), diag_(diag) { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 98 | SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation."); |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 99 | AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 100 | &no_values_); |
| 101 | AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | int Action(const std::vector<std::string>& args) override; |
| 105 | |
| 106 | private: |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 107 | text::Printer* printer_; |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 108 | android::IDiagnostics* diag_; |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 109 | bool no_values_ = false; |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 110 | bool verbose_ = false; |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 111 | }; |
| 112 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 113 | /** Easter egg command shown when users enter "badger" instead of "badging". */ |
| 114 | class DumpBadgerCommand : public Command { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 115 | public: |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 116 | explicit DumpBadgerCommand(text::Printer* printer) : Command("badger"), printer_(printer) { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | int Action(const std::vector<std::string>& args) override; |
| 120 | |
| 121 | private: |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 122 | text::Printer* printer_; |
| 123 | const static char kBadgerData[2925]; |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 124 | }; |
| 125 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 126 | class DumpBadgingCommand : public DumpApkCommand { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 127 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 128 | explicit DumpBadgingCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 129 | : DumpApkCommand("badging", printer, diag) { |
| 130 | SetDescription("Print information extracted from the manifest of the APK."); |
| 131 | AddOptionalSwitch("--include-meta-data", "Include meta-data information.", |
| 132 | &options_.include_meta_data); |
| 133 | } |
| 134 | |
Iurii Makhno | dcead62 | 2022-04-13 18:00:03 +0000 | [diff] [blame] | 135 | void SetIncludeMetaData(bool value) { |
| 136 | options_.include_meta_data = value; |
| 137 | } |
| 138 | |
| 139 | void SetOnlyPermissions(bool value) { |
| 140 | options_.only_permissions = value; |
| 141 | } |
| 142 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 143 | int Dump(LoadedApk* apk) override { |
| 144 | return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics()); |
| 145 | } |
| 146 | |
| 147 | private: |
| 148 | DumpManifestOptions options_; |
| 149 | }; |
| 150 | |
| 151 | class DumpConfigsCommand : public DumpApkCommand { |
| 152 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 153 | explicit DumpConfigsCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 154 | : DumpApkCommand("configurations", printer, diag) { |
| 155 | SetDescription("Print every configuration used by a resource in the APK."); |
| 156 | } |
| 157 | |
| 158 | int Dump(LoadedApk* apk) override; |
| 159 | }; |
| 160 | |
| 161 | class DumpPackageNameCommand : public DumpApkCommand { |
| 162 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 163 | explicit DumpPackageNameCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 164 | : DumpApkCommand("packagename", printer, diag) { |
| 165 | SetDescription("Print the package name of the APK."); |
| 166 | } |
| 167 | |
| 168 | int Dump(LoadedApk* apk) override; |
| 169 | }; |
| 170 | |
| 171 | class DumpPermissionsCommand : public DumpApkCommand { |
| 172 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 173 | explicit DumpPermissionsCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 174 | : DumpApkCommand("permissions", printer, diag) { |
| 175 | SetDescription("Print the permissions extracted from the manifest of the APK."); |
| 176 | } |
| 177 | |
| 178 | int Dump(LoadedApk* apk) override { |
| 179 | DumpManifestOptions options; |
| 180 | options.only_permissions = true; |
| 181 | return DumpManifest(apk, options, GetPrinter(), GetDiagnostics()); |
| 182 | } |
| 183 | }; |
| 184 | |
| 185 | class DumpStringsCommand : public DumpApkCommand { |
| 186 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 187 | explicit DumpStringsCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 188 | : DumpApkCommand("strings", printer, diag) { |
| 189 | SetDescription("Print the contents of the resource table string pool in the APK."); |
| 190 | } |
| 191 | |
| 192 | int Dump(LoadedApk* apk) override; |
| 193 | }; |
| 194 | |
Aurimas Liutikas | 13e6a1d | 2018-09-25 16:11:40 -0700 | [diff] [blame] | 195 | /** Prints the graph of parents of a style in an APK. */ |
| 196 | class DumpStyleParentCommand : public DumpApkCommand { |
| 197 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 198 | explicit DumpStyleParentCommand(text::Printer* printer, android::IDiagnostics* diag) |
Aurimas Liutikas | 13e6a1d | 2018-09-25 16:11:40 -0700 | [diff] [blame] | 199 | : DumpApkCommand("styleparents", printer, diag) { |
| 200 | SetDescription("Print the parents of a style in an APK."); |
| 201 | AddRequiredFlag("--style", "The name of the style to print", &style_); |
| 202 | } |
| 203 | |
| 204 | int Dump(LoadedApk* apk) override; |
| 205 | |
| 206 | private: |
| 207 | std::string style_; |
| 208 | }; |
| 209 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 210 | class DumpTableCommand : public DumpApkCommand { |
| 211 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 212 | explicit DumpTableCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 213 | : DumpApkCommand("resources", printer, diag) { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 214 | SetDescription("Print the contents of the resource table from the APK."); |
| 215 | AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", |
| 216 | &no_values_); |
| 217 | AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); |
| 218 | } |
| 219 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 220 | int Dump(LoadedApk* apk) override; |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 221 | |
| 222 | private: |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 223 | bool no_values_ = false; |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 224 | bool verbose_ = false; |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 225 | }; |
| 226 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 227 | class DumpXmlStringsCommand : public DumpApkCommand { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 228 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 229 | explicit DumpXmlStringsCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 230 | : DumpApkCommand("xmlstrings", printer, diag) { |
| 231 | SetDescription("Print the string pool of a compiled xml in an APK."); |
| 232 | AddRequiredFlagList("--file", "A compiled xml file to print", &files_); |
| 233 | } |
| 234 | |
| 235 | int Dump(LoadedApk* apk) override; |
| 236 | |
| 237 | private: |
| 238 | std::vector<std::string> files_; |
| 239 | }; |
| 240 | |
Ryan Mitchell | 19b2709 | 2018-08-13 11:36:27 -0700 | [diff] [blame] | 241 | class DumpChunks : public DumpApkCommand { |
| 242 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 243 | DumpChunks(text::Printer* printer, android::IDiagnostics* diag) |
| 244 | : DumpApkCommand("chunks", printer, diag) { |
Ryan Mitchell | 19b2709 | 2018-08-13 11:36:27 -0700 | [diff] [blame] | 245 | SetDescription("Print the chunk information of the compiled resources.arsc in the APK."); |
| 246 | } |
| 247 | |
| 248 | int Dump(LoadedApk* apk) override; |
| 249 | }; |
| 250 | |
| 251 | /** Prints the tree of a compiled xml in an APK. */ |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 252 | class DumpXmlTreeCommand : public DumpApkCommand { |
| 253 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 254 | explicit DumpXmlTreeCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 255 | : DumpApkCommand("xmltree", printer, diag) { |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 256 | SetDescription("Print the tree of a compiled xml in an APK."); |
| 257 | AddRequiredFlagList("--file", "A compiled xml file to print", &files_); |
| 258 | } |
| 259 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 260 | int Dump(LoadedApk* apk) override; |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 261 | |
| 262 | private: |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 263 | std::vector<std::string> files_; |
| 264 | }; |
| 265 | |
Mårten Kongstad | 1d3b6485 | 2019-09-17 13:02:32 +0200 | [diff] [blame] | 266 | class DumpOverlayableCommand : public DumpApkCommand { |
| 267 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 268 | explicit DumpOverlayableCommand(text::Printer* printer, android::IDiagnostics* diag) |
Mårten Kongstad | 1d3b6485 | 2019-09-17 13:02:32 +0200 | [diff] [blame] | 269 | : DumpApkCommand("overlayable", printer, diag) { |
| 270 | SetDescription("Print the <overlayable> resources of an APK."); |
| 271 | } |
| 272 | |
| 273 | int Dump(LoadedApk* apk) override; |
| 274 | }; |
| 275 | |
Todd Kennedy | 908b7fc | 2018-08-24 10:11:21 -0700 | [diff] [blame] | 276 | /** The default dump command. Performs no action because a subcommand is required. */ |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 277 | class DumpCommand : public Command { |
| 278 | public: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 279 | explicit DumpCommand(text::Printer* printer, android::IDiagnostics* diag) |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 280 | : Command("dump", "d"), diag_(diag) { |
| 281 | AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_)); |
| 282 | AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_)); |
| 283 | AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(printer, diag_)); |
| 284 | AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(printer, diag_)); |
| 285 | AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(printer, diag_)); |
| 286 | AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(printer, diag_)); |
Aurimas Liutikas | 13e6a1d | 2018-09-25 16:11:40 -0700 | [diff] [blame] | 287 | AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_)); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 288 | AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_)); |
Ryan Mitchell | 19b2709 | 2018-08-13 11:36:27 -0700 | [diff] [blame] | 289 | AddOptionalSubcommand(util::make_unique<DumpChunks>(printer, diag_)); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 290 | AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_)); |
| 291 | AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_)); |
Mårten Kongstad | 1d3b6485 | 2019-09-17 13:02:32 +0200 | [diff] [blame] | 292 | AddOptionalSubcommand(util::make_unique<DumpOverlayableCommand>(printer, diag_)); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 293 | AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true); |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 294 | } |
| 295 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 296 | int Action(const std::vector<std::string>& args) override { |
| 297 | if (args.size() == 0) { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 298 | diag_->Error(android::DiagMessage() << "no subcommand specified"); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 299 | } else { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 300 | diag_->Error(android::DiagMessage() << "unknown subcommand '" << args[0] << "'"); |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 301 | } |
| 302 | Usage(&std::cerr); |
| 303 | return 1; |
| 304 | } |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 305 | |
| 306 | private: |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame] | 307 | android::IDiagnostics* diag_; |
Ryan Mitchell | 5d27551 | 2018-07-19 14:29:00 -0700 | [diff] [blame] | 308 | }; |
| 309 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 310 | } // namespace aapt |
Ryan Mitchell | 833a1a6 | 2018-07-10 13:51:36 -0700 | [diff] [blame] | 311 | |
Ryan Mitchell | 214846d | 2018-09-19 16:57:01 -0700 | [diff] [blame] | 312 | #endif // AAPT2_DUMP_H |