Merge "Temporarily bypass apex availability check for /product apexes with a specific prefix" into main
diff --git a/Android.bp b/Android.bp
index 432c7fc..535246e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,8 @@
 package {
     default_applicable_licenses: ["Android-Apache-2.0"],
+    default_visibility: [
+        "//build/soong:__subpackages__",
+    ],
 }
 
 subdirs = [
@@ -23,6 +26,8 @@
     srcs: [
         "doc.go",
     ],
+    // Used by plugins, though probably shouldn't be.
+    visibility: ["//visibility:public"],
 }
 
 //
@@ -40,6 +45,7 @@
             enabled: true,
         },
     },
+    defaults_visibility: ["//visibility:public"],
 }
 
 //
@@ -51,6 +57,7 @@
     vendor: true,
     recovery_available: true,
     min_sdk_version: "apex_inherit",
+    visibility: ["//visibility:public"],
 }
 
 cc_genrule {
@@ -75,6 +82,7 @@
     cmd: "$(location) -s $(out) $(in)",
     srcs: [":linker"],
     out: ["linker.s"],
+    visibility: ["//bionic/libc"],
 }
 
 cc_genrule {
@@ -99,11 +107,13 @@
     cmd: "$(location) -T $(out) $(in)",
     srcs: [":linker"],
     out: ["linker.script"],
+    visibility: ["//visibility:public"],
 }
 
 // Instantiate the dex_bootjars singleton module.
 dex_bootjars {
     name: "dex_bootjars",
+    visibility: ["//visibility:public"],
 }
 
 // Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
@@ -123,6 +133,7 @@
 // container for apex_contributions selected using build flags
 all_apex_contributions {
     name: "all_apex_contributions",
+    visibility: ["//visibility:public"],
 }
 
 product_config {
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 9b638e7..d9a862c 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -88,6 +88,13 @@
 		ctx.PropertyErrorf("container", "missing container property")
 	}
 
+	// treating system_ext as system partition as we are combining them as one container
+	// TODO remove this logic once we start enforcing that system_ext cannot be specified as
+	// container in the container field.
+	if module.properties.Container == "system_ext" {
+		module.properties.Container = "system"
+	}
+
 	// Add a dependency on the aconfig_value_sets defined in
 	// RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that
 	// match our package.
@@ -219,11 +226,4 @@
 	android.SetProvider(ctx, android.AconfigReleaseDeclarationsProviderKey, providerData)
 }
 
-func (module *DeclarationsModule) BuildActionProviderKeys() []blueprint.AnyProviderKey {
-	return []blueprint.AnyProviderKey{
-		android.AconfigDeclarationsProviderKey,
-		android.AconfigReleaseDeclarationsProviderKey,
-	}
-}
-
 var _ blueprint.Incremental = &DeclarationsModule{}
diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go
index 7ba76c0..d72ec48 100644
--- a/aconfig/aconfig_value_set.go
+++ b/aconfig/aconfig_value_set.go
@@ -16,6 +16,9 @@
 
 import (
 	"android/soong/android"
+	"fmt"
+	"strings"
+
 	"github.com/google/blueprint"
 )
 
@@ -27,6 +30,9 @@
 	properties struct {
 		// aconfig_values modules
 		Values []string
+
+		// Paths to the Android.bp files where the aconfig_values modules are defined.
+		Srcs []string
 	}
 }
 
@@ -56,7 +62,35 @@
 
 var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]()
 
+func (module *ValueSetModule) FindAconfigValuesFromSrc(ctx android.BottomUpMutatorContext) map[string]android.Path {
+	moduleDir := ctx.ModuleDir()
+	srcs := android.PathsForModuleSrcExcludes(ctx, module.properties.Srcs, []string{ctx.BlueprintsFile()})
+
+	aconfigValuesPrefix := strings.Replace(module.Name(), "aconfig_value_set", "aconfig-values", 1)
+	moduleNamesSrcMap := make(map[string]android.Path)
+	for _, src := range srcs {
+		subDir := strings.TrimPrefix(src.String(), moduleDir+"/")
+		packageName, _, found := strings.Cut(subDir, "/")
+		if found {
+			moduleName := fmt.Sprintf("%s-%s-all", aconfigValuesPrefix, packageName)
+			moduleNamesSrcMap[moduleName] = src
+		}
+	}
+	return moduleNamesSrcMap
+}
+
 func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+
+	// TODO: b/366285733 - Replace the file path based solution with more robust solution.
+	aconfigValuesMap := module.FindAconfigValuesFromSrc(ctx)
+	for _, moduleName := range android.SortedKeys(aconfigValuesMap) {
+		if ctx.OtherModuleExists(moduleName) {
+			ctx.AddDependency(ctx.Module(), valueSetTag, moduleName)
+		} else {
+			ctx.ModuleErrorf("module %q not found. Rename the aconfig_values module defined in %q to %q", moduleName, aconfigValuesMap[moduleName], moduleName)
+		}
+	}
+
 	deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...)
 	for _, dep := range deps {
 		_, ok := dep.(*ValuesModule)
diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go
index 32c31cb..3b7281e 100644
--- a/aconfig/aconfig_value_set_test.go
+++ b/aconfig/aconfig_value_set_test.go
@@ -18,6 +18,8 @@
 	"testing"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint"
 )
 
 func TestAconfigValueSet(t *testing.T) {
@@ -41,3 +43,112 @@
 	depData, _ := android.OtherModuleProvider(result, module, valueSetProviderKey)
 	android.AssertStringEquals(t, "AvailablePackages", "blah.aconfig_values", depData.AvailablePackages["foo.package"][0].String())
 }
+
+func TestAconfigValueSetBpGlob(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				// .../some_release/android.foo/
+				"some_release/android.foo/Android.bp": []byte(`
+				aconfig_values {
+					name: "aconfig-values-platform_build_release-some_release-android.foo-all",
+					package: "android.foo",
+					srcs: [
+						"*.textproto",
+					],
+				}
+				`),
+				"some_release/android.foo/flag.textproto": nil,
+
+				// .../some_release/android.bar/
+				"some_release/android.bar/Android.bp": []byte(`
+				aconfig_values {
+					name: "aconfig-values-platform_build_release-some_release-android.bar-all",
+					package: "android.bar",
+					srcs: [
+						"*.textproto",
+					],
+				}
+				`),
+				"some_release/android.bar/flag.textproto": nil,
+
+				// .../some_release/
+				"some_release/Android.bp": []byte(`
+				aconfig_value_set {
+					name: "aconfig_value_set-platform_build_release-some_release",
+					srcs: [
+						"*/Android.bp",
+					],
+				}
+				`),
+			},
+		),
+	).RunTest(t)
+
+	checkModuleHasDependency := func(name, variant, dep string) bool {
+		t.Helper()
+		module := result.ModuleForTests(name, variant).Module()
+		depFound := false
+		result.VisitDirectDeps(module, func(m blueprint.Module) {
+			if m.Name() == dep {
+				depFound = true
+			}
+		})
+		return depFound
+	}
+	android.AssertBoolEquals(t,
+		"aconfig_value_set expected to depend on aconfig_value via srcs",
+		true,
+		checkModuleHasDependency(
+			"aconfig_value_set-platform_build_release-some_release",
+			"",
+			"aconfig-values-platform_build_release-some_release-android.foo-all",
+		),
+	)
+	android.AssertBoolEquals(t,
+		"aconfig_value_set expected to depend on aconfig_value via srcs",
+		true,
+		checkModuleHasDependency(
+			"aconfig_value_set-platform_build_release-some_release",
+			"",
+			"aconfig-values-platform_build_release-some_release-android.bar-all",
+		),
+	)
+}
+
+func TestAconfigValueSetBpGlobError(t *testing.T) {
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				// .../some_release/android.bar/
+				"some_release/android.bar/Android.bp": []byte(`
+				aconfig_values {
+					name: "aconfig-values-platform_build_release-some_release-android_bar-all",
+					package: "android.bar",
+					srcs: [
+						"*.textproto",
+					],
+				}
+				`),
+				"some_release/android.bar/flag.textproto": nil,
+
+				// .../some_release/
+				"some_release/Android.bp": []byte(`
+				aconfig_value_set {
+					name: "aconfig_value_set-platform_build_release-some_release",
+					srcs: [
+						"*/Android.bp",
+					],
+				}
+				`),
+			},
+		),
+	).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+		`module "aconfig_value_set-platform_build_release-some_release": module ` +
+			`"aconfig-values-platform_build_release-some_release-android.bar-all" not found. ` +
+			`Rename the aconfig_values module defined in "some_release/android.bar/Android.bp" ` +
+			`to "aconfig-values-platform_build_release-some_release-android.bar-all"`),
+	).RunTest(t)
+}
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index ec0a6b6..b5cf687 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -156,7 +156,7 @@
 		Args: map[string]string{
 			"gendir": this.generatedDir.String(),
 			"mode":   mode,
-			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorageCc()),
+			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
 		},
 	})
 
diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go
index 6182e14..98d288f 100644
--- a/aconfig/codegen/init.go
+++ b/aconfig/codegen/init.go
@@ -64,11 +64,12 @@
 				` && ${aconfig} create-rust-lib` +
 				`    --mode ${mode}` +
 				`    --cache ${in}` +
+				`    --allow-instrumentation ${debug}` +
 				`    --out ${gendir}`,
 			CommandDeps: []string{
 				"$aconfig",
 			},
-		}, "gendir", "mode")
+		}, "gendir", "mode", "debug")
 )
 
 func init() {
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
index 87b54a4..d8372f3 100644
--- a/aconfig/codegen/java_aconfig_library_test.go
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -260,7 +260,7 @@
 			aconfig_declarations {
 				name: "my_aconfig_declarations_bar",
 				package: "com.example.package.bar",
-				container: "system_ext",
+				container: "vendor",
 				srcs: ["bar.aconfig"],
 			}
 
diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
index ad8d632..4b896c3 100644
--- a/aconfig/codegen/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -2,6 +2,7 @@
 
 import (
 	"fmt"
+	"strconv"
 
 	"android/soong/android"
 	"android/soong/rust"
@@ -82,6 +83,7 @@
 		Args: map[string]string{
 			"gendir": generatedDir.String(),
 			"mode":   mode,
+			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
 		},
 	})
 	a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
diff --git a/aconfig/init.go b/aconfig/init.go
index 5fa7e76..6f91d8e 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -15,8 +15,6 @@
 package aconfig
 
 import (
-	"encoding/gob"
-
 	"android/soong/android"
 
 	"github.com/google/blueprint"
@@ -108,10 +106,6 @@
 	RegisterBuildComponents(android.InitRegistrationContext)
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
-
-	gob.Register(android.AconfigDeclarationsProviderData{})
-	gob.Register(android.AconfigReleaseDeclarationsProviderData{})
-	gob.Register(android.ModuleOutPath{})
 }
 
 func RegisterBuildComponents(ctx android.RegistrationContext) {
diff --git a/aidl_library/Android.bp b/aidl_library/Android.bp
index ec21504..07472a4 100644
--- a/aidl_library/Android.bp
+++ b/aidl_library/Android.bp
@@ -29,4 +29,5 @@
         "aidl_library_test.go",
     ],
     pluginFor: ["soong_build"],
+    visibility: ["//visibility:public"],
 }
diff --git a/android/Android.bp b/android/Android.bp
index 78eca11..2adedfe 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -59,6 +59,7 @@
         "gen_notice.go",
         "hooks.go",
         "image.go",
+        "init.go",
         "license.go",
         "license_kind.go",
         "license_metadata.go",
@@ -87,6 +88,7 @@
         "prebuilt.go",
         "prebuilt_build_tool.go",
         "product_config.go",
+        "product_config_to_bp.go",
         "proto.go",
         "provider.go",
         "raw_files.go",
@@ -153,4 +155,6 @@
         "vintf_fragment_test.go",
         "visibility_test.go",
     ],
+    // Used by plugins
+    visibility: ["//visibility:public"],
 }
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index f0675dd..d2a9622 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -136,7 +136,7 @@
 			AconfigFiles: mergedAconfigFiles,
 			ModeInfos:    mergedModeInfos,
 		})
-		ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
+		ctx.setAconfigPaths(getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles))
 	}
 }
 
@@ -187,6 +187,20 @@
 	}
 }
 
+func aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod Module, infos *AndroidMkProviderInfo) {
+	info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
+	if !ok || len(info.AconfigFiles) == 0 {
+		return
+	}
+	// All of the files in the module potentially depend on the aconfig flag values.
+	infos.PrimaryInfo.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles))
+	if len(infos.ExtraInfo) > 0 {
+		for _, ei := range (*infos).ExtraInfo {
+			ei.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles))
+		}
+	}
+}
+
 func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
 	inputs = SortedUniquePaths(inputs)
 	if len(inputs) == 1 {
@@ -219,7 +233,8 @@
 	} else if m.ProductSpecific() {
 		container = "product"
 	} else if m.SystemExtSpecific() {
-		container = "system_ext"
+		// system_ext and system partitions should be treated as one container
+		container = "system"
 	}
 
 	paths = append(paths, aconfigFiles[container]...)
diff --git a/android/androidmk.go b/android/androidmk.go
index 68a6415..cac2cfe 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -34,7 +34,6 @@
 	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 )
@@ -502,6 +501,7 @@
 	otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
 	ModuleType(module blueprint.Module) string
 	OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
+	HasMutatorFinished(mutatorName string) bool
 }
 
 func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
@@ -554,6 +554,14 @@
 		a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
 	}
 
+	if info.UncheckedModule {
+		a.SetBool("LOCAL_DONT_CHECK_MODULE", true)
+	} else if info.CheckbuildTarget != nil {
+		a.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget)
+	} else {
+		a.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
+	}
+
 	if len(info.TestData) > 0 {
 		a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
 	}
@@ -798,15 +806,19 @@
 
 	// Additional cases here require review for correct license propagation to make.
 	var err error
-	switch x := mod.(type) {
-	case AndroidMkDataProvider:
-		err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x)
-	case bootstrap.GoBinaryTool:
-		err = translateGoBinaryModule(ctx, w, mod, x)
-	case AndroidMkEntriesProvider:
-		err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x)
-	default:
-		// Not exported to make so no make variables to set.
+
+	if info, ok := ctx.otherModuleProvider(mod, AndroidMkInfoProvider); ok {
+		androidMkEntriesInfos := info.(*AndroidMkProviderInfo)
+		err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, androidMkEntriesInfos)
+	} else {
+		switch x := mod.(type) {
+		case AndroidMkDataProvider:
+			err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x)
+		case AndroidMkEntriesProvider:
+			err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x)
+		default:
+			// Not exported to make so no make variables to set.
+		}
 	}
 
 	if err != nil {
@@ -816,23 +828,6 @@
 	return err
 }
 
-// A simple, special Android.mk entry output func to make it possible to build blueprint tools using
-// m by making them phony targets.
-func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
-	goBinary bootstrap.GoBinaryTool) error {
-
-	name := ctx.ModuleName(mod)
-	fmt.Fprintln(w, ".PHONY:", name)
-	fmt.Fprintln(w, name+":", goBinary.InstallPath())
-	fmt.Fprintln(w, "")
-	// Assuming no rules in make include go binaries in distributables.
-	// If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files.
-	// In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for
-	// `goBinary.InstallPath()` pointing to the `name`.meta_lic file.
-
-	return nil
-}
-
 func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Module) {
 	// Get the preamble content through AndroidMkEntries logic.
 	data.Entries = AndroidMkEntries{
@@ -905,6 +900,7 @@
 		case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
 		case "*apex.apexBundle": // license properties written
 		case "*bpf.bpf": // license properties written (both for module and objs)
+		case "*libbpf_prog.libbpfProg": // license properties written (both for module and objs)
 		case "*genrule.Module": // writes non-custom before adding .phony
 		case "*java.SystemModules": // doesn't go through base_rules
 		case "*java.systemModulesImport": // doesn't go through base_rules
@@ -912,6 +908,7 @@
 		case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
 		case "*selinux.selinuxContextsModule": // license properties written
 		case "*sysprop.syspropLibrary": // license properties written
+		case "*vintf.vintfCompatibilityMatrixRule": // use case like phony
 		default:
 			if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
 				return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
@@ -973,11 +970,11 @@
 	return nil
 }
 
-func ShouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module Module) bool {
+func ShouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module Module) bool {
 	return shouldSkipAndroidMkProcessing(ctx, module.base())
 }
 
-func shouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module *ModuleBase) bool {
+func shouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module *ModuleBase) bool {
 	if !module.commonProperties.NamespaceExportedToMake {
 		// TODO(jeffrygaston) do we want to validate that there are no modules being
 		// exported to Kati that depend on this module?
@@ -1053,3 +1050,564 @@
 	}
 	fmt.Fprintln(w)
 }
+
+type AndroidMkProviderInfo struct {
+	PrimaryInfo AndroidMkInfo
+	ExtraInfo   []AndroidMkInfo
+}
+
+type AndroidMkInfo struct {
+	// Android.mk class string, e.g. EXECUTABLES, JAVA_LIBRARIES, ETC
+	Class string
+	// Optional suffix to append to the module name. Useful when a module wants to return multiple
+	// AndroidMkEntries objects. For example, when a java_library returns an additional entry for
+	// its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a
+	// different name than the parent's.
+	SubName string
+	// If set, this value overrides the base module name. SubName is still appended.
+	OverrideName string
+	// Dist files to output
+	DistFiles TaggedDistFiles
+	// The output file for Kati to process and/or install. If absent, the module is skipped.
+	OutputFile OptionalPath
+	// If true, the module is skipped and does not appear on the final Android-<product name>.mk
+	// file. Useful when a module needs to be skipped conditionally.
+	Disabled bool
+	// The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
+	// If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
+	Include string
+	// Required modules that need to be built and included in the final build output when building
+	// this module.
+	Required []string
+	// Required host modules that need to be built and included in the final build output when
+	// building this module.
+	Host_required []string
+	// Required device modules that need to be built and included in the final build output when
+	// building this module.
+	Target_required []string
+
+	HeaderStrings []string
+	FooterStrings []string
+
+	// A map that holds the up-to-date Make variable values. Can be accessed from tests.
+	EntryMap map[string][]string
+	// A list of EntryMap keys in insertion order. This serves a few purposes:
+	// 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this,
+	// the outputted Android-*.mk file may change even though there have been no content changes.
+	// 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR),
+	// without worrying about the variables being mixed up in the actual mk file.
+	// 3. Makes troubleshooting and spotting errors easier.
+	EntryOrder []string
+}
+
+// TODO: rename it to AndroidMkEntriesProvider after AndroidMkEntriesProvider interface is gone.
+var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]()
+
+func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
+	mod blueprint.Module, providerInfo *AndroidMkProviderInfo) error {
+	if shouldSkipAndroidMkProcessing(ctx, mod.(Module).base()) {
+		return nil
+	}
+
+	// Deep copy the provider info since we need to modify the info later
+	info := deepCopyAndroidMkProviderInfo(providerInfo)
+
+	aconfigUpdateAndroidMkInfos(ctx, mod.(Module), &info)
+
+	// Any new or special cases here need review to verify correct propagation of license information.
+	info.PrimaryInfo.fillInEntries(ctx, mod)
+	info.PrimaryInfo.write(w)
+	if len(info.ExtraInfo) > 0 {
+		for _, ei := range info.ExtraInfo {
+			ei.fillInEntries(ctx, mod)
+			ei.write(w)
+		}
+	}
+
+	if !info.PrimaryInfo.disabled() {
+		if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+			*moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+		}
+	}
+
+	return nil
+}
+
+// Utility funcs to manipulate Android.mk variable entries.
+
+// SetString sets a Make variable with the given name to the given value.
+func (a *AndroidMkInfo) SetString(name, value string) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	a.EntryMap[name] = []string{value}
+}
+
+// SetPath sets a Make variable with the given name to the given path string.
+func (a *AndroidMkInfo) SetPath(name string, path Path) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	a.EntryMap[name] = []string{path.String()}
+}
+
+// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid.
+// It is a no-op if the given path is invalid.
+func (a *AndroidMkInfo) SetOptionalPath(name string, path OptionalPath) {
+	if path.Valid() {
+		a.SetPath(name, path.Path())
+	}
+}
+
+// AddPath appends the given path string to a Make variable with the given name.
+func (a *AndroidMkInfo) AddPath(name string, path Path) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	a.EntryMap[name] = append(a.EntryMap[name], path.String())
+}
+
+// AddOptionalPath appends the given path string to a Make variable with the given name if it is
+// valid. It is a no-op if the given path is invalid.
+func (a *AndroidMkInfo) AddOptionalPath(name string, path OptionalPath) {
+	if path.Valid() {
+		a.AddPath(name, path.Path())
+	}
+}
+
+// SetPaths sets a Make variable with the given name to a slice of the given path strings.
+func (a *AndroidMkInfo) SetPaths(name string, paths Paths) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	a.EntryMap[name] = paths.Strings()
+}
+
+// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings
+// only if there are a non-zero amount of paths.
+func (a *AndroidMkInfo) SetOptionalPaths(name string, paths Paths) {
+	if len(paths) > 0 {
+		a.SetPaths(name, paths)
+	}
+}
+
+// AddPaths appends the given path strings to a Make variable with the given name.
+func (a *AndroidMkInfo) AddPaths(name string, paths Paths) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...)
+}
+
+// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true.
+// It is a no-op if the given flag is false.
+func (a *AndroidMkInfo) SetBoolIfTrue(name string, flag bool) {
+	if flag {
+		if _, ok := a.EntryMap[name]; !ok {
+			a.EntryOrder = append(a.EntryOrder, name)
+		}
+		a.EntryMap[name] = []string{"true"}
+	}
+}
+
+// SetBool sets a Make variable with the given name to if the given bool flag value.
+func (a *AndroidMkInfo) SetBool(name string, flag bool) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	if flag {
+		a.EntryMap[name] = []string{"true"}
+	} else {
+		a.EntryMap[name] = []string{"false"}
+	}
+}
+
+// AddStrings appends the given strings to a Make variable with the given name.
+func (a *AndroidMkInfo) AddStrings(name string, value ...string) {
+	if len(value) == 0 {
+		return
+	}
+	if _, ok := a.EntryMap[name]; !ok {
+		a.EntryOrder = append(a.EntryOrder, name)
+	}
+	a.EntryMap[name] = append(a.EntryMap[name], value...)
+}
+
+// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
+// for partial MTS and MCTS test suites.
+func (a *AndroidMkInfo) AddCompatibilityTestSuites(suites ...string) {
+	// M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
+	// To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite,
+	// we add the full test suite to our list.
+	if PrefixInList(suites, "mts-") && !InList("mts", suites) {
+		suites = append(suites, "mts")
+	}
+	if PrefixInList(suites, "mcts-") && !InList("mcts", suites) {
+		suites = append(suites, "mcts")
+	}
+	a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
+}
+
+func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
+	helperInfo := AndroidMkInfo{
+		EntryMap: make(map[string][]string),
+	}
+
+	amod := mod.(Module)
+	base := amod.base()
+	name := base.BaseModuleName()
+	if a.OverrideName != "" {
+		name = a.OverrideName
+	}
+
+	if a.Include == "" {
+		a.Include = "$(BUILD_PREBUILT)"
+	}
+	a.Required = append(a.Required, amod.RequiredModuleNames(ctx)...)
+	a.Required = append(a.Required, amod.VintfFragmentModuleNames(ctx)...)
+	a.Host_required = append(a.Host_required, amod.HostRequiredModuleNames()...)
+	a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...)
+
+	for _, distString := range a.GetDistForGoals(ctx, mod) {
+		a.HeaderStrings = append(a.HeaderStrings, distString)
+	}
+
+	a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod)))
+
+	// Collect make variable assignment entries.
+	helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
+	helperInfo.SetString("LOCAL_MODULE", name+a.SubName)
+	helperInfo.SetString("LOCAL_MODULE_CLASS", a.Class)
+	helperInfo.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
+	helperInfo.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
+	helperInfo.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
+	helperInfo.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
+	helperInfo.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod))
+
+	// If the install rule was generated by Soong tell Make about it.
+	info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
+	if len(info.KatiInstalls) > 0 {
+		// Assume the primary install file is last since it probably needs to depend on any other
+		// installed files.  If that is not the case we can add a method to specify the primary
+		// installed file.
+		helperInfo.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to)
+		helperInfo.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled())
+		helperInfo.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths())
+	} else {
+		// Soong may not have generated the install rule also when `no_full_install: true`.
+		// Mark this module as uninstallable in order to prevent Make from creating an
+		// install rule there.
+		helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
+	}
+
+	if len(info.TestData) > 0 {
+		helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
+	}
+
+	if am, ok := mod.(ApexModule); ok {
+		helperInfo.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform())
+	}
+
+	archStr := base.Arch().ArchType.String()
+	host := false
+	switch base.Os().Class {
+	case Host:
+		if base.Target().HostCross {
+			// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
+			if base.Arch().ArchType != Common {
+				helperInfo.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
+			}
+		} else {
+			// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
+			if base.Arch().ArchType != Common {
+				helperInfo.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
+			}
+		}
+		host = true
+	case Device:
+		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
+		if base.Arch().ArchType != Common {
+			if base.Target().NativeBridge {
+				hostArchStr := base.Target().NativeBridgeHostArchName
+				if hostArchStr != "" {
+					helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
+				}
+			} else {
+				helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
+			}
+		}
+
+		if !base.InVendorRamdisk() {
+			helperInfo.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths)
+		}
+		if len(info.VintfFragmentsPaths) > 0 {
+			helperInfo.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths)
+		}
+		helperInfo.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary))
+		if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) {
+			helperInfo.SetString("LOCAL_VENDOR_MODULE", "true")
+		}
+		helperInfo.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(base.commonProperties.Device_specific))
+		helperInfo.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(base.commonProperties.Product_specific))
+		helperInfo.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(base.commonProperties.System_ext_specific))
+		if base.commonProperties.Owner != nil {
+			helperInfo.SetString("LOCAL_MODULE_OWNER", *base.commonProperties.Owner)
+		}
+	}
+
+	if host {
+		makeOs := base.Os().String()
+		if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl {
+			makeOs = "linux"
+		}
+		helperInfo.SetString("LOCAL_MODULE_HOST_OS", makeOs)
+		helperInfo.SetString("LOCAL_IS_HOST_MODULE", "true")
+	}
+
+	prefix := ""
+	if base.ArchSpecific() {
+		switch base.Os().Class {
+		case Host:
+			if base.Target().HostCross {
+				prefix = "HOST_CROSS_"
+			} else {
+				prefix = "HOST_"
+			}
+		case Device:
+			prefix = "TARGET_"
+
+		}
+
+		if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType {
+			prefix = "2ND_" + prefix
+		}
+	}
+
+	if licenseMetadata, ok := OtherModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
+		helperInfo.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
+	}
+
+	if _, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+		helperInfo.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
+	}
+
+	a.mergeEntries(&helperInfo)
+
+	// Write to footer.
+	a.FooterStrings = append([]string{"include " + a.Include}, a.FooterStrings...)
+}
+
+// This method merges the entries to helperInfo, then replaces a's EntryMap and
+// EntryOrder with helperInfo's
+func (a *AndroidMkInfo) mergeEntries(helperInfo *AndroidMkInfo) {
+	for _, extraEntry := range a.EntryOrder {
+		if v, ok := helperInfo.EntryMap[extraEntry]; ok {
+			v = append(v, a.EntryMap[extraEntry]...)
+		} else {
+			helperInfo.EntryMap[extraEntry] = a.EntryMap[extraEntry]
+			helperInfo.EntryOrder = append(helperInfo.EntryOrder, extraEntry)
+		}
+	}
+	a.EntryOrder = helperInfo.EntryOrder
+	a.EntryMap = helperInfo.EntryMap
+}
+
+func (a *AndroidMkInfo) disabled() bool {
+	return a.Disabled || !a.OutputFile.Valid()
+}
+
+// write  flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the
+// given Writer object.
+func (a *AndroidMkInfo) write(w io.Writer) {
+	if a.disabled() {
+		return
+	}
+
+	combinedHeaderString := strings.Join(a.HeaderStrings, "\n")
+	combinedFooterString := strings.Join(a.FooterStrings, "\n")
+	w.Write([]byte(combinedHeaderString))
+	for _, name := range a.EntryOrder {
+		AndroidMkEmitAssignList(w, name, a.EntryMap[name])
+	}
+	w.Write([]byte(combinedFooterString))
+}
+
+// Compute the list of Make strings to declare phony goals and dist-for-goals
+// calls from the module's dist and dists properties.
+func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod blueprint.Module) []string {
+	distContributions := a.getDistContributions(ctx, mod)
+	if distContributions == nil {
+		return nil
+	}
+
+	return generateDistContributionsForMake(distContributions)
+}
+
+// Compute the contributions that the module makes to the dist.
+func (a *AndroidMkInfo) getDistContributions(ctx fillInEntriesContext, mod blueprint.Module) *distContributions {
+	amod := mod.(Module).base()
+	name := amod.BaseModuleName()
+
+	// Collate the set of associated tag/paths available for copying to the dist.
+	// Start with an empty (nil) set.
+	var availableTaggedDists TaggedDistFiles
+
+	// Then merge in any that are provided explicitly by the module.
+	if a.DistFiles != nil {
+		// Merge the DistFiles into the set.
+		availableTaggedDists = availableTaggedDists.merge(a.DistFiles)
+	}
+
+	// If no paths have been provided for the DefaultDistTag and the output file is
+	// valid then add that as the default dist path.
+	if _, ok := availableTaggedDists[DefaultDistTag]; !ok && a.OutputFile.Valid() {
+		availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
+	}
+
+	info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
+	// If the distFiles created by GenerateTaggedDistFiles contains paths for the
+	// DefaultDistTag then that takes priority so delete any existing paths.
+	if _, ok := info.DistFiles[DefaultDistTag]; ok {
+		delete(availableTaggedDists, DefaultDistTag)
+	}
+
+	// Finally, merge the distFiles created by GenerateTaggedDistFiles.
+	availableTaggedDists = availableTaggedDists.merge(info.DistFiles)
+
+	if len(availableTaggedDists) == 0 {
+		// Nothing dist-able for this module.
+		return nil
+	}
+
+	// Collate the contributions this module makes to the dist.
+	distContributions := &distContributions{}
+
+	if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) {
+		distContributions.licenseMetadataFile = info.LicenseMetadataFile
+	}
+
+	// Iterate over this module's dist structs, merged from the dist and dists properties.
+	for _, dist := range amod.Dists() {
+		// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
+		goals := strings.Join(dist.Targets, " ")
+
+		// Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map"
+		var tag string
+		if dist.Tag == nil {
+			// If the dist struct does not specify a tag, use the default output files tag.
+			tag = DefaultDistTag
+		} else {
+			tag = *dist.Tag
+		}
+
+		// Get the paths of the output files to be dist'd, represented by the tag.
+		// Can be an empty list.
+		tagPaths := availableTaggedDists[tag]
+		if len(tagPaths) == 0 {
+			// Nothing to dist for this tag, continue to the next dist.
+			continue
+		}
+
+		if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) {
+			errorMessage := "%s: Cannot apply dest/suffix for more than one dist " +
+				"file for %q goals tag %q in module %s. The list of dist files, " +
+				"which should have a single element, is:\n%s"
+			panic(fmt.Errorf(errorMessage, mod, goals, tag, name, tagPaths))
+		}
+
+		copiesForGoals := distContributions.getCopiesForGoals(goals)
+
+		// Iterate over each path adding a copy instruction to copiesForGoals
+		for _, path := range tagPaths {
+			// It's possible that the Path is nil from errant modules. Be defensive here.
+			if path == nil {
+				tagName := "default" // for error message readability
+				if dist.Tag != nil {
+					tagName = *dist.Tag
+				}
+				panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name))
+			}
+
+			dest := filepath.Base(path.String())
+
+			if dist.Dest != nil {
+				var err error
+				if dest, err = validateSafePath(*dist.Dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			ext := filepath.Ext(dest)
+			suffix := ""
+			if dist.Suffix != nil {
+				suffix = *dist.Suffix
+			}
+
+			productString := ""
+			if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product {
+				productString = fmt.Sprintf("_%s", ctx.Config().DeviceProduct())
+			}
+
+			if suffix != "" || productString != "" {
+				dest = strings.TrimSuffix(dest, ext) + suffix + productString + ext
+			}
+
+			if dist.Dir != nil {
+				var err error
+				if dest, err = validateSafePath(*dist.Dir, dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			copiesForGoals.addCopyInstruction(path, dest)
+		}
+	}
+
+	return distContributions
+}
+
+func deepCopyAndroidMkProviderInfo(providerInfo *AndroidMkProviderInfo) AndroidMkProviderInfo {
+	info := AndroidMkProviderInfo{
+		PrimaryInfo: deepCopyAndroidMkInfo(&providerInfo.PrimaryInfo),
+	}
+	if len(providerInfo.ExtraInfo) > 0 {
+		for _, i := range providerInfo.ExtraInfo {
+			info.ExtraInfo = append(info.ExtraInfo, deepCopyAndroidMkInfo(&i))
+		}
+	}
+	return info
+}
+
+func deepCopyAndroidMkInfo(mkinfo *AndroidMkInfo) AndroidMkInfo {
+	info := AndroidMkInfo{
+		Class:        mkinfo.Class,
+		SubName:      mkinfo.SubName,
+		OverrideName: mkinfo.OverrideName,
+		// There is no modification on DistFiles or OutputFile, so no need to
+		// make their deep copy.
+		DistFiles:       mkinfo.DistFiles,
+		OutputFile:      mkinfo.OutputFile,
+		Disabled:        mkinfo.Disabled,
+		Include:         mkinfo.Include,
+		Required:        deepCopyStringSlice(mkinfo.Required),
+		Host_required:   deepCopyStringSlice(mkinfo.Host_required),
+		Target_required: deepCopyStringSlice(mkinfo.Target_required),
+		HeaderStrings:   deepCopyStringSlice(mkinfo.HeaderStrings),
+		FooterStrings:   deepCopyStringSlice(mkinfo.FooterStrings),
+		EntryOrder:      deepCopyStringSlice(mkinfo.EntryOrder),
+	}
+	info.EntryMap = make(map[string][]string)
+	for k, v := range mkinfo.EntryMap {
+		info.EntryMap[k] = deepCopyStringSlice(v)
+	}
+
+	return info
+}
+
+func deepCopyStringSlice(original []string) []string {
+	result := make([]string, len(original))
+	copy(result, original)
+	return result
+}
diff --git a/android/apex.go b/android/apex.go
index 79ee0a8..114fe29 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"slices"
 	"sort"
 	"strconv"
@@ -87,6 +88,9 @@
 
 	// Returns the name of the overridden apex (com.android.foo)
 	BaseApexName string
+
+	// Returns the value of `apex_available_name`
+	ApexAvailableName string
 }
 
 // AllApexInfo holds the ApexInfo of all apexes that include this module.
@@ -145,6 +149,17 @@
 	return false
 }
 
+// To satisfy the comparable interface
+func (i ApexInfo) Equal(other any) bool {
+	otherApexInfo, ok := other.(ApexInfo)
+	return ok && i.ApexVariationName == otherApexInfo.ApexVariationName &&
+		i.MinSdkVersion == otherApexInfo.MinSdkVersion &&
+		i.Updatable == otherApexInfo.Updatable &&
+		i.UsePlatformApis == otherApexInfo.UsePlatformApis &&
+		reflect.DeepEqual(i.InApexVariants, otherApexInfo.InApexVariants) &&
+		reflect.DeepEqual(i.InApexModules, otherApexInfo.InApexModules)
+}
+
 // ApexTestForInfo stores the contents of APEXes for which this module is a test - although this
 // module is not part of the APEX - and thus has access to APEX internals.
 type ApexTestForInfo struct {
@@ -700,7 +715,7 @@
 	base.ApexProperties.InAnyApex = true
 	base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex
 
-	if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) {
+	if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() {
 		// Do not install the module for platform, but still allow it to output
 		// uninstallable AndroidMk entries in certain cases when they have side
 		// effects.  TODO(jiyong): move this routine to somewhere else
diff --git a/android/api_levels.go b/android/api_levels.go
index dc17238..2b1d01d 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -444,26 +444,27 @@
 
 func getApiLevelsMapReleasedVersions() (map[string]int, error) {
 	return map[string]int{
-		"G":              9,
-		"I":              14,
-		"J":              16,
-		"J-MR1":          17,
-		"J-MR2":          18,
-		"K":              19,
-		"L":              21,
-		"L-MR1":          22,
-		"M":              23,
-		"N":              24,
-		"N-MR1":          25,
-		"O":              26,
-		"O-MR1":          27,
-		"P":              28,
-		"Q":              29,
-		"R":              30,
-		"S":              31,
-		"S-V2":           32,
-		"Tiramisu":       33,
-		"UpsideDownCake": 34,
+		"G":               9,
+		"I":               14,
+		"J":               16,
+		"J-MR1":           17,
+		"J-MR2":           18,
+		"K":               19,
+		"L":               21,
+		"L-MR1":           22,
+		"M":               23,
+		"N":               24,
+		"N-MR1":           25,
+		"O":               26,
+		"O-MR1":           27,
+		"P":               28,
+		"Q":               29,
+		"R":               30,
+		"S":               31,
+		"S-V2":            32,
+		"Tiramisu":        33,
+		"UpsideDownCake":  34,
+		"VanillaIceCream": 35,
 	}, nil
 }
 
diff --git a/android/arch.go b/android/arch.go
index 6d896e5..942727a 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -23,7 +23,6 @@
 	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -397,45 +396,21 @@
 // device_supported and host_supported properties to determine which OsTypes are enabled for this
 // module, then searches through the Targets to determine which have enabled Targets for this
 // module.
-func osMutator(bpctx blueprint.BottomUpMutatorContext) {
-	var module Module
-	var ok bool
-	if module, ok = bpctx.Module().(Module); !ok {
-		// The module is not a Soong module, it is a Blueprint module.
-		if bootstrap.IsBootstrapModule(bpctx.Module()) {
-			// Bootstrap Go modules are always the build OS or linux bionic.
-			config := bpctx.Config().(Config)
-			osNames := []string{config.BuildOSTarget.OsVariation()}
-			for _, hostCrossTarget := range config.Targets[LinuxBionic] {
-				if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType {
-					osNames = append(osNames, hostCrossTarget.OsVariation())
-				}
-			}
-			osNames = FirstUniqueStrings(osNames)
-			bpctx.CreateVariations(osNames...)
-		}
-		return
-	}
+type osTransitionMutator struct{}
 
-	// Bootstrap Go module support above requires this mutator to be a
-	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
-	// 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)
+type allOsInfo struct {
+	Os         map[string]OsType
+	Variations []string
+}
 
-	base := module.base()
+var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate")
 
-	// Nothing to do for modules that are not architecture specific (e.g. a genrule).
-	if !base.ArchSpecific() {
-		return
-	}
-
-	// Collect a list of OSTypes supported by this module based on the HostOrDevice value
-	// passed to InitAndroidArchModule and the device_supported and host_supported properties.
+// moduleOSList collects a list of OSTypes supported by this module based on the HostOrDevice
+// value passed to InitAndroidArchModule and the device_supported and host_supported properties.
+func moduleOSList(ctx ConfigContext, base *ModuleBase) []OsType {
 	var moduleOSList []OsType
 	for _, os := range osTypeList {
-		for _, t := range mctx.Config().Targets[os] {
+		for _, t := range ctx.Config().Targets[os] {
 			if base.supportsTarget(t) {
 				moduleOSList = append(moduleOSList, os)
 				break
@@ -443,53 +418,91 @@
 		}
 	}
 
-	createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+	if base.commonProperties.CreateCommonOSVariant {
+		// A CommonOS variant was requested so add it to the list of OS variants to
+		// create. It needs to be added to the end because it needs to depend on the
+		// the other variants and inter variant dependencies can only be created from a
+		// later variant in that list to an earlier one. That is because variants are
+		// always processed in the order in which they are created.
+		moduleOSList = append(moduleOSList, CommonOS)
+	}
+
+	return moduleOSList
+}
+
+func (o *osTransitionMutator) Split(ctx BaseModuleContext) []string {
+	module := ctx.Module()
+	base := module.base()
+
+	// Nothing to do for modules that are not architecture specific (e.g. a genrule).
+	if !base.ArchSpecific() {
+		return []string{""}
+	}
+
+	moduleOSList := moduleOSList(ctx, base)
 
 	// If there are no supported OSes then disable the module.
-	if len(moduleOSList) == 0 && !createCommonOSVariant {
+	if len(moduleOSList) == 0 {
 		base.Disable()
-		return
+		return []string{""}
 	}
 
 	// Convert the list of supported OsTypes to the variation names.
 	osNames := make([]string, len(moduleOSList))
+	osMapping := make(map[string]OsType, len(moduleOSList))
 	for i, os := range moduleOSList {
 		osNames[i] = os.String()
+		osMapping[osNames[i]] = os
 	}
 
-	if createCommonOSVariant {
-		// A CommonOS variant was requested so add it to the list of OS variants to
-		// create. It needs to be added to the end because it needs to depend on the
-		// the other variants in the list returned by CreateVariations(...) and inter
-		// variant dependencies can only be created from a later variant in that list to
-		// an earlier one. That is because variants are always processed in the order in
-		// which they are returned from CreateVariations(...).
-		osNames = append(osNames, CommonOS.Name)
-		moduleOSList = append(moduleOSList, CommonOS)
+	SetProvider(ctx, allOsProvider, &allOsInfo{
+		Os:         osMapping,
+		Variations: osNames,
+	})
+
+	return osNames
+}
+
+func (o *osTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+	module := ctx.Module()
+	base := module.base()
+
+	if !base.ArchSpecific() {
+		return ""
 	}
 
-	// Create the variations, annotate each one with which OS it was created for, and
+	return incomingVariation
+}
+
+func (o *osTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+	module := ctx.Module()
+	base := module.base()
+
+	if variation == "" {
+		return
+	}
+
+	allOsInfo, ok := ModuleProvider(ctx, allOsProvider)
+	if !ok {
+		panic(fmt.Errorf("missing allOsProvider"))
+	}
+
+	// Annotate this variant with which OS it was created for, and
 	// squash the appropriate OS-specific properties into the top level properties.
-	modules := mctx.CreateVariations(osNames...)
-	for i, m := range modules {
-		m.base().commonProperties.CompileOS = moduleOSList[i]
-		m.base().setOSProperties(mctx)
-	}
+	base.commonProperties.CompileOS = allOsInfo.Os[variation]
+	base.setOSProperties(ctx)
 
-	if createCommonOSVariant {
+	if variation == CommonOS.String() {
 		// A CommonOS variant was requested so add dependencies from it (the last one in
 		// the list) to the OS type specific variants.
-		last := len(modules) - 1
-		commonOSVariant := modules[last]
-		commonOSVariant.base().commonProperties.CommonOSVariant = true
-		for _, module := range modules[0:last] {
-			// Ignore modules that are enabled. Note, this will only avoid adding
-			// dependencies on OsType variants that are explicitly disabled in their
-			// properties. The CommonOS variant will still depend on disabled variants
-			// if they are disabled afterwards, e.g. in archMutator if
-			if module.Enabled(mctx) {
-				mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
-			}
+		osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1]
+		for _, os := range osList {
+			variation := []blueprint.Variation{{"os", os}}
+			ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName())
 		}
 	}
 }
@@ -522,7 +535,7 @@
 
 var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
 
-// archMutator splits a module into a variant for each Target requested by the module.  Target selection
+// archTransitionMutator splits a module into a variant for each Target requested by the module.  Target selection
 // for a module is in three levels, OsClass, multilib, and then Target.
 // OsClass selection is determined by:
 //   - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
@@ -553,41 +566,32 @@
 //
 // Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
 // but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
-func archMutator(bpctx blueprint.BottomUpMutatorContext) {
-	var module Module
-	var ok bool
-	if module, ok = bpctx.Module().(Module); !ok {
-		if bootstrap.IsBootstrapModule(bpctx.Module()) {
-			// Bootstrap Go modules are always the build architecture.
-			bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation())
-		}
-		return
-	}
+type archTransitionMutator struct{}
 
-	// Bootstrap Go module support above requires this mutator to be a
-	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
-	// 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)
+type allArchInfo struct {
+	Targets      map[string]Target
+	MultiTargets []Target
+	Primary      string
+	Multilib     string
+}
 
+var allArchProvider = blueprint.NewMutatorProvider[*allArchInfo]("arch_propagate")
+
+func (a *archTransitionMutator) Split(ctx BaseModuleContext) []string {
+	module := ctx.Module()
 	base := module.base()
 
 	if !base.ArchSpecific() {
-		return
+		return []string{""}
 	}
 
 	os := base.commonProperties.CompileOS
 	if os == CommonOS {
-		// Make sure that the target related properties are initialized for the
-		// CommonOS variant.
-		addTargetProperties(module, commonTargetMap[os.Name], nil, true)
-
 		// Do not create arch specific variants for the CommonOS variant.
-		return
+		return []string{""}
 	}
 
-	osTargets := mctx.Config().Targets[os]
+	osTargets := ctx.Config().Targets[os]
 
 	image := base.commonProperties.ImageVariation
 	// Filter NativeBridge targets unless they are explicitly supported.
@@ -614,19 +618,18 @@
 	prefer32 := os == Windows
 
 	// Determine the multilib selection for this module.
-	ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice()
-	multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice)
+	multilib, extraMultilib := decodeMultilib(ctx, base)
 
 	// Convert the multilib selection into a list of Targets.
 	targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
 	if err != nil {
-		mctx.ModuleErrorf("%s", err.Error())
+		ctx.ModuleErrorf("%s", err.Error())
 	}
 
 	// If there are no supported targets disable the module.
 	if len(targets) == 0 {
 		base.Disable()
-		return
+		return []string{""}
 	}
 
 	// If the module is using extraMultilib, decode the extraMultilib selection into
@@ -635,7 +638,7 @@
 	if extraMultilib != "" {
 		multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
 		if err != nil {
-			mctx.ModuleErrorf("%s", err.Error())
+			ctx.ModuleErrorf("%s", err.Error())
 		}
 		multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
 	}
@@ -643,7 +646,7 @@
 	// Recovery is always the primary architecture, filter out any other architectures.
 	// Common arch is also allowed
 	if image == RecoveryVariation {
-		primaryArch := mctx.Config().DevicePrimaryArchType()
+		primaryArch := ctx.Config().DevicePrimaryArchType()
 		targets = filterToArch(targets, primaryArch, Common)
 		multiTargets = filterToArch(multiTargets, primaryArch, Common)
 	}
@@ -651,37 +654,109 @@
 	// If there are no supported targets disable the module.
 	if len(targets) == 0 {
 		base.Disable()
-		return
+		return []string{""}
 	}
 
 	// Convert the targets into a list of arch variation names.
 	targetNames := make([]string, len(targets))
+	targetMapping := make(map[string]Target, len(targets))
 	for i, target := range targets {
 		targetNames[i] = target.ArchVariation()
+		targetMapping[targetNames[i]] = targets[i]
 	}
 
-	// Create the variations, annotate each one with which Target it was created for, and
-	// squash the appropriate arch-specific properties into the top level properties.
-	modules := mctx.CreateVariations(targetNames...)
-	for i, m := range modules {
-		addTargetProperties(m, targets[i], multiTargets, i == 0)
-		m.base().setArchProperties(mctx)
+	SetProvider(ctx, allArchProvider, &allArchInfo{
+		Targets:      targetMapping,
+		MultiTargets: multiTargets,
+		Primary:      targetNames[0],
+		Multilib:     multilib,
+	})
+	return targetNames
+}
 
-		// Install support doesn't understand Darwin+Arm64
-		if os == Darwin && targets[i].HostCross {
-			m.base().commonProperties.SkipInstall = true
+func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+	module := ctx.Module()
+	base := module.base()
+
+	if !base.ArchSpecific() {
+		return ""
+	}
+
+	os := base.commonProperties.CompileOS
+	if os == CommonOS {
+		// Do not create arch specific variants for the CommonOS variant.
+		return ""
+	}
+
+	if incomingVariation == "" {
+		multilib, _ := decodeMultilib(ctx, base)
+		if multilib == "common" {
+			return "common"
 		}
 	}
+	return incomingVariation
+}
+
+func (a *archTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+	module := ctx.Module()
+	base := module.base()
+	os := base.commonProperties.CompileOS
+
+	if os == CommonOS {
+		// Make sure that the target related properties are initialized for the
+		// CommonOS variant.
+		addTargetProperties(module, commonTargetMap[os.Name], nil, true)
+		return
+	}
+
+	if variation == "" {
+		return
+	}
+
+	if !base.ArchSpecific() {
+		panic(fmt.Errorf("found variation %q for non arch specifc module", variation))
+	}
+
+	allArchInfo, ok := ModuleProvider(ctx, allArchProvider)
+	if !ok {
+		return
+	}
+
+	target, ok := allArchInfo.Targets[variation]
+	if !ok {
+		panic(fmt.Errorf("missing Target for %q", variation))
+	}
+	primary := variation == allArchInfo.Primary
+	multiTargets := allArchInfo.MultiTargets
+
+	// Annotate the new variant with which Target it was created for, and
+	// squash the appropriate arch-specific properties into the top level properties.
+	addTargetProperties(ctx.Module(), target, multiTargets, primary)
+	base.setArchProperties(ctx)
+
+	// Install support doesn't understand Darwin+Arm64
+	if os == Darwin && target.HostCross {
+		base.commonProperties.SkipInstall = true
+	}
 
 	// Create a dependency for Darwin Universal binaries from the primary to secondary
 	// architecture. The module itself will be responsible for calling lipo to merge the outputs.
 	if os == Darwin {
-		if multilib == "darwin_universal" && len(modules) == 2 {
-			mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0])
-		} else if multilib == "darwin_universal_common_first" && len(modules) == 3 {
-			mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1])
+		isUniversalBinary := (allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2) ||
+			allArchInfo.Multilib == "darwin_universal_common_first" && len(allArchInfo.Targets) == 3
+		isPrimary := variation == ctx.Config().BuildArch.String()
+		hasSecondaryConfigured := len(ctx.Config().Targets[Darwin]) > 1
+		if isUniversalBinary && isPrimary && hasSecondaryConfigured {
+			secondaryArch := ctx.Config().Targets[Darwin][1].Arch.String()
+			variation := []blueprint.Variation{{"arch", secondaryArch}}
+			ctx.AddVariationDependencies(variation, DarwinUniversalVariantTag, ctx.ModuleName())
 		}
 	}
+
 }
 
 // addTargetProperties annotates a variant with the Target is is being compiled for, the list
@@ -698,7 +773,9 @@
 // multilib from the factory's call to InitAndroidArchModule if none was set.  For modules that
 // called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
 // the actual multilib in extraMultilib.
-func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) {
+func decodeMultilib(ctx ConfigContext, base *ModuleBase) (multilib, extraMultilib string) {
+	os := base.commonProperties.CompileOS
+	ignorePrefer32OnDevice := ctx.Config().IgnorePrefer32OnDevice()
 	// First check the "android.compile_multilib" or "host.compile_multilib" properties.
 	switch os.Class {
 	case Device:
diff --git a/android/arch_list.go b/android/arch_list.go
index f1289a3..9501c87 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -26,6 +26,7 @@
 		"armv8-2a",
 		"armv8-2a-dotprod",
 		"armv9-a",
+		"armv9-2a",
 	},
 	X86: {
 		"amberlake",
@@ -159,6 +160,9 @@
 		"armv9-a": {
 			"dotprod",
 		},
+		"armv9-2a": {
+			"dotprod",
+		},
 	},
 	X86: {
 		"amberlake": {
diff --git a/android/arch_test.go b/android/arch_test.go
index 6134a06..57c9010 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -451,7 +451,7 @@
 
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			if tt.goOS != runtime.GOOS {
+			if tt.goOS != "" && tt.goOS != runtime.GOOS {
 				t.Skipf("requries runtime.GOOS %s", tt.goOS)
 			}
 
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 5506000..bb81377 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -220,6 +220,10 @@
 	// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
 	// can be used to evaluate the final value of Configurable properties.
 	EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
+
+	// HasMutatorFinished returns true if the given mutator has finished running.
+	// It will panic if given an invalid mutator name.
+	HasMutatorFinished(mutatorName string) bool
 }
 
 type baseModuleContext struct {
@@ -270,6 +274,10 @@
 	b.bp.SetProvider(provider, value)
 }
 
+func (b *baseModuleContext) HasMutatorFinished(mutatorName string) bool {
+	return b.bp.HasMutatorFinished(mutatorName)
+}
+
 func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
 	return b.bp.GetDirectDepWithTag(name, tag)
 }
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index a7b65e0..38f1382 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -17,6 +17,7 @@
 import (
 	"bytes"
 	"encoding/csv"
+	"encoding/gob"
 	"fmt"
 	"slices"
 	"strconv"
@@ -131,6 +132,28 @@
 	}
 }
 
+func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := encoder.Encode(c.properties)
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (c *ComplianceMetadataInfo) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := decoder.Decode(&c.properties)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func (c *ComplianceMetadataInfo) SetStringValue(propertyName string, value string) {
 	if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) {
 		panic(fmt.Errorf("Unknown metadata property: %s.", propertyName))
diff --git a/android/config.go b/android/config.go
index bbb08dd..00fc823 100644
--- a/android/config.go
+++ b/android/config.go
@@ -238,6 +238,11 @@
 	return c.config.productVariables.ReleaseAconfigFlagDefaultPermission
 }
 
+// Enable object size sanitizer
+func (c Config) ReleaseBuildObjectSizeSanitizer() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_BUILD_OBJECT_SIZE_SANITIZER")
+}
+
 // The flag indicating behavior for the tree wrt building modules or using prebuilts
 // derived from RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE
 func (c Config) ReleaseDefaultModuleBuildFromSource() bool {
@@ -270,6 +275,11 @@
 		Bool(c.config.productVariables.HiddenapiExportableStubs)
 }
 
+// Enable read flag from new storage
+func (c Config) ReleaseReadFromNewStorage() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE")
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
@@ -1490,11 +1500,6 @@
 		}
 	}
 	if coverage && len(c.config.productVariables.NativeCoverageExcludePaths) > 0 {
-		// Workaround coverage boot failure.
-		// http://b/269981180
-		if strings.HasPrefix(path, "external/protobuf") {
-			coverage = false
-		}
 		if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
 			coverage = false
 		}
@@ -1663,6 +1668,17 @@
 	return Bool(c.productVariables.TrimmedApex)
 }
 
+func (c *config) UseSoongSystemImage() bool {
+	return Bool(c.productVariables.UseSoongSystemImage)
+}
+
+func (c *config) SoongDefinedSystemImage() string {
+	if c.UseSoongSystemImage() {
+		return String(c.productVariables.ProductSoongDefinedSystemImage)
+	}
+	return ""
+}
+
 func (c *config) EnforceSystemCertificate() bool {
 	return Bool(c.productVariables.EnforceSystemCertificate)
 }
@@ -1828,10 +1844,6 @@
 	return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
 }
 
-func (c *deviceConfig) BuildBrokenUsesSoongPython2Modules() bool {
-	return c.config.productVariables.BuildBrokenUsesSoongPython2Modules
-}
-
 func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
 	return c.config.productVariables.BuildDebugfsRestrictionsEnabled
 }
@@ -1958,10 +1970,18 @@
 	return val, ok
 }
 
+func (c *config) UseOptimizedResourceShrinkingByDefault() bool {
+	return c.productVariables.GetBuildFlagBool("RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT")
+}
+
 func (c *config) UseResourceProcessorByDefault() bool {
 	return c.productVariables.GetBuildFlagBool("RELEASE_USE_RESOURCE_PROCESSOR_BY_DEFAULT")
 }
 
+func (c *config) UseTransitiveJarsInClasspath() bool {
+	return c.productVariables.GetBuildFlagBool("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH")
+}
+
 var (
 	mainlineApexContributionBuildFlagsToApexNames = map[string]string{
 		"RELEASE_APEX_CONTRIBUTIONS_ADBD":                    "com.android.adbd",
@@ -2064,3 +2084,19 @@
 func (c *config) EnableUffdGc() string {
 	return String(c.productVariables.EnableUffdGc)
 }
+
+func (c *config) DeviceFrameworkCompatibilityMatrixFile() []string {
+	return c.productVariables.DeviceFrameworkCompatibilityMatrixFile
+}
+
+func (c *config) DeviceProductCompatibilityMatrixFile() []string {
+	return c.productVariables.DeviceProductCompatibilityMatrixFile
+}
+
+func (c *config) BoardAvbEnable() bool {
+	return Bool(c.productVariables.BoardAvbEnable)
+}
+
+func (c *config) BoardAvbSystemAddHashtreeFooterArgs() []string {
+	return c.productVariables.BoardAvbSystemAddHashtreeFooterArgs
+}
diff --git a/android/container.go b/android/container.go
index 43dccf6..c048d6c 100644
--- a/android/container.go
+++ b/android/container.go
@@ -15,8 +15,10 @@
 package android
 
 import (
+	"fmt"
 	"reflect"
 	"slices"
+	"strings"
 
 	"github.com/google/blueprint"
 )
@@ -89,6 +91,10 @@
 	"framework-annotations-lib",
 	"unsupportedappusage",
 
+	// TODO(b/363016634): Remove from the allowlist when the module is converted
+	// to java_sdk_library and the java_aconfig_library modules depend on the stub.
+	"aconfig_storage_reader_java",
+
 	// framework-res provides core resources essential for building apps and system UI.
 	// This module is implicitly added as a dependency for java modules even when the
 	// dependency specifies sdk_version.
@@ -223,7 +229,6 @@
 // ----------------------------------------------------------------------------
 
 type InstallableModule interface {
-	ContainersInfo() ContainersInfo
 	StaticDependencyTags() []blueprint.DependencyTag
 	DynamicDependencyTags() []blueprint.DependencyTag
 }
@@ -395,6 +400,40 @@
 
 var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
 
+func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m, dep Module) bool {
+	for _, label := range allowedExceptionLabels {
+		if exceptionHandleFunctionsTable[label](ctx, m, dep) {
+			return true
+		}
+	}
+	return false
+}
+
+func (c *ContainersInfo) GetViolations(mctx ModuleContext, m, dep Module, depInfo ContainersInfo) []string {
+	var violations []string
+
+	// Any containers that the module belongs to but the dependency does not belong to must be examined.
+	_, containersUniqueToModule, _ := ListSetDifference(c.belongingContainers, depInfo.belongingContainers)
+
+	// Apex container should be examined even if both the module and the dependency belong to
+	// the apex container to check that the two modules belong to the same apex.
+	if InList(ApexContainer, c.belongingContainers) && !InList(ApexContainer, containersUniqueToModule) {
+		containersUniqueToModule = append(containersUniqueToModule, ApexContainer)
+	}
+
+	for _, containerUniqueToModule := range containersUniqueToModule {
+		for _, restriction := range containerUniqueToModule.restricted {
+			if InList(restriction.dependency, depInfo.belongingContainers) {
+				if !satisfyAllowedExceptions(mctx, restriction.allowedExceptions, m, dep) {
+					violations = append(violations, restriction.errorMessage)
+				}
+			}
+		}
+	}
+
+	return violations
+}
+
 func generateContainerInfo(ctx ModuleContext) ContainersInfo {
 	var containers []*container
 
@@ -417,7 +456,7 @@
 
 func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
 	if ctx.Module() == module {
-		return module.ContainersInfo(), true
+		return ctx.getContainersInfo(), true
 	}
 
 	return OtherModuleProvider(ctx, module, ContainersInfoProvider)
@@ -432,7 +471,36 @@
 
 	if _, ok := ctx.Module().(InstallableModule); ok {
 		containersInfo := generateContainerInfo(ctx)
-		ctx.Module().base().containersInfo = containersInfo
+		ctx.setContainersInfo(containersInfo)
 		SetProvider(ctx, ContainersInfoProvider, containersInfo)
 	}
 }
+
+func checkContainerViolations(ctx ModuleContext) {
+	if _, ok := ctx.Module().(InstallableModule); ok {
+		containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
+		ctx.VisitDirectDepsIgnoreBlueprint(func(dep Module) {
+			if !dep.Enabled(ctx) {
+				return
+			}
+
+			// Pre-existing violating dependencies are tracked in containerDependencyViolationAllowlist.
+			// If this dependency is allowlisted, do not check for violation.
+			// If not, check if this dependency matches any restricted dependency and
+			// satisfies any exception functions, which allows bypassing the
+			// restriction. If all of the exceptions are not satisfied, throw an error.
+			if depContainersInfo, ok := getContainerModuleInfo(ctx, dep); ok {
+				if allowedViolations, ok := ContainerDependencyViolationAllowlist[ctx.ModuleName()]; ok && InList(dep.Name(), allowedViolations) {
+					return
+				} else {
+					violations := containersInfo.GetViolations(ctx, ctx.Module(), dep, depContainersInfo)
+					if len(violations) > 0 {
+						errorMessage := fmt.Sprintf("%s cannot depend on %s. ", ctx.ModuleName(), dep.Name())
+						errorMessage += strings.Join(violations, " ")
+						ctx.ModuleErrorf(errorMessage)
+					}
+				}
+			}
+		})
+	}
+}
diff --git a/android/container_violations.go b/android/container_violations.go
index e67533d..4251484 100644
--- a/android/container_violations.go
+++ b/android/container_violations.go
@@ -169,6 +169,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsAppStartTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsAppTestStubsApp2": {
 		"framework", // cts -> unstable
 	},
@@ -273,6 +277,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsDocumentContentTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsDreamsTestCases": {
 		"framework", // cts -> unstable
 	},
@@ -281,6 +289,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsEmptyTestApp_RejectedByVerifier": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsEphemeralTestsEphemeralApp1": {
 		"framework", // cts -> unstable
 	},
@@ -301,10 +313,18 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsFgsTimeoutTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsFileDescriptorTestCases": {
 		"framework", // cts -> unstable
 	},
 
+	"CtsFingerprintTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsHostsideCompatChangeTestsApp": {
 		"framework", // cts -> unstable
 	},
@@ -433,6 +453,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsMediaProviderTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsMediaProviderTranscodeTests": {
 		"framework", // cts -> unstable
 	},
@@ -501,6 +525,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsOnDeviceIntelligenceServiceTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsOnDevicePersonalizationTestCases": {
 		"framework", // cts -> unstable
 	},
@@ -521,6 +549,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsPackageWatchdogTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsPermissionsSyncTestApp": {
 		"framework", // cts -> unstable
 	},
@@ -669,6 +701,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsTvTunerTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsUsageStatsTestCases": {
 		"framework", // cts -> unstable
 	},
@@ -799,6 +835,11 @@
 		"ondevicepersonalization_flags_lib", // apex [com.android.ondevicepersonalization] -> system
 	},
 
+	"framework-pdf-v.impl": {
+		"app-compat-annotations",      // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+		"modules-utils-preconditions", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+	},
+
 	"framework-pdf.impl": {
 		"modules-utils-preconditions", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
 	},
@@ -837,14 +878,54 @@
 		"libnativeloader_vendor_shared_lib", // system -> vendor
 	},
 
+	"MctsMediaBetterTogetherTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaCodecTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaDecoderTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"MctsMediaDrmFrameworkTestCases": {
 		"framework", // cts -> unstable
 	},
 
+	"MctsMediaEncoderTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaExtractorTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaMiscTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaMuxerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaPlayerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaRecorderTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"MctsMediaTranscodingTestCases": {
 		"framework", // cts -> unstable
 	},
 
+	"MctsMediaV2TestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"MediaProvider": {
 		"app-compat-annotations", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
 	},
diff --git a/android/deapexer.go b/android/deapexer.go
index dcae3e4..4049d2b 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -15,7 +15,6 @@
 package android
 
 import (
-	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -109,10 +108,6 @@
 	return i.exportedModuleNames
 }
 
-// Provider that can be used from within the `GenerateAndroidBuildActions` of a module that depends
-// on a `deapexer` module to retrieve its `DeapexerInfo`.
-var DeapexerProvider = blueprint.NewProvider[DeapexerInfo]()
-
 // NewDeapexerInfo creates and initializes a DeapexerInfo that is suitable
 // for use with a prebuilt_apex module.
 //
@@ -169,45 +164,6 @@
 	RequiresFilesFromPrebuiltApex()
 }
 
-// FindDeapexerProviderForModule searches through the direct dependencies of the current context
-// module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous
-// deapexer module isn't found then it returns it an error
-// clients should check the value of error and call ctx.ModuleErrof if a non nil error is received
-func FindDeapexerProviderForModule(ctx ModuleContext) (*DeapexerInfo, error) {
-	var di *DeapexerInfo
-	var err error
-	ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
-		if err != nil {
-			// An err has been found. Do not visit further.
-			return
-		}
-		c, ok := OtherModuleProvider(ctx, m, DeapexerProvider)
-		if !ok {
-			ctx.ModuleErrorf("Expected all deps with DeapexerTag to have a DeapexerProvider, but module %q did not", m.Name())
-			return
-		}
-		p := &c
-		if di != nil {
-			// If two DeapexerInfo providers have been found then check if they are
-			// equivalent. If they are then use the selected one, otherwise fail.
-			if selected := equivalentDeapexerInfoProviders(di, p); selected != nil {
-				di = selected
-				return
-			}
-			err = fmt.Errorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", di.ApexModuleName(), p.ApexModuleName())
-		}
-		di = p
-	})
-	if err != nil {
-		return nil, err
-	}
-	if di != nil {
-		return di, nil
-	}
-	ai, _ := ModuleProvider(ctx, ApexInfoProvider)
-	return nil, fmt.Errorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
-}
-
 // removeCompressedApexSuffix removes the _compressed suffix from the name if present.
 func removeCompressedApexSuffix(name string) string {
 	return strings.TrimSuffix(name, "_compressed")
diff --git a/android/defaults.go b/android/defaults.go
index 0d51d9d..3d06c69 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -69,7 +69,7 @@
 
 	// Apply defaults from the supplied Defaults to the property structures supplied to
 	// setProperties(...).
-	applyDefaults(TopDownMutatorContext, []Defaults)
+	applyDefaults(BottomUpMutatorContext, []Defaults)
 
 	// Set the hook to be called after any defaults have been applied.
 	//
@@ -101,6 +101,7 @@
 // A restricted subset of context methods, similar to LoadHookContext.
 type DefaultableHookContext interface {
 	EarlyModuleContext
+	OtherModuleProviderContext
 
 	CreateModule(ModuleFactory, ...interface{}) Module
 	AddMissingDependencies(missingDeps []string)
@@ -209,7 +210,7 @@
 
 var _ Defaults = (*DefaultsModuleBase)(nil)
 
-func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
+func (defaultable *DefaultableModuleBase) applyDefaults(ctx BottomUpMutatorContext,
 	defaultsList []Defaults) {
 
 	for _, defaults := range defaultsList {
@@ -226,7 +227,7 @@
 // Product variable properties need special handling, the type of the filtered product variable
 // property struct may not be identical between the defaults module and the defaultable module.
 // Use PrependMatchingProperties to apply whichever properties match.
-func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx BottomUpMutatorContext,
 	defaults Defaults, defaultableProp interface{}) {
 	if defaultableProp == nil {
 		return
@@ -254,7 +255,7 @@
 	}
 }
 
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx BottomUpMutatorContext,
 	defaults Defaults, defaultableProp interface{}) {
 
 	for _, def := range defaults.properties() {
@@ -273,7 +274,7 @@
 
 func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
-	ctx.TopDown("defaults", defaultsMutator).Parallel()
+	ctx.BottomUp("defaults", defaultsMutator).Parallel()
 }
 
 func defaultsDepsMutator(ctx BottomUpMutatorContext) {
@@ -282,8 +283,12 @@
 	}
 }
 
-func defaultsMutator(ctx TopDownMutatorContext) {
+func defaultsMutator(ctx BottomUpMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
+		if _, isDefaultsModule := ctx.Module().(Defaults); isDefaultsModule {
+			// Don't squash transitive defaults into defaults modules
+			return
+		}
 		defaults := defaultable.defaults().Defaults
 		if len(defaults) > 0 {
 			var defaultsList []Defaults
diff --git a/android/defs.go b/android/defs.go
index 78cdea2..9f3fb1e 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -16,7 +16,6 @@
 
 import (
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 )
 
 var (
@@ -120,8 +119,3 @@
 		return ctx.Config().RBEWrapper()
 	})
 }
-
-// GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
-func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
-	bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
-}
diff --git a/android/depset_generic.go b/android/depset_generic.go
index 45c1937..690987a 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -15,6 +15,9 @@
 package android
 
 import (
+	"bytes"
+	"encoding/gob"
+	"errors"
 	"fmt"
 )
 
@@ -65,6 +68,30 @@
 	transitive []*DepSet[T]
 }
 
+func (d *DepSet[T]) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(d.preorder), encoder.Encode(d.reverse),
+		encoder.Encode(d.order), encoder.Encode(d.direct), encoder.Encode(d.transitive))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (d *DepSet[T]) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&d.preorder), decoder.Decode(&d.reverse),
+		decoder.Decode(&d.order), decoder.Decode(&d.direct), decoder.Decode(&d.transitive))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
 func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*DepSet[T]) *DepSet[T] {
 	var directCopy []T
diff --git a/android/init.go b/android/init.go
new file mode 100644
index 0000000..b462292
--- /dev/null
+++ b/android/init.go
@@ -0,0 +1,23 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package android
+
+import "encoding/gob"
+
+func init() {
+	gob.Register(ModuleOutPath{})
+	gob.Register(PhonyPath{})
+	gob.Register(unstableInfo{})
+}
diff --git a/android/module.go b/android/module.go
index 4e46bdb..e2b7e11 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,9 @@
 package android
 
 import (
+	"bytes"
+	"encoding/gob"
+	"errors"
 	"fmt"
 	"net/url"
 	"path/filepath"
@@ -55,7 +58,7 @@
 
 	base() *ModuleBase
 	Disable()
-	Enabled(ctx ConfigAndErrorContext) bool
+	Enabled(ctx ConfigurableEvaluatorContext) bool
 	Target() Target
 	MultiTargets() []Target
 
@@ -106,15 +109,12 @@
 	// Get information about the properties that can contain visibility rules.
 	visibilityProperties() []visibilityProperty
 
-	RequiredModuleNames(ctx ConfigAndErrorContext) []string
+	RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string
 	HostRequiredModuleNames() []string
 	TargetRequiredModuleNames() []string
-	VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string
+	VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string
 
-	ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator
-
-	// Get the information about the containers this module belongs to.
-	ContainersInfo() ContainersInfo
+	ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator
 }
 
 // Qualified id for a module
@@ -381,7 +381,7 @@
 	Native_bridge_supported *bool `android:"arch_variant"`
 
 	// init.rc files to be installed if this module is installed
-	Init_rc []string `android:"arch_variant,path"`
+	Init_rc proptools.Configurable[[]string] `android:"arch_variant,path"`
 
 	// VINTF manifest fragments to be installed if this module is installed
 	Vintf_fragments proptools.Configurable[[]string] `android:"path"`
@@ -443,12 +443,6 @@
 	// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
 	CreateCommonOSVariant bool `blueprint:"mutated"`
 
-	// If set to true then this variant is the CommonOS variant that has dependencies on its
-	// OsType specific variants.
-	//
-	// Set by osMutator.
-	CommonOSVariant bool `blueprint:"mutated"`
-
 	// When set to true, this module is not installed to the full install path (ex: under
 	// out/target/product/<name>/<partition>). It can be installed only to the packaging
 	// modules like android_filesystem.
@@ -495,6 +489,10 @@
 
 	// vintf_fragment Modules required from this module.
 	Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"`
+
+	// List of module names that are prevented from being installed when this module gets
+	// installed.
+	Overrides []string
 }
 
 type distProperties struct {
@@ -839,17 +837,6 @@
 	buildParams []BuildParams
 	ruleParams  map[blueprint.Rule]blueprint.RuleParams
 	variables   map[string]string
-
-	// Merged Aconfig files for all transitive deps.
-	aconfigFilePaths Paths
-
-	// complianceMetadataInfo is for different module types to dump metadata.
-	// See android.ModuleContext interface.
-	complianceMetadataInfo *ComplianceMetadataInfo
-
-	// containersInfo stores the information about the containers and the information of the
-	// apexes the module belongs to.
-	containersInfo ContainersInfo
 }
 
 func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1228,7 +1215,7 @@
 
 // True if the current variant is a CommonOS variant, false otherwise.
 func (m *ModuleBase) IsCommonOSVariant() bool {
-	return m.commonProperties.CommonOSVariant
+	return m.commonProperties.CompileOS == CommonOS
 }
 
 // supportsTarget returns true if the given Target is supported by the current module.
@@ -1346,13 +1333,21 @@
 	return partition
 }
 
-func (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) bool {
+func (m *ModuleBase) Enabled(ctx ConfigurableEvaluatorContext) bool {
 	if m.commonProperties.ForcedDisabled {
 		return false
 	}
 	return m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled)
 }
 
+// Returns a copy of the enabled property, useful for passing it on to sub-modules
+func (m *ModuleBase) EnabledProperty() proptools.Configurable[bool] {
+	if m.commonProperties.ForcedDisabled {
+		return proptools.NewSimpleConfigurable(false)
+	}
+	return m.commonProperties.Enabled.Clone()
+}
+
 func (m *ModuleBase) Disable() {
 	m.commonProperties.ForcedDisabled = true
 }
@@ -1543,7 +1538,7 @@
 	return m.base().commonProperties.ImageVariation == RecoveryVariation
 }
 
-func (m *ModuleBase) RequiredModuleNames(ctx ConfigAndErrorContext) []string {
+func (m *ModuleBase) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
 	return m.base().commonProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
 }
 
@@ -1555,30 +1550,47 @@
 	return m.base().commonProperties.Target_required
 }
 
-func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string {
+func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string {
 	return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
 }
 
+func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) {
+	namespacePrefix := ctx.Namespace().id
+	if namespacePrefix != "" {
+		namespacePrefix = namespacePrefix + "-"
+	}
+
+	if !ctx.uncheckedModule {
+		name := namespacePrefix + ctx.ModuleName() + "-" + ctx.ModuleSubDir() + "-checkbuild"
+		ctx.Phony(name, ctx.checkbuildFiles...)
+		ctx.checkbuildTarget = PathForPhony(ctx, name)
+	}
+
+}
+
 func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) {
 	var allInstalledFiles InstallPaths
-	var allCheckbuildFiles Paths
+	var allCheckbuildTargets Paths
 	ctx.VisitAllModuleVariants(func(module Module) {
 		a := module.base()
-		var checkBuilds Paths
+		var checkbuildTarget Path
+		var uncheckedModule bool
 		if a == m {
 			allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
-			checkBuilds = ctx.checkbuildFiles
+			checkbuildTarget = ctx.checkbuildTarget
+			uncheckedModule = ctx.uncheckedModule
 		} else {
 			info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider)
 			allInstalledFiles = append(allInstalledFiles, info.InstallFiles...)
-			checkBuilds = info.CheckbuildFiles
+			checkbuildTarget = info.CheckbuildTarget
+			uncheckedModule = info.UncheckedModule
 		}
 		// A module's -checkbuild phony targets should
 		// not be created if the module is not exported to make.
 		// Those could depend on the build target and fail to compile
 		// for the current build target.
-		if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a) {
-			allCheckbuildFiles = append(allCheckbuildFiles, checkBuilds...)
+		if (!ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a)) && !uncheckedModule && checkbuildTarget != nil {
+			allCheckbuildTargets = append(allCheckbuildTargets, checkbuildTarget)
 		}
 	})
 
@@ -1599,11 +1611,10 @@
 		deps = append(deps, info.InstallTarget)
 	}
 
-	if len(allCheckbuildFiles) > 0 {
+	if len(allCheckbuildTargets) > 0 {
 		name := namespacePrefix + ctx.ModuleName() + "-checkbuild"
-		ctx.Phony(name, allCheckbuildFiles...)
-		info.CheckbuildTarget = PathForPhony(ctx, name)
-		deps = append(deps, info.CheckbuildTarget)
+		ctx.Phony(name, allCheckbuildTargets...)
+		deps = append(deps, PathForPhony(ctx, name))
 	}
 
 	if len(deps) > 0 {
@@ -1720,9 +1731,11 @@
 }
 
 type InstallFilesInfo struct {
-	InstallFiles    InstallPaths
-	CheckbuildFiles Paths
-	PackagingSpecs  []PackagingSpec
+	InstallFiles     InstallPaths
+	CheckbuildFiles  Paths
+	CheckbuildTarget Path
+	UncheckedModule  bool
+	PackagingSpecs   []PackagingSpec
 	// katiInstalls tracks the install rules that were created by Soong but are being exported
 	// to Make to convert to ninja rules so that Make can add additional dependencies.
 	KatiInstalls             katiInstalls
@@ -1769,6 +1782,9 @@
 	}
 
 	setContainerInfo(ctx)
+	if ctx.Config().Getenv("DISABLE_CONTAINER_CHECK") != "true" {
+		checkContainerViolations(ctx)
+	}
 
 	ctx.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
 
@@ -1839,7 +1855,7 @@
 			// so only a single rule is created for each init.rc or vintf fragment file.
 
 			if !m.InVendorRamdisk() {
-				ctx.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+				ctx.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc.GetOrDefault(ctx, nil))
 				rcDir := PathForModuleInstall(ctx, "etc", "init")
 				for _, src := range ctx.initRcPaths {
 					installedInitRc := rcDir.Join(ctx, src.Base())
@@ -1890,61 +1906,16 @@
 			return
 		}
 
-		incrementalAnalysis := false
-		incrementalEnabled := false
-		var cacheKey *blueprint.BuildActionCacheKey = nil
-		var incrementalModule *blueprint.Incremental = nil
-		if ctx.bp.GetIncrementalEnabled() {
-			if im, ok := m.module.(blueprint.Incremental); ok {
-				incrementalModule = &im
-				incrementalEnabled = im.IncrementalSupported()
-				incrementalAnalysis = ctx.bp.GetIncrementalAnalysis() && incrementalEnabled
-			}
-		}
-		if incrementalEnabled {
-			hash, err := proptools.CalculateHash(m.GetProperties())
-			if err != nil {
-				ctx.ModuleErrorf("failed to calculate properties hash: %s", err)
-				return
-			}
-			cacheInput := new(blueprint.BuildActionCacheInput)
-			cacheInput.PropertiesHash = hash
-			ctx.VisitDirectDeps(func(module Module) {
-				cacheInput.ProvidersHash =
-					append(cacheInput.ProvidersHash, ctx.bp.OtherModuleProviderInitialValueHashes(module))
-			})
-			hash, err = proptools.CalculateHash(&cacheInput)
-			if err != nil {
-				ctx.ModuleErrorf("failed to calculate cache input hash: %s", err)
-				return
-			}
-			cacheKey = &blueprint.BuildActionCacheKey{
-				Id:        ctx.bp.ModuleCacheKey(),
-				InputHash: hash,
-			}
+		m.module.GenerateAndroidBuildActions(ctx)
+		if ctx.Failed() {
+			return
 		}
 
-		restored := false
-		if incrementalAnalysis && cacheKey != nil {
-			restored = ctx.bp.RestoreBuildActions(cacheKey)
-		}
-
-		if !restored {
-			m.module.GenerateAndroidBuildActions(ctx)
-			if ctx.Failed() {
-				return
-			}
-
-			if x, ok := m.module.(IDEInfo); ok {
-				var result IdeInfo
-				x.IDEInfo(ctx, &result)
-				result.BaseModuleName = x.BaseModuleName()
-				SetProvider(ctx, IdeInfoProviderKey, result)
-			}
-		}
-
-		if incrementalEnabled && cacheKey != nil {
-			ctx.bp.CacheBuildActions(cacheKey, incrementalModule)
+		if x, ok := m.module.(IDEInfo); ok {
+			var result IdeInfo
+			x.IDEInfo(ctx, &result)
+			result.BaseModuleName = x.BaseModuleName()
+			SetProvider(ctx, IdeInfoProviderKey, result)
 		}
 
 		// Create the set of tagged dist files after calling GenerateAndroidBuildActions
@@ -1956,9 +1927,13 @@
 			return
 		}
 
+		m.generateVariantTarget(ctx)
+
 		installFiles.LicenseMetadataFile = ctx.licenseMetadataFile
 		installFiles.InstallFiles = ctx.installFiles
 		installFiles.CheckbuildFiles = ctx.checkbuildFiles
+		installFiles.CheckbuildTarget = ctx.checkbuildTarget
+		installFiles.UncheckedModule = ctx.uncheckedModule
 		installFiles.PackagingSpecs = ctx.packagingSpecs
 		installFiles.KatiInstalls = ctx.katiInstalls
 		installFiles.KatiSymlinks = ctx.katiSymlinks
@@ -2024,7 +1999,7 @@
 			TargetDependencies: targetRequired,
 			HostDependencies:   hostRequired,
 			Data:               data,
-			Required:           m.RequiredModuleNames(ctx),
+			Required:           append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...),
 		}
 		SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON)
 	}
@@ -2089,10 +2064,6 @@
 	return variant
 }
 
-func (m *ModuleBase) ContainersInfo() ContainersInfo {
-	return m.containersInfo
-}
-
 // Check the supplied dist structure to make sure that it is valid.
 //
 // property - the base property, e.g. dist or dists[1], which is combined with the
@@ -2131,11 +2102,61 @@
 	absFrom string
 }
 
+func (p *katiInstall) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.from), encoder.Encode(p.to),
+		encoder.Encode(p.implicitDeps), encoder.Encode(p.orderOnlyDeps),
+		encoder.Encode(p.executable), encoder.Encode(p.extraFiles),
+		encoder.Encode(p.absFrom))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *katiInstall) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.from), decoder.Decode(&p.to),
+		decoder.Decode(&p.implicitDeps), decoder.Decode(&p.orderOnlyDeps),
+		decoder.Decode(&p.executable), decoder.Decode(&p.extraFiles),
+		decoder.Decode(&p.absFrom))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 type extraFilesZip struct {
 	zip Path
 	dir InstallPath
 }
 
+func (p *extraFilesZip) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.zip), encoder.Encode(p.dir))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *extraFilesZip) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.zip), decoder.Decode(&p.dir))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 type katiInstalls []katiInstall
 
 // BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
@@ -2185,17 +2206,23 @@
 	return proptools.Bool(m.commonProperties.Native_bridge_supported)
 }
 
-type ConfigAndErrorContext interface {
+type ConfigContext interface {
+	Config() Config
+}
+
+type ConfigurableEvaluatorContext interface {
+	OtherModuleProviderContext
 	Config() Config
 	OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
+	HasMutatorFinished(mutatorName string) bool
 }
 
 type configurationEvalutor struct {
-	ctx ConfigAndErrorContext
+	ctx ConfigurableEvaluatorContext
 	m   Module
 }
 
-func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator {
+func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator {
 	return configurationEvalutor{
 		ctx: ctx,
 		m:   m.module,
@@ -2209,6 +2236,12 @@
 func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
 	ctx := e.ctx
 	m := e.m
+
+	if !ctx.HasMutatorFinished("defaults") {
+		ctx.OtherModulePropertyErrorf(m, property, "Cannot evaluate configurable property before the defaults mutator has run")
+		return proptools.ConfigurableValueUndefined()
+	}
+
 	switch condition.FunctionName() {
 	case "release_flag":
 		if condition.NumArgs() != 1 {
diff --git a/android/module_context.go b/android/module_context.go
index 5322240..2bf2a8f 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -85,7 +85,9 @@
 type ModuleContext interface {
 	BaseModuleContext
 
-	blueprintModuleContext() blueprint.ModuleContext
+	// BlueprintModuleContext returns the blueprint.ModuleContext that the ModuleContext wraps.  It may only be
+	// used by the golang module types that need to call into the bootstrap module types.
+	BlueprintModuleContext() blueprint.ModuleContext
 
 	// Deprecated: use ModuleContext.Build instead.
 	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
@@ -122,6 +124,16 @@
 	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
 
+	// InstallFileWithoutCheckbuild creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies, but does not add the file to the list of files to build
+	// during `m checkbuild`.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
+
 	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
 	// directory, and also unzip a zip file containing extra files to install into the same
 	// directory.
@@ -168,7 +180,8 @@
 	// dependency tags for which IsInstallDepNeeded returns true.
 	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
 
-	CheckbuildFile(srcPath Path)
+	CheckbuildFile(srcPaths ...Path)
+	UncheckedModule()
 
 	InstallInData() bool
 	InstallInTestcases() bool
@@ -183,7 +196,7 @@
 	InstallInVendor() bool
 	InstallForceOS() (*OsType, *ArchType)
 
-	RequiredModuleNames(ctx ConfigAndErrorContext) []string
+	RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string
 	HostRequiredModuleNames() []string
 	TargetRequiredModuleNames() []string
 
@@ -226,16 +239,24 @@
 	// which usually happens in GenerateAndroidBuildActions() of a module type.
 	// See android.ModuleBase.complianceMetadataInfo
 	ComplianceMetadataInfo() *ComplianceMetadataInfo
+
+	// Get the information about the containers this module belongs to.
+	getContainersInfo() ContainersInfo
+	setContainersInfo(info ContainersInfo)
+
+	setAconfigPaths(paths Paths)
 }
 
 type moduleContext struct {
 	bp blueprint.ModuleContext
 	baseModuleContext
-	packagingSpecs  []PackagingSpec
-	installFiles    InstallPaths
-	checkbuildFiles Paths
-	module          Module
-	phonies         map[string]Paths
+	packagingSpecs   []PackagingSpec
+	installFiles     InstallPaths
+	checkbuildFiles  Paths
+	checkbuildTarget Path
+	uncheckedModule  bool
+	module           Module
+	phonies          map[string]Paths
 	// outputFiles stores the output of a module by tag and is used to set
 	// the OutputFilesProvider in GenerateBuildActions
 	outputFiles OutputFilesInfo
@@ -270,6 +291,17 @@
 	// moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
 	// be included in the final module-info.json produced by Make.
 	moduleInfoJSON *ModuleInfoJSON
+
+	// containersInfo stores the information about the containers and the information of the
+	// apexes the module belongs to.
+	containersInfo ContainersInfo
+
+	// Merged Aconfig files for all transitive deps.
+	aconfigFilePaths Paths
+
+	// complianceMetadataInfo is for different module types to dump metadata.
+	// See android.ModuleContext interface.
+	complianceMetadataInfo *ComplianceMetadataInfo
 }
 
 var _ ModuleContext = &moduleContext{}
@@ -495,17 +527,22 @@
 
 func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
 	deps ...InstallPath) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, true, nil)
+	return m.installFile(installPath, name, srcPath, deps, false, true, true, nil)
+}
+
+func (m *moduleContext) InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path,
+	deps ...InstallPath) InstallPath {
+	return m.installFile(installPath, name, srcPath, deps, false, true, false, nil)
 }
 
 func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
 	deps ...InstallPath) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, true, true, nil)
+	return m.installFile(installPath, name, srcPath, deps, true, true, true, nil)
 }
 
 func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
 	extraZip Path, deps ...InstallPath) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, true, &extraFilesZip{
+	return m.installFile(installPath, name, srcPath, deps, false, true, true, &extraFilesZip{
 		zip: extraZip,
 		dir: installPath,
 	})
@@ -517,11 +554,16 @@
 }
 
 func (m *moduleContext) getAconfigPaths() *Paths {
-	return &m.module.base().aconfigFilePaths
+	return &m.aconfigFilePaths
+}
+
+func (m *moduleContext) setAconfigPaths(paths Paths) {
+	m.aconfigFilePaths = paths
 }
 
 func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
 	licenseFiles := m.Module().EffectiveLicenseFiles()
+	overrides := CopyOf(m.Module().base().commonProperties.Overrides)
 	spec := PackagingSpec{
 		relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
 		srcPath:               srcPath,
@@ -532,13 +574,15 @@
 		skipInstall:           m.skipInstall(),
 		aconfigPaths:          m.getAconfigPaths(),
 		archType:              m.target.Arch.ArchType,
+		overrides:             &overrides,
+		owner:                 m.ModuleName(),
 	}
 	m.packagingSpecs = append(m.packagingSpecs, spec)
 	return spec
 }
 
 func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
-	executable bool, hooks bool, extraZip *extraFilesZip) InstallPath {
+	executable bool, hooks bool, checkbuild bool, extraZip *extraFilesZip) InstallPath {
 
 	fullInstallPath := installPath.Join(m, name)
 	if hooks {
@@ -605,7 +649,9 @@
 
 	m.packageFile(fullInstallPath, srcPath, executable)
 
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	if checkbuild {
+		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	}
 
 	return fullInstallPath
 }
@@ -646,9 +692,9 @@
 		}
 
 		m.installFiles = append(m.installFiles, fullInstallPath)
-		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	}
 
+	overrides := CopyOf(m.Module().base().commonProperties.Overrides)
 	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
 		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
 		srcPath:          nil,
@@ -658,6 +704,8 @@
 		skipInstall:      m.skipInstall(),
 		aconfigPaths:     m.getAconfigPaths(),
 		archType:         m.target.Arch.ArchType,
+		overrides:        &overrides,
+		owner:            m.ModuleName(),
 	})
 
 	return fullInstallPath
@@ -693,6 +741,7 @@
 		m.installFiles = append(m.installFiles, fullInstallPath)
 	}
 
+	overrides := CopyOf(m.Module().base().commonProperties.Overrides)
 	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
 		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
 		srcPath:          nil,
@@ -702,6 +751,8 @@
 		skipInstall:      m.skipInstall(),
 		aconfigPaths:     m.getAconfigPaths(),
 		archType:         m.target.Arch.ArchType,
+		overrides:        &overrides,
+		owner:            m.ModuleName(),
 	})
 
 	return fullInstallPath
@@ -713,18 +764,24 @@
 	ret := make(InstallPaths, 0, len(data))
 	for _, d := range data {
 		relPath := d.ToRelativeInstallPath()
-		installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, nil)
+		installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, true, nil)
 		ret = append(ret, installed)
 	}
 
 	return ret
 }
 
-func (m *moduleContext) CheckbuildFile(srcPath Path) {
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+// CheckbuildFile specifies the output files that should be built by checkbuild.
+func (m *moduleContext) CheckbuildFile(srcPaths ...Path) {
+	m.checkbuildFiles = append(m.checkbuildFiles, srcPaths...)
 }
 
-func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
+// UncheckedModule marks the current module has having no files that should be built by checkbuild.
+func (m *moduleContext) UncheckedModule() {
+	m.uncheckedModule = true
+}
+
+func (m *moduleContext) BlueprintModuleContext() blueprint.ModuleContext {
 	return m.bp
 }
 
@@ -768,12 +825,10 @@
 }
 
 func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo {
-	if complianceMetadataInfo := m.module.base().complianceMetadataInfo; complianceMetadataInfo != nil {
-		return complianceMetadataInfo
+	if m.complianceMetadataInfo == nil {
+		m.complianceMetadataInfo = NewComplianceMetadataInfo()
 	}
-	complianceMetadataInfo := NewComplianceMetadataInfo()
-	m.module.base().complianceMetadataInfo = complianceMetadataInfo
-	return complianceMetadataInfo
+	return m.complianceMetadataInfo
 }
 
 // Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
@@ -802,7 +857,7 @@
 	return OptionalPath{}
 }
 
-func (m *moduleContext) RequiredModuleNames(ctx ConfigAndErrorContext) []string {
+func (m *moduleContext) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
 	return m.module.RequiredModuleNames(ctx)
 }
 
@@ -813,3 +868,11 @@
 func (m *moduleContext) TargetRequiredModuleNames() []string {
 	return m.module.TargetRequiredModuleNames()
 }
+
+func (m *moduleContext) getContainersInfo() ContainersInfo {
+	return m.containersInfo
+}
+
+func (m *moduleContext) setContainersInfo(info ContainersInfo) {
+	m.containersInfo = info
+}
diff --git a/android/mutator.go b/android/mutator.go
index 38fb857..9404945 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -148,9 +148,9 @@
 }
 
 func registerArchMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUpBlueprint("os", osMutator).Parallel()
+	ctx.Transition("os", &osTransitionMutator{})
 	ctx.Transition("image", &imageTransitionMutator{})
-	ctx.BottomUpBlueprint("arch", archMutator).Parallel()
+	ctx.Transition("arch", &archTransitionMutator{})
 }
 
 var preDeps = []RegisterMutatorFunc{
@@ -193,16 +193,16 @@
 	// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
 	// AddDependency or OtherModuleName until after this mutator pass is complete.
 	Rename(name string)
+
+	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
+	// the specified property structs to it as if the properties were set in a blueprint file.
+	CreateModule(ModuleFactory, ...interface{}) Module
 }
 
 type TopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
 	BaseMutatorContext
-
-	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
-	// the specified property structs to it as if the properties were set in a blueprint file.
-	CreateModule(ModuleFactory, ...interface{}) Module
 }
 
 type topDownMutatorContext struct {
@@ -516,6 +516,9 @@
 }
 
 func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
+	if a.finalPhase {
+		panic("TransitionMutator not allowed in FinalDepsMutators")
+	}
 	if m, ok := ctx.Module().(Module); ok {
 		moduleContext := m.base().baseModuleContextFactory(ctx)
 		return a.mutator.Split(&moduleContext)
@@ -739,6 +742,14 @@
 	b.Module().base().commonProperties.DebugName = name
 }
 
+func (b *bottomUpMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
+	return b.bp.CreateModule(factory, name, props...)
+}
+
+func (b *bottomUpMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
+	return createModule(b, factory, "_bottomUpMutatorModule", props...)
+}
+
 func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module {
 	if b.baseModuleContext.checkedMissingDeps() {
 		panic("Adding deps not allowed after checking for missing deps")
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 21eebd2..b3ef00f 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -81,6 +81,40 @@
 	AssertDeepEquals(t, "foo missing deps", []string{"added_missing_dep", "regular_missing_dep"}, foo.missingDeps)
 }
 
+type testTransitionMutator struct {
+	split              func(ctx BaseModuleContext) []string
+	outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string
+	incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string
+	mutate             func(ctx BottomUpMutatorContext, variation string)
+}
+
+func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string {
+	if t.split != nil {
+		return t.split(ctx)
+	}
+	return []string{""}
+}
+
+func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+	if t.outgoingTransition != nil {
+		return t.outgoingTransition(ctx, sourceVariation)
+	}
+	return sourceVariation
+}
+
+func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+	if t.incomingTransition != nil {
+		return t.incomingTransition(ctx, incomingVariation)
+	}
+	return incomingVariation
+}
+
+func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+	if t.mutate != nil {
+		t.mutate(ctx, variation)
+	}
+}
+
 func TestModuleString(t *testing.T) {
 	bp := `
 		test {
@@ -94,9 +128,11 @@
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 
 			ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
-				ctx.BottomUp("pre_arch", func(ctx BottomUpMutatorContext) {
-					moduleStrings = append(moduleStrings, ctx.Module().String())
-					ctx.CreateVariations("a", "b")
+				ctx.Transition("pre_arch", &testTransitionMutator{
+					split: func(ctx BaseModuleContext) []string {
+						moduleStrings = append(moduleStrings, ctx.Module().String())
+						return []string{"a", "b"}
+					},
 				})
 				ctx.TopDown("rename_top_down", func(ctx TopDownMutatorContext) {
 					moduleStrings = append(moduleStrings, ctx.Module().String())
@@ -105,16 +141,23 @@
 			})
 
 			ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-				ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) {
-					moduleStrings = append(moduleStrings, ctx.Module().String())
-					ctx.CreateVariations("c", "d")
+				ctx.Transition("pre_deps", &testTransitionMutator{
+					split: func(ctx BaseModuleContext) []string {
+						moduleStrings = append(moduleStrings, ctx.Module().String())
+						return []string{"c", "d"}
+					},
 				})
 			})
 
 			ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
-				ctx.BottomUp("post_deps", func(ctx BottomUpMutatorContext) {
-					moduleStrings = append(moduleStrings, ctx.Module().String())
-					ctx.CreateLocalVariations("e", "f")
+				ctx.Transition("post_deps", &testTransitionMutator{
+					split: func(ctx BaseModuleContext) []string {
+						moduleStrings = append(moduleStrings, ctx.Module().String())
+						return []string{"e", "f"}
+					},
+					outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string {
+						return ""
+					},
 				})
 				ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
 					moduleStrings = append(moduleStrings, ctx.Module().String())
@@ -138,15 +181,15 @@
 		"foo{pre_arch:b}",
 		"foo{pre_arch:a}",
 
-		// After rename_top_down.
-		"foo_renamed1{pre_arch:a}",
+		// After rename_top_down (reversed because pre_deps TransitionMutator.Split is TopDown).
 		"foo_renamed1{pre_arch:b}",
+		"foo_renamed1{pre_arch:a}",
 
-		// After pre_deps.
-		"foo_renamed1{pre_arch:a,pre_deps:c}",
-		"foo_renamed1{pre_arch:a,pre_deps:d}",
-		"foo_renamed1{pre_arch:b,pre_deps:c}",
+		// After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown).
 		"foo_renamed1{pre_arch:b,pre_deps:d}",
+		"foo_renamed1{pre_arch:b,pre_deps:c}",
+		"foo_renamed1{pre_arch:a,pre_deps:d}",
+		"foo_renamed1{pre_arch:a,pre_deps:c}",
 
 		// After post_deps.
 		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
@@ -202,8 +245,10 @@
 						ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep1Tag, "common_dep_1")
 					}
 				})
-				ctx.BottomUp("variant", func(ctx BottomUpMutatorContext) {
-					ctx.CreateLocalVariations("a", "b")
+				ctx.Transition("variant", &testTransitionMutator{
+					split: func(ctx BaseModuleContext) []string {
+						return []string{"a", "b"}
+					},
 				})
 			})
 
@@ -243,27 +288,20 @@
 }
 
 func TestNoCreateVariationsInFinalDeps(t *testing.T) {
-	checkErr := func() {
-		if err := recover(); err == nil || !strings.Contains(fmt.Sprintf("%s", err), "not allowed in FinalDepsMutators") {
-			panic("Expected FinalDepsMutators consistency check to fail")
-		}
-	}
-
 	GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
-				ctx.BottomUp("vars", func(ctx BottomUpMutatorContext) {
-					defer checkErr()
-					ctx.CreateVariations("a", "b")
-				})
-				ctx.BottomUp("local_vars", func(ctx BottomUpMutatorContext) {
-					defer checkErr()
-					ctx.CreateLocalVariations("a", "b")
+				ctx.Transition("vars", &testTransitionMutator{
+					split: func(ctx BaseModuleContext) []string {
+						return []string{"a", "b"}
+					},
 				})
 			})
 
 			ctx.RegisterModuleType("test", mutatorTestModuleFactory)
 		}),
 		FixtureWithRootAndroidBp(`test {name: "foo"}`),
-	).RunTest(t)
+	).
+		ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")).
+		RunTest(t)
 }
diff --git a/android/neverallow.go b/android/neverallow.go
index a68f5ea..b89d150 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -60,6 +60,7 @@
 	AddNeverAllowRules(createCcStubsRule())
 	AddNeverAllowRules(createJavaExcludeStaticLibsRule())
 	AddNeverAllowRules(createProhibitHeaderOnlyRule())
+	AddNeverAllowRules(createLimitNdkExportRule()...)
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -182,6 +183,7 @@
 		"packages/modules/SdkExtensions/derive_sdk",
 		// These are for apps and shouldn't be used by non-SDK variant modules.
 		"prebuilts/ndk",
+		"frameworks/native/libs/binder/ndk",
 		"tools/test/graphicsbenchmark/apps/sample_app",
 		"tools/test/graphicsbenchmark/functional_tests/java",
 		"vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests",
@@ -266,6 +268,22 @@
 		Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules")
 }
 
+func createLimitNdkExportRule() []Rule {
+	reason := "If the headers you're trying to export are meant to be a part of the NDK, they should be exposed by an ndk_headers module. If the headers shouldn't be a part of the NDK, the headers should instead be exposed from a separate `cc_library_headers` which consumers depend on."
+	// DO NOT ADD HERE - please consult danalbert@
+	// b/357711733
+	return []Rule{
+		NeverAllow().
+			NotIn("frameworks/native/libs/binder/ndk").
+			ModuleType("ndk_library").
+			WithMatcher("export_header_libs", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_generated_headers", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_include_dirs", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_shared_lib_headers", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_static_lib_headers", isSetMatcherInstance).Because(reason),
+	}
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/android/packaging.go b/android/packaging.go
index 42009d5..0909936 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -15,6 +15,9 @@
 package android
 
 import (
+	"bytes"
+	"encoding/gob"
+	"errors"
 	"fmt"
 	"path/filepath"
 	"sort"
@@ -56,6 +59,42 @@
 
 	// ArchType of the module which produced this packaging spec
 	archType ArchType
+
+	// List of module names that this packaging spec overrides
+	overrides *[]string
+
+	// Name of the module where this packaging spec is output of
+	owner string
+}
+
+func (p *PackagingSpec) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.relPathInPackage), encoder.Encode(p.srcPath),
+		encoder.Encode(p.symlinkTarget), encoder.Encode(p.executable),
+		encoder.Encode(p.effectiveLicenseFiles), encoder.Encode(p.partition),
+		encoder.Encode(p.skipInstall), encoder.Encode(p.aconfigPaths),
+		encoder.Encode(p.archType))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *PackagingSpec) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.relPathInPackage), decoder.Decode(&p.srcPath),
+		decoder.Decode(&p.symlinkTarget), decoder.Decode(&p.executable),
+		decoder.Decode(&p.effectiveLicenseFiles), decoder.Decode(&p.partition),
+		decoder.Decode(&p.skipInstall), decoder.Decode(&p.aconfigPaths),
+		decoder.Decode(&p.archType))
+	if err != nil {
+		return err
+	}
+
+	return nil
 }
 
 func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
@@ -325,7 +364,10 @@
 }
 
 func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
-	m := make(map[string]PackagingSpec)
+	// all packaging specs gathered from the dep.
+	var all []PackagingSpec
+	// list of module names overridden
+	var overridden []string
 
 	var arches []ArchType
 	for _, target := range getSupportedTargets(ctx) {
@@ -357,17 +399,33 @@
 					continue
 				}
 			}
-			dstPath := ps.relPathInPackage
-			if existingPs, ok := m[dstPath]; ok {
-				if !existingPs.Equals(&ps) {
-					ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
-				}
-				continue
+			all = append(all, ps)
+			if ps.overrides != nil {
+				overridden = append(overridden, *ps.overrides...)
 			}
-
-			m[dstPath] = ps
 		}
 	})
+
+	// all minus packaging specs that are overridden
+	var filtered []PackagingSpec
+	for _, ps := range all {
+		if ps.owner != "" && InList(ps.owner, overridden) {
+			continue
+		}
+		filtered = append(filtered, ps)
+	}
+
+	m := make(map[string]PackagingSpec)
+	for _, ps := range filtered {
+		dstPath := ps.relPathInPackage
+		if existingPs, ok := m[dstPath]; ok {
+			if !existingPs.Equals(&ps) {
+				ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
+			}
+			continue
+		}
+		m[dstPath] = ps
+	}
 	return m
 }
 
diff --git a/android/packaging_test.go b/android/packaging_test.go
index 19b46fe..f5b1020 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -28,6 +28,7 @@
 	props struct {
 		Deps         []string
 		Skip_install *bool
+		Overrides    []string
 	}
 }
 
@@ -117,6 +118,7 @@
 	}
 
 	result := GroupFixturePreparers(
+		PrepareForTestWithDefaults,
 		PrepareForTestWithArchMutator,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("component", componentTestModuleFactory)
@@ -650,3 +652,64 @@
 		runPackagingTest(t, config, bp, tc.expected)
 	}
 }
+
+func TestOverrides(t *testing.T) {
+	bpTemplate := `
+		component {
+			name: "foo",
+			deps: ["bar"],
+		}
+
+		component {
+			name: "bar",
+		}
+
+		component {
+			name: "bar_override",
+			overrides: ["bar"],
+		}
+
+		component {
+			name: "baz",
+			deps: ["bar_override"],
+		}
+
+		package_module {
+			name: "package",
+			deps: %DEPS%,
+		}
+	`
+	testcases := []struct {
+		deps     []string
+		expected []string
+	}{
+		{
+			deps:     []string{"foo"},
+			expected: []string{"lib64/foo", "lib64/bar"},
+		},
+		{
+			deps:     []string{"foo", "bar_override"},
+			expected: []string{"lib64/foo", "lib64/bar_override"},
+		},
+		{
+			deps:     []string{"foo", "bar", "bar_override"},
+			expected: []string{"lib64/foo", "lib64/bar_override"},
+		},
+		{
+			deps:     []string{"bar", "bar_override"},
+			expected: []string{"lib64/bar_override"},
+		},
+		{
+			deps:     []string{"foo", "baz"},
+			expected: []string{"lib64/foo", "lib64/baz", "lib64/bar_override"},
+		},
+	}
+	for _, tc := range testcases {
+		config := testConfig{
+			multiTarget:                true,
+			depsCollectFirstTargetOnly: false,
+		}
+		bp := strings.Replace(bpTemplate, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1)
+		runPackagingTest(t, config, bp, tc.expected)
+	}
+}
diff --git a/android/paths.go b/android/paths.go
index d20b84a..0d94f03 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -27,7 +27,6 @@
 	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/pathtools"
 )
 
@@ -92,8 +91,10 @@
 // the Path methods that rely on module dependencies having been resolved.
 type ModuleWithDepsPathContext interface {
 	EarlyModulePathContext
+	OtherModuleProviderContext
 	VisitDirectDepsBlueprint(visit func(blueprint.Module))
 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+	HasMutatorFinished(mutatorName string) bool
 }
 
 // ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
@@ -554,13 +555,6 @@
 	return ret
 }
 
-// PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module.
-func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path {
-	goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin")
-	rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath())
-	return goBinaryInstallDir.Join(ctx, rel)
-}
-
 // Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax.
 // If the dependency is not found, a missingErrorDependency is returned.
 // If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned.
@@ -572,10 +566,6 @@
 	if aModule, ok := module.(Module); ok && !aModule.Enabled(ctx) {
 		return nil, missingDependencyError{[]string{moduleName}}
 	}
-	if goBinary, ok := module.(bootstrap.GoBinaryTool); ok && tag == "" {
-		goBinaryPath := PathForGoBinary(ctx, goBinary)
-		return Paths{goBinaryPath}, nil
-	}
 	outputFiles, err := outputFilesForModule(ctx, module, tag)
 	if outputFiles != nil && err == nil {
 		return outputFiles, nil
@@ -1766,6 +1756,32 @@
 	fullPath string
 }
 
+func (p *InstallPath) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.soongOutDir),
+		encoder.Encode(p.partitionDir), encoder.Encode(p.partition),
+		encoder.Encode(p.makePath), encoder.Encode(p.fullPath))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *InstallPath) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.soongOutDir),
+		decoder.Decode(&p.partitionDir), decoder.Decode(&p.partition),
+		decoder.Decode(&p.makePath), decoder.Decode(&p.fullPath))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // Will panic if called from outside a test environment.
 func ensureTestOnly() {
 	if PrefixInList(os.Args, "-test.") {
diff --git a/android/product_config.go b/android/product_config.go
index 04180bf..ce3acc9 100644
--- a/android/product_config.go
+++ b/android/product_config.go
@@ -14,7 +14,9 @@
 
 package android
 
-import "github.com/google/blueprint/proptools"
+import (
+	"github.com/google/blueprint/proptools"
+)
 
 func init() {
 	ctx := InitRegistrationContext
diff --git a/android/product_config_to_bp.go b/android/product_config_to_bp.go
new file mode 100644
index 0000000..680328f
--- /dev/null
+++ b/android/product_config_to_bp.go
@@ -0,0 +1,35 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package android
+
+func init() {
+	ctx := InitRegistrationContext
+	ctx.RegisterParallelSingletonType("product_config_to_bp_singleton", productConfigToBpSingletonFactory)
+}
+
+type productConfigToBpSingleton struct{}
+
+func (s *productConfigToBpSingleton) GenerateBuildActions(ctx SingletonContext) {
+	// TODO: update content from make-based product config
+	var content string
+	generatedBp := PathForOutput(ctx, "soong_generated_product_config.bp")
+	WriteFileRule(ctx, generatedBp, content)
+	ctx.Phony("product_config_to_bp", generatedBp)
+}
+
+// productConfigToBpSingleton generates a bp file from make-based product config
+func productConfigToBpSingletonFactory() Singleton {
+	return &productConfigToBpSingleton{}
+}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 95e2b92..18bbcab 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -463,6 +463,8 @@
 	r.build(name, desc, true)
 }
 
+var sandboxEnvOnceKey = NewOnceKey("sandbox_environment_variables")
+
 func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
 	name = ninjaNameEscape(name)
 
@@ -580,16 +582,44 @@
 				})
 			}
 
-			// Set OUT_DIR to the relative path of the sandboxed out directory.
-			// Otherwise, OUT_DIR will be inherited from the rest of the build,
-			// which will allow scripts to escape the sandbox if OUT_DIR is an
-			// absolute path.
-			command.Env = append(command.Env, &sbox_proto.EnvironmentVariable{
-				Name: proto.String("OUT_DIR"),
-				State: &sbox_proto.EnvironmentVariable_Value{
-					Value: sboxOutSubDir,
-				},
-			})
+			// Only allow the build to access certain environment variables
+			command.DontInheritEnv = proto.Bool(true)
+			command.Env = r.ctx.Config().Once(sandboxEnvOnceKey, func() interface{} {
+				// The list of allowed variables was found by running builds of all
+				// genrules and seeing what failed
+				var result []*sbox_proto.EnvironmentVariable
+				inheritedVars := []string{
+					"PATH",
+					"JAVA_HOME",
+					"TMPDIR",
+					// Allow RBE variables because the art tests invoke RBE manually
+					"RBE_log_dir",
+					"RBE_platform",
+					"RBE_server_address",
+					// TODO: RBE_exec_root is set to the absolute path to the root of the source
+					// tree, which we don't want sandboxed actions to find. Remap it to ".".
+					"RBE_exec_root",
+				}
+				for _, v := range inheritedVars {
+					result = append(result, &sbox_proto.EnvironmentVariable{
+						Name: proto.String(v),
+						State: &sbox_proto.EnvironmentVariable_Inherit{
+							Inherit: true,
+						},
+					})
+				}
+				// Set OUT_DIR to the relative path of the sandboxed out directory.
+				// Otherwise, OUT_DIR will be inherited from the rest of the build,
+				// which will allow scripts to escape the sandbox if OUT_DIR is an
+				// absolute path.
+				result = append(result, &sbox_proto.EnvironmentVariable{
+					Name: proto.String("OUT_DIR"),
+					State: &sbox_proto.EnvironmentVariable_Value{
+						Value: sboxOutSubDir,
+					},
+				})
+				return result
+			}).([]*sbox_proto.EnvironmentVariable)
 			command.Chdir = proto.Bool(true)
 		}
 
diff --git a/android/sdk.go b/android/sdk.go
index d3f04a4..ab9a91c 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -813,8 +813,6 @@
 
 // SdkMemberContext provides access to information common to a specific member.
 type SdkMemberContext interface {
-	ConfigAndErrorContext
-
 	// SdkModuleContext returns the module context of the sdk common os variant which is creating the
 	// snapshot.
 	//
diff --git a/android/selects_test.go b/android/selects_test.go
index fc020a4..90d7091 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -1009,6 +1009,28 @@
 			},
 			expectedError: `variable already set in inherited scope, previous assignment:`,
 		},
+		{
+			name: "Basic string list postprocessor",
+			bp: `
+my_defaults {
+	name: "defaults_a",
+	my_string_list: ["a", "b", "c"],
+	string_list_postprocessor_add_to_elements: "1",
+}
+my_defaults {
+	name: "defaults_b",
+	my_string_list: ["d", "e", "f"],
+	string_list_postprocessor_add_to_elements: "2",
+}
+my_module_type {
+	name: "foo",
+	defaults: ["defaults_a", "defaults_b"],
+}
+`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"d2", "e2", "f2", "a1", "b1", "c1"},
+			},
+		},
 	}
 
 	for _, tc := range testCases {
@@ -1161,9 +1183,15 @@
 	return m
 }
 
+type selectsMockDefaultsProperties struct {
+	String_list_postprocessor_add_to_elements string
+}
+
 type selectsMockModuleDefaults struct {
 	ModuleBase
 	DefaultsModuleBase
+	myProperties       selectsMockModuleProperties
+	defaultsProperties selectsMockDefaultsProperties
 }
 
 func (d *selectsMockModuleDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -1173,10 +1201,22 @@
 	module := &selectsMockModuleDefaults{}
 
 	module.AddProperties(
-		&selectsMockModuleProperties{},
+		&module.myProperties,
+		&module.defaultsProperties,
 	)
 
 	InitDefaultsModule(module)
 
+	AddLoadHook(module, func(lhc LoadHookContext) {
+		if module.defaultsProperties.String_list_postprocessor_add_to_elements != "" {
+			module.myProperties.My_string_list.AddPostProcessor(func(x []string) []string {
+				for i := range x {
+					x[i] = x[i] + module.defaultsProperties.String_list_postprocessor_add_to_elements
+				}
+				return x
+			})
+		}
+	})
+
 	return module
 }
diff --git a/android/singleton.go b/android/singleton.go
index 8542bd9..913bf6a 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -90,6 +90,10 @@
 
 	// OtherModulePropertyErrorf reports an error on the line number of the given property of the given module
 	OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{})
+
+	// HasMutatorFinished returns true if the given mutator has finished running.
+	// It will panic if given an invalid mutator name.
+	HasMutatorFinished(mutatorName string) bool
 }
 
 type singletonAdaptor struct {
@@ -286,3 +290,7 @@
 func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) {
 	s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...)
 }
+
+func (s *singletonContextAdaptor) HasMutatorFinished(mutatorName string) bool {
+	return s.blueprintSingletonContext().HasMutatorFinished(mutatorName)
+}
diff --git a/android/singleton_module.go b/android/singleton_module.go
index 2351738..43028e8 100644
--- a/android/singleton_module.go
+++ b/android/singleton_module.go
@@ -68,7 +68,7 @@
 func (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
 	smb.lock.Lock()
 	if smb.variant != "" {
-		ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only  have one variant", smb.variant)
+		ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant)
 	}
 	smb.variant = ctx.ModuleSubDir()
 	smb.lock.Unlock()
diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go
index 3b1bf39..3b8c6b2 100644
--- a/android/singleton_module_test.go
+++ b/android/singleton_module_test.go
@@ -96,12 +96,6 @@
 	}
 }
 
-func testVariantSingletonModuleMutator(ctx BottomUpMutatorContext) {
-	if _, ok := ctx.Module().(*testSingletonModule); ok {
-		ctx.CreateVariations("a", "b")
-	}
-}
-
 func TestVariantSingletonModule(t *testing.T) {
 	if testing.Short() {
 		t.Skip("test fails with data race enabled")
@@ -116,7 +110,11 @@
 		prepareForSingletonModuleTest,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-				ctx.BottomUp("test_singleton_module_mutator", testVariantSingletonModuleMutator)
+				ctx.Transition("test_singleton_module_mutator", &testTransitionMutator{
+					split: func(ctx BaseModuleContext) []string {
+						return []string{"a", "b"}
+					},
+				})
 			})
 		}),
 	).
diff --git a/android/team_proto/Android.bp b/android/team_proto/Android.bp
index 7e2a4c1..5faaaf1 100644
--- a/android/team_proto/Android.bp
+++ b/android/team_proto/Android.bp
@@ -40,4 +40,8 @@
     proto: {
         canonical_path_from_root: false,
     },
+    visibility: [
+        "//build/soong:__subpackages__",
+        "//tools/asuite/team_build_scripts",
+    ],
 }
diff --git a/android/testing.go b/android/testing.go
index 816707d..196b22e 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1326,7 +1326,15 @@
 	return ctx.ctx.Config()
 }
 
-func PanickingConfigAndErrorContext(ctx *TestContext) ConfigAndErrorContext {
+func (ctx *panickingConfigAndErrorContext) HasMutatorFinished(mutatorName string) bool {
+	return ctx.ctx.HasMutatorFinished(mutatorName)
+}
+
+func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) {
+	return ctx.ctx.otherModuleProvider(m, p)
+}
+
+func PanickingConfigAndErrorContext(ctx *TestContext) ConfigurableEvaluatorContext {
 	return &panickingConfigAndErrorContext{
 		ctx: ctx,
 	}
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
index dd7dc2c..d2595ed 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -33,4 +33,4 @@
 // * AOSP            - xx9990000
 // * x-mainline-prod - xx9990000
 // * master          - 990090000
-const DefaultUpdatableModuleVersion = "350090000"
+const DefaultUpdatableModuleVersion = "352090000"
diff --git a/android/util.go b/android/util.go
index 3c0af2f..2d269b7 100644
--- a/android/util.go
+++ b/android/util.go
@@ -177,6 +177,41 @@
 	return m
 }
 
+// PrettyConcat returns the formatted concatenated string suitable for displaying user-facing
+// messages.
+func PrettyConcat(list []string, quote bool, lastSep string) string {
+	if len(list) == 0 {
+		return ""
+	}
+
+	quoteStr := func(v string) string {
+		if !quote {
+			return v
+		}
+		return fmt.Sprintf("%q", v)
+	}
+
+	if len(list) == 1 {
+		return quoteStr(list[0])
+	}
+
+	var sb strings.Builder
+	for i, val := range list {
+		if i > 0 {
+			sb.WriteString(", ")
+		}
+		if i == len(list)-1 {
+			sb.WriteString(lastSep)
+			if lastSep != "" {
+				sb.WriteString(" ")
+			}
+		}
+		sb.WriteString(quoteStr(val))
+	}
+
+	return sb.String()
+}
+
 // ListSetDifference checks if the two lists contain the same elements. It returns
 // a boolean which is true if there is a difference, and then returns lists of elements
 // that are in l1 but not l2, and l2 but not l1.
diff --git a/android/util_test.go b/android/util_test.go
index 6537d69..b76ffcf 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -867,3 +867,51 @@
 		})
 	}
 }
+
+var prettyConcatTestCases = []struct {
+	name          string
+	list          []string
+	quote         bool
+	lastSeparator string
+	expected      string
+}{
+	{
+		name:          "empty",
+		list:          []string{},
+		quote:         false,
+		lastSeparator: "and",
+		expected:      ``,
+	},
+	{
+		name:          "single",
+		list:          []string{"a"},
+		quote:         true,
+		lastSeparator: "and",
+		expected:      `"a"`,
+	},
+	{
+		name:          "with separator",
+		list:          []string{"a", "b", "c"},
+		quote:         true,
+		lastSeparator: "or",
+		expected:      `"a", "b", or "c"`,
+	},
+	{
+		name:          "without separator",
+		list:          []string{"a", "b", "c"},
+		quote:         false,
+		lastSeparator: "",
+		expected:      `a, b, c`,
+	},
+}
+
+func TestPrettyConcat(t *testing.T) {
+	for _, testCase := range prettyConcatTestCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			concatString := PrettyConcat(testCase.list, testCase.quote, testCase.lastSeparator)
+			if !reflect.DeepEqual(concatString, testCase.expected) {
+				t.Errorf("expected %#v, got %#v", testCase.expected, concatString)
+			}
+		})
+	}
+}
diff --git a/android/variable.go b/android/variable.go
index 14f1756..e0d512d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -121,6 +121,7 @@
 		// are used for dogfooding and performance testing, and should be as similar to user builds
 		// as possible.
 		Debuggable struct {
+			Apk             *string
 			Cflags          []string
 			Cppflags        []string
 			Init_rc         []string
@@ -422,6 +423,9 @@
 
 	TargetFSConfigGen []string `json:",omitempty"`
 
+	UseSoongSystemImage            *bool   `json:",omitempty"`
+	ProductSoongDefinedSystemImage *string `json:",omitempty"`
+
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
 
 	EnforceInterPartitionJavaSdkLibrary *bool    `json:",omitempty"`
@@ -445,7 +449,6 @@
 	GenruleSandboxing                   *bool    `json:",omitempty"`
 	BuildBrokenEnforceSyspropOwner      bool     `json:",omitempty"`
 	BuildBrokenTrebleSyspropNeverallow  bool     `json:",omitempty"`
-	BuildBrokenUsesSoongPython2Modules  bool     `json:",omitempty"`
 	BuildBrokenVendorPropertyNamespace  bool     `json:",omitempty"`
 	BuildBrokenIncorrectPartitionImages bool     `json:",omitempty"`
 	BuildBrokenInputDirModules          []string `json:",omitempty"`
@@ -515,6 +518,11 @@
 	OdmPropFiles       []string `json:",omitempty"`
 
 	EnableUffdGc *string `json:",omitempty"`
+
+	BoardAvbEnable                         *bool    `json:",omitempty"`
+	BoardAvbSystemAddHashtreeFooterArgs    []string `json:",omitempty"`
+	DeviceFrameworkCompatibilityMatrixFile []string `json:",omitempty"`
+	DeviceProductCompatibilityMatrixFile   []string `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
diff --git a/android/visibility.go b/android/visibility.go
index 89c0adc..61f2200 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -283,7 +283,7 @@
 
 // This must be registered after the deps have been resolved.
 func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
-	ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
+	ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
 }
 
 // Checks the per-module visibility rule lists before defaults expansion.
@@ -507,7 +507,7 @@
 	return true, pkg, name
 }
 
-func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
+func visibilityRuleEnforcer(ctx BottomUpMutatorContext) {
 	qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
 
 	// Visit all the dependencies making sure that this module has access to them all.
diff --git a/androidmk/parser/ast.go b/androidmk/parser/ast.go
index d5d1354..c3d198f 100644
--- a/androidmk/parser/ast.go
+++ b/androidmk/parser/ast.go
@@ -84,6 +84,7 @@
 	Prerequisites *MakeString
 	RecipePos     Pos
 	Recipe        string
+	RecipeEndPos  Pos
 }
 
 func (x *Rule) Dump() string {
@@ -95,7 +96,7 @@
 }
 
 func (x *Rule) Pos() Pos { return x.Target.Pos() }
-func (x *Rule) End() Pos { return Pos(int(x.RecipePos) + len(x.Recipe)) }
+func (x *Rule) End() Pos { return x.RecipeEndPos }
 
 type Variable struct {
 	Name *MakeString
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index 8a20bb0..f2477db 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -448,6 +448,7 @@
 			Prerequisites: prerequisites,
 			Recipe:        recipe,
 			RecipePos:     recipePos,
+			RecipeEndPos:  p.pos(),
 		})
 	}
 }
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
index fb03c23..e238f8b 100644
--- a/androidmk/parser/parser_test.go
+++ b/androidmk/parser/parser_test.go
@@ -124,3 +124,25 @@
 		})
 	}
 }
+
+func TestRuleEnd(t *testing.T) {
+	name := "ruleEndTest"
+	in := `all:
+ifeq (A, A)
+	echo foo
+	echo foo
+	echo foo
+	echo foo
+endif
+	echo bar
+`
+	p := NewParser(name, bytes.NewBufferString(in))
+	got, errs := p.Parse()
+	if len(errs) != 0 {
+		t.Fatalf("Unexpected errors while parsing: %v", errs)
+	}
+
+	if got[0].End() < got[len(got) -1].Pos() {
+		t.Errorf("Rule's end (%d) is smaller than directive that inside of rule's start (%v)\n", got[0].End(), got[len(got) -1].Pos())
+	}
+}
diff --git a/apex/Android.bp b/apex/Android.bp
index 17fdfc3..4848513 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,7 +15,6 @@
         "soong-cc",
         "soong-filesystem",
         "soong-java",
-        "soong-multitree",
         "soong-provenance",
         "soong-python",
         "soong-rust",
@@ -43,4 +42,6 @@
         "systemserver_classpath_fragment_test.go",
     ],
     pluginFor: ["soong_build"],
+    // Used by plugins
+    visibility: ["//visibility:public"],
 }
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
index 14c0b63..bb811f5 100644
--- a/apex/aconfig_test.go
+++ b/apex/aconfig_test.go
@@ -74,6 +74,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 		},
 		{
@@ -122,6 +124,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 		},
 		{
@@ -345,6 +349,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 			expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
 		},
@@ -392,6 +398,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
 		},
@@ -693,6 +701,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
 		},
@@ -769,6 +779,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 		},
 	}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 4112108..933682a 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -136,6 +136,11 @@
 		fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(modulePath, fi.stem()))
 		fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", fi.builtFile.String()+":"+filepath.Join(modulePath, fi.stem()))
 		fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
+		if fi.checkbuildTarget != nil {
+			fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.checkbuildTarget.String())
+		} else {
+			fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.builtFile.String())
+		}
 		fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
 		if fi.module != nil {
 			// This apexFile's module comes from Soong
diff --git a/apex/apex.go b/apex/apex.go
index 3850ee1..e21909a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -32,7 +32,6 @@
 	prebuilt_etc "android/soong/etc"
 	"android/soong/filesystem"
 	"android/soong/java"
-	"android/soong/multitree"
 	"android/soong/rust"
 	"android/soong/sh"
 )
@@ -56,11 +55,10 @@
 }
 
 func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel()
+	ctx.BottomUp("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel()
 }
 
 func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
 	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
 }
 
@@ -438,7 +436,6 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.OverridableModuleBase
-	multitree.ExportableModuleBase
 
 	// Properties
 	properties            apexBundleProperties
@@ -577,6 +574,8 @@
 	customStem string
 	symlinks   []string // additional symlinks
 
+	checkbuildTarget android.Path
+
 	// Info for Android.mk Module name of `module` in AndroidMk. Note the generated AndroidMk
 	// module for apexFile is named something like <AndroidMk module name>.<apex name>[<apex
 	// suffix>]
@@ -612,6 +611,9 @@
 		module:              module,
 	}
 	if module != nil {
+		if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
+			ret.checkbuildTarget = installFilesInfo.CheckbuildTarget
+		}
 		ret.moduleDir = ctx.OtherModuleDir(module)
 		ret.partition = module.PartitionTag(ctx.DeviceConfig())
 		ret.requiredModuleNames = module.RequiredModuleNames(ctx)
@@ -1073,6 +1075,7 @@
 		ApexContents:      []*android.ApexContents{apexContents},
 		TestApexes:        testApexes,
 		BaseApexName:      mctx.ModuleName(),
+		ApexAvailableName: proptools.String(a.properties.Apex_available_name),
 	}
 	mctx.WalkDeps(func(child, parent android.Module) bool {
 		if !continueApexDepsWalk(child, parent) {
@@ -1400,8 +1403,6 @@
 	return true
 }
 
-var _ multitree.Exportable = (*apexBundle)(nil)
-
 func (a *apexBundle) Exportable() bool {
 	return true
 }
@@ -1937,8 +1938,6 @@
 
 	// visitor skips these from this list of module names
 	unwantedTransitiveDeps []string
-
-	aconfigFiles []android.Path
 }
 
 func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
@@ -2005,7 +2004,6 @@
 				fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
-				addAconfigFiles(vctx, ctx, child)
 				// Collect the list of stub-providing libs except:
 				// - VNDK libs are only for vendors
 				// - bootstrap bionic libs are treated as provided by system
@@ -2017,7 +2015,6 @@
 				fi := apexFileForRustLibrary(ctx, ch)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
@@ -2026,11 +2023,9 @@
 			switch ch := child.(type) {
 			case *cc.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			case *rust.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf("binaries",
@@ -2070,7 +2065,6 @@
 					return false
 				}
 				vctx.filesInfo = append(vctx.filesInfo, af)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
@@ -2079,14 +2073,11 @@
 			switch ap := child.(type) {
 			case *java.AndroidApp:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			case *java.AndroidAppImport:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				addAconfigFiles(vctx, ctx, child)
 			case *java.AndroidTestHelperApp:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				addAconfigFiles(vctx, ctx, child)
 			case *java.AndroidAppSet:
 				appDir := "app"
 				if ap.Privileged() {
@@ -2100,7 +2091,6 @@
 				af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
 				af.certificate = java.PresignedCertificate
 				vctx.filesInfo = append(vctx.filesInfo, af)
-				addAconfigFiles(vctx, ctx, child)
 			default:
 				ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 			}
@@ -2132,7 +2122,6 @@
 				for _, etcFile := range filesToCopy {
 					vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
 				}
-				addAconfigFiles(vctx, ctx, child)
 			} else {
 				ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
 			}
@@ -2147,7 +2136,6 @@
 				af := apexFileForExecutable(ctx, ccTest)
 				af.class = nativeTest
 				vctx.filesInfo = append(vctx.filesInfo, af)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			} else {
 				ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
@@ -2227,7 +2215,6 @@
 			}
 
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		} else if rm, ok := child.(*rust.Module); ok {
 			if !android.IsDepInSameApex(ctx, am, am) {
@@ -2237,7 +2224,6 @@
 			af := apexFileForRustLibrary(ctx, rm)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		}
 	} else if cc.IsHeaderDepTag(depTag) {
@@ -2260,7 +2246,6 @@
 			af := apexFileForRustLibrary(ctx, rustm)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		}
 	} else if rust.IsRlibDepTag(depTag) {
@@ -2279,7 +2264,6 @@
 				return false
 			}
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("bootclasspath_fragments",
@@ -2294,7 +2278,6 @@
 			if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
 				vctx.filesInfo = append(vctx.filesInfo, *profileAf)
 			}
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("systemserverclasspath_fragments",
@@ -2312,19 +2295,6 @@
 	return false
 }
 
-func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
-	if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigPropagatingProviderKey); ok {
-		if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
-			vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
-		}
-	}
-
-	validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
-	if validationFlag == "error" || validationFlag == "warning" {
-		android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), module, validationFlag == "error")
-	}
-}
-
 func (a *apexBundle) shouldCheckDuplicate(ctx android.ModuleContext) bool {
 	// TODO(b/263308293) remove this
 	if a.properties.IsCoverageVariant {
@@ -2406,13 +2376,16 @@
 	// 3) some fields in apexBundle struct are configured
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = vctx.filesInfo
-	a.aconfigFiles = android.FirstUniquePaths(vctx.aconfigFiles)
 
 	a.setPayloadFsType(ctx)
 	a.setSystemLibLink(ctx)
 	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 
 	////////////////////////////////////////////////////////////////////////////////////////////
+	// 3.a) some artifacts are generated from the collected files
+	a.filesInfo = append(a.filesInfo, a.buildAconfigFiles(ctx)...)
+
+	////////////////////////////////////////////////////////////////////////////////////////////
 	// 4) generate the build rules to create the APEX. This is done in builder.go.
 	a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
 	a.buildApex(ctx)
@@ -2562,7 +2535,6 @@
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.overridableProperties.Overrides)
-	multitree.InitExportableModule(module)
 	return module
 }
 
@@ -2825,7 +2797,7 @@
 			return false
 		}
 
-		if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) {
+		if to.AvailableFor(apexName) {
 			return true
 		}
 
@@ -2885,74 +2857,6 @@
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.ResolvedSystemserverclasspathFragments...)
 }
 
-var (
-	apexAvailBaseline        = makeApexAvailableBaseline()
-	inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline)
-)
-
-func baselineApexAvailable(apex, moduleName string) bool {
-	key := apex
-	moduleName = normalizeModuleName(moduleName)
-
-	if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) {
-		return true
-	}
-
-	key = android.AvailableToAnyApex
-	if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) {
-		return true
-	}
-
-	return false
-}
-
-func normalizeModuleName(moduleName string) string {
-	// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
-	// system. Trim the prefix for the check since they are confusing
-	moduleName = android.RemoveOptionalPrebuiltPrefix(moduleName)
-	if strings.HasPrefix(moduleName, "libclang_rt.") {
-		// This module has many arch variants that depend on the product being built.
-		// We don't want to list them all
-		moduleName = "libclang_rt"
-	}
-	if strings.HasPrefix(moduleName, "androidx.") {
-		// TODO(b/156996905) Set apex_available/min_sdk_version for androidx support libraries
-		moduleName = "androidx"
-	}
-	return moduleName
-}
-
-// Transform the map of apex -> modules to module -> apexes.
-func invertApexBaseline(m map[string][]string) map[string][]string {
-	r := make(map[string][]string)
-	for apex, modules := range m {
-		for _, module := range modules {
-			r[module] = append(r[module], apex)
-		}
-	}
-	return r
-}
-
-// Retrieve the baseline of apexes to which the supplied module belongs.
-func BaselineApexAvailable(moduleName string) []string {
-	return inverseApexAvailBaseline[normalizeModuleName(moduleName)]
-}
-
-// This is a map from apex to modules, which overrides the apex_available setting for that
-// particular module to make it available for the apex regardless of its setting.
-// TODO(b/147364041): remove this
-func makeApexAvailableBaseline() map[string][]string {
-	// The "Module separator"s below are employed to minimize merge conflicts.
-	m := make(map[string][]string)
-	//
-	// Module separator
-	//
-	m["com.android.runtime"] = []string{
-		"libz",
-	}
-	return m
-}
-
 func init() {
 	android.AddNeverAllowRules(createBcpPermittedPackagesRules(qBcpPackages())...)
 	android.AddNeverAllowRules(createBcpPermittedPackagesRules(rBcpPackages())...)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index f36467e..feab7a3 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -267,6 +267,7 @@
 }
 
 func ensureMatches(t *testing.T, result string, expectedRex string) {
+	t.Helper()
 	ok, err := regexp.MatchString(expectedRex, result)
 	if err != nil {
 		t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err)
@@ -277,6 +278,14 @@
 	}
 }
 
+func ensureListContainsMatch(t *testing.T, result []string, expectedRex string) {
+	t.Helper()
+	p := regexp.MustCompile(expectedRex)
+	if android.IndexListPred(func(s string) bool { return p.MatchString(s) }, result) == -1 {
+		t.Errorf("%q is not found in %v", expectedRex, result)
+	}
+}
+
 func ensureListContains(t *testing.T, result []string, expected string) {
 	t.Helper()
 	if !android.InList(expected, result) {
@@ -3676,7 +3685,7 @@
 }
 
 func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
-	deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex")
+	deapexer := ctx.ModuleForTests(moduleName, variant).Description("deapex")
 	outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
 	if deapexer.Output != nil {
 		outputs = append(outputs, deapexer.Output.String())
@@ -4876,200 +4885,6 @@
 func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) {
 }
 
-// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
-// propagation of paths to dex implementation jars from the former to the latter.
-func TestPrebuiltExportDexImplementationJars(t *testing.T) {
-	transform := android.NullFixturePreparer
-
-	checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) {
-		t.Helper()
-		// Make sure the import has been given the correct path to the dex jar.
-		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
-		dexJarBuildPath := p.DexJarBuildPath(moduleErrorfTestCtx{}).PathOrNil()
-		stem := android.RemoveOptionalPrebuiltPrefix(name)
-		android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.",
-			".intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
-			android.NormalizePathForTesting(dexJarBuildPath))
-	}
-
-	checkDexJarInstallPath := func(t *testing.T, ctx *android.TestContext, name string) {
-		t.Helper()
-		// Make sure the import has been given the correct path to the dex jar.
-		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
-		dexJarBuildPath := p.DexJarInstallPath()
-		stem := android.RemoveOptionalPrebuiltPrefix(name)
-		android.AssertStringEquals(t, "DexJarInstallPath should be apex-related path.",
-			"target/product/test_device/apex/myapex/javalib/"+stem+".jar",
-			android.NormalizePathForTesting(dexJarBuildPath))
-	}
-
-	ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext, name string) {
-		t.Helper()
-		// Make sure that an apex variant is not created for the source module.
-		android.AssertArrayString(t, "Check if there is no source variant",
-			[]string{"android_common"},
-			ctx.ModuleVariantsForTests(name))
-	}
-
-	t.Run("prebuilt only", func(t *testing.T) {
-		bp := `
-		prebuilt_apex {
-			name: "myapex",
-			arch: {
-				arm64: {
-					src: "myapex-arm64.apex",
-				},
-				arm: {
-					src: "myapex-arm.apex",
-				},
-			},
-			exported_java_libs: ["libfoo", "libbar"],
-		}
-
-		java_import {
-			name: "libfoo",
-			jars: ["libfoo.jar"],
-		}
-
-		java_sdk_library_import {
-			name: "libbar",
-			public: {
-				jars: ["libbar.jar"],
-			},
-		}
-	`
-
-		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
-		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-
-		deapexerName := deapexerModuleName("prebuilt_myapex")
-		android.AssertStringEquals(t, "APEX module name from deapexer name", "prebuilt_myapex", apexModuleName(deapexerName))
-
-		// Make sure that the deapexer has the correct input APEX.
-		deapexer := ctx.ModuleForTests(deapexerName, "android_common")
-		rule := deapexer.Rule("deapexer")
-		if expected, actual := []string{"myapex-arm64.apex"}, android.NormalizePathsForTesting(rule.Implicits); !reflect.DeepEqual(expected, actual) {
-			t.Errorf("expected: %q, found: %q", expected, actual)
-		}
-
-		// Make sure that the prebuilt_apex has the correct input APEX.
-		prebuiltApex := ctx.ModuleForTests("myapex", "android_common_myapex")
-		rule = prebuiltApex.Rule("android/soong/android.Cp")
-		if expected, actual := "myapex-arm64.apex", android.NormalizePathForTesting(rule.Input); !reflect.DeepEqual(expected, actual) {
-			t.Errorf("expected: %q, found: %q", expected, actual)
-		}
-
-		checkDexJarBuildPath(t, ctx, "libfoo")
-		checkDexJarInstallPath(t, ctx, "libfoo")
-
-		checkDexJarBuildPath(t, ctx, "libbar")
-		checkDexJarInstallPath(t, ctx, "libbar")
-	})
-
-	t.Run("prebuilt with source preferred", func(t *testing.T) {
-
-		bp := `
-		prebuilt_apex {
-			name: "myapex",
-			arch: {
-				arm64: {
-					src: "myapex-arm64.apex",
-				},
-				arm: {
-					src: "myapex-arm.apex",
-				},
-			},
-			exported_java_libs: ["libfoo", "libbar"],
-		}
-
-		java_import {
-			name: "libfoo",
-			jars: ["libfoo.jar"],
-		}
-
-		java_library {
-			name: "libfoo",
-		}
-
-		java_sdk_library_import {
-			name: "libbar",
-			public: {
-				jars: ["libbar.jar"],
-			},
-		}
-
-		java_sdk_library {
-			name: "libbar",
-			srcs: ["foo/bar/MyClass.java"],
-			unsafe_ignore_missing_latest_api: true,
-		}
-	`
-
-		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
-		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-
-		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
-		checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
-		ensureNoSourceVariant(t, ctx, "libfoo")
-
-		checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
-		checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
-		ensureNoSourceVariant(t, ctx, "libbar")
-	})
-
-	t.Run("prebuilt preferred with source", func(t *testing.T) {
-		bp := `
-		prebuilt_apex {
-			name: "myapex",
-			arch: {
-				arm64: {
-					src: "myapex-arm64.apex",
-				},
-				arm: {
-					src: "myapex-arm.apex",
-				},
-			},
-			exported_java_libs: ["libfoo", "libbar"],
-		}
-
-		java_import {
-			name: "libfoo",
-			prefer: true,
-			jars: ["libfoo.jar"],
-		}
-
-		java_library {
-			name: "libfoo",
-		}
-
-		java_sdk_library_import {
-			name: "libbar",
-			prefer: true,
-			public: {
-				jars: ["libbar.jar"],
-			},
-		}
-
-		java_sdk_library {
-			name: "libbar",
-			srcs: ["foo/bar/MyClass.java"],
-			unsafe_ignore_missing_latest_api: true,
-		}
-	`
-
-		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
-		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-
-		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
-		checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
-		ensureNoSourceVariant(t, ctx, "libfoo")
-
-		checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
-		checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
-		ensureNoSourceVariant(t, ctx, "libbar")
-	})
-}
-
 func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
 	preparer := android.GroupFixturePreparers(
 		java.FixtureConfigureApexBootJars("myapex:libfoo", "myapex:libbar"),
@@ -5092,23 +4907,6 @@
 		}),
 	)
 
-	checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
-		t.Helper()
-		s := ctx.ModuleForTests("dex_bootjars", "android_common")
-		foundLibfooJar := false
-		base := stem + ".jar"
-		for _, output := range s.AllOutputs() {
-			if filepath.Base(output) == base {
-				foundLibfooJar = true
-				buildRule := s.Output(output)
-				android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String())
-			}
-		}
-		if !foundLibfooJar {
-			t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs()))
-		}
-	}
-
 	checkHiddenAPIIndexFromClassesInputs := func(t *testing.T, ctx *android.TestContext, expectedIntermediateInputs string) {
 		t.Helper()
 		platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common")
@@ -5161,10 +4959,13 @@
 			},
 		}
 
-		java_import {
+		java_sdk_library_import {
 			name: "libfoo",
-			jars: ["libfoo.jar"],
+			public: {
+				jars: ["libfoo.jar"],
+			},
 			apex_available: ["myapex"],
+			shared_library: false,
 			permitted_packages: ["foo"],
 		}
 
@@ -5180,8 +4981,6 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5197,18 +4996,10 @@
 		apex_set {
 			name: "myapex",
 			set: "myapex.apks",
-			exported_java_libs: ["myjavalib"],
 			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
 			exported_systemserverclasspath_fragments: ["my-systemserverclasspath-fragment"],
 		}
 
-		java_import {
-			name: "myjavalib",
-			jars: ["myjavalib.jar"],
-			apex_available: ["myapex"],
-			permitted_packages: ["javalib"],
-		}
-
 		prebuilt_bootclasspath_fragment {
 			name: "my-bootclasspath-fragment",
 			contents: ["libfoo", "libbar"],
@@ -5229,13 +5020,17 @@
 			apex_available: ["myapex"],
 		}
 
-		java_import {
+		java_sdk_library_import {
 			name: "libfoo",
-			jars: ["libfoo.jar"],
+			public: {
+				jars: ["libfoo.jar"],
+			},
 			apex_available: ["myapex"],
-			permitted_packages: ["foo"],
+			shared_library: false,
+			permitted_packages: ["libfoo"],
 		}
 
+
 		java_sdk_library_import {
 			name: "libbar",
 			public: {
@@ -5258,8 +5053,6 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5320,12 +5113,14 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
 			name: "libfoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5411,12 +5206,15 @@
 			},
 		}
 
-		java_import {
+		java_sdk_library_import {
 			name: "libfoo",
 			prefer: true,
-			jars: ["libfoo.jar"],
+			public: {
+				jars: ["libfoo.jar"],
+			},
 			apex_available: ["myapex"],
-			permitted_packages: ["foo"],
+			shared_library: false,
+			permitted_packages: ["libfoo"],
 		}
 
 		java_library {
@@ -5424,6 +5222,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5447,8 +5246,6 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5514,6 +5311,7 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -5522,6 +5320,7 @@
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5540,12 +5339,11 @@
 			apex_available: ["myapex"],
 			permitted_packages: ["bar"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -5657,8 +5455,6 @@
 		)
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer2, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
@@ -6134,6 +5930,7 @@
 			name: "TesterHelpAppFoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: [ "myapex" ],
+			sdk_version: "test_current",
 		}
 
 	`)
@@ -7451,7 +7248,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["a.java"],
-			libs: ["foo"],
+			libs: ["foo.impl"],
 			apex_available: ["myapex"],
 			sdk_version: "none",
 			system_modules: "none",
@@ -7504,7 +7301,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["a.java"],
-			libs: ["foo"],
+			libs: ["foo.stubs"],
 			sdk_version: "none",
 			system_modules: "none",
 		}
@@ -7558,7 +7355,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["a.java"],
-			libs: ["foo"],
+			libs: ["foo.impl"],
 			apex_available: ["myapex"],
 			sdk_version: "none",
 			system_modules: "none",
@@ -7902,7 +7699,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			libs: ["myotherjar"],
+			static_libs: ["myotherjar"],
 			apex_available: [
 				"myapex",
 				"myapex.updatable",
@@ -8231,9 +8028,9 @@
 	ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
 
 	// Check that the extractor produces the correct output file from the correct input file.
-	extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
+	extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.hwasan.apks"
 
-	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("myapex", "android_common_myapex")
 	extractedApex := m.Output(extractorOutput)
 
 	android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
@@ -8258,10 +8055,10 @@
 		}
 	`)
 
-	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("myapex", "android_common_myapex")
 
 	// Check that the extractor produces the correct apks file from the input module
-	extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.apks"
+	extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.apks"
 	extractedApex := m.Output(extractorOutput)
 
 	android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
@@ -8323,189 +8120,6 @@
 	return result.TestContext
 }
 
-func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
-	preparers := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		prepareForTestWithBootclasspathFragment,
-		dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"),
-		PrepareForTestWithApexBuildComponents,
-	).
-		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
-			"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art"))
-
-	bpBase := `
-		apex_set {
-			name: "com.android.art",
-			installable: true,
-			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
-			set: "myapex.apks",
-		}
-
-		apex_set {
-			name: "com.mycompany.android.art",
-			apex_name: "com.android.art",
-			installable: true,
-			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
-			set: "company-myapex.apks",
-		}
-
-		prebuilt_bootclasspath_fragment {
-			name: "art-bootclasspath-fragment",
-			apex_available: ["com.android.art"],
-			hidden_api: {
-				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
-				metadata: "my-bootclasspath-fragment/metadata.csv",
-				index: "my-bootclasspath-fragment/index.csv",
-				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
-				all_flags: "my-bootclasspath-fragment/all-flags.csv",
-			},
-			%s
-		}
-	`
-
-	t.Run("java_import", func(t *testing.T) {
-		_ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
-			java_import {
-				name: "libfoo",
-				jars: ["libfoo.jar"],
-				apex_available: ["com.android.art"],
-			}
-		`)
-	})
-
-	t.Run("java_sdk_library_import", func(t *testing.T) {
-		_ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
-			java_sdk_library_import {
-				name: "libfoo",
-				public: {
-					jars: ["libbar.jar"],
-				},
-				shared_library: false,
-				apex_available: ["com.android.art"],
-			}
-		`)
-	})
-
-	t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
-		_ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
-			image_name: "art",
-			contents: ["libfoo"],
-		`)+`
-			java_sdk_library_import {
-				name: "libfoo",
-				public: {
-					jars: ["libbar.jar"],
-				},
-				shared_library: false,
-				apex_available: ["com.android.art"],
-			}
-		`)
-	})
-}
-
-func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
-	preparers := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithApexBuildComponents,
-	)
-
-	errCtx := moduleErrorfTestCtx{}
-
-	bpBase := `
-		apex_set {
-			name: "com.android.myapex",
-			installable: true,
-			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
-			set: "myapex.apks",
-		}
-
-		apex_set {
-			name: "com.android.myapex_compressed",
-			apex_name: "com.android.myapex",
-			installable: true,
-			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
-			set: "myapex_compressed.apks",
-		}
-
-		prebuilt_bootclasspath_fragment {
-			name: "my-bootclasspath-fragment",
-			apex_available: [
-				"com.android.myapex",
-				"com.android.myapex_compressed",
-			],
-			hidden_api: {
-				annotation_flags: "annotation-flags.csv",
-				metadata: "metadata.csv",
-				index: "index.csv",
-				signature_patterns: "signature_patterns.csv",
-			},
-			%s
-		}
-	`
-
-	t.Run("java_import", func(t *testing.T) {
-		result := preparers.RunTestWithBp(t,
-			fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
-			java_import {
-				name: "libfoo",
-				jars: ["libfoo.jar"],
-				apex_available: [
-					"com.android.myapex",
-					"com.android.myapex_compressed",
-				],
-			}
-		`)
-
-		module := result.Module("libfoo", "android_common_com.android.myapex")
-		usesLibraryDep := module.(java.UsesLibraryDependency)
-		android.AssertPathRelativeToTopEquals(t, "dex jar path",
-			"out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
-			usesLibraryDep.DexJarBuildPath(errCtx).Path())
-	})
-
-	t.Run("java_sdk_library_import", func(t *testing.T) {
-		result := preparers.RunTestWithBp(t,
-			fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
-			java_sdk_library_import {
-				name: "libfoo",
-				public: {
-					jars: ["libbar.jar"],
-				},
-				apex_available: [
-					"com.android.myapex",
-					"com.android.myapex_compressed",
-				],
-				compile_dex: true,
-			}
-		`)
-
-		module := result.Module("libfoo", "android_common_com.android.myapex")
-		usesLibraryDep := module.(java.UsesLibraryDependency)
-		android.AssertPathRelativeToTopEquals(t, "dex jar path",
-			"out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
-			usesLibraryDep.DexJarBuildPath(errCtx).Path())
-	})
-
-	t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
-		_ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
-			image_name: "art",
-			contents: ["libfoo"],
-		`)+`
-			java_sdk_library_import {
-				name: "libfoo",
-				public: {
-					jars: ["libbar.jar"],
-				},
-				apex_available: [
-					"com.android.myapex",
-					"com.android.myapex_compressed",
-				],
-				compile_dex: true,
-			}
-		`)
-	})
-}
-
 func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
 	testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
 		apex {
@@ -8563,6 +8177,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "current",
 		}
 
 		systemserverclasspath_fragment {
@@ -8616,12 +8231,16 @@
 				},
 			}
 
-			java_import {
-				name: "libfoo",
+		java_sdk_library_import {
+			name: "libfoo",
+			prefer: true,
+			public: {
 				jars: ["libfoo.jar"],
-				apex_available: ["myapex"],
-				permitted_packages: ["libfoo"],
-			}
+			},
+			apex_available: ["myapex"],
+			shared_library: false,
+			permitted_packages: ["libfoo"],
+		}
 		`, "", preparer, fragment)
 	})
 }
@@ -9001,7 +8620,7 @@
 		}),
 	)
 
-	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("myapex", "android_common_myapex")
 
 	// Check extract_apks tool parameters.
 	extractedApex := m.Output("extracted/myapex.apks")
@@ -9042,7 +8661,7 @@
 		}),
 	)
 
-	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("myapex", "android_common_myapex")
 
 	// Check extract_apks tool parameters. No native bridge arch expected
 	extractedApex := m.Output("extracted/myapex.apks")
@@ -9605,6 +9224,7 @@
 			srcs: ["mybootclasspathlib.java"],
 			apex_available: ["myapex"],
 			compile_dex: true,
+			sdk_version: "current",
 		}
 
 		systemserverclasspath_fragment {
@@ -9728,42 +9348,6 @@
 	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex\n")
 }
 
-func TestAndroidMk_DexpreoptBuiltInstalledForApex_Prebuilt(t *testing.T) {
-	ctx := testApex(t, `
-		prebuilt_apex {
-			name: "myapex",
-			arch: {
-				arm64: {
-					src: "myapex-arm64.apex",
-				},
-				arm: {
-					src: "myapex-arm.apex",
-				},
-			},
-			exported_java_libs: ["foo"],
-		}
-
-		java_import {
-			name: "foo",
-			jars: ["foo.jar"],
-			apex_available: ["myapex"],
-		}
-	`,
-		dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
-	)
-
-	prebuilt := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*Prebuilt)
-	entriesList := android.AndroidMkEntriesForTest(t, ctx, prebuilt)
-	mainModuleEntries := entriesList[0]
-	android.AssertArrayString(t,
-		"LOCAL_REQUIRED_MODULES",
-		mainModuleEntries.EntryMap["LOCAL_REQUIRED_MODULES"],
-		[]string{
-			"foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex",
-			"foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex",
-		})
-}
-
 func TestAndroidMk_RequiredModules(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -9920,6 +9504,7 @@
 				unsafe_ignore_missing_latest_api: true,
 				min_sdk_version: "31",
 				static_libs: ["util"],
+				sdk_version: "core_current",
 			}
 
 			java_library {
@@ -9928,6 +9513,7 @@
 				apex_available: ["myapex"],
 				min_sdk_version: "31",
 				static_libs: ["another_util"],
+				sdk_version: "core_current",
 			}
 
 			java_library {
@@ -9935,6 +9521,7 @@
                 srcs: ["a.java"],
 				min_sdk_version: "31",
 				apex_available: ["myapex"],
+				sdk_version: "core_current",
 			}
 		`)
 	})
@@ -9990,7 +9577,7 @@
 	})
 
 	t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
-		preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
+		preparer.
 			RunTestWithBp(t, `
 				apex {
 					name: "myapex",
@@ -10021,6 +9608,8 @@
 					apex_available: ["myapex"],
 					compile_dex: true,
 					unsafe_ignore_missing_latest_api: true,
+					sdk_version: "current",
+					min_sdk_version: "30",
 				}
 		`)
 	})
@@ -10273,6 +9862,9 @@
 			key: "myapex.key",
 			bootclasspath_fragments: ["mybootclasspathfragment"],
 			min_sdk_version: "29",
+			java_libs: [
+				"jacocoagent",
+			],
 		}
 		apex_key {
 			name: "myapex.key",
@@ -10376,208 +9968,6 @@
 	}
 }
 
-func TestApexBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
-	bp := `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			native_shared_libs: ["libbaz"],
-			binaries: ["binfoo"],
-			min_sdk_version: "29",
-		}
-		apex_key {
-			name: "myapex.key",
-		}
-		cc_binary {
-			name: "binfoo",
-			shared_libs: ["libbar", "libbaz", "libqux",],
-			apex_available: ["myapex"],
-			min_sdk_version: "29",
-			recovery_available: false,
-		}
-		cc_library {
-			name: "libbar",
-			srcs: ["libbar.cc"],
-			stubs: {
-				symbol_file: "libbar.map.txt",
-				versions: [
-					"29",
-				],
-			},
-		}
-		cc_library {
-			name: "libbaz",
-			srcs: ["libbaz.cc"],
-			apex_available: ["myapex"],
-			min_sdk_version: "29",
-			stubs: {
-				symbol_file: "libbaz.map.txt",
-				versions: [
-					"29",
-				],
-			},
-		}
-		cc_api_library {
-			name: "libbar",
-			src: "libbar_stub.so",
-			min_sdk_version: "29",
-			variants: ["apex.29"],
-		}
-		cc_api_variant {
-			name: "libbar",
-			variant: "apex",
-			version: "29",
-			src: "libbar_apex_29.so",
-		}
-		cc_api_library {
-			name: "libbaz",
-			src: "libbaz_stub.so",
-			min_sdk_version: "29",
-			variants: ["apex.29"],
-		}
-		cc_api_variant {
-			name: "libbaz",
-			variant: "apex",
-			version: "29",
-			src: "libbaz_apex_29.so",
-		}
-		cc_api_library {
-			name: "libqux",
-			src: "libqux_stub.so",
-			min_sdk_version: "29",
-			variants: ["apex.29"],
-		}
-		cc_api_variant {
-			name: "libqux",
-			variant: "apex",
-			version: "29",
-			src: "libqux_apex_29.so",
-		}
-		api_imports {
-			name: "api_imports",
-			apex_shared_libs: [
-				"libbar",
-				"libbaz",
-				"libqux",
-			],
-		}
-		`
-	result := testApex(t, bp)
-
-	hasDep := func(m android.Module, wantDep android.Module) bool {
-		t.Helper()
-		var found bool
-		result.VisitDirectDeps(m, func(dep blueprint.Module) {
-			if dep == wantDep {
-				found = true
-			}
-		})
-		return found
-	}
-
-	// Library defines stubs and cc_api_library should be used with cc_api_library
-	binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Module()
-	libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
-	libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
-	android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
-
-	binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Rule("ld").Args["libFlags"]
-	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
-	android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
-	android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
-
-	// Library defined in the same APEX should be linked with original definition instead of cc_api_library
-	libbazApexVariant := result.ModuleForTests("libbaz", "android_arm64_armv8-a_shared_apex29").Module()
-	libbazApiImportCoreVariant := result.ModuleForTests("libbaz.apiimport", "android_arm64_armv8-a_shared").Module()
-	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even from same APEX", true, hasDep(binfooApexVariant, libbazApiImportCoreVariant))
-	android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbazApexVariant))
-
-	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbaz.so")
-	android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbaz.apiimport.so")
-	android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbaz.apex.29.apiimport.so")
-
-	// cc_api_library defined without original library should be linked with cc_api_library
-	libquxApiImportApexVariant := result.ModuleForTests("libqux.apiimport", "android_arm64_armv8-a_shared").Module()
-	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even original library definition does not exist", true, hasDep(binfooApexVariant, libquxApiImportApexVariant))
-	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libqux.apex.29.apiimport.so")
-}
-
-func TestPlatformBinaryBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
-	bp := `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			native_shared_libs: ["libbar"],
-			min_sdk_version: "29",
-		}
-		apex_key {
-			name: "myapex.key",
-		}
-		cc_binary {
-			name: "binfoo",
-			shared_libs: ["libbar"],
-			recovery_available: false,
-		}
-		cc_library {
-			name: "libbar",
-			srcs: ["libbar.cc"],
-			apex_available: ["myapex"],
-			min_sdk_version: "29",
-			stubs: {
-				symbol_file: "libbar.map.txt",
-				versions: [
-					"29",
-				],
-			},
-		}
-		cc_api_library {
-			name: "libbar",
-			src: "libbar_stub.so",
-			variants: ["apex.29"],
-		}
-		cc_api_variant {
-			name: "libbar",
-			variant: "apex",
-			version: "29",
-			src: "libbar_apex_29.so",
-		}
-		api_imports {
-			name: "api_imports",
-			apex_shared_libs: [
-				"libbar",
-			],
-		}
-		`
-
-	result := testApex(t, bp)
-
-	hasDep := func(m android.Module, wantDep android.Module) bool {
-		t.Helper()
-		var found bool
-		result.VisitDirectDeps(m, func(dep blueprint.Module) {
-			if dep == wantDep {
-				found = true
-			}
-		})
-		return found
-	}
-
-	// Library defines stubs and cc_api_library should be used with cc_api_library
-	binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Module()
-	libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
-	libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
-	android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
-
-	binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
-	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
-	android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
-	android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
-}
-
 func TestTrimmedApex(t *testing.T) {
 	bp := `
 		apex {
@@ -10616,21 +10006,6 @@
 			apex_available: ["myapex","mydcla"],
 			min_sdk_version: "29",
 		}
-		cc_api_library {
-			name: "libc",
-			src: "libc.so",
-			min_sdk_version: "29",
-			recovery_available: true,
-			vendor_available: true,
-			product_available: true,
-		}
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libc",
-			],
-			header_libs: [],
-		}
 		`
 	ctx := testApex(t, bp)
 	module := ctx.ModuleForTests("myapex", "android_common_myapex")
@@ -10902,14 +10277,14 @@
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 8 {
-		t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 12 {
+		t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 
-	ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
 
 	inputs := []string{
 		"my_aconfig_declarations_foo/intermediate.pb",
@@ -11037,14 +10412,14 @@
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 12 {
-		t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 16 {
+		t.Fatalf("Expected 16 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 
-	ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
 
 	inputs := []string{
 		"my_aconfig_declarations_foo/intermediate.pb",
@@ -11205,14 +10580,14 @@
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 32 {
-		t.Fatalf("Expected 28 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 36 {
+		t.Fatalf("Expected 36 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 
-	ensureMatches(t, copyCmds[28], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[29], "^cp -f .*/package.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[30], "^cp -f .*/flag.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[31], "^cp -f .*/flag.val .*/image.apex/etc$")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
 
 	inputs := []string{
 		"my_aconfig_declarations_foo/intermediate.pb",
@@ -11552,12 +10927,12 @@
 		{
 			desc:                      "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt",
 			selectedApexContributions: "foo.prebuilt.contributions",
-			expectedBootJar:           "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+			expectedBootJar:           "out/soong/.intermediates/prebuilt_com.android.foo/android_common_com.android.foo/deapexer/javalib/framework-foo.jar",
 		},
 		{
 			desc:                      "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt",
 			selectedApexContributions: "foo.prebuilt.v2.contributions",
-			expectedBootJar:           "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+			expectedBootJar:           "out/soong/.intermediates/com.android.foo.v2/android_common_com.android.foo/deapexer/javalib/framework-foo.jar",
 		},
 	}
 
@@ -12249,3 +11624,110 @@
 		)
 	})
 }
+
+func TestSdkLibraryTransitiveClassLoaderContext(t *testing.T) {
+	// This test case tests that listing the impl lib instead of the top level java_sdk_library
+	// in libs of android_app and java_library does not lead to class loader context device/host
+	// path mismatch errors.
+	android.GroupFixturePreparers(
+		prepareForApexTest,
+		android.PrepareForIntegrationTestWithAndroid,
+		PrepareForTestWithApexBuildComponents,
+		android.FixtureModifyEnv(func(env map[string]string) {
+			env["DISABLE_CONTAINER_CHECK"] = "true"
+		}),
+		withFiles(filesForSdkLibrary),
+		android.FixtureMergeMockFs(android.MockFS{
+			"system/sepolicy/apex/com.android.foo30-file_contexts": nil,
+		}),
+	).RunTestWithBp(t, `
+		apex {
+		name: "com.android.foo30",
+		key: "myapex.key",
+		updatable: true,
+		bootclasspath_fragments: [
+			"foo-bootclasspath-fragment",
+		],
+		java_libs: [
+			"bar",
+		],
+		apps: [
+			"bar-app",
+		],
+		min_sdk_version: "30",
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+		bootclasspath_fragment {
+			name: "foo-bootclasspath-fragment",
+			contents: [
+				"framework-foo",
+			],
+			apex_available: [
+				"com.android.foo30",
+			],
+			hidden_api: {
+				split_packages: ["*"]
+			},
+		}
+
+		java_sdk_library {
+			name: "framework-foo",
+			srcs: [
+				"A.java"
+			],
+			unsafe_ignore_missing_latest_api: true,
+			apex_available: [
+				"com.android.foo30",
+			],
+			compile_dex: true,
+			sdk_version: "core_current",
+			shared_library: false,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: [
+				"A.java"
+			],
+			libs: [
+				"framework-foo.impl",
+			],
+			apex_available: [
+				"com.android.foo30",
+			],
+			sdk_version: "core_current",
+		}
+
+		java_library {
+			name: "baz",
+			srcs: [
+				"A.java"
+			],
+			libs: [
+				"bar",
+			],
+			sdk_version: "core_current",
+		}
+
+		android_app {
+			name: "bar-app",
+			srcs: [
+				"A.java"
+			],
+			libs: [
+				"baz",
+				"framework-foo.impl",
+			],
+			apex_available: [
+				"com.android.foo30",
+			],
+			sdk_version: "core_current",
+			min_sdk_version: "30",
+			manifest: "AndroidManifest.xml",
+		}
+       `)
+}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 25131ee..e44d3f5 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -104,6 +104,7 @@
 			test: {
 				enabled: true,
 			},
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -397,11 +398,20 @@
 
 			// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
 			addPrebuilt(true, "foo", "bar"),
+			android.FixtureMergeMockFs(android.MockFS{
+				"apex_contributions/Android.bp": []byte(`
+				apex_contributions {
+					name: "prebuilt_art_contributions",
+					contents: ["prebuilt_com.android.art"],
+					api_domain: "com.android.art",
+				}
+			`)}),
+			android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
 
 			java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
 		).RunTest(t)
 
-		ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common", []string{
+		ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common_com.android.art", []string{
 			"etc/boot-image.prof",
 			"javalib/bar.jar",
 			"javalib/foo.jar",
@@ -494,6 +504,7 @@
 		java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
 		dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"),
 		java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
+		android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
 	)
 
 	bp := `
@@ -551,6 +562,12 @@
 			src: "com.mycompany.android.art.apex",
 			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 		}
+	
+		apex_contributions {
+			name: "prebuilt_art_contributions",
+			contents: ["prebuilt_com.android.art"],
+			api_domain: "com.android.art",
+		}
 	`
 
 	t.Run("disabled alternative APEX", func(t *testing.T) {
@@ -560,27 +577,18 @@
 			`all_apex_contributions`,
 			`dex2oatd`,
 			`prebuilt_art-bootclasspath-fragment`,
-			`prebuilt_com.android.art.apex.selector`,
-			`prebuilt_com.android.art.deapexer`,
 		})
 
 		java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
 			`all_apex_contributions`,
 			`dex2oatd`,
 			`prebuilt_bar`,
-			`prebuilt_com.android.art.deapexer`,
 			`prebuilt_foo`,
 		})
 
 		module := result.ModuleForTests("dex_bootjars", "android_common")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
-
-	t.Run("enabled alternative APEX", func(t *testing.T) {
-		preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
-			"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")).
-			RunTestWithBp(t, fmt.Sprintf(bp, ""))
-	})
 }
 
 // checkCopiesToPredefinedLocationForArt checks that the supplied modules are copied to the
@@ -749,6 +757,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library {
@@ -833,6 +842,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"art-bootclasspath-fragment",
 		"bar",
 		"dex2oatd",
@@ -922,6 +932,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1003,6 +1014,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"android-non-updatable.stubs",
 		"android-non-updatable.stubs.module_lib",
 		"android-non-updatable.stubs.system",
@@ -1093,6 +1105,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1174,6 +1187,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"android-non-updatable.stubs",
 		"android-non-updatable.stubs.system",
 		"android-non-updatable.stubs.test",
@@ -1245,6 +1259,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1326,6 +1341,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"art-bootclasspath-fragment",
 		"bar",
 		"dex2oatd",
diff --git a/apex/builder.go b/apex/builder.go
index 0d08483..437189f 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -83,6 +83,7 @@
 	pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf")
 	pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker")
 	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("host_apex_verifier", "host_apex_verifier")
 }
 
 type createStorageStruct struct {
@@ -249,6 +250,13 @@
 		Description: "run apex_linkerconfig_validation",
 	}, "image_dir")
 
+	apexHostVerifierRule = pctx.StaticRule("apexHostVerifierRule", blueprint.RuleParams{
+		Command: `${host_apex_verifier} --deapexer=${deapexer} --debugfs=${debugfs_static} ` +
+			`--fsckerofs=${fsck_erofs} --apex=${in} && touch ${out}`,
+		CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}"},
+		Description: "run host_apex_verifier",
+	})
+
 	assembleVintfRule = pctx.StaticRule("assembleVintfRule", blueprint.RuleParams{
 		Command:     `rm -f $out && VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i $in -o $out`,
 		CommandDeps: []string{"${assemble_vintf}"},
@@ -262,6 +270,58 @@
 	}, "tool_path", "unwanted")
 )
 
+func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile {
+	var aconfigFiles android.Paths
+	for _, file := range a.filesInfo {
+		if file.module == nil {
+			continue
+		}
+		if dep, ok := android.OtherModuleProvider(ctx, file.module, android.AconfigPropagatingProviderKey); ok {
+			if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
+				aconfigFiles = append(aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
+			}
+		}
+
+		validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
+		if validationFlag == "error" || validationFlag == "warning" {
+			android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), file.module, validationFlag == "error")
+		}
+	}
+	aconfigFiles = android.FirstUniquePaths(aconfigFiles)
+
+	var files []apexFile
+	if len(aconfigFiles) > 0 {
+		apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        aconfig.AllDeclarationsRule,
+			Inputs:      aconfigFiles,
+			Output:      apexAconfigFile,
+			Description: "combine_aconfig_declarations",
+			Args: map[string]string{
+				"cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "),
+			},
+		})
+		files = append(files, newApexFile(ctx, apexAconfigFile, "aconfig_flags", "etc", etc, nil))
+
+		for _, info := range createStorageInfo {
+			outputFile := android.PathForModuleOut(ctx, info.Output_file)
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        aconfig.CreateStorageRule,
+				Inputs:      aconfigFiles,
+				Output:      outputFile,
+				Description: info.Desc,
+				Args: map[string]string{
+					"container":   ctx.ModuleName(),
+					"file_type":   info.File_type,
+					"cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "),
+				},
+			})
+			files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, nil))
+		}
+	}
+	return files
+}
+
 // buildManifest creates buile rules to modify the input apex_manifest.json to add information
 // gathered by the build system such as provided/required native libraries. Two output files having
 // different formats are generated. a.manifestJsonOut is JSON format for Q devices, and
@@ -644,48 +704,10 @@
 	outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
 
-	defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
-	aconfigDest := imageDir.Join(ctx, "etc").String()
-	if len(a.aconfigFiles) > 0 {
-		apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        aconfig.AllDeclarationsRule,
-			Inputs:      a.aconfigFiles,
-			Output:      apexAconfigFile,
-			Description: "combine_aconfig_declarations",
-			Args: map[string]string{
-				"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
-			},
-		})
-
-		copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest)
-		implicitInputs = append(implicitInputs, apexAconfigFile)
-		defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base())
-
-		for _, info := range createStorageInfo {
-			outputFile := android.PathForModuleOut(ctx, info.Output_file)
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        aconfig.CreateStorageRule,
-				Inputs:      a.aconfigFiles,
-				Output:      outputFile,
-				Description: info.Desc,
-				Args: map[string]string{
-					"container":   ctx.ModuleName(),
-					"file_type":   info.File_type,
-					"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
-				},
-			})
-
-			copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest)
-			implicitInputs = append(implicitInputs, outputFile)
-			defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base())
-		}
-	}
-
 	////////////////////////////////////////////////////////////////////////////////////
 	// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
 	// in this APEX. The file will be used by apexer in later steps.
-	cannedFsConfig := a.buildCannedFsConfig(ctx, defaultReadOnlyFiles)
+	cannedFsConfig := a.buildCannedFsConfig(ctx)
 	implicitInputs = append(implicitInputs, cannedFsConfig)
 
 	////////////////////////////////////////////////////////////////////////////////////
@@ -952,6 +974,9 @@
 		validations = append(validations,
 			runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
 	}
+	if !a.testApex && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
+		validations = append(validations, runApexHostVerifier(ctx, unsignedOutputFile.OutputPath))
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "signapk",
@@ -1139,8 +1164,8 @@
 	a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
 }
 
-func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext, defaultReadOnlyFiles []string) android.OutputPath {
-	var readOnlyPaths = defaultReadOnlyFiles
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
+	var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
 	var executablePaths []string // this also includes dirs
 	var appSetDirs []string
 	appSetFiles := make(map[string]android.Path)
@@ -1246,3 +1271,13 @@
 	})
 	return timestamp
 }
+
+func runApexHostVerifier(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "host_apex_verifier.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexHostVerifierRule,
+		Input:  apexFile,
+		Output: timestamp,
+	})
+	return timestamp
+}
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index b9a9198..9e1ac94 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -92,6 +92,7 @@
 			],
 			srcs: ["b.java"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
diff --git a/apex/container_test.go b/apex/container_test.go
index 3931174..d28b1a6 100644
--- a/apex/container_test.go
+++ b/apex/container_test.go
@@ -30,7 +30,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForApexTest,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+		java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -68,16 +68,17 @@
 			],
 			compile_dex: true,
 			static_libs: [
-				"foo",
+				"food",
 				"baz",
 			],
 			libs: [
-				"bar",
+				"bar.stubs",
 			],
 			min_sdk_version: "30",
+			sdk_version: "current",
 		}
 		java_library {
-			name: "foo",
+			name: "food",
 			srcs:[
 				"A.java",
 			],
@@ -85,13 +86,15 @@
 				"myapex",
 			],
 			min_sdk_version: "30",
+			sdk_version: "core_current",
 		}
-		java_library {
+		java_sdk_library {
 			name: "bar",
 			srcs:[
 				"A.java",
 			],
 			min_sdk_version: "30",
+			sdk_version: "core_current",
 		}
 		java_library {
 			name: "baz",
@@ -103,6 +106,7 @@
 				"myapex",
 			],
 			min_sdk_version: "30",
+			sdk_version: "core_current",
 		}
 	`)
 	testcases := []struct {
@@ -130,7 +134,7 @@
 			isApexContainer:   false,
 		},
 		{
-			moduleName:        "foo",
+			moduleName:        "food",
 			variant:           "android_common_apex30",
 			isSystemContainer: true,
 			isApexContainer:   true,
@@ -162,7 +166,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForApexTest,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+		java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -199,26 +203,30 @@
 			],
 			compile_dex: true,
 			static_libs: [
-				"foo",
+				"food",
 			],
 			libs: [
-				"bar",
+				"bar.stubs",
 			],
+			sdk_version: "current",
 		}
 		java_library {
-			name: "foo",
+			name: "food",
 			srcs:[
 				"A.java",
 			],
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "core_current",
 		}
-		java_library {
+		java_sdk_library {
 			name: "bar",
 			srcs:[
 				"A.java",
 			],
+			sdk_version: "none",
+			system_modules: "none",
 		}
 	`)
 	testcases := []struct {
@@ -246,7 +254,7 @@
 			isApexContainer:   false,
 		},
 		{
-			moduleName:        "foo",
+			moduleName:        "food",
 			variant:           "android_common_apex10000",
 			isSystemContainer: true,
 			isApexContainer:   true,
diff --git a/apex/deapexer.go b/apex/deapexer.go
index a673108..3b8233d 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -15,37 +15,9 @@
 package apex
 
 import (
-	"strings"
-
 	"android/soong/android"
 )
 
-// Contains 'deapexer' a private module type used by 'prebuilt_apex' to make dex files contained
-// within a .apex file referenced by `prebuilt_apex` available for use by their associated
-// `java_import` modules.
-//
-// An 'apex' module references `java_library` modules from which .dex files are obtained that are
-// stored in the resulting `.apex` file. The resulting `.apex` file is then made available as a
-// prebuilt by referencing it from a `prebuilt_apex`. For each such `java_library` that is used by
-// modules outside the `.apex` file a `java_import` prebuilt is made available referencing a jar
-// that contains the Java classes.
-//
-// When building a Java module type, e.g. `java_module` or `android_app` against such prebuilts the
-// `java_import` provides the classes jar  (jar containing `.class` files) against which the
-// module's `.java` files are compiled. That classes jar usually contains only stub classes. The
-// resulting classes jar is converted into a dex jar (jar containing `.dex` files). Then if
-// necessary the dex jar is further processed by `dexpreopt` to produce an optimized form of the
-// library specific to the current Android version. This process requires access to implementation
-// dex jars for each `java_import`. The `java_import` will obtain the implementation dex jar from
-// the `.apex` file in the associated `prebuilt_apex`.
-//
-// This is intentionally not registered by name as it is not intended to be used from within an
-// `Android.bp` file.
-
-// DeapexerProperties specifies the properties supported by the deapexer module.
-//
-// As these are never intended to be supplied in a .bp file they use a different naming convention
-// to make it clear that they are different.
 type DeapexerProperties struct {
 	// List of common modules that may need access to files exported by this module.
 	//
@@ -72,46 +44,9 @@
 	Selected_apex *string `android:"path" blueprint:"mutated"`
 }
 
-type Deapexer struct {
-	android.ModuleBase
-
-	properties             DeapexerProperties
-	selectedApexProperties SelectedApexProperties
-
-	inputApex android.Path
-}
-
-// Returns the name of the deapexer module corresponding to an APEX module with the given name.
-func deapexerModuleName(apexModuleName string) string {
-	return apexModuleName + ".deapexer"
-}
-
-// Returns the name of the APEX module corresponding to an deapexer module with
-// the given name. This reverses deapexerModuleName.
-func apexModuleName(deapexerModuleName string) string {
-	return strings.TrimSuffix(deapexerModuleName, ".deapexer")
-}
-
-func privateDeapexerFactory() android.Module {
-	module := &Deapexer{}
-	module.AddProperties(&module.properties, &module.selectedApexProperties)
-	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
-	return module
-}
-
-func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
-	// Add dependencies from the java modules to which this exports files from the `.apex` file onto
-	// this module so that they can access the `DeapexerInfo` object that this provides.
-	// TODO: b/308174306 - Once all the mainline modules have been flagged, drop this dependency edge
-	for _, lib := range p.properties.CommonModules {
-		dep := prebuiltApexExportedModuleName(ctx, lib)
-		ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
-	}
-}
-
-func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
-
+// deapex creates the build rules to deapex a prebuilt .apex file
+// it returns a pointer to a DeapexerInfo object
+func deapex(ctx android.ModuleContext, apexFile android.Path, deapexerProps DeapexerProperties) *android.DeapexerInfo {
 	// Create and remember the directory into which the .apex file's contents will be unpacked.
 	deapexerOutput := android.PathForModuleOut(ctx, "deapexer")
 
@@ -119,7 +54,7 @@
 
 	// Create mappings from apex relative path to the extracted file's path.
 	exportedPaths := make(android.Paths, 0, len(exports))
-	for _, path := range p.properties.ExportedFiles {
+	for _, path := range deapexerProps.ExportedFiles {
 		// Populate the exports that this makes available.
 		extractedPath := deapexerOutput.Join(ctx, path)
 		exports[path] = extractedPath
@@ -131,9 +66,8 @@
 	// apex relative path to extracted file path available for other modules.
 	if len(exports) > 0 {
 		// Make the information available for other modules.
-		di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports, p.properties.CommonModules)
-		di.AddDexpreoptProfileGuidedExportedModuleNames(p.properties.DexpreoptProfileGuidedModules...)
-		android.SetProvider(ctx, android.DeapexerProvider, di)
+		di := android.NewDeapexerInfo(ctx.ModuleName(), exports, deapexerProps.CommonModules)
+		di.AddDexpreoptProfileGuidedExportedModuleNames(deapexerProps.DexpreoptProfileGuidedModules...)
 
 		// Create a sorted list of the files that this exports.
 		exportedPaths = android.SortedUniquePaths(exportedPaths)
@@ -147,11 +81,13 @@
 			BuiltTool("deapexer").
 			BuiltTool("debugfs").
 			BuiltTool("fsck.erofs").
-			Input(p.inputApex).
+			Input(apexFile).
 			Text(deapexerOutput.String())
 		for _, p := range exportedPaths {
 			command.Output(p.(android.WritablePath))
 		}
-		builder.Build("deapexer", "deapex "+apexModuleName(ctx.ModuleName()))
+		builder.Build("deapexer", "deapex "+ctx.ModuleName())
+		return &di
 	}
+	return nil
 }
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index d8ee4ba..4feade8 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -127,16 +127,29 @@
 			src: "com.android.art-arm.apex",
 			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 		}
+
+		apex_contributions {
+			name: "prebuilt_art_contributions",
+			contents: ["prebuilt_com.android.art"],
+			api_domain: "com.android.art",
+		}
 	`
 
-	result := android.GroupFixturePreparers(
+	fixture := android.GroupFixturePreparers(
 		java.PrepareForTestWithDexpreopt,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo"),
 		java.FixtureConfigureBootJars("com.android.art:core-oj", "platform:foo", "system_ext:bar", "platform:baz"),
 		PrepareForTestWithApexBuildComponents,
 		prepareForTestWithArtApex,
-	).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
+	)
+	if preferPrebuilt {
+		fixture = android.GroupFixturePreparers(
+			fixture,
+			android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
+		)
+	}
+	result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
 
 	dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
 	rule := dexBootJars.Output(ruleFile)
@@ -200,7 +213,7 @@
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
 		"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/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof",
 		"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
 		"out/soong/dexpreopt/uffd_gc_flag.txt",
 	}
@@ -384,12 +397,12 @@
 		{
 			desc:                         "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt",
 			selectedArtApexContributions: "art.prebuilt.contributions",
-			expectedProfile:              "out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
+			expectedProfile:              "out/soong/.intermediates/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof",
 		},
 		{
 			desc:                         "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt",
 			selectedArtApexContributions: "art.prebuilt.v2.contributions",
-			expectedProfile:              "out/soong/.intermediates/prebuilt_com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
+			expectedProfile:              "out/soong/.intermediates/com.android.art.v2/android_common_com.android.art/deapexer/etc/boot-image.prof",
 		},
 	}
 	for _, tc := range testCases {
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 17ade1d..9c2d899 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -293,6 +293,7 @@
 			],
 			srcs: ["b.java"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		// Add a java_import that is not preferred and so won't have an appropriate apex variant created
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index f1a134e..d3f14f9 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -107,11 +107,6 @@
 	// from PRODUCT_PACKAGES.
 	Overrides []string
 
-	// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
-	// APEX bundle will create an APEX variant and provide dex implementation jars for use by
-	// dexpreopt and boot jars package check.
-	Exported_java_libs []string
-
 	// List of bootclasspath fragments inside this prebuilt APEX bundle and for which this APEX
 	// bundle will create an APEX variant.
 	Exported_bootclasspath_fragments []string
@@ -199,9 +194,8 @@
 }
 
 // If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex
-func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
-	// If this apex does not export anything, return
-	if !p.hasExportedDeps() {
+func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext, di *android.DeapexerInfo) {
+	if di == nil {
 		return
 	}
 	// If this prebuilt apex has not been selected, return
@@ -210,10 +204,7 @@
 	}
 	// Use apex_name to determine the api domain of this prebuilt apex
 	apexName := p.ApexVariationName()
-	di, err := android.FindDeapexerProviderForModule(ctx)
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-	}
+	// TODO: do not compute twice
 	dc := dexpreopt.GetGlobalConfig(ctx)
 	systemServerJarList := dc.AllApexSystemServerJars(ctx)
 
@@ -262,10 +253,12 @@
 	return entriesList
 }
 
+// DEPRECATED. // TODO (spandandas): Remove this interface.
+
 // prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and
 // apex_set in order to create the modules needed to provide access to the prebuilt .apex file.
 type prebuiltApexModuleCreator interface {
-	createPrebuiltApexModules(ctx android.TopDownMutatorContext)
+	createPrebuiltApexModules(ctx android.BottomUpMutatorContext)
 }
 
 // prebuiltApexModuleCreatorMutator is the mutator responsible for invoking the
@@ -275,7 +268,7 @@
 // will need to access dependencies added by that (exported modules) but must run before the
 // DepsMutator so that the deapexer module it creates can add dependencies onto itself from the
 // exported modules.
-func prebuiltApexModuleCreatorMutator(ctx android.TopDownMutatorContext) {
+func prebuiltApexModuleCreatorMutator(ctx android.BottomUpMutatorContext) {
 	module := ctx.Module()
 	if creator, ok := module.(prebuiltApexModuleCreator); ok {
 		creator.createPrebuiltApexModules(ctx)
@@ -283,8 +276,7 @@
 }
 
 func (p *prebuiltCommon) hasExportedDeps() bool {
-	return len(p.prebuiltCommonProperties.Exported_java_libs) > 0 ||
-		len(p.prebuiltCommonProperties.Exported_bootclasspath_fragments) > 0 ||
+	return len(p.prebuiltCommonProperties.Exported_bootclasspath_fragments) > 0 ||
 		len(p.prebuiltCommonProperties.Exported_systemserverclasspath_fragments) > 0
 }
 
@@ -292,11 +284,6 @@
 func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorContext) {
 	module := ctx.Module()
 
-	for _, dep := range p.prebuiltCommonProperties.Exported_java_libs {
-		prebuiltDep := android.PrebuiltNameFromSource(dep)
-		ctx.AddDependency(module, exportedJavaLibTag, prebuiltDep)
-	}
-
 	for _, dep := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments {
 		prebuiltDep := android.PrebuiltNameFromSource(dep)
 		ctx.AddDependency(module, exportedBootclasspathFragmentTag, prebuiltDep)
@@ -414,34 +401,6 @@
 	}
 }
 
-// prebuiltApexSelectorModule is a private module type that is only created by the prebuilt_apex
-// module. It selects the apex to use and makes it available for use by prebuilt_apex and the
-// deapexer.
-type prebuiltApexSelectorModule struct {
-	android.ModuleBase
-
-	apexFileProperties ApexFileProperties
-
-	inputApex android.Path
-}
-
-func privateApexSelectorModuleFactory() android.Module {
-	module := &prebuiltApexSelectorModule{}
-	module.AddProperties(
-		&module.apexFileProperties,
-	)
-	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
-	return module
-}
-
-func (p *prebuiltApexSelectorModule) Srcs() android.Paths {
-	return android.Paths{p.inputApex}
-}
-
-func (p *prebuiltApexSelectorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	p.inputApex = android.SingleSourcePathFromSupplier(ctx, p.apexFileProperties.prebuiltApexSelector, "src")
-}
-
 type Prebuilt struct {
 	prebuiltCommon
 
@@ -484,11 +443,11 @@
 // to use methods on it that are specific to the current module.
 //
 // See the ApexFileProperties.Src property.
-func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext, prebuilt android.Module) []string {
+func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext, prebuilt android.Module) string {
 	multiTargets := prebuilt.MultiTargets()
 	if len(multiTargets) != 1 {
 		ctx.OtherModuleErrorf(prebuilt, "compile_multilib shouldn't be \"both\" for prebuilt_apex")
-		return nil
+		return ""
 	}
 	var src string
 	switch multiTargets[0].Arch.ArchType {
@@ -521,7 +480,7 @@
 		// logic from reporting a more general, less useful message.
 	}
 
-	return []string{src}
+	return src
 }
 
 type PrebuiltProperties struct {
@@ -538,35 +497,19 @@
 func PrebuiltFactory() android.Module {
 	module := &Prebuilt{}
 	module.AddProperties(&module.properties)
-	module.initPrebuiltCommon(module, &module.properties.PrebuiltCommonProperties)
+	module.prebuiltCommon.prebuiltCommonProperties = &module.properties.PrebuiltCommonProperties
+
+	// init the module as a prebuilt
+	// even though this module type has srcs, use `InitPrebuiltModuleWithoutSrcs`, since the existing
+	// InitPrebuiltModule* are not friendly with Sources of Configurable type.
+	// The actual src will be evaluated in GenerateAndroidBuildActions.
+	android.InitPrebuiltModuleWithoutSrcs(module)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 
 	return module
 }
 
-func createApexSelectorModule(ctx android.TopDownMutatorContext, name string, apexFileProperties *ApexFileProperties) {
-	props := struct {
-		Name *string
-	}{
-		Name: proptools.StringPtr(name),
-	}
-
-	ctx.CreateModule(privateApexSelectorModuleFactory,
-		&props,
-		apexFileProperties,
-	)
-}
-
-// createDeapexerModuleIfNeeded will create a deapexer module if it is needed.
-//
-// A deapexer module is only needed when the prebuilt apex specifies one or more modules in either
-// the `exported_java_libs` or `exported_bootclasspath_fragments` properties as that indicates that
-// the listed modules need access to files from within the prebuilt .apex file.
-func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string) {
-	// Only create the deapexer module if it is needed.
-	if !p.hasExportedDeps() {
-		return
-	}
-
+func (p *prebuiltCommon) getDeapexerPropertiesIfNeeded(ctx android.ModuleContext) DeapexerProperties {
 	// Compute the deapexer properties from the transitive dependencies of this module.
 	commonModules := []string{}
 	dexpreoptProfileGuidedModules := []string{}
@@ -600,7 +543,7 @@
 	})
 
 	// Create properties for deapexer module.
-	deapexerProperties := &DeapexerProperties{
+	deapexerProperties := DeapexerProperties{
 		// Remove any duplicates from the common modules lists as a module may be included via a direct
 		// dependency as well as transitive ones.
 		CommonModules:                 android.SortedUniqueStrings(commonModules),
@@ -609,22 +552,7 @@
 
 	// Populate the exported files property in a fixed order.
 	deapexerProperties.ExportedFiles = android.SortedUniqueStrings(exportedFiles)
-
-	props := struct {
-		Name          *string
-		Selected_apex *string
-	}{
-		Name:          proptools.StringPtr(deapexerName),
-		Selected_apex: proptools.StringPtr(apexFileSource),
-	}
-	ctx.CreateModule(privateDeapexerFactory,
-		&props,
-		deapexerProperties,
-	)
-}
-
-func apexSelectorModuleName(baseModuleName string) string {
-	return baseModuleName + ".apex.selector"
+	return deapexerProperties
 }
 
 func prebuiltApexExportedModuleName(ctx android.BottomUpMutatorContext, name string) string {
@@ -666,97 +594,50 @@
 var _ android.RequiresFilesFromPrebuiltApexTag = exportedDependencyTag{}
 
 var (
-	exportedJavaLibTag                       = exportedDependencyTag{name: "exported_java_libs"}
 	exportedBootclasspathFragmentTag         = exportedDependencyTag{name: "exported_bootclasspath_fragments"}
 	exportedSystemserverclasspathFragmentTag = exportedDependencyTag{name: "exported_systemserverclasspath_fragments"}
 )
 
-var _ prebuiltApexModuleCreator = (*Prebuilt)(nil)
-
-// createPrebuiltApexModules creates modules necessary to export files from the prebuilt apex to the
-// build.
-//
-// If this needs to make files from within a `.apex` file available for use by other Soong modules,
-// e.g. make dex implementation jars available for java_import modules listed in exported_java_libs,
-// it does so as follows:
-//
-//  1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
-//     makes them available for use by other modules, at both Soong and ninja levels.
-//
-//  2. It adds a dependency onto those modules and creates an apex specific variant similar to what
-//     an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
-//     dexpreopt, will work the same way from source and prebuilt.
-//
-//  3. The `deapexer` module adds a dependency from the modules that require the exported files onto
-//     itself so that they can retrieve the file paths to those files.
-//
-// It also creates a child module `selector` that is responsible for selecting the appropriate
-// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
-//
-//  1. To dedup the selection logic so it only runs in one module.
-//
-//  2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
-//     `apex_set`.
-//
-//     prebuilt_apex
-//     /      |      \
-//     /         |         \
-//     V            V            V
-//     selector  <---  deapexer  <---  exported java lib
-func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
-	apexSelectorModuleName := apexSelectorModuleName(p.Name())
-	createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
-
-	apexFileSource := ":" + apexSelectorModuleName
-	p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(p.Name()), apexFileSource)
-
-	// Add a source reference to retrieve the selected apex from the selector module.
-	p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
-}
-
 func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
 	p.prebuiltApexContentsDeps(ctx)
 }
 
-func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if p.hasExportedDeps() {
-		// Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
-		// The deapexer will return a provider which will be used to determine the exported artfifacts from this prebuilt.
-		ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.Name()))
-	}
-}
-
 var _ ApexInfoMutator = (*Prebuilt)(nil)
 
 func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
 	p.apexInfoMutator(mctx)
 }
 
+// creates the build rules to deapex the prebuilt, and returns a deapexerInfo
+func (p *prebuiltCommon) getDeapexerInfo(ctx android.ModuleContext, apexFile android.Path) *android.DeapexerInfo {
+	if !p.hasExportedDeps() {
+		// nothing to do
+		return nil
+	}
+	deapexerProps := p.getDeapexerPropertiesIfNeeded(ctx)
+	return deapex(ctx, apexFile, deapexerProps)
+}
+
 // Set a provider containing information about the jars and .prof provided by the apex
 // Apexes built from prebuilts retrieve this information by visiting its internal deapexer module
 // Used by dex_bootjars to generate the boot image
-func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext) {
-	if !p.hasExportedDeps() {
-		// nothing to do
+func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext, di *android.DeapexerInfo) {
+	if di == nil {
 		return
 	}
-	if di, err := android.FindDeapexerProviderForModule(ctx); err == nil {
-		javaModuleToDexPath := map[string]android.Path{}
-		for _, commonModule := range di.GetExportedModuleNames() {
-			if dex := di.PrebuiltExportPath(java.ApexRootRelativePathToJavaLib(commonModule)); dex != nil {
-				javaModuleToDexPath[commonModule] = dex
-			}
+	javaModuleToDexPath := map[string]android.Path{}
+	for _, commonModule := range di.GetExportedModuleNames() {
+		if dex := di.PrebuiltExportPath(java.ApexRootRelativePathToJavaLib(commonModule)); dex != nil {
+			javaModuleToDexPath[commonModule] = dex
 		}
-
-		exports := android.ApexExportsInfo{
-			ApexName:                      p.ApexVariationName(),
-			ProfilePathOnHost:             di.PrebuiltExportPath(java.ProfileInstallPathInApex),
-			LibraryNameToDexJarPathOnHost: javaModuleToDexPath,
-		}
-		android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
-	} else {
-		ctx.ModuleErrorf(err.Error())
 	}
+
+	exports := android.ApexExportsInfo{
+		ApexName:                      p.ApexVariationName(),
+		ProfilePathOnHost:             di.PrebuiltExportPath(java.ProfileInstallPathInApex),
+		LibraryNameToDexJarPathOnHost: javaModuleToDexPath,
+	}
+	android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
 }
 
 // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
@@ -792,7 +673,7 @@
 
 	p.apexKeysPath = writeApexKeys(ctx, p)
 	// TODO(jungjw): Check the key validity.
-	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
+	p.inputApex = android.PathForModuleSrc(ctx, p.properties.prebuiltApexSelector(ctx, ctx.Module()))
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
 	p.installFilename = p.InstallFilename()
 	if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
@@ -810,11 +691,13 @@
 		return
 	}
 
+	deapexerInfo := p.getDeapexerInfo(ctx, p.inputApex)
+
 	// dexpreopt any system server jars if present
-	p.dexpreoptSystemServerJars(ctx)
+	p.dexpreoptSystemServerJars(ctx, deapexerInfo)
 
 	// provide info used for generating the boot image
-	p.provideApexExportsInfo(ctx)
+	p.provideApexExportsInfo(ctx, deapexerInfo)
 
 	p.providePrebuiltInfo(ctx)
 
@@ -850,26 +733,11 @@
 	extractedApex android.WritablePath
 }
 
-func privateApexExtractorModuleFactory() android.Module {
-	module := &prebuiltApexExtractorModule{}
-	module.AddProperties(
-		&module.properties,
-	)
-	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
-	return module
-}
-
-func (p *prebuiltApexExtractorModule) Srcs() android.Paths {
-	return android.Paths{p.extractedApex}
-}
-
-func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	srcsSupplier := func(ctx android.BaseModuleContext, prebuilt android.Module) []string {
-		return p.properties.prebuiltSrcs(ctx)
-	}
+// extract registers the build actions to extract an apex from .apks file
+// returns the path of the extracted apex
+func extract(ctx android.ModuleContext, apexSet android.Path, prerelease *bool) android.Path {
 	defaultAllowPrerelease := ctx.Config().IsEnvTrue("SOONG_ALLOW_PRERELEASE_APEXES")
-	apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set")
-	p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base())
+	extractedApex := android.PathForModuleOut(ctx, "extracted", apexSet.Base())
 	// Filter out NativeBridge archs (b/260115309)
 	abis := java.SupportedAbis(ctx, true)
 	ctx.Build(pctx,
@@ -877,14 +745,16 @@
 			Rule:        extractMatchingApex,
 			Description: "Extract an apex from an apex set",
 			Inputs:      android.Paths{apexSet},
-			Output:      p.extractedApex,
+			Output:      extractedApex,
 			Args: map[string]string{
 				"abis":              strings.Join(abis, ","),
-				"allow-prereleased": strconv.FormatBool(proptools.BoolDefault(p.properties.Prerelease, defaultAllowPrerelease)),
+				"allow-prereleased": strconv.FormatBool(proptools.BoolDefault(prerelease, defaultAllowPrerelease)),
 				"sdk-version":       ctx.Config().PlatformSdkVersion().String(),
 				"skip-sdk-check":    strconv.FormatBool(ctx.Config().IsEnvTrue("SOONG_SKIP_APPSET_SDK_CHECK")),
 			},
-		})
+		},
+	)
+	return extractedApex
 }
 
 type ApexSet struct {
@@ -953,48 +823,18 @@
 func apexSetFactory() android.Module {
 	module := &ApexSet{}
 	module.AddProperties(&module.properties)
-	module.initPrebuiltCommon(module, &module.properties.PrebuiltCommonProperties)
+	module.prebuiltCommon.prebuiltCommonProperties = &module.properties.PrebuiltCommonProperties
+
+	// init the module as a prebuilt
+	// even though this module type has srcs, use `InitPrebuiltModuleWithoutSrcs`, since the existing
+	// InitPrebuiltModule* are not friendly with Sources of Configurable type.
+	// The actual src will be evaluated in GenerateAndroidBuildActions.
+	android.InitPrebuiltModuleWithoutSrcs(module)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 
 	return module
 }
 
-func createApexExtractorModule(ctx android.TopDownMutatorContext, name string, apexExtractorProperties *ApexExtractorProperties) {
-	props := struct {
-		Name *string
-	}{
-		Name: proptools.StringPtr(name),
-	}
-
-	ctx.CreateModule(privateApexExtractorModuleFactory,
-		&props,
-		apexExtractorProperties,
-	)
-}
-
-func apexExtractorModuleName(baseModuleName string) string {
-	return baseModuleName + ".apex.extractor"
-}
-
-var _ prebuiltApexModuleCreator = (*ApexSet)(nil)
-
-// createPrebuiltApexModules creates modules necessary to export files from the apex set to other
-// modules.
-//
-// This effectively does for apex_set what Prebuilt.createPrebuiltApexModules does for a
-// prebuilt_apex except that instead of creating a selector module which selects one .apex file
-// from those provided this creates an extractor module which extracts the appropriate .apex file
-// from the zip file containing them.
-func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
-	apexExtractorModuleName := apexExtractorModuleName(a.Name())
-	createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
-
-	apexFileSource := ":" + apexExtractorModuleName
-	a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(a.Name()), apexFileSource)
-
-	// After passing the arch specific src properties to the creating the apex selector module
-	a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
-}
-
 func (a *ApexSet) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
 	a.prebuiltApexContentsDeps(ctx)
 }
@@ -1017,7 +857,15 @@
 		ctx.ModuleErrorf("filename should end in %s or %s for apex_set", imageApexSuffix, imageCapexSuffix)
 	}
 
-	inputApex := android.OptionalPathForModuleSrc(ctx, a.prebuiltCommonProperties.Selected_apex).Path()
+	var apexSet android.Path
+	if srcs := a.properties.prebuiltSrcs(ctx); len(srcs) == 1 {
+		apexSet = android.PathForModuleSrc(ctx, srcs[0])
+	} else {
+		ctx.ModuleErrorf("Expected exactly one source apex_set file, found %v\n", srcs)
+	}
+
+	extractedApex := extract(ctx, apexSet, a.properties.Prerelease)
+
 	a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
 
 	// Build the output APEX. If compression is not enabled, make sure the output is not compressed even if the input is compressed
@@ -1027,7 +875,7 @@
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   buildRule,
-		Input:  inputApex,
+		Input:  extractedApex,
 		Output: a.outputApex,
 	})
 
@@ -1036,11 +884,13 @@
 		return
 	}
 
+	deapexerInfo := a.getDeapexerInfo(ctx, extractedApex)
+
 	// dexpreopt any system server jars if present
-	a.dexpreoptSystemServerJars(ctx)
+	a.dexpreoptSystemServerJars(ctx, deapexerInfo)
 
 	// provide info used for generating the boot image
-	a.provideApexExportsInfo(ctx)
+	a.provideApexExportsInfo(ctx, deapexerInfo)
 
 	a.providePrebuiltInfo(ctx)
 
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 452a43e..acb3649 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -80,6 +80,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "core_current",
 		}
 
 		systemserverclasspath_fragment {
@@ -276,8 +277,6 @@
 	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
 		`all_apex_contributions`,
 		`dex2oatd`,
-		`prebuilt_myapex.apex.selector`,
-		`prebuilt_myapex.deapexer`,
 		`prebuilt_mysystemserverclasspathfragment`,
 	})
 
@@ -285,10 +284,9 @@
 		`all_apex_contributions`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
-		`prebuilt_myapex.deapexer`,
 	})
 
-	ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
+	ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 		"javalib/bar.jar",
 		"javalib/bar.jar.prof",
@@ -350,6 +348,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "core_current",
 		}
 
 		systemserverclasspath_fragment {
@@ -437,10 +436,9 @@
 		`all_apex_contributions`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
-		`prebuilt_myapex.deapexer`,
 	})
 
-	ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
+	ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 		"javalib/bar.jar",
 		"javalib/bar.jar.prof",
diff --git a/apex/vndk.go b/apex/vndk.go
index 781aa3c..3ececc5 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -54,30 +54,6 @@
 	Vndk_version *string
 }
 
-func apexVndkMutator(mctx android.TopDownMutatorContext) {
-	if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
-		if ab.IsNativeBridgeSupported() {
-			mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
-		}
-
-		vndkVersion := ab.vndkVersion()
-		if vndkVersion != "" {
-			apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
-			if err != nil {
-				mctx.PropertyErrorf("vndk_version", "%s", err.Error())
-				return
-			}
-
-			targets := mctx.MultiTargets()
-			if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
-				// Disable VNDK APEXes for VNDK versions less than the minimum supported API
-				// level for the primary architecture.
-				ab.Disable()
-			}
-		}
-	}
-}
-
 func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
 		vndkVersion := m.VndkVersion()
@@ -93,8 +69,27 @@
 			mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName)
 		}
 	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
-		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
-		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...)
+		if a.IsNativeBridgeSupported() {
+			mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
+		}
+
+		vndkVersion := a.vndkVersion()
+		if vndkVersion != "" {
+			apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
+			if err != nil {
+				mctx.PropertyErrorf("vndk_version", "%s", err.Error())
+				return
+			}
+
+			targets := mctx.MultiTargets()
+			if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
+				// Disable VNDK APEXes for VNDK versions less than the minimum supported API
+				// level for the primary architecture.
+				a.Disable()
+			} else {
+				mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...)
+			}
+		}
 	}
 }
 
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 73c8800..8679821 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -56,6 +56,7 @@
 )
 
 func registerBpfBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("bpf_defaults", defaultsFactory)
 	ctx.RegisterModuleType("bpf", BpfFactory)
 }
 
@@ -77,10 +78,16 @@
 	// the C/C++ module.
 	Cflags []string
 
-	// directories (relative to the root of the source tree) that will
-	// be added to the include paths using -I.
+	// list of directories relative to the root of the source tree that
+	// will be added to the include paths using -I.
+	// If possible, don't use this. If adding paths from the current
+	// directory, use local_include_dirs. If adding paths from other
+	// modules, use export_include_dirs in that module.
 	Include_dirs []string
 
+	// list of directories relative to the Blueprint file that will be
+	// added to the include path using -I.
+	Local_include_dirs []string
 	// optional subdirectory under which this module is installed into.
 	Sub_dir string
 
@@ -94,7 +101,7 @@
 
 type bpf struct {
 	android.ModuleBase
-
+	android.DefaultableModuleBase
 	properties BpfProperties
 
 	objs android.Paths
@@ -163,6 +170,10 @@
 		"-I " + ctx.ModuleDir(),
 	}
 
+	for _, dir := range android.PathsForModuleSrc(ctx, bpf.properties.Local_include_dirs) {
+		cflags = append(cflags, "-I "+dir.String())
+	}
+
 	for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) {
 		cflags = append(cflags, "-I "+dir.String())
 	}
@@ -264,6 +275,26 @@
 	}
 }
 
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func defaultsFactory() android.Module {
+	return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+	module := &Defaults{}
+
+	module.AddProperties(props...)
+	module.AddProperties(&BpfProperties{})
+
+	android.InitDefaultsModule(module)
+
+	return module
+}
+
 func (bpf *bpf) SubDir() string {
 	return bpf.properties.Sub_dir
 }
@@ -274,5 +305,7 @@
 	module.AddProperties(&module.properties)
 
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+
 	return module
 }
diff --git a/bpf/libbpf/Android.bp b/bpf/libbpf/Android.bp
new file mode 100644
index 0000000..f0ba90f
--- /dev/null
+++ b/bpf/libbpf/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-libbpf",
+    pkgPath: "android/soong/bpf/libbpf",
+    deps: [
+        "blueprint",
+        "blueprint-proptools",
+        "soong-android",
+        "soong-cc",
+        "soong-cc-config",
+    ],
+    srcs: [
+        "libbpf_prog.go",
+    ],
+    testSrcs: [
+        "libbpf_prog_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go
new file mode 100644
index 0000000..ac61510
--- /dev/null
+++ b/bpf/libbpf/libbpf_prog.go
@@ -0,0 +1,310 @@
+// 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.
+
+package libbpf_prog
+
+import (
+	"fmt"
+	"io"
+	"runtime"
+	"strings"
+
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/genrule"
+
+	"github.com/google/blueprint"
+)
+
+type libbpfProgDepType struct {
+	blueprint.BaseDependencyTag
+}
+
+func init() {
+	registerLibbpfProgBuildComponents(android.InitRegistrationContext)
+	pctx.Import("android/soong/cc/config")
+	pctx.StaticVariable("relPwd", cc.PwdPrefix())
+}
+
+var (
+	pctx = android.NewPackageContext("android/soong/bpf/libbpf_prog")
+
+	libbpfProgCcRule = pctx.AndroidStaticRule("libbpfProgCcRule",
+		blueprint.RuleParams{
+			Depfile:     "${out}.d",
+			Deps:        blueprint.DepsGCC,
+			Command:     "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
+			CommandDeps: []string{"$ccCmd"},
+		},
+		"ccCmd", "cFlags")
+
+	libbpfProgStripRule = pctx.AndroidStaticRule("libbpfProgStripRule",
+		blueprint.RuleParams{
+			Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` +
+				`--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`,
+			CommandDeps: []string{"$stripCmd"},
+		},
+		"stripCmd")
+
+	libbpfProgDepTag = libbpfProgDepType{}
+)
+
+func registerLibbpfProgBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("libbpf_defaults", defaultsFactory)
+	ctx.RegisterModuleType("libbpf_prog", LibbpfProgFactory)
+}
+
+var PrepareForTestWithLibbpfProg = android.GroupFixturePreparers(
+	android.FixtureRegisterWithContext(registerLibbpfProgBuildComponents),
+	android.FixtureAddFile("libbpf_headers/Foo.h", nil),
+	android.FixtureAddFile("libbpf_headers/Android.bp", []byte(`
+		genrule {
+			name: "libbpf_headers",
+			out: ["foo.h",],
+		}
+	`)),
+	genrule.PrepareForTestWithGenRuleBuildComponents,
+)
+
+type LibbpfProgProperties struct {
+	// source paths to the files.
+	Srcs []string `android:"path"`
+
+	// additional cflags that should be used to build the libbpf variant of
+	// the C/C++ module.
+	Cflags []string `android:"arch_variant"`
+
+	// list of directories relative to the Blueprint file that will
+	// be added to the include path using -I
+	Local_include_dirs []string `android:"arch_variant"`
+
+	Header_libs []string `android:"arch_variant"`
+
+	// optional subdirectory under which this module is installed into.
+	Relative_install_path string
+}
+
+type libbpfProg struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	properties LibbpfProgProperties
+	objs       android.Paths
+}
+
+var _ android.ImageInterface = (*libbpfProg)(nil)
+
+func (libbpf *libbpfProg) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (libbpf *libbpfProg) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (libbpf *libbpfProg) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (libbpf *libbpfProg) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return true
+}
+
+func (libbpf *libbpfProg) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (libbpf *libbpfProg) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (libbpf *libbpfProg) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (libbpf *libbpfProg) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (libbpf *libbpfProg) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	return nil
+}
+
+func (libbpf *libbpfProg) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+}
+
+func (libbpf *libbpfProg) DepsMutator(ctx android.BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), libbpfProgDepTag, "libbpf_headers")
+	ctx.AddVariationDependencies(nil, cc.HeaderDepTag(), libbpf.properties.Header_libs...)
+}
+
+func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	var cFlagsDeps android.Paths
+	cflags := []string{
+		"-nostdlibinc",
+
+		// Make paths in deps files relative
+		"-no-canonical-prefixes",
+
+		"-O2",
+		"-Wall",
+		"-Werror",
+		"-Wextra",
+
+		"-isystem bionic/libc/include",
+		"-isystem bionic/libc/kernel/uapi",
+		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
+		"-isystem bionic/libc/kernel/uapi/asm-arm64",
+		"-isystem bionic/libc/kernel/android/uapi",
+		"-I " + ctx.ModuleDir(),
+		"-g", //Libbpf builds require BTF data
+	}
+
+	if runtime.GOOS != "darwin" {
+		cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
+	}
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		depTag := ctx.OtherModuleDependencyTag(dep)
+		if depTag == libbpfProgDepTag {
+			if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
+				cFlagsDeps = append(cFlagsDeps, genRule.GeneratedDeps()...)
+				dirs := genRule.GeneratedHeaderDirs()
+				for _, dir := range dirs {
+					cflags = append(cflags, "-I "+dir.String())
+				}
+			} else {
+				depName := ctx.OtherModuleName(dep)
+				ctx.ModuleErrorf("module %q is not a genrule", depName)
+			}
+		} else if depTag == cc.HeaderDepTag() {
+			depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
+			for _, dir := range depExporterInfo.IncludeDirs {
+				cflags = append(cflags, "-I "+dir.String())
+			}
+		}
+	})
+
+	for _, dir := range android.PathsForModuleSrc(ctx, libbpf.properties.Local_include_dirs) {
+		cflags = append(cflags, "-I "+dir.String())
+	}
+
+	cflags = append(cflags, libbpf.properties.Cflags...)
+
+	srcs := android.PathsForModuleSrc(ctx, libbpf.properties.Srcs)
+
+	for _, src := range srcs {
+		if strings.ContainsRune(src.Base(), '_') {
+			ctx.ModuleErrorf("invalid character '_' in source name")
+		}
+		obj := android.ObjPathWithExt(ctx, "unstripped", src, "o")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:      libbpfProgCcRule,
+			Input:     src,
+			Implicits: cFlagsDeps,
+			Output:    obj,
+			Args: map[string]string{
+				"cFlags": strings.Join(cflags, " "),
+				"ccCmd":  "${config.ClangBin}/clang",
+			},
+		})
+
+		objStripped := android.ObjPathWithExt(ctx, "", src, "o")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   libbpfProgStripRule,
+			Input:  obj,
+			Output: objStripped,
+			Args: map[string]string{
+				"stripCmd": "${config.ClangBin}/llvm-strip",
+			},
+		})
+		libbpf.objs = append(libbpf.objs, objStripped.WithoutRel())
+	}
+
+	installDir := android.PathForModuleInstall(ctx, "etc", "bpf/libbpf")
+	if len(libbpf.properties.Relative_install_path) > 0 {
+		installDir = installDir.Join(ctx, libbpf.properties.Relative_install_path)
+	}
+	for _, obj := range libbpf.objs {
+		ctx.PackageFile(installDir, obj.Base(), obj)
+	}
+
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
+
+	ctx.SetOutputFiles(libbpf.objs, "")
+}
+
+func (libbpf *libbpfProg) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			var names []string
+			fmt.Fprintln(w)
+			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+			fmt.Fprintln(w)
+			var localModulePath string
+			localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf/libbpf"
+			if len(libbpf.properties.Relative_install_path) > 0 {
+				localModulePath += "/" + libbpf.properties.Relative_install_path
+			}
+			for _, obj := range libbpf.objs {
+				objName := name + "_" + obj.Base()
+				names = append(names, objName)
+				fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf.obj")
+				fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
+				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
+				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
+				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
+				fmt.Fprintln(w, localModulePath)
+				// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
+				for _, extra := range data.Extra {
+					extra(w, nil)
+				}
+				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+				fmt.Fprintln(w)
+			}
+			fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf")
+			fmt.Fprintln(w, "LOCAL_MODULE := ", name)
+			android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
+			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
+		},
+	}
+}
+
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func defaultsFactory() android.Module {
+	return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+	module := &Defaults{}
+
+	module.AddProperties(props...)
+	module.AddProperties(&LibbpfProgProperties{})
+
+	android.InitDefaultsModule(module)
+
+	return module
+}
+
+func LibbpfProgFactory() android.Module {
+	module := &libbpfProg{}
+
+	module.AddProperties(&module.properties)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitDefaultableModule(module)
+
+	return module
+}
diff --git a/bpf/libbpf/libbpf_prog_test.go b/bpf/libbpf/libbpf_prog_test.go
new file mode 100644
index 0000000..f4f5167
--- /dev/null
+++ b/bpf/libbpf/libbpf_prog_test.go
@@ -0,0 +1,69 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package libbpf_prog
+
+import (
+	"os"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+func TestMain(m *testing.M) {
+	os.Exit(m.Run())
+}
+
+var prepareForLibbpfProgTest = android.GroupFixturePreparers(
+	cc.PrepareForTestWithCcDefaultModules,
+	android.FixtureMergeMockFs(
+		map[string][]byte{
+			"bpf.c":              nil,
+			"bpf_invalid_name.c": nil,
+			"BpfTest.cpp":        nil,
+		},
+	),
+	PrepareForTestWithLibbpfProg,
+)
+
+func TestLibbpfProgDataDependency(t *testing.T) {
+	bp := `
+		libbpf_prog {
+			name: "bpf.o",
+			srcs: ["bpf.c"],
+		}
+
+		cc_test {
+			name: "vts_test_binary_bpf_module",
+			srcs: ["BpfTest.cpp"],
+			data: [":bpf.o"],
+			gtest: false,
+		}
+	`
+
+	prepareForLibbpfProgTest.RunTestWithBp(t, bp)
+}
+
+func TestLibbpfProgSourceName(t *testing.T) {
+	bp := `
+		libbpf_prog {
+			name: "bpf_invalid_name.o",
+			srcs: ["bpf_invalid_name.c"],
+		}
+	`
+	prepareForLibbpfProgTest.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+		`invalid character '_' in source name`)).
+		RunTestWithBp(t, bp)
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 4c42048..850aeda 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -40,6 +40,7 @@
   merge_zips
   xref_cxx
   xref_java
+  xref_kotlin
   # TODO: b/286390153 - reenable rust
   # xref_rust
 )
diff --git a/cc/Android.bp b/cc/Android.bp
index e68e4a3..3688c8a 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -16,7 +16,6 @@
         "soong-etc",
         "soong-fuzz",
         "soong-genrule",
-        "soong-multitree",
         "soong-testing",
         "soong-tradefed",
     ],
@@ -65,7 +64,6 @@
         "library.go",
         "library_headers.go",
         "library_sdk_member.go",
-        "library_stub.go",
         "native_bridge_sdk_trait.go",
         "object.go",
         "test.go",
@@ -118,4 +116,6 @@
         "cmake_module_cc.txt",
     ],
     pluginFor: ["soong_build"],
+    // Used by plugins
+    visibility: ["//visibility:public"],
 }
diff --git a/cc/TEST_MAPPING b/cc/TEST_MAPPING
new file mode 100644
index 0000000..be2809d
--- /dev/null
+++ b/cc/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "bionic"
+    }
+  ]
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index cecaae2..6966f76 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -21,7 +21,6 @@
 	"strings"
 
 	"android/soong/android"
-	"android/soong/multitree"
 )
 
 var (
@@ -479,34 +478,6 @@
 	androidMkWritePrebuiltOptions(p.baseLinker, entries)
 }
 
-func (a *apiLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	entries.Class = "SHARED_LIBRARIES"
-	entries.SubName += multitree.GetApiImportSuffix()
-
-	entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-		a.libraryDecorator.androidMkWriteExportedFlags(entries)
-		src := *a.properties.Src
-		path, file := filepath.Split(src)
-		stem, suffix, ext := android.SplitFileExt(file)
-		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
-		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
-		entries.SetString("LOCAL_MODULE_STEM", stem)
-		entries.SetString("LOCAL_MODULE_PATH", path)
-		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-		entries.SetString("LOCAL_SOONG_TOC", a.toc().String())
-	})
-}
-
-func (a *apiHeadersDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	entries.Class = "HEADER_LIBRARIES"
-	entries.SubName += multitree.GetApiImportSuffix()
-
-	entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-		a.libraryDecorator.androidMkWriteExportedFlags(entries)
-		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-	})
-}
-
 func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkEntries) {
 	allow := linker.Properties.Allow_undefined_symbols
 	if allow != nil {
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 8a7ea88..4063714 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -132,7 +132,7 @@
 
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
-		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps)
+		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps)
 
 		p.SharedLibs = specifiedDeps.sharedLibs
 		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
diff --git a/cc/cc.go b/cc/cc.go
index 927935c..96795d3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -34,7 +34,6 @@
 	"android/soong/cc/config"
 	"android/soong/fuzz"
 	"android/soong/genrule"
-	"android/soong/multitree"
 )
 
 func init() {
@@ -60,10 +59,10 @@
 			san.registerMutators(ctx)
 		}
 
-		ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
+		ctx.BottomUp("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
-		ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
+		ctx.BottomUp("fuzz_deps", fuzzMutatorDeps)
 
 		ctx.Transition("coverage", &coverageTransitionMutator{})
 
@@ -74,7 +73,7 @@
 		ctx.Transition("lto", &ltoTransitionMutator{})
 
 		ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel()
-		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+		ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries).Parallel()
 	})
 
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -613,7 +612,7 @@
 	coverageOutputFilePath() android.OptionalPath
 
 	// Get the deps that have been explicitly specified in the properties.
-	linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps
+	linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps
 
 	moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
 }
@@ -970,7 +969,7 @@
 	return c.Properties.HideFromMake
 }
 
-func (c *Module) RequiredModuleNames(ctx android.ConfigAndErrorContext) []string {
+func (c *Module) RequiredModuleNames(ctx android.ConfigurableEvaluatorContext) []string {
 	required := android.CopyOf(c.ModuleBase.RequiredModuleNames(ctx))
 	if c.ImageVariation().Variation == android.CoreVariation {
 		required = append(required, c.Properties.Target.Platform.Required...)
@@ -2361,24 +2360,6 @@
 	}
 }
 
-func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) multitree.ApiImportInfo {
-	apiImportInfo := multitree.ApiImportInfo{}
-
-	if c.Device() {
-		var apiImportModule []blueprint.Module
-		if actx.OtherModuleExists("api_imports") {
-			apiImportModule = actx.AddDependency(c, nil, "api_imports")
-			if len(apiImportModule) > 0 && apiImportModule[0] != nil {
-				apiInfo, _ := android.OtherModuleProvider(actx, apiImportModule[0], multitree.ApiImportsProvider)
-				apiImportInfo = apiInfo
-				android.SetProvider(actx, multitree.ApiImportsProvider, apiInfo)
-			}
-		}
-	}
-
-	return apiImportInfo
-}
-
 func GetReplaceModuleName(lib string, replaceMap map[string]string) string {
 	if snapshot, ok := replaceMap[lib]; ok {
 		return snapshot
@@ -2448,11 +2429,6 @@
 			// NDK Variant
 			return true
 		}
-
-		if c.isImportedApiLibrary() {
-			// API Library should depend on API headers
-			return true
-		}
 	}
 
 	return false
@@ -2472,19 +2448,10 @@
 	ctx.ctx = ctx
 
 	deps := c.deps(ctx)
-	apiImportInfo := GetApiImports(c, actx)
 
 	apiNdkLibs := []string{}
 	apiLateNdkLibs := []string{}
 
-	if c.shouldUseApiSurface() {
-		deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config())
-		deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
-		deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
-		deps.ReexportHeaderLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportHeaderLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
-		deps.ReexportSharedLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportSharedLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
-	}
-
 	c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
 
 	variantNdkLibs := []string{}
@@ -2501,15 +2468,16 @@
 			depTag.reexportFlags = true
 		}
 
-		// Check header lib replacement from API surface first, and then check again with VSDK
-		if c.shouldUseApiSurface() {
-			lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
-		}
-
 		if c.isNDKStubLibrary() {
-			// ndk_headers do not have any variations
-			actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
-		} else if c.IsStubs() && !c.isImportedApiLibrary() {
+			variationExists := actx.OtherModuleDependencyVariantExists(nil, lib)
+			if variationExists {
+				actx.AddVariationDependencies(nil, depTag, lib)
+			} else {
+				// dependencies to ndk_headers fall here as ndk_headers do not have
+				// any variants.
+				actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
+			}
+		} else if c.IsStubs() {
 			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
 				depTag, lib)
 		} else {
@@ -2585,22 +2553,12 @@
 		}
 
 		name, version := StubsLibNameAndVersion(lib)
-		if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) {
-			name = apiLibraryName
-		}
 		sharedLibNames = append(sharedLibNames, name)
 
 		variations := []blueprint.Variation{
 			{Mutator: "link", Variation: "shared"},
 		}
-
-		if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
-			AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
-		}
-
-		if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
-			AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, apiLibraryName, version, false)
-		}
+		AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
 	}
 
 	for _, lib := range deps.LateStaticLibs {
@@ -2695,7 +2653,6 @@
 		)
 	}
 
-	updateImportedLibraryDependency(ctx)
 }
 
 func BeginMutator(ctx android.BottomUpMutatorContext) {
@@ -2724,10 +2681,6 @@
 		return
 	}
 
-	// TODO(b/244244438) : Remove this once all variants are implemented
-	if ccFrom, ok := from.(*Module); ok && ccFrom.isImportedApiLibrary() {
-		return
-	}
 	if from.SdkVersion() == "" {
 		// Platform code can link to anything
 		return
@@ -2750,10 +2703,6 @@
 			// the NDK.
 			return
 		}
-		if c.isImportedApiLibrary() {
-			// Imported library from the API surface is a stub library built against interface definition.
-			return
-		}
 	}
 
 	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {
@@ -2834,7 +2783,7 @@
 // If a library has a vendor variant and is a (transitive) dependency of an LLNDK library,
 // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
 // or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
-func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
+func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) {
 	check := func(child, parent android.Module) bool {
 		to, ok := child.(*Module)
 		if !ok {
@@ -2929,47 +2878,6 @@
 
 	skipModuleList := map[string]bool{}
 
-	var apiImportInfo multitree.ApiImportInfo
-	hasApiImportInfo := false
-
-	ctx.VisitDirectDeps(func(dep android.Module) {
-		if dep.Name() == "api_imports" {
-			apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
-			hasApiImportInfo = true
-		}
-	})
-
-	if hasApiImportInfo {
-		targetStubModuleList := map[string]string{}
-		targetOrigModuleList := map[string]string{}
-
-		// Search for dependency which both original module and API imported library with APEX stub exists
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			depName := ctx.OtherModuleName(dep)
-			if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
-				targetStubModuleList[apiLibrary] = depName
-			}
-		})
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			depName := ctx.OtherModuleName(dep)
-			if origLibrary, ok := targetStubModuleList[depName]; ok {
-				targetOrigModuleList[origLibrary] = depName
-			}
-		})
-
-		// Decide which library should be used between original and API imported library
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			depName := ctx.OtherModuleName(dep)
-			if apiLibrary, ok := targetOrigModuleList[depName]; ok {
-				if ShouldUseStubForApex(ctx, dep) {
-					skipModuleList[depName] = true
-				} else {
-					skipModuleList[apiLibrary] = true
-				}
-			}
-		})
-	}
-
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -3398,17 +3306,7 @@
 		// bootstrap modules, always link to non-stub variant
 		isNotInPlatform := dep.(android.ApexModule).NotInPlatform()
 
-		isApexImportedApiLibrary := false
-
-		if cc, ok := dep.(*Module); ok {
-			if apiLibrary, ok := cc.linker.(*apiLibraryDecorator); ok {
-				if apiLibrary.hasApexStubs() {
-					isApexImportedApiLibrary = true
-				}
-			}
-		}
-
-		useStubs = (isNotInPlatform || isApexImportedApiLibrary) && !bootstrap
+		useStubs = isNotInPlatform && !bootstrap
 
 		if useStubs {
 			// Another exception: if this module is a test for an APEX, then
@@ -3433,7 +3331,7 @@
 			// only partially overlapping apex_available. For that test_for
 			// modules would need to be split into APEX variants and resolved
 			// separately for each APEX they have access to.
-			if !isApexImportedApiLibrary && android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
+			if android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
 				useStubs = false
 			}
 		}
@@ -4017,11 +3915,6 @@
 	return c.Properties.IsSdkVariant
 }
 
-func (c *Module) isImportedApiLibrary() bool {
-	_, ok := c.linker.(*apiLibraryDecorator)
-	return ok
-}
-
 func kytheExtractAllFactory() android.Singleton {
 	return &kytheExtractAllSingleton{}
 }
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 93630db..3f3347b 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -49,17 +49,30 @@
 
 func registerTestMutators(ctx android.RegistrationContext) {
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("apex", testApexMutator).Parallel()
+		ctx.Transition("apex", &testApexTransitionMutator{})
 	})
 }
 
-func testApexMutator(mctx android.BottomUpMutatorContext) {
-	modules := mctx.CreateVariations(apexVariationName)
+type testApexTransitionMutator struct{}
+
+func (t *testApexTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	return []string{apexVariationName}
+}
+
+func (t *testApexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (t *testApexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	return incomingVariation
+}
+
+func (t *testApexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
 	apexInfo := android.ApexInfo{
 		ApexVariationName: apexVariationName,
 		MinSdkVersion:     android.ApiLevelForTest(apexVersion),
 	}
-	mctx.SetVariationProvider(modules[0], android.ApexInfoProvider, apexInfo)
+	android.SetProvider(ctx, android.ApexInfoProvider, apexInfo)
 }
 
 // testCcWithConfig runs tests using the prepareForCcTest
diff --git a/cc/check.go b/cc/check.go
index e3af3b2..fa1926d 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -40,6 +40,8 @@
 			ctx.PropertyErrorf(prop, "Bad flag: `%s`, use native_coverage instead", flag)
 		} else if flag == "-fwhole-program-vtables" {
 			ctx.PropertyErrorf(prop, "Bad flag: `%s`, use whole_program_vtables instead", flag)
+		} else if flag == "-fno-integrated-as" {
+			ctx.PropertyErrorf("Bad flag: `%s` is disallowed as it may invoke the `as` from the build host", flag)
 		} else if flag == "-Weverything" {
 			if !ctx.Config().IsEnvTrue("ANDROID_TEMPORARILY_ALLOW_WEVERYTHING") {
 				ctx.PropertyErrorf(prop, "-Weverything is not allowed in Android.bp files.  "+
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 289409f..f514db6 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -35,4 +35,8 @@
     testSrcs: [
         "tidy_test.go",
     ],
+    visibility: [
+        "//build/soong:__subpackages__",
+        "//prebuilts/clang/host/linux-x86/soong",
+    ],
 }
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index beb68e1..0dcf2cf 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -41,11 +41,18 @@
 		"armv8-2a-dotprod": []string{
 			"-march=armv8.2-a+dotprod",
 		},
+		// On ARMv9 and later, Pointer Authentication Codes (PAC) are mandatory,
+		// so -fstack-protector is unnecessary.
 		"armv9-a": []string{
 			"-march=armv8.2-a+dotprod",
 			"-mbranch-protection=standard",
 			"-fno-stack-protector",
 		},
+		"armv9-2a": []string{
+			"-march=armv9.2-a",
+			"-mbranch-protection=standard",
+			"-fno-stack-protector",
+		},
 	}
 
 	arm64Ldflags = []string{
@@ -111,11 +118,9 @@
 
 	pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
 
-	pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
-	pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " "))
-	pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
-	pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
-	pctx.StaticVariable("Arm64Armv9ACflags", strings.Join(arm64ArchVariantCflags["armv9-a"], " "))
+	for variant, cflags := range arm64ArchVariantCflags {
+		pctx.StaticVariable("Arm64"+variant+"VariantCflags", strings.Join(cflags, " "))
+	}
 
 	pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
 	pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
@@ -127,14 +132,6 @@
 }
 
 var (
-	arm64ArchVariantCflagsVar = map[string]string{
-		"armv8-a":            "${config.Arm64Armv8ACflags}",
-		"armv8-a-branchprot": "${config.Arm64Armv8ABranchProtCflags}",
-		"armv8-2a":           "${config.Arm64Armv82ACflags}",
-		"armv8-2a-dotprod":   "${config.Arm64Armv82ADotprodCflags}",
-		"armv9-a":            "${config.Arm64Armv9ACflags}",
-	}
-
 	arm64CpuVariantCflagsVar = map[string]string{
 		"cortex-a53": "${config.Arm64CortexA53Cflags}",
 		"cortex-a55": "${config.Arm64CortexA55Cflags}",
@@ -204,18 +201,12 @@
 }
 
 func arm64ToolchainFactory(arch android.Arch) Toolchain {
-	switch arch.ArchVariant {
-	case "armv8-a":
-	case "armv8-a-branchprot":
-	case "armv8-2a":
-	case "armv8-2a-dotprod":
-	case "armv9-a":
-		// Nothing extra for armv8-a/armv8-2a
-	default:
-		panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
+	// Error now rather than having a confusing Ninja error
+	if _, ok := arm64ArchVariantCflags[arch.ArchVariant]; !ok {
+		panic(fmt.Sprintf("Unknown ARM64 architecture version: %q", arch.ArchVariant))
 	}
 
-	toolchainCflags := []string{arm64ArchVariantCflagsVar[arch.ArchVariant]}
+	toolchainCflags := []string{"${config.Arm64" + arch.ArchVariant + "VariantCflags}"}
 	toolchainCflags = append(toolchainCflags,
 		variantOrDefault(arm64CpuVariantCflagsVar, arch.CpuVariant))
 
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 438e0e6..a19b0ed 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -87,8 +87,8 @@
 }
 
 func linuxBionicArm64ToolchainFactory(arch android.Arch) Toolchain {
-	archVariant := "armv8-a" // for host, default to armv8-a
-	toolchainCflags := []string{arm64ArchVariantCflagsVar[archVariant]}
+	// for host, default to armv8-a
+	toolchainCflags := []string{"-march=armv8-a"}
 
 	// We don't specify CPU architecture for host. Conservatively assume
 	// the host CPU needs the fix
diff --git a/cc/config/global.go b/cc/config/global.go
index 0e8fff6..9d3de6d 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -286,9 +286,10 @@
 		// New warnings to be fixed after clang-r468909
 		"-Wno-error=deprecated-builtins", // http://b/241601211
 		"-Wno-error=deprecated",          // in external/googletest/googletest
+		// Disabling until the warning is fixed in libc++abi header files b/366180429
+		"-Wno-deprecated-dynamic-exception-spec",
 		// New warnings to be fixed after clang-r475365
-		"-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903
-		"-Wno-error=enum-constexpr-conversion",               // http://b/243964282
+		"-Wno-error=enum-constexpr-conversion", // http://b/243964282
 		// New warnings to be fixed after clang-r522817
 		"-Wno-error=invalid-offsetof",
 		"-Wno-error=thread-safety-reference-return",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index d9e221b..3f21bc6 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -57,7 +57,7 @@
 	return []interface{}{&fuzzer.Properties}
 }
 
-func fuzzMutatorDeps(mctx android.TopDownMutatorContext) {
+func fuzzMutatorDeps(mctx android.BottomUpMutatorContext) {
 	currentModule, ok := mctx.Module().(*Module)
 	if !ok {
 		return
diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp
index b105a30..c1f2c10 100644
--- a/cc/libbuildversion/Android.bp
+++ b/cc/libbuildversion/Android.bp
@@ -20,4 +20,5 @@
         "//apex_available:anyapex",
     ],
     vendor_available: true,
+    visibility: ["//visibility:public"],
 }
diff --git a/cc/library.go b/cc/library.go
index 65a923a..3833b98 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -919,7 +919,7 @@
 	return deps
 }
 
-func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
 	specifiedDeps = library.baseLinker.linkerSpecifiedDeps(ctx, module, specifiedDeps)
 	var properties StaticOrSharedProperties
 	if library.static() {
@@ -1264,14 +1264,6 @@
 func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string {
 	var includeDirs, systemIncludeDirs []string
 
-	// The ABI checker does not need the preprocess which adds macro guards to function declarations.
-	preprocessedDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings()
-	if Bool(library.Properties.Llndk.Export_headers_as_system) {
-		systemIncludeDirs = append(systemIncludeDirs, preprocessedDirs...)
-	} else {
-		includeDirs = append(includeDirs, preprocessedDirs...)
-	}
-
 	if library.Properties.Llndk.Override_export_include_dirs != nil {
 		includeDirs = append(includeDirs, android.PathsForModuleSrc(
 			ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...)
@@ -1579,25 +1571,6 @@
 	}
 }
 
-func processLLNDKHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) (timestamp android.Path, installPaths android.WritablePaths) {
-	srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
-	srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
-
-	for _, header := range srcFiles {
-		headerDir := filepath.Dir(header.String())
-		relHeaderDir, err := filepath.Rel(srcDir.String(), headerDir)
-		if err != nil {
-			ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s",
-				srcDir.String(), headerDir, err)
-			continue
-		}
-
-		installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
-	}
-
-	return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths), installPaths
-}
-
 // link registers actions to link this library, and sets various fields
 // on this library to reflect information that should be exported up the build
 // tree (for example, exported flags and include paths).
@@ -1605,26 +1578,6 @@
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
 	if ctx.IsLlndk() {
-		if len(library.Properties.Llndk.Export_preprocessed_headers) > 0 {
-			// This is the vendor variant of an LLNDK library with preprocessed headers.
-			genHeaderOutDir := android.PathForModuleGen(ctx, "include")
-
-			var timestampFiles android.Paths
-			for _, dir := range library.Properties.Llndk.Export_preprocessed_headers {
-				timestampFile, installPaths := processLLNDKHeaders(ctx, dir, genHeaderOutDir)
-				timestampFiles = append(timestampFiles, timestampFile)
-				library.addExportedGeneratedHeaders(installPaths.Paths()...)
-			}
-
-			if Bool(library.Properties.Llndk.Export_headers_as_system) {
-				library.reexportSystemDirs(genHeaderOutDir)
-			} else {
-				library.reexportDirs(genHeaderOutDir)
-			}
-
-			library.reexportDeps(timestampFiles...)
-		}
-
 		// override the module's export_include_dirs with llndk.override_export_include_dirs
 		// if it is set.
 		if override := library.Properties.Llndk.Override_export_include_dirs; override != nil {
@@ -2397,9 +2350,8 @@
 	if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
 		isLLNDK := m.IsLlndk()
 		isVendorPublicLibrary := m.IsVendorPublicLibrary()
-		isImportedApiLibrary := m.isImportedApiLibrary()
 
-		if variation != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
+		if variation != "" || isLLNDK || isVendorPublicLibrary {
 			// A stubs or LLNDK stubs variant.
 			if m.sanitize != nil {
 				m.sanitize.Properties.ForceDisable = true
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 053c460..af3658d 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -543,7 +543,7 @@
 	p.ExportedFlags = exportedInfo.Flags
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
-		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps)
+		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps)
 
 		if lib := ccModule.library; lib != nil {
 			if !lib.hasStubsVariants() {
diff --git a/cc/library_stub.go b/cc/library_stub.go
deleted file mode 100644
index 6367825..0000000
--- a/cc/library_stub.go
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// 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.
-
-package cc
-
-import (
-	"regexp"
-	"strings"
-
-	"android/soong/android"
-	"android/soong/multitree"
-
-	"github.com/google/blueprint/proptools"
-)
-
-var (
-	ndkVariantRegex  = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
-	stubVariantRegex = regexp.MustCompile("apex\\.([a-zA-Z0-9]+)")
-)
-
-func init() {
-	RegisterLibraryStubBuildComponents(android.InitRegistrationContext)
-}
-
-func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
-	ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory)
-	ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory)
-}
-
-func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) {
-	m, ok := ctx.Module().(*Module)
-	if !ok {
-		return
-	}
-
-	apiLibrary, ok := m.linker.(*apiLibraryDecorator)
-	if !ok {
-		return
-	}
-
-	if m.InVendorOrProduct() && apiLibrary.hasLLNDKStubs() {
-		// Add LLNDK variant dependency
-		if inList("llndk", apiLibrary.properties.Variants) {
-			variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
-			ctx.AddDependency(m, nil, variantName)
-		}
-	} else if m.IsSdkVariant() {
-		// Add NDK variant dependencies
-		targetVariant := "ndk." + m.StubsVersion()
-		if inList(targetVariant, apiLibrary.properties.Variants) {
-			variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
-			ctx.AddDependency(m, nil, variantName)
-		}
-	} else if m.IsStubs() {
-		targetVariant := "apex." + m.StubsVersion()
-		if inList(targetVariant, apiLibrary.properties.Variants) {
-			variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
-			ctx.AddDependency(m, nil, variantName)
-		}
-	}
-}
-
-// 'cc_api_library' is a module type which is from the exported API surface
-// with C shared library type. The module will replace original module, and
-// offer a link to the module that generates shared library object from the
-// map file.
-type apiLibraryProperties struct {
-	Src      *string `android:"arch_variant"`
-	Variants []string
-}
-
-type apiLibraryDecorator struct {
-	*libraryDecorator
-	properties apiLibraryProperties
-}
-
-func CcApiLibraryFactory() android.Module {
-	module, decorator := NewLibrary(android.DeviceSupported)
-	apiLibraryDecorator := &apiLibraryDecorator{
-		libraryDecorator: decorator,
-	}
-	apiLibraryDecorator.BuildOnlyShared()
-
-	module.stl = nil
-	module.sanitize = nil
-	decorator.disableStripping()
-
-	module.compiler = nil
-	module.linker = apiLibraryDecorator
-	module.installer = nil
-	module.library = apiLibraryDecorator
-	module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
-
-	// Prevent default system libs (libc, libm, and libdl) from being linked
-	if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
-		apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
-	}
-
-	apiLibraryDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
-	apiLibraryDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
-
-	module.Init()
-
-	return module
-}
-
-func (d *apiLibraryDecorator) Name(basename string) string {
-	return basename + multitree.GetApiImportSuffix()
-}
-
-// Export include dirs without checking for existence.
-// The directories are not guaranteed to exist during Soong analysis.
-func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) {
-	exporterProps := d.flagExporter.Properties
-	for _, dir := range exporterProps.Export_include_dirs.GetOrDefault(ctx, nil) {
-		d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir))
-	}
-	// system headers
-	for _, dir := range exporterProps.Export_system_include_dirs {
-		d.systemDirs = append(d.systemDirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir))
-	}
-}
-
-func (d *apiLibraryDecorator) linkerInit(ctx BaseModuleContext) {
-	d.baseLinker.linkerInit(ctx)
-
-	if d.hasNDKStubs() {
-		// Set SDK version of module as current
-		ctx.Module().(*Module).Properties.Sdk_version = StringPtr("current")
-
-		// Add NDK stub as NDK known libs
-		name := ctx.ModuleName()
-
-		ndkKnownLibsLock.Lock()
-		ndkKnownLibs := getNDKKnownLibs(ctx.Config())
-		if !inList(name, *ndkKnownLibs) {
-			*ndkKnownLibs = append(*ndkKnownLibs, name)
-		}
-		ndkKnownLibsLock.Unlock()
-	}
-}
-
-func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
-	m, _ := ctx.Module().(*Module)
-
-	var in android.Path
-
-	// src might not exist during the beginning of soong analysis in Multi-tree
-	if src := String(d.properties.Src); src != "" {
-		in = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), src)
-	}
-
-	libName := m.BaseModuleName() + multitree.GetApiImportSuffix()
-
-	load_cc_variant := func(apiVariantModule string) {
-		var mod android.Module
-
-		ctx.VisitDirectDeps(func(depMod android.Module) {
-			if depMod.Name() == apiVariantModule {
-				mod = depMod
-				libName = apiVariantModule
-			}
-		})
-
-		if mod != nil {
-			variantMod, ok := mod.(*CcApiVariant)
-			if ok {
-				in = variantMod.Src()
-
-				// Copy LLDNK properties to cc_api_library module
-				exportIncludeDirs := append(d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil),
-					variantMod.exportProperties.Export_include_dirs...)
-				d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](
-					nil,
-					[]proptools.ConfigurableCase[[]string]{
-						proptools.NewConfigurableCase[[]string](nil, &exportIncludeDirs),
-					},
-				)
-
-				// Export headers as system include dirs if specified. Mostly for libc
-				if Bool(variantMod.exportProperties.Export_headers_as_system) {
-					d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
-						d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
-						d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)...)
-					d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](nil, nil)
-				}
-			}
-		}
-	}
-
-	if m.InVendorOrProduct() && d.hasLLNDKStubs() {
-		// LLNDK variant
-		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", ""))
-	} else if m.IsSdkVariant() {
-		// NDK Variant
-		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion()))
-	} else if m.IsStubs() {
-		// APEX Variant
-		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "apex", m.StubsVersion()))
-	}
-
-	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
-	d.exportIncludes(ctx)
-	d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
-	d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
-	d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
-	d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
-	d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
-
-	if in == nil {
-		ctx.PropertyErrorf("src", "Unable to locate source property")
-		return nil
-	}
-
-	// Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file)
-	// The .so file itself has an order-only dependency on the headers contributed by this library.
-	// Creating this dependency ensures that the headers are assembled before compilation of rdeps begins.
-	d.libraryDecorator.reexportDeps(in)
-	d.libraryDecorator.flagExporter.setProvider(ctx)
-
-	d.unstrippedOutputFile = in
-	libName += flags.Toolchain.ShlibSuffix()
-
-	tocFile := android.PathForModuleOut(ctx, libName+".toc")
-	d.tocFile = android.OptionalPathForPath(tocFile)
-	TransformSharedObjectToToc(ctx, in, tocFile)
-
-	outputFile := android.PathForModuleOut(ctx, libName)
-
-	// TODO(b/270485584) This copies with a new name, just to avoid conflict with prebuilts.
-	// We can just use original input if there is any way to avoid name conflict without copy.
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cp,
-		Description: "API surface imported library",
-		Input:       in,
-		Output:      outputFile,
-		Args: map[string]string{
-			"cpFlags": "-L",
-		},
-	})
-
-	android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
-		SharedLibrary: outputFile,
-		Target:        ctx.Target(),
-
-		TableOfContents: d.tocFile,
-	})
-
-	d.shareStubs(ctx)
-
-	return outputFile
-}
-
-// Share additional information about stub libraries with provider
-func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) {
-	stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
-	if len(stubs) > 0 {
-		var stubsInfo []SharedStubLibrary
-		for _, stub := range stubs {
-			stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
-			flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
-			stubsInfo = append(stubsInfo, SharedStubLibrary{
-				Version:           moduleLibraryInterface(stub).stubsVersion(),
-				SharedLibraryInfo: stubInfo,
-				FlagExporterInfo:  flagInfo,
-			})
-		}
-		android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
-			SharedStubLibraries: stubsInfo,
-
-			IsLLNDK: ctx.IsLlndk(),
-		})
-	}
-}
-
-func (d *apiLibraryDecorator) availableFor(what string) bool {
-	// Stub from API surface should be available for any APEX.
-	return true
-}
-
-func (d *apiLibraryDecorator) hasApexStubs() bool {
-	for _, variant := range d.properties.Variants {
-		if strings.HasPrefix(variant, "apex") {
-			return true
-		}
-	}
-	return false
-}
-
-func (d *apiLibraryDecorator) hasStubsVariants() bool {
-	return d.hasApexStubs()
-}
-
-func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
-	m, ok := ctx.Module().(*Module)
-
-	if !ok {
-		return nil
-	}
-
-	// TODO(b/244244438) Create more version information for NDK and APEX variations
-	// NDK variants
-	if m.IsSdkVariant() {
-		// TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant.
-		if d.hasNDKStubs() {
-			return d.getNdkVersions()
-		}
-	}
-
-	if d.hasLLNDKStubs() && m.InVendorOrProduct() {
-		// LLNDK libraries only need a single stubs variant.
-		return []string{android.FutureApiLevel.String()}
-	}
-
-	stubsVersions := d.getStubVersions()
-
-	if len(stubsVersions) != 0 {
-		return stubsVersions
-	}
-
-	if m.MinSdkVersion() == "" {
-		return nil
-	}
-
-	firstVersion, err := nativeApiLevelFromUser(ctx,
-		m.MinSdkVersion())
-
-	if err != nil {
-		return nil
-	}
-
-	return ndkLibraryVersions(ctx, firstVersion)
-}
-
-func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
-	return inList("llndk", d.properties.Variants)
-}
-
-func (d *apiLibraryDecorator) hasNDKStubs() bool {
-	for _, variant := range d.properties.Variants {
-		if ndkVariantRegex.MatchString(variant) {
-			return true
-		}
-	}
-	return false
-}
-
-func (d *apiLibraryDecorator) getNdkVersions() []string {
-	ndkVersions := []string{}
-
-	for _, variant := range d.properties.Variants {
-		if match := ndkVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
-			ndkVersions = append(ndkVersions, match[1])
-		}
-	}
-
-	return ndkVersions
-}
-
-func (d *apiLibraryDecorator) getStubVersions() []string {
-	stubVersions := []string{}
-
-	for _, variant := range d.properties.Variants {
-		if match := stubVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
-			stubVersions = append(stubVersions, match[1])
-		}
-	}
-
-	return stubVersions
-}
-
-// 'cc_api_headers' is similar with 'cc_api_library', but which replaces
-// header libraries. The module will replace any dependencies to existing
-// original header libraries.
-type apiHeadersDecorator struct {
-	*libraryDecorator
-}
-
-func CcApiHeadersFactory() android.Module {
-	module, decorator := NewLibrary(android.DeviceSupported)
-	apiHeadersDecorator := &apiHeadersDecorator{
-		libraryDecorator: decorator,
-	}
-	apiHeadersDecorator.HeaderOnly()
-
-	module.stl = nil
-	module.sanitize = nil
-	decorator.disableStripping()
-
-	module.compiler = nil
-	module.linker = apiHeadersDecorator
-	module.installer = nil
-
-	// Prevent default system libs (libc, libm, and libdl) from being linked
-	if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil {
-		apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{}
-	}
-
-	apiHeadersDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
-	apiHeadersDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
-
-	module.Init()
-
-	return module
-}
-
-func (d *apiHeadersDecorator) Name(basename string) string {
-	return basename + multitree.GetApiImportSuffix()
-}
-
-func (d *apiHeadersDecorator) availableFor(what string) bool {
-	// Stub from API surface should be available for any APEX.
-	return true
-}
-
-type ccApiexportProperties struct {
-	Src     *string `android:"arch_variant"`
-	Variant *string
-	Version *string
-}
-
-type variantExporterProperties struct {
-	// Header directory to export
-	Export_include_dirs []string `android:"arch_variant"`
-
-	// Export all headers as system include
-	Export_headers_as_system *bool
-}
-
-type CcApiVariant struct {
-	android.ModuleBase
-
-	properties       ccApiexportProperties
-	exportProperties variantExporterProperties
-
-	src android.Path
-}
-
-var _ android.Module = (*CcApiVariant)(nil)
-var _ android.ImageInterface = (*CcApiVariant)(nil)
-
-func CcApiVariantFactory() android.Module {
-	module := &CcApiVariant{}
-
-	module.AddProperties(&module.properties)
-	module.AddProperties(&module.exportProperties)
-
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
-	return module
-}
-
-func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// No need to build
-
-	if String(v.properties.Src) == "" {
-		ctx.PropertyErrorf("src", "src is a required property")
-	}
-
-	// Skip the existence check of the stub prebuilt file.
-	// The file is not guaranteed to exist during Soong analysis.
-	// Build orchestrator will be responsible for creating a connected ninja graph.
-	v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), String(v.properties.Src))
-}
-
-func (v *CcApiVariant) Name() string {
-	version := String(v.properties.Version)
-	return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
-}
-
-func (v *CcApiVariant) Src() android.Path {
-	return v.src
-}
-
-func BuildApiVariantName(baseName string, variant string, version string) string {
-	names := []string{baseName, variant}
-	if version != "" {
-		names = append(names, version)
-	}
-
-	return strings.Join(names[:], ".") + multitree.GetApiImportSuffix()
-}
-
-// Implement ImageInterface to generate image variants
-func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {}
-func (v *CcApiVariant) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
-	return String(v.properties.Variant) == "llndk"
-}
-func (v *CcApiVariant) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
-	return String(v.properties.Variant) == "llndk"
-}
-func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	return inList(String(v.properties.Variant), []string{"ndk", "apex"})
-}
-func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool       { return false }
-func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
-func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool  { return false }
-func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool      { return false }
-func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string   { return nil }
-func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string) {
-}
diff --git a/cc/linker.go b/cc/linker.go
index 0056817..1efacad 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -645,7 +645,7 @@
 	panic(fmt.Errorf("baseLinker doesn't know how to link"))
 }
 
-func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
 	eval := module.ConfigurableEvaluator(ctx)
 	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs.GetOrDefault(eval, nil)...)
 
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 5ece78a..c7950f9 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -36,10 +36,6 @@
 	// bionic/libc.
 	Export_headers_as_system *bool
 
-	// Which headers to process with versioner. This really only handles
-	// bionic/libc/include right now.
-	Export_preprocessed_headers []string
-
 	// Whether the system library uses symbol versions.
 	Unversioned *bool
 
diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go
index 8202cc0..2706261 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -46,7 +46,7 @@
 
 		if m, ok := module.(*Module); ok {
 			if installer, ok := m.installer.(*stubDecorator); ok {
-				if canDumpAbi(ctx.Config(), ctx.ModuleDir(module)) {
+				if installer.hasAbiDump {
 					depPaths = append(depPaths, installer.abiDumpPath)
 				}
 			}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index e002931..7481954 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -23,15 +23,6 @@
 )
 
 var (
-	versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
-		blueprint.RuleParams{
-			// The `&& touch $out` isn't really necessary, but Blueprint won't
-			// let us have only implicit outputs.
-			Command:     "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
-			CommandDeps: []string{"$versionerCmd"},
-		},
-		"depsPath", "srcDir", "outDir")
-
 	preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
 		blueprint.RuleParams{
 			Command:     "$preprocessor -o $out $in",
@@ -40,10 +31,6 @@
 		"preprocessor")
 )
 
-func init() {
-	pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
-}
-
 // Returns the NDK base include path for use with sdk_version current. Usable with -I.
 func getCurrentIncludePath(ctx android.PathContext) android.OutputPath {
 	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
@@ -167,126 +154,6 @@
 	return module
 }
 
-type versionedHeaderProperties struct {
-	// Base directory of the headers being installed. As an example:
-	//
-	// versioned_ndk_headers {
-	//     name: "foo",
-	//     from: "include",
-	//     to: "",
-	// }
-	//
-	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
-	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
-	From *string
-
-	// Install path within the sysroot. This is relative to usr/include.
-	To *string
-
-	// Path to the NOTICE file associated with the headers.
-	License *string
-}
-
-// Like ndk_headers, but preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
-//
-// Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
-// module does not have the srcs property, and operates on a full directory (the `from` property).
-//
-// Note that this is really only built to handle bionic/libc/include.
-type versionedHeaderModule struct {
-	android.ModuleBase
-
-	properties versionedHeaderProperties
-
-	srcPaths     android.Paths
-	installPaths android.Paths
-	licensePath  android.Path
-}
-
-// Return the glob pattern to find all .h files beneath `dir`
-func headerGlobPattern(dir string) string {
-	return filepath.Join(dir, "**", "*.h")
-}
-
-func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if String(m.properties.License) == "" {
-		ctx.PropertyErrorf("license", "field is required")
-	}
-
-	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
-
-	fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
-	toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
-	m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
-	var installPaths []android.WritablePath
-	for _, header := range m.srcPaths {
-		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
-		installPath := installDir.Join(ctx, header.Base())
-		installPaths = append(installPaths, installPath)
-		m.installPaths = append(m.installPaths, installPath)
-	}
-
-	if len(m.installPaths) == 0 {
-		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
-	}
-
-	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
-}
-
-func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
-	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
-	// The versioner depends on a dependencies directory to simplify determining include paths
-	// when parsing headers. This directory contains architecture specific directories as well
-	// as a common directory, each of which contains symlinks to the actually directories to
-	// be included.
-	//
-	// ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
-	// depend on these headers.
-	// TODO(http://b/35673191): Update the versioner to use a --sysroot.
-	depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
-	depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
-	for i, path := range depsGlob {
-		if ctx.IsSymlink(path) {
-			dest := ctx.Readlink(path)
-			// Additional .. to account for the symlink itself.
-			depsGlob[i] = android.PathForSource(
-				ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
-		}
-	}
-
-	timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:            versionBionicHeaders,
-		Description:     "versioner preprocess " + srcDir.Rel(),
-		Output:          timestampFile,
-		Implicits:       append(srcPaths, depsGlob...),
-		ImplicitOutputs: installPaths,
-		Args: map[string]string{
-			"depsPath": depsPath.String(),
-			"srcDir":   srcDir.String(),
-			"outDir":   outDir.String(),
-		},
-	})
-
-	return timestampFile
-}
-
-// versioned_ndk_headers preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
-// Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
-// directory level specified in `from` property. This is only used to process
-// the bionic/libc/include directory.
-func VersionedNdkHeadersFactory() android.Module {
-	module := &versionedHeaderModule{}
-
-	module.AddProperties(&module.properties)
-
-	android.InitAndroidModule(module)
-
-	return module
-}
-
 // preprocessed_ndk_header {
 //
 //	name: "foo",
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 3e35ef5..01551ab 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -103,8 +103,17 @@
 	// https://github.com/android-ndk/ndk/issues/265.
 	Unversioned_until *string
 
-	// Headers presented by this library to the Public API Surface
+	// DO NOT USE THIS
+	// NDK libraries should not export their headers. Headers belonging to NDK
+	// libraries should be added to the NDK with an ndk_headers module.
 	Export_header_libs []string
+
+	// Do not add other export_* properties without consulting with danalbert@.
+	// Consumers of ndk_library modules should emulate the typical NDK build
+	// behavior as closely as possible (that is, all NDK APIs are exposed to
+	// builds via --sysroot). Export behaviors used in Soong will not be present
+	// for app developers as they don't use Soong, and reliance on these export
+	// behaviors can mask issues with the NDK sysroot.
 }
 
 type stubDecorator struct {
@@ -116,6 +125,7 @@
 	parsedCoverageXmlPath android.ModuleOutPath
 	installPath           android.Path
 	abiDumpPath           android.OutputPath
+	hasAbiDump            bool
 	abiDiffPaths          android.Paths
 
 	apiLevel         android.ApiLevel
@@ -321,11 +331,11 @@
 }
 
 // Feature flag.
-func canDumpAbi(config android.Config, moduleDir string) bool {
+func (this *stubDecorator) canDumpAbi(ctx ModuleContext) bool {
 	if runtime.GOOS == "darwin" {
 		return false
 	}
-	if strings.HasPrefix(moduleDir, "bionic/") {
+	if strings.HasPrefix(ctx.ModuleDir(), "bionic/") {
 		// Bionic has enough uncommon implementation details like ifuncs and asm
 		// code that the ABI tracking here has a ton of false positives. That's
 		// causing pretty extreme friction for development there, so disabling
@@ -334,8 +344,14 @@
 		// http://b/358653811
 		return false
 	}
+
+	if this.apiLevel.IsCurrent() {
+		// "current" (AKA 10000) is not tracked.
+		return false
+	}
+
 	// http://b/156513478
-	return config.ReleaseNdkAbiMonitored()
+	return ctx.Config().ReleaseNdkAbiMonitored()
 }
 
 // Feature flag to disable diffing against prebuilts.
@@ -348,6 +364,7 @@
 	this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
 		this.apiLevel.String(), ctx.Arch().ArchType.String(),
 		this.libraryName(ctx), "abi.stg")
+	this.hasAbiDump = true
 	headersList := getNdkABIHeadersFile(ctx)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        stg,
@@ -412,41 +429,45 @@
 	// Also ensure that the ABI of the next API level (if there is one) matches
 	// this API level. *New* ABI is allowed, but any changes to APIs that exist
 	// in this API level are disallowed.
-	if !this.apiLevel.IsCurrent() && prebuiltAbiDump.Valid() {
+	if prebuiltAbiDump.Valid() {
 		nextApiLevel := findNextApiLevel(ctx, this.apiLevel)
 		if nextApiLevel == nil {
 			panic(fmt.Errorf("could not determine which API level follows "+
 				"non-current API level %s", this.apiLevel))
 		}
-		nextAbiDiffPath := android.PathForModuleOut(ctx,
-			"abidiff_next.timestamp")
-		nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel)
-		missingNextPrebuiltError := fmt.Sprintf(
-			missingPrebuiltErrorTemplate, this.libraryName(ctx),
-			nextAbiDump.InvalidReason())
-		if !nextAbiDump.Valid() {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:   android.ErrorRule,
-				Output: nextAbiDiffPath,
-				Args: map[string]string{
-					"error": missingNextPrebuiltError,
-				},
-			})
-		} else {
-			ctx.Build(pctx, android.BuildParams{
-				Rule: stgdiff,
-				Description: fmt.Sprintf(
-					"Comparing ABI to the next API level %s %s",
-					prebuiltAbiDump, nextAbiDump),
-				Output: nextAbiDiffPath,
-				Inputs: android.Paths{
-					prebuiltAbiDump.Path(), nextAbiDump.Path()},
-				Args: map[string]string{
-					"args": "--format=small --ignore=interface_addition",
-				},
-			})
+
+		// "current" ABI is not tracked.
+		if !nextApiLevel.IsCurrent() {
+			nextAbiDiffPath := android.PathForModuleOut(ctx,
+				"abidiff_next.timestamp")
+			nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel)
+			missingNextPrebuiltError := fmt.Sprintf(
+				missingPrebuiltErrorTemplate, this.libraryName(ctx),
+				nextAbiDump.InvalidReason())
+			if !nextAbiDump.Valid() {
+				ctx.Build(pctx, android.BuildParams{
+					Rule:   android.ErrorRule,
+					Output: nextAbiDiffPath,
+					Args: map[string]string{
+						"error": missingNextPrebuiltError,
+					},
+				})
+			} else {
+				ctx.Build(pctx, android.BuildParams{
+					Rule: stgdiff,
+					Description: fmt.Sprintf(
+						"Comparing ABI to the next API level %s %s",
+						prebuiltAbiDump, nextAbiDump),
+					Output: nextAbiDiffPath,
+					Inputs: android.Paths{
+						prebuiltAbiDump.Path(), nextAbiDump.Path()},
+					Args: map[string]string{
+						"args": "--format=small --ignore=interface_addition",
+					},
+				})
+			}
+			this.abiDiffPaths = append(this.abiDiffPaths, nextAbiDiffPath)
 		}
-		this.abiDiffPaths = append(this.abiDiffPaths, nextAbiDiffPath)
 	}
 }
 
@@ -469,7 +490,7 @@
 	nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "")
 	objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
 	c.versionScriptPath = nativeAbiResult.versionScript
-	if canDumpAbi(ctx.Config(), ctx.ModuleDir()) {
+	if c.canDumpAbi(ctx) {
 		c.dumpAbi(ctx, nativeAbiResult.symbolList)
 		if canDiffAbi(ctx.Config()) {
 			c.diffAbi(ctx)
@@ -484,7 +505,8 @@
 // Add a dependency on the header modules of this ndk_library
 func (linker *stubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
 	return Deps{
-		HeaderLibs: linker.properties.Export_header_libs,
+		ReexportHeaderLibHeaders: linker.properties.Export_header_libs,
+		HeaderLibs:               linker.properties.Export_header_libs,
 	}
 }
 
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index f571523..92da172 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -79,7 +79,6 @@
 func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
 	ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
@@ -230,17 +229,6 @@
 			licensePaths = append(licensePaths, m.licensePath)
 		}
 
-		if m, ok := module.(*versionedHeaderModule); ok {
-			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
-			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
-			// Verification intentionally not done for headers that go through
-			// versioner. It'd be nice to have, but the only user is bionic, and
-			// that one module would also need to use skip_verification, so it
-			// wouldn't help at all.
-			installPaths = append(installPaths, m.installPaths...)
-			licensePaths = append(licensePaths, m.licensePath)
-		}
-
 		if m, ok := module.(*preprocessedHeadersModule); ok {
 			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
 			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
diff --git a/cc/object.go b/cc/object.go
index a4f4c84..c89520a 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -203,7 +203,7 @@
 	return outputFile
 }
 
-func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
 	eval := module.ConfigurableEvaluator(ctx)
 	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, object.Properties.Shared_libs.GetOrDefault(eval, nil)...)
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 7b0652c..a8722a0 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -79,7 +79,7 @@
 
 	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
 		"-fno-sanitize-recover=integer,undefined"}
-	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
+	memtagStackCommonFlags = []string{"-Xclang -target-feature -Xclang +mte"}
 	memtagStackLlvmFlags   = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
 
 	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
@@ -176,7 +176,7 @@
 	switch t {
 	case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack:
 		sanitizer := &sanitizerSplitMutator{t}
-		ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
+		ctx.BottomUp(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
 		ctx.Transition(t.variationName(), sanitizer)
 	case Memtag_heap, Memtag_globals, intOverflow:
 		// do nothing
@@ -1153,7 +1153,7 @@
 // If an APEX is sanitized or not depends on whether it contains at least one
 // sanitized module. Transition mutators cannot propagate information up the
 // dependency graph this way, so we need an auxiliary mutator to do so.
-func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) {
+func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.BottomUpMutatorContext) {
 	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
 		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
 		ctx.VisitDirectDeps(func(dep android.Module) {
@@ -1355,7 +1355,7 @@
 }
 
 // Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
-func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) {
+func sanitizerRuntimeDepsMutator(mctx android.BottomUpMutatorContext) {
 	// Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers.
 	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
 		if c.sanitize.Properties.ForceDisable {
@@ -1437,11 +1437,11 @@
 					//"null",
 					//"shift-base",
 					//"signed-integer-overflow",
-					// TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
-					// https://llvm.org/PR19302
-					// http://reviews.llvm.org/D6974
-					// "object-size",
 				)
+
+				if mctx.Config().ReleaseBuildObjectSizeSanitizer() {
+					sanitizers = append(sanitizers, "object-size")
+				}
 			}
 			sanitizers = append(sanitizers, sanProps.Misc_undefined...)
 		}
diff --git a/cc/sdk.go b/cc/sdk.go
index dc1261d..5dd44d8 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -51,13 +51,6 @@
 				return []string{""}
 			}
 		}
-	case *CcApiVariant:
-		ccApiVariant, _ := ctx.Module().(*CcApiVariant)
-		if String(ccApiVariant.properties.Variant) == "ndk" {
-			return []string{"sdk"}
-		} else {
-			return []string{""}
-		}
 	}
 
 	return []string{""}
@@ -84,11 +77,6 @@
 				return incomingVariation
 			}
 		}
-	case *CcApiVariant:
-		ccApiVariant, _ := ctx.Module().(*CcApiVariant)
-		if String(ccApiVariant.properties.Variant) == "ndk" {
-			return "sdk"
-		}
 	}
 
 	if ctx.IsAddingDependency() {
diff --git a/cc/testing.go b/cc/testing.go
index 159f86c..14a6b7a 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,7 +20,6 @@
 
 	"android/soong/android"
 	"android/soong/genrule"
-	"android/soong/multitree"
 )
 
 func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
@@ -29,9 +28,6 @@
 	RegisterBinaryBuildComponents(ctx)
 	RegisterLibraryBuildComponents(ctx)
 	RegisterLibraryHeadersBuildComponents(ctx)
-	RegisterLibraryStubBuildComponents(ctx)
-
-	multitree.RegisterApiImportsModule(ctx)
 
 	ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool)
 	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
diff --git a/cmd/extract_apks/bundle_proto/Android.bp b/cmd/extract_apks/bundle_proto/Android.bp
index e56c0fb..0abf1e2 100644
--- a/cmd/extract_apks/bundle_proto/Android.bp
+++ b/cmd/extract_apks/bundle_proto/Android.bp
@@ -10,4 +10,8 @@
     proto: {
         canonical_path_from_root: false,
     },
+    visibility: [
+        "//build/soong:__subpackages__",
+        "//tools/mainline:__subpackages__",
+    ],
 }
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 6459ea1..f3931a4 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -275,7 +275,10 @@
 			if !state.Inherit {
 				return nil, fmt.Errorf("Can't have inherit set to false")
 			}
-			env = append(env, *envVar.Name+"="+os.Getenv(*envVar.Name))
+			val, ok := os.LookupEnv(*envVar.Name)
+			if ok {
+				env = append(env, *envVar.Name+"="+val)
+			}
 		default:
 			return nil, fmt.Errorf("Unhandled state type")
 		}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index a8be7ec..577c6cc 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -15,7 +15,6 @@
 package main
 
 import (
-	"bytes"
 	"encoding/json"
 	"errors"
 	"flag"
@@ -29,10 +28,12 @@
 	"android/soong/android/allowlists"
 	"android/soong/bp2build"
 	"android/soong/shared"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/deptools"
 	"github.com/google/blueprint/metrics"
+	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 	androidProtobuf "google.golang.org/protobuf/android"
 )
@@ -42,8 +43,6 @@
 	availableEnvFile string
 	usedEnvFile      string
 
-	globFile    string
-	globListDir string
 	delveListen string
 	delvePath   string
 
@@ -64,8 +63,6 @@
 	flag.StringVar(&cmdlineArgs.SoongOutDir, "soong_out", "", "Soong output directory (usually $TOP/out/soong)")
 	flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables")
 	flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables")
-	flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
-	flag.StringVar(&globListDir, "globListDir", "", "the directory containing the glob list files")
 	flag.StringVar(&cmdlineArgs.OutDir, "out", "", "the ninja builddir directory")
 	flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse")
 
@@ -206,20 +203,6 @@
 	ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile)
 }
 
-func writeBuildGlobsNinjaFile(ctx *android.Context) {
-	ctx.EventHandler.Begin("globs_ninja_file")
-	defer ctx.EventHandler.End("globs_ninja_file")
-
-	globDir := bootstrap.GlobDirectory(ctx.Config().SoongOutDir(), globListDir)
-	err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
-		GlobLister: ctx.Globs,
-		GlobFile:   globFile,
-		GlobDir:    globDir,
-		SrcDir:     ctx.SrcDir(),
-	}, ctx.Config())
-	maybeQuit(err, "")
-}
-
 func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
 	eventHandler.Begin("ninja_deps")
 	defer eventHandler.End("ninja_deps")
@@ -229,7 +212,14 @@
 }
 
 // Check if there are changes to the environment file, product variable file and
-// soong_build binary, in which case no incremental will be performed.
+// soong_build binary, in which case no incremental will be performed. For env
+// variables we check the used env file, which will be removed in soong ui if
+// there is any changes to the env variables used last time, in which case the
+// check below will fail and a full build will be attempted. If any new env
+// variables are added in the new run, soong ui won't be able to detect it, the
+// used env file check below will pass. But unless there is a soong build code
+// change, in which case the soong build binary check will fail, otherwise the
+// new env variables shouldn't have any affect.
 func incrementalValid(config android.Config, configCacheFile string) (*ConfigCache, bool) {
 	var newConfigCache ConfigCache
 	data, err := os.ReadFile(shared.JoinPath(topDir, usedEnvFile))
@@ -283,7 +273,9 @@
 }
 
 // runSoongOnlyBuild runs the standard Soong build in a number of different modes.
-func runSoongOnlyBuild(ctx *android.Context, extraNinjaDeps []string) string {
+// It returns the path to the output file (usually the ninja file) and the deps that need
+// to trigger a soong rerun.
+func runSoongOnlyBuild(ctx *android.Context) (string, []string) {
 	ctx.EventHandler.Begin("soong_build")
 	defer ctx.EventHandler.End("soong_build")
 
@@ -299,37 +291,30 @@
 
 	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
 	maybeQuit(err, "")
-	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
-	writeBuildGlobsNinjaFile(ctx)
 
 	// Convert the Soong module graph into Bazel BUILD files.
 	switch ctx.Config().BuildMode {
 	case android.GenerateQueryView:
 		queryviewMarkerFile := cmdlineArgs.BazelQueryViewDir + ".marker"
 		runQueryView(cmdlineArgs.BazelQueryViewDir, queryviewMarkerFile, ctx)
-		writeDepFile(queryviewMarkerFile, ctx.EventHandler, ninjaDeps)
-		return queryviewMarkerFile
+		return queryviewMarkerFile, ninjaDeps
 	case android.GenerateModuleGraph:
 		writeJsonModuleGraphAndActions(ctx, cmdlineArgs)
-		writeDepFile(cmdlineArgs.ModuleGraphFile, ctx.EventHandler, ninjaDeps)
-		return cmdlineArgs.ModuleGraphFile
+		return cmdlineArgs.ModuleGraphFile, ninjaDeps
 	case android.GenerateDocFile:
 		// TODO: we could make writeDocs() return the list of documentation files
 		// written and add them to the .d file. Then soong_docs would be re-run
 		// whenever one is deleted.
 		err := writeDocs(ctx, shared.JoinPath(topDir, cmdlineArgs.DocFile))
 		maybeQuit(err, "error building Soong documentation")
-		writeDepFile(cmdlineArgs.DocFile, ctx.EventHandler, ninjaDeps)
-		return cmdlineArgs.DocFile
+		return cmdlineArgs.DocFile, ninjaDeps
 	default:
 		// The actual output (build.ninja) was written in the RunBlueprint() call
 		// above
-		writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 		if needToWriteNinjaHint(ctx) {
 			writeNinjaHint(ctx)
 		}
-		return cmdlineArgs.OutFile
+		return cmdlineArgs.OutFile, ninjaDeps
 	}
 }
 
@@ -359,6 +344,8 @@
 func main() {
 	flag.Parse()
 
+	soongStartTime := time.Now()
+
 	shared.ReexecWithDelveMaybe(delveListen, delvePath)
 	android.InitSandbox(topDir)
 
@@ -369,13 +356,6 @@
 		configuration.SetAllowMissingDependencies()
 	}
 
-	extraNinjaDeps := []string{configuration.ProductVariablesFileName, usedEnvFile}
-	if shared.IsDebugging() {
-		// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
-		// enabled even if it completed successfully.
-		extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
-	}
-
 	// Bypass configuration.Getenv, as LOG_DIR does not need to be dependency tracked. By definition, it will
 	// change between every CI build, so tracking it would require re-running Soong for every build.
 	metricsDir := availableEnv["LOG_DIR"]
@@ -393,7 +373,16 @@
 	ctx.SetIncrementalAnalysis(incremental)
 
 	ctx.Register()
-	finalOutputFile := runSoongOnlyBuild(ctx, extraNinjaDeps)
+	finalOutputFile, ninjaDeps := runSoongOnlyBuild(ctx)
+
+	ninjaDeps = append(ninjaDeps, usedEnvFile)
+	if shared.IsDebugging() {
+		// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
+		// enabled even if it completed successfully.
+		ninjaDeps = append(ninjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
+	}
+
+	writeDepFile(finalOutputFile, ctx.EventHandler, ninjaDeps)
 
 	if ctx.GetIncrementalEnabled() {
 		data, err := shared.EnvFileContents(configuration.EnvDeps())
@@ -407,6 +396,9 @@
 
 	writeUsedEnvironmentFile(configuration)
 
+	err = writeGlobFile(ctx.EventHandler, finalOutputFile, ctx.Globs(), soongStartTime)
+	maybeQuit(err, "")
+
 	// Touch the output file so that it's the newest file created by soong_build.
 	// This is necessary because, if soong_build generated any files which
 	// are ninja inputs to the main output file, then ninja would superfluously
@@ -423,18 +415,33 @@
 	data, err := shared.EnvFileContents(configuration.EnvDeps())
 	maybeQuit(err, "error writing used environment file '%s'\n", usedEnvFile)
 
-	if preexistingData, err := os.ReadFile(path); err != nil {
-		if !os.IsNotExist(err) {
-			maybeQuit(err, "error reading used environment file '%s'", usedEnvFile)
-		}
-	} else if bytes.Equal(preexistingData, data) {
-		// used environment file is unchanged
-		return
-	}
-	err = os.WriteFile(path, data, 0666)
+	err = pathtools.WriteFileIfChanged(path, data, 0666)
 	maybeQuit(err, "error writing used environment file '%s'", usedEnvFile)
 }
 
+func writeGlobFile(eventHandler *metrics.EventHandler, finalOutFile string, globs pathtools.MultipleGlobResults, soongStartTime time.Time) error {
+	eventHandler.Begin("writeGlobFile")
+	defer eventHandler.End("writeGlobFile")
+
+	globsFile, err := os.Create(shared.JoinPath(topDir, finalOutFile+".globs"))
+	if err != nil {
+		return err
+	}
+	defer globsFile.Close()
+	globsFileEncoder := json.NewEncoder(globsFile)
+	for _, glob := range globs {
+		if err := globsFileEncoder.Encode(glob); err != nil {
+			return err
+		}
+	}
+
+	return os.WriteFile(
+		shared.JoinPath(topDir, finalOutFile+".globs_time"),
+		[]byte(fmt.Sprintf("%d\n", soongStartTime.UnixMicro())),
+		0666,
+	)
+}
+
 func touch(path string) {
 	f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
 	maybeQuit(err, "Error touching '%s'", path)
diff --git a/cmd/symbols_map/Android.bp b/cmd/symbols_map/Android.bp
index e3ae6ed..272e806 100644
--- a/cmd/symbols_map/Android.bp
+++ b/cmd/symbols_map/Android.bp
@@ -30,4 +30,5 @@
     srcs: [
         "symbols_map_proto/symbols_map.pb.go",
     ],
+    visibility: ["//visibility:public"],
 }
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 3ef7668..7f9b165 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -27,4 +27,6 @@
         "zip2zip.go",
     ],
     testSrcs: ["zip2zip_test.go"],
+    // Used by genrules
+    visibility: ["//visibility:public"],
 }
diff --git a/compliance/Android.bp b/compliance/Android.bp
new file mode 100644
index 0000000..08736b4
--- /dev/null
+++ b/compliance/Android.bp
@@ -0,0 +1,39 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-compliance",
+    pkgPath: "android/soong/compliance",
+    deps: [
+        "soong-android",
+    ],
+    srcs: [
+        "notice.go",
+    ],
+    testSrcs: [
+    ],
+    pluginFor: ["soong_build"],
+}
+
+notice_xml {
+    name: "notice_xml_system",
+    partition_name: "system",
+    visibility: [
+        "//device/google/cuttlefish/system_image",
+    ],
+}
diff --git a/compliance/license_metadata_proto/Android.bp b/compliance/license_metadata_proto/Android.bp
index 3c041e4..4761285 100644
--- a/compliance/license_metadata_proto/Android.bp
+++ b/compliance/license_metadata_proto/Android.bp
@@ -24,4 +24,8 @@
         "golang-protobuf-reflect-protoreflect",
         "golang-protobuf-runtime-protoimpl",
     ],
+    visibility: [
+        "//build/make/tools/compliance:__subpackages__",
+        "//build/soong:__subpackages__",
+    ],
 }
diff --git a/compliance/notice.go b/compliance/notice.go
new file mode 100644
index 0000000..4fc83ab
--- /dev/null
+++ b/compliance/notice.go
@@ -0,0 +1,100 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package compliance
+
+import (
+	"path/filepath"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterNoticeXmlBuildComponents(android.InitRegistrationContext)
+}
+
+var PrepareForTestWithNoticeXmlBuildComponents = android.GroupFixturePreparers(
+	android.FixtureRegisterWithContext(RegisterNoticeXmlBuildComponents),
+)
+
+var PrepareForTestWithNoticeXml = android.GroupFixturePreparers(
+	PrepareForTestWithNoticeXmlBuildComponents,
+)
+
+func RegisterNoticeXmlBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("notice_xml", NoticeXmlFactory)
+}
+
+var (
+	pctx = android.NewPackageContext("android/soong/compliance")
+
+	genNoticeXml = pctx.HostBinToolVariable("genNoticeXml", "gen_notice_xml")
+
+	// Command to generate NOTICE.xml.gz for a partition
+	genNoticeXmlRule = pctx.AndroidStaticRule("genNoticeXmlRule", blueprint.RuleParams{
+		Command: "rm -rf $out && " +
+			"${genNoticeXml} --output_file ${out} --metadata ${in} --partition ${partition} --product_out ${productOut} --soong_out ${soongOut}",
+		CommandDeps: []string{"${genNoticeXml}"},
+	}, "partition", "productOut", "soongOut")
+)
+
+func NoticeXmlFactory() android.Module {
+	m := &NoticeXmlModule{}
+	m.AddProperties(&m.props)
+	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibFirst)
+	return m
+}
+
+type NoticeXmlModule struct {
+	android.ModuleBase
+
+	props noticeXmlProperties
+
+	outputFile  android.OutputPath
+	installPath android.InstallPath
+}
+
+type noticeXmlProperties struct {
+	Partition_name string
+}
+
+func (nx *NoticeXmlModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	output := android.PathForModuleOut(ctx, "NOTICE.xml.gz")
+	metadataDb := android.PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "compliance-metadata.db")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   genNoticeXmlRule,
+		Input:  metadataDb,
+		Output: output,
+		Args: map[string]string{
+			"productOut": filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()),
+			"soongOut":   ctx.Config().SoongOutDir(),
+			"partition":  nx.props.Partition_name,
+		},
+	})
+
+	nx.outputFile = output.OutputPath
+
+	if android.Bool(ctx.Config().ProductVariables().UseSoongSystemImage) {
+		nx.installPath = android.PathForModuleInPartitionInstall(ctx, nx.props.Partition_name, "etc")
+		ctx.InstallFile(nx.installPath, "NOTICE.xml.gz", nx.outputFile)
+	}
+}
+
+func (nx *NoticeXmlModule) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(nx.outputFile),
+	}}
+}
diff --git a/compliance/notice_test.go b/compliance/notice_test.go
new file mode 100644
index 0000000..6187e53
--- /dev/null
+++ b/compliance/notice_test.go
@@ -0,0 +1,38 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package compliance
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+var prepareForNoticeXmlTest = android.GroupFixturePreparers(
+	android.PrepareForTestWithArchMutator,
+	PrepareForTestWithNoticeXml,
+)
+
+func TestPrebuiltEtcOutputFile(t *testing.T) {
+	result := prepareForNoticeXmlTest.RunTestWithBp(t, `
+		notice_xml {
+			name: "notice_xml_system",
+			partition_name: "system",
+		}
+	`)
+
+	m := result.Module("notice_xml_system", "android_arm64_armv8-a").(*NoticeXmlModule)
+	android.AssertStringEquals(t, "output file", "NOTICE.xml.gz", m.outputFile.Base())
+}
\ No newline at end of file
diff --git a/compliance/project_metadata_proto/Android.bp b/compliance/project_metadata_proto/Android.bp
index 56e76e7..0c807b2 100644
--- a/compliance/project_metadata_proto/Android.bp
+++ b/compliance/project_metadata_proto/Android.bp
@@ -24,4 +24,5 @@
         "golang-protobuf-reflect-protoreflect",
         "golang-protobuf-runtime-protoimpl",
     ],
+    visibility: ["//build/make/tools/compliance:__subpackages__"],
 }
diff --git a/docs/OWNERS b/docs/OWNERS
new file mode 100644
index 0000000..776beca
--- /dev/null
+++ b/docs/OWNERS
@@ -0,0 +1 @@
+per-file map_files.md = danalbert@google.com
diff --git a/docs/map_files.md b/docs/map_files.md
index e1ddefc..8d6af87 100644
--- a/docs/map_files.md
+++ b/docs/map_files.md
@@ -88,12 +88,17 @@
 
 ### introduced
 
-Indicates the version in which an API was first introduced. For example,
-`introduced=21` specifies that the API was first added (or first made public) in
-API level 21. This tag can be applied to either a version definition or an
-individual symbol. If applied to a version, all symbols contained in the version
-will have the tag applied. An `introduced` tag on a symbol overrides the value
-set for the version, if both are defined.
+Indicates the version in which an API was first introduced in the NDK. For
+example, `introduced=21` specifies that the API was first added (or first made
+public) in API level 21. This tag can be applied to either a version definition
+or an individual symbol. If applied to a version, all symbols contained in the
+version will have the tag applied. An `introduced` tag on a symbol overrides the
+value set for the version, if both are defined.
+
+The `introduced` tag should only be used with NDK APIs. Other API surface tags
+(such as `apex`) will override `introduced`. APIs that are in the NDK should
+never use tags like `apex`, and APIs that are not in the NDK should never use
+`introduced`.
 
 Note: The map file alone does not contain all the information needed to
 determine which API level an API was added in. The `first_version` property of
diff --git a/docs/tidy.md b/docs/tidy.md
index ae0ca93..2e4c957 100644
--- a/docs/tidy.md
+++ b/docs/tidy.md
@@ -38,7 +38,7 @@
 clang-tidy is enabled explicitly and with a different check list:
 ```
 cc_defaults {
-    name: "bpf_defaults",
+    name: "bpf_cc_defaults",
     // snipped
     tidy: true,
     tidy_checks: [
@@ -52,7 +52,7 @@
 }
 ```
 That means in normal builds, even without `WITH_TIDY=1`,
-the modules that use `bpf_defaults` _should_ run clang-tidy
+the modules that use `bpf_cc_defaults` _should_ run clang-tidy
 over C/C++ source files with the given `tidy_checks`.
 
 However since clang-tidy warnings and its runtime cost might
diff --git a/etc/Android.bp b/etc/Android.bp
index f02c12a..580c54f 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -20,4 +20,6 @@
         "install_symlink_test.go",
     ],
     pluginFor: ["soong_build"],
+    // Used by plugins
+    visibility: ["//visibility:public"],
 }
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 5c7ef43..0353992 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -147,14 +147,14 @@
 func filesystemFactory() android.Module {
 	module := &filesystem{}
 	module.filterPackagingSpec = module.filterInstallablePackagingSpec
-	initFilesystemModule(module)
+	initFilesystemModule(module, module)
 	return module
 }
 
-func initFilesystemModule(module *filesystem) {
-	module.AddProperties(&module.properties)
-	android.InitPackageModule(module)
-	module.PackagingBase.DepsCollectFirstTargetOnly = true
+func initFilesystemModule(module android.DefaultableModule, filesystemModule *filesystem) {
+	module.AddProperties(&filesystemModule.properties)
+	android.InitPackageModule(filesystemModule)
+	filesystemModule.PackagingBase.DepsCollectFirstTargetOnly = true
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 }
@@ -331,6 +331,14 @@
 	return f.CopySpecsToDirs(ctx, builder, dirsToSpecs)
 }
 
+func (f *filesystem) copyFilesToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) {
+	if f.Name() != ctx.Config().SoongDefinedSystemImage() {
+		return
+	}
+	installPath := android.PathForModuleInPartitionInstall(ctx, f.partitionName())
+	builder.Command().Textf("cp -prf %s/* %s", rebasedDir, installPath)
+}
+
 func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
 	rebasedDir := rootDir
@@ -348,6 +356,7 @@
 	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 	f.buildEventLogtagsFile(ctx, builder, rebasedDir)
 	f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
+	f.copyFilesToProductOut(ctx, builder, rebasedDir)
 
 	// run host_init_verifier
 	// Ideally we should have a concept of pluggable linters that verify the generated image.
@@ -490,6 +499,7 @@
 	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 	f.buildEventLogtagsFile(ctx, builder, rebasedDir)
 	f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
+	f.copyFilesToProductOut(ctx, builder, rebasedDir)
 
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 	cmd := builder.Command().
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index a8fd368..63cb627 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -27,7 +27,7 @@
 
 type systemImageProperties struct {
 	// Path to the input linker config json file.
-	Linker_config_src *string
+	Linker_config_src *string `android:"path"`
 }
 
 // android_system_image is a specialization of android_filesystem for the 'system' partition.
@@ -38,7 +38,7 @@
 	module.AddProperties(&module.properties)
 	module.filesystem.buildExtraFiles = module.buildExtraFiles
 	module.filesystem.filterPackagingSpec = module.filterPackagingSpec
-	initFilesystemModule(&module.filesystem)
+	initFilesystemModule(module, &module.filesystem)
 	return module
 }
 
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 3a9a64d..1d64796 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -213,6 +213,7 @@
 	ctx.InstallFile(v.installDir, v.installFileName(), v.output)
 
 	ctx.SetOutputFiles([]android.Path{v.output}, "")
+	android.SetProvider(ctx, android.AndroidMkInfoProvider, v.prepareAndroidMKProviderInfo())
 }
 
 // Returns the embedded shell command that prints the rollback index
@@ -265,20 +266,17 @@
 	return result
 }
 
-var _ android.AndroidMkEntriesProvider = (*vbmeta)(nil)
-
-// Implements android.AndroidMkEntriesProvider
-func (v *vbmeta) AndroidMkEntries() []android.AndroidMkEntries {
-	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "ETC",
-		OutputFile: android.OptionalPathForPath(v.output),
-		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
-			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-				entries.SetString("LOCAL_MODULE_PATH", v.installDir.String())
-				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
-			},
+func (v *vbmeta) prepareAndroidMKProviderInfo() *android.AndroidMkProviderInfo {
+	providerData := android.AndroidMkProviderInfo{
+		PrimaryInfo: android.AndroidMkInfo{
+			Class:      "ETC",
+			OutputFile: android.OptionalPathForPath(v.output),
+			EntryMap:   make(map[string][]string),
 		},
-	}}
+	}
+	providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String())
+	providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
+	return &providerData
 }
 
 var _ Filesystem = (*vbmeta)(nil)
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 306d65e..a059837 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -449,7 +449,7 @@
 	}
 }
 
-func IsValid(ctx android.ConfigAndErrorContext, fuzzModule FuzzModule) bool {
+func IsValid(ctx android.ConfigurableEvaluatorContext, fuzzModule FuzzModule) bool {
 	// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
 	// fuzz targets we're going to package anyway.
 	if !fuzzModule.Enabled(ctx) || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() {
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 7331741..f4197e6 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -22,4 +22,6 @@
         "genrule_test.go",
     ],
     pluginFor: ["soong_build"],
+    // Used by plugins
+    visibility: ["//visibility:public"],
 }
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 4f1b320..45a7f72 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -17,7 +17,6 @@
 var (
 	SandboxingDenyModuleList = []string{
 		// go/keep-sorted start
-		"com.google.pixel.camera.hal.manifest",
 		// go/keep-sorted end
 	}
 )
diff --git a/genrule/genrule.go b/genrule/genrule.go
index fd72d3c..a48038b 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -25,7 +25,6 @@
 	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -365,11 +364,6 @@
 						tools = append(tools, path.Path())
 						addLocationLabel(tag.label, toolLocation{android.Paths{path.Path()}})
 					}
-				case bootstrap.GoBinaryTool:
-					// A GoBinaryTool provides the install path to a tool, which will be copied.
-					p := android.PathForGoBinary(ctx, t)
-					tools = append(tools, p)
-					addLocationLabel(tag.label, toolLocation{android.Paths{p}})
 				default:
 					ctx.ModuleErrorf("%q is not a host tool provider", tool)
 					return
diff --git a/golang/Android.bp b/golang/Android.bp
new file mode 100644
index 0000000..3eae94f
--- /dev/null
+++ b/golang/Android.bp
@@ -0,0 +1,22 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-golang",
+    pkgPath: "android/soong/golang",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "blueprint-bootstrap",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "golang.go",
+    ],
+    testSrcs: [
+        "golang_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/golang/golang.go b/golang/golang.go
new file mode 100644
index 0000000..618a085
--- /dev/null
+++ b/golang/golang.go
@@ -0,0 +1,136 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+// Package golang wraps the blueprint blueprint_go_binary and bootstrap_go_binary module types in versions
+// that implement android.Module that are used when building in Soong.  This simplifies the code in Soong
+// so it can always assume modules are an android.Module.
+// The original blueprint blueprint_go_binary and bootstrap_go_binary module types are still used during
+// bootstrapping, so the Android.bp entries for these module types must be compatible with both the
+// original blueprint module types and these wrapped module types.
+package golang
+
+import (
+	"android/soong/android"
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/bootstrap"
+)
+
+func init() {
+	// Wrap the blueprint Go module types with Soong ones that interoperate with the rest of the Soong modules.
+	bootstrap.GoModuleTypesAreWrapped()
+	RegisterGoModuleTypes(android.InitRegistrationContext)
+}
+
+func RegisterGoModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("bootstrap_go_package", goPackageModuleFactory)
+	ctx.RegisterModuleType("blueprint_go_binary", goBinaryModuleFactory)
+}
+
+// A GoPackage is a module for building Go packages.
+type GoPackage struct {
+	android.ModuleBase
+	bootstrap.GoPackage
+}
+
+func goPackageModuleFactory() android.Module {
+	module := &GoPackage{}
+	module.AddProperties(module.Properties()...)
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	return module
+}
+
+func (g *GoPackage) GenerateBuildActions(ctx blueprint.ModuleContext) {
+	// The embedded ModuleBase and bootstrap.GoPackage each implement GenerateBuildActions,
+	// the delegation has to be implemented manually to disambiguate.  Call ModuleBase's
+	// GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call
+	// bootstrap.GoPackage.GenerateBuildActions.
+	g.ModuleBase.GenerateBuildActions(ctx)
+}
+
+func (g *GoPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	g.GoPackage.GenerateBuildActions(ctx.BlueprintModuleContext())
+}
+
+// A GoBinary is a module for building executable binaries from Go sources.
+type GoBinary struct {
+	android.ModuleBase
+	bootstrap.GoBinary
+
+	outputFile android.Path
+}
+
+func goBinaryModuleFactory() android.Module {
+	module := &GoBinary{}
+	module.AddProperties(module.Properties()...)
+	android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst)
+	return module
+}
+
+func (g *GoBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
+	// The embedded ModuleBase and bootstrap.GoBinary each implement GenerateBuildActions,
+	// the delegation has to be implemented manually to disambiguate.  Call ModuleBase's
+	// GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call
+	// bootstrap.GoBinary.GenerateBuildActions.
+	g.ModuleBase.GenerateBuildActions(ctx)
+}
+
+func (g *GoBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Install the file in Soong instead of blueprint so that Soong knows about the install rules.
+	g.GoBinary.SetSkipInstall()
+
+	// Run the build actions from the wrapped blueprint bootstrap module.
+	g.GoBinary.GenerateBuildActions(ctx.BlueprintModuleContext())
+
+	// Translate the bootstrap module's string path into a Path
+	outputFile := android.PathForArbitraryOutput(ctx, android.Rel(ctx, ctx.Config().OutDir(), g.IntermediateFile())).WithoutRel()
+	g.outputFile = outputFile
+
+	// Don't create install rules for modules used by bootstrap, the install command line will differ from
+	// what was used during bootstrap, which will cause ninja to rebuild the module on the next run,
+	// triggering reanalysis.
+	if !usedByBootstrap(ctx.ModuleName()) {
+		installPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), outputFile)
+
+		// Modules in an unexported namespace have no install rule, only add modules in the exported namespaces
+		// to the blueprint_tools phony rules.
+		if !ctx.Config().KatiEnabled() || g.ExportedToMake() {
+			ctx.Phony("blueprint_tools", installPath)
+		}
+	}
+
+	ctx.SetOutputFiles(android.Paths{outputFile}, "")
+}
+
+func usedByBootstrap(name string) bool {
+	switch name {
+	case "loadplugins", "soong_build":
+		return true
+	default:
+		return false
+	}
+}
+
+func (g *GoBinary) HostToolPath() android.OptionalPath {
+	return android.OptionalPathForPath(g.outputFile)
+}
+
+func (g *GoBinary) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{
+		{
+			Class:      "EXECUTABLES",
+			OutputFile: android.OptionalPathForPath(g.outputFile),
+			Include:    "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
+		},
+	}
+}
diff --git a/golang/golang_test.go b/golang/golang_test.go
new file mode 100644
index 0000000..b512144
--- /dev/null
+++ b/golang/golang_test.go
@@ -0,0 +1,51 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package golang
+
+import (
+	"android/soong/android"
+	"github.com/google/blueprint/bootstrap"
+	"path/filepath"
+	"testing"
+)
+
+func TestGolang(t *testing.T) {
+	bp := `
+		bootstrap_go_package {
+			name: "gopkg",
+			pkgPath: "test/pkg",
+		}
+
+		blueprint_go_binary {
+			name: "gobin",
+			deps: ["gopkg"],
+		}
+	`
+
+	result := android.GroupFixturePreparers(
+		android.PrepareForTestWithArchMutator,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			RegisterGoModuleTypes(ctx)
+			ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+				ctx.BottomUpBlueprint("bootstrap_deps", bootstrap.BootstrapDeps)
+			})
+		}),
+	).RunTestWithBp(t, bp)
+
+	bin := result.ModuleForTests("gobin", result.Config.BuildOSTarget.String())
+
+	expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "bin/go/gobin/obj/gobin")
+	android.AssertPathsRelativeToTopEquals(t, "output files", []string{expected}, bin.OutputFiles(result.TestContext, t, ""))
+}
diff --git a/java/Android.bp b/java/Android.bp
index 9603815..926a294 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -120,4 +120,5 @@
         "test_spec_test.go",
     ],
     pluginFor: ["soong_build"],
+    visibility: ["//visibility:public"],
 }
diff --git a/java/aar.go b/java/aar.go
index 1bd372f..b5e24c4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -15,10 +15,10 @@
 package java
 
 import (
+	"crypto/sha256"
 	"fmt"
 	"path/filepath"
 	"slices"
-	"strconv"
 	"strings"
 
 	"android/soong/android"
@@ -236,18 +236,20 @@
 		rroDirs = append(rroDirs, resRRODirs...)
 	}
 
+	assetDirsHasher := sha256.New()
 	var assetDeps android.Paths
-	for i, dir := range assetDirs {
+	for _, dir := range assetDirs {
 		// Add a dependency on every file in the asset directory.  This ensures the aapt2
 		// rule will be rerun if one of the files in the asset directory is modified.
-		assetDeps = append(assetDeps, androidResourceGlob(ctx, dir)...)
+		dirContents := androidResourceGlob(ctx, dir)
+		assetDeps = append(assetDeps, dirContents...)
 
-		// Add a dependency on a file that contains a list of all the files in the asset directory.
+		// Add a hash of all the files in the asset directory to the command line.
 		// This ensures the aapt2 rule will be run if a file is removed from the asset directory,
 		// or a file is added whose timestamp is older than the output of aapt2.
-		assetFileListFile := android.PathForModuleOut(ctx, "asset_dir_globs", strconv.Itoa(i)+".glob")
-		androidResourceGlobList(ctx, dir, assetFileListFile)
-		assetDeps = append(assetDeps, assetFileListFile)
+		for _, path := range dirContents.Strings() {
+			assetDirsHasher.Write([]byte(path))
+		}
 	}
 
 	assetDirStrings := assetDirs.Strings()
@@ -282,6 +284,7 @@
 	linkDeps = append(linkDeps, manifestPath)
 
 	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A "))
+	linkFlags = append(linkFlags, fmt.Sprintf("$$(: %x)", assetDirsHasher.Sum(nil)))
 	linkDeps = append(linkDeps, assetDeps...)
 
 	// Returns the effective version for {min|target}_sdk_version
@@ -403,6 +406,7 @@
 			packageName:        a.manifestValues.applicationId,
 		}
 		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams)
+		ctx.CheckbuildFile(a.mergedManifestFile)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
 			// will be propagated to the final application and merged there.  The merged manifest for libraries is
@@ -537,6 +541,8 @@
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
 		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
 		opts.aconfigTextFiles)
+	ctx.CheckbuildFile(packageRes)
+
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
 	if android.PrefixInList(linkFlags, "-A ") {
@@ -881,13 +887,12 @@
 		extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
 	}
 
-	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil)
 
 	a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
 	var res android.Paths
 	if a.androidLibraryProperties.BuildAAR {
 		BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res)
-		ctx.CheckbuildFile(a.aarFile)
 	}
 
 	prebuiltJniPackages := android.Paths{}
@@ -968,7 +973,7 @@
 	// Defaults to sdk_version if not set. See sdk_version for possible values.
 	Min_sdk_version *string
 	// List of java static libraries that the included ARR (android library prebuilts) has dependencies to.
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 	// List of java libraries that the included ARR (android library prebuilts) has dependencies to.
 	Libs []string
 	// If set to true, run Jetifier against .aar file. Defaults to false.
@@ -991,7 +996,7 @@
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
 
-	providesTransitiveHeaderJars
+	providesTransitiveHeaderJarsForR8
 
 	properties AARImportProperties
 
@@ -1098,7 +1103,7 @@
 	}
 
 	ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...)
-	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs.GetOrDefault(ctx, nil)...)
 
 	a.usesLibrary.deps(ctx, false)
 }
@@ -1252,10 +1257,12 @@
 	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
 	aapt2Link(ctx, exportPackage, nil, proguardOptionsFile, aaptRTxt,
 		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
+	ctx.CheckbuildFile(exportPackage)
 	a.exportPackage = exportPackage
 
 	rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
 	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, rJar, nil, true, nil, false)
+	ctx.CheckbuildFile(rJar)
 	a.rJar = rJar
 
 	aapt2ExtractExtraPackages(ctx, extraAaptPackagesFile, a.rJar)
@@ -1286,13 +1293,17 @@
 	android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
 	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 
-	a.collectTransitiveHeaderJars(ctx)
+	a.collectTransitiveHeaderJarsForR8(ctx)
 
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
 	var staticJars android.Paths
 	var staticHeaderJars android.Paths
 	var staticResourceJars android.Paths
+	var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsImplementationJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsResourceJars []*android.DepSet[android.Path]
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			tag := ctx.OtherModuleDependencyTag(module)
@@ -1301,63 +1312,111 @@
 				staticJars = append(staticJars, dep.ImplementationJars...)
 				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
 				staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
+				if dep.TransitiveStaticLibsImplementationJars != nil {
+					transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+				}
+				if dep.TransitiveStaticLibsResourceJars != nil {
+					transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars)
+				}
 			}
 		}
 		addCLCFromDep(ctx, module, a.classLoaderContexts)
 		addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary)
 	})
 
+	completeStaticLibsHeaderJars := android.NewDepSet(android.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsHeaderJars)
+	completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsImplementationJars)
+	completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsResourceJars)
+
 	var implementationJarFile android.Path
-	if len(staticJars) > 0 {
-		combineJars := append(android.Paths{classpathFile}, staticJars...)
-		combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName).OutputPath
-		TransformJarsToJar(ctx, combinedImplementationJar, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
-		implementationJarFile = combinedImplementationJar
+	var combineJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		combineJars = completeStaticLibsImplementationJars.ToList()
+	} else {
+		combineJars = append(android.Paths{classpathFile}, staticJars...)
+	}
+
+	if len(combineJars) > 1 {
+		implementationJarOutputPath := android.PathForModuleOut(ctx, "combined", jarName)
+		TransformJarsToJar(ctx, implementationJarOutputPath, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+		implementationJarFile = implementationJarOutputPath
 	} else {
 		implementationJarFile = classpathFile
 	}
 
 	var resourceJarFile android.Path
-	if len(staticResourceJars) > 1 {
+	var resourceJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		resourceJars = completeStaticLibsResourceJars.ToList()
+	} else {
+		resourceJars = staticResourceJars
+	}
+	if len(resourceJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
 			false, nil, nil)
 		resourceJarFile = combinedJar
-	} else if len(staticResourceJars) == 1 {
-		resourceJarFile = staticResourceJars[0]
+	} else if len(resourceJars) == 1 {
+		resourceJarFile = resourceJars[0]
 	}
 
 	// merge implementation jar with resources if necessary
-	implementationAndResourcesJar := implementationJarFile
-	if resourceJarFile != nil {
-		jars := android.Paths{resourceJarFile, implementationAndResourcesJar}
+	var implementationAndResourcesJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		implementationAndResourcesJars = append(slices.Clone(resourceJars), combineJars...)
+	} else {
+		implementationAndResourcesJars = android.PathsIfNonNil(resourceJarFile, implementationJarFile)
+	}
+	var implementationAndResourcesJar android.Path
+	if len(implementationAndResourcesJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJars, android.OptionalPath{},
 			false, nil, nil)
 		implementationAndResourcesJar = combinedJar
+	} else {
+		implementationAndResourcesJar = implementationAndResourcesJars[0]
 	}
 
 	a.implementationJarFile = implementationJarFile
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
 	a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel()
 
-	if len(staticHeaderJars) > 0 {
-		combineJars := append(android.Paths{classpathFile}, staticHeaderJars...)
+	var headerJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		headerJars = completeStaticLibsHeaderJars.ToList()
+	} else {
+		headerJars = append(android.Paths{classpathFile}, staticHeaderJars...)
+	}
+	if len(headerJars) > 1 {
 		headerJarFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
-		TransformJarsToJar(ctx, headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil)
+		TransformJarsToJar(ctx, headerJarFile, "combine header jars", headerJars, android.OptionalPath{}, false, nil, nil)
 		a.headerJarFile = headerJarFile
 	} else {
-		a.headerJarFile = classpathFile
+		a.headerJarFile = headerJars[0]
+	}
+
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		ctx.CheckbuildFile(classpathFile)
+	} else {
+		ctx.CheckbuildFile(a.headerJarFile)
+		ctx.CheckbuildFile(a.implementationJarFile)
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(a.headerJarFile),
-		ResourceJars:                   android.PathsIfNonNil(resourceJarFile),
-		TransitiveLibsHeaderJars:       a.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile),
-		ImplementationJars:             android.PathsIfNonNil(a.implementationJarFile),
-		StubsLinkType:                  Implementation,
+		HeaderJars:                             android.PathsIfNonNil(a.headerJarFile),
+		LocalHeaderJars:                        android.PathsIfNonNil(classpathFile),
+		TransitiveStaticLibsHeaderJars:         completeStaticLibsHeaderJars,
+		TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+		TransitiveStaticLibsResourceJars:       completeStaticLibsResourceJars,
+		ResourceJars:                           android.PathsIfNonNil(resourceJarFile),
+		TransitiveLibsHeaderJarsForR8:          a.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8:    a.transitiveStaticLibsHeaderJarsForR8,
+		ImplementationAndResourcesJars:         android.PathsIfNonNil(a.implementationAndResourcesJarFile),
+		ImplementationJars:                     android.PathsIfNonNil(a.implementationJarFile),
+		StubsLinkType:                          Implementation,
 		// TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 
diff --git a/java/android_resources.go b/java/android_resources.go
index 038a260..3bb3eb5 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -39,15 +39,6 @@
 	return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
 }
 
-// androidResourceGlobList creates a rule to write the list of files in the given directory, using
-// the standard exclusion patterns for Android resources, to the given output file.
-func androidResourceGlobList(ctx android.ModuleContext, dir android.Path,
-	fileListFile android.WritablePath) {
-
-	android.GlobToListFileRule(ctx, filepath.Join(dir.String(), "**/*"),
-		androidResourceIgnoreFilenames, fileListFile)
-}
-
 type overlayType int
 
 const (
diff --git a/java/app.go b/java/app.go
index abd78b7..4ac42a7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -690,7 +690,7 @@
 			extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
 		}
 
-		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil)
 		if a.dexProperties.resourceShrinkingEnabled(ctx) {
 			binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
 			aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
@@ -1009,6 +1009,8 @@
 		ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
 	}
 
+	ctx.CheckbuildFile(a.outputFile)
+
 	a.buildAppDependencyInfo(ctx)
 
 	providePrebuiltInfo(ctx,
@@ -1471,7 +1473,23 @@
 	return testConfig
 }
 
+func (a *AndroidTestHelperApp) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if len(a.ApexProperties.Apex_available) == 0 && ctx.Config().IsEnvTrue("EMMA_API_MAPPER") {
+		// Instrument the android_test_helper target to log potential API calls at the run time.
+		// Contact android-xts-infra team before using the environment var EMMA_API_MAPPER.
+		ctx.AddVariationDependencies(nil, staticLibTag, "apimapper-helper-device-lib")
+		a.setApiMapper(true)
+	}
+	a.AndroidApp.DepsMutator(ctx)
+}
+
 func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if len(a.ApexProperties.Apex_available) == 0 && ctx.Config().IsEnvTrue("EMMA_API_MAPPER") {
+		// Instrument the android_test_helper target to log potential API calls at the run time.
+		// Contact android-xts-infra team before using the environment var EMMA_API_MAPPER.
+		ctx.AddVariationDependencies(nil, staticLibTag, "apimapper-helper-device-lib")
+		a.setApiMapper(true)
+	}
 	a.AndroidApp.DepsMutator(ctx)
 }
 
diff --git a/java/app_test.go b/java/app_test.go
index ec97a55..d7f5f0c 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3241,7 +3241,7 @@
 		java_library {
 			name: "static-runtime-helper",
 			srcs: ["a.java"],
-			libs: ["runtime-library"],
+			libs: ["runtime-library.impl"],
 			sdk_version: "current",
 		}
 
@@ -3305,7 +3305,7 @@
 			name: "app",
 			srcs: ["a.java"],
 			libs: [
-				"qux",
+				"qux.impl",
 				"quuz.stubs"
 			],
 			static_libs: [
diff --git a/java/base.go b/java/base.go
index 4cd6021..b64eb5b 100644
--- a/java/base.go
+++ b/java/base.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"encoding/gob"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -80,7 +81,7 @@
 	Libs []string `android:"arch_variant"`
 
 	// list of java libraries that will be compiled into the resulting jar
-	Static_libs []string `android:"arch_variant"`
+	Static_libs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// list of java libraries that should not be used to build this module
 	Exclude_static_libs []string `android:"arch_variant"`
@@ -98,9 +99,6 @@
 	// if not blank, used as prefix to generate repackage rule
 	Jarjar_prefix *string
 
-	// if set to true, skip the jarjar repackaging
-	Skip_jarjar_repackage *bool
-
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
 
@@ -233,6 +231,10 @@
 	// Contributing api surface of the stub module. Is not visible to bp modules, and should
 	// only be set for stub submodules generated by the java_sdk_library
 	Stub_contributing_api *string `blueprint:"mutated"`
+
+	// If true, enable the "ApiMapper" tool on the output jar. "ApiMapper" is a tool to inject
+	// bytecode to log API calls.
+	ApiMapper bool `blueprint:"mutated"`
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -459,15 +461,10 @@
 	// 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
 
-	// jar file containing only resources including from static library dependencies
-	resourceJar android.Path
-
 	// args and dependencies to package source files into a srcjar
 	srcJarArgs []string
 	srcJarDeps android.Paths
@@ -538,7 +535,8 @@
 	linter
 
 	// list of the xref extraction files
-	kytheFiles android.Paths
+	kytheFiles       android.Paths
+	kytheKotlinFiles android.Paths
 
 	hideApexVariantFromMake bool
 
@@ -593,6 +591,13 @@
 	return j.ProductSpecific()
 }
 
+var _ android.StubsAvailableModule = (*Module)(nil)
+
+// To safisfy the StubsAvailableModule interface
+func (j *Module) IsStubsModule() bool {
+	return proptools.Bool(j.properties.Is_stubs_module)
+}
+
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
 	sdkVersion := j.SdkVersion(ctx)
 	if sdkVersion.Stable() {
@@ -732,6 +737,10 @@
 		ctx.DeviceConfig().JavaCoverageEnabledForPath(ctx.ModuleDir())
 }
 
+func (j *Module) shouldApiMapper() bool {
+	return j.properties.ApiMapper
+}
+
 func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
 	return j.properties.Supports_static_instrumentation &&
 		j.shouldInstrument(ctx) &&
@@ -760,6 +769,10 @@
 	j.properties.Instrument = value
 }
 
+func (j *Module) setApiMapper(value bool) {
+	j.properties.ApiMapper = value
+}
+
 func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
 	return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version))
 }
@@ -816,6 +829,10 @@
 	return j.ApexModuleBase.AvailableFor(what)
 }
 
+func (j *Module) staticLibs(ctx android.BaseModuleContext) []string {
+	return android.RemoveListFromList(j.properties.Static_libs.GetOrDefault(ctx, nil), j.properties.Exclude_static_libs)
+}
+
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		j.linter.deps(ctx)
@@ -832,8 +849,7 @@
 
 	libDeps := ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 
-	j.properties.Static_libs = android.RemoveListFromList(j.properties.Static_libs, j.properties.Exclude_static_libs)
-	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, j.staticLibs(ctx)...)
 
 	// Add dependency on libraries that provide additional hidden api annotations.
 	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
@@ -915,7 +931,7 @@
 		ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
 	}
 
-	if j.useCompose() {
+	if j.useCompose(ctx) {
 		ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag,
 			"androidx.compose.compiler_compiler-hosted")
 	}
@@ -1136,18 +1152,16 @@
 	j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path)
 }
 
-func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
+func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars, extraDepCombinedJars android.Paths) {
 	// Auto-propagating jarjar rules
 	jarjarProviderData := j.collectJarJarRules(ctx)
 	if jarjarProviderData != nil {
 		android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
-		if !proptools.Bool(j.properties.Skip_jarjar_repackage) {
-			text := getJarJarRuleText(jarjarProviderData)
-			if text != "" {
-				ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
-				android.WriteFileRule(ctx, ruleTextFile, text)
-				j.repackageJarjarRules = ruleTextFile
-			}
+		text := getJarJarRuleText(jarjarProviderData)
+		if text != "" {
+			ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+			android.WriteFileRule(ctx, ruleTextFile, text)
+			j.repackageJarjarRules = ruleTextFile
 		}
 	}
 
@@ -1236,7 +1250,6 @@
 	// Collect .java and .kt files for AIDEGen
 	j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
 
-	var kotlinJars android.Paths
 	var kotlinHeaderJars android.Paths
 
 	// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
@@ -1246,6 +1259,8 @@
 
 	j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...)
 
+	var localImplementationJars android.Paths
+
 	// If compiling headers then compile them and skip the rest
 	if proptools.Bool(j.properties.Headers_only) {
 		if srcFiles.HasExt(".kt") {
@@ -1255,20 +1270,43 @@
 			ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
 		}
 
-		_, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
+		transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars
+
+		localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
 			extraCombinedJars)
 
-		combinedHeaderJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
-		combinedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine")
+		combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
+		if jarjared {
+			localHeaderJars = android.Paths{combinedHeaderJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
+		combinedHeaderJarFile, repackaged := j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine")
+		if repackaged {
+			localHeaderJars = android.Paths{combinedHeaderJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
 		if ctx.Failed() {
 			return
 		}
 		j.headerJarFile = combinedHeaderJarFile
 
+		if ctx.Config().UseTransitiveJarsInClasspath() {
+			if len(localHeaderJars) > 0 {
+				ctx.CheckbuildFile(localHeaderJars...)
+			} else {
+				// There are no local sources or resources in this module, so there is nothing to checkbuild.
+				ctx.UncheckedModule()
+			}
+		} else {
+			ctx.CheckbuildFile(j.headerJarFile)
+		}
+
 		android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
 			HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
-			TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
-			TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+			LocalHeaderJars:                     localHeaderJars,
+			TransitiveStaticLibsHeaderJars:      android.NewDepSet(android.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars),
+			TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+			TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
 			AidlIncludeDirs:                     j.exportAidlIncludeDirs,
 			ExportedPlugins:                     j.exportedPluginJars,
 			ExportedPluginClasses:               j.exportedPluginClasses,
@@ -1325,7 +1363,7 @@
 			kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
 			kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
 			srcJars = append(srcJars, kaptSrcJar)
-			kotlinJars = append(kotlinJars, kaptResJar)
+			localImplementationJars = append(localImplementationJars, kaptResJar)
 			// Disable annotation processing in javac, it's already been handled by kapt
 			flags.processorPath = nil
 			flags.processors = nil
@@ -1333,26 +1371,29 @@
 
 		kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
 		kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName)
-		kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
+		j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
 		if ctx.Failed() {
 			return
 		}
 
-		kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc")
+		kotlinJarPath, _ := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc")
 
 		// Make javac rule depend on the kotlinc rule
 		flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
 
-		kotlinJars = append(kotlinJars, kotlinJarPath)
+		localImplementationJars = append(localImplementationJars, kotlinJarPath)
+
 		kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
 	}
 
-	jars := slices.Clone(kotlinJars)
-
 	j.compiledSrcJars = srcJars
 
+	transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars
+
 	enableSharding := false
-	var headerJarFileWithoutDepsOrJarjar android.Path
+	var localHeaderJars android.Paths
+	var shardingHeaderJars android.Paths
+	var repackagedHeaderJarFile android.Path
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine {
 		if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
 			enableSharding = true
@@ -1365,11 +1406,26 @@
 		extraJars := slices.Clone(kotlinHeaderJars)
 		extraJars = append(extraJars, extraCombinedJars...)
 		var combinedHeaderJarFile android.Path
-		headerJarFileWithoutDepsOrJarjar, combinedHeaderJarFile =
-			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
+		localHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
+		shardingHeaderJars = localHeaderJars
 
-		j.headerJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
-		j.repackagedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine")
+		var jarjared bool
+		j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
+		if jarjared {
+			// jarjar modifies transitive static dependencies, use the combined header jar and drop the transitive
+			// static libs header jars.
+			localHeaderJars = android.Paths{j.headerJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
+		var repackaged bool
+		repackagedHeaderJarFile, repackaged = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine")
+		if repackaged {
+			// repackage modifies transitive static dependencies, use the combined header jar and drop the transitive
+			// static libs header jars.
+			// TODO(b/356688296): this shouldn't export both the unmodified and repackaged header jars
+			localHeaderJars = android.Paths{j.headerJarFile, repackagedHeaderJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
 	}
 	if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 {
 		hasErrorproneableFiles := false
@@ -1404,8 +1460,8 @@
 		}
 
 		if enableSharding {
-			if headerJarFileWithoutDepsOrJarjar != nil {
-				flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+			if len(shardingHeaderJars) > 0 {
+				flags.classpath = append(classpath(slices.Clone(shardingHeaderJars)), flags.classpath...)
 			}
 			shardSize := int(*(j.properties.Javac_shard_size))
 			var shardSrcs []android.Paths
@@ -1414,8 +1470,8 @@
 				for idx, shardSrc := range shardSrcs {
 					classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
 						nil, flags, extraJarDeps)
-					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
-					jars = append(jars, classes)
+					classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
+					localImplementationJars = append(localImplementationJars, classes)
 				}
 			}
 			// Assume approximately 5 sources per srcjar.
@@ -1427,21 +1483,21 @@
 				for idx, shardSrcJars := range shardSrcJarsList {
 					classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
 						nil, shardSrcJars, flags, extraJarDeps)
-					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
-					jars = append(jars, classes)
+					classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
+					localImplementationJars = append(localImplementationJars, classes)
 				}
 			}
 		} else {
 			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
-			classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
-			jars = append(jars, classes)
+			classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
+			localImplementationJars = append(localImplementationJars, classes)
 		}
 		if ctx.Failed() {
 			return
 		}
 	}
 
-	jars = append(jars, extraCombinedJars...)
+	localImplementationJars = append(localImplementationJars, extraCombinedJars...)
 
 	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
 
@@ -1468,40 +1524,18 @@
 	resArgs = append(resArgs, extraArgs...)
 	resDeps = append(resDeps, extraDeps...)
 
+	var localResourceJars android.Paths
 	if len(resArgs) > 0 {
 		resourceJar := android.PathForModuleOut(ctx, "res", jarName)
 		TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
-		j.resourceJar = resourceJar
 		if ctx.Failed() {
 			return
 		}
+		localResourceJars = append(localResourceJars, resourceJar)
 	}
 
-	var resourceJars android.Paths
-	if j.resourceJar != nil {
-		resourceJars = append(resourceJars, j.resourceJar)
-	}
 	if Bool(j.properties.Include_srcs) {
-		resourceJars = append(resourceJars, includeSrcJar)
-	}
-	resourceJars = append(resourceJars, deps.staticResourceJars...)
-
-	if len(resourceJars) > 1 {
-		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
-			false, nil, nil)
-		j.resourceJar = combinedJar
-	} else if len(resourceJars) == 1 {
-		j.resourceJar = resourceJars[0]
-	}
-
-	if len(deps.staticJars) > 0 {
-		jars = append(jars, deps.staticJars...)
-	}
-
-	manifest := j.overrideManifest
-	if !manifest.Valid() && j.properties.Manifest != nil {
-		manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
+		localResourceJars = append(localResourceJars, includeSrcJar)
 	}
 
 	services := android.PathsForModuleSrc(ctx, j.properties.Services)
@@ -1526,35 +1560,68 @@
 			Implicits: services,
 			Args:      args,
 		})
-		jars = append(jars, servicesJar)
+		localResourceJars = append(localResourceJars, servicesJar)
+	}
+
+	completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, localResourceJars, deps.transitiveStaticLibsResourceJars)
+
+	var combinedResourceJar android.Path
+	var resourceJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		resourceJars = completeStaticLibsResourceJars.ToList()
+	} else {
+		resourceJars = append(slices.Clone(localResourceJars), deps.staticResourceJars...)
+	}
+	if len(resourceJars) == 1 {
+		combinedResourceJar = resourceJars[0]
+	} else if len(resourceJars) > 0 {
+		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
+			false, nil, nil)
+		combinedResourceJar = combinedJar
+	}
+
+	manifest := j.overrideManifest
+	if !manifest.Valid() && j.properties.Manifest != nil {
+		manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
 	}
 
 	// Combine the classes built from sources, any manifests, and any static libraries into
 	// classes.jar. If there is only one input jar this step will be skipped.
 	var outputFile android.Path
 
+	completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, localImplementationJars, deps.transitiveStaticLibsImplementationJars)
+
+	var jars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		jars = completeStaticLibsImplementationJars.ToList()
+	} else {
+		jars = append(slices.Clone(localImplementationJars), deps.staticJars...)
+	}
+
+	jars = append(jars, extraDepCombinedJars...)
+
 	if len(jars) == 1 && !manifest.Valid() {
 		// Optimization: skip the combine step as there is nothing to do
 		// TODO(ccross): this leaves any module-info.class files, but those should only come from
 		// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
-		// any if len(jars) == 1.
+		// any if len(extraJars) == 0.
 
 		// moduleStubLinkType determines if the module is the TopLevelStubLibrary generated
 		// from sdk_library. The TopLevelStubLibrary contains only one static lib,
 		// either with .from-source or .from-text suffix.
 		// outputFile should be agnostic to the build configuration,
-		// thus "combine" the single static lib in order to prevent the static lib from being exposed
+		// thus copy the single input static lib in order to prevent the static lib from being exposed
 		// to the copy rules.
-		stub, _ := moduleStubLinkType(j)
-
-		if stub {
-			combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
+		if stub, _ := moduleStubLinkType(j); stub {
+			copiedJar := android.PathForModuleOut(ctx, "combined", jarName)
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   android.Cp,
 				Input:  jars[0],
-				Output: combinedJar,
+				Output: copiedJar,
 			})
-			outputFile = combinedJar
+			completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, android.Paths{copiedJar}, nil)
+			outputFile = copiedJar
 		} else {
 			outputFile = jars[0]
 		}
@@ -1566,13 +1633,21 @@
 	}
 
 	// jarjar implementation jar if necessary
-	jarjarFile := j.jarjarIfNecessary(ctx, outputFile, jarName, "")
+	jarjarFile, jarjarred := j.jarjarIfNecessary(ctx, outputFile, jarName, "")
+	if jarjarred {
+		localImplementationJars = android.Paths{jarjarFile}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
+	}
 	outputFile = jarjarFile
 
 	// jarjar resource jar if necessary
-	if j.resourceJar != nil {
-		resourceJarJarFile := j.jarjarIfNecessary(ctx, j.resourceJar, jarName, "resource")
-		j.resourceJar = resourceJarJarFile
+	if combinedResourceJar != nil {
+		resourceJarJarFile, jarjarred := j.jarjarIfNecessary(ctx, combinedResourceJar, jarName, "resource")
+		combinedResourceJar = resourceJarJarFile
+		if jarjarred {
+			localResourceJars = android.Paths{resourceJarJarFile}
+			completeStaticLibsResourceJars = android.NewDepSet(android.PREORDER, localResourceJars, nil)
+		}
 	}
 
 	if ctx.Failed() {
@@ -1589,6 +1664,22 @@
 			Output:      ravenizerOutput,
 		})
 		outputFile = ravenizerOutput
+		localImplementationJars = android.Paths{ravenizerOutput}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
+	}
+
+	if j.shouldApiMapper() {
+		inputFile := outputFile
+		apiMapperFile := android.PathForModuleOut(ctx, "apimapper", jarName)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        apimapper,
+			Description: "apimapper",
+			Input:       inputFile,
+			Output:      apiMapperFile,
+		})
+		outputFile = apiMapperFile
+		localImplementationJars = android.Paths{apiMapperFile}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
 	}
 
 	// Check package restrictions if necessary.
@@ -1610,6 +1701,8 @@
 			Validation: pkgckFile,
 		})
 		outputFile = packageCheckOutputFile
+		localImplementationJars = android.Paths{packageCheckOutputFile}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
 
 		// Check packages and create a timestamp file when complete.
 		CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
@@ -1628,6 +1721,13 @@
 		headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName)
 		convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile)
 		j.headerJarFile = headerJarFile
+		if len(localImplementationJars) == 1 && ctx.Config().UseTransitiveJarsInClasspath() {
+			localHeaderJarFile := android.PathForModuleOut(ctx, "local-javac-header", jarName)
+			convertImplementationJarToHeaderJar(ctx, localImplementationJars[0], localHeaderJarFile)
+			localHeaderJars = append(localHeaderJars, localHeaderJarFile)
+		} else {
+			localHeaderJars = append(localHeaderJars, headerJarFile)
+		}
 	}
 
 	// enforce syntax check to jacoco filters for any build (http://b/183622051)
@@ -1641,16 +1741,27 @@
 	}
 
 	// merge implementation jar with resources if necessary
-	implementationAndResourcesJar := outputFile
-	if j.resourceJar != nil {
-		jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
-		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
-			false, nil, nil)
-		implementationAndResourcesJar = combinedJar
+	var implementationAndResourcesJarsToCombine android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		resourceJars := completeStaticLibsResourceJars.ToList()
+		if len(resourceJars) > 0 {
+			implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJars.ToList()...)
+			implementationAndResourcesJarsToCombine = append(implementationAndResourcesJarsToCombine, extraDepCombinedJars...)
+		}
+	} else {
+		if combinedResourceJar != nil {
+			implementationAndResourcesJarsToCombine = android.Paths{combinedResourceJar, outputFile}
+		}
 	}
 
-	j.implementationAndResourcesJar = implementationAndResourcesJar
+	if len(implementationAndResourcesJarsToCombine) > 0 {
+		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJarsToCombine, manifest,
+			false, nil, nil)
+		outputFile = combinedJar
+	}
+
+	j.implementationAndResourcesJar = outputFile
 
 	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
 	compileDex := j.dexProperties.Compile_dex
@@ -1676,17 +1787,17 @@
 				flags:         flags,
 				sdkVersion:    j.SdkVersion(ctx),
 				minSdkVersion: j.MinSdkVersion(ctx),
-				classesJar:    implementationAndResourcesJar,
+				classesJar:    outputFile,
 				jarName:       jarName,
 			}
-			if j.GetProfileGuided() && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting() {
+			if j.GetProfileGuided(ctx) && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting(ctx) {
 				ctx.PropertyErrorf("enable_profile_rewriting",
 					"Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on. The attached profile should be sourced from an unoptimized/unobfuscated APK.",
 				)
 			}
-			if j.EnableProfileRewriting() {
-				profile := j.GetProfile()
-				if profile == "" || !j.GetProfileGuided() {
+			if j.EnableProfileRewriting(ctx) {
+				profile := j.GetProfile(ctx)
+				if profile == "" || !j.GetProfileGuided(ctx) {
 					ctx.PropertyErrorf("enable_profile_rewriting", "Profile and Profile_guided must be set when enable_profile_rewriting is true")
 				}
 				params.artProfileInput = &profile
@@ -1702,10 +1813,20 @@
 			}
 
 			// merge dex jar with resources if necessary
-			if j.resourceJar != nil {
-				jars := android.Paths{dexOutputFile, j.resourceJar}
+			var dexAndResourceJarsToCombine android.Paths
+			if ctx.Config().UseTransitiveJarsInClasspath() {
+				resourceJars := completeStaticLibsResourceJars.ToList()
+				if len(resourceJars) > 0 {
+					dexAndResourceJarsToCombine = append(android.Paths{dexOutputFile}, resourceJars...)
+				}
+			} else {
+				if combinedResourceJar != nil {
+					dexAndResourceJarsToCombine = android.Paths{dexOutputFile, combinedResourceJar}
+				}
+			}
+			if len(dexAndResourceJarsToCombine) > 0 {
 				combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
-				TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
+				TransformJarsToJar(ctx, combinedJar, "for dex resources", dexAndResourceJarsToCombine, android.OptionalPath{},
 					false, nil, nil)
 				if *j.dexProperties.Uncompress_dex {
 					combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName)
@@ -1733,18 +1854,17 @@
 			j.dexpreopt(ctx, libName, dexOutputFile)
 
 			outputFile = dexOutputFile
+
+			ctx.CheckbuildFile(dexOutputFile)
 		} else {
 			// There is no code to compile into a dex jar, make sure the resources are propagated
 			// to the APK if this is an app.
-			outputFile = implementationAndResourcesJar
-			j.dexJarFile = makeDexJarPathFromPath(j.resourceJar)
+			j.dexJarFile = makeDexJarPathFromPath(combinedResourceJar)
 		}
 
 		if ctx.Failed() {
 			return
 		}
-	} else {
-		outputFile = implementationAndResourcesJar
 	}
 
 	if ctx.Device() {
@@ -1776,16 +1896,34 @@
 
 	j.collectTransitiveSrcFiles(ctx, srcFiles)
 
-	ctx.CheckbuildFile(outputFile)
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		if len(localImplementationJars) > 0 || len(localResourceJars) > 0 || len(localHeaderJars) > 0 {
+			ctx.CheckbuildFile(localImplementationJars...)
+			ctx.CheckbuildFile(localResourceJars...)
+			ctx.CheckbuildFile(localHeaderJars...)
+		} else {
+			// There are no local sources or resources in this module, so there is nothing to checkbuild.
+			ctx.UncheckedModule()
+		}
+	} else {
+		ctx.CheckbuildFile(j.implementationJarFile)
+		ctx.CheckbuildFile(j.headerJarFile)
+	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
-		RepackagedHeaderJars:                android.PathsIfNonNil(j.repackagedHeaderJarFile),
-		TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+		HeaderJars:           android.PathsIfNonNil(j.headerJarFile),
+		RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile),
+
+		LocalHeaderJars:                        localHeaderJars,
+		TransitiveStaticLibsHeaderJars:         android.NewDepSet(android.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars),
+		TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+		TransitiveStaticLibsResourceJars:       completeStaticLibsResourceJars,
+
+		TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
 		ImplementationAndResourcesJars:      android.PathsIfNonNil(j.implementationAndResourcesJar),
 		ImplementationJars:                  android.PathsIfNonNil(j.implementationJarFile),
-		ResourceJars:                        android.PathsIfNonNil(j.resourceJar),
+		ResourceJars:                        android.PathsIfNonNil(combinedResourceJar),
 		AidlIncludeDirs:                     j.exportAidlIncludeDirs,
 		SrcJarArgs:                          j.srcJarArgs,
 		SrcJarDeps:                          j.srcJarDeps,
@@ -1802,8 +1940,8 @@
 	j.outputFile = outputFile.WithoutRel()
 }
 
-func (j *Module) useCompose() bool {
-	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
+func (j *Module) useCompose(ctx android.BaseModuleContext) bool {
+	return android.InList("androidx.compose.runtime_runtime", j.staticLibs(ctx))
 }
 
 func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []*android.DepSet[android.Path]) {
@@ -1921,22 +2059,26 @@
 
 func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
 	deps deps, flags javaBuilderFlags, jarName string,
-	extraJars android.Paths) (headerJar android.Path, combinedHeaderJar android.Path) {
+	extraJars android.Paths) (localHeaderJars android.Paths, combinedHeaderJar android.Path) {
 
-	var jars android.Paths
 	if len(srcFiles) > 0 || len(srcJars) > 0 {
 		// Compile java sources into turbine.jar.
 		turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
 		TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
-		jars = append(jars, turbineJar)
-		headerJar = turbineJar
+		localHeaderJars = append(localHeaderJars, turbineJar)
 	}
 
-	jars = append(jars, extraJars...)
+	localHeaderJars = append(localHeaderJars, extraJars...)
 
 	// Combine any static header libraries into classes-header.jar. If there is only
 	// one input jar this step will be skipped.
-	jars = append(jars, deps.staticHeaderJars...)
+	var jars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		depSet := android.NewDepSet(android.PREORDER, localHeaderJars, deps.transitiveStaticLibsHeaderJars)
+		jars = depSet.ToList()
+	} else {
+		jars = append(slices.Clone(localHeaderJars), deps.staticHeaderJars...)
+	}
 
 	// we cannot skip the combine step for now if there is only one jar
 	// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
@@ -1944,7 +2086,7 @@
 	TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{},
 		false, nil, []string{"META-INF/TRANSITIVE"})
 
-	return headerJar, combinedHeaderJarOutputPath
+	return localHeaderJars, combinedHeaderJarOutputPath
 }
 
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1960,22 +2102,18 @@
 	return instrumentedJar
 }
 
-type providesTransitiveHeaderJars struct {
+type providesTransitiveHeaderJarsForR8 struct {
 	// set of header jars for all transitive libs deps
-	transitiveLibsHeaderJars *android.DepSet[android.Path]
+	transitiveLibsHeaderJarsForR8 *android.DepSet[android.Path]
 	// set of header jars for all transitive static libs deps
-	transitiveStaticLibsHeaderJars *android.DepSet[android.Path]
+	transitiveStaticLibsHeaderJarsForR8 *android.DepSet[android.Path]
 }
 
-func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet[android.Path] {
-	return j.transitiveLibsHeaderJars
-}
-
-func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet[android.Path] {
-	return j.transitiveStaticLibsHeaderJars
-}
-
-func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) {
+// collectTransitiveHeaderJarsForR8 visits direct dependencies and collects all transitive libs and static_libs
+// header jars.  The semantics of the collected jars are odd (it collects combined jars that contain the static
+// libs, but also the static libs, and it collects transitive libs dependencies of static_libs), so these
+// are only used to expand the --lib arguments to R8.
+func (j *providesTransitiveHeaderJarsForR8) collectTransitiveHeaderJarsForR8(ctx android.ModuleContext) {
 	directLibs := android.Paths{}
 	directStaticLibs := android.Paths{}
 	transitiveLibs := []*android.DepSet[android.Path]{}
@@ -1998,16 +2136,17 @@
 				return
 			}
 
-			if dep.TransitiveLibsHeaderJars != nil {
-				transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
+			if dep.TransitiveLibsHeaderJarsForR8 != nil {
+				transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJarsForR8)
 			}
-			if dep.TransitiveStaticLibsHeaderJars != nil {
-				transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
+			if dep.TransitiveStaticLibsHeaderJarsForR8 != nil {
+				transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJarsForR8)
 			}
+
 		}
 	})
-	j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
-	j.transitiveStaticLibsHeaderJars = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
+	j.transitiveLibsHeaderJarsForR8 = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
+	j.transitiveStaticLibsHeaderJarsForR8 = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
 }
 
 func (j *Module) HeaderJars() android.Paths {
@@ -2062,7 +2201,7 @@
 	}
 	dpInfo.Deps = append(dpInfo.Deps, j.CompilerDeps()...)
 	dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
-	dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
+	dpInfo.Static_libs = append(dpInfo.Static_libs, j.staticLibs(ctx)...)
 	dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
 }
 
@@ -2251,29 +2390,17 @@
 func (j *Module) collectDeps(ctx android.ModuleContext) deps {
 	var deps deps
 
-	if ctx.Device() {
-		sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
-		if sdkDep.invalidVersion {
-			ctx.AddMissingDependencies(sdkDep.bootclasspath)
-			ctx.AddMissingDependencies(sdkDep.java9Classpath)
-		} else if sdkDep.useFiles {
-			// sdkDep.jar is actually equivalent to turbine header.jar.
-			deps.classpath = append(deps.classpath, sdkDep.jars...)
-			deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...)
-			deps.aidlPreprocess = sdkDep.aidl
-			// Add the sdk module dependency to `compileDepNames`.
-			// This ensures that the dependency is reported in `module_bp_java_deps.json`
-			// TODO (b/358608607): Move this to decodeSdkDep
-			sdkSpec := android.SdkContext(j).SdkVersion(ctx)
-			j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String()))
-		} else {
-			deps.aidlPreprocess = sdkDep.aidl
-		}
-	}
-
 	sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
 
-	j.collectTransitiveHeaderJars(ctx)
+	j.collectTransitiveHeaderJarsForR8(ctx)
+
+	var transitiveBootClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveJava9ClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticJarsHeaderLibs []*android.DepSet[android.Path]
+	var transitiveStaticJarsImplementationLibs []*android.DepSet[android.Path]
+	var transitiveStaticJarsResourceLibs []*android.DepSet[android.Path]
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -2287,14 +2414,13 @@
 			return
 		}
 
-		if dep, ok := module.(SdkLibraryDependency); ok {
+		if _, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
-			case sdkLibTag, libTag:
-				depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
-				deps.classpath = append(deps.classpath, depHeaderJars...)
-				deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...)
-			case staticLibTag:
-				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
+			case sdkLibTag, libTag, staticLibTag:
+				sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
+				generatingLibsString := android.PrettyConcat(
+					getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
+				ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
 			}
 		} else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			if sdkLinkType != javaPlatform {
@@ -2308,6 +2434,9 @@
 			switch tag {
 			case bootClasspathTag:
 				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case sdkLibTag, libTag, instrumentationForTag:
 				if _, ok := module.(*Plugin); ok {
 					ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName)
@@ -2321,8 +2450,15 @@
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
 				addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
+
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case java9LibTag:
 				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case staticLibTag:
 				if _, ok := module.(*Plugin); ok {
 					ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName)
@@ -2338,6 +2474,17 @@
 				// optimization.
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
 				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
+
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+					transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, dep.TransitiveStaticLibsHeaderJars)
+				}
+				if dep.TransitiveStaticLibsImplementationJars != nil {
+					transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, dep.TransitiveStaticLibsImplementationJars)
+				}
+				if dep.TransitiveStaticLibsResourceJars != nil {
+					transitiveStaticJarsResourceLibs = append(transitiveStaticJarsResourceLibs, dep.TransitiveStaticLibsResourceJars)
+				}
 			case pluginTag:
 				if plugin, ok := module.(*Plugin); ok {
 					if plugin.pluginProperties.Processor_class != nil {
@@ -2386,11 +2533,18 @@
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 				deps.dexClasspath = append(deps.classpath, dep.Srcs()...)
+				transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars,
+					android.NewDepSet(android.PREORDER, dep.Srcs(), nil))
 			case staticLibTag:
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
+
+				depHeaderJars := android.NewDepSet(android.PREORDER, dep.Srcs(), nil)
+				transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJars)
+				transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, depHeaderJars)
+				transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, depHeaderJars)
 			}
 		} else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
 			switch tag {
@@ -2403,8 +2557,11 @@
 				// If a system modules dependency has been added to the bootclasspath
 				// then add its libs to the bootclasspath.
 				if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok {
-					depHeaderJars := sm.HeaderJars
-					deps.bootClasspath = append(deps.bootClasspath, depHeaderJars...)
+					deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars...)
+					if sm.TransitiveStaticLibsHeaderJars != nil {
+						transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars,
+							sm.TransitiveStaticLibsHeaderJars)
+					}
 				} else {
 					ctx.PropertyErrorf("boot classpath dependency %q does not provide SystemModulesProvider",
 						ctx.OtherModuleName(module))
@@ -2435,6 +2592,39 @@
 		addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary)
 	})
 
+	deps.transitiveStaticLibsHeaderJars = transitiveStaticJarsHeaderLibs
+	deps.transitiveStaticLibsImplementationJars = transitiveStaticJarsImplementationLibs
+	deps.transitiveStaticLibsResourceJars = transitiveStaticJarsResourceLibs
+
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		depSet := android.NewDepSet(android.PREORDER, nil, transitiveClasspathHeaderJars)
+		deps.classpath = depSet.ToList()
+		depSet = android.NewDepSet(android.PREORDER, nil, transitiveBootClasspathHeaderJars)
+		deps.bootClasspath = depSet.ToList()
+		depSet = android.NewDepSet(android.PREORDER, nil, transitiveJava9ClasspathHeaderJars)
+		deps.java9Classpath = depSet.ToList()
+	}
+
+	if ctx.Device() {
+		sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
+		if sdkDep.invalidVersion {
+			ctx.AddMissingDependencies(sdkDep.bootclasspath)
+			ctx.AddMissingDependencies(sdkDep.java9Classpath)
+		} else if sdkDep.useFiles {
+			// sdkDep.jar is actually equivalent to turbine header.jar.
+			deps.classpath = append(slices.Clone(classpath(sdkDep.jars)), deps.classpath...)
+			deps.dexClasspath = append(slices.Clone(classpath(sdkDep.jars)), deps.dexClasspath...)
+			deps.aidlPreprocess = sdkDep.aidl
+			// Add the sdk module dependency to `compileDepNames`.
+			// This ensures that the dependency is reported in `module_bp_java_deps.json`
+			// TODO (b/358608607): Move this to decodeSdkDep
+			sdkSpec := android.SdkContext(j).SdkVersion(ctx)
+			j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String()))
+		} else {
+			deps.aidlPreprocess = sdkDep.aidl
+		}
+	}
+
 	return deps
 }
 
@@ -2485,6 +2675,8 @@
 
 func init() {
 	android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
+
+	gob.Register(BaseJarJarProviderData{})
 }
 
 // BaseJarJarProviderData contains information that will propagate across dependencies regardless of
@@ -2744,22 +2936,22 @@
 }
 
 // Repackage the flags if the jarjar rule txt for the flags is generated
-func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path {
+func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) {
 	if j.repackageJarjarRules == nil {
-		return infile
+		return infile, false
 	}
 	repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info, jarName)
 	TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules)
-	return repackagedJarjarFile
+	return repackagedJarjarFile, true
 }
 
-func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path {
+func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) {
 	if j.expandJarjarRules == nil {
-		return infile
+		return infile, false
 	}
 	jarjarFile := android.PathForModuleOut(ctx, "jarjar", info, jarName)
 	TransformJarJar(ctx, jarjarFile, infile, j.expandJarjarRules)
-	return jarjarFile
+	return jarjarFile, true
 
 }
 
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 6223ded..3c3bd55 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -21,7 +21,7 @@
 // isActiveModule returns true if the given module should be considered for boot
 // jars, i.e. if it's enabled and the preferred one in case of source and
 // prebuilt alternatives.
-func isActiveModule(ctx android.ConfigAndErrorContext, module android.Module) bool {
+func isActiveModule(ctx android.ConfigurableEvaluatorContext, module android.Module) bool {
 	if !module.Enabled(ctx) {
 		return false
 	}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bef3b58..4fcd40b 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -414,6 +414,12 @@
 		// Cross-cutting metadata dependencies are metadata.
 		return false
 	}
+	// Dependency to the bootclasspath fragment of another apex
+	// e.g. concsrypt-bootclasspath-fragment --> art-bootclasspath-fragment
+	if tag == bootclasspathFragmentDepTag {
+		return false
+
+	}
 	panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
 }
 
@@ -463,6 +469,12 @@
 	// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
 	// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
 	dexpreopt.RegisterToolDeps(ctx)
+
+	// Add a dependency to `all_apex_contributions` to determine if prebuilts are active.
+	// If prebuilts are active, `contents` validation on the source bootclasspath fragment should be disabled.
+	if _, isPrebuiltModule := ctx.Module().(*PrebuiltBootclasspathFragmentModule); !isPrebuiltModule {
+		ctx.AddDependency(b, android.AcDepTag, "all_apex_contributions")
+	}
 }
 
 func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1093,22 +1105,10 @@
 	return &output
 }
 
+// DEPRECATED: this information is now generated in the context of the top level prebuilt apex.
 // produceBootImageProfile extracts the boot image profile from the APEX if available.
 func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx android.ModuleContext) android.WritablePath {
-	// This module does not provide a boot image profile.
-	if module.getProfileProviderApex(ctx) == "" {
-		return nil
-	}
-
-	di, err := android.FindDeapexerProviderForModule(ctx)
-	if err != nil {
-		// An error was found, possibly due to multiple apexes in the tree that export this library
-		// Defer the error till a client tries to call getProfilePath
-		module.profilePathErr = err
-		return nil // An error has been reported by FindDeapexerProviderForModule.
-	}
-
-	return di.PrebuiltExportPath(ProfileInstallPathInApex)
+	return android.PathForModuleInstall(ctx, "intentionally_no_longer_supported")
 }
 
 func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
diff --git a/java/builder.go b/java/builder.go
index 49207e5..81b0feb 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -265,6 +265,13 @@
 		},
 	)
 
+	apimapper = pctx.AndroidStaticRule("apimapper",
+		blueprint.RuleParams{
+			Command:     "${apimapper} --in-jar $in --out-jar $out",
+			CommandDeps: []string{"${apimapper}"},
+		},
+	)
+
 	zipalign = pctx.AndroidStaticRule("zipalign",
 		blueprint.RuleParams{
 			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
@@ -315,6 +322,7 @@
 
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("ravenizer", "ravenizer")
+	pctx.HostBinToolVariable("apimapper", "apimapper")
 	pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
 }
 
diff --git a/java/config/Android.bp b/java/config/Android.bp
index bfe83ab..6217390 100644
--- a/java/config/Android.bp
+++ b/java/config/Android.bp
@@ -17,4 +17,8 @@
         "kotlin.go",
         "makevars.go",
     ],
+    visibility: [
+        "//build/soong:__subpackages__",
+        "//external/error_prone/soong",
+    ],
 }
diff --git a/java/config/config.go b/java/config/config.go
index a50c1b4..4c1c723 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -52,6 +52,7 @@
 		"core-icu4j",
 		"core-oj",
 		"core-libart",
+		"wear-sdk.impl",
 	}
 )
 
@@ -144,6 +145,7 @@
 	pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
 	pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar")
 	pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
+	pctx.SourcePathVariable("KotlinKytheExtractor", "prebuilts/build-tools/${hostPrebuiltTag}/bin/kotlinc_extractor")
 	pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
 
 	pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar")
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index e5e187c..302d021 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -50,4 +50,11 @@
 	}, " "))
 
 	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " "))
+	// Use KotlincKytheGlobalFlags to prevent kotlinc version skew issues between android and
+	// g3 kythe indexers.
+	// This is necessary because there might be instances of kotlin code in android
+	// platform that are not fully compatible with the kotlinc used in g3 kythe indexers.
+	// e.g. uninitialized variables are a warning in 1.*, but an error in 2.*
+	// https://github.com/JetBrains/kotlin/blob/master/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt#L748
+	pctx.StaticVariable("KotlincKytheGlobalFlags", strings.Join([]string{"-language-version 1.9"}, " "))
 }
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index cee7a19..1cca7ad 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -38,6 +38,7 @@
     visibility: ["//visibility:public"],
     sdk_version: "none",
     system_modules: "none",
+    is_stubs_module: true,
 }
 
 java_library {
@@ -289,6 +290,7 @@
     sdk_version: "none",
     system_modules: "none",
     patch_module: "java.base",
+    is_stubs_module: true,
 }
 
 // Same as legacy.core.platform.api.stubs, but android annotations are
@@ -307,6 +309,7 @@
         "legacy.core.platform.api.stubs",
     ],
     patch_module: "java.base",
+    is_stubs_module: true,
 }
 
 java_library {
@@ -339,6 +342,7 @@
         "stable.core.platform.api.stubs",
     ],
     patch_module: "java.base",
+    is_stubs_module: true,
 }
 
 // Used when compiling higher-level code against *.core.platform.api.stubs.
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 7cc06fc..3f4e3cd 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -96,6 +96,10 @@
 		ctx.PropertyErrorf("libs", "at least one dependency is required")
 	}
 
+	var transitiveHeaderJars []*android.DepSet[android.Path]
+	var transitiveImplementationJars []*android.DepSet[android.Path]
+	var transitiveResourceJars []*android.DepSet[android.Path]
+
 	ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
 		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
 			d.headerJars = append(d.headerJars, dep.HeaderJars...)
@@ -105,6 +109,16 @@
 
 			d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...)
 			d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...)
+
+			if dep.TransitiveStaticLibsHeaderJars != nil {
+				transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+			}
+			if dep.TransitiveStaticLibsImplementationJars != nil {
+				transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+			}
+			if dep.TransitiveStaticLibsResourceJars != nil {
+				transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars)
+			}
 		} else {
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
@@ -131,13 +145,17 @@
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     d.headerJars,
-		ImplementationAndResourcesJars: d.implementationAndResourceJars,
-		ImplementationJars:             d.implementationJars,
-		ResourceJars:                   d.resourceJars,
-		SrcJarArgs:                     d.srcJarArgs,
-		SrcJarDeps:                     d.srcJarDeps,
-		StubsLinkType:                  Implementation,
+		HeaderJars:                             d.headerJars,
+		LocalHeaderJars:                        d.headerJars,
+		TransitiveStaticLibsHeaderJars:         android.NewDepSet(android.PREORDER, nil, transitiveHeaderJars),
+		TransitiveStaticLibsImplementationJars: android.NewDepSet(android.PREORDER, nil, transitiveImplementationJars),
+		TransitiveStaticLibsResourceJars:       android.NewDepSet(android.PREORDER, nil, transitiveResourceJars),
+		ImplementationAndResourcesJars:         d.implementationAndResourceJars,
+		ImplementationJars:                     d.implementationJars,
+		ResourceJars:                           d.resourceJars,
+		SrcJarArgs:                             d.srcJarArgs,
+		SrcJarDeps:                             d.srcJarDeps,
+		StubsLinkType:                          Implementation,
 		// TODO: Not sure if aconfig flags that have been moved between device and host variants
 		// make sense.
 	})
diff --git a/java/dex.go b/java/dex.go
index 6c739a2..e0e642c 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -108,7 +108,7 @@
 	resourcesInput          android.OptionalPath
 	resourcesOutput         android.OptionalPath
 
-	providesTransitiveHeaderJars
+	providesTransitiveHeaderJarsForR8
 }
 
 func (d *dexer) effectiveOptimizeEnabled() bool {
@@ -120,7 +120,7 @@
 }
 
 func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleContext) bool {
-	return d.resourceShrinkingEnabled(ctx) && Bool(d.Optimize.Optimized_shrink_resources)
+	return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault())
 }
 
 func (d *dexer) optimizeOrObfuscateEnabled() bool {
@@ -245,6 +245,16 @@
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
+	if !Bool(d.dexProperties.No_dex_container) && effectiveVersion.FinalOrFutureInt() >= 36 {
+		// W is 36, but we have not bumped the SDK version yet, so check for both.
+		if ctx.Config().PlatformSdkVersion().FinalInt() >= 36 ||
+			ctx.Config().PlatformSdkCodename() == "Wear" {
+			// TODO(b/329465418): Skip this module since it causes issue with app DRM
+			if ctx.ModuleName() != "framework-minus-apex" {
+				flags = append([]string{"-JDcom.android.tools.r8.dexContainerExperiment"}, flags...)
+			}
+		}
+	}
 
 	// If the specified SDK level is 10000, then configure the compiler to use the
 	// current platform SDK level and to compile the build as a platform build.
@@ -307,14 +317,14 @@
 	r8Deps = append(r8Deps, flags.dexClasspath...)
 
 	transitiveStaticLibsLookupMap := map[android.Path]bool{}
-	if d.transitiveStaticLibsHeaderJars != nil {
-		for _, jar := range d.transitiveStaticLibsHeaderJars.ToList() {
+	if d.transitiveStaticLibsHeaderJarsForR8 != nil {
+		for _, jar := range d.transitiveStaticLibsHeaderJarsForR8.ToList() {
 			transitiveStaticLibsLookupMap[jar] = true
 		}
 	}
 	transitiveHeaderJars := android.Paths{}
-	if d.transitiveLibsHeaderJars != nil {
-		for _, jar := range d.transitiveLibsHeaderJars.ToList() {
+	if d.transitiveLibsHeaderJarsForR8 != nil {
+		for _, jar := range d.transitiveLibsHeaderJarsForR8.ToList() {
 			if _, ok := transitiveStaticLibsLookupMap[jar]; ok {
 				// don't include a lib if it is already packaged in the current JAR as a static lib
 				continue
@@ -390,7 +400,7 @@
 		r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String())
 		r8Deps = append(r8Deps, d.resourcesInput.Path())
 		r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String())
-		if Bool(opt.Optimized_shrink_resources) {
+		if d.dexProperties.optimizedResourceShrinkingEnabled(ctx) {
 			r8Flags = append(r8Flags, "--optimized-resource-shrinking")
 		}
 	}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index f949b12..63a8634 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -147,25 +147,25 @@
 type DexpreoptProperties struct {
 	Dex_preopt struct {
 		// If false, prevent dexpreopting.  Defaults to true.
-		Enabled *bool
+		Enabled proptools.Configurable[bool] `android:"replace_instead_of_append"`
 
 		// If true, generate an app image (.art file) for this module.
-		App_image *bool
+		App_image proptools.Configurable[bool] `android:"replace_instead_of_append"`
 
 		// If true, use a checked-in profile to guide optimization.  Defaults to false unless
 		// a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
 		// that matches the name of this module, in which case it is defaulted to true.
-		Profile_guided *bool
+		Profile_guided proptools.Configurable[bool] `android:"replace_instead_of_append"`
 
 		// If set, provides the path to profile relative to the Android.bp file.  If not set,
 		// defaults to searching for a file that matches the name of this module in the default
 		// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
-		Profile *string `android:"path"`
+		Profile proptools.Configurable[string] `android:"path,replace_instead_of_append"`
 
 		// If set to true, r8/d8 will use `profile` as input to generate a new profile that matches
 		// the optimized dex.
 		// The new profile will be subsequently used as the profile to dexpreopt the dex file.
-		Enable_profile_rewriting *bool
+		Enable_profile_rewriting proptools.Configurable[bool] `android:"replace_instead_of_append"`
 	}
 
 	Dex_preopt_result struct {
@@ -209,13 +209,18 @@
 			psi = prebuiltSelectionInfo
 		}
 	})
+
 	// Find the apex variant for this module
-	var apexVariantsWithoutTestApexes []string
+	apexVariantsWithoutTestApexes := []string{}
 	if apexInfo.BaseApexName != "" {
 		// This is a transitive dependency of an override_apex
-		apexVariantsWithoutTestApexes = []string{apexInfo.BaseApexName}
+		apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, apexInfo.BaseApexName)
 	} else {
-		_, apexVariantsWithoutTestApexes, _ = android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+		_, variants, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+		apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, variants...)
+	}
+	if apexInfo.ApexAvailableName != "" {
+		apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, apexInfo.ApexAvailableName)
 	}
 	disableSource := false
 	// find the selected apexes
@@ -239,7 +244,7 @@
 		return true
 	}
 
-	if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) {
+	if !d.dexpreoptProperties.Dex_preopt.Enabled.GetOrDefault(ctx, true) {
 		return true
 	}
 
@@ -428,12 +433,12 @@
 
 	if d.inputProfilePathOnHost != nil {
 		profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost)
-	} else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) {
+	} else if d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, true) && !forPrebuiltApex(ctx) {
 		// If enable_profile_rewriting is set, use the rewritten profile instead of the checked-in profile
-		if d.EnableProfileRewriting() {
+		if d.EnableProfileRewriting(ctx) {
 			profileClassListing = android.OptionalPathForPath(d.GetRewrittenProfile())
 			profileIsTextListing = true
-		} else if profile := d.GetProfile(); profile != "" {
+		} else if profile := d.GetProfile(ctx); profile != "" {
 			// If dex_preopt.profile_guided is not set, default it based on the existence of the
 			// dexprepot.profile option or the profile class listing.
 			profileClassListing = android.OptionalPathForPath(
@@ -453,6 +458,8 @@
 	// Use the dexJar to create a unique scope for each
 	dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext())
 
+	appImage := d.dexpreoptProperties.Dex_preopt.App_image.Get(ctx)
+
 	// Full dexpreopt config, used to create dexpreopt build rules.
 	dexpreoptConfig := &dexpreopt.ModuleConfig{
 		Name:            libName,
@@ -481,14 +488,15 @@
 		PreoptBootClassPathDexFiles:     dexFiles.Paths(),
 		PreoptBootClassPathDexLocations: dexLocations,
 
-		NoCreateAppImage:    !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
-		ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
+		NoCreateAppImage:    !appImage.GetOrDefault(true),
+		ForceCreateAppImage: appImage.GetOrDefault(false),
 
 		PresignedPrebuilt: d.isPresignedPrebuilt,
 	}
 
 	d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config")
 	dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
+	ctx.CheckbuildFile(d.configPath)
 
 	if d.dexpreoptDisabled(ctx, libName) {
 		return
@@ -592,7 +600,8 @@
 
 			}
 		} else if !d.preventInstall {
-			ctx.InstallFile(installPath, installBase, install.From)
+			// Install without adding to checkbuild to match behavior of previous Make-based checkbuild rules
+			ctx.InstallFileWithoutCheckbuild(installPath, installBase, install.From)
 		}
 	}
 
@@ -650,16 +659,16 @@
 	d.shouldDisableDexpreopt = true
 }
 
-func (d *dexpreopter) EnableProfileRewriting() bool {
-	return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting)
+func (d *dexpreopter) EnableProfileRewriting(ctx android.BaseModuleContext) bool {
+	return d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting.GetOrDefault(ctx, false)
 }
 
-func (d *dexpreopter) GetProfile() string {
-	return proptools.String(d.dexpreoptProperties.Dex_preopt.Profile)
+func (d *dexpreopter) GetProfile(ctx android.BaseModuleContext) string {
+	return d.dexpreoptProperties.Dex_preopt.Profile.GetOrDefault(ctx, "")
 }
 
-func (d *dexpreopter) GetProfileGuided() bool {
-	return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Profile_guided)
+func (d *dexpreopter) GetProfileGuided(ctx android.BaseModuleContext) bool {
+	return d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, false)
 }
 
 func (d *dexpreopter) GetRewrittenProfile() android.Path {
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 73e33f4..07d0595 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -54,6 +54,7 @@
 					name: "foo",
 					installable: true,
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: true,
 		},
@@ -98,6 +99,7 @@
 				java_library {
 					name: "foo",
 					installable: true,
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -107,6 +109,7 @@
 				java_library {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -144,6 +147,7 @@
 					name: "foo",
 					srcs: ["a.java"],
 					compile_dex: true,
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -164,6 +168,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			apexVariant: true,
 			enabled:     false,
@@ -176,6 +181,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			moduleName:  "service-foo",
 			apexVariant: true,
@@ -189,6 +195,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			moduleName:  "prebuilt_service-foo",
 			apexVariant: true,
@@ -202,6 +209,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			moduleName:  "service-foo",
 			apexVariant: false,
@@ -311,6 +319,7 @@
 			installable: true,
 			srcs: ["a.java"],
 			apex_available: ["com.android.apex1"],
+			sdk_version: "current",
 		}`)
 	ctx := result.TestContext
 	module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
@@ -342,6 +351,7 @@
 			name: "foo",
 			installable: true,
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}`)
 	ctx = result.TestContext
 	module = ctx.ModuleForTests("foo", "android_common")
@@ -398,6 +408,7 @@
 			installable: true,
 			srcs: ["a.java"],
 			apex_available: ["com.android.apex1"],
+			sdk_version: "current",
 		}`)
 	ctx := result.TestContext
 	module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
@@ -429,6 +440,7 @@
 			name: "foo",
 			installable: true,
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}`)
 	ctx = result.TestContext
 	module = ctx.ModuleForTests("foo", "android_common")
@@ -454,6 +466,7 @@
 				profile: "art-profile",
 			},
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}`)
 
 	ctx := result.TestContext
diff --git a/java/droiddoc.go b/java/droiddoc.go
index f81c5ba..a7e92d9 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -54,7 +54,7 @@
 	Filter_packages []string
 
 	// list of java libraries that will be in the classpath.
-	Libs []string `android:"arch_variant"`
+	Libs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
 	Installable *bool
@@ -274,7 +274,7 @@
 		}
 	}
 
-	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs.GetOrDefault(ctx, nil)...)
 }
 
 func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
@@ -373,8 +373,11 @@
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
 		case libTag, sdkLibTag:
-			if dep, ok := module.(SdkLibraryDependency); ok {
-				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
+			if _, ok := module.(SdkLibraryDependency); ok {
+				sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
+				generatingLibsString := android.PrettyConcat(
+					getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
+				ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
 			} else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 				deps.classpath = append(deps.classpath, dep.HeaderJars...)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 137ec92..6bcdf85 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -970,10 +970,14 @@
 		d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt")
 		cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO:  Change to ":api-lint"
 
-		// Make sure that existing UnflaggedApi issues are reported as warnings but issues in
-		// new/changed code are treated as errors by the Build Warnings Aye Aye Analyzer in Gerrit.
+		// If UnflaggedApi issues have not already been configured then make sure that existing
+		// UnflaggedApi issues are reported as warnings but issues in new/changed code are treated as
+		// errors by the Build Warnings Aye Aye Analyzer in Gerrit.
 		// Once existing issues have been fixed this will be changed to error.
-		cmd.Flag("--error-when-new UnflaggedApi")
+		// TODO(b/362771529): Switch to --error
+		if !strings.Contains(cmd.String(), " UnflaggedApi ") {
+			cmd.Flag("--error-when-new UnflaggedApi")
+		}
 
 		// TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
 		if d.Name() != "android.car-system-stubs-docs" &&
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index d5e6d8f..79f1b6f 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -70,14 +70,6 @@
 	module.Library.properties.Libs = append(module.Library.properties.Libs, name)
 }
 
-// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
-func (module *GeneratedJavaLibraryModule) AddStaticLibrary(name string) {
-	if module.depsMutatorDone {
-		panic("GeneratedJavaLibraryModule.AddStaticLibrary called after DepsMutator")
-	}
-	module.Library.properties.Static_libs = append(module.Library.properties.Static_libs, name)
-}
-
 func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	module.callbacks.DepsMutator(module, ctx)
 	module.depsMutatorDone = true
diff --git a/java/java.go b/java/java.go
index 55c878e..91c4d6d 100644
--- a/java/java.go
+++ b/java/java.go
@@ -254,16 +254,26 @@
 type JavaInfo struct {
 	// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
 	// against this module.  If empty, ImplementationJars should be used instead.
+	// Unlike LocalHeaderJars, HeaderJars includes classes from static dependencies.
 	HeaderJars android.Paths
 
 	RepackagedHeaderJars android.Paths
 
 	// set of header jars for all transitive libs deps
-	TransitiveLibsHeaderJars *android.DepSet[android.Path]
+	TransitiveLibsHeaderJarsForR8 *android.DepSet[android.Path]
 
 	// set of header jars for all transitive static libs deps
+	TransitiveStaticLibsHeaderJarsForR8 *android.DepSet[android.Path]
+
+	// depset of header jars for this module and all transitive static dependencies
 	TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
 
+	// depset of implementation jars for this module and all transitive static dependencies
+	TransitiveStaticLibsImplementationJars *android.DepSet[android.Path]
+
+	// depset of resource jars for this module and all transitive static dependencies
+	TransitiveStaticLibsResourceJars *android.DepSet[android.Path]
+
 	// ImplementationAndResourceJars is a list of jars that contain the implementations of classes
 	// in the module as well as any resources included in the module.
 	ImplementationAndResourcesJars android.Paths
@@ -275,6 +285,9 @@
 	// ResourceJars is a list of jars that contain the resources included in the module.
 	ResourceJars android.Paths
 
+	// LocalHeaderJars is a list of jars that contain classes from this module, but not from any static dependencies.
+	LocalHeaderJars android.Paths
+
 	// AidlIncludeDirs is a list of directories that should be passed to the aidl tool when
 	// depending on this module.
 	AidlIncludeDirs android.Paths
@@ -343,12 +356,17 @@
 // TODO(jungjw): Move this to kythe.go once it's created.
 type xref interface {
 	XrefJavaFiles() android.Paths
+	XrefKotlinFiles() android.Paths
 }
 
 func (j *Module) XrefJavaFiles() android.Paths {
 	return j.kytheFiles
 }
 
+func (j *Module) XrefKotlinFiles() android.Paths {
+	return j.kytheKotlinFiles
+}
+
 func (d dependencyTag) PropagateAconfigValidation() bool {
 	return d.static
 }
@@ -553,7 +571,7 @@
 	// are provided by systemModules.
 	java9Classpath classpath
 
-	processorPath           classpath
+	processorPath           classpath ``
 	errorProneProcessorPath classpath
 	processorClasses        []string
 	staticJars              android.Paths
@@ -568,6 +586,10 @@
 	aconfigProtoFiles       android.Paths
 
 	disableTurbine bool
+
+	transitiveStaticLibsHeaderJars         []*android.DepSet[android.Path]
+	transitiveStaticLibsImplementationJars []*android.DepSet[android.Path]
+	transitiveStaticLibsResourceJars       []*android.DepSet[android.Path]
 }
 
 func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) {
@@ -980,7 +1002,7 @@
 			j.dexpreopter.disableDexpreopt()
 		}
 	}
-	j.compile(ctx, nil, nil, nil)
+	j.compile(ctx, nil, nil, nil, nil)
 
 	// If this module is an impl library created from java_sdk_library,
 	// install the files under the java_sdk_library module outdir instead of this module outdir.
@@ -1008,7 +1030,7 @@
 		}
 		hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host()
 		if hostDexNeeded {
-			j.hostdexInstallFile = ctx.InstallFile(
+			j.hostdexInstallFile = ctx.InstallFileWithoutCheckbuild(
 				android.PathForHostDexInstall(ctx, "framework"),
 				j.Stem()+"-hostdex.jar", j.outputFile)
 		}
@@ -1022,7 +1044,7 @@
 		} else {
 			installDir = android.PathForModuleInstall(ctx, "framework")
 		}
-		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
+		j.installFile = ctx.InstallFileWithoutCheckbuild(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 }
 
@@ -1994,11 +2016,11 @@
 
 	// List of shared java libs that this module has dependencies to and
 	// should be passed as classpath in javac invocation
-	Libs []string
+	Libs proptools.Configurable[[]string]
 
 	// List of java libs that this module has static dependencies to and will be
 	// merge zipped after metalava invocation
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 
 	// Version of previously released API file for compatibility check.
 	Previous_api *string `android:"path"`
@@ -2174,8 +2196,8 @@
 
 		}
 	}
-	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
-	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs.GetOrDefault(ctx, nil)...)
+	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
 
 	for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations {
 		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName)
@@ -2359,11 +2381,14 @@
 	ctx.Phony(ctx.ModuleName(), al.stubsJar)
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(al.stubsJar),
-		ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
-		ImplementationJars:             android.PathsIfNonNil(al.stubsJar),
-		AidlIncludeDirs:                android.Paths{},
-		StubsLinkType:                  Stubs,
+		HeaderJars:                             android.PathsIfNonNil(al.stubsJar),
+		LocalHeaderJars:                        android.PathsIfNonNil(al.stubsJar),
+		TransitiveStaticLibsHeaderJars:         android.NewDepSet(android.PREORDER, android.PathsIfNonNil(al.stubsJar), nil),
+		TransitiveStaticLibsImplementationJars: android.NewDepSet(android.PREORDER, android.PathsIfNonNil(al.stubsJar), nil),
+		ImplementationAndResourcesJars:         android.PathsIfNonNil(al.stubsJar),
+		ImplementationJars:                     android.PathsIfNonNil(al.stubsJar),
+		AidlIncludeDirs:                        android.Paths{},
+		StubsLinkType:                          Stubs,
 		// No aconfig libraries on api libraries
 	})
 }
@@ -2406,16 +2431,16 @@
 
 func (al *ApiLibrary) IDEInfo(ctx android.BaseModuleContext, i *android.IdeInfo) {
 	i.Deps = append(i.Deps, al.ideDeps(ctx)...)
-	i.Libs = append(i.Libs, al.properties.Libs...)
-	i.Static_libs = append(i.Static_libs, al.properties.Static_libs...)
+	i.Libs = append(i.Libs, al.properties.Libs.GetOrDefault(ctx, nil)...)
+	i.Static_libs = append(i.Static_libs, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
 	i.SrcJars = append(i.SrcJars, al.stubsSrcJar.String())
 }
 
 // deps of java_api_library for module_bp_java_deps.json
 func (al *ApiLibrary) ideDeps(ctx android.BaseModuleContext) []string {
 	ret := []string{}
-	ret = append(ret, al.properties.Libs...)
-	ret = append(ret, al.properties.Static_libs...)
+	ret = append(ret, al.properties.Libs.GetOrDefault(ctx, nil)...)
+	ret = append(ret, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
 	if al.properties.System_modules != nil {
 		ret = append(ret, proptools.String(al.properties.System_modules))
 	}
@@ -2459,7 +2484,7 @@
 	Libs []string
 
 	// List of static java libs that this module has dependencies to
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 
 	// List of files to remove from the jar file(s)
 	Exclude_files []string
@@ -2600,7 +2625,7 @@
 
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
-	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...)
 
 	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
 		sdkDeps(ctx, android.SdkContext(j), j.dexer)
@@ -2634,7 +2659,13 @@
 
 	var flags javaBuilderFlags
 
-	j.collectTransitiveHeaderJars(ctx)
+	var transitiveClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveBootClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsImplementationJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsResourceJars []*android.DepSet[android.Path]
+
+	j.collectTransitiveHeaderJarsForR8(ctx)
 	var staticJars android.Paths
 	var staticResourceJars android.Paths
 	var staticHeaderJars android.Paths
@@ -2645,32 +2676,67 @@
 			case libTag, sdkLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 				staticJars = append(staticJars, dep.ImplementationJars...)
 				staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
 				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+					transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
+				if dep.TransitiveStaticLibsImplementationJars != nil {
+					transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+				}
+				if dep.TransitiveStaticLibsResourceJars != nil {
+					transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars)
+				}
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			}
-		} else if dep, ok := module.(SdkLibraryDependency); ok {
+		} else if _, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
 			case libTag, sdkLibTag:
-				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
+				sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
+				generatingLibsString := android.PrettyConcat(
+					getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
+				ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
 			}
 		}
 
 		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
-	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
+	localJars := android.PathsForModuleSrc(ctx, j.properties.Jars)
 	jarName := j.Stem() + ".jar"
 
+	// Combine only the local jars together for use in transitive classpaths.
+	// Always pass input jar through TransformJarsToJar to strip module-info.class from prebuilts.
+	localCombinedHeaderJar := android.PathForModuleOut(ctx, "local-combined", jarName)
+	TransformJarsToJar(ctx, localCombinedHeaderJar, "combine local prebuilt implementation jars", localJars, android.OptionalPath{},
+		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+	localStrippedJars := android.Paths{localCombinedHeaderJar}
+
+	completeStaticLibsHeaderJars := android.NewDepSet(android.PREORDER, localStrippedJars, transitiveStaticLibsHeaderJars)
+	completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, localStrippedJars, transitiveStaticLibsImplementationJars)
+	completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsResourceJars)
+
 	// Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output
 	// file of the module to be named jarName.
 	var outputFile android.Path
 	combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName)
-	implementationJars := append(slices.Clone(jars), staticJars...)
+	var implementationJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		implementationJars = completeStaticLibsImplementationJars.ToList()
+	} else {
+		implementationJars = append(slices.Clone(localJars), staticJars...)
+	}
 	TransformJarsToJar(ctx, combinedImplementationJar, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
 		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
 	outputFile = combinedImplementationJar
@@ -2693,7 +2759,12 @@
 	if reuseImplementationJarAsHeaderJar {
 		headerJar = outputFile
 	} else {
-		headerJars := append(slices.Clone(jars), staticHeaderJars...)
+		var headerJars android.Paths
+		if ctx.Config().UseTransitiveJarsInClasspath() {
+			headerJars = completeStaticLibsHeaderJars.ToList()
+		} else {
+			headerJars = append(slices.Clone(localJars), staticHeaderJars...)
+		}
 		headerOutputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
 		TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
 			false, j.properties.Exclude_files, j.properties.Exclude_dirs)
@@ -2712,6 +2783,11 @@
 		} else {
 			headerJar = outputFile
 		}
+
+		// Enabling jetifier requires modifying classes from transitive dependencies, disable transitive
+		// classpath and use the combined header jar instead.
+		completeStaticLibsHeaderJars = android.NewDepSet(android.PREORDER, android.Paths{headerJar}, nil)
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, android.Paths{outputFile}, nil)
 	}
 
 	implementationJarFile := outputFile
@@ -2735,42 +2811,21 @@
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
 
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		ctx.CheckbuildFile(localJars...)
+	} else {
+		ctx.CheckbuildFile(outputFile)
+	}
+
 	if ctx.Device() {
-		// If this is a variant created for a prebuilt_apex then use the dex implementation jar
-		// obtained from the associated deapexer module.
+		// Shared libraries deapexed from prebuilt apexes are no longer supported.
+		// Set the dexJarBuildPath to a fake path.
+		// This allows soong analysis pass, but will be an error during ninja execution if there are
+		// any rdeps.
 		ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 		if ai.ForPrebuiltApex {
-			// Get the path of the dex implementation jar from the `deapexer` module.
-			di, err := android.FindDeapexerProviderForModule(ctx)
-			if err != nil {
-				// An error was found, possibly due to multiple apexes in the tree that export this library
-				// Defer the error till a client tries to call DexJarBuildPath
-				j.dexJarFileErr = err
-				j.initHiddenAPIError(err)
-				return
-			}
-			dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(j.BaseModuleName())
-			if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
-				dexJarFile := makeDexJarPathFromPath(dexOutputPath)
-				j.dexJarFile = dexJarFile
-				installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, ApexRootRelativePathToJavaLib(j.BaseModuleName()))
-				j.dexJarInstallFile = installPath
-
-				j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath)
-				setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
-				j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
-
-				if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
-					j.dexpreopter.inputProfilePathOnHost = profilePath
-				}
-
-				// Initialize the hiddenapi structure.
-				j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
-			} else {
-				// This should never happen as a variant for a prebuilt_apex is only created if the
-				// prebuilt_apex has been configured to export the java library dex file.
-				ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
-			}
+			j.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported"))
+			j.initHiddenAPI(ctx, j.dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
 		} else if Bool(j.dexProperties.Compile_dex) {
 			sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
 			if sdkDep.invalidVersion {
@@ -2801,6 +2856,7 @@
 			if ctx.Failed() {
 				return
 			}
+			ctx.CheckbuildFile(dexOutputFile)
 
 			// Initialize the hiddenapi structure.
 			j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex)
@@ -2814,14 +2870,18 @@
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(j.combinedHeaderFile),
-		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
-		ImplementationJars:             android.PathsIfNonNil(implementationJarFile.WithoutRel()),
-		ResourceJars:                   android.PathsIfNonNil(resourceJarFile),
-		AidlIncludeDirs:                j.exportAidlIncludeDirs,
-		StubsLinkType:                  j.stubsLinkType,
+		HeaderJars:                             android.PathsIfNonNil(j.combinedHeaderFile),
+		LocalHeaderJars:                        android.PathsIfNonNil(j.combinedHeaderFile),
+		TransitiveLibsHeaderJarsForR8:          j.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8:    j.transitiveStaticLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJars:         completeStaticLibsHeaderJars,
+		TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+		TransitiveStaticLibsResourceJars:       completeStaticLibsResourceJars,
+		ImplementationAndResourcesJars:         android.PathsIfNonNil(j.combinedImplementationFile),
+		ImplementationJars:                     android.PathsIfNonNil(implementationJarFile.WithoutRel()),
+		ResourceJars:                           android.PathsIfNonNil(resourceJarFile),
+		AidlIncludeDirs:                        j.exportAidlIncludeDirs,
+		StubsLinkType:                          j.stubsLinkType,
 		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 
@@ -3222,15 +3282,20 @@
 
 func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var xrefTargets android.Paths
+	var xrefKotlinTargets android.Paths
 	ctx.VisitAllModules(func(module android.Module) {
 		if javaModule, ok := module.(xref); ok {
 			xrefTargets = append(xrefTargets, javaModule.XrefJavaFiles()...)
+			xrefKotlinTargets = append(xrefKotlinTargets, javaModule.XrefKotlinFiles()...)
 		}
 	})
 	// TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets
 	if len(xrefTargets) > 0 {
 		ctx.Phony("xref_java", xrefTargets...)
 	}
+	if len(xrefKotlinTargets) > 0 {
+		ctx.Phony("xref_kotlin", xrefKotlinTargets...)
+	}
 }
 
 var Bool = proptools.Bool
@@ -3253,6 +3318,10 @@
 	if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() {
 		// A shared SDK library. This should be added as a top-level CLC element.
 		sdkLib = &depName
+	} else if lib, ok := depModule.(SdkLibraryComponentDependency); ok && lib.OptionalSdkLibraryImplementation() != nil {
+		if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation())+".impl" {
+			sdkLib = lib.OptionalSdkLibraryImplementation()
+		}
 	} else if ulib, ok := depModule.(ProvidesUsesLib); ok {
 		// A non-SDK library disguised as an SDK library by the means of `provides_uses_lib`
 		// property. This should be handled in the same way as a shared SDK library.
diff --git a/java/java_test.go b/java/java_test.go
index 9e39b51..e0fd0f2 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
 	"path/filepath"
 	"reflect"
 	"runtime"
+	"slices"
 	"strconv"
 	"strings"
 	"testing"
@@ -211,7 +212,7 @@
 }
 
 func TestSimple(t *testing.T) {
-	ctx, _ := testJava(t, `
+	bp := `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -222,31 +223,157 @@
 		java_library {
 			name: "bar",
 			srcs: ["b.java"],
+			static_libs: ["quz"],
 		}
 
 		java_library {
 			name: "baz",
 			srcs: ["c.java"],
+			static_libs: ["quz"],
 		}
-	`)
 
-	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
+		java_library {
+			name: "quz",
+			srcs: ["d.java"],
+		}`
 
-	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
-		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	frameworkTurbineCombinedJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
 	}
 
-	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
-	barTurbine := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
-	bazTurbine := filepath.Join("out", "soong", ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
+	frameworkTurbineJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
+	}
 
-	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barTurbine)
+	testCases := []struct {
+		name string
 
-	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazTurbine)
+		preparer android.FixturePreparer
 
-	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
-		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
+		fooJavacInputs          []string
+		fooJavacClasspath       []string
+		fooCombinedInputs       []string
+		fooHeaderCombinedInputs []string
+
+		barJavacInputs          []string
+		barJavacClasspath       []string
+		barCombinedInputs       []string
+		barHeaderCombinedInputs []string
+	}{
+		{
+			name:           "normal",
+			preparer:       android.NullFixturePreparer,
+			fooJavacInputs: []string{"a.java"},
+			fooJavacClasspath: slices.Concat(
+				frameworkTurbineCombinedJars,
+				[]string{
+					"out/soong/.intermediates/bar/android_common/turbine-combined/bar.jar",
+					"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+				},
+			),
+			fooCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+				"out/soong/.intermediates/baz/android_common/combined/baz.jar",
+			},
+
+			fooHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+				"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+			},
+
+			barJavacInputs: []string{"b.java"},
+			barJavacClasspath: slices.Concat(
+				frameworkTurbineCombinedJars,
+				[]string{
+					"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+				},
+			),
+			barCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/javac/bar.jar",
+				"out/soong/.intermediates/quz/android_common/javac/quz.jar",
+			},
+			barHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+				"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+			},
+		},
+		{
+			name:           "transitive classpath",
+			preparer:       PrepareForTestWithTransitiveClasspathEnabled,
+			fooJavacInputs: []string{"a.java"},
+			fooJavacClasspath: slices.Concat(
+				frameworkTurbineJars,
+				[]string{
+					"out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+					"out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+					"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+				},
+			),
+			fooCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+				"out/soong/.intermediates/baz/android_common/javac/baz.jar",
+				"out/soong/.intermediates/quz/android_common/javac/quz.jar",
+			},
+
+			fooHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+				"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+				"out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+			},
+
+			barJavacInputs: []string{"b.java"},
+			barJavacClasspath: slices.Concat(
+				frameworkTurbineJars,
+				[]string{"out/soong/.intermediates/quz/android_common/turbine/quz.jar"},
+			),
+			barCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/javac/bar.jar",
+				"out/soong/.intermediates/quz/android_common/javac/quz.jar",
+			},
+			barHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+				"out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+			},
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				tt.preparer,
+			).RunTestWithBp(t, bp)
+			foo := result.ModuleForTests("foo", "android_common")
+
+			fooJavac := foo.Rule("javac")
+			android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs)
+
+			fooJavacClasspath := fooJavac.Args["classpath"]
+			android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath,
+				strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":"))
+
+			fooCombinedJar := foo.Output("combined/foo.jar")
+			android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs)
+
+			fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar")
+			android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs)
+
+			bar := result.ModuleForTests("bar", "android_common")
+			barJavac := bar.Rule("javac")
+			android.AssertPathsRelativeToTopEquals(t, "bar javac inputs", tt.barJavacInputs, barJavac.Inputs)
+
+			barJavacClasspath := barJavac.Args["classpath"]
+			android.AssertStringPathsRelativeToTopEquals(t, "bar javac classpath", result.Config, tt.barJavacClasspath,
+				strings.Split(strings.TrimPrefix(barJavacClasspath, "-classpath "), ":"))
+
+			barCombinedJar := bar.Output("combined/bar.jar")
+			android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs)
+
+			barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar")
+			android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs)
+		})
 	}
 }
 
@@ -543,7 +670,7 @@
 		java_library {
 			name: "foo",
 			srcs: ["a.java", ":stubs-source"],
-			libs: ["bar", "sdklib"],
+			libs: ["bar", "sdklib.stubs"],
 			static_libs: ["baz"],
 		}
 
@@ -590,7 +717,7 @@
 	barModule := ctx.ModuleForTests("bar", "android_common")
 	barJar := barModule.Output("combined/bar.jar").Output
 	bazModule := ctx.ModuleForTests("baz", "android_common")
-	bazJar := bazModule.Rule("combineJar").Output
+	bazJar := bazModule.Output("combined/baz.jar").Output
 	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").
 		Output("combined/sdklib.stubs.jar").Output
 
@@ -2547,7 +2674,7 @@
 	android.AssertBoolEquals(t, "stub module expected to depend on from-source stub",
 		true, CheckModuleHasDependency(t, result.TestContext,
 			apiScopePublic.stubsLibraryModuleName("foo"), "android_common",
-			apiScopePublic.sourceStubLibraryModuleName("foo")))
+			apiScopePublic.sourceStubsLibraryModuleName("foo")))
 
 	android.AssertBoolEquals(t, "stub module expected to not depend on from-text stub",
 		false, CheckModuleHasDependency(t, result.TestContext,
diff --git a/java/kotlin.go b/java/kotlin.go
index c28bc3f..f42d163 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -64,6 +64,28 @@
 	"kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir",
 	"headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name")
 
+var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe",
+	blueprint.RuleParams{
+		Command: `rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
+			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` +
+			`${config.KotlinKytheExtractor} -corpus ${kytheCorpus} --srcs @$out.rsp --srcs @"$srcJarDir/list" $commonSrcFilesList --cp @$classpath -o $out --kotlin_out $outJar ` +
+			// wrap the additional kotlin args.
+			// Skip Xbuild file, pass the cp explicitly.
+			// Skip header jars, those should not have an effect on kythe results.
+			` --args '${config.KotlincGlobalFlags} ` +
+			` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` +
+			` $kotlincFlags -jvm-target $kotlinJvmTarget ` +
+			`${config.KotlincKytheGlobalFlags}'`,
+		CommandDeps: []string{
+			"${config.KotlinKytheExtractor}",
+			"${config.ZipSyncCmd}",
+		},
+		Rspfile:        "$out.rsp",
+		RspfileContent: "$in",
+	},
+	"classpath", "kotlincFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir",
+)
+
 func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath {
 	if len(commonSrcFiles) > 0 {
 		// The list of common_srcs may be too long to put on the command line, but
@@ -81,7 +103,7 @@
 }
 
 // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
-func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath,
+func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath,
 	srcFiles, commonSrcFiles, srcJars android.Paths,
 	flags javaBuilderFlags) {
 
@@ -127,6 +149,31 @@
 			"name":              kotlinName,
 		},
 	})
+
+	// Emit kythe xref rule
+	if (ctx.Config().EmitXrefRules()) && ctx.Module() == ctx.PrimaryModule() {
+		extractionFile := outputFile.ReplaceExtension(ctx, "kzip")
+		args := map[string]string{
+			"classpath":       classpathRspFile.String(),
+			"kotlincFlags":    flags.kotlincFlags,
+			"kotlinJvmTarget": flags.javaVersion.StringForKotlinc(),
+			"outJar":          outputFile.String(),
+			"srcJars":         strings.Join(srcJars.Strings(), " "),
+			"srcJarDir":       android.PathForModuleOut(ctx, "kotlinc", "srcJars.xref").String(),
+		}
+		if commonSrcsList.Valid() {
+			args["commonSrcFilesList"] = "--common_srcs @" + commonSrcsList.String()
+		}
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        kotlinKytheExtract,
+			Description: "kotlinKythe",
+			Output:      extractionFile,
+			Inputs:      srcFiles,
+			Implicits:   deps,
+			Args:        args,
+		})
+		j.kytheKotlinFiles = append(j.kytheKotlinFiles, extractionFile)
+	}
 }
 
 var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true},
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 844e974..f6e7fca 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -56,6 +56,13 @@
 		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine-combined/kotlin-annotations.jar",
 	}
 
+	kotlinStdlibTurbineJars := []string{
+		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine/kotlin-stdlib.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine/kotlin-stdlib-jdk7.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine/kotlin-stdlib-jdk8.jar",
+		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine/kotlin-annotations.jar",
+	}
+
 	kotlinStdlibJavacJars := []string{
 		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar",
 		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar",
@@ -68,11 +75,21 @@
 		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine-combined/core-lambda-stubs.jar",
 	}
 
+	bootclasspathTurbineJars := []string{
+		"out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine/stable.core.platform.api.stubs.jar",
+		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine/core-lambda-stubs.jar",
+	}
+
 	frameworkTurbineCombinedJars := []string{
 		"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
 		"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
 	}
 
+	frameworkTurbineJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
+	}
+
 	testCases := []struct {
 		name string
 
@@ -150,6 +167,69 @@
 				kotlinStdlibTurbineCombinedJars,
 			),
 		},
+		{
+			name:             "transitive classpath",
+			preparer:         PrepareForTestWithTransitiveClasspathEnabled,
+			fooKotlincInputs: []string{"a.java", "b.kt"},
+			fooJavacInputs:   []string{"a.java"},
+			fooKotlincClasspath: slices.Concat(
+				bootclasspathTurbineJars,
+				frameworkTurbineJars,
+				[]string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
+				kotlinStdlibTurbineJars,
+			),
+			fooJavacClasspath: slices.Concat(
+				[]string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
+				frameworkTurbineJars,
+				[]string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
+				kotlinStdlibTurbineJars,
+			),
+			fooCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
+					"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
+				},
+				kotlinStdlibJavacJars,
+			),
+			fooHeaderCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+				},
+				kotlinStdlibTurbineJars,
+			),
+
+			barKotlincInputs: []string{"b.kt"},
+			barKotlincClasspath: slices.Concat(
+				bootclasspathTurbineJars,
+				frameworkTurbineJars,
+				[]string{
+					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+				},
+				kotlinStdlibTurbineJars,
+				[]string{"out/soong/.intermediates/baz/android_common/turbine/baz.jar"},
+			),
+			barCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
+					"out/soong/.intermediates/baz/android_common/javac/baz.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
+				},
+				kotlinStdlibJavacJars,
+			),
+			barHeaderCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
+					"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+				},
+				kotlinStdlibTurbineJars,
+			),
+		},
 	}
 
 	for _, tt := range testCases {
diff --git a/java/metalava/Android.bp b/java/metalava/Android.bp
index ccbd191..6bf1832 100644
--- a/java/metalava/Android.bp
+++ b/java/metalava/Android.bp
@@ -15,4 +15,5 @@
 filegroup {
     name: "metalava-config-files",
     srcs: ["*-config.xml"],
+    visibility: ["//visibility:public"],
 }
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 67ed84e..5b145c6 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -110,6 +110,7 @@
 	p.installConfigFile = android.PathForModuleInstall(ctx, "etc", "compatconfig", p.configFile.Base())
 	rule.Build(configFileName, "Extract compat/compat_config.xml and install it")
 	ctx.InstallFile(p.installDirPath, p.configFile.Base(), p.configFile)
+	ctx.SetOutputFiles(android.Paths{p.configFile}, "")
 }
 
 func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 00613ee..527e479 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -124,8 +124,8 @@
 	return
 }
 
-func prebuiltApiModuleName(mctx android.LoadHookContext, module, scope, version string) string {
-	return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module)
+func prebuiltApiModuleName(moduleName, module, scope, version string) string {
+	return fmt.Sprintf("%s_%s_%s_%s", moduleName, scope, version, module)
 }
 func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) {
 	props := struct {
@@ -135,7 +135,7 @@
 		Installable *bool
 		Compile_dex *bool
 	}{
-		Name:        proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version)),
+		Name:        proptools.StringPtr(prebuiltApiModuleName(mctx.ModuleName(), module, scope, version)),
 		Jars:        []string{path},
 		Sdk_version: proptools.StringPtr(sdkVersion),
 		Installable: proptools.BoolPtr(false),
@@ -257,8 +257,8 @@
 		Name *string
 		Libs []string
 	}{}
-	props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", scope, version))
-	props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", scope, version))
+	props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx.ModuleName(), "system_modules", scope, version))
+	props.Libs = append(props.Libs, prebuiltApiModuleName(mctx.ModuleName(), "core-for-system-modules", scope, version))
 
 	mctx.CreateModule(systemModulesImportFactory, &props)
 }
diff --git a/java/ravenwood.go b/java/ravenwood.go
index bb136cf..9239bbd 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -33,8 +33,8 @@
 var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"}
 var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"}
 var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"}
-var ravenwoodDataTag = dependencyTag{name: "ravenwooddata"}
 var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"}
+var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"}
 
 const ravenwoodUtilsName = "ravenwood-utils"
 const ravenwoodRuntimeName = "ravenwood-runtime"
@@ -57,11 +57,17 @@
 	Jni_libs []string
 
 	// Specify another android_app module here to copy it to the test directory, so that
-	// the ravenwood test can access it.
+	// the ravenwood test can access it. This APK will be loaded as resources of the test
+	// target app.
 	// TODO: For now, we simply refer to another android_app module and copy it to the
 	// test directory. Eventually, android_ravenwood_test should support all the resource
 	// related properties and build resources from the `res/` directory.
 	Resource_apk *string
+
+	// Specify another android_app module here to copy it to the test directory, so that
+	// the ravenwood test can access it. This APK will be loaded as resources of the test
+	// instrumentation app itself.
+	Inst_resource_apk *string
 }
 
 type ravenwoodTest struct {
@@ -128,6 +134,10 @@
 	if resourceApk := proptools.String(r.ravenwoodTestProperties.Resource_apk); resourceApk != "" {
 		ctx.AddVariationDependencies(nil, ravenwoodTestResourceApkTag, resourceApk)
 	}
+
+	if resourceApk := proptools.String(r.ravenwoodTestProperties.Inst_resource_apk); resourceApk != "" {
+		ctx.AddVariationDependencies(nil, ravenwoodTestInstResourceApkTag, resourceApk)
+	}
 }
 
 func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -195,13 +205,16 @@
 	}
 
 	resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks")
-	if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 {
-		for _, installFile := range android.OtherModuleProviderOrDefault(
-			ctx, resApk[0], android.InstallFilesProvider).InstallFiles {
-			installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile)
+
+	copyResApk := func(tag blueprint.DependencyTag, toFileName string) {
+		if resApk := ctx.GetDirectDepsWithTag(tag); len(resApk) > 0 {
+			installFile := android.OutputFileForModule(ctx, resApk[0], "")
+			installResApk := ctx.InstallFile(resApkInstallPath, toFileName, installFile)
 			installDeps = append(installDeps, installResApk)
 		}
 	}
+	copyResApk(ravenwoodTestResourceApkTag, "ravenwood-res.apk")
+	copyResApk(ravenwoodTestInstResourceApkTag, "ravenwood-inst-res.apk")
 
 	// Install our JAR with all dependencies
 	ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
@@ -228,7 +241,10 @@
 	Jni_libs []string
 
 	// We use this to copy framework-res.apk to the ravenwood runtime directory.
-	Data []string
+	Data []string `android:"path,arch_variant"`
+
+	// We use this to copy font files to the ravenwood runtime directory.
+	Fonts []string `android:"path,arch_variant"`
 }
 
 type ravenwoodLibgroup struct {
@@ -267,9 +283,6 @@
 	for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs {
 		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
 	}
-	for _, data := range r.ravenwoodLibgroupProperties.Data {
-		ctx.AddVariationDependencies(nil, ravenwoodDataTag, data)
-	}
 }
 
 func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -309,12 +322,17 @@
 	}
 
 	dataInstallPath := installPath.Join(ctx, "ravenwood-data")
-	for _, data := range r.ravenwoodLibgroupProperties.Data {
-		libModule := ctx.GetDirectDepWithTag(data, ravenwoodDataTag)
-		file := android.OutputFileForModule(ctx, libModule, "")
+	data := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Data)
+	for _, file := range data {
 		ctx.InstallFile(dataInstallPath, file.Base(), file)
 	}
 
+	fontsInstallPath := installPath.Join(ctx, "fonts")
+	fonts := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Fonts)
+	for _, file := range fonts {
+		ctx.InstallFile(fontsInstallPath, file.Base(), file)
+	}
+
 	// Normal build should perform install steps
 	ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
 }
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
index d26db93..753a118 100644
--- a/java/ravenwood_test.go
+++ b/java/ravenwood_test.go
@@ -19,6 +19,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/etc"
 )
 
 var prepareRavenwoodRuntime = android.GroupFixturePreparers(
@@ -59,11 +60,19 @@
 		}
 		android_app {
 			name: "app1",
-            sdk_version: "current",
+			sdk_version: "current",
 		}
 		android_app {
 			name: "app2",
-            sdk_version: "current",
+			sdk_version: "current",
+		}
+		android_app {
+			name: "app3",
+			sdk_version: "current",
+		}
+		prebuilt_font {
+			name: "Font.ttf",
+			src: "Font.ttf",
 		}
 		android_ravenwood_libgroup {
 			name: "ravenwood-runtime",
@@ -76,7 +85,10 @@
 				"ravenwood-runtime-jni2",
 			],
 			data: [
-				"app1",
+				":app1",
+			],
+			fonts: [
+				":Font.ttf"
 			],
 		}
 		android_ravenwood_libgroup {
@@ -97,6 +109,7 @@
 
 	ctx := android.GroupFixturePreparers(
 		PrepareForIntegrationTestWithJava,
+		etc.PrepareForTestWithPrebuiltEtc,
 		prepareRavenwoodRuntime,
 	).RunTest(t)
 
@@ -114,6 +127,7 @@
 	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so")
 	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
 	runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/fonts/Font.ttf")
 	utils := ctx.ModuleForTests("ravenwood-utils", "android_common")
 	utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar")
 }
@@ -125,29 +139,30 @@
 
 	ctx := android.GroupFixturePreparers(
 		PrepareForIntegrationTestWithJava,
+		etc.PrepareForTestWithPrebuiltEtc,
 		prepareRavenwoodRuntime,
 	).RunTestWithBp(t, `
-	cc_library_shared {
-		name: "jni-lib1",
-		host_supported: true,
-		srcs: ["jni.cpp"],
-	}
-	cc_library_shared {
-		name: "jni-lib2",
-		host_supported: true,
-		srcs: ["jni.cpp"],
-		stem: "libblue",
-		shared_libs: [
-			"jni-lib3",
-		],
-	}
-	cc_library_shared {
-		name: "jni-lib3",
-		host_supported: true,
-		srcs: ["jni.cpp"],
-		stem: "libpink",
-	}
-	android_ravenwood_test {
+		cc_library_shared {
+			name: "jni-lib1",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+		}
+		cc_library_shared {
+			name: "jni-lib2",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+			stem: "libblue",
+			shared_libs: [
+				"jni-lib3",
+			],
+		}
+		cc_library_shared {
+			name: "jni-lib3",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+			stem: "libpink",
+		}
+		android_ravenwood_test {
 			name: "ravenwood-test",
 			srcs: ["Test.java"],
 			jni_libs: [
@@ -156,6 +171,7 @@
 				"ravenwood-runtime-jni2",
 			],
 			resource_apk: "app2",
+			inst_resource_apk: "app3",
 			sdk_version: "test_current",
 		}
 	`)
@@ -183,6 +199,7 @@
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so")
 	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk")
+	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk")
 
 	// ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted.
 	for _, o := range module.AllOutputs() {
diff --git a/java/robolectric.go b/java/robolectric.go
index 26f4b71..374fc5f 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -16,9 +16,6 @@
 
 import (
 	"fmt"
-	"io"
-	"strconv"
-	"strings"
 
 	"android/soong/android"
 	"android/soong/java/config"
@@ -88,16 +85,6 @@
 	robolectricProperties robolectricProperties
 	testProperties        testProperties
 
-	libs  []string
-	tests []string
-
-	manifest    android.Path
-	resourceApk android.Path
-
-	combinedJar android.WritablePath
-
-	roboSrcJar android.Path
-
 	testConfig android.Path
 	data       android.Paths
 
@@ -121,12 +108,12 @@
 	}
 
 	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
-		ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
+		ctx.AddVariationDependencies(nil, staticLibTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
 	} else if !proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) {
 		if proptools.Bool(r.robolectricProperties.Upstream) {
-			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream")
+			ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib+"_upstream")
 		} else {
-			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+			ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib)
 		}
 	}
 
@@ -134,10 +121,10 @@
 		ctx.AddVariationDependencies(nil, roboRuntimeOnlyTag, robolectricCurrentLib+"_upstream")
 	} else {
 		// opting out from strict mode, robolectric_non_strict_mode_permission lib should be added
-		ctx.AddVariationDependencies(nil, libTag, "robolectric_non_strict_mode_permission")
+		ctx.AddVariationDependencies(nil, staticLibTag, "robolectric_non_strict_mode_permission")
 	}
 
-	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, robolectricDefaultLibs...)
 
 	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
 
@@ -163,9 +150,6 @@
 	})
 	r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data)
 
-	roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
-		Join(ctx, "com/android/tools/test_config.properties")
-
 	var ok bool
 	var instrumentedApp *AndroidApp
 
@@ -181,90 +165,58 @@
 		panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
 	}
 
+	var resourceApk android.Path
+	var manifest android.Path
 	if instrumentedApp != nil {
-		r.manifest = instrumentedApp.mergedManifestFile
-		r.resourceApk = instrumentedApp.outputFile
-
-		generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
-		r.extraResources = android.Paths{roboTestConfig}
-	}
-
-	r.Library.GenerateAndroidBuildActions(ctx)
-
-	roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
-
-	if instrumentedApp != nil {
-		r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
-		r.roboSrcJar = roboSrcJar
+		manifest = instrumentedApp.mergedManifestFile
+		resourceApk = instrumentedApp.outputFile
 	}
 
 	roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
 	generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
 
-	combinedJarJars := android.Paths{
-		// roboTestConfigJar comes first so that its com/android/tools/test_config.properties
-		// overrides the one from r.extraResources.  The r.extraResources one can be removed
-		// once the Make test runner is removed.
-		roboTestConfigJar,
-		r.outputFile,
-	}
+	extraCombinedJars := android.Paths{roboTestConfigJar}
 
-	if instrumentedApp != nil {
-		combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar)
-	}
-
-	handleLibDeps := func(dep android.Module, runtimeOnly bool) {
-		if !runtimeOnly {
-			r.libs = append(r.libs, ctx.OtherModuleName(dep))
-		}
+	handleLibDeps := func(dep android.Module) {
 		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
 			if m, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
-				combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
+				extraCombinedJars = append(extraCombinedJars, m.ImplementationAndResourcesJars...)
 			}
 		}
 	}
 
 	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
-		handleLibDeps(dep, false)
+		handleLibDeps(dep)
 	}
 	for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) {
-		handleLibDeps(dep, false)
+		handleLibDeps(dep)
 	}
 	// handle the runtimeOnly tag for strict_mode
 	for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyTag) {
-		handleLibDeps(dep, true)
+		handleLibDeps(dep)
 	}
 
-	r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
-	TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{},
-		false, nil, nil)
-
-	// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
-	// annotated as a test and run it.
-	for _, src := range r.uniqueSrcFiles {
-		s := src.Rel()
-		if !strings.HasSuffix(s, "Test.java") && !strings.HasSuffix(s, "Test.kt") {
-			continue
-		} else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
-			continue
-		} else {
-			s = strings.TrimPrefix(s, "src/")
-		}
-		r.tests = append(r.tests, s)
+	if instrumentedApp != nil {
+		extraCombinedJars = append(extraCombinedJars, instrumentedApp.implementationAndResourcesJar)
 	}
 
+	r.stem = proptools.StringDefault(r.overridableProperties.Stem, ctx.ModuleName())
+	r.classLoaderContexts = r.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+	r.dexpreopter.disableDexpreopt()
+	r.compile(ctx, nil, nil, nil, extraCombinedJars)
+
 	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
 	var installDeps android.InstallPaths
 
-	if r.manifest != nil {
-		r.data = append(r.data, r.manifest)
-		installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+	if manifest != nil {
+		r.data = append(r.data, manifest)
+		installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", manifest)
 		installDeps = append(installDeps, installedManifest)
 	}
 
-	if r.resourceApk != nil {
-		r.data = append(r.data, r.resourceApk)
-		installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+	if resourceApk != nil {
+		r.data = append(r.data, resourceApk)
+		installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", resourceApk)
 		installDeps = append(installDeps, installedResourceApk)
 	}
 
@@ -287,29 +239,10 @@
 		installDeps = append(installDeps, installJni)
 	}
 
-	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
+	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
 	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
-func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
-	instrumentedApp *AndroidApp) {
-	rule := android.NewRuleBuilder(pctx, ctx)
-
-	manifest := instrumentedApp.mergedManifestFile
-	resourceApk := instrumentedApp.outputFile
-
-	rule.Command().Text("rm -f").Output(outputFile)
-	rule.Command().
-		Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
-		Textf(`echo "android_resource_apk=%s" >>`, resourceApk.String()).Output(outputFile).
-		// Make it depend on the files to which it points so the test file's timestamp is updated whenever the
-		// contents change
-		Implicit(manifest).
-		Implicit(resourceApk)
-
-	rule.Build("generate_test_config", "generate test_config.properties")
-}
-
 func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -332,22 +265,6 @@
 	rule.Build("generate_test_config_samedir", "generate test_config.properties")
 }
 
-func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
-	instrumentedApp *AndroidApp) {
-
-	srcJarArgs := android.CopyOf(instrumentedApp.srcJarArgs)
-	srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
-
-	for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
-		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
-			srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...)
-			srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...)
-		}
-	}
-
-	TransformResourcesToJar(ctx, outputFile, srcJarArgs, srcJarDeps)
-}
-
 func (r *robolectricTest) AndroidMkEntries() []android.AndroidMkEntries {
 	entriesList := r.Library.AndroidMkEntries()
 	entries := &entriesList[0]
@@ -359,61 +276,11 @@
 				entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig)
 			}
 		})
-
-	entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
-		func(w io.Writer, name, prefix, moduleDir string) {
-			if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
-				numShards := int(*s)
-				shardSize := (len(r.tests) + numShards - 1) / numShards
-				shards := android.ShardStrings(r.tests, shardSize)
-				for i, shard := range shards {
-					r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard)
-				}
-
-				// TODO: add rules to dist the outputs of the individual tests, or combine them together?
-				fmt.Fprintln(w, "")
-				fmt.Fprintln(w, ".PHONY:", "Run"+name)
-				fmt.Fprintln(w, "Run"+name, ": \\")
-				for i := range shards {
-					fmt.Fprintln(w, "   ", "Run"+name+strconv.Itoa(i), "\\")
-				}
-				fmt.Fprintln(w, "")
-			} else {
-				r.writeTestRunner(w, name, "Run"+name, r.tests)
-			}
-		},
-	}
-
 	return entriesList
 }
 
-func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, tests []string) {
-	fmt.Fprintln(w, "")
-	fmt.Fprintln(w, "include $(CLEAR_VARS)", " # java.robolectricTest")
-	fmt.Fprintln(w, "LOCAL_MODULE :=", name)
-	android.AndroidMkEmitAssignList(w, "LOCAL_JAVA_LIBRARIES", []string{module}, r.libs)
-	fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
-	if r.roboSrcJar != nil {
-		fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
-	}
-	android.AndroidMkEmitAssignList(w, "LOCAL_ROBOTEST_FILES", tests)
-	if t := r.robolectricProperties.Test_options.Timeout; t != nil {
-		fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
-	}
-	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
-		fmt.Fprintf(w, "-include prebuilts/misc/common/robolectric/%s/run_robotests.mk\n", v)
-	} else {
-		fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
-	}
-}
-
 // An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
-// instead of on a device.  It also generates a rule with the name of the module prefixed with "Run" that can be
-// used to run the tests.  Running the tests with build rule will eventually be deprecated and replaced with atest.
-//
-// The test runner considers any file listed in srcs whose name ends with Test.java to be a test class, unless
-// it is named BaseRobolectricTest.java.  The path to the each source file must exactly match the package
-// name, or match the package name when the prefix "src/" is removed.
+// instead of on a device.
 func RobolectricTestFactory() android.Module {
 	module := &robolectricTest{}
 
diff --git a/java/rro.go b/java/rro.go
index 0fc6e1c..8bb9be2 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -17,7 +17,11 @@
 // This file contains the module implementations for runtime_resource_overlay and
 // override_runtime_resource_overlay.
 
-import "android/soong/android"
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
+)
 
 func init() {
 	RegisterRuntimeResourceOverlayBuildComponents(android.InitRegistrationContext)
@@ -71,7 +75,7 @@
 	Min_sdk_version *string
 
 	// list of android_library modules whose resources are extracted and linked against statically
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 
 	// list of android_app modules whose resources are extracted and linked against
 	Resource_libs []string
@@ -120,7 +124,7 @@
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
 
-	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs.GetOrDefault(ctx, nil)...)
 	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
 
 	for _, aconfig_declaration := range r.aaptProperties.Flags_packages {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 25317c5..bb0d7d0 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -248,7 +248,7 @@
 	return scope.stubsLibraryModuleName(baseName) + ".from-text"
 }
 
-func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string {
+func (scope *apiScope) sourceStubsLibraryModuleName(baseName string) string {
 	return scope.stubsLibraryModuleName(baseName) + ".from-source"
 }
 
@@ -268,10 +268,6 @@
 	return baseName + ".stubs.source" + scope.moduleSuffix
 }
 
-func (scope *apiScope) apiModuleName(baseName string) string {
-	return baseName + ".api" + scope.moduleSuffix
-}
-
 func (scope *apiScope) String() string {
 	return scope.name
 }
@@ -830,16 +826,6 @@
 }
 
 type commonToSdkLibraryAndImportProperties struct {
-	// The naming scheme to use for the components that this module creates.
-	//
-	// If not specified then it defaults to "default".
-	//
-	// This is a temporary mechanism to simplify conversion from separate modules for each
-	// component that follow a different naming pattern to the default one.
-	//
-	// TODO(b/155480189) - Remove once naming inconsistencies have been resolved.
-	Naming_scheme *string
-
 	// Specifies whether this module can be used as an Android shared library; defaults
 	// to true.
 	//
@@ -915,8 +901,6 @@
 
 	scopePaths map[*apiScope]*scopePaths
 
-	namingScheme sdkLibraryComponentNamingScheme
-
 	commonSdkLibraryProperties commonToSdkLibraryAndImportProperties
 
 	// Paths to commonSdkLibraryProperties.Doctag_files
@@ -944,15 +928,6 @@
 }
 
 func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
-	schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default")
-	switch schemeProperty {
-	case "default":
-		c.namingScheme = &defaultNamingScheme{}
-	default:
-		ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
-		return false
-	}
-
 	namePtr := proptools.StringPtr(c.module.RootLibraryName())
 	c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
 
@@ -995,41 +970,41 @@
 // Name of the java_library module that compiles the stubs source.
 func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
 	baseName := c.module.RootLibraryName()
-	return c.namingScheme.stubsLibraryModuleName(apiScope, baseName)
+	return apiScope.stubsLibraryModuleName(baseName)
 }
 
 // Name of the java_library module that compiles the exportable stubs source.
 func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
 	baseName := c.module.RootLibraryName()
-	return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName)
+	return apiScope.exportableStubsLibraryModuleName(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.RootLibraryName()
-	return c.namingScheme.stubsSourceModuleName(apiScope, baseName)
+	return apiScope.stubsSourceModuleName(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.RootLibraryName()
-	return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
+	return apiScope.apiLibraryModuleName(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.RootLibraryName()
-	return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName)
+	return apiScope.sourceStubsLibraryModuleName(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.RootLibraryName()
-	return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName)
+	return apiScope.exportableSourceStubsLibraryModuleName(baseName)
 }
 
 // The component names for different outputs of the java_sdk_library.
@@ -1103,21 +1078,6 @@
 	return nil
 }
 
-func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-
-	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
-	if !sdkVersion.ApiLevel.IsPreview() {
-		return PrebuiltJars(ctx, c.module.RootLibraryName(), sdkVersion)
-	}
-
-	paths := c.selectScopePaths(ctx, sdkVersion.Kind)
-	if paths == nil {
-		return nil
-	}
-
-	return paths.stubsHeaderPath
-}
-
 // selectScopePaths returns the *scopePaths appropriate for the specific kind.
 //
 // If the module does not support the specific kind then it will return the *scopePaths for the
@@ -1284,12 +1244,6 @@
 type SdkLibraryDependency interface {
 	SdkLibraryComponentDependency
 
-	// Get the header jars appropriate for the supplied sdk_version.
-	//
-	// These are turbine generated jars so they only change if the externals of the
-	// class changes but it does not contain and implementation or JavaDoc.
-	SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
-
 	// SdkApiStubDexJar returns the dex jar for the stubs for the prebuilt
 	// java_sdk_library_import module. It is needed by the hiddenapi processing tool which
 	// processes dex files.
@@ -1306,9 +1260,36 @@
 	// sharedLibrary returns true if this can be used as a shared library.
 	sharedLibrary() bool
 
+	// getImplLibraryModule returns the pointer to the implementation library submodule of this
+	// sdk library.
 	getImplLibraryModule() *Library
 }
 
+type SdkLibraryInfo struct {
+	// GeneratingLibs is the names of the library modules that this sdk library
+	// generates. Note that this only includes the name of the modules that other modules can
+	// depend on, and is not a holistic list of generated modules.
+	GeneratingLibs []string
+}
+
+var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]()
+
+func getGeneratingLibs(ctx android.ModuleContext, sdkVersion android.SdkSpec, sdkLibraryModuleName string, sdkInfo SdkLibraryInfo) []string {
+	apiLevel := sdkVersion.ApiLevel
+	if apiLevel.IsPreview() {
+		return sdkInfo.GeneratingLibs
+	}
+
+	generatingPrebuilts := []string{}
+	for _, apiScope := range AllApiScopes {
+		scopePrebuiltModuleName := prebuiltApiModuleName("sdk", sdkLibraryModuleName, apiScope.name, apiLevel.String())
+		if ctx.OtherModuleExists(scopePrebuiltModuleName) {
+			generatingPrebuilts = append(generatingPrebuilts, scopePrebuiltModuleName)
+		}
+	}
+	return generatingPrebuilts
+}
+
 type SdkLibrary struct {
 	Library
 
@@ -1595,6 +1576,11 @@
 			module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile
 		}
 
+		if installFilesInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, android.InstallFilesProvider); ok {
+			if installFilesInfo.CheckbuildTarget != nil {
+				ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget)
+			}
+		}
 		android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: module.implLibraryModule.uniqueSrcFiles.Strings()})
 	}
 
@@ -1626,9 +1612,22 @@
 	}
 	android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
 	module.setOutputFiles(ctx)
+
+	var generatingLibs []string
+	for _, apiScope := range AllApiScopes {
+		if _, ok := module.scopePaths[apiScope]; ok {
+			generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope))
+		}
+	}
+
 	if module.requiresRuntimeImplementationLibrary() && module.implLibraryModule != nil {
+		generatingLibs = append(generatingLibs, module.implLibraryModuleName())
 		setOutputFiles(ctx, module.implLibraryModule.Module)
 	}
+
+	android.SetProvider(ctx, SdkLibraryInfoProvider, SdkLibraryInfo{
+		GeneratingLibs: generatingLibs,
+	})
 }
 
 func (module *SdkLibrary) BuiltInstalledForApex() []dexpreopterInstall {
@@ -1739,20 +1738,24 @@
 func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
 	visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
 
+	staticLibs := module.properties.Static_libs.Clone()
+	staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
 	props := struct {
 		Name           *string
+		Enabled        proptools.Configurable[bool]
 		Visibility     []string
 		Libs           []string
-		Static_libs    []string
+		Static_libs    proptools.Configurable[[]string]
 		Apex_available []string
 		Stem           *string
 	}{
 		Name:       proptools.StringPtr(module.implLibraryModuleName()),
+		Enabled:    module.EnabledProperty(),
 		Visibility: visibility,
 
 		Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...),
 
-		Static_libs: append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...),
+		Static_libs: staticLibs,
 		// Pass the apex_available settings down so that the impl library can be statically
 		// embedded within a library that is added to an APEX. Needed for updatable-media.
 		Apex_available: module.ApexAvailable(),
@@ -1776,6 +1779,7 @@
 
 type libraryProperties struct {
 	Name           *string
+	Enabled        proptools.Configurable[bool]
 	Visibility     []string
 	Srcs           []string
 	Installable    *bool
@@ -1802,6 +1806,7 @@
 
 func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
 	props := libraryProperties{}
+	props.Enabled = module.EnabledProperty()
 	props.Visibility = []string{"//visibility:override", "//visibility:private"}
 	// sources are generated from the droiddoc
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
@@ -1852,13 +1857,14 @@
 func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
 	props := struct {
 		Name                             *string
+		Enabled                          proptools.Configurable[bool]
 		Visibility                       []string
 		Srcs                             []string
 		Installable                      *bool
 		Sdk_version                      *string
 		Api_surface                      *string
 		System_modules                   *string
-		Libs                             []string
+		Libs                             proptools.Configurable[[]string]
 		Output_javadoc_comments          *bool
 		Arg_files                        []string
 		Args                             *string
@@ -1893,6 +1899,7 @@
 	// * libs (static_libs/libs)
 
 	props.Name = proptools.StringPtr(name)
+	props.Enabled = module.EnabledProperty()
 	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
 	props.Srcs = append(props.Srcs, module.properties.Srcs...)
 	props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
@@ -1902,10 +1909,11 @@
 	props.Installable = proptools.BoolPtr(false)
 	// A droiddoc module has only one Libs property and doesn't distinguish between
 	// shared libs and static libs. So we need to add both of these libs to Libs property.
-	props.Libs = module.properties.Libs
-	props.Libs = append(props.Libs, module.properties.Static_libs...)
-	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
-	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
+	props.Libs = proptools.NewConfigurable[[]string](nil, nil)
+	props.Libs.AppendSimpleValue(module.properties.Libs)
+	props.Libs.Append(module.properties.Static_libs)
+	props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
+	props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
 	props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
 	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
 	props.Java_version = module.properties.Java_version
@@ -2017,9 +2025,10 @@
 func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
 	props := struct {
 		Name              *string
+		Enabled           proptools.Configurable[bool]
 		Visibility        []string
 		Api_contributions []string
-		Libs              []string
+		Libs              proptools.Configurable[[]string]
 		Static_libs       []string
 		System_modules    *string
 		Enable_validation *bool
@@ -2029,6 +2038,7 @@
 	}{}
 
 	props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
+	props.Enabled = module.EnabledProperty()
 	props.Visibility = []string{"//visibility:override", "//visibility:private"}
 
 	apiContributions := []string{}
@@ -2051,11 +2061,12 @@
 	props.Api_contributions = apiContributions
 
 	// Ensure that stub-annotations is added to the classpath before any other libs
-	props.Libs = []string{"stub-annotations"}
-	props.Libs = append(props.Libs, module.properties.Libs...)
-	props.Libs = append(props.Libs, module.properties.Static_libs...)
-	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
-	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
+	props.Libs = proptools.NewConfigurable[[]string](nil, nil)
+	props.Libs.AppendSimpleValue([]string{"stub-annotations"})
+	props.Libs.AppendSimpleValue(module.properties.Libs)
+	props.Libs.Append(module.properties.Static_libs)
+	props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
+	props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
 
 	props.System_modules = module.deviceProperties.System_modules
@@ -2078,6 +2089,7 @@
 func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties {
 	props := libraryProperties{}
 
+	props.Enabled = module.EnabledProperty()
 	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
 	props.Sdk_version = proptools.StringPtr(sdkVersion)
@@ -2099,6 +2111,7 @@
 		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
 		props.Dist.Tag = proptools.StringPtr(".jar")
 	}
+	props.Is_stubs_module = proptools.BoolPtr(true)
 
 	return props
 }
@@ -2169,6 +2182,7 @@
 	}
 	props := struct {
 		Name                      *string
+		Enabled                   proptools.Configurable[bool]
 		Lib_name                  *string
 		Apex_available            []string
 		On_bootclasspath_since    *string
@@ -2179,6 +2193,7 @@
 		Uses_libs_dependencies    []string
 	}{
 		Name:                      proptools.StringPtr(module.xmlPermissionsModuleName()),
+		Enabled:                   module.EnabledProperty(),
 		Lib_name:                  proptools.StringPtr(module.BaseModuleName()),
 		Apex_available:            module.ApexProperties.Apex_available,
 		On_bootclasspath_since:    module.commonSdkLibraryProperties.On_bootclasspath_since,
@@ -2192,72 +2207,6 @@
 	mctx.CreateModule(sdkLibraryXmlFactory, &props)
 }
 
-func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths {
-	var ver android.ApiLevel
-	var kind android.SdkKind
-	if s.UsePrebuilt(ctx) {
-		ver = s.ApiLevel
-		kind = s.Kind
-	} else {
-		// We don't have prebuilt SDK for the specific sdkVersion.
-		// Instead of breaking the build, fallback to use "system_current"
-		ver = android.FutureApiLevel
-		kind = android.SdkSystem
-	}
-
-	dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String())
-	jar := filepath.Join(dir, baseName+".jar")
-	jarPath := android.ExistentPathForSource(ctx, jar)
-	if !jarPath.Valid() {
-		if ctx.Config().AllowMissingDependencies() {
-			return android.Paths{android.PathForSource(ctx, jar)}
-		} else {
-			ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.Raw, jar)
-		}
-		return nil
-	}
-	return android.Paths{jarPath.Path()}
-}
-
-// Check to see if the other module is within the same set of named APEXes as this module.
-//
-// If either this or the other module are on the platform then this will return
-// false.
-func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
-	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
-	otherApexInfo, _ := android.OtherModuleProvider(ctx, other, android.ApexInfoProvider)
-	return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
-}
-
-func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-	// If the client doesn't set sdk_version, but if this library prefers stubs over
-	// the impl library, let's provide the widest API surface possible. To do so,
-	// force override sdk_version to module_current so that the closest possible API
-	// surface could be found in selectHeaderJarsForSdkVersion
-	if module.defaultsToStubs() && !sdkVersion.Specified() {
-		sdkVersion = android.SdkSpecFrom(ctx, "module_current")
-	}
-
-	// Only provide access to the implementation library if it is actually built.
-	if module.requiresRuntimeImplementationLibrary() {
-		// Check any special cases for java_sdk_library.
-		//
-		// Only allow access to the implementation library in the following condition:
-		// * No sdk_version specified on the referencing module.
-		// * The referencing module is in the same apex as this.
-		if sdkVersion.Kind == android.SdkPrivate || withinSameApexesAs(ctx, module) {
-			return module.implLibraryHeaderJars
-		}
-	}
-
-	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
-}
-
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-	return module.sdkJars(ctx, sdkVersion)
-}
-
 var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
 
 func javaSdkLibraries(config android.Config) *[]string {
@@ -2274,11 +2223,6 @@
 // runtime libs and xml file. If requested, the stubs and docs are created twice
 // once for public API level and once for system API level
 func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) {
-	// If the module has been disabled then don't create any child modules.
-	if !module.Enabled(mctx) {
-		return
-	}
-
 	if len(module.properties.Srcs) == 0 {
 		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
 		return
@@ -2364,7 +2308,7 @@
 
 	// Add the impl_only_libs and impl_only_static_libs *after* we're done using them in submodules.
 	module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...)
-	module.properties.Static_libs = append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...)
+	module.properties.Static_libs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
 }
 
 func (module *SdkLibrary) InitSdkLibraryProperties() {
@@ -2381,54 +2325,6 @@
 	return !proptools.Bool(module.sdkLibraryProperties.Api_only)
 }
 
-func (module *SdkLibrary) defaultsToStubs() bool {
-	return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
-}
-
-// Defines how to name the individual component modules the sdk library creates.
-type sdkLibraryComponentNamingScheme interface {
-	stubsLibraryModuleName(scope *apiScope, baseName string) string
-
-	stubsSourceModuleName(scope *apiScope, baseName string) string
-
-	apiLibraryModuleName(scope *apiScope, baseName string) string
-
-	sourceStubsLibraryModuleName(scope *apiScope, baseName string) string
-
-	exportableStubsLibraryModuleName(scope *apiScope, baseName string) string
-
-	exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string
-}
-
-type defaultNamingScheme struct {
-}
-
-func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
-	return scope.stubsLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
-	return scope.stubsSourceModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName string) string {
-	return scope.apiLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) sourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
-	return scope.sourceStubLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) exportableStubsLibraryModuleName(scope *apiScope, baseName string) string {
-	return scope.exportableStubsLibraryModuleName(baseName)
-}
-
-func (s *defaultNamingScheme) exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
-	return scope.exportableSourceStubsLibraryModuleName(baseName)
-}
-
-var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
-
 func moduleStubLinkType(j *Module) (stub bool, ret sdkLinkType) {
 	kind := android.ToSdkKind(proptools.String(j.properties.Stub_contributing_api))
 	switch kind {
@@ -2872,69 +2768,36 @@
 	}
 
 	if ctx.Device() {
-		// If this is a variant created for a prebuilt_apex then use the dex implementation jar
-		// obtained from the associated deapexer module.
+		// Shared libraries deapexed from prebuilt apexes are no longer supported.
+		// Set the dexJarBuildPath to a fake path.
+		// This allows soong analysis pass, but will be an error during ninja execution if there are
+		// any rdeps.
 		ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 		if ai.ForPrebuiltApex {
-			// Get the path of the dex implementation jar from the `deapexer` module.
-			di, err := android.FindDeapexerProviderForModule(ctx)
-			if err != nil {
-				// An error was found, possibly due to multiple apexes in the tree that export this library
-				// Defer the error till a client tries to call DexJarBuildPath
-				module.dexJarFileErr = err
-				module.initHiddenAPIError(err)
-				return
-			}
-			dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(module.BaseModuleName())
-			if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
-				dexJarFile := makeDexJarPathFromPath(dexOutputPath)
-				module.dexJarFile = dexJarFile
-				installPath := android.PathForModuleInPartitionInstall(
-					ctx, "apex", ai.ApexVariationName, dexJarFileApexRootRelative)
-				module.installFile = installPath
-				module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+			module.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported"))
+			module.initHiddenAPI(ctx, module.dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+		}
+	}
 
-				module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath)
-				module.dexpreopter.isSDKLibrary = true
-				module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &module.dexpreopter)
-
-				if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
-					module.dexpreopter.inputProfilePathOnHost = profilePath
-				}
-			} else {
-				// This should never happen as a variant for a prebuilt_apex is only created if the
-				// prebuilt_apex has been configured to export the java library dex file.
-				ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
+	var generatingLibs []string
+	for _, apiScope := range AllApiScopes {
+		if scopeProperties, ok := module.scopeProperties[apiScope]; ok {
+			if len(scopeProperties.Jars) == 0 {
+				continue
 			}
+			generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope))
 		}
 	}
 
 	module.setOutputFiles(ctx)
 	if module.implLibraryModule != nil {
+		generatingLibs = append(generatingLibs, module.implLibraryModuleName())
 		setOutputFiles(ctx, module.implLibraryModule.Module)
 	}
-}
 
-func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
-
-	// For consistency with SdkLibrary make the implementation jar available to libraries that
-	// are within the same APEX.
-	implLibraryModule := module.implLibraryModule
-	if implLibraryModule != nil && withinSameApexesAs(ctx, module) {
-		if headerJars {
-			return implLibraryModule.HeaderJars()
-		} else {
-			return implLibraryModule.ImplementationJars()
-		}
-	}
-
-	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
-}
-
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-	// This module is just a wrapper for the prebuilt stubs.
-	return module.sdkJars(ctx, sdkVersion, true)
+	android.SetProvider(ctx, SdkLibraryInfoProvider, SdkLibraryInfo{
+		GeneratingLibs: generatingLibs,
+	})
 }
 
 // to satisfy UsesLibraryDependency interface
@@ -3500,7 +3363,6 @@
 		}
 	}
 
-	s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
 	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
 	s.Compile_dex = sdk.dexProperties.Compile_dex
 	s.Doctag_paths = sdk.doctagPaths
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 485776b..6031d72 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -22,8 +22,6 @@
 	"testing"
 
 	"android/soong/android"
-
-	"github.com/google/blueprint/proptools"
 )
 
 func TestJavaSdkLibrary(t *testing.T) {
@@ -55,7 +53,7 @@
 		java_library {
 			name: "baz",
 			srcs: ["c.java"],
-			libs: ["foo", "bar.stubs"],
+			libs: ["foo.stubs.system", "bar.stubs"],
 			sdk_version: "system_current",
 		}
 		java_sdk_library {
@@ -92,25 +90,25 @@
 		java_library {
 		    name: "qux",
 		    srcs: ["c.java"],
-		    libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
+		    libs: ["baz", "fred.stubs", "quuz.stubs", "wilma.stubs", "barney.stubs.system", "betty.stubs.system"],
 		    sdk_version: "system_current",
 		}
 		java_library {
 			name: "baz-test",
 			srcs: ["c.java"],
-			libs: ["foo"],
+			libs: ["foo.stubs.test"],
 			sdk_version: "test_current",
 		}
 		java_library {
 			name: "baz-29",
 			srcs: ["c.java"],
-			libs: ["foo"],
+			libs: ["sdk_system_29_foo"],
 			sdk_version: "system_29",
 		}
 		java_library {
 			name: "baz-module-30",
 			srcs: ["c.java"],
-			libs: ["foo"],
+			libs: ["sdk_module-lib_30_foo"],
 			sdk_version: "module_30",
 		}
 	`)
@@ -162,11 +160,11 @@
 
 	baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac")
 	// tests if baz-29 is actually linked to the system 29 stubs lib
-	android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar")
+	android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/sdk_system_29_foo/android_common/combined/sdk_system_29_foo.jar")
 
 	bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac")
 	// tests if "baz-module-30" is actually linked to the module 30 stubs lib
-	android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar")
+	android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/sdk_module-lib_30_foo/android_common/combined/sdk_module-lib_30_foo.jar")
 
 	// test if baz has exported SDK lib names foo and bar to qux
 	qux := result.ModuleForTests("qux", "android_common")
@@ -422,7 +420,7 @@
 	for _, expectation := range expectations {
 		verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
 
-		stubName := apiScopePublic.sourceStubLibraryModuleName("sdklib")
+		stubName := apiScopePublic.sourceStubsLibraryModuleName("sdklib")
 		verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
 	}
 }
@@ -445,7 +443,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["b.java"],
-			libs: ["foo"],
+			libs: ["foo.stubs"],
 		}
 		`)
 
@@ -763,7 +761,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["a.java"],
-			libs: ["foo-public", "foo-system", "foo-module-lib", "foo-system-server"],
+			libs: ["foo-public.stubs", "foo-system.stubs.system", "foo-module-lib.stubs.module_lib", "foo-system-server.stubs.system_server"],
 			sdk_version: "system_server_current",
 		}
 		`)
@@ -789,102 +787,26 @@
 	}
 }
 
-func TestJavaSdkLibrary_MissingScope(t *testing.T) {
-	prepareForJavaTest.
-		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)).
-		RunTestWithBp(t, `
-			java_sdk_library {
-				name: "foo",
-				srcs: ["a.java"],
-				public: {
-					enabled: false,
-				},
-			}
-
-			java_library {
-				name: "baz",
-				srcs: ["a.java"],
-				libs: ["foo"],
-				sdk_version: "module_current",
-			}
-		`)
-}
-
-func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
-	android.GroupFixturePreparers(
-		prepareForJavaTest,
-		PrepareForTestWithJavaSdkLibraryFiles,
-		FixtureWithLastReleaseApis("foo"),
-	).RunTestWithBp(t, `
-		java_sdk_library {
-			name: "foo",
-			srcs: ["a.java"],
-			system: {
-				enabled: true,
-			},
-		}
-
-		java_library {
-			name: "baz",
-			srcs: ["a.java"],
-			libs: ["foo"],
-			// foo does not have module-lib scope so it should fallback to system
-			sdk_version: "module_current",
-		}
-		`)
-}
-
-func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
-	result := android.GroupFixturePreparers(
-		prepareForJavaTest,
-		PrepareForTestWithJavaSdkLibraryFiles,
-		FixtureWithLastReleaseApis("foo"),
-	).RunTestWithBp(t, `
-		java_sdk_library {
-			name: "foo",
-			srcs: ["a.java"],
-			system: {
-				enabled: true,
-			},
-			default_to_stubs: true,
-		}
-
-		java_library {
-			name: "baz",
-			srcs: ["a.java"],
-			libs: ["foo"],
-			// does not have sdk_version set, should fallback to module,
-			// which will then fallback to system because the module scope
-			// is not enabled.
-		}
-		`)
-	// The baz library should depend on the system stubs jar.
-	bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac")
-	if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
-		t.Errorf("expected %q, found %#q", expected, actual)
-	}
-}
-
 func TestJavaSdkLibraryImport(t *testing.T) {
 	result := prepareForJavaTest.RunTestWithBp(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
-			libs: ["sdklib"],
+			libs: ["sdklib.stubs"],
 			sdk_version: "current",
 		}
 
 		java_library {
 			name: "foo.system",
 			srcs: ["a.java"],
-			libs: ["sdklib"],
+			libs: ["sdklib.stubs.system"],
 			sdk_version: "system_current",
 		}
 
 		java_library {
 			name: "foo.test",
 			srcs: ["a.java"],
-			libs: ["sdklib"],
+			libs: ["sdklib.stubs.test"],
 			sdk_version: "test_current",
 		}
 
@@ -907,7 +829,7 @@
 		fooModule := result.ModuleForTests("foo"+scope, "android_common")
 		javac := fooModule.Rule("javac")
 
-		sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+		sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output
 		android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
 	}
 
@@ -1017,7 +939,7 @@
 		java_library {
 			name: "public",
 			srcs: ["a.java"],
-			libs: ["sdklib"],
+			libs: ["sdklib.stubs"],
 			sdk_version: "current",
 		}
 		`)
@@ -1190,155 +1112,6 @@
 	}
 }
 
-func TestJavaSdkLibraryEnforce(t *testing.T) {
-	partitionToBpOption := func(partition string) string {
-		switch partition {
-		case "system":
-			return ""
-		case "vendor":
-			return "soc_specific: true,"
-		case "product":
-			return "product_specific: true,"
-		default:
-			panic("Invalid partition group name: " + partition)
-		}
-	}
-
-	type testConfigInfo struct {
-		libraryType                string
-		fromPartition              string
-		toPartition                string
-		enforceProductInterface    bool
-		enforceJavaSdkLibraryCheck bool
-		allowList                  []string
-	}
-
-	createPreparer := func(info testConfigInfo) android.FixturePreparer {
-		bpFileTemplate := `
-			java_library {
-				name: "foo",
-				srcs: ["foo.java"],
-				libs: ["bar"],
-				sdk_version: "current",
-				%s
-			}
-
-			%s {
-				name: "bar",
-				srcs: ["bar.java"],
-				sdk_version: "current",
-				%s
-			}
-		`
-
-		bpFile := fmt.Sprintf(bpFileTemplate,
-			partitionToBpOption(info.fromPartition),
-			info.libraryType,
-			partitionToBpOption(info.toPartition))
-
-		return android.GroupFixturePreparers(
-			PrepareForTestWithJavaSdkLibraryFiles,
-			FixtureWithLastReleaseApis("bar"),
-			android.FixtureWithRootAndroidBp(bpFile),
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
-				variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
-				variables.InterPartitionJavaLibraryAllowList = info.allowList
-			}),
-		)
-	}
-
-	runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) {
-		t.Run(fmt.Sprintf("%v", info), func(t *testing.T) {
-			errorHandler := android.FixtureExpectsNoErrors
-			if expectedErrorPattern != "" {
-				errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern)
-			}
-			android.GroupFixturePreparers(
-				prepareForJavaTest,
-				createPreparer(info),
-			).
-				ExtendWithErrorHandler(errorHandler).
-				RunTest(t)
-		})
-	}
-
-	errorMessage := "is not allowed across the partitions"
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_library",
-		fromPartition:              "product",
-		toPartition:                "system",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: false,
-	}, "")
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_library",
-		fromPartition:              "product",
-		toPartition:                "system",
-		enforceProductInterface:    false,
-		enforceJavaSdkLibraryCheck: true,
-	}, "")
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_library",
-		fromPartition:              "product",
-		toPartition:                "system",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-	}, errorMessage)
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_library",
-		fromPartition:              "vendor",
-		toPartition:                "system",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-	}, errorMessage)
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_library",
-		fromPartition:              "vendor",
-		toPartition:                "system",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-		allowList:                  []string{"bar"},
-	}, "")
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_library",
-		fromPartition:              "vendor",
-		toPartition:                "product",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-	}, errorMessage)
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_sdk_library",
-		fromPartition:              "product",
-		toPartition:                "system",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-	}, "")
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_sdk_library",
-		fromPartition:              "vendor",
-		toPartition:                "system",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-	}, "")
-
-	runTest(t, testConfigInfo{
-		libraryType:                "java_sdk_library",
-		fromPartition:              "vendor",
-		toPartition:                "product",
-		enforceProductInterface:    true,
-		enforceJavaSdkLibraryCheck: true,
-	}, "")
-}
-
 func TestJavaSdkLibraryDist(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		PrepareForTestWithJavaBuildComponents,
@@ -1528,7 +1301,8 @@
 
 	// The foo.stubs.source should depend on bar-lib
 	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
-	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+	eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
 }
 
 func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) {
@@ -1554,7 +1328,8 @@
 
 	// The foo.stubs.source should depend on bar-lib
 	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
-	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+	eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
 }
 
 func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
@@ -1655,7 +1430,7 @@
 			name: "bar",
 			srcs: ["c.java", "b.java"],
 			libs: [
-				"foo",
+				"foo.stubs",
 			],
 			uses_libs: [
 				"foo",
@@ -1705,18 +1480,15 @@
 	exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo")
 
 	// Check modules generation
-	topLevelModule := result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
+	result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
 	result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common")
 
 	// Check static lib dependency
 	android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+
 		"exportable source stubs library module", true,
-		CheckModuleHasDependency(t, result.TestContext, exportableStubsLibraryModuleName,
-			"android_common", exportableSourceStubsLibraryModuleName),
+		CheckModuleHasDependencyWithTag(t, result.TestContext, exportableStubsLibraryModuleName,
+			"android_common", staticLibTag, exportableSourceStubsLibraryModuleName),
 	)
-	android.AssertArrayString(t, "exportable source stub library is a static lib of the"+
-		"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
@@ -1753,7 +1525,7 @@
 			name: "mymodule",
 			srcs: ["a.java"],
 			sdk_version: "current",
-			libs: ["sdklib",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
+			libs: ["sdklib.stubs",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
 		}
 	`
 
@@ -1894,3 +1666,111 @@
 		}
 		`)
 }
+
+func TestSdkLibDirectDependency(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo", "bar"),
+	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{
+		`module "baz" variant "android_common": cannot depend directly on java_sdk_library ` +
+			`"foo"; try depending on "foo.stubs", or "foo.impl" instead`,
+		`module "baz" variant "android_common": cannot depend directly on java_sdk_library ` +
+			`"prebuilt_bar"; try depending on "bar.stubs", or "bar.impl" instead`,
+	}),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			public: {
+				enabled: true,
+			},
+		}
+
+		java_sdk_library_import {
+			name: "foo",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+
+		java_sdk_library {
+			name: "bar",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			public: {
+				enabled: true,
+			},
+		}
+
+		java_sdk_library_import {
+			name: "bar",
+			prefer: true,
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["b.java"],
+			libs: [
+				"foo",
+				"bar",
+			],
+		}
+	`)
+}
+
+func TestSdkLibDirectDependencyWithPrebuiltSdk(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_sdk_version = intPtr(34)
+			variables.Platform_sdk_codename = stringPtr("VanillaIceCream")
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+			variables.Platform_systemsdk_versions = []string{"33", "34", "VanillaIceCream"}
+			variables.DeviceSystemSdkVersions = []string{"VanillaIceCream"}
+		}),
+		FixtureWithPrebuiltApis(map[string][]string{
+			"33": {"foo"},
+			"34": {"foo"},
+			"35": {"foo"},
+		}),
+	).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+		`module "baz" variant "android_common": cannot depend directly on java_sdk_library "foo"; `+
+			`try depending on "sdk_public_33_foo", "sdk_system_33_foo", "sdk_test_33_foo", `+
+			`"sdk_module-lib_33_foo", or "sdk_system-server_33_foo" instead`),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			},
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["b.java"],
+			libs: [
+				"foo",
+			],
+			sdk_version: "system_33",
+		}
+	`)
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 2dac27a..9bfe6a2 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -391,15 +391,19 @@
 	t.Parallel()
 	t.Run("basic", func(t *testing.T) {
 		t.Parallel()
-		testClasspathTestCases(t, classpathTestcases, false)
+		testClasspathTestCases(t, classpathTestcases, false, false)
 	})
 
 	t.Run("Always_use_prebuilt_sdks=true", func(t *testing.T) {
-		testClasspathTestCases(t, classpathTestcases, true)
+		testClasspathTestCases(t, classpathTestcases, true, false)
+	})
+
+	t.Run("UseTransitiveJarsInClasspath", func(t *testing.T) {
+		testClasspathTestCases(t, classpathTestcases, false, true)
 	})
 }
 
-func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks bool) {
+func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks, useTransitiveJarsInClasspath bool) {
 	for _, testcase := range classpathTestcases {
 		if testcase.forAlwaysUsePrebuiltSdks != nil && *testcase.forAlwaysUsePrebuiltSdks != alwaysUsePrebuiltSdks {
 			continue
@@ -437,7 +441,14 @@
 			convertModulesToPaths := func(cp []string) []string {
 				ret := make([]string, len(cp))
 				for i, e := range cp {
-					ret[i] = defaultModuleToPath(e)
+					switch {
+					case e == `""`, strings.HasSuffix(e, ".jar"):
+						ret[i] = e
+					case useTransitiveJarsInClasspath:
+						ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine", e+".jar")
+					default:
+						ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine-combined", e+".jar")
+					}
 				}
 				return ret
 			}
@@ -531,6 +542,9 @@
 					variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
 				})
 			}
+			if useTransitiveJarsInClasspath {
+				preparer = PrepareForTestWithTransitiveClasspathEnabled
+			}
 
 			fixtureFactory := android.GroupFixturePreparers(
 				prepareForJavaTest,
diff --git a/java/system_modules.go b/java/system_modules.go
index f89bf9e..d9430b2 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -127,6 +127,9 @@
 
 	OutputDir     android.Path
 	OutputDirDeps android.Paths
+
+	// depset of header jars for this module and all transitive static dependencies
+	TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
 }
 
 var SystemModulesProvider = blueprint.NewProvider[*SystemModulesProviderInfo]()
@@ -149,18 +152,23 @@
 func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	var jars android.Paths
 
+	var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path]
 	ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
 		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			jars = append(jars, dep.HeaderJars...)
+			if dep.TransitiveStaticLibsHeaderJars != nil {
+				transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+			}
 		}
 	})
 
 	system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars)
 
 	android.SetProvider(ctx, SystemModulesProvider, &SystemModulesProviderInfo{
-		HeaderJars:    jars,
-		OutputDir:     system.outputDir,
-		OutputDirDeps: system.outputDeps,
+		HeaderJars:                     jars,
+		OutputDir:                      system.outputDir,
+		OutputDirDeps:                  system.outputDeps,
+		TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsHeaderJars),
 	})
 }
 
diff --git a/java/testing.go b/java/testing.go
index 0e85022..0c79e9f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -184,6 +184,10 @@
 			host_supported: true,
 			srcs: ["Test.java"],
 			sdk_version: "current",
+			apex_available: [
+				"//apex_available:anyapex",
+				"//apex_available:platform",
+			],
 		}
 	`)),
 )
@@ -408,7 +412,6 @@
 		"core.current.stubs",
 		"legacy.core.platform.api.stubs",
 		"stable.core.platform.api.stubs",
-
 		"android_stubs_current_exportable",
 		"android_system_stubs_current_exportable",
 		"android_test_stubs_current_exportable",
@@ -416,13 +419,11 @@
 		"android_system_server_stubs_current_exportable",
 		"core.current.stubs.exportable",
 		"legacy.core.platform.api.stubs.exportable",
-
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 		"stub-annotations",
-
 		"aconfig-annotations-lib",
 		"unsupportedappusage",
 	}
@@ -435,6 +436,7 @@
 				sdk_version: "none",
 				system_modules: "stable-core-platform-api-stubs-system-modules",
 				compile_dex: true,
+				is_stubs_module: true,
 			}
 		`, extra)
 	}
@@ -579,6 +581,7 @@
 				name: "%[1]s-lib",
 				sdk_version: "none",
 				system_modules: "none",
+				srcs: ["a.java"],
 			}
 		`, extra)
 	}
@@ -630,6 +633,18 @@
 	return false
 }
 
+// CheckModuleHasDependency returns true if the module depends on the expected dependency.
+func CheckModuleHasDependencyWithTag(t *testing.T, ctx *android.TestContext, name, variant string, desiredTag blueprint.DependencyTag, expected string) bool {
+	module := ctx.ModuleForTests(name, variant).Module()
+	found := false
+	ctx.VisitDirectDepsWithTags(module, func(m blueprint.Module, tag blueprint.DependencyTag) {
+		if tag == desiredTag && m.Name() == expected {
+			found = true
+		}
+	})
+	return found
+}
+
 // CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
 // the platform-bootclasspath module.
 func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
@@ -778,3 +793,5 @@
 		config.installDir = installDir
 	})
 }
+
+var PrepareForTestWithTransitiveClasspathEnabled = android.PrepareForTestWithBuildFlag("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH", "true")
diff --git a/linkerconfig/proto/Android.bp b/linkerconfig/proto/Android.bp
index 754e7bf..a930502 100644
--- a/linkerconfig/proto/Android.bp
+++ b/linkerconfig/proto/Android.bp
@@ -15,6 +15,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    visibility: ["//system/linkerconfig"],
 }
 
 python_library_host {
diff --git a/multitree/Android.bp b/multitree/Android.bp
deleted file mode 100644
index 78c4962..0000000
--- a/multitree/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
-    name: "soong-multitree",
-    pkgPath: "android/soong/multitree",
-    deps: [
-        "blueprint",
-        "soong-android",
-    ],
-    srcs: [
-        "api_imports.go",
-        "api_surface.go",
-        "export.go",
-        "metadata.go",
-        "import.go",
-    ],
-    pluginFor: ["soong_build"],
-}
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
deleted file mode 100644
index 51b9e07..0000000
--- a/multitree/api_imports.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// 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.
-
-package multitree
-
-import (
-	"android/soong/android"
-	"strings"
-
-	"github.com/google/blueprint"
-)
-
-var (
-	apiImportNameSuffix = ".apiimport"
-)
-
-func init() {
-	RegisterApiImportsModule(android.InitRegistrationContext)
-	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
-}
-
-func RegisterApiImportsModule(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("api_imports", apiImportsFactory)
-}
-
-type ApiImports struct {
-	android.ModuleBase
-	properties apiImportsProperties
-}
-
-type apiImportsProperties struct {
-	Shared_libs      []string // List of C shared libraries from API surfaces
-	Header_libs      []string // List of C header libraries from API surfaces
-	Apex_shared_libs []string // List of C shared libraries with APEX stubs
-}
-
-// 'api_imports' is a module which describes modules available from API surfaces.
-// This module is required to get the list of all imported API modules, because
-// it is discouraged to loop and fetch all modules from its type information. The
-// only module with name 'api_imports' will be used from the build.
-func apiImportsFactory() android.Module {
-	module := &ApiImports{}
-	module.AddProperties(&module.properties)
-	android.InitAndroidModule(module)
-	return module
-}
-
-func (imports *ApiImports) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// ApiImport module does not generate any build actions
-}
-
-type ApiImportInfo struct {
-	SharedLibs, HeaderLibs, ApexSharedLibs map[string]string
-}
-
-var ApiImportsProvider = blueprint.NewMutatorProvider[ApiImportInfo]("deps")
-
-// Store module lists into ApiImportInfo and share it over mutator provider.
-func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) {
-	generateNameMapWithSuffix := func(names []string) map[string]string {
-		moduleNameMap := make(map[string]string)
-		for _, name := range names {
-			moduleNameMap[name] = name + apiImportNameSuffix
-		}
-
-		return moduleNameMap
-	}
-
-	sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs)
-	headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
-	apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs)
-
-	android.SetProvider(ctx, ApiImportsProvider, ApiImportInfo{
-		SharedLibs:     sharedLibs,
-		HeaderLibs:     headerLibs,
-		ApexSharedLibs: apexSharedLibs,
-	})
-}
-
-func GetApiImportSuffix() string {
-	return apiImportNameSuffix
-}
-
-func makeVarsProvider(ctx android.MakeVarsContext) {
-	ctx.VisitAllModules(func(m android.Module) {
-		if i, ok := m.(*ApiImports); ok {
-			ctx.Strict("API_IMPORTED_SHARED_LIBRARIES", strings.Join(i.properties.Shared_libs, " "))
-			ctx.Strict("API_IMPORTED_HEADER_LIBRARIES", strings.Join(i.properties.Header_libs, " "))
-		}
-	})
-}
diff --git a/multitree/api_surface.go b/multitree/api_surface.go
deleted file mode 100644
index 0f605d8..0000000
--- a/multitree/api_surface.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// 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.
-
-package multitree
-
-import (
-	"android/soong/android"
-	"github.com/google/blueprint"
-)
-
-var (
-	pctx = android.NewPackageContext("android/soong/multitree")
-)
-
-func init() {
-	RegisterApiSurfaceBuildComponents(android.InitRegistrationContext)
-}
-
-var PrepareForTestWithApiSurface = android.FixtureRegisterWithContext(RegisterApiSurfaceBuildComponents)
-
-func RegisterApiSurfaceBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("api_surface", ApiSurfaceFactory)
-}
-
-type ApiSurface struct {
-	android.ModuleBase
-	ExportableModuleBase
-	properties apiSurfaceProperties
-
-	taggedOutputs map[string]android.Paths
-}
-
-type apiSurfaceProperties struct {
-	Contributions []string
-}
-
-func ApiSurfaceFactory() android.Module {
-	module := &ApiSurface{}
-	module.AddProperties(&module.properties)
-	android.InitAndroidModule(module)
-	InitExportableModule(module)
-	return module
-}
-
-func (surface *ApiSurface) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if surface.properties.Contributions != nil {
-		ctx.AddVariationDependencies(nil, nil, surface.properties.Contributions...)
-	}
-
-}
-func (surface *ApiSurface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	contributionFiles := make(map[string]android.Paths)
-	var allOutputs android.Paths
-	ctx.WalkDeps(func(child, parent android.Module) bool {
-		if contribution, ok := child.(ApiContribution); ok {
-			copied := contribution.CopyFilesWithTag(ctx)
-			for tag, files := range copied {
-				contributionFiles[child.Name()+"#"+tag] = files
-			}
-			for _, paths := range copied {
-				allOutputs = append(allOutputs, paths...)
-			}
-			return false // no transitive dependencies
-		}
-		return false
-	})
-
-	// phony target
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   blueprint.Phony,
-		Output: android.PathForPhony(ctx, ctx.ModuleName()),
-		Inputs: allOutputs,
-	})
-
-	surface.taggedOutputs = contributionFiles
-
-	ctx.SetOutputFiles(allOutputs, "")
-}
-
-func (surface *ApiSurface) TaggedOutputs() map[string]android.Paths {
-	return surface.taggedOutputs
-}
-
-func (surface *ApiSurface) Exportable() bool {
-	return true
-}
-
-var _ Exportable = (*ApiSurface)(nil)
-
-type ApiContribution interface {
-	// copy files necessaryt to construct an API surface
-	// For C, it will be map.txt and .h files
-	// For Java, it will be api.txt
-	CopyFilesWithTag(ctx android.ModuleContext) map[string]android.Paths // output paths
-
-	// Generate Android.bp in out/ to use the exported .txt files
-	// GenerateBuildFiles(ctx ModuleContext) Paths //output paths
-}
diff --git a/multitree/export.go b/multitree/export.go
deleted file mode 100644
index 8be8f70..0000000
--- a/multitree/export.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// 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.
-
-package multitree
-
-import (
-	"android/soong/android"
-
-	"github.com/google/blueprint/proptools"
-)
-
-type moduleExportProperty struct {
-	// True if the module is exported to the other components in a multi-tree.
-	// Any components in the multi-tree can import this module to use.
-	Export *bool
-}
-
-type ExportableModuleBase struct {
-	properties moduleExportProperty
-}
-
-type Exportable interface {
-	// Properties for the exporable module.
-	exportableModuleProps() *moduleExportProperty
-
-	// Check if this module can be exported.
-	// If this returns false, the module will not be exported regardless of the 'export' value.
-	Exportable() bool
-
-	// Returns 'true' if this module has 'export: true'
-	// This module will not be exported if it returns 'false' to 'Exportable()' interface even if
-	// it has 'export: true'.
-	IsExported() bool
-
-	// Map from tags to outputs.
-	// Each module can tag their outputs for convenience.
-	TaggedOutputs() map[string]android.Paths
-}
-
-type ExportableModule interface {
-	android.Module
-	Exportable
-}
-
-func InitExportableModule(module ExportableModule) {
-	module.AddProperties(module.exportableModuleProps())
-}
-
-func (m *ExportableModuleBase) exportableModuleProps() *moduleExportProperty {
-	return &m.properties
-}
-
-func (m *ExportableModuleBase) IsExported() bool {
-	return proptools.Bool(m.properties.Export)
-}
diff --git a/multitree/import.go b/multitree/import.go
deleted file mode 100644
index 1e5c421..0000000
--- a/multitree/import.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// 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.
-
-package multitree
-
-import (
-	"android/soong/android"
-)
-
-var (
-	nameSuffix = ".imported"
-)
-
-type MultitreeImportedModuleInterface interface {
-	GetMultitreeImportedModuleName() string
-}
-
-func init() {
-	android.RegisterModuleType("imported_filegroup", importedFileGroupFactory)
-
-	android.PreArchMutators(RegisterMultitreePreArchMutators)
-}
-
-type importedFileGroupProperties struct {
-	// Imported modules from the other components in a multi-tree
-	Imported []string
-}
-
-type importedFileGroup struct {
-	android.ModuleBase
-
-	properties importedFileGroupProperties
-	srcs       android.Paths
-}
-
-func (ifg *importedFileGroup) Name() string {
-	return ifg.BaseModuleName() + nameSuffix
-}
-
-func importedFileGroupFactory() android.Module {
-	module := &importedFileGroup{}
-	module.AddProperties(&module.properties)
-
-	android.InitAndroidModule(module)
-	return module
-}
-
-var _ MultitreeImportedModuleInterface = (*importedFileGroup)(nil)
-
-func (ifg *importedFileGroup) GetMultitreeImportedModuleName() string {
-	// The base module name of the imported filegroup is used as the imported module name
-	return ifg.BaseModuleName()
-}
-
-var _ android.SourceFileProducer = (*importedFileGroup)(nil)
-
-func (ifg *importedFileGroup) Srcs() android.Paths {
-	return ifg.srcs
-}
-
-func (ifg *importedFileGroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// srcs from this module must not be used. Adding a dot path to avoid the empty
-	// source failure. Still soong returns error when a module wants to build against
-	// this source, which is intended.
-	ifg.srcs = android.PathsForModuleSrc(ctx, []string{"."})
-}
-
-func RegisterMultitreePreArchMutators(ctx android.RegisterMutatorsContext) {
-	ctx.BottomUp("multitree_imported_rename", MultitreeImportedRenameMutator).Parallel()
-}
-
-func MultitreeImportedRenameMutator(ctx android.BottomUpMutatorContext) {
-	if m, ok := ctx.Module().(MultitreeImportedModuleInterface); ok {
-		name := m.GetMultitreeImportedModuleName()
-		if !ctx.OtherModuleExists(name) {
-			// Provide an empty filegroup not to break the build while updating the metadata.
-			// In other cases, soong will report an error to guide users to run 'm update-meta'
-			// first.
-			if !ctx.Config().TargetMultitreeUpdateMeta() {
-				ctx.ModuleErrorf("\"%s\" filegroup must be imported.\nRun 'm update-meta' first to import the filegroup.", name)
-			}
-			ctx.Rename(name)
-		}
-	}
-}
diff --git a/multitree/metadata.go b/multitree/metadata.go
deleted file mode 100644
index 0eb0efc..0000000
--- a/multitree/metadata.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// 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.
-
-package multitree
-
-import (
-	"android/soong/android"
-	"encoding/json"
-)
-
-func init() {
-	android.RegisterParallelSingletonType("update-meta", UpdateMetaSingleton)
-}
-
-func UpdateMetaSingleton() android.Singleton {
-	return &updateMetaSingleton{}
-}
-
-type jsonImported struct {
-	FileGroups map[string][]string `json:",omitempty"`
-}
-
-type metadataJsonFlags struct {
-	Imported jsonImported        `json:",omitempty"`
-	Exported map[string][]string `json:",omitempty"`
-}
-
-type updateMetaSingleton struct {
-	importedModules       []string
-	generatedMetadataFile android.OutputPath
-}
-
-func (s *updateMetaSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	metadata := metadataJsonFlags{
-		Imported: jsonImported{
-			FileGroups: make(map[string][]string),
-		},
-		Exported: make(map[string][]string),
-	}
-	ctx.VisitAllModules(func(module android.Module) {
-		if ifg, ok := module.(*importedFileGroup); ok {
-			metadata.Imported.FileGroups[ifg.BaseModuleName()] = ifg.properties.Imported
-		}
-		if e, ok := module.(ExportableModule); ok {
-			if e.IsExported() && e.Exportable() {
-				for tag, files := range e.TaggedOutputs() {
-					// TODO(b/219846705): refactor this to a dictionary
-					metadata.Exported[e.Name()+":"+tag] = append(metadata.Exported[e.Name()+":"+tag], files.Strings()...)
-				}
-			}
-		}
-	})
-	jsonStr, err := json.Marshal(metadata)
-	if err != nil {
-		ctx.Errorf(err.Error())
-	}
-	s.generatedMetadataFile = android.PathForOutput(ctx, "multitree", "metadata.json")
-	android.WriteFileRule(ctx, s.generatedMetadataFile, string(jsonStr))
-}
-
-func (s *updateMetaSingleton) MakeVars(ctx android.MakeVarsContext) {
-	ctx.Strict("MULTITREE_METADATA", s.generatedMetadataFile.String())
-}
diff --git a/phony/Android.bp b/phony/Android.bp
index db5efc9..2e250c6 100644
--- a/phony/Android.bp
+++ b/phony/Android.bp
@@ -13,4 +13,5 @@
         "phony.go",
     ],
     pluginFor: ["soong_build"],
+    visibility: ["//visibility:public"],
 }
diff --git a/python/python.go b/python/python.go
index 8726f02..01ac86c 100644
--- a/python/python.go
+++ b/python/python.go
@@ -264,10 +264,9 @@
 			variants = append(variants, pyVersion3)
 		}
 		if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
-			if !ctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
-				ctx.ModuleName() != "py2-cmd" &&
+			if ctx.ModuleName() != "py2-cmd" &&
 				ctx.ModuleName() != "py2-stdlib" {
-				ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
+				ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.")
 			}
 			variants = append(variants, pyVersion2)
 		}
diff --git a/response/Android.bp b/response/Android.bp
index e19981f..2f319fe 100644
--- a/response/Android.bp
+++ b/response/Android.bp
@@ -13,4 +13,8 @@
     testSrcs: [
         "response_test.go",
     ],
+    visibility: [
+        "//build/make/tools/compliance",
+        "//build/soong:__subpackages__",
+    ],
 }
diff --git a/rust/Android.bp b/rust/Android.bp
index 53c9462..781f325 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -61,4 +61,5 @@
         "test_test.go",
     ],
     pluginFor: ["soong_build"],
+    visibility: ["//visibility:public"],
 }
diff --git a/rust/clippy.go b/rust/clippy.go
index 6f0ed7f..426fd73 100644
--- a/rust/clippy.go
+++ b/rust/clippy.go
@@ -38,11 +38,14 @@
 }
 
 func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
-	enabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints)
+	dirEnabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints)
 	if err != nil {
 		ctx.PropertyErrorf("clippy_lints", err.Error())
 	}
-	flags.Clippy = enabled
+
+	envDisable := ctx.Config().IsEnvTrue("SOONG_DISABLE_CLIPPY")
+
+	flags.Clippy = dirEnabled && !envDisable
 	flags.ClippyFlags = append(flags.ClippyFlags, lints)
 	return flags, deps
 }
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 79ea7a1..25f7580 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -24,4 +24,8 @@
         "x86_64_device.go",
         "arm64_linux_host.go",
     ],
+    visibility: [
+        "//build/soong:__subpackages__",
+        "//prebuilts/rust/soong",
+    ],
 }
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 9850570..94a4457 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -35,8 +35,13 @@
 		},
 		"armv8-2a":         []string{},
 		"armv8-2a-dotprod": []string{},
+
+		// branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
 		"armv9-a": []string{
-			// branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
+		"armv9-2a": []string{
 			"-Z branch-protection=bti,pac-ret",
 			"-Z stack-protector=none",
 		},
diff --git a/rust/config/global.go b/rust/config/global.go
index 990a643..68a74c2 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var (
 	pctx = android.NewPackageContext("android/soong/rust/config")
 
-	RustDefaultVersion = "1.80.1"
+	RustDefaultVersion = "1.81.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/coverage.go b/rust/coverage.go
index 91a7806..381fcf1 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -87,10 +87,6 @@
 }
 
 func (cov *coverage) begin(ctx BaseModuleContext) {
-	if ctx.Host() {
-		// Host coverage not yet supported.
-	} else {
-		// Update useSdk and sdkVersion args if Rust modules become SDK aware.
-		cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
-	}
+	// Update useSdk and sdkVersion args if Rust modules become SDK aware.
+	cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
 }
diff --git a/rust/rust.go b/rust/rust.go
index 5a973c4..50f822b 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -29,7 +29,6 @@
 	"android/soong/cc"
 	cc_config "android/soong/cc/config"
 	"android/soong/fuzz"
-	"android/soong/multitree"
 	"android/soong/rust/config"
 )
 
@@ -947,6 +946,7 @@
 			sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
 			mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
 		}
+		ctx.CheckbuildFile(mod.sourceProvider.Srcs()...)
 		android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
 	}
 
@@ -957,15 +957,13 @@
 			return
 		}
 		mod.outputFile = android.OptionalPathForPath(buildOutput.outputFile)
+		ctx.CheckbuildFile(buildOutput.outputFile)
 		if buildOutput.kytheFile != nil {
 			mod.kytheFiles = append(mod.kytheFiles, buildOutput.kytheFile)
 		}
 		bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath()))
 
 		mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps)
-		if mod.docTimestampFile.Valid() {
-			ctx.CheckbuildFile(mod.docTimestampFile.Path())
-		}
 
 		apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
 		if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) && !mod.ProcMacro() {
@@ -1219,47 +1217,6 @@
 
 	skipModuleList := map[string]bool{}
 
-	var apiImportInfo multitree.ApiImportInfo
-	hasApiImportInfo := false
-
-	ctx.VisitDirectDeps(func(dep android.Module) {
-		if dep.Name() == "api_imports" {
-			apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
-			hasApiImportInfo = true
-		}
-	})
-
-	if hasApiImportInfo {
-		targetStubModuleList := map[string]string{}
-		targetOrigModuleList := map[string]string{}
-
-		// Search for dependency which both original module and API imported library with APEX stub exists
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			depName := ctx.OtherModuleName(dep)
-			if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
-				targetStubModuleList[apiLibrary] = depName
-			}
-		})
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			depName := ctx.OtherModuleName(dep)
-			if origLibrary, ok := targetStubModuleList[depName]; ok {
-				targetOrigModuleList[origLibrary] = depName
-			}
-		})
-
-		// Decide which library should be used between original and API imported library
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			depName := ctx.OtherModuleName(dep)
-			if apiLibrary, ok := targetOrigModuleList[depName]; ok {
-				if cc.ShouldUseStubForApex(ctx, dep) {
-					skipModuleList[depName] = true
-				} else {
-					skipModuleList[apiLibrary] = true
-				}
-			}
-		})
-	}
-
 	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
 	var directAndroidMkSharedLibs []string
 
@@ -1610,13 +1567,6 @@
 	deps := mod.deps(ctx)
 	var commonDepVariations []blueprint.Variation
 
-	apiImportInfo := cc.GetApiImports(mod, actx)
-	if mod.usePublicApi() || mod.useVendorApi() {
-		for idx, lib := range deps.SharedLibs {
-			deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
-		}
-	}
-
 	if ctx.Os() == android.Android {
 		deps.SharedLibs, _ = cc.FilterNdkLibs(mod, ctx.Config(), deps.SharedLibs)
 	}
@@ -1709,15 +1659,7 @@
 		variations := []blueprint.Variation{
 			{Mutator: "link", Variation: "shared"},
 		}
-		// For core variant, add a dep on the implementation (if it exists) and its .apiimport (if it exists)
-		// GenerateAndroidBuildActions will pick the correct impl/stub based on the api_domain boundary
-		if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
-			cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
-		}
-
-		if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
-			cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, apiLibraryName, version, false)
-		}
+		cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
 	}
 
 	for _, lib := range deps.WholeStaticLibs {
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index bb88cce..1d2fc64 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -3,7 +3,52 @@
 
 ###################################################
 # core-libart.jar & core-oj.jar
-java(\..*)?
+java\.awt\.font
+java\.beans
+java\.io
+java\.lang
+java\.lang\.annotation
+java\.lang\.constant
+java\.lang\.invoke
+java\.lang\.ref
+java\.lang\.reflect
+java\.lang\.runtime
+java\.math
+java\.net
+java\.nio
+java\.nio\.file
+java\.nio\.file\.spi
+java\.nio\.file\.attribute
+java\.nio\.channels
+java\.nio\.channels\.spi
+java\.nio\.charset
+java\.nio\.charset\.spi
+java\.security
+java\.security\.acl
+java\.security\.cert
+java\.security\.interfaces
+java\.security\.spec
+java\.sql
+java\.text
+java\.text\.spi
+java\.time
+java\.time\.chrono
+java\.time\.format
+java\.time\.temporal
+java\.time\.zone
+java\.util
+java\.util\.concurrent
+java\.util\.concurrent\.atomic
+java\.util\.concurrent\.locks
+java\.util\.function
+java\.util\.jar
+java\.util\.logging
+java\.util\.prefs
+java\.util\.random
+java\.util\.regex
+java\.util\.spi
+java\.util\.stream
+java\.util\.zip
 # TODO: Remove javax.annotation.processing if possible, see http://b/132338110:
 javax\.annotation\.processing
 javax\.crypto
@@ -27,7 +72,20 @@
 javax\.xml\.transform\.stream
 javax\.xml\.validation
 javax\.xml\.xpath
-jdk\..*
+jdk\.internal
+jdk\.internal\.access
+jdk\.internal\.event
+jdk\.internal\.math
+jdk\.internal\.misc
+jdk\.internal\.ref
+jdk\.internal\.reflect
+jdk\.internal\.util
+jdk\.internal\.util\.jar
+jdk\.internal\.util\.random
+jdk\.internal\.vm
+jdk\.internal\.vm\.annotation
+jdk\.net
+jdk\.random
 org\.w3c\.dom
 org\.w3c\.dom\.ls
 org\.w3c\.dom\.traversal
diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py
index abab2e1..db64f90 100755
--- a/scripts/check_prebuilt_presigned_apk.py
+++ b/scripts/check_prebuilt_presigned_apk.py
@@ -36,7 +36,7 @@
                 if fail:
                     sys.exit(args.apk + ': Contains compressed JNI libraries')
                 return True
-            # It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
+            # It's ok for non-privileged apps to have compressed dex files
             if args.privileged and args.uncompress_priv_app_dex:
                 if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED:
                     if fail:
@@ -46,6 +46,10 @@
 
 
 def main():
+    # This script enforces requirements for presigned apps as documented in:
+    # go/gms-uncompressed-jni-slides
+    # https://docs.partner.android.com/gms/building/integrating/jni-libs
+    # https://docs.partner.android.com/gms/policies/domains/mba#jni-lib
     parser = argparse.ArgumentParser()
     parser.add_argument('--aapt2', help = "the path to the aapt2 executable")
     parser.add_argument('--zipalign', help = "the path to the zipalign executable")
diff --git a/scripts/manifest.py b/scripts/manifest.py
index 81f9c61..32603e8 100755
--- a/scripts/manifest.py
+++ b/scripts/manifest.py
@@ -23,9 +23,40 @@
 android_ns = 'http://schemas.android.com/apk/res/android'
 
 
+def get_or_create_applications(doc, manifest):
+  """Get all <application> tags from the manifest, or create one if none exist.
+  Multiple <application> tags may exist when manifest feature flagging is used.
+  """
+  applications = get_children_with_tag(manifest, 'application')
+  if len(applications) == 0:
+    application = doc.createElement('application')
+    indent = get_indent(manifest.firstChild, 1)
+    first = manifest.firstChild
+    manifest.insertBefore(doc.createTextNode(indent), first)
+    manifest.insertBefore(application, first)
+    applications.append(application)
+  return applications
+
+
+def get_or_create_uses_sdks(doc, manifest):
+  """Get all <uses-sdk> tags from the manifest, or create one if none exist.
+  Multiple <uses-sdk> tags may exist when manifest feature flagging is used.
+  """
+  uses_sdks = get_children_with_tag(manifest, 'uses-sdk')
+  if len(uses_sdks) == 0:
+    uses_sdk = doc.createElement('uses-sdk')
+    indent = get_indent(manifest.firstChild, 1)
+    manifest.insertBefore(uses_sdk, manifest.firstChild)
+
+    # Insert an indent before uses-sdk to line it up with the indentation of the
+    # other children of the <manifest> tag.
+    manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
+    uses_sdks.append(uses_sdk)
+  return uses_sdks
+
 def get_children_with_tag(parent, tag_name):
   children = []
-  for child in  parent.childNodes:
+  for child in parent.childNodes:
     if child.nodeType == minidom.Node.ELEMENT_NODE and \
        child.tagName == tag_name:
       children.append(child)
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index b101259..1e32d1d 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -25,10 +25,7 @@
 import sys
 from xml.dom import minidom
 
-from manifest import android_ns
-from manifest import get_children_with_tag
-from manifest import parse_manifest
-from manifest import write_xml
+from manifest import *
 
 
 class ManifestMismatchError(Exception):
@@ -122,7 +119,7 @@
     # handles module names specified in Android.bp properties. However not all
     # <uses-library> entries in the manifest correspond to real modules: some of
     # the optional libraries may be missing at build time. Therefor this script
-    # accepts raw module names as spelled in Android.bp/Amdroid.mk and trims the
+    # accepts raw module names as spelled in Android.bp/Android.mk and trims the
     # optional namespace part manually.
     required = trim_namespace_parts(required)
     optional = trim_namespace_parts(optional)
@@ -205,15 +202,9 @@
     """Extract <uses-library> tags from the manifest."""
 
     manifest = parse_manifest(xml)
-    elems = get_children_with_tag(manifest, 'application')
-    if len(elems) > 1:
-        raise RuntimeError('found multiple <application> tags')
-    if not elems:
-        return [], [], []
-
-    application = elems[0]
-
-    libs = get_children_with_tag(application, 'uses-library')
+    libs = [child
+            for application in get_or_create_applications(xml, manifest)
+            for child in get_children_with_tag(application, 'uses-library')]
 
     required = [uses_library_name(x) for x in libs if uses_library_required(x)]
     optional = [
@@ -266,7 +257,7 @@
     manifest: manifest (either parsed XML or aapt dump of APK)
     is_apk:   if the manifest comes from an APK or an XML file
     """
-    if is_apk: #pylint: disable=no-else-return
+    if is_apk:  #pylint: disable=no-else-return
         return extract_target_sdk_version_apk(manifest)
     else:
         return extract_target_sdk_version_xml(manifest)
@@ -376,7 +367,7 @@
 
             # Create a status file that is empty on success, or contains an
             # error message on failure. When exceptions are suppressed,
-            # dexpreopt command command will check file size to determine if
+            # dexpreopt command will check file size to determine if
             # the check has failed.
             if args.enforce_uses_libraries_status:
                 with open(args.enforce_uses_libraries_status, 'w') as f:
@@ -386,7 +377,7 @@
         if args.extract_target_sdk_version:
             try:
                 print(extract_target_sdk_version(manifest, is_apk))
-            except: #pylint: disable=bare-except
+            except:  #pylint: disable=bare-except
                 # Failed; don't crash, return "any" SDK version. This will
                 # result in dexpreopt not adding any compatibility libraries.
                 print(10000)
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
index 8003b3e..abe0d8b 100755
--- a/scripts/manifest_check_test.py
+++ b/scripts/manifest_check_test.py
@@ -44,8 +44,8 @@
 class EnforceUsesLibrariesTest(unittest.TestCase):
     """Unit tests for add_extract_native_libs function."""
 
-    def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[],
-                 missing_optional_uses_libraries=[]): #pylint: disable=dangerous-default-value
+    def run_test(self, xml, apk, uses_libraries=(), optional_uses_libraries=(),
+                 missing_optional_uses_libraries=()):  #pylint: disable=dangerous-default-value
         doc = minidom.parseString(xml)
         try:
             relax = False
@@ -114,14 +114,14 @@
         self.assertFalse(matches)
 
     def test_missing_uses_library(self):
-        xml = self.xml_tmpl % ('')
-        apk = self.apk_tmpl % ('')
+        xml = self.xml_tmpl % ''
+        apk = self.apk_tmpl % ''
         matches = self.run_test(xml, apk, uses_libraries=['foo'])
         self.assertFalse(matches)
 
     def test_missing_optional_uses_library(self):
-        xml = self.xml_tmpl % ('')
-        apk = self.apk_tmpl % ('')
+        xml = self.xml_tmpl % ''
+        apk = self.apk_tmpl % ''
         matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
         self.assertFalse(matches)
 
@@ -234,6 +234,32 @@
             optional_uses_libraries=['//x/y/z:bar'])
         self.assertTrue(matches)
 
+    def test_multiple_applications(self):
+        xml = """<?xml version="1.0" encoding="utf-8"?>
+            <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+                <application android:featureFlag="foo">
+                    <uses-library android:name="foo" />
+                    <uses-library android:name="bar" android:required="false" />
+                </application>
+                <application android:featureFlag="!foo">
+                    <uses-library android:name="foo" />
+                    <uses-library android:name="qux" android:required="false" />
+                </application>
+            </manifest>
+        """
+        apk = self.apk_tmpl % ('\n'.join([
+            uses_library_apk('foo'),
+            uses_library_apk('bar', required_apk(False)),
+            uses_library_apk('foo'),
+            uses_library_apk('qux', required_apk(False))
+        ]))
+        matches = self.run_test(
+            xml,
+            apk,
+            uses_libraries=['//x/y/z:foo'],
+            optional_uses_libraries=['//x/y/z:bar', '//x/y/z:qux'])
+        self.assertTrue(matches)
+
 
 class ExtractTargetSdkVersionTest(unittest.TestCase):
 
@@ -256,12 +282,12 @@
         "targetSdkVersion:'%s'\n"
         "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n")
 
-    def test_targert_sdk_version_28(self):
+    def test_target_sdk_version_28(self):
         xml = self.xml_tmpl % '28'
         apk = self.apk_tmpl % '28'
         self.run_test(xml, apk, '28')
 
-    def test_targert_sdk_version_29(self):
+    def test_target_sdk_version_29(self):
         xml = self.xml_tmpl % '29'
         apk = self.apk_tmpl % '29'
         self.run_test(xml, apk, '29')
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 58079aa..9847ad5 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -23,15 +23,7 @@
 from xml.dom import minidom
 
 
-from manifest import android_ns
-from manifest import compare_version_gt
-from manifest import ensure_manifest_android_ns
-from manifest import find_child_with_attribute
-from manifest import get_children_with_tag
-from manifest import get_indent
-from manifest import parse_manifest
-from manifest import write_xml
-
+from manifest import *
 
 def parse_args():
   """Parse commandline arguments."""
@@ -48,9 +40,9 @@
   parser.add_argument('--library', dest='library', action='store_true',
                       help='manifest is for a static library')
   parser.add_argument('--uses-library', dest='uses_libraries', action='append',
-                      help='specify additional <uses-library> tag to add. android:requred is set to true')
+                      help='specify additional <uses-library> tag to add. android:required is set to true')
   parser.add_argument('--optional-uses-library', dest='optional_uses_libraries', action='append',
-                      help='specify additional <uses-library> tag to add. android:requred is set to false')
+                      help='specify additional <uses-library> tag to add. android:required is set to false')
   parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true',
                       help='manifest is for a package built against the platform')
   parser.add_argument('--logging-parent', dest='logging_parent', default='',
@@ -91,47 +83,33 @@
 
   manifest = parse_manifest(doc)
 
-  # Get or insert the uses-sdk element
-  uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
-  if len(uses_sdk) > 1:
-    raise RuntimeError('found multiple uses-sdk elements')
-  elif len(uses_sdk) == 1:
-    element = uses_sdk[0]
-  else:
-    element = doc.createElement('uses-sdk')
-    indent = get_indent(manifest.firstChild, 1)
-    manifest.insertBefore(element, manifest.firstChild)
-
-    # Insert an indent before uses-sdk to line it up with the indentation of the
-    # other children of the <manifest> tag.
-    manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
-
-  # Get or insert the minSdkVersion attribute.  If it is already present, make
-  # sure it as least the requested value.
-  min_attr = element.getAttributeNodeNS(android_ns, 'minSdkVersion')
-  if min_attr is None:
-    min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion')
-    min_attr.value = min_sdk_version
-    element.setAttributeNode(min_attr)
-  else:
-    if compare_version_gt(min_sdk_version, min_attr.value):
+  for uses_sdk in get_or_create_uses_sdks(doc, manifest):
+    # Get or insert the minSdkVersion attribute.  If it is already present, make
+    # sure it as least the requested value.
+    min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion')
+    if min_attr is None:
+      min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion')
       min_attr.value = min_sdk_version
-
-  # Insert the targetSdkVersion attribute if it is missing.  If it is already
-  # present leave it as is.
-  target_attr = element.getAttributeNodeNS(android_ns, 'targetSdkVersion')
-  if target_attr is None:
-    target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion')
-    if library:
-      # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but
-      # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it
-      # is empty.  Set it to something low so that it will be overriden by the
-      # main manifest, but high enough that it doesn't cause implicit
-      # permissions grants.
-      target_attr.value = '16'
+      uses_sdk.setAttributeNode(min_attr)
     else:
-      target_attr.value = target_sdk_version
-    element.setAttributeNode(target_attr)
+      if compare_version_gt(min_sdk_version, min_attr.value):
+        min_attr.value = min_sdk_version
+
+    # Insert the targetSdkVersion attribute if it is missing.  If it is already
+    # present leave it as is.
+    target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion')
+    if target_attr is None:
+      target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion')
+      if library:
+        # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but
+        # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it
+        # is empty.  Set it to something low so that it will be overridden by the
+        # main manifest, but high enough that it doesn't cause implicit
+        # permissions grants.
+        target_attr.value = '16'
+      else:
+        target_attr.value = target_sdk_version
+      uses_sdk.setAttributeNode(target_attr)
 
 
 def add_logging_parent(doc, logging_parent_value):
@@ -147,37 +125,27 @@
   manifest = parse_manifest(doc)
 
   logging_parent_key = 'android.content.pm.LOGGING_PARENT'
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
+  for application in get_or_create_applications(doc, manifest):
+    indent = get_indent(application.firstChild, 2)
 
-  indent = get_indent(application.firstChild, 2)
-
-  last = application.lastChild
-  if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
-    last = None
-
-  if not find_child_with_attribute(application, 'meta-data', android_ns,
-                                   'name', logging_parent_key):
-    ul = doc.createElement('meta-data')
-    ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
-    ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
-    application.insertBefore(doc.createTextNode(indent), last)
-    application.insertBefore(ul, last)
     last = application.lastChild
+    if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+      last = None
 
-  # align the closing tag with the opening tag if it's not
-  # indented
-  if last and last.nodeType != minidom.Node.TEXT_NODE:
-    indent = get_indent(application.previousSibling, 1)
-    application.appendChild(doc.createTextNode(indent))
+    if not find_child_with_attribute(application, 'meta-data', android_ns,
+                                     'name', logging_parent_key):
+      ul = doc.createElement('meta-data')
+      ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
+      ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
+      application.insertBefore(doc.createTextNode(indent), last)
+      application.insertBefore(ul, last)
+      last = application.lastChild
+
+    # align the closing tag with the opening tag if it's not
+    # indented
+    if last and last.nodeType != minidom.Node.TEXT_NODE:
+      indent = get_indent(application.previousSibling, 1)
+      application.appendChild(doc.createTextNode(indent))
 
 
 def add_uses_libraries(doc, new_uses_libraries, required):
@@ -192,42 +160,32 @@
   """
 
   manifest = parse_manifest(doc)
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
+  for application in get_or_create_applications(doc, manifest):
+    indent = get_indent(application.firstChild, 2)
 
-  indent = get_indent(application.firstChild, 2)
+    last = application.lastChild
+    if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+      last = None
 
-  last = application.lastChild
-  if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
-    last = None
+    for name in new_uses_libraries:
+      if find_child_with_attribute(application, 'uses-library', android_ns,
+                                   'name', name) is not None:
+        # If the uses-library tag of the same 'name' attribute value exists,
+        # respect it.
+        continue
 
-  for name in new_uses_libraries:
-    if find_child_with_attribute(application, 'uses-library', android_ns,
-                                 'name', name) is not None:
-      # If the uses-library tag of the same 'name' attribute value exists,
-      # respect it.
-      continue
+      ul = doc.createElement('uses-library')
+      ul.setAttributeNS(android_ns, 'android:name', name)
+      ul.setAttributeNS(android_ns, 'android:required', str(required).lower())
 
-    ul = doc.createElement('uses-library')
-    ul.setAttributeNS(android_ns, 'android:name', name)
-    ul.setAttributeNS(android_ns, 'android:required', str(required).lower())
+      application.insertBefore(doc.createTextNode(indent), last)
+      application.insertBefore(ul, last)
 
-    application.insertBefore(doc.createTextNode(indent), last)
-    application.insertBefore(ul, last)
-
-  # align the closing tag with the opening tag if it's not
-  # indented
-  if application.lastChild.nodeType != minidom.Node.TEXT_NODE:
-    indent = get_indent(application.previousSibling, 1)
-    application.appendChild(doc.createTextNode(indent))
+    # align the closing tag with the opening tag if it's not
+    # indented
+    if application.lastChild.nodeType != minidom.Node.TEXT_NODE:
+      indent = get_indent(application.previousSibling, 1)
+      application.appendChild(doc.createTextNode(indent))
 
 
 def add_uses_non_sdk_api(doc):
@@ -240,111 +198,63 @@
   """
 
   manifest = parse_manifest(doc)
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
-
-  attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi')
-  if attr is None:
-    attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi')
-    attr.value = 'true'
-    application.setAttributeNode(attr)
+  for application in get_or_create_applications(doc, manifest):
+    attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi')
+    if attr is None:
+      attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi')
+      attr.value = 'true'
+      application.setAttributeNode(attr)
 
 
 def add_use_embedded_dex(doc):
   manifest = parse_manifest(doc)
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
-
-  attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex')
-  if attr is None:
-    attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex')
-    attr.value = 'true'
-    application.setAttributeNode(attr)
-  elif attr.value != 'true':
-    raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
+  for application in get_or_create_applications(doc, manifest):
+    attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex')
+    if attr is None:
+      attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex')
+      attr.value = 'true'
+      application.setAttributeNode(attr)
+    elif attr.value != 'true':
+      raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
 
 
 def add_extract_native_libs(doc, extract_native_libs):
   manifest = parse_manifest(doc)
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
-
-  value = str(extract_native_libs).lower()
-  attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
-  if attr is None:
-    attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
-    attr.value = value
-    application.setAttributeNode(attr)
-  elif attr.value != value:
-    raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
-                       (attr.value, value))
+  for application in get_or_create_applications(doc, manifest):
+    value = str(extract_native_libs).lower()
+    attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
+    if attr is None:
+      attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
+      attr.value = value
+      application.setAttributeNode(attr)
+    elif attr.value != value:
+      raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
+                         (attr.value, value))
 
 
 def set_has_code_to_false(doc):
   manifest = parse_manifest(doc)
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
+  for application in get_or_create_applications(doc, manifest):
+    attr = application.getAttributeNodeNS(android_ns, 'hasCode')
+    if attr is not None:
+      # Do nothing if the application already has a hasCode attribute.
+      continue
+    attr = doc.createAttributeNS(android_ns, 'android:hasCode')
+    attr.value = 'false'
+    application.setAttributeNode(attr)
 
-  attr = application.getAttributeNodeNS(android_ns, 'hasCode')
-  if attr is not None:
-    # Do nothing if the application already has a hasCode attribute.
-    return
-  attr = doc.createAttributeNS(android_ns, 'android:hasCode')
-  attr.value = 'false'
-  application.setAttributeNode(attr)
 
 def set_test_only_flag_to_true(doc):
   manifest = parse_manifest(doc)
-  elems = get_children_with_tag(manifest, 'application')
-  application = elems[0] if len(elems) == 1 else None
-  if len(elems) > 1:
-    raise RuntimeError('found multiple <application> tags')
-  elif not elems:
-    application = doc.createElement('application')
-    indent = get_indent(manifest.firstChild, 1)
-    first = manifest.firstChild
-    manifest.insertBefore(doc.createTextNode(indent), first)
-    manifest.insertBefore(application, first)
+  for application in get_or_create_applications(doc, manifest):
+    attr = application.getAttributeNodeNS(android_ns, 'testOnly')
+    if attr is not None:
+      # Do nothing If the application already has a testOnly attribute.
+      continue
+    attr = doc.createAttributeNS(android_ns, 'android:testOnly')
+    attr.value = 'true'
+    application.setAttributeNode(attr)
 
-  attr = application.getAttributeNodeNS(android_ns, 'testOnly')
-  if attr is not None:
-    # Do nothing If the application already has a testOnly attribute.
-    return
-  attr = doc.createAttributeNS(android_ns, 'android:testOnly')
-  attr.value = 'true'
-  application.setAttributeNode(attr)
 
 def set_max_sdk_version(doc, max_sdk_version):
   """Replace the maxSdkVersion attribute value for permission and
@@ -364,6 +274,7 @@
       if max_attr and max_attr.value == 'current':
         max_attr.value = max_sdk_version
 
+
 def override_placeholder_version(doc, new_version):
   """Replace the versionCode attribute value if it\'s currently
   set to the placeholder version of 0.
@@ -374,9 +285,10 @@
   """
   manifest = parse_manifest(doc)
   version = manifest.getAttribute("android:versionCode")
-  if (version == '0'):
+  if version == '0':
     manifest.setAttribute("android:versionCode", new_version)
 
+
 def main():
   """Program entry point."""
   try:
@@ -427,5 +339,6 @@
     print('error: ' + str(err), file=sys.stderr)
     sys.exit(-1)
 
+
 if __name__ == '__main__':
   main()
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 0a62b10..e4d8dc3 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -20,12 +20,13 @@
 import sys
 import unittest
 from xml.dom import minidom
-import xml.etree.ElementTree as ET
+import xml.etree.ElementTree as ElementTree
 
 import manifest_fixer
 
 sys.dont_write_bytecode = True
 
+
 class CompareVersionGtTest(unittest.TestCase):
   """Unit tests for compare_version_gt function."""
 
@@ -69,25 +70,24 @@
       '%s'
       '</manifest>\n')
 
-  # pylint: disable=redefined-builtin
-  def uses_sdk(self, min=None, target=None, extra=''):
+  def uses_sdk(self, min_sdk=None, target_sdk=None, extra=''):
     attrs = ''
-    if min:
-      attrs += ' android:minSdkVersion="%s"' % (min)
-    if target:
-      attrs += ' android:targetSdkVersion="%s"' % (target)
+    if min_sdk:
+      attrs += ' android:minSdkVersion="%s"' % min_sdk
+    if target_sdk:
+      attrs += ' android:targetSdkVersion="%s"' % target_sdk
     if extra:
       attrs += ' ' + extra
-    return '    <uses-sdk%s/>\n' % (attrs)
+    return '    <uses-sdk%s/>\n' % attrs
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def test_no_uses_sdk(self):
     """Tests inserting a uses-sdk element into a manifest."""
 
     manifest_input = self.manifest_tmpl % ''
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
     self.assert_xml_equal(output, expected)
 
@@ -95,7 +95,7 @@
     """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
 
     manifest_input = self.manifest_tmpl % '    <uses-sdk extra="foo"/>\n'
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28',
                                                   extra='extra="foo"')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
     self.assert_xml_equal(output, expected)
@@ -103,64 +103,64 @@
   def test_raise_min(self):
     """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
     self.assert_xml_equal(output, expected)
 
   def test_raise(self):
     """Tests raising a minSdkVersion attribute."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
     self.assert_xml_equal(output, expected)
 
   def test_no_raise_min(self):
     """Tests a minSdkVersion that doesn't need raising."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
     output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
     self.assert_xml_equal(output, expected)
 
   def test_raise_codename(self):
     """Tests raising a minSdkVersion attribute to a codename."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
-    expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='P')
     output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
     self.assert_xml_equal(output, expected)
 
   def test_no_raise_codename(self):
     """Tests a minSdkVersion codename that doesn't need raising."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
-    expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='P')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='28')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
     self.assert_xml_equal(output, expected)
 
   def test_target(self):
     """Tests an existing targetSdkVersion is preserved."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='26', target_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
     self.assert_xml_equal(output, expected)
 
   def test_no_target(self):
     """Tests inserting targetSdkVersion when minSdkVersion exists."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
     self.assert_xml_equal(output, expected)
 
   def test_target_no_min(self):
     """"Tests inserting targetSdkVersion when minSdkVersion exists."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
     self.assert_xml_equal(output, expected)
 
@@ -168,23 +168,23 @@
     """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
 
     manifest_input = self.manifest_tmpl % ''
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
     self.assert_xml_equal(output, expected)
 
   def test_library_no_target(self):
     """Tests inserting targetSdkVersion when minSdkVersion exists."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
     self.assert_xml_equal(output, expected)
 
   def test_library_target_no_min(self):
     """Tests inserting targetSdkVersion when minSdkVersion exists."""
 
-    manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
+    manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
     self.assert_xml_equal(output, expected)
 
@@ -192,7 +192,7 @@
     """Tests inserting targetSdkVersion when minSdkVersion does not exist."""
 
     manifest_input = self.manifest_tmpl % ''
-    expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
+    expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16')
     output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
     self.assert_xml_equal(output, expected)
 
@@ -228,12 +228,24 @@
 
     self.assert_xml_equal(output, expected)
 
+  def test_multiple_uses_sdks(self):
+    """Tests a manifest that contains multiple uses_sdks elements."""
+
+    manifest_input = self.manifest_tmpl % (
+        '    <uses-sdk android:featureFlag="foo" android:minSdkVersion="21" />\n'
+        '    <uses-sdk android:featureFlag="!foo" android:minSdkVersion="22" />\n')
+    expected = self.manifest_tmpl % (
+      '    <uses-sdk android:featureFlag="foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n'
+      '    <uses-sdk android:featureFlag="!foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n')
+
+    output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
+    self.assert_xml_equal(output, expected)
 
 class AddLoggingParentTest(unittest.TestCase):
   """Unit tests for add_logging_parent function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def add_logging_parent_test(self, input_manifest, logging_parent=None):
     doc = minidom.parseString(input_manifest)
@@ -253,8 +265,8 @@
     attrs = ''
     if logging_parent:
       meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" '
-                   'android:value="%s"/>\n') % (logging_parent)
-      attrs += '    <application>\n        %s    </application>\n' % (meta_text)
+                   'android:value="%s"/>\n') % logging_parent
+      attrs += '    <application>\n        %s    </application>\n' % meta_text
 
     return attrs
 
@@ -277,7 +289,7 @@
   """Unit tests for add_uses_libraries function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest, new_uses_libraries):
     doc = minidom.parseString(input_manifest)
@@ -289,18 +301,16 @@
   manifest_tmpl = (
       '<?xml version="1.0" encoding="utf-8"?>\n'
       '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
-      '    <application>\n'
       '%s'
-      '    </application>\n'
       '</manifest>\n')
 
   def uses_libraries(self, name_required_pairs):
-    ret = ''
+    ret = '    <application>\n'
     for name, required in name_required_pairs:
       ret += (
           '        <uses-library android:name="%s" android:required="%s"/>\n'
       ) % (name, required)
-
+    ret += '    </application>\n'
     return ret
 
   def test_empty(self):
@@ -361,12 +371,23 @@
     output = self.run_test(manifest_input, ['foo', 'bar'])
     self.assert_xml_equal(output, expected)
 
+  def test_multiple_application(self):
+    """When there are multiple applications, the libs are added to each."""
+    manifest_input = self.manifest_tmpl % (
+            self.uses_libraries([('foo', 'false')]) +
+            self.uses_libraries([('bar', 'false')]))
+    expected = self.manifest_tmpl % (
+            self.uses_libraries([('foo', 'false'), ('bar', 'true')]) +
+            self.uses_libraries([('bar', 'false'), ('foo', 'true')]))
+    output = self.run_test(manifest_input, ['foo', 'bar'])
+    self.assert_xml_equal(output, expected)
+
 
 class AddUsesNonSdkApiTest(unittest.TestCase):
   """Unit tests for add_uses_libraries function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest):
     doc = minidom.parseString(input_manifest)
@@ -378,11 +399,11 @@
   manifest_tmpl = (
       '<?xml version="1.0" encoding="utf-8"?>\n'
       '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
-      '    <application%s/>\n'
+      '    %s\n'
       '</manifest>\n')
 
   def uses_non_sdk_api(self, value):
-    return ' android:usesNonSdkApi="true"' if value else ''
+    return '<application %s/>' % ('android:usesNonSdkApi="true"' if value else '')
 
   def test_set_true(self):
     """Empty new_uses_libraries must not touch the manifest."""
@@ -398,12 +419,19 @@
     output = self.run_test(manifest_input)
     self.assert_xml_equal(output, expected)
 
+  def test_multiple_applications(self):
+    """new_uses_libraries must be added to all applications."""
+    manifest_input = self.manifest_tmpl % (self.uses_non_sdk_api(True) +  self.uses_non_sdk_api(False))
+    expected = self.manifest_tmpl % (self.uses_non_sdk_api(True) +  self.uses_non_sdk_api(True))
+    output = self.run_test(manifest_input)
+    self.assert_xml_equal(output, expected)
+
 
 class UseEmbeddedDexTest(unittest.TestCase):
   """Unit tests for add_use_embedded_dex function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest):
     doc = minidom.parseString(input_manifest)
@@ -415,14 +443,14 @@
   manifest_tmpl = (
       '<?xml version="1.0" encoding="utf-8"?>\n'
       '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
-      '    <application%s/>\n'
+      '    %s\n'
       '</manifest>\n')
 
   def use_embedded_dex(self, value):
-    return ' android:useEmbeddedDex="%s"' % value
+    return '<application android:useEmbeddedDex="%s" />' % value
 
   def test_manifest_with_undeclared_preference(self):
-    manifest_input = self.manifest_tmpl % ''
+    manifest_input = self.manifest_tmpl % '<application/>'
     expected = self.manifest_tmpl % self.use_embedded_dex('true')
     output = self.run_test(manifest_input)
     self.assert_xml_equal(output, expected)
@@ -437,12 +465,24 @@
     manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
     self.assertRaises(RuntimeError, self.run_test, manifest_input)
 
+  def test_multiple_applications(self):
+    manifest_input = self.manifest_tmpl % (
+        self.use_embedded_dex('true') +
+        '<application/>'
+    )
+    expected = self.manifest_tmpl % (
+        self.use_embedded_dex('true') +
+        self.use_embedded_dex('true')
+    )
+    output = self.run_test(manifest_input)
+    self.assert_xml_equal(output, expected)
+
 
 class AddExtractNativeLibsTest(unittest.TestCase):
   """Unit tests for add_extract_native_libs function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest, value):
     doc = minidom.parseString(input_manifest)
@@ -454,20 +494,20 @@
   manifest_tmpl = (
       '<?xml version="1.0" encoding="utf-8"?>\n'
       '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
-      '    <application%s/>\n'
+      '    %s\n'
       '</manifest>\n')
 
   def extract_native_libs(self, value):
-    return ' android:extractNativeLibs="%s"' % value
+    return '<application android:extractNativeLibs="%s" />' % value
 
   def test_set_true(self):
-    manifest_input = self.manifest_tmpl % ''
+    manifest_input = self.manifest_tmpl % '<application/>'
     expected = self.manifest_tmpl % self.extract_native_libs('true')
     output = self.run_test(manifest_input, True)
     self.assert_xml_equal(output, expected)
 
   def test_set_false(self):
-    manifest_input = self.manifest_tmpl % ''
+    manifest_input = self.manifest_tmpl % '<application/>'
     expected = self.manifest_tmpl % self.extract_native_libs('false')
     output = self.run_test(manifest_input, False)
     self.assert_xml_equal(output, expected)
@@ -482,12 +522,18 @@
     manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
     self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
 
+  def test_multiple_applications(self):
+    manifest_input = self.manifest_tmpl % (self.extract_native_libs('true') + '<application/>')
+    expected = self.manifest_tmpl % (self.extract_native_libs('true') + self.extract_native_libs('true'))
+    output = self.run_test(manifest_input, True)
+    self.assert_xml_equal(output, expected)
+
 
 class AddNoCodeApplicationTest(unittest.TestCase):
   """Unit tests for set_has_code_to_false function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest):
     doc = minidom.parseString(input_manifest)
@@ -515,7 +561,7 @@
     self.assert_xml_equal(output, expected)
 
   def test_has_application_has_code_false(self):
-    """ Do nothing if there's already an application elemeent. """
+    """ Do nothing if there's already an application element. """
     manifest_input = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
     output = self.run_test(manifest_input)
     self.assert_xml_equal(output, manifest_input)
@@ -527,12 +573,25 @@
     output = self.run_test(manifest_input)
     self.assert_xml_equal(output, manifest_input)
 
+  def test_multiple_applications(self):
+    """ Apply to all applications  """
+    manifest_input = self.manifest_tmpl % (
+        '    <application android:hasCode="true" />\n' +
+        '    <application android:hasCode="false" />\n' +
+        '    <application/>\n')
+    expected = self.manifest_tmpl % (
+        '    <application android:hasCode="true" />\n' +
+        '    <application android:hasCode="false" />\n' +
+        '    <application android:hasCode="false" />\n')
+    output = self.run_test(manifest_input)
+    self.assert_xml_equal(output, expected)
+
 
 class AddTestOnlyApplicationTest(unittest.TestCase):
   """Unit tests for set_test_only_flag_to_true function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest):
     doc = minidom.parseString(input_manifest)
@@ -571,12 +630,26 @@
     output = self.run_test(manifest_input)
     self.assert_xml_equal(output, manifest_input)
 
+  def test_multiple_applications(self):
+    manifest_input = self.manifest_tmpl % (
+        '    <application android:testOnly="true" />\n' +
+        '    <application android:testOnly="false" />\n' +
+        '    <application/>\n'
+    )
+    expected = self.manifest_tmpl % (
+        '    <application android:testOnly="true" />\n' +
+        '    <application android:testOnly="false" />\n' +
+        '    <application android:testOnly="true" />\n'
+    )
+    output = self.run_test(manifest_input)
+    self.assert_xml_equal(output, expected)
+
 
 class SetMaxSdkVersionTest(unittest.TestCase):
   """Unit tests for set_max_sdk_version function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest, max_sdk_version):
     doc = minidom.parseString(input_manifest)
@@ -591,15 +664,15 @@
       '%s'
       '</manifest>\n')
 
-  def permission(self, max=None):
-    if max is None:
+  def permission(self, max_sdk=None):
+    if max_sdk is None:
       return '   <permission/>'
-    return '    <permission android:maxSdkVersion="%s"/>\n' % max
+    return '    <permission android:maxSdkVersion="%s"/>\n' % max_sdk
 
-  def uses_permission(self, max=None):
-    if max is None:
+  def uses_permission(self, max_sdk=None):
+    if max_sdk is None:
       return '   <uses-permission/>'
-    return '    <uses-permission android:maxSdkVersion="%s"/>\n' % max
+    return '    <uses-permission android:maxSdkVersion="%s"/>\n' % max_sdk
 
   def test_permission_no_max_sdk_version(self):
     """Tests if permission has no maxSdkVersion attribute"""
@@ -643,11 +716,12 @@
     output = self.run_test(manifest_input, '9000')
     self.assert_xml_equal(output, expected)
 
+
 class OverrideDefaultVersionTest(unittest.TestCase):
   """Unit tests for override_default_version function."""
 
   def assert_xml_equal(self, output, expected):
-    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+    self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected))
 
   def run_test(self, input_manifest, version):
     doc = minidom.parseString(input_manifest)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 7ee548f..39c8123 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -204,7 +204,19 @@
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core1.jar
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core2.jar
 		`),
-		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
+		snapshotTestPreparer(checkSnapshotWithoutSource, android.GroupFixturePreparers(
+			preparerForSnapshot,
+			// Flag ART prebuilts
+			android.FixtureMergeMockFs(android.MockFS{
+				"apex_contributions/Android.bp": []byte(`
+				apex_contributions {
+					name: "prebuilt_art_contributions",
+					contents: ["prebuilt_com.android.art"],
+					api_domain: "com.android.art",
+				}
+			`)}),
+			android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"),
+		)),
 
 		// Check the behavior of the snapshot without the source.
 		snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
@@ -212,8 +224,8 @@
 			checkBootJarsPackageCheckRule(t, result,
 				append(
 					[]string{
-						"out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
-						"out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
+						"out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core1.jar",
+						"out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core2.jar",
 						"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
 					},
 					java.ApexBootJarDexJarPaths...,
@@ -338,6 +350,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "2",
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -348,6 +361,7 @@
 				public: {enabled: true},
 				min_sdk_version: "2",
 				permitted_packages: ["myothersdklibrary"],
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -357,6 +371,7 @@
 				compile_dex: true,
 				public: {enabled: true},
 				min_sdk_version: "2",
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -624,6 +639,7 @@
 				min_sdk_version: "2",
 				permitted_packages: ["myothersdklibrary"],
 				compile_dex: true,
+				sdk_version: "current",
 			}
 		`),
 
@@ -655,6 +671,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "2",
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -877,6 +894,7 @@
 				public: {enabled: true},
 				permitted_packages: ["mysdklibrary"],
 				min_sdk_version: "current",
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -895,6 +913,7 @@
 					package_prefixes: ["newlibrary.all.mine"],
 					single_packages: ["newlibrary.mine"],
 				},
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -1080,6 +1099,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "S",
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -1090,6 +1110,7 @@
 				public: {enabled: true},
 				min_sdk_version: "Tiramisu",
 				permitted_packages: ["mynewsdklibrary"],
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -1287,6 +1308,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "Tiramisu",
+				sdk_version: "current",
 			}
 			java_sdk_library {
 				name: "mynewsdklibrary",
@@ -1296,6 +1318,7 @@
 				public: {enabled: true},
 				min_sdk_version: "Tiramisu",
 				permitted_packages: ["mynewsdklibrary"],
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 0fb5c70..09a7c9e 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1703,61 +1703,6 @@
 	)
 }
 
-func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) {
-	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
-		sdk {
-			name: "mysdk",
-			java_sdk_libs: ["myjavalib"],
-		}
-
-		java_sdk_library {
-			name: "myjavalib",
-			apex_available: ["//apex_available:anyapex"],
-			srcs: ["Test.java"],
-			sdk_version: "current",
-			naming_scheme: "default",
-			public: {
-				enabled: true,
-			},
-		}
-	`)
-
-	CheckSnapshot(t, result, "mysdk", "",
-		checkAndroidBpContents(`
-// This is auto-generated. DO NOT EDIT.
-
-apex_contributions_defaults {
-    name: "mysdk.contributions",
-    contents: ["prebuilt_myjavalib"],
-}
-
-java_sdk_library_import {
-    name: "myjavalib",
-    prefer: false,
-    visibility: ["//visibility:public"],
-    apex_available: ["//apex_available:anyapex"],
-    naming_scheme: "default",
-    shared_library: true,
-    public: {
-        jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
-        current_api: "sdk_library/public/myjavalib.txt",
-        removed_api: "sdk_library/public/myjavalib-removed.txt",
-        sdk_version: "current",
-    },
-}
-`),
-		checkAllCopyRules(`
-.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-`),
-		checkMergeZips(
-			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
-		),
-	)
-}
-
 func TestSnapshotWithJavaSdkLibrary_DoctagFiles(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForSdkTestWithJavaSdkLibrary,
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 5b644fd..aa82abb 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -84,20 +84,6 @@
 
 	// True if this is a module_exports (or module_exports_snapshot) module type.
 	Module_exports bool `blueprint:"mutated"`
-
-	// The additional visibility to add to the prebuilt modules to allow them to
-	// reference each other.
-	//
-	// This can only be used to widen the visibility of the members:
-	//
-	// * Specifying //visibility:public here will make all members visible and
-	//   essentially ignore their own visibility.
-	// * Specifying //visibility:private here is an error.
-	// * Specifying any other rule here will add it to the members visibility and
-	//   be output to the member prebuilt in the snapshot. Duplicates will be
-	//   dropped. Adding a rule to members that have //visibility:private will
-	//   cause the //visibility:private to be discarded.
-	Prebuilt_visibility []string
 }
 
 // sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
@@ -130,8 +116,6 @@
 
 	s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties, &traitsWrapper)
 
-	// Make sure that the prebuilt visibility property is verified for errors.
-	android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility)
 	android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(s)
 	android.AddLoadHook(s, func(ctx android.LoadHookContext) {
@@ -211,6 +195,11 @@
 		OutputFile: s.snapshotFile,
 		DistFiles:  android.MakeDefaultDistFiles(s.snapshotFile.Path(), s.infoFile.Path()),
 		Include:    "$(BUILD_PHONY_PACKAGE)",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.SetBool("LOCAL_DONT_CHECK_MODULE", true)
+			},
+		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
 			func(w io.Writer, name, prefix, moduleDir string) {
 				// Allow the sdk to be built by simply passing its name on the command line.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 057b370..2532a25 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -53,9 +53,6 @@
 				// generated sdk_snapshot.
 				":__subpackages__",
 			],
-			prebuilt_visibility: [
-				"//prebuilts/mysdk",
-			],
 			java_header_libs: [
 				"myjavalib",
 				"mypublicjavalib",
@@ -131,11 +128,7 @@
 java_import {
     name: "myjavalib",
     prefer: false,
-    visibility: [
-        "//other/foo",
-        "//package",
-        "//prebuilts/mysdk",
-    ],
+    visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
@@ -151,11 +144,7 @@
 java_import {
     name: "mydefaultedjavalib",
     prefer: false,
-    visibility: [
-        "//other/bar",
-        "//package",
-        "//prebuilts/mysdk",
-    ],
+    visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/mydefaultedjavalib.jar"],
 }
@@ -163,50 +152,13 @@
 java_import {
     name: "myprivatejavalib",
     prefer: false,
-    visibility: [
-        "//package",
-        "//prebuilts/mysdk",
-    ],
+    visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/myprivatejavalib.jar"],
 }
 `))
 }
 
-func TestPrebuiltVisibilityProperty_IsValidated(t *testing.T) {
-	testSdkError(t, `prebuilt_visibility: cannot mix "//visibility:private" with any other visibility rules`, `
-		sdk {
-			name: "mysdk",
-			prebuilt_visibility: [
-				"//foo",
-				"//visibility:private",
-			],
-		}
-`)
-}
-
-func TestPrebuiltVisibilityProperty_AddPrivate(t *testing.T) {
-	testSdkError(t, `prebuilt_visibility: "//visibility:private" does not widen the visibility`, `
-		sdk {
-			name: "mysdk",
-			prebuilt_visibility: [
-				"//visibility:private",
-			],
-			java_header_libs: [
-				"myjavalib",
-			],
-		}
-
-		java_library {
-			name: "myjavalib",
-			// Uses package default visibility
-			srcs: ["Test.java"],
-			system_modules: "none",
-			sdk_version: "none",
-		}
-`)
-}
-
 func TestSdkInstall(t *testing.T) {
 	sdk := `
 		sdk {
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index c1c4ed6..fd6c4e7 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -80,6 +80,7 @@
 				dex_preopt: {
 					profile: "art-profile",
 				},
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -110,12 +111,14 @@
 			apex_available: ["myapex"],
 			srcs: ["Test.java"],
 			min_sdk_version: "33", // Tiramisu
+			sdk_version: "current",
 		}
 		java_sdk_library {
 			name: "mysdklibrary-future",
 			apex_available: ["myapex"],
 			srcs: ["Test.java"],
 			min_sdk_version: "34", // UpsideDownCake
+			sdk_version: "current",
 		}
 		sdk {
 			name: "mysdk",
@@ -199,6 +202,7 @@
 			apex_available: ["myapex"],
 			srcs: ["Test.java"],
 			min_sdk_version: "34", // UpsideDownCake
+			sdk_version: "current",
 		}
 		sdk {
 			name: "mysdk",
diff --git a/sdk/update.go b/sdk/update.go
index a4b1967..7f4f80a 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -22,7 +22,6 @@
 	"sort"
 	"strings"
 
-	"android/soong/apex"
 	"android/soong/cc"
 	"android/soong/java"
 
@@ -563,11 +562,11 @@
 	}
 	builder.infoContents = string(output)
 	android.WriteFileRuleVerbatim(ctx, info, builder.infoContents)
-	installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
+	installedInfo := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
 	s.infoFile = android.OptionalPathForPath(installedInfo)
 
 	// Install the zip, making sure that the info file has been installed as well.
-	installedZip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
+	installedZip := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
 	s.snapshotFile = android.OptionalPathForPath(installedZip)
 }
 
@@ -1109,20 +1108,24 @@
 		// same package so can be marked as private.
 		m.AddProperty("visibility", []string{"//visibility:private"})
 	} else {
-		// Extract visibility information from a member variant. All variants have the same
-		// visibility so it doesn't matter which one is used.
-		visibilityRules := android.EffectiveVisibilityRules(s.ctx, variant)
-
-		// Add any additional visibility rules needed for the prebuilts to reference each other.
-		err := visibilityRules.Widen(s.sdk.properties.Prebuilt_visibility)
-		if err != nil {
-			s.ctx.PropertyErrorf("prebuilt_visibility", "%s", err)
-		}
-
-		visibility := visibilityRules.Strings()
-		if len(visibility) != 0 {
-			m.AddProperty("visibility", visibility)
-		}
+		// Change the visibility of the module SDK prebuilts to public.
+		// This includes
+		// 1. Stub libraries of `sdk` modules
+		// 2. Binaries and libraries of `module_exports` modules
+		//
+		// This is a workaround to improve maintainlibility of the module SDK.
+		// Since module sdks are generated from release branches and dropped to development
+		// branches, there might be a visibility skew between the sources and prebuilts
+		// of a specific module.
+		// To reconcile this potential skew, change the visibility to public.
+		//
+		// This means dependencies can bypass visibility restrictions when prebuilts are used, so we rely
+		// on source builds in CI to check them.
+		//
+		// TODO (b/361303067): This special case for category (2) can be removed if existing usages
+		// of host/test prebuilts of modules like conscrypt,tzdata,i18n are switched to source builds.
+		// It will also require ART switching to full manifests.
+		m.AddProperty("visibility", []string{"//visibility:public"})
 	}
 
 	// Where available copy apex_available properties from the member.
@@ -1133,9 +1136,6 @@
 			apexAvailable = []string{android.AvailableToPlatform}
 		}
 
-		// Add in any baseline apex available settings.
-		apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
-
 		// Remove duplicates and sort.
 		apexAvailable = android.FirstUniqueStrings(apexAvailable)
 		sort.Strings(apexAvailable)
@@ -1989,14 +1989,6 @@
 	return m.builder.targetBuildRelease.EarlierThan(buildReleaseT)
 }
 
-func (m *memberContext) Config() android.Config {
-	return m.sdkMemberContext.Config()
-}
-
-func (m *memberContext) OtherModulePropertyErrorf(module android.Module, property string, fmt string, args ...interface{}) {
-	m.sdkMemberContext.OtherModulePropertyErrorf(module, property, fmt, args)
-}
-
 var _ android.SdkMemberContext = (*memberContext)(nil)
 
 func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index a00a5e4..22cba3b 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -21,4 +21,6 @@
         "sysprop_test.go",
     ],
     pluginFor: ["soong_build"],
+    // Used by plugins
+    visibility: ["//visibility:public"],
 }
diff --git a/testing/code_metadata_internal_proto/Android.bp b/testing/code_metadata_internal_proto/Android.bp
index a534cc2..396e44f 100644
--- a/testing/code_metadata_internal_proto/Android.bp
+++ b/testing/code_metadata_internal_proto/Android.bp
@@ -20,10 +20,14 @@
     name: "soong-testing-code_metadata_internal_proto",
     pkgPath: "android/soong/testing/code_metadata_internal_proto",
     deps: [
-            "golang-protobuf-reflect-protoreflect",
-            "golang-protobuf-runtime-protoimpl",
-        ],
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
     srcs: [
         "code_metadata_internal.pb.go",
     ],
+    visibility: [
+        "//build/make/tools/metadata",
+        "//build/soong:__subpackages__",
+    ],
 }
diff --git a/testing/code_metadata_proto/Android.bp b/testing/code_metadata_proto/Android.bp
index f07efff..ae41d4a 100644
--- a/testing/code_metadata_proto/Android.bp
+++ b/testing/code_metadata_proto/Android.bp
@@ -26,6 +26,7 @@
     srcs: [
         "code_metadata.pb.go",
     ],
+    visibility: ["//build/make/tools/metadata"],
 }
 
 python_library_host {
@@ -40,4 +41,5 @@
     proto: {
         canonical_path_from_root: false,
     },
+    visibility: ["//tools/asuite/team_build_scripts"],
 }
diff --git a/testing/test_spec_proto/Android.bp b/testing/test_spec_proto/Android.bp
index d5ad70b..1070d1a 100644
--- a/testing/test_spec_proto/Android.bp
+++ b/testing/test_spec_proto/Android.bp
@@ -26,6 +26,11 @@
     srcs: [
         "test_spec.pb.go",
     ],
+    visibility: [
+        "//build/make/tools/metadata",
+        "//build/soong:__subpackages__",
+        "//vendor:__subpackages__",
+    ],
 }
 
 python_library_host {
@@ -40,4 +45,5 @@
     proto: {
         canonical_path_from_root: false,
     },
+    visibility: ["//tools/asuite/team_build_scripts"],
 }
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 2e40950..715f976 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -145,36 +145,19 @@
   run_soong
   local -r ninja_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
-  local glob_deps_file=out/soong/globs/"${target_product}"/0.d
-
   run_soong
   local -r ninja_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
-  # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
-  # the entry in the .ninja_log.  It doesn't update the output file, but we can detect the rerun
-  # by checking if the deps file was created.
-  if [ ! -e "$glob_deps_file" ]; then
-    fail "Glob deps file missing after second build"
-  fi
-
-  local -r glob_deps_mtime2=$(stat -c "%y" "$glob_deps_file")
-
   if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
     fail "Ninja file rewritten on null incremental build"
   fi
 
   run_soong
   local -r ninja_mtime3=$(stat -c "%y" out/soong/build."${target_product}".ninja)
-  local -r glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
 
   if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
     fail "Ninja file rewritten on null incremental build"
   fi
-
-  # The bpglob commands should not rerun after the first incremental build.
-  if [[ "$glob_deps_mtime2" != "$glob_deps_mtime3" ]]; then
-    fail "Glob deps file rewritten on second null incremental build"
-  fi
 }
 
 function test_add_file_to_glob() {
diff --git a/tests/build_action_caching_test.sh b/tests/build_action_caching_test.sh
new file mode 100755
index 0000000..8ecd037
--- /dev/null
+++ b/tests/build_action_caching_test.sh
@@ -0,0 +1,190 @@
+#!/bin/bash -u
+
+set -o pipefail
+
+# Test that the mk and ninja files generated by Soong don't change if some
+# incremental modules are restored from cache.
+
+OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+
+echo ${OUTPUT_DIR}
+
+function cleanup {
+  rm -rf "${OUTPUT_DIR}"
+}
+trap cleanup EXIT
+
+function run_soong_build {
+  USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode "$@" nothing
+}
+
+function run_soong_clean {
+  build/soong/soong_ui.bash --make-mode clean
+}
+
+function assert_files_equal {
+  if [ $# -ne 2 ]; then
+    echo "Usage: assert_files_equal file1 file2"
+    exit 1
+  fi
+
+  if ! cmp -s "$1" "$2"; then
+    echo "Files are different: $1 $2"
+    exit 1
+  fi
+}
+
+function compare_mtimes() {
+  if [ $# -ne 2 ]; then
+    echo "Usage: compare_mtimes file1 file2"
+    exit 1
+  fi
+
+  file1_mtime=$(stat -c '%Y' $1)
+  file2_mtime=$(stat -c '%Y' $2)
+
+  if [ "$file1_mtime" -eq "$file2_mtime" ]; then
+      return 1
+  else
+      return 0
+  fi
+}
+
+function test_build_action_restoring() {
+  local test_dir="${OUTPUT_DIR}/test_build_action_restoring"
+  mkdir -p ${test_dir}
+  run_soong_clean
+  cat > ${test_dir}/Android.bp <<'EOF'
+python_binary_host {
+  name: "my_little_binary_host",
+  srcs: ["my_little_binary_host.py"],
+}
+EOF
+  touch ${test_dir}/my_little_binary_host.py
+  run_soong_build --incremental-build-actions
+  local dir_before="${test_dir}/before"
+  mkdir -p ${dir_before}
+  cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/before
+  # add a comment to the bp file, this should force a new analysis but no module
+  # should be really impacted, so all the incremental modules should be skipped.
+  cat >> ${test_dir}/Android.bp <<'EOF'
+// new comments
+EOF
+  run_soong_build --incremental-build-actions
+  local dir_after="${test_dir}/after"
+  mkdir -p ${dir_after}
+  cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/after
+
+  compare_incremental_files $dir_before $dir_after
+  rm -rf "$test_dir"
+  echo "test_build_action_restoring test passed"
+}
+
+function test_incremental_build_parity() {
+  local test_dir="${OUTPUT_DIR}/test_incremental_build_parity"
+  run_soong_clean
+  run_soong_build
+  local dir_before="${test_dir}/before"
+  mkdir -p ${dir_before}
+  cp -pr out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/before
+
+  # Now run clean build with incremental enabled
+  run_soong_clean
+  run_soong_build --incremental-build-actions
+  local dir_after="${test_dir}/after"
+  mkdir -p ${dir_after}
+  cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm*.ninja ${test_dir}/after
+
+  compare_files_parity $dir_before $dir_after
+  rm -rf "$test_dir"
+  echo "test_incremental_build_parity test passed"
+}
+
+function compare_files_parity() {
+  local dir_before=$1; shift
+  local dir_after=$1; shift
+  count=0
+  for file_before in ${dir_before}/*.mk; do
+    file_after="${dir_after}/$(basename "$file_before")"
+    assert_files_equal $file_before $file_after
+    ((count++))
+  done
+  echo "Compared $count mk files"
+
+  combined_before_file="${dir_before}/combined_files.ninja"
+  count=0
+  for file in ${dir_before}/build.aosp_arm.*.ninja; do
+    cat $file >> $combined_before_file
+    ((count++))
+  done
+  echo "Combined $count ninja files from normal build"
+
+  combined_after_file="${dir_after}/combined_files.ninja"
+  count=0
+  for file in ${dir_after}/build.aosp_arm.*.ninja; do
+    cat $file >> $combined_after_file
+    ((count++))
+  done
+  echo "Combined $count ninja files from incremental build"
+
+  combined_incremental_ninjas="${dir_after}/combined_incremental_files.ninja"
+  count=0
+  for file in ${dir_after}/build_aosp_arm_ninja_incremental/*.ninja; do
+    cat $file >> $combined_incremental_ninjas
+    ((count++))
+  done
+  echo "Combined $count incremental ninja files"
+
+  cat $combined_incremental_ninjas >> $combined_after_file
+  sort $combined_after_file -o $combined_after_file
+  sort $combined_before_file -o $combined_before_file
+  assert_files_equal $combined_before_file $combined_after_file
+}
+
+function compare_incremental_files() {
+  local dir_before=$1; shift
+  local dir_after=$1; shift
+  count=0
+  for file_before in ${dir_before}/*.ninja; do
+    file_after="${dir_after}/$(basename "$file_before")"
+    assert_files_equal $file_before $file_after
+    compare_mtimes $file_before $file_after
+    if [ $? -ne 0 ]; then
+      echo "Files have identical mtime: $file_before $file_after"
+      exit 1
+    fi
+    ((count++))
+  done
+  echo "Compared $count ninja files"
+
+  count=0
+  for file_before in ${dir_before}/*.mk; do
+    file_after="${dir_after}/$(basename "$file_before")"
+    assert_files_equal $file_before $file_after
+    compare_mtimes $file_before $file_after
+    # mk files shouldn't be regenerated
+    if [ $? -ne 1 ]; then
+      echo "Files have different mtimes: $file_before $file_after"
+      exit 1
+    fi
+    ((count++))
+  done
+  echo "Compared $count mk files"
+
+  count=0
+  for file_before in ${dir_before}/build_aosp_arm_ninja_incremental/*.ninja; do
+    file_after="${dir_after}/build_aosp_arm_ninja_incremental/$(basename "$file_before")"
+    assert_files_equal $file_before $file_after
+    compare_mtimes $file_before $file_after
+    # ninja files of skipped modules shouldn't be regenerated
+    if [ $? -ne 1 ]; then
+      echo "Files have different mtimes: $file_before $file_after"
+      exit 1
+    fi
+    ((count++))
+  done
+  echo "Compared $count incremental ninja files"
+}
+
+test_incremental_build_parity
+test_build_action_restoring
diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go
index ef18131..7a04c19 100644
--- a/tradefed_modules/test_module_config.go
+++ b/tradefed_modules/test_module_config.go
@@ -242,6 +242,7 @@
 
 				entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", m.provider.IsUnitTest)
 				entries.AddCompatibilityTestSuites(m.tradefedProperties.Test_suites...)
+				entries.AddStrings("LOCAL_HOST_REQUIRED_MODULES", m.provider.HostRequiredModuleNames...)
 
 				// The app_prebuilt_internal.mk files try create a copy of the OutputFile as an .apk.
 				// Normally, this copies the "package.apk" from the intermediate directory here.
diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go
index 1510a03..f76a152 100644
--- a/tradefed_modules/test_module_config_test.go
+++ b/tradefed_modules/test_module_config_test.go
@@ -40,6 +40,7 @@
 			name: "base",
 			sdk_version: "current",
                         data: [":HelperApp", "data/testfile"],
+                        host_required: ["other-module"],
                         test_suites: ["general-tests"],
 		}
 
@@ -80,6 +81,7 @@
 	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{})
 
 	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_REQUIRED_MODULES"], []string{"base"})
+	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_HOST_REQUIRED_MODULES"], []string{"other-module"})
 	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_CERTIFICATE"], []string{"build/make/target/product/security/testkey.x509.pem"})
 	android.AssertStringEquals(t, "", entries.Class, "APPS")
 
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index 2bad5a8..2ec8972 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -25,6 +25,8 @@
 	"dalvik/",
 	"developers/",
 	"development/",
+	"device/common/",
+	"device/google_car/",
 	"device/sample/",
 	"frameworks/",
 	// Do not block other directories in kernel/, see b/319658303.
@@ -41,6 +43,15 @@
 	"trusty/",
 	// Add back toolchain/ once defensive Android.mk files are removed
 	//"toolchain/",
+	"vendor/google_contexthub/",
+	"vendor/google_data/",
+	"vendor/google_elmyra/",
+	"vendor/google_mhl/",
+	"vendor/google_pdk/",
+	"vendor/google_testing/",
+	"vendor/partner_testing/",
+	"vendor/partner_tools/",
+	"vendor/pdk/",
 }
 
 func blockAndroidMks(ctx Context, androidMks []string) {
diff --git a/ui/build/build.go b/ui/build/build.go
index 49ac791..28c3284 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -80,7 +80,7 @@
 		if username, ok = config.environ.Get("BUILD_USERNAME"); !ok {
 			ctx.Fatalln("Missing BUILD_USERNAME")
 		}
-		buildNumber = fmt.Sprintf("eng.%.6s.00000000.000000", username)
+		buildNumber = fmt.Sprintf("eng.%.6s", username)
 		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
 	}
 	// Write the build number to a file so it can be read back in
diff --git a/ui/build/config.go b/ui/build/config.go
index 6432348..851a22a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -41,6 +41,7 @@
 const (
 	envConfigDir = "vendor/google/tools/soong_config"
 	jsonSuffix   = "json"
+	abfsSrcDir   = "/src"
 )
 
 var (
@@ -53,6 +54,16 @@
 	rbeRandPrefix = rand.Intn(1000)
 }
 
+// Which builder are we using?
+type ninjaCommandType = int
+
+const (
+	_ = iota
+	NINJA_NINJA
+	NINJA_N2
+	NINJA_SISO
+)
+
 type Config struct{ *configImpl }
 
 type configImpl struct {
@@ -122,9 +133,8 @@
 	// could consider merging them.
 	moduleDebugFile string
 
-	// Whether to use n2 instead of ninja.  This is controlled with the
-	// environment variable SOONG_USE_N2
-	useN2 bool
+	// Which builder are we using
+	ninjaCommand ninjaCommandType
 }
 
 type NinjaWeightListSource uint
@@ -214,6 +224,10 @@
 		sandboxConfig:         &SandboxConfig{},
 		ninjaWeightListSource: DEFAULT,
 	}
+	wd, err := os.Getwd()
+	if err != nil {
+		ctx.Fatalln("Failed to get working directory:", err)
+	}
 
 	// Skip soong tests by default on Linux
 	if runtime.GOOS == "linux" {
@@ -245,17 +259,13 @@
 
 	// Make sure OUT_DIR is set appropriately
 	if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
-		ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
+		ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, filepath.Clean(outDir)))
 	} else {
 		outDir := "out"
 		if baseDir, ok := ret.environ.Get("OUT_DIR_COMMON_BASE"); ok {
-			if wd, err := os.Getwd(); err != nil {
-				ctx.Fatalln("Failed to get working directory:", err)
-			} else {
-				outDir = filepath.Join(baseDir, filepath.Base(wd))
-			}
+			outDir = filepath.Join(baseDir, filepath.Base(wd))
 		}
-		ret.environ.Set("OUT_DIR", outDir)
+		ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, outDir))
 	}
 
 	// loadEnvConfig needs to know what the OUT_DIR is, so it should
@@ -287,8 +297,16 @@
 		ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json"))
 	}
 
-	if os.Getenv("SOONG_USE_N2") == "true" {
-		ret.useN2 = true
+	ret.ninjaCommand = NINJA_NINJA
+	switch os.Getenv("SOONG_NINJA") {
+	case "n2":
+		ret.ninjaCommand = NINJA_N2
+	case "siso":
+		ret.ninjaCommand = NINJA_SISO
+	default:
+		if os.Getenv("SOONG_USE_N2") == "true" {
+			ret.ninjaCommand = NINJA_N2
+		}
 	}
 
 	ret.environ.Unset(
@@ -348,7 +366,8 @@
 		// We read it here already, don't let others share in the fun
 		"GENERATE_SOONG_DEBUG",
 
-		// Use config.useN2 instead.
+		// Use config.ninjaCommand instead.
+		"SOONG_NINJA",
 		"SOONG_USE_N2",
 	)
 
@@ -361,12 +380,12 @@
 	ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
 
 	tmpDir := absPath(ctx, ret.TempDir())
-	ret.environ.Set("TMPDIR", tmpDir)
+	ret.environ.Set("TMPDIR", ret.sandboxPath(wd, tmpDir))
 
 	// Always set ASAN_SYMBOLIZER_PATH so that ASAN-based tools can symbolize any crashes
 	symbolizerPath := filepath.Join("prebuilts/clang/host", ret.HostPrebuiltTag(),
 		"llvm-binutils-stable/llvm-symbolizer")
-	ret.environ.Set("ASAN_SYMBOLIZER_PATH", absPath(ctx, symbolizerPath))
+	ret.environ.Set("ASAN_SYMBOLIZER_PATH", ret.sandboxPath(wd, absPath(ctx, symbolizerPath)))
 
 	// Precondition: the current directory is the top of the source tree
 	checkTopDir(ctx)
@@ -426,9 +445,9 @@
 	}
 
 	ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
-	ret.environ.Set("JAVA_HOME", absJavaHome)
-	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
-	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
+	ret.environ.Set("JAVA_HOME", ret.sandboxPath(wd, absJavaHome))
+	ret.environ.Set("ANDROID_JAVA_HOME", ret.sandboxPath(wd, javaHome))
+	ret.environ.Set("ANDROID_JAVA8_HOME", ret.sandboxPath(wd, java8Home))
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -444,7 +463,7 @@
 		ret.buildDateTime = strconv.FormatInt(time.Now().Unix(), 10)
 	}
 
-	ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
+	ret.environ.Set("BUILD_DATETIME_FILE", ret.sandboxPath(wd, buildDateTimeFile))
 
 	if _, ok := ret.environ.Get("BUILD_USERNAME"); !ok {
 		username := "unknown"
@@ -455,6 +474,7 @@
 		}
 		ret.environ.Set("BUILD_USERNAME", username)
 	}
+	ret.environ.Set("PWD", ret.sandboxPath(wd, wd))
 
 	if ret.UseRBE() {
 		for k, v := range getRBEVars(ctx, Config{ret}) {
@@ -1035,10 +1055,6 @@
 	}
 }
 
-func (c *configImpl) NamedGlobFile(name string) string {
-	return shared.JoinPath(c.SoongOutDir(), "globs-"+name+".ninja")
-}
-
 func (c *configImpl) UsedEnvFile(tag string) string {
 	if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
 		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+c.CoverageSuffix()+"."+tag)
@@ -1296,6 +1312,19 @@
 	return err == nil
 }
 
+func (c *configImpl) sandboxPath(base, in string) string {
+	if !c.UseABFS() {
+		return in
+	}
+
+	rel, err := filepath.Rel(base, in)
+	if err != nil {
+		return in
+	}
+
+	return filepath.Join(abfsSrcDir, rel)
+}
+
 func (c *configImpl) UseRBE() bool {
 	// These alternate modes of running Soong do not use RBE / reclient.
 	if c.Queryview() || c.JsonModuleGraph() {
@@ -1364,8 +1393,10 @@
 	// Perform a log directory cleanup only when the log directory
 	// is auto created by the build rather than user-specified.
 	for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
-		if _, ok := c.environ.Get(f); ok {
-			return false
+		if v, ok := c.environ.Get(f); ok {
+			if v != c.rbeTmpDir() {
+				return false
+			}
 		}
 	}
 	return true
@@ -1630,6 +1661,12 @@
 	return strings.ReplaceAll(path, "/linux-x86/", "/linux_musl-x86/")
 }
 
+func (c *configImpl) SisoBin() string {
+	path := c.PrebuiltBuildTool("siso")
+	// Use musl instead of glibc because glibc on the build server is old and has bugs
+	return strings.ReplaceAll(path, "/linux-x86/", "/linux_musl-x86/")
+}
+
 func (c *configImpl) PrebuiltBuildTool(name string) string {
 	if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
 		if sanitize := strings.Fields(v); inList("address", sanitize) {
@@ -1722,6 +1759,11 @@
 }
 
 func (c *configImpl) SkipMetricsUpload() bool {
+	// b/362625275 - Metrics upload sometimes prevents abfs unmount
+	if c.UseABFS() {
+		return true
+	}
+
 	return c.skipMetricsUpload
 }
 
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 4e3e544..def0783 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -49,14 +49,10 @@
 	nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
 	defer nr.Close()
 
-	executable := config.NinjaBin()
-	args := []string{
-		"-d", "keepdepfile",
-		"-d", "keeprsp",
-		"-d", "stats",
-		"--frontend_file", fifo,
-	}
-	if config.useN2 {
+	var executable string
+	var args []string
+	switch config.ninjaCommand {
+	case NINJA_N2:
 		executable = config.N2Bin()
 		args = []string{
 			"-d", "trace",
@@ -66,8 +62,31 @@
 			//"-d", "stats",
 			"--frontend-file", fifo,
 		}
+	case NINJA_SISO:
+		executable = config.SisoBin()
+		args = []string{
+			"ninja",
+			"--log_dir", config.SoongOutDir(),
+			// TODO: implement these features, or remove them.
+			//"-d", "trace",
+			//"-d", "keepdepfile",
+			//"-d", "keeprsp",
+			//"-d", "stats",
+			//"--frontend-file", fifo,
+		}
+	default:
+		// NINJA_NINJA is the default.
+		executable = config.NinjaBin()
+		args = []string{
+			"-d", "keepdepfile",
+			"-d", "keeprsp",
+			"-d", "stats",
+			"--frontend_file", fifo,
+			"-o", "usesphonyoutputs=yes",
+			"-w", "dupbuild=err",
+			"-w", "missingdepfile=err",
+		}
 	}
-
 	args = append(args, config.NinjaArgs()...)
 
 	var parallel int
@@ -83,17 +102,10 @@
 
 	args = append(args, "-f", config.CombinedNinjaFile())
 
-	if !config.useN2 {
-		args = append(args,
-			"-o", "usesphonyoutputs=yes",
-			"-w", "dupbuild=err",
-			"-w", "missingdepfile=err")
-	}
-
 	if !config.BuildBrokenMissingOutputs() {
 		// Missing outputs will be treated as errors.
 		// BUILD_BROKEN_MISSING_OUTPUTS can be used to bypass this check.
-		if !config.useN2 {
+		if config.ninjaCommand != NINJA_N2 {
 			args = append(args,
 				"-w", "missingoutfile=err",
 			)
@@ -110,21 +122,18 @@
 		cmd.Environment.AppendFromKati(config.KatiEnvFile())
 	}
 
-	switch config.NinjaWeightListSource() {
-	case NINJA_LOG:
-		if !config.useN2 {
+	// TODO(b/346806126): implement this for the other ninjaCommand values.
+	if config.ninjaCommand == NINJA_NINJA {
+		switch config.NinjaWeightListSource() {
+		case NINJA_LOG:
 			cmd.Args = append(cmd.Args, "-o", "usesninjalogasweightlist=yes")
-		}
-	case EVENLY_DISTRIBUTED:
-		// pass empty weight list means ninja considers every tasks's weight as 1(default value).
-		if !config.useN2 {
+		case EVENLY_DISTRIBUTED:
+			// pass empty weight list means ninja considers every tasks's weight as 1(default value).
 			cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
-		}
-	case EXTERNAL_FILE:
-		fallthrough
-	case HINT_FROM_SOONG:
-		// The weight list is already copied/generated.
-		if !config.useN2 {
+		case EXTERNAL_FILE:
+			fallthrough
+		case HINT_FROM_SOONG:
+			// The weight list is already copied/generated.
 			ninjaWeightListPath := filepath.Join(config.OutDir(), ninjaWeightListFileName)
 			cmd.Args = append(cmd.Args, "-o", "usesweightlist="+ninjaWeightListPath)
 		}
@@ -227,6 +236,8 @@
 			// We don't want this build broken flag to cause reanalysis, so allow it through to the
 			// actions.
 			"BUILD_BROKEN_INCORRECT_PARTITION_IMAGES",
+			// Do not do reanalysis just because we changed ninja commands.
+			"SOONG_NINJA",
 			"SOONG_USE_N2",
 			"RUST_BACKTRACE",
 			"RUST_LOG",
@@ -235,8 +246,11 @@
 
 	cmd.Environment.Set("DIST_DIR", config.DistDir())
 	cmd.Environment.Set("SHELL", "/bin/bash")
-	if config.useN2 {
+	switch config.ninjaCommand {
+	case NINJA_N2:
 		cmd.Environment.Set("RUST_BACKTRACE", "1")
+	default:
+		// Only set RUST_BACKTRACE for n2.
 	}
 
 	// Print the environment variables that Ninja is operating in.
diff --git a/ui/build/path.go b/ui/build/path.go
index 51ebff1..cc1d7e9 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -57,6 +57,22 @@
 	return ret
 }
 
+func updatePathForSandbox(config Config) {
+	wd, err := os.Getwd()
+	if err != nil {
+		return
+	}
+
+	var newPath []string
+	if path, ok := config.Environment().Get("PATH"); ok && path != "" {
+		entries := strings.Split(path, string(filepath.ListSeparator))
+		for _, ent := range entries {
+			newPath = append(newPath, config.sandboxPath(wd, ent))
+		}
+	}
+	config.Environment().Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
+}
+
 // SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other
 // places that does not need the full logging capabilities of path_interposer,
 // wants the minimal performance overhead, and still get the benefits of $PATH
@@ -109,18 +125,10 @@
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
-	if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
-		py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
-		if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
-			myPath = py2Path + string(os.PathListSeparator) + myPath
-		}
-	} else if value != "" {
-		ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
-	}
-
 	// Set $PATH to be the directories containing the host tool symlinks, and
 	// the prebuilts directory for the current host OS.
 	config.Environment().Set("PATH", myPath)
+	updatePathForSandbox(config)
 	config.pathReplaced = true
 }
 
@@ -253,17 +261,9 @@
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
-	if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
-		py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
-		if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
-			myPath = py2Path + string(os.PathListSeparator) + myPath
-		}
-	} else if value != "" {
-		ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
-	}
-
 	// Replace the $PATH variable with the path_interposer symlinks, and
 	// checked-in prebuilts.
 	config.Environment().Set("PATH", myPath)
+	updatePathForSandbox(config)
 	config.pathReplaced = true
 }
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index d9ca854..95b71a7 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -50,7 +50,6 @@
 
 const (
 	nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
-	abfsSrcDir = "/src"
 )
 
 var sandboxConfig struct {
@@ -148,20 +147,42 @@
 	return sandboxConfig.working
 }
 
-func (c *Cmd) srcDirArg() string {
-	if !c.config.UseABFS() {
-		return sandboxConfig.srcDir
+// Assumes input path is absolute, clean, and if applicable, an evaluated
+// symlink. If path is not a subdirectory of src dir or relative path
+// cannot be determined, return the input untouched.
+func (c *Cmd) relFromSrcDir(path string) string {
+	if !strings.HasPrefix(path, sandboxConfig.srcDir) {
+		return path
 	}
 
-	return sandboxConfig.srcDir + ":" + abfsSrcDir
+	rel, err := filepath.Rel(sandboxConfig.srcDir, path)
+	if err != nil {
+		return path
+	}
+
+	return rel
+}
+
+func (c *Cmd) dirArg(path string) string {
+	if !c.config.UseABFS() {
+		return path
+	}
+
+	rel := c.relFromSrcDir(path)
+
+	return path + ":" + filepath.Join(abfsSrcDir, rel)
+}
+
+func (c *Cmd) srcDirArg() string {
+	return c.dirArg(sandboxConfig.srcDir)
 }
 
 func (c *Cmd) outDirArg() string {
-	if !c.config.UseABFS() {
-		return sandboxConfig.outDir
-	}
+	return c.dirArg(sandboxConfig.outDir)
+}
 
-	return sandboxConfig.outDir + ":" + filepath.Join(abfsSrcDir, sandboxConfig.outDir)
+func (c *Cmd) distDirArg() string {
+	return c.dirArg(sandboxConfig.distDir)
 }
 
 // When configured to use ABFS, we need to allow the creation of the /src
@@ -187,8 +208,17 @@
 	return args
 }
 
+func (c *Cmd) workDir() string {
+	if !c.config.UseABFS() {
+		wd, _ := os.Getwd()
+		return wd
+	}
+
+	return abfsSrcDir
+}
+
 func (c *Cmd) wrapSandbox() {
-	wd, _ := os.Getwd()
+	wd := c.workDir()
 
 	var sandboxArgs []string
 	sandboxArgs = append(sandboxArgs,
@@ -226,7 +256,7 @@
 	)
 
 	sandboxArgs = append(sandboxArgs,
-		c.readMountArgs()...
+		c.readMountArgs()...,
 	)
 
 	sandboxArgs = append(sandboxArgs,
@@ -264,7 +294,7 @@
 
 	if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
 		//Mount dist dir as read-write if it already exists
-		sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+		sandboxArgs = append(sandboxArgs, "-B", c.distDirArg())
 	}
 
 	if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a9c2cc7..eb51022 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,10 +15,14 @@
 package build
 
 import (
+	"encoding/json"
+	"errors"
 	"fmt"
 	"io/fs"
 	"os"
 	"path/filepath"
+	"runtime"
+	"slices"
 	"strconv"
 	"strings"
 	"sync"
@@ -52,7 +56,7 @@
 
 	// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
 	// version of bootstrap and needs cleaning before continuing the build.  Increment this for
-	// incompatible changes, for example when moving the location of the bpglob binary that is
+	// incompatible changes, for example when moving the location of a microfactory binary that is
 	// executed during bootstrap before the primary builder has had a chance to update the path.
 	bootstrapEpoch = 1
 )
@@ -226,10 +230,6 @@
 
 	var allArgs []string
 	allArgs = append(allArgs, pb.specificArgs...)
-	globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
-	allArgs = append(allArgs,
-		"--globListDir", globPathName,
-		"--globFile", pb.config.NamedGlobFile(globPathName))
 
 	allArgs = append(allArgs, commonArgs...)
 	allArgs = append(allArgs, environmentArgs(pb.config, pb.name)...)
@@ -241,11 +241,8 @@
 	}
 	allArgs = append(allArgs, "Android.bp")
 
-	globfiles := bootstrap.GlobFileListFiles(bootstrap.GlobDirectory(config.SoongOutDir(), globPathName))
-
 	return bootstrap.PrimaryBuilderInvocation{
-		Inputs:      []string{"Android.bp"},
-		Implicits:   globfiles,
+		Implicits:   []string{pb.output + ".glob_results"},
 		Outputs:     []string{pb.output},
 		Args:        allArgs,
 		Description: pb.description,
@@ -277,24 +274,15 @@
 				os.Remove(file)
 			}
 		}
-		for _, globFile := range bootstrapGlobFileList(config) {
-			os.Remove(globFile)
-		}
+		os.Remove(soongNinjaFile + ".globs")
+		os.Remove(soongNinjaFile + ".globs_time")
+		os.Remove(soongNinjaFile + ".glob_results")
 
 		// Mark the tree as up to date with the current epoch by writing the epoch marker file.
 		writeEmptyFile(ctx, epochPath)
 	}
 }
 
-func bootstrapGlobFileList(config Config) []string {
-	return []string{
-		config.NamedGlobFile(getGlobPathName(config)),
-		config.NamedGlobFile(jsonModuleGraphTag),
-		config.NamedGlobFile(queryviewTag),
-		config.NamedGlobFile(soongDocsTag),
-	}
-}
-
 func bootstrapBlueprint(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
 	defer ctx.EndTrace()
@@ -412,32 +400,9 @@
 		runGoTests:  !config.skipSoongTests,
 		// If we want to debug soong_build, we need to compile it for debugging
 		debugCompilation:          delvePort != "",
-		subninjas:                 bootstrapGlobFileList(config),
 		primaryBuilderInvocations: invocations,
 	}
 
-	// The glob ninja files are generated during the main build phase. However, the
-	// primary buildifer invocation depends on all of its glob files, even before
-	// it's been run. Generate a "empty" glob ninja file on the first run,
-	// so that the files can be there to satisfy the dependency.
-	for _, pb := range pbfs {
-		globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
-		globNinjaFile := config.NamedGlobFile(globPathName)
-		if _, err := os.Stat(globNinjaFile); os.IsNotExist(err) {
-			err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
-				GlobLister: func() pathtools.MultipleGlobResults { return nil },
-				GlobFile:   globNinjaFile,
-				GlobDir:    bootstrap.GlobDirectory(config.SoongOutDir(), globPathName),
-				SrcDir:     ".",
-			}, blueprintConfig)
-			if err != nil {
-				ctx.Fatal(err)
-			}
-		} else if err != nil {
-			ctx.Fatal(err)
-		}
-	}
-
 	// since `bootstrap.ninja` is regenerated unconditionally, we ignore the deps, i.e. little
 	// reason to write a `bootstrap.ninja.d` file
 	_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
@@ -615,9 +580,6 @@
 		}
 	}()
 
-	runMicrofactory(ctx, config, "bpglob", "github.com/google/blueprint/bootstrap/bpglob",
-		map[string]string{"github.com/google/blueprint": "build/blueprint"})
-
 	ninja := func(targets ...string) {
 		ctx.BeginTrace(metrics.RunSoong, "bootstrap")
 		defer ctx.EndTrace()
@@ -626,19 +588,11 @@
 		nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
 		defer nr.Close()
 
-		ninjaArgs := []string{
-			"-d", "keepdepfile",
-			"-d", "stats",
-			"-o", "usesphonyoutputs=yes",
-			"-o", "preremoveoutputs=yes",
-			"-w", "dupbuild=err",
-			"-w", "outputdir=err",
-			"-w", "missingoutfile=err",
-			"-j", strconv.Itoa(config.Parallel()),
-			"--frontend_file", fifo,
-			"-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
-		}
-		if config.useN2 {
+		var ninjaCmd string
+		var ninjaArgs []string
+		switch config.ninjaCommand {
+		case NINJA_N2:
+			ninjaCmd = config.N2Bin()
 			ninjaArgs = []string{
 				// TODO: implement these features, or remove them.
 				//"-d", "keepdepfile",
@@ -653,6 +607,39 @@
 				"--frontend-file", fifo,
 				"-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
 			}
+		case NINJA_SISO:
+			ninjaCmd = config.SisoBin()
+			ninjaArgs = []string{
+				"ninja",
+				// TODO: implement these features, or remove them.
+				//"-d", "keepdepfile",
+				//"-d", "stats",
+				//"-o", "usesphonyoutputs=yes",
+				//"-o", "preremoveoutputs=yes",
+				//"-w", "dupbuild=err",
+				//"-w", "outputdir=err",
+				//"-w", "missingoutfile=err",
+				"-v",
+				"-j", strconv.Itoa(config.Parallel()),
+				//"--frontend-file", fifo,
+				"--log_dir", config.SoongOutDir(),
+				"-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
+			}
+		default:
+			// NINJA_NINJA is the default.
+			ninjaCmd = config.NinjaBin()
+			ninjaArgs = []string{
+				"-d", "keepdepfile",
+				"-d", "stats",
+				"-o", "usesphonyoutputs=yes",
+				"-o", "preremoveoutputs=yes",
+				"-w", "dupbuild=err",
+				"-w", "outputdir=err",
+				"-w", "missingoutfile=err",
+				"-j", strconv.Itoa(config.Parallel()),
+				"--frontend_file", fifo,
+				"-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
+			}
 		}
 
 		if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok {
@@ -661,10 +648,6 @@
 		}
 
 		ninjaArgs = append(ninjaArgs, targets...)
-		ninjaCmd := config.NinjaBin()
-		if config.useN2 {
-			ninjaCmd = config.N2Bin()
-		}
 
 		cmd := Command(ctx, config, "soong bootstrap",
 			ninjaCmd, ninjaArgs...)
@@ -699,6 +682,12 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
+	for _, target := range targets {
+		if err := checkGlobs(ctx, target); err != nil {
+			ctx.Fatalf("Error checking globs: %s", err.Error())
+		}
+	}
+
 	beforeSoongTimestamp := time.Now()
 
 	ninja(targets...)
@@ -725,6 +714,160 @@
 	}
 }
 
+// checkGlobs manages the globs that cause soong to rerun.
+//
+// When soong_build runs, it will run globs. It will write all the globs
+// it ran into the "{finalOutFile}.globs" file. Then every build,
+// soong_ui will check that file, rerun the globs, and if they changed
+// from the results that soong_build got, update the ".glob_results"
+// file, causing soong_build to rerun. The ".glob_results" file will
+// be empty on the first run of soong_build, because we don't know
+// what the globs are yet, but also remain empty until the globs change
+// so that we don't run soong_build a second time unnecessarily.
+// Both soong_build and soong_ui will also update a ".globs_time" file
+// with the time that they ran at every build. When soong_ui checks
+// globs, it only reruns globs whose dependencies are newer than the
+// time in the ".globs_time" file.
+func checkGlobs(ctx Context, finalOutFile string) error {
+	ctx.BeginTrace(metrics.RunSoong, "check_globs")
+	defer ctx.EndTrace()
+	st := ctx.Status.StartTool()
+	st.Status("Running globs...")
+	defer st.Finish()
+
+	globsFile, err := os.Open(finalOutFile + ".globs")
+	if errors.Is(err, fs.ErrNotExist) {
+		// if the glob file doesn't exist, make sure the glob_results file exists and is empty.
+		if err := os.MkdirAll(filepath.Dir(finalOutFile), 0777); err != nil {
+			return err
+		}
+		f, err := os.Create(finalOutFile + ".glob_results")
+		if err != nil {
+			return err
+		}
+		return f.Close()
+	} else if err != nil {
+		return err
+	}
+	defer globsFile.Close()
+	globsFileDecoder := json.NewDecoder(globsFile)
+
+	globsTimeBytes, err := os.ReadFile(finalOutFile + ".globs_time")
+	if err != nil {
+		return err
+	}
+	globsTimeMicros, err := strconv.ParseInt(strings.TrimSpace(string(globsTimeBytes)), 10, 64)
+	if err != nil {
+		return err
+	}
+	globCheckStartTime := time.Now().UnixMicro()
+
+	globsChan := make(chan pathtools.GlobResult)
+	errorsChan := make(chan error)
+	wg := sync.WaitGroup{}
+	hasChangedGlobs := false
+	for i := 0; i < runtime.NumCPU()*2; i++ {
+		wg.Add(1)
+		go func() {
+			for cachedGlob := range globsChan {
+				// If we've already determined we have changed globs, just finish consuming
+				// the channel without doing any more checks.
+				if hasChangedGlobs {
+					continue
+				}
+				// First, check if any of the deps are newer than the last time globs were checked.
+				// If not, we don't need to rerun the glob.
+				hasNewDep := false
+				for _, dep := range cachedGlob.Deps {
+					info, err := os.Stat(dep)
+					if errors.Is(err, fs.ErrNotExist) {
+						hasNewDep = true
+						break
+					} else if err != nil {
+						errorsChan <- err
+						continue
+					}
+					if info.ModTime().UnixMicro() > globsTimeMicros {
+						hasNewDep = true
+						break
+					}
+				}
+				if !hasNewDep {
+					continue
+				}
+
+				// Then rerun the glob and check if we got the same result as before.
+				result, err := pathtools.Glob(cachedGlob.Pattern, cachedGlob.Excludes, pathtools.FollowSymlinks)
+				if err != nil {
+					errorsChan <- err
+				} else {
+					if !slices.Equal(result.Matches, cachedGlob.Matches) {
+						hasChangedGlobs = true
+					}
+				}
+			}
+			wg.Done()
+		}()
+	}
+	go func() {
+		wg.Wait()
+		close(errorsChan)
+	}()
+
+	errorsWg := sync.WaitGroup{}
+	errorsWg.Add(1)
+	var errFromGoRoutines error
+	go func() {
+		for result := range errorsChan {
+			if errFromGoRoutines == nil {
+				errFromGoRoutines = result
+			}
+		}
+		errorsWg.Done()
+	}()
+
+	var cachedGlob pathtools.GlobResult
+	for globsFileDecoder.More() {
+		if err := globsFileDecoder.Decode(&cachedGlob); err != nil {
+			return err
+		}
+		// Need to clone the GlobResult because the json decoder will
+		// reuse the same slice allocations.
+		globsChan <- cachedGlob.Clone()
+	}
+	close(globsChan)
+	errorsWg.Wait()
+	if errFromGoRoutines != nil {
+		return errFromGoRoutines
+	}
+
+	// Update the globs_time file whether or not we found changed globs,
+	// so that we don't rerun globs in the future that we just saw didn't change.
+	err = os.WriteFile(
+		finalOutFile+".globs_time",
+		[]byte(fmt.Sprintf("%d\n", globCheckStartTime)),
+		0666,
+	)
+	if err != nil {
+		return err
+	}
+
+	if hasChangedGlobs {
+		fmt.Fprintf(os.Stdout, "Globs changed, rerunning soong...\n")
+		// Write the current time to the glob_results file. We just need
+		// some unique value to trigger a rerun, it doesn't matter what it is.
+		err = os.WriteFile(
+			finalOutFile+".glob_results",
+			[]byte(fmt.Sprintf("%d\n", globCheckStartTime)),
+			0666,
+		)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // loadSoongBuildMetrics reads out/soong_build_metrics.pb if it was generated by soong_build and copies the
 // events stored in it into the soong_ui trace to provide introspection into how long the different phases of
 // soong_build are taking.
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 3faa94d..ba53119 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -79,9 +79,6 @@
 	// out/build_date.txt is considered a "source file"
 	buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt")
 
-	// bpglob is built explicitly using Microfactory
-	bpglob := filepath.Join(config.SoongOutDir(), "bpglob")
-
 	// release-config files are generated from the initial lunch or Kati phase
 	// before running soong and ninja.
 	releaseConfigDir := filepath.Join(outDir, "soong", "release-config")
@@ -105,7 +102,6 @@
 			line == extraVariablesFilePath ||
 			line == dexpreoptConfigFilePath ||
 			line == buildDatetimeFilePath ||
-			line == bpglob ||
 			strings.HasPrefix(line, releaseConfigDir) ||
 			buildFingerPrintFilePattern.MatchString(line) {
 			// Leaf node is in one of Soong's bootstrap directories, which do not have
diff --git a/zip/cmd/Android.bp b/zip/cmd/Android.bp
index 43bf232..16c3f69 100644
--- a/zip/cmd/Android.bp
+++ b/zip/cmd/Android.bp
@@ -24,4 +24,6 @@
     srcs: [
         "main.go",
     ],
+    // Used by genrules
+    visibility: ["//visibility:public"],
 }