diff options
author | Adam Lesinski <adamlesinski@google.com> | 2017-02-21 14:22:30 -0800 |
---|---|---|
committer | Adam Lesinski <adamlesinski@google.com> | 2017-02-22 11:41:55 -0800 |
commit | d48944a745f9ed121e6bde22ef6feb3a44fbec39 (patch) | |
tree | 349c152caa68f1283535b2f9c49f5cd8a50eb59b /tools/aapt2/optimize/Optimize.cpp | |
parent | ceb9b2f80f853059233cdd29057f39a5960a74ae (diff) |
AAPT2: Rename strip phase to optimize
- Allow resource deduping, version collapsing, and sparse resource
encoding.
Test: manual
Change-Id: Ia4aa892ab5b06ba1d5ea4a6efb51b00bc3a980c4
Diffstat (limited to 'tools/aapt2/optimize/Optimize.cpp')
-rw-r--r-- | tools/aapt2/optimize/Optimize.cpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/tools/aapt2/optimize/Optimize.cpp b/tools/aapt2/optimize/Optimize.cpp new file mode 100644 index 000000000000..96159622e653 --- /dev/null +++ b/tools/aapt2/optimize/Optimize.cpp @@ -0,0 +1,201 @@ +/* + * 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" +#include "SdkConstants.h" +#include "flatten/TableFlattener.h" +#include "optimize/ResourceDeduper.h" +#include "optimize/VersionCollapser.h" +#include "split/TableSplitter.h" + +using android::StringPiece; + +namespace aapt { + +struct OptimizeOptions { + // 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; + + TableFlattenerOptions table_flattener_options; +}; + +class OptimizeContext : 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; } + + void SetMinSdkVersion(int sdk_version) { sdk_version_ = sdk_version; } + + int GetMinSdkVersion() override { return sdk_version_; } + + private: + StdErrDiagnostics diagnostics_; + bool verbose_ = false; + int sdk_version_ = 0; +}; + +class OptimizeCommand { + public: + OptimizeCommand(OptimizeContext* context, const OptimizeOptions& options) + : options_(options), + context_(context) {} + + int Run(std::unique_ptr<LoadedApk> apk) { + if (context_->IsVerbose()) { + context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK..."); + } + + VersionCollapser collapser; + if (!collapser.Consume(context_, apk->GetResourceTable())) { + return 1; + } + + ResourceDeduper deduper; + if (!deduper.Consume(context_, apk->GetResourceTable())) { + context_->GetDiagnostics()->Error(DiagMessage() << "failed deduping resources"); + return 1; + } + + // Stripping the APK using the TableSplitter with no splits and the target + // densities as the preferred densities. The resource table is modified in + // place in the LoadedApk. + TableSplitterOptions splitter_options; + for (auto& config : options_.target_configs) { + splitter_options.preferred_densities.push_back(config.density); + } + std::vector<SplitConstraints> splits; + TableSplitter splitter(splits, splitter_options); + splitter.SplitTable(apk->GetResourceTable()); + + std::unique_ptr<IArchiveWriter> writer = + CreateZipFileArchiveWriter(context_->GetDiagnostics(), options_.output_path); + if (!apk->WriteToArchive(context_, options_.table_flattener_options, writer.get())) { + return 1; + } + + return 0; + } + + private: + OptimizeOptions options_; + OptimizeContext* context_; +}; + +int Optimize(const std::vector<StringPiece>& args) { + OptimizeContext context; + OptimizeOptions options; + Maybe<std::string> target_densities; + bool verbose = false; + Flags flags = + Flags() + .RequiredFlag("-o", "Path to the output APK.", &options.output_path) + .OptionalFlag( + "--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("--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("-v", "Enables verbose logging", &verbose); + + if (!flags.Parse("aapt2 optimize", args, &std::cerr)) { + return 1; + } + + if (flags.GetArgs().size() != 1u) { + std::cerr << "must have one APK as argument.\n\n"; + flags.Usage("aapt2 optimize", &std::cerr); + return 1; + } + + std::unique_ptr<LoadedApk> apk = + LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]); + if (!apk) { + return 1; + } + + if (verbose) { + context.SetVerbose(verbose); + } + + if (target_densities) { + // Parse the target screen densities. + for (const StringPiece& config_str : util::Tokenize(target_densities.value(), ',')) { + 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); + } + } + + // TODO(adamlesinski): Read manfiest and set the proper minSdkVersion. + // context.SetMinSdkVersion(SDK_O); + + OptimizeCommand cmd(&context, options); + return cmd.Run(std::move(apk)); +} + +} // namespace aapt |