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 <androidfw/FileStream.h> 21 #include <io/ZipArchive.h> 22 23 #include "Command.h" 24 #include "Debug.h" 25 #include "LoadedApk.h" 26 #include "dump/DumpManifest.h" 27 28 namespace aapt { 29 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: DumpApkCommand(const std::string && name,text::Printer * printer,android::IDiagnostics * diag)36 explicit DumpApkCommand(const std::string&& name, text::Printer* printer, 37 android::IDiagnostics* diag) 38 : Command(name), printer_(printer), diag_(diag) { 39 SetDescription("Dump information about an APK or APC."); 40 } 41 GetPrinter()42 text::Printer* GetPrinter() { 43 return printer_; 44 } 45 GetDiagnostics()46 android::IDiagnostics* GetDiagnostics() { 47 return diag_; 48 } 49 GetPackageName(LoadedApk * apk)50 std::optional<std::string> GetPackageName(LoadedApk* apk) { 51 xml::Element* manifest_el = apk->GetManifest()->root.get(); 52 if (!manifest_el) { 53 GetDiagnostics()->Error(android::DiagMessage() << "No AndroidManifest."); 54 return {}; 55 } 56 57 xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); 58 if (!attr) { 59 GetDiagnostics()->Error(android::DiagMessage() << "No package name."); 60 return {}; 61 } 62 return attr->value; 63 } 64 65 /** Perform the dump operation on the apk. */ 66 virtual int Dump(LoadedApk* apk) = 0; 67 Action(const std::vector<std::string> & args)68 int Action(const std::vector<std::string>& args) final { 69 if (args.size() < 1) { 70 diag_->Error(android::DiagMessage() << "No dump apk specified."); 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_; 90 android::IDiagnostics* diag_; 91 }; 92 93 /** Command that prints contents of files generated from the compilation stage. */ 94 class DumpAPCCommand : public Command { 95 public: DumpAPCCommand(text::Printer * printer,android::IDiagnostics * diag)96 explicit DumpAPCCommand(text::Printer* printer, android::IDiagnostics* diag) 97 : Command("apc"), printer_(printer), diag_(diag) { 98 SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation."); 99 AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", 100 &no_values_); 101 AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); 102 } 103 104 int Action(const std::vector<std::string>& args) override; 105 106 private: 107 text::Printer* printer_; 108 android::IDiagnostics* diag_; 109 bool no_values_ = false; 110 bool verbose_ = false; 111 }; 112 113 /** Easter egg command shown when users enter "badger" instead of "badging". */ 114 class DumpBadgerCommand : public Command { 115 public: DumpBadgerCommand(text::Printer * printer)116 explicit DumpBadgerCommand(text::Printer* printer) : Command("badger"), printer_(printer) { 117 } 118 119 int Action(const std::vector<std::string>& args) override; 120 121 private: 122 text::Printer* printer_; 123 const static char kBadgerData[2925]; 124 }; 125 126 class DumpBadgingCommand : public DumpApkCommand { 127 public: DumpBadgingCommand(text::Printer * printer,android::IDiagnostics * diag)128 explicit DumpBadgingCommand(text::Printer* printer, android::IDiagnostics* diag) 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 SetIncludeMetaData(bool value)135 void SetIncludeMetaData(bool value) { 136 options_.include_meta_data = value; 137 } 138 SetOnlyPermissions(bool value)139 void SetOnlyPermissions(bool value) { 140 options_.only_permissions = value; 141 } 142 Dump(LoadedApk * apk)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: DumpConfigsCommand(text::Printer * printer,android::IDiagnostics * diag)153 explicit DumpConfigsCommand(text::Printer* printer, android::IDiagnostics* diag) 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: DumpPackageNameCommand(text::Printer * printer,android::IDiagnostics * diag)163 explicit DumpPackageNameCommand(text::Printer* printer, android::IDiagnostics* diag) 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: DumpPermissionsCommand(text::Printer * printer,android::IDiagnostics * diag)173 explicit DumpPermissionsCommand(text::Printer* printer, android::IDiagnostics* diag) 174 : DumpApkCommand("permissions", printer, diag) { 175 SetDescription("Print the permissions extracted from the manifest of the APK."); 176 } 177 Dump(LoadedApk * apk)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: DumpStringsCommand(text::Printer * printer,android::IDiagnostics * diag)187 explicit DumpStringsCommand(text::Printer* printer, android::IDiagnostics* diag) 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 195 /** Prints the graph of parents of a style in an APK. */ 196 class DumpStyleParentCommand : public DumpApkCommand { 197 public: DumpStyleParentCommand(text::Printer * printer,android::IDiagnostics * diag)198 explicit DumpStyleParentCommand(text::Printer* printer, android::IDiagnostics* diag) 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 210 class DumpTableCommand : public DumpApkCommand { 211 public: DumpTableCommand(text::Printer * printer,android::IDiagnostics * diag)212 explicit DumpTableCommand(text::Printer* printer, android::IDiagnostics* diag) 213 : DumpApkCommand("resources", printer, diag) { 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 220 int Dump(LoadedApk* apk) override; 221 222 private: 223 bool no_values_ = false; 224 bool verbose_ = false; 225 }; 226 227 class DumpXmlStringsCommand : public DumpApkCommand { 228 public: DumpXmlStringsCommand(text::Printer * printer,android::IDiagnostics * diag)229 explicit DumpXmlStringsCommand(text::Printer* printer, android::IDiagnostics* diag) 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 241 class DumpChunks : public DumpApkCommand { 242 public: DumpChunks(text::Printer * printer,android::IDiagnostics * diag)243 DumpChunks(text::Printer* printer, android::IDiagnostics* diag) 244 : DumpApkCommand("chunks", printer, diag) { 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. */ 252 class DumpXmlTreeCommand : public DumpApkCommand { 253 public: DumpXmlTreeCommand(text::Printer * printer,android::IDiagnostics * diag)254 explicit DumpXmlTreeCommand(text::Printer* printer, android::IDiagnostics* diag) 255 : DumpApkCommand("xmltree", printer, diag) { 256 SetDescription("Print the tree of a compiled xml in an APK."); 257 AddRequiredFlagList("--file", "A compiled xml file to print", &files_); 258 } 259 260 int Dump(LoadedApk* apk) override; 261 262 private: 263 std::vector<std::string> files_; 264 }; 265 266 class DumpOverlayableCommand : public DumpApkCommand { 267 public: DumpOverlayableCommand(text::Printer * printer,android::IDiagnostics * diag)268 explicit DumpOverlayableCommand(text::Printer* printer, android::IDiagnostics* diag) 269 : DumpApkCommand("overlayable", printer, diag) { 270 SetDescription("Print the <overlayable> resources of an APK."); 271 } 272 273 int Dump(LoadedApk* apk) override; 274 }; 275 276 /** The default dump command. Performs no action because a subcommand is required. */ 277 class DumpCommand : public Command { 278 public: DumpCommand(text::Printer * printer,android::IDiagnostics * diag)279 explicit DumpCommand(text::Printer* printer, android::IDiagnostics* diag) 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_)); 287 AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_)); 288 AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_)); 289 AddOptionalSubcommand(util::make_unique<DumpChunks>(printer, diag_)); 290 AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_)); 291 AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_)); 292 AddOptionalSubcommand(util::make_unique<DumpOverlayableCommand>(printer, diag_)); 293 AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true); 294 } 295 Action(const std::vector<std::string> & args)296 int Action(const std::vector<std::string>& args) override { 297 if (args.size() == 0) { 298 diag_->Error(android::DiagMessage() << "no subcommand specified"); 299 } else { 300 diag_->Error(android::DiagMessage() << "unknown subcommand '" << args[0] << "'"); 301 } 302 Usage(&std::cerr); 303 return 1; 304 } 305 306 private: 307 android::IDiagnostics* diag_; 308 }; 309 310 } // namespace aapt 311 312 #endif // AAPT2_DUMP_H 313