Merge "Remove -fstrict-aliasing from arm32." into main
diff --git a/android/arch.go b/android/arch.go
index 4b4691b..152016c 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1884,10 +1884,10 @@
 		buildTargets = filterMultilibTargets(targets, "lib64")
 		// Reverse the targets so that the first architecture can depend on the second
 		// architecture module in order to merge the outputs.
-		reverseSliceInPlace(buildTargets)
+		ReverseSliceInPlace(buildTargets)
 	case "darwin_universal_common_first":
 		archTargets := filterMultilibTargets(targets, "lib64")
-		reverseSliceInPlace(archTargets)
+		ReverseSliceInPlace(archTargets)
 		buildTargets = append(getCommonTargets(targets), archTargets...)
 	default:
 		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 4b1a8f4..5d93f06 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -176,8 +176,6 @@
 	// (for example, that it is MixedBuildBuildable).
 	IsModuleNameAllowed(moduleName string, withinApex bool) bool
 
-	IsModuleDclaAllowed(moduleName string) bool
-
 	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
 	OutputBase() string
 
@@ -316,10 +314,6 @@
 	return true
 }
 
-func (m MockBazelContext) IsModuleDclaAllowed(_ string) bool {
-	return true
-}
-
 func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
 
 func (m MockBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
@@ -461,10 +455,6 @@
 	return false
 }
 
-func (n noopBazelContext) IsModuleDclaAllowed(_ string) bool {
-	return false
-}
-
 func (m noopBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
 	return []*bazel.BuildStatement{}
 }
@@ -598,17 +588,13 @@
 	if context.bazelEnabledModules[moduleName] {
 		return true
 	}
-	if withinApex && context.IsModuleDclaAllowed(moduleName) {
+	if withinApex && context.bazelDclaEnabledModules[moduleName] {
 		return true
 	}
 
 	return false
 }
 
-func (context *mixedBuildBazelContext) IsModuleDclaAllowed(moduleName string) bool {
-	return context.bazelDclaEnabledModules[moduleName]
-}
-
 func pwdPrefix() string {
 	// Darwin doesn't have /proc
 	if runtime.GOOS != "darwin" {
@@ -1284,6 +1270,12 @@
 		// because this would cause circular dependency. So, until we move aquery processing
 		// to the 'android' package, we need to handle special cases here.
 		switch buildStatement.Mnemonic {
+		case "RepoMappingManifest":
+			// It appears RepoMappingManifest files currently have
+			// non-deterministic content. Just emit empty files for
+			// now because they're unused.
+			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
+			WriteFileRuleVerbatim(ctx, out, "")
 		case "FileWrite", "SourceSymlinkManifest":
 			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
 			WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents)
diff --git a/android/config.go b/android/config.go
index 839ff05..fa43962 100644
--- a/android/config.go
+++ b/android/config.go
@@ -701,6 +701,10 @@
 		if c.productVariables.DeviceArch != nil && *c.productVariables.DeviceArch == "riscv64" {
 			return false
 		}
+		// Disable Bazel when Kythe is running
+		if c.EmitXrefRules() {
+			return false
+		}
 		if c.IsEnvTrue("GLOBAL_THINLTO") {
 			return false
 		}
diff --git a/android/depset_generic.go b/android/depset_generic.go
index ae14d32..45c1937 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -79,8 +79,8 @@
 	if order == TOPOLOGICAL {
 		// TOPOLOGICAL is implemented as a postorder traversal followed by reversing the output.
 		// Pre-reverse the inputs here so their order is maintained in the output.
-		directCopy = reverseSlice(direct)
-		transitiveCopy = reverseSlice(transitive)
+		directCopy = ReverseSlice(direct)
+		transitiveCopy = ReverseSlice(transitive)
 	} else {
 		directCopy = append([]T(nil), direct...)
 		transitiveCopy = append([]*DepSet[T](nil), transitive...)
@@ -175,16 +175,6 @@
 // its transitive dependencies, in which case the ordering of the duplicated element is not
 // guaranteed).
 func (d *DepSet[T]) ToList() []T {
-	return d.toList(firstUnique[T])
-}
-
-// toList returns the DepSet flattened to a list.  The order in the list is based on the order
-// of the DepSet.  POSTORDER and PREORDER orders return a postordered or preordered left to right
-// flattened list.  TOPOLOGICAL returns a list that guarantees that elements of children are listed
-// after all of their parents (unless there are duplicate direct elements in the DepSet or any of
-// its transitive dependencies, in which case the ordering of the duplicated element is not
-// guaranteed).  The firstUniqueFunc is used to remove duplicates from the list.
-func (d *DepSet[T]) toList(firstUniqueFunc func([]T) []T) []T {
 	if d == nil {
 		return nil
 	}
@@ -192,9 +182,9 @@
 	d.walk(func(paths []T) {
 		list = append(list, paths...)
 	})
-	list = firstUniqueFunc(list)
+	list = firstUniqueInPlace(list)
 	if d.reverse {
-		reverseSliceInPlace(list)
+		ReverseSliceInPlace(list)
 	}
 	return list
 }
diff --git a/android/fixture.go b/android/fixture.go
index 03abb7f..dbc3bc5 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -275,15 +275,6 @@
 	})
 }
 
-// Sync the mock filesystem with the current config, then modify the context,
-// This allows context modification that requires filesystem access.
-func FixtureModifyContextWithMockFs(mutator func(ctx *TestContext)) FixturePreparer {
-	return newSimpleFixturePreparer(func(f *fixture) {
-		f.config.mockFileSystem("", f.mockFS)
-		mutator(f.ctx)
-	})
-}
-
 func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
 	return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
 }
diff --git a/android/register.go b/android/register.go
index 5d277e1..64b0207 100644
--- a/android/register.go
+++ b/android/register.go
@@ -15,13 +15,9 @@
 package android
 
 import (
-	"bufio"
 	"fmt"
-	"path/filepath"
 	"reflect"
-	"regexp"
 
-	"android/soong/shared"
 	"github.com/google/blueprint"
 )
 
@@ -201,49 +197,6 @@
 	RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
 }
 
