Merge "Quote zip2zip arg with a *." into main
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 3d07e16..5a52624 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -95,11 +95,45 @@
 	})
 }
 
+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("droidcore", invalidExportedFlags)
+		}
+	}
+
+	ctx.Phony("all_aconfig_declarations", depsFiles...)
 
 	android.SetProvider(ctx, allAconfigDeclarationsInfoProvider, allAconfigDeclarationsInfo{
 		parsedFlagsFile: parsedFlagsFile,
@@ -111,7 +145,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/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 00dc50a..71e6747 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -83,6 +83,7 @@
         "nothing.go",
         "notices.go",
         "onceper.go",
+        "otatools_package_cert_zip.go",
         "override_module.go",
         "package.go",
         "package_ctx.go",
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index 7185a89..bb73f0b 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -248,7 +248,7 @@
 // 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 {
diff --git a/android/all_teams.go b/android/all_teams.go
index 8b55ade..18a050f 100644
--- a/android/all_teams.go
+++ b/android/all_teams.go
@@ -116,7 +116,7 @@
 			testOnly:           testModInfo.TestOnly,
 			topLevelTestTarget: testModInfo.TopLevelTarget,
 			kind:               ctx.ModuleType(module),
-			teamName:           OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).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 e4366fa..7cc6aef 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -510,6 +510,9 @@
 	a.EntryMap = make(map[string][]string)
 	base := mod.base()
 	name := base.BaseModuleName()
+	if bmn, ok := mod.(baseModuleName); ok {
+		name = bmn.BaseModuleName()
+	}
 	if a.OverrideName != "" {
 		name = a.OverrideName
 	}
@@ -528,6 +531,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)
@@ -880,14 +891,14 @@
 			}
 		}
 
-		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
 			}
@@ -1312,7 +1323,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
 	}
@@ -1323,11 +1334,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)
 		}
 	}
@@ -1476,12 +1487,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)
diff --git a/android/apex.go b/android/apex.go
index 39de6de..57baff5 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -695,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
@@ -723,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
@@ -733,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.
@@ -765,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_list.go b/android/arch_list.go
index 389f194..8659549 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -27,6 +27,8 @@
 		"armv8-2a-dotprod",
 		"armv9-a",
 		"armv9-2a",
+		"armv9-3a",
+		"armv9-4a",
 	},
 	X86: {
 		"alderlake",
@@ -151,6 +153,12 @@
 		"armv9-2a": {
 			"dotprod",
 		},
+		"armv9-3a": {
+			"dotprod",
+		},
+		"armv9-4a": {
+			"dotprod",
+		},
 	},
 	X86: {
 		"alderlake": {
diff --git a/android/base_module_context.go b/android/base_module_context.go
index d2404fd..5cb9e71 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -410,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)})
@@ -440,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 7c0ab85..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,32 +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
-	filesContained []string
+	properties          map[string]string
+	filesContained      []string
+	prebuiltFilesCopied []string
 }
 
 type complianceMetadataInfoGob struct {
-	Properties     map[string]string
-	FilesContained []string
+	Properties          map[string]string
+	FilesContained      []string
+	PrebuiltFilesCopied []string
 }
 
 func NewComplianceMetadataInfo() *ComplianceMetadataInfo {
 	return &ComplianceMetadataInfo{
-		properties:     map[string]string{},
-		filesContained: make([]string, 0),
+		properties:          map[string]string{},
+		filesContained:      make([]string, 0),
+		prebuiltFilesCopied: make([]string, 0),
 	}
 }
 
 func (m *ComplianceMetadataInfo) ToGob() *complianceMetadataInfoGob {
 	return &complianceMetadataInfoGob{
-		Properties:     m.properties,
-		FilesContained: m.filesContained,
+		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) {
@@ -182,6 +189,14 @@
 	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))
@@ -289,7 +304,7 @@
 
 	rowId := -1
 	ctx.VisitAllModuleProxies(func(module ModuleProxy) {
-		commonInfo, _ := OtherModuleProvider(ctx, module, CommonModuleInfoKey)
+		commonInfo := OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider)
 		if !commonInfo.Enabled {
 			return
 		}
@@ -329,24 +344,40 @@
 	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() {
-		// In soong-only build the installed file list is from android_device module
 		ctx.VisitAllModuleProxies(func(module ModuleProxy) {
-			if androidDeviceInfo, ok := OtherModuleProvider(ctx, module, AndroidDeviceInfoProvider); !ok || !androidDeviceInfo.Main_device {
-				return
-			}
-			if metadataInfo, ok := OtherModuleProvider(ctx, module, ComplianceMetadataProvider); ok {
-				if len(metadataInfo.filesContained) > 0 {
-					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(metadataInfo.filesContained)+1)
-					csvContent = append(csvContent, csvHeaders)
-					for _, file := range metadataInfo.filesContained {
-						csvContent = append(csvContent, file+",,Y,,,,,,,")
+			// 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")
 					}
-					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
 				}
-				return
 			}
 		})
 	}
diff --git a/android/config.go b/android/config.go
index 9ccd099..52d7f3b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -22,6 +22,7 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"reflect"
 	"runtime"
 	"strconv"
 	"strings"
@@ -108,6 +109,10 @@
 
 const testKeyDir = "build/make/target/product/security"
 
+func (c Config) genericConfig() Config {
+	return Config{c.config.genericConfig}
+}
+
 // SoongOutDir returns the build output directory for the configuration.
 func (c Config) SoongOutDir() string {
 	return c.soongOutDir
@@ -200,6 +205,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 +243,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 {
@@ -372,7 +377,7 @@
 	// regenerate build.ninja.
 	ninjaFileDepsSet sync.Map
 
-	OncePer
+	*OncePer
 
 	// If buildFromSourceStub is true then the Java API stubs are
 	// built from the source Java files, not the signature text files.
@@ -382,6 +387,17 @@
 	// modules that aren't mixed-built for at least one variant will cause a build
 	// failure
 	ensureAllowlistIntegrity bool
+
+	// If isGeneric is true, this config is the generic config.
+	isGeneric bool
+
+	// InstallPath requires the device name.
+	// This is only for the installPath.
+	deviceNameToInstall *string
+
+	// Copy of this config struct but some product-specific variables are
+	// replaced with the generic configuration values.
+	genericConfig *config
 }
 
 type partialCompileFlags struct {
@@ -639,11 +655,9 @@
 	}
 }
 
