Remove ActionContextConsumer

Instead, add some simple APIs to ExecutorBuilder and inline all the previous
subclasses into their corresponding modules. This removes a bunch of
boilerplate.

PiperOrigin-RevId: 200017162
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/SpawnLogModule.java b/src/main/java/com/google/devtools/build/lib/bazel/SpawnLogModule.java
index ca6d3a3..ab03ba8 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/SpawnLogModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/SpawnLogModule.java
@@ -15,10 +15,8 @@
 
 import com.google.devtools.build.lib.buildtool.BuildRequest;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.exec.ActionContextConsumer;
 import com.google.devtools.build.lib.exec.ExecutionOptions;
 import com.google.devtools.build.lib.exec.ExecutorBuilder;
-import com.google.devtools.build.lib.exec.SpawnActionContextMaps;
 import com.google.devtools.build.lib.exec.SpawnLogContext;
 import com.google.devtools.build.lib.runtime.BlazeModule;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
@@ -31,14 +29,6 @@
  * Module providing on-demand spawn logging.
  */
 public final class SpawnLogModule extends BlazeModule {
-
-  private static final class SpawnLogContextConsumer implements ActionContextConsumer {
-    @Override
-    public void populate(SpawnActionContextMaps.Builder builder) {
-      builder.strategyByContextMap().put(SpawnLogContext.class, "");
-    }
-  }
-
   private SpawnLogContext spawnLogContext;
 
   @Override
@@ -58,7 +48,7 @@
             "Error found creating SpawnLogContext", ExitCode.COMMAND_LINE_ERROR));
       }
       builder.addActionContext(spawnLogContext);
-      builder.addActionContextConsumer(new SpawnLogContextConsumer());
+      builder.addStrategyByContext(SpawnLogContext.class, "");
     } else {
       spawnLogContext = null;
     }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelActionContextConsumer.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelActionContextConsumer.java
deleted file mode 100644
index 009d039..0000000
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelActionContextConsumer.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.bazel.rules;
-
-import com.google.devtools.build.lib.actions.ActionContext;
-import com.google.devtools.build.lib.analysis.actions.FileWriteActionContext;
-import com.google.devtools.build.lib.bazel.rules.BazelStrategyModule.BazelExecutionOptions;
-import com.google.devtools.build.lib.exec.ActionContextConsumer;
-import com.google.devtools.build.lib.exec.SpawnActionContextMaps;
-import com.google.devtools.build.lib.exec.SpawnCache;
-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;
-import com.google.devtools.build.lib.rules.cpp.CppIncludeScanningContext;
-import java.util.Map;
-
-/**
- * An object describing the {@link ActionContext} implementation that some actions require in Bazel.
- */
-public class BazelActionContextConsumer implements ActionContextConsumer {
-  private final BazelExecutionOptions options;
-
-  protected BazelActionContextConsumer(BazelExecutionOptions options) {
-    this.options = options;
-  }
-
-  @Override
-  public void populate(SpawnActionContextMaps.Builder builder) {
-    // Default strategies for certain mnemonics - they can be overridden by --strategy= flags.
-    builder.strategyByMnemonicMap().put("Javac", "worker");
-    builder.strategyByMnemonicMap().put("Closure", "worker");
-
-    for (Map.Entry<String, String> strategy : options.strategy) {
-      String strategyName = strategy.getValue();
-      // TODO(philwo) - remove this when the standalone / local mess is cleaned up.
-      // Some flag expansions use "local" as the strategy name, but the strategy is now called
-      // "standalone", so we'll translate it here.
-      if (strategyName.equals("local")) {
-        strategyName = "standalone";
-      }
-      builder.strategyByMnemonicMap().put(strategy.getKey(), strategyName);
-    }
-
-    if (!options.genruleStrategy.isEmpty()) {
-      builder.strategyByMnemonicMap().put("Genrule", options.genruleStrategy);
-    }
-
-    // TODO(bazel-team): put this in getActionContexts (key=SpawnActionContext.class) instead
-    if (!options.spawnStrategy.isEmpty()) {
-      builder.strategyByMnemonicMap().put("", options.spawnStrategy);
-    }
-
-    builder
-        .strategyByContextMap()
-        .put(CppCompileActionContext.class, "")
-        .put(CppIncludeExtractionContext.class, "")
-        .put(CppIncludeScanningContext.class, "")
-        .put(FileWriteActionContext.class, "")
-        .put(WriteAdbArgsActionContext.class, "")
-        .put(SpawnCache.class, "");
-  }
-}
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 e829da2..96abb16 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
@@ -15,9 +15,14 @@
 package com.google.devtools.build.lib.bazel.rules;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.actions.FileWriteActionContext;
 import com.google.devtools.build.lib.buildtool.BuildRequest;
 import com.google.devtools.build.lib.exec.ExecutorBuilder;
