Resource Path Obfuscation

This CL allows aapt2 to obfuscate resource paths within the output apk
and move resources to shorter obfuscated paths. This reduces apk size
when there is a large number of resources since the path metadata exists
in 4 places in the apk.

This CL adds two arguments to aapt2, one to enable resource path
obfuscation and one to point to a path to output the path map to (for
later debugging).

Test: make aapt2_tests
Bug: b/75965637

Change-Id: I9cacafe1d17800d673566b2d61b0b88f3fb8d60c
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 328b0be..2e6af18 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -41,6 +41,7 @@
 #include "optimize/MultiApkGenerator.h"
 #include "optimize/ResourceDeduper.h"
 #include "optimize/ResourceFilter.h"
+#include "optimize/ResourcePathShortener.h"
 #include "optimize/VersionCollapser.h"
 #include "split/TableSplitter.h"
 #include "util/Files.h"
@@ -52,6 +53,7 @@
 using ::android::ResTable_config;
 using ::android::StringPiece;
 using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFile;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
 
@@ -143,6 +145,21 @@
       return 1;
     }
 
+    if (options_.shorten_resource_paths) {
+      ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map);
+      if (!shortener.Consume(context_, apk->GetResourceTable())) {
+        context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths");
+        return 1;
+      }
+      if (options_.shortened_paths_map_path
+          && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
+                                      options_.shortened_paths_map_path.value())) {
+        context_->GetDiagnostics()->Error(DiagMessage()
+                                          << "failed to write shortened resource paths to file");
+        return 1;
+      }
+    }
+
     // Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
     // equal to the minSdk.
     options_.split_constraints =
@@ -264,6 +281,15 @@
                                         ArchiveEntry::kAlign, writer);
   }
 
+  bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
+                               const std::string &file_path) {
+    std::stringstream ss;
+    for (auto it = path_map.cbegin(); it != path_map.cend(); ++it) {
+      ss << it->first << " -> " << it->second << "\n";
+    }
+    return WriteStringToFile(ss.str(), file_path);
+  }
+
   OptimizeOptions options_;
   OptimizeContext* context_;
 };