Added support for rex to optionally compress dex files.

--
MOS_MIGRATED_REVID=135805730
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index ec92b04..8a22927 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -431,16 +431,46 @@
                 resourceApk.getMainDexProguardConfig(),
                 resourceClasses);
 
+    Artifact finalDexes;
+    Artifact finalProguardMap;
+
+    if (ruleContext.getFragment(AndroidConfiguration.class).useRexToCompressDexFiles()
+        || (ruleContext.attributes().get("rewrite_dexes_with_rex", Type.BOOLEAN))) {
+      finalDexes = getDxArtifact(ruleContext, "rexed_dexes.zip");
+      Builder rexActionBuilder = new SpawnAction.Builder();
+      rexActionBuilder
+          .setExecutable(ruleContext.getExecutablePrerequisite("$rex_wrapper", Mode.HOST))
+          .setMnemonic("Rex")
+          .setProgressMessage("Rexing dex files")
+          .addArgument("--dex_input")
+          .addInputArgument(dexingOutput.classesDexZip)
+          .addArgument("--dex_output")
+          .addOutputArgument(finalDexes);
+      if (proguardOutput.getMapping() != null) {
+        finalProguardMap = getDxArtifact(ruleContext, "rexed_proguard.map");
+        rexActionBuilder
+            .addArgument("--proguard_input_map")
+            .addInputArgument(proguardOutput.getMapping())
+            .addArgument("--proguard_output_map")
+            .addOutputArgument(finalProguardMap);
+      } else {
+        finalProguardMap = proguardOutput.getMapping();
+      }
+      ruleContext.registerAction(rexActionBuilder.build(ruleContext));
+    } else {
+      finalDexes = dexingOutput.classesDexZip;
+      finalProguardMap = proguardOutput.getMapping();
+    }
+
     ApkSigningMethod signingMethod =
         ruleContext.getFragment(AndroidConfiguration.class).getApkSigningMethod();
-
     Artifact unsignedApk =
         ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_UNSIGNED_APK);
     Artifact zipAlignedApk =
         ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_APK);
 
     ApkActionsBuilder.create("apk", signingMethod)
-        .setClassesDex(dexingOutput.classesDexZip)
+        .setClassesDex(finalDexes)
         .setResourceApk(resourceApk.getArtifact())
         .setJavaResourceZip(dexingOutput.javaResourceJar)
         .setNativeLibs(nativeLibs)
@@ -675,9 +705,9 @@
         builder, ruleContext, javaCommon, androidCommon, jarToDex);
 
     if (proguardOutput.getMapping() != null) {
-      builder.add(ProguardMappingProvider.class,
-          ProguardMappingProvider.create(
-              proguardOutput.getMapping(), proguardOutput.getProtoMapping()));
+      builder.add(
+          ProguardMappingProvider.class,
+          ProguardMappingProvider.create(finalProguardMap, proguardOutput.getProtoMapping()));
     }
 
     return builder
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
index e718d82..1a4695d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
@@ -376,6 +376,14 @@
         help = "dx flags supported in incremental dexing.")
     public List<String> dexoptsSupportedInIncrementalDexing;
 
+    @Option(
+      name = "experimental_android_rewrite_dexes_with_rex",
+      defaultValue = "false",
+      category = "undocumented",
+      help = "use rex tool to rewrite dex files"
+    )
+    public boolean useRexToCompressDexFiles;
+
     @Option(name = "experimental_allow_android_library_deps_without_srcs",
         defaultValue = "true",
         category = "undocumented",
@@ -498,6 +506,7 @@
   private final ImmutableList<String> dexoptsSupportedInIncrementalDexing;
   private final ImmutableList<String> targetDexoptsThatPreventIncrementalDexing;
   private final boolean desugarJava8;
+  private final boolean useRexToCompressDexFiles;
   private final boolean allowAndroidLibraryDepsWithoutSrcs;
   private final boolean useAndroidResourceShrinking;
   private final boolean useRClassGenerator;
@@ -530,6 +539,7 @@
     this.manifestMerger = options.manifestMerger;
     this.apkSigningMethod = options.apkSigningMethod;
     this.useSingleJarApkBuilder = options.useSingleJarApkBuilder;
+    this.useRexToCompressDexFiles = options.useRexToCompressDexFiles;
   }
 
   public String getCpu() {
@@ -586,6 +596,10 @@
     return desugarJava8;
   }
 