-// NewConfig creates a new Config object. The srcDir argument specifies the path
-// to the root source directory. It also loads the config file, if found.
-func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
+func initConfig(cmdArgs CmdArgs, availableEnv map[string]string) (*config, error) {
 	// Make a config with default options.
-	config := &config{
+	newConfig := &config{
 		ProductVariablesFileName: cmdArgs.SoongVariables,
 
 		env: availableEnv,
@@ -657,70 +671,72 @@
 		moduleListFile: cmdArgs.ModuleListFile,
 		fs:             pathtools.NewOsFs(absSrcDir),
 
+		OncePer: &OncePer{},
+
 		buildFromSourceStub: cmdArgs.BuildFromSourceStub,
 	}
 	variant, ok := os.LookupEnv("TARGET_BUILD_VARIANT")
 	isEngBuild := !ok || variant == "eng"
 
-	config.deviceConfig = &deviceConfig{
-		config: config,
+	newConfig.deviceConfig = &deviceConfig{
+		config: newConfig,
 	}
 
 	// Soundness check of the build and source directories. This won't catch strange
 	// configurations with symlinks, but at least checks the obvious case.
 	absBuildDir, err := filepath.Abs(cmdArgs.SoongOutDir)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	absSrcDir, err := filepath.Abs(".")
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	if strings.HasPrefix(absSrcDir, absBuildDir) {
-		return Config{}, fmt.Errorf("Build dir must not contain source directory")
+		return &config{}, fmt.Errorf("Build dir must not contain source directory")
 	}
 
 	// Load any configurable options from the configuration file
-	err = loadConfig(config)
+	err = loadConfig(newConfig)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	KatiEnabledMarkerFile := filepath.Join(cmdArgs.SoongOutDir, ".soong.kati_enabled")
 	if _, err := os.Stat(absolutePath(KatiEnabledMarkerFile)); err == nil {
-		config.katiEnabled = true
+		newConfig.katiEnabled = true
 	}
 
-	determineBuildOS(config)
+	determineBuildOS(newConfig)
 
 	// Sets up the map of target OSes to the finer grained compilation targets
 	// that are configured from the product variables.
-	targets, err := decodeTargetProductVariables(config)
+	targets, err := decodeTargetProductVariables(newConfig)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
-	config.partialCompileFlags, err = config.parsePartialCompileFlags(isEngBuild)
+	newConfig.partialCompileFlags, err = newConfig.parsePartialCompileFlags(isEngBuild)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	// Make the CommonOS OsType available for all products.
 	targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
 
 	var archConfig []archConfig
-	if config.NdkAbis() {
+	if newConfig.NdkAbis() {
 		archConfig = getNdkAbisConfig()
-	} else if config.AmlAbis() {
+	} else if newConfig.AmlAbis() {
 		archConfig = getAmlAbisConfig()
 	}
 
 	if archConfig != nil {
 		androidTargets, err := decodeAndroidArchSettings(archConfig)
 		if err != nil {
-			return Config{}, err
+			return &config{}, err
 		}
 		targets[Android] = androidTargets
 	}
@@ -728,37 +744,113 @@
 	multilib := make(map[string]bool)
 	for _, target := range targets[Android] {
 		if seen := multilib[target.Arch.ArchType.Multilib]; seen {
-			config.multilibConflicts[target.Arch.ArchType] = true
+			newConfig.multilibConflicts[target.Arch.ArchType] = true
 		}
 		multilib[target.Arch.ArchType.Multilib] = true
 	}
 
 	// Map of OS to compilation targets.
-	config.Targets = targets
+	newConfig.Targets = targets
 
 	// Compilation targets for host tools.
-	config.BuildOSTarget = config.Targets[config.BuildOS][0]
-	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
+	newConfig.BuildOSTarget = newConfig.Targets[newConfig.BuildOS][0]
+	newConfig.BuildOSCommonTarget = getCommonTargets(newConfig.Targets[newConfig.BuildOS])[0]
 
 	// Compilation targets for Android.
-	if len(config.Targets[Android]) > 0 {
-		config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
-		config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
+	if len(newConfig.Targets[Android]) > 0 {
+		newConfig.AndroidCommonTarget = getCommonTargets(newConfig.Targets[Android])[0]
+		newConfig.AndroidFirstDeviceTarget = FirstTarget(newConfig.Targets[Android], "lib64", "lib32")[0]
 	}
 
 	setBuildMode := func(arg string, mode SoongBuildMode) {
 		if arg != "" {
-			if config.BuildMode != AnalysisNoBazel {
+			if newConfig.BuildMode != AnalysisNoBazel {
 				fmt.Fprintf(os.Stderr, "buildMode is already set, illegal argument: %s", arg)
 				os.Exit(1)
 			}
-			config.BuildMode = mode
+			newConfig.BuildMode = mode
 		}
 	}
 	setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
 	setBuildMode(cmdArgs.DocFile, GenerateDocFile)
 
-	config.productVariables.Build_from_text_stub = boolPtr(config.BuildFromTextStub())
+	newConfig.productVariables.Build_from_text_stub = boolPtr(newConfig.BuildFromTextStub())
+
+	newConfig.deviceNameToInstall = newConfig.productVariables.DeviceName
+
+	return newConfig, err
+}
+
+// Replace variables in config.productVariables that have tags with "generic" key.
+// A generic tag may have a string or an int value for the generic configuration.
+// If the value is "unset", generic configuration will unset the variable.
+func overrideGenericConfig(config *config) {
+	config.genericConfig.isGeneric = true
+	type_pv := reflect.TypeOf(config.genericConfig.productVariables)
+	value_pv := reflect.ValueOf(&config.genericConfig.productVariables)
+	for i := range type_pv.NumField() {
+		type_pv_field := type_pv.Field(i)
+		generic_value := type_pv_field.Tag.Get("generic")
+		// If a product variable has an annotation of "generic" tag, use the
+		// value of the tag to set the generic variable.
+		if generic_value != "" {
+			value_pv_field := value_pv.Elem().Field(i)
+
+			if generic_value == "unset" {
+				// unset the product variable
+				value_pv_field.SetZero()
+				continue
+			}
+
+			kind_of_type_pv := type_pv_field.Type.Kind()
+			is_pointer := false
+			if kind_of_type_pv == reflect.Pointer {
+				is_pointer = true
+				kind_of_type_pv = type_pv_field.Type.Elem().Kind()
+			}
+
+			switch kind_of_type_pv {
+			case reflect.String:
+				if is_pointer {
+					value_pv_field.Set(reflect.ValueOf(stringPtr(generic_value)))
+				} else {
+					value_pv_field.Set(reflect.ValueOf(generic_value))
+				}
+			case reflect.Int:
+				generic_int, err := strconv.Atoi(generic_value)
+				if err != nil {
+					panic(fmt.Errorf("Only an int value can be assigned to int variable: %s", err))
+				}
+				if is_pointer {
+					value_pv_field.Set(reflect.ValueOf(intPtr(generic_int)))
+				} else {
+					value_pv_field.Set(reflect.ValueOf(generic_int))
+				}
+			default:
+				panic(fmt.Errorf("Unknown type to replace for generic variable: %s", &kind_of_type_pv))
+			}
+		}
+	}
+
+	// OncePer must be a singleton.
+	config.genericConfig.OncePer = config.OncePer
+	// keep the device name to get the install path.
+	config.genericConfig.deviceNameToInstall = config.deviceNameToInstall
+}
+
+// NewConfig creates a new Config object. It also loads the config file, if
+// found. The Config object includes a duplicated Config object in it for the
+// generic configuration that does not provide any product specific information.
+func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
+	config, err := initConfig(cmdArgs, availableEnv)
+	if err != nil {
+		return Config{}, err
+	}
+
+	// Initialize generic configuration.
+	config.genericConfig, err = initConfig(cmdArgs, availableEnv)
+	// Update product specific variables with the generic configuration.
+	overrideGenericConfig(config)
 
 	return Config{config}, err
 }
@@ -946,7 +1038,7 @@
 // require them to run and get the current build fingerprint. This ensures they
 // don't rebuild on every incremental build when the build number changes.
 func (c *config) BuildFingerprintFile(ctx PathContext) Path {
-	return PathForArbitraryOutput(ctx, "target", "product", c.DeviceName(), String(c.productVariables.BuildFingerprintFile))
+	return PathForArbitraryOutput(ctx, "target", "product", *c.deviceNameToInstall, String(c.productVariables.BuildFingerprintFile))
 }
 
 // BuildNumberFile returns the path to a text file containing metadata
@@ -974,7 +1066,7 @@
 // require them to run and get the current build thumbprint. This ensures they
 // don't rebuild on every incremental build when the build thumbprint changes.
 func (c *config) BuildThumbprintFile(ctx PathContext) Path {
-	return PathForArbitraryOutput(ctx, "target", "product", c.DeviceName(), String(c.productVariables.BuildThumbprintFile))
+	return PathForArbitraryOutput(ctx, "target", "product", *c.deviceNameToInstall, String(c.productVariables.BuildThumbprintFile))
 }
 
 // DeviceName returns the name of the current device target.
@@ -1207,6 +1299,10 @@
 	return otaPaths
 }
 
+func (c *config) ExtraOtaRecoveryKeys() []string {
+	return c.productVariables.ExtraOtaRecoveryKeys
+}
+
 func (c *config) BuildKeys() string {
 	defaultCert := String(c.productVariables.DefaultAppCertificate)
 	if defaultCert == "" || defaultCert == filepath.Join(testKeyDir, "testkey") {
diff --git a/android/config_test.go b/android/config_test.go
index d1b26c1..81b7c3e 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -281,3 +281,72 @@
 		})
 	}
 }
+
+type configTestProperties struct {
+	Use_generic_config *bool
+}
+
+type configTestModule struct {
+	ModuleBase
+	properties configTestProperties
+}
+
+func (d *configTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	deviceName := ctx.Config().DeviceName()
+	if ctx.ModuleName() == "foo" {
+		if ctx.Module().UseGenericConfig() {
+			ctx.PropertyErrorf("use_generic_config", "must not be set for this test")
+		}
+	} else if ctx.ModuleName() == "bar" {
+		if !ctx.Module().UseGenericConfig() {
+			ctx.ModuleErrorf("\"use_generic_config: true\" must be set for this test")
+		}
+	}
+
+	if ctx.Module().UseGenericConfig() {
+		if deviceName != "generic" {
+			ctx.ModuleErrorf("Device name for this module must be \"generic\" but %q\n", deviceName)
+		}
+	} else {
+		if deviceName == "generic" {
+			ctx.ModuleErrorf("Device name for this module must not be \"generic\"\n")
+		}
+	}
+}
+
+func configTestModuleFactory() Module {
+	module := &configTestModule{}
+	module.AddProperties(&module.properties)
+	InitAndroidModule(module)
+	return module
+}
+
+var prepareForConfigTest = GroupFixturePreparers(
+	FixtureRegisterWithContext(func(ctx RegistrationContext) {
+		ctx.RegisterModuleType("test", configTestModuleFactory)
+	}),
+)
+
+func TestGenericConfig(t *testing.T) {
+	bp := `
+		test {
+			name: "foo",
+		}
+
+		test {
+			name: "bar",
+			use_generic_config: true,
+		}
+	`
+
+	result := GroupFixturePreparers(
+		prepareForConfigTest,
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
+
+	foo := result.Module("foo", "").(*configTestModule)
+	bar := result.Module("bar", "").(*configTestModule)
+
+	AssertBoolEquals(t, "Do not use generic config", false, foo.UseGenericConfig())
+	AssertBoolEquals(t, "Use generic config", true, bar.UseGenericConfig())
+}
diff --git a/android/configurable_properties.go b/android/configurable_properties.go
index 2c794a1..bde33e9 100644
--- a/android/configurable_properties.go
+++ b/android/configurable_properties.go
@@ -7,7 +7,8 @@
 // to indicate a "default" case.
 func CreateSelectOsToBool(cases map[string]*bool) proptools.Configurable[bool] {
 	var resultCases []proptools.ConfigurableCase[bool]
-	for pattern, value := range cases {
+	for _, pattern := range SortedKeys(cases) {
+		value := cases[pattern]
 		if pattern == "" {
 			resultCases = append(resultCases, proptools.NewConfigurableCase(
 				[]proptools.ConfigurablePattern{proptools.NewDefaultConfigurablePattern()},
diff --git a/android/configured_jars.go b/android/configured_jars.go
index c7b808f..657826e 100644
--- a/android/configured_jars.go
+++ b/android/configured_jars.go
@@ -264,7 +264,7 @@
 			subdir = filepath.Join("apex", apex, "javalib")
 		}
 
-		if ostype.Class == Host {
+		if ostype.Class == Host || cfg.IsEnvTrue("ART_USE_SIMULATOR") {
 			paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
 		} else {
 			paths[i] = filepath.Join("/", subdir, name)
diff --git a/android/container.go b/android/container.go
index a5aab79..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.
@@ -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/early_module_context.go b/android/early_module_context.go
index 8d28285..300edf1 100644
--- a/android/early_module_context.go
+++ b/android/early_module_context.go
@@ -146,6 +146,13 @@
 }
 
 func (e *earlyModuleContext) Config() Config {
+	// Only the system image may use the generic config.
+	// If a module builds multiple image variations, provide the generic config only for the core
+	// variant which is installed in the system partition. Other image variant may still read the
+	// original configurations.
+	if e.Module().base().UseGenericConfig() && e.Module().base().commonProperties.ImageVariation == "" {
+		return e.EarlyModuleContext.Config().(Config).genericConfig()
+	}
 	return e.EarlyModuleContext.Config().(Config)
 }
 
diff --git a/android/gen_notice.go b/android/gen_notice.go
index 482b1e0..45f90f4 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -60,7 +60,7 @@
 		for _, name := range gm.For {
 			mods := ctx.ModuleVariantsFromName(m, name)
 			for _, mod := range mods {
-				if !OtherModuleProviderOrDefault(ctx, mod, CommonModuleInfoKey).Enabled { // 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)
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 55f46ae..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,
diff --git a/android/logtags.go b/android/logtags.go
index 88d36ec..074f402 100644
--- a/android/logtags.go
+++ b/android/logtags.go
@@ -43,7 +43,7 @@
 func (l *logtagsSingleton) GenerateBuildActions(ctx SingletonContext) {
 	var allLogtags Paths
 	ctx.VisitAllModuleProxies(func(module ModuleProxy) {
-		if !OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).ExportedToMake {
+		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 692b27e..7017e7d 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -259,7 +259,7 @@
 	singletonDists.lock.Unlock()
 
 	ctx.VisitAllModuleProxies(func(m ModuleProxy) {
-		commonInfo, _ := OtherModuleProvider(ctx, m, CommonModuleInfoKey)
+		commonInfo := OtherModulePointerProviderOrDefault(ctx, m, CommonModuleInfoProvider)
 		if provider, ok := OtherModuleProvider(ctx, m, ModuleMakeVarsInfoProvider); ok &&
 			commonInfo.Enabled {
 			mctx := &makeVarsContext{
diff --git a/android/module.go b/android/module.go
index a56fea3..c0abfd0 100644
--- a/android/module.go
+++ b/android/module.go
@@ -22,6 +22,7 @@
 	"reflect"
 	"slices"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -44,6 +45,14 @@
 	// For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go
 	GenerateAndroidBuildActions(ModuleContext)
 
+	// CleanupAfterBuildActions is called after ModuleBase.GenerateBuildActions is finished.
+	// If all interactions with this module are handled via providers instead of direct access
+	// to the module then it can free memory attached to the module.
+	// This is a temporary measure to reduce memory usage, eventually blueprint's reference
+	// to the Module should be dropped after GenerateAndroidBuildActions once all accesses
+	// can be done through providers.
+	CleanupAfterBuildActions()
+
 	// Add dependencies to the components of a module, i.e. modules that are created
 	// by the module and which are considered to be part of the creating module.
 	//
@@ -128,6 +137,9 @@
 	// WARNING: This should not be used outside build/soong/fsgen
 	// Overrides returns the list of modules which should not be installed if this module is installed.
 	Overrides() []string
+
+	// If this is true, the module must not read product-specific configurations.
+	UseGenericConfig() bool
 }
 
 // Qualified id for a module
@@ -507,6 +519,10 @@
 	// List of module names that are prevented from being installed when this module gets
 	// installed.
 	Overrides []string
+
+	// Set to true if this module must be generic and does not require product-specific information.
+	// To be included in the system image, this property must be set to true.
+	Use_generic_config *bool
 }
 
 // Properties common to all modules inheriting from ModuleBase. Unlike commonProperties, these
@@ -520,6 +536,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 {
@@ -997,11 +1018,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) {
@@ -1483,7 +1512,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)
 			}
@@ -1500,7 +1529,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.
@@ -1923,7 +1952,7 @@
 	IsPlatform bool
 }
 
-var CommonModuleInfoKey = blueprint.NewProvider[CommonModuleInfo]()
+var CommonModuleInfoProvider = blueprint.NewProvider[*CommonModuleInfo]()
 
 type PrebuiltModuleInfo struct {
 	SourceExists bool
@@ -2331,7 +2360,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(),
@@ -2366,8 +2395,12 @@
 			})
 		}
 	}
+
+	m.module.CleanupAfterBuildActions()
 }
 
+func (m *ModuleBase) CleanupAfterBuildActions() {}
+
 func SetJarJarPrefixHandler(handler func(ModuleContext)) {
 	if jarJarPrefixHandler != nil {
 		panic("jarJarPrefixHandler already set")
@@ -2575,6 +2608,10 @@
 	return m.commonProperties.Overrides
 }
 
+func (m *ModuleBase) UseGenericConfig() bool {
+	return proptools.Bool(m.commonProperties.Use_generic_config)
+}
+
 type ConfigContext interface {
 	Config() Config
 }
@@ -2649,6 +2686,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))
@@ -2673,6 +2712,13 @@
 					return proptools.ConfigurableValueString(v)
 				case "bool":
 					return proptools.ConfigurableValueBool(v == "true")
+				case "int":
+					i, err := strconv.ParseInt(v, 10, 64)
+					if err != nil {
+						ctx.OtherModulePropertyErrorf(m, property, "integer soong_config_variable was not an int: %q", v)
+						return proptools.ConfigurableValueUndefined()
+					}
+					return proptools.ConfigurableValueInt(i)
 				case "string_list":
 					return proptools.ConfigurableValueStringList(strings.Split(v, " "))
 				default:
diff --git a/android/module_proxy.go b/android/module_proxy.go
index 77abc11..81d90e9 100644
--- a/android/module_proxy.go
+++ b/android/module_proxy.go
@@ -27,6 +27,10 @@
 	panic("method is not implemented on ModuleProxy")
 }
 
+func (m ModuleProxy) CleanupAfterBuildActions() {
+	panic("method is not implemented on ModuleProxy")
+}
+
 func (m ModuleProxy) ComponentDepsMutator(ctx BottomUpMutatorContext) {
 	panic("method is not implemented on ModuleProxy")
 }
@@ -231,3 +235,7 @@
 func (m ModuleProxy) VintfFragments(ctx ConfigurableEvaluatorContext) []string {
 	panic("method is not implemented on ModuleProxy")
 }
+
+func (m ModuleProxy) UseGenericConfig() bool {
+	panic("method is not implemented on ModuleProxy")
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 8995a0f..98b443e 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.bin",
+		"trusty_desktop_test_vm_arm64.bin",
+		"trusty_desktop_test_vm_x86_64.bin",
+		"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").
-			// Trusty TEE target names
-			Without("name", "trusty_tee_package_goog").
-			Without("name", "trusty_tee_package").
-			// Trusty vm target names
-			Without("name", "trusty_test_vm_arm64.bin").
-			Without("name", "trusty_test_vm_x86_64.elf").
-			Without("name", "trusty_test_vm_os_arm64.bin").
-			Without("name", "trusty_test_vm_os_x86_64.elf").
-			Without("name", "trusty_security_vm_arm64.bin").
-			Without("name", "trusty_security_vm_x86_64.elf").
-			Without("name", "trusty_widevine_vm_arm64.bin").
-			Without("name", "trusty_widevine_vm_x86_64.elf").
-			WithMatcher("dir_srcs", isSetMatcherInstance).Because(reason),
+			WithoutMatcher("name", InAllowedList(allowedModuleNameList)).
+			WithMatcher("dir_srcs", isSetMatcherInstance).Because(dirSrcsReason),
 		NeverAllow().
 			ModuleType("genrule").
-			// Trusty TEE target names
-			Without("name", "trusty_tee_package_goog").
-			Without("name", "trusty_tee_package").
-			// Trusty vm target names
-			Without("name", "trusty_test_vm_arm64.bin").
-			Without("name", "trusty_test_vm_x86_64.elf").
-			Without("name", "trusty_test_vm_os_arm64.bin").
-			Without("name", "trusty_test_vm_os_x86_64.elf").
-			Without("name", "trusty_security_vm_arm64.bin").
-			Without("name", "trusty_security_vm_x86_64.elf").
-			Without("name", "trusty_widevine_vm_arm64.bin").
-			Without("name", "trusty_widevine_vm_x86_64.elf").
-			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,10 @@
 			"prebuilt_sbin",
 			"prebuilt_system",
 			"prebuilt_first_stage_ramdisk",
+			"prebuilt_radio",
+			"prebuilt_gpu",
+			"prebuilt_vendor_overlay",
+			"prebuilt_tee",
 		).
 		DefinedInBpFile().
 		Because("module type not allowed to be defined in bp file")
@@ -409,7 +420,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/otatools_package_cert_zip.go b/android/otatools_package_cert_zip.go
new file mode 100644
index 0000000..3a654cf
--- /dev/null
+++ b/android/otatools_package_cert_zip.go
@@ -0,0 +1,62 @@
+// 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"
+)
+
+func init() {
+	RegisterOtatoolsPackageBuildComponents(InitRegistrationContext)
+	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
+}
+
+func RegisterOtatoolsPackageBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("otatools_package_cert_files", OtatoolsPackageFactory)
+}
+
+type OtatoolsPackage struct {
+	ModuleBase
+}
+
+func OtatoolsPackageFactory() Module {
+	module := &OtatoolsPackage{}
+	InitAndroidModule(module)
+	return module
+}
+
+var (
+	otatoolsPackageCertRule = pctx.AndroidStaticRule("otatools_package_cert_files", blueprint.RuleParams{
+		Command:     "echo '$out : ' $$(cat $in) > ${out}.d && ${SoongZipCmd} -o $out -l $in",
+		CommandDeps: []string{"${SoongZipCmd}"},
+		Depfile:     "${out}.d",
+		Description: "Zip otatools-package cert files",
+	})
+)
+
+func (fg *OtatoolsPackage) GenerateAndroidBuildActions(ctx ModuleContext) {
+	if ctx.ModuleDir() != "build/make/tools/otatools_package" {
+		ctx.ModuleErrorf("There can only be one otatools_package_cert_files module in build/make/tools/otatools_package")
+		return
+	}
+	fileListFile := PathForArbitraryOutput(ctx, ".module_paths", "OtaToolsCertFiles.list")
+	otatoolsPackageCertZip := PathForModuleOut(ctx, "otatools_package_cert_files.zip")
+	ctx.Build(pctx, BuildParams{
+		Rule:   otatoolsPackageCertRule,
+		Input:  fileListFile,
+		Output: otatoolsPackageCertZip,
+	})
+	ctx.SetOutputFiles([]Path{otatoolsPackageCertZip}, "")
+}
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 42f17b1..52bddf9 100644
--- a/android/package.go
+++ b/android/package.go
@@ -62,7 +62,7 @@
 }
 
 func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
-	ctx.SetProvider(CommonModuleInfoKey, CommonModuleInfo{
+	ctx.SetProvider(CommonModuleInfoProvider, &CommonModuleInfo{
 		Enabled:                 true,
 		PrimaryLicensesProperty: p.primaryLicensesProperty,
 	})
diff --git a/android/packaging.go b/android/packaging.go
index 6146f02..bf18409 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
 }
 
@@ -500,13 +506,11 @@
 	// all packaging specs gathered from the high priority deps.
 	var highPriorities []PackagingSpec
 
-	// Name of the dependency which requested the packaging spec.
-	// If this dep is overridden, the packaging spec will not be installed via this dependency chain.
-	// (the packaging spec might still be installed if there are some other deps which depend on it).
-	var depNames []string
-
 	// list of module names overridden
-	var overridden []string
+	overridden := make(map[string]bool)
+
+	// all installed modules which are not overridden.
+	modulesToInstall := make(map[string]bool)
 
 	var arches []ArchType
 	for _, target := range getSupportedTargets(ctx) {
@@ -523,6 +527,7 @@
 		return false
 	}
 
+	// find all overridden modules and packaging specs
 	ctx.VisitDirectDepsProxy(func(child ModuleProxy) {
 		depTag := ctx.OtherModuleDependencyTag(child)
 		if pi, ok := depTag.(PackagingItem); !ok || !pi.IsPackagingItem() {
@@ -550,20 +555,32 @@
 				regularPriorities = append(regularPriorities, ps)
 			}
 
-			depNames = append(depNames, child.Name())
-			overridden = append(overridden, ps.overrides.ToSlice()...)
+			for o := range ps.overrides.Iter() {
+				overridden[o] = true
+			}
 		}
 	})
 
-	filterOverridden := func(input []PackagingSpec) []PackagingSpec {
-		// input minus packaging specs that are overridden
-		var filtered []PackagingSpec
-		for index, ps := range input {
-			if ps.owner != "" && InList(ps.owner, overridden) {
-				continue
+	// gather modules to install, skipping overridden modules
+	ctx.WalkDeps(func(child, parent Module) bool {
+		owner := ctx.OtherModuleName(child)
+		if o, ok := child.(OverridableModule); ok {
+			if overriddenBy := o.GetOverriddenBy(); overriddenBy != "" {
+				owner = overriddenBy
 			}
-			// The dependency which requested this packaging spec has been overridden.
-			if InList(depNames[index], overridden) {
+		}
+		if overridden[owner] {
+			return false
+		}
+		modulesToInstall[owner] = true
+		return true
+	})
+
+	filterOverridden := func(input []PackagingSpec) []PackagingSpec {
+		// input minus packaging specs that are not installed
+		var filtered []PackagingSpec
+		for _, ps := range input {
+			if !modulesToInstall[ps.owner] {
 				continue
 			}
 			filtered = append(filtered, ps)
diff --git a/android/paths.go b/android/paths.go
index 9c0c9a2..6612d37 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -683,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}}
 	}
 
@@ -2054,7 +2054,7 @@
 	var partitionPaths []string
 
 	if os.Class == Device {
-		partitionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
+		partitionPaths = []string{"target", "product", *ctx.Config().deviceNameToInstall, partition}
 	} else {
 		osName := os.String()
 		if os == Linux {
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 4a94c0b..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 {
@@ -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/provider.go b/android/provider.go
index d005daf..aae93ef 100644
--- a/android/provider.go
+++ b/android/provider.go
@@ -41,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/selects_test.go b/android/selects_test.go
index 7f20a3d..8e469f8 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -666,6 +666,81 @@
 			},
 		},
 		{
+			name: "Select on integer soong config variable",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					34: "34",
+					default: "other",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "34",
+				},
+			},
+			vendorVarTypes: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "int",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("34"),
+			},
+		},
+		{
+			name: "Select on integer soong config variable default",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					34: "34",
+					default: "other",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "5",
+				},
+			},
+			vendorVarTypes: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "int",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("other"),
+			},
+		},
+		{
+			name: "Assign to integer property",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_int64: select(soong_config_variable("my_namespace", "my_variable"), {
+					any @ val: val,
+					default: "other",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "5",
+				},
+			},
+			vendorVarTypes: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "int",
+				},
+			},
+			provider: selectsTestProvider{
+				my_int64: proptools.Int64Ptr(5),
+			},
+		},
+		{
 			name: "Mismatched condition types",
 			bp: `
 			my_module_type {
@@ -1132,6 +1207,7 @@
 type selectsTestProvider struct {
 	my_bool                        *bool
 	my_string                      *string
+	my_int64                       *int64
 	my_string_list                 *[]string
 	my_paths                       *[]string
 	replacing_string_list          *[]string
@@ -1181,6 +1257,7 @@
 
 type selectsMockModuleProperties struct {
 	My_bool                        proptools.Configurable[bool]
+	My_int64                       proptools.Configurable[int64]
 	My_string                      proptools.Configurable[string]
 	My_string_list                 proptools.Configurable[[]string]
 	My_paths                       proptools.Configurable[[]string] `android:"path"`
@@ -1213,6 +1290,7 @@
 	SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{
 		my_bool:                        optionalToPtr(p.properties.My_bool.Get(ctx)),
 		my_string:                      optionalToPtr(p.properties.My_string.Get(ctx)),
+		my_int64:                       optionalToPtr(p.properties.My_int64.Get(ctx)),
 		my_string_list:                 optionalToPtr(p.properties.My_string_list.Get(ctx)),
 		my_paths:                       optionalToPtr(p.properties.My_paths.Get(ctx)),
 		replacing_string_list:          optionalToPtr(p.properties.Replacing_string_list.Get(ctx)),
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/test_config.go b/android/test_config.go
index 3609e6b..5d79df0 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -23,8 +23,7 @@
 	"github.com/google/blueprint/proptools"
 )
 
-// TestConfig returns a Config object for testing.
-func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+func initTestConfig(buildDir string, env map[string]string) *config {
 	envCopy := make(map[string]string)
 	for k, v := range env {
 		envCopy[k] = v
@@ -58,6 +57,7 @@
 		soongOutDir:  filepath.Join(buildDir, "soong"),
 		captureBuild: true,
 		env:          envCopy,
+		OncePer:      &OncePer{},
 
 		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
 		// passed to PathForSource or PathForModuleSrc.
@@ -69,10 +69,21 @@
 		config: config,
 	}
 	config.TestProductVariables = &config.productVariables
+	config.deviceNameToInstall = config.TestProductVariables.DeviceName
+
+	determineBuildOS(config)
+
+	return config
+}
+
+// TestConfig returns a Config object for testing.
+func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+	config := initTestConfig(buildDir, env)
 
 	config.mockFileSystem(bp, fs)
 
-	determineBuildOS(config)
+	config.genericConfig = initTestConfig(buildDir, env)
+	overrideGenericConfig(config)
 
 	return Config{config}
 }
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/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 5bc0b29..5980efd 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"`
@@ -230,8 +225,8 @@
 	Platform_version_last_stable           *string  `json:",omitempty"`
 	Platform_version_known_codenames       *string  `json:",omitempty"`
 
-	DeviceName                            *string  `json:",omitempty"`
-	DeviceProduct                         *string  `json:",omitempty"`
+	DeviceName                            *string  `json:",omitempty" generic:"generic"`
+	DeviceProduct                         *string  `json:",omitempty" generic:"generic"`
 	DeviceArch                            *string  `json:",omitempty"`
 	DeviceArchVariant                     *string  `json:",omitempty"`
 	DeviceCpuVariant                      *string  `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"`
@@ -717,6 +715,10 @@
 
 	ReleaseToolsExtensionDir string `json:",omitempty"`
 
+	BoardPartialOtaUpdatePartitionsList []string `json:",omitempty"`
+	BoardFlashBlockSize                 string   `json:",omitempty"`
+	BootloaderInUpdatePackage           bool     `json:",omitempty"`
+
 	BoardFastbootInfoFile string `json:",omitempty"`
 }
 
