Merge "Generate ATS 2.0 config for Mobly test." into main
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index e6817e0..4b8d346 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -102,6 +102,13 @@
 		},
 	})
 
+	// Mark our generated code as possibly needing jarjar repackaging
+	// TODO: Maybe control this with a property?
+	module.AddJarJarRenameRule(declarations.Package+".Flags", "")
+	module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "")
+	module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "")
+	module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "")
+
 	return srcJarPath
 }
 
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index be9beb1..1444e7d 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -171,7 +171,7 @@
 }
 
 func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
-	inputs = LastUniquePaths(inputs)
+	inputs = SortedUniquePaths(inputs)
 	if len(inputs) == 1 {
 		return Paths{inputs[0]}
 	}
diff --git a/android/all_teams.go b/android/all_teams.go
index 6c3a219..dd7d2db 100644
--- a/android/all_teams.go
+++ b/android/all_teams.go
@@ -118,8 +118,8 @@
 // either the declared team data for that module or the package default team data for that module.
 func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
 	teamsProto := make([]*team_proto.Team, len(this.teams_for_mods))
-	i := 0
-	for moduleName, m := range this.teams_for_mods {
+	for i, moduleName := range SortedKeys(this.teams_for_mods) {
+		m, _ := this.teams_for_mods[moduleName]
 		teamName := m.teamName
 		var teamProperties teamProperties
 		found := false
@@ -152,7 +152,6 @@
 			}
 		}
 		teamsProto[i] = teamData
-		i++
 	}
 	return &team_proto.AllTeams{Teams: teamsProto}
 }
diff --git a/android/arch.go b/android/arch.go
index c39db02..4fe4345 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -426,6 +426,7 @@
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
 	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	defer bottomUpMutatorContextPool.Put(mctx)
 
 	base := module.base()
 
@@ -572,6 +573,7 @@
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
 	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	defer bottomUpMutatorContextPool.Put(mctx)
 
 	base := module.base()
 
@@ -1058,9 +1060,7 @@
 	// order checks the `android:"variant_prepend"` tag to handle properties where the
 	// arch-specific value needs to come before the generic value, for example for lists of
 	// include directories.
-	order := func(property string,
-		dstField, srcField reflect.StructField,
-		dstValue, srcValue interface{}) (proptools.Order, error) {
+	order := func(dstField, srcField reflect.StructField) (proptools.Order, error) {
 		if proptools.HasTag(dstField, "android", "variant_prepend") {
 			return proptools.Prepend, nil
 		} else {
diff --git a/android/module.go b/android/module.go
index 5c7bbbf..b615ff5 100644
--- a/android/module.go
+++ b/android/module.go
@@ -34,6 +34,7 @@
 var (
 	DeviceSharedLibrary = "shared_library"
 	DeviceStaticLibrary = "static_library"
+	jarJarPrefixHandler func(ctx ModuleContext)
 )
 
 type Module interface {
@@ -1772,6 +1773,13 @@
 			return
 		}
 
+		if jarJarPrefixHandler != nil {
+			jarJarPrefixHandler(ctx)
+			if ctx.Failed() {
+				return
+			}
+		}
+
 		m.module.GenerateAndroidBuildActions(ctx)
 		if ctx.Failed() {
 			return
@@ -1865,6 +1873,13 @@
 	m.variables = ctx.variables
 }
 
+func SetJarJarPrefixHandler(handler func(ModuleContext)) {
+	if jarJarPrefixHandler != nil {
+		panic("jarJarPrefixHandler already set")
+	}
+	jarJarPrefixHandler = handler
+}
+
 func (m *ModuleBase) moduleInfoRegisterName(ctx ModuleContext, subName string) string {
 	name := m.BaseModuleName()
 
diff --git a/android/mutator.go b/android/mutator.go
index 22e9160..0ff4f48 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,6 +15,8 @@
 package android
 
 import (
+	"sync"
+
 	"github.com/google/blueprint"
 )
 
@@ -328,29 +330,52 @@
 	SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{})
 }
 
+// An outgoingTransitionContextImpl and incomingTransitionContextImpl is created for every dependency of every module
+// for each transition mutator.  bottomUpMutatorContext and topDownMutatorContext are created once for every module
+// for every BottomUp or TopDown mutator.  Use a global pool for each to avoid reallocating every time.
+var (
+	outgoingTransitionContextPool = sync.Pool{
+		New: func() any { return &outgoingTransitionContextImpl{} },
+	}
+	incomingTransitionContextPool = sync.Pool{
+		New: func() any { return &incomingTransitionContextImpl{} },
+	}
+	bottomUpMutatorContextPool = sync.Pool{
+		New: func() any { return &bottomUpMutatorContext{} },
+	}
+
+	topDownMutatorContextPool = sync.Pool{
+		New: func() any { return &topDownMutatorContext{} },
+	}
+)
+
 type bottomUpMutatorContext struct {
 	bp blueprint.BottomUpMutatorContext
 	baseModuleContext
 	finalPhase bool
 }
 
+// callers must immediately follow the call to this function with defer bottomUpMutatorContextPool.Put(mctx).
 func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
 	finalPhase bool) BottomUpMutatorContext {
 
 	moduleContext := a.base().baseModuleContextFactory(ctx)
-
-	return &bottomUpMutatorContext{
+	mctx := bottomUpMutatorContextPool.Get().(*bottomUpMutatorContext)
+	*mctx = bottomUpMutatorContext{
 		bp:                ctx,
 		baseModuleContext: moduleContext,
 		finalPhase:        finalPhase,
 	}
+	return mctx
 }
 
 func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
 	finalPhase := x.finalPhase
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			m(bottomUpMutatorContextFactory(ctx, a, finalPhase))
+			mctx := bottomUpMutatorContextFactory(ctx, a, finalPhase)
+			defer bottomUpMutatorContextPool.Put(mctx)
+			m(mctx)
 		}
 	}
 	mutator := &mutator{name: x.mutatorName(name), bottomUpMutator: f}
@@ -514,7 +539,9 @@
 
 func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
 	if m, ok := bpctx.Module().(Module); ok {
-		ctx := &outgoingTransitionContextImpl{
+		ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl)
+		defer outgoingTransitionContextPool.Put(ctx)
+		*ctx = outgoingTransitionContextImpl{
 			archModuleContext: m.base().archModuleContextFactory(bpctx),
 			bp:                bpctx,
 		}
@@ -543,7 +570,9 @@
 
 func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
 	if m, ok := bpctx.Module().(Module); ok {
-		ctx := &incomingTransitionContextImpl{
+		ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl)
+		defer incomingTransitionContextPool.Put(ctx)
+		*ctx = incomingTransitionContextImpl{
 			archModuleContext: m.base().archModuleContextFactory(bpctx),
 			bp:                bpctx,
 		}
@@ -555,7 +584,9 @@
 
 func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
 	if am, ok := ctx.Module().(Module); ok {
-		a.mutator.Mutate(bottomUpMutatorContextFactory(ctx, am, a.finalPhase), variation)
+		mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
+		defer bottomUpMutatorContextPool.Put(mctx)
+		a.mutator.Mutate(mctx, variation)
 	}
 }
 
@@ -578,7 +609,9 @@
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
 			moduleContext := a.base().baseModuleContextFactory(ctx)
-			actx := &topDownMutatorContext{
+			actx := topDownMutatorContextPool.Get().(*topDownMutatorContext)
+			defer topDownMutatorContextPool.Put(actx)
+			*actx = topDownMutatorContext{
 				bp:                ctx,
 				baseModuleContext: moduleContext,
 			}
diff --git a/android/paths.go b/android/paths.go
index 95f53ea..61c1258 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1661,6 +1661,8 @@
 
 	// makePath indicates whether this path is for Soong (false) or Make (true).
 	makePath bool
+
+	fullPath string
 }
 
 // Will panic if called from outside a test environment.
@@ -1673,7 +1675,12 @@
 
 func (p InstallPath) RelativeToTop() Path {
 	ensureTestOnly()
-	p.soongOutDir = OutSoongDir
+	if p.makePath {
+		p.soongOutDir = OutDir
+	} else {
+		p.soongOutDir = OutSoongDir
+	}
+	p.fullPath = filepath.Join(p.soongOutDir, p.path)
 	return p
 }
 
@@ -1691,12 +1698,7 @@
 func (p InstallPath) writablePath() {}
 
 func (p InstallPath) String() string {
-	if p.makePath {
-		// Make path starts with out/ instead of out/soong.
-		return filepath.Join(p.soongOutDir, "../", p.path)
-	} else {
-		return filepath.Join(p.soongOutDir, p.path)
-	}
+	return p.fullPath
 }
 
 // PartitionDir returns the path to the partition where the install path is rooted at. It is
@@ -1726,6 +1728,7 @@
 
 func (p InstallPath) withRel(rel string) InstallPath {
 	p.basePath = p.basePath.withRel(rel)
+	p.fullPath = filepath.Join(p.fullPath, rel)
 	return p
 }
 
@@ -1769,6 +1772,25 @@
 	return os, arch
 }
 
+func pathForPartitionInstallDir(ctx PathContext, partition, partitionPath string, makePath bool) InstallPath {
+	fullPath := ctx.Config().SoongOutDir()
+	if makePath {
+		// Make path starts with out/ instead of out/soong.
+		fullPath = filepath.Join(fullPath, "../", partitionPath)
+	} else {
+		fullPath = filepath.Join(fullPath, partitionPath)
+	}
+
+	return InstallPath{
+		basePath:     basePath{partitionPath, ""},
+		soongOutDir:  ctx.Config().soongOutDir,
+		partitionDir: partitionPath,
+		partition:    partition,
+		makePath:     makePath,
+		fullPath:     fullPath,
+	}
+}
+
 func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string,
 	pathComponents ...string) InstallPath {
 
@@ -1805,27 +1827,12 @@
 		reportPathError(ctx, err)
 	}
 
-	base := InstallPath{
-		basePath:     basePath{partitionPath, ""},
-		soongOutDir:  ctx.Config().soongOutDir,
-		partitionDir: partitionPath,
-		partition:    partition,
-	}
-
-	if ctx.Config().KatiEnabled() {
-		base.makePath = true
-	}
-
+	base := pathForPartitionInstallDir(ctx, partition, partitionPath, ctx.Config().KatiEnabled())
 	return base.Join(ctx, pathComponents...)
 }
 
 func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