-func (c *Context) ParseBuildFiles(topDir string, existingBazelFiles []string) error {
-	result := map[string][]string{}
-
-	// Search for instances of `name = "$NAME"` (with arbitrary spacing).
-	targetNameRegex := regexp.MustCompile(`(?m)^\s*name\s*=\s*\"([^\"]+)\"`)
-
-	parseBuildFile := func(path string) error {
-		fullPath := shared.JoinPath(topDir, path)
-		sourceDir := filepath.Dir(path)
-
-		fileInfo, err := c.Config().fs.Stat(fullPath)
-		if err != nil {
-			return fmt.Errorf("Error accessing Bazel file '%s': %s", path, err)
-		}
-		if !fileInfo.IsDir() &&
-			(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") {
-			f, err := c.Config().fs.Open(fullPath)
-			if err != nil {
-				return fmt.Errorf("Error reading Bazel file '%s': %s", path, err)
-			}
-			defer f.Close()
-			scanner := bufio.NewScanner(f)
-			for scanner.Scan() {
-				line := scanner.Text()
-				matches := targetNameRegex.FindAllStringSubmatch(line, -1)
-				for _, match := range matches {
-					result[sourceDir] = append(result[sourceDir], match[1])
-				}
-			}
-		}
-		return nil
-	}
-
-	for _, path := range existingBazelFiles {
-		err := parseBuildFile(path)
-		if err != nil {
-			return err
-		}
-	}
-	c.Config().SetBazelBuildFileTargets(result)
-	return nil
-}
-
 // RegisterForApiBazelConversion is similar to RegisterForBazelConversion except that
 // it only generates API targets in the generated  workspace
 func (ctx *Context) RegisterForApiBazelConversion() {
diff --git a/android/test_suites.go b/android/test_suites.go
index b48d71a..63a709f 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -68,7 +68,8 @@
 		FlagWithOutput("-o ", outputFile).
 		FlagWithArg("-P ", "host/testcases").
 		FlagWithArg("-C ", testCasesDir.String()).
-		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths())
+		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
+        Flag("-sha256")
 	rule.Build("robolectric_tests_zip", "robolectric-tests.zip")
 
 	return outputFile
diff --git a/android/util.go b/android/util.go
index 9695454..e17d7b2 100644
--- a/android/util.go
+++ b/android/util.go
@@ -25,12 +25,12 @@
 )
 
 // CopyOf returns a new slice that has the same contents as s.
-func CopyOf(s []string) []string {
+func CopyOf[T any](s []T) []T {
 	// If the input is nil, return nil and not an empty list
 	if s == nil {
 		return s
 	}
-	return append([]string{}, s...)
+	return append([]T{}, s...)
 }
 
 // Concat returns a new slice concatenated from the two input slices. It does not change the input
@@ -288,22 +288,25 @@
 }
 
 // FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
-// each.  It modifies the slice contents in place, and returns a subslice of the original slice.
+// each.  It does not modify the input slice.
 func FirstUniqueStrings(list []string) []string {
-	// Do not moodify the input in-place, operate on a copy instead.
-	list = CopyOf(list)
-	// 128 was chosen based on BenchmarkFirstUniqueStrings results.
-	if len(list) > 128 {
-		return firstUnique(list)
-	}
 	return firstUnique(list)
 }
 
 // firstUnique returns all unique elements of a slice, keeping the first copy of each.  It
-// modifies the slice contents in place, and returns a subslice of the original slice.
+// does not modify the input slice.
 func firstUnique[T comparable](slice []T) []T {
-	// 4 was chosen based on Benchmark_firstUnique results.
-	if len(slice) > 4 {
+	// Do not modify the input in-place, operate on a copy instead.
+	slice = CopyOf(slice)
+	return firstUniqueInPlace(slice)
+}
+
+// firstUniqueInPlace returns all unique elements of a slice, keeping the first copy of
+// each.  It modifies the slice contents in place, and returns a subslice of the original
+// slice.
+func firstUniqueInPlace[T comparable](slice []T) []T {
+	// 128 was chosen based on BenchmarkFirstUniqueStrings results.
+	if len(slice) > 128 {
 		return firstUniqueMap(slice)
 	}
 	return firstUniqueList(slice)
@@ -348,15 +351,19 @@
 	return in[0:writeIndex]
 }
 
-// reverseSliceInPlace reverses the elements of a slice in place.
-func reverseSliceInPlace[T any](in []T) {
+// ReverseSliceInPlace reverses the elements of a slice in place and returns it.
+func ReverseSliceInPlace[T any](in []T) []T {
 	for i, j := 0, len(in)-1; i < j; i, j = i+1, j-1 {
 		in[i], in[j] = in[j], in[i]
 	}
+	return in
 }
 
-// reverseSlice returns a copy of a slice in reverse order.
-func reverseSlice[T any](in []T) []T {
+// ReverseSlice returns a copy of a slice in reverse order.
+func ReverseSlice[T any](in []T) []T {
+	if in == nil {
+		return in
+	}
 	out := make([]T, len(in))
 	for i := 0; i < len(in); i++ {
 		out[i] = in[len(in)-1-i]
diff --git a/android/util_test.go b/android/util_test.go
index bee31a9..20161e5 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -20,6 +20,7 @@
 	"strconv"
 	"strings"
 	"testing"
+	"unsafe"
 )
 
 var firstUniqueStringsTestCases = []struct {
@@ -385,7 +386,7 @@
 	emptyList := []string{}
 	copyOfEmptyList := CopyOf(emptyList)
 	AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
-	copyOfNilList := CopyOf(nil)
+	copyOfNilList := CopyOf([]string(nil))
 	AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
 }
 
@@ -754,3 +755,65 @@
 		})
 	}
 }
+
+var reverseTestCases = []struct {
+	name     string
+	in       []string
+	expected []string
+}{
+	{
+		name:     "nil",
+		in:       nil,
+		expected: nil,
+	},
+	{
+		name:     "empty",
+		in:       []string{},
+		expected: []string{},
+	},
+	{
+		name:     "one",
+		in:       []string{"one"},
+		expected: []string{"one"},
+	},
+	{
+		name:     "even",
+		in:       []string{"one", "two"},
+		expected: []string{"two", "one"},
+	},
+	{
+		name:     "odd",
+		in:       []string{"one", "two", "three"},
+		expected: []string{"three", "two", "one"},
+	},
+}
+
+func TestReverseSliceInPlace(t *testing.T) {
+	for _, testCase := range reverseTestCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			slice := CopyOf(testCase.in)
+			slice2 := slice
+			ReverseSliceInPlace(slice)
+			if !reflect.DeepEqual(slice, testCase.expected) {
+				t.Errorf("expected %#v, got %#v", testCase.expected, slice)
+			}
+			if unsafe.SliceData(slice) != unsafe.SliceData(slice2) {
+				t.Errorf("expected slices to share backing array")
+			}
+		})
+	}
+}
+
+func TestReverseSlice(t *testing.T) {
+	for _, testCase := range reverseTestCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			slice := ReverseSlice(testCase.in)
+			if !reflect.DeepEqual(slice, testCase.expected) {
+				t.Errorf("expected %#v, got %#v", testCase.expected, slice)
+			}
+			if slice != nil && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
+				t.Errorf("expected slices to have different backing arrays")
+			}
+		})
+	}
+}
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 9623a8b..7212a07 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -166,7 +166,7 @@
 		}
 	} else {
 		llvmStrip := config.ClangPath(ctx, "bin/llvm-strip")
-		llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so.1")
+		llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so")
 		for _, strip := range s.properties.Strip_files {
 			cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib)
 			if !ctx.Windows() {
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 95e52ae..480158c 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -677,7 +677,7 @@
 		if len(actionEntry.Arguments) < 1 {
 			return a.templateExpandActionBuildStatement(actionEntry)
 		}
-	case "FileWrite", "SourceSymlinkManifest":
+	case "FileWrite", "SourceSymlinkManifest", "RepoMappingManifest":
 		return a.fileWriteActionBuildStatement(actionEntry)
 	case "SymlinkTree":
 		return a.symlinkTreeActionBuildStatement(actionEntry)
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 1a35743..e127fd5 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1946,36 +1946,3 @@
 	actual, _ := prettyPrintAttribute(lla, 0)
 	android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual)
 }