diff --git a/android/visibility.go b/android/visibility.go
index 416a3f1..9153687 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -551,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())
 		}
 	})
 }
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 3a81ee4..0a5644a 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -75,7 +75,7 @@
 // populated by Soong for unconverted APEXes, or Bazel in mixed mode. Use
 // apexFile#isBazelPrebuilt to differentiate.
 func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir string,
-	apexAndroidMkData android.AndroidMkData) []string {
+	apexAndroidMkData android.AndroidMkData) (archSpecificModuleNames []string, moduleNames []string) {
 
 	// apexBundleName comes from the 'name' property or soong module.
 	// apexName comes from 'name' property of apex_manifest.
@@ -84,11 +84,12 @@
 	// However, symbol files for apex files are installed under /apex/<apexBundleName> to avoid
 	// conflicts between two apexes with the same apexName.
 
-	moduleNames := []string{}
-
 	for _, fi := range a.filesInfo {
 		linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
 		moduleName := a.fullModuleName(apexBundleName, linkToSystemLib, &fi)
+		if !android.InList(moduleName, moduleNames) {
+			moduleNames = append(moduleNames, moduleName)
+		}
 
 		// This name will be added to LOCAL_REQUIRED_MODULES of the APEX. We need to be
 		// arch-specific otherwise we will end up installing both ABIs even when only
@@ -100,8 +101,8 @@
 		case "lib64":
 			aName = aName + ":64"
 		}
-		if !android.InList(aName, moduleNames) {
-			moduleNames = append(moduleNames, aName)
+		if !android.InList(aName, archSpecificModuleNames) {
+			archSpecificModuleNames = append(archSpecificModuleNames, aName)
 		}
 
 		if linkToSystemLib {
@@ -216,7 +217,7 @@
 			fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
 		}
 	}
-	return moduleNames
+	return
 }
 
 func (a *apexBundle) writeRequiredModules(w io.Writer, moduleNames []string) {
@@ -235,9 +236,10 @@
 	return android.AndroidMkData{
 		// While we do not provide a value for `Extra`, AconfigUpdateAndroidMkData may add some, which we must honor.
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			archSpecificModuleNames := []string{}
 			moduleNames := []string{}
 			if a.installable() {
-				moduleNames = a.androidMkForFiles(w, name, moduleDir, data)
+				archSpecificModuleNames, moduleNames = a.androidMkForFiles(w, name, moduleDir, data)
 			}
 
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)  # apex.apexBundle")
@@ -274,7 +276,7 @@
 			}
 
 			android.AndroidMkEmitAssignList(w, "LOCAL_OVERRIDES_MODULES", a.overridableProperties.Overrides)
-			a.writeRequiredModules(w, moduleNames)
+			a.writeRequiredModules(w, archSpecificModuleNames)
 			// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
 			for _, extra := range data.Extra {
 				extra(w, a.outputFile)
@@ -296,6 +298,9 @@
 				fmt.Fprintln(w, dist)
 			}
 
+			fmt.Fprintf(w, "ALL_MODULES.$(my_register_name).SYMBOLIC_OUTPUT_PATH := $(foreach m,%s,$(ALL_MODULES.$(m).SYMBOLIC_OUTPUT_PATH))\n", strings.Join(moduleNames, " "))
+			fmt.Fprintf(w, "ALL_MODULES.$(my_register_name).ELF_SYMBOL_MAPPING_PATH := $(foreach m,%s,$(ALL_MODULES.$(m).ELF_SYMBOL_MAPPING_PATH))\n", strings.Join(moduleNames, " "))
+
 			distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
 			distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String())
 			distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String())
diff --git a/apex/apex.go b/apex/apex.go
index 38ab012..a726098 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -569,19 +569,6 @@
 	shBinary
 )
 
-var (
-	classes = map[string]apexFileClass{
-		"app":              app,
-		"appSet":           appSet,
-		"etc":              etc,
-		"javaSharedLib":    javaSharedLib,
-		"nativeExecutable": nativeExecutable,
-		"nativeSharedLib":  nativeSharedLib,
-		"nativeTest":       nativeTest,
-		"shBinary":         shBinary,
-	}
-)
-
 // apexFile represents a file in an APEX bundle. This is created during the first half of
 // GenerateAndroidBuildActions by traversing the dependencies of the APEX. Then in the second half
 // of the function, this is used to create commands that copies the files into a staging directory,
@@ -1502,7 +1489,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 {
@@ -1607,35 +1594,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
@@ -1848,7 +1808,7 @@
 	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
 	}
@@ -1866,7 +1826,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:
@@ -1883,11 +1843,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",
@@ -1895,7 +1855,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)
 			}
@@ -1949,7 +1909,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
 					}
@@ -1996,8 +1956,12 @@
 			}
 		case testTag:
 			if ccInfo, ok := android.OtherModuleProvider(ctx, child, cc.CcInfoProvider); ok {
-				af := apexFileForExecutable(ctx, child, &commonInfo, ccInfo)
-				af.class = nativeTest
+				af := apexFileForExecutable(ctx, child, commonInfo, ccInfo)
+				// We make this a nativeExecutable instead of a nativeTest because we don't want
+				// the androidmk modules generated in AndroidMkForFiles to be treated as real
+				// tests that are then packaged into suites. Our AndroidMkForFiles does not
+				// implement enough functionality to support real tests.
+				af.class = nativeExecutable
 				vctx.filesInfo = append(vctx.filesInfo, af)
 				return true // track transitive dependencies
 			} else {
@@ -2033,7 +1997,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 {
@@ -2095,7 +2059,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
@@ -2127,7 +2091,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
@@ -2143,7 +2107,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)
 		}
 	}
@@ -2557,7 +2521,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.
@@ -2671,7 +2635,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
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index dabec49..797f47b 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -164,7 +164,7 @@
 		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 && !android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoKey).HideFromMake {
+		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 36a6974..327e018 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -11468,6 +11468,16 @@
 		// 1. The contents of the selected apex_contributions are visible to make
 		// 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make
 		checkHideFromMake(t, ctx, tc.expectedVisibleModuleName, tc.expectedHiddenModuleNames)
+
+		// Check that source_apex_name is written as LOCAL_MODULE for make packaging
+		if tc.expectedVisibleModuleName == "prebuilt_com.google.android.foo.v2" {
+			apex := ctx.ModuleForTests(t, "prebuilt_com.google.android.foo.v2", "android_common_prebuilt_com.android.foo").Module()
+			entries := android.AndroidMkEntriesForTest(t, ctx, apex)[0]
+
+			expected := "com.google.android.foo"
+			actual := entries.EntryMap["LOCAL_MODULE"][0]
+			android.AssertStringEquals(t, "LOCAL_MODULE", expected, actual)
+		}
 	}
 }
 
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/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/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 4da1103..c616165 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -81,12 +81,13 @@
 	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{}
@@ -96,6 +97,7 @@
 	// 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 {
@@ -120,6 +122,10 @@
 	NdkSysrootPath android.Path
 }
 
+type PrebuiltLibraryLinkerInfo struct {
+	VndkFileName string
+}
+
 type LibraryInfo struct {
 	BuildStubs bool
 }
@@ -128,6 +134,13 @@
 	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
@@ -148,6 +161,7 @@
 	StaticExecutable     bool
 	Static               bool
 	Shared               bool
+	Header               bool
 	HasStubsVariants     bool
 	StubsVersion         string
 	IsStubs              bool
@@ -195,7 +209,11 @@
 	APIListCoverageXMLPath android.ModuleOutPath
 	// FuzzSharedLibraries returns the shared library dependencies for this module.
 	// Expects that IsFuzzModule returns true.
-	FuzzSharedLibraries android.RuleBuilderInstalls
+	FuzzSharedLibraries      android.RuleBuilderInstalls
+	IsVndkPrebuiltLibrary    bool
+	HasLLNDKStubs            bool
+	IsLLNDKMovedToApex       bool
+	ImplementationModuleName string
 }
 
 var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]()
@@ -779,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.
@@ -2356,9 +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),
-				NdkSysrootPath: c.linker.(*libraryDecorator).ndkSysrootPath,
+				InjectBsslHash: Bool(lk.Properties.Inject_bssl_hash),
+				NdkSysrootPath: lk.ndkSysrootPath,
+				VndkFileName:   lk.getLibNameHelper(c.BaseModuleName(), true, false) + ".so",
 			}
 		case *testBinary:
 			ccInfo.LinkerInfo.TestBinaryInfo = &TestBinaryInfo{
@@ -2372,6 +2394,11 @@
 			}
 		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 {
@@ -2383,6 +2410,8 @@
 			name := v.ImplementationModuleName(ctx.OtherModuleName(c))
 			ccInfo.LinkerInfo.ImplementationModuleName = &name
 		}
+
+		c.linker.testSuiteInfo(ctx)
 	}
 	if c.library != nil {
 		ccInfo.LibraryInfo = &LibraryInfo{
@@ -2409,6 +2438,27 @@
 	}
 }
 
+func (c *Module) CleanupAfterBuildActions() {
+	// Clear as much of Module as possible to reduce memory usage.
+	c.generators = nil
+	c.compiler = nil
+	c.installer = nil
+	c.features = nil
+	c.coverage = nil
+	c.fuzzer = nil
+	c.sabi = nil
+	c.lto = nil
+	c.afdo = nil
+	c.orderfile = nil
+
+	// TODO: these can be cleared after nativeBinaryInfoProperties and nativeLibInfoProperties are switched to
+	//  using providers.
+	// c.linker = nil
+	// c.stl = nil
+	// c.sanitize = nil
+	// c.library = nil
+}
+
 func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableInterface) *LinkableInfo {
 	info := &LinkableInfo{
 		StaticExecutable:     mod.StaticExecutable(),
@@ -2441,12 +2491,17 @@
 		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() {
@@ -3388,7 +3443,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
@@ -3642,7 +3697,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(
@@ -3669,7 +3724,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())
@@ -3745,7 +3800,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/compdb.go b/cc/compdb.go
index 4132e09..3818e9c 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -193,7 +193,7 @@
 			}
 			builds[src.String()] = compDbEntry{
 				Directory: android.AbsSrcDirForExistingUseCases(),
-				Arguments: getArguments(src, ctx, ccModule, ccPath, cxxPath),
+				Arguments: args,
 				File:      src.String(),
 			}
 		}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 0dcf2cf..25edb79 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",
 		},
@@ -53,6 +53,16 @@
 			"-mbranch-protection=standard",
 			"-fno-stack-protector",
 		},
