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