Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3ee72ce authored by Iurii Makhno's avatar Iurii Makhno Committed by Android (Google) Code Review
Browse files

Merge "Expose flags for collapse resource name to 'convert' command."

parents 0a97965a 054e4331
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -21,7 +21,9 @@
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
#include "android-base/file.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "format/binary/TableFlattener.h"
@@ -353,6 +355,27 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
  return 0;
}

bool ExtractResourceConfig(const std::string& path, IAaptContext* context,
                           TableFlattenerOptions& out_options) {
  std::string content;
  if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
    context->GetDiagnostics()->Error(android::DiagMessage(path) << "failed reading config file");
    return false;
  }
  std::unordered_set<ResourceName> resources_exclude_list;
  bool result = ParseResourceConfig(content, context, resources_exclude_list,
                                    out_options.name_collapse_exemptions);
  if (!result) {
    return false;
  }
  if (!resources_exclude_list.empty()) {
    context->GetDiagnostics()->Error(android::DiagMessage(path)
                                     << "Unsupported '#remove' directive in resource config.");
    return false;
  }
  return true;
}

const char* ConvertCommand::kOutputFormatProto = "proto";
const char* ConvertCommand::kOutputFormatBinary = "binary";

@@ -401,6 +424,11 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
  if (force_sparse_encoding_) {
    table_flattener_options_.sparse_entries = SparseEntriesMode::Forced;
  }
  if (resources_config_path_) {
    if (!ExtractResourceConfig(*resources_config_path_, &context, table_flattener_options_)) {
      return 1;
    }
  }

  return Convert(&context, apk.get(), writer.get(), format, table_flattener_options_,
                 xml_flattener_options_);
+20 −0
Original line number Diff line number Diff line
@@ -50,6 +50,25 @@ class ConvertCommand : public Command {
        android::base::StringPrintf("Preserve raw attribute values in xml files when using the"
            " '%s' output format", kOutputFormatBinary),
        &xml_flattener_options_.keep_raw_values);
    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_);
    AddOptionalSwitch(
        "--collapse-resource-names",
        "Collapses resource names to a single value in the key string pool. Resources can \n"
        "be exempted using the \"no_collapse\" directive in a file specified by "
        "--resources-config-path.",
        &table_flattener_options_.collapse_key_stringpool);
    AddOptionalSwitch(
        "--deduplicate-entry-values",
        "Whether to deduplicate pairs of resource entry and value for simple resources.\n"
        "This is recommended to be used together with '--collapse-resource-names' flag or for\n"
        "APKs where resource names are manually collapsed. For such APKs this flag allows to\n"
        "store the same resource value only once in resource table which decreases APK size.\n"
        "Has no effect on APKs where resource names are kept.",
        &table_flattener_options_.deduplicate_entry_values);
    AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
  }

@@ -66,6 +85,7 @@ class ConvertCommand : public Command {
  bool verbose_ = false;
  bool enable_sparse_encoding_ = false;
  bool force_sparse_encoding_ = false;
  std::optional<std::string> resources_config_path_;
};