+  public boolean useRexToCompressDexFiles() {
+    return useRexToCompressDexFiles;
+  }
+
   public boolean allowSrcsLessAndroidLibraryDeps() {
     return allowAndroidLibraryDepsWithoutSrcs;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 9ee0dfb..879b8a2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -594,9 +594,10 @@
           <p>This rule currently forces source and class compatibility with Java 6.
           </p>
           <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-          .add(attr("srcs", LABEL_LIST)
-              .direct_compile_time_input()
-              .allowedFileTypes(JavaSemantics.JAVA_SOURCE, JavaSemantics.SOURCE_JAR))
+          .add(
+              attr("srcs", LABEL_LIST)
+                  .direct_compile_time_input()
+                  .allowedFileTypes(JavaSemantics.JAVA_SOURCE, JavaSemantics.SOURCE_JAR))
           /* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(deps) -->
           The list of other libraries to be linked in to the binary target.
           Permitted library types are: <code>android_library</code>,
@@ -604,38 +605,77 @@
           <code>cc_library</code> wrapping or producing <code>.so</code> native libraries for the
           Android target platform.
           <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-          .override(builder.copy("deps")
-              .cfg(ANDROID_SPLIT_TRANSITION)
-              .allowedRuleClasses(ALLOWED_DEPENDENCIES)
-              .allowedFileTypes()
-              .aspect(androidNeverlinkAspect)
-              .aspect(dexArchiveAspect, DexArchiveAspect.PARAM_EXTRACTOR)
-              .aspect(jackAspect))
+          .override(
+              builder
+                  .copy("deps")
+                  .cfg(ANDROID_SPLIT_TRANSITION)
+                  .allowedRuleClasses(ALLOWED_DEPENDENCIES)
+                  .allowedFileTypes()
+                  .aspect(androidNeverlinkAspect)
+                  .aspect(dexArchiveAspect, DexArchiveAspect.PARAM_EXTRACTOR)
+                  .aspect(jackAspect))
           // Proguard rule specifying master list of classes to keep during legacy multidexing.
-          .add(attr("$build_incremental_dexmanifest", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel(BUILD_INCREMENTAL_DEXMANIFEST_LABEL)))
-          .add(attr("$stubify_manifest", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel(STUBIFY_MANIFEST_LABEL)))
-          .add(attr("$shuffle_jars", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel("//tools/android:shuffle_jars")))
-          .add(attr("$dexbuilder", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel("//tools/android:dexbuilder")))
-          .add(attr("$dexmerger", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel("//tools/android:dexmerger")))
-          .add(attr("$merge_dexzips", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel("//tools/android:merge_dexzips")))
-          .add(attr("$incremental_install", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel(INCREMENTAL_INSTALL_LABEL)))
-          .add(attr("$build_split_manifest", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel(BUILD_SPLIT_MANIFEST_LABEL)))
-          .add(attr("$strip_resources", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel(STRIP_RESOURCES_LABEL)))
-          .add(attr("$incremental_stub_application", LABEL)
-              .value(env.getToolsLabel(DEFAULT_INCREMENTAL_STUB_APPLICATION)))
-          .add(attr("$incremental_split_stub_application", LABEL)
-              .value(env.getToolsLabel(DEFAULT_INCREMENTAL_SPLIT_STUB_APPLICATION)))
-          .add(attr("$desugar", LABEL).cfg(HOST).exec()
-              .value(env.getToolsLabel("//tools/android:desugar_java8")))
+          .add(
+              attr("$build_incremental_dexmanifest", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel(BUILD_INCREMENTAL_DEXMANIFEST_LABEL)))
+          .add(
+              attr("$stubify_manifest", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel(STUBIFY_MANIFEST_LABEL)))
+          .add(
+              attr("$shuffle_jars", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:shuffle_jars")))
+          .add(
+              attr("$dexbuilder", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:dexbuilder")))
+          .add(
+              attr("$dexmerger", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:dexmerger")))
+          .add(
+              attr("$merge_dexzips", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:merge_dexzips")))
+          .add(
+              attr("$incremental_install", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel(INCREMENTAL_INSTALL_LABEL)))
+          .add(
+              attr("$build_split_manifest", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel(BUILD_SPLIT_MANIFEST_LABEL)))
+          .add(
+              attr("$strip_resources", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel(STRIP_RESOURCES_LABEL)))
+          .add(
+              attr("$incremental_stub_application", LABEL)
+                  .value(env.getToolsLabel(DEFAULT_INCREMENTAL_STUB_APPLICATION)))
+          .add(
+              attr("$incremental_split_stub_application", LABEL)
+                  .value(env.getToolsLabel(DEFAULT_INCREMENTAL_SPLIT_STUB_APPLICATION)))
+          .add(
+              attr("$desugar", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:desugar_java8")))
+          .add(
+              attr("$rex_wrapper", LABEL)
+                  .cfg(HOST)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:rex_wrapper")))
           /* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(dexopts) -->
           Additional command-line flags for the dx tool when generating classes.dex.
           Subject to <a href="${link make-variables}">"Make variable"</a> substitution and
@@ -661,9 +701,10 @@
           android_test rules with binary_under_test set. We are working on addressing these
           shortcomings so please check with us if you run into these limitations.
           <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-          .add(attr("incremental_dexing", TRISTATE)
-              // Read by DexArchiveAspect's attribute extractor
-              .nonconfigurable("AspectParameters don't support configurations."))
+          .add(
+              attr("incremental_dexing", TRISTATE)
+                  // Read by DexArchiveAspect's attribute extractor
+                  .nonconfigurable("AspectParameters don't support configurations."))
           /* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(multidex) -->
           Whether to split code into multiple dex files.<br/>
           Possible values:
@@ -682,9 +723,10 @@
               index limit.</li>
           </ul>
           <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-          .add(attr("multidex", STRING)
-              .allowedValues(new AllowedValueSet(MultidexMode.getValidValues()))
-              .value(MultidexMode.OFF.getAttributeValue()))
+          .add(
+              attr("multidex", STRING)
+                  .allowedValues(new AllowedValueSet(MultidexMode.getValidValues()))
+                  .value(MultidexMode.OFF.getAttributeValue()))
           /* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(main_dex_list_opts) -->
           Command line options to pass to the main dex list builder.
           Use this option to affect the classes included in the main dex list.
@@ -694,13 +736,13 @@
 
           A text file contains a list of class file names. Classes defined by those class files are
           put in the primary classes.dex. e.g.:<pre class="code">
-android/support/multidex/MultiDex$V19.class
-android/support/multidex/MultiDex.class
-android/support/multidex/MultiDexApplication.class
-com/google/common/base/Objects.class
-          </pre>
-          Must be used with <code>multidex="manual_main_dex"</code>.
-          <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+          android/support/multidex/MultiDex$V19.class
+          android/support/multidex/MultiDex.class
+          android/support/multidex/MultiDexApplication.class
+          com/google/common/base/Objects.class
+                    </pre>
+                    Must be used with <code>multidex="manual_main_dex"</code>.
+                    <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
           .add(attr("main_dex_list", LABEL).legacyAllowAnyFileType())
           /* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(main_dex_proguard_specs) -->
           Files to be used as the Proguard specifications to determine classes that must be kept in
@@ -722,8 +764,10 @@
           specification should contain neither <code>-dontobfuscate</code> nor
           <code>-printmapping</code>.</em></p>
           <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-          .add(attr("proguard_generate_mapping", BOOLEAN).value(false)
-              .nonconfigurable("value is referenced in an ImplicitOutputsFunction"))
+          .add(
+              attr("proguard_generate_mapping", BOOLEAN)
+                  .value(false)
+                  .nonconfigurable("value is referenced in an ImplicitOutputsFunction"))
           /* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(proguard_apply_mapping) -->
           File to be used as a mapping for proguard.
           A mapping file generated by <code>proguard_generate_mapping</code> to be
@@ -731,10 +775,12 @@
           <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
           .add(attr("proguard_apply_mapping", LABEL).legacyAllowAnyFileType())
           // TODO(mstaib): Remove this attribute and the matching flag after some cleanup of users
-          .add(attr("legacy_native_support", TRISTATE)
-              .value(TriState.AUTO)
-              .undocumented("No-op, soon to be removed"))
+          .add(
+              attr("legacy_native_support", TRISTATE)
+                  .value(TriState.AUTO)
+                  .undocumented("No-op, soon to be removed"))
           .add(attr(":extra_proguard_specs", LABEL_LIST).value(JavaSemantics.EXTRA_PROGUARD_SPECS))
+          .add(attr("rewrite_dexes_with_rex", BOOLEAN).value(false).undocumented("experimental"))
           .advertiseProvider(JavaCompilationArgsProvider.class)
           .build();
       }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index b741e07..ff558d95 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -174,6 +174,7 @@
         .add("sh_binary(name = 'resource_parser', srcs = ['empty.sh'])")
         .add("sh_binary(name = 'resource_shrinker', srcs = ['empty.sh'])")
         .add("sh_binary(name = 'resource_validator', srcs = ['empty.sh'])")
+        .add("sh_binary(name = 'rex_wrapper', srcs = ['empty.sh'])")
         .add("android_library(name = 'incremental_stub_application')")
         .add("android_library(name = 'incremental_split_stub_application')")
         .add("sh_binary(name = 'stubify_manifest', srcs = ['empty.sh'])")
diff --git a/tools/android/BUILD b/tools/android/BUILD
index 4e64147..b8406ff 100644
--- a/tools/android/BUILD
+++ b/tools/android/BUILD
@@ -207,6 +207,11 @@
     ],
 )
 
+sh_binary(
+    name = "rex_wrapper",
+    srcs = ["fail.sh"],
+)
+
 # If needed, this file can be regenerated by (validity is 30 * 365 days):
 # keytool -genkeypair \
 #    -alias androiddebugkey \