-
-func TestAlreadyPresentBuildTarget(t *testing.T) {
-	bp := `
-	custom {
-		name: "foo",
-	}
-	custom {
-		name: "bar",
-	}
-	`
-	alreadyPresentBuildFile :=
-		MakeBazelTarget(
-			"custom",
-			"foo",
-			AttrNameToString{},
-		)
-	expectedBazelTargets := []string{
-		MakeBazelTarget(
-			"custom",
-			"bar",
-			AttrNameToString{},
-		),
-	}
-	registerCustomModule := func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-	}
-	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		AlreadyExistingBuildContents: alreadyPresentBuildFile,
-		Blueprint:                    bp,
-		ExpectedBazelTargets:         expectedBazelTargets,
-		Description:                  "Not duplicating work for an already-present BUILD target.",
-	})
-}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 89ef07b..140b214 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -21,7 +21,6 @@
 
 import (
 	"fmt"
-	"path/filepath"
 	"sort"
 	"strings"
 	"testing"
@@ -83,12 +82,7 @@
 	// ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
 	// Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
 	ExpectedBazelTargets []string
-	// AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file
-	// in the directory under test. The BUILD file has the given contents. This BUILD file
-	// will also be treated as "BUILD file to keep" by the simulated bp2build environment.
-	AlreadyExistingBuildContents string
-
-	Filesystem map[string]string
+	Filesystem           map[string]string
 	// Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
 	// This should used in conjunction with the Filesystem property to check for targets
 	// generated from a directory that is not the root.
@@ -125,22 +119,11 @@
 
 func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
 	t.Helper()
-	checkDir := "."
-	if tc.Dir != "" {
-		checkDir = tc.Dir
-	}
-	keepExistingBuildDirs := tc.KeepBuildFileForDirs
-	buildFilesToParse := []string{}
+	dir := "."
 	filesystem := make(map[string][]byte)
 	for f, content := range tc.Filesystem {
 		filesystem[f] = []byte(content)
 	}
-	if len(tc.AlreadyExistingBuildContents) > 0 {
-		buildFilePath := filepath.Join(checkDir, "BUILD")
-		filesystem[buildFilePath] = []byte(tc.AlreadyExistingBuildContents)
-		keepExistingBuildDirs = append(keepExistingBuildDirs, checkDir)
-		buildFilesToParse = append(buildFilesToParse, buildFilePath)
-	}
 
 	preparers := []android.FixturePreparer{
 		extraPreparer,
@@ -149,7 +132,7 @@
 		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 			ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
 		}),
-		android.FixtureModifyContextWithMockFs(func(ctx *android.TestContext) {
+		android.FixtureModifyContext(func(ctx *android.TestContext) {
 			// A default configuration for tests to not have to specify bp2build_available on top level
 			// targets.
 			bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
@@ -157,7 +140,7 @@
 					android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
 				},
 			)
-			for _, f := range keepExistingBuildDirs {
+			for _, f := range tc.KeepBuildFileForDirs {
 				bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
 					f: /*recursive=*/ false,
 				})
@@ -167,10 +150,6 @@
 			// from cloning modules to their original state after mutators run. This
 			// would lose some data intentionally set by these mutators.
 			ctx.SkipCloneModulesAfterMutators = true
-			err := ctx.ParseBuildFiles(".", buildFilesToParse)
-			if err != nil {
-				t.Errorf("error parsing build files in test setup: %s", err)
-			}
 		}),
 		android.FixtureModifyEnv(func(env map[string]string) {
 			if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
@@ -189,6 +168,10 @@
 		return
 	}
 
+	checkDir := dir
+	if tc.Dir != "" {
+		checkDir = tc.Dir
+	}
 	expectedTargets := map[string][]string{
 		checkDir: tc.ExpectedBazelTargets,
 	}
diff --git a/build_kzip.bash b/build_kzip.bash
index eeef7d4..b161861 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -35,8 +35,16 @@
 # sufficiently many files were generated.
 declare -r out="${OUT_DIR:-out}"
 
-# Build extraction files for C++ and Java. Build `merge_zips` which we use later.
-build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java xref_rust
+# Build extraction files and `merge_zips` which we use later.
+kzip_targets=(
+  merge_zips
+  xref_cxx
+  xref_java
+  # TODO: b/286390153 - reenable rust
+  # xref_rust
+)
+
+build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k "${kzip_targets[@]}"
 
 # Build extraction file for Go the files in build/{blueprint,soong} directories.
 declare -r abspath_out=$(realpath "${out}")
@@ -63,10 +71,9 @@
 set +e
 
 declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l)
