AAPT2: Refactor flags into commands
Refactors the flag based command invocation into classes that make using
subcommands easier.
Test: manual tests of printing
Change-Id: Ic8df6af0be30db552e32150afebecbfeec7e1075
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 7a33de0..2ecf25b 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -15,6 +15,7 @@
//
toolSources = [
+ "cmd/Command.cpp",
"cmd/Compile.cpp",
"cmd/Convert.cpp",
"cmd/Diff.cpp",
@@ -124,7 +125,6 @@
"ConfigDescription.cpp",
"Debug.cpp",
"DominatorTree.cpp",
- "Flags.cpp",
"java/AnnotationProcessor.cpp",
"java/ClassDefinition.cpp",
"java/JavaClassGenerator.cpp",
diff --git a/tools/aapt2/Flags.cpp b/tools/aapt2/Flags.cpp
deleted file mode 100644
index 84977ab..0000000
--- a/tools/aapt2/Flags.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Flags.h"
-
-#include <iomanip>
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include "androidfw/StringPiece.h"
-
-#include "util/Util.h"
-
-using android::StringPiece;
-
-namespace aapt {
-
-Flags& Flags::RequiredFlag(const StringPiece& name,
- const StringPiece& description, std::string* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- *value = arg.to_string();
- return true;
- };
-
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
- return *this;
-}
-
-Flags& Flags::RequiredFlagList(const StringPiece& name,
- const StringPiece& description,
- std::vector<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- value->push_back(arg.to_string());
- return true;
- };
-
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
- return *this;
-}
-
-Flags& Flags::OptionalFlag(const StringPiece& name,
- const StringPiece& description,
- Maybe<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- *value = arg.to_string();
- return true;
- };
-
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
- return *this;
-}
-
-Flags& Flags::OptionalFlagList(const StringPiece& name,
- const StringPiece& description,
- std::vector<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- value->push_back(arg.to_string());
- return true;
- };
-
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
- return *this;
-}
-
-Flags& Flags::OptionalFlagList(const StringPiece& name,
- const StringPiece& description,
- std::unordered_set<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- value->insert(arg.to_string());
- return true;
- };
-
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
- return *this;
-}
-
-Flags& Flags::OptionalSwitch(const StringPiece& name,
- const StringPiece& description, bool* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- *value = true;
- return true;
- };
-
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
- return *this;
-}
-
-void Flags::Usage(const StringPiece& command, std::ostream* out) {
- constexpr size_t kWidth = 50;
-
- *out << command << " [options]";
- for (const Flag& flag : flags_) {
- if (flag.required) {
- *out << " " << flag.name << " arg";
- }
- }
-
- *out << " files...\n\nOptions:\n";
-
- for (const Flag& flag : flags_) {
- std::string argline = flag.name;
- if (flag.num_args > 0) {
- argline += " arg";
- }
-
- // Split the description by newlines and write out the argument (which is
- // empty after
- // the first line) followed by the description line. This will make sure
- // that multiline
- // descriptions are still right justified and aligned.
- for (StringPiece line : util::Tokenize(flag.description, '\n')) {
- *out << " " << std::setw(kWidth) << std::left << argline << line << "\n";
- argline = " ";
- }
- }
- *out << " " << std::setw(kWidth) << std::left << "-h"
- << "Displays this help menu\n";
- out->flush();
-}
-
-bool Flags::Parse(const StringPiece& command,
- const std::vector<StringPiece>& args,
- std::ostream* out_error) {
- for (size_t i = 0; i < args.size(); i++) {
- StringPiece arg = args[i];
- if (*(arg.data()) != '-') {
- args_.push_back(arg.to_string());
- continue;
- }
-
- if (arg == "-h" || arg == "--help") {
- Usage(command, out_error);
- return false;
- }
-
- bool match = false;
- for (Flag& flag : flags_) {
- if (arg == flag.name) {
- if (flag.num_args > 0) {
- i++;
- if (i >= args.size()) {
- *out_error << flag.name << " missing argument.\n\n";
- Usage(command, out_error);
- return false;
- }
- flag.action(args[i]);
- } else {
- flag.action({});
- }
- flag.parsed = true;
- match = true;
- break;
- }
- }
-
- if (!match) {
- *out_error << "unknown option '" << arg << "'.\n\n";
- Usage(command, out_error);
- return false;
- }
- }
-
- for (const Flag& flag : flags_) {
- if (flag.required && !flag.parsed) {
- *out_error << "missing required flag " << flag.name << "\n\n";
- Usage(command, out_error);
- return false;
- }
- }
- return true;
-}
-
-const std::vector<std::string>& Flags::GetArgs() { return args_; }
-
-} // namespace aapt
diff --git a/tools/aapt2/Flags.h b/tools/aapt2/Flags.h
deleted file mode 100644
index 3b3ae71..0000000
--- a/tools/aapt2/Flags.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_FLAGS_H
-#define AAPT_FLAGS_H
-
-#include <functional>
-#include <ostream>
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include "androidfw/StringPiece.h"
-
-#include "util/Maybe.h"
-
-namespace aapt {
-
-class Flags {
- public:
- Flags& RequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
- std::string* value);
- Flags& RequiredFlagList(const android::StringPiece& name, const android::StringPiece& description,
- std::vector<std::string>* value);
- Flags& OptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
- Maybe<std::string>* value);
- Flags& OptionalFlagList(const android::StringPiece& name, const android::StringPiece& description,
- std::vector<std::string>* value);
- Flags& OptionalFlagList(const android::StringPiece& name, const android::StringPiece& description,
- std::unordered_set<std::string>* value);
- Flags& OptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
- bool* value);
-
- void Usage(const android::StringPiece& command, std::ostream* out);
-
- bool Parse(const android::StringPiece& command, const std::vector<android::StringPiece>& args,
- std::ostream* outError);
-
- const std::vector<std::string>& GetArgs();
-
- private:
- struct Flag {
- std::string name;
- std::string description;
- std::function<bool(const android::StringPiece& value)> action;
- bool required;
- size_t num_args;
-
- bool parsed;
- };
-
- std::vector<Flag> flags_;
- std::vector<std::string> args_;
-};
-
-} // namespace aapt
-
-#endif // AAPT_FLAGS_H
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 808b29c..23903c9e 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -29,6 +29,13 @@
#include "androidfw/StringPiece.h"
#include "Diagnostics.h"
+#include "cmd/Command.h"
+#include "cmd/Compile.h"
+#include "cmd/Convert.h"
+#include "cmd/Diff.h"
+#include "cmd/Dump.h"
+#include "cmd/Link.h"
+#include "cmd/Optimize.h"
#include "util/Files.h"
#include "util/Util.h"
@@ -43,114 +50,121 @@
// Update minor version whenever a feature or flag is added.
static const char* sMinorVersion = "19";
-static void PrintVersion() {
- std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion,
- sMinorVersion)
- << std::endl;
-}
+/** Prints the version information of AAPT2. */
+class VersionCommand : public Command {
+ public:
+ explicit VersionCommand() : Command("version") {
+ SetDescription("Prints the version of aapt.");
+ }
-static void PrintUsage() {
- std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|convert|version] ..." << std::endl;
-}
-
-extern int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics);
-extern int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics);
-extern int Dump(const std::vector<StringPiece>& args);
-extern int Diff(const std::vector<StringPiece>& args);
-extern int Optimize(const std::vector<StringPiece>& args);
-extern int Convert(const std::vector<StringPiece>& args);
-
-static int ExecuteCommand(const StringPiece& command, const std::vector<StringPiece>& args,
- IDiagnostics* diagnostics) {
- if (command == "compile" || command == "c") {
- return Compile(args, diagnostics);
- } else if (command == "link" || command == "l") {
- return Link(args, diagnostics);
- } else if (command == "dump" || command == "d") {
- return Dump(args);
- } else if (command == "diff") {
- return Diff(args);
- } else if (command == "optimize") {
- return Optimize(args);
- } else if (command == "convert") {
- return Convert(args);
- } else if (command == "version") {
- PrintVersion();
+ int Action(const std::vector<std::string>& /* args */) override {
+ std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion,
+ sMinorVersion)
+ << std::endl;
return 0;
}
- diagnostics->Error(DiagMessage() << "unknown command '" << command << "'");
- return -1;
-}
+};
-static void RunDaemon(IDiagnostics* diagnostics) {
- std::cout << "Ready" << std::endl;
-
- // Run in daemon mode. The first line of input is the command. This can be 'quit' which ends
- // the daemon mode. Each subsequent line is a single parameter to the command. The end of a
- // invocation is signaled by providing an empty line. At any point, an EOF signal or the
- // command 'quit' will end the daemon mode.
- while (true) {
- std::vector<std::string> raw_args;
- for (std::string line; std::getline(std::cin, line) && !line.empty();) {
- raw_args.push_back(line);
- }
-
- if (!std::cin) {
- break;
- }
-
- // An empty command does nothing.
- if (raw_args.empty()) {
- continue;
- }
-
- if (raw_args[0] == "quit") {
- break;
- }
-
- std::vector<StringPiece> args;
- args.insert(args.end(), ++raw_args.begin(), raw_args.end());
- int ret = ExecuteCommand(raw_args[0], args, diagnostics);
- if (ret != 0) {
- std::cerr << "Error" << std::endl;
- }
- std::cerr << "Done" << std::endl;
+/** The main entry point of AAPT. */
+class MainCommand : public Command {
+ public:
+ explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) {
+ AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
+ AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
+ AddOptionalSubcommand(util::make_unique<DumpCommand>());
+ AddOptionalSubcommand(util::make_unique<DiffCommand>());
+ AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
+ AddOptionalSubcommand(util::make_unique<ConvertCommand>());
+ AddOptionalSubcommand(util::make_unique<VersionCommand>());
}
- std::cout << "Exiting daemon" << std::endl;
-}
+
+ int Action(const std::vector<std::string>& args) override {
+ if (args.size() == 0) {
+ diagnostics_->Error(DiagMessage() << "no subcommand specified");
+ } else {
+ diagnostics_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+ }
+
+ Usage(&std::cerr);
+ return -1;
+ }
+
+ private:
+ IDiagnostics* diagnostics_;
+};
+
+/*
+ * Run in daemon mode. The first line of input is the command. This can be 'quit' which ends
+ * the daemon mode. Each subsequent line is a single parameter to the command. The end of a
+ * invocation is signaled by providing an empty line. At any point, an EOF signal or the
+ * command 'quit' will end the daemon mode.
+ */
+class DaemonCommand : public Command {
+ public:
+ explicit DaemonCommand(IDiagnostics* diagnostics) : Command("daemon", "m"),
+ diagnostics_(diagnostics) {
+ SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
+ "command. The end of an invocation is signaled by providing an empty line.");
+ }
+
+ int Action(const std::vector<std::string>& /* args */) override {
+ std::cout << "Ready" << std::endl;
+
+ while (true) {
+ std::vector<std::string> raw_args;
+ for (std::string line; std::getline(std::cin, line) && !line.empty();) {
+ raw_args.push_back(line);
+ }
+
+ if (!std::cin) {
+ break;
+ }
+
+ // An empty command does nothing.
+ if (raw_args.empty()) {
+ continue;
+ }
+
+ // End the dameon
+ if (raw_args[0] == "quit") {
+ break;
+ }
+
+ std::vector<StringPiece> args;
+ args.insert(args.end(), raw_args.begin(), raw_args.end());
+ if (MainCommand(diagnostics_).Execute(args, &std::cerr) != 0) {
+ std::cerr << "Error" << std::endl;
+ }
+ std::cerr << "Done" << std::endl;
+ }
+ std::cout << "Exiting daemon" << std::endl;
+
+ return 0;
+ }
+
+ private:
+ IDiagnostics* diagnostics_;
+};
} // namespace aapt
int MainImpl(int argc, char** argv) {
- if (argc < 2) {
- std::cerr << "no command specified\n";
- aapt::PrintUsage();
+ if (argc < 1) {
return -1;
}
- argv += 1;
- argc -= 1;
-
- aapt::StdErrDiagnostics diagnostics;
-
// Collect the arguments starting after the program name and command name.
std::vector<StringPiece> args;
for (int i = 1; i < argc; i++) {
args.push_back(argv[i]);
}
- const StringPiece command(argv[0]);
- if (command != "daemon" && command != "m") {
- // Single execution.
- const int result = aapt::ExecuteCommand(command, args, &diagnostics);
- if (result < 0) {
- aapt::PrintUsage();
- }
- return result;
- }
+ // Add the daemon subcommand here so it cannot be called while executing the daemon
+ aapt::StdErrDiagnostics diagnostics;
+ auto main_command = new aapt::MainCommand(&diagnostics);
+ main_command->AddOptionalSubcommand(aapt::util::make_unique<aapt::DaemonCommand>(&diagnostics));
- aapt::RunDaemon(&diagnostics);
- return 0;
+ return main_command->Execute(args, &std::cerr);
}
int main(int argc, char** argv) {
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
new file mode 100644
index 0000000..09411b9
--- /dev/null
+++ b/tools/aapt2/cmd/Command.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Command.h"
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "androidfw/StringPiece.h"
+
+#include "util/Util.h"
+
+using android::StringPiece;
+
+namespace aapt {
+
+void Command::AddRequiredFlag(const StringPiece& name,
+ const StringPiece& description, std::string* value) {
+ auto func = [value](const StringPiece& arg) -> bool {
+ *value = arg.to_string();
+ return true;
+ };
+
+ flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
+}
+
+void Command::AddRequiredFlagList(const StringPiece& name,
+ const StringPiece& description,
+ std::vector<std::string>* value) {
+ auto func = [value](const StringPiece& arg) -> bool {
+ value->push_back(arg.to_string());
+ return true;
+ };
+
+ flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
+}
+
+void Command::AddOptionalFlag(const StringPiece& name,
+ const StringPiece& description,
+ Maybe<std::string>* value) {
+ auto func = [value](const StringPiece& arg) -> bool {
+ *value = arg.to_string();
+ return true;
+ };
+
+ flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+}
+
+void Command::AddOptionalFlagList(const StringPiece& name,
+ const StringPiece& description,
+ std::vector<std::string>* value) {
+ auto func = [value](const StringPiece& arg) -> bool {
+ value->push_back(arg.to_string());
+ return true;
+ };
+
+ flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+}
+
+void Command::AddOptionalFlagList(const StringPiece& name,
+ const StringPiece& description,
+ std::unordered_set<std::string>* value) {
+ auto func = [value](const StringPiece& arg) -> bool {
+ value->insert(arg.to_string());
+ return true;
+ };
+
+ flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+}
+
+void Command::AddOptionalSwitch(const StringPiece& name,
+ const StringPiece& description, bool* value) {
+ auto func = [value](const StringPiece& arg) -> bool {
+ *value = true;
+ return true;
+ };
+
+ flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
+}
+
+void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand) {
+ subcommand->fullname_ = name_ + " " + subcommand->name_;
+ subcommands_.push_back(std::move(subcommand));
+}
+
+void Command::SetDescription(const android::StringPiece& description) {
+ description_ = description.to_string();
+}
+
+void Command::Usage(std::ostream* out) {
+ constexpr size_t kWidth = 50;
+
+ *out << fullname_;
+
+ if (!subcommands_.empty()) {
+ *out << " [subcommand]";
+ }
+
+ *out << " [options]";
+ for (const Flag& flag : flags_) {
+ if (flag.required) {
+ *out << " " << flag.name << " arg";
+ }
+ }
+
+ *out << " files...\n";
+
+ if (!subcommands_.empty()) {
+ *out << "\nSubcommands:\n";
+ for (auto& subcommand : subcommands_) {
+ std::string argline = subcommand->name_;
+
+ // Split the description by newlines and write out the argument (which is
+ // empty after the first line) followed by the description line. This will make sure
+ // that multiline descriptions are still right justified and aligned.
+ for (StringPiece line : util::Tokenize(subcommand->description_, '\n')) {
+ *out << " " << std::setw(kWidth) << std::left << argline << line << "\n";
+ argline = " ";
+ }
+ }
+ }
+
+ *out << "\nOptions:\n";
+
+ for (const Flag& flag : flags_) {
+ std::string argline = flag.name;
+ if (flag.num_args > 0) {
+ argline += " arg";
+ }
+
+ // Split the description by newlines and write out the argument (which is
+ // empty after the first line) followed by the description line. This will make sure
+ // that multiline descriptions are still right justified and aligned.
+ for (StringPiece line : util::Tokenize(flag.description, '\n')) {
+ *out << " " << std::setw(kWidth) << std::left << argline << line << "\n";
+ argline = " ";
+ }
+ }
+ *out << " " << std::setw(kWidth) << std::left << "-h"
+ << "Displays this help menu\n";
+ out->flush();
+}
+
+int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream* out_error) {
+ std::vector<std::string> file_args;
+
+ for (size_t i = 0; i < args.size(); i++) {
+ StringPiece arg = args[i];
+ if (*(arg.data()) != '-') {
+ // Continue parsing as the sub command if the first argument matches one of the subcommands
+ if (i == 0) {
+ for (auto& subcommand : subcommands_) {
+ if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+ return subcommand->Execute(
+ std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+ }
+ }
+ }
+
+ file_args.push_back(arg.to_string());
+ continue;
+ }
+
+ if (arg == "-h" || arg == "--help") {
+ Usage(out_error);
+ return 1;
+ }
+
+ bool match = false;
+ for (Flag& flag : flags_) {
+ if (arg == flag.name) {
+ if (flag.num_args > 0) {
+ i++;
+ if (i >= args.size()) {
+ *out_error << flag.name << " missing argument.\n\n";
+ Usage(out_error);
+ return false;
+ }
+ flag.action(args[i]);
+ } else {
+ flag.action({});
+ }
+ flag.parsed = true;
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ *out_error << "unknown option '" << arg << "'.\n\n";
+ Usage(out_error);
+ return 1;
+ }
+ }
+
+ for (const Flag& flag : flags_) {
+ if (flag.required && !flag.parsed) {
+ *out_error << "missing required flag " << flag.name << "\n\n";
+ Usage(out_error);
+ return 1;
+ }
+ }
+
+ return Action(file_args);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
new file mode 100644
index 0000000..71dc6fe
--- /dev/null
+++ b/tools/aapt2/cmd/Command.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_COMMAND_H
+#define AAPT_COMMAND_H
+
+#include <functional>
+#include <ostream>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "androidfw/StringPiece.h"
+
+#include "util/Maybe.h"
+
+namespace aapt {
+
+class Command {
+ public:
+ explicit Command(const android::StringPiece& name) : name_(name.to_string()),
+ fullname_(name.to_string()) { }
+ explicit Command(const android::StringPiece& name, const android::StringPiece& short_name)
+ : name_(name.to_string()), short_name_(short_name.to_string()), fullname_(name.to_string()) {}
+ virtual ~Command() = default;
+
+ void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
+ std::string* value);
+ void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece&
+ description, std::vector<std::string>* value);
+ void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
+ Maybe<std::string>* value);
+ void AddOptionalFlagList(const android::StringPiece& name,
+ const android::StringPiece& description, std::vector<std::string>* value);
+ void AddOptionalFlagList(const android::StringPiece& name,
+ const android::StringPiece& description, std::unordered_set<std::string>* value);
+ void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
+ bool* value);
+ void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand);
+
+ void SetDescription(const android::StringPiece& name);
+
+ /** Prints the help menu of the command. */
+ void Usage(std::ostream* out);
+
+ /**
+ * Parses the command line arguments, sets the flag variable values, and runs the action of
+ * the command. If the arguments fail to parse to the command and its subcommands, then the action
+ * will not be run and the usage will be printed instead.
+ **/
+ int Execute(const std::vector<android::StringPiece>& args, std::ostream* outError);
+
+ /** The action to preform when the command is executed. */
+ virtual int Action(const std::vector<std::string>& args) = 0;
+
+ private:
+ struct Flag {
+ std::string name;
+ std::string description;
+ std::function<bool(const android::StringPiece& value)> action;
+ bool required;
+ size_t num_args;
+
+ bool parsed;
+ };
+
+ std::string description_;
+ std::string name_;
+ std::string short_name_;
+ std::string fullname_;
+ std::vector<Flag> flags_;
+ std::vector<std::unique_ptr<Command>> subcommands_;
+};
+
+} // namespace aapt
+
+#endif // AAPT_COMMAND_H
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index a17a0d3..8c1fa9a 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include <dirent.h>
+#include "Compile.h"
+#include <dirent.h>
#include <string>
#include "android-base/errors.h"
@@ -27,7 +28,6 @@
#include "ConfigDescription.h"
#include "Diagnostics.h"
-#include "Flags.h"
#include "ResourceParser.h"
#include "ResourceTable.h"
#include "cmd/Util.h"
@@ -121,17 +121,6 @@
extension.to_string(), config_str.to_string(), config};
}
-struct CompileOptions {
- std::string output_path;
- Maybe<std::string> res_dir;
- Maybe<std::string> generate_text_symbols_path;
- Maybe<Visibility::Level> visibility;
- bool pseudolocalize = false;
- bool no_png_crunch = false;
- bool legacy_mode = false;
- bool verbose = false;
-};
-
static std::string BuildIntermediateContainerFilename(const ResourcePathData& data) {
std::stringstream name;
name << data.resource_dir;
@@ -712,50 +701,21 @@
bool verbose_ = false;
};
-// Entry point for compilation phase. Parses arguments and dispatches to the correct steps.
-int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) {
- CompileContext context(diagnostics);
- CompileOptions options;
+int CompileCommand::Action(const std::vector<std::string>& args) {
+ CompileContext context(diagnostic_);
+ context.SetVerbose(options_.verbose);
- bool verbose = false;
- Maybe<std::string> visibility;
- Flags flags =
- Flags()
- .RequiredFlag("-o", "Output path", &options.output_path)
- .OptionalFlag("--dir", "Directory to scan for resources", &options.res_dir)
- .OptionalFlag("--output-text-symbols",
- "Generates a text file containing the resource symbols in the\n"
- "specified file",
- &options.generate_text_symbols_path)
- .OptionalSwitch("--pseudo-localize",
- "Generate resources for pseudo-locales "
- "(en-XA and ar-XB)",
- &options.pseudolocalize)
- .OptionalSwitch("--no-crunch", "Disables PNG processing", &options.no_png_crunch)
- .OptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
- &options.legacy_mode)
- .OptionalSwitch("-v", "Enables verbose logging", &verbose)
- .OptionalFlag("--visibility",
- "Sets the visibility of the compiled resources to the specified\n"
- "level. Accepted levels: public, private, default",
- &visibility);
- if (!flags.Parse("aapt2 compile", args, &std::cerr)) {
- return 1;
- }
-
- context.SetVerbose(verbose);
-
- if (visibility) {
- if (visibility.value() == "public") {
- options.visibility = Visibility::Level::kPublic;
- } else if (visibility.value() == "private") {
- options.visibility = Visibility::Level::kPrivate;
- } else if (visibility.value() == "default") {
- options.visibility = Visibility::Level::kUndefined;
+ if (visibility_) {
+ if (visibility_.value() == "public") {
+ options_.visibility = Visibility::Level::kPublic;
+ } else if (visibility_.value() == "private") {
+ options_.visibility = Visibility::Level::kPrivate;
+ } else if (visibility_.value() == "default") {
+ options_.visibility = Visibility::Level::kUndefined;
} else {
context.GetDiagnostics()->Error(
DiagMessage() << "Unrecognized visibility level passes to --visibility: '"
- << visibility.value() << "'. Accepted levels: public, private, default");
+ << visibility_.value() << "'. Accepted levels: public, private, default");
return 1;
}
}
@@ -763,25 +723,25 @@
std::unique_ptr<IArchiveWriter> archive_writer;
std::vector<ResourcePathData> input_data;
- if (options.res_dir) {
- if (!flags.GetArgs().empty()) {
+ if (options_.res_dir) {
+ if (!args.empty()) {
// Can't have both files and a resource directory.
context.GetDiagnostics()->Error(DiagMessage() << "files given but --dir specified");
- flags.Usage("aapt2 compile", &std::cerr);
+ Usage(&std::cerr);
return 1;
}
- if (!LoadInputFilesFromDir(&context, options, &input_data)) {
+ if (!LoadInputFilesFromDir(&context, options_, &input_data)) {
return 1;
}
- archive_writer = CreateZipFileArchiveWriter(context.GetDiagnostics(), options.output_path);
+ archive_writer = CreateZipFileArchiveWriter(context.GetDiagnostics(), options_.output_path);
} else {
- input_data.reserve(flags.GetArgs().size());
+ input_data.reserve(args.size());
// Collect data from the path for each input file.
- for (const std::string& arg : flags.GetArgs()) {
+ for (const std::string& arg : args) {
std::string error_str;
if (Maybe<ResourcePathData> path_data = ExtractResourcePathData(arg, &error_str)) {
input_data.push_back(std::move(path_data.value()));
@@ -791,7 +751,7 @@
}
}
- archive_writer = CreateDirectoryArchiveWriter(context.GetDiagnostics(), options.output_path);
+ archive_writer = CreateDirectoryArchiveWriter(context.GetDiagnostics(), options_.output_path);
}
if (!archive_writer) {
@@ -800,7 +760,7 @@
bool error = false;
for (ResourcePathData& path_data : input_data) {
- if (options.verbose) {
+ if (options_.verbose) {
context.GetDiagnostics()->Note(DiagMessage(path_data.source) << "processing");
}
@@ -821,21 +781,21 @@
if (*type != ResourceType::kRaw) {
if (path_data.extension == "xml") {
compile_func = &CompileXml;
- } else if ((!options.no_png_crunch && path_data.extension == "png")
+ } else if ((!options_.no_png_crunch && path_data.extension == "png")
|| path_data.extension == "9.png") {
compile_func = &CompilePng;
}
}
} else {
context.GetDiagnostics()->Error(DiagMessage()
- << "invalid file path '" << path_data.source << "'");
+ << "invalid file path '" << path_data.source << "'");
error = true;
continue;
}
// Treat periods as a reserved character that should not be present in a file name
// Legacy support for AAPT which did not reserve periods
- if (compile_func != &CompileFile && !options.legacy_mode
+ if (compile_func != &CompileFile && !options_.legacy_mode
&& std::count(path_data.name.begin(), path_data.name.end(), '.') != 0) {
error = true;
context.GetDiagnostics()->Error(DiagMessage() << "resource file '" << path_data.source.path
@@ -846,7 +806,7 @@
// Compile the file.
const std::string out_path = BuildIntermediateContainerFilename(path_data);
- error |= !compile_func(&context, options, path_data, archive_writer.get(), out_path);
+ error |= !compile_func(&context, options_, path_data, archive_writer.get(), out_path);
}
return error ? 1 : 0;
}
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index d95cf1c..4151952 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -1,13 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#ifndef AAPT2_COMPILE_H
#define AAPT2_COMPILE_H
#include "androidfw/StringPiece.h"
+#include "Command.h"
#include "Diagnostics.h"
+#include "ResourceTable.h"
namespace aapt {
- int Compile(const std::vector<android::StringPiece>& args, IDiagnostics* diagnostics);
+struct CompileOptions {
+ std::string output_path;
+ Maybe<std::string> res_dir;
+ Maybe<std::string> generate_text_symbols_path;
+ Maybe<Visibility::Level> visibility;
+ bool pseudolocalize = false;
+ bool no_png_crunch = false;
+ bool legacy_mode = false;
+ bool verbose = false;
+};
+
+class CompileCommand : public Command {
+ public:
+ explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"),
+ diagnostic_(diagnostic) {
+ SetDescription("Compiles resources to be linked into an apk.");
+ AddRequiredFlag("-o", "Output path", &options_.output_path);
+ AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir);
+ AddOptionalFlag("--output-text-symbols",
+ "Generates a text file containing the resource symbols in the\n"
+ "specified file", &options_.generate_text_symbols_path);
+ AddOptionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
+ "(en-XA and ar-XB)", &options_.pseudolocalize);
+ AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch);
+ AddOptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
+ &options_.legacy_mode);
+ AddOptionalSwitch("-v", "Enables verbose logging", &options_.verbose);
+ AddOptionalFlag("--visibility",
+ "Sets the visibility of the compiled resources to the specified\n"
+ "level. Accepted levels: public, private, default", &visibility_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ IDiagnostics* diagnostic_;
+ CompileOptions options_;
+ Maybe<std::string> visibility_;
+};
}// namespace aapt
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index 212f2cf..d21addf 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -23,7 +23,8 @@
namespace aapt {
-int TestCompile(std::string path, std::string outDir, bool legacy, StdErrDiagnostics& diag) {
+int TestCompile(const std::string& path, const std::string& outDir, bool legacy,
+ StdErrDiagnostics& diag) {
std::vector<android::StringPiece> args;
args.push_back(path);
args.push_back("-o");
@@ -32,7 +33,7 @@
if (legacy) {
args.push_back("--legacy");
}
- return aapt::Compile(args, &diag);
+ return CompileCommand(&diag).Execute(args, &std::cerr);
}
TEST(CompilerTest, MultiplePeriods) {
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 3c8beaa..4b82eef 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -14,12 +14,13 @@
* limitations under the License.
*/
+#include "Convert.h"
+
#include <vector>
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
-#include "Flags.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
#include "cmd/Util.h"
@@ -325,37 +326,18 @@
StdErrDiagnostics diag_;
};
-int Convert(const vector<StringPiece>& args) {
+const char* ConvertCommand::kOutputFormatProto = "proto";
+const char* ConvertCommand::kOutputFormatBinary = "binary";
- static const char* kOutputFormatProto = "proto";
- static const char* kOutputFormatBinary = "binary";
+int ConvertCommand::Action(const std::vector<std::string>& args) {
+ if (args.size() != 1) {
+ std::cerr << "must supply a single proto APK\n";
+ Usage(&std::cerr);
+ return 1;
+ }
Context context;
- std::string output_path;
- Maybe<std::string> output_format;
- TableFlattenerOptions options;
- Flags flags =
- Flags()
- .RequiredFlag("-o", "Output path", &output_path)
- .OptionalFlag("--output-format", StringPrintf("Format of the output. Accepted values are "
- "'%s' and '%s'. When not set, defaults to '%s'.", kOutputFormatProto,
- kOutputFormatBinary, kOutputFormatBinary), &output_format)
- .OptionalSwitch("--enable-sparse-encoding",
- "Enables encoding sparse entries using a binary search tree.\n"
- "This decreases APK size at the cost of resource retrieval performance.",
- &options.use_sparse_entries)
- .OptionalSwitch("-v", "Enables verbose logging", &context.verbose_);
- if (!flags.Parse("aapt2 convert", args, &std::cerr)) {
- return 1;
- }
-
- if (flags.GetArgs().size() != 1) {
- std::cerr << "must supply a single proto APK\n";
- flags.Usage("aapt2 convert", &std::cerr);
- return 1;
- }
-
- const StringPiece& path = flags.GetArgs()[0];
+ const StringPiece& path = args[0];
unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
if (apk == nullptr) {
context.GetDiagnostics()->Error(DiagMessage(path) << "failed to load APK");
@@ -371,24 +353,24 @@
context.package_ = app_info.value().package;
unique_ptr<IArchiveWriter> writer =
- CreateZipFileArchiveWriter(context.GetDiagnostics(), output_path);
+ CreateZipFileArchiveWriter(context.GetDiagnostics(), output_path_);
if (writer == nullptr) {
return 1;
}
unique_ptr<IApkSerializer> serializer;
- if (!output_format || output_format.value() == kOutputFormatBinary) {
- serializer.reset(new BinaryApkSerializer(&context, apk->GetSource(), options));
- } else if (output_format.value() == kOutputFormatProto) {
+ if (!output_format_ || output_format_.value() == ConvertCommand::kOutputFormatBinary) {
+
+ serializer.reset(new BinaryApkSerializer(&context, apk->GetSource(), options_));
+ } else if (output_format_.value() == ConvertCommand::kOutputFormatProto) {
serializer.reset(new ProtoApkSerializer(&context, apk->GetSource()));
} else {
context.GetDiagnostics()->Error(DiagMessage(path)
- << "Invalid value for flag --output-format: "
- << output_format.value());
+ << "Invalid value for flag --output-format: "
+ << output_format_.value());
return 1;
}
-
return ConvertApk(&context, std::move(apk), serializer.get(), writer.get()) ? 0 : 1;
}
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
new file mode 100644
index 0000000..fcec23d
--- /dev/null
+++ b/tools/aapt2/cmd/Convert.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_CONVERT_H
+#define AAPT2_CONVERT_H
+
+#include "Command.h"
+#include "format/binary/TableFlattener.h"
+
+namespace aapt {
+
+class ConvertCommand : public Command {
+ public:
+ explicit ConvertCommand() : Command("convert") {
+ SetDescription("Converts an apk between binary and proto formats.");
+ AddRequiredFlag("-o", "Output path", &output_path_);
+ AddOptionalFlag("--output-format", android::base::StringPrintf("Format of the output. "
+ "Accepted values are '%s' and '%s'. When not set, defaults to '%s'.",
+ kOutputFormatProto, kOutputFormatBinary, kOutputFormatBinary), &output_format_);
+ AddOptionalSwitch("--enable-sparse-encoding",
+ "Enables encoding sparse entries using a binary search tree.\n"
+ "This decreases APK size at the cost of resource retrieval performance.",
+ &options_.use_sparse_entries);
+ AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ const static char* kOutputFormatProto;
+ const static char* kOutputFormatBinary;
+
+ TableFlattenerOptions options_;
+ std::string output_path_;
+ Maybe<std::string> output_format_;
+ bool verbose_ = false;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_CONVERT_H
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 16c7bba..7875a2b 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -14,9 +14,10 @@
* limitations under the License.
*/
+#include "Diff.h"
+
#include "android-base/macros.h"
-#include "Flags.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
#include "process/IResourceTableConsumer.h"
@@ -348,23 +349,18 @@
VisitAllValuesInTable(table, &visitor);
}
-int Diff(const std::vector<StringPiece>& args) {
+int DiffCommand::Action(const std::vector<std::string>& args) {
DiffContext context;
- Flags flags;
- if (!flags.Parse("aapt2 diff", args, &std::cerr)) {
- return 1;
- }
-
- if (flags.GetArgs().size() != 2u) {
+ if (args.size() != 2u) {
std::cerr << "must have two apks as arguments.\n\n";
- flags.Usage("aapt2 diff", &std::cerr);
+ Usage(&std::cerr);
return 1;
}
IDiagnostics* diag = context.GetDiagnostics();
- std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(flags.GetArgs()[0], diag);
- std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(flags.GetArgs()[1], diag);
+ std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
+ std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
if (!apk_a || !apk_b) {
return 1;
}
diff --git a/tools/aapt2/cmd/Diff.h b/tools/aapt2/cmd/Diff.h
new file mode 100644
index 0000000..c388888
--- /dev/null
+++ b/tools/aapt2/cmd/Diff.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_DIFF_H
+#define AAPT2_DIFF_H
+
+#include "Command.h"
+
+namespace aapt {
+
+class DiffCommand : public Command {
+ public:
+ explicit DiffCommand() : Command("diff") {
+ SetDescription("Prints the differences in resources of two apks.");
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_DIFF_H
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index fd133f3..717e757 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "Dump.h"
+
#include <cinttypes>
#include <vector>
@@ -22,7 +24,6 @@
#include "Debug.h"
#include "Diagnostics.h"
-#include "Flags.h"
#include "format/Container.h"
#include "format/binary/BinaryResourceParser.h"
#include "format/proto/ProtoDeserialize.h"
@@ -38,13 +39,6 @@
namespace aapt {
-struct DumpOptions {
- DebugPrintTableOptions print_options;
-
- // The path to a file within an APK to dump.
- Maybe<std::string> file_to_dump_path;
-};
-
static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
switch (type) {
case ResourceFile::Type::kPng:
@@ -309,29 +303,13 @@
} // namespace
-// Entry point for dump command.
-int Dump(const std::vector<StringPiece>& args) {
- bool verbose = false;
- bool no_values = false;
- DumpOptions options;
- Flags flags = Flags()
- .OptionalSwitch("--no-values",
- "Suppresses output of values when displaying resource tables.",
- &no_values)
- .OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
- &options.file_to_dump_path)
- .OptionalSwitch("-v", "increase verbosity of output", &verbose);
- if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
- return 1;
- }
-
+int DumpCommand::Action(const std::vector<std::string>& args) {
DumpContext context;
- context.SetVerbose(verbose);
-
- options.print_options.show_sources = true;
- options.print_options.show_values = !no_values;
- for (const std::string& arg : flags.GetArgs()) {
- if (!TryDumpFile(&context, arg, options)) {
+ context.SetVerbose(verbose_);
+ options_.print_options.show_sources = true;
+ options_.print_options.show_values = !no_values_;
+ for (const std::string& arg : args) {
+ if (!TryDumpFile(&context, arg, options_)) {
return 1;
}
}
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
new file mode 100644
index 0000000..4893c8b
--- /dev/null
+++ b/tools/aapt2/cmd/Dump.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_DUMP_H
+#define AAPT2_DUMP_H
+
+#include "Command.h"
+#include "Debug.h"
+
+namespace aapt {
+
+struct DumpOptions {
+ DebugPrintTableOptions print_options;
+
+ // The path to a file within an APK to dump.
+ Maybe<std::string> file_to_dump_path;
+};
+
+class DumpCommand : public Command {
+ public:
+ DumpCommand() : Command("dump", "d") {
+ SetDescription("Prints resource and manifest information.");
+ AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
+ &no_values_);
+ AddOptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
+ &options_.file_to_dump_path);
+ AddOptionalSwitch("-v", "increase verbosity of output", &verbose_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ DumpOptions options_;
+
+ bool verbose_ = false;
+ bool no_values_ = false;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_DUMP_H
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 1a2da7f..26770d1 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "Link.h"
+
#include <sys/stat.h>
#include <cinttypes>
@@ -29,7 +31,6 @@
#include "AppInfo.h"
#include "Debug.h"
-#include "Flags.h"
#include "LoadedApk.h"
#include "Locale.h"
#include "NameMangler.h"
@@ -74,74 +75,6 @@
namespace aapt {
-enum class OutputFormat {
- kApk,
- kProto,
-};
-
-struct LinkOptions {
- std::string output_path;
- std::string manifest_path;
- std::vector<std::string> include_paths;
- std::vector<std::string> overlay_files;
- std::vector<std::string> assets_dirs;
- bool output_to_directory = false;
- bool auto_add_overlay = false;
- OutputFormat output_format = OutputFormat::kApk;
-
- // Java/Proguard options.
- Maybe<std::string> generate_java_class_path;
- Maybe<std::string> custom_java_package;
- std::set<std::string> extra_java_packages;
- Maybe<std::string> generate_text_symbols_path;
- Maybe<std::string> generate_proguard_rules_path;
- Maybe<std::string> generate_main_dex_proguard_rules_path;
- bool generate_conditional_proguard_rules = false;
- bool generate_non_final_ids = false;
- std::vector<std::string> javadoc_annotations;
- Maybe<std::string> private_symbols;
-
- // Optimizations/features.
- bool no_auto_version = false;
- bool no_version_vectors = false;
- bool no_version_transitions = false;
- bool no_resource_deduping = false;
- bool no_xml_namespaces = false;
- bool do_not_compress_anything = false;
- std::unordered_set<std::string> extensions_to_not_compress;
-
- // Static lib options.
- bool no_static_lib_packages = false;
- bool auto_namespace_static_lib = false;
-
- // AndroidManifest.xml massaging options.
- ManifestFixerOptions manifest_fixer_options;
-
- // Products to use/filter on.
- std::unordered_set<std::string> products;
-
- // Flattening options.
- TableFlattenerOptions table_flattener_options;
-
- // Split APK options.
- TableSplitterOptions table_splitter_options;
- std::vector<SplitConstraints> split_constraints;
- std::vector<std::string> split_paths;
-
- // Stable ID options.
- std::unordered_map<ResourceName, ResourceId> stable_id_map;
- Maybe<std::string> resource_id_map_path;
-
- // When 'true', allow reserved package IDs to be used for applications. Pre-O, the platform
- // treats negative resource IDs [those with a package ID of 0x80 or higher] as invalid.
- // In order to work around this limitation, we allow the use of traditionally reserved
- // resource IDs [those between 0x02 and 0x7E].
- bool allow_reserved_package_id = false;
-
- // Whether we should fail on definitions of a resource with conflicting visibility.
- bool strict_visibility = false;
-};
-
class LinkContext : public IAaptContext {
public:
LinkContext(IDiagnostics* diagnostics)
@@ -785,9 +718,9 @@
return table.getTableCookie(idx);
}
-class LinkCommand {
+class Linker {
public:
- LinkCommand(LinkContext* context, const LinkOptions& options)
+ Linker(LinkContext* context, const LinkOptions& options)
: options_(options),
context_(context),
final_table_(),
@@ -2040,197 +1973,12 @@
Maybe<std::string> included_feature_base_;
};
-int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) {
- LinkContext context(diagnostics);
- LinkOptions options;
- std::vector<std::string> overlay_arg_list;
- std::vector<std::string> extra_java_packages;
- Maybe<std::string> package_id;
- std::vector<std::string> configs;
- Maybe<std::string> preferred_density;
- Maybe<std::string> product_list;
- bool legacy_x_flag = false;
- bool require_localization = false;
- bool verbose = false;
- bool shared_lib = false;
- bool static_lib = false;
- bool proto_format = false;
- Maybe<std::string> stable_id_file_path;
- std::vector<std::string> split_args;
- Flags flags =
- Flags()
- .RequiredFlag("-o", "Output path.", &options.output_path)
- .RequiredFlag("--manifest", "Path to the Android manifest to build.",
- &options.manifest_path)
- .OptionalFlagList("-I", "Adds an Android APK to link against.", &options.include_paths)
- .OptionalFlagList("-A",
- "An assets directory to include in the APK. These are unprocessed.",
- &options.assets_dirs)
- .OptionalFlagList("-R",
- "Compilation unit to link, using `overlay` semantics.\n"
- "The last conflicting resource given takes precedence.",
- &overlay_arg_list)
- .OptionalFlag("--package-id",
- "Specify the package ID to use for this app. Must be greater or equal to\n"
- "0x7f and can't be used with --static-lib or --shared-lib.",
- &package_id)
- .OptionalFlag("--java", "Directory in which to generate R.java.",
- &options.generate_java_class_path)
- .OptionalFlag("--proguard", "Output file for generated Proguard rules.",
- &options.generate_proguard_rules_path)
- .OptionalFlag("--proguard-main-dex",
- "Output file for generated Proguard rules for the main dex.",
- &options.generate_main_dex_proguard_rules_path)
- .OptionalSwitch("--proguard-conditional-keep-rules",
- "Generate conditional Proguard keep rules.",
- &options.generate_conditional_proguard_rules)
- .OptionalSwitch("--no-auto-version",
- "Disables automatic style and layout SDK versioning.",
- &options.no_auto_version)
- .OptionalSwitch("--no-version-vectors",
- "Disables automatic versioning of vector drawables. Use this only\n"
- "when building with vector drawable support library.",
- &options.no_version_vectors)
- .OptionalSwitch("--no-version-transitions",
- "Disables automatic versioning of transition resources. Use this only\n"
- "when building with transition support library.",
- &options.no_version_transitions)
- .OptionalSwitch("--no-resource-deduping",
- "Disables automatic deduping of resources with\n"
- "identical values across compatible configurations.",
- &options.no_resource_deduping)
- .OptionalSwitch("--enable-sparse-encoding",
- "Enables encoding sparse entries using a binary search tree.\n"
- "This decreases APK size at the cost of resource retrieval performance.",
- &options.table_flattener_options.use_sparse_entries)
- .OptionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01.",
- &legacy_x_flag)
- .OptionalSwitch("-z", "Require localization of strings marked 'suggested'.",
- &require_localization)
- .OptionalFlagList("-c",
- "Comma separated list of configurations to include. The default\n"
- "is all configurations.",
- &configs)
- .OptionalFlag("--preferred-density",
- "Selects the closest matching density and strips out all others.",
- &preferred_density)
- .OptionalFlag("--product", "Comma separated list of product names to keep", &product_list)
- .OptionalSwitch("--output-to-dir",
- "Outputs the APK contents to a directory specified by -o.",
- &options.output_to_directory)
- .OptionalSwitch("--no-xml-namespaces",
- "Removes XML namespace prefix and URI information from\n"
- "AndroidManifest.xml and XML binaries in res/*.",
- &options.no_xml_namespaces)
- .OptionalFlag("--min-sdk-version",
- "Default minimum SDK version to use for AndroidManifest.xml.",
- &options.manifest_fixer_options.min_sdk_version_default)
- .OptionalFlag("--target-sdk-version",
- "Default target SDK version to use for AndroidManifest.xml.",
- &options.manifest_fixer_options.target_sdk_version_default)
- .OptionalFlag("--version-code",
- "Version code (integer) to inject into the AndroidManifest.xml if none is\n"
- "present.",
- &options.manifest_fixer_options.version_code_default)
- .OptionalFlag("--version-name",
- "Version name to inject into the AndroidManifest.xml if none is present.",
- &options.manifest_fixer_options.version_name_default)
- .OptionalSwitch("--replace-version",
- "If --version-code and/or --version-name are specified, these\n"
- "values will replace any value already in the manifest. By\n"
- "default, nothing is changed if the manifest already defines\n"
- "these attributes.",
- &options.manifest_fixer_options.replace_version)
- .OptionalFlag("--compile-sdk-version-code",
- "Version code (integer) to inject into the AndroidManifest.xml if none is\n"
- "present.",
- &options.manifest_fixer_options.compile_sdk_version)
- .OptionalFlag("--compile-sdk-version-name",
- "Version name to inject into the AndroidManifest.xml if none is present.",
- &options.manifest_fixer_options.compile_sdk_version_codename)
- .OptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
- &shared_lib)
- .OptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib)
- .OptionalSwitch("--proto-format",
- "Generates compiled resources in Protobuf format.\n"
- "Suitable as input to the bundle tool for generating an App Bundle.",
- &proto_format)
- .OptionalSwitch("--no-static-lib-packages",
- "Merge all library resources under the app's package.",
- &options.no_static_lib_packages)
- .OptionalSwitch("--auto-namespace-static-lib",
- "Automatically namespace resource references when building a static\n"
- "library.",
- &options.auto_namespace_static_lib)
- .OptionalSwitch("--non-final-ids",
- "Generates R.java without the final modifier. This is implied when\n"
- "--static-lib is specified.",
- &options.generate_non_final_ids)
- .OptionalFlag("--stable-ids", "File containing a list of name to ID mapping.",
- &stable_id_file_path)
- .OptionalFlag("--emit-ids",
- "Emit a file at the given path with a list of name to ID mappings,\n"
- "suitable for use with --stable-ids.",
- &options.resource_id_map_path)
- .OptionalFlag("--private-symbols",
- "Package name to use when generating R.java for private symbols.\n"
- "If not specified, public and private symbols will use the application's\n"
- "package name.",
- &options.private_symbols)
- .OptionalFlag("--custom-package", "Custom Java package under which to generate R.java.",
- &options.custom_java_package)
- .OptionalFlagList("--extra-packages",
- "Generate the same R.java but with different package names.",
- &extra_java_packages)
- .OptionalFlagList("--add-javadoc-annotation",
- "Adds a JavaDoc annotation to all generated Java classes.",
- &options.javadoc_annotations)
- .OptionalFlag("--output-text-symbols",
- "Generates a text file containing the resource symbols of the R class in\n"
- "the specified folder.",
- &options.generate_text_symbols_path)
- .OptionalSwitch("--allow-reserved-package-id",
- "Allows the use of a reserved package ID. This should on be used for\n"
- "packages with a pre-O min-sdk\n",
- &options.allow_reserved_package_id)
- .OptionalSwitch("--auto-add-overlay",
- "Allows the addition of new resources in overlays without\n"
- "<add-resource> tags.",
- &options.auto_add_overlay)
- .OptionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml.",
- &options.manifest_fixer_options.rename_manifest_package)
- .OptionalFlag("--rename-instrumentation-target-package",
- "Changes the name of the target package for instrumentation. Most useful\n"
- "when used in conjunction with --rename-manifest-package.",
- &options.manifest_fixer_options.rename_instrumentation_target_package)
- .OptionalFlagList("-0", "File extensions not to compress.",
- &options.extensions_to_not_compress)
- .OptionalSwitch("--no-compress", "Do not compress any resources.",
- &options.do_not_compress_anything)
- .OptionalSwitch("--warn-manifest-validation",
- "Treat manifest validation errors as warnings.",
- &options.manifest_fixer_options.warn_validation)
- .OptionalFlagList("--split",
- "Split resources matching a set of configs out to a Split APK.\n"
- "Syntax: path/to/output.apk:<config>[,<config>[...]].\n"
- "On Windows, use a semicolon ';' separator instead.",
- &split_args)
- .OptionalSwitch("-v", "Enables verbose logging.", &verbose)
- .OptionalSwitch("--debug-mode",
- "Inserts android:debuggable=\"true\" in to the application node of the\n"
- "manifest, making the application debuggable even on production devices.",
- &options.manifest_fixer_options.debug_mode)
- .OptionalSwitch("--strict-visibility",
- "Do not allow overlays with different visibility levels.",
- &options.strict_visibility);
-
- if (!flags.Parse("aapt2 link", args, &std::cerr)) {
- return 1;
- }
+int LinkCommand::Action(const std::vector<std::string>& args) {
+ LinkContext context(diag_);
// Expand all argument-files passed into the command line. These start with '@'.
std::vector<std::string> arg_list;
- for (const std::string& arg : flags.GetArgs()) {
+ for (const std::string& arg : args) {
if (util::StartsWith(arg, "@")) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
@@ -2244,27 +1992,27 @@
}
// Expand all argument-files passed to -R.
- for (const std::string& arg : overlay_arg_list) {
+ for (const std::string& arg : overlay_arg_list_) {
if (util::StartsWith(arg, "@")) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
- if (!file::AppendArgsFromFile(path, &options.overlay_files, &error)) {
+ if (!file::AppendArgsFromFile(path, &options_.overlay_files, &error)) {
context.GetDiagnostics()->Error(DiagMessage(path) << error);
return 1;
}
} else {
- options.overlay_files.push_back(arg);
+ options_.overlay_files.push_back(arg);
}
}
- if (verbose) {
- context.SetVerbose(verbose);
+ if (verbose_) {
+ context.SetVerbose(verbose_);
}
- if (int{shared_lib} + int{static_lib} + int{proto_format} > 1) {
+ if (int{shared_lib_} + int{static_lib_} + int{proto_format_} > 1) {
context.GetDiagnostics()->Error(
DiagMessage()
- << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
+ << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
return 1;
}
@@ -2272,18 +2020,18 @@
context.SetPackageType(PackageType::kApp);
context.SetPackageId(kAppPackageId);
- if (shared_lib) {
+ if (shared_lib_) {
context.SetPackageType(PackageType::kSharedLib);
context.SetPackageId(0x00);
- } else if (static_lib) {
+ } else if (static_lib_) {
context.SetPackageType(PackageType::kStaticLib);
- options.output_format = OutputFormat::kProto;
- } else if (proto_format) {
- options.output_format = OutputFormat::kProto;
+ options_.output_format = OutputFormat::kProto;
+ } else if (proto_format_) {
+ options_.output_format = OutputFormat::kProto;
}
- if (options.auto_namespace_static_lib) {
- if (!static_lib) {
+ if (options_.auto_namespace_static_lib) {
+ if (!static_lib_) {
context.GetDiagnostics()->Error(
DiagMessage() << "--auto-namespace-static-lib can only be used with --static-lib");
return 1;
@@ -2291,16 +2039,16 @@
context.SetAutoNamespace(true);
}
- if (package_id) {
+ if (package_id_) {
if (context.GetPackageType() != PackageType::kApp) {
context.GetDiagnostics()->Error(
DiagMessage() << "can't specify --package-id when not building a regular app");
return 1;
}
- const Maybe<uint32_t> maybe_package_id_int = ResourceUtils::ParseInt(package_id.value());
+ const Maybe<uint32_t> maybe_package_id_int = ResourceUtils::ParseInt(package_id_.value());
if (!maybe_package_id_int) {
- context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id.value()
+ context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id_.value()
<< "' is not a valid integer");
return 1;
}
@@ -2308,7 +2056,7 @@
const uint32_t package_id_int = maybe_package_id_int.value();
if (package_id_int > std::numeric_limits<uint8_t>::max()
|| package_id_int == kFrameworkPackageId
- || (!options.allow_reserved_package_id && package_id_int < kAppPackageId)) {
+ || (!options_.allow_reserved_package_id && package_id_int < kAppPackageId)) {
context.GetDiagnostics()->Error(
DiagMessage() << StringPrintf(
"invalid package ID 0x%02x. Must be in the range 0x7f-0xff.", package_id_int));
@@ -2318,71 +2066,71 @@
}
// Populate the set of extra packages for which to generate R.java.
- for (std::string& extra_package : extra_java_packages) {
+ for (std::string& extra_package : extra_java_packages_) {
// A given package can actually be a colon separated list of packages.
for (StringPiece package : util::Split(extra_package, ':')) {
- options.extra_java_packages.insert(package.to_string());
+ options_.extra_java_packages.insert(package.to_string());
}
}
- if (product_list) {
- for (StringPiece product : util::Tokenize(product_list.value(), ',')) {
+ if (product_list_) {
+ for (StringPiece product : util::Tokenize(product_list_.value(), ',')) {
if (product != "" && product != "default") {
- options.products.insert(product.to_string());
+ options_.products.insert(product.to_string());
}
}
}
std::unique_ptr<IConfigFilter> filter;
- if (!configs.empty()) {
- filter = ParseConfigFilterParameters(configs, context.GetDiagnostics());
+ if (!configs_.empty()) {
+ filter = ParseConfigFilterParameters(configs_, context.GetDiagnostics());
if (filter == nullptr) {
return 1;
}
- options.table_splitter_options.config_filter = filter.get();
+ options_.table_splitter_options.config_filter = filter.get();
}
- if (preferred_density) {
+ if (preferred_density_) {
Maybe<uint16_t> density =
- ParseTargetDensityParameter(preferred_density.value(), context.GetDiagnostics());
+ ParseTargetDensityParameter(preferred_density_.value(), context.GetDiagnostics());
if (!density) {
return 1;
}
- options.table_splitter_options.preferred_densities.push_back(density.value());
+ options_.table_splitter_options.preferred_densities.push_back(density.value());
}
// Parse the split parameters.
- for (const std::string& split_arg : split_args) {
- options.split_paths.push_back({});
- options.split_constraints.push_back({});
- if (!ParseSplitParameter(split_arg, context.GetDiagnostics(), &options.split_paths.back(),
- &options.split_constraints.back())) {
+ for (const std::string& split_arg : split_args_) {
+ options_.split_paths.push_back({});
+ options_.split_constraints.push_back({});
+ if (!ParseSplitParameter(split_arg, context.GetDiagnostics(), &options_.split_paths.back(),
+ &options_.split_constraints.back())) {
return 1;
}
}
- if (context.GetPackageType() != PackageType::kStaticLib && stable_id_file_path) {
- if (!LoadStableIdMap(context.GetDiagnostics(), stable_id_file_path.value(),
- &options.stable_id_map)) {
+ if (context.GetPackageType() != PackageType::kStaticLib && stable_id_file_path_) {
+ if (!LoadStableIdMap(context.GetDiagnostics(), stable_id_file_path_.value(),
+ &options_.stable_id_map)) {
return 1;
}
}
// Populate some default no-compress extensions that are already compressed.
- options.extensions_to_not_compress.insert(
+ options_.extensions_to_not_compress.insert(
{".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp2", ".mp3", ".ogg",
- ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl",
- ".imy", ".xmf", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2",
- ".3gpp2", ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"});
+ ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl",
+ ".imy", ".xmf", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2",
+ ".3gpp2", ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"});
// Turn off auto versioning for static-libs.
if (context.GetPackageType() == PackageType::kStaticLib) {
- options.no_auto_version = true;
- options.no_version_vectors = true;
- options.no_version_transitions = true;
+ options_.no_auto_version = true;
+ options_.no_version_vectors = true;
+ options_.no_version_transitions = true;
}
- LinkCommand cmd(&context, options);
+ Linker cmd(&context, options_);
return cmd.Run(arg_list);
}
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
new file mode 100644
index 0000000..434475e
--- /dev/null
+++ b/tools/aapt2/cmd/Link.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_LINK_H
+#define AAPT2_LINK_H
+
+#include "Command.h"
+#include "Diagnostics.h"
+#include "Resource.h"
+#include "split/TableSplitter.h"
+#include "format/binary/TableFlattener.h"
+#include "link/ManifestFixer.h"
+
+namespace aapt {
+
+enum class OutputFormat {
+ kApk,
+ kProto,
+};
+
+struct LinkOptions {
+ std::string output_path;
+ std::string manifest_path;
+ std::vector<std::string> include_paths;
+ std::vector<std::string> overlay_files;
+ std::vector<std::string> assets_dirs;
+ bool output_to_directory = false;
+ bool auto_add_overlay = false;
+ OutputFormat output_format = OutputFormat::kApk;
+
+ // Java/Proguard options.
+ Maybe<std::string> generate_java_class_path;
+ Maybe<std::string> custom_java_package;
+ std::set<std::string> extra_java_packages;
+ Maybe<std::string> generate_text_symbols_path;
+ Maybe<std::string> generate_proguard_rules_path;
+ Maybe<std::string> generate_main_dex_proguard_rules_path;
+ bool generate_conditional_proguard_rules = false;
+ bool generate_non_final_ids = false;
+ std::vector<std::string> javadoc_annotations;
+ Maybe<std::string> private_symbols;
+
+ // Optimizations/features.
+ bool no_auto_version = false;
+ bool no_version_vectors = false;
+ bool no_version_transitions = false;
+ bool no_resource_deduping = false;
+ bool no_xml_namespaces = false;
+ bool do_not_compress_anything = false;
+ std::unordered_set<std::string> extensions_to_not_compress;
+
+ // Static lib options.
+ bool no_static_lib_packages = false;
+ bool auto_namespace_static_lib = false;
+
+ // AndroidManifest.xml massaging options.
+ ManifestFixerOptions manifest_fixer_options;
+
+ // Products to use/filter on.
+ std::unordered_set<std::string> products;
+
+ // Flattening options.
+ TableFlattenerOptions table_flattener_options;
+
+ // Split APK options.
+ TableSplitterOptions table_splitter_options;
+ std::vector<SplitConstraints> split_constraints;
+ std::vector<std::string> split_paths;
+
+ // Stable ID options.
+ std::unordered_map<ResourceName, ResourceId> stable_id_map;
+ Maybe<std::string> resource_id_map_path;
+
+ // When 'true', allow reserved package IDs to be used for applications. Pre-O, the platform
+ // treats negative resource IDs [those with a package ID of 0x80 or higher] as invalid.
+ // In order to work around this limitation, we allow the use of traditionally reserved
+ // resource IDs [those between 0x02 and 0x7E].
+ bool allow_reserved_package_id = false;
+
+ // Whether we should fail on definitions of a resource with conflicting visibility.
+ bool strict_visibility = false;
+};
+
+class LinkCommand : public Command {
+ public:
+ explicit LinkCommand(IDiagnostics* diag) : Command("link", "l"),
+ diag_(diag) {
+ SetDescription("Links resources into an apk.");
+ AddRequiredFlag("-o", "Output path.", &options_.output_path);
+ AddRequiredFlag("--manifest", "Path to the Android manifest to build.",
+ &options_.manifest_path);
+ AddOptionalFlagList("-I", "Adds an Android APK to link against.", &options_.include_paths);
+ AddOptionalFlagList("-A", "An assets directory to include in the APK. These are unprocessed.",
+ &options_.assets_dirs);
+ AddOptionalFlagList("-R", "Compilation unit to link, using `overlay` semantics.\n"
+ "The last conflicting resource given takes precedence.", &overlay_arg_list_);
+ AddOptionalFlag("--package-id",
+ "Specify the package ID to use for this app. Must be greater or equal to\n"
+ "0x7f and can't be used with --static-lib or --shared-lib.", &package_id_);
+ AddOptionalFlag("--java", "Directory in which to generate R.java.",
+ &options_.generate_java_class_path);
+ AddOptionalFlag("--proguard", "Output file for generated Proguard rules.",
+ &options_.generate_proguard_rules_path);
+ AddOptionalFlag("--proguard-main-dex",
+ "Output file for generated Proguard rules for the main dex.",
+ &options_.generate_main_dex_proguard_rules_path);
+ AddOptionalSwitch("--proguard-conditional-keep-rules",
+ "Generate conditional Proguard keep rules.",
+ &options_.generate_conditional_proguard_rules);
+ AddOptionalSwitch("--no-auto-version", "Disables automatic style and layout SDK versioning.",
+ &options_.no_auto_version);
+ AddOptionalSwitch("--no-version-vectors",
+ "Disables automatic versioning of vector drawables. Use this only\n"
+ "when building with vector drawable support library.",
+ &options_.no_version_vectors);
+ AddOptionalSwitch("--no-version-transitions",
+ "Disables automatic versioning of transition resources. Use this only\n"
+ "when building with transition support library.",
+ &options_.no_version_transitions);
+ AddOptionalSwitch("--no-resource-deduping", "Disables automatic deduping of resources with\n"
+ "identical values across compatible configurations.",
+ &options_.no_resource_deduping);
+ AddOptionalSwitch("--enable-sparse-encoding",
+ "This decreases APK size at the cost of resource retrieval performance.",
+ &options_.table_flattener_options.use_sparse_entries);
+ AddOptionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01.",
+ &legacy_x_flag_);
+ AddOptionalSwitch("-z", "Require localization of strings marked 'suggested'.",
+ &require_localization_);
+ AddOptionalFlagList("-c",
+ "Comma separated list of configurations to include. The default\n"
+ "is all configurations.", &configs_);
+ AddOptionalFlag("--preferred-density",
+ "Selects the closest matching density and strips out all others.",
+ &preferred_density_);
+ AddOptionalFlag("--product", "Comma separated list of product names to keep", &product_list_);
+ AddOptionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified by -o.",
+ &options_.output_to_directory);
+ AddOptionalSwitch("--no-xml-namespaces", "Removes XML namespace prefix and URI information\n"
+ "from AndroidManifest.xml and XML binaries in res/*.",
+ &options_.no_xml_namespaces);
+ AddOptionalFlag("--min-sdk-version",
+ "Default minimum SDK version to use for AndroidManifest.xml.",
+ &options_.manifest_fixer_options.min_sdk_version_default);
+ AddOptionalFlag("--target-sdk-version",
+ "Default target SDK version to use for AndroidManifest.xml.",
+ &options_.manifest_fixer_options.target_sdk_version_default);
+ AddOptionalFlag("--version-code",
+ "Version code (integer) to inject into the AndroidManifest.xml if none is\n"
+ "present.",
+ &options_.manifest_fixer_options.version_code_default);
+ AddOptionalFlag("--version-name",
+ "Version name to inject into the AndroidManifest.xml if none is present.",
+ &options_.manifest_fixer_options.version_name_default);
+ AddOptionalSwitch("--replace-version",
+ "If --version-code and/or --version-name are specified, these\n"
+ "values will replace any value already in the manifest. By\n"
+ "default, nothing is changed if the manifest already defines\n"
+ "these attributes.",
+ &options_.manifest_fixer_options.replace_version);
+ AddOptionalFlag("--compile-sdk-version-code",
+ "Version code (integer) to inject into the AndroidManifest.xml if none is\n"
+ "present.",
+ &options_.manifest_fixer_options.compile_sdk_version);
+ AddOptionalFlag("--compile-sdk-version-name",
+ "Version name to inject into the AndroidManifest.xml if none is present.",
+ &options_.manifest_fixer_options.compile_sdk_version_codename);
+ AddOptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
+ &shared_lib_);
+ AddOptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib_);
+ AddOptionalSwitch("--proto-format",
+ "Generates compiled resources in Protobuf format.\n"
+ "Suitable as input to the bundle tool for generating an App Bundle.",
+ &proto_format_);
+ AddOptionalSwitch("--no-static-lib-packages",
+ "Merge all library resources under the app's package.",
+ &options_.no_static_lib_packages);
+ AddOptionalSwitch("--auto-namespace-static-lib",
+ "Automatically namespace resource references when building a static\n"
+ "library.",
+ &options_.auto_namespace_static_lib);
+ AddOptionalSwitch("--non-final-ids",
+ "Generates R.java without the final modifier. This is implied when\n"
+ "--static-lib is specified.",
+ &options_.generate_non_final_ids);
+ AddOptionalFlag("--stable-ids", "File containing a list of name to ID mapping.",
+ &stable_id_file_path_);
+ AddOptionalFlag("--emit-ids",
+ "Emit a file at the given path with a list of name to ID mappings,\n"
+ "suitable for use with --stable-ids.",
+ &options_.resource_id_map_path);
+ AddOptionalFlag("--private-symbols",
+ "Package name to use when generating R.java for private symbols.\n"
+ "If not specified, public and private symbols will use the application's\n"
+ "package name.",
+ &options_.private_symbols);
+ AddOptionalFlag("--custom-package", "Custom Java package under which to generate R.java.",
+ &options_.custom_java_package);
+ AddOptionalFlagList("--extra-packages",
+ "Generate the same R.java but with different package names.",
+ &extra_java_packages_);
+ AddOptionalFlagList("--add-javadoc-annotation",
+ "Adds a JavaDoc annotation to all generated Java classes.",
+ &options_.javadoc_annotations);
+ AddOptionalFlag("--output-text-symbols",
+ "Generates a text file containing the resource symbols of the R class in\n"
+ "the specified folder.",
+ &options_.generate_text_symbols_path);
+ AddOptionalSwitch("--allow-reserved-package-id",
+ "Allows the use of a reserved package ID. This should on be used for\n"
+ "packages with a pre-O min-sdk\n",
+ &options_.allow_reserved_package_id);
+ AddOptionalSwitch("--auto-add-overlay",
+ "Allows the addition of new resources in overlays without\n"
+ "<add-resource> tags.",
+ &options_.auto_add_overlay);
+ AddOptionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml.",
+ &options_.manifest_fixer_options.rename_manifest_package);
+ AddOptionalFlag("--rename-instrumentation-target-package",
+ "Changes the name of the target package for instrumentation. Most useful\n"
+ "when used in conjunction with --rename-manifest-package.",
+ &options_.manifest_fixer_options.rename_instrumentation_target_package);
+ AddOptionalFlagList("-0", "File extensions not to compress.",
+ &options_.extensions_to_not_compress);
+ AddOptionalSwitch("--no-compress", "Do not compress any resources.",
+ &options_.do_not_compress_anything);
+ AddOptionalSwitch("--warn-manifest-validation",
+ "Treat manifest validation errors as warnings.",
+ &options_.manifest_fixer_options.warn_validation);
+ AddOptionalFlagList("--split",
+ "Split resources matching a set of configs out to a Split APK.\n"
+ "Syntax: path/to/output.apk:<config>[,<config>[...]].\n"
+ "On Windows, use a semicolon ';' separator instead.",
+ &split_args_);
+ AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
+ AddOptionalSwitch("--debug-mode",
+ "Inserts android:debuggable=\"true\" in to the application node of the\n"
+ "manifest, making the application debuggable even on production devices.",
+ &options_.manifest_fixer_options.debug_mode);
+ AddOptionalSwitch("--strict-visibility",
+ "Do not allow overlays with different visibility levels.",
+ &options_.strict_visibility);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ IDiagnostics* diag_;
+ LinkOptions options_;
+
+ std::vector<std::string> overlay_arg_list_;
+ std::vector<std::string> extra_java_packages_;
+ Maybe<std::string> package_id_;
+ std::vector<std::string> configs_;
+ Maybe<std::string> preferred_density_;
+ Maybe<std::string> product_list_;
+ bool legacy_x_flag_ = false;
+ bool require_localization_ = false;
+ bool verbose_ = false;
+ bool shared_lib_ = false;
+ bool static_lib_ = false;
+ bool proto_format_ = false;
+ Maybe<std::string> stable_id_file_path_;
+ std::vector<std::string> split_args_;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_LINK_H
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 4afa8f0..b4cba8c 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "Optimize.h"
+
#include <memory>
#include <vector>
@@ -24,7 +26,6 @@
#include "androidfw/StringPiece.h"
#include "Diagnostics.h"
-#include "Flags.h"
#include "LoadedApk.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
@@ -54,36 +55,6 @@
namespace aapt {
-struct OptimizeOptions {
- // Path to the output APK.
- Maybe<std::string> output_path;
- // Path to the output APK directory for splits.
- Maybe<std::string> output_dir;
-
- // Details of the app extracted from the AndroidManifest.xml
- AppInfo app_info;
-
- // Blacklist of unused resources that should be removed from the apk.
- std::unordered_set<ResourceName> resources_blacklist;
-
- // Split APK options.
- TableSplitterOptions table_splitter_options;
-
- // List of output split paths. These are in the same order as `split_constraints`.
- std::vector<std::string> split_paths;
-
- // List of SplitConstraints governing what resources go into each split. Ordered by `split_paths`.
- std::vector<SplitConstraints> split_constraints;
-
- TableFlattenerOptions table_flattener_options;
-
- Maybe<std::vector<OutputArtifact>> apk_artifacts;
-
- // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
- // are kept and will be written as output.
- std::unordered_set<std::string> kept_artifacts;
-};
-
class OptimizeContext : public IAaptContext {
public:
OptimizeContext() = default;
@@ -145,9 +116,9 @@
int sdk_version_ = 0;
};
-class OptimizeCommand {
+class Optimizer {
public:
- OptimizeCommand(OptimizeContext* context, const OptimizeOptions& options)
+ Optimizer(OptimizeContext* context, const OptimizeOptions& options)
: options_(options), context_(context) {
}
@@ -378,82 +349,24 @@
return true;
}
-int Optimize(const std::vector<StringPiece>& args) {
- OptimizeContext context;
- OptimizeOptions options;
- Maybe<std::string> config_path;
- Maybe<std::string> whitelist_path;
- Maybe<std::string> resources_config_path;
- Maybe<std::string> target_densities;
- std::vector<std::string> configs;
- std::vector<std::string> split_args;
- std::unordered_set<std::string> kept_artifacts;
- bool verbose = false;
- bool print_only = false;
- Flags flags =
- Flags()
- .OptionalFlag("-o", "Path to the output APK.", &options.output_path)
- .OptionalFlag("-d", "Path to the output directory (for splits).", &options.output_dir)
- .OptionalFlag("-x", "Path to XML configuration file.", &config_path)
- .OptionalSwitch("-p", "Print the multi APK artifacts and exit.", &print_only)
- .OptionalFlag(
- "--target-densities",
- "Comma separated list of the screen densities that the APK will be optimized for.\n"
- "All the resources that would be unused on devices of the given densities will be \n"
- "removed from the APK.",
- &target_densities)
- .OptionalFlag("--whitelist-path",
- "Path to the whitelist.cfg file containing whitelisted resources \n"
- "whose names should not be altered in final resource tables.",
- &whitelist_path)
- .OptionalFlag("--resources-config-path",
- "Path to the resources.cfg file containing the list of resources and \n"
- "directives to each resource. \n"
- "Format: type/resource_name#[directive][,directive]",
- &resources_config_path)
- .OptionalFlagList("-c",
- "Comma separated list of configurations to include. The default\n"
- "is all configurations.",
- &configs)
- .OptionalFlagList("--split",
- "Split resources matching a set of configs out to a "
- "Split APK.\nSyntax: path/to/output.apk;<config>[,<config>[...]].\n"
- "On Windows, use a semicolon ';' separator instead.",
- &split_args)
- .OptionalFlagList("--keep-artifacts",
- "Comma separated list of artifacts to keep. If none are specified,\n"
- "all artifacts will be kept.",
- &kept_artifacts)
- .OptionalSwitch("--enable-sparse-encoding",
- "Enables encoding sparse entries using a binary search tree.\n"
- "This decreases APK size at the cost of resource retrieval performance.",
- &options.table_flattener_options.use_sparse_entries)
- .OptionalSwitch("--enable-resource-obfuscation",
- "Enables obfuscation of key string pool to single value",
- &options.table_flattener_options.collapse_key_stringpool)
- .OptionalSwitch("-v", "Enables verbose logging", &verbose);
-
- if (!flags.Parse("aapt2 optimize", args, &std::cerr)) {
- return 1;
- }
-
- if (flags.GetArgs().size() != 1u) {
+int OptimizeCommand::Action(const std::vector<std::string>& args) {
+ if (args.size() != 1u) {
std::cerr << "must have one APK as argument.\n\n";
- flags.Usage("aapt2 optimize", &std::cerr);
+ Usage(&std::cerr);
return 1;
}
- const std::string& apk_path = flags.GetArgs()[0];
-
- context.SetVerbose(verbose);
+ const std::string& apk_path = args[0];
+ OptimizeContext context;
+ context.SetVerbose(verbose_);
IDiagnostics* diag = context.GetDiagnostics();
- if (config_path) {
- std::string& path = config_path.value();
+ if (config_path_) {
+ std::string& path = config_path_.value();
Maybe<ConfigurationParser> for_path = ConfigurationParser::ForPath(path);
if (for_path) {
- options.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path);
- if (!options.apk_artifacts) {
+ options_.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path);
+ if (!options_.apk_artifacts) {
diag->Error(DiagMessage() << "Failed to parse the output artifact list");
return 1;
}
@@ -463,28 +376,28 @@
return 1;
}
- if (print_only) {
- for (const OutputArtifact& artifact : options.apk_artifacts.value()) {
+ if (print_only_) {
+ for (const OutputArtifact& artifact : options_.apk_artifacts.value()) {
std::cout << artifact.name << std::endl;
}
return 0;
}
- if (!kept_artifacts.empty()) {
- for (const std::string& artifact_str : kept_artifacts) {
+ if (!kept_artifacts_.empty()) {
+ for (const std::string& artifact_str : kept_artifacts_) {
for (const StringPiece& artifact : util::Tokenize(artifact_str, ',')) {
- options.kept_artifacts.insert(artifact.to_string());
+ options_.kept_artifacts.insert(artifact.to_string());
}
}
}
// Since we know that we are going to process the APK (not just print targets), make sure we
// have somewhere to write them to.
- if (!options.output_dir) {
+ if (!options_.output_dir) {
diag->Error(DiagMessage() << "Output directory is required when using a configuration file");
return 1;
}
- } else if (print_only) {
+ } else if (print_only_) {
diag->Error(DiagMessage() << "Asked to print artifacts without providing a configurations");
return 1;
}
@@ -494,57 +407,57 @@
return 1;
}
- if (target_densities) {
+ if (target_densities_) {
// Parse the target screen densities.
- for (const StringPiece& config_str : util::Tokenize(target_densities.value(), ',')) {
+ for (const StringPiece& config_str : util::Tokenize(target_densities_.value(), ',')) {
Maybe<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag);
if (!target_density) {
return 1;
}
- options.table_splitter_options.preferred_densities.push_back(target_density.value());
+ options_.table_splitter_options.preferred_densities.push_back(target_density.value());
}
}
std::unique_ptr<IConfigFilter> filter;
- if (!configs.empty()) {
- filter = ParseConfigFilterParameters(configs, diag);
+ if (!configs_.empty()) {
+ filter = ParseConfigFilterParameters(configs_, diag);
if (filter == nullptr) {
return 1;
}
- options.table_splitter_options.config_filter = filter.get();
+ options_.table_splitter_options.config_filter = filter.get();
}
// Parse the split parameters.
- for (const std::string& split_arg : split_args) {
- options.split_paths.emplace_back();
- options.split_constraints.emplace_back();
- if (!ParseSplitParameter(split_arg, diag, &options.split_paths.back(),
- &options.split_constraints.back())) {
+ for (const std::string& split_arg : split_args_) {
+ options_.split_paths.emplace_back();
+ options_.split_constraints.emplace_back();
+ if (!ParseSplitParameter(split_arg, diag, &options_.split_paths.back(),
+ &options_.split_constraints.back())) {
return 1;
}
}
- if (options.table_flattener_options.collapse_key_stringpool) {
- if (whitelist_path) {
- std::string& path = whitelist_path.value();
- if (!ExtractObfuscationWhitelistFromConfig(path, &context, &options)) {
+ if (options_.table_flattener_options.collapse_key_stringpool) {
+ if (whitelist_path_) {
+ std::string& path = whitelist_path_.value();
+ if (!ExtractObfuscationWhitelistFromConfig(path, &context, &options_)) {
return 1;
}
}
}
- if (resources_config_path) {
- std::string& path = resources_config_path.value();
- if (!ExtractConfig(path, &context, &options)) {
+ if (resources_config_path_) {
+ std::string& path = resources_config_path_.value();
+ if (!ExtractConfig(path, &context, &options_)) {
return 1;
}
}
- if (!ExtractAppDataFromManifest(&context, apk.get(), &options)) {
+ if (!ExtractAppDataFromManifest(&context, apk.get(), &options_)) {
return 1;
}
- OptimizeCommand cmd(&context, options);
+ Optimizer cmd(&context, options_);
return cmd.Run(std::move(apk));
}
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
new file mode 100644
index 0000000..43bc216
--- /dev/null
+++ b/tools/aapt2/cmd/Optimize.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_OPTIMIZE_H
+#define AAPT2_OPTIMIZE_H
+
+#include "AppInfo.h"
+#include "Command.h"
+#include "configuration/ConfigurationParser.h"
+#include "format/binary/TableFlattener.h"
+#include "split/TableSplitter.h"
+
+namespace aapt {
+
+struct OptimizeOptions {
+ friend class OptimizeCommand;
+
+ // Path to the output APK.
+ Maybe<std::string> output_path;
+ // Path to the output APK directory for splits.
+ Maybe<std::string> output_dir;
+
+ // Details of the app extracted from the AndroidManifest.xml
+ AppInfo app_info;
+
+ // Blacklist of unused resources that should be removed from the apk.
+ std::unordered_set<ResourceName> resources_blacklist;
+
+ // Split APK options.
+ TableSplitterOptions table_splitter_options;
+
+ // List of output split paths. These are in the same order as `split_constraints`.
+ std::vector<std::string> split_paths;
+
+ // List of SplitConstraints governing what resources go into each split. Ordered by `split_paths`.
+ std::vector<SplitConstraints> split_constraints;
+
+ TableFlattenerOptions table_flattener_options;
+
+ Maybe<std::vector<aapt::configuration::OutputArtifact>> apk_artifacts;
+
+ // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
+ // are kept and will be written as output.
+ std::unordered_set<std::string> kept_artifacts;
+};
+
+class OptimizeCommand : public Command {
+ public:
+ explicit OptimizeCommand() : Command("optimize") {
+ SetDescription("Preforms resource optimizations on an apk.");
+ AddOptionalFlag("-o", "Path to the output APK.", &options_.output_path);
+ AddOptionalFlag("-d", "Path to the output directory (for splits).", &options_.output_dir);
+ AddOptionalFlag("-x", "Path to XML configuration file.", &config_path_);
+ AddOptionalSwitch("-p", "Print the multi APK artifacts and exit.", &print_only_);
+ AddOptionalFlag(
+ "--target-densities",
+ "Comma separated list of the screen densities that the APK will be optimized for.\n"
+ "All the resources that would be unused on devices of the given densities will be \n"
+ "removed from the APK.",
+ &target_densities_);
+ AddOptionalFlag("--whitelist-path",
+ "Path to the whitelist.cfg file containing whitelisted resources \n"
+ "whose names should not be altered in final resource tables.",
+ &whitelist_path_);
+ AddOptionalFlag("--resources-config-path",
+ "Path to the resources.cfg file containing the list of resources and \n"
+ "directives to each resource. \n"
+ "Format: type/resource_name#[directive][,directive]",
+ &resources_config_path_);
+ AddOptionalFlagList("-c",
+ "Comma separated list of configurations to include. The default\n"
+ "is all configurations.",
+ &configs_);
+ AddOptionalFlagList("--split",
+ "Split resources matching a set of configs out to a "
+ "Split APK.\nSyntax: path/to/output.apk;<config>[,<config>[...]].\n"
+ "On Windows, use a semicolon ';' separator instead.",
+ &split_args_);
+ AddOptionalFlagList("--keep-artifacts",
+ "Comma separated list of artifacts to keep. If none are specified,\n"
+ "all artifacts will be kept.",
+ &kept_artifacts_);
+ AddOptionalSwitch("--enable-sparse-encoding",
+ "Enables encoding sparse entries using a binary search tree.\n"
+ "This decreases APK size at the cost of resource retrieval performance.",
+ &options_.table_flattener_options.use_sparse_entries);
+ AddOptionalSwitch("--enable-resource-obfuscation",
+ "Enables obfuscation of key string pool to single value",
+ &options_.table_flattener_options.collapse_key_stringpool);
+ AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ OptimizeOptions options_;
+
+ Maybe<std::string> config_path_;
+ Maybe<std::string> whitelist_path_;
+ Maybe<std::string> resources_config_path_;
+ Maybe<std::string> target_densities_;
+ std::vector<std::string> configs_;
+ std::vector<std::string> split_args_;
+ std::unordered_set<std::string> kept_artifacts_;
+ bool print_only_ = false;
+ bool verbose_ = false;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_OPTIMIZE_H
\ No newline at end of file
diff --git a/tools/aapt2/jni/aapt2_jni.cpp b/tools/aapt2/jni/aapt2_jni.cpp
index ad5ad4c..ba9646f 100644
--- a/tools/aapt2/jni/aapt2_jni.cpp
+++ b/tools/aapt2/jni/aapt2_jni.cpp
@@ -25,15 +25,12 @@
#include "ScopedUtfChars.h"
#include "Diagnostics.h"
+#include "cmd/Compile.h"
+#include "cmd/Link.h"
#include "util/Util.h"
using android::StringPiece;
-namespace aapt {
-extern int Compile(const std::vector<StringPiece>& args, IDiagnostics* iDiagnostics);
-extern int Link(const std::vector<StringPiece>& args, IDiagnostics* iDiagnostics);
-}
-
/*
* Converts a java List<String> into C++ vector<ScopedUtfChars>.
*/
@@ -126,7 +123,7 @@
list_to_utfchars(env, arguments_obj);
std::vector<StringPiece> compile_args = extract_pieces(compile_args_jni);
JniDiagnostics diagnostics(env, diagnostics_obj);
- return aapt::Compile(compile_args, &diagnostics);
+ return aapt::CompileCommand(&diagnostics).Execute(compile_args, &std::cerr);
}
JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeLink(JNIEnv* env,
@@ -137,7 +134,7 @@
list_to_utfchars(env, arguments_obj);
std::vector<StringPiece> link_args = extract_pieces(link_args_jni);
JniDiagnostics diagnostics(env, diagnostics_obj);
- return aapt::Link(link_args, &diagnostics);
+ return aapt::LinkCommand(&diagnostics).Execute(link_args, &std::cerr);
}
JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping(