Strengthen metalava sandbox support using sbox

Run sandbox metalava rules inside sbox, which copies only the expected
inputs into a separate directory tree.  This ensures it can't read any
extra inputs.

Test: m hwbinder.stubs
Test: TestDroidstubs
Test: TestDroidstubsSandboxed
Change-Id: I71a83e3af6a385cc23f895397c2c883a2ac5fa22
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 75dd86b..e453e62 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -383,32 +383,42 @@
 
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
 		rule.Remoteable(android.RemoteRuleSupports{RBE: true})
-		pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
-		execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
-		labels := map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"}
-		if !sandbox {
-			execStrategy = remoteexec.LocalExecStrategy
-			labels["shallow"] = "true"
+		if sandbox {
+			execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+			labels := map[string]string{"type": "tool", "name": "metalava"}
+			// TODO: metalava pool rejects these jobs
+			pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
+			rule.Rewrapper(&remoteexec.REParams{
+				Labels:          labels,
+				ExecStrategy:    execStrategy,
+				ToolchainInputs: []string{config.JavaCmd(ctx).String()},
+				Platform:        map[string]string{remoteexec.PoolKey: pool},
+			})
+		} else {
+			execStrategy := remoteexec.LocalExecStrategy
+			labels := map[string]string{"type": "compile", "lang": "java", "compiler": "metalava", "shallow": "true"}
+			pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
+
+			inputs := []string{
+				ctx.Config().HostJavaToolPath(ctx, "metalava").String(),
+				homeDir.String(),
+			}
+			if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
+				inputs = append(inputs, strings.Split(v, ",")...)
+			}
+			cmd.Text((&remoteexec.REParams{
+				Labels:               labels,
+				ExecStrategy:         execStrategy,
+				Inputs:               inputs,
+				RSPFiles:             []string{implicitsRsp.String()},
+				ToolchainInputs:      []string{config.JavaCmd(ctx).String()},
+				Platform:             map[string]string{remoteexec.PoolKey: pool},
+				EnvironmentVariables: []string{"ANDROID_PREFS_ROOT"},
+			}).NoVarTemplate(ctx.Config().RBEWrapper()))
 		}
-		inputs := []string{
-			ctx.Config().HostJavaToolPath(ctx, "metalava").String(),
-			homeDir.String(),
-		}
-		if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
-			inputs = append(inputs, strings.Split(v, ",")...)
-		}
-		cmd.Text((&remoteexec.REParams{
-			Labels:               labels,
-			ExecStrategy:         execStrategy,
-			Inputs:               inputs,
-			RSPFiles:             []string{implicitsRsp.String()},
-			ToolchainInputs:      []string{config.JavaCmd(ctx).String()},
-			Platform:             map[string]string{remoteexec.PoolKey: pool},
-			EnvironmentVariables: []string{"ANDROID_PREFS_ROOT"},
-		}).NoVarTemplate(ctx.Config().RBEWrapper()))
 	}
 
-	cmd.BuiltTool("metalava").
+	cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
 		Flag(config.JavacVmFlags).
 		Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
 		FlagWithArg("-encoding ", "UTF-8").
@@ -416,18 +426,16 @@
 		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
 		FlagWithInput("@", srcJarList)
 
-	if javaHome := ctx.Config().Getenv("ANDROID_JAVA_HOME"); javaHome != "" {
-		cmd.Implicit(android.PathForSource(ctx, javaHome))
-	}
+	if !sandbox {
+		if javaHome := ctx.Config().Getenv("ANDROID_JAVA_HOME"); javaHome != "" {
+			cmd.Implicit(android.PathForSource(ctx, javaHome))
+		}
 
-	if sandbox {
-		cmd.FlagWithOutput("--strict-input-files ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
-	} else {
 		cmd.FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
-	}
 
-	if implicitsRsp != nil {
-		cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String())
+		if implicitsRsp != nil {
+			cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String())
+		}
 	}
 
 	if len(bootclasspath) > 0 {
@@ -465,6 +473,13 @@
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 
+	sandbox := proptools.Bool(d.Javadoc.properties.Sandbox)
+	if sandbox {
+		rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
+			android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
+			SandboxInputs()
+	}
+
 	if BoolDefault(d.properties.High_mem, false) {
 		// This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
 		rule.HighMem()
@@ -485,7 +500,7 @@
 	homeDir := android.PathForModuleOut(ctx, "metalava", "home")
 	cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
 		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp, homeDir,
-		Bool(d.Javadoc.properties.Sandbox))
+		sandbox)
 	cmd.Implicits(d.Javadoc.implicits)
 
 	d.stubsFlags(ctx, cmd, stubsDir)
@@ -610,17 +625,21 @@
 		cmd.FlagWithArg("--error-message:compatibility:released ", msg)
 	}
 
-	impRule := android.NewRuleBuilder(pctx, ctx)
-	impCmd := impRule.Command()
-	// An action that copies the ninja generated rsp file to a new location. This allows us to
-	// add a large number of inputs to a file without exceeding bash command length limits (which
-	// would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
-	// rsp file to be ${output}.rsp.
-	impCmd.Text("cp").
-		FlagWithRspFileInputList("", android.PathForModuleOut(ctx, "metalava-implicits.rsp"), cmd.GetImplicits()).
-		Output(implicitsRsp)
-	impRule.Build("implicitsGen", "implicits generation")
-	cmd.Implicit(implicitsRsp)
+	if !sandbox {
+		// When sandboxing is enabled RuleBuilder tracks all the inputs needed for remote execution.
+		// Without it we have to do it manually.
+		impRule := android.NewRuleBuilder(pctx, ctx)
+		impCmd := impRule.Command()
+		// An action that copies the ninja generated rsp file to a new location. This allows us to
+		// add a large number of inputs to a file without exceeding bash command length limits (which
+		// would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
+		// rsp file to be ${output}.rsp.
+		impCmd.Text("cp").
+			FlagWithRspFileInputList("", android.PathForModuleOut(ctx, "metalava-implicits.rsp"), cmd.GetImplicits()).
+			Output(implicitsRsp)
+		impRule.Build("implicitsGen", "implicits generation")
+		cmd.Implicit(implicitsRsp)
+	}
 
 	if generateStubs {
 		rule.Command().
@@ -652,7 +671,10 @@
 		rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
 	}
 
-	rule.Restat()
+	// TODO(b/183630617): rewrapper doesn't support restat rules
+	if !sandbox {
+		rule.Restat()
+	}
 
 	zipSyncCleanupCmd(rule, srcJarDir)