int Convert(IAaptContext* context, LoadedApk* input, IArchiveWriter* output_writer,
+77 −0
Original line number Diff line number Diff line
@@ -17,13 +17,18 @@
#include "Convert.h"

#include "LoadedApk.h"
#include "test/Common.h"
#include "test/Test.h"
#include "ziparchive/zip_archive.h"

using testing::AnyOfArray;
using testing::Eq;
using testing::Ne;
using testing::Not;
using testing::SizeIs;

namespace aapt {
using namespace aapt::test;

using ConvertTest = CommandTestFixture;

@@ -145,4 +150,76 @@ TEST_F(ConvertTest, DuplicateEntriesWrittenOnce) {
  EXPECT_THAT(count, Eq(1));
}

TEST_F(ConvertTest, ConvertWithResourceNameCollapsing) {
  StdErrDiagnostics diag;
  const std::string compiled_files_dir = GetTestPath("compiled");
  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
                          R"(<resources>
                               <string name="first">string</string>
                               <string name="second">string</string>
                               <string name="third">another string</string>

                               <bool name="bool1">true</bool>
                               <bool name="bool2">true</bool>
                               <bool name="bool3">true</bool>

                               <integer name="int1">10</integer>
                               <integer name="int2">10</integer>
                             </resources>)",
                          compiled_files_dir, &diag));
  std::string resource_config_path = GetTestPath("resource-config");
  WriteFile(resource_config_path, "integer/int1#no_collapse\ninteger/int2#no_collapse");

  const std::string proto_apk = GetTestPath("proto.apk");
  std::vector<std::string> link_args = {
      "--proto-format", "--manifest", GetDefaultManifest(kDefaultPackageName), "-o", proto_apk,
  };
  ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));

  const std::string binary_apk = GetTestPath("binary.apk");
  std::vector<android::StringPiece> convert_args = {"-o",
                                                    binary_apk,
                                                    "--output-format",
                                                    "binary",
                                                    "--collapse-resource-names",
                                                    "--deduplicate-entry-values",
                                                    "--resources-config-path",
                                                    resource_config_path,
                                                    proto_apk};
  ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));

  std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(binary_apk, &diag);
  for (const auto& package : apk->GetResourceTable()->packages) {
    for (const auto& type : package->types) {
      switch (type->named_type.type) {
        case ResourceType::kBool:
          EXPECT_THAT(type->entries, SizeIs(3));
          for (const auto& entry : type->entries) {
            auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
            EXPECT_THAT(value.data, Eq(0xffffffffu));
          }
          break;
        case ResourceType::kString:
          EXPECT_THAT(type->entries, SizeIs(3));
          for (const auto& entry : type->entries) {
            auto value = ValueCast<String>(entry->FindValue({})->value.get())->value;
            EXPECT_THAT(entry->name, Not(AnyOfArray({"first", "second", "third"})));
            EXPECT_THAT(*value, AnyOfArray({"string", "another string"}));
          }
          break;
        case ResourceType::kInteger:
          EXPECT_THAT(type->entries, SizeIs(2));
          for (const auto& entry : type->entries) {
            auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
            EXPECT_THAT(entry->name, AnyOfArray({"int1", "int2"}));
            EXPECT_THAT(value.data, Eq(10));
          }
          break;
        default:
          break;
      }
    }
  }
}

}  // namespace aapt
+2 −39
Original line number Diff line number Diff line
@@ -305,51 +305,14 @@ class Optimizer {
  OptimizeContext* context_;
};

bool ParseConfig(const std::string& content, IAaptContext* context, OptimizeOptions* options) {
  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(android::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(android::DiagMessage(line) << "Malformed resource name");
      return false;
    }
    if (!resource_name.package.empty()) {
      context->GetDiagnostics()->Error(android::DiagMessage(line)
                                       << "Package set for resource. Only use type/name");
      return false;
    }
    for (StringPiece directive : util::Tokenize(directives, ',')) {
      if (directive == "remove") {
        options->resources_exclude_list.insert(resource_name.ToResourceName());
      } else if (directive == "no_collapse" || directive == "no_obfuscate") {
        options->table_flattener_options.name_collapse_exemptions.insert(
            resource_name.ToResourceName());
      }
    }
  }
  return true;
}

bool ExtractConfig(const std::string& path, IAaptContext* context, OptimizeOptions* options) {
  std::string content;
  if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
    context->GetDiagnostics()->Error(android::DiagMessage(path) << "failed reading config file");
    return false;
  }
  return ParseConfig(content, context, options);
  return ParseResourceConfig(content, context, options->resources_exclude_list,
                             options->table_flattener_options.name_collapse_exemptions);
}

bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
+8 −0
Original line number Diff line number Diff line
@@ -123,6 +123,14 @@ class OptimizeCommand : public Command {
    AddOptionalFlag("--resource-path-shortening-map",
        "Path to output the map of old resource paths to shortened paths.",
        &options_.shortened_paths_map_path);
    AddOptionalSwitch(
        "--deduplicate-entry-values",
        "Whether to deduplicate pairs of resource entry and value for simple resources.\n"
        "This is recommended to be used together with '--collapse-resource-names' flag or for\n"
        "APKs where resource names are manually collapsed. For such APKs this flag allows to\n"
        "store the same resource value only once in resource table which decreases APK size.\n"
        "Has no effect on APKs where resource names are kept.",
        &options_.table_flattener_options.deduplicate_entry_values);
    AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
  }

Loading