Add property for incremental nsjail genrules

Normally genrule sandboxes run the build command in a clean state.
Setting keep_gendir as true, along with use_nsjail, will keep $(genDir)
so the genrule can be incrementally built.

Bug: 381459587
Test: build with and without the flag
Change-Id: I07bbea965f7b644ee8c8d2ead5b6abdd1f0c9aa6
diff --git a/android/neverallow.go b/android/neverallow.go
index 7f7ffa7..1213704 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -282,7 +282,7 @@
 }
 
 func createLimitDirgroupRule() []Rule {
-	reason := "dirgroup module and dir_srcs property of genrule is allowed only to Trusty build rule."
+	reason := "dirgroup module and dir_srcs / keep_gendir property of genrule is allowed only to Trusty build rule."
 	return []Rule{
 		NeverAllow().
 			ModuleType("dirgroup").
@@ -297,6 +297,13 @@
 			Without("name", "trusty-x86_64.lk.elf.gen").
 			Without("name", "trusty-x86_64-test.lk.elf.gen").
 			WithMatcher("dir_srcs", isSetMatcherInstance).Because(reason),
+		NeverAllow().
+			ModuleType("genrule").
+			Without("name", "trusty-arm64.lk.elf.gen").
+			Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen").
+			Without("name", "trusty-x86_64.lk.elf.gen").
+			Without("name", "trusty-x86_64-test.lk.elf.gen").
+			With("keep_gendir", "true").Because(reason),
 	}
 }
 
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 83f8b99..0df4357 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -63,6 +63,7 @@
 	missingDeps      []string
 	args             map[string]string
 	nsjail           bool
+	nsjailKeepGendir bool
 	nsjailBasePath   WritablePath
 	nsjailImplicits  Paths
 }
@@ -208,6 +209,18 @@
 	return r
 }
 
+// By default, nsjail rules truncate outputDir and baseDir before running commands, similar to Sbox
+// rules which always run commands in a fresh sandbox. Calling NsjailKeepGendir keeps outputDir and
+// baseDir as-is, leaving previous artifacts. This is useful when the rules support incremental
+// builds.
+func (r *RuleBuilder) NsjailKeepGendir() *RuleBuilder {
+	if !r.nsjail {
+		panic("NsjailKeepGendir() must be called after Nsjail()")
+	}
+	r.nsjailKeepGendir = true
+	return r
+}
+
 // SandboxTools enables tool sandboxing for the rule by copying any referenced tools into the
 // sandbox.
 func (r *RuleBuilder) SandboxTools() *RuleBuilder {
@@ -555,8 +568,17 @@
 	if r.nsjail {
 		var nsjailCmd strings.Builder
 		nsjailPath := r.ctx.Config().PrebuiltBuildTool(r.ctx, "nsjail")
+		if !r.nsjailKeepGendir {
+			nsjailCmd.WriteString("rm -rf ")
+			nsjailCmd.WriteString(r.nsjailBasePath.String())
+			nsjailCmd.WriteRune(' ')
+			nsjailCmd.WriteString(r.outDir.String())
+			nsjailCmd.WriteString(" && ")
+		}
 		nsjailCmd.WriteString("mkdir -p ")
 		nsjailCmd.WriteString(r.nsjailBasePath.String())
+		nsjailCmd.WriteRune(' ')
+		nsjailCmd.WriteString(r.outDir.String())
 		nsjailCmd.WriteString(" && ")
 		nsjailCmd.WriteString(nsjailPath.String())
 		nsjailCmd.WriteRune(' ')
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 9d2dbc7..ac62b8d 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -230,8 +230,9 @@
 	shards int
 
 	// For nsjail tasks
-	useNsjail bool
-	dirSrcs   android.DirectoryPaths
+	useNsjail  bool
+	dirSrcs    android.DirectoryPaths
+	keepGendir bool
 }
 
 func (g *Module) GeneratedSourceFiles() android.Paths {
@@ -487,6 +488,9 @@
 		name := "generator"
 		if task.useNsjail {
 			rule = android.NewRuleBuilder(pctx, ctx).Nsjail(task.genDir, android.PathForModuleOut(ctx, "nsjail_build_sandbox"))
+			if task.keepGendir {
+				rule.NsjailKeepGendir()
+			}
 		} else {
 			manifestName := "genrule.sbox.textproto"
 			if task.shards > 0 {
@@ -897,17 +901,24 @@
 			return nil
 		}
 
+		keepGendir := Bool(properties.Keep_gendir)
+		if keepGendir && !useNsjail {
+			ctx.PropertyErrorf("keep_gendir", "can't use keep_gendir if use_nsjail is false")
+			return nil
+		}
+
 		outs := make(android.WritablePaths, len(properties.Out))
 		for i, out := range properties.Out {
 			outs[i] = android.PathForModuleGen(ctx, out)
 		}
 		return []generateTask{{
-			in:        srcFiles,
-			out:       outs,
-			genDir:    android.PathForModuleGen(ctx),
-			cmd:       rawCommand,
-			useNsjail: useNsjail,
-			dirSrcs:   dirSrcs,
+			in:         srcFiles,
+			out:        outs,
+			genDir:     android.PathForModuleGen(ctx),
+			cmd:        rawCommand,
+			useNsjail:  useNsjail,
+			dirSrcs:    dirSrcs,
+			keepGendir: keepGendir,
 		}}
 	}
 
@@ -928,6 +939,10 @@
 	// dir_srcs is limited only to Trusty build.
 	Dir_srcs []string `android:"path"`
 
+	// If set to true, $(genDir) is not truncated. Useful when this genrule can be incrementally
+	// built. Can be set only when use_nsjail is true.
+	Keep_gendir *bool
+
 	// names of the output files that will be generated
 	Out []string `android:"arch_variant"`
 }