-(($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
+(($kzip_count>100000)) || { >&2 printf "ERROR: Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
 
 # Pack
-# TODO(asmundak): this should be done by soong.
 declare -r allkzip="$KZIP_NAME.kzip"
 "$out/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
 
diff --git a/cc/afdo.go b/cc/afdo.go
index 137ea97..bc7cd52 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -34,7 +34,8 @@
 
 var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
 
-const afdoCFlagsFormat = "-fprofile-sample-use=%s"
+// This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering
+const afdoFlagsFormat = "-fprofile-sample-use=%s"
 
 func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
 	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
@@ -86,7 +87,7 @@
 	}
 	if path := afdo.Properties.FdoProfilePath; path != nil {
 		// The flags are prepended to allow overriding.
-		profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
+		profileUseFlag := fmt.Sprintf(afdoFlagsFormat, *path)
 		flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
 		flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
 
diff --git a/cc/cc.go b/cc/cc.go
index 52a30d7..6087970 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1997,9 +1997,6 @@
 func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	if !apexInfo.IsForPlatform() {
-		if !ctx.Config().BazelContext.IsModuleDclaAllowed(ctx.Module().Name()) {
-			return nil
-		}
 		apexKey := android.ApexConfigKey{
 			WithinApex:     true,
 			ApexSdkVersion: findApexSdkVersion(ctx, apexInfo).String(),
diff --git a/cc/config/global.go b/cc/config/global.go
index e450ba7..013b659 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -305,7 +305,7 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r487747c"
+	ClangDefaultVersion      = "clang-r498229"
 	ClangDefaultShortVersion = "17"
 
 	// Directories with warnings from Android.bp files.
diff --git a/cc/lto.go b/cc/lto.go
index 878c21f..510dd79 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -76,43 +76,44 @@
 		return flags
 	}
 	if lto.Properties.LtoEnabled {
-		var ltoCFlag string
-		var ltoLdFlag string
-		if lto.ThinLTO() {
-			ltoCFlag = "-flto=thin -fsplit-lto-unit"
-		} else {
-			ltoCFlag = "-flto=thin -fsplit-lto-unit"
-			ltoLdFlag = "-Wl,--lto-O0"
+		ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
+		var ltoLdFlags []string
+
+		// The module did not explicitly turn on LTO. Only leverage LTO's
+		// better dead code elinmination and CFG simplification, but do
+		// not perform costly optimizations for a balance between compile
+		// time, binary size and performance.
+		if !lto.ThinLTO() {
+			ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
 		}
 
-		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlag)
-		flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlag)
-
 		if Bool(lto.Properties.Whole_program_vtables) {
-			flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
+			ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables")
 		}
 
 		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
 			// Set appropriate ThinLTO cache policy
 			cacheDirFormat := "-Wl,--thinlto-cache-dir="
 			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
-			flags.Local.LdFlags = append(flags.Local.LdFlags, cacheDirFormat+cacheDir)
+			ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir)
 
 			// Limit the size of the ThinLTO cache to the lesser of 10% of available
 			// disk space and 10GB.
 			cachePolicyFormat := "-Wl,--thinlto-cache-policy="
 			policy := "cache_size=10%:cache_size_bytes=10g"
-			flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy)
+			ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
 		}
 
 		// If the module does not have a profile, be conservative and limit cross TU inline
 		// limit to 5 LLVM IR instructions, to balance binary size increase and performance.
-		if !ctx.isPgoCompile() && !ctx.isAfdoCompile() {
-			flags.Local.LdFlags = append(flags.Local.LdFlags,
-				"-Wl,-plugin-opt,-import-instr-limit=5")
+		if !ctx.Darwin() && !ctx.isPgoCompile() && !ctx.isAfdoCompile() {
+			ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
 		}
+
+		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
+		flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...)
 	}
 	return flags
 }
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index bf5af2c..22d64a2 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -21,6 +21,7 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"time"
 
@@ -724,22 +725,47 @@
 
 		// FIXME: 'frameworks/compile/slang' has a filegroup error due to an escaping issue
 		"frameworks/compile/slang",
-
-		// FIXME(b/260809113): 'prebuilts/clang/host/linux-x86/clang-dev' is a tool-generated symlink
-		// directory that contains a BUILD file. The bazel files finder code doesn't traverse into symlink dirs,
-		// and hence is not aware of this BUILD file and exclude it accordingly during symlink forest generation
-		// when checking against keepExistingBuildFiles allowlist.
-		//
-		// This is necessary because globs in //prebuilts/clang/host/linux-x86/BUILD
-		// currently assume no subpackages (keepExistingBuildFile is not recursive for that directory).
-		//
-		// This is a bandaid until we the symlink forest logic can intelligently exclude BUILD files found in
-		// source symlink dirs according to the keepExistingBuildFile allowlist.
-		"prebuilts/clang/host/linux-x86/clang-dev",
 	)
 	return excluded
 }
 