-	base := InstallPath{
-		basePath:     basePath{prefix, ""},
-		soongOutDir:  ctx.Config().soongOutDir,
-		partitionDir: prefix,
-		makePath:     false,
-	}
+	base := pathForPartitionInstallDir(ctx, "", prefix, false)
 	return base.Join(ctx, paths...)
 }
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index a94f5b7..13cda9d 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -518,7 +518,7 @@
 	// query all_apex_contributions to see if any module in this family has been selected
 	for _, moduleInFamily := range allModulesInFamily {
 		// validate that are no duplicates
-		if psi.IsSelected(moduleInFamily.Name()) {
+		if isSelected(psi, moduleInFamily) {
 			if selectedModuleInFamily == nil {
 				// Store this so we can validate that there are no duplicates
 				selectedModuleInFamily = moduleInFamily
@@ -547,13 +547,29 @@
 	if p := GetEmbeddedPrebuilt(m); p != nil {
 		bmn, _ := m.(baseModuleName)
 		name := bmn.BaseModuleName()
+		psi := PrebuiltSelectionInfoMap{}
+		ctx.VisitDirectDepsWithTag(acDepTag, func(am Module) {
+			psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
+		})
+
 		if p.properties.UsePrebuilt {
 			if p.properties.SourceExists {
 				ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+					if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
+						// Do not replace deps to the top-level prebuilt java_sdk_library hook.
+						// This hook has been special-cased in #isSelected to be _always_ active, even in next builds
+						// for dexpreopt and hiddenapi processing.
+						// If we do not special-case this here, rdeps referring to a java_sdk_library in next builds via libs
+						// will get prebuilt stubs
+						// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
+						if psi.IsSelected(*sdkLibrary.SdkLibraryName()) {
+							return false
+						}
+					}
+
 					if t, ok := tag.(ReplaceSourceWithPrebuilt); ok {
 						return t.ReplaceSourceWithPrebuilt()
 					}
-
 					return true
 				})
 			}
@@ -582,15 +598,20 @@
 func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool {
 	if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
 		sln := proptools.String(sdkLibrary.SdkLibraryName())
+
 		// This is the top-level library
 		// Do not supersede the existing prebuilts vs source selection mechanisms
-		if sln == m.base().BaseModuleName() {
+		// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
+		if bmn, ok := m.(baseModuleName); ok && sln == bmn.BaseModuleName() {
 			return false
 		}
 
 		// Stub library created by java_sdk_library_import
-		if p := GetEmbeddedPrebuilt(m); p != nil {
-			return psi.IsSelected(PrebuiltNameFromSource(sln))
+		// java_sdk_library creates several child modules (java_import + prebuilt_stubs_sources) dynamically.
+		// This code block ensures that these child modules are selected if the top-level java_sdk_library_import is listed
+		// in the selected apex_contributions.
+		if javaImport, ok := m.(createdByJavaSdkLibraryName); ok && javaImport.CreatedByJavaSdkLibraryName() != nil {
+			return psi.IsSelected(PrebuiltNameFromSource(proptools.String(javaImport.CreatedByJavaSdkLibraryName())))
 		}
 
 		// Stub library created by java_sdk_library
@@ -599,6 +620,11 @@
 	return psi.IsSelected(m.Name())
 }
 
+// implemented by child modules of java_sdk_library_import
+type createdByJavaSdkLibraryName interface {
+	CreatedByJavaSdkLibraryName() *string
+}
+
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
 func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 9355667..b2ff960 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -393,6 +393,7 @@
 // Export the name of the soong modules representing the various Java API surfaces.
 func javaSdkMakeVars(ctx MakeVarsContext) {
 	ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_PUBLIC_EXPORTABLE_STUBS", SdkPublic.DefaultExportableJavaLibraryName())
 	ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.DefaultJavaLibraryName())
 	ctx.Strict("ANDROID_TEST_STUBS", SdkTest.DefaultJavaLibraryName())
 	ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.DefaultJavaLibraryName())
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7e67c0f..d3959ec 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1455,6 +1455,7 @@
 			name: "libc",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			stubs: { versions: ["1"] },
@@ -1469,6 +1470,7 @@
 			name: "libclang_rt.hwasan",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			srcs: [""],
@@ -1511,6 +1513,7 @@
 			name: "libc",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			stubs: { versions: ["1"] },
@@ -1521,6 +1524,7 @@
 			name: "libclang_rt.hwasan",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			srcs: [""],
@@ -3768,13 +3772,6 @@
 				"lib64/libvndk.so",
 				"lib64/libvndksp.so"),
 		},
-		{
-			vndkVersion: "",
-			expectedFiles: append(commonFiles,
-				// Legacy VNDK APEX contains only VNDK-SP files (of core variant)
-				"lib/libvndksp.so",
-				"lib64/libvndksp.so"),
-		},
 	}
 	for _, tc := range testCases {
 		t.Run("VNDK.current with DeviceVndkVersion="+tc.vndkVersion, func(t *testing.T) {
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index d9ab8fa..7a17f50 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -164,6 +164,7 @@
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
 		"out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
 		"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
+		"out/soong/dexpreopt/uffd_gc_flag.txt",
 	}
 
 	expectedOutputs := []string{
@@ -201,6 +202,7 @@
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
 		"out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
 		"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
+		"out/soong/dexpreopt/uffd_gc_flag.txt",
 	}
 
 	expectedOutputs := []string{
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 399d9b9..cebbae9 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -639,7 +639,7 @@
 			return false
 		}
 
-		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
+		name := java.ModuleStemForDeapexing(child)
 		if _, ok := tag.(android.RequiresFilesFromPrebuiltApexTag); ok {
 			commonModules = append(commonModules, name)
 
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index e2aee96..894aece 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -8,66 +8,6 @@
 	"android/soong/android"
 )
 
-func TestVndkApexForVndkLite(t *testing.T) {
-	ctx := testApex(t, `
-		apex_vndk {
-			name: "com.android.vndk.current",
-			key: "com.android.vndk.current.key",
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.vndk.current.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "libvndk",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-
-		cc_library {
-			name: "libvndksp",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-	`+vndkLibrariesTxtFiles("current"),
-		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.DeviceVndkVersion = proptools.StringPtr("")
-			variables.KeepVndk = proptools.BoolPtr(true)
-		}),
-	)
-	// VNDK-Lite contains only core variants of VNDK-Sp libraries
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
-		"lib/libvndksp.so",
-		"lib/libc++.so",
-		"lib64/libvndksp.so",
-		"lib64/libc++.so",
-		"etc/llndk.libraries.29.txt",
-		"etc/vndkcore.libraries.29.txt",
-		"etc/vndksp.libraries.29.txt",
-		"etc/vndkprivate.libraries.29.txt",
-		"etc/vndkproduct.libraries.29.txt",
-	})
-}
-
 func TestVndkApexUsesVendorVariant(t *testing.T) {
 	bp := `
 		apex_vndk {
diff --git a/bin/soongdbg b/bin/soongdbg
new file mode 100755
index 0000000..132a0f0
--- /dev/null
+++ b/bin/soongdbg
@@ -0,0 +1,313 @@
+#!/usr/bin/env python3
+
+import argparse
+import fnmatch
+import json
+import os
+import pathlib
+import types
+import sys
+
+
+class Graph:
+    def __init__(self, modules):
+        def get_or_make_node(dictionary, id, module):
+            node = dictionary.get(id)
+            if node:
+                if module and not node.module:
+                    node.module = module
+                return node
+            node = Node(id, module)
+            dictionary[id] = node
+            return node
+        self.nodes = dict()
+        for module in modules.values():
+            node = get_or_make_node(self.nodes, module.id, module)
+            for d in module.deps:
+                dep = get_or_make_node(self.nodes, d.id, None)
+                node.deps.add(dep)
+                dep.rdeps.add(node)
+
+    def find_paths(self, id1, id2):
+        # Throws KeyError if one of the names isn't found
+        def recurse(node1, node2, visited):
+            result = set()
+            for dep in node1.rdeps:
+                if dep == node2:
+                    result.add(node2)
+                if dep not in visited:
+                    visited.add(dep)
+                    found = recurse(dep, node2, visited)
+                    if found:
+                        result |= found
+                        result.add(dep)
+            return result
+        node1 = self.nodes[id1]
+        node2 = self.nodes[id2]
+        # Take either direction
+        p = recurse(node1, node2, set())
+        if p:
+            p.add(node1)
+            return p
+        p = recurse(node2, node1, set())
+        p.add(node2)
+        return p
+
+
+class Node:
+    def __init__(self, id, module):
+        self.id = id
+        self.module = module
+        self.deps = set()
+        self.rdeps = set()
+
+
+PROVIDERS = [
+    "android/soong/java.JarJarProviderData",
+    "android/soong/java.BaseJarJarProviderData",
+]
+
+
+def format_node_label(node):
+    if not node.module:
+        return node.id
+    if node.module.debug:
+        module_debug = f"<tr><td>{node.module.debug}</td></tr>"
+    else:
+        module_debug = ""
+
+    result = (f"<<table border=\"0\" cellborder=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
+            + f"<tr><td><b>{node.module.name}</b></td></tr>"
+            + module_debug
+            + f"<tr><td>{node.module.type}</td></tr>")
+    for p in node.module.providers:
+        if p.type in PROVIDERS:
+            result += "<tr><td><font color=\"#666666\">" + format_provider(p) + "</font></td></tr>"
+    result += "</table>>"
+    return result
+
+
+def format_source_pos(file, lineno):
+    result = file
+    if lineno:
+        result += f":{lineno}"
+    return result
+
+
+STRIP_TYPE_PREFIXES = [
+    "android/soong/",
+    "github.com/google/",
+]
+
+
+def format_provider(provider):
+    result = ""
+    for prefix in STRIP_TYPE_PREFIXES:
+        if provider.type.startswith(prefix):
+            result = provider.type[len(prefix):]
+            break
+    if not result:
+        result = provider.type
+    if True and provider.debug:
+        result += " (" + provider.debug + ")"
+    return result
+
+
+def load_soong_debug():
+    # Read the json
+    try:
+        with open(SOONG_DEBUG_DATA_FILENAME) as f:
+            info = json.load(f, object_hook=lambda d: types.SimpleNamespace(**d))
+    except IOError:
+        sys.stderr.write(f"error: Unable to open {SOONG_DEBUG_DATA_FILENAME}. Make sure you have"
+                         + " built with GENERATE_SOONG_DEBUG.\n")
+        sys.exit(1)
+
+    # Construct IDs, which are name + variant if the
+    name_counts = dict()
+    for m in info.modules:
+        name_counts[m.name] = name_counts.get(m.name, 0) + 1
+    def get_id(m):
+        result = m.name
+        if name_counts[m.name] > 1 and m.variant:
+            result += "@@" + m.variant
+        return result
+    for m in info.modules:
+        m.id = get_id(m)
+        for dep in m.deps:
+            dep.id = get_id(dep)
+
+    return info
+
+
+def load_modules():
+    info = load_soong_debug()
+
+    # Filter out unnamed modules
+    modules = dict()
+    for m in info.modules:
+        if not m.name:
+            continue
+        modules[m.id] = m
+
+    return modules
+
+
+def load_graph():
+    modules=load_modules()
+    return Graph(modules)
+
+
+def module_selection_args(parser):
+    parser.add_argument("modules", nargs="*",
+                        help="Modules to match. Can be glob-style wildcards.")
+    parser.add_argument("--provider", nargs="+",
+                        help="Match the given providers.")
+    parser.add_argument("--dep", nargs="+",
+                        help="Match the given providers.")
+
+
+def load_and_filter_modules(args):
+    # Which modules are printed
+    matchers = []
+    if args.modules:
+        matchers.append(lambda m: [True for pattern in args.modules
+                                   if fnmatch.fnmatchcase(m.name, pattern)])
+    if args.provider:
+        matchers.append(lambda m: [True for pattern in args.provider
+                                   if [True for p in m.providers if p.type.endswith(pattern)]])
+    if args.dep:
+        matchers.append(lambda m: [True for pattern in args.dep
+                                   if [True for d in m.deps if d.id == pattern]])
+
+    if not matchers:
+        sys.stderr.write("error: At least one module matcher must be supplied\n")
+        sys.exit(1)
+
+    info = load_soong_debug()
+    for m in sorted(info.modules, key=lambda m: (m.name, m.variant)):
+        if len([matcher for matcher in matchers if matcher(m)]) == len(matchers):
+            yield m
+
+
+def print_nodes(nodes):
+    print("digraph {")
+    for node in nodes:
+        print(f"\"{node.id}\"[label={format_node_label(node)}];")
+        for dep in node.deps:
+            if dep in nodes:
+                print(f"\"{node.id}\" -> \"{dep.id}\";")
+    print("}")
+
+
+def get_deps(nodes, root):
+    if root in nodes:
+        return
+    nodes.add(root)
+    for dep in root.deps:
+        get_deps(nodes, dep)
+
+
+class BetweenCommand:
+    help = "Print the module graph between two nodes."
+
+    def args(self, parser):
+        parser.add_argument("module", nargs=2,
+                            help="The two modules")
+
+    def run(self, args):
+        graph = load_graph()
+        print_nodes(graph.find_paths(args.module[0], args.module[1]))
+
+
+class DepsCommand:
+    help = "Print the module graph of dependencies of one or more modules"
+
+    def args(self, parser):
+        parser.add_argument("module", nargs="+",
+                            help="Module to print dependencies of")
+
+    def run(self, args):
+        graph = load_graph()
+        nodes = set()
+        err = False
+        for id in sys.argv[3:]:
+            root = graph.nodes.get(id)
+            if not root:
+                sys.stderr.write(f"error: Can't find root: {id}\n")
+                err = True
+                continue
+            get_deps(nodes, root)
+        if err:
+            sys.exit(1)
+        print_nodes(nodes)
+
+
+class IdCommand:
+    help = "Print the id (name + variant) of matching modules"
+
+    def args(self, parser):
+        module_selection_args(parser)
+
+    def run(self, args):
+        for m in load_and_filter_modules(args):
+            print(m.id)
+
+
+class QueryCommand:
+    help = "Query details about modules"
+
+    def args(self, parser):
+        module_selection_args(parser)
+
+    def run(self, args):
+        for m in load_and_filter_modules(args):
+            print(m.id)
+            print(f"    type:     {m.type}")
+            print(f"    location: {format_source_pos(m.source_file, m.source_line)}")
+            for p in m.providers:
+                print(f"    provider: {format_provider(p)}")
+            for d in m.deps:
+                print(f"    dep:      {d.id}")
+
+
+COMMANDS = {
+    "between": BetweenCommand(),
+    "deps": DepsCommand(),
+    "id": IdCommand(),
+    "query": QueryCommand(),
+}
+
+
+def assert_env(name):
+    val = os.getenv(name)
+    if not val:
+        sys.stderr.write(f"{name} not set. please make sure you've run lunch.")
+    return val
+
+ANDROID_BUILD_TOP = assert_env("ANDROID_BUILD_TOP")
+
+TARGET_PRODUCT = assert_env("TARGET_PRODUCT")
+OUT_DIR = os.getenv("OUT_DIR")
+if not OUT_DIR:
+    OUT_DIR = "out"
+if OUT_DIR[0] != "/":
+    OUT_DIR = pathlib.Path(ANDROID_BUILD_TOP).joinpath(OUT_DIR)
+SOONG_DEBUG_DATA_FILENAME = pathlib.Path(OUT_DIR).joinpath("soong/soong-debug-info.json")
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    subparsers = parser.add_subparsers(required=True, dest="command")
+    for name in sorted(COMMANDS.keys()):
+        command = COMMANDS[name]
+        subparser = subparsers.add_parser(name, help=command.help)
+        command.args(subparser)
+    args = parser.parse_args()
+    COMMANDS[args.command].run(args)
+    sys.exit(0)
+
+
+if __name__ == "__main__":
+    main()
+
diff --git a/cc/androidmk.go b/cc/androidmk.go
index c39668c..20673e8 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -107,7 +107,6 @@
 				}
 				entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
 				if c.InVendorOrProduct() {
-					entries.SetBool("LOCAL_USE_VNDK", true)
 					if c.IsVndk() && !c.static() {
 						entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
 						// VNDK libraries available to vendor are not installed because
@@ -117,6 +116,11 @@
 						}
 					}
 				}
+				if c.InVendor() {
+					entries.SetBool("LOCAL_IN_VENDOR", true)
+				} else if c.InProduct() {
+					entries.SetBool("LOCAL_IN_PRODUCT", true)
+				}
 				if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
 					// Make the SDK variant uninstallable so that there are not two rules to install
 					// to the same location.
diff --git a/cc/compiler.go b/cc/compiler.go
index c57b72c..de1ae71 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -116,6 +116,10 @@
 	// if set to false, use -std=c++* instead of -std=gnu++*
 	Gnu_extensions *bool
 
+	// cc Build rules targeting BPF must set this to true. The correct fix is to
+	// ban targeting bpf in cc rules instead use bpf_rules. (b/323415017)
+	Bpf_target *bool
+
 	Yacc *YaccProperties
 	Lex  *LexProperties
 
@@ -483,6 +487,11 @@
 		}
 	}
 
+	// bpf targets don't need the default target triple. b/308826679
+	if proptools.Bool(compiler.Properties.Bpf_target) {
+		target = "--target=bpf"
+	}
+
 	flags.Global.CFlags = append(flags.Global.CFlags, target)
 	flags.Global.AsFlags = append(flags.Global.AsFlags, target)
 	flags.Global.LdFlags = append(flags.Global.LdFlags, target)
@@ -498,8 +507,12 @@
 
 	flags.Global.AsFlags = append(flags.Global.AsFlags, tc.Asflags())
 	flags.Global.CppFlags = append([]string{"${config.CommonGlobalCppflags}"}, flags.Global.CppFlags...)
+
+	// bpf targets don't need the target specific toolchain cflags. b/308826679
+	if !proptools.Bool(compiler.Properties.Bpf_target) {
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.Cflags())
+	}
 	flags.Global.CommonFlags = append(flags.Global.CommonFlags,
-		tc.Cflags(),
 		"${config.CommonGlobalCflags}",
 		fmt.Sprintf("${config.%sGlobalCflags}", hod))
 
@@ -521,7 +534,11 @@
 
 	flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags())
 
-	flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
+	// bpf targets don't need the target specific toolchain cflags. b/308826679
+	if !proptools.Bool(compiler.Properties.Bpf_target) {
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
+	}
+
 
 	cStd := parseCStd(compiler.Properties.C_std)
 	cppStd := parseCppStd(compiler.Properties.Cpp_std)
diff --git a/cc/config/bionic.go b/cc/config/bionic.go
index a1e3851..ed724f5 100644
--- a/cc/config/bionic.go
+++ b/cc/config/bionic.go
@@ -24,6 +24,7 @@
 	bionicCrtBeginStaticBinary, bionicCrtEndStaticBinary   = []string{"crtbegin_static"}, []string{"crtend_android"}
 	bionicCrtBeginSharedBinary, bionicCrtEndSharedBinary   = []string{"crtbegin_dynamic"}, []string{"crtend_android"}
 	bionicCrtBeginSharedLibrary, bionicCrtEndSharedLibrary = []string{"crtbegin_so"}, []string{"crtend_so"}
+	bionicCrtPadSegmentSharedLibrary                       = []string{"crt_pad_segment"}
 )
 
 func (toolchainBionic) Bionic() bool { return true }
@@ -36,9 +37,10 @@
 
 func (toolchainBionic) AvailableLibraries() []string { return nil }
 
-func (toolchainBionic) CrtBeginStaticBinary() []string  { return bionicCrtBeginStaticBinary }
-func (toolchainBionic) CrtBeginSharedBinary() []string  { return bionicCrtBeginSharedBinary }
-func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary }
-func (toolchainBionic) CrtEndStaticBinary() []string    { return bionicCrtEndStaticBinary }
-func (toolchainBionic) CrtEndSharedBinary() []string    { return bionicCrtEndSharedBinary }
-func (toolchainBionic) CrtEndSharedLibrary() []string   { return bionicCrtEndSharedLibrary }
+func (toolchainBionic) CrtBeginStaticBinary() []string       { return bionicCrtBeginStaticBinary }
+func (toolchainBionic) CrtBeginSharedBinary() []string       { return bionicCrtBeginSharedBinary }
+func (toolchainBionic) CrtBeginSharedLibrary() []string      { return bionicCrtBeginSharedLibrary }
+func (toolchainBionic) CrtEndStaticBinary() []string         { return bionicCrtEndStaticBinary }
+func (toolchainBionic) CrtEndSharedBinary() []string         { return bionicCrtEndSharedBinary }
+func (toolchainBionic) CrtEndSharedLibrary() []string        { return bionicCrtEndSharedLibrary }
+func (toolchainBionic) CrtPadSegmentSharedLibrary() []string { return bionicCrtPadSegmentSharedLibrary }
diff --git a/cc/config/global.go b/cc/config/global.go
index 5fed7f1..c562614 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -253,6 +253,14 @@
 		// http://b/161386391 for -Wno-pointer-to-int-cast
 		"-Wno-pointer-to-int-cast",
 		"-Werror=fortify-source",
+		// http://b/315246135 temporarily disabled
+		"-Wno-error=unused-variable",
+		// http://b/315250603 temporarily disabled
+		"-Wno-error=format",
+		// Disabled because it produces many false positives. http://b/323050926
+		"-Wno-missing-field-initializers",
+		// http://b/323050889
+		"-Wno-packed-non-pod",
 
 		"-Werror=address-of-temporary",
 		"-Werror=incompatible-function-pointer-types",
@@ -351,11 +359,16 @@
 		// enabling since it's a cosmetic issue.
 		"-Wno-bitwise-instead-of-logical",
 
-		"-Wno-unused-but-set-variable",
+		"-Wno-unused",
+		"-Wno-unused-parameter",
 		"-Wno-unused-but-set-parameter",
 		"-Wno-unqualified-std-cast-call",
 		"-Wno-array-parameter",
 		"-Wno-gnu-offsetof-extensions",
+		// TODO: Enable this warning http://b/315245071
+		"-Wno-fortify-source",
+		"-Wno-tautological-negation-compare",
+		"-Wno-tautological-undefined-compare",
 	}
 
 	llvmNextExtraCommonGlobalCflags = []string{
@@ -375,8 +388,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r498229b"
-	ClangDefaultShortVersion = "17"
+	ClangDefaultVersion      = "clang-r510928"
+	ClangDefaultShortVersion = "18"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 62f75d1..71e98fe 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -100,6 +100,7 @@
 	CrtEndStaticBinary() []string
 	CrtEndSharedBinary() []string
 	CrtEndSharedLibrary() []string
+	CrtPadSegmentSharedLibrary() []string
 
 	// DefaultSharedLibraries returns the list of shared libraries that will be added to all
 	// targets unless they explicitly specify system_shared_libs.
@@ -155,12 +156,13 @@
 
 type toolchainNoCrt struct{}
 
-func (toolchainNoCrt) CrtBeginStaticBinary() []string  { return nil }
-func (toolchainNoCrt) CrtBeginSharedBinary() []string  { return nil }
-func (toolchainNoCrt) CrtBeginSharedLibrary() []string { return nil }
-func (toolchainNoCrt) CrtEndStaticBinary() []string    { return nil }
-func (toolchainNoCrt) CrtEndSharedBinary() []string    { return nil }
-func (toolchainNoCrt) CrtEndSharedLibrary() []string   { return nil }
+func (toolchainNoCrt) CrtBeginStaticBinary() []string       { return nil }
+func (toolchainNoCrt) CrtBeginSharedBinary() []string       { return nil }
+func (toolchainNoCrt) CrtBeginSharedLibrary() []string      { return nil }
+func (toolchainNoCrt) CrtEndStaticBinary() []string         { return nil }
+func (toolchainNoCrt) CrtEndSharedBinary() []string         { return nil }
+func (toolchainNoCrt) CrtEndSharedLibrary() []string        { return nil }
+func (toolchainNoCrt) CrtPadSegmentSharedLibrary() []string { return nil }
 
 func (toolchainBase) DefaultSharedLibraries() []string {
 	return nil
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index f95da0b..f497bf9 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -328,12 +328,13 @@
 
 func (toolchainMusl) Musl() bool { return true }
 
-func (toolchainMusl) CrtBeginStaticBinary() []string  { return muslCrtBeginStaticBinary }
-func (toolchainMusl) CrtBeginSharedBinary() []string  { return muslCrtBeginSharedBinary }
-func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary }
-func (toolchainMusl) CrtEndStaticBinary() []string    { return muslCrtEndStaticBinary }
-func (toolchainMusl) CrtEndSharedBinary() []string    { return muslCrtEndSharedBinary }
-func (toolchainMusl) CrtEndSharedLibrary() []string   { return muslCrtEndSharedLibrary }
+func (toolchainMusl) CrtBeginStaticBinary() []string       { return muslCrtBeginStaticBinary }
+func (toolchainMusl) CrtBeginSharedBinary() []string       { return muslCrtBeginSharedBinary }
+func (toolchainMusl) CrtBeginSharedLibrary() []string      { return muslCrtBeginSharedLibrary }
+func (toolchainMusl) CrtEndStaticBinary() []string         { return muslCrtEndStaticBinary }
+func (toolchainMusl) CrtEndSharedBinary() []string         { return muslCrtEndSharedBinary }
+func (toolchainMusl) CrtEndSharedLibrary() []string        { return muslCrtEndSharedLibrary }
+func (toolchainMusl) CrtPadSegmentSharedLibrary() []string { return nil }
 
 func (toolchainMusl) DefaultSharedLibraries() []string { return MuslDefaultSharedLibraries }
 
diff --git a/cc/library.go b/cc/library.go
index 4b6ac59..4684d32 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -974,6 +974,10 @@
 		if library.baseLinker.Properties.crt() {
 			deps.CrtBegin = append(deps.CrtBegin, ctx.toolchain().CrtBeginSharedLibrary()...)
 			deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtEndSharedLibrary()...)
+
+		}
+		if library.baseLinker.Properties.crtPadSegment() {
+			deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtPadSegmentSharedLibrary()...)
 		}
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
 		deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
@@ -1476,7 +1480,9 @@
 			headerAbiChecker.Exclude_symbol_tags,
 			currVersion)
 
-		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
+		for _, tag := range classifySourceAbiDump(ctx) {
+			addLsdumpPath(tag + ":" + library.sAbiOutputFile.String())
+		}
 
 		dumpDir := getRefAbiDumpDir(isNdk, isLlndk)
 		binderBitness := ctx.DeviceConfig().BinderBitness()
diff --git a/cc/linker.go b/cc/linker.go
index 85c128e..2c50db2 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -91,6 +91,10 @@
 	// compiling crt or libc.
 	Nocrt *bool `android:"arch_variant"`
 
+	// don't link in crt_pad_segment. This flag is currently only used internal to
+	// soong for testing and for vndk prebuilt shared libraries.
+	No_crt_pad_segment *bool `android:"arch_variant"`
+
 	// deprecated and ignored because lld makes it unnecessary. See b/189475744.
 	Group_static_libs *bool `android:"arch_variant"`
 
@@ -253,6 +257,10 @@
 	return blp.No_libcrt == nil || !*blp.No_libcrt
 }
 
+func (blp *BaseLinkerProperties) crtPadSegment() bool {
+	return blp.No_crt_pad_segment == nil || !*blp.No_crt_pad_segment
+}
+
 func NewBaseLinker(sanitize *sanitize) *baseLinker {
 	return &baseLinker{sanitize: sanitize}
 }
diff --git a/cc/sabi.go b/cc/sabi.go
index 9f5781f..4ca9f5c 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -97,36 +97,34 @@
 	return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump
 }
 
-// Returns a string that represents the class of the ABI dump.
-// Returns an empty string if ABI check is disabled for this library.
-func classifySourceAbiDump(ctx android.BaseModuleContext) string {
+// Returns a slice of strings that represent the ABI dumps generated for this module.
+func classifySourceAbiDump(ctx android.BaseModuleContext) []string {
+	result := []string{}
 	m := ctx.Module().(*Module)
 	headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx)
 	if headerAbiChecker.explicitlyDisabled() {
-		return ""
+		return result
 	}
 	if !m.InProduct() && !m.InVendor() {
-		// Return NDK if the library is both NDK and LLNDK.
-		if m.IsNdk(ctx.Config()) {
-			return "NDK"
-		}
 		if m.isImplementationForLLNDKPublic() {
-			return "LLNDK"
+			result = append(result, "LLNDK")
 		}
-		if m.library.hasStubsVariants() {
-			return "PLATFORM"
+		// Return NDK if the library is both NDK and APEX.
+		// TODO(b/309880485): Split NDK and APEX ABI.
+		if m.IsNdk(ctx.Config()) {
+			result = append(result, "NDK")
+		} else if m.library.hasStubsVariants() || headerAbiChecker.enabled() {
+			result = append(result, "PLATFORM")
 		}
-	}
-	if headerAbiChecker.enabled() {
+	} else if headerAbiChecker.enabled() {
 		if m.InProduct() {
-			return "PRODUCT"
+			result = append(result, "PRODUCT")
 		}
 		if m.InVendor() {
-			return "VENDOR"
+			result = append(result, "VENDOR")
 		}
-		return "PLATFORM"
 	}
-	return ""
+	return result
 }
 
 // Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
@@ -195,7 +193,7 @@
 			return false
 		}
 	}
-	return classifySourceAbiDump(ctx) != ""
+	return len(classifySourceAbiDump(ctx)) > 0
 }
 
 // Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
diff --git a/cc/testing.go b/cc/testing.go
index bac41e7..9c2900c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -77,6 +77,7 @@
 			no_libcrt: true,
 			sdk_version: "minimum",
 			nocrt: true,
+			no_crt_pad_segment: true,
 			system_shared_libs: [],
 			stl: "none",
 			check_elf_files: false,
@@ -385,6 +386,11 @@
 		}
 
 		cc_object {
+			name: "crt_pad_segment",
+			defaults: ["crt_defaults"],
+		}
+
+		cc_object {
 			name: "crtbrand",
 			defaults: ["crt_defaults"],
 			srcs: ["crtbrand.c"],
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 890a533..0a55431 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -341,6 +341,7 @@
 		vendor: true,
 		nocrt: true,
 		no_libcrt: true,
+		no_crt_pad_segment: true,
 		stl: "none",
 		system_shared_libs: [],
 		compile_multilib: "64",
@@ -458,6 +459,7 @@
 		vendor: true,
 		nocrt: true,
 		no_libcrt: true,
+		no_crt_pad_segment: true,
 		stl: "none",
 		system_shared_libs: [],
 	}
@@ -467,6 +469,7 @@
 		vendor: true,
 		nocrt: true,
 		no_libcrt: true,
+		no_crt_pad_segment: true,
 		stl: "none",
 		system_shared_libs: [],
 		shared_libs: ["libvndk", "libvendor_available", "libllndk"],
@@ -487,6 +490,7 @@
 		vendor: true,
 		nocrt: true,
 		no_libcrt: true,
+		no_crt_pad_segment: true,
 		stl: "none",
 		system_shared_libs: [],
 		static_libs: ["libvendor"],
@@ -501,6 +505,7 @@
 		vendor: true,
 		nocrt: true,
 		no_libcrt: true,
+		no_crt_pad_segment: true,
 		stl: "none",
 		system_shared_libs: [],
 		vndk: {
@@ -597,6 +602,7 @@
 		target_arch: "arm64",
 		compile_multilib: "both",
 		vendor: true,
+		no_crt_pad_segment: true,
 		shared_libs: [
 			"libvendor_without_snapshot",
 			"libvendor_available",
@@ -620,6 +626,7 @@
 		target_arch: "arm64",
 		compile_multilib: "both",
 		vendor: true,
+		no_crt_pad_segment: true,
 		overrides: ["libvendor"],
 		shared_libs: [
 			"libvendor_without_snapshot",
@@ -657,6 +664,7 @@
 		target_arch: "arm64",
 		compile_multilib: "32",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm: {
 				src: "lib32.so",
@@ -683,6 +691,7 @@
 		target_arch: "arm64",
 		compile_multilib: "64",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm64: {
 				src: "lib64.so",
@@ -722,6 +731,7 @@
 		target_arch: "arm64",
 		compile_multilib: "both",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm64: {
 				src: "libvendor_available.so",
diff --git a/cc/vndk.go b/cc/vndk.go
index 0e0dba9..2b2ea64 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -377,22 +377,17 @@
 			return false
 		}
 
-		// ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
-		platformVndkApiLevel := android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())
-		if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
-			return false
+		platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
+		if platformVndkVersion != "" {
+			// ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
+			platformVndkApiLevel := android.ApiLevelOrPanic(mctx, platformVndkVersion)
+			if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
+				return false
+			}
 		}
 	}
 
 	if lib, ok := m.linker.(libraryInterface); ok {
-		// VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
-		if mctx.DeviceConfig().VndkVersion() == "" {
-			// b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
-			if mctx.ModuleName() == "libz" {
-				return false
-			}
-			return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.IsVndkSp() && !m.IsVndkExt()
-		}
 		// VNDK APEX doesn't need stub variants
 		if lib.buildStubs() {
 			return false
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index eb1790f..43030b8 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -131,11 +131,14 @@
 
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
-	platformVndkApiLevel := android.ApiLevelOrPanic(ctx, ctx.DeviceConfig().PlatformVndkVersion())
-	if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
-		// This prebuilt VNDK module is not required for the current build
-		ctx.Module().HideFromMake()
-		return nil
+	platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+	if platformVndkVersion != "" {
+		platformVndkApiLevel := android.ApiLevelOrPanic(ctx, platformVndkVersion)
+		if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
+			// This prebuilt VNDK module is not required for the current build
+			ctx.Module().HideFromMake()
+			return nil
+		}
 	}
 
 	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
@@ -232,6 +235,7 @@
 	prebuilt.properties.Check_elf_files = BoolPtr(false)
 	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
 	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+	prebuilt.baseLinker.Properties.No_crt_pad_segment = BoolPtr(true)
 
 	// Prevent default system libs (libc, libm, and libdl) from being linked
 	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
@@ -246,14 +250,6 @@
 		&prebuilt.properties,
 	)
 
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		// empty BOARD_VNDK_VERSION implies that the device won't support
-		// system only OTA. In this case, VNDK snapshots aren't needed.
-		if ctx.DeviceConfig().VndkVersion() == "" {
-			ctx.Module().Disable()
-		}
-	})
-
 	return module
 }
 
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 4727566..673f305 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -79,6 +79,7 @@
 	flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
 	flag.BoolVar(&cmdlineArgs.BuildFromSourceStub, "build-from-source-stub", false, "build Java stubs from source files instead of API text files")
 	flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
+	flag.StringVar(&cmdlineArgs.ModuleDebugFile, "soong_module_debug", "", "soong module debug info file to write")
 	// Flags that probably shouldn't be flags of soong_build, but we haven't found
 	// the time to remove them yet
 	flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 6163952..fe6317c 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -98,7 +98,9 @@
 	// measure, as it masks real errors and affects performance.
 	RelaxUsesLibraryCheck bool
 
-	EnableUffdGc bool // preopt with the assumption that userfaultfd GC will be used on device.
+	// "true" to force preopt with CMC GC (a.k.a., UFFD GC); "false" to force preopt with CC GC;
+	// "default" to determine the GC type based on the kernel version file.
+	EnableUffdGc string
 }
 
 var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars")
@@ -154,6 +156,7 @@
 	Zip2zip          android.Path
 	ManifestCheck    android.Path
 	ConstructContext android.Path
+	UffdGcFlag       android.WritablePath
 }
 
 type ModuleConfig struct {
@@ -537,6 +540,7 @@
 		Zip2zip:          ctx.Config().HostToolPath(ctx, "zip2zip"),
 		ManifestCheck:    ctx.Config().HostToolPath(ctx, "manifest_check"),
 		ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"),
+		UffdGcFlag:       getUffdGcFlagPath(ctx),
 	}
 }
 
@@ -588,6 +592,7 @@
 	Zip2zip          string
 	ManifestCheck    string
 	ConstructContext string
+	UffdGcFlag       string
 }
 
 // ParseGlobalSoongConfig parses the given data assumed to be read from the
@@ -609,6 +614,7 @@
 		Zip2zip:          constructPath(ctx, jc.Zip2zip),
 		ManifestCheck:    constructPath(ctx, jc.ManifestCheck),
 		ConstructContext: constructPath(ctx, jc.ConstructContext),
+		UffdGcFlag:       constructWritablePath(ctx, jc.UffdGcFlag),
 	}
 
 	return config, nil
@@ -633,12 +639,15 @@
 }
 
 func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	checkBootJarsConfigConsistency(ctx, GetGlobalConfig(ctx), ctx.Config())
+	global := GetGlobalConfig(ctx)
+	checkBootJarsConfigConsistency(ctx, global, ctx.Config())
 
-	if GetGlobalConfig(ctx).DisablePreopt {
+	if global.DisablePreopt {
 		return
 	}
 
+	buildUffdGcFlag(ctx, global)
+
 	config := GetCachedGlobalSoongConfig(ctx)
 	if config == nil {
 		// No module has enabled dexpreopting, so we assume there will be no calls
@@ -654,6 +663,7 @@
 		Zip2zip:          config.Zip2zip.String(),
 		ManifestCheck:    config.ManifestCheck.String(),
 		ConstructContext: config.ConstructContext.String(),
+		UffdGcFlag:       config.UffdGcFlag.String(),
 	}
 
 	data, err := json.Marshal(jc)
@@ -684,9 +694,32 @@
 		config.Zip2zip.String(),
 		config.ManifestCheck.String(),
 		config.ConstructContext.String(),
+		config.UffdGcFlag.String(),
 	}, " "))
 }
 
+func buildUffdGcFlag(ctx android.BuilderContext, global *GlobalConfig) {
+	uffdGcFlag := getUffdGcFlagPath(ctx)
+
+	if global.EnableUffdGc == "true" {
+		android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "--runtime-arg -Xgc:CMC")
+	} else if global.EnableUffdGc == "false" {
+		android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "")
+	} else if global.EnableUffdGc == "default" {
+		// Generated by `build/make/core/Makefile`.
+		kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")
+		// Determine the UFFD GC flag by the kernel version file.
+		rule := android.NewRuleBuilder(pctx, ctx)
+		rule.Command().
+			Tool(ctx.Config().HostToolPath(ctx, "construct_uffd_gc_flag")).
+			Input(kernelVersionFile).
+			Output(uffdGcFlag)
+		rule.Restat().Build("dexpreopt_uffd_gc_flag", "dexpreopt_uffd_gc_flag")
+	} else {
+		panic(fmt.Sprintf("Unknown value of PRODUCT_ENABLE_UFFD_GC: %s", global.EnableUffdGc))
+	}
+}
+
 func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig {
 	return &GlobalConfig{
 		DisablePreopt:                  false,
@@ -731,7 +764,7 @@
 	}
 }
 
-func globalSoongConfigForTests() *GlobalSoongConfig {
+func globalSoongConfigForTests(ctx android.BuilderContext) *GlobalSoongConfig {
 	return &GlobalSoongConfig{
 		Profman:          android.PathForTesting("profman"),
 		Dex2oat:          android.PathForTesting("dex2oat"),
@@ -740,5 +773,19 @@
 		Zip2zip:          android.PathForTesting("zip2zip"),
 		ManifestCheck:    android.PathForTesting("manifest_check"),
 		ConstructContext: android.PathForTesting("construct_context"),
+		UffdGcFlag:       android.PathForOutput(ctx, "dexpreopt_test", "uffd_gc_flag.txt"),
 	}
 }
+
+func GetDexpreoptDirName(ctx android.PathContext) string {
+	prefix := "dexpreopt_"
+	targets := ctx.Config().Targets[android.Android]
+	if len(targets) > 0 {
+		return prefix + targets[0].Arch.ArchType.String()
+	}
+	return prefix + "unknown_target"
+}
+
+func getUffdGcFlagPath(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "dexpreopt/uffd_gc_flag.txt")
+}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 94707ba..04bc61d 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -390,7 +390,8 @@
 		Flag("--generate-build-id").
 		Flag("--abort-on-hard-verifier-error").
 		Flag("--force-determinism").
-		FlagWithArg("--no-inline-from=", "core-oj.jar")
+		FlagWithArg("--no-inline-from=", "core-oj.jar").
+		Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
 
 	var preoptFlags []string
 	if len(module.PreoptFlags) > 0 {
@@ -506,10 +507,6 @@
 		cmd.FlagWithInput("--profile-file=", profile)
 	}
 
-	if global.EnableUffdGc {
-		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
-	}
-
 	rule.Install(odexPath, odexInstallPath)
 	rule.Install(vdexPath, vdexInstallPath)
 }
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 230fbb4..7071f3e 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -96,7 +96,7 @@
 func TestDexPreopt(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testSystemModuleConfig(ctx, "test")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -114,12 +114,15 @@
 	if rule.Installs().String() != wantInstalls.String() {
 		t.Errorf("\nwant installs:\n   %v\ngot:\n   %v", wantInstalls, rule.Installs())
 	}
+
+	android.AssertStringListContains(t, "", rule.Inputs().RelativeToTop().Strings(),
+		"out/soong/dexpreopt_test/uffd_gc_flag.txt")
 }
 
 func TestDexPreoptSystemOther(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	systemModule := testSystemModuleConfig(ctx, "Stest")
 	systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
@@ -180,7 +183,7 @@
 func TestDexPreoptApexSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -204,7 +207,7 @@
 func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testPlatformSystemServerModuleConfig(ctx, "service-A")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -228,7 +231,7 @@
 func TestDexPreoptSystemExtSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -252,7 +255,7 @@
 func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -276,7 +279,7 @@
 func TestDexPreoptProfile(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testSystemModuleConfig(ctx, "test")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -316,3 +319,55 @@
 	after := fmt.Sprintf("%v", parsed)
 	android.AssertStringEquals(t, "The result must be the same as the original after marshalling and unmarshalling it.", before, after)
 }
+
+func TestUffdGcFlagForce(t *testing.T) {
+	for _, enableUffdGc := range []string{"true", "false"} {
+		t.Run(enableUffdGc, func(t *testing.T) {
+			preparers := android.GroupFixturePreparers(
+				PrepareForTestWithFakeDex2oatd,
+				PrepareForTestWithDexpreoptConfig,
+				FixtureSetEnableUffdGc(enableUffdGc),
+			)
+
+			result := preparers.RunTest(t)
+			ctx := result.TestContext
+
+			ctx.SingletonForTests("dexpreopt-soong-config").Output("out/soong/dexpreopt/uffd_gc_flag.txt")
+		})
+	}
+}
+
+func TestUffdGcFlagDefault(t *testing.T) {
+	preparers := android.GroupFixturePreparers(
+		PrepareForTestWithFakeDex2oatd,
+		PrepareForTestWithDexpreoptConfig,
+		FixtureSetEnableUffdGc("default"),
+	)
+
+	result := preparers.RunTest(t)
+	ctx := result.TestContext
+	config := ctx.Config()
+
+	rule := ctx.SingletonForTests("dexpreopt-soong-config").Rule("dexpreopt_uffd_gc_flag")
+
+	android.AssertStringDoesContain(t, "", rule.RuleParams.Command, "construct_uffd_gc_flag")
+	android.AssertStringPathsRelativeToTopEquals(t, "", config, []string{
+		"out/soong/dexpreopt/uffd_gc_flag.txt",
+	}, rule.AllOutputs())
+	android.AssertPathsRelativeToTopEquals(t, "", []string{
+		"out/soong/dexpreopt/kernel_version_for_uffd_gc.txt",
+	}, rule.Implicits)
+}
+
+func TestUffdGcFlagBogus(t *testing.T) {
+	preparers := android.GroupFixturePreparers(
+		PrepareForTestWithFakeDex2oatd,
+		PrepareForTestWithDexpreoptConfig,
+		FixtureSetEnableUffdGc("bogus"),
+	)
+
+	preparers.
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+			"Unknown value of PRODUCT_ENABLE_UFFD_GC: bogus")).
+		RunTest(t)
+}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 147a562..b1fbef5 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -88,6 +88,15 @@
 	FixtureModifyGlobalConfig(func(android.PathContext, *GlobalConfig) {}),
 )
 
+var PrepareForTestWithDexpreoptConfig = android.GroupFixturePreparers(
+	android.PrepareForTestWithAndroidBuildComponents,
+	android.FixtureModifyContext(func(ctx *android.TestContext) {
+		ctx.RegisterParallelSingletonType("dexpreopt-soong-config", func() android.Singleton {
+			return &globalSoongConfigSingleton{}
+		})
+	}),
+)
+
 // FixtureModifyGlobalConfig enables dexpreopt (unless modified by the mutator) and modifies the
 // configuration.
 func FixtureModifyGlobalConfig(configModifier func(ctx android.PathContext, dexpreoptConfig *GlobalConfig)) android.FixturePreparer {
@@ -195,3 +204,10 @@
 		dexpreoptConfig.DisablePreopt = disable
 	})
 }
+
+// FixtureSetEnableUffdGc sets the EnableUffdGc property in the global config.
+func FixtureSetEnableUffdGc(value string) android.FixturePreparer {
+	return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+		dexpreoptConfig.EnableUffdGc = value
+	})
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index b523594..b7df9bf 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -549,8 +549,8 @@
 				if BoolDefault(jd.properties.Installable, true) {
 					entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", jd.docZip)
 				}
-				if jd.stubsSrcJar != nil {
-					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.stubsSrcJar)
+				if jd.exportableStubsSrcJar != nil {
+					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.exportableStubsSrcJar)
 				}
 			},
 		},
@@ -596,17 +596,17 @@
 		Include:    "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-				if dstubs.Javadoc.stubsSrcJar != nil {
-					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.stubsSrcJar)
+				if dstubs.Javadoc.exportableStubsSrcJar != nil {
+					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.exportableStubsSrcJar)
 				}
 				if dstubs.everythingArtifacts.apiVersionsXml != nil {
-					entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.everythingArtifacts.apiVersionsXml)
+					entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.exportableArtifacts.apiVersionsXml)
 				}
 				if dstubs.everythingArtifacts.annotationsZip != nil {
-					entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.everythingArtifacts.annotationsZip)
+					entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.exportableArtifacts.annotationsZip)
 				}
 				if dstubs.everythingArtifacts.metadataZip != nil {
-					entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.everythingArtifacts.metadataZip)
+					entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.exportableArtifacts.metadataZip)
 				}
 			},
 		},
diff --git a/java/base.go b/java/base.go
index e52cedd..284ec99 100644
--- a/java/base.go
+++ b/java/base.go
@@ -17,6 +17,8 @@
 import (
 	"fmt"
 	"path/filepath"
+	"reflect"
+	"slices"
 	"strconv"
 	"strings"
 
@@ -89,6 +91,9 @@
 	// if not blank, run jarjar using the specified rules file
 	Jarjar_rules *string `android:"path,arch_variant"`
 
+	// if not blank, used as prefix to generate repackage rule
+	Jarjar_prefix *string
+
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
 
@@ -425,6 +430,8 @@
 	// inserting into the bootclasspath/classpath of another compile
 	headerJarFile android.Path
 
+	repackagedHeaderJarFile android.Path
+
 	// jar file containing implementation classes including static library dependencies but no
 	// resources
 	implementationJarFile android.Path
@@ -489,6 +496,9 @@
 	// expanded Jarjar_rules
 	expandJarjarRules android.Path
 
+	// jarjar rule for inherited jarjar rules
+	repackageJarjarRules android.Path
+
 	// Extra files generated by the module type to be added as java resources.
 	extraResources android.Paths
 
@@ -518,6 +528,10 @@
 
 	// Single aconfig "cache file" merged from this module and all dependencies.
 	mergedAconfigFiles map[string]android.Paths
+
+	// Values that will be set in the JarJarProvider data for jarjar repackaging,
+	// and merged with our dependencies' rules.
+	jarjarRenameRules map[string]string
 }
 
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -1072,6 +1086,19 @@
 }
 
 func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
+
+	// Auto-propagating jarjar rules
+	jarjarProviderData := j.collectJarJarRules(ctx)
+	if jarjarProviderData != nil {
+		android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
+		text := getJarJarRuleText(jarjarProviderData)
+		if text != "" {
+			ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+			android.WriteFileRule(ctx, ruleTextFile, text)
+			j.repackageJarjarRules = ruleTextFile
+		}
+	}
+
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
 	deps := j.collectDeps(ctx)
@@ -1170,7 +1197,7 @@
 			ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
 		}
 
-		_, j.headerJarFile =
+		_, j.headerJarFile, _ =
 			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
 				extraCombinedJars)
 		if ctx.Failed() {
@@ -1285,7 +1312,7 @@
 			// with sharding enabled. See: b/77284273.
 		}
 		extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
-		headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
+		headerJarFileWithoutDepsOrJarjar, j.headerJarFile, j.repackagedHeaderJarFile =
 			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
 		if ctx.Failed() {
 			return
@@ -1509,6 +1536,16 @@
 		}
 	}
 
+	// Automatic jarjar rules propagation
+	if j.repackageJarjarRules != nil {
+		repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", jarName).OutputPath
+		TransformJarJar(ctx, repackagedJarjarFile, outputFile, j.repackageJarjarRules)
+		outputFile = repackagedJarjarFile
+		if ctx.Failed() {
+			return
+		}
+	}
+
 	// Check package restrictions if necessary.
 	if len(j.properties.Permitted_packages) > 0 {
 		// Time stamp file created by the package check rule.
@@ -1678,6 +1715,7 @@
 
 	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
 		HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
+		RepackagedHeaderJars:           android.PathsIfNonNil(j.repackagedHeaderJarFile),
 		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
 		ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
@@ -1813,7 +1851,7 @@
 
 func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
 	deps deps, flags javaBuilderFlags, jarName string,
-	extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
+	extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar android.Path) {
 
 	var jars android.Paths
 	if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1821,7 +1859,7 @@
 		turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
 		TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
 		if ctx.Failed() {
-			return nil, nil
+			return nil, nil, nil
 		}
 		jars = append(jars, turbineJar)
 		headerJar = turbineJar
@@ -1846,11 +1884,22 @@
 		TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
 		jarjarAndDepsHeaderJar = jarjarFile
 		if ctx.Failed() {
-			return nil, nil
+			return nil, nil, nil
 		}
 	}
 
-	return headerJar, jarjarAndDepsHeaderJar
+	if j.repackageJarjarRules != nil {
+		repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-turbine-jarjar", jarName)
+		TransformJarJar(ctx, repackagedJarjarFile, jarjarAndDepsHeaderJar, j.repackageJarjarRules)
+		jarjarAndDepsRepackagedHeaderJar = repackagedJarjarFile
+		if ctx.Failed() {
+			return nil, nil, nil
+		}
+	} else {
+		jarjarAndDepsRepackagedHeaderJar = jarjarAndDepsHeaderJar
+	}
+
+	return headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar
 }
 
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -2207,6 +2256,10 @@
 				}
 				deps.classpath = append(deps.classpath, dep.HeaderJars...)
 				deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...)
+				if len(dep.RepackagedHeaderJars) == 1 && !slices.Contains(dep.HeaderJars, dep.RepackagedHeaderJars[0]) {
+					deps.classpath = append(deps.classpath, dep.RepackagedHeaderJars...)
+					deps.dexClasspath = append(deps.dexClasspath, dep.RepackagedHeaderJars...)
+				}
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
 				addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
@@ -2311,6 +2364,187 @@
 	return deps
 }
 
+// Provider for jarjar renaming rules.
+//
+// Modules can set their jarjar renaming rules with addJarJarRenameRule, and those renamings will be
+// passed to all rdeps.  The typical way that these renamings will NOT be inherited is when a module
+// links against stubs -- these are not passed through stubs. The classes will remain unrenamed on
+// classes until a module with jarjar_prefix is reached, and all as yet unrenamed classes will then
+// be renamed from that module.
+// TODO: Add another property to suppress the forwarding of
+type JarJarProviderData struct {
+	// Mapping of class names: original --> renamed.  If the value is "", the class will be
+	// renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has
+	// attribute). Rdeps of that module will inherit the renaming.
+	Rename map[string]string
+}
+
+func (this JarJarProviderData) GetDebugString() string {
+	result := ""
+	for k, v := range this.Rename {
+		if strings.Contains(k, "android.companion.virtual.flags.FakeFeatureFlagsImpl") {
+			result += k + "--&gt;" + v + ";"
+		}
+	}
+	return result
+}
+
+var JarJarProvider = blueprint.NewProvider[JarJarProviderData]()
+
+var overridableJarJarPrefix = "com.android.internal.hidden_from_bootclasspath"
+
+func init() {
+	android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
+}
+
+// BaseJarJarProviderData contains information that will propagate across dependencies regardless of
+// whether they are java modules or not.
+type BaseJarJarProviderData struct {
+	JarJarProviderData JarJarProviderData
+}
+
+func (this BaseJarJarProviderData) GetDebugString() string {
+	return this.JarJarProviderData.GetDebugString()
+}
+
+var BaseJarJarProvider = blueprint.NewProvider[BaseJarJarProviderData]()
+
+// mergeJarJarPrefixes is called immediately before module.GenerateAndroidBuildActions is called.
+// Since there won't be a JarJarProvider, we create the BaseJarJarProvider if any of our deps have
+// either JarJarProvider or BaseJarJarProvider.
+func mergeJarJarPrefixes(ctx android.ModuleContext) {
+	mod := ctx.Module()
+	// Explicitly avoid propagating into some module types.
+	switch reflect.TypeOf(mod).String() {
+	case "*java.Droidstubs":
+		return
+	}
+	jarJarData := collectDirectDepsProviders(ctx)
+	if jarJarData != nil {
+		providerData := BaseJarJarProviderData{
+			JarJarProviderData: *jarJarData,
+		}
+		android.SetProvider(ctx, BaseJarJarProvider, providerData)
+	}
+
+}
+
+// Add a jarjar renaming rule to this module, to be inherited to all dependent modules.
+func (module *Module) addJarJarRenameRule(original string, renamed string) {
+	if module.jarjarRenameRules == nil {
+		module.jarjarRenameRules = make(map[string]string)
+	}
+	module.jarjarRenameRules[original] = renamed
+}
+
+func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProviderData) {
+	// Gather repackage information from deps
+	// If the dep jas a JarJarProvider, it is used.  Otherwise, any BaseJarJarProvider is used.
+	ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) {
+		merge := func(theirs *JarJarProviderData) {
+			for orig, renamed := range theirs.Rename {
+				if result == nil {
+					result = &JarJarProviderData{
+						Rename: make(map[string]string),
+					}
+				}
+				if preexisting, exists := (*result).Rename[orig]; !exists || preexisting == "" {
+					result.Rename[orig] = renamed
+				} else if preexisting != "" && renamed != "" && preexisting != renamed {
+					if strings.HasPrefix(preexisting, overridableJarJarPrefix) {
+						result.Rename[orig] = renamed
+					} else if !strings.HasPrefix(renamed, overridableJarJarPrefix) {
+						ctx.ModuleErrorf("1. Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting, ctx.ModuleName(), m.Name())
+						continue
+					}
+				}
+			}
+		}
+		if theirs, ok := android.OtherModuleProvider(ctx, m, JarJarProvider); ok {
+			merge(&theirs)
+		} else if theirs, ok := android.OtherModuleProvider(ctx, m, BaseJarJarProvider); ok {
+			// TODO: if every java.Module should have a JarJarProvider, and we find only the
+			// BaseJarJarProvider, then there is a bug.  Consider seeing if m can be cast
+			// to java.Module.
+			merge(&theirs.JarJarProviderData)
+		}
+	})
+	return
+}
+
+func (this Module) GetDebugString() string {
+	return "sdk_version=" + proptools.String(this.deviceProperties.Sdk_version)
+}
+
+// Merge the jarjar rules we inherit from our dependencies, any that have been added directly to
+// us, and if it's been set, apply the jarjar_prefix property to rename them.
+func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProviderData {
+	// Gather repackage information from deps
+	result := collectDirectDepsProviders(ctx)
+
+	// Update that with entries we've stored for ourself
+	for orig, renamed := range module.jarjarRenameRules {
+		if result == nil {
+			result = &JarJarProviderData{
+				Rename: make(map[string]string),
+			}
+		}
+		if renamed != "" {
+			if preexisting, exists := (*result).Rename[orig]; exists && preexisting != renamed {
+				ctx.ModuleErrorf("Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting)
+				continue
+			}
+		}
+		(*result).Rename[orig] = renamed
+	}
+
+	// If there are no renamings, then jarjar_prefix does nothing, so skip the extra work.
+	if result == nil {
+		return nil
+	}
+
+	// If they've given us a jarjar_prefix property, then we will use that to rename any classes
+	// that have not yet been renamed.
+	prefix := proptools.String(module.properties.Jarjar_prefix)
+	if prefix != "" {
+		if prefix[0] == '.' {
+			ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not start with '.'")
+			return nil
+		}
+		if prefix[len(prefix)-1] == '.' {
+			ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not end with '.'")
+			return nil
+		}
+
+		var updated map[string]string
+		for orig, renamed := range (*result).Rename {
+			if renamed == "" {
+				if updated == nil {
+					updated = make(map[string]string)
+				}
+				updated[orig] = prefix + "." + orig
+			}
+		}
+		for orig, renamed := range updated {
+			(*result).Rename[orig] = renamed
+		}
+	}
+
+	return result
+}
+
+// Get the jarjar rule text for a given provider for the fully resolved rules. Classes that map
+// to "" won't be in this list because they shouldn't be renamed yet.
+func getJarJarRuleText(provider *JarJarProviderData) string {
+	result := ""
+	for orig, renamed := range provider.Rename {
+		if renamed != "" {
+			result += "rule " + orig + " " + renamed + "\n"
+		}
+	}
+	return result
+}
+
 func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) {
 	deps.processorPath = append(deps.processorPath, pluginJars...)
 	deps.processorClasses = append(deps.processorClasses, pluginClasses...)
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 2017801..0ebab4d 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -103,8 +103,8 @@
 func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
 	set := map[string]struct{}{}
 	for _, name := range contents {
-		dep := ctx.GetDirectDepWithTag(name, tag)
-		set[name] = struct{}{}
+		dep, _ := ctx.GetDirectDepWithTag(name, tag).(android.Module)
+		set[ModuleStemForDeapexing(dep)] = struct{}{}
 		if m, ok := dep.(ModuleWithStem); ok {
 			set[m.Stem()] = struct{}{}
 		} else {
diff --git a/java/dex.go b/java/dex.go
index cdae0a2..4474c63 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -262,7 +262,7 @@
 	var proguardRaiseDeps classpath
 	ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
 		dep, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider)
-		proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...)
+		proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...)
 	})
 
 	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ec8b4c8..f7e3cb9 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -617,7 +617,8 @@
 
 // GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
 func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
-	d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config")
+	d.dexpreoptConfigForMake =
+		android.PathForOutput(ctx, dexpreopt.GetDexpreoptDirName(ctx), "dexpreopt.config")
 	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
 }
 
@@ -725,13 +726,19 @@
 	return nil, false
 }
 
+// Returns the stem of an artifact inside a prebuilt apex
+func ModuleStemForDeapexing(m android.Module) string {
+	bmn, _ := m.(interface{ BaseModuleName() string })
+	return bmn.BaseModuleName()
+}
+
 // Returns the java libraries exported by the apex for hiddenapi and dexpreopt
 // This information can come from two mechanisms
 // 1. New: Direct deps to _selected_ apexes. The apexes return a ApexExportsInfo
 // 2. Legacy: An edge to java_library or java_import (java_sdk_library) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
 // TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
 func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToApexExportsInfoMap apexNameToApexExportsInfoMap) android.Path {
-	if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, android.RemoveOptionalPrebuiltPrefix(pair.jarModule.Name())); found {
+	if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, ModuleStemForDeapexing(pair.jarModule)); found {
 		return dex
 	}
 	// TODO: b/308174306 - Remove the legacy mechanism
@@ -1066,8 +1073,8 @@
 		cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
 	}
 
-	if global.EnableUffdGc && image.target.Os == android.Android {
-		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+	if image.target.Os == android.Android {
+		cmd.Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
 	}
 
 	if global.BootFlags != "" {
@@ -1235,7 +1242,7 @@
 func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
 	var allPhonies android.Paths
 	name := image.name
-	global := dexpreopt.GetGlobalConfig(ctx)
+	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 	for _, image := range image.variants {
 		arch := image.target.Arch.ArchType
 		suffix := arch.String()
@@ -1247,6 +1254,7 @@
 		output := android.PathForOutput(ctx, name+"."+suffix+".oatdump.txt")
 		rule := android.NewRuleBuilder(pctx, ctx)
 		imageLocationsOnHost, _ := image.imageLocations()
+
 		cmd := rule.Command().
 			BuiltTool("oatdump").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
@@ -1254,8 +1262,8 @@
 			FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
-		if global.EnableUffdGc && image.target.Os == android.Android {
-			cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+		if image.target.Os == android.Android {
+			cmd.Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
 		}
 		rule.Build("dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 254b2c1..dc0973c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -115,7 +115,7 @@
 func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
 		targets := dexpreoptTargets(ctx)
-		deviceDir := android.PathForOutput(ctx, getDexpreoptDirName(ctx))
+		deviceDir := android.PathForOutput(ctx, dexpreopt.GetDexpreoptDirName(ctx))
 
 		configs := genBootImageConfigRaw(ctx)
 
@@ -234,12 +234,3 @@
 func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
 }
-
-func getDexpreoptDirName(ctx android.PathContext) string {
-	prefix := "dexpreopt_"
-	targets := ctx.Config().Targets[android.Android]
-	if len(targets) > 0 {
-		return prefix + targets[0].Arch.ArchType.String()
-	}
-	return prefix + "unknown_target"
-}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 6ef2afe..56ae427 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -333,66 +333,89 @@
 	}
 }
 
-func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (ret android.Path, err error) {
 	switch stubsType {
 	case Everything:
-		return d.everythingArtifacts.annotationsZip, nil
+		ret, err = d.everythingArtifacts.annotationsZip, nil
 	case Exportable:
-		return d.exportableArtifacts.annotationsZip, nil
+		ret, err = d.exportableArtifacts.annotationsZip, nil
 	default:
-		return nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
+		ret, err = nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
 	}
+	return ret, err
 }
 
-func (d *Droidstubs) ApiFilePath(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) ApiFilePath(stubsType StubsType) (ret android.Path, err error) {
 	switch stubsType {
 	case Everything:
-		return d.apiFile, nil
+		ret, err = d.apiFile, nil
 	case Exportable:
-		return d.exportableApiFile, nil
+		ret, err = d.exportableApiFile, nil
 	default:
-		return nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
+		ret, err = nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
 	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
 }
 
-func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (ret android.Path, err error) {
 	switch stubsType {
 	case Everything:
-		return d.everythingArtifacts.apiVersionsXml, nil
-	default:
-		return nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
-	}
-}
-
-func (d *Droidstubs) DocZip(stubsType StubsType) (android.Path, error) {
-	switch stubsType {
-	case Everything:
-		return d.docZip, nil
-	default:
-		return nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
-	}
-}
-
-func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (android.Path, error) {
-	switch stubsType {
-	case Everything:
-		return d.removedApiFile, nil
+		ret, err = d.everythingArtifacts.apiVersionsXml, nil
 	case Exportable:
-		return d.exportableRemovedApiFile, nil
+		ret, err = d.exportableArtifacts.apiVersionsXml, nil
 	default:
-		return nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
+		ret, err = nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
 	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("api versions xml file is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
 }
 
-func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) DocZip(stubsType StubsType) (ret android.Path, err error) {
 	switch stubsType {
 	case Everything:
-		return d.stubsSrcJar, nil
-	case Exportable:
-		return d.exportableStubsSrcJar, nil
+		ret, err = d.docZip, nil
 	default:
-		return nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
+		ret, err = nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
 	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("docs zip is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
+}
+
+func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.removedApiFile, nil
+	case Exportable:
+		ret, err = d.exportableRemovedApiFile, nil
+	default:
+		ret, err = nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("removed api file is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
+}
+
+func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.stubsSrcJar, nil
+	case Exportable:
+		ret, err = d.exportableStubsSrcJar, nil
+	default:
+		ret, err = nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
 }
 
 func (d *Droidstubs) CurrentApiTimestamp() android.Path {
@@ -537,11 +560,17 @@
 	var apiVersions android.Path
 	if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
 		d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml)
-		apiVersions = d.everythingArtifacts.apiVersionsXml
+		apiVersions = apiVersionsXml
 	} else {
 		ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
 			if s, ok := m.(*Droidstubs); ok {
-				apiVersions = s.everythingArtifacts.apiVersionsXml
+				if stubsType == Everything {
+					apiVersions = s.everythingArtifacts.apiVersionsXml
+				} else if stubsType == Exportable {
+					apiVersions = s.exportableArtifacts.apiVersionsXml
+				} else {
+					ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String())
+				}
 			} else {
 				ctx.PropertyErrorf("api_levels_module",
 					"module %q is not a droidstubs module", ctx.OtherModuleName(m))
@@ -976,8 +1005,11 @@
 		stubConfig: params,
 	}
 
-	d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
-	optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar
+	if params.generateStubs {
+		d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
+		optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar
+	}
+
 	if params.writeSdkValues {
 		d.exportableArtifacts.metadataZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-metadata.zip")
 		d.exportableArtifacts.metadataDir = android.PathForModuleOut(ctx, params.stubsType.String(), "metadata")
@@ -1288,6 +1320,24 @@
 
 type PrebuiltStubsSourcesProperties struct {
 	Srcs []string `android:"path"`
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+
+	// Non-nil if this prebuilt stub srcs  module was dynamically created by a java_sdk_library_import
+	// The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
+	// (without any prebuilt_ prefix)
+	Created_by_java_sdk_library_name *string `blueprint:"mutated"`
+}
+
+func (j *PrebuiltStubsSources) BaseModuleName() string {
+	return proptools.StringDefault(j.properties.Source_module_name, j.ModuleBase.Name())
+}
+
+func (j *PrebuiltStubsSources) CreatedByJavaSdkLibraryName() *string {
+	return j.properties.Created_by_java_sdk_library_name
 }
 
 type PrebuiltStubsSources struct {
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index 40f780c..e8316cc 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -107,3 +107,8 @@
 	module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
 	module.Library.GenerateAndroidBuildActions(ctx)
 }
+
+// Add a rule to the jarjar renaming rules.  See RepackageProviderData.
+func (module *GeneratedJavaLibraryModule) AddJarJarRenameRule(original string, renamed string) {
+	module.addJarJarRenameRule(original, renamed)
+}
diff --git a/java/java.go b/java/java.go
index cd249ed..d7d271c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -248,6 +248,8 @@
 	// against this module.  If empty, ImplementationJars should be used instead.
 	HeaderJars android.Paths
 
+	RepackagedHeaderJars android.Paths
+
 	// set of header jars for all transitive libs deps
 	TransitiveLibsHeaderJars *android.DepSet[android.Path]
 
@@ -2095,6 +2097,11 @@
 	// If unspecified, follows the naming convention that the source module of
 	// the prebuilt is Name() without "prebuilt_" prefix
 	Source_module_name *string
+
+	// Non-nil if this java_import module was dynamically created by a java_sdk_library_import
+	// The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
+	// (without any prebuilt_ prefix)
+	Created_by_java_sdk_library_name *string `blueprint:"mutated"`
 }
 
 type Import struct {
@@ -2180,6 +2187,10 @@
 	return proptools.StringDefault(j.properties.Stem, j.BaseModuleName())
 }
 
+func (j *Import) CreatedByJavaSdkLibraryName() *string {
+	return j.properties.Created_by_java_sdk_library_name
+}
+
 func (a *Import) JacocoReportClassesFile() android.Path {
 	return nil
 }
@@ -2831,7 +2842,20 @@
 type JavaApiContributionImport struct {
 	JavaApiContribution
 
-	prebuilt android.Prebuilt
+	prebuilt           android.Prebuilt
+	prebuiltProperties javaApiContributionImportProperties
+}
+
+type javaApiContributionImportProperties struct {
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+
+	// Non-nil if this java_import module was dynamically created by a java_sdk_library_import
+	// The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
+	// (without any prebuilt_ prefix)
+	Created_by_java_sdk_library_name *string `blueprint:"mutated"`
 }
 
 func ApiContributionImportFactory() android.Module {
@@ -2839,7 +2863,7 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	android.InitPrebuiltModule(module, &[]string{""})
-	module.AddProperties(&module.properties)
+	module.AddProperties(&module.properties, &module.prebuiltProperties)
 	module.AddProperties(&module.sdkLibraryComponentProperties)
 	return module
 }
@@ -2852,6 +2876,14 @@
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
+func (j *JavaApiContributionImport) BaseModuleName() string {
+	return proptools.StringDefault(j.prebuiltProperties.Source_module_name, j.ModuleBase.Name())
+}
+
+func (j *JavaApiContributionImport) CreatedByJavaSdkLibraryName() *string {
+	return j.prebuiltProperties.Created_by_java_sdk_library_name
+}
+
 func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	ap.JavaApiContribution.GenerateAndroidBuildActions(ctx)
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 49e6727..fbde042 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -907,7 +907,30 @@
 type commonSdkLibraryAndImportModule interface {
 	android.Module
 
-	BaseModuleName() string
+	// Returns the name of the root java_sdk_library that creates the child stub libraries
+	// This is the `name` as it appears in Android.bp, and not the name in Soong's build graph
+	// (with the prebuilt_ prefix)
+	//
+	// e.g. in the following java_sdk_library_import
+	// java_sdk_library_import {
+	//    name: "framework-foo.v1",
+	//    source_module_name: "framework-foo",
+	// }
+	// the values returned by
+	// 1. Name(): prebuilt_framework-foo.v1 # unique
+	// 2. BaseModuleName(): framework-foo # the source
+	// 3. RootLibraryName: framework-foo.v1 # the undecordated `name` from Android.bp
+	RootLibraryName() string
+}
+
+func (m *SdkLibrary) RootLibraryName() string {
+	return m.BaseModuleName()
+}
+
+func (m *SdkLibraryImport) RootLibraryName() string {
+	// m.BaseModuleName refers to the source of the import
+	// use moduleBase.Name to get the name of the module as it appears in the .bp file
+	return m.ModuleBase.Name()
 }
 
 // Common code between sdk library and sdk library import
@@ -946,7 +969,7 @@
 		return false
 	}
 
-	namePtr := proptools.StringPtr(c.module.BaseModuleName())
+	namePtr := proptools.StringPtr(c.module.RootLibraryName())
 	c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
 
 	// Only track this sdk library if this can be used as a shared library.
@@ -973,51 +996,51 @@
 
 // Module name of the runtime implementation library
 func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
-	return c.module.BaseModuleName() + ".impl"
+	return c.module.RootLibraryName() + ".impl"
 }
 
 // Module name of the XML file for the lib
 func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
-	return c.module.BaseModuleName() + sdkXmlFileSuffix
+	return c.module.RootLibraryName() + sdkXmlFileSuffix
 }
 
 // Name of the java_library module that compiles the stubs source.
 func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.stubsLibraryModuleName(apiScope, baseName)
 }
 
 // Name of the java_library module that compiles the exportable stubs source.
 func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName)
 }
 
 // Name of the droidstubs module that generates the stubs source and may also
 // generate/check the API.
 func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.stubsSourceModuleName(apiScope, baseName)
 }
 
 // Name of the java_api_library module that generates the from-text stubs source
 // and compiles to a jar file.
 func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
 }
 
 // Name of the java_library module that compiles the stubs
 // generated from source Java files.
 func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName)
 }
 
 // Name of the java_library module that compiles the exportable stubs
 // generated from source Java files.
 func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName)
 }
 
@@ -1067,7 +1090,7 @@
 		if scope, ok := scopeByName[scopeName]; ok {
 			paths := c.findScopePaths(scope)
 			if paths == nil {
-				return nil, fmt.Errorf("%q does not provide api scope %s", c.module.BaseModuleName(), scopeName)
+				return nil, fmt.Errorf("%q does not provide api scope %s", c.module.RootLibraryName(), scopeName)
 			}
 
 			switch component {
@@ -1103,7 +1126,7 @@
 			if c.doctagPaths != nil {
 				return c.doctagPaths, nil
 			} else {
-				return nil, fmt.Errorf("no doctag_files specified on %s", c.module.BaseModuleName())
+				return nil, fmt.Errorf("no doctag_files specified on %s", c.module.RootLibraryName())
 			}
 		}
 		return nil, nil
@@ -1149,7 +1172,7 @@
 
 	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
 	if !sdkVersion.ApiLevel.IsPreview() {
-		return PrebuiltJars(ctx, c.module.BaseModuleName(), sdkVersion)
+		return PrebuiltJars(ctx, c.module.RootLibraryName(), sdkVersion)
 	}
 
 	paths := c.selectScopePaths(ctx, sdkVersion.Kind)
@@ -1176,7 +1199,7 @@
 				scopes = append(scopes, s.name)
 			}
 		}
-		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.BaseModuleName(), scopes)
+		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.RootLibraryName(), scopes)
 		return nil
 	}
 
@@ -1238,7 +1261,7 @@
 		SdkLibraryToImplicitlyTrack *string
 	}{}
 
-	namePtr := proptools.StringPtr(c.module.BaseModuleName())
+	namePtr := proptools.StringPtr(c.module.RootLibraryName())
 	componentProps.SdkLibraryName = namePtr
 
 	if c.sharedLibrary() {
@@ -2525,6 +2548,11 @@
 
 	// If not empty, classes are restricted to the specified packages and their sub-packages.
 	Permitted_packages []string
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 }
 
 type SdkLibraryImport struct {
@@ -2638,6 +2666,10 @@
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
+func (module *SdkLibraryImport) BaseModuleName() string {
+	return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name())
+}
+
 func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
 
 	// If the build is configured to use prebuilts then force this to be preferred.
@@ -2670,15 +2702,19 @@
 func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	// Creates a java import for the jar with ".stubs" suffix
 	props := struct {
-		Name        *string
-		Sdk_version *string
-		Libs        []string
-		Jars        []string
-		Compile_dex *bool
+		Name                             *string
+		Source_module_name               *string
+		Created_by_java_sdk_library_name *string
+		Sdk_version                      *string
+		Libs                             []string
+		Jars                             []string
+		Compile_dex                      *bool
 
 		android.UserSuppliedPrebuiltProperties
 	}{}
 	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+	props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName()))
+	props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
 	props.Sdk_version = scopeProperties.Sdk_version
 	// Prepend any of the libs from the legacy public properties to the libs for each of the
 	// scopes to avoid having to duplicate them in each scope.
@@ -2700,12 +2736,16 @@
 
 func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	props := struct {
-		Name *string
-		Srcs []string
+		Name                             *string
+		Source_module_name               *string
+		Created_by_java_sdk_library_name *string
+		Srcs                             []string
 
 		android.UserSuppliedPrebuiltProperties
 	}{}
 	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
+	props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
+	props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
 	props.Srcs = scopeProperties.Stub_srcs
 
 	// The stubs source is preferred if the java_sdk_library_import is preferred.
@@ -2719,13 +2759,17 @@
 	api_surface := &apiScope.name
 
 	props := struct {
-		Name        *string
-		Api_surface *string
-		Api_file    *string
-		Visibility  []string
+		Name                             *string
+		Source_module_name               *string
+		Created_by_java_sdk_library_name *string
+		Api_surface                      *string
+		Api_file                         *string
+		Visibility                       []string
 	}{}
 
 	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution")
+	props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution")
+	props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
 	props.Api_surface = api_surface
 	props.Api_file = api_file
 	props.Visibility = []string{"//visibility:override", "//visibility:public"}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 3326ec5..93ef408 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1772,3 +1772,151 @@
 		"top level exportable stubs library", []string{exportableSourceStubsLibraryModuleName},
 		topLevelModule.Module().(*Library).properties.Static_libs)
 }
+
+// For java libraries depending on java_sdk_library(_import) via libs, assert that
+// rdep gets stubs of source if source is listed in apex_contributions and prebuilt has prefer (legacy mechanism)
+func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) {
+	bp := `
+		apex_contributions {
+			name: "my_mainline_module_contributions",
+			api_domain: "my_mainline_module",
+			contents: ["sdklib"], // source is selected using apex_contributions, but prebuilt is selected using prefer
+		}
+		java_sdk_library {
+			name: "sdklib",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+		}
+		java_sdk_library_import {
+			name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+			prefer: true, // Set prefer explicitly on the prebuilt. We will assert that rdep gets source in a test case.
+		}
+		// rdeps
+		java_library {
+			name: "mymodule",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			libs: ["sdklib",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
+		}
+	`
+
+	fixture := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("sdklib"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				// We can use any of the apex contribution build flags from build/soong/android/config.go#mainlineApexContributionBuildFlags here
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
+			}
+		}),
+	)
+
+	result := fixture.RunTestWithBp(t, bp)
+	// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
+	public := result.ModuleForTests("mymodule", "android_common")
+	rule := public.Output("javac/mymodule.jar")
+	inputs := rule.Implicits.Strings()
+	android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar")
+}
+
+// test that rdep gets resolved to the correct version of a java_sdk_library (source or a specific prebuilt)
+func TestMultipleSdkLibraryPrebuilts(t *testing.T) {
+	bp := `
+		apex_contributions {
+			name: "my_mainline_module_contributions",
+			api_domain: "my_mainline_module",
+			contents: ["%s"],
+		}
+		java_sdk_library {
+			name: "sdklib",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+		}
+		java_sdk_library_import {
+			name: "sdklib.v1", //prebuilt
+			source_module_name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+		java_sdk_library_import {
+			name: "sdklib.v2", //prebuilt
+			source_module_name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+		// rdeps
+		java_library {
+			name: "mymodule",
+			srcs: ["a.java"],
+			libs: ["sdklib.stubs",],
+		}
+	`
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+		expectedStubPath       string
+	}{
+		{
+			desc:                   "Source library is selected using apex_contributions",
+			selectedDependencyName: "sdklib",
+			expectedStubPath:       "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar",
+		},
+		{
+			desc:                   "Prebuilt library v1 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_sdklib.v1",
+			expectedStubPath:       "out/soong/.intermediates/prebuilt_sdklib.v1.stubs/android_common/combined/sdklib.stubs.jar",
+		},
+		{
+			desc:                   "Prebuilt library v2 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_sdklib.v2",
+			expectedStubPath:       "out/soong/.intermediates/prebuilt_sdklib.v2.stubs/android_common/combined/sdklib.stubs.jar",
+		},
+	}
+
+	fixture := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("sdklib", "sdklib.v1", "sdklib.v2"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
+			}
+		}),
+	)
+
+	for _, tc := range testCases {
+		result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
+		public := result.ModuleForTests("mymodule", "android_common")
+		rule := public.Output("javac/mymodule.jar")
+		inputs := rule.Implicits.Strings()
+		android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, tc.expectedStubPath)
+	}
+}
diff --git a/java/system_modules.go b/java/system_modules.go
index f344648..92e31cd 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -19,6 +19,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -210,7 +211,7 @@
 // type and the one to use is selected at runtime.
 func systemModulesImportFactory() android.Module {
 	module := &systemModulesImport{}
-	module.AddProperties(&module.properties)
+	module.AddProperties(&module.properties, &module.prebuiltProperties)
 	android.InitPrebuiltModule(module, &module.properties.Libs)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
@@ -219,13 +220,39 @@
 
 type systemModulesImport struct {
 	SystemModules
-	prebuilt android.Prebuilt
+	prebuilt           android.Prebuilt
+	prebuiltProperties prebuiltSystemModulesProperties
+}
+
+type prebuiltSystemModulesProperties struct {
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 }
 
 func (system *systemModulesImport) Name() string {
 	return system.prebuilt.Name(system.ModuleBase.Name())
 }
 
+// BaseModuleName returns the source module that will get shadowed by this prebuilt
+// e.g.
+//
+//	java_system_modules_import {
+//	   name: "my_system_modules.v1",
+//	   source_module_name: "my_system_modules",
+//	}
+//
+//	java_system_modules_import {
+//	   name: "my_system_modules.v2",
+//	   source_module_name: "my_system_modules",
+//	}
+//
+// `BaseModuleName` for both will return `my_system_modules`
+func (system *systemModulesImport) BaseModuleName() string {
+	return proptools.StringDefault(system.prebuiltProperties.Source_module_name, system.ModuleBase.Name())
+}
+
 func (system *systemModulesImport) Prebuilt() *android.Prebuilt {
 	return &system.prebuilt
 }
diff --git a/java/system_modules_test.go b/java/system_modules_test.go
index 2ceca5d..336dd21 100644
--- a/java/system_modules_test.go
+++ b/java/system_modules_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -111,3 +112,85 @@
 	expectedPrebuiltPaths := getModuleHeaderJarsAsRelativeToTopPaths(result, "prebuilt_system-module1", "prebuilt_system-module2")
 	android.AssertArrayString(t, "prebuilt system modules inputs", expectedPrebuiltPaths, prebuiltInputs.RelativeToTop().Strings())
 }
+
+func TestMultipleSystemModulesPrebuilts(t *testing.T) {
+	bp := `
+		// an rdep
+		java_library {
+			name: "foo",
+			sdk_version: "none",
+			system_modules: "my_system_modules",
+		}
+
+		// multiple variations of java_system_modules
+		// source
+		java_system_modules {
+			name: "my_system_modules",
+			libs: ["bar"],
+		}
+		java_library {
+			name: "bar",
+			srcs: ["bar.java"],
+		}
+		// prebuilt "v1"
+		java_system_modules_import {
+			name: "my_system_modules.v1",
+			source_module_name: "my_system_modules",
+			libs: ["bar.v1"],
+		}
+		java_import {
+			name: "bar.v1",
+			source_module_name: "bar",
+			jars: ["bar.v1.jar"],
+		}
+		// prebuilt "v2"
+		java_system_modules_import {
+			name: "my_system_modules.v2",
+			source_module_name: "my_system_modules",
+			libs: ["bar.v2"],
+		}
+		java_import {
+			name: "bar.v2",
+			source_module_name: "bar",
+			jars: ["bar.v2.jar"],
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["%v"],
+		}
+	`
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+	}{
+		{
+			desc:                   "Source system_modules is selected using apex_contributions",
+			selectedDependencyName: "my_system_modules",
+		},
+		{
+			desc:                   "Prebuilt system_modules v1 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_my_system_modules.v1",
+		},
+		{
+			desc:                   "Prebuilt system_modules v2 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_my_system_modules.v2",
+		},
+	}
+
+	for _, tc := range testCases {
+		res := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		// check that rdep gets the correct variation of system_modules
+		hasDep := CheckModuleHasDependency(t, res.TestContext, "foo", "android_common", tc.selectedDependencyName)
+		android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from foo to %s\n", tc.selectedDependencyName), true, hasDep)
+	}
+}
diff --git a/python/scripts/precompile_python.py b/python/scripts/precompile_python.py
index e12e7d2..80e7c76 100644
--- a/python/scripts/precompile_python.py
+++ b/python/scripts/precompile_python.py
@@ -16,6 +16,7 @@
 import argparse
 import py_compile
 import os
+import sys
 import shutil
 import tempfile
 import zipfile
@@ -23,22 +24,31 @@
 # This file needs to support both python 2 and 3.
 
 
-def process_one_file(name, inf, outzip):
-    if not name.endswith('.py'):
-        outzip.writestr(name, inf.read())
+def process_one_file(info, infile, outzip):
+    if not info.filename.endswith('.py'):
+        outzip.writestr(info, infile.read())
         return
 
     # Unfortunately py_compile requires the input/output files to be written
     # out to disk.
     with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
-        shutil.copyfileobj(inf, tmp)
+        shutil.copyfileobj(infile, tmp)
         in_name = tmp.name
     with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
         out_name = tmp.name
     try:
-        py_compile.compile(in_name, out_name, name, doraise=True)
+        # Ensure deterministic pyc by using the hash rather than timestamp.
+        # This is required to improve caching in accelerated builds.
+        # Only works on Python 3.7+ (see https://docs.python.org/3/library/py_compile.html#py_compile.PycInvalidationMode)
+        # which should cover most updated branches and developer machines.
+        if sys.version_info >= (3, 7):
+            py_compile.compile(in_name, out_name, info.filename, doraise=True, invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH)
+        else:
+            py_compile.compile(in_name, out_name, info.filename, doraise=True)
         with open(out_name, 'rb') as f:
-            outzip.writestr(name + 'c', f.read())
+            info.filename = info.filename + 'c'
+            # Use ZipInfo rather than str to reuse timestamps for deterministic zip files.
+            outzip.writestr(info, f.read())
     finally:
         os.remove(in_name)
         os.remove(out_name)
@@ -52,9 +62,9 @@
 
     with open(args.dst_zip, 'wb') as outf, open(args.src_zip, 'rb') as inf:
         with zipfile.ZipFile(outf, mode='w') as outzip, zipfile.ZipFile(inf, mode='r') as inzip:
-            for name in inzip.namelist():
-                with inzip.open(name, mode='r') as inzipf:
-                    process_one_file(name, inzipf, outzip)
+            for info in inzip.infolist():
+                with inzip.open(info.filename, mode='r') as inzipf:
+                    process_one_file(info, inzipf, outzip)
 
 
 if __name__ == "__main__":
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 17fd2d8..e0cb3ce 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -63,8 +63,10 @@
 				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.transitiveAndroidMkSharedLibs.ToList()...)
 				entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
 				entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
-				if mod.UseVndk() {
-					entries.SetBool("LOCAL_USE_VNDK", true)
+				if mod.InVendor() {
+					entries.SetBool("LOCAL_IN_VENDOR", true)
+				} else if mod.InProduct() {
+					entries.SetBool("LOCAL_IN_PRODUCT", true)
 				}
 				android.SetAconfigFileMkEntries(mod.AndroidModuleBase(), entries, mod.mergedAconfigFiles)
 			},
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 77ba277..85cc220 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion = "clang-r498229b"
+	bindgenClangVersion = "clang-r510928"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 4f45799..7ebe66b 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -553,6 +553,7 @@
 		vendor: true,
 		nocrt: true,
 		no_libcrt: true,
+		no_crt_pad_segment: true,
 		stl: "none",
 		system_shared_libs: [],
 	}
@@ -857,6 +858,7 @@
 		target_arch: "arm64",
 		compile_multilib: "32",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm: {
 				src: "lib32.so",
@@ -870,6 +872,7 @@
 		target_arch: "arm64",
 		compile_multilib: "64",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm64: {
 				src: "lib64.so",
@@ -882,6 +885,7 @@
 		target_arch: "arm64",
 		compile_multilib: "64",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm64: {
 				src: "liblog.so",
@@ -913,6 +917,7 @@
 		target_arch: "arm64",
 		compile_multilib: "both",
 		vendor: true,
+		no_crt_pad_segment: true,
 		arch: {
 			arm64: {
 				src: "libvendor_available.so",
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 7baaadb..e2fd59f 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -143,6 +143,39 @@
 }
 
 python_library_host {
+    name: "uffd_gc_utils",
+    srcs: [
+        "uffd_gc_utils.py",
+    ],
+    visibility: [
+        "//build/make/tools:__subpackages__",
+    ],
+}
+
+python_test_host {
+    name: "uffd_gc_utils_test",
+    main: "uffd_gc_utils_test.py",
+    srcs: [
+        "uffd_gc_utils_test.py",
+    ],
+    libs: [
+        "uffd_gc_utils",
+    ],
+    test_suites: ["general-tests"],
+}
+
+python_binary_host {
+    name: "construct_uffd_gc_flag",
+    main: "construct_uffd_gc_flag.py",
+    srcs: [
+        "construct_uffd_gc_flag.py",
+    ],
+    libs: [
+        "uffd_gc_utils",
+    ],
+}
+
+python_library_host {
     name: "ninja_rsp",
     srcs: ["ninja_rsp.py"],
 }
diff --git a/scripts/construct_uffd_gc_flag.py b/scripts/construct_uffd_gc_flag.py
new file mode 100644
index 0000000..f437961
--- /dev/null
+++ b/scripts/construct_uffd_gc_flag.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A tool for constructing UFFD GC flag."""
+
+import argparse
+import os
+
+from uffd_gc_utils import should_enable_uffd_gc
+
+
+def parse_args():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('kernel_version_file')
+  parser.add_argument('output')
+  return parser.parse_args()
+
+def main():
+  args = parse_args()
+  enable_uffd_gc = should_enable_uffd_gc(args.kernel_version_file)
+  flag = '--runtime-arg -Xgc:CMC' if enable_uffd_gc else ''
+  # Prevent the file's mtime from being changed if the contents don't change.
+  # This avoids unnecessary dexpreopt reruns.
+  if os.path.isfile(args.output):
+    with open(args.output, 'r') as f:
+      if f.read() == flag:
+        return
+  with open(args.output, 'w') as f:
+    f.write(flag)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/uffd_gc_utils.py b/scripts/uffd_gc_utils.py
new file mode 100644
index 0000000..2d35494
--- /dev/null
+++ b/scripts/uffd_gc_utils.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Utils to determine whether to enable UFFD GC."""
+
+import re
+import sys
+
+
+def should_enable_uffd_gc(kernel_version_file):
+  with open(kernel_version_file, 'r') as f:
+    kernel_version = f.read().strip()
+  return should_enable_uffd_gc_impl(kernel_version)
+
+def should_enable_uffd_gc_impl(kernel_version):
+  # See https://source.android.com/docs/core/architecture/kernel/gki-versioning#determine-release
+  p = r"^(?P<w>\d+)[.](?P<x>\d+)[.](?P<y>\d+)(-android(?P<z>\d+)-(?P<k>\d+).*$)?"
+  m = re.match(p, kernel_version)
+  if m is not None:
+    if m.group('z') is not None:
+      android_release = int(m.group('z'))
+      # No need to check w, x, y because all Android 12 kernels have backports.
+      return android_release >= 12
+    else:
+      # Old kernel or non-GKI kernel.
+      version = int(m.group('w'))
+      patch_level = int(m.group('x'))
+      if version < 5:
+        # Old kernel.
+        return False
+      elif (version == 5 and patch_level >= 7) or version >= 6:
+        # New non-GKI kernel. 5.7 supports MREMAP_DONTUNMAP without the need for
+        # backports.
+        return True
+      else:
+        # Non-GKI kernel between 5 and 5.6. It may have backports.
+        raise exit_with_error(kernel_version)
+  elif kernel_version == '<unknown-kernel>':
+    # The kernel information isn't available to the build system, probably
+    # because PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS is set to false. We
+    # assume that the kernel supports UFFD GC because it is the case for most of
+    # the products today and it is the future.
+    return True
+  else:
+    # Unrecognizable non-GKI kernel.
+    raise exit_with_error(kernel_version)
+
+def exit_with_error(kernel_version):
+  sys.exit(f"""
+Unable to determine UFFD GC flag for kernel version "{kernel_version}".
+You can fix this by explicitly setting PRODUCT_ENABLE_UFFD_GC to "true" or
+"false" based on the kernel version.
+1. Set PRODUCT_ENABLE_UFFD_GC to "true" if the kernel supports userfaultfd(2)
+   and MREMAP_DONTUNMAP.
+2. Set PRODUCT_ENABLE_UFFD_GC to "false" otherwise.""")
diff --git a/scripts/uffd_gc_utils_test.py b/scripts/uffd_gc_utils_test.py
new file mode 100644
index 0000000..c86ab4b
--- /dev/null
+++ b/scripts/uffd_gc_utils_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Unit tests for uffd_gc_utils.py."""
+
+import unittest
+
+from uffd_gc_utils import should_enable_uffd_gc_impl
+
+
+class UffdGcUtilsTest(unittest.TestCase):
+  def test_should_enable_uffd_gc_impl(self):
+    # GKI kernels in new format.
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "6.1.25-android14-11-g34fde9ec08a3-ab10675345"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "5.4.42-android12-0-something"))
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "5.4.42-android11-0-something"))
+    # GKI kernels in old format.
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "4.19.282-g4b749a433956-ab10893502"))
+    # Non GKI kernels.
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "6.1.25-foo"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "6.1.25"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "5.10.19-foo"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "5.10.19"))
+    with self.assertRaises(SystemExit):
+        should_enable_uffd_gc_impl("5.4.42-foo")
+    with self.assertRaises(SystemExit):
+        should_enable_uffd_gc_impl("5.4.42")
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "4.19.282-foo"))
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "4.19.282"))
+    with self.assertRaises(SystemExit):
+        should_enable_uffd_gc_impl("foo")
+    # No kernel.
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "<unknown-kernel>"))
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/ui/build/config.go b/ui/build/config.go
index 5085c68..e29d239 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -115,6 +115,11 @@
 
 	// Data source to write ninja weight list
 	ninjaWeightListSource NinjaWeightListSource
+
+	// This file is a detailed dump of all soong-defined modules for debugging purposes.
+	// There's quite a bit of overlap with module-info.json and soong module graph. We
+	// could consider merging them.
+	moduleDebugFile string
 }
 
 type NinjaWeightListSource uint
@@ -273,6 +278,10 @@
 		ret.sandboxConfig.SetSrcDirIsRO(srcDirIsWritable == "false")
 	}
 
+	if os.Getenv("GENERATE_SOONG_DEBUG") == "true" {
+		ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json"))
+	}
+
 	ret.environ.Unset(
 		// We're already using it
 		"USE_SOONG_UI",
@@ -325,6 +334,9 @@
 		"ANDROID_DEV_SCRIPTS",
 		"ANDROID_EMULATOR_PREBUILTS",
 		"ANDROID_PRE_BUILD_PATHS",
+
+		// We read it here already, don't let others share in the fun
+		"GENERATE_SOONG_DEBUG",
 	)
 
 	if ret.UseGoma() || ret.ForceUseGoma() {
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 65e2c8e..2f25a8c 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -93,6 +93,7 @@
 	"fuser":          Allowed,
 	"gcert":          Allowed,
 	"gcertstatus":    Allowed,
+	"gcloud":         Allowed,
 	"getopt":         Allowed,
 	"git":            Allowed,
 	"hexdump":        Allowed,
@@ -101,7 +102,6 @@
 	"javap":          Allowed,
 	"lsof":           Allowed,
 	"openssl":        Allowed,
-	"prodcertstatus": Allowed,
 	"pstree":         Allowed,
 	"rsync":          Allowed,
 	"sh":             Allowed,
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 90c3bfc..a201ac5 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -204,6 +204,11 @@
 		commonArgs = append(commonArgs, "--build-from-source-stub")
 	}
 
+	if pb.config.moduleDebugFile != "" {
+		commonArgs = append(commonArgs, "--soong_module_debug")
+		commonArgs = append(commonArgs, pb.config.moduleDebugFile)
+	}
+
 	commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
 	invocationEnv := make(map[string]string)
 	if pb.debugPort != "" {