Turn SandboxHelpers into a stateful class.

This is to simplify an upcoming fix, which requires tracking an option,
and an upcoming optimization, which requires carrying state around the
various sandbox instances.

RELNOTES: None.
PiperOrigin-RevId: 301837964
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
index e2a5658..85dc8b0 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
@@ -99,6 +99,7 @@
     return true;
   }
 
+  private final SandboxHelpers helpers;
   private final Path execRoot;
   private final boolean allowNetwork;
   private final Path processWrapper;
@@ -120,6 +121,7 @@
    * Creates a sandboxed spawn runner that uses the {@code process-wrapper} tool and the MacOS
    * {@code sandbox-exec} binary.
    *
+   * @param helpers common tools and state across all spawns during sandboxed execution
    * @param cmdEnv the command environment to use
    * @param sandboxBase path to the sandbox base directory
    * @param timeoutKillDelay additional grace period before killing timing out commands
@@ -128,6 +130,7 @@
    * @param sandboxfsMapSymlinkTargets map the targets of symlinks within the sandbox if true
    */
   DarwinSandboxedSpawnRunner(
+      SandboxHelpers helpers,
       CommandEnvironment cmdEnv,
       Path sandboxBase,
       Duration timeoutKillDelay,
@@ -136,8 +139,9 @@
       TreeDeleter treeDeleter)
       throws IOException {
     super(cmdEnv);
+    this.helpers = helpers;
     this.execRoot = cmdEnv.getExecRoot();
-    this.allowNetwork = SandboxHelpers.shouldAllowNetwork(cmdEnv.getOptions());
+    this.allowNetwork = helpers.shouldAllowNetwork(cmdEnv.getOptions());
     this.alwaysWritableDirs = getAlwaysWritableDirs(cmdEnv.getRuntime().getFileSystem());
     this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
     this.localEnvProvider = LocalEnvProvider.forCurrentOs(cmdEnv.getClientEnv());
@@ -231,13 +235,13 @@
     writableDirs.addAll(extraWritableDirs);
 
     SandboxInputs inputs =
-        SandboxHelpers.processInputFiles(
+        helpers.processInputFiles(
             context.getInputMapping(
                 getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree),
             spawn,
             context.getArtifactExpander(),
             execRoot);
-    SandboxOutputs outputs = SandboxHelpers.getOutputs(spawn);
+    SandboxOutputs outputs = helpers.getOutputs(spawn);
 
     final Path sandboxConfigPath = sandboxPath.getRelative("sandbox.sb");
     Duration timeout = context.getTimeout();
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java
index dfda924..ccbd38b 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java
@@ -137,6 +137,7 @@
 
   private static final ConcurrentHashMap<String, String> imageMap = new ConcurrentHashMap<>();
 
+  private final SandboxHelpers helpers;
   private final Path execRoot;
   private final boolean allowNetwork;
   private final Path dockerClient;
@@ -157,6 +158,7 @@
   /**
    * Creates a sandboxed spawn runner that uses the {@code linux-sandbox} tool.
    *
+   * @param helpers common tools and state across all spawns during sandboxed execution
    * @param cmdEnv the command environment to use
    * @param dockerClient path to the `docker` executable
    * @param sandboxBase path to the sandbox base directory
@@ -166,6 +168,7 @@
    * @param treeDeleter scheduler for tree deletions
    */
   DockerSandboxedSpawnRunner(
+      SandboxHelpers helpers,
       CommandEnvironment cmdEnv,
       Path dockerClient,
       Path sandboxBase,
@@ -174,8 +177,9 @@
       boolean useCustomizedImages,
       TreeDeleter treeDeleter) {
     super(cmdEnv);
+    this.helpers = helpers;
     this.execRoot = cmdEnv.getExecRoot();
-    this.allowNetwork = SandboxHelpers.shouldAllowNetwork(cmdEnv.getOptions());
+    this.allowNetwork = helpers.shouldAllowNetwork(cmdEnv.getOptions());
     this.dockerClient = dockerClient;
     this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
     this.sandboxBase = sandboxBase;
@@ -218,13 +222,13 @@
         localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), binTools, "/tmp");
 
     SandboxInputs inputs =
-        SandboxHelpers.processInputFiles(
+        helpers.processInputFiles(
             context.getInputMapping(
                 getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree),
             spawn,
             context.getArtifactExpander(),
             execRoot);
-    SandboxOutputs outputs = SandboxHelpers.getOutputs(spawn);
+    SandboxOutputs outputs = helpers.getOutputs(spawn);
 
     Duration timeout = context.getTimeout();
 
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
index d569c9b..3332796 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
@@ -86,6 +86,7 @@
     return true;
   }
 
+  private final SandboxHelpers helpers;
   private final FileSystem fileSystem;
   private final BlazeDirectories blazeDirs;
   private final Path execRoot;
@@ -103,6 +104,7 @@
   /**
    * Creates a sandboxed spawn runner that uses the {@code linux-sandbox} tool.
    *
+   * @param helpers common tools and state across all spawns during sandboxed execution
    * @param cmdEnv the command environment to use
    * @param sandboxBase path to the sandbox base directory
    * @param inaccessibleHelperFile path to a file that is (already) inaccessible
@@ -113,6 +115,7 @@
    * @param sandboxfsMapSymlinkTargets map the targets of symlinks within the sandbox if true
    */
   LinuxSandboxedSpawnRunner(
+      SandboxHelpers helpers,
       CommandEnvironment cmdEnv,
       Path sandboxBase,
       Path inaccessibleHelperFile,
@@ -122,10 +125,11 @@
       boolean sandboxfsMapSymlinkTargets,
       TreeDeleter treeDeleter) {
     super(cmdEnv);
+    this.helpers = helpers;
     this.fileSystem = cmdEnv.getRuntime().getFileSystem();
     this.blazeDirs = cmdEnv.getDirectories();
     this.execRoot = cmdEnv.getExecRoot();
-    this.allowNetwork = SandboxHelpers.shouldAllowNetwork(cmdEnv.getOptions());
+    this.allowNetwork = helpers.shouldAllowNetwork(cmdEnv.getOptions());
     this.linuxSandbox = LinuxSandboxUtil.getLinuxSandbox(cmdEnv);
     this.sandboxBase = sandboxBase;
     this.inaccessibleHelperFile = inaccessibleHelperFile;
@@ -161,13 +165,13 @@
     ImmutableSet<Path> writableDirs = getWritableDirs(sandboxExecRoot, environment);
 
     SandboxInputs inputs =
-        SandboxHelpers.processInputFiles(
+        helpers.processInputFiles(
             context.getInputMapping(
                 getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree),
             spawn,
             context.getArtifactExpander(),
             execRoot);
-    SandboxOutputs outputs = SandboxHelpers.getOutputs(spawn);
+    SandboxOutputs outputs = helpers.getOutputs(spawn);
 
     Duration timeout = context.getTimeout();
 
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
index a31938b..70f4325 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
@@ -38,6 +38,7 @@
   /**
    * Creates a sandboxed spawn runner that uses the {@code linux-sandbox} tool.
    *
+   * @param helpers common tools and state across all spawns during sandboxed execution
    * @param cmdEnv the command environment to use
    * @param sandboxBase path to the sandbox base directory
    * @param timeoutKillDelay additional grace period before killing timing out commands
@@ -46,6 +47,7 @@
    * @param sandboxfsMapSymlinkTargets map the targets of symlinks within the sandbox if true
    */
   static LinuxSandboxedSpawnRunner create(
+      SandboxHelpers helpers,
       CommandEnvironment cmdEnv,
       Path sandboxBase,
       Duration timeoutKillDelay,
@@ -66,6 +68,7 @@
     inaccessibleHelperDir.setExecutable(false);
 
     return new LinuxSandboxedSpawnRunner(
+        helpers,
         cmdEnv,
         sandboxBase,
         inaccessibleHelperFile,
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
index 489ac89..65f6748 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
@@ -37,6 +37,7 @@
     return OS.isPosixCompatible() && ProcessWrapperUtil.isSupported(cmdEnv);
   }
 
+  private final SandboxHelpers helpers;
   private final Path processWrapper;
   private final Path execRoot;
   private final Path sandboxBase;
@@ -49,6 +50,7 @@
   /**
    * Creates a sandboxed spawn runner that uses the {@code process-wrapper} tool.
    *
+   * @param helpers common tools and state across all spawns during sandboxed execution
    * @param cmdEnv the command environment to use
    * @param sandboxBase path to the sandbox base directory
    * @param timeoutKillDelay additional grace period before killing timing out commands
@@ -57,6 +59,7 @@
    * @param sandboxfsMapSymlinkTargets map the targets of symlinks within the sandbox if true
    */
   ProcessWrapperSandboxedSpawnRunner(
+      SandboxHelpers helpers,
       CommandEnvironment cmdEnv,
       Path sandboxBase,
       Duration timeoutKillDelay,
@@ -64,6 +67,7 @@
       boolean sandboxfsMapSymlinkTargets,
       TreeDeleter treeDeleter) {
     super(cmdEnv);
+    this.helpers = helpers;
     this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
     this.execRoot = cmdEnv.getExecRoot();
     this.localEnvProvider = LocalEnvProvider.forCurrentOs(cmdEnv.getClientEnv());
@@ -109,13 +113,13 @@
     }
 
     SandboxInputs inputs =
-        SandboxHelpers.processInputFiles(
+        helpers.processInputFiles(
             context.getInputMapping(
                 getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree),
             spawn,
             context.getArtifactExpander(),
             execRoot);
-    SandboxOutputs outputs = SandboxHelpers.getOutputs(spawn);
+    SandboxOutputs outputs = helpers.getOutputs(spawn);
 
     if (sandboxfsProcess != null) {
       return new SandboxfsSandboxedSpawn(
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
index 5d9ee96..f7dc09b 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
@@ -35,7 +35,11 @@
 import java.util.Map;
 import java.util.TreeMap;
 
-/** Helper methods that are shared by the different sandboxing strategies in this package. */
+/**
+ * Helper methods that are shared by the different sandboxing strategies.
+ *
+ * <p>All sandboxed strategies within a build should share the same instance of this object.
+ */
 public final class SandboxHelpers {
   /** Wrapper class for the inputs of a sandbox. */
   public static final class SandboxInputs {
@@ -64,7 +68,7 @@
    *
    * @throws IOException If any files could not be written.
    */
-  public static SandboxInputs processInputFiles(
+  public SandboxInputs processInputFiles(
       Map<PathFragment, ActionInput> inputMap,
       Spawn spawn,
       ArtifactExpander artifactExpander,
@@ -140,7 +144,7 @@
     }
   }
 
-  public static SandboxOutputs getOutputs(Spawn spawn) {
+  public SandboxOutputs getOutputs(Spawn spawn) {
     ImmutableSet.Builder<PathFragment> files = ImmutableSet.builder();
     ImmutableSet.Builder<PathFragment> dirs = ImmutableSet.builder();
     for (ActionInput output : spawn.getOutputFiles()) {
@@ -161,7 +165,7 @@
    * reference to the full set of build options (and also for performance, since this only needs to
    * be checked once-per-build).
    */
-  static boolean shouldAllowNetwork(OptionsParsingResult buildOptions) {
+  boolean shouldAllowNetwork(OptionsParsingResult buildOptions) {
     // Allow network access, when --java_debug is specified, otherwise we can't connect to the
     // remote debug server of the test. This intentionally overrides the "block-network" execution
     // tag.
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 10ae634..21fe4ac 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
@@ -180,6 +180,8 @@
     SandboxOptions options = checkNotNull(env.getOptions().getOptions(SandboxOptions.class));
     sandboxBase = computeSandboxBase(options, env);
 
+    SandboxHelpers helpers = new SandboxHelpers();
+
     // Do not remove the sandbox base when --sandbox_debug was specified so that people can check
     // out the contents of the generated sandbox directories.
     shouldCleanupSandboxBase = !options.sandboxDebug;
@@ -269,6 +271,7 @@
           withFallback(
               cmdEnv,
               new ProcessWrapperSandboxedSpawnRunner(
+                  helpers,
                   cmdEnv,
                   sandboxBase,
                   timeoutKillDelay,
@@ -296,6 +299,7 @@
             withFallback(
                 cmdEnv,
                 new DockerSandboxedSpawnRunner(
+                    helpers,
                     cmdEnv,
                     pathToDocker,
                     sandboxBase,
@@ -321,6 +325,7 @@
           withFallback(
               cmdEnv,
               LinuxSandboxedStrategy.create(
+                  helpers,
                   cmdEnv,
                   sandboxBase,
                   timeoutKillDelay,
@@ -341,6 +346,7 @@
           withFallback(
               cmdEnv,
               new DarwinSandboxedSpawnRunner(
+                  helpers,
                   cmdEnv,
                   sandboxBase,
                   timeoutKillDelay,
@@ -359,7 +365,8 @@
       SpawnRunner spawnRunner =
           withFallback(
               cmdEnv,
-              new WindowsSandboxedSpawnRunner(cmdEnv, timeoutKillDelay, windowsSandboxPath));
+              new WindowsSandboxedSpawnRunner(
+                  helpers, cmdEnv, timeoutKillDelay, windowsSandboxPath));
       spawnRunners.add(spawnRunner);
       builder.addActionContext(
           SpawnStrategy.class,
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java
index ceb0757..afbfa6e 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java
@@ -31,6 +31,7 @@
 /** Spawn runner that uses BuildXL Sandbox APIs to execute a local subprocess. */
 final class WindowsSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
 
+  private final SandboxHelpers helpers;
   private final Path execRoot;
   private final PathFragment windowsSandbox;
   private final LocalEnvProvider localEnvProvider;
@@ -39,13 +40,18 @@
   /**
    * Creates a sandboxed spawn runner that uses the {@code windows-sandbox} tool.
    *
+   * @param helpers common tools and state across all spawns during sandboxed execution
    * @param cmdEnv the command environment to use
    * @param timeoutKillDelay an additional grace period before killing timing out commands
    * @param windowsSandboxPath path to windows-sandbox binary
    */
   WindowsSandboxedSpawnRunner(
-      CommandEnvironment cmdEnv, Duration timeoutKillDelay, PathFragment windowsSandboxPath) {
+      SandboxHelpers helpers,
+      CommandEnvironment cmdEnv,
+      Duration timeoutKillDelay,
+      PathFragment windowsSandboxPath) {
     super(cmdEnv);
+    this.helpers = helpers;
     this.execRoot = cmdEnv.getExecRoot();
     this.windowsSandbox = windowsSandboxPath;
     this.timeoutKillDelay = timeoutKillDelay;
@@ -63,7 +69,7 @@
             spawn.getEnvironment(), binTools, commandTmpDir.getPathString());
 
     SandboxInputs readablePaths =
-        SandboxHelpers.processInputFiles(
+        helpers.processInputFiles(
             context.getInputMapping(
                 getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree),
             spawn,
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 4d521cd..adcf574 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
@@ -34,6 +34,7 @@
 import com.google.devtools.build.lib.runtime.Command;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
 import com.google.devtools.build.lib.runtime.commands.CleanCommand.CleanStartingEvent;
+import com.google.devtools.build.lib.sandbox.SandboxHelpers;
 import com.google.devtools.build.lib.sandbox.SandboxOptions;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.worker.WorkerOptions.MultiResourceConverter;
@@ -144,6 +145,7 @@
     LocalEnvProvider localEnvProvider = LocalEnvProvider.forCurrentOs(env.getClientEnv());
     WorkerSpawnRunner spawnRunner =
         new WorkerSpawnRunner(
+            new SandboxHelpers(),
             env.getExecRoot(),
             workerPool,
             extraFlags,
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
index 244d321..e9b54c3 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
@@ -75,6 +75,7 @@
   /** Pattern for @flagfile.txt and --flagfile=flagfile.txt */
   private static final Pattern FLAG_FILE_PATTERN = Pattern.compile("(?:@|--?flagfile=)(.+)");
 
+  private final SandboxHelpers helpers;
   private final Path execRoot;
   private final WorkerPool workers;
   private final Multimap<String, String> extraFlags;
@@ -87,6 +88,7 @@
   private final RunfilesTreeUpdater runfilesTreeUpdater;
 
   public WorkerSpawnRunner(
+      SandboxHelpers helpers,
       Path execRoot,
       WorkerPool workers,
       Multimap<String, String> extraFlags,
@@ -97,6 +99,7 @@
       BinTools binTools,
       ResourceManager resourceManager,
       RunfilesTreeUpdater runfilesTreeUpdater) {
+    this.helpers = helpers;
     this.execRoot = execRoot;
     this.workers = Preconditions.checkNotNull(workers);
     this.extraFlags = extraFlags;
@@ -171,12 +174,12 @@
     HashCode workerFilesCombinedHash = WorkerFilesHash.getCombinedHash(workerFiles);
 
     SandboxInputs inputFiles =
-        SandboxHelpers.processInputFiles(
+        helpers.processInputFiles(
             context.getInputMapping(sandboxUsesExpandedTreeArtifactsInRunfiles),
             spawn,
             context.getArtifactExpander(),
             execRoot);
-    SandboxOutputs outputs = SandboxHelpers.getOutputs(spawn);
+    SandboxOutputs outputs = helpers.getOutputs(spawn);
 
     WorkerKey key =
         new WorkerKey(