+		"armv9-3a": []string{
+			"-march=armv9.3-a",
+			"-mbranch-protection=standard",
+			"-fno-stack-protector",
+		},
+		"armv9-4a": []string{
+			"-march=armv9.4-a",
+			"-mbranch-protection=standard",
+			"-fno-stack-protector",
+		},
 	}
 
 	arm64Ldflags = []string{
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/fdo_profile.go b/cc/fdo_profile.go
index 1a33957..c79ea10 100644
--- a/cc/fdo_profile.go
+++ b/cc/fdo_profile.go
@@ -17,6 +17,8 @@
 import (
 	"android/soong/android"
 	"github.com/google/blueprint"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -34,7 +36,7 @@
 }
 
 type fdoProfileProperties struct {
-	Profile *string `android:"arch_variant"`
+	Profile proptools.Configurable[string] `android:"arch_variant,replace_instead_of_append"`
 }
 
 // FdoProfileInfo is provided by FdoProfileProvider
@@ -47,8 +49,9 @@
 
 // GenerateAndroidBuildActions of fdo_profile does not have any build actions
 func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if fp.properties.Profile != nil {
-		path := android.PathForModuleSrc(ctx, *fp.properties.Profile)
+	profile := fp.properties.Profile.GetOrDefault(ctx, "")
+	if profile != "" {
+		path := android.PathForModuleSrc(ctx, profile)
 		android.SetProvider(ctx, FdoProfileProvider, FdoProfileInfo{
 			Path: path,
 		})
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 325354b..79874fc 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -486,7 +486,7 @@
 			sharedLibsInstallDirPrefix = "lib/vendor"
 		}
 
-		commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey)
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider)
 		isHost := commonInfo.Target.Os.Class == android.Host
 		hostOrTargetString := "target"
 		if commonInfo.Target.HostCross {
diff --git a/cc/library.go b/cc/library.go
index b248224..5299771 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1078,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 {
 
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index d1440ea..4629030 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -573,9 +573,8 @@
 
 func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path {
 	var path android.Path
-	outputFile := ccModule.OutputFile()
-	if outputFile.Valid() {
-		path = outputFile.Path()
+	if info, ok := android.OtherModuleProvider(ctx.SdkModuleContext(), ccModule, LinkableInfoProvider); ok && info.OutputFile.Valid() {
+		path = info.OutputFile.Path()
 	} else {
 		ctx.SdkModuleContext().ModuleErrorf("member variant %s does not have a valid output file", ccModule)
 	}
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 a9f26a4..b96a779 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -40,7 +40,7 @@
 func (n *ndkAbiDumpSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var depPaths android.Paths
 	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
-		if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
@@ -78,7 +78,7 @@
 func (n *ndkAbiDiffSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var depPaths android.Paths
 	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
-		if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 34f6195..1677862 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -212,7 +212,7 @@
 	var licensePaths android.Paths
 	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
 
-		if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
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 db99a53..f0b0308 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -79,7 +79,7 @@
 
 	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
 		"-fno-sanitize-recover=integer,undefined"}
-	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
+	memtagStackCommonFlags = []string{"-Xclang -target-feature -Xclang +mte"}
 	memtagStackLlvmFlags   = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
 
 	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
@@ -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 8b68c55..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()...)
 }
@@ -578,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()...)
 }
@@ -695,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 8e7f899..bf273e9 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -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)
diff --git a/ci_tests/ci_test_package_zip.go b/ci_tests/ci_test_package_zip.go
index 451dac4..d7aaa66 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")
 	}
@@ -166,6 +170,9 @@
 	builder.Command().Text("mkdir").Flag("-p").Output(stagingDir)
 	builder.Temporary(stagingDir)
 	ctx.WalkDeps(func(child, parent android.Module) bool {
+		if !child.Enabled(ctx) {
+			return false
+		}
 		if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == testPackageZipDepTag {
 			// handle direct deps
 			extendBuilderCommand(ctx, child, builder, stagingDir, productOut, arch, secondArch)
@@ -214,7 +221,13 @@
 		ctx.ModuleErrorf("Module %s doesn't set InstallFilesProvider", m.Name())
 	}
 
-	for _, installedFile := range installedFilesInfo.InstallFiles {
+	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"
@@ -253,7 +266,9 @@
 
 		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)
+		// 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)
 	}
 }
@@ -269,6 +284,10 @@
 		android.AndroidMkEntries{
 			Class:      "ETC",
 			OutputFile: android.OptionalPathForPath(p.output),
+			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+					entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+				}},
 		},
 	}
 }
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
index bf4f866..0f88159 100644
--- a/cmd/find_input_delta/find_input_delta_lib/internal_state.go
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
@@ -95,9 +95,14 @@
 	}
 	ret := []*fid_proto.PartialCompileInput{}
 	for _, v := range rc.File {
+		// Only include timestamp when there is no CRC.
+		timeNsec := proto.Int64(v.ModTime().UnixNano())
+		if v.CRC32 != 0 {
+			timeNsec = nil
+		}
 		pci := &fid_proto.PartialCompileInput{
 			Name:      proto.String(v.Name),
-			MtimeNsec: proto.Int64(v.ModTime().UnixNano()),
+			MtimeNsec: timeNsec,
 			Hash:      proto.String(fmt.Sprintf("%08x", v.CRC32)),
 		}
 		ret = append(ret, pci)
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
index b0f8cb7..dd98bca 100644
--- a/cmd/release_config/release_config_lib/release_configs.go
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -314,6 +314,9 @@
 				}
 			}
 		}
+		if flagDeclaration.Namespace == nil {
+			return fmt.Errorf("Flag declaration %s has no namespace.", path)
+		}
 
 		m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
 		name := *flagDeclaration.Name
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 4f6de82..584cc04 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -333,7 +333,7 @@
 
 	varName := flags.Arg(0)
 	if varName == "report_config" {
-		varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
+		varData, err := build.DumpMakeVars(ctx, config, nil, append(build.BannerVars, "PRODUCT_SOONG_ONLY"))
 		if err != nil {
 			ctx.Fatal(err)
 		}
@@ -400,7 +400,7 @@
 
 	if i := indexList("report_config", allVars); i != -1 {
 		allVars = append(allVars[:i], allVars[i+1:]...)
-		allVars = append(allVars, build.BannerVars...)
+		allVars = append(allVars, append(build.BannerVars, "PRODUCT_SOONG_ONLY")...)
 	}
 
 	if len(allVars) == 0 {
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 f3c2b2c..af09dbc 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -139,6 +139,11 @@
 
 // Returns all jars that system_server loads.
 func (g *GlobalConfig) AllSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
+	// dexpreopt does not initialize the soong config.
+	// Initialize the OncePer here.
+	if ctx.Config().OncePer == nil {
+		ctx.Config().OncePer = &android.OncePer{}
+	}
 	return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
 		res := g.AllPlatformSystemServerJars(ctx).AppendList(g.AllApexSystemServerJars(ctx))
 		return &res
@@ -464,8 +469,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
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index fad8f07..7820047 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,15 @@
 	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_tee", PrebuiltTeeFactory)
 	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 +91,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 +118,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 +156,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 +205,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 +397,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 +625,7 @@
 	p.AddProperties(&p.properties)
 	p.AddProperties(&p.subdirProperties)
 	p.AddProperties(&p.rootProperties)
+	p.AddProperties(&p.dstsProperties)
 }
 
 func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -621,6 +637,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 +681,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 +862,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.
@@ -871,6 +911,16 @@
 	return module
 }
 
+// prebuilt_tee installs files in <partition>/tee directory.
+func PrebuiltTeeFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "tee")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_media installs media files in <partition>/media directory.
 func PrebuiltMediaFactory() android.Module {
 	module := &PrebuiltEtc{}
@@ -921,6 +971,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 +1091,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/android_device.go b/filesystem/android_device.go
index b1f668d..b96c5ea 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -90,6 +90,10 @@
 	Releasetools_extension *string `android:"path"`
 	FastbootInfo           *string `android:"path"`
 
+	Partial_ota_update_partitions []string
+	Flash_block_size              *string
+	Bootloader_in_update_package  *bool
+
 	// 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
@@ -191,7 +195,7 @@
 	allInstalledModules := a.allInstalledModules(ctx)
 
 	a.apkCertsInfo = a.buildApkCertsInfo(ctx, allInstalledModules)
-	a.kernelConfig, a.kernelVersion = a.extractKernelVersionAndConfigs(ctx)
+	a.kernelVersion, a.kernelConfig = a.extractKernelVersionAndConfigs(ctx)
 	a.miscInfo = a.addMiscInfo(ctx)
 	a.buildTargetFilesZip(ctx, allInstalledModules)
 	a.buildProguardZips(ctx, allInstalledModules)
@@ -294,18 +298,26 @@
 }
 
 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()...)
 			}
 		})
 	}
-	sort.Strings(filesContained)
-
+	// 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
@@ -383,6 +395,13 @@
 		if a.deviceProps.Android_info != nil {
 			ctx.DistForGoal("droidcore-unbundled", android.PathForModuleSrc(ctx, *a.deviceProps.Android_info))
 		}
+		if a.miscInfo != nil {
+			ctx.DistForGoal("droidcore-unbundled", a.miscInfo)
+			if a.partitionProps.Super_partition_name != nil {
+				ctx.DistForGoalWithFilename("dist_files", a.miscInfo, "super_misc_info.txt")
+			}
+		}
+
 	}
 }
 
@@ -615,6 +634,10 @@
 					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())
 		}
@@ -673,7 +696,13 @@
 		}
 		if partition == "vendor_ramdisk" {
 			// Create vendor_boot_filesystem_config from the assembled VENDOR_BOOT/RAMDISK intermediates directory
-			a.generateFilesystemConfigForTargetFiles(ctx, builder, nil, targetFilesDir.String(), targetFilesDir.String()+"/VENDOR_BOOT/RAMDISK", "vendor_boot_filesystem_config.txt")
+			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
@@ -730,26 +759,91 @@
 
 }
 
+var (
+	// https://cs.android.com/android/_/android/platform/build/+/30f05352c3e6f4333c77d4af66c253572d3ea6c9:core/Makefile;l=2111-2120;drc=519f75666431ee2926e0ec8991c682b28a4c9521;bpv=1;bpt=0
+	defaultTargetRecoveryFstypeMountOptions = "ext4=max_batch_time=0,commit=1,data=ordered,barrier=1,errors=panic,nodelalloc"
+)
+
 // 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 {
+	buildType := func() string {
+		if ctx.Config().Debuggable() {
+			return "userdebug"
+		} else if ctx.Config().Eng() {
+			return "eng"
+		} else {
+			return "user"
+		}
+	}
+	defaultAppCertificate := func() string {
+		pem, _ := ctx.Config().DefaultAppCertificate(ctx)
+		return strings.TrimSuffix(pem.String(), ".x509.pem")
+	}
+
 	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).
+		Textf("&& echo build_type=%s >> %s", buildType(), miscInfo).
+		Textf("&& echo default_system_dev_certificate=%s >> %s", defaultAppCertificate(), miscInfo).
+		Textf("&& echo root_dir=%s >> %s", android.PathForModuleInPartitionInstall(ctx, "root"), miscInfo).
 		ImplicitOutput(miscInfo)
+	if len(ctx.Config().ExtraOtaRecoveryKeys()) > 0 {
+		builder.Command().Textf(`echo "extra_recovery_keys=%s" >> %s`, strings.Join(ctx.Config().ExtraOtaRecoveryKeys(), ""), miscInfo)
+	} else {
+		if a.partitionProps.Boot_partition_name != nil {
+			builder.Command().
+				Textf("echo mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo).
+				// TODO: Use boot's header version for recovery for now since cuttlefish does not set `BOARD_RECOVERY_MKBOOTIMG_ARGS`
+				Textf(" && echo recovery_mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo)
+		}
+		if a.partitionProps.Init_boot_partition_name != nil {
+			builder.Command().
+				Textf("echo mkbootimg_init_args='--header_version' %s >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Init_boot_partition_name), miscInfo)
+		}
+		builder.Command().
+			Textf("echo mkbootimg_version_args='--os_version %s --os_patch_level %s' >> %s", ctx.Config().PlatformVersionLastStable(), ctx.Config().PlatformSecurityPatch(), miscInfo).
+			Textf(" && echo multistage_support=1 >> %s", miscInfo).
+			Textf(" && echo blockimgdiff_versions=3,4 >> %s", miscInfo)
+	}
+	fsInfos := a.getFsInfos(ctx)
+	if _, ok := fsInfos["vendor"]; ok {
+		builder.Command().Textf("echo board_uses_vendorimage=true >> %s", miscInfo)
+	}
+	if fsInfos["system"].ErofsCompressHints != nil {
+		builder.Command().Textf("echo erofs_default_compress_hints=%s >> %s", fsInfos["system"].ErofsCompressHints, miscInfo)
+	}
+	if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil {
+		builder.Command().Textf("echo tool_extensions=%s >> %s", filepath.Dir(releaseTools.String()), miscInfo)
+	}
+	// ramdisk uses `compressed_cpio` fs_type
+	// https://cs.android.com/android/_/android/platform/build/+/30f05352c3e6f4333c77d4af66c253572d3ea6c9:core/Makefile;l=5923-5925;drc=519f75666431ee2926e0ec8991c682b28a4c9521;bpv=1;bpt=0
+	if _, ok := fsInfos["ramdisk"]; ok {
+		builder.Command().Textf("echo lz4_ramdisks=true >> %s", miscInfo)
+	}
+	// recovery_mount_options
+	// TODO: Add support for TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS which can be used to override the default
+	builder.Command().Textf("echo recovery_mount_options=%s >> %s", defaultTargetRecoveryFstypeMountOptions, miscInfo)
+
+	// vintf information
+	if proptools.Bool(ctx.Config().ProductVariables().Enforce_vintf_manifest) {
+		builder.Command().Textf("echo vintf_enforce=true >> %s", miscInfo)
+	}
+	if len(ctx.Config().DeviceManifestFiles()) > 0 {
+		builder.Command().Textf("echo vintf_include_empty_vendor_sku=true >> %s", 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 fsInfos[partition].PropFileForMiscInfo != nil {
+			builder.Command().Text("cat").Input(fsInfos[partition].PropFileForMiscInfo).Textf(" >> %s", miscInfo)
 		}
 	}
 	if len(a.partitionProps.Vbmeta_partitions) > 0 {
@@ -757,16 +851,82 @@
 			Textf("echo avb_enable=true >> %s", miscInfo).
 			Textf("&& echo avb_building_vbmeta_image=true >> %s", miscInfo).
 			Textf("&& echo avb_avbtool=avbtool >> %s", miscInfo)
+
+		var allChainedVbmetaPartitionTypes []string
+		for _, vbmetaPartitionName := range a.partitionProps.Vbmeta_partitions {
+			img := ctx.GetDirectDepProxyWithTag(vbmetaPartitionName, filesystemDepTag)
+			if provider, ok := android.OtherModuleProvider(ctx, img, vbmetaPartitionProvider); ok {
+				builder.Command().Text("cat").Input(provider.PropFileForMiscInfo).Textf(" >> %s", miscInfo)
+				if provider.FilesystemPartitionType != "" { // the top-level vbmeta.img
+					allChainedVbmetaPartitionTypes = append(allChainedVbmetaPartitionTypes, provider.FilesystemPartitionType)
+				}
+			} else {
+				ctx.ModuleErrorf("vbmeta dep %s does not set vbmetaPartitionProvider\n", vbmetaPartitionName)
+			}
+		}
+		// Determine the custom vbmeta partitions by removing system and vendor
+		customVbmetaPartitionTypes := android.RemoveListFromList(allChainedVbmetaPartitionTypes, []string{"system", "vendor"})
+		builder.Command().Textf("echo avb_custom_vbmeta_images_partition_list=%s >> %s",
+			strings.Join(android.SortedUniqueStrings(customVbmetaPartitionTypes), " "),
+			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)
+			if info.AbUpdate {
+				builder.Command().Textf("echo ab_update=true >> %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.Command().Textf("echo blocksize=%s >> %s", proptools.String(a.deviceProps.Flash_block_size), miscInfo)
+	if proptools.Bool(a.deviceProps.Bootloader_in_update_package) {
+		builder.Command().Textf("echo bootloader_in_update_package=true >> %s", miscInfo)
+	}
+	if len(a.deviceProps.Partial_ota_update_partitions) > 0 {
+		builder.Command().Textf("echo partial_ota_update_partitions_list=%s >> %s", strings.Join(a.deviceProps.Partial_ota_update_partitions, " "), miscInfo)
+	}
+
+	// Sort and dedup
+	builder.Command().Textf("sort -u %s -o %s", miscInfo, miscInfo)
+
 	builder.Build("misc_info", "Building misc_info")
 
 	return miscInfo
 }
 
+func (a *androidDevice) getBootimgHeaderVersion(ctx android.ModuleContext, bootImgName *string) string {
+	bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(bootImgName), filesystemDepTag)
+	bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
+	return bootImgInfo.HeaderVersion
+}
+
 // addImgToTargetFiles invokes `add_img_to_target_files` and creates the following files in META/
 // - apex_info.pb
 // - care_map.pb
@@ -881,11 +1041,12 @@
 		Flag("--tools lz4:"+lz4tool.String()).Implicit(lz4tool).
 		FlagWithInput("--input ", kernel).
 		FlagWithOutput("--output-release ", extractedVersionFile).
-		FlagWithOutput("--output-configs ", extractedConfigsFile)
+		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.WriteFileRuleVerbatim(ctx, specifiedVersionFile, specifiedVersion)
+		android.WriteFileRule(ctx, specifiedVersionFile, specifiedVersion)
 		builder.Command().Text("diff -q").
 			Input(specifiedVersionFile).
 			Input(extractedVersionFile).
@@ -924,18 +1085,25 @@
 	}
 
 	apkCerts := []string{}
+	var apkCertsFiles android.Paths
 	for _, installedModule := range allInstalledModules {
 		partition := ""
-		if commonInfo, ok := android.OtherModuleProvider(ctx, installedModule, android.CommonModuleInfoKey); ok {
+		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))
+			if info.AppSet {
+				apkCertsFiles = append(apkCertsFiles, info.ApkCertsFile)
+			} else {
+				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 {
-				apkCerts = append(apkCerts, formatLine(certInfo.Certificate, certInfo.InstallApkName+".apk", partition))
+				// 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))
@@ -951,7 +1119,14 @@
 		}
 	}
 
+	apkCertsInfoWithoutAppSets := android.PathForModuleOut(ctx, "apkcerts_without_app_sets.txt")
+	android.WriteFileRuleVerbatim(ctx, apkCertsInfoWithoutAppSets, strings.Join(apkCerts, "\n")+"\n")
 	apkCertsInfo := android.PathForModuleOut(ctx, "apkcerts.txt")
-	android.WriteFileRuleVerbatim(ctx, apkCertsInfo, strings.Join(apkCerts, "\n")+"\n")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cat,
+		Description: "combine apkcerts.txt",
+		Output:      apkCertsInfo,
+		Inputs:      append(apkCertsFiles, apkCertsInfoWithoutAppSets),
+	})
 	return apkCertsInfo
 }
diff --git a/filesystem/android_device_product_out.go b/filesystem/android_device_product_out.go
index 7d37f1e..aa06337 100644
--- a/filesystem/android_device_product_out.go
+++ b/filesystem/android_device_product_out.go
@@ -167,7 +167,7 @@
 	}
 
 	if proptools.String(a.deviceProps.Android_info) != "" {
-		installPath := android.PathForModuleInPartitionInstall(ctx, "", "android_info.txt")
+		installPath := android.PathForModuleInPartitionInstall(ctx, "", "android-info.txt")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.Cp,
 			Input:  android.PathForModuleSrc(ctx, *a.deviceProps.Android_info),
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index 327a41f..c776012 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -70,7 +70,7 @@
 	Props []avbProp
 
 	// The index used to prevent rollback of the image on device.
-	Rollback_index *int64
+	Rollback_index proptools.Configurable[int64] `android:"replace_instead_of_append"`
 
 	// Include descriptors from images
 	Include_descriptors_from_images []string `android:"path,arch_variant"`
@@ -134,8 +134,9 @@
 		addAvbProp(ctx, cmd, prop)
 	}
 
