Home | History | Annotate | Download | only in cmd
      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:
     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 
     38   text::Printer* GetPrinter() {
     39     return printer_;
     40   }
     41 
     42   IDiagnostics* GetDiagnostics() {
     43     return diag_;
     44   }
     45 
     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 
     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:
     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:
    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:
    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 
    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:
    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:
    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:
    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 
    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:
    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:
    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:
    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:
    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:
    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 /** The default dump command. Performs no action because a subcommand is required. */
    244 class DumpCommand : public Command {
    245  public:
    246   explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
    247       : Command("dump", "d"), diag_(diag) {
    248     AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
    249     AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
    250     AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(printer, diag_));
    251     AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(printer, diag_));
    252     AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(printer, diag_));
    253     AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(printer, diag_));
    254     AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_));
    255     AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_));
    256     AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_));
    257     AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_));
    258     AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true);
    259     // TODO(b/120609160): Add aapt2 overlayable dump command
    260   }
    261 
    262   int Action(const std::vector<std::string>& args) override {
    263     if (args.size() == 0) {
    264       diag_->Error(DiagMessage() << "no subcommand specified");
    265     } else {
    266       diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
    267     }
    268     Usage(&std::cerr);
    269     return 1;
    270   }
    271 
    272  private:
    273   IDiagnostics* diag_;
    274 };
    275 
    276 }  // namespace aapt
    277 
    278 #endif  // AAPT2_DUMP_H
    279