+// buildTargetsByPackage parses Bazel BUILD.bazel and BUILD files under
+// the workspace, and returns a map containing names of Bazel targets defined in
+// these BUILD files.
+// For example, maps "//foo/bar" to ["baz", "qux"] if `//foo/bar:{baz,qux}` exist.
+func buildTargetsByPackage(ctx *android.Context) map[string][]string {
+	existingBazelFiles, err := getExistingBazelRelatedFiles(topDir)
+	maybeQuit(err, "Error determining existing Bazel-related files")
+
+	result := map[string][]string{}
+
+	// Search for instances of `name = "$NAME"` (with arbitrary spacing).
+	targetNameRegex := regexp.MustCompile(`(?m)^\s*name\s*=\s*\"([^\"]+)\"`)
+
+	for _, path := range existingBazelFiles {
+		if !ctx.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) {
+			continue
+		}
+		fullPath := shared.JoinPath(topDir, path)
+		sourceDir := filepath.Dir(path)
+		fileInfo, err := os.Stat(fullPath)
+		maybeQuit(err, "Error accessing Bazel file '%s'", fullPath)
+
+		if !fileInfo.IsDir() &&
+			(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") {
+			// Process this BUILD file.
+			buildFileContent, err := os.ReadFile(fullPath)
+			maybeQuit(err, "Error reading Bazel file '%s'", fullPath)
+
+			matches := targetNameRegex.FindAllStringSubmatch(string(buildFileContent), -1)
+			for _, match := range matches {
+				result[sourceDir] = append(result[sourceDir], match[1])
+			}
+		}
+	}
+	return result
+}
+
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
@@ -748,11 +774,7 @@
 	ctx.EventHandler.Do("bp2build", func() {
 
 		ctx.EventHandler.Do("read_build", func() {
-			existingBazelFiles, err := getExistingBazelRelatedFiles(topDir)
-			maybeQuit(err, "Error determining existing Bazel-related files")
-
-			err = ctx.ParseBuildFiles(topDir, existingBazelFiles)
-			maybeQuit(err, "Error parsing existing Bazel-related files")
+			ctx.Config().SetBazelBuildFileTargets(buildTargetsByPackage(ctx))
 		})
 
 		// Propagate "allow misssing dependencies" bit. This is normally set in
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 6ead589..57c7ae8 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -310,7 +310,7 @@
 	// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
 	for ver, _ := range nestedClcMap {
 		if ver != AnySdkVersion {
-			clcPaths := ComputeClassLoaderContextDependencies(nestedClcMap)
+			_, clcPaths := ComputeClassLoaderContextDependencies(nestedClcMap)
 			return fmt.Errorf("nested class loader context shouldn't have conditional part: %+v", clcPaths)
 		}
 	}
@@ -553,27 +553,28 @@
 	return true, nil
 }
 
-// Returns a slice of build paths for all possible dependencies that the class loader context may
-// refer to.
+// Returns a slice of library names and a slice of build paths for all possible dependencies that
+// the class loader context may refer to.
 // Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
-func ComputeClassLoaderContextDependencies(clcMap ClassLoaderContextMap) android.Paths {
-	var paths android.Paths
+func ComputeClassLoaderContextDependencies(clcMap ClassLoaderContextMap) (names []string, paths android.Paths) {
 	for _, clcs := range clcMap {
-		hostPaths := ComputeClassLoaderContextDependenciesRec(clcs)
-		paths = append(paths, hostPaths...)
+		currentNames, currentPaths := ComputeClassLoaderContextDependenciesRec(clcs)
+		names = append(names, currentNames...)
+		paths = append(paths, currentPaths...)
 	}
-	return android.FirstUniquePaths(paths)
+	return android.FirstUniqueStrings(names), android.FirstUniquePaths(paths)
 }
 
 // Helper function for ComputeClassLoaderContextDependencies() that handles recursion.
-func ComputeClassLoaderContextDependenciesRec(clcs []*ClassLoaderContext) android.Paths {
-	var paths android.Paths
+func ComputeClassLoaderContextDependenciesRec(clcs []*ClassLoaderContext) (names []string, paths android.Paths) {
 	for _, clc := range clcs {
-		subPaths := ComputeClassLoaderContextDependenciesRec(clc.Subcontexts)
+		subNames, subPaths := ComputeClassLoaderContextDependenciesRec(clc.Subcontexts)
+		names = append(names, clc.Name)
 		paths = append(paths, clc.Host)
+		names = append(names, subNames...)
 		paths = append(paths, subPaths...)
 	}
-	return paths
+	return names, paths
 }
 
 // Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 39b4652..7260abb 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -97,10 +97,11 @@
 
 	fixClassLoaderContext(m)
 
-	var havePaths android.Paths
+	var actualNames []string
+	var actualPaths android.Paths
 	var haveUsesLibsReq, haveUsesLibsOpt []string
 	if valid && validationError == nil {
-		havePaths = ComputeClassLoaderContextDependencies(m)
+		actualNames, actualPaths = ComputeClassLoaderContextDependencies(m)
 		haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
 	}
 
@@ -112,19 +113,26 @@
 	})
 
 	// Test that all expected build paths are gathered.
-	t.Run("paths", func(t *testing.T) {
-		wantPaths := []string{
+	t.Run("names and paths", func(t *testing.T) {
+		expectedNames := []string{
+			"a'", "a1", "a2", "a3", "android.hidl.base-V1.0-java", "android.hidl.manager-V1.0-java", "b",
+			"b1", "b2", "b3", "c", "c2", "d", "f",
+		}
+		expectedPaths := []string{
 			"out/soong/android.hidl.manager-V1.0-java.jar", "out/soong/android.hidl.base-V1.0-java.jar",
 			"out/soong/a.jar", "out/soong/b.jar", "out/soong/c.jar", "out/soong/d.jar",
 			"out/soong/a2.jar", "out/soong/b2.jar", "out/soong/c2.jar",
 			"out/soong/a1.jar", "out/soong/b1.jar",
 			"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
 		}
-		actual := havePaths.Strings()
+		actualPathsStrs := actualPaths.Strings()
 		// The order does not matter.
-		sort.Strings(wantPaths)
-		sort.Strings(actual)
-		android.AssertArrayString(t, "", wantPaths, actual)
+		sort.Strings(expectedNames)
+		sort.Strings(actualNames)
+		android.AssertArrayString(t, "", expectedNames, actualNames)
+		sort.Strings(expectedPaths)
+		sort.Strings(actualPathsStrs)
+		android.AssertArrayString(t, "", expectedPaths, actualPathsStrs)
 	})
 
 	// Test the JSON passed to construct_context.py.
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 20737e3..29ae188 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -353,7 +353,7 @@
 		}
 
 		// Generate command that saves host and target class loader context in shell variables.
-		paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
+		_, paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
 		rule.Command().
 			Text(`eval "$(`).Tool(globalSoong.ConstructContext).
 			Text(` --target-sdk-version ${target_sdk_version}`).
@@ -630,5 +630,3 @@
 	}
 	return false
 }
-
-var copyOf = android.CopyOf
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index b470304..ada4712 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -368,6 +368,9 @@
 	Triage_assignee string `json:"triage_assignee,omitempty"`
 	// Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
 	Use_platform_libs UsePlatformLibs `json:"use_platform_libs,omitempty"`
+	// Specifies whether fuzz target should check presubmitted code changes for crashes.
+	// Defaults to false.
+	Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"`
 }
 
 type FuzzFrameworks struct {
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index c767685..02b1145 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -56,7 +56,6 @@
 		"RSTest-rscript",
 		"BluetoothGeneratedDumpsysBinarySchema_bfbs",
 		"TracingVMProtoStub_h",
-		"FrontendStub_h",
 		"VehicleServerProtoStub_cc",
 		"AudioFocusControlProtoStub_cc",
 		"AudioFocusControlProtoStub_h",
@@ -98,7 +97,6 @@
 		"BlueberryFacadeGeneratedStub_cc",
 		"BlueberryFacadeGeneratedStub_h",
 		"BluetoothGeneratedDumpsysDataSchema_h",
-		"FrontendStub_cc",
 		"OpenwrtControlServerProto_cc",
 		"OpenwrtControlServerProto_h",
 		"c2hal_test_genc++",
diff --git a/java/app_import.go b/java/app_import.go
index 9c01960..8427217 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -17,6 +17,7 @@
 // This file contains the module implementations for android_app_import and android_test_import.
 
 import (
+	"fmt"
 	"reflect"
 
 	"github.com/google/blueprint"
@@ -410,6 +411,15 @@
 	return a.outputFile
 }
 
+func (a *AndroidAppImport) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return []android.Path{a.outputFile}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (a *AndroidAppImport) JacocoReportClassesFile() android.Path {
 	return nil
 }
diff --git a/java/app_test.go b/java/app_test.go
index cf7d174..0f98416 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2697,7 +2697,7 @@
 	cmd := app.Rule("dexpreopt").RuleParams.Command
 	android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
 	android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
-		"--product-packages=out/soong/target/product/test_device/product_packages.txt")
+		"--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/product_packages.txt")
 }
 
 func TestDexpreoptBcp(t *testing.T) {
diff --git a/java/base.go b/java/base.go
index 75e25e3..f2ad5c2 100644
--- a/java/base.go
+++ b/java/base.go
@@ -2202,7 +2202,7 @@
 
 func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	switch ctx.ModuleType() {
-	case "java_library", "java_library_host", "java_library_static":
+	case "java_library", "java_library_host", "java_library_static", "tradefed_java_library_host":
 		if lib, ok := ctx.Module().(*Library); ok {
 			javaLibraryBp2Build(ctx, lib)
 		}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index e588c9a..998730e 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -390,11 +391,37 @@
 
 	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 
-	// "product_packages.txt" is generated by `build/make/core/Makefile`.
+	// The root "product_packages.txt" is generated by `build/make/core/Makefile`. It contains a list
+	// of all packages that are installed on the device. We use `grep` to filter the list by the app's
+	// dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime
+	// from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns.
 	productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
+	appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", "product_packages.txt")
+	appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
+	clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
+	sort.Strings(clcNames) // The order needs to be deterministic.
+	productPackagesRule := android.NewRuleBuilder(pctx, ctx)
+	if len(clcNames) > 0 {
+		productPackagesRule.Command().
+			Text("grep -F -x").
+			FlagForEachArg("-e ", clcNames).
+			Input(productPackages).
+			FlagWithOutput("> ", appProductPackagesStaging).
+			Text("|| true")
+	} else {
+		productPackagesRule.Command().
+			Text("rm -f").Output(appProductPackagesStaging).
+			Text("&&").
+			Text("touch").Output(appProductPackagesStaging)
+	}
+	productPackagesRule.Command().
+		Text("rsync --checksum").
+		Input(appProductPackagesStaging).
+		Output(appProductPackages)
+	productPackagesRule.Restat().Build("product_packages", "dexpreopt product_packages")
 
 	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
-		ctx, globalSoong, global, dexpreoptConfig, productPackages)
+		ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
 	if err != nil {
 		ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
 		return
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 35f6097..2b0f57e 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -789,7 +789,6 @@
 		Flag("--generate-build-id").
 		Flag("--image-format=lz4hc").
 		FlagWithArg("--oat-symbols=", symbolsFile.String()).
-		Flag("--strip").
 		FlagWithArg("--oat-file=", outputPath.String()).
 		FlagWithArg("--oat-location=", oatLocation).
 		FlagWithArg("--image=", imagePath.String()).
@@ -799,6 +798,11 @@
 		Flag("--force-determinism").
 		Flag("--abort-on-hard-verifier-error")
 
+	// We don't strip on host to make perf tools work.
+	if image.target.Os == android.Android {
+		cmd.Flag("--strip")
+	}
+
 	// If the image is profile-guided but the profile is disabled, we omit "--compiler-filter" to
 	// leave the decision to dex2oat to pick the compiler filter.
 	if !(image.isProfileGuided() && global.DisableGenerateProfile) {
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 9100e87..28f50d7 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -250,8 +250,6 @@
 
 var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath")
 
-var copyOf = android.CopyOf
-
 func init() {
 	android.RegisterMakeVarsProvider(pctx, dexpreoptConfigMakevars)
 }
diff --git a/java/java.go b/java/java.go
index caafaa2..50d48ab 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1624,13 +1624,6 @@
 	})
 }
 