-	if a.properties.Rollback_index != nil {
-		rollbackIndex := proptools.Int(a.properties.Rollback_index)
+	rollbackIndex := a.properties.Rollback_index.Get(ctx)
+	if rollbackIndex.IsPresent() {
+		rollbackIndex := rollbackIndex.Get()
 		if rollbackIndex < 0 {
 			ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative")
 		}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 2bf0d59..485eae4 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,15 @@
 	}
 
 	// 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),
+		HeaderVersion:       proptools.String(b.properties.Header_version),
 	})
 
 	extractedPublicKey := android.PathForModuleOut(ctx, b.partitionName()+".avbpubkey")
@@ -265,6 +269,16 @@
 	})
 
 	// 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)
 	}
@@ -273,11 +287,13 @@
 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
+	HeaderVersion       string
 }
 
 func (b *bootimg) getKernelPath(ctx android.ModuleContext) android.Path {
@@ -496,6 +512,65 @@
 	return propFile, deps
 }
 
+func (b *bootimg) getAvbHashFooterArgs(ctx android.ModuleContext) string {
+	ret := ""
+	if !b.bootImageType.isVendorBoot() {
+		ret += "--prop " + fmt.Sprintf("com.android.build.%s.os_version:%s", b.bootImageType.String(), ctx.Config().PlatformVersionLastStable())
+	}
+
+	fingerprintFile := ctx.Config().BuildFingerprintFile(ctx)
+	ret += " --prop " + fmt.Sprintf("com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", b.bootImageType.String(), fingerprintFile.String())
+
+	if b.properties.Security_patch != nil {
+		ret += " --prop " + fmt.Sprintf("com.android.build.%s.security_patch:%s", b.bootImageType.String(), *b.properties.Security_patch)
+	}
+
+	if b.properties.Avb_rollback_index != nil {
+		ret += " --rollback_index " + strconv.FormatInt(*b.properties.Avb_rollback_index, 10)
+	}
+	return strings.TrimSpace(ret)
+}
+
+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", b.getAvbHashFooterArgs(ctx))
+	if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" {
+		ramdiskModule := ctx.GetDirectDepWithTag(ramdisk, bootimgRamdiskDep)
+		fsInfo, _ := android.OtherModuleProvider(ctx, ramdiskModule, FilesystemProvider)
+		if fsInfo.HasOrIsRecovery {
+			// Create a dup entry for recovery
+			addStr("avb_recovery_add_hash_footer_args", strings.ReplaceAll(b.getAvbHashFooterArgs(ctx), bootImgType, "recovery"))
+		}
+	}
+	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)))
+	}
+	if b.properties.Partition_size != nil {
+		addStr(bootImgType+"_size", strconv.FormatInt(*b.properties.Partition_size, 10))
+	}
+	if bootImgType != "boot" {
+		addStr(bootImgType, "true")
+	}
+
+	propFilePreProcessing := android.PathForModuleOut(ctx, "prop_for_misc_info_pre_processing")
+	android.WriteFileRuleVerbatim(ctx, propFilePreProcessing, sb.String())
+	propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   textFileProcessorRule,
+		Input:  propFilePreProcessing,
+		Output: propFile,
+	})
+
+	return propFile
+}
+
 var _ android.AndroidMkEntriesProvider = (*bootimg)(nil)
 
 // Implements android.AndroidMkEntriesProvider
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 065acbd..fd1c784 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -375,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
@@ -438,9 +452,20 @@
 
 	Owners []InstalledModuleInfo
 
-	UseAvb bool
-
 	HasFsverity bool
+
+	PropFileForMiscInfo android.Path
+
+	// Additional avb and partition size information.
+	// `system_other` will use this information of `system` dep for misc_info.txt processing.
+	PartitionSize    *int64
+	UseAvb           bool
+	AvbAlgorithm     string
+	AvbHashAlgorithm string
+	AvbKey           android.Path
+	PartitionName    string
+	// HasOrIsRecovery returns true for recovery and for ramdisks with a recovery partition.
+	HasOrIsRecovery bool
 }
 
 // FullInstallPathInfo contains information about the "full install" paths of all the files
@@ -624,9 +649,11 @@
 	var buildImagePropFile android.Path
 	var buildImagePropFileDeps android.Paths
 	var extraRootDirs android.Paths
+	var propFileForMiscInfo android.Path
 	switch f.fsType(ctx) {
 	case ext4Type, erofsType, f2fsType:
 		buildImagePropFile, buildImagePropFileDeps = f.buildPropFile(ctx)
+		propFileForMiscInfo = f.buildPropFileForMiscInfo(ctx)
 		output := android.PathForModuleOut(ctx, f.installFileName())
 		f.buildImageUsingBuildImage(ctx, builder, buildImageParams{rootDir, buildImagePropFile, buildImagePropFileDeps, output})
 		f.output = output
@@ -689,12 +716,23 @@
 			[]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,
+		ErofsCompressHints:  erofsCompressHints,
+		SelinuxFc:           f.selinuxFc,
+		FilesystemConfig:    f.generateFilesystemConfig(ctx, rootDir, rebasedDir),
+		Owners:              f.gatherOwners(specs),
+		HasFsverity:         f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) != nil,
+		PropFileForMiscInfo: propFileForMiscInfo,
+		PartitionSize:       f.properties.Partition_size,
+		PartitionName:       f.partitionName(),
+		HasOrIsRecovery:     f.hasOrIsRecovery(ctx),
+	}
+	if proptools.Bool(f.properties.Use_avb) {
+		fsInfo.UseAvb = true
+		fsInfo.AvbAlgorithm = proptools.StringDefault(f.properties.Avb_algorithm, "SHA256_RSA4096")
+		fsInfo.AvbHashAlgorithm = proptools.StringDefault(f.properties.Avb_hash_algorithm, "sha256")
+		if f.properties.Avb_private_key != nil {
+			fsInfo.AvbKey = android.PathForModuleSrc(ctx, *f.properties.Avb_private_key)
+		}
 	}
 
 	android.SetProvider(ctx, FilesystemProvider, fsInfo)
@@ -1031,21 +1069,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"))
@@ -1064,28 +1088,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 {
@@ -1134,7 +1137,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))
@@ -1165,6 +1168,104 @@
 	return propFile, deps
 }
 
+func (f *filesystem) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
+	var lines []string
+	addStr := func(name string, value string) {
+		lines = append(lines, fmt.Sprintf("%s=%s", name, value))
+	}
+
+	addStr("use_dynamic_partition_size", "true")
+	addStr("ext_mkuserimg", "mkuserimg_mke2fs")
+
+	addStr("building_"+f.partitionName()+"_image", "true")
+	addStr(f.partitionName()+"_fs_type", f.fsType(ctx).String())
+
+	if proptools.Bool(f.properties.Use_avb) {
+		addStr("avb_"+f.partitionName()+"_hashtree_enable", "true")
+		addStr("avb_"+f.partitionName()+"_add_hashtree_footer_args", strings.TrimSpace(f.getAvbAddHashtreeFooterArgs(ctx)))
+	}
+
+	if f.selinuxFc != nil {
+		addStr(f.partitionName()+"_selinux_fc", f.selinuxFc.String())
+	}
+
+	// Disable sparse only when partition size is not defined. disable_sparse has the same
+	// effect as <partition name>_disable_sparse.
+	if f.properties.Partition_size == nil {
+		addStr(f.partitionName()+"_disable_sparse", "true")
+	} else if f.partitionName() == "userdata" {
+		// Add userdata's partition size to misc_info.txt.
+		// userdata has been special-cased to make the make packaging misc_info.txt implementation
+		addStr("userdata_size", strconv.FormatInt(*f.properties.Partition_size, 10))
+	}
+
+	fst := f.fsType(ctx)
+	switch fst {
+	case erofsType:
+		// Add erofs properties
+		addStr("erofs_default_compressor", proptools.StringDefault(f.properties.Erofs.Compressor, "lz4hc,9"))
+		if proptools.BoolDefault(f.properties.Erofs.Sparse, true) {
+			// https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2292;bpv=1;bpt=0;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b
+			addStr("erofs_sparse_flag", "-s")
+		}
+	case f2fsType:
+		if proptools.BoolDefault(f.properties.F2fs.Sparse, true) {
+			// https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2294;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
+			addStr("f2fs_sparse_flag", "-S")
+		}
+	}
+
+	if proptools.BoolDefault(f.properties.Support_casefolding, false) {
+		addStr("needs_casefold", "1")
+	}
+
+	if proptools.BoolDefault(f.properties.Support_project_quota, false) {
+		addStr("needs_projid", "1")
+	}
+
+	if proptools.BoolDefault(f.properties.Enable_compression, false) {
+		addStr("needs_compress", "1")
+	}
+
+	sort.Strings(lines)
+
+	propFilePreProcessing := android.PathForModuleOut(ctx, "prop_misc_info_pre_processing")
+	android.WriteFileRule(ctx, propFilePreProcessing, strings.Join(lines, "\n"))
+	propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   textFileProcessorRule,
+		Input:  propFilePreProcessing,
+		Output: propFile,
+	})
+
+	return propFile
+}
+
+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) {
@@ -1207,6 +1308,19 @@
 	return
 }
 
