Remove support for `multidex=off`

PiperOrigin-RevId: 453318216
Change-Id: I6270f61ea08e7cd4b2712ead2f86a34a8330b40e
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 158497e..5131c58 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
@@ -178,12 +178,6 @@
       ruleContext.throwWithAttributeError("shrink_resources", "This attribute is not supported");
     }
 
-    if (Allowlist.hasAllowlist(ruleContext, "android_multidex_off_allowlist")
-        && !Allowlist.isAvailable(ruleContext, "android_multidex_off_allowlist")
-        && AndroidBinary.getMultidexMode(ruleContext) == MultidexMode.OFF) {
-      ruleContext.attributeError("multidex", "Multidex must be enabled");
-    }
-
     if (ruleContext.attributes().isAttributeValueExplicitlySpecified("min_sdk_version")
         && Allowlist.hasAllowlist(ruleContext, "allow_min_sdk_version")
         && !Allowlist.isAvailable(ruleContext, "allow_min_sdk_version")) {
@@ -191,13 +185,6 @@
           "min_sdk_version", "Target is not permitted to set min_sdk_version");
     }
 
-    if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()
-        && getMultidexMode(ruleContext) == MultidexMode.OFF) {
-      // Multidex is required so we can include legacy libs as a separate .dex file.
-      ruleContext.throwWithAttributeError(
-          "multidex", "Support for Java 8 libraries on legacy devices requires multidex");
-    }
-
     if (ruleContext.getFragment(JavaConfiguration.class).enforceProguardFileExtension()
         && ruleContext.attributes().has(ProguardHelper.PROGUARD_SPECS)) {
       List<PathFragment> pathsWithUnexpectedExtension =
@@ -1294,10 +1281,6 @@
 
     int dexShards = ruleContext.attributes().get("dex_shards", Type.INTEGER).toIntUnchecked();
     if (dexShards > 1) {
-      if (multidexMode == MultidexMode.OFF) {
-        ruleContext.throwWithRuleError(".dex sharding is only available in multidex mode");
-      }
-
       if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
         ruleContext.throwWithRuleError(".dex sharding is not available in manual multidex mode");
       }
@@ -1320,11 +1303,90 @@
         AndroidCommon.getAndroidConfig(ruleContext).getJavaResourcesFromOptimizedJar()
             ? proguardedJar
             : binaryJar;
-    if (multidexMode == MultidexMode.OFF) {
-      // Single dex mode: generate classes.dex directly from the input jar.
-      Artifact classesDex;
+
+    // Multidex mode: generate classes.dex.zip, where the zip contains [classes.dex,
+    // classes2.dex, ... classesN.dex].
+
+    if (multidexMode == MultidexMode.LEGACY) {
+      // For legacy multidex, we need to generate a list for the dexer's --main-dex-list flag.
+      mainDexList =
+          createMainDexListAction(
+              ruleContext, androidSemantics, proguardedJar, mainDexProguardSpec, proguardOutputMap);
+    } else if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
+      mainDexList =
+          transformDexListThroughProguardMapAction(ruleContext, proguardOutputMap, mainDexList);
+    }
+
+    Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip");
+    if (dexShards > 1) {
+      ImmutableList<Artifact> shards =
+          makeShardArtifacts(ruleContext, dexShards, usesDexArchives ? ".jar.dex.zip" : ".jar");
+
+      Artifact javaResourceJar =
+          createShuffleJarActions(
+              ruleContext,
+              usesDexArchives,
+              singleJarToDex,
+              shards,
+              common,
+              inclusionFilterJar,
+              dexopts,
+              minSdkVersion,
+              androidSemantics,
+              attributes,
+              derivedJarFunction,
+              mainDexList);
+
+      ImmutableList.Builder<Artifact> shardDexesBuilder = ImmutableList.builder();
+      for (int i = 1; i <= dexShards; i++) {
+        Artifact shard = shards.get(i - 1);
+        Artifact shardDex = getDxArtifact(ruleContext, "shard" + i + ".dex.zip");
+        shardDexesBuilder.add(shardDex);
+        if (usesDexArchives) {
+          // If there's a main dex list then the first shard contains exactly those files.
+          // To work with devices that lack native multi-dex support we need to make sure that
+          // the main dex list becomes one dex file if at all possible.
+          // Note shard here (mostly) contains of .class.dex files from shuffled dex archives,
+          // instead of being a conventional Jar file with .class files.
+          createDexMergerAction(
+              ruleContext,
+              mainDexList != null && i == 1 ? "minimal" : "best_effort",
+              ImmutableList.of(shard),
+              shardDex,
+              /*mainDexList=*/ null,
+              dexopts);
+        } else {
+          AndroidCommon.createDexAction(
+              ruleContext, shard, shardDex, dexopts, minSdkVersion, /*mainDexList=*/ null);
+        }
+      }
+      ImmutableList<Artifact> shardDexes = shardDexesBuilder.build();
+
+      CommandLine mergeCommandLine =
+          CustomCommandLine.builder()
+              .addExecPaths(VectorArg.addBefore("--input_zip").each(shardDexes))
+              .addExecPath("--output_zip", classesDex)
+              .build();
+      ruleContext.registerAction(
+          createSpawnActionBuilder(ruleContext)
+              .useDefaultShellEnvironment()
+              .setMnemonic("MergeDexZips")
+              .setProgressMessage("Merging dex shards for %s", ruleContext.getLabel())
+              .setExecutable(ruleContext.getExecutablePrerequisite("$merge_dexzips"))
+              .addInputs(shardDexes)
+              .addOutput(classesDex)
+              .addCommandLine(mergeCommandLine)
+              .build(ruleContext));
       if (usesDexArchives) {
-        classesDex = getDxArtifact(ruleContext, "classes.dex.zip");
+        // Using the deploy jar for java resources gives better "bazel mobile-install" performance
+        // with incremental dexing b/c bazel can create the "incremental" and "split resource"
+        // APKs earlier (b/c these APKs don't depend on code being dexed here).  This is also done
+        // for other multidex modes.
+        javaResourceJar = javaResourceSourceJar;
+      }
+      return new DexingOutput(classesDex, javaResourceJar, shardDexes);
+    } else {
+      if (usesDexArchives) {
         createIncrementalDexingActions(
             ruleContext,
             singleJarToDex,
@@ -1335,156 +1397,30 @@
             androidSemantics,
             attributes,
             derivedJarFunction,
-            /*multidex=*/ false,
-            /*mainDexList=*/ null,
+            mainDexList,
             classesDex);
       } else {
-        // By *not* writing a zip we get dx to drop resources on the floor.
-        classesDex = getDxArtifact(ruleContext, "classes.dex");
+        // Because the dexer also places resources into this zip, we also need to create a cleanup
+        // action that removes all non-.dex files before staging for apk building.
+        // Create an artifact for the intermediate zip output that includes non-.dex files.
+        Artifact classesDexIntermediate =
+            AndroidBinary.getDxArtifact(ruleContext, "intermediate_classes.dex.zip");
+        // Have the dexer generate the intermediate file and the "cleaner" action consume this to
+        // generate the final archive with only .dex files.
         AndroidCommon.createDexAction(
             ruleContext,
             proguardedJar,
-            classesDex,
+            classesDexIntermediate,
             dexopts,
             minSdkVersion,
-            /*multidex=*/ false,
-            /*mainDexList=*/ null);
+            mainDexList);
+        createCleanDexZipAction(ruleContext, classesDexIntermediate, classesDex);
       }
       return new DexingOutput(classesDex, javaResourceSourceJar, ImmutableList.of(classesDex));
-    } else {
-      // Multidex mode: generate classes.dex.zip, where the zip contains [classes.dex,
-      // classes2.dex, ... classesN.dex].
-
-      if (multidexMode == MultidexMode.LEGACY) {
-        // For legacy multidex, we need to generate a list for the dexer's --main-dex-list flag.
-        mainDexList =
-            createMainDexListAction(
-                ruleContext,
-                androidSemantics,
-                proguardedJar,
-                mainDexProguardSpec,
-                proguardOutputMap);
-      } else if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
-        mainDexList =
-            transformDexListThroughProguardMapAction(ruleContext, proguardOutputMap, mainDexList);
-      }
-
-      Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip");
-      if (dexShards > 1) {
-        ImmutableList<Artifact> shards =
-            makeShardArtifacts(ruleContext, dexShards, usesDexArchives ? ".jar.dex.zip" : ".jar");
-
-        Artifact javaResourceJar =
-            createShuffleJarActions(
-                ruleContext,
-                usesDexArchives,
-                singleJarToDex,
-                shards,
-                common,
-                inclusionFilterJar,
-                dexopts,
-                minSdkVersion,
-                androidSemantics,
-                attributes,
-                derivedJarFunction,
-                mainDexList);
-
-        ImmutableList.Builder<Artifact> shardDexesBuilder = ImmutableList.builder();
-        for (int i = 1; i <= dexShards; i++) {
-          Artifact shard = shards.get(i - 1);
-          Artifact shardDex = getDxArtifact(ruleContext, "shard" + i + ".dex.zip");
-          shardDexesBuilder.add(shardDex);
-          if (usesDexArchives) {
-            // If there's a main dex list then the first shard contains exactly those files.
-            // To work with devices that lack native multi-dex support we need to make sure that
-            // the main dex list becomes one dex file if at all possible.
-            // Note shard here (mostly) contains of .class.dex files from shuffled dex archives,
-            // instead of being a conventional Jar file with .class files.
-            createDexMergerAction(
-                ruleContext,
-                mainDexList != null && i == 1 ? "minimal" : "best_effort",
-                ImmutableList.of(shard),
-                shardDex,
-                /*mainDexList=*/ null,
-                dexopts);
-          } else {
-            AndroidCommon.createDexAction(
-                ruleContext,
-                shard,
-                shardDex,
-                dexopts,
-                minSdkVersion,
-                /*multidex=*/ true,
-                /*mainDexList=*/ null);
-          }
-        }
-        ImmutableList<Artifact> shardDexes = shardDexesBuilder.build();
-
-        CommandLine mergeCommandLine =
-            CustomCommandLine.builder()
-                .addExecPaths(VectorArg.addBefore("--input_zip").each(shardDexes))
-                .addExecPath("--output_zip", classesDex)
-                .build();
-        ruleContext.registerAction(
-            createSpawnActionBuilder(ruleContext)
-                .useDefaultShellEnvironment()
-                .setMnemonic("MergeDexZips")
-                .setProgressMessage("Merging dex shards for %s", ruleContext.getLabel())
-                .setExecutable(ruleContext.getExecutablePrerequisite("$merge_dexzips"))
-                .addInputs(shardDexes)
-                .addOutput(classesDex)
-                .addCommandLine(mergeCommandLine)
-                .build(ruleContext));
-        if (usesDexArchives) {
-          // Using the deploy jar for java resources gives better "bazel mobile-install" performance
-          // with incremental dexing b/c bazel can create the "incremental" and "split resource"
-          // APKs earlier (b/c these APKs don't depend on code being dexed here).  This is also done
-          // for other multidex modes.
-          javaResourceJar = javaResourceSourceJar;
-        }
-        return new DexingOutput(classesDex, javaResourceJar, shardDexes);
-      } else {
-        if (usesDexArchives) {
-          createIncrementalDexingActions(
-              ruleContext,
-              singleJarToDex,
-              common,
-              inclusionFilterJar,
-              dexopts,
-              minSdkVersion,
-              androidSemantics,
-              attributes,
-              derivedJarFunction,
-              /*multidex=*/ true,
-              mainDexList,
-              classesDex);
-        } else {
-          // Because the dexer also places resources into this zip, we also need to create a cleanup
-          // action that removes all non-.dex files before staging for apk building.
-          // Create an artifact for the intermediate zip output that includes non-.dex files.
-          Artifact classesDexIntermediate =
-              AndroidBinary.getDxArtifact(ruleContext, "intermediate_classes.dex.zip");
-          // Have the dexer generate the intermediate file and the "cleaner" action consume this to
-          // generate the final archive with only .dex files.
-          AndroidCommon.createDexAction(
-              ruleContext,
-              proguardedJar,
-              classesDexIntermediate,
-              dexopts,
-              minSdkVersion,
-              /*multidex=*/ true,
-              mainDexList);
-          createCleanDexZipAction(ruleContext, classesDexIntermediate, classesDex);
-        }
-        return new DexingOutput(classesDex, javaResourceSourceJar, ImmutableList.of(classesDex));
-      }
     }
   }
 
