|  | // Copyright 2017 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.devtools.build.lib.actions.ExecException; | 
|  | import com.google.devtools.build.lib.actions.Spawn; | 
|  | import com.google.devtools.build.lib.actions.SpawnResult; | 
|  | import com.google.devtools.build.lib.exec.apple.XcodeLocalEnvProvider; | 
|  | import com.google.devtools.build.lib.exec.local.LocalEnvProvider; | 
|  | import com.google.devtools.build.lib.exec.local.PosixLocalEnvProvider; | 
|  | import com.google.devtools.build.lib.runtime.CommandEnvironment; | 
|  | import com.google.devtools.build.lib.runtime.ProcessWrapperUtil; | 
|  | import com.google.devtools.build.lib.util.OS; | 
|  | import com.google.devtools.build.lib.vfs.Path; | 
|  | import java.io.IOException; | 
|  | import java.time.Duration; | 
|  | import java.util.Map; | 
|  |  | 
|  | /** Strategy that uses sandboxing to execute a process. */ | 
|  | final class ProcessWrapperSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { | 
|  |  | 
|  | public static boolean isSupported(CommandEnvironment cmdEnv) { | 
|  | return OS.isPosixCompatible() && ProcessWrapperUtil.isSupported(cmdEnv); | 
|  | } | 
|  |  | 
|  | private final Path processWrapper; | 
|  | private final Path execRoot; | 
|  | private final Path sandboxBase; | 
|  | private final LocalEnvProvider localEnvProvider; | 
|  | private final Duration timeoutKillDelay; | 
|  |  | 
|  | /** | 
|  | * Creates a sandboxed spawn runner that uses the {@code process-wrapper} tool. | 
|  | * | 
|  | * @param cmdEnv the command environment to use | 
|  | * @param sandboxBase path to the sandbox base directory | 
|  | * @param productName the product name to use | 
|  | * @param timeoutKillDelay additional grace period before killing timing out commands | 
|  | */ | 
|  | ProcessWrapperSandboxedSpawnRunner( | 
|  | CommandEnvironment cmdEnv, Path sandboxBase, String productName, Duration timeoutKillDelay) { | 
|  | super(cmdEnv); | 
|  | this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv); | 
|  | this.execRoot = cmdEnv.getExecRoot(); | 
|  | this.localEnvProvider = | 
|  | OS.getCurrent() == OS.DARWIN | 
|  | ? new XcodeLocalEnvProvider(cmdEnv.getClientEnv()) | 
|  | : new PosixLocalEnvProvider(cmdEnv.getClientEnv()); | 
|  | this.sandboxBase = sandboxBase; | 
|  | this.timeoutKillDelay = timeoutKillDelay; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionContext context) | 
|  | throws ExecException, IOException, InterruptedException { | 
|  | // Each invocation of "exec" gets its own sandbox base. | 
|  | // Note that the value returned by context.getId() is only unique inside one given SpawnRunner, | 
|  | // so we have to prefix our name to turn it into a globally unique value. | 
|  | Path sandboxPath = | 
|  | sandboxBase.getRelative(getName()).getRelative(Integer.toString(context.getId())); | 
|  | sandboxPath.getParentDirectory().createDirectory(); | 
|  | sandboxPath.createDirectory(); | 
|  |  | 
|  | // b/64689608: The execroot of the sandboxed process must end with the workspace name, just like | 
|  | // the normal execroot does. | 
|  | Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName()); | 
|  | sandboxExecRoot.getParentDirectory().createDirectory(); | 
|  | sandboxExecRoot.createDirectory(); | 
|  |  | 
|  | Map<String, String> environment = | 
|  | localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, "/tmp"); | 
|  |  | 
|  | Duration timeout = context.getTimeout(); | 
|  | ProcessWrapperUtil.CommandLineBuilder commandLineBuilder = | 
|  | ProcessWrapperUtil.commandLineBuilder(processWrapper.getPathString(), spawn.getArguments()) | 
|  | .setTimeout(timeout); | 
|  |  | 
|  | commandLineBuilder.setKillDelay(timeoutKillDelay); | 
|  |  | 
|  | Path statisticsPath = null; | 
|  | if (getSandboxOptions().collectLocalSandboxExecutionStatistics) { | 
|  | statisticsPath = sandboxPath.getRelative("stats.out"); | 
|  | commandLineBuilder.setStatisticsPath(statisticsPath); | 
|  | } | 
|  |  | 
|  | SandboxedSpawn sandbox = | 
|  | new SymlinkedSandboxedSpawn( | 
|  | sandboxPath, | 
|  | sandboxExecRoot, | 
|  | commandLineBuilder.build(), | 
|  | environment, | 
|  | SandboxHelpers.processInputFiles( | 
|  | spawn, | 
|  | context, | 
|  | execRoot, | 
|  | getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree), | 
|  | SandboxHelpers.getOutputs(spawn), | 
|  | getWritableDirs(sandboxExecRoot, environment)); | 
|  |  | 
|  | return runSpawn(spawn, sandbox, context, execRoot, timeout, statisticsPath); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String getName() { | 
|  | return "processwrapper-sandbox"; | 
|  | } | 
|  | } |