-type JavaApiLibraryDepsInfo struct {
-	JavaInfo
-	StubsSrcJar android.Path
-}
-
-var JavaApiLibraryDepsProvider = blueprint.NewProvider(JavaApiLibraryDepsInfo{})
-
 type ApiLibrary struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -1672,10 +1665,11 @@
 	// merge zipped after metalava invocation
 	Static_libs []string
 
-	// Java Api library to provide the full API surface text files and jar file.
-	// If this property is set, the provided full API surface text files and
-	// jar file are passed to metalava invocation.
-	Dep_api_srcs *string
+	// Java Api library to provide the full API surface stub jar file.
+	// If this property is set, the stub jar of this module is created by
+	// extracting the compiled class files provided by the
+	// full_api_surface_stub module.
+	Full_api_surface_stub *string
 }
 
 func ApiLibraryFactory() android.Module {
@@ -1762,35 +1756,37 @@
 	}
 }
 
-// This method extracts the stub java files from the srcjar file provided from dep_api_srcs module
-// and replaces the java stubs generated by invoking metalava in this module.
+// This method extracts the stub class files from the stub jar file provided
+// from full_api_surface_stub module instead of compiling the srcjar generated from invoking metalava.
 // This method is used because metalava can generate compilable from-text stubs only when
-// the codebase encompasses all classes listed in the input API text file, but a class can extend
+// the codebase encompasses all classes listed in the input API text file, and a class can extend
 // a class that is not within the same API domain.
-func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.RuleBuilder, stubsDir android.OptionalPath, depApiSrcsSrcJar android.Path) {
-	generatedStubsList := android.PathForModuleOut(ctx, "metalava", "sources.txt")
+func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.RuleBuilder, stubsDir android.OptionalPath, fullApiSurfaceStubJar android.Path) {
+	classFilesList := android.PathForModuleOut(ctx, "metalava", "classes.txt")
 	unzippedSrcJarDir := android.PathForModuleOut(ctx, "metalava", "unzipDir")
 
 	rule.Command().
 		BuiltTool("list_files").
 		Text(stubsDir.String()).
-		FlagWithOutput("--out ", generatedStubsList).
+		FlagWithOutput("--out ", classFilesList).
 		FlagWithArg("--extensions ", ".java").
-		FlagWithArg("--root ", unzippedSrcJarDir.String())
+		FlagWithArg("--root ", unzippedSrcJarDir.String()).
+		Flag("--classes")
 
 	rule.Command().
 		Text("unzip").
 		Flag("-q").
-		Input(depApiSrcsSrcJar).
+		Input(fullApiSurfaceStubJar).
 		FlagWithArg("-d ", unzippedSrcJarDir.String())
 
 	rule.Command().
 		BuiltTool("soong_zip").
-		Flag("-srcjar").
+		Flag("-jar").
 		Flag("-write_if_changed").
+		Flag("-ignore_missing_files").
 		FlagWithArg("-C ", unzippedSrcJarDir.String()).
-		FlagWithInput("-l ", generatedStubsList).
-		FlagWithOutput("-o ", al.stubsSrcJar)
+		FlagWithInput("-l ", classFilesList).
+		FlagWithOutput("-o ", al.stubsJarWithoutStaticLibs)
 }
 
 func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1800,8 +1796,8 @@
 	}
 	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
-	if al.properties.Dep_api_srcs != nil {
-		ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Dep_api_srcs))
+	if al.properties.Full_api_surface_stub != nil {
+		ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Full_api_surface_stub))
 	}
 }
 
@@ -1823,7 +1819,7 @@
 	var srcFiles android.Paths
 	var classPaths android.Paths
 	var staticLibs android.Paths
-	var depApiSrcsStubsSrcJar android.Path
+	var depApiSrcsStubsJar android.Path
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		tag := ctx.OtherModuleDependencyTag(dep)
 		switch tag {
@@ -1841,9 +1837,8 @@
 			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
 			staticLibs = append(staticLibs, provider.HeaderJars...)
 		case depApiSrcsTag:
-			provider := ctx.OtherModuleProvider(dep, JavaApiLibraryDepsProvider).(JavaApiLibraryDepsInfo)
-			classPaths = append(classPaths, provider.HeaderJars...)
-			depApiSrcsStubsSrcJar = provider.StubsSrcJar
+			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+			depApiSrcsStubsJar = provider.HeaderJars[0]
 		}
 	})
 
@@ -1861,31 +1856,31 @@
 	al.stubsFlags(ctx, cmd, stubsDir)
 
 	al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
+	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar")
+	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
 