-  /**
-   * Helper that sets up dexbuilder/dexmerger actions when dex_shards attribute is not set, for use
-   * with or without multidex.
-   */
+  /** Helper that sets up dexbuilder/dexmerger actions when dex_shards attribute is not set. */
   private static void createIncrementalDexingActions(
       RuleContext ruleContext,
       @Nullable Artifact proguardedJar,
@@ -1495,13 +1431,11 @@
       AndroidSemantics androidSemantics,
       JavaTargetAttributes attributes,
       Function<Artifact, Artifact> derivedJarFunction,
-      boolean multidex,
       @Nullable Artifact mainDexList,
       Artifact classesDex)
       throws InterruptedException, RuleErrorException {
     ImmutableList<Artifact> dexArchives;
     if (proguardedJar == null
-        && (multidex || inclusionFilterJar == null)
         && AndroidCommon.getAndroidConfig(ruleContext).incrementalDexingUseDexSharder()) {
       dexArchives =
           toDexedClasspath(
@@ -1555,10 +1489,9 @@
       }
     }
 
-    if (dexArchives.size() == 1 || !multidex) {
+    if (dexArchives.size() == 1) {
       checkState(inclusionFilterJar == null);
-      createDexMergerAction(
-          ruleContext, multidex ? "minimal" : "off", dexArchives, classesDex, mainDexList, dexopts);
+      createDexMergerAction(ruleContext, "minimal", dexArchives, classesDex, mainDexList, dexopts);
     } else {
       SpecialArtifact shardsToMerge =
           createSharderAction(ruleContext, dexArchives, mainDexList, dexopts, inclusionFilterJar);
@@ -2220,12 +2153,8 @@
 
   /** Returns the multidex mode to apply to this target. */
   public static MultidexMode getMultidexMode(RuleContext ruleContext) {
-    if (ruleContext.getRule().isAttrDefined("multidex", Type.STRING)) {
       return Preconditions.checkNotNull(
           MultidexMode.fromValue(ruleContext.attributes().get("multidex", Type.STRING)));
-    } else {
-      return MultidexMode.OFF;
-    }
   }
 
   private static int getMinSdkVersion(RuleContext ruleContext) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
index 42cb097..5d38196 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
@@ -367,9 +367,9 @@
     Artifact stubDex =
         getMobileInstallArtifact(
             ruleContext,
-            split ? "split_stub_application/classes.dex" : "stub_application/classes.dex");
+            split ? "split_stub_application/classes.dex.zip" : "stub_application/classes.dex.zip");
     AndroidCommon.createDexAction(
-        ruleContext, stubDeployJar, stubDex, ImmutableList.<String>of(), 0, false, null);
+        ruleContext, stubDeployJar, stubDex, ImmutableList.<String>of(), 0, null);
 
     return stubDex;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
index 28c705c..420c070 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
@@ -188,28 +188,17 @@
       Artifact classesDex,
       List<String> dexOptions,
       int minSdkVersion,
-      boolean multidex,
       Artifact mainDexList) {
     CustomCommandLine.Builder commandLine = CustomCommandLine.builder();
     commandLine.add("--dex");
 
-    // Multithreaded dex does not work when using --multi-dex.
-    if (!multidex) {
-      // Multithreaded dex tends to run faster, but only up to about 5 threads (at which point the
-      // law of diminishing returns kicks in). This was determined experimentally, with 5-thread dex
-      // performing about 25% faster than 1-thread dex.
-      commandLine.add("--num-threads=" + DEX_THREADS);
-    }
-
     commandLine.addAll(dexOptions);
     if (minSdkVersion > 0) {
       commandLine.add("--min_sdk_version", Integer.toString(minSdkVersion));
     }
-    if (multidex) {
-      commandLine.add("--multi-dex");
-      if (mainDexList != null) {
-        commandLine.addPrefixedExecPath("--main-dex-list=", mainDexList);
-      }
+    commandLine.add("--multi-dex");
+    if (mainDexList != null) {
+      commandLine.addPrefixedExecPath("--main-dex-list=", mainDexList);
     }
     commandLine.addPrefixedExecPath("--output=", classesDex);
     commandLine.addExecPath(jarToDex);
@@ -687,7 +676,7 @@
 
     filesToBuild = filesBuilder.build();
 
-    if ( attributes.hasSources() && jar != null) {
+    if (attributes.hasSources() && jar != null) {
       iJar = helper.createCompileTimeJarAction(jar, javaArtifactsBuilder);
     }
 
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 880d6a1..fca1830 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
@@ -741,7 +741,7 @@
           .add(
               attr("multidex", STRING)
                   .allowedValues(new AllowedValueSet(MultidexMode.getValidValues()))
-                  .value(MultidexMode.OFF.getAttributeValue()))
+                  .value(MultidexMode.NATIVE.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.
@@ -914,9 +914,7 @@
     // Build dexes with multidex and implement support at the application level.
     LEGACY,
     // Build dexes with multidex, main dex list needs to be manually specified.
-    MANUAL_MAIN_DEX,
-    // Build all dex code into a single classes.dex file.
-    OFF;
+    MANUAL_MAIN_DEX;
 
     /** Returns the attribute value that specifies this mode. */
     public String getAttributeValue() {
@@ -928,7 +926,7 @@
      * (possibly) multiple files.
      */
     public String getOutputDexFilename() {
-      return this == OFF ? "classes.dex" : "classes.dex.zip";
+      return "classes.dex.zip";
     }
 
     /** Converts an attribute value to a corresponding mode. Returns null on no match. */
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMultidexTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMultidexTest.java
index e0ff970..bef41ab 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMultidexTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMultidexTest.java
@@ -57,7 +57,7 @@
         "    srcs = ['a.java'],",
         "    manifest = 'AndroidManifest.xml',",
         "    resource_files = glob(['res/**']),",
-        "    multidex = 'off')");
+        ")");
     internalTestNonMultidexBuildStructure("//java/foo:nomultidex");
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
index 0983bfb..f0f6b3c 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
@@ -1093,7 +1093,8 @@
 
     ConfiguredTarget topTarget = getConfiguredTarget("//java/com/google/android:top");
     assertNoEvents();
-    Action dexAction = getGeneratingAction(getBinArtifact("_dx/top/classes.dex", topTarget));
+    Action dexAction =
+        getGeneratingAction(getBinArtifact("_dx/top/intermediate_classes.dex.zip", topTarget));
     assertThat(
             Iterables.filter(
                 ActionsTestUtil.baseArtifactNames(dexAction.getInputs()),
@@ -1227,37 +1228,6 @@
   }
 
   @Test
-  public void testIncrementalDexingAfterProguard_autoShardedMonodex() throws Exception {
-    useConfiguration("--experimental_incremental_dexing_after_proguard=3");
-    // Use "legacy" multidex mode so we get a main dex list file and can test that it's passed to
-    // the splitter action (similar to _withDexShards below), unlike without the dex splitter where
-    // the main dex list goes to the merging action.
-    scratch.file(
-        "java/com/google/android/BUILD",
-        "android_binary(",
-        "  name = 'top',",
-        "  srcs = ['foo.java', 'bar.srcjar'],",
-        "  manifest = 'AndroidManifest.xml',",
-        "  incremental_dexing = 1,",
-        "  multidex = 'off',",
-        "  proguard_specs = ['b.pro'],",
-        ")");
-
-    ConfiguredTarget topTarget = getConfiguredTarget("//java/com/google/android:top");
-    assertNoEvents();
-    SpawnAction mergeAction =
-        getGeneratingSpawnAction(getBinArtifact("_dx/top/classes.dex.zip", topTarget));
-    assertThat(mergeAction.getArguments()).doesNotContain("--main-dex-list");
-    assertThat(ActionsTestUtil.baseArtifactNames(getNonToolInputs(mergeAction)))
-        .containsExactly("shard1.jar.dex.zip", "shard2.jar.dex.zip", "shard3.jar.dex.zip");
-    SpawnAction shuffleAction =
-        getGeneratingSpawnAction(getBinArtifact("_dx/top/shard1.jar", topTarget));
-    assertThat(shuffleAction.getArguments()).doesNotContain("--main-dex-list");
-    assertThat(ActionsTestUtil.baseArtifactNames(getNonToolInputs(shuffleAction)))
-        .containsExactly("top_proguard.jar");
-  }
-
-  @Test
   public void testV1SigningMethod() throws Exception {
     actualSignerToolTests("v1", "true", "false", null);
   }
@@ -1804,16 +1774,17 @@
         "    manifest = 'AndroidManifest.xml')");
 
     // Include arguments that are always included.
-    List<String> fixedArgs = ImmutableList.of("--num-threads=5");
+    ImmutableList<String> fixedArgs = ImmutableList.of("--multi-dex");
     expectedArgs =
-        new ImmutableList.Builder<String>().addAll(fixedArgs).addAll(expectedArgs).build();
+        new ImmutableList.Builder<String>().addAll(expectedArgs).addAll(fixedArgs).build();
 
     // Ensure that the args that immediately follow "--dex" match the expectation.
     ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android:b");
     List<String> args =
         getGeneratingSpawnActionArgs(
             ActionsTestUtil.getFirstArtifactEndingWith(
-                actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)), "classes.dex"));
+                actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)),
+                "intermediate_classes.dex.zip"));
     int start = args.indexOf("--dex") + 1;
     assertThat(start).isNotEqualTo(0);
     int end = Math.min(args.size(), start + expectedArgs.size());
