Merge changes Ied0a6cfe,I8c025efe into main

* changes:
  Reland: Use depsets for transitive manifests and assets
  Add test for manifest merger
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 8f63ec4..d962a1d 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -74,6 +74,8 @@
 
 	InApex  = "in_apex"
 	NonApex = "non_apex"
+
+	ErrorproneDisabled = "errorprone_disabled"
 )
 
 func PowerSetWithoutEmptySet[T any](items []T) [][]T {
@@ -216,6 +218,11 @@
 		NonApex:                    "//build/bazel/rules/apex:non_apex",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
+
+	errorProneMap = map[string]string{
+		ErrorproneDisabled:         "//build/bazel/rules/java/errorprone:errorprone_globally_disabled",
+		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
+	}
 )
 
 // basic configuration types
@@ -229,6 +236,7 @@
 	productVariables
 	osAndInApex
 	inApex
+	errorProneDisabled
 )
 
 func osArchString(os string, arch string) string {
@@ -237,13 +245,14 @@
 
 func (ct configurationType) String() string {
 	return map[configurationType]string{
-		noConfig:         "no_config",
-		arch:             "arch",
-		os:               "os",
-		osArch:           "arch_os",
-		productVariables: "product_variables",
-		osAndInApex:      "os_in_apex",
-		inApex:           "in_apex",
+		noConfig:           "no_config",
+		arch:               "arch",
+		os:                 "os",
+		osArch:             "arch_os",
+		productVariables:   "product_variables",
+		osAndInApex:        "os_in_apex",
+		inApex:             "in_apex",
+		errorProneDisabled: "errorprone_disabled",
 	}[ct]
 }
 
@@ -274,6 +283,10 @@
 		if _, ok := inApexMap[config]; !ok {
 			panic(fmt.Errorf("Unknown in_apex config: %s", config))
 		}
+	case errorProneDisabled:
+		if _, ok := errorProneMap[config]; !ok {
+			panic(fmt.Errorf("Unknown errorprone config: %s", config))
+		}
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
 	}
@@ -303,6 +316,8 @@
 		return config
 	case inApex:
 		return inApexMap[config]
+	case errorProneDisabled:
+		return errorProneMap[config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
 	}
@@ -321,6 +336,8 @@
 	OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
 	// An axis for in_apex-specific configurations
 	InApexAxis = ConfigurationAxis{configurationType: inApex}
+
+	ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/properties.go b/bazel/properties.go
index e22f4db..15af09b 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -766,7 +766,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex, inApex:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -782,7 +782,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables, osAndInApex, inApex:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -1346,7 +1346,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -1362,7 +1362,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 18cb9e1..4b36cc7 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -881,7 +881,7 @@
 		targets: []testBazelTarget{
 			{"cc_binary", "foo", AttrNameToString{
 				"local_includes": `["."]`,
-				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
 			}},
 		},
 	})
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 1e3d72e..490cd91 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -4194,11 +4194,11 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
 				"local_includes": `["."]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
 				"local_includes": `["."]`,
 			}),
 		},
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 2d61d53..ccb426f 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -1225,7 +1225,7 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
 				"local_includes": `["."]`,
 			}),
 		},
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 18225df..8084a5d 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1918,7 +1918,7 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
 				"local_includes": `["."]`,
 			}),
 		},
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index fd92e95..c501a7b 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -183,8 +183,8 @@
 	})
 }
 
-func TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
+func TestJavaLibraryErrorproneEnabledManually(t *testing.T) {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
@@ -192,7 +192,13 @@
     errorprone: {
         enabled: true,
         javacflags: ["-Xep:SpeedLimit:OFF"],
+        extra_check_modules: ["plugin2"],
     },
+}
+java_plugin {
+    name: "plugin2",
+    srcs: ["a.java"],
+    bazel_module: { bp2build_available: false },
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
@@ -200,10 +206,14 @@
         "-Xsuper-fast",
         "-Xep:SpeedLimit:OFF",
     ]`,
-				"srcs": `["a.java"]`,
+				"plugins":                 `[":plugin2"]`,
+				"srcs":                    `["a.java"]`,
+				"errorprone_force_enable": `True`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("java_plugin", java.PluginFactory)
 	})
 }
 
@@ -227,21 +237,23 @@
 	})
 }
 