+import com.google.devtools.build.lib.exec.SpawnCache;
 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;
+import com.google.devtools.build.lib.rules.cpp.CppIncludeScanningContext;
 import com.google.devtools.build.lib.runtime.BlazeModule;
 import com.google.devtools.build.lib.runtime.Command;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
@@ -86,6 +91,37 @@
   public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) {
     builder.addActionContext(new WriteAdbArgsActionContext(env.getClientEnv().get("HOME")));
     BazelExecutionOptions options = env.getOptions().getOptions(BazelExecutionOptions.class);
-    builder.addActionContextConsumer(new BazelActionContextConsumer(options));
+
+    // Default strategies for certain mnemonics - they can be overridden by --strategy= flags.
+    builder.addStrategyByMnemonic("Javac", "worker");
+    builder.addStrategyByMnemonic("Closure", "worker");
+
+    for (Map.Entry<String, String> strategy : options.strategy) {
+      String strategyName = strategy.getValue();
+      // TODO(philwo) - remove this when the standalone / local mess is cleaned up.
+      // Some flag expansions use "local" as the strategy name, but the strategy is now called
+      // "standalone", so we'll translate it here.
+      if (strategyName.equals("local")) {
+        strategyName = "standalone";
+      }
+      builder.addStrategyByMnemonic(strategy.getKey(), strategyName);
+    }
+
+    if (!options.genruleStrategy.isEmpty()) {
+      builder.addStrategyByMnemonic("Genrule", options.genruleStrategy);
+    }
+
+    // TODO(bazel-team): put this in getActionContexts (key=SpawnActionContext.class) instead
+    if (!options.spawnStrategy.isEmpty()) {
+      builder.addStrategyByMnemonic("", options.spawnStrategy);
+    }
+
+    builder
+        .addStrategyByContext(CppCompileActionContext.class, "")
+        .addStrategyByContext(CppIncludeExtractionContext.class, "")
+        .addStrategyByContext(CppIncludeScanningContext.class, "")
+        .addStrategyByContext(FileWriteActionContext.class, "")
+        .addStrategyByContext(WriteAdbArgsActionContext.class, "")
+        .addStrategyByContext(SpawnCache.class, "");
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
index f046110..8b3d866 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
@@ -55,7 +55,6 @@
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
 import com.google.devtools.build.lib.events.Reporter;
-import com.google.devtools.build.lib.exec.ActionContextConsumer;
 import com.google.devtools.build.lib.exec.ActionContextProvider;
 import com.google.devtools.build.lib.exec.BlazeExecutor;
 import com.google.devtools.build.lib.exec.CheckUpToDateFilter;
@@ -140,12 +139,9 @@
     // TODO(philwo) - the ExecutionTool should not add arbitrary dependencies on its own, instead
     // these dependencies should be added to the ActionContextConsumer of the module that actually
     // depends on them.
-    builder.addActionContextConsumer(
-        b -> {
-          b.strategyByContextMap()
-              .put(WorkspaceStatusAction.Context.class, "")
-              .put(SymlinkTreeActionContext.class, "");
-        });
+    builder
+        .addStrategyByContext(WorkspaceStatusAction.Context.class, "")
+        .addStrategyByContext(SymlinkTreeActionContext.class, "");
 
     // Unfortunately, the exec root cache is not shared with caches in the remote execution client.
     this.fileCache =
@@ -162,13 +158,8 @@
     // independently from each other, for example, to run genrules locally and Java compile action
     // in prod. Thus, for SpawnActions, we decide the action context to use not only based on the
     // context class, but also the mnemonic of the action.
-    SpawnActionContextMaps.Builder spawnActionContextMapsBuilder =
-        new SpawnActionContextMaps.Builder();
-    for (ActionContextConsumer consumer : builder.getActionContextConsumers()) {
-      consumer.populate(spawnActionContextMapsBuilder);
-    }
     spawnActionContextMaps =
-        spawnActionContextMapsBuilder.build(
+        builder.getSpawnActionContextMapsBuilder().build(
             actionContextProviders, request.getOptions(ExecutionOptions.class).testStrategy);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ActionContextConsumer.java b/src/main/java/com/google/devtools/build/lib/exec/ActionContextConsumer.java
deleted file mode 100644
index a63176b..0000000
--- a/src/main/java/com/google/devtools/build/lib/exec/ActionContextConsumer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.exec;
-
-import com.google.devtools.build.lib.actions.ActionContext;
-import com.google.devtools.build.lib.exec.SpawnActionContextMaps.Builder;
-
-/**
- * An object describing that actions require a particular implementation of an {@link
- * ActionContext}.
- *
- * <p>This is expected to be implemented by modules that also implement actions which need these
- * contexts. Other modules will provide implementations for various action contexts by implementing
- * {@link ActionContextProvider}.
- *
- * <p>Example: a module requires {@code SpawnActionContext} to do its job, and it creates actions
- * with the mnemonic <code>C++</code>. Then the {@link #populate(Builder)} method of this module
- * would put <code>("C++", strategy)</code> in the map returned by {@link
- * Builder#strategyByMnemonicMap()}.
- *
- * <p>The module can either decide for itself which implementation is needed and make the value
- * associated with this key a constant or defer that decision to the user, for example, by providing
- * a command line option and setting the value in the map based on that.
- *
- * <p>Other modules are free to provide different implementations of {@code SpawnActionContext}.
- * This can be used, for example, to implement sandboxed or distributed execution of {@code
- * SpawnAction}s in different ways, while giving the user control over how exactly they are
- * executed.
- *
- * <p>Example: if a module requires {@code MyCustomActionContext} to be available, but doesn't
- * associate it with any strategy, its {@link #populate(Builder)} should add {@code
- * (MyCustomActionContext.class, "")} to the builder's {@link Builder#strategyByContextMap}.
- *
- * <p>Example: if a module requires {@code MyLocalCustomActionContext} to be available, and wants it
- * to always use the "local" strategy, its {@link #populate(Builder)} should add {@code
- * (MyCustomActionContext.class, "local")} to the builder's {@link Builder#strategyByContextMap}. .
- */
-public interface ActionContextConsumer {
-  /**
-   * Provides a {@link SpawnActionContextMaps.Builder} instance which modules may use to configure
-   * the {@link ActionContext} instances the module requires for particular actions.
-   */
-  void populate(SpawnActionContextMaps.Builder builder);
-}
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java
index 79ea2cd..0afdb13 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java
@@ -22,7 +22,7 @@
 /**
  * An object that provides execution strategies to {@link BlazeExecutor}.
  *
- * <p>For more information, see {@link ActionContextConsumer}.
+ * <p>For more information, see {@link ExecutorBuilder}.
  */
 public abstract class ActionContextProvider {
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ExecutorBuilder.java b/src/main/java/com/google/devtools/build/lib/exec/ExecutorBuilder.java
index 398e183..753dd8f 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/ExecutorBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/ExecutorBuilder.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.actions.ActionContext;
 import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
 import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.util.RegexFilter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -27,7 +28,8 @@
  */
 public class ExecutorBuilder {
   private final List<ActionContextProvider> actionContextProviders = new ArrayList<>();
-  private final List<ActionContextConsumer> actionContextConsumers = new ArrayList<>();
+  private final SpawnActionContextMaps.Builder spawnActionContextMapsBuilder =
+      new SpawnActionContextMaps.Builder();
   private ActionInputPrefetcher prefetcher;
 
   // These methods shouldn't be public, but they have to be right now as ExecutionTool is in another
@@ -36,8 +38,8 @@
     return ImmutableList.copyOf(actionContextProviders);
   }
 
-  public ImmutableList<ActionContextConsumer> getActionContextConsumers() {
-    return ImmutableList.copyOf(actionContextConsumers);
+  public SpawnActionContextMaps.Builder getSpawnActionContextMapsBuilder() {
+    return spawnActionContextMapsBuilder;
   }
 
   public ActionInputPrefetcher getActionInputPrefetcher() {
@@ -61,10 +63,48 @@
   }
 
   /**
-   * Adds the specified action context consumer to the executor.
+   * Sets the strategy name for a given action mnemonic.
+   *
+   * <p>The calling module can either decide for itself which implementation is needed and make the
+   * value associated with this key a constant or defer that decision to the user, for example, by
+   * providing a command line option and setting the value in the map based on that.
+   *
+   * <p>Example: a module requires {@code SpawnActionContext} to do its job, and it creates actions
+   * with the mnemonic <code>C++</code>. The the module can call
+   * <code>addStrategyByMnemonic("C++", strategy)</code>.
    */
-  public ExecutorBuilder addActionContextConsumer(ActionContextConsumer consumer) {
-    this.actionContextConsumers.add(consumer);
+  public ExecutorBuilder addStrategyByMnemonic(String mnemonic, String strategy) {
+    spawnActionContextMapsBuilder.strategyByMnemonicMap().put(mnemonic, strategy);
+    return this;
+  }
+
+  /**
+   * Adds an implementation with a specific strategy name.
+   *
+   * <p>Modules are free to provide different implementations of {@code ActionContext}. This can be
+   * used, for example, to implement sandboxed or distributed execution of {@code SpawnAction}s in
+   * different ways, while giving the user control over how exactly they are executed.
+   *
+   * <p>Example: a module requires {@code MyCustomActionContext} to be available, but doesn't
+   * associate it with any strategy. Call
+   * <code>addStrategyByContext(MyCustomActionContext.class, "")</code>.
+   *
+   * <p>Example: a module requires {@code MyLocalCustomActionContext} to be available, and wants
+   * it to always use the "local" strategy. Call
+   * <code>addStrategyByContext(MyCustomActionContext.class, "local")</code>.
+   */
+  public ExecutorBuilder addStrategyByContext(
+      Class<? extends ActionContext> actionContext, String strategy) {
+    spawnActionContextMapsBuilder.strategyByContextMap().put(actionContext, strategy);
+    return this;
+  }
+
+  /**
+   * Similar to {@link #addStrategyByMnemonic}, but allows specifying a regex for the set of
+   * matching mnemonics, instead of an exact string.
+   */
+  public ExecutorBuilder addStrategyByRegexp(RegexFilter regexFilter, String strategy) {
+    spawnActionContextMapsBuilder.addStrategyByRegexp(regexFilter, strategy);
     return this;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnActionContextMaps.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnActionContextMaps.java
index 4fc32aa..8a1a067 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SpawnActionContextMaps.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnActionContextMaps.java
@@ -54,8 +54,8 @@
 /**
  * Container for looking up the {@link ActionContext} to use for a given action.
  *
- * <p>Holds {@link ActionContext} mappings populated by {@link ActionContextConsumer} modules. These
- * include mappings from mnemonics and from description patterns.
+ * <p>Holds {@link ActionContext} mappings populated by modules. These include mappings from
+ * mnemonics and from description patterns.
  *
  * <p>At startup time, the application provides {@link Builder} to each module to register its
  * contexts and mappings. At runtime, the {@link BlazeExecutor} uses the constructed object to find
@@ -201,9 +201,9 @@
         strategyByContextMapBuilder = ImmutableListMultimap.builder();
 
     private final ImmutableList.Builder<RegexFilterStrategy> strategyByRegexpBuilder =
-        new ImmutableList.Builder();
+        ImmutableList.builder();
 
-    /*
+    /**
      * Returns a builder modules can use to add mappings from mnemonics to strategy names.
      *
      * <p>If a spawn action is executed whose mnemonic maps to the empty string or is not present in
@@ -217,7 +217,7 @@
       return strategyByMnemonicMapBuilder;
     }
 
-    /*
+    /**
      * Returns a builder modules can use to associate {@link ActionContext} classes with
      * strategy names.
      */
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java
deleted file mode 100644
index 08547c30..0000000
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.sandbox;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.devtools.build.lib.actions.ActionContext;
-import com.google.devtools.build.lib.actions.SpawnActionContext;
-import com.google.devtools.build.lib.exec.ActionContextConsumer;
-import com.google.devtools.build.lib.exec.SpawnActionContextMaps;
-import com.google.devtools.build.lib.runtime.CommandEnvironment;
-
-/**
- * {@link ActionContextConsumer} that requests the action contexts necessary for sandboxed
- * execution.
- */
-final class SandboxActionContextConsumer implements ActionContextConsumer {
-
-  private final ImmutableMultimap<Class<? extends ActionContext>, String> contexts;
-  private final ImmutableMap<String, String> spawnContexts;
-
-  public SandboxActionContextConsumer(CommandEnvironment cmdEnv) {
-    ImmutableMultimap.Builder<Class<? extends ActionContext>, String> contexts =
-        ImmutableMultimap.builder();
-    ImmutableMap.Builder<String, String> spawnContexts = ImmutableMap.builder();
-
-    if (LinuxSandboxedSpawnRunner.isSupported(cmdEnv)
-        || DarwinSandboxedSpawnRunner.isSupported(cmdEnv)
-        || ProcessWrapperSandboxedSpawnRunner.isSupported(cmdEnv)) {
-      // This makes the "sandboxed" strategy available via --spawn_strategy=sandboxed,
-      // but it is not necessarily the default.
-      contexts.put(SpawnActionContext.class, "sandboxed");
-
-      // This makes the "sandboxed" strategy the default Spawn strategy, unless it is
-      // overridden by a later BlazeModule.
-      spawnContexts.put("", "sandboxed");
-    }
-
-    this.contexts = contexts.build();
-    this.spawnContexts = spawnContexts.build();
-  }
-
-  @Override
-  public void populate(SpawnActionContextMaps.Builder builder) {
-    builder.strategyByMnemonicMap().putAll(spawnContexts.entrySet());
-    builder.strategyByContextMap().putAll(contexts.entries());
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
index a8fb190..14abac4 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.eventbus.Subscribe;
 import com.google.devtools.build.lib.actions.ExecutorInitException;
+import com.google.devtools.build.lib.actions.SpawnActionContext;
 import com.google.devtools.build.lib.buildtool.BuildRequest;
 import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
 import com.google.devtools.build.lib.buildtool.buildevent.BuildInterruptedEvent;
@@ -133,7 +134,18 @@
       throw new ExecutorInitException("Failed to initialize sandbox", e);
     }
     builder.addActionContextProvider(provider);
-    builder.addActionContextConsumer(new SandboxActionContextConsumer(cmdEnv));
+
+    if (LinuxSandboxedSpawnRunner.isSupported(cmdEnv)
+        || DarwinSandboxedSpawnRunner.isSupported(cmdEnv)
+        || ProcessWrapperSandboxedSpawnRunner.isSupported(cmdEnv)) {
+      // This makes the "sandboxed" strategy available via --spawn_strategy=sandboxed,
+      // but it is not necessarily the default.
+      builder.addStrategyByContext(SpawnActionContext.class, "sandboxed");
+
+      // This makes the "sandboxed" strategy the default Spawn strategy, unless it is
+      // overridden by a later BlazeModule.
+      builder.addStrategyByMnemonic("", "sandboxed");
+    }
 
     // Do not remove the sandbox base when --sandbox_debug was specified so that people can check
     // out the contents of the generated sandbox directories.
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextConsumer.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextConsumer.java
deleted file mode 100644
index 225b3a3..0000000
--- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextConsumer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.standalone;
-
-import com.google.devtools.build.lib.actions.SpawnActionContext;
-import com.google.devtools.build.lib.exec.ActionContextConsumer;
-import com.google.devtools.build.lib.exec.SpawnActionContextMaps;
-
-/**
- * {@link ActionContextConsumer} that requests the action contexts necessary for standalone
- * execution.
- */
-public class StandaloneActionContextConsumer implements ActionContextConsumer {
-
-  @Override
-  public void populate(SpawnActionContextMaps.Builder builder) {
-    // This makes the "sandboxed" strategy the default Spawn strategy, unless it is overridden by a
-    // later BlazeModule.
-    builder.strategyByMnemonicMap().put("", "standalone");
-
-    // This makes the "standalone" strategy available via --spawn_strategy=standalone, but it is not
-    // necessarily the default.
-    builder.strategyByContextMap().put(SpawnActionContext.class, "standalone");
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java
index ead6811..728dc4b 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java
+++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.standalone;
 
+import com.google.devtools.build.lib.actions.SpawnActionContext;
 import com.google.devtools.build.lib.buildtool.BuildRequest;
 import com.google.devtools.build.lib.exec.ExecutorBuilder;
 import com.google.devtools.build.lib.runtime.BlazeModule;
@@ -26,6 +27,12 @@
   public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) {
     builder.addActionContextProvider(new StandaloneActionContextProvider(env));
     builder.addActionContextProvider(new DummyIncludeScanningContextProvider(env));
-    builder.addActionContextConsumer(new StandaloneActionContextConsumer());
+    // This makes the "sandboxed" strategy the default Spawn strategy, unless it is overridden by a
+    // later BlazeModule.
+    builder.addStrategyByMnemonic("", "standalone");
+
+    // This makes the "standalone" strategy available via --spawn_strategy=standalone, but it is not
+    // necessarily the default.
+    builder.addStrategyByContext(SpawnActionContext.class, "standalone");
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextConsumer.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextConsumer.java
deleted file mode 100644
index d3c083d..0000000
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextConsumer.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.worker;
-
-import com.google.devtools.build.lib.actions.SpawnActionContext;
-import com.google.devtools.build.lib.exec.ActionContextConsumer;
-import com.google.devtools.build.lib.exec.SpawnActionContextMaps;
-
-/**
- * {@link ActionContextConsumer} that requests the action contexts necessary for worker process
- * execution.
- */
-public class WorkerActionContextConsumer implements ActionContextConsumer {
-
-  @Override
-  public void populate(SpawnActionContextMaps.Builder builder) {
-    builder.strategyByContextMap().put(SpawnActionContext.class, "standalone");
-    builder.strategyByContextMap().put(SpawnActionContext.class, "worker");
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java
index c5160d9..b75702d 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.eventbus.Subscribe;
+import com.google.devtools.build.lib.actions.SpawnActionContext;
 import com.google.devtools.build.lib.buildtool.BuildRequest;
 import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
 import com.google.devtools.build.lib.buildtool.buildevent.BuildInterruptedEvent;
@@ -125,7 +126,8 @@
   public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) {
     Preconditions.checkNotNull(workerPool);
     builder.addActionContextProvider(new WorkerActionContextProvider(env, workerPool));
-    builder.addActionContextConsumer(new WorkerActionContextConsumer());
+    builder.addStrategyByContext(SpawnActionContext.class, "standalone");
+    builder.addStrategyByContext(SpawnActionContext.class, "worker");
   }
 
   @Subscribe
diff --git a/src/test/shell/integration/bazel_worker_test.sh b/src/test/shell/integration/bazel_worker_test.sh
index f29f746..c7202cf 100755
--- a/src/test/shell/integration/bazel_worker_test.sh
+++ b/src/test/shell/integration/bazel_worker_test.sh
@@ -35,6 +35,7 @@
 add_to_bazelrc "build -s"
 add_to_bazelrc "build --strategy=Javac=worker --strategy=Work=worker"
 add_to_bazelrc "build --worker_verbose --worker_max_instances=1"
+add_to_bazelrc "build --debug_print_action_contexts"
 add_to_bazelrc "build ${ADDITIONAL_BUILD_FLAGS}"
 
 function set_up() {