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

Commit 8ceb39c9 authored by felkachang's avatar felkachang
Browse files

Use lambda to refactor the obfuscating resource name.

There are 2 copy codes for handling the obfuscating resources names
between serializing to pb format file and writing to apks. The
obfuscator also needs to dump resources names. It means there are
3 places to handle the obfuscating resources names.

So, using C++ lambda to apply the callback mechanism refactors the
codes.

Obfuscator
* Initial a Obfuscator according to Optimizer's options
* Add Obfuscator.IsEnabled() function.
    return true either shorten_resource_paths_ is true or
    collapse_key_stringpool_ is true.

Bug: 228192695

Test: atest aapt2_test idmap2_test

Change-Id: Idd2442beecf41e9392620ff801a36fd1285e06f9
parent 0eef7918
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -154,8 +154,8 @@ class Optimizer {
      return 1;
    }

    if (options_.shorten_resource_paths) {
      Obfuscator obfuscator(options_.table_flattener_options.shortened_path_map);
    Obfuscator obfuscator(options_);
    if (obfuscator.IsEnabled()) {
      if (!obfuscator.Consume(context_, apk->GetResourceTable())) {
        context_->GetDiagnostics()->Error(android::DiagMessage()
                                          << "failed shortening resource paths");
+16 −17
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include "format/binary/ChunkWriter.h"
#include "format/binary/ResEntryWriter.h"
#include "format/binary/ResourceTypeExtensions.h"
#include "optimize/Obfuscator.h"
#include "trace/TraceBuffer.h"

using namespace android;
@@ -466,9 +467,6 @@ class PackageFlattener {
      // table.
      std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map;

      // hardcoded string uses characters which make it an invalid resource name
      const std::string obfuscated_resource_name = "0_resource_name_obfuscated";

      for (const ResourceTableEntryView& entry : type.entries) {
        if (entry.staged_id) {
          aliases_.insert(std::make_pair(
@@ -477,30 +475,31 @@ class PackageFlattener {
        }

        uint32_t local_key_index;
        ResourceName resource_name({}, type.named_type, entry.name);
        if (!collapse_key_stringpool_ ||
            name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) {
        auto onObfuscate = [this, &local_key_index, &entry](Obfuscator::Result obfuscatedResult,
                                                            const ResourceName& resource_name) {
          if (obfuscatedResult == Obfuscator::Result::Keep_ExemptionList) {
            local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
        } else {
          // resource isn't exempt from collapse, add it as obfuscated value
          if (entry.overlayable_item) {
          } else if (obfuscatedResult == Obfuscator::Result::Keep_Overlayable) {
            // if the resource name of the specific entry is obfuscated and this
            // entry is in the overlayable list, the overlay can't work on this
            // overlayable at runtime because the name has been obfuscated in
            // resources.arsc during flatten operation.
            const OverlayableItem& item = entry.overlayable_item.value();
            context_->GetDiagnostics()->Warn(android::DiagMessage(item.overlayable->source)
                                             << "The resource name of overlayable entry "
                                             << resource_name.to_string() << "'"
                                             << " shouldn't be obfuscated in resources.arsc");
                                             << "The resource name of overlayable entry '"
                                             << resource_name.to_string()
                                             << "' shouldn't be obfuscated in resources.arsc");

            local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
          } else {
            // TODO(b/228192695): output the entry.name and Resource id to make
            //  de-obfuscated possible.
            local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index();
          }
            local_key_index =
                (uint32_t)key_pool_.MakeRef(Obfuscator::kObfuscatedResourceName).index();
          }
        };

        Obfuscator::ObfuscateResourceName(collapse_key_stringpool_, name_collapse_exemptions_,
                                          type.named_type, entry, onObfuscate);

        // Group values by configuration.
        for (auto& config_value : entry.values) {
          config_to_entry_list_map[config_value->config].push_back(
+13 −5
Original line number Diff line number Diff line
@@ -14,8 +14,13 @@
 * limitations under the License.
 */

#ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H
#define AAPT_FORMAT_BINARY_TABLEFLATTENER_H
#ifndef TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
#define TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_

#include <map>
#include <set>
#include <string>
#include <unordered_map>

#include "Resource.h"
#include "ResourceTable.h"
@@ -71,6 +76,9 @@ struct TableFlattenerOptions {
  //
  // This applies only to simple entries (entry->flags & ResTable_entry::FLAG_COMPLEX == 0).
  bool deduplicate_entry_values = false;

  // Map from original resource ids to obfuscated names.
  std::unordered_map<uint32_t, std::string> id_resource_map;
};

class TableFlattener : public IResourceTableConsumer {
@@ -82,12 +90,12 @@ class TableFlattener : public IResourceTableConsumer {
  bool Consume(IAaptContext* context, ResourceTable* table) override;

 private:
  DISALLOW_COPY_AND_ASSIGN(TableFlattener);

  TableFlattenerOptions options_;
  android::BigBuffer* buffer_;

  DISALLOW_COPY_AND_ASSIGN(TableFlattener);
};

}  // namespace aapt

#endif /* AAPT_FORMAT_BINARY_TABLEFLATTENER_H */
#endif  // TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
+11 −10
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "ValueVisitor.h"
#include "androidfw/BigBuffer.h"
#include "optimize/Obfuscator.h"

using android::ConfigDescription;

@@ -366,21 +367,21 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
      }
      pb_type->set_name(type.named_type.to_string());

      // hardcoded string uses characters which make it an invalid resource name
      static const char* obfuscated_resource_name = "0_resource_name_obfuscated";
      for (const auto& entry : type.entries) {
        pb::Entry* pb_entry = pb_type->add_entry();
        if (entry.id) {
          pb_entry->mutable_entry_id()->set_id(entry.id.value());
        }
        ResourceName resource_name({}, type.named_type, entry.name);
        if (options.collapse_key_stringpool &&
            options.name_collapse_exemptions.find(resource_name) ==
            options.name_collapse_exemptions.end()) {
          pb_entry->set_name(obfuscated_resource_name);
        } else {
          pb_entry->set_name(entry.name);
        }
        auto onObfuscate = [pb_entry, &entry](Obfuscator::Result obfuscatedResult,
                                              const ResourceName& resource_name) {
          pb_entry->set_name(obfuscatedResult == Obfuscator::Result::Obfuscated
                                 ? Obfuscator::kObfuscatedResourceName
                                 : entry.name);
        };

        Obfuscator::ObfuscateResourceName(options.collapse_key_stringpool,
                                          options.name_collapse_exemptions, type.named_type, entry,
                                          onObfuscate);

        // Write the Visibility struct.
        pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
+92 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "optimize/Obfuscator.h"

#include <map>
#include <set>
#include <string>
#include <unordered_set>
@@ -32,7 +33,10 @@ static const char base64_chars[] =

namespace aapt {

Obfuscator::Obfuscator(std::map<std::string, std::string>& path_map_out) : path_map_(path_map_out) {
Obfuscator::Obfuscator(OptimizeOptions& optimizeOptions)
    : options_(optimizeOptions.table_flattener_options),
      shorten_resource_paths_(optimizeOptions.shorten_resource_paths),
      collapse_key_stringpool_(optimizeOptions.table_flattener_options.collapse_key_stringpool) {
}

std::string ShortenFileName(const android::StringPiece& file_path, int output_length) {
@@ -77,7 +81,8 @@ struct PathComparator {
  }
};

bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
static bool HandleShortenFilePaths(ResourceTable* table,
                                   std::map<std::string, std::string>& shortened_path_map) {
  // used to detect collisions
  std::unordered_set<std::string> shortened_paths;
  std::set<FileReference*, PathComparator> file_refs;
@@ -109,10 +114,94 @@ bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
      shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
    }
    shortened_paths.insert(shortened_path);
    path_map_.insert({*file_ref->path, shortened_path});
    shortened_path_map.insert({*file_ref->path, shortened_path});
    file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
  }
  return true;
}

void Obfuscator::ObfuscateResourceName(
    const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions,
    const ResourceNamedType& type_name, const ResourceTableEntryView& entry,
    const android::base::function_ref<void(Result obfuscatedResult, const ResourceName&)>
        onObfuscate) {
  ResourceName resource_name({}, type_name, entry.name);
  if (!collapse_key_stringpool ||
      name_collapse_exemptions.find(resource_name) != name_collapse_exemptions.end()) {
    onObfuscate(Result::Keep_ExemptionList, resource_name);
  } else {
    // resource isn't exempt from collapse, add it as obfuscated value
    if (entry.overlayable_item) {
      // if the resource name of the specific entry is obfuscated and this
      // entry is in the overlayable list, the overlay can't work on this
      // overlayable at runtime because the name has been obfuscated in
      // resources.arsc during flatten operation.
      onObfuscate(Result::Keep_Overlayable, resource_name);
    } else {
      onObfuscate(Result::Obfuscated, resource_name);
    }
  }
}

static bool HandleCollapseKeyStringPool(
    const ResourceTable* table, const bool collapse_key_string_pool,
    const std::set<ResourceName>& name_collapse_exemptions,
    std::unordered_map<uint32_t, std::string>& id_resource_map) {
  if (!collapse_key_string_pool) {
    return true;
  }

  int entryResId = 0;
  auto onObfuscate = [&entryResId, &id_resource_map](const Obfuscator::Result obfuscatedResult,
                                                     const ResourceName& resource_name) {
    if (obfuscatedResult == Obfuscator::Result::Obfuscated) {
      id_resource_map.insert({entryResId, resource_name.entry});
    }
  };

  for (auto& package : table->packages) {
    for (auto& type : package->types) {
      for (auto& entry : type->entries) {
        if (!entry->id.has_value() || entry->name.empty()) {
          continue;
        }
        entryResId = entry->id->id;
        ResourceTableEntryView entry_view{
            .name = entry->name,
            .id = entry->id ? entry->id.value().entry_id() : (std::optional<uint16_t>)std::nullopt,
            .visibility = entry->visibility,
            .allow_new = entry->allow_new,
            .overlayable_item = entry->overlayable_item,
            .staged_id = entry->staged_id};

        Obfuscator::ObfuscateResourceName(collapse_key_string_pool, name_collapse_exemptions,
                                          type->named_type, entry_view, onObfuscate);
      }
    }
  }

  return true;
}

bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
  HandleCollapseKeyStringPool(table, options_.collapse_key_stringpool,
                              options_.name_collapse_exemptions, options_.id_resource_map);
  if (shorten_resource_paths_) {
    return HandleShortenFilePaths(table, options_.shortened_path_map);
  }
  return true;
}

/**
 * Tell the optimizer whether it's needed to dump information for de-obfuscating.
 *
 * There are two conditions need to dump the information for de-obfuscating.
 * * the option of shortening file paths is enabled.
 * * the option of collapsing resource names is enabled.
 * @return true if the information needed for de-obfuscating, otherwise false
 */
bool Obfuscator::IsEnabled() const {
  return shorten_resource_paths_ || collapse_key_stringpool_;
}

}  // namespace aapt
Loading