Merge "[Sim] Add device paths for ART simulator" into main
diff --git a/Android.bp b/Android.bp
index 337545b..7134591 100644
--- a/Android.bp
+++ b/Android.bp
@@ -176,6 +176,12 @@
     footer_files: [
         ":applied_backported_fixes",
     ],
+    dist: {
+        targets: [
+            "droidcore-unbundled",
+            "sdk",
+        ],
+    },
     // Currently, only microdroid, Ravenwood, and cf system image can refer to system-build.prop
     visibility: [
         "//build/soong/fsgen",
@@ -191,6 +197,10 @@
     system_ext_specific: true,
     product_config: ":product_config",
     relative_install_path: "etc", // system_ext/etc/build.prop
+    dist: {
+        targets: ["droidcore-unbundled"],
+        dest: "build.prop-system_ext",
+    },
     visibility: [
         "//build/make/target/product/gsi",
         "//build/soong/fsgen",
@@ -203,6 +213,10 @@
     product_specific: true,
     product_config: ":product_config",
     relative_install_path: "etc", // product/etc/build.prop
+    dist: {
+        targets: ["droidcore-unbundled"],
+        dest: "build.prop-product",
+    },
     visibility: [
         "//build/make/target/product/gsi",
         "//build/soong/fsgen",
@@ -215,6 +229,10 @@
     device_specific: true,
     product_config: ":product_config",
     relative_install_path: "etc", // odm/etc/build.prop
+    dist: {
+        targets: ["droidcore-unbundled"],
+        dest: "build.prop-odm",
+    },
     visibility: ["//build/soong/fsgen"],
 }
 
@@ -251,6 +269,10 @@
     ramdisk: true,
     product_config: ":product_config",
     relative_install_path: "etc/ramdisk", // ramdisk/system/etc/ramdisk/build.prop
+    dist: {
+        targets: ["droidcore-unbundled"],
+        dest: "build.prop-ramdisk",
+    },
     visibility: ["//visibility:private"],
 }
 
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 9a9e568..b068398 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -47,7 +47,7 @@
 		// are from RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS.
 		ReleaseConfigValues []AconfigReleaseConfigValue
 
-		// Container(system/vendor/apex) that this module belongs to
+		// Container(system/system_ext/vendor/apex) that this module belongs to
 		Container string
 
 		// The flags will only be repackaged if this prop is true.
@@ -88,13 +88,6 @@
 		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.
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 3d07e16..f3c68c3 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -95,11 +95,44 @@
 	})
 }
 
+func GenerateExportedFlagCheck(ctx android.ModuleContext, outputPath android.WritablePath,
+	parsedFlagsFile android.Path, apiSurface ApiSurfaceContributorProperties) {
+
+	apiSignatureFiles := android.Paths{}
+	for _, apiSignatureFile := range apiSurface.Api_signature_files.GetOrDefault(ctx, nil) {
+		if path := android.PathForModuleSrc(ctx, apiSignatureFile); path != nil {
+			apiSignatureFiles = append(apiSignatureFiles, path)
+		}
+	}
+	finalizedFlagsFile := android.PathForModuleSrc(ctx, apiSurface.Finalized_flags_file)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   ExportedFlagCheckRule,
+		Inputs: append(apiSignatureFiles, finalizedFlagsFile, parsedFlagsFile),
+		Output: outputPath,
+		Args: map[string]string{
+			"api_signature_files":  android.JoinPathsWithPrefix(apiSignatureFiles, "--api-signature-file "),
+			"finalized_flags_file": "--finalized-flags-file " + finalizedFlagsFile.String(),
+			"parsed_flags_file":    "--parsed-flags-file " + parsedFlagsFile.String(),
+		},
+	})
+}
+
 func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	parsedFlagsFile := android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
 	this.finalizedFlags = android.PathForIntermediates(ctx, "finalized-flags.txt")
 	GenerateFinalizedFlagsForApiSurface(ctx, this.finalizedFlags, parsedFlagsFile, this.properties)
-	ctx.Phony("all_aconfig_declarations", this.finalizedFlags)
+
+	depsFiles := android.Paths{this.finalizedFlags}
+	if checkExportedFlag, ok := ctx.Config().GetBuildFlag("RELEASE_EXPORTED_FLAG_CHECK"); ok {
+		if checkExportedFlag == "true" {
+			invalidExportedFlags := android.PathForIntermediates(ctx, "invalid_exported_flags.txt")
+			GenerateExportedFlagCheck(ctx, invalidExportedFlags, parsedFlagsFile, this.properties)
+			depsFiles = append(depsFiles, invalidExportedFlags)
+		}
+	}
+
+	ctx.Phony("all_aconfig_declarations", depsFiles...)
 
 	android.SetProvider(ctx, allAconfigDeclarationsInfoProvider, allAconfigDeclarationsInfo{
 		parsedFlagsFile: parsedFlagsFile,
@@ -111,7 +144,7 @@
 		// Find all of the aconfig_declarations modules
 		var packages = make(map[string]int)
 		var cacheFiles android.Paths
-		ctx.VisitAllModules(func(module android.Module) {
+		ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 			decl, ok := android.OtherModuleProvider(ctx, module, android.AconfigReleaseDeclarationsProviderKey)
 			if !ok {
 				return
diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go
index e375d9c..3a06e72 100644
--- a/aconfig/build_flags/build_flags_singleton.go
+++ b/aconfig/build_flags/build_flags_singleton.go
@@ -15,8 +15,9 @@
 package build_flags
 
 import (
-	"android/soong/android"
 	"fmt"
+
+	"android/soong/android"
 )
 
 // A singleton module that collects all of the build flags declared in the
@@ -42,7 +43,7 @@
 	var flagsFiles android.Paths
 	// Find all of the release_config_contribution modules
 	var contributionDirs android.Paths
-	ctx.VisitAllModules(func(module android.Module) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 		decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
 		if ok {
 			flagsFiles = append(flagsFiles, decl.IntermediateCacheOutputPath)
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
index 8854369..b9455f7 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: "vendor",
+				container: "system_ext",
 				srcs: ["bar.aconfig"],
 			}
 
diff --git a/aconfig/exported_java_aconfig_library.go b/aconfig/exported_java_aconfig_library.go
index 63d824a..ffb2a0c 100644
--- a/aconfig/exported_java_aconfig_library.go
+++ b/aconfig/exported_java_aconfig_library.go
@@ -15,8 +15,9 @@
 package aconfig
 
 import (
-	"android/soong/android"
 	"strconv"
+
+	"android/soong/android"
 )
 
 func ExportedJavaDeclarationsLibraryFactory() android.Singleton {
@@ -30,7 +31,7 @@
 func (this *exportedJavaDeclarationsLibrarySingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	// Find all of the aconfig_declarations modules
 	var cacheFiles android.Paths
-	ctx.VisitAllModules(func(module android.Module) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 		decl, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
 		if !ok {
 			return
diff --git a/aconfig/init.go b/aconfig/init.go
index b2fe5a3..d8d5470 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -77,6 +77,13 @@
 				"${record-finalized-flags}",
 			},
 		}, "api_signature_files", "finalized_flags_file", "parsed_flags_file")
+	ExportedFlagCheckRule = pctx.AndroidStaticRule("ExportedFlagCheckRule",
+		blueprint.RuleParams{
+			Command: `${exported-flag-check} ${parsed_flags_file} ${finalized_flags_file} ${api_signature_files} > ${out}`,
+			CommandDeps: []string{
+				"${exported-flag-check}",
+			},
+		}, "api_signature_files", "finalized_flags_file", "parsed_flags_file")
 
 	CreateStorageRule = pctx.AndroidStaticRule("aconfig_create_storage",
 		blueprint.RuleParams{
@@ -124,6 +131,7 @@
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
 	pctx.HostBinToolVariable("record-finalized-flags", "record-finalized-flags")
+	pctx.HostBinToolVariable("exported-flag-check", "exported-flag-check")
 }
 
 func RegisterBuildComponents(ctx android.RegistrationContext) {
diff --git a/android/Android.bp b/android/Android.bp
index 1cc7ffe..4b75148 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -97,6 +97,7 @@
         "product_packages_file.go",
         "proto.go",
         "provider.go",
+        "provider_keys.go",
         "raw_files.go",
         "recovery_build_prop.go",
         "register.go",
@@ -170,3 +171,7 @@
     // Used by plugins
     visibility: ["//visibility:public"],
 }
+
+otatools_package_filegroup {
+    name: "otatools_package_filegroup",
+}
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index 205b855..bb73f0b 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -238,8 +238,7 @@
 	} else if base.ProductSpecific() {
 		container = "product"
 	} else if base.SystemExtSpecific() {
-		// system_ext and system partitions should be treated as one container
-		container = "system"
+		container = "system_ext"
 	}
 
 	return container
@@ -249,14 +248,13 @@
 // Please only access the module's internal data through providers.
 func getContainerUsingProviders(ctx OtherModuleProviderContext, m Module) string {
 	container := "system"
-	commonInfo, _ := OtherModuleProvider(ctx, m, CommonModuleInfoKey)
+	commonInfo := OtherModulePointerProviderOrDefault(ctx, m, CommonModuleInfoProvider)
 	if commonInfo.Vendor || commonInfo.Proprietary || commonInfo.SocSpecific {
 		container = "vendor"
 	} else if commonInfo.ProductSpecific {
 		container = "product"
 	} else if commonInfo.SystemExtSpecific {
-		// system_ext and system partitions should be treated as one container
-		container = "system"
+		container = "system_ext"
 	}
 
 	return container
diff --git a/android/all_teams.go b/android/all_teams.go
index 3b20107..18a050f 100644
--- a/android/all_teams.go
+++ b/android/all_teams.go
@@ -78,19 +78,19 @@
 	t.teams = make(map[string]teamProperties)
 	t.teams_for_mods = make(map[string]moduleTeamAndTestInfo)
 
-	ctx.VisitAllModules(func(module Module) {
+	ctx.VisitAllModuleProxies(func(module ModuleProxy) {
 		bpFile := ctx.BlueprintFile(module)
 
 		// Package Modules and Team Modules are stored in a map so we can look them up by name for
 		// modules without a team.
-		if pack, ok := module.(*packageModule); ok {
+		if pack, ok := OtherModuleProvider(ctx, module, PackageInfoProvider); ok {
 			// Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context.
 			pkgKey := bpFile
-			t.packages[pkgKey] = pack.properties
+			t.packages[pkgKey] = pack.Properties
 			return
 		}
-		if team, ok := module.(*teamModule); ok {
-			t.teams[team.Name()] = team.properties
+		if team, ok := OtherModuleProvider(ctx, module, TeamInfoProvider); ok {
+			t.teams[module.Name()] = team.Properties
 			return
 		}
 
@@ -116,7 +116,7 @@
 			testOnly:           testModInfo.TestOnly,
 			topLevelTestTarget: testModInfo.TopLevelTarget,
 			kind:               ctx.ModuleType(module),
-			teamName:           module.base().Team(),
+			teamName:           OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).Team,
 		}
 		t.teams_for_mods[module.Name()] = entry
 
diff --git a/android/androidmk.go b/android/androidmk.go
index 5cb5a66..7845593 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -78,6 +78,12 @@
 	Entries AndroidMkEntries
 }
 
+type AndroidMkDataInfo struct {
+	Class string
+}
+
+var AndroidMkDataInfoProvider = blueprint.NewProvider[AndroidMkDataInfo]()
+
 type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
 
 // Interface for modules to declare their Android.mk outputs. Note that every module needs to
@@ -349,30 +355,15 @@
 	return
 }
 
-// Compute the contributions that the module makes to the dist.
-func (a *AndroidMkEntries) getDistContributions(mod Module) *distContributions {
+// This gets the dist contributuions from the given module that were specified in the Android.bp
+// file using the dist: property. It does not include contribututions that the module's
+// implementation may have defined with ctx.DistForGoals(), for that, see DistProvider.
+func getDistContributions(ctx ConfigAndOtherModuleProviderContext, mod Module) *distContributions {
 	amod := mod.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
-
-	// If no paths have been provided for the DefaultDistTag and the output file is
-	// valid then add that as the default dist path.
-	if a.OutputFile.Valid() {
-		availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
-	}
-
-	info := OtherModuleProviderOrDefault(a.entryContext, 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)
+	info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
+	availableTaggedDists := info.DistFiles
 
 	if len(availableTaggedDists) == 0 {
 		// Nothing dist-able for this module.
@@ -446,7 +437,7 @@
 
 			productString := ""
 			if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product {
-				productString = fmt.Sprintf("_%s", a.entryContext.Config().DeviceProduct())
+				productString = fmt.Sprintf("_%s", ctx.Config().DeviceProduct())
 			}
 
 			if suffix != "" || productString != "" {
@@ -494,7 +485,7 @@
 // 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 *AndroidMkEntries) GetDistForGoals(mod Module) []string {
-	distContributions := a.getDistContributions(mod)
+	distContributions := getDistContributions(a.entryContext, mod)
 	if distContributions == nil {
 		return nil
 	}
@@ -537,6 +528,14 @@
 
 	fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))
 
+	// Add the TestSuites from the provider to LOCAL_SOONG_PROVIDER_TEST_SUITES.
+	// LOCAL_SOONG_PROVIDER_TEST_SUITES will be compared against LOCAL_COMPATIBILITY_SUITES
+	// in make and enforced they're the same, to ensure we've successfully translated all
+	// LOCAL_COMPATIBILITY_SUITES usages to the provider.
+	if testSuiteInfo, ok := OtherModuleProvider(ctx, mod, TestSuiteInfoProvider); ok {
+		a.AddStrings("LOCAL_SOONG_PROVIDER_TEST_SUITES", testSuiteInfo.TestSuites...)
+	}
+
 	// Collect make variable assignment entries.
 	a.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
 	a.SetString("LOCAL_MODULE", name+a.SubName)
@@ -889,32 +888,23 @@
 			}
 		}
 
-		commonInfo, _ := OtherModuleProvider(ctx, mod, CommonModuleInfoKey)
+		commonInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider)
 		if commonInfo.SkipAndroidMkProcessing {
 			continue
 		}
 		if info, ok := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok {
 			// Deep copy the provider info since we need to modify the info later
 			info := deepCopyAndroidMkProviderInfo(info)
-			info.PrimaryInfo.fillInEntries(ctx, mod, &commonInfo)
+			info.PrimaryInfo.fillInEntries(ctx, mod, commonInfo)
 			if info.PrimaryInfo.disabled() {
 				continue
 			}
 			if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
 				moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
 			}
-			if contribution := info.PrimaryInfo.getDistContributions(ctx, mod, &commonInfo); contribution != nil {
+			if contribution := getDistContributions(ctx, mod); contribution != nil {
 				allDistContributions = append(allDistContributions, *contribution)
 			}
-			for _, ei := range info.ExtraInfo {
-				ei.fillInEntries(ctx, mod, &commonInfo)
-				if ei.disabled() {
-					continue
-				}
-				if contribution := ei.getDistContributions(ctx, mod, &commonInfo); contribution != nil {
-					allDistContributions = append(allDistContributions, *contribution)
-				}
-			}
 		} else {
 			if x, ok := mod.(AndroidMkDataProvider); ok {
 				data := x.AndroidMk()
@@ -930,7 +920,7 @@
 				if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
 					moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
 				}
-				if contribution := data.Entries.getDistContributions(mod); contribution != nil {
+				if contribution := getDistContributions(ctx, mod); contribution != nil {
 					allDistContributions = append(allDistContributions, *contribution)
 				}
 			}
@@ -944,7 +934,7 @@
 					if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
 						moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
 					}
-					if contribution := entries.getDistContributions(mod); contribution != nil {
+					if contribution := getDistContributions(ctx, mod); contribution != nil {
 						allDistContributions = append(allDistContributions, *contribution)
 					}
 				}
@@ -1330,7 +1320,7 @@
 // Please only access the module's internal data through providers.
 func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
 	mod Module, providerInfo *AndroidMkProviderInfo) error {
-	commonInfo, _ := OtherModuleProvider(ctx, mod, CommonModuleInfoKey)
+	commonInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider)
 	if commonInfo.SkipAndroidMkProcessing {
 		return nil
 	}
@@ -1341,11 +1331,11 @@
 	aconfigUpdateAndroidMkInfos(ctx, mod, &info)
 
 	// Any new or special cases here need review to verify correct propagation of license information.
-	info.PrimaryInfo.fillInEntries(ctx, mod, &commonInfo)
+	info.PrimaryInfo.fillInEntries(ctx, mod, commonInfo)
 	info.PrimaryInfo.write(w)
 	if len(info.ExtraInfo) > 0 {
 		for _, ei := range info.ExtraInfo {
-			ei.fillInEntries(ctx, mod, &commonInfo)
+			ei.fillInEntries(ctx, mod, commonInfo)
 			ei.write(w)
 		}
 	}
@@ -1494,12 +1484,17 @@
 	a.Host_required = append(a.Host_required, commonInfo.HostRequiredModuleNames...)
 	a.Target_required = append(a.Target_required, commonInfo.TargetRequiredModuleNames...)
 
-	for _, distString := range a.GetDistForGoals(ctx, mod, commonInfo) {
-		a.HeaderStrings = append(a.HeaderStrings, distString)
-	}
-
+	a.HeaderStrings = append(a.HeaderStrings, a.GetDistForGoals(ctx, mod, commonInfo)...)
 	a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s", ctx.ModuleType(mod), commonInfo.BaseModuleName, ctx.ModuleSubDir(mod)))
 
+	// Add the TestSuites from the provider to LOCAL_SOONG_PROVIDER_TEST_SUITES.
+	// LOCAL_SOONG_PROVIDER_TEST_SUITES will be compared against LOCAL_COMPATIBILITY_SUITES
+	// in make and enforced they're the same, to ensure we've successfully translated all
+	// LOCAL_COMPATIBILITY_SUITES usages to the provider.
+	if testSuiteInfo, ok := OtherModuleProvider(ctx, mod, TestSuiteInfoProvider); ok {
+		helperInfo.AddStrings("LOCAL_SOONG_PROVIDER_TEST_SUITES", testSuiteInfo.TestSuites...)
+	}
+
 	// Collect make variable assignment entries.
 	helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
 	helperInfo.SetString("LOCAL_MODULE", name+a.SubName)
@@ -1653,7 +1648,7 @@
 // TODO(b/397766191): Change the signature to take ModuleProxy
 // Please only access the module's internal data through providers.
 func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod Module, commonInfo *CommonModuleInfo) []string {
-	distContributions := a.getDistContributions(ctx, mod, commonInfo)
+	distContributions := getDistContributions(ctx, mod)
 	if distContributions == nil {
 		return nil
 	}
@@ -1661,127 +1656,6 @@
 	return generateDistContributionsForMake(distContributions)
 }
 
-// Compute the contributions that the module makes to the dist.
-// TODO(b/397766191): Change the signature to take ModuleProxy
-// Please only access the module's internal data through providers.
-func (a *AndroidMkInfo) getDistContributions(ctx fillInEntriesContext, mod Module,
-	commonInfo *CommonModuleInfo) *distContributions {
-	name := commonInfo.BaseModuleName
-
-	// Collate the set of associated tag/paths available for copying to the dist.
-	// Start with an empty (nil) set.
-	var availableTaggedDists TaggedDistFiles
-
-	// If no paths have been provided for the DefaultDistTag and the output file is
-	// valid then add that as the default dist path.
-	if 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 !commonInfo.ExemptFromRequiredApplicableLicensesProperty {
-		distContributions.licenseMetadataFile = info.LicenseMetadataFile
-	}
-
-	// Iterate over this module's dist structs, merged from the dist and dists properties.
-	for _, dist := range commonInfo.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),
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index 4cdd6a3..cd61133 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -346,7 +346,7 @@
 			if len(entries) != 1 {
 				t.Errorf("Expected a single AndroidMk entry, got %d", len(entries))
 			}
-			distContributions := entries[0].getDistContributions(module)
+			distContributions := getDistContributions(ctx, module)
 
 			if err := compareContributions(expectedContributions, distContributions); err != nil {
 				t.Errorf("%s\nExpected Contributions\n%sActualContributions\n%s",
@@ -648,8 +648,8 @@
 				default_dist_files: "none",
 				dist_output_file: false,
 				dists: [
-					// The following is silently ignored because there is not default file
-					// in either the dist files or the output file.
+					// The following will dist one.out because there's no default dist file provided
+					// (default_dist_files: "none") and one.out is the outputfile for the "" tag.
 					{
 						targets: ["my_goal"],
 					},
@@ -664,6 +664,12 @@
 			{
 				goals: "my_goal",
 				copies: []distCopy{
+					distCopyForTest("one.out", "one.out"),
+				},
+			},
+			{
+				goals: "my_goal",
+				copies: []distCopy{
 					distCopyForTest("two.out", "two.out"),
 					distCopyForTest("three/four.out", "four.out"),
 				},
diff --git a/android/apex.go b/android/apex.go
index 91fa2c7..57baff5 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -196,7 +196,7 @@
 		return false
 	}
 
-	if !ctx.EqualModules(ctx.Module(), module) {
+	if !EqualModules(ctx.Module(), module) {
 		if moduleInfo, ok := OtherModuleProvider(ctx, module, DepInSameApexInfoProvider); ok {
 			if !moduleInfo.Checker.OutgoingDepIsInSameApex(depTag) {
 				return false
@@ -646,6 +646,13 @@
 	FullListPath() Path
 }
 
+type ApexBundleDepsData struct {
+	Updatable    bool
+	FlatListPath Path
+}
+
+var ApexBundleDepsDataProvider = blueprint.NewProvider[ApexBundleDepsData]()
+
 func (d *ApexBundleDepsInfo) FlatListPath() Path {
 	return d.flatListPath
 }
@@ -688,7 +695,7 @@
 // Function called while walking an APEX's payload dependencies.
 //
 // Return true if the `to` module should be visited, false otherwise.
-type PayloadDepsCallback func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool
+type PayloadDepsCallback func(ctx BaseModuleContext, from, to ModuleProxy, externalDep bool) bool
 type WalkPayloadDepsFunc func(ctx BaseModuleContext, do PayloadDepsCallback)
 
 // ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
@@ -716,7 +723,7 @@
 		return
 	}
 
-	walk(ctx, func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool {
+	walk(ctx, func(ctx BaseModuleContext, from, to ModuleProxy, externalDep bool) bool {
 		if externalDep {
 			// external deps are outside the payload boundary, which is "stable"
 			// interface. We don't have to check min_sdk_version for external
@@ -726,7 +733,7 @@
 		if !IsDepInSameApex(ctx, from, to) {
 			return false
 		}
-		if info, ok := OtherModuleProvider(ctx, to, CommonModuleInfoKey); ok && info.ModuleWithMinSdkVersionCheck {
+		if info, ok := OtherModuleProvider(ctx, to, CommonModuleInfoProvider); ok && info.ModuleWithMinSdkVersionCheck {
 			if info.MinSdkVersion.ApiLevel == nil || !info.MinSdkVersion.ApiLevel.Specified() {
 				// This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version
 				// to trigger the check.
@@ -758,7 +765,7 @@
 // implementing this interface should provide an implementation. A module supports an sdk
 // version when the module's min_sdk_version is equal to or less than the given sdk version.
 func ShouldSupportSdkVersion(ctx BaseModuleContext, module Module, sdkVersion ApiLevel) error {
-	info, ok := OtherModuleProvider(ctx, module, CommonModuleInfoKey)
+	info, ok := OtherModuleProvider(ctx, module, CommonModuleInfoProvider)
 	if !ok || info.MinSdkVersionSupported.IsNone() {
 		return fmt.Errorf("min_sdk_version is not specified")
 	}
diff --git a/android/api_levels.go b/android/api_levels.go
index c042eeb..c83fae8 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -19,6 +19,8 @@
 	"fmt"
 	"strconv"
 	"strings"
+
+	"github.com/google/blueprint/gobtools"
 )
 
 func init() {
@@ -52,6 +54,34 @@
 	isPreview bool
 }
 
+type apiLevelGob struct {
+	Value     string
+	Number    int
+	IsPreview bool
+}
+
+func (a *ApiLevel) ToGob() *apiLevelGob {
+	return &apiLevelGob{
+		Value:     a.value,
+		Number:    a.number,
+		IsPreview: a.isPreview,
+	}
+}
+
+func (a *ApiLevel) FromGob(data *apiLevelGob) {
+	a.value = data.Value
+	a.number = data.Number
+	a.isPreview = data.IsPreview
+}
+
+func (a ApiLevel) GobEncode() ([]byte, error) {
+	return gobtools.CustomGobEncode[apiLevelGob](&a)
+}
+
+func (a *ApiLevel) GobDecode(data []byte) error {
+	return gobtools.CustomGobDecode[apiLevelGob](data, a)
+}
+
 func (this ApiLevel) FinalInt() int {
 	if this.IsInvalid() {
 		panic(fmt.Errorf("%v is not a recognized api_level\n", this))
diff --git a/android/arch.go b/android/arch.go
index 3cd6e4b..d6b2971 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1553,7 +1553,7 @@
 	config.BuildOS = func() OsType {
 		switch runtime.GOOS {
 		case "linux":
-			if Bool(config.productVariables.HostMusl) {
+			if Bool(config.productVariables.HostMusl) || runtime.GOARCH == "arm64" {
 				return LinuxMusl
 			}
 			return Linux
@@ -1565,11 +1565,25 @@
 	}()
 
 	config.BuildArch = func() ArchType {
-		switch runtime.GOARCH {
-		case "amd64":
-			return X86_64
+		switch runtime.GOOS {
+		case "linux":
+			switch runtime.GOARCH {
+			case "amd64":
+				return X86_64
+			case "arm64":
+				return Arm64
+			default:
+				panic(fmt.Sprintf("unsupported arch: %s", runtime.GOARCH))
+			}
+		case "darwin":
+			switch runtime.GOARCH {
+			case "amd64":
+				return X86_64
+			default:
+				panic(fmt.Sprintf("unsupported arch: %s", runtime.GOARCH))
+			}
 		default:
-			panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
+			panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
 		}
 	}()
 
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 5e05f54..5cb9e71 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -34,8 +34,6 @@
 
 	blueprintBaseModuleContext() blueprint.BaseModuleContext
 
-	EqualModules(m1, m2 Module) bool
-
 	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
 	// It is intended for use inside the visit functions of Visit* and WalkDeps.
 	OtherModuleName(m blueprint.Module) string
@@ -271,8 +269,8 @@
 	return module
 }
 
-func (b *baseModuleContext) EqualModules(m1, m2 Module) bool {
-	return b.bp.EqualModules(getWrappedModule(m1), getWrappedModule(m2))
+func EqualModules(m1, m2 Module) bool {
+	return blueprint.EqualModules(getWrappedModule(m1), getWrappedModule(m2))
 }
 
 func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
@@ -412,7 +410,7 @@
 		return &aModule
 	}
 
-	if !OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).Enabled {
+	if !OtherModulePointerProviderOrDefault(b, module, CommonModuleInfoProvider).Enabled {
 		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependencyProxy(b, aModule) {
 			if b.Config().AllowMissingDependencies() {
 				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
@@ -442,7 +440,7 @@
 func (b *baseModuleContext) getDirectDepsProxyInternal(name string, tag blueprint.DependencyTag) []ModuleProxy {
 	var deps []ModuleProxy
 	b.VisitDirectDepsProxy(func(module ModuleProxy) {
-		if OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).BaseModuleName == name {
+		if OtherModulePointerProviderOrDefault(b, module, CommonModuleInfoProvider).BaseModuleName == name {
 			returnedTag := b.OtherModuleDependencyTag(module)
 			if tag == nil || returnedTag == tag {
 				deps = append(deps, module)
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index a6dbb8d..16a3853 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -18,7 +18,9 @@
 	"bytes"
 	"encoding/csv"
 	"fmt"
+	"path/filepath"
 	"slices"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -127,27 +129,37 @@
 // dependencies, built/installed files, etc. It is a wrapper on a map[string]string with some utility
 // methods to get/set properties' values.
 type ComplianceMetadataInfo struct {
-	properties map[string]string
+	properties          map[string]string
+	filesContained      []string
+	prebuiltFilesCopied []string
 }
 
 type complianceMetadataInfoGob struct {
-	Properties map[string]string
+	Properties          map[string]string
+	FilesContained      []string
+	PrebuiltFilesCopied []string
 }
 
 func NewComplianceMetadataInfo() *ComplianceMetadataInfo {
 	return &ComplianceMetadataInfo{
-		properties: map[string]string{},
+		properties:          map[string]string{},
+		filesContained:      make([]string, 0),
+		prebuiltFilesCopied: make([]string, 0),
 	}
 }
 
 func (m *ComplianceMetadataInfo) ToGob() *complianceMetadataInfoGob {
 	return &complianceMetadataInfoGob{
-		Properties: m.properties,
+		Properties:          m.properties,
+		FilesContained:      m.filesContained,
+		PrebuiltFilesCopied: m.prebuiltFilesCopied,
 	}
 }
 
 func (m *ComplianceMetadataInfo) FromGob(data *complianceMetadataInfoGob) {
 	m.properties = data.Properties
+	m.filesContained = data.FilesContained
+	m.prebuiltFilesCopied = data.PrebuiltFilesCopied
 }
 
 func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
@@ -169,6 +181,22 @@
 	c.SetStringValue(propertyName, strings.TrimSpace(strings.Join(value, " ")))
 }
 
+func (c *ComplianceMetadataInfo) SetFilesContained(files []string) {
+	c.filesContained = files
+}
+
+func (c *ComplianceMetadataInfo) GetFilesContained() []string {
+	return c.filesContained
+}
+
+func (c *ComplianceMetadataInfo) SetPrebuiltFilesCopied(files []string) {
+	c.prebuiltFilesCopied = files
+}
+
+func (c *ComplianceMetadataInfo) GetPrebuiltFilesCopied() []string {
+	return c.prebuiltFilesCopied
+}
+
 func (c *ComplianceMetadataInfo) getStringValue(propertyName string) string {
 	if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) {
 		panic(fmt.Errorf("Unknown metadata property: %s.", propertyName))
@@ -276,7 +304,7 @@
 
 	rowId := -1
 	ctx.VisitAllModuleProxies(func(module ModuleProxy) {
-		commonInfo, _ := OtherModuleProvider(ctx, module, CommonModuleInfoKey)
+		commonInfo := OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider)
 		if !commonInfo.Enabled {
 			return
 		}
@@ -316,9 +344,42 @@
 	makeMetadataCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-metadata.csv")
 	makeModulesCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-modules.csv")
 
+	productOutPath := filepath.Join(ctx.Config().OutDir(), "target", "product", String(ctx.Config().productVariables.DeviceName))
 	if !ctx.Config().KatiEnabled() {
-		WriteFileRule(ctx, makeMetadataCsv, "installed_file,module_path,is_soong_module,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,static_libs,whole_static_libs,license_text")
-		WriteFileRule(ctx, makeModulesCsv, "name,module_path,module_class,module_type,static_libs,whole_static_libs,built_files,installed_files")
+		ctx.VisitAllModuleProxies(func(module ModuleProxy) {
+			// In soong-only build the installed file list is from android_device module
+			if androidDeviceInfo, ok := OtherModuleProvider(ctx, module, AndroidDeviceInfoProvider); ok && androidDeviceInfo.Main_device {
+				if metadataInfo, ok := OtherModuleProvider(ctx, module, ComplianceMetadataProvider); ok {
+					if len(metadataInfo.filesContained) > 0 || len(metadataInfo.prebuiltFilesCopied) > 0 {
+						allFiles := make([]string, 0, len(metadataInfo.filesContained)+len(metadataInfo.prebuiltFilesCopied))
+						allFiles = append(allFiles, metadataInfo.filesContained...)
+						prebuiltFilesSrcDest := make(map[string]string)
+						for _, srcDestPair := range metadataInfo.prebuiltFilesCopied {
+							prebuiltFilePath := filepath.Join(productOutPath, strings.Split(srcDestPair, ":")[1])
+							allFiles = append(allFiles, prebuiltFilePath)
+							prebuiltFilesSrcDest[prebuiltFilePath] = srcDestPair
+						}
+						sort.Strings(allFiles)
+
+						csvHeaders := "installed_file,module_path,is_soong_module,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,static_libs,whole_static_libs,license_text"
+						csvContent := make([]string, 0, len(allFiles)+1)
+						csvContent = append(csvContent, csvHeaders)
+						for _, file := range allFiles {
+							if _, ok := prebuiltFilesSrcDest[file]; ok {
+								srcDestPair := prebuiltFilesSrcDest[file]
+								csvContent = append(csvContent, file+",,,,"+srcDestPair+",,,,,")
+							} else {
+								csvContent = append(csvContent, file+",,Y,,,,,,,")
+							}
+						}
+
+						WriteFileRuleVerbatim(ctx, makeMetadataCsv, strings.Join(csvContent, "\n"))
+						WriteFileRuleVerbatim(ctx, makeModulesCsv, "name,module_path,module_class,module_type,static_libs,whole_static_libs,built_files,installed_files")
+					}
+					return
+				}
+			}
+		})
 	}
 
 	// Import metadata from Make and Soong to sqlite3 database
diff --git a/android/config.go b/android/config.go
index a5edf0d..d47f0d4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -200,6 +200,11 @@
 	return c.config.productVariables.ReleaseAconfigValueSets
 }
 
+// If native modules should have symbols stripped by default. Default false, enabled for build tools
+func (c Config) StripByDefault() bool {
+	return proptools.Bool(c.config.productVariables.StripByDefault)
+}
+
 func (c Config) ReleaseAconfigExtraReleaseConfigs() []string {
 	result := []string{}
 	if val, ok := c.config.productVariables.BuildFlags["RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS"]; ok {
@@ -233,11 +238,6 @@
 	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 {
@@ -385,24 +385,28 @@
 }
 
 type partialCompileFlags struct {
-	// Is partial compilation enabled at all?
-	Enabled bool
-
 	// Whether to use d8 instead of r8
 	Use_d8 bool
 
+	// Whether to disable stub validation.  This is slightly more surgical
+	// than DISABLE_STUB_VALIDATION, in that it only applies to partial
+	// compile builds.
+	Disable_stub_validation bool
+
+	// Whether to disable api lint.
+	Disable_api_lint bool
+
 	// Add others as needed.
 }
 
 // These are the flags when `SOONG_PARTIAL_COMPILE` is empty or not set.
-var defaultPartialCompileFlags = partialCompileFlags{
-	Enabled: false,
-}
+var defaultPartialCompileFlags = partialCompileFlags{}
 
 // These are the flags when `SOONG_PARTIAL_COMPILE=true`.
 var enabledPartialCompileFlags = partialCompileFlags{
-	Enabled: true,
-	Use_d8:  true,
+	Use_d8:                  true,
+	Disable_stub_validation: false,
+	Disable_api_lint:        false,
 }
 
 type deviceConfig struct {
@@ -477,13 +481,29 @@
 			state = "+"
 		}
 		switch tok {
+		case "all":
+			// Turn on **all** of the flags.
+			ret = partialCompileFlags{
+				Use_d8:                  true,
+				Disable_stub_validation: true,
+				Disable_api_lint:        true,
+			}
 		case "true":
 			ret = enabledPartialCompileFlags
 		case "false":
 			// Set everything to false.
 			ret = partialCompileFlags{}
-		case "enabled":
-			ret.Enabled = makeVal(state, defaultPartialCompileFlags.Enabled)
+
+		case "api_lint", "enable_api_lint":
+			ret.Disable_api_lint = !makeVal(state, !defaultPartialCompileFlags.Disable_api_lint)
+		case "disable_api_lint":
+			ret.Disable_api_lint = makeVal(state, defaultPartialCompileFlags.Disable_api_lint)
+
+		case "stub_validation", "enable_stub_validation":
+			ret.Disable_stub_validation = !makeVal(state, !defaultPartialCompileFlags.Disable_stub_validation)
+		case "disable_stub_validation":
+			ret.Disable_stub_validation = makeVal(state, defaultPartialCompileFlags.Disable_stub_validation)
+
 		case "use_d8":
 			ret.Use_d8 = makeVal(state, defaultPartialCompileFlags.Use_d8)
 		default:
@@ -814,11 +834,18 @@
 func (c *config) PrebuiltOS() string {
 	switch runtime.GOOS {
 	case "linux":
-		return "linux-x86"
+		switch runtime.GOARCH {
+		case "amd64":
+			return "linux-x86"
+		case "arm64":
+			return "linux-arm64"
+		default:
+			panic(fmt.Errorf("Unknown GOARCH %s", runtime.GOARCH))
+		}
 	case "darwin":
 		return "darwin-x86"
 	default:
-		panic("Unknown GOOS")
+		panic(fmt.Errorf("Unknown GOOS %s", runtime.GOOS))
 	}
 }
 
@@ -2222,7 +2249,6 @@
 		"RELEASE_APEX_CONTRIBUTIONS_NFC":                     "com.android.nfcservices",
 		"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION": "com.android.ondevicepersonalization",
 		"RELEASE_APEX_CONTRIBUTIONS_PERMISSION":              "com.android.permission",
-		"RELEASE_APEX_CONTRIBUTIONS_PRIMARY_LIBS":            "",
 		"RELEASE_APEX_CONTRIBUTIONS_PROFILING":               "com.android.profiling",
 		"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING":   "com.android.rkpd",
 		"RELEASE_APEX_CONTRIBUTIONS_RESOLV":                  "com.android.resolv",
diff --git a/android/config_test.go b/android/config_test.go
index 3d86860..d1b26c1 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -213,13 +213,18 @@
 	})
 }
 
-func (p partialCompileFlags) updateEnabled(value bool) partialCompileFlags {
-	p.Enabled = value
+func (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags {
+	p.Use_d8 = value
 	return p
 }
 
-func (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags {
-	p.Use_d8 = value
+func (p partialCompileFlags) updateDisableApiLint(value bool) partialCompileFlags {
+	p.Disable_api_lint = value
+	return p
+}
+
+func (p partialCompileFlags) updateDisableStubValidation(value bool) partialCompileFlags {
+	p.Disable_stub_validation = value
 	return p
 }
 
@@ -241,10 +246,29 @@
 		{"false", true, partialCompileFlags{}},
 		{"true", true, enabledPartialCompileFlags},
 		{"true", false, partialCompileFlags{}},
+		{"all", true, partialCompileFlags{}.updateUseD8(true).updateDisableApiLint(true).updateDisableStubValidation(true)},
+
+		// This verifies both use_d8 and the processing order.
 		{"true,use_d8", true, enabledPartialCompileFlags.updateUseD8(true)},
 		{"true,-use_d8", true, enabledPartialCompileFlags.updateUseD8(false)},
 		{"use_d8,false", true, partialCompileFlags{}},
 		{"false,+use_d8", true, partialCompileFlags{}.updateUseD8(true)},
+
+		// disable_api_lint can be specified with any of 3 options.
+		{"false,-api_lint", true, partialCompileFlags{}.updateDisableApiLint(true)},
+		{"false,-enable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(true)},
+		{"false,+disable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(true)},
+		{"false,+api_lint", true, partialCompileFlags{}.updateDisableApiLint(false)},
+		{"false,+enable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(false)},
+		{"false,-disable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(false)},
+
+		// disable_stub_validation can be specified with any of 3 options.
+		{"false,-stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(true)},
+		{"false,-enable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(true)},
+		{"false,+disable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(true)},
+		{"false,+stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(false)},
+		{"false,+enable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(false)},
+		{"false,-disable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(false)},
 	}
 
 	for _, test := range tests {
diff --git a/android/container.go b/android/container.go
index 5dc97d3..547fe81 100644
--- a/android/container.go
+++ b/android/container.go
@@ -39,7 +39,7 @@
 
 // Returns true if the dependency module is a stubs module
 var depIsStubsModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) bool {
-	return OtherModuleProviderOrDefault(mctx, dep, CommonModuleInfoKey).IsStubsModule
+	return OtherModulePointerProviderOrDefault(mctx, dep, CommonModuleInfoProvider).IsStubsModule
 }
 
 // Returns true if the dependency module belongs to any of the apexes.
@@ -449,7 +449,7 @@
 }
 
 func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
-	if ctx.EqualModules(ctx.Module(), module) {
+	if EqualModules(ctx.Module(), module) {
 		return ctx.getContainersInfo(), true
 	}
 
@@ -474,7 +474,7 @@
 	if _, ok := ctx.Module().(InstallableModule); ok {
 		containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
 		ctx.VisitDirectDepsProxy(func(dep ModuleProxy) {
-			if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled {
+			if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoProvider).Enabled {
 				return
 			}
 
diff --git a/android/filegroup.go b/android/filegroup.go
index 47102b9..9bcfd0a 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -33,6 +33,7 @@
 func RegisterFilegroupBuildComponents(ctx RegistrationContext) {
 	ctx.RegisterModuleType("filegroup", FileGroupFactory)
 	ctx.RegisterModuleType("filegroup_defaults", FileGroupDefaultsFactory)
+	ctx.RegisterModuleType("otatools_package_filegroup", OtatoolsFileGroupFactory)
 }
 
 type fileGroupProperties struct {
@@ -131,10 +132,11 @@
 	return append(Paths{}, fg.srcs...)
 }
 
-func (fg *fileGroup) MakeVars(ctx MakeVarsModuleContext) {
+func (fg *fileGroup) MakeVars(_ MakeVarsModuleContext) []ModuleMakeVarsValue {
 	if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
-		ctx.StrictRaw(makeVar, strings.Join(fg.srcs.Strings(), " "))
+		return []ModuleMakeVarsValue{{makeVar, strings.Join(fg.srcs.Strings(), " ")}}
 	}
+	return nil
 }
 
 // Defaults
@@ -162,3 +164,54 @@
 		}
 	}
 }
+
+type OtatoolsFileGroup struct {
+	ModuleBase
+}
+
+func OtatoolsFileGroupFactory() Module {
+	module := &OtatoolsFileGroup{}
+	InitAndroidModule(module)
+	AddLoadHook(module, func(ctx LoadHookContext) {
+		module.createOTAToolsPackagefilegroup(ctx)
+	})
+	return module
+}
+
+func (fg *OtatoolsFileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+// Create the filegroup to collect cert files for otatools.zip.
+func (fg *OtatoolsFileGroup) createOTAToolsPackagefilegroup(ctx LoadHookContext) {
+	ctx.CreateModuleInDirectory(
+		FileGroupFactory,
+		".",
+		&struct {
+			Name       *string
+			Srcs       []string
+			Visibility []string
+		}{
+			Name: proptools.StringPtr("soong_generated_otatools_package_filegroup"),
+			Srcs: []string{
+				"build/make/target/product/security/**/*.x509.pem",
+				"build/make/target/product/security/**/*.pk8",
+				"device/**/*.pk8",
+				"device/**/verifiedboot*",
+				"device/**/*.pem",
+				"device/**/oem*.prop",
+				"device/**/*.avbpubkey",
+				"external/avb/test/data/**/testkey_*.pem",
+				"external/avb/test/data/**/atx_metadata.bin",
+				"packages/modules/**/*.x509.pem",
+				"packages/modules/**/*.pk8",
+				"packages/modules/**/*.key.pem",
+				"vendor/**/*.pk8",
+				"vendor/**/verifiedboot*",
+				"vendor/**/*.pem",
+				"vendor/**/oem*.prop",
+				"vendor/**/*.avbpubkey",
+			},
+			Visibility: []string{"//build/make/tools/otatools_package"},
+		},
+	)
+}
diff --git a/android/gen_notice.go b/android/gen_notice.go
index 9adde9e..45f90f4 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -19,6 +19,7 @@
 	"path/filepath"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -35,34 +36,31 @@
 type genNoticeBuildRules struct{}
 
 func (s *genNoticeBuildRules) GenerateBuildActions(ctx SingletonContext) {
-	ctx.VisitAllModules(func(m Module) {
-		gm, ok := m.(*genNoticeModule)
+	ctx.VisitAllModuleProxies(func(m ModuleProxy) {
+		gm, ok := OtherModuleProvider(ctx, m, GenNoticeInfoProvider)
 		if !ok {
 			return
 		}
-		if len(gm.missing) > 0 {
-			missingReferencesRule(ctx, gm)
+		if len(gm.Missing) > 0 {
+			missingReferencesRule(ctx, m, &gm)
 			return
 		}
 		out := BuildNoticeTextOutputFromLicenseMetadata
-		if proptools.Bool(gm.properties.Xml) {
+		if gm.Xml {
 			out = BuildNoticeXmlOutputFromLicenseMetadata
-		} else if proptools.Bool(gm.properties.Html) {
+		} else if gm.Html {
 			out = BuildNoticeHtmlOutputFromLicenseMetadata
 		}
 		defaultName := ""
-		if len(gm.properties.For) > 0 {
-			defaultName = gm.properties.For[0]
+		if len(gm.For) > 0 {
+			defaultName = gm.For[0]
 		}
 
-		modules := make([]Module, 0)
-		for _, name := range gm.properties.For {
-			mods := ctx.ModuleVariantsFromName(gm, name)
+		modules := make([]ModuleProxy, 0)
+		for _, name := range gm.For {
+			mods := ctx.ModuleVariantsFromName(m, name)
 			for _, mod := range mods {
-				if mod == nil {
-					continue
-				}
-				if !mod.Enabled(ctx) { // don't depend on variants without build rules
+				if !OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider).Enabled { // don't depend on variants without build rules
 					continue
 				}
 				modules = append(modules, mod)
@@ -71,8 +69,8 @@
 		if ctx.Failed() {
 			return
 		}
-		out(ctx, gm.output, ctx.ModuleName(gm),
-			proptools.StringDefault(gm.properties.ArtifactName, defaultName),
+		out(ctx, gm.Output, ctx.ModuleName(m),
+			proptools.StringDefault(gm.ArtifactName, defaultName),
 			[]string{
 				filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()) + "/",
 				ctx.Config().OutDir() + "/",
@@ -115,6 +113,22 @@
 	missing []string
 }
 
+type GenNoticeInfo struct {
+	// For specifies the modules for which to generate a notice file.
+	For []string
+	// ArtifactName specifies the internal name to use for the notice file.
+	// It appears in the "used by:" list for targets whose entire name is stripped by --strip_prefix.
+	ArtifactName *string
+	// Html indicates an html-format file is needed. The default is text. Can be Html or Xml but not both.
+	Html bool
+	// Xml indicates an xml-format file is needed. The default is text. Can be Html or Xml but not both.
+	Xml     bool
+	Output  OutputPath
+	Missing []string
+}
+
+var GenNoticeInfoProvider = blueprint.NewProvider[GenNoticeInfo]()
+
 func (m *genNoticeModule) DepsMutator(ctx BottomUpMutatorContext) {
 	if ctx.ContainsProperty("licenses") {
 		ctx.PropertyErrorf("licenses", "not supported on \"gen_notice\" modules")
@@ -176,6 +190,15 @@
 	}
 	out := m.getStem() + m.getSuffix()
 	m.output = PathForModuleOut(ctx, out).OutputPath
+
+	SetProvider(ctx, GenNoticeInfoProvider, GenNoticeInfo{
+		For:          m.properties.For,
+		ArtifactName: m.properties.ArtifactName,
+		Xml:          proptools.Bool(m.properties.Xml),
+		Html:         proptools.Bool(m.properties.Html),
+		Output:       m.output,
+		Missing:      m.missing,
+	})
 	ctx.SetOutputFiles(Paths{m.output}, "")
 }
 
@@ -205,17 +228,17 @@
 }
 
 // missingReferencesRule emits an ErrorRule for missing module references.
-func missingReferencesRule(ctx BuilderContext, m *genNoticeModule) {
-	if len(m.missing) < 1 {
+func missingReferencesRule(ctx BuilderContext, m ModuleProxy, genInfo *GenNoticeInfo) {
+	if len(genInfo.Missing) < 1 {
 		panic(fmt.Errorf("missing references rule requested with no missing references"))
 	}
 
 	ctx.Build(pctx, BuildParams{
 		Rule:        ErrorRule,
-		Output:      m.output,
-		Description: "notice for " + proptools.StringDefault(m.properties.ArtifactName, "container"),
+		Output:      genInfo.Output,
+		Description: "notice for " + proptools.StringDefault(genInfo.ArtifactName, "container"),
 		Args: map[string]string{
-			"error": m.Name() + " references missing module(s): " + strings.Join(m.missing, ", "),
+			"error": m.Name() + " references missing module(s): " + strings.Join(genInfo.Missing, ", "),
 		},
 	})
 }
diff --git a/android/init.go b/android/init.go
index d3a13d0..af50323 100644
--- a/android/init.go
+++ b/android/init.go
@@ -17,6 +17,7 @@
 import "encoding/gob"
 
 func init() {
+	gob.Register(applicableLicensesPropertyImpl{})
 	gob.Register(extraFilesZip{})
 	gob.Register(InstallPath{})
 	gob.Register(ModuleGenPath{})
diff --git a/android/license_metadata.go b/android/license_metadata.go
index d15dfa8..0b880dd 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -65,7 +65,7 @@
 	var allDepMetadataDepSets []depset.DepSet[Path]
 
 	ctx.VisitDirectDepsProxy(func(dep ModuleProxy) {
-		if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled {
+		if !OtherModulePointerProviderOrDefault(ctx, dep, CommonModuleInfoProvider).Enabled {
 			return
 		}
 
diff --git a/android/licenses.go b/android/licenses.go
index 32d12c8..3877921 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -22,6 +22,7 @@
 	"sync"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/gobtools"
 )
 
 // Adds cross-cutting licenses dependency to propagate license metadata through the build system.
@@ -67,6 +68,31 @@
 	licensesProperty *[]string
 }
 
+type applicableLicensesPropertyImplGob struct {
+	Name             string
+	LicensesProperty []string
+}
+
+func (a *applicableLicensesPropertyImpl) ToGob() *applicableLicensesPropertyImplGob {
+	return &applicableLicensesPropertyImplGob{
+		Name:             a.name,
+		LicensesProperty: *a.licensesProperty,
+	}
+}
+
+func (a *applicableLicensesPropertyImpl) FromGob(data *applicableLicensesPropertyImplGob) {
+	a.name = data.Name
+	a.licensesProperty = &data.LicensesProperty
+}
+
+func (a applicableLicensesPropertyImpl) GobEncode() ([]byte, error) {
+	return gobtools.CustomGobEncode[applicableLicensesPropertyImplGob](&a)
+}
+
+func (a *applicableLicensesPropertyImpl) GobDecode(data []byte) error {
+	return gobtools.CustomGobDecode[applicableLicensesPropertyImplGob](data, a)
+}
+
 func newApplicableLicensesProperty(name string, licensesProperty *[]string) applicableLicensesProperty {
 	return applicableLicensesPropertyImpl{
 		name:             name,
@@ -351,9 +377,7 @@
 	ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String())
 	ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String())
 	ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String())
-	ctx.Strict("COMPLIANCENOTICE_BOM", ctx.Config().HostToolPath(ctx, "compliancenotice_bom").String())
 	ctx.Strict("COMPLIANCENOTICE_SHIPPEDLIBS", ctx.Config().HostToolPath(ctx, "compliancenotice_shippedlibs").String())
 	ctx.Strict("COMPLIANCE_LISTSHARE", ctx.Config().HostToolPath(ctx, "compliance_listshare").String())
 	ctx.Strict("COMPLIANCE_CHECKSHARE", ctx.Config().HostToolPath(ctx, "compliance_checkshare").String())
-	ctx.Strict("COMPLIANCE_SBOM", ctx.Config().HostToolPath(ctx, "compliance_sbom").String())
 }
diff --git a/android/logtags.go b/android/logtags.go
index abc37f9..074f402 100644
--- a/android/logtags.go
+++ b/android/logtags.go
@@ -42,8 +42,8 @@
 
 func (l *logtagsSingleton) GenerateBuildActions(ctx SingletonContext) {
 	var allLogtags Paths
-	ctx.VisitAllModules(func(module Module) {
-		if !module.ExportedToMake() {
+	ctx.VisitAllModuleProxies(func(module ModuleProxy) {
+		if !OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).ExportedToMake {
 			return
 		}
 		if logtagsInfo, ok := OtherModuleProvider(ctx, module, LogtagsProviderKey); ok {
diff --git a/android/makevars.go b/android/makevars.go
index 2931d0b..7017e7d 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -84,6 +84,7 @@
 	Errorf(format string, args ...interface{})
 
 	VisitAllModules(visit func(Module))
+	VisitAllModuleProxies(visit func(proxy ModuleProxy))
 	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
 
 	// Verify the make variable matches the Soong version, fail the build
@@ -108,7 +109,7 @@
 // MakeVarsModuleContext contains the set of functions available for modules
 // implementing the ModuleMakeVarsProvider interface.
 type MakeVarsModuleContext interface {
-	BaseMakeVarsContext
+	Config() Config
 }
 
 var _ PathContext = MakeVarsContext(nil)
@@ -150,14 +151,21 @@
 	return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
 }
 
+type ModuleMakeVarsValue struct {
+	// Make variable name.
+	Name string
+	// Make variable value.
+	Value string
+}
+
 // ModuleMakeVarsProvider is a Module with an extra method to provide extra values to be exported to Make.
 type ModuleMakeVarsProvider interface {
-	Module
-
 	// MakeVars uses a MakeVarsModuleContext to provide extra values to be exported to Make.
-	MakeVars(ctx MakeVarsModuleContext)
+	MakeVars(ctx MakeVarsModuleContext) []ModuleMakeVarsValue
 }
 
+var ModuleMakeVarsInfoProvider = blueprint.NewProvider[[]ModuleMakeVarsValue]()
+
 // /////////////////////////////////////////////////////////////////////////////
 
 func makeVarsSingletonFunc() Singleton {
@@ -250,19 +258,24 @@
 	dists = append(dists, singletonDists.dists...)
 	singletonDists.lock.Unlock()
 
-	ctx.VisitAllModules(func(m Module) {
-		if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(m ModuleProxy) {
+		commonInfo := OtherModulePointerProviderOrDefault(ctx, m, CommonModuleInfoProvider)
+		if provider, ok := OtherModuleProvider(ctx, m, ModuleMakeVarsInfoProvider); ok &&
+			commonInfo.Enabled {
 			mctx := &makeVarsContext{
 				SingletonContext: ctx,
 			}
-
-			provider.MakeVars(mctx)
+			for _, val := range provider {
+				if val.Name != "" {
+					mctx.StrictRaw(val.Name, val.Value)
+				}
+			}
 
 			vars = append(vars, mctx.vars...)
 			phonies = append(phonies, mctx.phonies...)
 		}
 
-		if m.ExportedToMake() {
+		if commonInfo.ExportedToMake {
 			info := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider)
 			katiInstalls = append(katiInstalls, info.KatiInstalls...)
 			katiInitRcInstalls = append(katiInitRcInstalls, info.KatiInitRcInstalls...)
diff --git a/android/module.go b/android/module.go
index d387c2c..a3fe837 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"errors"
 	"fmt"
 	"net/url"
 	"path/filepath"
@@ -519,6 +520,11 @@
 
 	// names of other modules to install on target if this module is installed
 	Target_required []string `android:"arch_variant"`
+
+	// If this is a soong config module, this property will be set to the name of the original
+	// module type. This is used by neverallow to ensure you can't bypass a ModuleType() matcher
+	// just by creating a soong config module type.
+	Soong_config_base_module_type *string `blueprint:"mutated"`
 }
 
 type distProperties struct {
@@ -996,11 +1002,19 @@
 	pv := ctx.Config().productVariables
 	fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil
 	if fullManifest {
-		addRequiredDeps(ctx)
 		addVintfFragmentDeps(ctx)
 	}
 }
 
+// required property can be overridden too; handle it separately
+func (m *ModuleBase) baseOverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
+	pv := ctx.Config().productVariables
+	fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil
+	if fullManifest {
+		addRequiredDeps(ctx)
+	}
+}
+
 // addRequiredDeps adds required, target_required, and host_required as dependencies.
 func addRequiredDeps(ctx BottomUpMutatorContext) {
 	addDep := func(target Target, depName string) {
@@ -1219,6 +1233,13 @@
 		tag := proptools.StringDefault(dist.Tag, DefaultDistTag)
 
 		distFileForTagFromProvider, err := outputFilesForModuleFromProvider(ctx, m.module, tag)
+
+		// If the module doesn't define output files for the DefaultDistTag, try the files under
+		// the "" tag.
+		if tag == DefaultDistTag && errors.Is(err, ErrUnsupportedOutputTag) {
+			distFileForTagFromProvider, err = outputFilesForModuleFromProvider(ctx, m.module, "")
+		}
+
 		if err != OutputFilesProviderNotSet {
 			if err != nil && tag != DefaultDistTag {
 				ctx.PropertyErrorf("dist.tag", "%s", err.Error())
@@ -1475,7 +1496,7 @@
 			// Installation is still handled by Make, so anything hidden from Make is not
 			// installable.
 			info := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider)
-			commonInfo := OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey)
+			commonInfo := OtherModulePointerProviderOrDefault(ctx, dep, CommonModuleInfoProvider)
 			if !commonInfo.HideFromMake && !commonInfo.SkipInstall {
 				installDeps = append(installDeps, info.TransitiveInstallFiles)
 			}
@@ -1492,7 +1513,7 @@
 // should also install the output files of the given dependency and dependency tag.
 func isInstallDepNeeded(ctx ModuleContext, dep ModuleProxy) bool {
 	// Don't add a dependency from the platform to a library provided by an apex.
-	if OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).UninstallableApexPlatformVariant {
+	if OtherModulePointerProviderOrDefault(ctx, dep, CommonModuleInfoProvider).UninstallableApexPlatformVariant {
 		return false
 	}
 	// Only install modules if the dependency tag is an InstallDepNeeded tag.
@@ -1646,38 +1667,10 @@
 
 }
 
+// generateModuleTarget generates phony targets so that you can do `m <module-name>`.
+// It will be run on every variant of the module, so it relies on the fact that phony targets
+// are deduped to merge all the deps from different variants together.
 func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) {
-	var allInstalledFiles InstallPaths
-	var allCheckbuildTargets Paths
-	var alloutputFiles Paths
-	ctx.VisitAllModuleVariantProxies(func(module ModuleProxy) {
-		var checkbuildTarget Path
-		var uncheckedModule bool
-		var skipAndroidMkProcessing bool
-		if ctx.EqualModules(m.module, module) {
-			allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
-			checkbuildTarget = ctx.checkbuildTarget
-			uncheckedModule = ctx.uncheckedModule
-			skipAndroidMkProcessing = shouldSkipAndroidMkProcessing(ctx, m)
-		} else {
-			info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider)
-			allInstalledFiles = append(allInstalledFiles, info.InstallFiles...)
-			checkbuildTarget = info.CheckbuildTarget
-			uncheckedModule = info.UncheckedModule
-			skipAndroidMkProcessing = OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).SkipAndroidMkProcessing
-		}
-		if outputFiles, err := outputFilesForModule(ctx, module, ""); err == nil {
-			alloutputFiles = append(alloutputFiles, outputFiles...)
-		}
-		// 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() || !skipAndroidMkProcessing) && !uncheckedModule && checkbuildTarget != nil {
-			allCheckbuildTargets = append(allCheckbuildTargets, checkbuildTarget)
-		}
-	})
-
 	var namespacePrefix string
 	nameSpace := ctx.Namespace().Path
 	if nameSpace != "." {
@@ -1685,25 +1678,30 @@
 	}
 
 	var deps Paths
-	var info FinalModuleBuildTargetsInfo
+	var info ModuleBuildTargetsInfo
 
-	if len(allInstalledFiles) > 0 {
+	if len(ctx.installFiles) > 0 {
 		name := namespacePrefix + ctx.ModuleName() + "-install"
-		ctx.Phony(name, allInstalledFiles.Paths()...)
+		installFiles := ctx.installFiles.Paths()
+		ctx.Phony(name, installFiles...)
 		info.InstallTarget = PathForPhony(ctx, name)
-		deps = append(deps, info.InstallTarget)
+		deps = append(deps, installFiles...)
 	}
 
-	if len(allCheckbuildTargets) > 0 {
+	// 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, m)) && !ctx.uncheckedModule && ctx.checkbuildTarget != nil {
 		name := namespacePrefix + ctx.ModuleName() + "-checkbuild"
-		ctx.Phony(name, allCheckbuildTargets...)
-		deps = append(deps, PathForPhony(ctx, name))
+		ctx.Phony(name, ctx.checkbuildTarget)
+		deps = append(deps, ctx.checkbuildTarget)
 	}
 
-	if len(alloutputFiles) > 0 {
+	if outputFiles, err := outputFilesForModule(ctx, ctx.Module(), ""); err == nil && len(outputFiles) > 0 {
 		name := namespacePrefix + ctx.ModuleName() + "-outputs"
-		ctx.Phony(name, alloutputFiles...)
-		deps = append(deps, PathForPhony(ctx, name))
+		ctx.Phony(name, outputFiles...)
+		deps = append(deps, outputFiles...)
 	}
 
 	if len(deps) > 0 {
@@ -1726,7 +1724,7 @@
 		}
 
 		info.BlueprintDir = ctx.ModuleDir()
-		SetProvider(ctx, FinalModuleBuildTargetsProvider, info)
+		SetProvider(ctx, ModuleBuildTargetsProvider, info)
 	}
 }
 
@@ -1868,15 +1866,15 @@
 
 var SourceFilesInfoProvider = blueprint.NewProvider[SourceFilesInfo]()
 
-// FinalModuleBuildTargetsInfo is used by buildTargetSingleton to create checkbuild and
-// per-directory build targets. Only set on the final variant of each module
-type FinalModuleBuildTargetsInfo struct {
+// ModuleBuildTargetsInfo is used by buildTargetSingleton to create checkbuild and
+// per-directory build targets.
+type ModuleBuildTargetsInfo struct {
 	InstallTarget    WritablePath
 	CheckbuildTarget WritablePath
 	BlueprintDir     string
 }
 
-var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
+var ModuleBuildTargetsProvider = blueprint.NewProvider[ModuleBuildTargetsInfo]()
 
 type CommonModuleInfo struct {
 	Enabled bool
@@ -1928,6 +1926,9 @@
 	TargetRequiredModuleNames                    []string
 	VintfFragmentModuleNames                     []string
 	Dists                                        []Dist
+	ExportedToMake                               bool
+	Team                                         string
+	PartitionTag                                 string
 }
 
 type ApiLevelOrPlatform struct {
@@ -1935,7 +1936,7 @@
 	IsPlatform bool
 }
 
-var CommonModuleInfoKey = blueprint.NewProvider[CommonModuleInfo]()
+var CommonModuleInfoProvider = blueprint.NewProvider[*CommonModuleInfo]()
 
 type PrebuiltModuleInfo struct {
 	SourceExists bool
@@ -2141,14 +2142,19 @@
 	}
 
 	if sourceFileProducer, ok := m.module.(SourceFileProducer); ok {
+		srcs := sourceFileProducer.Srcs()
+		for _, src := range srcs {
+			if src == nil {
+				ctx.ModuleErrorf("SourceFileProducer cannot return nil srcs")
+				return
+			}
+		}
 		SetProvider(ctx, SourceFilesInfoProvider, SourceFilesInfo{Srcs: sourceFileProducer.Srcs()})
 	}
 
-	if ctx.IsFinalModule(m.module) {
-		m.generateModuleTarget(ctx)
-		if ctx.Failed() {
-			return
-		}
+	m.generateModuleTarget(ctx)
+	if ctx.Failed() {
+		return
 	}
 
 	ctx.TransitiveInstallFiles = depset.New[InstallPath](depset.TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
@@ -2176,6 +2182,7 @@
 			} else {
 				hostRequired = m.baseProperties.Host_required
 			}
+			hostRequired = append(hostRequired, moduleInfoJSON.ExtraHostRequired...)
 
 			var data []string
 			for _, d := range ctx.testData {
@@ -2287,6 +2294,9 @@
 		TargetRequiredModuleNames:                    m.module.TargetRequiredModuleNames(),
 		VintfFragmentModuleNames:                     m.module.VintfFragmentModuleNames(ctx),
 		Dists:                                        m.Dists(),
+		ExportedToMake:                               m.ExportedToMake(),
+		Team:                                         m.Team(),
+		PartitionTag:                                 m.PartitionTag(ctx.DeviceConfig()),
 	}
 	if mm, ok := m.module.(interface {
 		MinSdkVersion(ctx EarlyModuleContext) ApiLevel
@@ -2334,7 +2344,7 @@
 	if mm, ok := m.module.(interface{ BaseModuleName() string }); ok {
 		commonData.BaseModuleName = mm.BaseModuleName()
 	}
-	SetProvider(ctx, CommonModuleInfoKey, commonData)
+	SetProvider(ctx, CommonModuleInfoProvider, &commonData)
 	if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil {
 		SetProvider(ctx, PrebuiltModuleInfoProvider, PrebuiltModuleInfo{
 			SourceExists: p.Prebuilt().SourceExists(),
@@ -2357,6 +2367,18 @@
 			GeneratedDeps:        s.GeneratedDeps(),
 		})
 	}
+
+	if m.Enabled(ctx) {
+		if v, ok := m.module.(ModuleMakeVarsProvider); ok {
+			SetProvider(ctx, ModuleMakeVarsInfoProvider, v.MakeVars(ctx))
+		}
+
+		if am, ok := m.module.(AndroidMkDataProvider); ok {
+			SetProvider(ctx, AndroidMkDataInfoProvider, AndroidMkDataInfo{
+				Class: am.AndroidMk().Class,
+			})
+		}
+	}
 }
 
 func SetJarJarPrefixHandler(handler func(ModuleContext)) {
@@ -2640,6 +2662,8 @@
 			return proptools.ConfigurableValueBool(ctx.Config().UseDebugArt())
 		case "selinux_ignore_neverallows":
 			return proptools.ConfigurableValueBool(ctx.Config().SelinuxIgnoreNeverallows())
+		case "always_use_prebuilt_sdks":
+			return proptools.ConfigurableValueBool(ctx.Config().AlwaysUsePrebuiltSdks())
 		default:
 			// TODO(b/323382414): Might add these on a case-by-case basis
 			ctx.OtherModulePropertyErrorf(m, property, fmt.Sprintf("TODO(b/323382414): Product variable %q is not yet supported in selects", variable))
@@ -2873,6 +2897,8 @@
 
 // OutputFileForModule returns the output file paths with the given tag.  On error, including if the
 // module produced zero or multiple paths, it reports errors to the ctx and returns nil.
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
 func OutputFileForModule(ctx PathContext, module Module, tag string) Path {
 	paths, err := outputFilesForModule(ctx, module, tag)
 	if err != nil {
@@ -2910,9 +2936,10 @@
 	OtherModuleProviderContext
 	Module() Module
 	GetOutputFiles() OutputFilesInfo
-	EqualModules(m1, m2 Module) bool
 }
 
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
 func outputFilesForModule(ctx PathContext, module Module, tag string) (Paths, error) {
 	outputFilesFromProvider, err := outputFilesForModuleFromProvider(ctx, module, tag)
 	if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet {
@@ -2920,7 +2947,7 @@
 	}
 
 	if octx, ok := ctx.(OutputFilesProviderModuleContext); ok {
-		if octx.EqualModules(octx.Module(), module) {
+		if EqualModules(octx.Module(), module) {
 			// It is the current module, we can access the srcs through interface
 			if sourceFileProducer, ok := module.(SourceFileProducer); ok {
 				return sourceFileProducer.Srcs(), nil
@@ -2945,14 +2972,12 @@
 // If a module doesn't have the OutputFilesProvider, nil is returned.
 func outputFilesForModuleFromProvider(ctx PathContext, module Module, tag string) (Paths, error) {
 	var outputFiles OutputFilesInfo
-	fromProperty := false
 
 	if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx {
-		if !mctx.EqualModules(mctx.Module(), module) {
+		if !EqualModules(mctx.Module(), module) {
 			outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider)
 		} else {
 			outputFiles = mctx.GetOutputFiles()
-			fromProperty = true
 		}
 	} else if cta, isCta := ctx.(*singletonContextAdaptor); isCta {
 		outputFiles, _ = OtherModuleProvider(cta, module, OutputFilesProvider)
@@ -2969,10 +2994,8 @@
 	} else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag {
 		return taggedOutputFiles, nil
 	} else {
-		if fromProperty {
-			return nil, fmt.Errorf("unsupported tag %q for module getting its own output files", tag)
-		} else {
-			return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+		return nil, UnsupportedOutputTagError{
+			tag: tag,
 		}
 	}
 }
@@ -2991,8 +3014,24 @@
 
 var OutputFilesProvider = blueprint.NewProvider[OutputFilesInfo]()
 
+type UnsupportedOutputTagError struct {
+	tag string
+}
+
+func (u UnsupportedOutputTagError) Error() string {
+	return fmt.Sprintf("unsupported output tag %q", u.tag)
+}
+
+func (u UnsupportedOutputTagError) Is(e error) bool {
+	_, ok := e.(UnsupportedOutputTagError)
+	return ok
+}
+
+var _ error = UnsupportedOutputTagError{}
+
 // This is used to mark the case where OutputFilesProvider is not set on some modules.
 var OutputFilesProviderNotSet = fmt.Errorf("No output files from provider")
+var ErrUnsupportedOutputTag = UnsupportedOutputTagError{}
 
 // Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to
 // specify that they can be used as a tool by a genrule module.
@@ -3058,8 +3097,8 @@
 
 	modulesInDir := make(map[string]Paths)
 
-	ctx.VisitAllModules(func(module Module) {
-		info := OtherModuleProviderOrDefault(ctx, module, FinalModuleBuildTargetsProvider)
+	ctx.VisitAllModuleProxies(func(module ModuleProxy) {
+		info := OtherModuleProviderOrDefault(ctx, module, ModuleBuildTargetsProvider)
 
 		if info.CheckbuildTarget != nil {
 			checkbuildDeps = append(checkbuildDeps, info.CheckbuildTarget)
@@ -3141,14 +3180,6 @@
 	BaseModuleName() string
 }
 
-// Extract the base module name from the Import name.
-// Often the Import name has a prefix "prebuilt_".
-// Remove the prefix explicitly if needed
-// until we find a better solution to get the Import name.
-type IDECustomizedModuleName interface {
-	IDECustomizedModuleName() string
-}
-
 // Collect information for opening IDE project files in java/jdeps.go.
 type IdeInfo struct {
 	BaseModuleName    string   `json:"-"`
diff --git a/android/module_context.go b/android/module_context.go
index fb62e67..0a23a74 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -456,6 +456,11 @@
 }
 
 func (m *moduleContext) Phony(name string, deps ...Path) {
+	for _, dep := range deps {
+		if dep == nil {
+			panic("Phony dep cannot be nil")
+		}
+	}
 	m.phonies[name] = append(m.phonies[name], deps...)
 }
 
@@ -748,6 +753,9 @@
 	m.packageFile(fullInstallPath, srcPath, executable, m.requiresFullInstall())
 
 	if checkbuild {
+		if srcPath == nil {
+			panic("srcPath cannot be nil")
+		}
 		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	}
 
@@ -879,6 +887,11 @@
 
 // CheckbuildFile specifies the output files that should be built by checkbuild.
 func (m *moduleContext) CheckbuildFile(srcPaths ...Path) {
+	for _, srcPath := range srcPaths {
+		if srcPath == nil {
+			panic("CheckbuildFile() files cannot be nil")
+		}
+	}
 	m.checkbuildFiles = append(m.checkbuildFiles, srcPaths...)
 }
 
diff --git a/android/module_info_json.go b/android/module_info_json.go
index bb309ff..50c961a 100644
--- a/android/module_info_json.go
+++ b/android/module_info_json.go
@@ -40,10 +40,12 @@
 	StaticDependencies  []string `json:"static_dependencies,omitempty"`   // $(sort $(ALL_MODULES.$(m).LOCAL_STATIC_LIBRARIES))
 	DataDependencies    []string `json:"data_dependencies,omitempty"`     // $(sort $(ALL_MODULES.$(m).TEST_DATA_BINS))
 
-	CompatibilitySuites []string `json:"compatibility_suites,omitempty"` // $(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES))
-	AutoTestConfig      []string `json:"auto_test_config,omitempty"`     // $(ALL_MODULES.$(m).auto_test_config)
-	TestConfig          []string `json:"test_config,omitempty"`          // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS)
-	ExtraRequired       []string `json:"-"`
+	CompatibilitySuites  []string `json:"compatibility_suites,omitempty"` // $(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES))
+	AutoTestConfig       []string `json:"auto_test_config,omitempty"`     // $(ALL_MODULES.$(m).auto_test_config)
+	TestConfig           []string `json:"test_config,omitempty"`          // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS)
+	TestModuleConfigBase string   `json:"test_module_config_base,omitempty"`
+	ExtraRequired        []string `json:"-"`
+	ExtraHostRequired    []string `json:"-"`
 
 	SupportedVariantsOverride []string `json:"-"`
 	Disabled                  bool     `json:"-"`
diff --git a/android/neverallow.go b/android/neverallow.go
index 70af2ac..5c90501 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -60,7 +60,8 @@
 	AddNeverAllowRules(createCcStubsRule())
 	AddNeverAllowRules(createProhibitHeaderOnlyRule())
 	AddNeverAllowRules(createLimitNdkExportRule()...)
-	AddNeverAllowRules(createLimitDirgroupRule()...)
+	AddNeverAllowRules(createLimitDirgroupRules()...)
+	AddNeverAllowRules(createLimitGenruleRules()...)
 	AddNeverAllowRules(createFilesystemIsAutoGeneratedRule())
 	AddNeverAllowRules(createKotlinPluginRule()...)
 	AddNeverAllowRules(createPrebuiltEtcBpDefineRule())
@@ -251,6 +252,7 @@
 			NotModuleType("prebuilt_system").
 			NotModuleType("prebuilt_first_stage_ramdisk").
 			NotModuleType("prebuilt_res").
+			NotModuleType("prebuilt_any").
 			Because("install_in_root is only for init_first_stage or librecovery_ui_ext."),
 	}
 }
@@ -287,45 +289,49 @@
 	}
 }
 
-func createLimitDirgroupRule() []Rule {
-	reason := "dirgroup module and dir_srcs / keep_gendir property of genrule is allowed only to Trusty build rule."
+func createLimitDirgroupRules() []Rule {
+	reason := "The dirgroup module can only be used with Trusty visibility"
+	scriptsDirsList := []string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"}
 	return []Rule{
 		NeverAllow().
 			ModuleType("dirgroup").
-			WithMatcher("visibility", NotInList([]string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"})).Because(reason),
+			WithMatcher("visibility", NotInList(scriptsDirsList)).Because(reason),
 		NeverAllow().
 			ModuleType("dirgroup").
-			WithoutMatcher("visibility", InAllowedList([]string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"})).Because(reason),
+			WithoutMatcher("visibility", InAllowedList(scriptsDirsList)).Because(reason),
+	}
+}
+
+func createLimitGenruleRules() []Rule {
+	dirSrcsReason := "The `dir_srcs` property in a `genrule` module can only be used by Trusty"
+	keepGendirReason := "The `keep_gendir` property in a `genrule` module can only be used by Trusty"
+	allowedModuleNameList := []string{
+		// Trusty TEE target names
+		"trusty_tee_package_goog",
+		"trusty_tee_package",
+		// Trusty vm target names
+		"trusty_desktop_vm_arm64.bin",
+		"trusty_desktop_vm_x86_64.elf",
+		"trusty_desktop_test_vm_arm64.bin",
+		"trusty_desktop_test_vm_x86_64.elf",
+		"trusty_test_vm_arm64.bin",
+		"trusty_test_vm_x86_64.elf",
+		"trusty_test_vm_os_arm64.bin",
+		"trusty_test_vm_os_x86_64.elf",
+		"trusty_security_vm_arm64.bin",
+		"trusty_security_vm_x86_64.elf",
+		"trusty_widevine_vm_arm64.bin",
+		"trusty_widevine_vm_x86_64.elf",
+	}
+	return []Rule{
 		NeverAllow().
 			ModuleType("genrule").
-			// TODO: remove the 4 below targets once new targets are submitted
-			Without("name", "trusty-arm64.lk.elf.gen").
-			Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen").
-			Without("name", "trusty-x86_64.lk.elf.gen").
-			Without("name", "trusty-x86_64-test.lk.elf.gen").
-			// trusty vm target names moving forward
-			Without("name", "trusty-test_vm-arm64.elf.gen").
-			Without("name", "trusty-test_vm-x86.elf.gen").
-			Without("name", "trusty-security_vm-arm64.elf.gen").
-			Without("name", "trusty-security_vm-x86.elf.gen").
-			Without("name", "trusty-widevine_vm-arm64.elf.gen").
-			Without("name", "trusty-widevine_vm-x86.elf.gen").
-			WithMatcher("dir_srcs", isSetMatcherInstance).Because(reason),
+			WithoutMatcher("name", InAllowedList(allowedModuleNameList)).
+			WithMatcher("dir_srcs", isSetMatcherInstance).Because(dirSrcsReason),
 		NeverAllow().
 			ModuleType("genrule").
-			// TODO: remove the 4 below targets once new targets are submitted
-			Without("name", "trusty-arm64.lk.elf.gen").
-			Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen").
-			Without("name", "trusty-x86_64.lk.elf.gen").
-			Without("name", "trusty-x86_64-test.lk.elf.gen").
-			// trusty vm target names moving forward
-			Without("name", "trusty-test_vm-arm64.elf.gen").
-			Without("name", "trusty-test_vm-x86.elf.gen").
-			Without("name", "trusty-security_vm-arm64.elf.gen").
-			Without("name", "trusty-security_vm-x86.elf.gen").
-			Without("name", "trusty-widevine_vm-arm64.elf.gen").
-			Without("name", "trusty-widevine_vm-x86.elf.gen").
-			With("keep_gendir", "true").Because(reason),
+			WithoutMatcher("name", InAllowedList(allowedModuleNameList)).
+			With("keep_gendir", "true").Because(keepGendirReason),
 	}
 }
 
@@ -363,6 +369,7 @@
 func createPrebuiltEtcBpDefineRule() Rule {
 	return NeverAllow().
 		ModuleType(
+			"prebuilt_any",
 			"prebuilt_usr_srec",
 			"prebuilt_priv_app",
 			"prebuilt_rfs",
@@ -378,6 +385,9 @@
 			"prebuilt_sbin",
 			"prebuilt_system",
 			"prebuilt_first_stage_ramdisk",
+			"prebuilt_radio",
+			"prebuilt_gpu",
+			"prebuilt_vendor_overlay",
 		).
 		DefinedInBpFile().
 		Because("module type not allowed to be defined in bp file")
@@ -409,7 +419,8 @@
 			continue
 		}
 
-		if !n.appliesToModuleType(ctx.ModuleType()) {
+		modType := proptools.StringDefault(m.base().baseProperties.Soong_config_base_module_type, ctx.ModuleType())
+		if !n.appliesToModuleType(modType) {
 			continue
 		}
 
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index c74d5ff..3ccc883 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -388,6 +388,30 @@
 			`module type not allowed to be defined in bp file`,
 		},
 	},
+	// Test the a neverallowed module type can't be smuggled through a soong config module type
+	{
+		name: `smuggling module types through soong config modules`,
+		fs: map[string][]byte{
+			"a/b/Android.bp": []byte(`
+				soong_config_bool_variable {
+					name: "my_var",
+				}
+				soong_config_module_type {
+					name: "smuggled_prebuilt_usr_srec",
+					module_type: "prebuilt_usr_srec",
+					config_namespace: "ANDROID",
+					variables: ["my_var"],
+					properties: ["enabled"],
+				}
+				smuggled_prebuilt_usr_srec {
+					name: "foo",
+				}
+			`),
+		},
+		expectedErrors: []string{
+			`module type not allowed to be defined in bp file`,
+		},
+	},
 }
 
 var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -399,6 +423,7 @@
 		ctx.RegisterModuleType("filesystem", newMockFilesystemModule)
 		ctx.RegisterModuleType("prebuilt_usr_srec", newMockPrebuiltUsrSrecModule)
 	}),
+	PrepareForTestWithSoongConfigModuleBuildComponents,
 )
 
 func TestNeverallow(t *testing.T) {
diff --git a/android/notices.go b/android/notices.go
index 3c41d92..dc2290c 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -18,9 +18,11 @@
 	"fmt"
 	"path/filepath"
 	"strings"
+
+	"github.com/google/blueprint"
 )
 
-func modulesOutputDirs(ctx BuilderContext, modules ...Module) []string {
+func modulesOutputDirs(ctx BuilderContext, modules ...ModuleProxy) []string {
 	dirs := make([]string, 0, len(modules))
 	for _, module := range modules {
 		paths, err := outputFilesForModule(ctx, module, "")
@@ -41,12 +43,12 @@
 	OtherModuleProviderContext
 }
 
-func modulesLicenseMetadata(ctx OtherModuleProviderContext, modules ...Module) Paths {
+func modulesLicenseMetadata(ctx OtherModuleProviderContext, modules ...ModuleProxy) Paths {
 	result := make(Paths, 0, len(modules))
 	mctx, isMctx := ctx.(ModuleContext)
 	for _, module := range modules {
 		var mf Path
-		if isMctx && mctx.Module() == module {
+		if isMctx && EqualModules(mctx.Module(), module) {
 			mf = mctx.LicenseMetadataFile()
 		} else {
 			mf = OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).LicenseMetadataFile
@@ -61,12 +63,12 @@
 // buildNoticeOutputFromLicenseMetadata writes out a notice file.
 func buildNoticeOutputFromLicenseMetadata(
 	ctx BuilderAndOtherModuleProviderContext, tool, ruleName string, outputFile WritablePath,
-	libraryName string, stripPrefix []string, modules ...Module) {
+	libraryName string, stripPrefix []string, modules ...ModuleProxy) {
 	depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
 	rule := NewRuleBuilder(pctx, ctx)
 	if len(modules) == 0 {
 		if mctx, ok := ctx.(ModuleContext); ok {
-			modules = []Module{mctx.Module()}
+			modules = []ModuleProxy{{blueprint.CreateModuleProxy(mctx.Module())}}
 		} else {
 			panic(fmt.Errorf("%s %q needs a module to generate the notice for", ruleName, libraryName))
 		}
@@ -97,7 +99,7 @@
 // current context module if none given.
 func BuildNoticeTextOutputFromLicenseMetadata(
 	ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
-	stripPrefix []string, modules ...Module) {
+	stripPrefix []string, modules ...ModuleProxy) {
 	buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName,
 		outputFile, libraryName, stripPrefix, modules...)
 }
@@ -107,7 +109,7 @@
 // current context module if none given.
 func BuildNoticeHtmlOutputFromLicenseMetadata(
 	ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
-	stripPrefix []string, modules ...Module) {
+	stripPrefix []string, modules ...ModuleProxy) {
 	buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName,
 		outputFile, libraryName, stripPrefix, modules...)
 }
@@ -117,7 +119,7 @@
 // current context module if none given.
 func BuildNoticeXmlOutputFromLicenseMetadata(
 	ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
-	stripPrefix []string, modules ...Module) {
+	stripPrefix []string, modules ...ModuleProxy) {
 	buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName,
 		outputFile, libraryName, stripPrefix, modules...)
 }
diff --git a/android/override_module.go b/android/override_module.go
index 50ddc9b..96620ef 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -367,6 +367,7 @@
 }
 
 func overridableModuleDepsMutator(ctx BottomUpMutatorContext) {
+	ctx.Module().base().baseOverridablePropertiesDepsMutator(ctx)
 	if b, ok := ctx.Module().(OverridableModule); ok && b.Enabled(ctx) {
 		b.OverridablePropertiesDepsMutator(ctx)
 	}
diff --git a/android/package.go b/android/package.go
index 385326e..52bddf9 100644
--- a/android/package.go
+++ b/android/package.go
@@ -38,6 +38,12 @@
 	Default_team                *string `android:"path"`
 }
 
+type PackageInfo struct {
+	Properties packageProperties
+}
+
+var PackageInfoProvider = blueprint.NewProvider[PackageInfo]()
+
 type packageModule struct {
 	ModuleBase
 
@@ -56,10 +62,14 @@
 }
 
 func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
-	ctx.SetProvider(CommonModuleInfoKey, CommonModuleInfo{
+	ctx.SetProvider(CommonModuleInfoProvider, &CommonModuleInfo{
 		Enabled:                 true,
 		PrimaryLicensesProperty: p.primaryLicensesProperty,
 	})
+
+	ctx.SetProvider(PackageInfoProvider, PackageInfo{
+		Properties: p.properties,
+	})
 }
 
 func (p *packageModule) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
diff --git a/android/packaging.go b/android/packaging.go
index 6146f02..bb1fe4e 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -89,6 +89,8 @@
 	ArchType              ArchType
 	Overrides             []string
 	Owner                 string
+	RequiresFullInstall   bool
+	FullInstallPath       InstallPath
 	Variation             string
 }
 
@@ -113,6 +115,8 @@
 		ArchType:              p.archType,
 		Overrides:             p.overrides.ToSlice(),
 		Owner:                 p.owner,
+		RequiresFullInstall:   p.requiresFullInstall,
+		FullInstallPath:       p.fullInstallPath,
 		Variation:             p.variation,
 	}
 }
@@ -129,6 +133,8 @@
 	p.archType = data.ArchType
 	p.overrides = uniquelist.Make(data.Overrides)
 	p.owner = data.Owner
+	p.requiresFullInstall = data.RequiresFullInstall
+	p.fullInstallPath = data.FullInstallPath
 	p.variation = data.Variation
 }
 
diff --git a/android/paths.go b/android/paths.go
index 1c0321c..977473f 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -209,6 +209,10 @@
 
 var _ ModuleErrorfContext = blueprint.ModuleContext(nil)
 
+type AddMissingDependenciesContext interface {
+	AddMissingDependencies([]string)
+}
+
 // reportPathError will register an error with the attached context. It
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
@@ -220,7 +224,9 @@
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
 func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
-	if mctx, ok := ctx.(ModuleErrorfContext); ok {
+	if mctx, ok := ctx.(AddMissingDependenciesContext); ok && ctx.Config().AllowMissingDependencies() {
+		mctx.AddMissingDependencies([]string{fmt.Sprintf(format, args...)})
+	} else if mctx, ok := ctx.(ModuleErrorfContext); ok {
 		mctx.ModuleErrorf(format, args...)
 	} else if ectx, ok := ctx.(errorfContext); ok {
 		ectx.Errorf(format, args...)
@@ -229,6 +235,8 @@
 	}
 }
 
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
 func pathContextName(ctx PathContext, module blueprint.Module) string {
 	if x, ok := ctx.(interface{ ModuleName(blueprint.Module) string }); ok {
 		return x.ModuleName(module)
@@ -675,7 +683,7 @@
 	if module == nil {
 		return nil, missingDependencyError{[]string{moduleName}}
 	}
-	if !OtherModuleProviderOrDefault(ctx, *module, CommonModuleInfoKey).Enabled {
+	if !OtherModulePointerProviderOrDefault(ctx, *module, CommonModuleInfoProvider).Enabled {
 		return nil, missingDependencyError{[]string{moduleName}}
 	}
 
diff --git a/android/phony.go b/android/phony.go
index 7bdd9d3..99ff0aa 100644
--- a/android/phony.go
+++ b/android/phony.go
@@ -55,7 +55,7 @@
 
 func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) {
 	p.phonyMap = getSingletonPhonyMap(ctx.Config())
-	ctx.VisitAllModules(func(m Module) {
+	ctx.VisitAllModuleProxies(func(m ModuleProxy) {
 		if info, ok := OtherModuleProvider(ctx, m, ModulePhonyProvider); ok {
 			for k, v := range info.Phonies {
 				p.phonyMap[k] = append(p.phonyMap[k], v...)
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 7273599..1ff009b 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -358,7 +358,7 @@
 }
 
 func IsModulePreferredProxy(ctx OtherModuleProviderContext, module ModuleProxy) bool {
-	if OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).ReplacedByPrebuilt {
+	if OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).ReplacedByPrebuilt {
 		// A source module that has been replaced by a prebuilt counterpart.
 		return false
 	}
@@ -397,7 +397,7 @@
 // the right module. This function is only safe to call after all TransitionMutators
 // have run, e.g. in GenerateAndroidBuildActions.
 func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module {
-	if !OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).ReplacedByPrebuilt {
+	if !OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).ReplacedByPrebuilt {
 		return module
 	}
 	if _, ok := OtherModuleProvider(ctx, module, PrebuiltModuleInfoProvider); ok {
@@ -412,7 +412,7 @@
 		if prebuiltMod != nil {
 			return false
 		}
-		if ctx.EqualModules(parent, ctx.Module()) {
+		if EqualModules(parent, ctx.Module()) {
 			// First level: Only recurse if the module is found as a direct dependency.
 			sourceModDepFound = child == module
 			return sourceModDepFound
@@ -607,11 +607,6 @@
 		if !moduleInFamily.ExportedToMake() {
 			continue
 		}
-		// Skip for the top-level java_sdk_library_(_import). This has some special cases that need to be addressed first.
-		// This does not run into non-determinism because PrebuiltPostDepsMutator also has the special case
-		if sdkLibrary, ok := moduleInFamily.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
-			continue
-		}
 		if p := GetEmbeddedPrebuilt(moduleInFamily); p != nil && p.properties.UsePrebuilt {
 			if selectedPrebuilt == nil {
 				selectedPrebuilt = moduleInFamily
@@ -638,26 +633,10 @@
 	if p := GetEmbeddedPrebuilt(m); p != nil {
 		bmn, _ := m.(baseModuleName)
 		name := bmn.BaseModuleName()
-		psi := PrebuiltSelectionInfoMap{}
-		ctx.VisitDirectDepsWithTag(AcDepTag, func(am Module) {
-			psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
-		})
 
 		if p.properties.UsePrebuilt {
 			if p.properties.SourceExists {
 				ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
-					if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
-						// Do not replace deps to the top-level prebuilt java_sdk_library hook.
-						// This hook has been special-cased in #isSelected to be _always_ active, even in next builds
-						// for dexpreopt and hiddenapi processing.
-						// If we do not special-case this here, rdeps referring to a java_sdk_library in next builds via libs
-						// will get prebuilt stubs
-						// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
-						if psi.IsSelected(name) {
-							return false
-						}
-					}
-
 					if t, ok := tag.(ReplaceSourceWithPrebuilt); ok {
 						return t.ReplaceSourceWithPrebuilt()
 					}
@@ -679,23 +658,13 @@
 // java_sdk_library_import is a macro that creates
 // 1. top-level "impl" library
 // 2. stub libraries (suffixed with .stubs...)
-//
-// the impl of java_sdk_library_import is a "hook" for hiddenapi and dexpreopt processing. It does not have an impl jar, but acts as a shim
-// to provide the jar deapxed from the prebuilt apex
-//
-// isSelected uses `all_apex_contributions` to supersede source vs prebuilts selection of the stub libraries. It does not supersede the
-// selection of the top-level "impl" library so that this hook can work
-//
-// TODO (b/308174306) - Fix this when we need to support multiple prebuilts in main
 func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool {
 	if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
 		sln := proptools.String(sdkLibrary.SdkLibraryName())
 
 		// This is the top-level library
-		// Do not supersede the existing prebuilts vs source selection mechanisms
-		// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
 		if bmn, ok := m.(baseModuleName); ok && sln == bmn.BaseModuleName() {
-			return false
+			return psi.IsSelected(m.Name())
 		}
 
 		// Stub library created by java_sdk_library_import
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index 17b3230..7773bf8 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -84,13 +84,12 @@
 	t.toolPath = OptionalPathForPath(installedPath)
 }
 
-func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
-	if makeVar := String(t.properties.Export_to_make_var); makeVar != "" {
-		if t.Target().Os != ctx.Config().BuildOS {
-			return
-		}
-		ctx.StrictRaw(makeVar, t.toolPath.String())
+func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) []ModuleMakeVarsValue {
+	if makeVar := String(t.properties.Export_to_make_var); makeVar != "" &&
+		t.Target().Os == ctx.Config().BuildOS {
+		return []ModuleMakeVarsValue{{makeVar, t.toolPath.String()}}
 	}
+	return nil
 }
 
 func (t *prebuiltBuildTool) HostToolPath() OptionalPath {
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 27a68fb..d31fc4f 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -551,6 +551,9 @@
 }
 
 func (s *sourceModule) Srcs() Paths {
+	if s.src == nil {
+		return nil
+	}
 	return Paths{s.src}
 }
 
diff --git a/android/provider.go b/android/provider.go
index b48fd91..aae93ef 100644
--- a/android/provider.go
+++ b/android/provider.go
@@ -16,6 +16,12 @@
 var _ OtherModuleProviderContext = SingletonContext(nil)
 var _ OtherModuleProviderContext = (*TestContext)(nil)
 
+// ConfigAndOtherModuleProviderContext is OtherModuleProviderContext + ConfigContext
+type ConfigAndOtherModuleProviderContext interface {
+	OtherModuleProviderContext
+	ConfigContext
+}
+
 // OtherModuleProvider reads the provider for the given module.  If the provider has been set the value is
 // returned and the boolean is true.  If it has not been set the zero value of the provider's type  is returned
 // and the boolean is false.  The value returned may be a deep copy of the value originally passed to SetProvider.
@@ -35,6 +41,14 @@
 	return value
 }
 
+func OtherModulePointerProviderOrDefault[K *T, T any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) K {
+	if value, ok := OtherModuleProvider(ctx, module, provider); ok {
+		return value
+	}
+	var val T
+	return &val
+}
+
 // ModuleProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext
 // for use in ModuleProvider.
 type ModuleProviderContext interface {
diff --git a/android/provider_keys.go b/android/provider_keys.go
new file mode 100644
index 0000000..60b383f
--- /dev/null
+++ b/android/provider_keys.go
@@ -0,0 +1,24 @@
+// Copyright 2025 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 "github.com/google/blueprint"
+
+// Providers of package filesystem
+type AndroidDeviceInfo struct {
+	Main_device bool
+}
+
+var AndroidDeviceInfoProvider = blueprint.NewProvider[AndroidDeviceInfo]()
diff --git a/android/rule_builder.go b/android/rule_builder.go
index db56c3f..01fe6d8 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -660,12 +660,17 @@
 			}
 			for _, c := range r.commands {
 				for _, tool := range c.packagedTools {
-					command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
-						From:       proto.String(tool.srcPath.String()),
-						To:         proto.String(sboxPathForPackagedToolRel(tool)),
-						Executable: proto.Bool(tool.executable),
-					})
-					tools = append(tools, tool.srcPath)
+					if tool.srcPath != nil {
+						command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
+							From:       proto.String(tool.srcPath.String()),
+							To:         proto.String(sboxPathForPackagedToolRel(tool)),
+							Executable: proto.Bool(tool.executable),
+						})
+						tools = append(tools, tool.srcPath)
+					} else if tool.SymlinkTarget() == "" {
+						// We ignore symlinks for now, could be added later if needed
+						panic("Expected tool packagingSpec to either be a file or symlink")
+					}
 				}
 			}
 		}
@@ -1187,7 +1192,11 @@
 // Textf adds the specified formatted text to the command line.  The text should not contain input or output paths or
 // the rule will not have them listed in its dependencies or outputs.
 func (c *RuleBuilderCommand) Textf(format string, a ...interface{}) *RuleBuilderCommand {
-	return c.Text(fmt.Sprintf(format, a...))
+	if c.buf.Len() > 0 {
+		c.buf.WriteByte(' ')
+	}
+	fmt.Fprintf(&c.buf, format, a...)
+	return c
 }
 
 // Flag adds the specified raw text to the command line.  The text should not contain input or output paths or the
diff --git a/android/singleton.go b/android/singleton.go
index a03ea74..e5f2684 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -36,7 +36,7 @@
 
 	// ModuleVariantsFromName returns the list of module variants named `name` in the same namespace as `referer` enforcing visibility rules.
 	// Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context.
-	ModuleVariantsFromName(referer Module, name string) []Module
+	ModuleVariantsFromName(referer ModuleProxy, name string) []ModuleProxy
 
 	otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
 
@@ -290,6 +290,10 @@
 	return s.SingletonContext.ModuleType(getWrappedModule(module))
 }
 
+func (s *singletonContextAdaptor) BlueprintFile(module blueprint.Module) string {
+	return s.SingletonContext.BlueprintFile(getWrappedModule(module))
+}
+
 func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
 	s.SingletonContext.VisitAllModules(visit)
 }
@@ -327,7 +331,7 @@
 }
 
 func (s *singletonContextAdaptor) VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) {
-	s.SingletonContext.VisitAllModuleVariantProxies(module, visitProxyAdaptor(visit))
+	s.SingletonContext.VisitAllModuleVariantProxies(getWrappedModule(module), visitProxyAdaptor(visit))
 }
 
 func (s *singletonContextAdaptor) PrimaryModule(module Module) Module {
@@ -339,32 +343,30 @@
 }
 
 func (s *singletonContextAdaptor) IsFinalModule(module Module) bool {
-	return s.SingletonContext.IsFinalModule(module)
+	return s.SingletonContext.IsFinalModule(getWrappedModule(module))
 }
 
-func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
+func (s *singletonContextAdaptor) ModuleVariantsFromName(referer ModuleProxy, name string) []ModuleProxy {
 	// get module reference for visibility enforcement
-	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer)
+	qualified := createVisibilityModuleProxyReference(s, s.ModuleName(referer), s.ModuleDir(referer), referer)
 
-	modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
-	result := make([]Module, 0, len(modules))
-	for _, m := range modules {
-		if module, ok := m.(Module); ok {
-			// enforce visibility
-			depName := s.ModuleName(module)
-			depDir := s.ModuleDir(module)
-			depQualified := qualifiedModuleName{depDir, depName}
-			// Targets are always visible to other targets in their own package.
-			if depQualified.pkg != qualified.name.pkg {
-				rule := effectiveVisibilityRules(s.Config(), depQualified)
-				if !rule.matches(qualified) {
-					s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
-						referer.Name(), depQualified, "//"+s.ModuleDir(referer))
-					continue
-				}
+	modules := s.SingletonContext.ModuleVariantsFromName(referer.module, name)
+	result := make([]ModuleProxy, 0, len(modules))
+	for _, module := range modules {
+		// enforce visibility
+		depName := s.ModuleName(module)
+		depDir := s.ModuleDir(module)
+		depQualified := qualifiedModuleName{depDir, depName}
+		// Targets are always visible to other targets in their own package.
+		if depQualified.pkg != qualified.name.pkg {
+			rule := effectiveVisibilityRules(s.Config(), depQualified)
+			if !rule.matches(qualified) {
+				s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
+					referer.Name(), depQualified, "//"+s.ModuleDir(referer))
+				continue
 			}
-			result = append(result, module)
 		}
+		result = append(result, ModuleProxy{module})
 	}
 	return result
 }
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index e0b1d7c..a61c9d3 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -506,6 +506,10 @@
 		conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
 		props = append(props, conditionalProps.Interface())
 
+		if m, ok := module.(Module); ok {
+			m.base().baseProperties.Soong_config_base_module_type = &moduleType.BaseModuleType
+		}
+
 		// Regular Soong operation wraps the existing module factory with a
 		// conditional on Soong config variables by reading the product
 		// config variables from Make.
diff --git a/android/team.go b/android/team.go
index c273dc6..ad37f28 100644
--- a/android/team.go
+++ b/android/team.go
@@ -32,6 +32,12 @@
 	Trendy_team_id *string `json:"trendy_team_id"`
 }
 
+type TeamInfo struct {
+	Properties teamProperties
+}
+
+var TeamInfoProvider = blueprint.NewProvider[TeamInfo]()
+
 type teamModule struct {
 	ModuleBase
 	DefaultableModuleBase
@@ -48,7 +54,11 @@
 
 // Real work is done for the module that depends on us.
 // If needed, the team can serialize the config to json/proto file as well.
-func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	SetProvider(ctx, TeamInfoProvider, TeamInfo{
+		Properties: t.properties,
+	})
+}
 
 func (t *teamModule) TrendyTeamId(ctx ModuleContext) string {
 	return *t.properties.Trendy_team_id
diff --git a/android/test_suites.go b/android/test_suites.go
index 39317ec..9eaf785 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -29,10 +29,7 @@
 	return &testSuiteFiles{}
 }
 
-type testSuiteFiles struct {
-	robolectric []Path
-	ravenwood   []Path
-}
+type testSuiteFiles struct{}
 
 type TestSuiteModule interface {
 	Module
@@ -61,22 +58,22 @@
 		}
 	})
 
-	t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
-	ctx.Phony("robolectric-tests", t.robolectric...)
+	robolectricZip, robolectrictListZip := buildTestSuite(ctx, "robolectric-tests", files["robolectric-tests"])
+	ctx.Phony("robolectric-tests", robolectricZip, robolectrictListZip)
+	ctx.DistForGoal("robolectric-tests", robolectricZip, robolectrictListZip)
 
-	t.ravenwood = ravenwoodTestSuite(ctx, files["ravenwood-tests"])
-	ctx.Phony("ravenwood-tests", t.ravenwood...)
-	ctx.DistForGoal("robolectric-tests", t.robolectric...)
-	ctx.DistForGoal("ravenwood-tests", t.ravenwood...)
+	ravenwoodZip, ravenwoodListZip := buildTestSuite(ctx, "ravenwood-tests", files["ravenwood-tests"])
+	ctx.Phony("ravenwood-tests", ravenwoodZip, ravenwoodListZip)
+	ctx.DistForGoal("ravenwood-tests", ravenwoodZip, ravenwoodListZip)
 }
 
-func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path {
+func buildTestSuite(ctx SingletonContext, suiteName string, files map[string]InstallPaths) (Path, Path) {
 	var installedPaths InstallPaths
 	for _, module := range SortedKeys(files) {
 		installedPaths = append(installedPaths, files[module]...)
 	}
 
-	outputFile := pathForPackaging(ctx, "robolectric-tests.zip")
+	outputFile := pathForPackaging(ctx, suiteName+".zip")
 	rule := NewRuleBuilder(pctx, ctx)
 	rule.Command().BuiltTool("soong_zip").
 		FlagWithOutput("-o ", outputFile).
@@ -85,8 +82,8 @@
 		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
 		Flag("-sha256") // necessary to save cas_uploader's time
 
-	testList := buildTestList(ctx, "robolectric-tests_list", installedPaths)
-	testListZipOutputFile := pathForPackaging(ctx, "robolectric-tests_list.zip")
+	testList := buildTestList(ctx, suiteName+"_list", installedPaths)
+	testListZipOutputFile := pathForPackaging(ctx, suiteName+"_list.zip")
 
 	rule.Command().BuiltTool("soong_zip").
 		FlagWithOutput("-o ", testListZipOutputFile).
@@ -94,38 +91,9 @@
 		FlagWithInput("-f ", testList).
 		Flag("-sha256")
 
-	rule.Build("robolectric_tests_zip", "robolectric-tests.zip")
+	rule.Build(strings.ReplaceAll(suiteName, "-", "_")+"_zip", suiteName+".zip")
 
-	return []Path{outputFile, testListZipOutputFile}
-}
-
-func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path {
-	var installedPaths InstallPaths
-	for _, module := range SortedKeys(files) {
-		installedPaths = append(installedPaths, files[module]...)
-	}
-
-	outputFile := pathForPackaging(ctx, "ravenwood-tests.zip")
-	rule := NewRuleBuilder(pctx, ctx)
-	rule.Command().BuiltTool("soong_zip").
-		FlagWithOutput("-o ", outputFile).
-		FlagWithArg("-P ", "host/testcases").
-		FlagWithArg("-C ", pathForTestCases(ctx).String()).
-		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
-		Flag("-sha256") // necessary to save cas_uploader's time
-
-	testList := buildTestList(ctx, "ravenwood-tests_list", installedPaths)
-	testListZipOutputFile := pathForPackaging(ctx, "ravenwood-tests_list.zip")
-
-	rule.Command().BuiltTool("soong_zip").
-		FlagWithOutput("-o ", testListZipOutputFile).
-		FlagWithArg("-C ", pathForPackaging(ctx).String()).
-		FlagWithInput("-f ", testList).
-		Flag("-sha256")
-
-	rule.Build("ravenwood_tests_zip", "ravenwood-tests.zip")
-
-	return []Path{outputFile, testListZipOutputFile}
+	return outputFile, testListZipOutputFile
 }
 
 func buildTestList(ctx SingletonContext, listFile string, installedPaths InstallPaths) Path {
diff --git a/android/test_suites_test.go b/android/test_suites_test.go
index dda9329..03aa424 100644
--- a/android/test_suites_test.go
+++ b/android/test_suites_test.go
@@ -108,7 +108,8 @@
 
 func (f *fake_module) GenerateAndroidBuildActions(ctx ModuleContext) {
 	for _, output := range f.props.Outputs {
-		ctx.InstallFile(pathForTestCases(ctx), output, nil)
+		f := PathForModuleOut(ctx, output)
+		ctx.InstallFile(pathForTestCases(ctx), output, f)
 	}
 
 	SetProvider(ctx, TestSuiteInfoProvider, TestSuiteInfo{
diff --git a/android/testing.go b/android/testing.go
index 1962fde..d2949ec 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1197,11 +1197,11 @@
 
 	info := OtherModuleProviderOrDefault(ctx, mod, AndroidMkInfoProvider)
 	aconfigUpdateAndroidMkInfos(ctx, mod, info)
-	commonInfo, _ := OtherModuleProvider(ctx, mod, CommonModuleInfoKey)
-	info.PrimaryInfo.fillInEntries(ctx, mod, &commonInfo)
+	commonInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider)
+	info.PrimaryInfo.fillInEntries(ctx, mod, commonInfo)
 	if len(info.ExtraInfo) > 0 {
 		for _, ei := range info.ExtraInfo {
-			ei.fillInEntries(ctx, mod, &commonInfo)
+			ei.fillInEntries(ctx, mod, commonInfo)
 		}
 	}
 
diff --git a/android/variable.go b/android/variable.go
index 81999f3..3d5a6ae 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -65,12 +65,6 @@
 			Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
 		} `android:"arch_variant"`
 
-		// similar to `Unbundled_build`, but `Always_use_prebuilt_sdks` means that it uses prebuilt
-		// sdk specifically.
-		Always_use_prebuilt_sdks struct {
-			Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
-		} `android:"arch_variant"`
-
 		Malloc_low_memory struct {
 			Cflags              []string `android:"arch_variant"`
 			Shared_libs         []string `android:"arch_variant"`
@@ -216,6 +210,7 @@
 	Platform_display_version_name          *string  `json:",omitempty"`
 	Platform_version_name                  *string  `json:",omitempty"`
 	Platform_sdk_version                   *int     `json:",omitempty"`
+	Platform_sdk_minor_version             *int     `json:",omitempty"`
 	Platform_sdk_codename                  *string  `json:",omitempty"`
 	Platform_sdk_version_or_codename       *string  `json:",omitempty"`
 	Platform_sdk_final                     *bool    `json:",omitempty"`
@@ -553,6 +548,8 @@
 	OdmManifestFiles       []string `json:",omitempty"`
 
 	UseSoongNoticeXML *bool `json:",omitempty"`
+
+	StripByDefault *bool `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
@@ -653,6 +650,7 @@
 	ProductUseDynamicPartitions       bool                                     `json:",omitempty"`
 	ProductRetrofitDynamicPartitions  bool                                     `json:",omitempty"`
 	ProductBuildSuperPartition        bool                                     `json:",omitempty"`
+	BuildingSuperEmptyImage           bool                                     `json:",omitempty"`
 	BoardSuperPartitionSize           string                                   `json:",omitempty"`
 	BoardSuperPartitionMetadataDevice string                                   `json:",omitempty"`
 	BoardSuperPartitionBlockDevices   []string                                 `json:",omitempty"`
@@ -667,6 +665,7 @@
 	AbOtaPartitions                   []string                                 `json:",omitempty"`
 	AbOtaKeys                         []string                                 `json:",omitempty"`
 	AbOtaPostInstallConfig            []string                                 `json:",omitempty"`
+	BoardSuperImageInUpdatePackage    bool                                     `json:",omitempty"`
 
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
@@ -715,6 +714,8 @@
 	ProductFsCompression string `json:",omitempty"`
 
 	ReleaseToolsExtensionDir string `json:",omitempty"`
+
+	BoardFastbootInfoFile string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/android/visibility.go b/android/visibility.go
index 4837c7d..9153687 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -58,15 +58,29 @@
 var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
 
 type visibilityModuleReference struct {
-	name   qualifiedModuleName
-	module Module
+	name          qualifiedModuleName
+	partitionType *string
 }
 
 func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference {
-	return visibilityModuleReference{
-		name:   createQualifiedModuleName(name, dir),
-		module: module,
+	vis := visibilityModuleReference{
+		name: createQualifiedModuleName(name, dir),
 	}
+	if m, ok := module.(PartitionTypeInterface); ok {
+		pt := m.PartitionType()
+		vis.partitionType = &pt
+	}
+	return vis
+}
+
+func createVisibilityModuleProxyReference(ctx OtherModuleProviderContext, name, dir string, module ModuleProxy) visibilityModuleReference {
+	vis := visibilityModuleReference{
+		name: createQualifiedModuleName(name, dir),
+	}
+	if m, ok := OtherModuleProvider(ctx, module, PartitionTypeInfoProvider); ok {
+		vis.partitionType = &m.PartitionType
+	}
+	return vis
 }
 
 // A visibility rule is associated with a module and determines which other modules it is visible
@@ -222,9 +236,17 @@
 	PartitionType() string
 }
 
+type PartitionTypeInfo struct {
+	// Identifies which partition this is for //visibility:any_system_image (and others) visibility
+	// checks, and will be used in the future for API surface checks.
+	PartitionType string
+}
+
+var PartitionTypeInfoProvider = blueprint.NewProvider[PartitionTypeInfo]()
+
 func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
-	if m2, ok := m.module.(PartitionTypeInterface); ok {
-		return m2.PartitionType() == r.partitionType
+	if m.partitionType != nil {
+		return *m.partitionType == r.partitionType
 	}
 	return false
 }
@@ -529,7 +551,7 @@
 
 		rule := effectiveVisibilityRules(ctx.Config(), depQualified)
 		if !rule.matches(qualified) {
-			ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility, %#v", depQualified, "//"+ctx.ModuleDir(), ctx.OtherModuleDependencyTag(dep))
+			ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility", depQualified, "//"+ctx.ModuleDir())
 		}
 	})
 }
@@ -647,42 +669,6 @@
 	return v.rules
 }
 
-// Get the effective visibility rules, i.e. the actual rules that affect the visibility of the
-// property irrespective of where they are defined.
-//
-// Includes visibility rules specified by package default_visibility and/or on defaults.
-// Short hand forms, e.g. //:__subpackages__ are replaced with their full form, e.g.
-// //package/containing/rule:__subpackages__.
-func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) VisibilityRuleSet {
-	moduleName := ctx.OtherModuleName(module)
-	dir := ctx.OtherModuleDir(module)
-	qualified := qualifiedModuleName{dir, moduleName}
-
-	rule := effectiveVisibilityRules(ctx.Config(), qualified)
-
-	currentModule := createVisibilityModuleReference(moduleName, dir, module)
-
-	// Modules are implicitly visible to other modules in the same package,
-	// without checking the visibility rules. Here we need to add that visibility
-	// explicitly.
-	if !rule.matches(currentModule) {
-		if len(rule) == 1 {
-			if _, ok := rule[0].(privateRule); ok {
-				// If the rule is //visibility:private we can't append another
-				// visibility to it. Semantically we need to convert it to a package
-				// visibility rule for the location where the result is used, but since
-				// modules are implicitly visible within the package we get the same
-				// result without any rule at all, so just make it an empty list to be
-				// appended below.
-				rule = nil
-			}
-		}
-		rule = append(rule, packageRule{dir})
-	}
-
-	return &visibilityRuleSet{rule.Strings()}
-}
-
 // Clear the default visibility properties so they can be replaced.
 func clearVisibilityProperties(module Module) {
 	module.base().visibilityPropertyInfo = nil
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 277be0f..4acaa02 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -2112,7 +2112,10 @@
 	ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
 }
 
-func (p *mockFilesystemModule) GenerateAndroidBuildActions(ModuleContext) {
+func (p *mockFilesystemModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	SetProvider(ctx, PartitionTypeInfoProvider, PartitionTypeInfo{
+		PartitionType: p.PartitionType(),
+	})
 }
 
 func (p *mockFilesystemModule) PartitionType() string {
diff --git a/apex/apex.go b/apex/apex.go
index 6e4685b..c6566e1 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,6 +18,7 @@
 
 import (
 	"fmt"
+	"path"
 	"path/filepath"
 	"regexp"
 	"slices"
@@ -549,6 +550,9 @@
 
 	// Required modules, filled out during GenerateAndroidBuildActions and used in AndroidMk
 	required []string
+
+	// appinfo of the apk-in-apex of this module
+	appInfos java.AppInfos
 }
 
 // apexFileClass represents a type of file that can be included in APEX.
@@ -1498,7 +1502,7 @@
 func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module android.Module,
 	javaInfo *java.JavaInfo, dexImplementationJar android.Path) apexFile {
 	dirInApex := "javalib"
-	commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey)
+	commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider)
 	af := newApexFile(ctx, dexImplementationJar, commonInfo.BaseModuleName, dirInApex, javaSharedLib, module)
 	af.jacocoReportClassesFile = javaInfo.JacocoReportClassesFile
 	if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok {
@@ -1603,35 +1607,8 @@
 // to the child modules. Returning false makes the visit to continue in the sibling or the parent
 // modules. This is used in check* functions below.
 func (a *apexBundle) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
-	ctx.WalkDeps(func(child, parent android.Module) bool {
-		am, ok := child.(android.ApexModule)
-		if !ok || !am.CanHaveApexVariants() {
-			return false
-		}
-
-		// Filter-out unwanted depedendencies
-		depTag := ctx.OtherModuleDependencyTag(child)
-		if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
-			return false
-		}
-		if dt, ok := depTag.(*dependencyTag); ok && !dt.payload {
-			return false
-		}
-		if depTag == android.RequiredDepTag {
-			return false
-		}
-
-		externalDep := !android.IsDepInSameApex(ctx, parent, child)
-
-		// Visit actually
-		return do(ctx, parent, am, externalDep)
-	})
-}
-
-func (a *apexBundle) WalkPayloadDepsProxy(ctx android.BaseModuleContext,
-	do func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool) {
 	ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
-		if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).CanHaveApexVariants {
+		if !android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider).CanHaveApexVariants {
 			return false
 		}
 		// Filter-out unwanted depedendencies
@@ -1844,12 +1821,12 @@
 	if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
 		return false
 	}
-	commonInfo := android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey)
+	commonInfo := android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider)
 	if !commonInfo.Enabled {
 		return false
 	}
 	depName := ctx.OtherModuleName(child)
-	if ctx.EqualModules(parent, ctx.Module()) {
+	if android.EqualModules(parent, ctx.Module()) {
 		switch depTag {
 		case sharedLibTag, jniLibTag:
 			isJniLib := depTag == jniLibTag
@@ -1862,7 +1839,7 @@
 				if ch.IsStubs {
 					ctx.PropertyErrorf(propertyName, "%q is a stub. Remove it from the list.", depName)
 				}
-				fi := apexFileForNativeLibrary(ctx, child, &commonInfo, ch, vctx.handleSpecialLibs)
+				fi := apexFileForNativeLibrary(ctx, child, commonInfo, ch, vctx.handleSpecialLibs)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
 				// Collect the list of stub-providing libs except:
@@ -1879,11 +1856,11 @@
 
 		case executableTag:
 			if ccInfo, ok := android.OtherModuleProvider(ctx, child, cc.CcInfoProvider); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, child, &commonInfo, ccInfo))
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, child, commonInfo, ccInfo))
 				return true // track transitive dependencies
 			}
 			if _, ok := android.OtherModuleProvider(ctx, child, rust.RustInfoProvider); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, child, &commonInfo))
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, child, commonInfo))
 				return true // track transitive dependencies
 			} else {
 				ctx.PropertyErrorf("binaries",
@@ -1891,7 +1868,7 @@
 			}
 		case shBinaryTag:
 			if csh, ok := android.OtherModuleProvider(ctx, child, sh.ShBinaryInfoProvider); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, child, &commonInfo, &csh))
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, child, commonInfo, &csh))
 			} else {
 				ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
 			}
@@ -1930,6 +1907,7 @@
 			}
 		case androidAppTag:
 			if appInfo, ok := android.OtherModuleProvider(ctx, child, java.AppInfoProvider); ok {
+				a.appInfos = append(a.appInfos, *appInfo)
 				if appInfo.AppSet {
 					appDir := "app"
 					if appInfo.Privileged {
@@ -1944,7 +1922,7 @@
 					af.certificate = java.PresignedCertificate
 					vctx.filesInfo = append(vctx.filesInfo, af)
 				} else {
-					vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, child, &commonInfo, appInfo)...)
+					vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, child, commonInfo, appInfo)...)
 					if !appInfo.Prebuilt && !appInfo.TestHelperApp {
 						return true // track transitive dependencies
 					}
@@ -1991,7 +1969,7 @@
 			}
 		case testTag:
 			if ccInfo, ok := android.OtherModuleProvider(ctx, child, cc.CcInfoProvider); ok {
-				af := apexFileForExecutable(ctx, child, &commonInfo, ccInfo)
+				af := apexFileForExecutable(ctx, child, commonInfo, ccInfo)
 				af.class = nativeTest
 				vctx.filesInfo = append(vctx.filesInfo, af)
 				return true // track transitive dependencies
@@ -2028,7 +2006,7 @@
 	// tags used below are private (e.g. `cc.sharedDepTag`).
 	if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
 		if ch, ok := android.OtherModuleProvider(ctx, child, cc.LinkableInfoProvider); ok {
-			af := apexFileForNativeLibrary(ctx, child, &commonInfo, ch, vctx.handleSpecialLibs)
+			af := apexFileForNativeLibrary(ctx, child, commonInfo, ch, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 
 			if ch.IsStubs || ch.HasStubsVariants {
@@ -2090,7 +2068,7 @@
 			}
 
 			linkableInfo := android.OtherModuleProviderOrDefault(ctx, child, cc.LinkableInfoProvider)
-			af := apexFileForNativeLibrary(ctx, child, &commonInfo, linkableInfo, vctx.handleSpecialLibs)
+			af := apexFileForNativeLibrary(ctx, child, commonInfo, linkableInfo, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
 			return true // track transitive dependencies
@@ -2122,7 +2100,7 @@
 			javaInfo := android.OtherModuleProviderOrDefault(ctx, child, java.JavaInfoProvider)
 			af := apexFileForJavaModule(ctx, child, javaInfo)
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			if profileAf := apexFileForJavaModuleProfile(ctx, &commonInfo, javaInfo); profileAf != nil {
+			if profileAf := apexFileForJavaModuleProfile(ctx, commonInfo, javaInfo); profileAf != nil {
 				vctx.filesInfo = append(vctx.filesInfo, *profileAf)
 			}
 			return true // track transitive dependencies
@@ -2138,7 +2116,7 @@
 		ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
 	} else if android.IsVintfDepTag(depTag) {
 		if vf, ok := android.OtherModuleProvider(ctx, child, android.VintfFragmentInfoProvider); ok {
-			apexFile := apexFileForVintfFragment(ctx, child, &commonInfo, &vf)
+			apexFile := apexFileForVintfFragment(ctx, child, commonInfo, &vf)
 			vctx.filesInfo = append(vctx.filesInfo, apexFile)
 		}
 	}
@@ -2258,6 +2236,16 @@
 	a.enforcePartitionTagOnApexSystemServerJar(ctx)
 
 	a.verifyNativeImplementationLibs(ctx)
+	a.enforceNoVintfInUpdatable(ctx)
+
+	android.SetProvider(ctx, android.ApexBundleDepsDataProvider, android.ApexBundleDepsData{
+		FlatListPath: a.FlatListPath(),
+		Updatable:    a.Updatable(),
+	})
+
+	android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{a.apexKeysPath})
+
+	android.SetProvider(ctx, java.AppInfosProvider, a.appInfos)
 }
 
 // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
@@ -2542,7 +2530,7 @@
 		librariesDirectlyInApex[ctx.OtherModuleName(dep)] = true
 	})
 
-	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
 		if info, ok := android.OtherModuleProvider(ctx, to, cc.LinkableInfoProvider); ok {
 			// If `to` is not actually in the same APEX as `from` then it does not need
 			// apex_available and neither do any of its dependencies.
@@ -2656,7 +2644,7 @@
 		return
 	}
 
-	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
 		// As soon as the dependency graph crosses the APEX boundary, don't go further.
 		if externalDep {
 			return false
@@ -2886,7 +2874,7 @@
 
 				tag := ctx.OtherModuleDependencyTag(child)
 
-				if ctx.EqualModules(parent, ctx.Module()) {
+				if android.EqualModules(parent, ctx.Module()) {
 					if !checkApexTag(tag) {
 						return false
 					}
@@ -2911,3 +2899,16 @@
 		}
 	}
 }
+
+// TODO(b/399527905) libvintf is not forward compatible.
+func (a *apexBundle) enforceNoVintfInUpdatable(ctx android.ModuleContext) {
+	if !a.Updatable() {
+		return
+	}
+	for _, fi := range a.filesInfo {
+		if match, _ := path.Match("etc/vintf/*", fi.path()); match {
+			ctx.ModuleErrorf("VINTF fragment (%s) is not supported in updatable APEX.", fi.path())
+			break
+		}
+	}
+}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index a8bd984..797f47b 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -90,11 +90,11 @@
 
 func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	updatableFlatLists := android.Paths{}
-	ctx.VisitAllModules(func(module android.Module) {
-		if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if binaryInfo, ok := android.OtherModuleProvider(ctx, module, android.ApexBundleDepsDataProvider); ok {
 			apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
-			if path := binaryInfo.FlatListPath(); path != nil {
-				if binaryInfo.Updatable() || apexInfo.Updatable {
+			if path := binaryInfo.FlatListPath; path != nil {
+				if binaryInfo.Updatable || apexInfo.Updatable {
 					if strings.HasPrefix(module.String(), "com.android.") {
 						updatableFlatLists = append(updatableFlatLists, path)
 					}
@@ -160,11 +160,11 @@
 func (a *apexPrebuiltInfo) GenerateBuildActions(ctx android.SingletonContext) {
 	prebuiltInfos := []android.PrebuiltInfo{}
 
-	ctx.VisitAllModules(func(m android.Module) {
+	ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
 		prebuiltInfo, exists := android.OtherModuleProvider(ctx, m, android.PrebuiltInfoProvider)
 		// Use prebuiltInfoProvider to filter out non apex soong modules.
 		// Use HideFromMake to filter out the unselected variants of a specific apex.
-		if exists && !m.IsHideFromMake() {
+		if exists && !android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider).HideFromMake {
 			prebuiltInfos = append(prebuiltInfos, prebuiltInfo)
 		}
 	})
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 9eaf814..36a6974 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -11667,7 +11667,7 @@
 
 	// Arguments passed to aconfig to retrieve the state of the flags defined in the
 	// textproto files
-	aconfigFlagArgs := m.Output("released-flagged-apis-exportable.txt").Args["flags_path"]
+	aconfigFlagArgs := m.Output("released-flags-exportable.pb").Args["flags_path"]
 
 	// "bar-lib" is a static_lib of "foo" and is passed to metalava as classpath. Thus the
 	// cache file provided by the associated aconfig_declarations module "bar" should be passed
@@ -12216,3 +12216,30 @@
 	// Ensure that vintf fragment file is being installed
 	ensureContains(t, cmd, "/etc/vintf/my_vintf_fragment.xml ")
 }
+
+func TestNoVintfFragmentInUpdatableApex(t *testing.T) {
+	t.Parallel()
+	testApexError(t, `VINTF fragment .* is not supported in updatable APEX`, apex_default_bp+`
+		apex {
+			name: "myapex",
+			manifest: ":myapex.manifest",
+			key: "myapex.key",
+			binaries: [ "mybin" ],
+			updatable: true,
+			min_sdk_version: "29",
+		}
+
+		cc_binary {
+			name: "mybin",
+			srcs: ["mybin.cpp"],
+			vintf_fragment_modules: ["my_vintf_fragment.xml"],
+			apex_available: [ "myapex" ],
+			min_sdk_version: "29",
+		}
+
+		vintf_fragment {
+			name: "my_vintf_fragment.xml",
+			src: "my_vintf_fragment.xml",
+		}
+	`)
+}
diff --git a/apex/builder.go b/apex/builder.go
index 2fc4902..23c2ed8 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -1102,7 +1102,7 @@
 	}
 
 	depInfos := android.DepNameToDepInfoMap{}
-	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
 		if from.Name() == to.Name() {
 			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
 			// As soon as the dependency graph crosses the APEX boundary, don't go further.
@@ -1111,7 +1111,7 @@
 
 		// Skip dependencies that are only available to APEXes; they are developed with updatability
 		// in mind and don't need manual approval.
-		if android.OtherModuleProviderOrDefault(ctx, to, android.CommonModuleInfoKey).NotAvailableForPlatform {
+		if android.OtherModulePointerProviderOrDefault(ctx, to, android.CommonModuleInfoProvider).NotAvailableForPlatform {
 			return !externalDep
 		}
 
@@ -1129,7 +1129,7 @@
 			depInfos[to.Name()] = info
 		} else {
 			toMinSdkVersion := "(no version)"
-			if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoKey); ok &&
+			if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoProvider); ok &&
 				!info.MinSdkVersion.IsPlatform && info.MinSdkVersion.ApiLevel != nil {
 				toMinSdkVersion = info.MinSdkVersion.ApiLevel.String()
 			}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 0a97027..89b0091 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -21,6 +21,7 @@
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
+	"android/soong/filesystem"
 	"android/soong/java"
 	"android/soong/provenance"
 
@@ -677,6 +678,8 @@
 	}
 
 	ctx.SetOutputFiles(android.Paths{p.outputApex}, "")
+
+	android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{p.apexKeysPath})
 }
 
 func (p *Prebuilt) ProvenanceMetaDataFile() android.Path {
@@ -873,4 +876,6 @@
 	}
 
 	ctx.SetOutputFiles(android.Paths{a.outputApex}, "")
+
+	android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{a.apexKeysPath})
 }
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 26f2aa8..d78a907 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -84,8 +84,8 @@
 
 func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var deps android.Paths
-	ctx.VisitAllModules(func(m android.Module) {
-		if !m.ExportedToMake() {
+	ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
+		if !android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider).ExportedToMake {
 			return
 		}
 		filePaths, ok := android.OtherModuleProvider(ctx, m, fileSizeMeasurerKey)
diff --git a/cc/afdo.go b/cc/afdo.go
index 8d8341e..9be3918 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -105,6 +105,11 @@
 		// The flags are prepended to allow overriding.
 		profileUseFlag := fmt.Sprintf(afdoFlagsFormat, fdoProfilePath)
 		flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
+		// Salvage stale profile by fuzzy matching and use the remapped location for sample profile query.
+		flags.Local.CFlags = append([]string{"-mllvm", "--salvage-stale-profile=true"}, flags.Local.CFlags...)
+		flags.Local.CFlags = append([]string{"-mllvm", "--salvage-stale-profile-max-callsites=2000"}, flags.Local.CFlags...)
+		// Salvage stale profile by fuzzy matching renamed functions.
+		flags.Local.CFlags = append([]string{"-mllvm", "--salvage-unused-profile=true"}, flags.Local.CFlags...)
 		flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
 
 		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
diff --git a/cc/api_level.go b/cc/api_level.go
index deca723..fa8dfaf 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -31,11 +31,7 @@
 	case android.Arm64, android.X86_64:
 		return android.FirstLp64Version
 	case android.Riscv64:
-		apiLevel, err := android.ApiLevelFromUser(ctx, "VanillaIceCream")
-		if err != nil {
-			panic(err)
-		}
-		return apiLevel
+		return android.FutureApiLevel
 	default:
 		panic(fmt.Errorf("Unknown arch %q", arch))
 	}
diff --git a/cc/binary.go b/cc/binary.go
index 627d5e5..608251a 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -551,6 +551,10 @@
 	binary.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
 }
 
+func (binary *binaryDecorator) testSuiteInfo(ctx ModuleContext) {
+	// not a test
+}
+
 var _ overridable = (*binaryDecorator)(nil)
 
 func init() {
diff --git a/cc/cc.go b/cc/cc.go
index 4b314cd..85d2ebf 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -81,18 +81,23 @@
 	HeaderLibs               []string
 	ImplementationModuleName *string
 
-	BinaryDecoratorInfo    *BinaryDecoratorInfo
-	LibraryDecoratorInfo   *LibraryDecoratorInfo
-	TestBinaryInfo         *TestBinaryInfo
-	BenchmarkDecoratorInfo *BenchmarkDecoratorInfo
-	ObjectLinkerInfo       *ObjectLinkerInfo
-	StubDecoratorInfo      *StubDecoratorInfo
+	BinaryDecoratorInfo       *BinaryDecoratorInfo
+	LibraryDecoratorInfo      *LibraryDecoratorInfo
+	TestBinaryInfo            *TestBinaryInfo
+	BenchmarkDecoratorInfo    *BenchmarkDecoratorInfo
+	ObjectLinkerInfo          *ObjectLinkerInfo
+	StubDecoratorInfo         *StubDecoratorInfo
+	PrebuiltLibraryLinkerInfo *PrebuiltLibraryLinkerInfo
 }
 
 type BinaryDecoratorInfo struct{}
 type LibraryDecoratorInfo struct {
 	ExportIncludeDirs []string
 	InjectBsslHash    bool
+	// Location of the static library in the sysroot. Empty if the library is
+	// not included in the NDK.
+	NdkSysrootPath android.Path
+	VndkFileName   string
 }
 
 type SnapshotInfo struct {
@@ -104,14 +109,38 @@
 }
 type BenchmarkDecoratorInfo struct{}
 
-type StubDecoratorInfo struct{}
+type StubDecoratorInfo struct {
+	AbiDumpPath  android.OutputPath
+	HasAbiDump   bool
+	AbiDiffPaths android.Paths
+	InstallPath  android.Path
+}
 
-type ObjectLinkerInfo struct{}
+type ObjectLinkerInfo struct {
+	// Location of the object in the sysroot. Empty if the object is not
+	// included in the NDK.
+	NdkSysrootPath android.Path
+}
+
+type PrebuiltLibraryLinkerInfo struct {
+	VndkFileName string
+}
 
 type LibraryInfo struct {
 	BuildStubs bool
 }
 
+type InstallerInfo struct {
+	StubDecoratorInfo *StubDecoratorInfo
+}
+
+type LocalOrGlobalFlagsInfo struct {
+	CommonFlags []string // Flags that apply to C, C++, and assembly source files
+	CFlags      []string // Flags that apply to C and C++ source files
+	ConlyFlags  []string // Flags that apply to C source files
+	CppFlags    []string // Flags that apply to C++ source files
+}
+
 // Common info about the cc module.
 type CcInfo struct {
 	IsPrebuilt             bool
@@ -122,6 +151,7 @@
 	LinkerInfo             *LinkerInfo
 	SnapshotInfo           *SnapshotInfo
 	LibraryInfo            *LibraryInfo
+	InstallerInfo          *InstallerInfo
 }
 
 var CcInfoProvider = blueprint.NewProvider[*CcInfo]()
@@ -131,6 +161,7 @@
 	StaticExecutable     bool
 	Static               bool
 	Shared               bool
+	Header               bool
 	HasStubsVariants     bool
 	StubsVersion         string
 	IsStubs              bool
@@ -176,6 +207,13 @@
 	// Symlinks returns a list of symlinks that should be created for this module.
 	Symlinks               []string
 	APIListCoverageXMLPath android.ModuleOutPath
+	// FuzzSharedLibraries returns the shared library dependencies for this module.
+	// Expects that IsFuzzModule returns true.
+	FuzzSharedLibraries      android.RuleBuilderInstalls
+	IsVndkPrebuiltLibrary    bool
+	HasLLNDKStubs            bool
+	IsLLNDKMovedToApex       bool
+	ImplementationModuleName string
 }
 
 var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]()
@@ -759,6 +797,8 @@
 	defaultDistFiles() []android.Path
 
 	moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
+
+	testSuiteInfo(ctx ModuleContext)
 }
 
 // specifiedDeps is a tuple struct representing dependencies of a linked binary owned by the linker.
@@ -2336,8 +2376,11 @@
 		case *binaryDecorator:
 			ccInfo.LinkerInfo.BinaryDecoratorInfo = &BinaryDecoratorInfo{}
 		case *libraryDecorator:
+			lk := c.linker.(*libraryDecorator)
 			ccInfo.LinkerInfo.LibraryDecoratorInfo = &LibraryDecoratorInfo{
-				InjectBsslHash: Bool(c.linker.(*libraryDecorator).Properties.Inject_bssl_hash),
+				InjectBsslHash: Bool(lk.Properties.Inject_bssl_hash),
+				NdkSysrootPath: lk.ndkSysrootPath,
+				VndkFileName:   lk.getLibNameHelper(c.BaseModuleName(), true, false) + ".so",
 			}
 		case *testBinary:
 			ccInfo.LinkerInfo.TestBinaryInfo = &TestBinaryInfo{
@@ -2346,9 +2389,16 @@
 		case *benchmarkDecorator:
 			ccInfo.LinkerInfo.BenchmarkDecoratorInfo = &BenchmarkDecoratorInfo{}
 		case *objectLinker:
-			ccInfo.LinkerInfo.ObjectLinkerInfo = &ObjectLinkerInfo{}
+			ccInfo.LinkerInfo.ObjectLinkerInfo = &ObjectLinkerInfo{
+				NdkSysrootPath: c.linker.(*objectLinker).ndkSysrootPath,
+			}
 		case *stubDecorator:
 			ccInfo.LinkerInfo.StubDecoratorInfo = &StubDecoratorInfo{}
+		case *prebuiltLibraryLinker:
+			ccInfo.LinkerInfo.PrebuiltLibraryLinkerInfo = &PrebuiltLibraryLinkerInfo{
+				VndkFileName: c.linker.(*prebuiltLibraryLinker).getLibNameHelper(
+					c.BaseModuleName(), true, false) + ".so",
+			}
 		}
 
 		if s, ok := c.linker.(SnapshotInterface); ok {
@@ -2360,12 +2410,25 @@
 			name := v.ImplementationModuleName(ctx.OtherModuleName(c))
 			ccInfo.LinkerInfo.ImplementationModuleName = &name
 		}
+
+		c.linker.testSuiteInfo(ctx)
 	}
 	if c.library != nil {
 		ccInfo.LibraryInfo = &LibraryInfo{
 			BuildStubs: c.library.BuildStubs(),
 		}
 	}
+	if c.installer != nil {
+		ccInfo.InstallerInfo = &InstallerInfo{}
+		if installer, ok := c.installer.(*stubDecorator); ok {
+			ccInfo.InstallerInfo.StubDecoratorInfo = &StubDecoratorInfo{
+				HasAbiDump:   installer.hasAbiDump,
+				AbiDumpPath:  installer.abiDumpPath,
+				AbiDiffPaths: installer.abiDiffPaths,
+				InstallPath:  installer.installPath,
+			}
+		}
+	}
 	android.SetProvider(ctx, CcInfoProvider, &ccInfo)
 
 	c.setOutputFiles(ctx)
@@ -2407,12 +2470,23 @@
 		Multilib:                        mod.Multilib(),
 		ImplementationModuleNameForMake: mod.ImplementationModuleNameForMake(),
 		Symlinks:                        mod.Symlinks(),
+		Header:                          mod.Header(),
+		IsVndkPrebuiltLibrary:           mod.IsVndkPrebuiltLibrary(),
 	}
 
 	vi := mod.VersionedInterface()
 	if vi != nil {
 		info.IsStubsImplementationRequired = vi.IsStubsImplementationRequired()
 		info.APIListCoverageXMLPath = vi.GetAPIListCoverageXMLPath()
+		info.HasLLNDKStubs = vi.HasLLNDKStubs()
+		info.IsLLNDKMovedToApex = vi.IsLLNDKMovedToApex()
+		info.ImplementationModuleName = vi.ImplementationModuleName(mod.BaseModuleName())
+	}
+
+	if !mod.PreventInstall() && fuzz.IsValid(ctx, mod.FuzzModuleStruct()) && mod.IsFuzzModule() {
+		info.FuzzSharedLibraries = mod.FuzzSharedLibraries()
+		fm := mod.FuzzPackagedModule()
+		fuzz.SetFuzzPackagedModuleInfo(ctx, &fm)
 	}
 
 	return info
@@ -3348,7 +3422,7 @@
 			return
 		}
 
-		commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider)
 		if commonInfo.Target.Os != ctx.Os() {
 			ctx.ModuleErrorf("OS mismatch between %q (%s) and %q (%s)", ctx.ModuleName(), ctx.Os().Name, depName, dep.Target().Os.Name)
 			return
@@ -3602,7 +3676,7 @@
 					c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...)
 			}
 
-			makeLibName := MakeLibName(ccInfo, linkableInfo, &commonInfo, commonInfo.BaseModuleName) + libDepTag.makeSuffix
+			makeLibName := MakeLibName(ccInfo, linkableInfo, commonInfo, commonInfo.BaseModuleName) + libDepTag.makeSuffix
 			switch {
 			case libDepTag.header():
 				c.Properties.AndroidMkHeaderLibs = append(
@@ -3629,7 +3703,7 @@
 			switch depTag {
 			case runtimeDepTag:
 				c.Properties.AndroidMkRuntimeLibs = append(
-					c.Properties.AndroidMkRuntimeLibs, MakeLibName(ccInfo, linkableInfo, &commonInfo,
+					c.Properties.AndroidMkRuntimeLibs, MakeLibName(ccInfo, linkableInfo, commonInfo,
 						commonInfo.BaseModuleName)+libDepTag.makeSuffix)
 			case objDepTag:
 				depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
@@ -3673,7 +3747,7 @@
 func ShouldUseStubForApex(ctx android.ModuleContext, parent android.Module, dep android.ModuleProxy) bool {
 	inVendorOrProduct := false
 	bootstrap := false
-	if ctx.EqualModules(ctx.Module(), parent) {
+	if android.EqualModules(ctx.Module(), parent) {
 		if linkable, ok := parent.(LinkableInterface); !ok {
 			ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName())
 		} else {
@@ -3705,7 +3779,7 @@
 		// platform APIs, use stubs only when it is from an APEX (and not from
 		// platform) However, for host, ramdisk, vendor_ramdisk, recovery or
 		// bootstrap modules, always link to non-stub variant
-		isNotInPlatform := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey).NotInPlatform
+		isNotInPlatform := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider).NotInPlatform
 
 		useStubs = isNotInPlatform && !bootstrap
 	} else {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 2c06924..7240ea5 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2689,7 +2689,7 @@
 	cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
 
 	cflags := []string{"-Werror", "-std=candcpp"}
-	cstd := []string{"-std=gnu17", "-std=conly"}
+	cstd := []string{"-std=gnu23", "-std=conly"}
 	cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
 
 	lastNDKFlags := []string{
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 0dcf2cf..45b1580 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -44,7 +44,7 @@
 		// On ARMv9 and later, Pointer Authentication Codes (PAC) are mandatory,
 		// so -fstack-protector is unnecessary.
 		"armv9-a": []string{
-			"-march=armv8.2-a+dotprod",
+			"-march=armv9-a",
 			"-mbranch-protection=standard",
 			"-fno-stack-protector",
 		},
diff --git a/cc/config/global.go b/cc/config/global.go
index 7bea124..5011acd 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -375,7 +375,7 @@
 		"-w",
 	}
 
-	CStdVersion               = "gnu17"
+	CStdVersion               = "gnu23"
 	CppStdVersion             = "gnu++20"
 	ExperimentalCStdVersion   = "gnu2x"
 	ExperimentalCppStdVersion = "gnu++2b"
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index ddc86c2..d2f88ef 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -28,7 +28,7 @@
 		"-fno-omit-frame-pointer",
 
 		"-U_FORTIFY_SOURCE",
-		"-D_FORTIFY_SOURCE=2",
+		"-D_FORTIFY_SOURCE=3",
 		"-fstack-protector-strong",
 
 		// From x86_64_device
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index c070050..c3f25aa 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -29,7 +29,7 @@
 		"-fno-omit-frame-pointer",
 
 		"-U_FORTIFY_SOURCE",
-		"-D_FORTIFY_SOURCE=2",
+		"-D_FORTIFY_SOURCE=3",
 		"-fstack-protector",
 
 		"--gcc-toolchain=${LinuxGccRoot}",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index bd3d8e4..79874fc 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -470,43 +470,37 @@
 	// multiple fuzzers that depend on the same shared library.
 	sharedLibraryInstalled := make(map[string]bool)
 
-	ctx.VisitAllModules(func(module android.Module) {
-		ccModule, ok := module.(LinkableInterface)
-		if !ok || ccModule.PreventInstall() {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		ccModule, ok := android.OtherModuleProvider(ctx, module, LinkableInfoProvider)
+		if !ok {
 			return
 		}
 		// Discard non-fuzz targets.
-		if ok := fuzz.IsValid(ctx, ccModule.FuzzModuleStruct()); !ok {
+		fuzzInfo, ok := android.OtherModuleProvider(ctx, module, fuzz.FuzzPackagedModuleInfoProvider)
+		if !ok {
 			return
 		}
 
 		sharedLibsInstallDirPrefix := "lib"
-		if ccModule.InVendor() {
+		if ccModule.InVendor {
 			sharedLibsInstallDirPrefix = "lib/vendor"
 		}
 
-		if !ccModule.IsFuzzModule() {
-			return
-		}
-
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider)
+		isHost := commonInfo.Target.Os.Class == android.Host
 		hostOrTargetString := "target"
-		if ccModule.Target().HostCross {
+		if commonInfo.Target.HostCross {
 			hostOrTargetString = "host_cross"
-		} else if ccModule.Host() {
+		} else if isHost {
 			hostOrTargetString = "host"
 		}
 		if s.onlyIncludePresubmits == true {
 			hostOrTargetString = "presubmit-" + hostOrTargetString
 		}
 
-		fpm := fuzz.FuzzPackagedModule{}
-		if ok {
-			fpm = ccModule.FuzzPackagedModule()
-		}
-
 		intermediatePath := "fuzz"
 
-		archString := ccModule.Target().Arch.ArchType.String()
+		archString := commonInfo.Target.Arch.ArchType.String()
 		archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
 		archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
@@ -514,23 +508,24 @@
 		builder := android.NewRuleBuilder(pctx, ctx)
 
 		// Package the corpus, data, dict and config into a zipfile.
-		files = s.PackageArtifacts(ctx, module, fpm, archDir, builder)
+		files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder)
 
 		// Package shared libraries
-		files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
+		files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries, isHost, ccModule.InVendor, &s.FuzzPackager,
+			archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
 
 		// The executable.
-		files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")})
+		files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, module, "unstripped")})
 
 		if s.onlyIncludePresubmits == true {
-			if fpm.FuzzProperties.Fuzz_config == nil {
+			if fuzzInfo.FuzzConfig == nil {
 				return
 			}
-			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) {
+			if !fuzzInfo.FuzzConfig.UseForPresubmit {
 				return
 			}
 		}
-		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+		archDirs[archOs], ok = s.BuildZipFile(ctx, module, &fuzzInfo, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
 			return
 		}
@@ -559,7 +554,8 @@
 
 // GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
 // packaging.
-func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
+func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, isHost bool, inVendor bool, s *fuzz.FuzzPackager,
+	archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
 	var files []fuzz.FileToZip
 
 	fuzzDir := "fuzz"
@@ -577,7 +573,7 @@
 		// install it to the output directory. Setup the install destination here,
 		// which will be used by $(copy-many-files) in the Make backend.
 		installDestination := SharedLibraryInstallLocation(
-			install, module.Host(), module.InVendor(), fuzzDir, archString)
+			install, isHost, inVendor, fuzzDir, archString)
 		if (*sharedLibraryInstalled)[installDestination] {
 			continue
 		}
@@ -594,8 +590,8 @@
 		// dir. Symbolized DSO's are always installed to the device when fuzzing, but
 		// we want symbolization tools (like `stack`) to be able to find the symbols
 		// in $ANDROID_PRODUCT_OUT/symbols automagically.
-		if !module.Host() {
-			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString)
+		if !isHost {
+			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, inVendor, fuzzDir, archString)
 			symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
 			s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
 				library.String()+":"+symbolsInstallDestination)
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index 438eb98..4e700a2 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -17,6 +17,7 @@
 import (
 	"reflect"
 	"slices"
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -254,3 +255,42 @@
 		gen_64bit,
 	)
 }
+
+// Test that a genrule can depend on a tool with symlinks. The symlinks are ignored, but
+// at least it doesn't cause errors.
+func TestGenruleToolWithSymlinks(t *testing.T) {
+	bp := `
+	genrule {
+		name: "gen",
+		tools: ["tool_with_symlinks"],
+		cmd: "$(location tool_with_symlinks) $(in) $(out)",
+		out: ["out"],
+	}
+
+	cc_binary_host {
+		name: "tool_with_symlinks",
+		symlinks: ["symlink1", "symlink2"],
+	}
+	`
+	ctx := PrepareForIntegrationTestWithCc.
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, bp)
+	gen := ctx.ModuleForTests(t, "gen", "").Output("out")
+	toolFound := false
+	symlinkFound := false
+	for _, dep := range gen.RuleParams.CommandDeps {
+		if strings.HasSuffix(dep, "/tool_with_symlinks") {
+			toolFound = true
+		}
+		if strings.HasSuffix(dep, "/symlink1") || strings.HasSuffix(dep, "/symlink2") {
+			symlinkFound = true
+		}
+	}
+	if !toolFound {
+		t.Errorf("Tool not found")
+	}
+	// We may want to change genrules to include symlinks later
+	if symlinkFound {
+		t.Errorf("Symlinks found")
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index ee7610d..5299771 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -220,6 +220,7 @@
 
 func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("cc_library_static", LibraryStaticFactory)
+	ctx.RegisterModuleType("cc_rustlibs_for_make", LibraryMakeRustlibsFactory)
 	ctx.RegisterModuleType("cc_library_shared", LibrarySharedFactory)
 	ctx.RegisterModuleType("cc_library", LibraryFactory)
 	ctx.RegisterModuleType("cc_library_host_static", LibraryHostStaticFactory)
@@ -249,6 +250,19 @@
 	return module.Init()
 }
 
+// cc_rustlibs_for_make creates a static library which bundles together rust_ffi_static
+// deps for Make. This should not be depended on in Soong, and is probably not the
+// module you need unless you are sure of what you're doing. These should only
+// be declared as dependencies in Make. To ensure inclusion, rust_ffi_static modules
+// should be declared in the whole_static_libs property.
+func LibraryMakeRustlibsFactory() android.Module {
+	module, library := NewLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyStatic()
+	library.wideStaticlibForMake = true
+	module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
+	return module.Init()
+}
+
 // cc_library_shared creates a shared library for a device and/or host.
 func LibrarySharedFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
@@ -437,6 +451,10 @@
 
 	// Path to the file containing the APIs exported by this library
 	stubsSymbolFilePath android.Path
+
+	// Forces production of the generated Rust staticlib for cc_library_static.
+	// Intended to be used to provide these generated staticlibs for Make.
+	wideStaticlibForMake bool
 }
 
 // linkerProps returns the list of properties structs relevant for this library. (For example, if
@@ -588,10 +606,22 @@
 			panic(err)
 		}
 
+		llndkFlag := "--llndk"
+		if ctx.baseModuleName() == "libbinder_ndk" && ctx.inProduct() {
+			// This is a special case only for the libbinder_ndk. As the product partition is in the
+			// framework side along with system and system_ext partitions in Treble, libbinder_ndk
+			// provides different binder interfaces between product and vendor modules.
+			// In libbinder_ndk, 'llndk' annotation is for the vendor APIs; while 'systemapi'
+			// annotation is for the product APIs.
+			// Use '--systemapi' flag for building the llndk stub of product variant for the
+			// libbinder_ndk.
+			llndkFlag = "--systemapi"
+		}
+
 		// This is the vendor variant of an LLNDK library, build the LLNDK stubs.
 		nativeAbiResult := ParseNativeAbiDefinition(ctx,
 			String(library.Properties.Llndk.Symbol_file),
-			nativeClampedApiLevel(ctx, version), "--llndk")
+			nativeClampedApiLevel(ctx, version), llndkFlag)
 		objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags)
 		if !Bool(library.Properties.Llndk.Unversioned) {
 			library.versionScriptPath = android.OptionalPathForPath(
@@ -1048,6 +1078,10 @@
 	library.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
 }
 
+func (library *libraryDecorator) testSuiteInfo(ctx ModuleContext) {
+	// not a test
+}
+
 func (library *libraryDecorator) linkStatic(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
@@ -1055,6 +1089,16 @@
 	library.objects = library.objects.Append(objs)
 	library.wholeStaticLibsFromPrebuilts = android.CopyOfPaths(deps.WholeStaticLibsFromPrebuilts)
 
+	if library.wideStaticlibForMake {
+		if generatedLib := GenerateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
+			// WholeStaticLibsFromPrebuilts are .a files that get included whole into the resulting staticlib
+			// so reuse that here for our Rust staticlibs because we don't have individual object files for
+			// these.
+			deps.WholeStaticLibsFromPrebuilts = append(deps.WholeStaticLibsFromPrebuilts, generatedLib)
+		}
+
+	}
+
 	fileName := ctx.ModuleName() + staticLibraryExtension
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	builderFlags := flagsToBuilderFlags(flags)
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 8ca3ca1..b119fda 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -82,11 +82,10 @@
 func (s *movedToApexLlndkLibraries) GenerateBuildActions(ctx android.SingletonContext) {
 	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to generate the linker config.
 	movedToApexLlndkLibrariesMap := make(map[string]bool)
-	ctx.VisitAllModules(func(module android.Module) {
-		if library := moduleVersionedInterface(module); library != nil && library.HasLLNDKStubs() {
-			if library.IsLLNDKMovedToApex() {
-				name := library.ImplementationModuleName(module.(*Module).BaseModuleName())
-				movedToApexLlndkLibrariesMap[name] = true
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if library, ok := android.OtherModuleProvider(ctx, module, LinkableInfoProvider); ok {
+			if library.HasLLNDKStubs && library.IsLLNDKMovedToApex {
+				movedToApexLlndkLibrariesMap[library.ImplementationModuleName] = true
 			}
 		}
 	})
@@ -151,14 +150,16 @@
 	etc.SetCommonPrebuiltEtcInfo(ctx, txt)
 }
 
-func getVndkFileName(m *Module) (string, error) {
-	if library, ok := m.linker.(*libraryDecorator); ok {
-		return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
+func getVndkFileName(info *LinkerInfo) (string, error) {
+	if info != nil {
+		if info.LibraryDecoratorInfo != nil {
+			return info.LibraryDecoratorInfo.VndkFileName, nil
+		}
+		if info.PrebuiltLibraryLinkerInfo != nil {
+			return info.PrebuiltLibraryLinkerInfo.VndkFileName, nil
+		}
 	}
-	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
-		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
-	}
-	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
+	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", info)
 }
 
 func (txt *llndkLibrariesTxtModule) GenerateSingletonBuildActions(ctx android.SingletonContext) {
@@ -167,9 +168,17 @@
 		return
 	}
 
-	ctx.VisitAllModules(func(m android.Module) {
-		if c, ok := m.(*Module); ok && c.VendorProperties.IsLLNDK && !c.Header() && !c.IsVndkPrebuiltLibrary() {
-			filename, err := getVndkFileName(c)
+	ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
+		ccInfo, ok := android.OtherModuleProvider(ctx, m, CcInfoProvider)
+		if !ok {
+			return
+		}
+		linkableInfo, ok := android.OtherModuleProvider(ctx, m, LinkableInfoProvider)
+		if !ok {
+			return
+		}
+		if linkableInfo.IsLlndk && !linkableInfo.Header && !linkableInfo.IsVndkPrebuiltLibrary {
+			filename, err := getVndkFileName(ccInfo.LinkerInfo)
 			if err != nil {
 				ctx.ModuleErrorf(m, "%s", err)
 			}
diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go
index 2706261..b96a779 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -39,15 +39,15 @@
 
 func (n *ndkAbiDumpSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var depPaths android.Paths
-	ctx.VisitAllModules(func(module android.Module) {
-		if !module.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
-		if m, ok := module.(*Module); ok {
-			if installer, ok := m.installer.(*stubDecorator); ok {
-				if installer.hasAbiDump {
-					depPaths = append(depPaths, installer.abiDumpPath)
+		if ccInfo, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok {
+			if ccInfo.InstallerInfo != nil && ccInfo.InstallerInfo.StubDecoratorInfo != nil {
+				if ccInfo.InstallerInfo.StubDecoratorInfo.HasAbiDump {
+					depPaths = append(depPaths, ccInfo.InstallerInfo.StubDecoratorInfo.AbiDumpPath)
 				}
 			}
 		}
@@ -77,14 +77,14 @@
 
 func (n *ndkAbiDiffSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var depPaths android.Paths
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(android.Module); ok && !m.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
-		if m, ok := module.(*Module); ok {
-			if installer, ok := m.installer.(*stubDecorator); ok {
-				depPaths = append(depPaths, installer.abiDiffPaths...)
+		if ccInfo, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok {
+			if ccInfo.InstallerInfo != nil && ccInfo.InstallerInfo.StubDecoratorInfo != nil {
+				depPaths = append(depPaths, ccInfo.InstallerInfo.StubDecoratorInfo.AbiDiffPaths...)
 			}
 		}
 	})
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 7481954..6e26d4c 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -80,6 +80,20 @@
 	licensePath  android.Path
 }
 
+type NdkHeaderInfo struct {
+	SrcPaths     android.Paths
+	InstallPaths android.Paths
+	LicensePath  android.Path
+	// Set to true if the headers installed by this module should skip
+	// verification. This step ensures that each header is self-contained (can
+	// be #included alone) and is valid C. This should not be disabled except in
+	// rare cases. Outside bionic and external, if you're using this option
+	// you've probably made a mistake.
+	SkipVerification bool
+}
+
+var NdkHeaderInfoProvider = blueprint.NewProvider[NdkHeaderInfo]()
+
 func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
 	to string) android.OutputPath {
 	// Output path is the sysroot base + "usr/include" + to directory + directory component
@@ -135,6 +149,13 @@
 	if len(m.installPaths) == 0 {
 		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
 	}
+
+	android.SetProvider(ctx, NdkHeaderInfoProvider, NdkHeaderInfo{
+		SrcPaths:         m.srcPaths,
+		InstallPaths:     m.installPaths,
+		LicensePath:      m.licensePath,
+		SkipVerification: Bool(m.properties.Skip_verification),
+	})
 }
 
 // ndk_headers installs the sets of ndk headers defined in the srcs property
@@ -203,6 +224,8 @@
 	licensePath  android.Path
 }
 
+var NdkPreprocessedHeaderInfoProvider = blueprint.NewProvider[NdkHeaderInfo]()
+
 func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if String(m.properties.License) == "" {
 		ctx.PropertyErrorf("license", "field is required")
@@ -231,6 +254,13 @@
 	if len(m.installPaths) == 0 {
 		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
 	}
+
+	android.SetProvider(ctx, NdkPreprocessedHeaderInfoProvider, NdkHeaderInfo{
+		SrcPaths:         m.srcPaths,
+		InstallPaths:     m.installPaths,
+		LicensePath:      m.licensePath,
+		SkipVerification: Bool(m.properties.Skip_verification),
+	})
 }
 
 // preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index a5f014b..1677862 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -53,11 +53,12 @@
 // TODO(danalbert): Write `ndk_static_library` rule.
 
 import (
-	"android/soong/android"
 	"fmt"
 	"path/filepath"
 	"strings"
 
+	"android/soong/android"
+
 	"github.com/google/blueprint"
 )
 
@@ -209,57 +210,61 @@
 	var headerCCompatVerificationTimestampPaths android.Paths
 	var installPaths android.Paths
 	var licensePaths android.Paths
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(android.Module); ok && !m.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
-		if m, ok := module.(*headerModule); ok {
-			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
-			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
-			if !Bool(m.properties.Skip_verification) {
-				for i, installPath := range m.installPaths {
+		if m, ok := android.OtherModuleProvider(ctx, module, NdkHeaderInfoProvider); ok {
+			headerSrcPaths = append(headerSrcPaths, m.SrcPaths...)
+			headerInstallPaths = append(headerInstallPaths, m.InstallPaths...)
+			if !m.SkipVerification {
+				for i, installPath := range m.InstallPaths {
 					headersToVerify = append(headersToVerify, srcDestPair{
-						src:  m.srcPaths[i],
+						src:  m.SrcPaths[i],
 						dest: installPath,
 					})
 				}
 			}
-			installPaths = append(installPaths, m.installPaths...)
-			licensePaths = append(licensePaths, m.licensePath)
+			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...)
-			if !Bool(m.properties.Skip_verification) {
-				for i, installPath := range m.installPaths {
+		if m, ok := android.OtherModuleProvider(ctx, module, NdkPreprocessedHeaderInfoProvider); ok {
+			headerSrcPaths = append(headerSrcPaths, m.SrcPaths...)
+			headerInstallPaths = append(headerInstallPaths, m.InstallPaths...)
+			if !m.SkipVerification {
+				for i, installPath := range m.InstallPaths {
 					headersToVerify = append(headersToVerify, srcDestPair{
-						src:  m.srcPaths[i],
+						src:  m.SrcPaths[i],
 						dest: installPath,
 					})
 				}
 			}
-			installPaths = append(installPaths, m.installPaths...)
-			licensePaths = append(licensePaths, m.licensePath)
+			installPaths = append(installPaths, m.InstallPaths...)
+			licensePaths = append(licensePaths, m.LicensePath)
 		}
 
-		if m, ok := module.(*Module); ok {
-			if installer, ok := m.installer.(*stubDecorator); ok && m.library.BuildStubs() {
-				installPaths = append(installPaths, installer.installPath)
+		if ccInfo, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok {
+			if installer := ccInfo.InstallerInfo; installer != nil && installer.StubDecoratorInfo != nil &&
+				ccInfo.LibraryInfo != nil && ccInfo.LibraryInfo.BuildStubs {
+				installPaths = append(installPaths, installer.StubDecoratorInfo.InstallPath)
 			}
 
-			if library, ok := m.linker.(*libraryDecorator); ok {
-				if library.ndkSysrootPath != nil {
-					staticLibInstallPaths = append(
-						staticLibInstallPaths, library.ndkSysrootPath)
+			if ccInfo.LinkerInfo != nil {
+				if library := ccInfo.LinkerInfo.LibraryDecoratorInfo; library != nil {
+					if library.NdkSysrootPath != nil {
+						staticLibInstallPaths = append(
+							staticLibInstallPaths, library.NdkSysrootPath)
+					}
 				}
-			}
 
-			if object, ok := m.linker.(*objectLinker); ok {
-				if object.ndkSysrootPath != nil {
-					staticLibInstallPaths = append(
-						staticLibInstallPaths, object.ndkSysrootPath)
+				if object := ccInfo.LinkerInfo.ObjectLinkerInfo; object != nil {
+					if object.NdkSysrootPath != nil {
+						staticLibInstallPaths = append(
+							staticLibInstallPaths, object.NdkSysrootPath)
+					}
 				}
 			}
 		}
diff --git a/cc/object.go b/cc/object.go
index 95a8beb..ea3ed61 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -250,3 +250,7 @@
 	object.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
 	moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
 }
+
+func (object *objectLinker) testSuiteInfo(ctx ModuleContext) {
+	// not a test
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b704ef4..f0b0308 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1422,6 +1422,7 @@
 				sanitizers = append(sanitizers,
 					"bool",
 					"integer-divide-by-zero",
+					"object-size",
 					"return",
 					"returns-nonnull-attribute",
 					"shift-exponent",
@@ -1438,10 +1439,6 @@
 					//"shift-base",
 					//"signed-integer-overflow",
 				)
-
-				if mctx.Config().ReleaseBuildObjectSizeSanitizer() {
-					sanitizers = append(sanitizers, "object-size")
-				}
 			}
 			sanitizers = append(sanitizers, sanProps.Misc_undefined...)
 		}
diff --git a/cc/strip.go b/cc/strip.go
index a950df8..42c9137 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -23,8 +23,9 @@
 // StripProperties defines the type of stripping applied to the module.
 type StripProperties struct {
 	Strip struct {
-		// Device and host modules default to stripping enabled leaving mini debuginfo.
-		// This can be disabled by setting none to true.
+		// Device modules default to stripping enabled leaving mini debuginfo.
+		// Host modules default to stripping disabled, but can be enabled by setting any other
+		// strip boolean property.
 		None *bool `android:"arch_variant"`
 
 		// all forces stripping everything, including the mini debug info.
@@ -50,7 +51,12 @@
 // NeedsStrip determines if stripping is required for a module.
 func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool {
 	forceDisable := Bool(stripper.StripProperties.Strip.None)
-	return !forceDisable
+	// Strip is enabled by default for device variants.
+	defaultEnable := actx.Device() || actx.Config().StripByDefault()
+	forceEnable := Bool(stripper.StripProperties.Strip.All) ||
+		Bool(stripper.StripProperties.Strip.Keep_symbols) ||
+		Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame)
+	return !forceDisable && (forceEnable || defaultEnable)
 }
 
 func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
diff --git a/cc/test.go b/cc/test.go
index d2c4b28..9c276b8 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -274,6 +274,12 @@
 	}
 }
 
+func (test *testDecorator) testSuiteInfo(ctx ModuleContext) {
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: test.InstallerProperties.Test_suites,
+	})
+}
+
 func NewTestInstaller() *baseInstaller {
 	return NewBaseInstaller("nativetest", "nativetest64", InstallInData)
 }
@@ -342,6 +348,10 @@
 
 }
 
+func (test *testBinary) testSuiteInfo(ctx ModuleContext) {
+	test.testDecorator.testSuiteInfo(ctx)
+}
+
 func (test *testBinary) installerProps() []interface{} {
 	return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...)
 }
@@ -455,6 +465,9 @@
 			if standaloneTestDep.SkipInstall() {
 				continue
 			}
+			if standaloneTestDep.Partition() == "data" {
+				continue
+			}
 			test.binaryDecorator.baseInstaller.installStandaloneTestDep(ctx, standaloneTestDep)
 		}
 	}
@@ -575,6 +588,10 @@
 	test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
 }
 
+func (test *testLibrary) testSuiteInfo(ctx ModuleContext) {
+	test.testDecorator.testSuiteInfo(ctx)
+}
+
 func (test *testLibrary) installerProps() []interface{} {
 	return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...)
 }
@@ -692,6 +709,12 @@
 	}
 }
 
+func (benchmark *benchmarkDecorator) testSuiteInfo(ctx ModuleContext) {
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: benchmark.Properties.Test_suites,
+	})
+}
+
 func NewBenchmark(hod android.HostOrDeviceSupported) *Module {
 	module, binary := newBinary(hod)
 	module.multilib = android.MultilibBoth
diff --git a/cc/tidy.go b/cc/tidy.go
index 2373658..bf273e9 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -211,7 +211,7 @@
 type tidyPhonySingleton struct{}
 
 // Given a final module, add its tidy/obj phony targets to tidy/objModulesInDirGroup.
-func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Module,
+func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.ModuleProxy,
 	tidyModulesInDirGroup, objModulesInDirGroup map[string]map[string]android.Paths) {
 	allObjFileGroups := make(map[string]android.Paths)     // variant group name => obj file Paths
 	allTidyFileGroups := make(map[string]android.Paths)    // variant group name => tidy file Paths
@@ -220,7 +220,7 @@
 
 	// (1) Collect all obj/tidy files into OS-specific groups.
 	ctx.VisitAllModuleVariantProxies(module, func(variant android.ModuleProxy) {
-		osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonModuleInfoKey).Target.Os.Name
+		osName := android.OtherModulePointerProviderOrDefault(ctx, variant, android.CommonModuleInfoProvider).Target.Os.Name
 		info := android.OtherModuleProviderOrDefault(ctx, variant, CcObjectInfoProvider)
 		addToOSGroup(osName, info.ObjFiles, allObjFileGroups, subsetObjFileGroups)
 		addToOSGroup(osName, info.TidyFiles, allTidyFileGroups, subsetTidyFileGroups)
@@ -253,7 +253,7 @@
 	objModulesInDirGroup := make(map[string]map[string]android.Paths)
 
 	// Collect tidy/obj targets from the 'final' modules.
-	ctx.VisitAllModules(func(module android.Module) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 		if ctx.IsFinalModule(module) {
 			collectTidyObjModuleTargets(ctx, module, tidyModulesInDirGroup, objModulesInDirGroup)
 		}
@@ -268,7 +268,7 @@
 }
 
 // The name for an obj/tidy module variant group phony target is Name_group-obj/tidy,
-func objTidyModuleGroupName(module android.Module, group string, suffix string) string {
+func objTidyModuleGroupName(module android.ModuleProxy, group string, suffix string) string {
 	if group == "" {
 		return module.Name() + "-" + suffix
 	}
@@ -327,7 +327,7 @@
 }
 
 // Add an all-OS group, with groupName, to include all os-specific phony targets.
-func addAllOSGroup(ctx android.SingletonContext, module android.Module, phonyTargetGroups map[string]android.Paths, groupName string, objTidyName string) {
+func addAllOSGroup(ctx android.SingletonContext, module android.ModuleProxy, phonyTargetGroups map[string]android.Paths, groupName string, objTidyName string) {
 	if len(phonyTargetGroups) > 0 {
 		var targets android.Paths
 		for group, _ := range phonyTargetGroups {
@@ -338,7 +338,7 @@
 }
 
 // Create one phony targets for each group and add them to the targetGroups.
-func genObjTidyPhonyTargets(ctx android.SingletonContext, module android.Module, objTidyName string, fileGroups map[string]android.Paths, targetGroups map[string]android.Path) {
+func genObjTidyPhonyTargets(ctx android.SingletonContext, module android.ModuleProxy, objTidyName string, fileGroups map[string]android.Paths, targetGroups map[string]android.Path) {
 	for group, files := range fileGroups {
 		groupName := objTidyModuleGroupName(module, group, objTidyName)
 		ctx.Phony(groupName, files...)
diff --git a/ci_tests/ci_test_package_zip.go b/ci_tests/ci_test_package_zip.go
index acfa8e0..95249aa 100644
--- a/ci_tests/ci_test_package_zip.go
+++ b/ci_tests/ci_test_package_zip.go
@@ -20,6 +20,7 @@
 	"strings"
 
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -139,6 +140,9 @@
 }
 
 func (p *testPackageZip) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Never install this test package, it's for disting only
+	p.SkipInstall()
+
 	if !android.InList(ctx.ModuleName(), moduleNamesAllowed) {
 		ctx.ModuleErrorf("%s is not allowed to use module type test_package")
 	}
@@ -148,9 +152,9 @@
 	ctx.SetOutputFiles(android.Paths{p.output}, "")
 
 	// dist the test output
-	if ctx.ModuleName() == "platform_tests_soong" {
-		distedName := ctx.Config().Getenv("TARGET_PRODUCT") + "-tests-" + ctx.Config().BuildId() + ".zip"
-		ctx.DistForGoalsWithFilename([]string{"droid", "platform_tests"}, p.output, distedName)
+	if ctx.ModuleName() == "platform_tests" {
+		distedName := ctx.Config().Getenv("TARGET_PRODUCT") + "-tests-FILE_NAME_TAG_PLACEHOLDER.zip"
+		ctx.DistForGoalWithFilename("platform_tests", p.output, distedName)
 	}
 }
 
@@ -165,52 +169,20 @@
 	builder.Command().Text("rm").Flag("-rf").Text(stagingDir.String())
 	builder.Command().Text("mkdir").Flag("-p").Output(stagingDir)
 	builder.Temporary(stagingDir)
-	ctx.VisitDirectDepsWithTag(testPackageZipDepTag, func(m android.Module) {
-		info, ok := android.OtherModuleProvider(ctx, m, android.ModuleInfoJSONProvider)
-		if !ok {
-			ctx.OtherModuleErrorf(m, "doesn't set ModuleInfoJSON provider")
-		} else if len(info) != 1 {
-			ctx.OtherModuleErrorf(m, "doesn't provide exactly one ModuleInfoJSON")
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		if !child.Enabled(ctx) {
+			return false
 		}
-
-		classes := info[0].GetClass()
-		if len(info[0].Class) != 1 {
-			ctx.OtherModuleErrorf(m, "doesn't have exactly one class in its ModuleInfoJSON")
-		}
-		class := strings.ToLower(classes[0])
-		if class == "apps" {
-			class = "app"
-		} else if class == "java_libraries" {
-			class = "framework"
-		}
-
-		installedFilesInfo, ok := android.OtherModuleProvider(ctx, m, android.InstallFilesProvider)
-		if !ok {
-			ctx.ModuleErrorf("Module %s doesn't set InstallFilesProvider", m.Name())
-		}
-
-		for _, installedFile := range installedFilesInfo.InstallFiles {
-			// there are additional installed files for some app-class modules, we only need the .apk files in the test package
-			if class == "app" && installedFile.Ext() != ".apk" {
-				continue
-			}
-			name := removeFileExtension(installedFile.Base())
-			f := strings.TrimPrefix(installedFile.String(), productOut+"/")
-			if strings.HasPrefix(f, "out") {
-				continue
-			}
-			f = strings.ReplaceAll(f, "system/", "DATA/")
-			f = strings.ReplaceAll(f, filepath.Join("testcases", name, arch), filepath.Join("DATA", class, name))
-			f = strings.ReplaceAll(f, filepath.Join("testcases", name, secondArch), filepath.Join("DATA", class, name))
-			f = strings.ReplaceAll(f, "testcases", filepath.Join("DATA", class))
-			f = strings.ReplaceAll(f, "data/", "DATA/")
-			f = strings.ReplaceAll(f, "DATA_other", "system_other")
-			f = strings.ReplaceAll(f, "system_other/DATA", "system_other/system")
-			dir := filepath.Dir(f)
-			tempOut := android.PathForModuleOut(ctx, "STAGING", f)
-			builder.Command().Text("mkdir").Flag("-p").Text(filepath.Join(stagingDir.String(), dir))
-			builder.Command().Text("cp").Flag("-Rf").Input(installedFile).Output(tempOut)
-			builder.Temporary(tempOut)
+		if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == testPackageZipDepTag {
+			// handle direct deps
+			extendBuilderCommand(ctx, child, builder, stagingDir, productOut, arch, secondArch)
+			return true
+		} else if !android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == android.RequiredDepTag {
+			// handle the "required" from deps
+			extendBuilderCommand(ctx, child, builder, stagingDir, productOut, arch, secondArch)
+			return true
+		} else {
+			return false
 		}
 	})
 
@@ -225,6 +197,82 @@
 	return output
 }
 
+func extendBuilderCommand(ctx android.ModuleContext, m android.Module, builder *android.RuleBuilder, stagingDir android.ModuleOutPath, productOut, arch, secondArch string) {
+	info, ok := android.OtherModuleProvider(ctx, m, android.ModuleInfoJSONProvider)
+	if !ok {
+		ctx.OtherModuleErrorf(m, "doesn't set ModuleInfoJSON provider")
+	} else if len(info) != 1 {
+		ctx.OtherModuleErrorf(m, "doesn't provide exactly one ModuleInfoJSON")
+	}
+
+	classes := info[0].GetClass()
+	if len(info[0].Class) != 1 {
+		ctx.OtherModuleErrorf(m, "doesn't have exactly one class in its ModuleInfoJSON")
+	}
+	class := strings.ToLower(classes[0])
+	if class == "apps" {
+		class = "app"
+	} else if class == "java_libraries" {
+		class = "framework"
+	}
+
+	installedFilesInfo, ok := android.OtherModuleProvider(ctx, m, android.InstallFilesProvider)
+	if !ok {
+		ctx.ModuleErrorf("Module %s doesn't set InstallFilesProvider", m.Name())
+	}
+
+	for _, spec := range installedFilesInfo.PackagingSpecs {
+		if spec.SrcPath() == nil {
+			// Probably a symlink
+			continue
+		}
+		installedFile := spec.FullInstallPath()
+
+		ext := installedFile.Ext()
+		// there are additional installed files for some app-class modules, we only need the .apk, .odex and .vdex files in the test package
+		excludeInstalledFile := ext != ".apk" && ext != ".odex" && ext != ".vdex"
+		if class == "app" && excludeInstalledFile {
+			continue
+		}
+		// only .jar files should be included for a framework dep
+		if class == "framework" && ext != ".jar" {
+			continue
+		}
+		name := removeFileExtension(installedFile.Base())
+		// some apks have other apk as installed files, these additional files shouldn't be included
+		isAppOrFramework := class == "app" || class == "framework"
+		if isAppOrFramework && name != ctx.OtherModuleName(m) {
+			continue
+		}
+
+		f := strings.TrimPrefix(installedFile.String(), productOut+"/")
+		if strings.HasPrefix(f, "out") {
+			continue
+		}
+		if strings.HasPrefix(f, "system/") {
+			f = strings.Replace(f, "system/", "DATA/", 1)
+		}
+		f = strings.ReplaceAll(f, filepath.Join("testcases", name, arch), filepath.Join("DATA", class, name))
+		f = strings.ReplaceAll(f, filepath.Join("testcases", name, secondArch), filepath.Join("DATA", class, name))
+		if strings.HasPrefix(f, "testcases") {
+			f = strings.Replace(f, "testcases", filepath.Join("DATA", class), 1)
+		}
+		if strings.HasPrefix(f, "data/") {
+			f = strings.Replace(f, "data/", "DATA/", 1)
+		}
+		f = strings.ReplaceAll(f, "DATA_other", "system_other")
+		f = strings.ReplaceAll(f, "system_other/DATA", "system_other/system")
+		dir := filepath.Dir(f)
+
+		tempOut := android.PathForModuleOut(ctx, "STAGING", f)
+		builder.Command().Text("mkdir").Flag("-p").Text(filepath.Join(stagingDir.String(), dir))
+		// Copy srcPath instead of installedFile because some rules like target-files.zip
+		// are non-hermetic and would be affected if we built the installed files.
+		builder.Command().Text("cp").Flag("-Rf").Input(spec.SrcPath()).Output(tempOut)
+		builder.Temporary(tempOut)
+	}
+}
+
 func removeFileExtension(filename string) string {
 	return strings.TrimSuffix(filename, filepath.Ext(filename))
 }
diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp
index 679d066..dbc1922 100644
--- a/dexpreopt/Android.bp
+++ b/dexpreopt/Android.bp
@@ -9,6 +9,8 @@
         "class_loader_context.go",
         "config.go",
         "dexpreopt.go",
+        "dexpreopt_tools_zip.go",
+        "system_server_zip.go",
         "testing.go",
     ],
     testSrcs: [
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index af1d33d..7f50912 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -291,6 +291,11 @@
 	// For prebuilts, library should have the same name as the source module.
 	lib = android.RemoveOptionalPrebuiltPrefix(lib)
 
+	// Bootclasspath libraries should not be added to CLC.
+	if android.InList(lib, ctx.Config().BootJars()) {
+		return nil
+	}
+
 	devicePath := UnknownInstallLibraryPath
 	if installPath == nil {
 		if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index c5cafb1..e57384f 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -464,8 +464,8 @@
 
 func (d dex2oatDependencyTag) AllowDisabledModuleDependencyProxy(
 	ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
-	return android.OtherModuleProviderOrDefault(
-		ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
+	return android.OtherModulePointerProviderOrDefault(
+		ctx, target, android.CommonModuleInfoProvider).ReplacedByPrebuilt
 }
 
 // Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that
@@ -510,7 +510,7 @@
 	var dex2oatModule android.ModuleProxy
 	ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
 		prebuiltInfo, isPrebuilt := android.OtherModuleProvider(ctx, child, android.PrebuiltModuleInfoProvider)
-		if ctx.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag {
+		if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag {
 			// Found the source module, or prebuilt module that has replaced the source.
 			dex2oatModule = child
 			if isPrebuilt {
@@ -519,7 +519,7 @@
 				return true // Recurse to check if the source has a prebuilt dependency.
 			}
 		}
-		if ctx.EqualModules(parent, dex2oatModule) && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
+		if android.EqualModules(parent, dex2oatModule) && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
 			if isPrebuilt && prebuiltInfo.UsePrebuilt {
 				dex2oatModule = child // Found a prebuilt that should be used.
 			}
@@ -717,17 +717,8 @@
 	} else if global.EnableUffdGc == "false" {
 		android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "")
 	} else if global.EnableUffdGc == "default" {
-		// Generated by `build/make/core/Makefile`.
+		// Generated by build/make/core/Makefile, or the android_device module in soong-only builds.
 		kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")
-		if !ctx.Config().KatiEnabled() {
-			// In soong-only mode, we need to generate the kernel_version_for_uffd_gc.txt with kernel version
-			kernelVersion := android.String(ctx.Config().ProductVariables().BoardKernelVersion)
-			if kernelVersion == "" {
-				// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5382;drc=66783fca85911af9da48d9b4f35a61b3873023e9
-				panic("BOARD_KERNEL_VERSION is not set. Build team will convert more stuff from Make to Soong to support this scenario.")
-			}
-			android.WriteFileRule(ctx, kernelVersionFile, kernelVersion)
-		}
 
 		// Determine the UFFD GC flag by the kernel version file.
 		rule := android.NewRuleBuilder(pctx, ctx)
diff --git a/dexpreopt/dexpreopt_tools_zip.go b/dexpreopt/dexpreopt_tools_zip.go
new file mode 100644
index 0000000..c7cf128
--- /dev/null
+++ b/dexpreopt/dexpreopt_tools_zip.go
@@ -0,0 +1,62 @@
+package dexpreopt
+
+import "android/soong/android"
+
+func init() {
+	android.InitRegistrationContext.RegisterSingletonType("dexpreopt_tools_zip_singleton", dexpreoptToolsZipSingletonFactory)
+}
+
+func dexpreoptToolsZipSingletonFactory() android.Singleton {
+	return &dexpreoptToolsZipSingleton{}
+}
+
+type dexpreoptToolsZipSingleton struct{}
+
+func (s *dexpreoptToolsZipSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// The mac build doesn't build dex2oat, so create the zip file only if the build OS is linux.
+	if !ctx.Config().BuildOS.Linux() {
+		return
+	}
+	global := GetGlobalConfig(ctx)
+	if global.DisablePreopt {
+		return
+	}
+	config := GetCachedGlobalSoongConfig(ctx)
+	if config == nil {
+		return
+	}
+
+	deps := android.Paths{
+		ctx.Config().HostToolPath(ctx, "dexpreopt_gen"),
+		ctx.Config().HostToolPath(ctx, "dexdump"),
+		ctx.Config().HostToolPath(ctx, "oatdump"),
+		config.Profman,
+		config.Dex2oat,
+		config.Aapt,
+		config.SoongZip,
+		config.Zip2zip,
+		config.ManifestCheck,
+		config.ConstructContext,
+		config.UffdGcFlag,
+	}
+
+	out := android.PathForOutput(ctx, "dexpreopt_tools.zip")
+	builder := android.NewRuleBuilder(pctx, ctx)
+
+	cmd := builder.Command().BuiltTool("soong_zip").
+		Flag("-d").
+		FlagWithOutput("-o ", out).
+		Flag("-j")
+
+	for _, dep := range deps {
+		cmd.FlagWithInput("-f ", dep)
+	}
+
+	// This reads through a symlink to include the file it points to. This isn't great for
+	// build reproducibility, will need to be revisited later.
+	cmd.Textf("-f $(realpath %s)", config.Dex2oat)
+
+	builder.Build("dexpreopt_tools_zip", "building dexpreopt_tools.zip")
+
+	ctx.DistForGoal("droidcore", out)
+}
diff --git a/dexpreopt/system_server_zip.go b/dexpreopt/system_server_zip.go
new file mode 100644
index 0000000..cef847b
--- /dev/null
+++ b/dexpreopt/system_server_zip.go
@@ -0,0 +1,49 @@
+package dexpreopt
+
+import "android/soong/android"
+
+func init() {
+	android.InitRegistrationContext.RegisterSingletonType("system_server_zip_singleton", systemServerZipSingletonFactory)
+}
+
+func systemServerZipSingletonFactory() android.Singleton {
+	return &systemServerZipSingleton{}
+}
+
+type systemServerZipSingleton struct{}
+
+func (s *systemServerZipSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	global := GetGlobalConfig(ctx)
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage {
+		return
+	}
+
+	systemServerDexjarsDir := android.PathForOutput(ctx, SystemServerDexjarsDir)
+
+	out := android.PathForOutput(ctx, "system_server.zip")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	cmd := builder.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", out).
+		FlagWithArg("-C ", systemServerDexjarsDir.String())
+
+	for i := 0; i < global.SystemServerJars.Len(); i++ {
+		jar := global.SystemServerJars.Jar(i) + ".jar"
+		cmd.FlagWithInput("-f ", systemServerDexjarsDir.Join(ctx, jar))
+	}
+	for i := 0; i < global.StandaloneSystemServerJars.Len(); i++ {
+		jar := global.StandaloneSystemServerJars.Jar(i) + ".jar"
+		cmd.FlagWithInput("-f ", systemServerDexjarsDir.Join(ctx, jar))
+	}
+	for i := 0; i < global.ApexSystemServerJars.Len(); i++ {
+		jar := global.ApexSystemServerJars.Jar(i) + ".jar"
+		cmd.FlagWithInput("-f ", systemServerDexjarsDir.Join(ctx, jar))
+	}
+	for i := 0; i < global.ApexStandaloneSystemServerJars.Len(); i++ {
+		jar := global.ApexStandaloneSystemServerJars.Jar(i) + ".jar"
+		cmd.FlagWithInput("-f ", systemServerDexjarsDir.Join(ctx, jar))
+	}
+
+	builder.Build("system_server_zip", "building system_server.zip")
+
+	ctx.DistForGoal("droidcore", out)
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index fad8f07..3b0c032 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -65,6 +65,7 @@
 	ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
 	ctx.RegisterModuleType("prebuilt_overlay", PrebuiltOverlayFactory)
 	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+	ctx.RegisterModuleType("prebuilt_gpu", PrebuiltGPUFactory)
 	ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
 	ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory)
 	ctx.RegisterModuleType("prebuilt_renderscript_bitcode", PrebuiltRenderScriptBitcodeFactory)
@@ -73,12 +74,14 @@
 	ctx.RegisterModuleType("prebuilt_bin", PrebuiltBinaryFactory)
 	ctx.RegisterModuleType("prebuilt_wallpaper", PrebuiltWallpaperFactory)
 	ctx.RegisterModuleType("prebuilt_priv_app", PrebuiltPrivAppFactory)
+	ctx.RegisterModuleType("prebuilt_radio", PrebuiltRadioFactory)
 	ctx.RegisterModuleType("prebuilt_rfs", PrebuiltRfsFactory)
 	ctx.RegisterModuleType("prebuilt_framework", PrebuiltFrameworkFactory)
 	ctx.RegisterModuleType("prebuilt_res", PrebuiltResFactory)
 	ctx.RegisterModuleType("prebuilt_wlc_upt", PrebuiltWlcUptFactory)
 	ctx.RegisterModuleType("prebuilt_odm", PrebuiltOdmFactory)
 	ctx.RegisterModuleType("prebuilt_vendor_dlkm", PrebuiltVendorDlkmFactory)
+	ctx.RegisterModuleType("prebuilt_vendor_overlay", PrebuiltVendorOverlayFactory)
 	ctx.RegisterModuleType("prebuilt_bt_firmware", PrebuiltBtFirmwareFactory)
 	ctx.RegisterModuleType("prebuilt_tvservice", PrebuiltTvServiceFactory)
 	ctx.RegisterModuleType("prebuilt_optee", PrebuiltOpteeFactory)
@@ -87,6 +90,7 @@
 	ctx.RegisterModuleType("prebuilt_sbin", PrebuiltSbinFactory)
 	ctx.RegisterModuleType("prebuilt_system", PrebuiltSystemFactory)
 	ctx.RegisterModuleType("prebuilt_first_stage_ramdisk", PrebuiltFirstStageRamdiskFactory)
+	ctx.RegisterModuleType("prebuilt_any", PrebuiltAnyFactory)
 
 	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 
@@ -113,12 +117,6 @@
 	// set. May use globs in filenames.
 	Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`
 
-	// Destination files of this prebuilt. Requires srcs to be used and causes srcs not to implicitly
-	// set filename_from_src. This can be used to install each source file to a different directory
-	// and/or change filenames when files are installed. Must be exactly one entry per source file,
-	// which means care must be taken if srcs has globs.
-	Dsts proptools.Configurable[[]string] `android:"path,arch_variant"`
-
 	// Optional name for the installed file. If unspecified, name of the module is used as the file
 	// name. Only available when using a single source (src).
 	Filename *string `android:"arch_variant"`
@@ -157,6 +155,20 @@
 	Oem_specific *bool `android:"arch_variant"`
 }
 
+// Dsts is useful in that it allows prebuilt_* modules to easily map the source files to the
+// install path within the partition. Dsts values are allowed to contain filepath separator
+// so that the source files can be installed in subdirectories within the partition.
+// However, this functionality should not be supported for prebuilt_root module type, as it
+// allows the module to install to any arbitrary location. Thus, this property is defined in
+// a separate struct so that it's not available to be set in prebuilt_root module type.
+type PrebuiltDstsProperties struct {
+	// Destination files of this prebuilt. Requires srcs to be used and causes srcs not to implicitly
+	// set filename_from_src. This can be used to install each source file to a different directory
+	// and/or change filenames when files are installed. Must be exactly one entry per source file,
+	// which means care must be taken if srcs has globs.
+	Dsts proptools.Configurable[[]string] `android:"path,arch_variant"`
+}
+
 type prebuiltSubdirProperties struct {
 	// Optional subdirectory under which this file is installed into, cannot be specified with
 	// relative_install_path, prefer relative_install_path.
@@ -192,6 +204,8 @@
 
 	properties PrebuiltEtcProperties
 
+	dstsProperties PrebuiltDstsProperties
+
 	// rootProperties is used to return the value of the InstallInRoot() method. Currently, only
 	// prebuilt_avb and prebuilt_root modules use this.
 	rootProperties prebuiltRootProperties
@@ -382,7 +396,7 @@
 	if srcProperty.IsPresent() && len(srcsProperty) > 0 {
 		ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
 	}
-	dstsProperty := p.properties.Dsts.GetOrDefault(ctx, nil)
+	dstsProperty := p.dstsProperties.Dsts.GetOrDefault(ctx, nil)
 	if len(dstsProperty) > 0 && len(srcsProperty) == 0 {
 		ctx.PropertyErrorf("dsts", "dsts is set. Must use srcs")
 	}
@@ -610,6 +624,7 @@
 	p.AddProperties(&p.properties)
 	p.AddProperties(&p.subdirProperties)
 	p.AddProperties(&p.rootProperties)
+	p.AddProperties(&p.dstsProperties)
 }
 
 func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -621,6 +636,7 @@
 func InitPrebuiltAvbModule(p *PrebuiltEtc) {
 	p.installDirBase = "avb"
 	p.AddProperties(&p.properties)
+	p.AddProperties(&p.dstsProperties)
 	p.rootProperties.Install_in_root = proptools.BoolPtr(true)
 }
 
@@ -664,6 +680,20 @@
 	return module
 }
 
+// prebuilt_any is a special module where the module can define the subdirectory that the files
+// are installed to. This is only used for converting the PRODUCT_COPY_FILES entries to Soong
+// modules, and should never be defined in the bp files. If none of the existing prebuilt_*
+// modules allow installing the file at the desired location, introduce a new prebuilt_* module
+// type instead.
+func PrebuiltAnyFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, ".")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_etc_host is for a host prebuilt artifact that is installed in
 // <partition>/etc/<sub_dir> directory.
 func PrebuiltEtcCaCertsFactory() android.Module {
@@ -831,6 +861,15 @@
 	return module
 }
 
+// prebuilt_gpu is for a prebuilt artifact in <partition>/gpu directory.
+func PrebuiltGPUFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "gpu")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
 // prebuilt_dsp installs a DSP related file to <partition>/etc/dsp directory for system image.
 // If soc_specific property is set to true, the DSP related file is installed to the
 // vendor <partition>/dsp directory for vendor image.
@@ -921,6 +960,16 @@
 	return module
 }
 
+// prebuilt_radio installs files in <partition>/radio directory.
+func PrebuiltRadioFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "radio")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_rfs installs files in <partition>/rfs directory.
 func PrebuiltRfsFactory() android.Module {
 	module := &PrebuiltEtc{}
@@ -1031,6 +1080,16 @@
 	return module
 }
 
+// prebuilt_vendor_overlay is for a prebuilt artifact in <partition>/vendor_overlay directory.
+func PrebuiltVendorOverlayFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "vendor_overlay")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_sbin installs files in <partition>/sbin directory.
 func PrebuiltSbinFactory() android.Module {
 	module := &PrebuiltEtc{}
diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go
index b4173d7..20a1953 100644
--- a/filesystem/aconfig_files.go
+++ b/filesystem/aconfig_files.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"strconv"
+	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -31,20 +32,13 @@
 		Command:     `$aconfig create-storage --container $container --file $fileType --out $out --cache $in --version $version`,
 		CommandDeps: []string{"$aconfig"},
 	}, "container", "fileType", "version")
+
+	subPartitionsInPartition = map[string][]string{
+		"system": {"system_ext", "product", "vendor"},
+		"vendor": {"odm"},
+	}
 )
 
-type installedAconfigFlagsInfo struct {
-	aconfigFiles android.Paths
-}
-
-var installedAconfigFlagsProvider = blueprint.NewProvider[installedAconfigFlagsInfo]()
-
-type importAconfigDepDag struct {
-	blueprint.BaseDependencyTag
-}
-
-var importAconfigDependencyTag = interPartitionDepTag{}
-
 func (f *filesystem) buildAconfigFlagsFiles(
 	ctx android.ModuleContext,
 	builder *android.RuleBuilder,
@@ -52,88 +46,97 @@
 	dir android.OutputPath,
 	fullInstallPaths *[]FullInstallPathInfo,
 ) {
-	var caches []android.Path
-	for _, ps := range specs {
-		caches = append(caches, ps.GetAconfigPaths()...)
-	}
-
-	ctx.VisitDirectDepsWithTag(importAconfigDependencyTag, func(m android.Module) {
-		info, ok := android.OtherModuleProvider(ctx, m, installedAconfigFlagsProvider)
-		if !ok {
-			ctx.ModuleErrorf("expected dependency %s to have an installedAconfigFlagsProvider", m.Name())
-			return
-		}
-		caches = append(caches, info.aconfigFiles...)
-	})
-	caches = android.SortedUniquePaths(caches)
-
-	android.SetProvider(ctx, installedAconfigFlagsProvider, installedAconfigFlagsInfo{
-		aconfigFiles: caches,
-	})
-
 	if !proptools.Bool(f.properties.Gen_aconfig_flags_pb) {
 		return
 	}
 
-	container := f.PartitionType()
+	partition := f.PartitionType()
+	subPartitionsFound := map[string]bool{}
+	fullInstallPath := android.PathForModuleInPartitionInstall(ctx, partition)
 
-	aconfigFlagsPb := android.PathForModuleOut(ctx, "aconfig", "aconfig_flags.pb")
-	aconfigFlagsPbBuilder := android.NewRuleBuilder(pctx, ctx)
-	cmd := aconfigFlagsPbBuilder.Command().
-		BuiltTool("aconfig").
-		Text(" dump-cache --dedup --format protobuf --out").
-		Output(aconfigFlagsPb).
-		Textf("--filter container:%s+state:ENABLED", container).
-		Textf("--filter container:%s+permission:READ_WRITE", container)
-	for _, cache := range caches {
-		cmd.FlagWithInput("--cache ", cache)
-	}
-	aconfigFlagsPbBuilder.Build("aconfig_flags_pb", "build aconfig_flags.pb")
-
-	installAconfigFlagsPath := dir.Join(ctx, "etc", "aconfig_flags.pb")
-	builder.Command().Text("mkdir -p ").Text(dir.Join(ctx, "etc").String())
-	builder.Command().Text("cp").Input(aconfigFlagsPb).Text(installAconfigFlagsPath.String())
-	*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
-		FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc/aconfig_flags.pb"),
-		SourcePath:      aconfigFlagsPb,
-	})
-	f.appendToEntry(ctx, installAconfigFlagsPath)
-
-	// To enable fingerprint, we need to have v2 storage files. The default version is 1.
-	storageFilesVersion := 1
-	if ctx.Config().ReleaseFingerprintAconfigPackages() {
-		storageFilesVersion = 2
+	for _, subPartition := range subPartitionsInPartition[partition] {
+		subPartitionsFound[subPartition] = false
 	}
 
-	installAconfigStorageDir := dir.Join(ctx, "etc", "aconfig")
-	builder.Command().Text("mkdir -p").Text(installAconfigStorageDir.String())
+	var caches []android.Path
+	for _, ps := range specs {
+		caches = append(caches, ps.GetAconfigPaths()...)
+		for subPartition, found := range subPartitionsFound {
+			if !found && strings.HasPrefix(ps.RelPathInPackage(), subPartition+"/") {
+				subPartitionsFound[subPartition] = true
+				break
+			}
+		}
+	}
+	caches = android.SortedUniquePaths(caches)
 
-	generatePartitionAconfigStorageFile := func(fileType, fileName string) {
-		outPath := android.PathForModuleOut(ctx, "aconfig", fileName)
-		installPath := installAconfigStorageDir.Join(ctx, fileName)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   aconfigCreateStorage,
-			Input:  aconfigFlagsPb,
-			Output: outPath,
-			Args: map[string]string{
-				"container": container,
-				"fileType":  fileType,
-				"version":   strconv.Itoa(storageFilesVersion),
-			},
-		})
-		builder.Command().
-			Text("cp").Input(outPath).Text(installPath.String())
+	buildAconfigFlagsFiles := func(container string, dir android.OutputPath, fullInstallPath android.InstallPath) {
+		aconfigFlagsPb := android.PathForModuleOut(ctx, "aconfig", container, "aconfig_flags.pb")
+		aconfigFlagsPbBuilder := android.NewRuleBuilder(pctx, ctx)
+		cmd := aconfigFlagsPbBuilder.Command().
+			BuiltTool("aconfig").
+			Text(" dump-cache --dedup --format protobuf --out").
+			Output(aconfigFlagsPb).
+			Textf("--filter container:%s+state:ENABLED", container).
+			Textf("--filter container:%s+permission:READ_WRITE", container)
+		for _, cache := range caches {
+			cmd.FlagWithInput("--cache ", cache)
+		}
+		aconfigFlagsPbBuilder.Build(container+"_aconfig_flags_pb", "build aconfig_flags.pb")
+
+		installEtcDir := dir.Join(ctx, "etc")
+		installAconfigFlagsPath := installEtcDir.Join(ctx, "aconfig_flags.pb")
+		builder.Command().Text("mkdir -p ").Text(installEtcDir.String())
+		builder.Command().Text("cp").Input(aconfigFlagsPb).Text(installAconfigFlagsPath.String())
 		*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
-			SourcePath:      outPath,
-			FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc/aconfig", fileName),
+			FullInstallPath: fullInstallPath.Join(ctx, "etc/aconfig_flags.pb"),
+			SourcePath:      aconfigFlagsPb,
 		})
-		f.appendToEntry(ctx, installPath)
+		f.appendToEntry(ctx, installAconfigFlagsPath)
+
+		// To enable fingerprint, we need to have v2 storage files. The default version is 1.
+		storageFilesVersion := 1
+		if ctx.Config().ReleaseFingerprintAconfigPackages() {
+			storageFilesVersion = 2
+		}
+
+		installAconfigStorageDir := installEtcDir.Join(ctx, "aconfig")
+		builder.Command().Text("mkdir -p").Text(installAconfigStorageDir.String())
+
+		generatePartitionAconfigStorageFile := func(fileType, fileName string) {
+			outPath := android.PathForModuleOut(ctx, "aconfig", container, fileName)
+			installPath := installAconfigStorageDir.Join(ctx, fileName)
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   aconfigCreateStorage,
+				Input:  aconfigFlagsPb,
+				Output: outPath,
+				Args: map[string]string{
+					"container": container,
+					"fileType":  fileType,
+					"version":   strconv.Itoa(storageFilesVersion),
+				},
+			})
+			builder.Command().
+				Text("cp").Input(outPath).Text(installPath.String())
+			*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+				SourcePath:      outPath,
+				FullInstallPath: fullInstallPath.Join(ctx, "etc/aconfig", fileName),
+			})
+			f.appendToEntry(ctx, installPath)
+		}
+
+		if ctx.Config().ReleaseCreateAconfigStorageFile() {
+			generatePartitionAconfigStorageFile("package_map", "package.map")
+			generatePartitionAconfigStorageFile("flag_map", "flag.map")
+			generatePartitionAconfigStorageFile("flag_val", "flag.val")
+			generatePartitionAconfigStorageFile("flag_info", "flag.info")
+		}
 	}
 
-	if ctx.Config().ReleaseCreateAconfigStorageFile() {
-		generatePartitionAconfigStorageFile("package_map", "package.map")
-		generatePartitionAconfigStorageFile("flag_map", "flag.map")
-		generatePartitionAconfigStorageFile("flag_val", "flag.val")
-		generatePartitionAconfigStorageFile("flag_info", "flag.info")
+	buildAconfigFlagsFiles(partition, dir, fullInstallPath)
+	for _, subPartition := range android.SortedKeys(subPartitionsFound) {
+		if subPartitionsFound[subPartition] {
+			buildAconfigFlagsFiles(subPartition, dir.Join(ctx, subPartition), fullInstallPath.Join(ctx, subPartition))
+		}
 	}
 }
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index fef4aeb..3f6348d 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -19,6 +19,7 @@
 	"fmt"
 	"path/filepath"
 	"slices"
+	"sort"
 	"strings"
 	"sync/atomic"
 
@@ -87,6 +88,14 @@
 
 	Ramdisk_node_list      *string `android:"path"`
 	Releasetools_extension *string `android:"path"`
+	FastbootInfo           *string `android:"path"`
+
+	// The kernel version in the build. Will be verified against the actual kernel.
+	// If not provided, will attempt to extract it from the loose kernel or the kernel inside
+	// the boot image. The version is later used to decide whether or not to enable uffd_gc
+	// when dexpreopting apps. So setting this doesn't really do anything except enforce that the
+	// actual kernel version is as specified here.
+	Kernel_version *string
 }
 
 type androidDevice struct {
@@ -98,9 +107,15 @@
 
 	allImagesZip android.Path
 
-	proguardDictZip     android.Path
-	proguardDictMapping android.Path
-	proguardUsageZip    android.Path
+	proguardDictZip             android.Path
+	proguardDictMapping         android.Path
+	proguardUsageZip            android.Path
+	kernelConfig                android.Path
+	kernelVersion               android.Path
+	miscInfo                    android.Path
+	rootDirForFsConfig          string
+	rootDirForFsConfigTimestamp android.Path
+	apkCertsInfo                android.Path
 }
 
 func AndroidDeviceFactory() android.Module {
@@ -175,7 +190,10 @@
 
 	allInstalledModules := a.allInstalledModules(ctx)
 
-	a.buildTargetFilesZip(ctx)
+	a.apkCertsInfo = a.buildApkCertsInfo(ctx, allInstalledModules)
+	a.kernelVersion, a.kernelConfig = a.extractKernelVersionAndConfigs(ctx)
+	a.miscInfo = a.addMiscInfo(ctx)
+	a.buildTargetFilesZip(ctx, allInstalledModules)
 	a.buildProguardZips(ctx, allInstalledModules)
 
 	var deps []android.Path
@@ -263,6 +281,39 @@
 	a.setVbmetaPhonyTargets(ctx)
 
 	a.distFiles(ctx)
+
+	android.SetProvider(ctx, android.AndroidDeviceInfoProvider, android.AndroidDeviceInfo{
+		Main_device: android.Bool(a.deviceProps.Main_device),
+	})
+
+	if proptools.String(a.partitionProps.Super_partition_name) != "" {
+		buildComplianceMetadata(ctx, superPartitionDepTag, filesystemDepTag)
+	} else {
+		buildComplianceMetadata(ctx, filesystemDepTag)
+	}
+}
+
+func buildComplianceMetadata(ctx android.ModuleContext, tags ...blueprint.DependencyTag) {
+	// Collect metadata from deps
+	filesContained := make([]string, 0)
+	prebuiltFilesCopied := make([]string, 0)
+	for _, tag := range tags {
+		ctx.VisitDirectDepsProxyWithTag(tag, func(m android.ModuleProxy) {
+			if complianceMetadataInfo, ok := android.OtherModuleProvider(ctx, m, android.ComplianceMetadataProvider); ok {
+				filesContained = append(filesContained, complianceMetadataInfo.GetFilesContained()...)
+				prebuiltFilesCopied = append(prebuiltFilesCopied, complianceMetadataInfo.GetPrebuiltFilesCopied()...)
+			}
+		})
+	}
+	// Merge to module's ComplianceMetadataInfo
+	complianceMetadataInfo := ctx.ComplianceMetadataInfo()
+	filesContained = append(filesContained, complianceMetadataInfo.GetFilesContained()...)
+	sort.Strings(filesContained)
+	complianceMetadataInfo.SetFilesContained(filesContained)
+
+	prebuiltFilesCopied = append(prebuiltFilesCopied, complianceMetadataInfo.GetPrebuiltFilesCopied()...)
+	sort.Strings(prebuiltFilesCopied)
+	complianceMetadataInfo.SetPrebuiltFilesCopied(prebuiltFilesCopied)
 }
 
 // Returns a list of modules that are installed, which are collected from the dependency
@@ -279,7 +330,7 @@
 
 	ret := []android.Module{}
 	ctx.WalkDepsProxy(func(mod, _ android.ModuleProxy) bool {
-		if variations, ok := allOwners[mod.Name()]; ok && android.InList(ctx.OtherModuleSubDir(mod), variations) {
+		if variations, ok := allOwners[ctx.OtherModuleName(mod)]; ok && android.InList(ctx.OtherModuleSubDir(mod), variations) {
 			ret = append(ret, mod)
 		}
 		return true
@@ -302,18 +353,32 @@
 	return strings.TrimSuffix(file, ext) + insertion + ext
 }
 
+func (a *androidDevice) distInstalledFiles(ctx android.ModuleContext) {
+	distInstalledFilesJsonAndTxt := func(installedFiles InstalledFilesStruct) {
+		if installedFiles.Json != nil {
+			ctx.DistForGoal("droidcore-unbundled", installedFiles.Json)
+		}
+		if installedFiles.Txt != nil {
+			ctx.DistForGoal("droidcore-unbundled", installedFiles.Txt)
+		}
+	}
+
+	fsInfoMap := a.getFsInfos(ctx)
+	for _, partition := range android.SortedKeys(fsInfoMap) {
+		// installed-files-*{.txt | .json} is not disted for userdata partition
+		if partition == "userdata" {
+			continue
+		}
+		fsInfo := fsInfoMap[partition]
+		for _, installedFiles := range fsInfo.InstalledFilesDepSet.ToList() {
+			distInstalledFilesJsonAndTxt(installedFiles)
+		}
+	}
+}
+
 func (a *androidDevice) distFiles(ctx android.ModuleContext) {
 	if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) {
-		fsInfoMap := a.getFsInfos(ctx)
-		for _, partition := range android.SortedKeys(fsInfoMap) {
-			fsInfo := fsInfoMap[partition]
-			if fsInfo.InstalledFiles.Json != nil {
-				ctx.DistForGoal("droidcore-unbundled", fsInfo.InstalledFiles.Json)
-			}
-			if fsInfo.InstalledFiles.Txt != nil {
-				ctx.DistForGoal("droidcore-unbundled", fsInfo.InstalledFiles.Txt)
-			}
-		}
+		a.distInstalledFiles(ctx)
 
 		namePrefix := ""
 		if ctx.Config().HasDeviceProduct() {
@@ -322,13 +387,18 @@
 		ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardDictZip, namePrefix+insertBeforeExtension(a.proguardDictZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER"))
 		ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardDictMapping, namePrefix+insertBeforeExtension(a.proguardDictMapping.Base(), "-FILE_NAME_TAG_PLACEHOLDER"))
 		ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardUsageZip, namePrefix+insertBeforeExtension(a.proguardUsageZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER"))
+
+		if a.deviceProps.Android_info != nil {
+			ctx.DistForGoal("droidcore-unbundled", android.PathForModuleSrc(ctx, *a.deviceProps.Android_info))
+		}
 	}
 }
 
-func (a *androidDevice) MakeVars(ctx android.MakeVarsModuleContext) {
+func (a *androidDevice) MakeVars(_ android.MakeVarsModuleContext) []android.ModuleMakeVarsValue {
 	if proptools.Bool(a.deviceProps.Main_device) {
-		ctx.StrictRaw("SOONG_ONLY_ALL_IMAGES_ZIP", a.allImagesZip.String())
+		return []android.ModuleMakeVarsValue{{"SOONG_ONLY_ALL_IMAGES_ZIP", a.allImagesZip.String()}}
 	}
+	return nil
 }
 
 func (a *androidDevice) buildProguardZips(ctx android.ModuleContext, allInstalledModules []android.Module) {
@@ -392,7 +462,7 @@
 	destSubdir string
 }
 
-func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext) {
+func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstalledModules []android.Module) {
 	targetFilesDir := android.PathForModuleOut(ctx, "target_files_dir")
 	targetFilesZip := android.PathForModuleOut(ctx, "target_files.zip")
 
@@ -458,6 +528,17 @@
 		if toCopy.destSubdir == "SYSTEM" {
 			// Create the ROOT partition in target_files.zip
 			builder.Command().Textf("rsync --links --exclude=system/* %s/ -r %s/ROOT", toCopy.fsInfo.RootDir, targetFilesDir.String())
+			// Add a duplicate rule to assemble the ROOT/ directory in separate intermediates.
+			// The output timestamp will be an input to a separate fs_config call.
+			a.rootDirForFsConfig = android.PathForModuleOut(ctx, "root_dir_for_fs_config").String()
+			rootDirBuilder := android.NewRuleBuilder(pctx, ctx)
+			rootDirForFsConfigTimestamp := android.PathForModuleOut(ctx, "root_dir_for_fs_config.timestamp")
+			rootDirBuilder.Command().Textf("rsync --links --exclude=system/* %s/ -r %s", toCopy.fsInfo.RootDir, a.rootDirForFsConfig).
+				Implicit(toCopy.fsInfo.Output).
+				Text("&& touch").
+				Output(rootDirForFsConfigTimestamp)
+			rootDirBuilder.Build("assemble_root_dir_for_fs_config", "Assemble ROOT/ for fs_config")
+			a.rootDirForFsConfigTimestamp = rootDirForFsConfigTimestamp
 		}
 	}
 	// Copy cmdline, kernel etc. files of boot images
@@ -496,7 +577,7 @@
 	}
 
 	a.copyImagesToTargetZip(ctx, builder, targetFilesDir)
-	a.copyMetadataToTargetZip(ctx, builder, targetFilesDir)
+	a.copyMetadataToTargetZip(ctx, builder, targetFilesDir, allInstalledModules)
 
 	builder.Command().
 		BuiltTool("soong_zip").
@@ -542,13 +623,17 @@
 					builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].MapFile).Textf(" %s/IMAGES/", targetFilesDir.String())
 				}
 			}
+			// super_empty.img
+			if info.SuperEmptyImage != nil {
+				builder.Command().Textf("cp ").Input(info.SuperEmptyImage).Textf(" %s/IMAGES/", targetFilesDir.String())
+			}
 		} else {
 			ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
 		}
 	}
 }
 
-func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) {
+func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath, allInstalledModules []android.Module) {
 	// Create a META/ subdirectory
 	builder.Command().Textf("mkdir -p %s/META", targetFilesDir.String())
 	if proptools.Bool(a.deviceProps.Ab_ota_updater) {
@@ -586,7 +671,28 @@
 		if android.InList(partition, []string{"userdata"}) {
 			continue
 		}
-		builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/%s", targetFilesDir.String(), a.filesystemConfigNameForTargetFiles(partition))
+		if partition != "vendor_ramdisk" {
+			// vendor_ramdisk will be handled separately.
+			builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/%s", targetFilesDir.String(), a.filesystemConfigNameForTargetFiles(partition))
+		}
+		if partition == "ramdisk" {
+			// Create an additional copy at boot_filesystem_config.txt
+			builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/boot_filesystem_config.txt", targetFilesDir.String())
+		}
+		if partition == "system" {
+			// Create root_filesystem_config from the assembled ROOT/ intermediates directory
+			a.generateFilesystemConfigForTargetFiles(ctx, builder, a.rootDirForFsConfigTimestamp, targetFilesDir.String(), a.rootDirForFsConfig, "root_filesystem_config.txt")
+		}
+		if partition == "vendor_ramdisk" {
+			// Create vendor_boot_filesystem_config from the assembled VENDOR_BOOT/RAMDISK intermediates directory
+			vendorRamdiskStagingDir := targetFilesDir.String() + "/VENDOR_BOOT/RAMDISK"
+			vendorRamdiskFsConfigOut := targetFilesDir.String() + "/META/vendor_boot_filesystem_config.txt"
+			fsConfigBin := ctx.Config().HostToolPath(ctx, "fs_config")
+			builder.Command().Textf(
+				`(cd %s; find . -type d | sed 's,$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,,' | %s -C -D %s -R \"\" > %s`,
+				vendorRamdiskStagingDir, fsConfigBin, vendorRamdiskStagingDir, vendorRamdiskFsConfigOut).
+				Implicit(fsConfigBin)
+		}
 	}
 	// Copy ramdisk_node_list
 	if ramdiskNodeList := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Ramdisk_node_list)); ramdiskNodeList != nil {
@@ -596,6 +702,148 @@
 	if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil {
 		builder.Command().Textf("cp").Input(releaseTools).Textf(" %s/META/", targetFilesDir.String())
 	}
+	// apexkeys.txt
+	var installedApexKeys []android.Path
+	for _, installedModule := range allInstalledModules {
+		if info, ok := android.OtherModuleProvider(ctx, installedModule, ApexKeyPathInfoProvider); ok {
+			installedApexKeys = append(installedApexKeys, info.ApexKeyPath)
+		}
+	}
+	installedApexKeys = android.SortedUniquePaths(installedApexKeys) // Sort by keypath to match make
+	builder.Command().Text("cat").Inputs(installedApexKeys).Textf(" >> %s/META/apexkeys.txt", targetFilesDir.String())
+	// apkcerts.txt
+	builder.Command().Textf("cp").Input(a.apkCertsInfo).Textf(" %s/META/", targetFilesDir.String())
+
+	// Copy fastboot-info.txt
+	if fastbootInfo := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.FastbootInfo)); fastbootInfo != nil {
+		// TODO (b/399788523): Autogenerate fastboot-info.txt if there is no source fastboot-info.txt
+		// https://cs.android.com/android/_/android/platform/build/+/80b9546f8f69e78b8fe1870e0e745d70fc18dfcd:core/Makefile;l=5831-5893;drc=077490384423dff9eac954da5c001c6f0be3fa6e;bpv=0;bpt=0
+		builder.Command().Textf("cp").Input(fastbootInfo).Textf(" %s/META/fastboot-info.txt", targetFilesDir.String())
+	}
+
+	// kernel_configs.txt and kernel_version.txt
+	if a.kernelConfig != nil {
+		builder.Command().Textf("cp").Input(a.kernelConfig).Textf(" %s/META/", targetFilesDir.String())
+	}
+	if a.kernelVersion != nil {
+		builder.Command().Textf("cp").Input(a.kernelVersion).Textf(" %s/META/", targetFilesDir.String())
+	}
+	// misc_info.txt
+	if a.miscInfo != nil {
+		builder.Command().Textf("cp").Input(a.miscInfo).Textf(" %s/META/", targetFilesDir.String())
+	}
+	// apex_info.pb, care_map.pb, vbmeta_digest.txt
+	a.addImgToTargetFiles(ctx, builder, targetFilesDir.String())
+
+	if a.partitionProps.Super_partition_name != nil {
+		superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
+			// dynamic_partitions_info.txt
+			// TODO (b/390192334): Add `building_super_empty_partition=true`
+			builder.Command().Text("cp").Input(info.DynamicPartitionsInfo).Textf(" %s/META/", targetFilesDir.String())
+		} else {
+			ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
+		}
+	}
+
+}
+
+// A partial implementation of make's $PRODUCT_OUT/misc_info.txt
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5894?q=misc_info.txt%20f:build%2Fmake%2Fcore%2FMakefile&ss=android%2Fplatform%2Fsuperproject%2Fmain
+// This file is subsequently used by add_img_to_target_files to create additioanl metadata files like apex_info.pb
+// TODO (b/399788119): Complete the migration of misc_info.txt
+func (a *androidDevice) addMiscInfo(ctx android.ModuleContext) android.Path {
+	builder := android.NewRuleBuilder(pctx, ctx)
+	miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
+	builder.Command().
+		Textf("rm -f %s", miscInfo).
+		Textf("&& echo recovery_api_version=%s >> %s", ctx.Config().VendorConfig("recovery").String("recovery_api_version"), miscInfo).
+		Textf("&& echo fstab_version=%s >> %s", ctx.Config().VendorConfig("recovery").String("recovery_fstab_version"), miscInfo).
+		ImplicitOutput(miscInfo)
+
+	if a.partitionProps.Recovery_partition_name == nil {
+		builder.Command().Textf("echo no_recovery=true >> %s", miscInfo)
+	}
+	fsInfos := a.getFsInfos(ctx)
+	for _, partition := range android.SortedKeys(fsInfos) {
+		if fsInfos[partition].UseAvb {
+			builder.Command().Textf("echo 'avb_%s_hashtree_enable=true' >> %s", partition, miscInfo)
+		}
+	}
+	if len(a.partitionProps.Vbmeta_partitions) > 0 {
+		builder.Command().
+			Textf("echo avb_enable=true >> %s", miscInfo).
+			Textf("&& echo avb_building_vbmeta_image=true >> %s", miscInfo).
+			Textf("&& echo avb_avbtool=avbtool >> %s", miscInfo)
+	}
+	if a.partitionProps.Boot_partition_name != nil {
+		builder.Command().Textf("echo boot_images=boot.img >> %s", miscInfo)
+	}
+
+	if a.partitionProps.Super_partition_name != nil {
+		superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
+			// cat dynamic_partition_info.txt
+			builder.Command().Text("cat").Input(info.DynamicPartitionsInfo).Textf(" >> %s", miscInfo)
+		} else {
+			ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
+		}
+	}
+	bootImgNames := []*string{
+		a.partitionProps.Boot_partition_name,
+		a.partitionProps.Init_boot_partition_name,
+		a.partitionProps.Vendor_boot_partition_name,
+	}
+	for _, bootImgName := range bootImgNames {
+		if bootImgName == nil {
+			continue
+		}
+
+		bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(bootImgName), filesystemDepTag)
+		bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
+		// cat avb_ metadata of the boot images
+		builder.Command().Text("cat").Input(bootImgInfo.PropFileForMiscInfo).Textf(" >> %s", miscInfo)
+	}
+
+	builder.Build("misc_info", "Building misc_info")
+
+	return miscInfo
+}
+
+// addImgToTargetFiles invokes `add_img_to_target_files` and creates the following files in META/
+// - apex_info.pb
+// - care_map.pb
+// - vbmeta_digest.txt
+func (a *androidDevice) addImgToTargetFiles(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir string) {
+	mkbootimg := ctx.Config().HostToolPath(ctx, "mkbootimg")
+	builder.Command().
+		Textf("PATH=%s:$PATH", ctx.Config().HostToolDir()).
+		Textf("MKBOOTIMG=%s", mkbootimg).
+		Implicit(mkbootimg).
+		BuiltTool("add_img_to_target_files").
+		Flag("-a -v -p").
+		Flag(ctx.Config().HostToolDir()).
+		Text(targetFilesDir)
+}
+
+type ApexKeyPathInfo struct {
+	ApexKeyPath android.Path
+}
+
+var ApexKeyPathInfoProvider = blueprint.NewProvider[ApexKeyPathInfo]()
+
+func (a *androidDevice) generateFilesystemConfigForTargetFiles(ctx android.ModuleContext, builder *android.RuleBuilder, stagingDirTimestamp android.Path, targetFilesDir, stagingDir, filename string) {
+	fsConfigOut := android.PathForModuleOut(ctx, filename)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:     fsConfigRule,
+		Implicit: stagingDirTimestamp,
+		Output:   fsConfigOut,
+		Args: map[string]string{
+			"rootDir": stagingDir,
+			"prefix":  "",
+		},
+	})
+	builder.Command().Textf("cp").Input(fsConfigOut).Textf(" %s/META/", targetFilesDir)
 }
 
 // Filenames for the partition specific fs_config files.
@@ -635,3 +883,121 @@
 		}
 	}
 }
+
+func (a *androidDevice) getKernel(ctx android.ModuleContext) android.Path {
+	if a.partitionProps.Boot_partition_name != nil {
+		bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag)
+		bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
+		return bootImgInfo.Kernel
+	}
+	return nil
+}
+
+// Gets the kernel version and configs from the actual kernel file itself. Roughly equivalent to
+// this make code: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5443;drc=c0b66fc59de069e06ce0ffd703d4d21613be30c6
+// However, it is a simplified version of that make code. Differences include:
+//   - Not handling BOARD_KERNEL_CONFIG_FILE because BOARD_KERNEL_CONFIG_FILE was never used.
+//   - Not unpacking the bootimage, as we should be able to just always export the kernel directly
+//     in the BootimgInfo. We don't currently support prebuilt boot images, but even if we add that
+//     in the future, it can be done in a prebuilt_bootimage module type that still exports the same
+//     BootimgInfo.
+//   - We don't print a warning and output '<unknown-kernel>' to kernel_version_for_uffd_gc.txt
+//     because we expect the kernel to always be present. If it's not, we will get an error that
+//     kernel_version_for_uffd_gc.txt doesn't exist. This may require later tweaking to the
+//     dexpreopt rules so that they don't attempt to access that file in builds that don't have
+//     a kernel.
+func (a *androidDevice) extractKernelVersionAndConfigs(ctx android.ModuleContext) (android.Path, android.Path) {
+	kernel := a.getKernel(ctx)
+	// If there's no kernel, don't create kernel version / kernel config files. Reverse dependencies
+	// on those files have to account for this, for example by disabling dexpreopt in unbundled
+	// builds.
+	if kernel == nil {
+		return nil, nil
+	}
+
+	lz4tool := ctx.Config().HostToolPath(ctx, "lz4")
+
+	extractedVersionFile := android.PathForModuleOut(ctx, "kernel_version.txt")
+	extractedConfigsFile := android.PathForModuleOut(ctx, "kernel_configs.txt")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	builder.Command().BuiltTool("extract_kernel").
+		Flag("--tools lz4:"+lz4tool.String()).Implicit(lz4tool).
+		FlagWithInput("--input ", kernel).
+		FlagWithOutput("--output-release ", extractedVersionFile).
+		FlagWithOutput("--output-configs ", extractedConfigsFile).
+		Textf(`&& printf "\n" >> %s`, extractedVersionFile)
+
+	if specifiedVersion := proptools.String(a.deviceProps.Kernel_version); specifiedVersion != "" {
+		specifiedVersionFile := android.PathForModuleOut(ctx, "specified_kernel_version.txt")
+		android.WriteFileRule(ctx, specifiedVersionFile, specifiedVersion)
+		builder.Command().Text("diff -q").
+			Input(specifiedVersionFile).
+			Input(extractedVersionFile).
+			Textf(`|| (echo "Specified kernel version '$(cat %s)' does not match actual kernel version '$(cat %s)'"; exit 1)`, specifiedVersionFile, extractedVersionFile)
+	}
+
+	builder.Build("extract_kernel_info", "Extract kernel version and configs")
+
+	if proptools.Bool(a.deviceProps.Main_device) && !ctx.Config().KatiEnabled() {
+		if ctx.Config().EnableUffdGc() == "default" {
+			kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.CpIfChanged,
+				Input:  extractedVersionFile,
+				Output: kernelVersionFile,
+			})
+		}
+
+		ctx.DistForGoal("droid_targets", extractedVersionFile)
+	}
+
+	return extractedVersionFile, extractedConfigsFile
+}
+
+func (a *androidDevice) buildApkCertsInfo(ctx android.ModuleContext, allInstalledModules []android.Module) android.Path {
+	// TODO (spandandas): Add compressed
+	formatLine := func(cert java.Certificate, name, partition string) string {
+		pem := cert.AndroidMkString()
+		var key string
+		if cert.Key == nil {
+			key = ""
+		} else {
+			key = cert.Key.String()
+		}
+		return fmt.Sprintf(`name="%s" certificate="%s" private_key="%s" partition="%s"`, name, pem, key, partition)
+	}
+
+	apkCerts := []string{}
+	for _, installedModule := range allInstalledModules {
+		partition := ""
+		if commonInfo, ok := android.OtherModuleProvider(ctx, installedModule, android.CommonModuleInfoProvider); ok {
+			partition = commonInfo.PartitionTag
+		} else {
+			ctx.ModuleErrorf("%s does not set CommonModuleInfoKey", installedModule.Name())
+		}
+		if info, ok := android.OtherModuleProvider(ctx, installedModule, java.AppInfoProvider); ok {
+			apkCerts = append(apkCerts, formatLine(info.Certificate, info.InstallApkName+".apk", partition))
+		} else if info, ok := android.OtherModuleProvider(ctx, installedModule, java.AppInfosProvider); ok {
+			for _, certInfo := range info {
+				// Partition information of apk-in-apex is not exported to the legacy Make packaging system.
+				// Hardcode the partition to "system"
+				apkCerts = append(apkCerts, formatLine(certInfo.Certificate, certInfo.InstallApkName+".apk", "system"))
+			}
+		} else if info, ok := android.OtherModuleProvider(ctx, installedModule, java.RuntimeResourceOverlayInfoProvider); ok {
+			apkCerts = append(apkCerts, formatLine(info.Certificate, info.OutputFile.Base(), partition))
+		}
+	}
+	slices.Sort(apkCerts) // sort by name
+	fsInfos := a.getFsInfos(ctx)
+	if fsInfos["system"].HasFsverity {
+		defaultPem, defaultKey := ctx.Config().DefaultAppCertificate(ctx)
+		apkCerts = append(apkCerts, formatLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifest.apk", "system"))
+		if info, ok := fsInfos["system_ext"]; ok && info.HasFsverity {
+			apkCerts = append(apkCerts, formatLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifestSystemExt.apk", "system_ext"))
+		}
+	}
+
+	apkCertsInfo := android.PathForModuleOut(ctx, "apkcerts.txt")
+	android.WriteFileRuleVerbatim(ctx, apkCertsInfo, strings.Join(apkCerts, "\n")+"\n")
+	return apkCertsInfo
+}
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index c1e03cb..327a41f 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -210,6 +210,9 @@
 
 // Implements android.SourceFileProducer
 func (a *avbAddHashFooter) Srcs() android.Paths {
+	if a.output == nil {
+		return nil
+	}
 	return append(android.Paths{}, a.output)
 }
 
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index effbd65..7959365 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -201,7 +201,8 @@
 		return
 	}
 
-	unsignedOutput := b.buildBootImage(ctx, b.getKernelPath(ctx))
+	kernelPath := b.getKernelPath(ctx)
+	unsignedOutput := b.buildBootImage(ctx, kernelPath)
 
 	output := unsignedOutput
 	if proptools.Bool(b.properties.Use_avb) {
@@ -212,7 +213,7 @@
 		case "default":
 			output = b.signImage(ctx, unsignedOutput)
 		case "make_legacy":
-			output = b.addAvbFooter(ctx, unsignedOutput, b.getKernelPath(ctx))
+			output = b.addAvbFooter(ctx, unsignedOutput, kernelPath)
 		default:
 			ctx.PropertyErrorf("avb_mode", `Unknown value for avb_mode, expected "default" or "make_legacy", got: %q`, *b.properties.Avb_mode)
 		}
@@ -235,12 +236,14 @@
 	}
 
 	// Set BootimgInfo for building target_files.zip
+	dtbPath := b.getDtbPath(ctx)
 	android.SetProvider(ctx, BootimgInfoProvider, BootimgInfo{
-		Cmdline:    b.properties.Cmdline,
-		Kernel:     b.getKernelPath(ctx),
-		Dtb:        b.getDtbPath(ctx),
-		Bootconfig: b.getBootconfigPath(ctx),
-		Output:     output,
+		Cmdline:             b.properties.Cmdline,
+		Kernel:              kernelPath,
+		Dtb:                 dtbPath,
+		Bootconfig:          b.getBootconfigPath(ctx),
+		Output:              output,
+		PropFileForMiscInfo: b.buildPropFileForMiscInfo(ctx),
 	})
 
 	extractedPublicKey := android.PathForModuleOut(ctx, b.partitionName()+".avbpubkey")
@@ -263,16 +266,32 @@
 		PublicKey:             extractedPublicKey,
 		Output:                output,
 	})
+
+	// Dump compliance metadata
+	complianceMetadataInfo := ctx.ComplianceMetadataInfo()
+	prebuiltFilesCopied := make([]string, 0)
+	if kernelPath != nil {
+		prebuiltFilesCopied = append(prebuiltFilesCopied, kernelPath.String()+":kernel")
+	}
+	if dtbPath != nil {
+		prebuiltFilesCopied = append(prebuiltFilesCopied, dtbPath.String()+":dtb.img")
+	}
+	complianceMetadataInfo.SetPrebuiltFilesCopied(prebuiltFilesCopied)
+
+	if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" {
+		buildComplianceMetadata(ctx, bootimgRamdiskDep)
+	}
 }
 
 var BootimgInfoProvider = blueprint.NewProvider[BootimgInfo]()
 
 type BootimgInfo struct {
-	Cmdline    []string
-	Kernel     android.Path
-	Dtb        android.Path
-	Bootconfig android.Path
-	Output     android.Path
+	Cmdline             []string
+	Kernel              android.Path
+	Dtb                 android.Path
+	Bootconfig          android.Path
+	Output              android.Path
+	PropFileForMiscInfo android.Path
 }
 
 func (b *bootimg) getKernelPath(ctx android.ModuleContext) android.Path {
@@ -491,6 +510,25 @@
 	return propFile, deps
 }
 
+func (b *bootimg) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
+	var sb strings.Builder
+	addStr := func(name string, value string) {
+		fmt.Fprintf(&sb, "%s=%s\n", name, value)
+	}
+
+	bootImgType := proptools.String(b.properties.Boot_image_type)
+	addStr("avb_"+bootImgType+"_add_hash_footer_args", "TODO(b/398036609)")
+	if b.properties.Avb_private_key != nil {
+		addStr("avb_"+bootImgType+"_algorithm", proptools.StringDefault(b.properties.Avb_algorithm, "SHA256_RSA4096"))
+		addStr("avb_"+bootImgType+"_key_path", android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key)).String())
+		addStr("avb_"+bootImgType+"_rollback_index_location", strconv.Itoa(proptools.Int(b.properties.Avb_rollback_index_location)))
+	}
+
+	propFile := android.PathForModuleOut(ctx, "prop_for_misc_info")
+	android.WriteFileRuleVerbatim(ctx, propFile, sb.String())
+	return propFile
+}
+
 var _ android.AndroidMkEntriesProvider = (*bootimg)(nil)
 
 // Implements android.AndroidMkEntriesProvider
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 28eb36d..b854880 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -30,6 +30,7 @@
 	"android/soong/linkerconfig"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/depset"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -208,11 +209,6 @@
 	// Install aconfig_flags.pb file for the modules installed in this partition.
 	Gen_aconfig_flags_pb *bool
 
-	// List of names of other filesystem partitions to import their aconfig flags from.
-	// This is used for the system partition to import system_ext's aconfig flags, as currently
-	// those are considered one "container": aosp/3261300
-	Import_aconfig_flags_from []string
-
 	Fsverity fsverityProperties
 
 	// If this property is set to true, the filesystem will call ctx.UncheckedModule(), causing
@@ -359,9 +355,6 @@
 	if f.properties.Android_filesystem_deps.System_ext != nil {
 		ctx.AddDependency(ctx.Module(), interPartitionDependencyTag, proptools.String(f.properties.Android_filesystem_deps.System_ext))
 	}
-	for _, partition := range f.properties.Import_aconfig_flags_from {
-		ctx.AddDependency(ctx.Module(), importAconfigDependencyTag, partition)
-	}
 	for _, partition := range f.properties.Include_files_of {
 		ctx.AddDependency(ctx.Module(), interPartitionInstallDependencyTag, partition)
 	}
@@ -382,6 +375,20 @@
 	return fs == unknown
 }
 
+// Type string that build_image.py accepts.
+func (t fsType) String() string {
+	switch t {
+	// TODO(372522486): add more types like f2fs, erofs, etc.
+	case ext4Type:
+		return "ext4"
+	case erofsType:
+		return "erofs"
+	case f2fsType:
+		return "f2fs"
+	}
+	panic(fmt.Errorf("unsupported fs type %d", t))
+}
+
 type InstalledFilesStruct struct {
 	Txt  android.Path
 	Json android.Path
@@ -432,8 +439,8 @@
 
 	FullInstallPaths []FullInstallPathInfo
 
-	// Installed files list
-	InstalledFiles InstalledFilesStruct
+	// Installed files dep set of this module and its dependency filesystem modules
+	InstalledFilesDepSet depset.DepSet[InstalledFilesStruct]
 
 	// Path to compress hints file for erofs filesystems
 	// This will be nil for other fileystems like ext4
@@ -444,6 +451,10 @@
 	FilesystemConfig android.Path
 
 	Owners []InstalledModuleInfo
+
+	UseAvb bool
+
+	HasFsverity bool
 }
 
 // FullInstallPathInfo contains information about the "full install" paths of all the files
@@ -474,11 +485,7 @@
 
 var FilesystemProvider = blueprint.NewProvider[FilesystemInfo]()
 
-type FilesystemDefaultsInfo struct {
-	// Identifies which partition this is for //visibility:any_system_image (and others) visibility
-	// checks, and will be used in the future for API surface checks.
-	PartitionType string
-}
+type FilesystemDefaultsInfo struct{}
 
 var FilesystemDefaultsInfoProvider = blueprint.NewProvider[FilesystemDefaultsInfo]()
 
@@ -551,13 +558,13 @@
 	}
 }
 
-func buildInstalledFiles(ctx android.ModuleContext, partition string, rootDir android.Path, image android.Path) (txt android.ModuleOutPath, json android.ModuleOutPath) {
+func buildInstalledFiles(ctx android.ModuleContext, partition string, rootDir android.Path, image android.Path) InstalledFilesStruct {
 	fileName := "installed-files"
 	if len(partition) > 0 {
 		fileName += fmt.Sprintf("-%s", partition)
 	}
-	txt = android.PathForModuleOut(ctx, fmt.Sprintf("%s.txt", fileName))
-	json = android.PathForModuleOut(ctx, fmt.Sprintf("%s.json", fileName))
+	txt := android.PathForModuleOut(ctx, fmt.Sprintf("%s.txt", fileName))
+	json := android.PathForModuleOut(ctx, fmt.Sprintf("%s.json", fileName))
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        installedFilesJsonRule,
@@ -576,7 +583,10 @@
 		Description: "Installed file list txt",
 	})
 
-	return txt, json
+	return InstalledFilesStruct{
+		Txt:  txt,
+		Json: json,
+	}
 }
 
 func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -659,11 +669,15 @@
 	fileListFile := android.PathForModuleOut(ctx, "fileList")
 	android.WriteFileRule(ctx, fileListFile, f.installedFilesList())
 
-	partitionName := f.partitionName()
-	if partitionName == "system" {
-		partitionName = ""
+	var partitionNameForInstalledFiles string
+	switch f.partitionName() {
+	case "system":
+		partitionNameForInstalledFiles = ""
+	case "vendor_ramdisk":
+		partitionNameForInstalledFiles = "vendor-ramdisk"
+	default:
+		partitionNameForInstalledFiles = f.partitionName()
 	}
-	installedFileTxt, installedFileJson := buildInstalledFiles(ctx, partitionName, rootDir, f.output)
 
 	var erofsCompressHints android.Path
 	if f.properties.Erofs.Compress_hints != nil {
@@ -684,18 +698,25 @@
 		BuildImagePropFileDeps: buildImagePropFileDeps,
 		SpecsForSystemOther:    f.systemOtherFiles(ctx),
 		FullInstallPaths:       fullInstallPaths,
-		InstalledFiles: InstalledFilesStruct{
-			Txt:  installedFileTxt,
-			Json: installedFileJson,
-		},
+		InstalledFilesDepSet: depset.New(
+			depset.POSTORDER,
+			[]InstalledFilesStruct{buildInstalledFiles(ctx, partitionNameForInstalledFiles, rootDir, f.output)},
+			includeFilesInstalledFiles(ctx),
+		),
 		ErofsCompressHints: erofsCompressHints,
 		SelinuxFc:          f.selinuxFc,
 		FilesystemConfig:   f.generateFilesystemConfig(ctx, rootDir, rebasedDir),
 		Owners:             f.gatherOwners(specs),
+		UseAvb:             proptools.Bool(f.properties.Use_avb),
+		HasFsverity:        f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) != nil,
 	}
 
 	android.SetProvider(ctx, FilesystemProvider, fsInfo)
 
+	android.SetProvider(ctx, android.PartitionTypeInfoProvider, android.PartitionTypeInfo{
+		PartitionType: f.PartitionType(),
+	})
+
 	f.fileListFile = fileListFile
 
 	if proptools.Bool(f.properties.Unchecked_module) {
@@ -703,6 +724,14 @@
 	}
 
 	f.setVbmetaPartitionProvider(ctx)
+
+	// Dump metadata that can not be done in android/compliance-metadata.go
+	complianceMetadataInfo := ctx.ComplianceMetadataInfo()
+	filesContained := make([]string, 0, len(fullInstallPaths))
+	for _, file := range fullInstallPaths {
+		filesContained = append(filesContained, file.FullInstallPath.String())
+	}
+	complianceMetadataInfo.SetFilesContained(filesContained)
 }
 
 func (f *filesystem) fileystemStagingDirTimestamp(ctx android.ModuleContext) android.WritablePath {
@@ -822,11 +851,12 @@
 	}
 
 	ctx.VisitDirectDepsProxyWithTag(android.DefaultsDepTag, func(m android.ModuleProxy) {
-		if fdm, ok := android.OtherModuleProvider(ctx, m, FilesystemDefaultsInfoProvider); ok {
-			if p.PartitionType() != fdm.PartitionType {
+		if _, ok := android.OtherModuleProvider(ctx, m, FilesystemDefaultsInfoProvider); ok {
+			partitionInfo := android.OtherModuleProviderOrDefault(ctx, m, android.PartitionTypeInfoProvider)
+			if p.PartitionType() != partitionInfo.PartitionType {
 				ctx.PropertyErrorf("partition_type",
 					"%s doesn't match with the partition type %s of the filesystem default module %s",
-					p.PartitionType(), fdm.PartitionType, m.Name())
+					p.PartitionType(), partitionInfo.PartitionType, m.Name())
 			}
 		}
 	})
@@ -886,13 +916,24 @@
 		builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String()))
 		builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
 		f.appendToEntry(ctx, dst)
-		// Only add the fullInstallPath logic for files in the rebased dir. The root dir
-		// is harder to install to.
-		if strings.HasPrefix(name, rebasedPrefix) {
+		// Add the fullInstallPath logic for files in the rebased dir, and for non-rebased files in "system" partition
+		// the fullInstallPath is changed to "root" which aligns to the behavior in Make.
+		if f.PartitionType() == "system" {
+			installPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix))
+			if !strings.HasPrefix(name, rebasedPrefix) {
+				installPath = android.PathForModuleInPartitionInstall(ctx, "root", name)
+			}
 			*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
-				FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)),
+				FullInstallPath: installPath,
 				SymlinkTarget:   target,
 			})
+		} else {
+			if strings.HasPrefix(name, rebasedPrefix) {
+				*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+					FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)),
+					SymlinkTarget:   target,
+				})
+			}
 		}
 	}
 
@@ -1004,21 +1045,7 @@
 		deps = append(deps, path)
 	}
 
-	// Type string that build_image.py accepts.
-	fsTypeStr := func(t fsType) string {
-		switch t {
-		// TODO(372522486): add more types like f2fs, erofs, etc.
-		case ext4Type:
-			return "ext4"
-		case erofsType:
-			return "erofs"
-		case f2fsType:
-			return "f2fs"
-		}
-		panic(fmt.Errorf("unsupported fs type %v", t))
-	}
-
-	addStr("fs_type", fsTypeStr(f.fsType(ctx)))
+	addStr("fs_type", f.fsType(ctx).String())
 	addStr("mount_point", proptools.StringDefault(f.properties.Mount_point, "/"))
 	addStr("use_dynamic_partition_size", "true")
 	addPath("ext_mkuserimg", ctx.Config().HostToolPath(ctx, "mkuserimg_mke2fs"))
@@ -1037,28 +1064,7 @@
 			addPath("avb_key_path", key)
 		}
 		addStr("partition_name", f.partitionName())
-		avb_add_hashtree_footer_args := ""
-		if !proptools.BoolDefault(f.properties.Use_fec, true) {
-			avb_add_hashtree_footer_args += " --do_not_generate_fec"
-		}
-		hashAlgorithm := proptools.StringDefault(f.properties.Avb_hash_algorithm, "sha256")
-		avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
-		if f.properties.Rollback_index != nil {
-			rollbackIndex := proptools.Int(f.properties.Rollback_index)
-			if rollbackIndex < 0 {
-				ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative")
-			}
-			avb_add_hashtree_footer_args += " --rollback_index " + strconv.Itoa(rollbackIndex)
-		}
-		avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.os_version:%s", f.partitionName(), ctx.Config().PlatformVersionLastStable())
-		// We're not going to add BuildFingerPrintFile as a dep. If it changed, it's likely because
-		// the build number changed, and we don't want to trigger rebuilds solely based on the build
-		// number.
-		avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildFingerprintFile(ctx))
-		if f.properties.Security_patch != nil && proptools.String(f.properties.Security_patch) != "" {
-			avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.security_patch:%s", f.partitionName(), proptools.String(f.properties.Security_patch))
-		}
-		addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
+		addStr("avb_add_hashtree_footer_args", f.getAvbAddHashtreeFooterArgs(ctx))
 	}
 
 	if f.properties.File_contexts != nil && f.properties.Precompiled_file_contexts != nil {
@@ -1107,7 +1113,7 @@
 			addStr("f2fs_sparse_flag", "-S")
 		}
 	}
-	f.checkFsTypePropertyError(ctx, fst, fsTypeStr(fst))
+	f.checkFsTypePropertyError(ctx, fst, fst.String())
 
 	if f.properties.Partition_size != nil {
 		addStr("partition_size", strconv.FormatInt(*f.properties.Partition_size, 10))
@@ -1138,6 +1144,31 @@
 	return propFile, deps
 }
 
+func (f *filesystem) getAvbAddHashtreeFooterArgs(ctx android.ModuleContext) string {
+	avb_add_hashtree_footer_args := ""
+	if !proptools.BoolDefault(f.properties.Use_fec, true) {
+		avb_add_hashtree_footer_args += " --do_not_generate_fec"
+	}
+	hashAlgorithm := proptools.StringDefault(f.properties.Avb_hash_algorithm, "sha256")
+	avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
+	if f.properties.Rollback_index != nil {
+		rollbackIndex := proptools.Int(f.properties.Rollback_index)
+		if rollbackIndex < 0 {
+			ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative")
+		}
+		avb_add_hashtree_footer_args += " --rollback_index " + strconv.Itoa(rollbackIndex)
+	}
+	avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.os_version:%s", f.partitionName(), ctx.Config().PlatformVersionLastStable())
+	// We're not going to add BuildFingerPrintFile as a dep. If it changed, it's likely because
+	// the build number changed, and we don't want to trigger rebuilds solely based on the build
+	// number.
+	avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildFingerprintFile(ctx))
+	if f.properties.Security_patch != nil && proptools.String(f.properties.Security_patch) != "" {
+		avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.security_patch:%s", f.partitionName(), proptools.String(f.properties.Security_patch))
+	}
+	return avb_add_hashtree_footer_args
+}
+
 // This method checks if there is any property set for the fstype(s) other than
 // the current fstype.
 func (f *filesystem) checkFsTypePropertyError(ctx android.ModuleContext, t fsType, fs string) {
@@ -1171,6 +1202,15 @@
 	return rootDirs, partitions
 }
 
+func includeFilesInstalledFiles(ctx android.ModuleContext) (ret []depset.DepSet[InstalledFilesStruct]) {
+	ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) {
+		if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok {
+			ret = append(ret, fsProvider.InstalledFilesDepSet)
+		}
+	})
+	return
+}
+
 func (f *filesystem) buildCpioImage(
 	ctx android.ModuleContext,
 	builder *android.RuleBuilder,
@@ -1413,7 +1453,8 @@
 
 func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	validatePartitionType(ctx, f)
-	android.SetProvider(ctx, FilesystemDefaultsInfoProvider, FilesystemDefaultsInfo{
+	android.SetProvider(ctx, FilesystemDefaultsInfoProvider, FilesystemDefaultsInfo{})
+	android.SetProvider(ctx, android.PartitionTypeInfoProvider, android.PartitionTypeInfo{
 		PartitionType: f.PartitionType(),
 	})
 }
@@ -1432,7 +1473,7 @@
 
 	deps := f.gatherFilteredPackagingSpecs(ctx)
 	ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
-		if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider).Enabled {
 			return false
 		}
 		for _, ps := range android.OtherModuleProviderOrDefault(
@@ -1453,7 +1494,7 @@
 
 	var requireModules []android.ModuleProxy
 	ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
-		if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider).Enabled {
 			return false
 		}
 		_, parentInPackage := modulesInPackageByModule[parent]
@@ -1525,10 +1566,11 @@
 	})
 }
 
-func (f *filesystem) MakeVars(ctx android.MakeVarsModuleContext) {
+func (f *filesystem) MakeVars(ctx android.MakeVarsModuleContext) []android.ModuleMakeVarsValue {
 	if f.Name() == ctx.Config().SoongDefinedSystemImage() {
-		ctx.StrictRaw("SOONG_DEFINED_SYSTEM_IMAGE_PATH", f.output.String())
+		return []android.ModuleMakeVarsValue{{"SOONG_DEFINED_SYSTEM_IMAGE_PATH", f.output.String()}}
 	}
+	return nil
 }
 
 func setCommonFilesystemInfo(ctx android.ModuleContext, m Filesystem) {
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 6d0b490..bf7f5b6 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -723,26 +723,47 @@
 
 // override_android_* modules implicitly override their base module.
 // If both of these are listed in `deps`, the base module should not be installed.
+// Also, required deps should be updated too.
 func TestOverrideModulesInDeps(t *testing.T) {
 	result := fixture.RunTestWithBp(t, `
+		cc_library_shared {
+			name: "libfoo",
+			stl: "none",
+			system_shared_libs: [],
+		}
+		cc_library_shared {
+			name: "libbar",
+			stl: "none",
+			system_shared_libs: [],
+		}
 		android_filesystem {
 			name: "myfilesystem",
+			deps: ["myapp"],
+		}
+		android_filesystem {
+			name: "myfilesystem_overridden",
 			deps: ["myapp", "myoverrideapp"],
 		}
 
 		android_app {
 			name: "myapp",
 			platform_apis: true,
+			required: ["libfoo"],
 		}
 		override_android_app {
 			name: "myoverrideapp",
 			base: "myapp",
+			required: ["libbar"],
 		}
 	`)
 
 	partition := result.ModuleForTests(t, "myfilesystem", "android_common")
 	fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
-	android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\n", fileList)
+	android.AssertStringEquals(t, "filesystem without override app", "app/myapp/myapp.apk\nlib64/libfoo.so\n", fileList)
+
+	overriddenPartition := result.ModuleForTests(t, "myfilesystem_overridden", "android_common")
+	overriddenFileList := android.ContentFromFileRuleForTests(t, result.TestContext, overriddenPartition.Output("fileList"))
+	android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\nlib64/libbar.so\n", overriddenFileList)
 }
 
 func TestRamdiskPartitionSetsDevNodes(t *testing.T) {
diff --git a/filesystem/super_image.go b/filesystem/super_image.go
index 58c938a..cd7df02 100644
--- a/filesystem/super_image.go
+++ b/filesystem/super_image.go
@@ -78,6 +78,10 @@
 		// specified we default to COW version 2 in update_engine for backwards compatibility
 		Cow_version *int64
 	}
+	// Whether the super image will be disted in the update package
+	Super_image_in_update_package *bool
+	// Whether a super_empty.img should be created
+	Create_super_empty *bool
 }
 
 type PartitionGroupsInfo struct {
@@ -114,6 +118,10 @@
 	// Mapping from the sub-partition type to its re-exported FileSystemInfo providers from the
 	// sub-partitions.
 	SubImageInfo map[string]FilesystemInfo
+
+	DynamicPartitionsInfo android.Path
+
+	SuperEmptyImage android.Path
 }
 
 var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]()
@@ -159,7 +167,7 @@
 }
 
 func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	miscInfo, deps, subImageInfos := s.buildMiscInfo(ctx)
+	miscInfo, deps, subImageInfos := s.buildMiscInfo(ctx, false)
 	builder := android.NewRuleBuilder(pctx, ctx)
 	output := android.PathForModuleOut(ctx, s.installFileName())
 	lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
@@ -172,90 +180,52 @@
 		Implicits(deps).
 		Output(output)
 	builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
+	var superEmptyImage android.WritablePath
+	if proptools.Bool(s.properties.Create_super_empty) {
+		superEmptyImageBuilder := android.NewRuleBuilder(pctx, ctx)
+		superEmptyImage = android.PathForModuleOut(ctx, "super_empty.img")
+		superEmptyMiscInfo, superEmptyDeps, _ := s.buildMiscInfo(ctx, true)
+		if superEmptyDeps != nil {
+			ctx.ModuleErrorf("TODO: Handle additional deps when building super_empty.img")
+		}
+		superEmptyImageBuilder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
+			BuiltTool("build_super_image").
+			Text("-v").
+			Input(superEmptyMiscInfo).
+			Implicit(lpMake).
+			Output(superEmptyImage)
+		superEmptyImageBuilder.Build("build_super_empty_image", fmt.Sprintf("Creating super empty image %s", s.BaseModuleName()))
+	}
 	android.SetProvider(ctx, SuperImageProvider, SuperImageInfo{
-		SuperImage:   output,
-		SubImageInfo: subImageInfos,
+		SuperImage:            output,
+		SubImageInfo:          subImageInfos,
+		DynamicPartitionsInfo: s.generateDynamicPartitionsInfo(ctx),
+		SuperEmptyImage:       superEmptyImage,
 	})
 	ctx.SetOutputFiles([]android.Path{output}, "")
 	ctx.CheckbuildFile(output)
+
+	buildComplianceMetadata(ctx, subImageDepTag)
 }
 
 func (s *superImage) installFileName() string {
 	return "super.img"
 }
 
-func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths, map[string]FilesystemInfo) {
+func (s *superImage) buildMiscInfo(ctx android.ModuleContext, superEmpty bool) (android.Path, android.Paths, map[string]FilesystemInfo) {
 	var miscInfoString strings.Builder
+	partitionList := s.dumpDynamicPartitionInfo(ctx, &miscInfoString)
 	addStr := func(name string, value string) {
 		miscInfoString.WriteString(name)
 		miscInfoString.WriteRune('=')
 		miscInfoString.WriteString(value)
 		miscInfoString.WriteRune('\n')
 	}
-
-	addStr("build_super_partition", "true")
-	addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
-	if proptools.Bool(s.properties.Retrofit) {
-		addStr("dynamic_partition_retrofit", "true")
-	}
-	addStr("lpmake", "lpmake")
-	addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
-	if len(s.properties.Block_devices) > 0 {
-		addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
-	}
-	addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size)))
-	// TODO: In make, there's more complicated logic than just this surrounding super_*_device_size
-	addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
-	var groups, partitionList []string
-	for _, groupInfo := range s.properties.Partition_groups {
-		groups = append(groups, groupInfo.Name)
-		partitionList = append(partitionList, groupInfo.PartitionList...)
-		addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
-		addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
-	}
-	initialPartitionListLen := len(partitionList)
-	partitionList = android.SortedUniqueStrings(partitionList)
-	if len(partitionList) != initialPartitionListLen {
-		ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property")
-	}
-	addStr("super_partition_groups", strings.Join(groups, " "))
-	addStr("dynamic_partition_list", strings.Join(partitionList, " "))
-
 	addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
-
-	if proptools.Bool(s.properties.Virtual_ab.Enable) {
-		addStr("virtual_ab", "true")
-		if proptools.Bool(s.properties.Virtual_ab.Retrofit) {
-			addStr("virtual_ab_retrofit", "true")
-		}
-		addStr("virtual_ab_compression", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab.Compression)))
-		if s.properties.Virtual_ab.Compression_method != nil {
-			matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", *s.properties.Virtual_ab.Compression_method)
-			if !matched {
-				ctx.PropertyErrorf("virtual_ab.compression_method", "compression_method cannot have special characters")
-			}
-			addStr("virtual_ab_compression_method", *s.properties.Virtual_ab.Compression_method)
-		}
-		if s.properties.Virtual_ab.Compression_factor != nil {
-			addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10))
-		}
-		if s.properties.Virtual_ab.Cow_version != nil {
-			addStr("virtual_ab_cow_version", strconv.FormatInt(*s.properties.Virtual_ab.Cow_version, 10))
-		}
-
-	} else {
-		if s.properties.Virtual_ab.Retrofit != nil {
-			ctx.PropertyErrorf("virtual_ab.retrofit", "This property cannot be set when virtual_ab is disabled")
-		}
-		if s.properties.Virtual_ab.Compression != nil {
-			ctx.PropertyErrorf("virtual_ab.compression", "This property cannot be set when virtual_ab is disabled")
-		}
-		if s.properties.Virtual_ab.Compression_method != nil {
-			ctx.PropertyErrorf("virtual_ab.compression_method", "This property cannot be set when virtual_ab is disabled")
-		}
-		if s.properties.Virtual_ab.Compression_factor != nil {
-			ctx.PropertyErrorf("virtual_ab.compression_factor", "This property cannot be set when virtual_ab is disabled")
-		}
+	if superEmpty {
+		miscInfo := android.PathForModuleOut(ctx, "misc_info_super_empty.txt")
+		android.WriteFileRule(ctx, miscInfo, miscInfoString.String())
+		return miscInfo, nil, nil
 	}
 
 	subImageInfo := make(map[string]FilesystemInfo)
@@ -346,3 +316,95 @@
 	android.WriteFileRule(ctx, miscInfo, miscInfoString.String(), missingPartitionErrorMessageFile)
 	return miscInfo, deps, subImageInfo
 }
+
+func (s *superImage) dumpDynamicPartitionInfo(ctx android.ModuleContext, sb *strings.Builder) []string {
+	addStr := func(name string, value string) {
+		sb.WriteString(name)
+		sb.WriteRune('=')
+		sb.WriteString(value)
+		sb.WriteRune('\n')
+	}
+
+	addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
+	if proptools.Bool(s.properties.Retrofit) {
+		addStr("dynamic_partition_retrofit", "true")
+	}
+	addStr("lpmake", "lpmake")
+	addStr("build_super_partition", "true")
+	if proptools.Bool(s.properties.Create_super_empty) {
+		addStr("build_super_empty_partition", "true")
+	}
+	addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
+	if len(s.properties.Block_devices) > 0 {
+		addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
+	}
+	// TODO: In make, there's more complicated logic than just this surrounding super_*_device_size
+	addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
+	var groups, partitionList []string
+	for _, groupInfo := range s.properties.Partition_groups {
+		groups = append(groups, groupInfo.Name)
+		partitionList = append(partitionList, groupInfo.PartitionList...)
+	}
+	addStr("dynamic_partition_list", strings.Join(android.SortedUniqueStrings(partitionList), " "))
+	addStr("super_partition_groups", strings.Join(groups, " "))
+	initialPartitionListLen := len(partitionList)
+	partitionList = android.SortedUniqueStrings(partitionList)
+	if len(partitionList) != initialPartitionListLen {
+		ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property")
+	}
+	// Add Partition group info after adding `super_partition_groups` and `dynamic_partition_list`
+	for _, groupInfo := range s.properties.Partition_groups {
+		addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
+		addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
+	}
+
+	if proptools.Bool(s.properties.Super_image_in_update_package) {
+		addStr("super_image_in_update_package", "true")
+	}
+	addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size)))
+
+	if proptools.Bool(s.properties.Virtual_ab.Enable) {
+		addStr("virtual_ab", "true")
+		if proptools.Bool(s.properties.Virtual_ab.Retrofit) {
+			addStr("virtual_ab_retrofit", "true")
+		}
+		addStr("virtual_ab_compression", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab.Compression)))
+		if s.properties.Virtual_ab.Compression_method != nil {
+			matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", *s.properties.Virtual_ab.Compression_method)
+			if !matched {
+				ctx.PropertyErrorf("virtual_ab.compression_method", "compression_method cannot have special characters")
+			}
+			addStr("virtual_ab_compression_method", *s.properties.Virtual_ab.Compression_method)
+		}
+		if s.properties.Virtual_ab.Cow_version != nil {
+			addStr("virtual_ab_cow_version", strconv.FormatInt(*s.properties.Virtual_ab.Cow_version, 10))
+		}
+		if s.properties.Virtual_ab.Compression_factor != nil {
+			addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10))
+		}
+
+	} else {
+		if s.properties.Virtual_ab.Retrofit != nil {
+			ctx.PropertyErrorf("virtual_ab.retrofit", "This property cannot be set when virtual_ab is disabled")
+		}
+		if s.properties.Virtual_ab.Compression != nil {
+			ctx.PropertyErrorf("virtual_ab.compression", "This property cannot be set when virtual_ab is disabled")
+		}
+		if s.properties.Virtual_ab.Compression_method != nil {
+			ctx.PropertyErrorf("virtual_ab.compression_method", "This property cannot be set when virtual_ab is disabled")
+		}
+		if s.properties.Virtual_ab.Compression_factor != nil {
+			ctx.PropertyErrorf("virtual_ab.compression_factor", "This property cannot be set when virtual_ab is disabled")
+		}
+	}
+
+	return partitionList
+}
+
+func (s *superImage) generateDynamicPartitionsInfo(ctx android.ModuleContext) android.Path {
+	var contents strings.Builder
+	s.dumpDynamicPartitionInfo(ctx, &contents)
+	dynamicPartitionsInfo := android.PathForModuleOut(ctx, "dynamic_partitions_info.txt")
+	android.WriteFileRuleVerbatim(ctx, dynamicPartitionsInfo, contents.String())
+	return dynamicPartitionsInfo
+}
diff --git a/filesystem/system_other.go b/filesystem/system_other.go
index 5309e90..cbfd78b 100644
--- a/filesystem/system_other.go
+++ b/filesystem/system_other.go
@@ -172,9 +172,10 @@
 	builder.Build("build_system_other_hermetic", "build system other")
 
 	fsInfo := FilesystemInfo{
-		Output:         output,
-		OutputHermetic: outputHermetic,
-		RootDir:        stagingDir,
+		Output:           output,
+		OutputHermetic:   outputHermetic,
+		RootDir:          stagingDir,
+		FilesystemConfig: m.generateFilesystemConfig(ctx, stagingDir, stagingDirTimestamp),
 	}
 
 	android.SetProvider(ctx, FilesystemProvider, fsInfo)
@@ -183,6 +184,20 @@
 	ctx.CheckbuildFile(output)
 }
 
+func (s *systemOtherImage) generateFilesystemConfig(ctx android.ModuleContext, stagingDir, stagingDirTimestamp android.Path) android.Path {
+	out := android.PathForModuleOut(ctx, "filesystem_config.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   fsConfigRule,
+		Input:  stagingDirTimestamp, // assemble the staging directory
+		Output: out,
+		Args: map[string]string{
+			"rootDir": stagingDir.String(),
+			"prefix":  "system/",
+		},
+	})
+	return out
+}
+
 func (f *systemOtherImage) propFileForHermeticImg(ctx android.ModuleContext, builder *android.RuleBuilder, inputPropFile android.Path) android.Path {
 	propFilePinnedTimestamp := android.PathForModuleOut(ctx, "for_target_files", "prop")
 	builder.Command().Textf("cat").Input(inputPropFile).Flag(">").Output(propFilePinnedTimestamp).
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
index 58ebcc4..0ba0a90 100644
--- a/fsgen/boot_imgs.go
+++ b/fsgen/boot_imgs.go
@@ -69,6 +69,7 @@
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
+			Boot_image_type:             proptools.StringPtr("boot"),
 			Kernel_prebuilt:             proptools.StringPtr(":" + kernelFilegroupName),
 			Header_version:              proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
 			Partition_size:              partitionSize,
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 3d83706..b73fb21 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -340,6 +340,26 @@
 	return releaseToolsFilegroupName, true
 }
 
+func (f *filesystemCreator) createFastbootInfoFilegroup(ctx android.LoadHookContext) (string, bool) {
+	fastbootInfoFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardFastbootInfoFile
+	if fastbootInfoFile == "" {
+		return "", false
+	}
+
+	fastbootInfoFilegroupName := generatedModuleName(ctx.Config(), "fastboot")
+	filegroupProps := &struct {
+		Name       *string
+		Srcs       []string
+		Visibility []string
+	}{
+		Name:       proptools.StringPtr(fastbootInfoFilegroupName),
+		Srcs:       []string{fastbootInfoFile},
+		Visibility: []string{"//visibility:public"},
+	}
+	ctx.CreateModuleInDirectory(android.FileGroupFactory, ".", filegroupProps)
+	return fastbootInfoFilegroupName, true
+}
+
 func (f *filesystemCreator) createDeviceModule(
 	ctx android.LoadHookContext,
 	partitions allGeneratedPartitionData,
@@ -405,6 +425,7 @@
 		Ab_ota_postinstall_config: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPostInstallConfig,
 		Ramdisk_node_list:         proptools.StringPtr(":ramdisk_node_list"),
 		Android_info:              proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop{.txt}")),
+		Kernel_version:            ctx.Config().ProductVariables().BoardKernelVersion,
 	}
 
 	if bootloader, ok := f.createBootloaderFilegroup(ctx); ok {
@@ -413,6 +434,9 @@
 	if releaseTools, ok := f.createReleaseToolsFilegroup(ctx); ok {
 		deviceProps.Releasetools_extension = proptools.StringPtr(":" + releaseTools)
 	}
+	if fastbootInfo, ok := f.createFastbootInfoFilegroup(ctx); ok {
+		deviceProps.FastbootInfo = proptools.StringPtr(":" + fastbootInfo)
+	}
 
 	ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps, deviceProps)
 }
@@ -469,10 +493,6 @@
 		fsProps.Base_dir = proptools.StringPtr("system")
 		fsProps.Dirs = proptools.NewSimpleConfigurable(commonPartitionDirs)
 		fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch())
-
-		if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" {
-			fsProps.Import_aconfig_flags_from = []string{systemExtName}
-		}
 		fsProps.Stem = proptools.StringPtr("system.img")
 	case "system_ext":
 		if partitionVars.ProductFsverityGenerateMetadata {
@@ -485,6 +505,7 @@
 		}
 		fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch())
 		fsProps.Stem = proptools.StringPtr("system_ext.img")
+		fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
 	case "product":
 		fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
 		fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system"))
@@ -833,19 +854,29 @@
 		Product_config *string
 		Android_info   *string
 		Licenses       []string
+		Dist           android.Dist
 	}{
 		Name:           proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")),
 		Vendor:         proptools.BoolPtr(true),
 		Stem:           proptools.StringPtr("build.prop"),
 		Product_config: proptools.StringPtr(":product_config"),
 		Android_info:   proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop")),
-		Licenses:       []string{"Android-Apache-2.0"},
+		Dist: android.Dist{
+			Targets: []string{"droidcore-unbundled"},
+			Dest:    proptools.StringPtr("build.prop-vendor"),
+		},
+		Licenses: []string{"Android-Apache-2.0"},
 	}
 	vendorBuildProp := ctx.CreateModule(
 		android.BuildPropFactory,
 		vendorBuildProps,
 	)
-	vendorBuildProp.HideFromMake()
+	// We don't want this to conflict with the make-built vendor build.prop, but unfortunately
+	// calling HideFromMake() prevents disting files, even in soong-only mode. So only call
+	// HideFromMake() on soong+make builds.
+	if ctx.Config().KatiEnabled() {
+		vendorBuildProp.HideFromMake()
+	}
 }
 
 func createRecoveryBuildProp(ctx android.LoadHookContext) string {
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index 418e48b..81236a0 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -287,6 +287,8 @@
 				"some/non/existing/file.txt:system/etc/file.txt",
 				"device/sample/etc/apns-full-conf.xml:product/etc/apns-conf.xml:google",
 				"device/sample/etc/apns-full-conf.xml:product/etc/apns-conf-2.xml",
+				"device/sample/etc/apns-full-conf.xml:system/foo/file.txt",
+				"device/sample/etc/apns-full-conf.xml:system/foo/apns-full-conf.xml",
 			}
 			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
 				map[string]android.PartitionQualifiedVariablesType{
@@ -364,15 +366,25 @@
 	eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
 	android.AssertBoolEquals(
 		t,
-		"module expected to set correct srcs and dsts properties",
+		"module expected to set correct srcs property",
 		true,
 		checkModuleProp(generatedModule0, func(actual interface{}) bool {
 			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
 				srcs := p.Srcs.GetOrDefault(eval, nil)
-				dsts := p.Dsts.GetOrDefault(eval, nil)
 				return len(srcs) == 1 &&
-					srcs[0] == "apns-full-conf.xml" &&
-					len(dsts) == 1 &&
+					srcs[0] == "apns-full-conf.xml"
+			}
+			return false
+		}),
+	)
+	android.AssertBoolEquals(
+		t,
+		"module expected to set correct dsts property",
+		true,
+		checkModuleProp(generatedModule0, func(actual interface{}) bool {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				return len(dsts) == 1 &&
 					dsts[0] == "apns-conf.xml"
 			}
 			return false
@@ -383,15 +395,25 @@
 	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
 	android.AssertBoolEquals(
 		t,
-		"module expected to set correct srcs and dsts properties",
+		"module expected to set correct srcs property",
 		true,
 		checkModuleProp(generatedModule1, func(actual interface{}) bool {
 			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
 				srcs := p.Srcs.GetOrDefault(eval, nil)
-				dsts := p.Dsts.GetOrDefault(eval, nil)
 				return len(srcs) == 1 &&
-					srcs[0] == "apns-full-conf.xml" &&
-					len(dsts) == 1 &&
+					srcs[0] == "apns-full-conf.xml"
+			}
+			return false
+		}),
+	)
+	android.AssertBoolEquals(
+		t,
+		"module expected to set correct dsts property",
+		true,
+		checkModuleProp(generatedModule1, func(actual interface{}) bool {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				return len(dsts) == 1 &&
 					dsts[0] == "apns-conf-2.xml"
 			}
 			return false
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 9b25e77..4f3d2a7 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -105,12 +105,14 @@
 					"libgsi":                                    defaultDepCandidateProps(ctx.Config()),
 					"llndk.libraries.txt":                       defaultDepCandidateProps(ctx.Config()),
 					"logpersist.start":                          defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_system":                         defaultDepCandidateProps(ctx.Config()),
 					"update_engine_sideload":                    defaultDepCandidateProps(ctx.Config()),
 					// keep-sorted end
 				},
 				"vendor": {
 					"fs_config_files_vendor":                               defaultDepCandidateProps(ctx.Config()),
 					"fs_config_dirs_vendor":                                defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_vendor":                                    defaultDepCandidateProps(ctx.Config()),
 					generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
 				},
 				"odm": {
@@ -118,34 +120,41 @@
 					// https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
 					"fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
 					"fs_config_dirs_odm":  defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_odm":      defaultDepCandidateProps(ctx.Config()),
 				},
-				"product": {},
+				"product": {
+					"notice_xml_product": defaultDepCandidateProps(ctx.Config()),
+				},
 				"system_ext": {
 					// VNDK apexes are automatically included.
 					// This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
 					// https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
-					"com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
-					"com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
-					"com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
-					"com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
-					"com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v30":  defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v31":  defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v32":  defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v33":  defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v34":  defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_system_ext": defaultDepCandidateProps(ctx.Config()),
 				},
 				"userdata": {},
 				"system_dlkm": {
 					// these are phony required deps of the phony fs_config_dirs_nonsystem
 					"fs_config_dirs_system_dlkm":  defaultDepCandidateProps(ctx.Config()),
 					"fs_config_files_system_dlkm": defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_system_dlkm":      defaultDepCandidateProps(ctx.Config()),
 					// build props are automatically added to `ALL_DEFAULT_INSTALLED_MODULES`
 					"system_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
 				},
 				"vendor_dlkm": {
 					"fs_config_dirs_vendor_dlkm":  defaultDepCandidateProps(ctx.Config()),
 					"fs_config_files_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_vendor_dlkm":      defaultDepCandidateProps(ctx.Config()),
 					"vendor_dlkm-build.prop":      defaultDepCandidateProps(ctx.Config()),
 				},
 				"odm_dlkm": {
 					"fs_config_dirs_odm_dlkm":  defaultDepCandidateProps(ctx.Config()),
 					"fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
+					"notice_xml_odm_dlkm":      defaultDepCandidateProps(ctx.Config()),
 					"odm_dlkm-build.prop":      defaultDepCandidateProps(ctx.Config()),
 				},
 				"ramdisk":        {},
@@ -178,6 +187,10 @@
 			(*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config())
 		}
 
+		if len(ctx.Config().DeviceManifestFiles()) > 0 {
+			(*fsGenState.fsDeps["vendor"])["vendor_manifest.xml"] = defaultDepCandidateProps(ctx.Config())
+		}
+
 		// Add common resources `prebuilt_res` module as dep of recovery partition
 		(*fsGenState.fsDeps["recovery"])[fmt.Sprintf("recovery-resources-common-%s", getDpi(ctx))] = defaultDepCandidateProps(ctx.Config())
 		(*fsGenState.fsDeps["recovery"])[getRecoveryFontModuleName(ctx)] = defaultDepCandidateProps(ctx.Config())
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index e028b1d..df36197 100644
--- a/fsgen/prebuilt_etc_modules_gen.go
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -164,7 +164,6 @@
 	Ramdisk             *bool
 
 	Srcs []string
-	Dsts []string
 
 	No_full_install *bool
 
@@ -199,6 +198,7 @@
 		"etc/dsp":             etc.PrebuiltDSPFactory,
 		"etc/firmware":        etc.PrebuiltFirmwareFactory,
 		"firmware":            etc.PrebuiltFirmwareFactory,
+		"gpu":                 etc.PrebuiltGPUFactory,
 		"first_stage_ramdisk": etc.PrebuiltFirstStageRamdiskFactory,
 		"fonts":               etc.PrebuiltFontFactory,
 		"framework":           etc.PrebuiltFrameworkFactory,
@@ -210,6 +210,7 @@
 		"optee":               etc.PrebuiltOpteeFactory,
 		"overlay":             etc.PrebuiltOverlayFactory,
 		"priv-app":            etc.PrebuiltPrivAppFactory,
+		"radio":               etc.PrebuiltRadioFactory,
 		"sbin":                etc.PrebuiltSbinFactory,
 		"system":              etc.PrebuiltSystemFactory,
 		"res":                 etc.PrebuiltResFactory,
@@ -225,6 +226,7 @@
 		"usr/idc":             etc.PrebuiltUserIdcFactory,
 		"vendor":              etc.PrebuiltVendorFactory,
 		"vendor_dlkm":         etc.PrebuiltVendorDlkmFactory,
+		"vendor_overlay":      etc.PrebuiltVendorOverlayFactory,
 		"wallpaper":           etc.PrebuiltWallpaperFactory,
 		"wlc_upt":             etc.PrebuiltWlcUptFactory,
 	}
@@ -299,6 +301,7 @@
 			etcInstallPathKey = etcInstallPath
 		}
 	}
+	moduleFactory := etcInstallPathToFactoryList[etcInstallPathKey]
 	relDestDirFromInstallDirBase, _ := filepath.Rel(etcInstallPathKey, destDir)
 
 	for fileIndex := range maxLen {
@@ -348,15 +351,23 @@
 				})
 			}
 		} else {
-			modulePropsPtr.Srcs = srcBaseFiles
-			dsts := []string{}
-			for _, installBaseFile := range installBaseFiles {
-				dsts = append(dsts, filepath.Join(relDestDirFromInstallDirBase, installBaseFile))
+			// If dsts property has to be set and the selected module type is prebuilt_root,
+			// use prebuilt_any instead.
+			if etcInstallPathKey == "" {
+				moduleFactory = etc.PrebuiltAnyFactory
 			}
-			modulePropsPtr.Dsts = dsts
+			modulePropsPtr.Srcs = srcBaseFiles
+			dsts := proptools.NewConfigurable[[]string](nil, nil)
+			for _, installBaseFile := range installBaseFiles {
+				dsts.AppendSimpleValue([]string{filepath.Join(relDestDirFromInstallDirBase, installBaseFile)})
+			}
+
+			propsList = append(propsList, &etc.PrebuiltDstsProperties{
+				Dsts: dsts,
+			})
 		}
 
-		ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
+		ctx.CreateModuleInDirectory(moduleFactory, srcDir, propsList...)
 		moduleNames = append(moduleNames, moduleName)
 	}
 
diff --git a/fsgen/super_img.go b/fsgen/super_img.go
index 569f780..1d610f6 100644
--- a/fsgen/super_img.go
+++ b/fsgen/super_img.go
@@ -40,11 +40,13 @@
 	}
 
 	superImageProps := &filesystem.SuperImageProperties{
-		Metadata_device:        proptools.StringPtr(partitionVars.BoardSuperPartitionMetadataDevice),
-		Block_devices:          partitionVars.BoardSuperPartitionBlockDevices,
-		Ab_update:              proptools.BoolPtr(partitionVars.AbOtaUpdater),
-		Retrofit:               proptools.BoolPtr(partitionVars.ProductRetrofitDynamicPartitions),
-		Use_dynamic_partitions: proptools.BoolPtr(partitionVars.ProductUseDynamicPartitions),
+		Metadata_device:               proptools.StringPtr(partitionVars.BoardSuperPartitionMetadataDevice),
+		Block_devices:                 partitionVars.BoardSuperPartitionBlockDevices,
+		Ab_update:                     proptools.BoolPtr(partitionVars.AbOtaUpdater),
+		Retrofit:                      proptools.BoolPtr(partitionVars.ProductRetrofitDynamicPartitions),
+		Use_dynamic_partitions:        proptools.BoolPtr(partitionVars.ProductUseDynamicPartitions),
+		Super_image_in_update_package: proptools.BoolPtr(partitionVars.BoardSuperImageInUpdatePackage),
+		Create_super_empty:            proptools.BoolPtr(partitionVars.BuildingSuperEmptyImage),
 	}
 	if partitionVars.ProductVirtualAbOta {
 		superImageProps.Virtual_ab.Enable = proptools.BoolPtr(true)
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 83ccd89..f08378d 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -22,6 +22,7 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -309,14 +310,14 @@
 	return false
 }
 
-func IsValidConfig(fuzzModule FuzzPackagedModule, moduleName string) bool {
-	var config = fuzzModule.FuzzProperties.Fuzz_config
+func IsValidConfig(fuzzModule *FuzzPackagedModuleInfo, moduleName string) bool {
+	var config = fuzzModule.FuzzConfig
 	if config != nil {
 		if !config.Vector.isValidVector() {
 			panic(fmt.Errorf("Invalid vector in fuzz config in %s", moduleName))
 		}
 
-		if !config.Service_privilege.isValidServicePrivilege() {
+		if !config.ServicePrivilege.isValidServicePrivilege() {
 			panic(fmt.Errorf("Invalid service_privilege in fuzz config in %s", moduleName))
 		}
 
@@ -324,15 +325,15 @@
 			panic(fmt.Errorf("Invalid users (user_data) in fuzz config in %s", moduleName))
 		}
 
-		if !config.Fuzzed_code_usage.isValidFuzzedCodeUsage() {
+		if !config.FuzzedCodeUsage.isValidFuzzedCodeUsage() {
 			panic(fmt.Errorf("Invalid fuzzed_code_usage in fuzz config in %s", moduleName))
 		}
 
-		if !config.Automatically_route_to.isValidAutomaticallyRouteTo() {
+		if !config.AutomaticallyRouteTo.isValidAutomaticallyRouteTo() {
 			panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName))
 		}
 
-		if !config.Use_platform_libs.isValidUsePlatformLibs() {
+		if !config.UsePlatformLibs.isValidUsePlatformLibs() {
 			panic(fmt.Errorf("Invalid use_platform_libs in fuzz config in %s", moduleName))
 		}
 	}
@@ -451,6 +452,62 @@
 	Data           android.Paths
 }
 
+type FuzzConfigInfo struct {
+	Vector Vector
+	// How privileged the service being fuzzed is.
+	ServicePrivilege ServicePrivilege
+	// Whether the service being fuzzed handles data from multiple users or only
+	// a single one.
+	Users UserData
+	// Specifies the use state of the code being fuzzed. This state factors into
+	// how an issue is handled.
+	FuzzedCodeUsage FuzzedCodeUsage
+	// Which team to route this to, if it should be routed automatically.
+	AutomaticallyRouteTo AutomaticallyRouteTo
+	// Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
+	UsePlatformLibs UsePlatformLibs
+	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
+	FuzzOnHaikuDevice bool
+	// Specify whether to enable continuous fuzzing on host. Defaults to true.
+	FuzzOnHaikuHost bool
+	// Specifies whether fuzz target should check presubmitted code changes for crashes.
+	// Defaults to false.
+	UseForPresubmit bool
+}
+type FuzzPackagedModuleInfo struct {
+	FuzzConfig *FuzzConfigInfo
+	Dictionary android.Path
+	Corpus     android.Paths
+	Config     android.Path
+	Data       android.Paths
+}
+
+var FuzzPackagedModuleInfoProvider = blueprint.NewProvider[FuzzPackagedModuleInfo]()
+
+func SetFuzzPackagedModuleInfo(ctx android.ModuleContext, fm *FuzzPackagedModule) {
+	info := FuzzPackagedModuleInfo{
+		Dictionary: fm.Dictionary,
+		Config:     fm.Config,
+		Corpus:     fm.Corpus,
+		Data:       fm.Data,
+	}
+	if fm.FuzzProperties.Fuzz_config != nil {
+		info.FuzzConfig = &FuzzConfigInfo{
+			Vector:               fm.FuzzProperties.Fuzz_config.Vector,
+			ServicePrivilege:     fm.FuzzProperties.Fuzz_config.Service_privilege,
+			Users:                fm.FuzzProperties.Fuzz_config.Users,
+			FuzzedCodeUsage:      fm.FuzzProperties.Fuzz_config.Fuzzed_code_usage,
+			AutomaticallyRouteTo: fm.FuzzProperties.Fuzz_config.Automatically_route_to,
+			FuzzOnHaikuDevice:    BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_device, true),
+			FuzzOnHaikuHost:      BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_host, true),
+			UsePlatformLibs:      fm.FuzzProperties.Fuzz_config.Use_platform_libs,
+			UseForPresubmit:      BoolDefault(fm.FuzzProperties.Fuzz_config.Use_for_presubmit, false),
+		}
+	}
+
+	android.SetProvider(ctx, FuzzPackagedModuleInfoProvider, info)
+}
+
 func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
 	framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
 
@@ -509,7 +566,9 @@
 	return true
 }
 
-func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
+func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
 	// Package the corpora into a zipfile.
 	var files []FileToZip
 	if fuzzModule.Corpus != nil {
@@ -548,7 +607,9 @@
 	return files
 }
 
-func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
+func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
 	fuzzZip := archDir.Join(ctx, module.Name()+".zip")
 
 	command := builder.Command().BuiltTool("soong_zip").
@@ -570,10 +631,10 @@
 	builder.Build("create-"+fuzzZip.String(),
 		"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
 
-	if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil {
-		if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) {
+	if config := fuzzModule.FuzzConfig; config != nil {
+		if strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuHost {
 			return archDirs[archOs], false
-		} else if !strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_device, true) {
+		} else if !strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuDevice {
 			return archDirs[archOs], false
 		}
 	}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6bd1fcc..710ec95 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -112,8 +112,8 @@
 
 func (t hostToolDependencyTag) AllowDisabledModuleDependencyProxy(
 	ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
-	return android.OtherModuleProviderOrDefault(
-		ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
+	return android.OtherModulePointerProviderOrDefault(
+		ctx, target, android.CommonModuleInfoProvider).ReplacedByPrebuilt
 }
 
 var _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil)
@@ -353,7 +353,7 @@
 				if h, ok := android.OtherModuleProvider(ctx, module, android.HostToolProviderInfoProvider); ok {
 					// A HostToolProvider provides the path to a tool, which will be copied
 					// into the sandbox.
-					if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+					if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 						if ctx.Config().AllowMissingDependencies() {
 							ctx.AddMissingDependencies([]string{tool})
 						} else {
diff --git a/java/Android.bp b/java/Android.bp
index 911af83..99d9c38 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -78,6 +78,7 @@
         "system_modules.go",
         "systemserver_classpath_fragment.go",
         "testing.go",
+        "tracereferences.go",
         "tradefed.go",
     ],
     testSrcs: [
diff --git a/java/aar.go b/java/aar.go
index 976e4fc..ebada65 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -219,11 +219,7 @@
 func (a *aapt) useResourceProcessorBusyBox(ctx android.BaseModuleContext) bool {
 	return BoolDefault(a.aaptProperties.Use_resource_processor, true) &&
 		// TODO(b/331641946): remove this when ResourceProcessorBusyBox supports generating shared libraries.
-		!slices.Contains(a.aaptProperties.Aaptflags, "--shared-lib") &&
-		// Use the legacy resource processor in kythe builds.
-		// The legacy resource processor creates an R.srcjar, which kythe can use for generating crossrefs.
-		// TODO(b/354854007): Re-enable BusyBox in kythe builds
-		!ctx.Config().EmitXrefRules()
+		!slices.Contains(a.aaptProperties.Aaptflags, "--shared-lib")
 }
 
 func (a *aapt) filterProduct() string {
@@ -945,6 +941,12 @@
 
 var AndroidLibraryInfoProvider = blueprint.NewProvider[AndroidLibraryInfo]()
 
+type AARImportInfo struct {
+	// Empty for now
+}
+
+var AARImportInfoProvider = blueprint.NewProvider[AARImportInfo]()
+
 type AndroidLibrary struct {
 	Library
 	aapt
@@ -1571,6 +1573,8 @@
 		JniPackages: a.jniPackages,
 	})
 
+	android.SetProvider(ctx, AARImportInfoProvider, AARImportInfo{})
+
 	ctx.SetOutputFiles([]android.Path{a.implementationAndResourcesJarFile}, "")
 	ctx.SetOutputFiles([]android.Path{a.aarPath}, ".aar")
 
diff --git a/java/app.go b/java/app.go
index 17548e7..553c658 100644
--- a/java/app.go
+++ b/java/app.go
@@ -425,6 +425,10 @@
 	} else {
 		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
 	}
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: a.appTestHelperAppProperties.Test_suites,
+	})
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -531,7 +535,7 @@
 		if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); !ok {
 			panic(fmt.Errorf("jni dependency is not a cc module: %v", m))
 		}
-		commonInfo, ok := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoKey)
+		commonInfo, ok := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoProvider)
 		if !ok {
 			panic(fmt.Errorf("jni dependency doesn't have CommonModuleInfo provider: %v", m))
 		}
@@ -611,7 +615,7 @@
 	ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
 		tag := ctx.OtherModuleDependencyTag(dep)
 		switch tag {
-		case staticLibTag:
+		case staticLibTag, rroDepTag:
 			if flagPackages, ok := android.OtherModuleProvider(ctx, dep, FlagsPackagesProvider); ok {
 				aconfigTextFilePaths = append(aconfigTextFilePaths, flagPackages.AconfigTextFiles...)
 			}
@@ -1124,6 +1128,11 @@
 		android.SetProvider(ctx, JavaInfoProvider, javaInfo)
 	}
 
+	android.SetProvider(ctx, android.ApexBundleDepsDataProvider, android.ApexBundleDepsData{
+		FlatListPath: a.FlatListPath(),
+		Updatable:    a.Updatable(),
+	})
+
 	moduleInfoJSON := ctx.ModuleInfoJSON()
 	moduleInfoJSON.Class = []string{"APPS"}
 	if !a.embeddedJniLibs {
@@ -1170,7 +1179,7 @@
 			apkInApex := ctx.Module().(android.ApexModule).NotInPlatform()
 			childLinkable, _ := android.OtherModuleProvider(ctx, child, cc.LinkableInfoProvider)
 			parentIsLinkable := false
-			if ctx.EqualModules(ctx.Module(), parent) {
+			if android.EqualModules(ctx.Module(), parent) {
 				parentLinkable, _ := ctx.Module().(cc.LinkableInterface)
 				parentIsLinkable = parentLinkable != nil
 			} else {
@@ -1224,7 +1233,7 @@
 	seenModulePaths := make(map[string]bool)
 
 	ctx.WalkDepsProxy(func(module, parent android.ModuleProxy) bool {
-		if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return false
 		}
 		otherName := ctx.OtherModuleName(module)
@@ -1244,7 +1253,7 @@
 					}
 					seenModulePaths[path.String()] = true
 
-					commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey)
+					commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider)
 					if checkNativeSdkVersion && commonInfo.SdkVersion == "" {
 						ctx.PropertyErrorf("jni_libs", "JNI dependency %q uses platform APIs, but this module does not",
 							otherName)
@@ -1282,13 +1291,13 @@
 }
 
 func (a *AndroidApp) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
-	ctx.WalkDeps(func(child, parent android.Module) bool {
+	ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
 		// TODO(ccross): Should this use android.DepIsInSameApex?  Right now it is applying the android app
 		// heuristics to every transitive dependency, when it should probably be using the heuristics of the
 		// immediate parent.
 		isExternal := !a.GetDepInSameApexChecker().OutgoingDepIsInSameApex(ctx.OtherModuleDependencyTag(child))
-		if am, ok := child.(android.ApexModule); ok {
-			if !do(ctx, parent, am, isExternal) {
+		if am, ok := android.OtherModuleProvider(ctx, child, android.CommonModuleInfoProvider); ok && am.IsApexModule {
+			if !do(ctx, parent, child, isExternal) {
 				return false
 			}
 		}
@@ -1302,12 +1311,12 @@
 	}
 
 	depsInfo := android.DepNameToDepInfoMap{}
-	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool {
 		depName := to.Name()
 
 		// Skip dependencies that are only available to APEXes; they are developed with updatability
 		// in mind and don't need manual approval.
-		if android.OtherModuleProviderOrDefault(ctx, to, android.CommonModuleInfoKey).NotAvailableForPlatform {
+		if android.OtherModulePointerProviderOrDefault(ctx, to, android.CommonModuleInfoProvider).NotAvailableForPlatform {
 			return true
 		}
 
@@ -1317,7 +1326,7 @@
 			depsInfo[depName] = info
 		} else {
 			toMinSdkVersion := "(no version)"
-			if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoKey); ok &&
+			if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoProvider); ok &&
 				!info.MinSdkVersion.IsPlatform && info.MinSdkVersion.ApiLevel != nil {
 				toMinSdkVersion = info.MinSdkVersion.ApiLevel.String()
 			}
@@ -1698,6 +1707,10 @@
 		moduleInfoJSON.AutoTestConfig = []string{"true"}
 	}
 	moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, a.testProperties.Test_mainline_modules...)
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: a.testProperties.Test_suites,
+	})
 }
 
 func testcaseRel(paths android.Paths) []string {
@@ -2204,3 +2217,7 @@
 	appInfo.Certificate = m.Certificate()
 	appInfo.PrivAppAllowlist = m.PrivAppAllowlist()
 }
+
+type AppInfos []AppInfo
+
+var AppInfosProvider = blueprint.NewProvider[AppInfos]()
diff --git a/java/app_import.go b/java/app_import.go
index 37c673c..c0e8171 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -177,7 +177,7 @@
 	Prebuilt_info *string `android:"path"`
 
 	// Path of extracted apk which is extracted from prebuilt apk. Use this extracted to import.
-	Extract_apk *string
+	Extract_apk proptools.Configurable[string]
 
 	// Compress the output APK using gzip. Defaults to false.
 	Compress_apk proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
@@ -307,7 +307,7 @@
 
 func (a *AndroidAppImport) extractSubApk(
 	ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
-	extractApkPath := *a.properties.Extract_apk
+	extractApkPath := a.properties.Extract_apk.GetOrDefault(ctx, "")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   extractApkRule,
 		Input:  inputPath,
@@ -405,7 +405,7 @@
 	// TODO: LOCAL_PACKAGE_SPLITS
 
 	srcApk := a.prebuilt.SingleSourcePath(ctx)
-	if a.properties.Extract_apk != nil {
+	if a.properties.Extract_apk.GetOrDefault(ctx, "") != "" {
 		extract_apk := android.PathForModuleOut(ctx, "extract-apk", ctx.ModuleName()+".apk")
 		a.extractSubApk(ctx, srcApk, extract_apk)
 		srcApk = extract_apk
@@ -787,6 +787,10 @@
 	a.updateModuleInfoJSON(ctx)
 
 	a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: a.testProperties.Test_suites,
+	})
 }
 
 func (a *AndroidTestImport) updateModuleInfoJSON(ctx android.ModuleContext) {
diff --git a/java/base.go b/java/base.go
index 0833831..1a12075 100644
--- a/java/base.go
+++ b/java/base.go
@@ -629,7 +629,7 @@
 			return nil
 		}
 		if info.SdkVersion.Kind == android.SdkCorePlatform {
-			if useLegacyCorePlatformApi(ctx, android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).BaseModuleName) {
+			if useLegacyCorePlatformApi(ctx, android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).BaseModuleName) {
 				return fmt.Errorf("non stable SDK %v - uses legacy core platform", info.SdkVersion)
 			} else {
 				// Treat stable core platform as stable.
@@ -888,6 +888,10 @@
 	// Add dependency on libraries that provide additional hidden api annotations.
 	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
 
+	// Add dependency on (soft) downstream libs from which to trace references during optimization.
+	traceRefs := j.dexProperties.Optimize.Trace_references_from.GetOrDefault(ctx, []string{})
+	ctx.AddVariationDependencies(nil, traceReferencesTag, traceRefs...)
+
 	// For library dependencies that are component libraries (like stubs), add the implementation
 	// as a dependency (dexpreopt needs to be against the implementation library, not stubs).
 	for _, dep := range libDeps {
diff --git a/java/builder.go b/java/builder.go
index ade9784..dff0032 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -310,7 +310,7 @@
 
 	gatherReleasedFlaggedApisRule = pctx.AndroidStaticRule("gatherReleasedFlaggedApisRule",
 		blueprint.RuleParams{
-			Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}' ` +
+			Command: `${aconfig} dump-cache --dedup --format=protobuf ` +
 				`--out ${out} ` +
 				`${flags_path} ` +
 				`${filter_args} `,
@@ -320,8 +320,8 @@
 
 	generateMetalavaRevertAnnotationsRule = pctx.AndroidStaticRule("generateMetalavaRevertAnnotationsRule",
 		blueprint.RuleParams{
-			Command:     `${keep-flagged-apis} ${in} > ${out}`,
-			CommandDeps: []string{"${keep-flagged-apis}"},
+			Command:     `${aconfig-to-metalava-flags} ${in} > ${out}`,
+			CommandDeps: []string{"${aconfig-to-metalava-flags}"},
 		})
 
 	generateApiXMLRule = pctx.AndroidStaticRule("generateApiXMLRule",
@@ -339,7 +339,7 @@
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("ravenizer", "ravenizer")
 	pctx.HostBinToolVariable("apimapper", "apimapper")
-	pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
+	pctx.HostBinToolVariable("aconfig-to-metalava-flags", "aconfig-to-metalava-flags")
 }
 
 type javaBuilderFlags struct {
diff --git a/java/config/config.go b/java/config/config.go
index 71025de..fdb8d78 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -173,6 +173,7 @@
 	pctx.HostBinToolVariable("R8Cmd", "r8")
 	pctx.HostBinToolVariable("ExtractR8RulesCmd", "extract-r8-rules")
 	pctx.HostBinToolVariable("ResourceShrinkerCmd", "resourceshrinker")
+	pctx.HostBinToolVariable("TraceReferencesCmd", "tracereferences")
 	pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
 	pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
 	pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
diff --git a/java/dex.go b/java/dex.go
index ed2df21..ed9c82b 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -103,6 +103,34 @@
 		// If true, transitive reverse dependencies of this module will have this
 		// module's proguard spec appended to their optimization action
 		Export_proguard_flags_files *bool
+
+		// Path to a file containing a list of class names that should not be compiled using R8.
+		// These classes will be compiled by D8 similar to when Optimize.Enabled is false.
+		//
+		// Example:
+		//
+		//   r8.exclude:
+		//   com.example.Foo
+		//   com.example.Bar
+		//   com.example.Bar$Baz
+		//
+		// By default all classes are compiled using R8 when Optimize.Enabled is set.
+		Exclude *string `android:"path"`
+
+		// Optional list of downstream (Java) libraries from which to trace and preserve references
+		// when optimizing. Note that this requires that the source reference does *not* have
+		// a strict lib dependency on this target; dependencies should be on intermediate targets
+		// statically linked into this target, e.g., if A references B, and we want to trace and
+		// keep references from A when optimizing B, you would create an intermediate B.impl (
+		// containing all static code), have A depend on `B.impl` via libs, and set
+		// `trace_references_from: ["A"]` on B.
+		//
+		// Also note that these are *not* inherited across targets, they must be specified at the
+		// top-level target that is optimized.
+		//
+		// TODO(b/212737576): Handle this implicitly using bottom-up deps mutation and implicit
+		// creation of a proxy `.impl` library.
+		Trace_references_from proptools.Configurable[[]string] `android:"arch_variant"`
 	}
 
 	// Keep the data uncompressed. We always need uncompressed dex for execution,
@@ -445,6 +473,20 @@
 
 	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...)
 
+	traceReferencesSources := android.Paths{}
+	ctx.VisitDirectDepsProxyWithTag(traceReferencesTag, func(m android.ModuleProxy) {
+		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
+			traceReferencesSources = append(traceReferencesSources, dep.ImplementationJars...)
+		}
+	})
+	if len(traceReferencesSources) > 0 {
+		traceTarget := dexParams.classesJar
+		traceLibs := android.FirstUniquePaths(append(flags.bootClasspath.Paths(), flags.dexClasspath.Paths()...))
+		traceReferencesFlags := android.PathForModuleOut(ctx, "proguard", "trace_references.flags")
+		TraceReferences(ctx, traceReferencesSources, traceTarget, traceLibs, traceReferencesFlags)
+		flagFiles = append(flagFiles, traceReferencesFlags)
+	}
+
 	flagFiles = android.FirstUniquePaths(flagFiles)
 
 	r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include "))
@@ -528,6 +570,11 @@
 		r8Flags = append(r8Flags, "--store-store-fence-constructor-inlining")
 	}
 
+	if opt.Exclude != nil {
+		r8Flags = append(r8Flags, "--exclude", *opt.Exclude)
+		r8Deps = append(r8Deps, android.PathForModuleSrc(ctx, *opt.Exclude))
+	}
+
 	return r8Flags, r8Deps, artProfileOutput
 }
 
diff --git a/java/dex_test.go b/java/dex_test.go
index 66d801d..e94864b 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -866,3 +866,46 @@
 		})
 	}
 }
+
+func TestTraceReferences(t *testing.T) {
+	t.Parallel()
+	bp := `
+		android_app {
+			name: "app",
+			libs: ["lib.impl"],
+			srcs: ["foo.java"],
+			platform_apis: true,
+		}
+
+		java_library {
+			name: "lib",
+			optimize: {
+				enabled: true,
+				trace_references_from: ["app"],
+			},
+			srcs: ["bar.java"],
+			static_libs: ["lib.impl"],
+			installable: true,
+		}
+
+		java_library {
+			name: "lib.impl",
+			srcs: ["baz.java"],
+		}
+	`
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, bp)
+
+	appJar := result.ModuleForTests(t, "app", "android_common").Output("combined/app.jar").Output
+	libJar := result.ModuleForTests(t, "lib", "android_common").Output("combined/lib.jar").Output
+	libTraceRefs := result.ModuleForTests(t, "lib", "android_common").Rule("traceReferences")
+	libR8 := result.ModuleForTests(t, "lib", "android_common").Rule("r8")
+
+	android.AssertStringDoesContain(t, "expected trace reference source from app jar",
+		libTraceRefs.Args["sources"], "--source "+appJar.String())
+	android.AssertStringEquals(t, "expected trace reference target into lib jar",
+		libJar.String(), libTraceRefs.Input.String())
+	android.AssertStringDoesContain(t, "expected trace reference proguard flags in lib r8 flags",
+		libR8.Args["r8Flags"], "trace_references.flags")
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index b21cfc9..e8e1cd4 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -650,6 +650,9 @@
 		// for now just exclude any known irrelevant dependencies that would lead to incorrect errors.
 		if _, ok := tag.(bootclasspathDependencyTag); ok {
 			return false
+		} else if tag == traceReferencesTag {
+			// Allow ordering inversion if the dependency is purely for tracing references.
+			return false
 		}
 		depIndex := jars.IndexOfJar(dep.Name())
 		if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 313d8c7..2287043 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -675,6 +675,139 @@
 			installs: artBootImageHostInstalls,
 		},
 	)
+
+	d.buildBootZip(ctx)
+}
+
+// Build the boot.zip which contains the boot jars and their compilation output
+// We can do this only if preopt is enabled and if the product uses libart config (which sets the
+// default properties for preopting).
+// Origionally, this was only for ART Cloud.
+func (d *dexpreoptBootJars) buildBootZip(ctx android.ModuleContext) {
+	image := d.defaultBootImage
+	if image == nil || SkipDexpreoptBootJars(ctx) {
+		return
+	}
+	global := dexpreopt.GetGlobalConfig(ctx)
+	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage {
+		return
+	}
+
+	bootclasspathDexFiles, bootclassPathLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
+	if len(bootclasspathDexFiles) == 0 {
+		return
+	}
+
+	systemServerDexjarsDir := android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir)
+
+	bootZipMetadataTmp := android.PathForModuleOut(ctx, "boot_zip", "METADATA.txt.tmp")
+	bootZipMetadata := android.PathForModuleOut(ctx, "boot_zip", "METADATA.txt")
+	newlineFile := android.PathForModuleOut(ctx, "boot_zip", "newline.txt")
+	android.WriteFileRule(ctx, newlineFile, "")
+
+	dexPreoptRootDir := filepath.Dir(filepath.Dir(bootclasspathDexFiles[0].String()))
+
+	var sb strings.Builder
+	sb.WriteString("bootclasspath = ")
+	for i, bootclasspathJar := range bootclasspathDexFiles {
+		if i > 0 {
+			sb.WriteString(":")
+		}
+		rel, err := filepath.Rel(dexPreoptRootDir, bootclasspathJar.String())
+		if err != nil {
+			ctx.ModuleErrorf("All dexpreopt jars should be under the same rootdir %q, but %q wasn't.", dexPreoptRootDir, bootclasspathJar)
+		} else {
+			sb.WriteString(rel)
+		}
+	}
+	sb.WriteString("\nbootclasspath-locations = ")
+	for i, bootclasspathLocation := range bootclassPathLocations {
+		if i > 0 {
+			sb.WriteString(":")
+		}
+		sb.WriteString(bootclasspathLocation)
+	}
+	sb.WriteString("\nboot-image = ")
+
+	// Infix can be 'art' (ART image for testing), 'boot' (primary), or 'mainline' (mainline
+	// extension). Soong creates a set of variables for Make, one or each boot image. The only
+	// reason why the ART image is exposed to Make is testing (art gtests) and benchmarking (art
+	// golem benchmarks). Install rules that use those variables are in dex_preopt_libart.mk. Here
+	// for dexpreopt purposes the infix is always 'boot' or 'mainline'.
+	dexpreoptInfix := "boot"
+	if global.PreoptWithUpdatableBcp {
+		dexpreoptInfix = "mainline"
+	}
+
+	var dexPreoptImageZipBoot android.Path
+	var dexPreoptImageZipArt android.Path
+	var dexPreoptImageZipMainline android.Path
+	for _, current := range append(d.otherImages, image) {
+		if current.name == dexpreoptInfix {
+			_, imageLocationsOnDevice := current.getAnyAndroidVariant().imageLocations()
+			for i, location := range imageLocationsOnDevice {
+				imageLocationsOnDevice[i] = strings.TrimPrefix(location, "/")
+			}
+			sb.WriteString(strings.Join(imageLocationsOnDevice, ":"))
+		}
+		switch current.name {
+		case "boot":
+			dexPreoptImageZipBoot = current.zip
+		case "art":
+			dexPreoptImageZipArt = current.zip
+		case "mainline":
+			dexPreoptImageZipMainline = current.zip
+		}
+	}
+	sb.WriteString("\nextra-args = ")
+	android.WriteFileRuleVerbatim(ctx, bootZipMetadataTmp, sb.String())
+	ctx.Build(pctx, android.BuildParams{
+		Rule: android.Cat,
+		Inputs: []android.Path{
+			bootZipMetadataTmp,
+			globalSoong.UffdGcFlag,
+			newlineFile,
+		},
+		Output: bootZipMetadata,
+	})
+
+	bootZipFirstPart := android.PathForModuleOut(ctx, "boot_zip", "boot_first_part.zip")
+	bootZip := android.PathForModuleOut(ctx, "boot_zip", "boot.zip")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	cmd := builder.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", bootZipFirstPart).
+		FlagWithArg("-C ", filepath.Dir(filepath.Dir(bootclasspathDexFiles[0].String())))
+	for _, bootclasspathJar := range bootclasspathDexFiles {
+		cmd.FlagWithInput("-f ", bootclasspathJar)
+	}
+	for i := range global.SystemServerJars.Len() {
+		// Use "/system" path for JARs with "platform:" prefix. These JARs counterintuitively use
+		// "platform" prefix but they will be actually installed to /system partition.
+		// For the remaining system server JARs use the partition signified by the prefix.
+		// For example, prefix "system_ext:" will use "/system_ext" path.
+		dir := global.SystemServerJars.Apex(i)
+		if dir == "platform" {
+			dir = "system"
+		}
+		jar := global.SystemServerJars.Jar(i) + ".jar"
+		cmd.FlagWithArg("-e ", dir+"/framework/"+jar)
+		cmd.FlagWithInput("-f ", systemServerDexjarsDir.Join(ctx, jar))
+	}
+	cmd.Flag("-j")
+	cmd.FlagWithInput("-f ", bootZipMetadata)
+
+	builder.Command().BuiltTool("merge_zips").
+		Output(bootZip).
+		Input(bootZipFirstPart).
+		Input(dexPreoptImageZipBoot).
+		Input(dexPreoptImageZipArt).
+		Input(dexPreoptImageZipMainline)
+
+	builder.Build("boot_zip", "build boot.zip")
+
+	ctx.DistForGoal("droidcore", bootZipMetadata)
+	ctx.DistForGoal("droidcore", bootZip)
 }
 
 // GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index c971565..9d0f539 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -100,7 +100,12 @@
 		if systemServerJar.InstallInSystemExt() && ctx.Config().InstallApexSystemServerDexpreoptSamePartition() {
 			partition = ctx.DeviceConfig().SystemExtPath() // system_ext
 		}
-		dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, systemServerJar.Name())
+		var dexLocation string
+		if m, ok := systemServerJar.(ModuleWithStem); ok {
+			dexLocation = dexpreopt.GetSystemServerDexLocation(ctx, global, m.Stem())
+		} else {
+			ctx.PropertyErrorf("dexpreopt_systemserver_check", "%v is not a ModuleWithStem", systemServerJar.Name())
+		}
 		odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType, partition)
 		odexPath := getInstallPath(ctx, odexLocation)
 		vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex"))
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 225f201..3faf294 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -195,6 +195,9 @@
 				"them instead.")
 		}
 		return false
+	} else if ctx.Config().PartialCompileFlags().Disable_stub_validation &&
+		!ctx.Config().BuildFromTextStub() {
+		return false
 	} else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" {
 		return true
 	} else if String(apiToCheck.Api_file) != "" {
diff --git a/java/droidstubs.go b/java/droidstubs.go
index caad688..c215925 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -821,19 +821,17 @@
 		}
 	}
 
-	if len(aconfigFlagsPaths) == 0 {
-		// This argument should not be added for "everything" stubs
-		cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
-		return
-	}
+	// If aconfigFlagsPaths is empty then it is still important to generate the
+	// Metalava flags config file, albeit with an empty set of flags, so that all
+	// flagged APIs will be reverted.
 
-	releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String()))
-	revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String()))
+	releasedFlagsFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flags-%s.pb", stubsType.String()))
+	metalavaFlagsConfigFile := android.PathForModuleOut(ctx, fmt.Sprintf("flags-config-%s.xml", stubsType.String()))
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        gatherReleasedFlaggedApisRule,
 		Inputs:      aconfigFlagsPaths,
-		Output:      releasedFlaggedApisFile,
+		Output:      releasedFlagsFile,
 		Description: fmt.Sprintf("%s gather aconfig flags", stubsType),
 		Args: map[string]string{
 			"flags_path":  android.JoinPathsWithPrefix(aconfigFlagsPaths, "--cache "),
@@ -843,12 +841,12 @@
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        generateMetalavaRevertAnnotationsRule,
-		Input:       releasedFlaggedApisFile,
-		Output:      revertAnnotationsFile,
-		Description: fmt.Sprintf("%s revert annotations", stubsType),
+		Input:       releasedFlagsFile,
+		Output:      metalavaFlagsConfigFile,
+		Description: fmt.Sprintf("%s metalava flags config", stubsType),
 	})
 
-	cmd.FlagWithInput("@", revertAnnotationsFile)
+	cmd.FlagWithInput("--config-file ", metalavaFlagsConfigFile)
 }
 
 func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
@@ -1245,7 +1243,7 @@
 
 	// Add options for the other optional tasks: API-lint and check-released.
 	// We generate separate timestamp files for them.
-	doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false)
+	doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().PartialCompileFlags().Disable_api_lint
 	doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released")
 
 	writeSdkValues := Bool(d.properties.Write_sdk_values)
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index dfdf877..1f9d223 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -410,12 +410,12 @@
 
 	m := result.ModuleForTests(t, "foo", "android_common")
 	android.AssertStringDoesContain(t, "foo generates revert annotations file",
-		strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt")
+		strings.Join(m.AllOutputs(), ""), "flags-config-exportable.xml")
 
 	// revert-annotations.txt passed to exportable stubs generation metalava command
 	manifest := m.Output("metalava_exportable.sbox.textproto")
 	cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
-	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt")
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "flags-config-exportable.xml")
 
 	android.AssertStringDoesContain(t, "foo generates exportable stubs jar",
 		strings.Join(m.AllOutputs(), ""), "exportable/foo-stubs.srcjar")
@@ -460,7 +460,7 @@
 
 	m := result.ModuleForTests(t, "foo", "android_common")
 
-	rule := m.Output("released-flagged-apis-exportable.txt")
+	rule := m.Output("released-flags-exportable.pb")
 	exposeWritableApisFilter := "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
 	android.AssertStringEquals(t, "Filter argument expected to contain READ_WRITE permissions", exposeWritableApisFilter, rule.Args["filter_args"])
 }
diff --git a/java/fuzz.go b/java/fuzz.go
index 5973957..0e239f0 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -132,6 +132,8 @@
 	}
 
 	j.Test.GenerateAndroidBuildActions(ctx)
+
+	fuzz.SetFuzzPackagedModuleInfo(ctx, &j.fuzzPackagedModule)
 }
 
 type javaFuzzPackager struct {
@@ -153,6 +155,10 @@
 		if !ok {
 			return
 		}
+		fuzzInfo, ok := android.OtherModuleProvider(ctx, module, fuzz.FuzzPackagedModuleInfoProvider)
+		if !ok {
+			return
+		}
 
 		hostOrTargetString := "target"
 		if javaFuzzModule.Target().HostCross {
@@ -179,7 +185,7 @@
 		builder := android.NewRuleBuilder(pctx, ctx)
 
 		// Package the artifacts (data, corpus, config and dictionary) into a zipfile.
-		files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
+		files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder)
 
 		// Add .jar
 		if !javaFuzzModule.Host() {
@@ -193,7 +199,7 @@
 			files = append(files, fuzz.FileToZip{SourceFilePath: fPath})
 		}
 
-		archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+		archDirs[archOs], ok = s.BuildZipFile(ctx, module, &fuzzInfo, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
 			return
 		}
diff --git a/java/java.go b/java/java.go
index b18c561..dd9f852 100644
--- a/java/java.go
+++ b/java/java.go
@@ -432,6 +432,9 @@
 	DexJarBuildPath OptionalDexJarPath
 
 	DexpreopterInfo *DexpreopterInfo
+
+	XrefJavaFiles   android.Paths
+	XrefKotlinFiles android.Paths
 }
 
 var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]()
@@ -575,6 +578,7 @@
 	extraLintCheckTag       = dependencyTag{name: "extra-lint-check", toolchain: true}
 	jniLibTag               = dependencyTag{name: "jnilib", runtimeLinked: true}
 	r8LibraryJarTag         = dependencyTag{name: "r8-libraryjar", runtimeLinked: true}
+	traceReferencesTag      = dependencyTag{name: "trace-references"}
 	syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
 	javaApiContributionTag  = dependencyTag{name: "java-api-contribution"}
 	aconfigDeclarationTag   = dependencyTag{name: "aconfig-declaration"}
@@ -605,6 +609,7 @@
 		kotlinPluginTag,
 		syspropPublicStubDepTag,
 		instrumentationForTag,
+		traceReferencesTag,
 	}
 )
 
@@ -1951,6 +1956,10 @@
 			ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".jar", j.outputFile)
 		}
 	}
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: j.testProperties.Test_suites,
+	})
 }
 
 func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1967,6 +1976,10 @@
 	if optionalConfig.Valid() {
 		moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String())
 	}
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: j.testHelperLibraryProperties.Test_suites,
+	})
 }
 
 func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -2222,7 +2235,7 @@
 	// install these alongside the java binary.
 	ctx.VisitDirectDepsProxyWithTag(jniInstallTag, func(jni android.ModuleProxy) {
 		// Use the BaseModuleName of the dependency (without any prebuilt_ prefix)
-		commonInfo, _ := android.OtherModuleProvider(ctx, jni, android.CommonModuleInfoKey)
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, jni, android.CommonModuleInfoProvider)
 		j.androidMkNamesOfJniLibs = append(j.androidMkNamesOfJniLibs, commonInfo.BaseModuleName+":"+commonInfo.Target.Arch.ArchType.Bitness())
 	})
 	// Check that native libraries are not listed in `required`. Prompt users to use `jni_libs` instead.
@@ -2527,6 +2540,7 @@
 	apiContributions := al.properties.Api_contributions
 	addValidations := !ctx.Config().IsEnvTrue("DISABLE_STUB_VALIDATION") &&
 		!ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") &&
+		!ctx.Config().PartialCompileFlags().Disable_stub_validation &&
 		proptools.BoolDefault(al.properties.Enable_validation, true)
 	for _, apiContributionName := range apiContributions {
 		ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName)
@@ -3360,21 +3374,12 @@
 
 // Add compile time check for interface implementation
 var _ android.IDEInfo = (*Import)(nil)
-var _ android.IDECustomizedModuleName = (*Import)(nil)
 
 // Collect information for opening IDE project files in java/jdeps.go.
-
 func (j *Import) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Jars = append(dpInfo.Jars, j.combinedImplementationFile.String())
 }
 
-func (j *Import) IDECustomizedModuleName() string {
-	// TODO(b/113562217): Extract the base module name from the Import name, often the Import name
-	// has a prefix "prebuilt_". Remove the prefix explicitly if needed until we find a better
-	// solution to get the Import name.
-	return android.RemoveOptionalPrebuiltPrefix(j.Name())
-}
-
 var _ android.PrebuiltInterface = (*Import)(nil)
 
 func (j *Import) IsInstallable() bool {
@@ -3649,10 +3654,10 @@
 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()...)
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if javaInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+			xrefTargets = append(xrefTargets, javaInfo.XrefJavaFiles...)
+			xrefKotlinTargets = append(xrefKotlinTargets, javaInfo.XrefKotlinFiles...)
 		}
 	})
 	// TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets
@@ -3853,4 +3858,9 @@
 			ApexSystemServerDexJars:           di.ApexSystemServerDexJars(),
 		}
 	}
+
+	if xr, ok := module.(xref); ok {
+		javaInfo.XrefJavaFiles = xr.XrefJavaFiles()
+		javaInfo.XrefKotlinFiles = xr.XrefKotlinFiles()
+	}
 }
diff --git a/java/java_test.go b/java/java_test.go
index a6290a6..1ba78d4 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2912,12 +2912,12 @@
 
 	m := result.ModuleForTests(t, "foo", "android_common")
 	android.AssertStringDoesContain(t, "foo generates revert annotations file",
-		strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt")
+		strings.Join(m.AllOutputs(), ""), "flags-config-exportable.xml")
 
 	// revert-annotations.txt passed to exportable stubs generation metalava command
 	manifest := m.Output("metalava.sbox.textproto")
 	cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
-	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt")
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "flags-config-exportable.xml")
 }
 
 func TestTestOnly(t *testing.T) {
@@ -3193,3 +3193,72 @@
 	deps := findDepsOfModule(res, res.ModuleForTests(t, "myjavabin", "android_common").Module(), "mynativelib")
 	android.AssertIntEquals(t, "Create a dep on the first variant", 1, len(deps))
 }
+
+func TestBootJarNotInUsesLibs(t *testing.T) {
+	t.Parallel()
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary"),
+		FixtureConfigureApexBootJars("myapex:mysdklibrary"),
+	).RunTestWithBp(t, `
+		bootclasspath_fragment {
+			name: "myfragment",
+			contents: ["mysdklibrary"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
+		java_sdk_library {
+			name: "mysdklibrary",
+			srcs: ["Test.java"],
+			compile_dex: true,
+			public: {enabled: true},
+			min_sdk_version: "2",
+			permitted_packages: ["mysdklibrary"],
+			sdk_version: "current",
+		}
+
+		java_sdk_library {
+			name: "myothersdklibrary",
+			srcs: ["Test.java"],
+			compile_dex: true,
+			public: {enabled: true},
+			min_sdk_version: "2",
+			permitted_packages: ["myothersdklibrary"],
+			sdk_version: "current",
+		}
+
+		java_library {
+			name: "foo",
+			libs: [
+				"bar",
+				"mysdklibrary.stubs",
+			],
+			srcs: ["A.java"],
+		}
+
+		java_library {
+			name: "bar",
+			libs: [
+				"myothersdklibrary.stubs"
+			],
+		}
+	`)
+	ctx := result.TestContext
+	fooModule := ctx.ModuleForTests(t, "foo", "android_common")
+
+	androidMkEntries := android.AndroidMkEntriesForTest(t, ctx, fooModule.Module())[0]
+	localExportSdkLibraries := androidMkEntries.EntryMap["LOCAL_EXPORT_SDK_LIBRARIES"]
+	android.AssertStringListDoesNotContain(t,
+		"boot jar should not be included in uses libs entries",
+		localExportSdkLibraries,
+		"mysdklibrary",
+	)
+	android.AssertStringListContains(t,
+		"non boot jar is included in uses libs entries",
+		localExportSdkLibraries,
+		"myothersdklibrary",
+	)
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index 07f8c43..56142c8 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -45,13 +45,13 @@
 	// (b/204397180) Generate module_bp_java_deps.json by default.
 	moduleInfos := make(map[string]android.IdeInfo)
 
-	ctx.VisitAllModules(func(module android.Module) {
-		if !module.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
 		// Prevent including both prebuilts and matching source modules when one replaces the other.
-		if !android.IsModulePreferred(module) {
+		if !android.IsModulePreferredProxy(ctx, module) {
 			return
 		}
 
@@ -60,9 +60,11 @@
 			return
 		}
 		name := ideInfoProvider.BaseModuleName
-		ideModuleNameProvider, ok := module.(android.IDECustomizedModuleName)
-		if ok {
-			name = ideModuleNameProvider.IDECustomizedModuleName()
+		if info, ok := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider); ok && info.Prebuilt {
+			// TODO(b/113562217): Extract the base module name from the Import name, often the Import name
+			// has a prefix "prebuilt_". Remove the prefix explicitly if needed until we find a better
+			// solution to get the Import name.
+			name = android.RemoveOptionalPrebuiltPrefix(module.Name())
 		}
 
 		dpInfo := moduleInfos[name]
@@ -70,13 +72,12 @@
 		dpInfo.Paths = []string{ctx.ModuleDir(module)}
 		moduleInfos[name] = dpInfo
 
-		mkProvider, ok := module.(android.AndroidMkDataProvider)
+		mkProvider, ok := android.OtherModuleProvider(ctx, module, android.AndroidMkDataInfoProvider)
 		if !ok {
 			return
 		}
-		data := mkProvider.AndroidMk()
-		if data.Class != "" {
-			dpInfo.Classes = append(dpInfo.Classes, data.Class)
+		if mkProvider.Class != "" {
+			dpInfo.Classes = append(dpInfo.Classes, mkProvider.Class)
 		}
 
 		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
diff --git a/java/lint.go b/java/lint.go
index 66f7f85..dc1e51f 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -595,12 +595,12 @@
 	l.copyLintDependencies(ctx)
 }
 
-func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
-	var res android.Module
-	ctx.VisitAllModules(func(m android.Module) {
+func findModuleOrErr(ctx android.SingletonContext, moduleName string) *android.ModuleProxy {
+	var res *android.ModuleProxy
+	ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
 		if ctx.ModuleName(m) == moduleName {
 			if res == nil {
-				res = m
+				res = &m
 			} else {
 				ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
 					ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
@@ -635,13 +635,13 @@
 
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.CpIfChanged,
-			Input:  android.OutputFileForModule(ctx, sdkAnnotations, ""),
+			Input:  android.OutputFileForModule(ctx, *sdkAnnotations, ""),
 			Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
 		})
 
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.CpIfChanged,
-			Input:  android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
+			Input:  android.OutputFileForModule(ctx, *apiVersionsDb, ".api_versions.xml"),
 			Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
 		})
 	}
@@ -658,12 +658,13 @@
 
 	var outputs []*LintInfo
 	var dirs []string
-	ctx.VisitAllModules(func(m android.Module) {
-		if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
+	ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider)
+		if ctx.Config().KatiEnabled() && !commonInfo.ExportedToMake {
 			return
 		}
 
-		if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
+		if commonInfo.IsApexModule && commonInfo.NotAvailableForPlatform {
 			apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
 			if apexInfo.IsForPlatform() {
 				// There are stray platform variants of modules in apexes that are not available for
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 363521a..d2ec8bd 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -99,6 +99,14 @@
 	includeInMergedXml() bool
 }
 
+type PlatformCompatConfigMetadataInfo struct {
+	CompatConfigMetadata android.Path
+	// Whether to include it in the "merged" XML (merged_compat_config.xml) or not.
+	IncludeInMergedXml bool
+}
+
+var PlatformCompatConfigMetadataInfoProvider = blueprint.NewProvider[PlatformCompatConfigMetadataInfo]()
+
 type PlatformCompatConfigIntf interface {
 	android.Module
 
@@ -136,6 +144,11 @@
 		CompatConfig: p.CompatConfig(),
 		SubDir:       p.SubDir(),
 	})
+
+	android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{
+		CompatConfigMetadata: p.compatConfigMetadata(),
+		IncludeInMergedXml:   p.includeInMergedXml(),
+	})
 }
 
 func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries {
@@ -238,6 +251,11 @@
 
 func (module *prebuiltCompatConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	module.metadataFile = module.prebuilt.SingleSourcePath(ctx)
+
+	android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{
+		CompatConfigMetadata: module.compatConfigMetadata(),
+		IncludeInMergedXml:   module.includeInMergedXml(),
+	})
 }
 
 // A prebuilt version of platform_compat_config that provides the metadata.
@@ -258,18 +276,18 @@
 
 	var compatConfigMetadata android.Paths
 
-	ctx.VisitAllModules(func(module android.Module) {
-		if !module.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
-		if c, ok := module.(platformCompatConfigMetadataProvider); ok {
-			if !android.IsModulePreferred(module) {
+		if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigMetadataInfoProvider); ok {
+			if !android.IsModulePreferredProxy(ctx, module) {
 				return
 			}
-			if !c.includeInMergedXml() {
+			if !c.IncludeInMergedXml {
 				return
 			}
-			metadata := c.compatConfigMetadata()
+			metadata := c.CompatConfigMetadata
 			compatConfigMetadata = append(compatConfigMetadata, metadata)
 		}
 	})
diff --git a/java/ravenwood.go b/java/ravenwood.go
index c4078c5..a942dc6 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -117,6 +117,8 @@
 		"ravenwood-tests",
 	}
 	module.testProperties.Test_options.Unit_test = proptools.BoolPtr(false)
+	module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Top_level_test_target = true
 
 	InitJavaModule(module, android.DeviceSupported)
 	android.InitDefaultableModule(module)
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
index 24a02bb..d6493bc 100644
--- a/java/ravenwood_test.go
+++ b/java/ravenwood_test.go
@@ -230,4 +230,15 @@
 	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/libred.so")
 	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
 	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-utils/framework-rules.ravenwood.jar")
+
+	// Ensure they are listed as "test" modules for code coverage
+	expectedTestOnlyModules := []string{
+		"ravenwood-test",
+		"ravenwood-test-empty",
+	}
+	expectedTopLevelTests := []string{
+		"ravenwood-test",
+		"ravenwood-test-empty",
+	}
+	assertTestOnlyAndTopLevel(t, ctx, expectedTestOnlyModules, expectedTopLevelTests)
 }
diff --git a/java/robolectric.go b/java/robolectric.go
index be369f7..1d204a4 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -284,6 +284,11 @@
 	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
 		TestSuites: r.TestSuites(),
 	})
+
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       Bool(r.sourceProperties.Test_only),
+		TopLevelTarget: r.sourceProperties.Top_level_test_target,
+	})
 }
 
 func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
@@ -335,7 +340,8 @@
 
 	module.Module.dexpreopter.isTest = true
 	module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true)
-
+	module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Top_level_test_target = true
 	module.testProperties.Test_suites = []string{"robolectric-tests"}
 
 	InitJavaModule(module, android.DeviceSupported)
diff --git a/java/robolectric_test.go b/java/robolectric_test.go
index 4bf224b..cc16c6a 100644
--- a/java/robolectric_test.go
+++ b/java/robolectric_test.go
@@ -107,4 +107,15 @@
 	// Check that the .so files make it into the output.
 	module := ctx.ModuleForTests(t, "robo-test", "android_common")
 	module.Output(installPathPrefix + "/robo-test/lib64/jni-lib1.so")
+
+	// Ensure they are listed as "test" modules for code coverage
+	expectedTestOnlyModules := []string{
+		"robo-test",
+	}
+
+	expectedTopLevelTests := []string{
+		"robo-test",
+	}
+	assertTestOnlyAndTopLevel(t, ctx, expectedTestOnlyModules, expectedTopLevelTests)
+
 }
diff --git a/java/rro.go b/java/rro.go
index f7f85f0..4ae8d7f 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -99,15 +99,6 @@
 	Overrides []string
 }
 
-// RuntimeResourceOverlayModule interface is used by the apex package to gather information from
-// a RuntimeResourceOverlay module.
-type RuntimeResourceOverlayModule interface {
-	android.Module
-	OutputFile() android.Path
-	Certificate() Certificate
-	Theme() string
-}
-
 // RRO's partition logic is different from the partition logic of other modules defined in soong/android/paths.go
 // The default partition for RRO is "/product" and not "/system"
 func rroPartition(ctx android.ModuleContext) string {
@@ -217,11 +208,13 @@
 	})
 
 	android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{
-		OutputFile:  r.OutputFile(),
+		OutputFile:  r.outputFile,
 		Certificate: r.Certificate(),
 		Theme:       r.Theme(),
 	})
 
+	ctx.SetOutputFiles([]android.Path{r.outputFile}, "")
+
 	buildComplianceMetadata(ctx)
 }
 
@@ -252,10 +245,6 @@
 	return r.certificate
 }
 
-func (r *RuntimeResourceOverlay) OutputFile() android.Path {
-	return r.outputFile
-}
-
 func (r *RuntimeResourceOverlay) Theme() string {
 	return String(r.properties.Theme)
 }
@@ -406,10 +395,11 @@
 
 	a.aapt.buildActions(ctx,
 		aaptBuildActionOptions{
-			sdkContext:      a,
-			extraLinkFlags:  aaptLinkFlags,
-			rroDirs:         &rroDirs,
-			manifestForAapt: genManifest,
+			sdkContext:       a,
+			extraLinkFlags:   aaptLinkFlags,
+			rroDirs:          &rroDirs,
+			manifestForAapt:  genManifest,
+			aconfigTextFiles: getAconfigFilePaths(ctx),
 		},
 	)
 
@@ -426,6 +416,11 @@
 	// Install the signed apk
 	installDir := android.PathForModuleInstall(ctx, "overlay")
 	ctx.InstallFile(installDir, signed.Base(), signed)
+
+	android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{
+		OutputFile:  signed,
+		Certificate: a.certificate,
+	})
 }
 
 func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
diff --git a/java/rro_test.go b/java/rro_test.go
index 0ccc8e7..3e4fed5 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -358,3 +358,21 @@
 		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
 	)
 }
+
+func TestCanBeDataOfTest(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+		runtime_resource_overlay {
+			name: "foo",
+			sdk_version: "current",
+		}
+		android_test {
+			name: "bar",
+			data: [
+				":foo",
+			],
+		}
+	`)
+	// Just test that this doesn't get errors
+}
diff --git a/java/sdk.go b/java/sdk.go
index 8510959..73262da 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -274,7 +274,7 @@
 func createFrameworkAidl(stubsModules []string, path android.WritablePath, ctx android.SingletonContext) *android.RuleBuilder {
 	stubsJars := make([]android.Paths, len(stubsModules))
 
-	ctx.VisitAllModules(func(module android.Module) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 		// Collect dex jar paths for the modules listed above.
 		if j, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			name := ctx.ModuleName(module)
@@ -382,7 +382,7 @@
 
 	rule.Build("api_fingerprint", "generate api_fingerprint.txt")
 
-	if ctx.Config().BuildOS == android.Linux {
+	if ctx.Config().BuildOS.Linux() {
 		ctx.DistForGoals([]string{"sdk", "droidcore"}, out)
 	}
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 7944bb2..00ba8b2 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1337,10 +1337,10 @@
 
 func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) {
 	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) {
-		ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+		ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
 			isExternal := !android.IsDepInSameApex(ctx, module, child)
-			if am, ok := child.(android.ApexModule); ok {
-				if !do(ctx, parent, am, isExternal) {
+			if am, ok := android.OtherModuleProvider(ctx, child, android.CommonModuleInfoProvider); ok && am.IsApexModule {
+				if !do(ctx, parent, child, isExternal) {
 					return false
 				}
 			}
@@ -1580,7 +1580,9 @@
 		setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo)
 	}
 
-	javaInfo := &JavaInfo{}
+	javaInfo := &JavaInfo{
+		JacocoReportClassesFile: module.jacocoReportClassesFile,
+	}
 	setExtraJavaInfo(ctx, ctx.Module(), javaInfo)
 	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
 
@@ -2240,6 +2242,10 @@
 	}
 
 	javaInfo := &JavaInfo{}
+	if module.implLibraryInfo != nil {
+		javaInfo.JacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile
+	}
+
 	setExtraJavaInfo(ctx, ctx.Module(), javaInfo)
 	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
 
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 431bbac..6d27e54 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -494,7 +494,7 @@
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("foo"),
 	).
-		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": unsupported module reference tag ".public.annotations.zip"`)).
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": unsupported output tag ".public.annotations.zip"`)).
 		RunTestWithBp(t, `
 		java_sdk_library {
 			name: "foo",
@@ -520,7 +520,7 @@
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("foo"),
 	).
-		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": unsupported module reference tag ".system.stubs.source"`)).
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": unsupported output tag ".system.stubs.source"`)).
 		RunTestWithBp(t, `
 		java_sdk_library {
 			name: "foo",
diff --git a/java/support_libraries.go b/java/support_libraries.go
index c483fc1..f76eb11 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -28,7 +28,7 @@
 func supportLibrariesMakeVarsProvider(ctx android.MakeVarsContext) {
 	var supportAars, supportJars []string
 
-	ctx.VisitAllModules(func(module android.Module) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 		dir := ctx.ModuleDir(module)
 		switch {
 		case strings.HasPrefix(dir, "prebuilts/sdk/current/extras"),
@@ -47,11 +47,16 @@
 			return
 		}
 
-		switch module.(type) {
-		case *AndroidLibrary, *AARImport:
+		_, isAndroidLibrary := android.OtherModuleProvider(ctx, module, AndroidLibraryInfoProvider)
+		_, isAARImport := android.OtherModuleProvider(ctx, module, AARImportInfoProvider)
+		if isAndroidLibrary || isAARImport {
 			supportAars = append(supportAars, name)
-		case *Library, *Import:
-			supportJars = append(supportJars, name)
+		} else {
+			_, isJavaLibrary := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider)
+			_, isJavaPlugin := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider)
+			if isJavaLibrary && !isJavaPlugin {
+				supportJars = append(supportJars, name)
+			}
 		}
 	})
 
diff --git a/java/testing.go b/java/testing.go
index 3abbb84..d7878d6 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -424,7 +424,6 @@
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 		"stub-annotations",
-
 		"aconfig-annotations-lib",
 		"aconfig_storage_stub",
 		"unsupportedappusage",
diff --git a/java/tracereferences.go b/java/tracereferences.go
new file mode 100644
index 0000000..342b6a6
--- /dev/null
+++ b/java/tracereferences.go
@@ -0,0 +1,54 @@
+// Copyright 2025 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 java
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+var traceReferences = pctx.AndroidStaticRule("traceReferences",
+	blueprint.RuleParams{
+		Command: `${config.TraceReferencesCmd} ` +
+			// Note that we suppress missing def errors, as we're only interested
+			// in the direct deps between the sources and target.
+			`--map-diagnostics:MissingDefinitionsDiagnostic error none ` +
+			`--keep-rules ` +
+			`--output ${out} ` +
+			`--target ${in} ` +
+			// `--source` and `--lib` are already prepended to each
+			// jar reference in the sources and libs joined string args.
+			`${sources} ` +
+			`${libs}`,
+		CommandDeps: []string{"${config.TraceReferencesCmd}"},
+	}, "sources", "libs")
+
+// Generates keep rules in output corresponding to any references from sources
+// (a list of jars) onto target (the referenced jar) that are not included in
+// libs (a list of external jars).
+func TraceReferences(ctx android.ModuleContext, sources android.Paths, target android.Path, libs android.Paths,
+	output android.WritablePath) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:      traceReferences,
+		Input:     target,
+		Output:    output,
+		Implicits: append(sources, libs...),
+		Args: map[string]string{
+			"sources": android.JoinWithPrefix(sources.Strings(), "--source "),
+			"libs":    android.JoinWithPrefix(libs.Strings(), "--lib "),
+		},
+	})
+}
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 43fe8aa..925d7b1 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -127,7 +127,7 @@
 	for _, m := range requireModules {
 		if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok {
 			if android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider).HasStubsVariants &&
-				!android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoKey).Host {
+				!android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider).Host {
 				name := ctx.OtherModuleName(m)
 				if ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok && ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.ImplementationModuleName != nil {
 					name = *ccInfo.LinkerInfo.ImplementationModuleName
diff --git a/phony/phony.go b/phony/phony.go
index 4f61c45..e75f4c8 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -104,8 +104,7 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 
-	phonyDepsModuleNames []string
-	properties           PhonyProperties
+	properties PhonyProperties
 }
 
 type PhonyProperties struct {
@@ -126,18 +125,8 @@
 }
 
 func (p *PhonyRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	p.phonyDepsModuleNames = p.properties.Phony_deps.GetOrDefault(ctx, nil)
-}
-
-func (p *PhonyRule) AndroidMk() android.AndroidMkData {
-	return android.AndroidMkData{
-		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-			if len(p.phonyDepsModuleNames) > 0 {
-				depModulesStr := strings.Join(p.phonyDepsModuleNames, " ")
-				fmt.Fprintln(w, ".PHONY:", name)
-				fmt.Fprintln(w, name, ":", depModulesStr)
-			}
-		},
+	for _, dep := range p.properties.Phony_deps.GetOrDefault(ctx, nil) {
+		ctx.Phony(ctx.ModuleName(), android.PathForPhony(ctx, dep))
 	}
 }
 
diff --git a/provenance/provenance_metadata_proto/Android.bp b/provenance/provenance_metadata_proto/Android.bp
index 7fc47a9..b4176a5 100644
--- a/provenance/provenance_metadata_proto/Android.bp
+++ b/provenance/provenance_metadata_proto/Android.bp
@@ -20,11 +20,6 @@
 
 python_library_host {
     name: "provenance_metadata_proto",
-    version: {
-        py3: {
-            enabled: true,
-        },
-    },
     srcs: [
         "provenance_metadata.proto",
     ],
diff --git a/python/binary.go b/python/binary.go
index feac72a..f894299 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -125,6 +125,7 @@
 func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
 	embeddedLauncher := p.isEmbeddedLauncherEnabled()
 	depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
+	bundleSharedLibs := p.collectSharedLibDeps(ctx)
 	main := ""
 	if p.autorun() {
 		main = p.getPyMainFile(ctx, p.srcsPathMappings)
@@ -149,6 +150,11 @@
 		srcsZips = append(srcsZips, p.srcsZip)
 	}
 	srcsZips = append(srcsZips, depsSrcsZips...)
+	if ctx.Host() && len(bundleSharedLibs) > 0 {
+		// only bundle shared libs for host binaries
+		sharedLibZip := p.zipSharedLibs(ctx, bundleSharedLibs)
+		srcsZips = append(srcsZips, sharedLibZip)
+	}
 	p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
 		"python3", main, p.getStem(ctx), srcsZips)
 
@@ -159,6 +165,10 @@
 		sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
 	}
 	p.androidMkSharedLibs = sharedLibs
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: p.binaryProperties.Test_suites,
+	})
 }
 
 func (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/python/python.go b/python/python.go
index f8f4165..de21e39 100644
--- a/python/python.go
+++ b/python/python.go
@@ -20,11 +20,13 @@
 	"fmt"
 	"path/filepath"
 	"regexp"
+	"sort"
 	"strings"
 
 	"android/soong/cc"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/depset"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -36,6 +38,7 @@
 	SrcsZip            android.Path
 	PrecompiledSrcsZip android.Path
 	PkgPath            string
+	BundleSharedLibs   android.Paths
 }
 
 var PythonLibraryInfoProvider = blueprint.NewProvider[PythonLibraryInfo]()
@@ -105,6 +108,10 @@
 	// list of the Python libraries compatible both with Python2 and Python3.
 	Libs []string `android:"arch_variant"`
 
+	// TODO: b/403060602 - add unit tests for this property and related code
+	// list of shared libraries that should be packaged with the python code for this module.
+	Shared_libs []string `android:"arch_variant"`
+
 	Version struct {
 		// Python2-specific properties, including whether Python2 is supported for this module
 		// and version-specific sources, exclusions and dependencies.
@@ -158,6 +165,10 @@
 	precompiledSrcsZip android.Path
 
 	sourceProperties android.SourceProperties
+
+	// The shared libraries that should be bundled with the python code for
+	// any standalone python binaries that depend on this module.
+	bundleSharedLibs android.Paths
 }
 
 // newModule generates new Python base module
@@ -197,6 +208,10 @@
 	return &p.properties
 }
 
+func (p *PythonLibraryModule) getBundleSharedLibs() android.Paths {
+	return p.bundleSharedLibs
+}
+
 func (p *PythonLibraryModule) init() android.Module {
 	p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
@@ -224,6 +239,7 @@
 var (
 	pythonLibTag = dependencyTag{name: "pythonLib"}
 	javaDataTag  = dependencyTag{name: "javaData"}
+	sharedLibTag = dependencyTag{name: "sharedLib"}
 	// The python interpreter, with soong module name "py3-launcher" or "py3-launcher-autorun".
 	launcherTag          = dependencyTag{name: "launcher"}
 	launcherSharedLibTag = installDependencyTag{name: "launcherSharedLib"}
@@ -288,6 +304,12 @@
 	javaDataVariation := []blueprint.Variation{{"arch", android.Common.String()}}
 	ctx.AddVariationDependencies(javaDataVariation, javaDataTag, p.properties.Java_data...)
 
+	if ctx.Host() {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), sharedLibTag, p.properties.Shared_libs...)
+	} else if len(p.properties.Shared_libs) > 0 {
+		ctx.PropertyErrorf("shared_libs", "shared_libs is not supported for device builds")
+	}
+
 	p.AddDepsOnPythonLauncherAndStdlib(ctx, hostStdLibTag, hostLauncherTag, hostlauncherSharedLibTag, false, ctx.Config().BuildOSTarget)
 }
 
@@ -377,6 +399,25 @@
 		expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
 	}
 
+	var directImplementationDeps android.Paths
+	var transitiveImplementationDeps []depset.DepSet[android.Path]
+	ctx.VisitDirectDepsProxyWithTag(sharedLibTag, func(dep android.ModuleProxy) {
+		sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
+		if sharedLibInfo.SharedLibrary != nil {
+			expandedData = append(expandedData, android.OutputFilesForModule(ctx, dep, "")...)
+			directImplementationDeps = append(directImplementationDeps, android.OutputFilesForModule(ctx, dep, "")...)
+			if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+				transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+				p.bundleSharedLibs = append(p.bundleSharedLibs, info.ImplementationDeps.ToList()...)
+			}
+		} else {
+			ctx.PropertyErrorf("shared_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+		}
+	})
+	android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+		ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+	})
+
 	// Validate pkg_path property
 	pkgPath := String(p.properties.Pkg_path)
 	if pkgPath != "" {
@@ -400,8 +441,7 @@
 
 	// generate the zipfile of all source and data files
 	p.srcsZip = p.createSrcsZip(ctx, pkgPath)
-	// TODO(b/388344853): precompilation temporarily disabled for python3.13 upgrade
-	p.precompiledSrcsZip = p.srcsZip //p.precompileSrcs(ctx)
+	p.precompiledSrcsZip = p.precompileSrcs(ctx)
 
 	android.SetProvider(ctx, PythonLibraryInfoProvider, PythonLibraryInfo{
 		SrcsPathMappings:   p.getSrcsPathMappings(),
@@ -409,6 +449,7 @@
 		SrcsZip:            p.getSrcsZip(),
 		PkgPath:            p.getPkgPath(),
 		PrecompiledSrcsZip: p.getPrecompiledSrcsZip(),
+		BundleSharedLibs:   p.getBundleSharedLibs(),
 	})
 }
 
@@ -685,6 +726,56 @@
 	return result
 }
 
+func (p *PythonLibraryModule) collectSharedLibDeps(ctx android.ModuleContext) android.Paths {
+	seen := make(map[android.Module]bool)
+
+	var result android.Paths
+
+	ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool {
+		// we only collect dependencies tagged as python library deps
+		if ctx.OtherModuleDependencyTag(child) != pythonLibTag {
+			return false
+		}
+		if seen[child] {
+			return false
+		}
+		seen[child] = true
+		dep, isLibrary := android.OtherModuleProvider(ctx, child, PythonLibraryInfoProvider)
+		if isLibrary {
+			result = append(result, dep.BundleSharedLibs...)
+		}
+		return true
+	})
+	return result
+}
+
+func (p *PythonLibraryModule) zipSharedLibs(ctx android.ModuleContext, bundleSharedLibs android.Paths) android.Path {
+	// sort the paths to keep the output deterministic
+	sort.Slice(bundleSharedLibs, func(i, j int) bool {
+		return bundleSharedLibs[i].String() < bundleSharedLibs[j].String()
+	})
+
+	parArgs := []string{"-symlinks=false", "-P lib64"}
+	paths := android.Paths{}
+	for _, path := range bundleSharedLibs {
+		// specify relative root of file in following -f arguments
+		parArgs = append(parArgs, `-C `+filepath.Dir(path.String()))
+		parArgs = append(parArgs, `-f `+path.String())
+		paths = append(paths, path)
+	}
+	srcsZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".sharedlibs.srcszip")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        zip,
+		Description: "bundle shared libraries for python binary",
+		Output:      srcsZip,
+		Implicits:   paths,
+		Args: map[string]string{
+			"args": strings.Join(parArgs, " "),
+		},
+	})
+	return srcsZip
+}
+
 // chckForDuplicateOutputPath checks whether outputPath has already been included in map m, which
 // would result in two files being placed in the same location.
 // If there is a duplicate path, an error is thrown and true is returned
diff --git a/python/scripts/main.py b/python/scripts/main.py
index 225dbe4..35cdfc4 100644
--- a/python/scripts/main.py
+++ b/python/scripts/main.py
@@ -1,5 +1,13 @@
+
+import os
 import runpy
+import shutil
 import sys
+import tempfile
+import zipfile
+
+from pathlib import PurePath
+
 
 sys.argv[0] = __loader__.archive
 
@@ -9,4 +17,32 @@
 # when people try to use it.
 sys.executable = None
 
-runpy._run_module_as_main("ENTRY_POINT", alter_argv=False)
+# Extract the shared libraries from the zip file into a temporary directory.
+# This works around the limitations of dynamic linker.  Some Python libraries
+# reference the .so files relatively and so extracting only the .so files
+# does not work, so we extract the entire parent directory of the .so files to a
+# tempdir and then add that to sys.path.
+tempdir = None
+with zipfile.ZipFile(__loader__.archive) as z:
+  # any root so files or root directories that contain so files will be
+  # extracted to the tempdir so the linker load them, this minimizes the
+  # number of files that need to be extracted to a tempdir
+  extract_paths = {}
+  for member in z.infolist():
+    if member.filename.endswith('.so'):
+      extract_paths[PurePath(member.filename).parts[0]] = member.filename
+  if extract_paths:
+    tempdir = tempfile.mkdtemp()
+    for member in z.infolist():
+      if not PurePath(member.filename).parts[0] in extract_paths.keys():
+        continue
+      if member.is_dir():
+        os.makedirs(os.path.join(tempdir, member.filename))
+      else:
+        z.extract(member, tempdir)
+    sys.path.insert(0, tempdir)
+try:
+  runpy._run_module_as_main("ENTRY_POINT", alter_argv=False)
+finally:
+  if tempdir is not None:
+    shutil.rmtree(tempdir)
diff --git a/rust/benchmark.go b/rust/benchmark.go
index daba964..3aa2f17 100644
--- a/rust/benchmark.go
+++ b/rust/benchmark.go
@@ -146,4 +146,8 @@
 	} else {
 		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
 	}
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: benchmark.Properties.Test_suites,
+	})
 }
diff --git a/rust/config/OWNERS b/rust/config/OWNERS
index dfff873..e4bf5e6 100644
--- a/rust/config/OWNERS
+++ b/rust/config/OWNERS
@@ -1,2 +1,2 @@
-per-file global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
+per-file global.go = srhines@google.com, pirama@google.com, yikong@google.com
 
diff --git a/rust/doc.go b/rust/doc.go
index fe20523..3616c8e 100644
--- a/rust/doc.go
+++ b/rust/doc.go
@@ -37,14 +37,14 @@
 		FlagWithArg("-C ", docDir.String()).
 		FlagWithArg("-D ", docDir.String())
 
-	ctx.VisitAllModules(func(module android.Module) {
-		if !module.Enabled(ctx) {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
-		if m, ok := module.(*Module); ok {
-			if m.docTimestampFile.Valid() {
-				zipCmd.Implicit(m.docTimestampFile.Path())
+		if m, ok := android.OtherModuleProvider(ctx, module, RustInfoProvider); ok {
+			if m.DocTimestampFile.Valid() {
+				zipCmd.Implicit(m.DocTimestampFile.Path())
 			}
 		}
 	})
diff --git a/rust/library_test.go b/rust/library_test.go
index 6db9525..6cc4f25 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -426,6 +426,45 @@
 	android.AssertStringDoesContain(t, "cFlags for lib module", libfooStatic.Args["cFlags"], " -Irust_includes ")
 }
 
+// Make sure cc_rustlibs_for_make has the expected behavior, and that
+// cc_library_static does as well.
+// This is here instead of cc/library_test.go because the test needs to
+// define a rust_ffi module which can't be done in soong-cc to avoid the
+// circular dependency.
+func TestCCRustlibsForMake(t *testing.T) {
+	t.Parallel()
+	result := testRust(t, `
+		rust_ffi_static {
+			name: "libbar",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			export_include_dirs: ["rust_includes"],
+			host_supported: true,
+		}
+
+		cc_rustlibs_for_make {
+			name: "libmakerustlibs",
+			whole_static_libs: ["libbar"],
+		}
+
+		cc_library_static {
+			name: "libccstatic",
+			whole_static_libs: ["libbar"],
+		}
+	`)
+
+	libmakerustlibs := result.ModuleForTests(t, "libmakerustlibs", "android_arm64_armv8-a_static").MaybeRule("rustc")
+	libccstatic := result.ModuleForTests(t, "libccstatic", "android_arm64_armv8-a_static").MaybeRule("rustc")
+
+	if libmakerustlibs.Output == nil {
+		t.Errorf("cc_rustlibs_for_make is not generating a  Rust staticlib when it should")
+	}
+
+	if libccstatic.Output != nil {
+		t.Errorf("cc_library_static is generating a Rust staticlib when it should not")
+	}
+}
+
 func TestRustVersionScript(t *testing.T) {
 	ctx := testRust(t, `
 	rust_library {
diff --git a/rust/rust.go b/rust/rust.go
index 4eebda3..54b5d92 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -60,6 +60,8 @@
 	CompilerInfo                  *CompilerInfo
 	SnapshotInfo                  *cc.SnapshotInfo
 	SourceProviderInfo            *SourceProviderInfo
+	XrefRustFiles                 android.Paths
+	DocTimestampFile              android.OptionalPath
 }
 
 var RustInfoProvider = blueprint.NewProvider[*RustInfo]()
@@ -1171,6 +1173,8 @@
 		AndroidMkSuffix:               mod.AndroidMkSuffix(),
 		RustSubName:                   mod.Properties.RustSubName,
 		TransitiveAndroidMkSharedLibs: mod.transitiveAndroidMkSharedLibs,
+		XrefRustFiles:                 mod.XrefRustFiles(),
+		DocTimestampFile:              mod.docTimestampFile,
 	}
 	if mod.compiler != nil {
 		rustInfo.CompilerInfo = &CompilerInfo{
@@ -1476,10 +1480,10 @@
 		rustInfo, hasRustInfo := android.OtherModuleProvider(ctx, dep, RustInfoProvider)
 		ccInfo, _ := android.OtherModuleProvider(ctx, dep, cc.CcInfoProvider)
 		linkableInfo, hasLinkableInfo := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider)
-		commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider)
 		if hasRustInfo && !linkableInfo.Static && !linkableInfo.Shared {
 			//Handle Rust Modules
-			makeLibName := rustMakeLibName(rustInfo, linkableInfo, &commonInfo, depName+rustInfo.RustSubName)
+			makeLibName := rustMakeLibName(rustInfo, linkableInfo, commonInfo, depName+rustInfo.RustSubName)
 
 			switch {
 			case depTag == dylibDepTag:
@@ -1624,7 +1628,7 @@
 			}
 		} else if hasLinkableInfo {
 			//Handle C dependencies
-			makeLibName := cc.MakeLibName(ccInfo, linkableInfo, &commonInfo, depName)
+			makeLibName := cc.MakeLibName(ccInfo, linkableInfo, commonInfo, depName)
 			if !hasRustInfo {
 				if commonInfo.Target.Os != ctx.Os() {
 					ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
@@ -2236,9 +2240,9 @@
 
 func (k kytheExtractRustSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var xrefTargets android.Paths
-	ctx.VisitAllModules(func(module android.Module) {
-		if rustModule, ok := module.(xref); ok {
-			xrefTargets = append(xrefTargets, rustModule.XrefRustFiles()...)
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		if rustModule, ok := android.OtherModuleProvider(ctx, module, RustInfoProvider); ok {
+			xrefTargets = append(xrefTargets, rustModule.XrefRustFiles...)
 		}
 	})
 	if len(xrefTargets) > 0 {
diff --git a/rust/test.go b/rust/test.go
index 9833ffd..cedced2 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -165,7 +165,7 @@
 		if linkableDep.OutputFile.Valid() {
 			// Copy the output in "lib[64]" so that it's compatible with
 			// the default rpath values.
-			commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+			commonInfo := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider)
 			libDir := "lib"
 			if commonInfo.Target.Arch.ArchType.Multilib == "lib64" {
 				libDir = "lib64"
@@ -242,6 +242,10 @@
 		flags.RustFlags = append(flags.RustFlags, "-Z panic_abort_tests")
 	}
 
+	// Add a default rpath to allow tests to dlopen libraries specified in data_libs.
+	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, `-Wl,-rpath,\$$ORIGIN/lib64`)
+	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
+
 	return flags
 }
 
@@ -316,6 +320,10 @@
 	} else {
 		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
 	}
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: test.Properties.Test_suites,
+	})
 }
 
 func rustTestHostMultilib(ctx android.LoadHookContext) {
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 94163a5..c0e13d5 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -287,9 +287,13 @@
     ],
 }
 
-sh_binary_host {
-    name: "keep-flagged-apis",
-    src: "keep-flagged-apis.sh",
+python_binary_host {
+    name: "aconfig-to-metalava-flags",
+    main: "aconfig-to-metalava-flags.py",
+    srcs: ["aconfig-to-metalava-flags.py"],
+    libs: [
+        "libaconfig_python_proto",
+    ],
 }
 
 python_binary_host {
diff --git a/scripts/aconfig-to-metalava-flags.py b/scripts/aconfig-to-metalava-flags.py
new file mode 100644
index 0000000..efa85ec
--- /dev/null
+++ b/scripts/aconfig-to-metalava-flags.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2025 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.
+
+"""Converts a set of aconfig protobuf flags to a Metalava config file."""
+
+# Formatted using `pyformat -i scripts/aconfig-to-metalava-flags.py`
+
+import argparse
+import sys
+import xml.etree.ElementTree as ET
+
+from protos import aconfig_pb2
+
+_READ_ONLY = aconfig_pb2.flag_permission.READ_ONLY
+_ENABLED = aconfig_pb2.flag_state.ENABLED
+_DISABLED = aconfig_pb2.flag_state.DISABLED
+
+# The namespace of the Metalava config file.
+CONFIG_NS = 'http://www.google.com/tools/metalava/config'
+
+
+def config_name(tag: str):
+  """Create a QName in the config namespace.
+
+  :param:tag the name of the entity in the config namespace.
+  """
+  return f'{{{CONFIG_NS}}}{tag}'
+
+
+def main():
+  """Program entry point."""
+  args_parser = argparse.ArgumentParser(
+      description='Generate Metalava flags config from aconfig protobuf',
+  )
+  args_parser.add_argument(
+      'input',
+      help='The path to the aconfig protobuf file',
+  )
+  args = args_parser.parse_args(sys.argv[1:])
+
+  # Read the parsed_flags from the protobuf file.
+  with open(args.input, 'rb') as f:
+    parsed_flags = aconfig_pb2.parsed_flags.FromString(f.read())
+
+  # Create the structure of the XML config file.
+  config = ET.Element(config_name('config'))
+  api_flags = ET.SubElement(config, config_name('api-flags'))
+  # Create an <api-flag> element for each parsed_flag.
+  for flag in parsed_flags.parsed_flag:
+    if flag.permission == _READ_ONLY:
+      # Ignore any read only disabled flags as Metalava assumes that as the
+      # default when an <api-flags/> element is provided so this reduces the
+      # size of the file.
+      if flag.state == _DISABLED:
+        continue
+      mutability = 'immutable'
+    else:
+      mutability = 'mutable'
+    if flag.state == _ENABLED:
+      status = 'enabled'
+    else:
+      status = 'disabled'
+    attributes = {
+        'package': flag.package,
+        'name': flag.name,
+        'mutability': mutability,
+        'status': status,
+    }
+    # Convert the attribute names into qualified names in, what will become, the
+    # default namespace for the XML file. This is needed to ensure that the
+    # attribute will be written in the XML file without a prefix, e.g.
+    # `name="flag_name"`. Without it, a namespace prefix, e.g. `ns1`, will be
+    # synthesized for the attribute when writing the XML file, i.e. it
+    # will be written as `ns1:name="flag_name"`. Strictly speaking, that is
+    # unnecessary as the "Namespaces in XML 1.0 (Third Edition)" specification
+    # says that unprefixed attribute names have no namespace.
+    qualified_attributes = {config_name(k): v for (k, v) in attributes.items()}
+    ET.SubElement(api_flags, config_name('api-flag'), qualified_attributes)
+
+  # Create a tree and add white space so it will pretty print when written out.
+  tree = ET.ElementTree(config)
+  ET.indent(tree)
+
+  # Write the tree using the config namespace as the default.
+  tree.write(sys.stdout, encoding='unicode', default_namespace=CONFIG_NS)
+  sys.stdout.close()
+
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py
index 74befd5..a0d2546 100644
--- a/scripts/gen_build_prop.py
+++ b/scripts/gen_build_prop.py
@@ -113,6 +113,7 @@
   print("####################################")
 
   config = args.config
+  build_flags = config["BuildFlags"]
   partition = args.partition
 
   if partition == "system":
@@ -164,6 +165,7 @@
   print(f"ro.{partition}.build.version.release={config['Platform_version_last_stable']}")
   print(f"ro.{partition}.build.version.release_or_codename={config['Platform_version_name']}")
   print(f"ro.{partition}.build.version.sdk={config['Platform_sdk_version']}")
+  print(f"ro.{partition}.build.version.sdk_minor={build_flags['RELEASE_PLATFORM_SDK_MINOR_VERSION']}")
 
 def generate_build_info(args):
   print()
@@ -196,6 +198,7 @@
     print(f"ro.build.display.id?={config['BuildDesc']}")
   print(f"ro.build.version.incremental={config['BuildNumber']}")
   print(f"ro.build.version.sdk={config['Platform_sdk_version']}")
+  print(f"ro.build.version.sdk_minor={build_flags['RELEASE_PLATFORM_SDK_MINOR_VERSION']}")
   print(f"ro.build.version.preview_sdk={config['Platform_preview_sdk_version']}")
   print(f"ro.build.version.preview_sdk_fingerprint={config['PlatformPreviewSdkFingerprint']}")
   print(f"ro.build.version.codename={config['Platform_sdk_codename']}")
diff --git a/scripts/keep-flagged-apis.sh b/scripts/keep-flagged-apis.sh
deleted file mode 100755
index 48efb7a..0000000
--- a/scripts/keep-flagged-apis.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash -e
-#
-# Copyright 2023 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.
-
-# Convert a list of flags in the input file to a list of metalava options
-# that will keep the APIs for those flags will hiding all other flagged
-# APIs.
-
-FLAGS="$1"
-
-FLAGGED="android.annotation.FlaggedApi"
-
-# Convert the list of feature flags in the input file to Metalava options
-# of the form `--revert-annotation !android.annotation.FlaggedApi("<flag>")`
-# to prevent the annotated APIs from being hidden, i.e. include the annotated
-# APIs in the SDK snapshots.
-while read -r line; do
-  # Escape and quote the key for sed
-  escaped_line=$(echo "$line" | sed "s/'/\\\'/g; s/ /\\ /g")
-
-  echo "--revert-annotation '!$FLAGGED(\"$escaped_line\")'"
-done < "$FLAGS"
-
-# Revert all flagged APIs, unless listed above.
-echo "--revert-annotation $FLAGGED"
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 175451e..96dc5a6 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -132,7 +132,7 @@
 
     #pylint: disable=line-too-long
     errmsg = ''.join([
-        'mismatch in the <uses-library> tags between the build system and the '
+        'mismatch or misordering in the <uses-library> tags between the build system and the '
         'manifest:\n',
         '\t- required libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(required), C_OFF),
         '\t                 vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_required), C_OFF),
diff --git a/scripts/microfactory.bash b/scripts/microfactory.bash
index ce4a0e4..49988fa 100644
--- a/scripts/microfactory.bash
+++ b/scripts/microfactory.bash
@@ -23,7 +23,14 @@
 # Ensure GOROOT is set to the in-tree version.
 case $(uname) in
     Linux)
-        export GOROOT="${TOP}/prebuilts/go/linux-x86/"
+        case $(uname -m) in
+            x86_64)
+                export GOROOT="${TOP}/prebuilts/go/linux-x86/"
+                ;;
+            aarch64)
+                export GOROOT="${TOP}/prebuilts/go/linux-arm64/"
+                ;;
+        esac
         ;;
     Darwin)
         export GOROOT="${TOP}/prebuilts/go/darwin-x86/"
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index f8d1ce5..57f5ad1 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -356,6 +356,8 @@
 	for _, symlink := range s.Symlinks() {
 		ctx.InstallSymlink(installDir, symlink, s.installedFile)
 	}
+	moduleInfoJSON := ctx.ModuleInfoJSON()
+	moduleInfoJSON.Class = []string{"EXECUTABLES"}
 }
 
 func (s *ShBinary) AndroidMkEntries() []android.AndroidMkEntries {
@@ -508,7 +510,7 @@
 				// so that it's compatible with the default rpath values.
 				var relPath string
 				linkableInfo := android.OtherModuleProviderOrDefault(ctx, dep, cc.LinkableInfoProvider)
-				commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey)
+				commonInfo := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider)
 
 				if commonInfo.Target.Arch.ArchType.Multilib == "lib64" {
 					relPath = filepath.Join("lib64", linkableInfo.OutputFile.Path().Base())
@@ -572,6 +574,10 @@
 		moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.testConfig.String())
 	}
 	moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.extraTestConfigs.Strings()...)
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: s.testProperties.Test_suites,
+	})
 }
 
 func addArch(archType string, paths android.Paths) []string {
@@ -607,6 +613,8 @@
 					entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", s.extraTestConfigs.Strings()...)
 				}
 
+				entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !proptools.BoolDefault(s.testProperties.Auto_gen_config, true))
+
 				s.testProperties.Test_options.SetAndroidMkEntries(entries)
 			},
 		},
diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go
index 988352c..2b34128 100644
--- a/tradefed_modules/test_module_config.go
+++ b/tradefed_modules/test_module_config.go
@@ -162,6 +162,22 @@
 	m.validateBase(ctx, &testModuleConfigTag, "android_test", false)
 	m.generateManifestAndConfig(ctx)
 
+	moduleInfoJSON := ctx.ModuleInfoJSON()
+	moduleInfoJSON.Class = []string{m.provider.MkAppClass}
+	if m.provider.MkAppClass != "NATIVE_TESTS" {
+		moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests")
+	}
+	if m.provider.IsUnitTest {
+		moduleInfoJSON.IsUnitTest = "true"
+	}
+	moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, m.tradefedProperties.Test_suites...)
+	moduleInfoJSON.SystemSharedLibs = []string{"none"}
+	moduleInfoJSON.ExtraRequired = append(moduleInfoJSON.ExtraRequired, m.provider.RequiredModuleNames...)
+	moduleInfoJSON.ExtraRequired = append(moduleInfoJSON.ExtraRequired, *m.Base)
+	moduleInfoJSON.ExtraHostRequired = append(moduleInfoJSON.ExtraRequired, m.provider.HostRequiredModuleNames...)
+	moduleInfoJSON.TestConfig = []string{m.testConfig.String()}
+	moduleInfoJSON.AutoTestConfig = []string{"true"}
+	moduleInfoJSON.TestModuleConfigBase = proptools.String(m.Base)
 }
 
 // Ensure at least one test_suite is listed.  Ideally it should be general-tests
@@ -410,6 +426,10 @@
 		LocalCertificate:        m.provider.LocalCertificate,
 		IsUnitTest:              m.provider.IsUnitTest,
 	})
+
+	android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
+		TestSuites: m.tradefedProperties.Test_suites,
+	})
 }
 
 var _ android.AndroidMkEntriesProvider = (*testModuleConfigHostModule)(nil)
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index 640a82d..cd49ec8 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -70,8 +70,8 @@
 	}
 }
 
-// The Android.mk files in these directories are for NDK build system.
-var external_ndk_androidmks []string = []string{
+var external_androidmks []string = []string{
+	// The Android.mk files in these directories are for NDK build system.
 	"external/fmtlib/",
 	"external/google-breakpad/",
 	"external/googletest/",
@@ -83,6 +83,9 @@
 	"external/vulkan-validation-layers/",
 	"external/walt/",
 	"external/webp/",
+	// These directories hold the published Android SDK, used in Unbundled Gradle builds.
+	"prebuilts/fullsdk-darwin",
+	"prebuilts/fullsdk-linux",
 }
 
 var art_androidmks = []string{
@@ -90,8 +93,8 @@
 }
 
 func ignoreSomeAndroidMks(androidMks []string) (filtered []string) {
-	ignore_androidmks := make([]string, 0, len(external_ndk_androidmks)+len(art_androidmks))
-	ignore_androidmks = append(ignore_androidmks, external_ndk_androidmks...)
+	ignore_androidmks := make([]string, 0, len(external_androidmks)+len(art_androidmks))
+	ignore_androidmks = append(ignore_androidmks, external_androidmks...)
 	ignore_androidmks = append(ignore_androidmks, art_androidmks...)
 
 	shouldKeep := func(androidmk string) bool {
diff --git a/ui/build/config.go b/ui/build/config.go
index a4f778d..94b0781 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1117,11 +1117,18 @@
 func (c *configImpl) PrebuiltOS() string {
 	switch runtime.GOOS {
 	case "linux":
-		return "linux-x86"
+		switch runtime.GOARCH {
+		case "amd64":
+			return "linux-x86"
+		case "arm64":
+			return "linux-arm64"
+		default:
+			panic(fmt.Errorf("Unknown GOARCH %s", runtime.GOARCH))
+		}
 	case "darwin":
 		return "darwin-x86"
 	default:
-		panic("Unknown GOOS")
+		panic(fmt.Errorf("Unknown GOOS %s", runtime.GOOS))
 	}
 }
 
@@ -1711,13 +1718,7 @@
 }
 
 func (c *configImpl) HostPrebuiltTag() string {
-	if runtime.GOOS == "linux" {
-		return "linux-x86"
-	} else if runtime.GOOS == "darwin" {
-		return "darwin-x86"
-	} else {
-		panic("Unsupported OS")
-	}
+	return c.PrebuiltOS()
 }
 
 func (c *configImpl) KatiBin() string {
diff --git a/ui/build/path.go b/ui/build/path.go
index cc1d7e9..b92d799 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -20,7 +20,6 @@
 	"os"
 	"os/exec"
 	"path/filepath"
-	"runtime"
 	"strings"
 
 	"github.com/google/blueprint/microfactory"
@@ -122,7 +121,7 @@
 	myPath, _ = filepath.Abs(myPath)
 
 	// Set up the checked-in prebuilts path directory for the current host OS.
-	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
+	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + config.PrebuiltOS())
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
 	// Set $PATH to be the directories containing the host tool symlinks, and
@@ -258,7 +257,7 @@
 
 	// We put some prebuilts in $PATH, since it's infeasible to add dependencies
 	// for all of them.
-	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
+	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + config.PrebuiltOS())
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
 	// Replace the $PATH variable with the path_interposer symlinks, and