@@ -2450,20 +2421,6 @@
   }
 
   @Test
-  public void testDexShardingNeedsMultidex() throws Exception {
-    scratch.file(
-        "java/a/BUILD",
-        "android_binary(",
-        "    name='a',",
-        "    srcs=['A.java'],",
-        "    dex_shards=2,",
-        "    manifest='AndroidManifest.xml')");
-    reporter.removeHandler(failFastHandler);
-    getConfiguredTarget("//java/a:a");
-    assertContainsEvent(".dex sharding is only available in multidex mode");
-  }
-
-  @Test
   public void testDexShardingDoesNotWorkWithManualMultidex() throws Exception {
     scratch.file(
         "java/a/BUILD",
@@ -3346,20 +3303,6 @@
   }
 
   @Test
-  public void testDesugarJava8Libs_noMultidexError() throws Exception {
-    useConfiguration("--experimental_desugar_java8_libs");
-    checkError(
-        /*packageName=*/ "java/com/google/android",
-        /*ruleName=*/ "foo",
-        /*expectedErrorMessage=*/ "multidex",
-        "android_binary(",
-        "  name = 'foo',",
-        "  srcs = ['foo.java'],",
-        "  manifest = 'AndroidManifest.xml',",
-        ")");
-  }
-
-  @Test
   public void testApplyProguardMapping() throws Exception {
     scratch.file(
         "java/com/google/android/BUILD",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java
index 23bc91b..cc41085 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java
@@ -416,7 +416,9 @@
     Action dexAction =
         actionsTestUtil()
             .getActionForArtifactEndingWith(
-                actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)), "classes.dex");
+                actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)), "classes.dex.zip");
+    dexAction =
+        actionsTestUtil().getActionForArtifactEndingWith(dexAction.getInputs(), "classes.dex.zip");
     Artifact trimmedJar = getFirstArtifactEndingWith(dexAction.getInputs(), artifact);
     assertWithMessage("Dex should be built from jar trimmed with Proguard.")
         .that(trimmedJar)
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidCommonTest.java
index 170bfd0..478aa20 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidCommonTest.java
@@ -116,7 +116,7 @@
   @Test
   public void testMultidexModeEnum() throws Exception {
     assertThat(MultidexMode.getValidValues())
-        .containsExactly("native", "legacy", "manual_main_dex", "off");
+        .containsExactly("native", "legacy", "manual_main_dex");
     assertThat(MultidexMode.fromValue("native")).isSameInstanceAs(MultidexMode.NATIVE);
     assertThat(MultidexMode.NATIVE.getAttributeValue()).isEqualTo("native");
     assertThat(MultidexMode.fromValue("legacy")).isSameInstanceAs(MultidexMode.LEGACY);
@@ -124,14 +124,11 @@
     assertThat(MultidexMode.fromValue("manual_main_dex"))
         .isSameInstanceAs(MultidexMode.MANUAL_MAIN_DEX);
     assertThat(MultidexMode.MANUAL_MAIN_DEX.getAttributeValue()).isEqualTo("manual_main_dex");
-    assertThat(MultidexMode.fromValue("off")).isSameInstanceAs(MultidexMode.OFF);
-    assertThat(MultidexMode.OFF.getAttributeValue()).isEqualTo("off");
   }
 
   /** Tests that each multidex mode produces the expected output dex classes file name. */
   @Test
   public void testOutputDexforMultidexModes() throws Exception {
-    assertThat(MultidexMode.OFF.getOutputDexFilename()).isEqualTo("classes.dex");
     assertThat(MultidexMode.LEGACY.getOutputDexFilename()).isEqualTo("classes.dex.zip");
     assertThat(MultidexMode.NATIVE.getOutputDexFilename()).isEqualTo("classes.dex.zip");
   }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidMultidexBaseTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidMultidexBaseTest.java
index 6b7615b..4463af5 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidMultidexBaseTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidMultidexBaseTest.java
@@ -102,9 +102,7 @@
                 dexMergerInput.getExecPathString(),
                 "--output",
                 finalDexOutput.getExecPathString());
-    if (multidexMode != MultidexMode.OFF) {
-      argsBuilder.add("--multidex=minimal");
-    }
+    argsBuilder.add("--multidex=minimal");
     if (multidexMode == MultidexMode.LEGACY || multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
       argsBuilder.add("--main-dex-list", mainDexList.getExecPathString());
     }
@@ -115,7 +113,7 @@
 
   /**
    * Internal helper method: given an android_binary rule label, check that the dex merger runs is
-   * invoked with {@code --multidex=off}.
+   * invoked with {@code --multidex=minimal}.
    */
   protected void internalTestNonMultidexBuildStructure(String ruleLabel) throws Exception {
     ConfiguredTarget binary = getConfiguredTarget(ruleLabel);
@@ -130,7 +128,7 @@
             dexInput.getExecPathString(),
             "--output",
             dexOutput.getExecPathString(),
-            "--multidex=off")
+            "--multidex=minimal")
         .inOrder();
   }
 }