-func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledManually(t *testing.T) {
+func TestJavaLibraryErrorproneDisabledManually(t *testing.T) {
 	runJavaLibraryTestCase(t, Bp2buildTestCase{
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
     javacflags: ["-Xsuper-fast"],
     errorprone: {
-		enabled: false,
-        javacflags: ["-Xep:SpeedLimit:OFF"],
+    enabled: false,
     },
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"javacopts": `["-Xsuper-fast"]`,
-				"srcs":      `["a.java"]`,
+				"javacopts": `[
+        "-Xsuper-fast",
+        "-XepDisableAllChecks",
+    ]`,
+				"srcs": `["a.java"]`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 5459595..85a2284 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -1819,7 +1819,7 @@
 			if blocklist != nil {
 				// Format the blocklist name to be used in a feature name
 				blocklistFeatureSuffix := strings.Replace(strings.ToLower(*blocklist), ".", "_", -1)
-				features = append(features, "ubsan_blocklist_"+blocklistFeatureSuffix)
+				features = append(features, "sanitizer_blocklist_"+blocklistFeatureSuffix)
 			}
 			if sanitizerProps.Sanitize.Cfi != nil && !proptools.Bool(sanitizerProps.Sanitize.Cfi) {
 				features = append(features, "-android_cfi")
diff --git a/cc/cc_test.go b/cc/cc_test.go
index fe54463..7534db2 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4979,7 +4979,6 @@
 
 	conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
 	cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
-	ltoFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
 
 	cflags := []string{"-Werror", "-std=candcpp"}
 	cstd := []string{"-std=gnu17", "-std=conly"}
@@ -5006,17 +5005,17 @@
 		{
 			name:     "c",
 			src:      "foo.c",
-			expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, ltoFlags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+			expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
 		},
 		{
 			name:     "cc",
 			src:      "foo.cc",
-			expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, ltoFlags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+			expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
 		},
 		{
 			name:     "assemble",
 			src:      "foo.s",
-			expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, ltoFlags, lastIncludes),
+			expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
 		},
 	}
 
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index 3bc1e69..40919c0 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -26,9 +26,6 @@
 		// Help catch common 32/64-bit errors.
 		"-Werror=implicit-function-declaration",
 		"-fno-emulated-tls",
-		// A temporary fix for SExtWRemoval miscompilation bug.
-		"-mllvm",
-		"-riscv-disable-sextw-removal=true",
 		"-march=rv64gc_zba_zbb_zbs",
 	}
 
diff --git a/cc/lto.go b/cc/lto.go
index e334af9..44361db 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -74,6 +74,9 @@
 	} else if ctx.Host() {
 		// Performance and binary size are less important for host binaries.
 		ltoDefault = false
+	} else if ctx.Arch().ArchType.Multilib == "lib32" {
+		// LP32 has many subtle issues and less test coverage.
+		ltoDefault = false
 	}
 
 	// Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index ba0648d..3fb4454 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -556,7 +556,8 @@
     {{- end}}
     {{- end}}
     {{- if .IsApk}}
-    presigned: true
+    preprocessed: true,
+    presigned: true,
     {{- end}}
 
 }
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 682fb75..4097e8a 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -218,6 +218,11 @@
 
 	trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
 
+	log.Verbose("Command Line: ")
+	for i, arg := range os.Args {
+		log.Verbosef("  [%d] %s", i, arg)
+	}
+
 	defer func() {
 		stat.Finish()
 		criticalPath.WriteToMetrics(met)
diff --git a/java/java.go b/java/java.go
index d3762f6..011dc1c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2767,11 +2767,12 @@
 type javaCommonAttributes struct {
 	*javaResourcesAttributes
 	*kotlinAttributes
-	Srcs         bazel.LabelListAttribute
-	Plugins      bazel.LabelListAttribute
-	Javacopts    bazel.StringListAttribute
-	Sdk_version  bazel.StringAttribute
-	Java_version bazel.StringAttribute
+	Srcs                    bazel.LabelListAttribute
+	Plugins                 bazel.LabelListAttribute
+	Javacopts               bazel.StringListAttribute
+	Sdk_version             bazel.StringAttribute
+	Java_version            bazel.StringAttribute
+	Errorprone_force_enable bazel.BoolAttribute
 }
 
 type javaDependencyLabels struct {
@@ -2913,26 +2914,35 @@
 		staticDeps.Add(&bazel.Label{Label: ":" + javaAidlLibName})
 	}
 
-	var javacopts []string
+	var javacopts bazel.StringListAttribute //[]string
+	plugins := bazel.MakeLabelListAttribute(
+		android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
+	)
 	if m.properties.Javacflags != nil {
-		javacopts = append(javacopts, m.properties.Javacflags...)
+		javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags)
 	}
 
 	epEnabled := m.properties.Errorprone.Enabled
