Skip to content

Commit

Permalink
[7.1.0] Add multiplex sandboxing support to JavaBuilder (#21598)
Browse files Browse the repository at this point in the history
This does not include adding support to Java actions yet.

Work towards #21091

Closes #21370.

PiperOrigin-RevId: 613231195
Change-Id: I87e76d2cebed3075a1eedfd8445b910ebd7604b9

Closes #21518
  • Loading branch information
fmeum authored Mar 6, 2024
1 parent 3ef407d commit c43ace2
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
Expand All @@ -46,7 +47,12 @@ public static void main(String[] args) {
if (args.length == 1 && args[0].equals("--persistent_worker")) {
WorkRequestHandler workerHandler =
new WorkRequestHandlerBuilder(
builder::parseAndBuild,
new WorkRequestHandler.WorkRequestCallback(
(workRequest, printWriter) ->
builder.parseAndBuild(
workRequest.getArgumentsList(),
Path.of(workRequest.getSandboxDir()),
printWriter)),
System.err,
new ProtoWorkerMessageProcessor(System.in, System.out))
.setCpuUsageBeforeGc(Duration.ofSeconds(10))
Expand All @@ -66,17 +72,17 @@ public static void main(String[] args) {
new PrintWriter(new OutputStreamWriter(System.err, Charset.defaultCharset()));
int returnCode;
try {
returnCode = builder.parseAndBuild(Arrays.asList(args), pw);
returnCode = builder.parseAndBuild(Arrays.asList(args), Path.of(""), pw);
} finally {
pw.flush();
}
System.exit(returnCode);
}
}

public int parseAndBuild(List<String> args, PrintWriter pw) {
public int parseAndBuild(List<String> args, Path workDir, PrintWriter pw) {
try {
JavaLibraryBuildRequest build = parse(args);
JavaLibraryBuildRequest build = parse(args, workDir);
try (SimpleJavaLibraryBuilder builder =
build.getDependencyModule().reduceClasspath()
? new ReducedClasspathJavaLibraryBuilder()
Expand Down Expand Up @@ -122,12 +128,13 @@ protected int build(
* @throws InvalidCommandLineException on any command line error
*/
@VisibleForTesting
public JavaLibraryBuildRequest parse(List<String> args)
public JavaLibraryBuildRequest parse(List<String> args, Path workDir)
throws IOException, InvalidCommandLineException {
OptionsParser optionsParser =
new OptionsParser(args, JavacOptions.createWithWarningsAsErrorsDefault(ImmutableList.of()));
ImmutableList<BlazeJavaCompilerPlugin> plugins =
ImmutableList.of(new ErrorPronePlugin(BazelScannerSuppliers.bazelChecks()));
return new JavaLibraryBuildRequest(optionsParser, plugins, new DependencyModule.Builder());
return new JavaLibraryBuildRequest(
optionsParser, plugins, new DependencyModule.Builder(), workDir);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand All @@ -44,7 +43,10 @@

/** All the information needed to perform a single Java library build operation. */
public final class JavaLibraryBuildRequest {
private ImmutableList<String> javacOpts;
private final ImmutableList<String> javacOpts;

/** The directory relative to which all other paths should be resolved. */
private final Path workDir;

/** Where to store source files generated by annotation processors. */
private final Path sourceGenDir;
Expand Down Expand Up @@ -104,7 +106,7 @@ public final class JavaLibraryBuildRequest {
public JavaLibraryBuildRequest(
OptionsParser optionsParser, List<BlazeJavaCompilerPlugin> extraPlugins)
throws InvalidCommandLineException, IOException {
this(optionsParser, extraPlugins, new DependencyModule.Builder());
this(optionsParser, extraPlugins, new DependencyModule.Builder(), Path.of(""));
}

/**
Expand All @@ -114,14 +116,16 @@ public JavaLibraryBuildRequest(
* @param optionsParser the parsed command line args.
* @param extraPlugins extraneous plugins to use in addition to the strict dependency module.
* @param depsBuilder a preconstructed dependency module builder.
* @param workDir the directory relative to which all other paths should be resolved.
* @throws InvalidCommandLineException on any command line error
*/
public JavaLibraryBuildRequest(
OptionsParser optionsParser,
List<BlazeJavaCompilerPlugin> extraPlugins,
DependencyModule.Builder depsBuilder)
DependencyModule.Builder depsBuilder,
Path workDir)
throws InvalidCommandLineException, IOException {
this(optionsParser, extraPlugins, depsBuilder, ImmutableMap.of(), OptionalInt.empty());
this(optionsParser, extraPlugins, depsBuilder, ImmutableMap.of(), workDir, OptionalInt.empty());
}

/**
Expand All @@ -139,19 +143,22 @@ public JavaLibraryBuildRequest(
List<BlazeJavaCompilerPlugin> extraPlugins,
DependencyModule.Builder depsBuilder,
ImmutableMap<String, ByteString> inputsAndDigest,
Path workDir,
OptionalInt requestId)
throws InvalidCommandLineException, IOException {
// Keep this first as it is used by asPath.
this.workDir = workDir;
depsBuilder.setDirectJars(
optionsParser.directJars().stream().map(Paths::get).collect(toImmutableSet()));
optionsParser.directJars().stream().map(this::asPath).collect(toImmutableSet()));
if (optionsParser.getStrictJavaDeps() != null) {
depsBuilder.setStrictJavaDeps(optionsParser.getStrictJavaDeps());
}
if (optionsParser.getOutputDepsProtoFile() != null) {
depsBuilder.setOutputDepsProtoFile(Paths.get(optionsParser.getOutputDepsProtoFile()));
depsBuilder.setOutputDepsProtoFile(asPath(optionsParser.getOutputDepsProtoFile()));
}
depsBuilder.addDepsArtifacts(asPaths(optionsParser.getDepsArtifacts()));
depsBuilder.setPlatformJars(
optionsParser.getBootClassPath().stream().map(Paths::get).collect(toImmutableSet()));
optionsParser.getBootClassPath().stream().map(this::asPath).collect(toImmutableSet()));
if (optionsParser.reduceClasspathMode() != OptionsParser.ReduceClasspathMode.NONE) {
depsBuilder.setReduceClasspath();
}
Expand All @@ -165,7 +172,7 @@ public JavaLibraryBuildRequest(
AnnotationProcessingModule.Builder processingBuilder = AnnotationProcessingModule.builder();
processingBuilder.setSourceGenDir(sourceGenDir);
if (optionsParser.getManifestProtoPath() != null) {
processingBuilder.setManifestProtoPath(Paths.get(optionsParser.getManifestProtoPath()));
processingBuilder.setManifestProtoPath(asPath(optionsParser.getManifestProtoPath()));
}
this.processingModule = processingBuilder.build();

Expand Down Expand Up @@ -217,25 +224,29 @@ public JavaLibraryBuildRequest(
*/
// TODO(b/169793789): kill this with fire if javahotswap starts using jars instead of classes
@VisibleForTesting
static Path deriveDirectory(String label, String outputJar, String suffix) throws IOException {
static Path deriveDirectory(String label, String outputJar, String suffix, Path workDir) {
checkArgument(label != null, "--target_label is required");
checkArgument(outputJar != null, "--output is required");
checkArgument(
label.contains(":"), "--target_label must be a canonical label (containing a `:`)");

Path path = Paths.get(outputJar);
Path path = workDir.resolve(outputJar);
String name = MoreFiles.getNameWithoutExtension(path);
String base = label.substring(label.lastIndexOf(':') + 1);
return path.resolveSibling("_javac").resolve(base).resolve(name + suffix);
}

private static ImmutableList<Path> asPaths(Collection<String> paths) {
return paths.stream().map(Paths::get).collect(toImmutableList());
private Path deriveDirectory(String label, String outputJar, String suffix) {
return deriveDirectory(label, outputJar, suffix, workDir);
}

private ImmutableList<Path> asPaths(Collection<String> paths) {
return paths.stream().map(this::asPath).collect(toImmutableList());
}

@Nullable
private static Path asPath(@Nullable String path) {
return path != null ? Paths.get(path) : null;
private Path asPath(@Nullable String path) {
return path != null ? workDir.resolve(path) : null;
}

public ImmutableList<String> getJavacOpts() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@ private ImmutableMap<String, String> getExecutionInfo() throws RuleErrorExceptio
if (javaToolchain.getJavacSupportsWorkerCancellation()) {
modifiableExecutionInfo.put(ExecutionRequirements.SUPPORTS_WORKER_CANCELLATION, "1");
}
if (javaToolchain.getJavacSupportsWorkerMultiplexSandboxing()) {
modifiableExecutionInfo.put(ExecutionRequirements.SUPPORTS_MULTIPLEX_SANDBOXING, "1");
}
ImmutableMap.Builder<String, String> executionInfo = ImmutableMap.builder();
executionInfo.putAll(
getConfiguration()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ public boolean getJavacSupportsWorkerCancellation() throws RuleErrorException {
return getUnderlyingValue("_javac_supports_worker_cancellation", Boolean.class);
}

/** Returns whether JavaBuilders supports running multiplex persistent workers in sandbox mode */
public boolean getJavacSupportsWorkerMultiplexSandboxing() throws RuleErrorException {
return getUnderlyingValue("_javac_supports_worker_multiplex_sandboxing", Boolean.class);
}

/** Returns the global {@code java_package_configuration} data. */
public ImmutableList<JavaPackageConfigurationProvider> packageConfiguration()
throws RuleErrorException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ The Java target version (e.g., '6' or '7'). It specifies for which Java runtime
True if JavaBuilder supports cancellation of persistent workers, false if it doesn't.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
.add(attr("javac_supports_worker_cancellation", BOOLEAN).value(true))
/* <!-- #BLAZE_RULE(java_toolchain).ATTRIBUTE(javac_supports_worker_multiplex_sandboxing) -->
True if JavaBuilder supports multiplex sandboxing, false if it doesn't.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
.add(attr("javac_supports_worker_multiplex_sandboxing", BOOLEAN).value(false))
/* <!-- #BLAZE_RULE(java_toolchain).ATTRIBUTE(tools) -->
Labels of tools available for label-expansion in jvm_opts.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public WorkRequest readWorkRequest() throws IOException {
List<Input> inputs = null;
Integer requestId = null;
Integer verbosity = null;
String sandboxDir = null;
try {
reader.beginObject();
while (reader.hasNext()) {
Expand Down Expand Up @@ -134,6 +135,12 @@ public WorkRequest readWorkRequest() throws IOException {
}
verbosity = reader.nextInt();
break;
case "sandboxDir":
if (sandboxDir != null) {
throw new IOException("Work response cannot have more than one sandboxDir");
}
sandboxDir = reader.nextString();
break;
default:
// As per https://bazel.build/docs/creating-workers#work-responses,
// unknown fields are ignored.
Expand All @@ -159,6 +166,9 @@ public WorkRequest readWorkRequest() throws IOException {
if (verbosity != null) {
requestBuilder.setVerbosity(verbosity);
}
if (sandboxDir != null) {
requestBuilder.setSandboxDir(sandboxDir);
}
return requestBuilder.build();
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/starlark/builtins_bzl/common/java/java_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ JavaToolchainInfo, _new_javatoolchaininfo = provider(
"_javac_supports_workers": _PRIVATE_API_DOC_STRING,
"_javac_supports_multiplex_workers": _PRIVATE_API_DOC_STRING,
"_javac_supports_worker_cancellation": _PRIVATE_API_DOC_STRING,
"_javac_supports_worker_multiplex_sandboxing": _PRIVATE_API_DOC_STRING,
"_jspecify_info": _PRIVATE_API_DOC_STRING,
"_local_java_optimization_config": _PRIVATE_API_DOC_STRING,
"_one_version_tool": _PRIVATE_API_DOC_STRING,
Expand Down Expand Up @@ -116,6 +117,7 @@ def _java_toolchain_impl(ctx):
_javac_supports_workers = ctx.attr.javac_supports_workers,
_javac_supports_multiplex_workers = ctx.attr.javac_supports_multiplex_workers,
_javac_supports_worker_cancellation = ctx.attr.javac_supports_worker_cancellation,
_javac_supports_worker_multiplex_sandboxing = ctx.attr.javac_supports_worker_multiplex_sandboxing,
_jspecify_info = _get_jspecify_info(ctx),
_local_java_optimization_config = ctx.files._local_java_optimization_configuration,
_one_version_tool = ctx.attr.oneversion.files_to_run if ctx.attr.oneversion else None,
Expand Down Expand Up @@ -242,6 +244,7 @@ _java_toolchain = rule(
"javac_supports_workers": attr.bool(default = True),
"javac_supports_multiplex_workers": attr.bool(default = True),
"javac_supports_worker_cancellation": attr.bool(default = True),
"javac_supports_worker_multiplex_sandboxing": attr.bool(default = False),
"javacopts": attr.string_list(default = []),
"jspecify_implicit_deps": attr.label(cfg = "exec", allow_single_file = True, executable = True),
"jspecify_javacopts": attr.string_list(),
Expand Down
32 changes: 32 additions & 0 deletions src/test/shell/bazel/bazel_java_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1949,4 +1949,36 @@ EOF
bazel build //pkg:a >& $TEST_log || fail "build failed"
}

function test_sandboxed_multiplexing() {
if [[ "${JAVA_TOOLS_ZIP}" == released ]]; then
# TODO: Enable test after the next java_tools release.
return 0
fi

mkdir -p pkg
cat << 'EOF' > pkg/BUILD
load("@bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")
default_java_toolchain(
name = "java_toolchain",
source_version = "17",
target_version = "17",
javac_supports_worker_multiplex_sandboxing = True,
)
java_library(name = "a", srcs = ["A.java"], deps = [":b"])
java_library(name = "b", srcs = ["B.java"])
EOF
cat << 'EOF' > pkg/A.java
public class A extends B {}
EOF
cat << 'EOF' > pkg/B.java
public class B {}
EOF

bazel build //pkg:a \
--experimental_worker_multiplex_sandboxing \
--java_language_version=17 \
--extra_toolchains=//pkg:java_toolchain_definition \
>& $TEST_log || fail "build failed"
}

run_suite "Java integration tests"

0 comments on commit c43ace2

Please sign in to comment.