-	if depApiSrcsStubsSrcJar != nil {
-		al.extractApiSrcs(ctx, rule, stubsDir, depApiSrcsStubsSrcJar)
-	} else {
-		rule.Command().
-			BuiltTool("soong_zip").
-			Flag("-write_if_changed").
-			Flag("-jar").
-			FlagWithOutput("-o ", al.stubsSrcJar).
-			FlagWithArg("-C ", stubsDir.String()).
-			FlagWithArg("-D ", stubsDir.String())
+	if depApiSrcsStubsJar != nil {
+		al.extractApiSrcs(ctx, rule, stubsDir, depApiSrcsStubsJar)
 	}
+	rule.Command().
+		BuiltTool("soong_zip").
+		Flag("-write_if_changed").
+		Flag("-jar").
+		FlagWithOutput("-o ", al.stubsSrcJar).
+		FlagWithArg("-C ", stubsDir.String()).
+		FlagWithArg("-D ", stubsDir.String())
 
 	rule.Build("metalava", "metalava merged")
 
-	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar")
-	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
+	if depApiSrcsStubsJar == nil {
+		var flags javaBuilderFlags
+		flags.javaVersion = getStubsJavaVersion()
+		flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
+		flags.classpath = classpath(classPaths)
 
-	var flags javaBuilderFlags
-	flags.javaVersion = getStubsJavaVersion()
-	flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
-	flags.classpath = classpath(classPaths)
-
-	TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{},
-		android.Paths{al.stubsSrcJar}, flags, android.Paths{})
+		TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{},
+			android.Paths{al.stubsSrcJar}, flags, android.Paths{})
+	}
 
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().
@@ -1917,13 +1912,6 @@
 		ImplementationJars:             android.PathsIfNonNil(al.stubsJar),
 		AidlIncludeDirs:                android.Paths{},
 	})
-
-	ctx.SetProvider(JavaApiLibraryDepsProvider, JavaApiLibraryDepsInfo{
-		JavaInfo: JavaInfo{
-			HeaderJars: android.PathsIfNonNil(al.stubsJar),
-		},
-		StubsSrcJar: al.stubsSrcJar,
-	})
 }
 
 func (al *ApiLibrary) DexJarBuildPath() OptionalDexJarPath {
diff --git a/java/java_test.go b/java/java_test.go
index 561b187..4738304 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2208,7 +2208,7 @@
 	}
 }
 
-func TestJavaApiLibraryDepApiSrcs(t *testing.T) {
+func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) {
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
@@ -2234,7 +2234,7 @@
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
-			dep_api_srcs: "lib1",
+			full_api_surface_stub: "lib1",
 		}
 		`,
 		map[string][]byte{
@@ -2247,9 +2247,7 @@
 	manifest := m.Output("metalava.sbox.textproto")
 	sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
 	manifestCommand := sboxProto.Commands[0].GetCommand()
-
-	android.AssertStringDoesContain(t, "Command expected to contain module srcjar file", manifestCommand, "bar1-stubs.srcjar")
-	android.AssertStringDoesContain(t, "Command expected to contain output files list text file flag", manifestCommand, "--out __SBOX_SANDBOX_DIR__/out/sources.txt")
+	android.AssertStringDoesContain(t, "Command expected to contain full_api_surface_stub output jar", manifestCommand, "lib1.jar")
 }
 
 func TestJavaApiLibraryFilegroupInput(t *testing.T) {
diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go
index 6d59601..bf1b04d 100644
--- a/java/resourceshrinker.go
+++ b/java/resourceshrinker.go
@@ -22,7 +22,8 @@
 
 var shrinkResources = pctx.AndroidStaticRule("shrinkResources",
 	blueprint.RuleParams{
-		Command:     `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources`,
+		// Note that we suppress stdout to avoid successful log confirmations.
+		Command:     `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources >/dev/null`,
 		CommandDeps: []string{"${config.ResourceShrinkerCmd}"},
 	}, "raw_resources")
 
diff --git a/java/robolectric.go b/java/robolectric.go
index 6bbe872..0041af4 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -299,7 +299,7 @@
 func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	instrumentedApp *AndroidApp) {
 
-	srcJarArgs := copyOf(instrumentedApp.srcJarArgs)
+	srcJarArgs := android.CopyOf(instrumentedApp.srcJarArgs)
 	srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
 
 	for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index a3d81ce..dbb2f02 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1780,12 +1780,12 @@
 
 func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
 	props := struct {
-		Name              *string
-		Visibility        []string
-		Api_contributions []string
-		Libs              []string
-		Static_libs       []string
-		Dep_api_srcs      *string
+		Name                  *string
+		Visibility            []string
+		Api_contributions     []string
+		Libs                  []string
+		Static_libs           []string
+		Full_api_surface_stub *string
 	}{}
 
 	props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
@@ -1807,12 +1807,12 @@
 	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
 	props.Libs = append(props.Libs, "stub-annotations")
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
-	props.Dep_api_srcs = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text")
+	props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text")
 
 	// android_module_lib_stubs_current.from-text only comprises api contributions from art, conscrypt and i18n.
 	// Thus, replace with android_module_lib_stubs_current_full.from-text, which comprises every api domains.
 	if apiScope.kind == android.SdkModule {
-		props.Dep_api_srcs = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + "_full.from-text")
+		props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + "_full.from-text")
 	}
 
 	mctx.CreateModule(ApiLibraryFactory, &props)
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 7ba1f6d..c22b980 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1442,35 +1442,35 @@
 	`)
 
 	testCases := []struct {
-		scope            *apiScope
-		apiContributions []string
-		depApiSrcs       string
+		scope              *apiScope
+		apiContributions   []string
+		fullApiSurfaceStub string
 	}{
 		{
-			scope:            apiScopePublic,
-			apiContributions: []string{"foo.stubs.source.api.contribution"},
-			depApiSrcs:       "android_stubs_current.from-text",
+			scope:              apiScopePublic,
+			apiContributions:   []string{"foo.stubs.source.api.contribution"},
+			fullApiSurfaceStub: "android_stubs_current.from-text",
 		},
 		{
-			scope:            apiScopeSystem,
-			apiContributions: []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			depApiSrcs:       "android_system_stubs_current.from-text",
+			scope:              apiScopeSystem,
+			apiContributions:   []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+			fullApiSurfaceStub: "android_system_stubs_current.from-text",
 		},
 		{
-			scope:            apiScopeTest,
-			apiContributions: []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			depApiSrcs:       "android_test_stubs_current.from-text",
+			scope:              apiScopeTest,
+			apiContributions:   []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+			fullApiSurfaceStub: "android_test_stubs_current.from-text",
 		},
 		{
-			scope:            apiScopeModuleLib,
-			apiContributions: []string{"foo.stubs.source.module_lib.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			depApiSrcs:       "android_module_lib_stubs_current_full.from-text",
+			scope:              apiScopeModuleLib,
+			apiContributions:   []string{"foo.stubs.source.module_lib.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+			fullApiSurfaceStub: "android_module_lib_stubs_current_full.from-text",
 		},
 	}
 
 	for _, c := range testCases {
 		m := result.ModuleForTests(c.scope.apiLibraryModuleName("foo"), "android_common").Module().(*ApiLibrary)
 		android.AssertArrayString(t, "Module expected to contain api contributions", c.apiContributions, m.properties.Api_contributions)
-		android.AssertStringEquals(t, "Module expected to contain full api surface api library", c.depApiSrcs, *m.properties.Dep_api_srcs)
+		android.AssertStringEquals(t, "Module expected to contain full api surface api library", c.fullApiSurfaceStub, *m.properties.Full_api_surface_stub)
 	}
 }
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 96645b0..7dc1b4b 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -247,7 +247,7 @@
 
 	var cmd, cmdDesc string
 	if b.Properties.Custom_bindgen != "" {
-		cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String()
+		cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(android.HostToolProvider).HostToolPath().String()
 		cmdDesc = b.Properties.Custom_bindgen
 	} else {
 		cmd = "$bindgenCmd"
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 894109a..d830968 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -1194,3 +1194,58 @@
 			expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "")
 	})
 }