-	//TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
-	if Bool(epEnabled) {
-		javacopts = append(javacopts, m.properties.Errorprone.Javacflags...)
+	epJavacflags := m.properties.Errorprone.Javacflags
+	var errorproneForceEnable bazel.BoolAttribute
+	if epEnabled == nil {
+		//TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
+	} else if *epEnabled {
+		plugins.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.properties.Errorprone.Extra_check_modules)))
+		javacopts.Append(bazel.MakeStringListAttribute(epJavacflags))
+		errorproneForceEnable.Value = epEnabled
+	} else {
+		javacopts.Append(bazel.MakeStringListAttribute([]string{"-XepDisableAllChecks"}))
 	}
 
 	commonAttrs := &javaCommonAttributes{
 		Srcs:                    javaSrcs,
 		javaResourcesAttributes: m.convertJavaResourcesAttributes(ctx),
-		Plugins: bazel.MakeLabelListAttribute(
-			android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
-		),
-		Javacopts:    bazel.MakeStringListAttribute(javacopts),
-		Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:  bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Plugins:                 plugins,
+		Javacopts:               javacopts,
+		Java_version:            bazel.StringAttribute{Value: m.properties.Java_version},
+		Sdk_version:             bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Errorprone_force_enable: errorproneForceEnable,
 	}
 
 	for axis, configToProps := range archVariantProps {
diff --git a/scripts/unpack-prebuilt-apex.sh b/scripts/unpack-prebuilt-apex.sh
index 2a20e45..18f4da2 100755
--- a/scripts/unpack-prebuilt-apex.sh
+++ b/scripts/unpack-prebuilt-apex.sh
@@ -17,7 +17,7 @@
 # limitations under the License.
 
 # Tool to unpack an apex file and verify that the required files were extracted.
-if [ $# -lt 7 ]; then
+if [ $# -lt 6 ]; then
   echo "usage: $0 <deapaxer_path> <debugfs_path> <fsck.erofs_path> <apex file> <output_dir> <required_files>+" >&2
   exit 1
 fi
diff --git a/tests/genrule_sandbox_test.py b/tests/genrule_sandbox_test.py
index a9f0c9b..0cebc2a 100755
--- a/tests/genrule_sandbox_test.py
+++ b/tests/genrule_sandbox_test.py
@@ -17,34 +17,37 @@
 import argparse
 import collections
 import json
-import os.path
+import os
 import subprocess
+import sys
 import tempfile
 
-SRC_ROOT_DIR = os.path.abspath(__file__ + "/../../../..")
+def get_top() -> str:
+  path = '.'
+  while not os.path.isfile(os.path.join(path, 'build/soong/tests/genrule_sandbox_test.py')):
+    if os.path.abspath(path) == '/':
+      sys.exit('Could not find android source tree root.')
+    path = os.path.join(path, '..')
+  return os.path.abspath(path)
 
-
-def _module_graph_path(out_dir):
-  return os.path.join(SRC_ROOT_DIR, out_dir, "soong", "module-actions.json")
-
-
-def _build_with_soong(targets, target_product, out_dir, extra_env={}):
+def _build_with_soong(targets, target_product, *, keep_going = False, extra_env={}):
   env = {
+      **os.environ,
       "TARGET_PRODUCT": target_product,
       "TARGET_BUILD_VARIANT": "userdebug",
   }
-  env.update(os.environ)
   env.update(extra_env)
   args = [
       "build/soong/soong_ui.bash",
       "--make-mode",
       "--skip-soong-tests",
   ]
+  if keep_going:
+    args.append("-k")
   args.extend(targets)
   try:
-    out = subprocess.check_output(
+    subprocess.check_output(
         args,
-        cwd=SRC_ROOT_DIR,
         env=env,
     )
   except subprocess.CalledProcessError as e:
@@ -55,14 +58,13 @@
 
 
 def _find_outputs_for_modules(modules, out_dir, target_product):
-  module_path = os.path.join(
-      SRC_ROOT_DIR, out_dir, "soong", "module-actions.json"
-  )
+  module_path = os.path.join(out_dir, "soong", "module-actions.json")
 
   if not os.path.exists(module_path):
-    _build_with_soong(["json-module-graph"], target_product, out_dir)
+    _build_with_soong(["json-module-graph"], target_product)
 
-  action_graph = json.load(open(_module_graph_path(out_dir)))
+  with open(module_path) as f:
+    action_graph = json.load(f)
 
   module_to_outs = collections.defaultdict(set)
   for mod in action_graph:
@@ -74,50 +76,15 @@
   return module_to_outs
 
 
-def _store_outputs_to_tmp(output_files):
-  try:
-    tempdir = tempfile.TemporaryDirectory()
-    for f in output_files:
-      out = subprocess.check_output(
-          ["cp", "--parents", f, tempdir.name],
-          cwd=SRC_ROOT_DIR,
-      )
-    return tempdir
-  except subprocess.CalledProcessError as e:
-    print(e)
-    print(e.stdout)
-    print(e.stderr)
-
-
-def _diff_outs(file1, file2, show_diff):
-  output = None
-  base_args = ["diff"]
-  if not show_diff:
-    base_args.append("--brief")
-  try:
-    args = base_args + [file1, file2]
-    output = subprocess.check_output(
-        args,
-        cwd=SRC_ROOT_DIR,
-    )
-  except subprocess.CalledProcessError as e:
-    if e.returncode == 1:
-      if show_diff:
-        return output
-      return True
-  return None
-
-
-def _compare_outputs(module_to_outs, tempdir, show_diff):
+def _compare_outputs(module_to_outs, tempdir) -> dict[str, list[str]]:
   different_modules = collections.defaultdict(list)
   for module, outs in module_to_outs.items():
     for out in outs:
-      output = None
-      diff = _diff_outs(os.path.join(tempdir.name, out), out, show_diff)
-      if diff:
-        different_modules[module].append(diff)
+      try:
+        subprocess.check_output(["diff", os.path.join(tempdir, out), out])
+      except subprocess.CalledProcessError as e:
+        different_modules[module].append(e.stdout)
 
-  tempdir.cleanup()
   return different_modules
 
 
@@ -138,53 +105,56 @@
       "--show-diff",
       "-d",
       action="store_true",
-      required=False,
       help="whether to display differing files",
   )
   parser.add_argument(
       "--output-paths-only",
       "-o",
       action="store_true",
-      required=False,
       help="Whether to only return the output paths per module",
   )
   args = parser.parse_args()
+  os.chdir(get_top())
 
   out_dir = os.environ.get("OUT_DIR", "out")
-  target_product = args.target_product
-  modules = set(args.modules)
 
-  module_to_outs = _find_outputs_for_modules(modules, out_dir, target_product)
+  print("finding output files for the modules...")
+  module_to_outs = _find_outputs_for_modules(set(args.modules), out_dir, args.target_product)
   if not module_to_outs:
-    print("No outputs found")
-    exit(1)
+    sys.exit("No outputs found")
 
   if args.output_paths_only:
     for m, o in module_to_outs.items():
       print(f"{m} outputs: {o}")
-    exit(0)
+    sys.exit(0)
 
-  all_outs = set()
-  for outs in module_to_outs.values():
-    all_outs.update(outs)
-  print("build without sandboxing")
-  _build_with_soong(list(all_outs), target_product, out_dir)
-  tempdir = _store_outputs_to_tmp(all_outs)
-  print("build with sandboxing")
-  _build_with_soong(
-      list(all_outs),
-      target_product,
-      out_dir,
-      extra_env={"GENRULE_SANDBOXING": "true"},
-  )
-  diffs = _compare_outputs(module_to_outs, tempdir, args.show_diff)
-  if len(diffs) == 0:
-    print("All modules are correct")
-  elif args.show_diff:
-    for m, d in diffs.items():
-      print(f"Module {m} has diffs {d}")
-  else:
-    print(f"Modules {list(diffs.keys())} have diffs")
+  all_outs = list(set.union(*module_to_outs.values()))
+
+  print("building without sandboxing...")
+  _build_with_soong(all_outs, args.target_product)
+  with tempfile.TemporaryDirectory() as tempdir:
+    for f in all_outs:
+      subprocess.check_call(["cp", "--parents", f, tempdir])
+
+    print("building with sandboxing...")
+    _build_with_soong(
+        all_outs,
+        args.target_product,
+        # We've verified these build without sandboxing already, so do the sandboxing build
+        # with keep_going = True so that we can find all the genrules that fail to build with
+        # sandboxing.
+        keep_going = True,
+        extra_env={"GENRULE_SANDBOXING": "true"},
+    )
+
+    diffs = _compare_outputs(module_to_outs, tempdir)
+    if len(diffs) == 0:
+      print("All modules are correct")
+    elif args.show_diff:
+      for m, d in diffs.items():
+        print(f"Module {m} has diffs {d}")
+    else:
+      print(f"Modules {list(diffs.keys())} have diffs")
 
 
 if __name__ == "__main__":