OSDN Git Service

Backbone of the new aapt2 strip command.
authorPierre Lecesne <lecesne@google.com>
Tue, 31 Jan 2017 23:58:27 +0000 (23:58 +0000)
committerPierre Lecesne <lecesne@google.com>
Wed, 1 Feb 2017 18:49:19 +0000 (18:49 +0000)
The strip command takes an APK as argument and a --target-densities flag which
contains the list of screen densities for which to optimize the APK. All
the resources that would be unused for a device having the given
densities are stripped from the APK leaving only the ones actually being
used.

Test: Manual.

Change-Id: I68368b00876a18ccdbbfc0a8dd265bd361117933

tools/aapt2/Android.bp
tools/aapt2/Main.cpp
tools/aapt2/strip/Strip.cpp [new file with mode: 0644]

index 8c28083..dabaca6 100644 (file)
@@ -19,6 +19,7 @@ toolSources = [
     "diff/Diff.cpp",
     "dump/Dump.cpp",
     "link/Link.cpp",
+    "strip/Strip.cpp",
 ]
 
 cc_defaults {
index 15d7e2e..3ed698b 100644 (file)
@@ -37,6 +37,7 @@ extern int Compile(const std::vector<android::StringPiece>& args);
 extern int Link(const std::vector<android::StringPiece>& args);
 extern int Dump(const std::vector<android::StringPiece>& args);
 extern int Diff(const std::vector<android::StringPiece>& args);
+extern int Strip(const std::vector<android::StringPiece>& args);
 
 }  // namespace aapt
 
@@ -59,6 +60,8 @@ int main(int argc, char** argv) {
       return aapt::Dump(args);
     } else if (command == "diff") {
       return aapt::Diff(args);
+    } else if (command == "strip") {
+      return aapt::Strip(args);
     } else if (command == "version") {
       return aapt::PrintVersion();
     }
@@ -67,7 +70,7 @@ int main(int argc, char** argv) {
     std::cerr << "no command specified\n";
   }
 
-  std::cerr << "\nusage: aapt2 [compile|link|dump|diff|version] ..."
+  std::cerr << "\nusage: aapt2 [compile|link|dump|diff|strip|version] ..."
             << std::endl;
   return 1;
 }
diff --git a/tools/aapt2/strip/Strip.cpp b/tools/aapt2/strip/Strip.cpp
new file mode 100644 (file)
index 0000000..b3787ec
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 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 <memory>
+#include <vector>
+
+#include "androidfw/StringPiece.h"
+
+#include "Diagnostics.h"
+#include "Flags.h"
+#include "LoadedApk.h"
+
+using android::StringPiece;
+
+namespace aapt {
+
+struct StripOptions {
+  /** Path to the output APK. */
+  std::string output_path;
+
+  /** List of screen density configurations the APK will be optimized for. */
+  std::vector<ConfigDescription> target_configs;
+};
+
+class StripContext : public IAaptContext {
+ public:
+  IDiagnostics* GetDiagnostics() override { return &diagnostics_; }
+
+  NameMangler* GetNameMangler() override {
+    abort();
+    return nullptr;
+  }
+
+  const std::string& GetCompilationPackage() override {
+    static std::string empty;
+    return empty;
+  }
+
+  uint8_t GetPackageId() override { return 0; }
+
+  SymbolTable* GetExternalSymbols() override {
+    abort();
+    return nullptr;
+  }
+
+  bool IsVerbose() override { return verbose_; }
+
+  void SetVerbose(bool val) { verbose_ = val; }
+
+  int GetMinSdkVersion() override { return 0; }
+
+ private:
+  StdErrDiagnostics diagnostics_;
+  bool verbose_ = false;
+};
+
+class StripCommand {
+ public:
+  StripCommand(StripContext* context, const StripOptions& options)
+      : options_(options),
+        context_(context) {}
+
+  int Run(std::unique_ptr<LoadedApk> apk) {
+    if (context_->IsVerbose()) {
+      context_->GetDiagnostics()->Note(DiagMessage() << "Stripping APK...");
+    }
+
+    // TODO(lecesne): Implement stripping here.
+
+    return 0;
+  }
+
+ private:
+  StripOptions options_;
+  StripContext* context_;
+};
+
+int Strip(const std::vector<StringPiece>& args) {
+  StripContext context;
+  StripOptions options;
+  std::string target_densities;
+  bool verbose = false;
+  Flags flags =
+      Flags()
+          .RequiredFlag("-o", "Path to the output APK.", &options.output_path)
+          .RequiredFlag(
+              "--target-densities",
+              "Comma separated list of the screen densities that the APK will "
+              "be optimized for. All the resources that would be unused on "
+              "devices of the given densities will be removed from the APK.",
+              &target_densities)
+          .OptionalSwitch("-v", "Enables verbose logging", &verbose);
+
+  if (!flags.Parse("aapt2 strip", args, &std::cerr)) {
+    return 1;
+  }
+
+  if (flags.GetArgs().size() != 1u) {
+    std::cerr << "must have one APK as argument.\n\n";
+    flags.Usage("aapt2 strip", &std::cerr);
+    return 1;
+  }
+
+  std::unique_ptr<LoadedApk> apk =
+      LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
+  if (!apk) {
+    return 1;
+  }
+
+  if (verbose) {
+    context.SetVerbose(verbose);
+  }
+
+  // Parse the target screen densities.
+  for (const StringPiece& config_str : util::Tokenize(target_densities, ',')) {
+    ConfigDescription config;
+    if (!ConfigDescription::Parse(config_str, &config) || config.density == 0) {
+      context.GetDiagnostics()->Error(
+          DiagMessage() << "invalid density '" << config_str
+                        << "' for --target-densities option");
+      return 1;
+    }
+
+    // Clear the version that can be automatically added.
+    config.sdkVersion = 0;
+
+    if (config.diff(ConfigDescription::DefaultConfig()) !=
+        ConfigDescription::CONFIG_DENSITY) {
+      context.GetDiagnostics()->Error(
+          DiagMessage() << "invalid density '" << config_str
+                        << "' for --target-densities option. Must be only a "
+                        << "density value.");
+      return 1;
+    }
+
+    options.target_configs.push_back(config);
+  }
+
+  StripCommand cmd(&context, options);
+  return cmd.Run(std::move(apk));
+}
+
+}  // namespace aapt