+
+func TestSnapshotWithEmptyBootClasspathFragment(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mynewsdklibrary"),
+		java.FixtureConfigureApexBootJars("myapex:mysdklibrary", "myapex:mynewsdklibrary"),
+		prepareForSdkTestWithApex,
+		// Add a platform_bootclasspath that depends on the fragment.
+		fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
+		android.FixtureMergeEnv(map[string]string{
+			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
+		}),
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				apexes: ["myapex"],
+			}
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				min_sdk_version: "S",
+				bootclasspath_fragments: ["mybootclasspathfragment"],
+			}
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				apex_available: ["myapex"],
+				contents: ["mysdklibrary", "mynewsdklibrary"],
+				hidden_api: {
+					split_packages: [],
+				},
+			}
+			java_sdk_library {
+				name: "mysdklibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				shared_library: false,
+				public: {enabled: true},
+				min_sdk_version: "Tiramisu",
+			}
+			java_sdk_library {
+				name: "mynewsdklibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				compile_dex: true,
+				public: {enabled: true},
+				min_sdk_version: "Tiramisu",
+				permitted_packages: ["mynewsdklibrary"],
+			}
+		`),
+	).RunTest(t)
+
+	CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT.`))
+}
diff --git a/sdk/bp.go b/sdk/bp.go
index 7ff85a1..57eb2ca 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -311,13 +311,15 @@
 }
 
 func (m *bpModule) deepCopy() *bpModule {
-	return m.transform(deepCopyTransformer)
+	return transformModule(m, deepCopyTransformer)
 }
 
-func (m *bpModule) transform(transformer bpTransformer) *bpModule {
+func transformModule(m *bpModule, transformer bpTransformer) *bpModule {
 	transformedModule := transformer.transformModule(m)
-	// Copy the contents of the returned property set into the module and then transform that.
-	transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
+	if transformedModule != nil {
+		// Copy the contents of the returned property set into the module and then transform that.
+		transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
+	}
 	return transformedModule
 }
 
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 66c44c8..7ccc114 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -86,6 +86,51 @@
 	)
 }
 
+func TestSnapshotWithEmptySystemServerClasspathFragment(t *testing.T) {
+	commonSdk := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			min_sdk_version: "Tiramisu",
+			systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+		}
+		systemserverclasspath_fragment {
+			name: "mysystemserverclasspathfragment",
+			apex_available: ["myapex"],
+			contents: ["mysdklibrary"],
+		}
+		java_sdk_library {
+			name: "mysdklibrary",
+			apex_available: ["myapex"],
+			srcs: ["Test.java"],
+			min_sdk_version: "34", // UpsideDownCake
+		}
+		sdk {
+			name: "mysdk",
+			apexes: ["myapex"],
+		}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary"),
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:mysdklibrary"),
+		android.FixtureModifyEnv(func(env map[string]string) {
+			// targeting Tiramisu here means that we won't export mysdklibrary
+			env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = "Tiramisu"
+		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"UpsideDownCake"}
+		}),
+		prepareForSdkTestWithApex,
+		android.FixtureWithRootAndroidBp(commonSdk),
+	).RunTest(t)
+
+	CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT.`))
+}
+
 func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
 
 	commonSdk := `
diff --git a/sdk/update.go b/sdk/update.go
index d3c59b0..4c39fae 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -455,11 +455,14 @@
 
 	for _, module := range builder.prebuiltOrder {
 		// Prune any empty property sets.
-		module = module.transform(pruneEmptySetTransformer{})
+		module = transformModule(module, pruneEmptySetTransformer{})
 
 		// Transform the module module to make it suitable for use in the snapshot.
-		module.transform(snapshotTransformer)
-		bpFile.AddModule(module)
+		module = transformModule(module, snapshotTransformer)
+		module = transformModule(module, emptyClasspathContentsTransformation{})
+		if module != nil {
+			bpFile.AddModule(module)
+		}
 	}
 
 	// generate Android.bp
@@ -835,9 +838,11 @@
 }
 
 func (t snapshotTransformation) transformModule(module *bpModule) *bpModule {
-	// If the module is an internal member then use a unique name for it.
-	name := module.Name()
-	module.setProperty("name", t.builder.snapshotSdkMemberName(name, true))
+	if module != nil {
+		// If the module is an internal member then use a unique name for it.
+		name := module.Name()
+		module.setProperty("name", t.builder.snapshotSdkMemberName(name, true))
+	}
 	return module
 }
 
@@ -850,6 +855,25 @@
 	}
 }
 
+type emptyClasspathContentsTransformation struct {
+	identityTransformation
+}
+
+func (t emptyClasspathContentsTransformation) transformModule(module *bpModule) *bpModule {
+	classpathModuleTypes := []string{
+		"prebuilt_bootclasspath_fragment",
+		"prebuilt_systemserverclasspath_fragment",
+	}
+	if module != nil && android.InList(module.moduleType, classpathModuleTypes) {
+		if contents, ok := module.bpPropertySet.properties["contents"].([]string); ok {
+			if len(contents) == 0 {
+				return nil
+			}
+		}
+	}
+	return module
+}
+
 type pruneEmptySetTransformer struct {
 	identityTransformation
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index e642772..fb5f7dd 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1375,10 +1375,15 @@
 }
 
 func (c *configImpl) UseRBE() bool {
+	// These alternate modes of running Soong do not use RBE / reclient.
+	if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() {
+		return false
+	}
+
 	authType, _ := c.rbeAuth()
 	// Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
 	// its unlikely that we will be able to obtain necessary creds without stubby.
-	if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds"){
+	if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
 		return false
 	}
 	if v, ok := c.Environment().Get("USE_RBE"); ok {