+func (f *filesystem) hasOrIsRecovery(ctx android.ModuleContext) bool {
+	if f.partitionName() == "recovery" {
+		return true
+	}
+	ret := false
+	ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) {
+		if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok && fsProvider.PartitionName == "recovery" {
+			ret = true
+		}
+	})
+	return ret
+}
+
 func (f *filesystem) buildCpioImage(
 	ctx android.ModuleContext,
 	builder *android.RuleBuilder,
@@ -1469,7 +1583,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(
@@ -1490,7 +1604,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]
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 6d0b490..e57e45c 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -723,26 +723,60 @@
 
 // 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, `
-		android_filesystem {
-			name: "myfilesystem",
-			deps: ["myapp", "myoverrideapp"],
+		cc_library_shared {
+			name: "libfoo",
+			stl: "none",
+			system_shared_libs: [],
 		}
-
+		cc_library_shared {
+			name: "libbar",
+			stl: "none",
+			system_shared_libs: [],
+		}
+		phony {
+			name: "myapp_phony",
+			required: ["myapp"],
+		}
+		phony {
+			name: "myoverrideapp_phony",
+			required: ["myoverrideapp"],
+		}
 		android_app {
 			name: "myapp",
 			platform_apis: true,
+			required: ["libfoo"],
 		}
 		override_android_app {
 			name: "myoverrideapp",
 			base: "myapp",
+			required: ["libbar"],
+		}
+		android_filesystem {
+			name: "myfilesystem",
+			deps: ["myapp"],
+		}
+		android_filesystem {
+			name: "myfilesystem_overridden",
+			deps: ["myapp", "myoverrideapp"],
+		}
+		android_filesystem {
+			name: "myfilesystem_overridden_indirect",
+			deps: ["myapp_phony", "myoverrideapp_phony"],
 		}
 	`)
 
 	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)
+
+	for _, overridden := range []string{"myfilesystem_overridden", "myfilesystem_overridden_indirect"} {
+		overriddenPartition := result.ModuleForTests(t, overridden, "android_common")
+		overriddenFileList := android.ContentFromFileRuleForTests(t, result.TestContext, overriddenPartition.Output("fileList"))
+		android.AssertStringEquals(t, "filesystem with "+overridden, "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 9e4412c..cf7e125 100644
--- a/filesystem/super_image.go
+++ b/filesystem/super_image.go
@@ -80,6 +80,8 @@
 	}
 	// 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 {
@@ -118,6 +120,10 @@
 	SubImageInfo map[string]FilesystemInfo
 
 	DynamicPartitionsInfo android.Path
+
+	SuperEmptyImage android.Path
+
+	AbUpdate bool
 }
 
 var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]()
@@ -163,7 +169,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")
@@ -176,10 +182,28 @@
 		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,
 		DynamicPartitionsInfo: s.generateDynamicPartitionsInfo(ctx),
+		SuperEmptyImage:       superEmptyImage,
+		AbUpdate:              proptools.Bool(s.properties.Ab_update),
 	})
 	ctx.SetOutputFiles([]android.Path{output}, "")
 	ctx.CheckbuildFile(output)
@@ -191,7 +215,7 @@
 	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) {
@@ -200,6 +224,12 @@
 		miscInfoString.WriteString(value)
 		miscInfoString.WriteRune('\n')
 	}
+	addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
+	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)
 	var deps android.Paths
@@ -298,38 +328,43 @@
 		sb.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("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, " "))
 	}
-	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)))
 	// 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, " "))
 	}
+	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")
 	}
-	addStr("super_partition_groups", strings.Join(groups, " "))
-	addStr("dynamic_partition_list", strings.Join(partitionList, " "))
+	// 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, " "))
+	}
 
-	addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
+	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")
@@ -344,12 +379,12 @@
 			}
 			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))
 		}
+		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 {
@@ -373,6 +408,6 @@
 	var contents strings.Builder
 	s.dumpDynamicPartitionInfo(ctx, &contents)
 	dynamicPartitionsInfo := android.PathForModuleOut(ctx, "dynamic_partitions_info.txt")
-	android.WriteFileRule(ctx, dynamicPartitionsInfo, contents.String())
+	android.WriteFileRuleVerbatim(ctx, dynamicPartitionsInfo, contents.String())
 	return dynamicPartitionsInfo
 }
diff --git a/filesystem/system_other.go b/filesystem/system_other.go
index cbfd78b..32a6cc7 100644
--- a/filesystem/system_other.go
+++ b/filesystem/system_other.go
@@ -16,8 +16,11 @@
 
 import (
 	"android/soong/android"
+	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
+	"time"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -117,8 +120,11 @@
 	// TOOD: CopySpecsToDir only exists on PackagingBase, but doesn't use any fields from it. Clean this up.
 	(&android.PackagingBase{}).CopySpecsToDir(ctx, builder, specs, stagingDir)
 
+	fullInstallPaths := []string{}
 	if len(m.properties.Preinstall_dexpreopt_files_from) > 0 {
 		builder.Command().Textf("touch %s", filepath.Join(stagingDir.String(), "system-other-odex-marker"))
+		installPath := android.PathForModuleInPartitionInstall(ctx, "system_other", "system-other-odex-marker")
+		fullInstallPaths = append(fullInstallPaths, installPath.String())
 	}
 	builder.Command().Textf("touch").Output(stagingDirTimestamp)
 	builder.Build("assemble_filesystem_staging_dir", "Assemble filesystem staging dir")
@@ -172,16 +178,21 @@
 	builder.Build("build_system_other_hermetic", "build system other")
 
 	fsInfo := FilesystemInfo{
-		Output:           output,
-		OutputHermetic:   outputHermetic,
-		RootDir:          stagingDir,
-		FilesystemConfig: m.generateFilesystemConfig(ctx, stagingDir, stagingDirTimestamp),
+		Output:              output,
+		OutputHermetic:      outputHermetic,
+		RootDir:             stagingDir,
+		FilesystemConfig:    m.generateFilesystemConfig(ctx, stagingDir, stagingDirTimestamp),
+		PropFileForMiscInfo: m.buildPropFileForMiscInfo(ctx),
 	}
 
 	android.SetProvider(ctx, FilesystemProvider, fsInfo)
 
 	ctx.SetOutputFiles(android.Paths{output}, "")
 	ctx.CheckbuildFile(output)
+
+	// Dump compliance metadata
+	complianceMetadataInfo := ctx.ComplianceMetadataInfo()
+	complianceMetadataInfo.SetFilesContained(fullInstallPaths)
 }
 
 func (s *systemOtherImage) generateFilesystemConfig(ctx android.ModuleContext, stagingDir, stagingDirTimestamp android.Path) android.Path {
@@ -204,3 +215,52 @@
 		Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp)
 	return propFilePinnedTimestamp
 }
+
+func (f *systemOtherImage) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
+	var lines []string
+	addStr := func(name string, value string) {
+		lines = append(lines, fmt.Sprintf("%s=%s", name, value))
+	}
+
+	addStr("building_system_other_image", "true")
+
+	systemImage := ctx.GetDirectDepProxyWithTag(*f.properties.System_image, systemImageDependencyTag)
+	systemInfo, ok := android.OtherModuleProvider(ctx, systemImage, FilesystemProvider)
+	if !ok {
+		ctx.PropertyErrorf("system_image", "Expected system_image module to provide FilesystemProvider")
+		return nil
+	}
+	if systemInfo.PartitionSize == nil {
+		addStr("system_other_disable_sparse", "true")
+	}
+	if systemInfo.UseAvb {
+		addStr("avb_system_other_hashtree_enable", "true")
+		addStr("avb_system_other_algorithm", systemInfo.AvbAlgorithm)
+		footerArgs := fmt.Sprintf("--hash_algorithm %s", systemInfo.AvbHashAlgorithm)
+		if rollbackIndex, err := f.avbRollbackIndex(ctx); err == nil {
+			footerArgs += fmt.Sprintf(" --rollback_index %d", rollbackIndex)
+		} else {
+			ctx.ModuleErrorf("Could not determine rollback_index %s\n", err)
+		}
+		addStr("avb_system_other_add_hashtree_footer_args", footerArgs)
+		if systemInfo.AvbKey != nil {
+			addStr("avb_system_other_key_path", systemInfo.AvbKey.String())
+		}
+	}
+
+	sort.Strings(lines)
+
+	propFile := android.PathForModuleOut(ctx, "prop_file")
+	android.WriteFileRule(ctx, propFile, strings.Join(lines, "\n"))
+	return propFile
+}
+
+// Use the default: PlatformSecurityPatch
+// TODO: Get this value from vbmeta_system
+func (f *systemOtherImage) avbRollbackIndex(ctx android.ModuleContext) (int64, error) {
+	t, err := time.Parse(time.DateOnly, ctx.Config().PlatformSecurityPatch())
+	if err != nil {
+		return -1, err
+	}
+	return t.Unix(), err
+}
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 01b453e..e7a39be 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -16,7 +16,10 @@
 
 import (
 	"fmt"
+	"sort"
 	"strconv"
+	"strings"
+	"time"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -52,6 +55,10 @@
 	// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
 	Partition_name *string
 
+	// Type of the `android_filesystem` for which the vbmeta.img is created.
+	// Examples are system, vendor, product.
+	Filesystem_partition_type *string
+
 	// Set the name of the output. Defaults to <module_name>.img.
 	Stem *string
 
@@ -115,6 +122,9 @@
 	// Name of the partition
 	Name string
 
+	// Partition type of the correspdonding android_filesystem.
+	FilesystemPartitionType string
+
 	// Rollback index location, non-negative int
 	RollbackIndexLocation int
 
@@ -124,6 +134,10 @@
 
 	// The output of the vbmeta module
 	Output android.Path
+
+	// Information about the vbmeta partition that will be added to misc_info.txt
+	// created by android_device
+	PropFileForMiscInfo android.Path
 }
 
 var vbmetaPartitionProvider = blueprint.NewProvider[vbmetaPartitionInfo]()
@@ -298,10 +312,12 @@
 	})
 
 	android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
-		Name:                  v.partitionName(),
-		RollbackIndexLocation: ril,
-		PublicKey:             extractedPublicKey,
-		Output:                output,
+		Name:                    v.partitionName(),
+		FilesystemPartitionType: proptools.String(v.properties.Filesystem_partition_type),
+		RollbackIndexLocation:   ril,
+		PublicKey:               extractedPublicKey,
+		Output:                  output,
+		PropFileForMiscInfo:     v.buildPropFileForMiscInfo(ctx),
 	})
 
 	ctx.SetOutputFiles([]android.Path{output}, "")
@@ -310,6 +326,41 @@
 	setCommonFilesystemInfo(ctx, v)
 }
 
+func (v *vbmeta) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
+	var lines []string
+	addStr := func(name string, value string) {
+		lines = append(lines, fmt.Sprintf("%s=%s", name, value))
+	}
+
+	addStr(fmt.Sprintf("avb_%s_algorithm", v.partitionName()), proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096"))
+	if v.properties.Private_key != nil {
+		addStr(fmt.Sprintf("avb_%s_key_path", v.partitionName()), android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key)).String())
+	}
+	if v.properties.Rollback_index_location != nil {
+		addStr(fmt.Sprintf("avb_%s_rollback_index_location", v.partitionName()), strconv.FormatInt(*v.properties.Rollback_index_location, 10))
+	}
+
+	var partitionDepNames []string
+	ctx.VisitDirectDepsProxyWithTag(vbmetaPartitionDep, func(child android.ModuleProxy) {
+		if info, ok := android.OtherModuleProvider(ctx, child, vbmetaPartitionProvider); ok {
+			partitionDepNames = append(partitionDepNames, info.Name)
+		} else {
+			ctx.ModuleErrorf("vbmeta dep %s does not set vbmetaPartitionProvider\n", child)
+		}
+	})
+	if v.partitionName() != "vbmeta" { // skip for vbmeta to match Make's misc_info.txt
+		addStr(fmt.Sprintf("avb_%s", v.partitionName()), strings.Join(android.SortedUniqueStrings(partitionDepNames), " "))
+	}
+
+	addStr(fmt.Sprintf("avb_%s_args", v.partitionName()), fmt.Sprintf("--padding_size 4096 --rollback_index %s", v.rollbackIndexString(ctx)))
+
+	sort.Strings(lines)
+
+	propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info")
+	android.WriteFileRule(ctx, propFile, strings.Join(lines, "\n"))
+	return propFile
+}
+
 // Returns the embedded shell command that prints the rollback index
 func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
 	if v.properties.Rollback_index != nil {
@@ -320,6 +371,17 @@
 	}
 }
 
+// Similar to rollbackIndexCommand, but guarantees that the rollback index is
+// always computed during Soong analysis, even if v.properties.Rollback_index is nil
+func (v *vbmeta) rollbackIndexString(ctx android.ModuleContext) string {
+	if v.properties.Rollback_index != nil {
+		return fmt.Sprintf("%d", *v.properties.Rollback_index)
+	} else {
+		t, _ := time.Parse(time.DateOnly, ctx.Config().PlatformSecurityPatch())
+		return fmt.Sprintf("%d", t.Unix())
+	}
+}
+
 var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
 
 func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
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 b73fb21..14aa062 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -419,13 +419,16 @@
 	partitionProps.Vbmeta_partitions = vbmetaPartitions
 
 	deviceProps := &filesystem.DeviceProperties{
-		Main_device:               proptools.BoolPtr(true),
-		Ab_ota_updater:            proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaUpdater),
-		Ab_ota_partitions:         ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPartitions,
-		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,
+		Main_device:                   proptools.BoolPtr(true),
+		Ab_ota_updater:                proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaUpdater),
+		Ab_ota_partitions:             ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPartitions,
+		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,
+		Partial_ota_update_partitions: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardPartialOtaUpdatePartitionsList,
+		Flash_block_size:              proptools.StringPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardFlashBlockSize),
+		Bootloader_in_update_package:  proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BootloaderInUpdatePackage),
 	}
 
 	if bootloader, ok := f.createBootloaderFilegroup(ctx); ok {
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index 418e48b..2c4d3c8 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -287,6 +287,12 @@
 				"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",
+				"device/sample/firmware/firmware.bin:recovery/root/firmware.bin",
+				"device/sample/firmware/firmware.bin:recovery/root/firmware-2.bin",
+				"device/sample/firmware/firmware.bin:recovery/root/lib/firmware/firmware.bin",
+				"device/sample/firmware/firmware.bin:recovery/root/lib/firmware/firmware-2.bin",
 			}
 			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
 				map[string]android.PartitionQualifiedVariablesType{
@@ -307,22 +313,23 @@
 			"frameworks/base/data/keyboards/Vendor_0079_Product_0011.kl": nil,
 			"frameworks/base/data/keyboards/Vendor_0079_Product_18d4.kl": nil,
 			"device/sample/etc/apns-full-conf.xml":                       nil,
+			"device/sample/firmware/firmware.bin":                        nil,
 		}),
 	).RunTest(t)
 
-	checkModuleProp := func(m android.Module, matcher func(actual interface{}) bool) bool {
+	getModuleProp := func(m android.Module, matcher func(actual interface{}) string) string {
 		for _, prop := range m.GetProperties() {
 
-			if matcher(prop) {
-				return true
+			if str := matcher(prop); str != "" {
+				return str
 			}
 		}
-		return false
+		return ""
 	}
 
 	// check generated prebuilt_* module type install path and install partition
 	generatedModule := result.ModuleForTests(t, "system-frameworks_base_config-etc-0", "android_arm64_armv8-a").Module()
-	etcModule, _ := generatedModule.(*etc.PrebuiltEtc)
+	etcModule := generatedModule.(*etc.PrebuiltEtc)
 	android.AssertStringEquals(
 		t,
 		"module expected to have etc install path",
@@ -340,7 +347,7 @@
 
 	// check generated prebuilt_* module specifies correct relative_install_path property
 	generatedModule = result.ModuleForTests(t, "system-frameworks_base_data_keyboards-usr_keylayout_subdir-0", "android_arm64_armv8-a").Module()
-	etcModule, _ = generatedModule.(*etc.PrebuiltEtc)
+	etcModule = generatedModule.(*etc.PrebuiltEtc)
 	android.AssertStringEquals(
 		t,
 		"module expected to set correct relative_install_path properties",
@@ -348,6 +355,37 @@
 		etcModule.SubDir(),
 	)
 
+	// check that generated prebuilt_* module sets correct srcs
+	eval := generatedModule.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"Vendor_0079_Product_0011.kl",
+		getModuleProp(generatedModule, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 2 {
+					return srcs[0]
+				}
+			}
+			return ""
+		}),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"Vendor_0079_Product_18d4.kl",
+		getModuleProp(generatedModule, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 2 {
+					return srcs[1]
+				}
+			}
+			return ""
+		}),
+	)
+
 	// check that prebuilt_* module is not generated for non existing source file
 	android.AssertStringEquals(
 		t,
@@ -361,40 +399,264 @@
 	generatedModule1 := result.ModuleForTests(t, "product-device_sample_etc-etc-1", "android_arm64_armv8-a").Module()
 
 	// check that generated prebuilt_* module sets correct srcs and dsts property
-	eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
-	android.AssertBoolEquals(
+	eval = generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
 		t,
-		"module expected to set correct srcs and dsts properties",
-		true,
-		checkModuleProp(generatedModule0, func(actual interface{}) bool {
+		"module expected to set correct srcs property",
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
 			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 &&
-					dsts[0] == "apns-conf.xml"
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
 			}
-			return false
+			return ""
+		}),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct dsts property",
+		"apns-conf.xml",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
+			}
+			return ""
 		}),
 	)
 
 	// check that generated prebuilt_* module sets correct srcs and dsts property
 	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
-	android.AssertBoolEquals(
+	android.AssertStringEquals(
 		t,
-		"module expected to set correct srcs and dsts properties",
-		true,
-		checkModuleProp(generatedModule1, func(actual interface{}) bool {
+		"module expected to set correct srcs property",
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
 			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 &&
-					dsts[0] == "apns-conf-2.xml"
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
 			}
-			return false
+			return ""
+		}),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct dsts property",
+		"apns-conf-2.xml",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	generatedModule0 = result.ModuleForTests(t, "system-device_sample_etc-foo-0", "android_common").Module()
+	generatedModule1 = result.ModuleForTests(t, "system-device_sample_etc-foo-1", "android_common").Module()
+
+	// check that generated prebuilt_* module sets correct srcs and dsts property
+	eval = generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
+			}
+			return ""
+		}),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct dsts property",
+		"foo/file.txt",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	// check generated prebuilt_* module specifies correct install path and relative install path
+	etcModule = generatedModule1.(*etc.PrebuiltEtc)
+	android.AssertStringEquals(
+		t,
+		"module expected to have . install path",
+		".",
+		etcModule.BaseDir(),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct relative_install_path properties",
+		"foo",
+		etcModule.SubDir(),
+	)
+
+	// check that generated prebuilt_* module sets correct srcs
+	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	generatedModule0 = result.ModuleForTests(t, "recovery-device_sample_firmware-0", "android_recovery_arm64_armv8-a").Module()
+	generatedModule1 = result.ModuleForTests(t, "recovery-device_sample_firmware-1", "android_recovery_common").Module()
+
+	// check generated prebuilt_* module specifies correct install path and relative install path
+	etcModule = generatedModule0.(*etc.PrebuiltEtc)
+	android.AssertStringEquals(
+		t,
+		"module expected to have . install path",
+		".",
+		etcModule.BaseDir(),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set empty relative_install_path properties",
+		"",
+		etcModule.SubDir(),
+	)
+
+	// check that generated prebuilt_* module don't set dsts
+	eval = generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to not set dsts property",
+		"",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) != 0 {
+					return dsts[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	// check generated prebuilt_* module specifies correct install path and relative install path
+	etcModule = generatedModule1.(*etc.PrebuiltEtc)
+	android.AssertStringEquals(
+		t,
+		"module expected to have . install path",
+		".",
+		etcModule.BaseDir(),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set empty relative_install_path properties",
+		"",
+		etcModule.SubDir(),
+	)
+
+	// check that generated prebuilt_* module sets correct dsts
+	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct dsts property",
+		"firmware-2.bin",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	generatedModule0 = result.ModuleForTests(t, "recovery-device_sample_firmware-lib_firmware-0", "android_recovery_common").Module()
+	generatedModule1 = result.ModuleForTests(t, "recovery-device_sample_firmware-lib_firmware-1", "android_recovery_common").Module()
+
+	// check generated prebuilt_* module specifies correct install path and relative install path
+	etcModule = generatedModule0.(*etc.PrebuiltEtc)
+	android.AssertStringEquals(
+		t,
+		"module expected to have . install path",
+		".",
+		etcModule.BaseDir(),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct relative_install_path properties",
+		"lib/firmware",
+		etcModule.SubDir(),
+	)
+
+	// check that generated prebuilt_* module sets correct srcs
+	eval = generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to not set dsts property",
+		"",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) != 0 {
+					return dsts[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	// check generated prebuilt_* module specifies correct install path and relative install path
+	etcModule = generatedModule1.(*etc.PrebuiltEtc)
+	android.AssertStringEquals(
+		t,
+		"module expected to have . install path",
+		".",
+		etcModule.BaseDir(),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set empty relative_install_path properties",
+		"",
+		etcModule.SubDir(),
+	)
+
+	// check that generated prebuilt_* module sets correct srcs
+	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct dsts property",
+		"lib/firmware/firmware-2.bin",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
+			}
+			return ""
 		}),
 	)
 }
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index d34ae77..4f3d2a7 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -187,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..c0f114c 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,10 +210,12 @@
 		"optee":               etc.PrebuiltOpteeFactory,
 		"overlay":             etc.PrebuiltOverlayFactory,
 		"priv-app":            etc.PrebuiltPrivAppFactory,
+		"radio":               etc.PrebuiltRadioFactory,
 		"sbin":                etc.PrebuiltSbinFactory,
 		"system":              etc.PrebuiltSystemFactory,
 		"res":                 etc.PrebuiltResFactory,
 		"rfs":                 etc.PrebuiltRfsFactory,
+		"tee":                 etc.PrebuiltTeeFactory,
 		"tts":                 etc.PrebuiltVoicepackFactory,
 		"tvconfig":            etc.PrebuiltTvConfigFactory,
 		"tvservice":           etc.PrebuiltTvServiceFactory,
@@ -225,6 +227,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 +302,7 @@
 			etcInstallPathKey = etcInstallPath
 		}
 	}
+	moduleFactory := etcInstallPathToFactoryList[etcInstallPathKey]
 	relDestDirFromInstallDirBase, _ := filepath.Rel(etcInstallPathKey, destDir)
 
 	for fileIndex := range maxLen {
@@ -333,30 +337,49 @@
 			propsList = append(propsList, &prebuiltInstallInRootProperties{
 				Install_in_root: proptools.BoolPtr(true),
 			})
+			// Discard any previously picked module and force it to prebuilt_{root,any} as
+			// they are the only modules allowed to specify the `install_in_root` property.
+			etcInstallPathKey = ""
+			relDestDirFromInstallDirBase = destDir
 		}
 
 		// Set appropriate srcs, dsts, and releative_install_path based on
 		// the source and install file names
-		if allCopyFileNamesUnchanged {
-			modulePropsPtr.Srcs = srcBaseFiles
+		modulePropsPtr.Srcs = srcBaseFiles
 
-			// Specify relative_install_path if it is not installed in the root directory of the
-			// partition
+		// prebuilt_root should only be used in very limited cases in prebuilt_etc moddule gen, where:
+		// - all source file names are identical to the installed file names, and
+		// - all source files are installed in root, not the subdirectories of root
+		// prebuilt_root currently does not have a good way to specify the names of the multiple
+		// installed files, and prebuilt_root does not allow installing files at a subdirectory
+		// of the root.
+		// Use prebuilt_any instead of prebuilt_root if either of the conditions are not met as
+		// a fallback behavior.
+		if etcInstallPathKey == "" {
+			if !(allCopyFileNamesUnchanged && android.InList(relDestDirFromInstallDirBase, []string{"", "."})) {
+				moduleFactory = etc.PrebuiltAnyFactory
+			}
+		}
+
+		if allCopyFileNamesUnchanged {
+			// Specify relative_install_path if it is not installed in the base directory of the module.
+			// In case of prebuilt_{root,any} this is equivalent to the root of the partition.
 			if !android.InList(relDestDirFromInstallDirBase, []string{"", "."}) {
 				propsList = append(propsList, &prebuiltSubdirProperties{
 					Relative_install_path: proptools.StringPtr(relDestDirFromInstallDirBase),
 				})
 			}
 		} else {
-			modulePropsPtr.Srcs = srcBaseFiles
-			dsts := []string{}
+			dsts := proptools.NewConfigurable[[]string](nil, nil)
 			for _, installBaseFile := range installBaseFiles {
-				dsts = append(dsts, filepath.Join(relDestDirFromInstallDirBase, installBaseFile))
+				dsts.AppendSimpleValue([]string{filepath.Join(relDestDirFromInstallDirBase, installBaseFile)})
 			}
-			modulePropsPtr.Dsts = dsts
+			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 f564636..1d610f6 100644
--- a/fsgen/super_img.go
+++ b/fsgen/super_img.go
@@ -46,6 +46,7 @@
 		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/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go
index 11f4bd0..594c404 100644
--- a/fsgen/vbmeta_partitions.go
+++ b/fsgen/vbmeta_partitions.go
@@ -76,6 +76,7 @@
 	var chainedPartitionTypes []string
 	for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) {
 		props := partitionVars.ChainedVbmetaPartitions[chainedName]
+		filesystemPartitionType := chainedName
 		chainedName = "vbmeta_" + chainedName
 		if len(props.Partitions) == 0 {
 			continue
@@ -123,13 +124,14 @@
 			filesystem.VbmetaFactory,
 			".", // Create in the root directory for now so its easy to get the key
 			&filesystem.VbmetaProperties{
-				Partition_name:          proptools.StringPtr(chainedName),
-				Stem:                    proptools.StringPtr(chainedName + ".img"),
-				Private_key:             proptools.StringPtr(props.Key),
-				Algorithm:               &props.Algorithm,
-				Rollback_index:          rollbackIndex,
-				Rollback_index_location: &ril,
-				Partitions:              proptools.NewSimpleConfigurable(partitionModules),
+				Partition_name:            proptools.StringPtr(chainedName),
+				Filesystem_partition_type: proptools.StringPtr(filesystemPartitionType),
+				Stem:                      proptools.StringPtr(chainedName + ".img"),
+				Private_key:               proptools.StringPtr(props.Key),
+				Algorithm:                 &props.Algorithm,
+				Rollback_index:            rollbackIndex,
+				Rollback_index_location:   &ril,
+				Partitions:                proptools.NewSimpleConfigurable(partitionModules),
 			}, &struct {
 				Name *string
 			}{
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 49df480..b82f2a9 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -14,7 +14,6 @@
         "soong-shared",
     ],
     srcs: [
-        "allowlists.go",
         "genrule.go",
         "locations.go",
     ],
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
deleted file mode 100644
index 45a7f72..0000000
--- a/genrule/allowlists.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-package genrule
-
-var (
-	SandboxingDenyModuleList = []string{
-		// go/keep-sorted start
-		// go/keep-sorted end
-	}
-)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6bd1fcc..a7c09e7 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 {
@@ -969,30 +969,9 @@
 	return module
 }
 
-var sandboxingAllowlistKey = android.NewOnceKey("genruleSandboxingAllowlistKey")
-
-type sandboxingAllowlistSets struct {
-	sandboxingDenyModuleSet map[string]bool
-}
-
-func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSets {
-	return ctx.Config().Once(sandboxingAllowlistKey, func() interface{} {
-		sandboxingDenyModuleSet := map[string]bool{}
-
-		android.AddToStringSet(sandboxingDenyModuleSet, SandboxingDenyModuleList)
-		return &sandboxingAllowlistSets{
-			sandboxingDenyModuleSet: sandboxingDenyModuleSet,
-		}
-	}).(*sandboxingAllowlistSets)
-}
-
 func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
 	if !ctx.DeviceConfig().GenruleSandboxing() {
 		return r.SandboxTools()
 	}
-	sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
-	if sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
-		return r.SandboxTools()
-	}
 	return r.SandboxInputs()
 }
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/app.go b/java/app.go
index 65ccc68..05b4a96 100644
--- a/java/app.go
+++ b/java/app.go
@@ -82,6 +82,7 @@
 	Certificate                   Certificate
 	PrivAppAllowlist              android.OptionalPath
 	OverriddenManifestPackageName *string
+	ApkCertsFile                  android.Path
 }
 
 var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
@@ -425,6 +426,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 +536,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))
 		}
@@ -687,7 +692,7 @@
 	}
 
 	// Use non final ids if we are doing optimized shrinking and are using R8.
-	nonFinalIds := a.dexProperties.optimizedResourceShrinkingEnabled(ctx) && a.dexer.effectiveOptimizeEnabled()
+	nonFinalIds := a.dexProperties.optimizedResourceShrinkingEnabled(ctx) && a.dexer.effectiveOptimizeEnabled(ctx)
 
 	aconfigTextFilePaths := getAconfigFilePaths(ctx)
 
@@ -1229,7 +1234,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)
@@ -1249,7 +1254,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)
@@ -1287,13 +1292,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
 			}
 		}
@@ -1307,12 +1312,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
 		}
 
@@ -1322,7 +1327,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()
 			}
@@ -1703,6 +1708,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 {
diff --git a/java/app_import.go b/java/app_import.go
index c63c336..9fb13ba 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/app_set.go b/java/app_set.go
index 2e9d314..6a2c678 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -193,9 +193,10 @@
 	)
 
 	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
-		AppSet:     true,
-		Privileged: as.Privileged(),
-		OutputFile: as.OutputFile(),
+		AppSet:       true,
+		Privileged:   as.Privileged(),
+		OutputFile:   as.OutputFile(),
+		ApkCertsFile: as.apkcertsFile,
 	})
 }
 
diff --git a/java/base.go b/java/base.go
index 0833831..8aa0109 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 {
@@ -1812,7 +1816,7 @@
 				classesJar:    outputFile,
 				jarName:       jarName,
 			}
-			if j.GetProfileGuided(ctx) && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting(ctx) {
+			if j.GetProfileGuided(ctx) && j.optimizeOrObfuscateEnabled(ctx) && !j.EnableProfileRewriting(ctx) {
 				ctx.PropertyErrorf("enable_profile_rewriting",
 					"Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on. The attached profile should be sourced from an unoptimized/unobfuscated APK.",
 				)
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 b32d5ae..f2406fb 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -42,6 +42,9 @@
 		// True if the module containing this has it set by default.
 		EnabledByDefault bool `blueprint:"mutated"`
 
+		// If true, then this module will be optimized on eng builds.
+		Enabled_on_eng *bool
+
 		// Whether to allow that library classes inherit from program classes.
 		// Defaults to false.
 		Ignore_library_extends_program *bool
@@ -116,6 +119,21 @@
 		//
 		// 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,
@@ -146,7 +164,10 @@
 	providesTransitiveHeaderJarsForR8
 }
 
-func (d *dexer) effectiveOptimizeEnabled() bool {
+func (d *dexer) effectiveOptimizeEnabled(ctx android.EarlyModuleContext) bool {
+	if ctx.Config().Eng() {
+		return proptools.Bool(d.dexProperties.Optimize.Enabled_on_eng)
+	}
 	return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
 }
 
@@ -158,8 +179,8 @@
 	return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault())
 }
 
-func (d *dexer) optimizeOrObfuscateEnabled() bool {
-	return d.effectiveOptimizeEnabled() && (proptools.Bool(d.dexProperties.Optimize.Optimize) || proptools.Bool(d.dexProperties.Optimize.Obfuscate))
+func (d *dexer) optimizeOrObfuscateEnabled(ctx android.EarlyModuleContext) bool {
+	return d.effectiveOptimizeEnabled(ctx) && (proptools.Bool(d.dexProperties.Optimize.Optimize) || proptools.Bool(d.dexProperties.Optimize.Obfuscate))
 }
 
 var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
@@ -338,7 +359,7 @@
 		flags = append(flags, "--release")
 	} else if ctx.Config().Eng() {
 		flags = append(flags, "--debug")
-	} else if !d.effectiveOptimizeEnabled() && d.dexProperties.Optimize.EnabledByDefault {
+	} else if !d.effectiveOptimizeEnabled(ctx) && d.dexProperties.Optimize.EnabledByDefault {
 		// D8 uses --debug by default, whereas R8 uses --release by default.
 		// For targets that default to R8 usage (e.g., apps), but override this default, we still
 		// want D8 to run in release mode, preserving semantics as much as possible between the two.
@@ -458,6 +479,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 "))
@@ -598,7 +633,7 @@
 		mergeZipsFlags = "-stripFile META-INF/*.kotlin_module -stripFile **/*.kotlin_builtins"
 	}
 
-	useR8 := d.effectiveOptimizeEnabled()
+	useR8 := d.effectiveOptimizeEnabled(ctx)
 	useD8 := !useR8 || ctx.Config().PartialCompileFlags().Use_d8
 	rbeR8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8")
 	rbeD8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8")
diff --git a/java/dex_test.go b/java/dex_test.go
index 66d801d..8c1e5f7 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -797,12 +797,14 @@
 		},
 		{
 			name:          "app_eng",
+			useD8:         true,
 			isEng:         true,
 			expectedFlags: "--debug",
 		},
 		{
 			name:    "app_release_eng",
 			isEng:   true,
+			useD8:   true,
 			dxFlags: "--release",
 			// Eng mode does *not* override explicit dxflags.
 			expectedFlags: "--release",
@@ -866,3 +868,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_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/java.go b/java/java.go
index 215fbbd..07e38a1 100644
--- a/java/java.go
+++ b/java/java.go
@@ -578,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"}
@@ -608,6 +609,7 @@
 		kotlinPluginTag,
 		syspropPublicStubDepTag,
 		instrumentationForTag,
+		traceReferencesTag,
 	}
 )
 
@@ -668,12 +670,12 @@
 		ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 		ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
 		ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
-		if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
+		if d.effectiveOptimizeEnabled(ctx) && sdkDep.hasStandardLibs() {
 			ctx.AddVariationDependencies(nil, proguardRaiseTag,
 				config.LegacyCorePlatformBootclasspathLibraries...,
 			)
 		}
-		if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
+		if d.effectiveOptimizeEnabled(ctx) && sdkDep.hasFrameworkLibs() {
 			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
 		}
 	}
@@ -1954,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) {
@@ -1970,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) {
@@ -2225,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.
diff --git a/java/java_test.go b/java/java_test.go
index 6df81e5..1ba78d4 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -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 4711dc1..56142c8 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -46,7 +46,7 @@
 	moduleInfos := make(map[string]android.IdeInfo)
 
 	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
-		if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 
diff --git a/java/lint.go b/java/lint.go
index c31dfd0..dc1e51f 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -659,7 +659,7 @@
 	var outputs []*LintInfo
 	var dirs []string
 	ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
-		commonInfo, _ := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoKey)
+		commonInfo := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider)
 		if ctx.Config().KatiEnabled() && !commonInfo.ExportedToMake {
 			return
 		}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index ab4f8f8..d2ec8bd 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -277,7 +277,7 @@
 	var compatConfigMetadata android.Paths
 
 	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
-		if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
+		if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled {
 			return
 		}
 		if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigMetadataInfoProvider); ok {
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 42d42b8..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)
 }
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_library.go b/java/sdk_library.go
index 0fee529..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
 				}
 			}
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/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/arm64_device.go b/rust/config/arm64_device.go
index 94a4457..efcd56a 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -45,6 +45,14 @@
 			"-Z branch-protection=bti,pac-ret",
 			"-Z stack-protector=none",
 		},
+		"armv9-3a": []string{
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
+		"armv9-4a": []string{
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
 	}
 )
 
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/fuzz_test.go b/rust/fuzz_test.go
index bdcfbbb..f462795 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -134,17 +134,24 @@
 			}
 	`)
 
-	fuzz_shared_libtest := ctx.ModuleForTests(t, "fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
-	fuzz_static_libtest := ctx.ModuleForTests(t, "fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
-	fuzz_staticffi_libtest := ctx.ModuleForTests(t, "fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
+	fuzz_shared_libtest := ctx.ModuleForTests(t, "fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module()
+	fuzz_static_libtest := ctx.ModuleForTests(t, "fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module()
+	fuzz_staticffi_libtest := ctx.ModuleForTests(t, "fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module()
 
-	if !strings.Contains(fuzz_shared_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
-		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", fuzz_shared_libtest.FuzzSharedLibraries().String())
+	fuzzSharedLibraries := func(module android.Module) string {
+		if info, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok {
+			return info.FuzzSharedLibraries.String()
+		}
+		return ""
 	}
-	if !strings.Contains(fuzz_static_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
-		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String())
+
+	if libs := fuzzSharedLibraries(fuzz_shared_libtest); !strings.Contains(libs, ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", libs)
 	}
-	if !strings.Contains(fuzz_staticffi_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
-		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String())
+	if libs := fuzzSharedLibraries(fuzz_static_libtest); !strings.Contains(libs, ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", libs)
+	}
+	if libs := fuzzSharedLibraries(fuzz_staticffi_libtest); !strings.Contains(libs, ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", libs)
 	}
 }
diff --git a/rust/image.go b/rust/image.go
index 51b8289..aa10a6d 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -137,7 +137,7 @@
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
 	// module. As well as SoC specific modules, vendor variants must be installed to /vendor
 	// unless they have "odm_available: true".
-	return mod.InVendor() && !mod.VendorVariantToOdm()
+	return mod.HasVendorVariant() && mod.InVendor() && !mod.VendorVariantToOdm()
 }
 
 func (mod *Module) InstallInOdm() bool {
diff --git a/rust/rust.go b/rust/rust.go
index d8a0444..54b5d92 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -61,6 +61,7 @@
 	SnapshotInfo                  *cc.SnapshotInfo
 	SourceProviderInfo            *SourceProviderInfo
 	XrefRustFiles                 android.Paths
+	DocTimestampFile              android.OptionalPath
 }
 
 var RustInfoProvider = blueprint.NewProvider[*RustInfo]()
@@ -1173,6 +1174,7 @@
 		RustSubName:                   mod.Properties.RustSubName,
 		TransitiveAndroidMkSharedLibs: mod.transitiveAndroidMkSharedLibs,
 		XrefRustFiles:                 mod.XrefRustFiles(),
+		DocTimestampFile:              mod.docTimestampFile,
 	}
 	if mod.compiler != nil {
 		rustInfo.CompilerInfo = &CompilerInfo{
@@ -1478,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:
@@ -1626,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)
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/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/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/sh/sh_binary.go b/sh/sh_binary.go
index d00c056..57f5ad1 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -510,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())
@@ -574,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 {
@@ -609,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/Android.bp b/tradefed_modules/Android.bp
index a765a05..37bae39 100644
--- a/tradefed_modules/Android.bp
+++ b/tradefed_modules/Android.bp
@@ -14,11 +14,9 @@
     ],
     srcs: [
         "test_module_config.go",
-        "test_suite.go",
     ],
     testSrcs: [
         "test_module_config_test.go",
-        "test_suite_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go
index 6dd48eb..2b34128 100644
--- a/tradefed_modules/test_module_config.go
+++ b/tradefed_modules/test_module_config.go
@@ -426,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/tradefed_modules/test_suite.go b/tradefed_modules/test_suite.go
deleted file mode 100644
index 8b7babf..0000000
--- a/tradefed_modules/test_suite.go
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package tradefed_modules
-
-import (
-	"encoding/json"
-	"path"
-	"path/filepath"
-
-	"android/soong/android"
-	"android/soong/tradefed"
-	"github.com/google/blueprint"
-)
-
-const testSuiteModuleType = "test_suite"
-
-type testSuiteTag struct {
-	blueprint.BaseDependencyTag
-}
-
-type testSuiteManifest struct {
-	Name  string   `json:"name"`
-	Files []string `json:"files"`
-}
-
-func init() {
-	RegisterTestSuiteBuildComponents(android.InitRegistrationContext)
-}
-
-func RegisterTestSuiteBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType(testSuiteModuleType, TestSuiteFactory)
-}
-
-var PrepareForTestWithTestSuiteBuildComponents = android.GroupFixturePreparers(
-	android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-)
-
-type testSuiteProperties struct {
-	Description string
-	Tests       []string `android:"path,arch_variant"`
-}
-
-type testSuiteModule struct {
-	android.ModuleBase
-	android.DefaultableModuleBase
-	testSuiteProperties
-}
-
-func (t *testSuiteModule) DepsMutator(ctx android.BottomUpMutatorContext) {
-	for _, test := range t.Tests {
-		if ctx.OtherModuleDependencyVariantExists(ctx.Config().BuildOSCommonTarget.Variations(), test) {
-			// Host tests.
-			ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), testSuiteTag{}, test)
-		} else {
-			// Target tests.
-			ctx.AddDependency(ctx.Module(), testSuiteTag{}, test)
-		}
-	}
-}
-
-func (t *testSuiteModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	suiteName := ctx.ModuleName()
-	modulesByName := make(map[string]android.Module)
-	ctx.WalkDeps(func(child, parent android.Module) bool {
-		// Recurse into test_suite dependencies.
-		if ctx.OtherModuleType(child) == testSuiteModuleType {
-			ctx.Phony(suiteName, android.PathForPhony(ctx, child.Name()))
-			return true
-		}
-
-		// Only write out top level test suite dependencies here.
-		if _, ok := ctx.OtherModuleDependencyTag(child).(testSuiteTag); !ok {
-			return false
-		}
-
-		if !child.InstallInTestcases() {
-			ctx.ModuleErrorf("test_suite only supports modules installed in testcases. %q is not installed in testcases.", child.Name())
-			return false
-		}
-
-		modulesByName[child.Name()] = child
-		return false
-	})
-
-	var files []string
-	for name, module := range modulesByName {
-		// Get the test provider data from the child.
-		tp, ok := android.OtherModuleProvider(ctx, module, tradefed.BaseTestProviderKey)
-		if !ok {
-			// TODO: Consider printing out a list of all module types.
-			ctx.ModuleErrorf("%q is not a test module.", name)
-			continue
-		}
-
-		files = append(files, packageModuleFiles(ctx, suiteName, module, tp)...)
-		ctx.Phony(suiteName, android.PathForPhony(ctx, name))
-	}
-
-	manifestPath := android.PathForSuiteInstall(ctx, suiteName, suiteName+".json")
-	b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: android.SortedUniqueStrings(files)})
-	if err != nil {
-		ctx.ModuleErrorf("Failed to marshal manifest: %v", err)
-		return
-	}
-	android.WriteFileRule(ctx, manifestPath, string(b))
-
-	ctx.Phony(suiteName, manifestPath)
-}
-
-func TestSuiteFactory() android.Module {
-	module := &testSuiteModule{}
-	module.AddProperties(&module.testSuiteProperties)
-
-	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
-	android.InitDefaultableModule(module)
-
-	return module
-}
-
-func packageModuleFiles(ctx android.ModuleContext, suiteName string, module android.Module, tp tradefed.BaseTestProviderData) []string {
-
-	hostOrTarget := "target"
-	if tp.IsHost {
-		hostOrTarget = "host"
-	}
-
-	// suiteRoot at out/soong/packaging/<suiteName>.
-	suiteRoot := android.PathForSuiteInstall(ctx, suiteName)
-
-	var installed android.InstallPaths
-	// Install links to installed files from the module.
-	if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
-		for _, f := range installFilesInfo.InstallFiles {
-			// rel is anything under .../<partition>, normally under .../testcases.
-			rel := android.Rel(ctx, f.PartitionDir(), f.String())
-
-			// Install the file under <suiteRoot>/<host|target>/<partition>.
-			installDir := suiteRoot.Join(ctx, hostOrTarget, f.Partition(), path.Dir(rel))
-			linkTo, err := filepath.Rel(installDir.String(), f.String())
-			if err != nil {
-				ctx.ModuleErrorf("Failed to get relative path from %s to %s: %v", installDir.String(), f.String(), err)
-				continue
-			}
-			installed = append(installed, ctx.InstallAbsoluteSymlink(installDir, path.Base(rel), linkTo))
-		}
-	}
-
-	// Install config file.
-	if tp.TestConfig != nil {
-		moduleRoot := suiteRoot.Join(ctx, hostOrTarget, "testcases", module.Name())
-		installed = append(installed, ctx.InstallFile(moduleRoot, module.Name()+".config", tp.TestConfig))
-	}
-
-	// Add to phony and manifest, manifestpaths are relative to suiteRoot.
-	var manifestEntries []string
-	for _, f := range installed {
-		manifestEntries = append(manifestEntries, android.Rel(ctx, suiteRoot.String(), f.String()))
-		ctx.Phony(suiteName, f)
-	}
-	return manifestEntries
-}
diff --git a/tradefed_modules/test_suite_test.go b/tradefed_modules/test_suite_test.go
deleted file mode 100644
index 3e1472c..0000000
--- a/tradefed_modules/test_suite_test.go
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package tradefed_modules
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-	"encoding/json"
-	"slices"
-	"testing"
-)
-
-func TestTestSuites(t *testing.T) {
-	t.Parallel()
-	ctx := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-	).RunTestWithBp(t, `
-		android_test {
-			name: "TestModule1",
-			sdk_version: "current",
-		}
-
-		android_test {
-			name: "TestModule2",
-			sdk_version: "current",
-		}
-
-		test_suite {
-			name: "my-suite",
-			description: "a test suite",
-			tests: [
-				"TestModule1",
-				"TestModule2",
-			]
-		}
-	`)
-	manifestPath := ctx.ModuleForTests(t, "my-suite", "android_common").Output("out/soong/test_suites/my-suite/my-suite.json")
-	var actual testSuiteManifest
-	if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil {
-		t.Errorf("failed to unmarshal manifest: %v", err)
-	}
-	slices.Sort(actual.Files)
-
-	expected := testSuiteManifest{
-		Name: "my-suite",
-		Files: []string{
-			"target/testcases/TestModule1/TestModule1.config",
-			"target/testcases/TestModule1/arm64/TestModule1.apk",
-			"target/testcases/TestModule2/TestModule2.config",
-			"target/testcases/TestModule2/arm64/TestModule2.apk",
-		},
-	}
-
-	android.AssertDeepEquals(t, "manifests differ", expected, actual)
-}
-
-func TestTestSuitesWithNested(t *testing.T) {
-	t.Parallel()
-	ctx := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-	).RunTestWithBp(t, `
-		android_test {
-			name: "TestModule1",
-			sdk_version: "current",
-		}
-
-		android_test {
-			name: "TestModule2",
-			sdk_version: "current",
-		}
-
-		android_test {
-			name: "TestModule3",
-			sdk_version: "current",
-		}
-
-		test_suite {
-			name: "my-child-suite",
-			description: "a child test suite",
-			tests: [
-				"TestModule1",
-				"TestModule2",
-			]
-		}
-
-		test_suite {
-			name: "my-all-tests-suite",
-			description: "a parent test suite",
-			tests: [
-				"TestModule1",
-				"TestModule3",
-				"my-child-suite",
-			]
-		}
-	`)
-	manifestPath := ctx.ModuleForTests(t, "my-all-tests-suite", "android_common").Output("out/soong/test_suites/my-all-tests-suite/my-all-tests-suite.json")
-	var actual testSuiteManifest
-	if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil {
-		t.Errorf("failed to unmarshal manifest: %v", err)
-	}
-	slices.Sort(actual.Files)
-
-	expected := testSuiteManifest{
-		Name: "my-all-tests-suite",
-		Files: []string{
-			"target/testcases/TestModule1/TestModule1.config",
-			"target/testcases/TestModule1/arm64/TestModule1.apk",
-			"target/testcases/TestModule2/TestModule2.config",
-			"target/testcases/TestModule2/arm64/TestModule2.apk",
-			"target/testcases/TestModule3/TestModule3.config",
-			"target/testcases/TestModule3/arm64/TestModule3.apk",
-		},
-	}
-
-	android.AssertDeepEquals(t, "manifests differ", expected, actual)
-}
-
-func TestTestSuitesNotInstalledInTestcases(t *testing.T) {
-	t.Parallel()
-	android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{
-		`"SomeHostTest" is not installed in testcases`,
-	})).RunTestWithBp(t, `
-			java_test_host {
-				name: "SomeHostTest",
-				srcs: ["a.java"],
-			}
-			test_suite {
-				name: "my-suite",
-				description: "a test suite",
-				tests: [
-					"SomeHostTest",
-				]
-			}
-	`)
-}
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index cd49ec8..622aadb 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -15,20 +15,29 @@
 package build
 
 import (
+	"os"
+	"slices"
 	"strings"
 )
 
 var androidmk_denylist []string = []string{
+	"art/",
 	"bionic/",
-	"chained_build_config/",
+	"bootable/",
+	"build/",
 	"cts/",
 	"dalvik/",
 	"developers/",
 	"development/",
 	"device/common/",
+	"device/generic/",
+	"device/google/",
 	"device/google_car/",
 	"device/sample/",
+	"external/",
 	"frameworks/",
+	"hardware/google/",
+	"hardware/interfaces/",
 	"hardware/libhardware/",
 	"hardware/libhardware_legacy/",
 	"hardware/ril/",
@@ -45,24 +54,38 @@
 	"sdk/",
 	"system/",
 	"test/",
+	"tools/",
 	"trusty/",
-	// Add back toolchain/ once defensive Android.mk files are removed
-	//"toolchain/",
-	"vendor/google_contexthub/",
-	"vendor/google_data/",
-	"vendor/google_elmyra/",
-	"vendor/google_mhl/",
-	"vendor/google_pdk/",
-	"vendor/google_testing/",
-	"vendor/partner_testing/",
-	"vendor/partner_tools/",
-	"vendor/pdk/",
+	"toolchain/",
+}
+
+var androidmk_allowlist []string = []string{
+	"art/Android.mk",
+	"bootable/deprecated-ota/updater/Android.mk",
+}
+
+func getAllLines(ctx Context, filename string) []string {
+	bytes, err := os.ReadFile(filename)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return []string{}
+		} else {
+			ctx.Fatalf("Could not read %s: %v", filename, err)
+		}
+	}
+	return strings.Split(strings.Trim(string(bytes), " \n"), "\n")
 }
 
 func blockAndroidMks(ctx Context, androidMks []string) {
+	allowlist := getAllLines(ctx, "vendor/google/build/androidmk/allowlist.txt")
+	androidmk_allowlist = append(androidmk_allowlist, allowlist...)
+
+	denylist := getAllLines(ctx, "vendor/google/build/androidmk/denylist.txt")
+	androidmk_denylist = append(androidmk_denylist, denylist...)
+
 	for _, mkFile := range androidMks {
 		for _, d := range androidmk_denylist {
-			if strings.HasPrefix(mkFile, d) {
+			if strings.HasPrefix(mkFile, d) && !slices.Contains(androidmk_allowlist, mkFile) {
 				ctx.Fatalf("Found blocked Android.mk file: %s. "+
 					"Please see androidmk_denylist.go for the blocked directories and contact build system team if the file should not be blocked.", mkFile)
 			}
@@ -86,6 +109,12 @@
 	// These directories hold the published Android SDK, used in Unbundled Gradle builds.
 	"prebuilts/fullsdk-darwin",
 	"prebuilts/fullsdk-linux",
+	// wpa_supplicant_8 has been converted to Android.bp and Android.mk files are kept for troubleshooting.
+	"external/wpa_supplicant_8/",
+	// Empty Android.mk in package's top directory
+	"external/proguard/",
+	"external/swig/",
+	"toolchain/",
 }
 
 var art_androidmks = []string{
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 16a3db8..710be84 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -181,7 +181,12 @@
 			fmt.Fprintf(b, "%s=%s\n", name, make_vars[name])
 		}
 	}
-	fmt.Fprintf(b, "SOONG_ONLY=%t\n", config.soongOnlyRequested)
+	if config.skipKatiControlledByFlags {
+		fmt.Fprintf(b, "SOONG_ONLY=%t\n", config.soongOnlyRequested)
+	} else { // default for this product
+		fmt.Fprintf(b, "SOONG_ONLY=%t\n", make_vars["PRODUCT_SOONG_ONLY"] == "true")
+	}
+
 	fmt.Fprint(b, "============================================")
 
 	return b.String()
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 783b488..ff8908b 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -84,8 +84,14 @@
 			// METADATA file of packages
 			"METADATA",
 		},
-		// .mk files for product/board configuration.
-		IncludeSuffixes: []string{".mk"},
+		IncludeSuffixes: []string{
+			// .mk files for product/board configuration.
+			".mk",
+			// otatools cert files
+			".pk8",
+			".pem",
+			".avbpubkey",
+		},
 	}
 	dumpDir := config.FileListDir()
 	f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard),
