diff options
Diffstat (limited to 'tools/aapt2/cmd/Optimize.cpp')
-rw-r--r-- | tools/aapt2/cmd/Optimize.cpp | 227 |
1 files changed, 107 insertions, 120 deletions
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index 9c76119f9504..b4cba8c2801c 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" @@ -38,6 +39,7 @@ #include "io/Util.h" #include "optimize/MultiApkGenerator.h" #include "optimize/ResourceDeduper.h" +#include "optimize/ResourceFilter.h" #include "optimize/VersionCollapser.h" #include "split/TableSplitter.h" #include "util/Files.h" @@ -53,33 +55,6 @@ using ::android::base::StringPrintf; 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; - - // 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; @@ -129,6 +104,10 @@ class OptimizeContext : public IAaptContext { return sdk_version_; } + bool IsAutoNamespace() override { + return false; + } + private: DISALLOW_COPY_AND_ASSIGN(OptimizeContext); @@ -137,9 +116,9 @@ class OptimizeContext : public IAaptContext { 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) { } @@ -147,6 +126,13 @@ class OptimizeCommand { if (context_->IsVerbose()) { context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK..."); } + if (!options_.resources_blacklist.empty()) { + ResourceFilter filter(options_.resources_blacklist); + if (!filter.Consume(context_, apk->GetResourceTable())) { + context_->GetDiagnostics()->Error(DiagMessage() << "failed filtering resources"); + return 1; + } + } VersionCollapser collapser; if (!collapser.Consume(context_, apk->GetResourceTable())) { @@ -284,16 +270,62 @@ class OptimizeCommand { OptimizeContext* context_; }; -bool ExtractWhitelistFromConfig(const std::string& path, OptimizeContext* context, - OptimizeOptions* options) { +bool ExtractObfuscationWhitelistFromConfig(const std::string& path, OptimizeContext* context, + OptimizeOptions* options) { std::string contents; if (!ReadFileToString(path, &contents, true)) { context->GetDiagnostics()->Error(DiagMessage() << "failed to parse whitelist from config file: " << path); return false; } - for (const StringPiece& resource_name : util::Tokenize(contents, ',')) { - options->table_flattener_options.whitelisted_resources.insert(resource_name.to_string()); + for (StringPiece resource_name : util::Tokenize(contents, ',')) { + options->table_flattener_options.whitelisted_resources.insert( + resource_name.to_string()); + } + return true; +} + +bool ExtractConfig(const std::string& path, OptimizeContext* context, + OptimizeOptions* options) { + std::string content; + if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) { + context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading whitelist"); + return false; + } + + size_t line_no = 0; + for (StringPiece line : util::Tokenize(content, '\n')) { + line_no++; + line = util::TrimWhitespace(line); + if (line.empty()) { + continue; + } + + auto split_line = util::Split(line, '#'); + if (split_line.size() < 2) { + context->GetDiagnostics()->Error(DiagMessage(line) << "No # found in line"); + return false; + } + StringPiece resource_string = split_line[0]; + StringPiece directives = split_line[1]; + ResourceNameRef resource_name; + if (!ResourceUtils::ParseResourceName(resource_string, &resource_name)) { + context->GetDiagnostics()->Error(DiagMessage(line) << "Malformed resource name"); + return false; + } + if (!resource_name.package.empty()) { + context->GetDiagnostics()->Error(DiagMessage(line) + << "Package set for resource. Only use type/name"); + return false; + } + for (StringPiece directive : util::Tokenize(directives, ',')) { + if (directive == "remove") { + options->resources_blacklist.insert(resource_name.ToResourceName()); + } else if (directive == "no_obfuscate") { + options->table_flattener_options.whitelisted_resources.insert( + resource_name.entry.to_string()); + } + } } return true; } @@ -317,76 +349,24 @@ bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk, 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> 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-config-path", - "Path to the whitelist.cfg file containing whitelisted resources \n" - "whose names should not be altered in final resource tables.", - &whitelist_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; } @@ -396,28 +376,28 @@ int Optimize(const std::vector<StringPiece>& args) { 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; } @@ -427,50 +407,57 @@ int Optimize(const std::vector<StringPiece>& args) { 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 (!ExtractWhitelistFromConfig(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 (!ExtractAppDataFromManifest(&context, apk.get(), &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_)) { return 1; } - OptimizeCommand cmd(&context, options); + Optimizer cmd(&context, options_); return cmd.Run(std::move(apk)); } |