Use a reasonable set of spawn strategies by default.

This is only enabled when using --incompatible_list_based_execution_strategy_selection.

Note that this does *not* yet disable the built-in fallback behavior in the spawn strategies, but that's not required for this feature to work. That'll just be a nice addition to make the code clearer and allows us to remove the fallback code from all strategies.

RELNOTES: When using --incompatible_list_based_execution_strategy_selection, Bazel will use remote execution by default (if you specify --remote_executor), otherwise persistent workers (if the action supports it), otherwise sandboxed local execution (if the action and platform supports it) and at last unsandboxed local execution. The flags --spawn_strategy and --strategy continue to work as before - this only sets new defaults for the case where you don't specify these flags.
PiperOrigin-RevId: 235932751
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index b36522d..f4d88c0 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -749,6 +749,7 @@
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
+        "//src/main/java/com/google/devtools/build/lib/remote",
         "//src/main/java/com/google/devtools/build/lib/rules/apple",
         "//src/main/java/com/google/devtools/build/lib/rules/apple/cpp",
         "//src/main/java/com/google/devtools/build/lib/rules/apple/swift",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelStrategyModule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelStrategyModule.java
index 6b3712c..90cc493 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelStrategyModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelStrategyModule.java
@@ -21,6 +21,8 @@
 import com.google.devtools.build.lib.exec.ExecutionOptions;
 import com.google.devtools.build.lib.exec.ExecutorBuilder;
 import com.google.devtools.build.lib.exec.SpawnCache;
+import com.google.devtools.build.lib.remote.RemoteModule;
+import com.google.devtools.build.lib.remote.RemoteOptions;
 import com.google.devtools.build.lib.rules.android.WriteAdbArgsActionContext;
 import com.google.devtools.build.lib.rules.cpp.CppCompileActionContext;
 import com.google.devtools.build.lib.rules.cpp.CppIncludeExtractionContext;
@@ -28,8 +30,10 @@
 import com.google.devtools.build.lib.runtime.BlazeModule;
 import com.google.devtools.build.lib.runtime.Command;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
+import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.RegexFilter;
 import com.google.devtools.common.options.OptionsBase;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -38,7 +42,7 @@
   @Override
   public Iterable<Class<? extends OptionsBase>> getCommandOptions(Command command) {
     return "build".equals(command.name())
-        ? ImmutableList.of(ExecutionOptions.class)
+        ? ImmutableList.of(ExecutionOptions.class, RemoteOptions.class)
         : ImmutableList.of();
   }
 
@@ -46,11 +50,36 @@
   public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) {
     builder.addActionContext(new WriteAdbArgsActionContext(env.getClientEnv().get("HOME")));
     ExecutionOptions options = env.getOptions().getOptions(ExecutionOptions.class);
+    RemoteOptions remoteOptions = env.getOptions().getOptions(RemoteOptions.class);
 
-    // Default strategies for certain mnemonics - they can be overridden by --strategy= flags.
-    builder.addStrategyByMnemonic("Javac", ImmutableList.of("worker"));
-    builder.addStrategyByMnemonic("Closure", ImmutableList.of("worker"));
-    builder.addStrategyByMnemonic("DexBuilder", ImmutableList.of("worker"));
+    List<String> spawnStrategies = new ArrayList<>(options.spawnStrategy);
+
+    if (options.incompatibleListBasedExecutionStrategySelection) {
+      if (spawnStrategies.isEmpty()) {
+        if (RemoteModule.shouldEnableRemoteExecution(remoteOptions)) {
+          spawnStrategies.add("remote");
+        }
+        spawnStrategies.add("worker");
+        // Sandboxing is not yet available on Windows.
+        if (OS.getCurrent() != OS.WINDOWS) {
+          spawnStrategies.add("sandboxed");
+        }
+        spawnStrategies.add("local");
+      }
+    } else {
+      // Default strategies for certain mnemonics - they can be overridden by --strategy= flags.
+      builder.addStrategyByMnemonic("Javac", ImmutableList.of("worker"));
+      builder.addStrategyByMnemonic("Closure", ImmutableList.of("worker"));
+      builder.addStrategyByMnemonic("DexBuilder", ImmutableList.of("worker"));
+
+      // The --spawn_strategy= flag is a bit special: If it's set to the empty string, we actually
+      // have to pass a literal empty string to the builder to trigger the "use the strategy that
+      // was registered last" behavior. Otherwise we would have no default strategy at all and Bazel
+      // would crash.
+      if (spawnStrategies.isEmpty()) {
+        spawnStrategies = ImmutableList.of("");
+      }
+    }
 
     // Allow genrule_strategy to also be overridden by --strategy= flags.
     builder.addStrategyByMnemonic("Genrule", options.genruleStrategy);
@@ -59,12 +88,6 @@
       builder.addStrategyByMnemonic(strategy.getKey(), strategy.getValue());
     }
 
-    // The --spawn_strategy= flag is a bit special: If it's set to the empty string, we actually
-    // have to pass a literal empty string to the builder to trigger the "use the strategy that was
-    // registered last" behavior. Otherwise we would have no default strategy at all and Bazel would
-    // crash.
-    List<String> spawnStrategies =
-        options.spawnStrategy.isEmpty() ? ImmutableList.of("") : options.spawnStrategy;
     builder.addStrategyByMnemonic("", spawnStrategies);
 
     for (Map.Entry<RegexFilter, List<String>> entry : options.strategyByRegexp) {
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
index 97926fc..25e23e4 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
@@ -110,6 +110,11 @@
         return true; // if *all* > 0 violations have type MISSING
       };
 
+  /** Returns whether remote execution should be available. */
+  public static boolean shouldEnableRemoteExecution(RemoteOptions options) {
+    return !Strings.isNullOrEmpty(options.remoteExecutor);
+  }
+
   @Override
   public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
     RemoteOptions remoteOptions = env.getOptions().getOptions(RemoteOptions.class);
@@ -130,7 +135,7 @@
     }
     boolean enableBlobStoreCache = enableRestCache || enableDiskCache;
     boolean enableGrpcCache = GrpcRemoteCache.isRemoteCacheOptions(remoteOptions);
-    boolean enableRemoteExecution = !Strings.isNullOrEmpty(remoteOptions.remoteExecutor);
+    boolean enableRemoteExecution = shouldEnableRemoteExecution(remoteOptions);
     if (enableBlobStoreCache && enableRemoteExecution) {
       throw new AbruptExitException(
           "Cannot combine gRPC based remote execution with local disk or HTTP-based caching",