@@ -118,6 +124,18 @@
 	return entries.DirNames, matches
 }
 
+func findOtaToolsCertFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
+	matches := []string{}
+	for _, foundName := range entries.FileNames {
+		if strings.HasSuffix(foundName, ".pk8") ||
+			strings.HasSuffix(foundName, ".pem") ||
+			strings.HasSuffix(foundName, ".avbpubkey") {
+			matches = append(matches, foundName)
+		}
+	}
+	return entries.DirNames, matches
+}
+
 // FindSources searches for source files known to <f> and writes them to the filesystem for
 // use later.
 func FindSources(ctx Context, config Config, f *finder.Finder) {
@@ -184,6 +202,17 @@
 		ctx.Fatalf("Could not find TEST_MAPPING: %v", err)
 	}
 
+	// Recursively look for all otatools cert files.
+	otatools_cert_files := f.FindMatching("build/make/target/product/security", findOtaToolsCertFiles)
+	otatools_cert_files = append(otatools_cert_files, f.FindMatching("device", findOtaToolsCertFiles)...)
+	otatools_cert_files = append(otatools_cert_files, f.FindMatching("external/avb/test/data", findOtaToolsCertFiles)...)
+	otatools_cert_files = append(otatools_cert_files, f.FindMatching("packages/modules", findOtaToolsCertFiles)...)
+	otatools_cert_files = append(otatools_cert_files, f.FindMatching("vendor", findOtaToolsCertFiles)...)
+	err = dumpListToFile(ctx, config, otatools_cert_files, filepath.Join(dumpDir, "OtaToolsCertFiles.list"))
+	if err != nil {
+		ctx.Fatalf("Could not find otatools cert files: %v", err)
+	}
+
 	// Recursively look for all Android.bp files
 	androidBps := f.FindNamedAt(".", "Android.bp")
 	if len(androidBps) == 0 {