Refactor our sandboxing code.

--
MOS_MIGRATED_REVID=131817068
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 bd8c365..391748f 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
@@ -4,22 +4,109 @@
 // 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
+// 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.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.devtools.build.lib.actions.ActionExecutionContext;
+import com.google.devtools.build.lib.actions.ActionInput;
+import com.google.devtools.build.lib.actions.ActionStatusMessage;
+import com.google.devtools.build.lib.actions.ExecException;
+import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.actions.Spawn;
+import com.google.devtools.build.lib.actions.UserExecException;
+import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.buildtool.BuildRequest;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.standalone.StandaloneSpawnStrategy;
+import com.google.devtools.build.lib.util.Preconditions;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /** Helper methods that are shared by the different sandboxing strategies in this package. */
 final class SandboxHelpers {
 
+  static void lazyCleanup(ExecutorService backgroundWorkers, final SandboxRunner runner) {
+    // By deleting the sandbox directory in the background, we avoid having to wait for it to
+    // complete before returning from the action, which improves performance.
+    backgroundWorkers.execute(
+        new Runnable() {
+          @Override
+          public void run() {
+            try {
+              while (!Thread.currentThread().isInterrupted()) {
+                try {
+                  runner.cleanup();
+                  return;
+                } catch (IOException e2) {
+                  // Sleep & retry.
+                  Thread.sleep(250);
+                }
+              }
+            } catch (InterruptedException e) {
+              // Mark ourselves as interrupted and then exit.
+              Thread.currentThread().interrupt();
+            }
+          }
+        });
+  }
+
+  static void fallbackToNonSandboxedExecution(
+      Spawn spawn, ActionExecutionContext actionExecutionContext, Executor executor)
+      throws ExecException {
+    StandaloneSpawnStrategy standaloneStrategy =
+        Preconditions.checkNotNull(executor.getContext(StandaloneSpawnStrategy.class));
+    standaloneStrategy.exec(spawn, actionExecutionContext);
+  }
+
+  static void reportSubcommand(Executor executor, Spawn spawn) {
+    if (executor.reportsSubcommands()) {
+      executor.reportSubcommand(
+          Label.print(spawn.getOwner().getLabel())
+              + " ["
+              + spawn.getResourceOwner().prettyPrint()
+              + "]",
+          spawn.asShellCommand(executor.getExecRoot()));
+    }
+  }
+
+  static int getTimeout(Spawn spawn) throws ExecException {
+    String timeoutStr = spawn.getExecutionInfo().get("timeout");
+    if (timeoutStr != null) {
+      try {
+        return Integer.parseInt(timeoutStr);
+      } catch (NumberFormatException e) {
+        throw new UserExecException("Could not parse timeout", e);
+      }
+    }
+    return -1;
+  }
+
+  static ImmutableSet<PathFragment> getOutputFiles(Spawn spawn) {
+    Builder<PathFragment> outputFiles = ImmutableSet.builder();
+    for (PathFragment optionalOutput : spawn.getOptionalOutputFiles()) {
+      Preconditions.checkArgument(!optionalOutput.isAbsolute());
+      outputFiles.add(optionalOutput);
+    }
+    for (ActionInput output : spawn.getOutputFiles()) {
+      outputFiles.add(new PathFragment(output.getExecPathString()));
+    }
+    return outputFiles.build();
+  }
+
   static boolean shouldAllowNetwork(BuildRequest buildRequest, Spawn spawn) {
     // If we don't run tests, allow network access.
     if (!buildRequest.shouldRunTests()) {
@@ -42,4 +129,18 @@
 
     return false;
   }
+
+  static void postActionStatusMessage(Executor executor, Spawn spawn) {
+    executor
+        .getEventBus()
+        .post(ActionStatusMessage.runningStrategy(spawn.getResourceOwner(), "sandbox"));
+  }
+
+  static Path getSandboxRoot(
+      BlazeDirectories blazeDirs, String productName, UUID uuid, AtomicInteger execCounter) {
+    return blazeDirs
+        .getOutputBase()
+        .getRelative(productName + "-sandbox")
+        .getRelative(uuid + "-" + execCounter.getAndIncrement());
+  }
 }