Merge "Search for default_team in Android.bp when other .bp files are included." into main
diff --git a/android/Android.bp b/android/Android.bp
index 841a6af..96e8133 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -106,6 +106,7 @@
         "updatable_modules.go",
         "util.go",
         "variable.go",
+        "vintf_fragment.go",
         "visibility.go",
     ],
     testSrcs: [
@@ -148,6 +149,7 @@
         "test_suites_test.go",
         "util_test.go",
         "variable_test.go",
+        "vintf_fragment_test.go",
         "visibility_test.go",
     ],
 }
diff --git a/android/androidmk.go b/android/androidmk.go
index e9df752..081bca9 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -536,13 +536,14 @@
 	a.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod))
 
 	// If the install rule was generated by Soong tell Make about it.
-	if len(base.katiInstalls) > 0 {
+	info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
+	if len(info.KatiInstalls) > 0 {
 		// Assume the primary install file is last since it probably needs to depend on any other
 		// installed files.  If that is not the case we can add a method to specify the primary
 		// installed file.
-		a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", base.katiInstalls[len(base.katiInstalls)-1].to)
-		a.SetString("LOCAL_SOONG_INSTALL_PAIRS", base.katiInstalls.BuiltInstalled())
-		a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", base.katiSymlinks.InstallPaths().Paths())
+		a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to)
+		a.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled())
+		a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths())
 	} else {
 		// Soong may not have generated the install rule also when `no_full_install: true`.
 		// Mark this module as uninstallable in order to prevent Make from creating an
@@ -550,8 +551,8 @@
 		a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
 	}
 
-	if len(base.testData) > 0 {
-		a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(base.testData)...)
+	if len(info.TestData) > 0 {
+		a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
 	}
 
 	if am, ok := mod.(ApexModule); ok {
@@ -861,6 +862,7 @@
 	}
 
 	data := provider.AndroidMk()
+
 	if data.Include == "" {
 		data.Include = "$(BUILD_PREBUILT)"
 	}
@@ -907,6 +909,7 @@
 		case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
 		case "*selinux.selinuxContextsModule": // license properties written
 		case "*sysprop.syspropLibrary": // license properties written
+		case "*vintf.vintfCompatibilityMatrixRule": // use case like phony
 		default:
 			if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
 				return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
diff --git a/android/apex.go b/android/apex.go
index ecab8e3..ef4cf82 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -280,7 +280,6 @@
 	//
 	// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
 	// "//apex_available:platform" refers to non-APEX partitions like "system.img".
-	// "com.android.gki.*" matches any APEX module name with the prefix "com.android.gki.".
 	// Default is ["//apex_available:platform"].
 	Apex_available []string
 
@@ -473,14 +472,12 @@
 const (
 	AvailableToPlatform = "//apex_available:platform"
 	AvailableToAnyApex  = "//apex_available:anyapex"
-	AvailableToGkiApex  = "com.android.gki.*"
 )
 
 var (
 	AvailableToRecognziedWildcards = []string{
 		AvailableToPlatform,
 		AvailableToAnyApex,
-		AvailableToGkiApex,
 	}
 )
 
@@ -496,7 +493,6 @@
 	}
 	return InList(what, apex_available) ||
 		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
-		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available)) ||
 		(what == "com.google.mainline.primary.libs") || // TODO b/248601389
 		(what == "com.google.mainline.go.primary.libs") // TODO b/248601389
 }
@@ -524,7 +520,7 @@
 // This function makes sure that the apex_available property is valid
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
 	for _, n := range m.ApexProperties.Apex_available {
-		if n == AvailableToPlatform || n == AvailableToAnyApex || n == AvailableToGkiApex {
+		if n == AvailableToPlatform || n == AvailableToAnyApex {
 			continue
 		}
 		if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
diff --git a/android/build_prop.go b/android/build_prop.go
index b127755..13d59f9 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -56,7 +56,7 @@
 }
 
 func (p *buildPropModule) propFiles(ctx ModuleContext) Paths {
-	partition := p.PartitionTag(ctx.DeviceConfig())
+	partition := p.partition(ctx.DeviceConfig())
 	if partition == "system" {
 		return ctx.Config().SystemPropFiles(ctx)
 	} else if partition == "system_ext" {
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index 0080b9a..4c92f71 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -160,7 +160,7 @@
 // buildComplianceMetadataProvider starts with the ModuleContext.ComplianceMetadataInfo() and fills in more common metadata
 // for different module types without accessing their private fields but through android.Module interface
 // and public/private fields of package android. The final metadata is stored to a module's ComplianceMetadataProvider.
-func buildComplianceMetadataProvider(ctx ModuleContext, m *ModuleBase) {
+func buildComplianceMetadataProvider(ctx *moduleContext, m *ModuleBase) {
 	complianceMetadataInfo := ctx.ComplianceMetadataInfo()
 	complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.NAME, m.Name())
 	complianceMetadataInfo.SetStringValue(ComplianceMetadataProp.PACKAGE, ctx.ModuleDir())
@@ -186,9 +186,9 @@
 		}
 
 		var installed InstallPaths
-		installed = append(installed, m.module.FilesToInstall()...)
-		installed = append(installed, m.katiInstalls.InstallPaths()...)
-		installed = append(installed, m.katiSymlinks.InstallPaths()...)
+		installed = append(installed, ctx.installFiles...)
+		installed = append(installed, ctx.katiInstalls.InstallPaths()...)
+		installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
 		installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
 		installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
 		complianceMetadataInfo.SetListValue(ComplianceMetadataProp.INSTALLED_FILES, FirstUniqueStrings(installed.Strings()))
diff --git a/android/config.go b/android/config.go
index d13e5ab..d6d76a4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -2053,3 +2053,19 @@
 func (c *config) EnableUffdGc() string {
 	return String(c.productVariables.EnableUffdGc)
 }
+
+func (c *config) DeviceFrameworkCompatibilityMatrixFile() []string {
+	return c.productVariables.DeviceFrameworkCompatibilityMatrixFile
+}
+
+func (c *config) DeviceProductCompatibilityMatrixFile() []string {
+	return c.productVariables.DeviceProductCompatibilityMatrixFile
+}
+
+func (c *config) BoardAvbEnable() bool {
+	return Bool(c.productVariables.BoardAvbEnable)
+}
+
+func (c *config) BoardAvbSystemAddHashtreeFooterArgs() []string {
+	return c.productVariables.BoardAvbSystemAddHashtreeFooterArgs
+}
diff --git a/android/container.go b/android/container.go
index 05897dd..10aff4d 100644
--- a/android/container.go
+++ b/android/container.go
@@ -43,16 +43,86 @@
 	return false
 }
 
+// Returns true if the dependency module belongs to any of the apexes.
+var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _, dep Module) bool {
+	depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
+	return InList(ApexContainer, depContainersInfo.belongingContainers)
+}
+
+// Returns true if the module and the dependent module belongs to common apexes.
+var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m, dep Module) bool {
+	mContainersInfo, _ := getContainerModuleInfo(mctx, m)
+	depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
+
+	return HasIntersection(mContainersInfo.ApexNames(), depContainersInfo.ApexNames())
+}
+
+// Returns true when all apexes that the module belongs to are non updatable.
+// For an apex module to be allowed to depend on a non-apex partition module,
+// all apexes that the module belong to must be non updatable.
+var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m, _ Module) bool {
+	mContainersInfo, _ := getContainerModuleInfo(mctx, m)
+
+	return !mContainersInfo.UpdatableApex()
+}
+
+// Returns true if the dependency is added via dependency tags that are not used to tag dynamic
+// dependency tags.
+var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
+	mInstallable, _ := m.(InstallableModule)
+	depTag := ctx.OtherModuleDependencyTag(dep)
+	return !InList(depTag, mInstallable.DynamicDependencyTags())
+}
+
+// Returns true if the dependency is added via dependency tags that are not used to tag static
+// or dynamic dependency tags. These dependencies do not affect the module in compile time or in
+// runtime, thus are not significant enough to raise an error.
+var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
+	mInstallable, _ := m.(InstallableModule)
+	depTag := ctx.OtherModuleDependencyTag(dep)
+	return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...))
+}
+
+var globallyAllowlistedDependencies = []string{
+	// Modules that provide annotations used within the platform and apexes.
+	"aconfig-annotations-lib",
+	"framework-annotations-lib",
+	"unsupportedappusage",
+
+	// framework-res provides core resources essential for building apps and system UI.
+	// This module is implicitly added as a dependency for java modules even when the
+	// dependency specifies sdk_version.
+	"framework-res",
+}
+
+// Returns true when the dependency is globally allowlisted for inter-container dependency
+var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
+	return InList(dep.Name(), globallyAllowlistedDependencies)
+}
+
 // Labels of exception functions, which are used to determine special dependencies that allow
 // otherwise restricted inter-container dependencies
 type exceptionHandleFuncLabel int
 
 const (
 	checkStubs exceptionHandleFuncLabel = iota
+	checkApexModule
+	checkInCommonApexes
+	checkApexIsNonUpdatable
+	checkNotDynamicDepTag
+	checkNotStaticOrDynamicDepTag
+	checkGlobalAllowlistedDep
 )
 
+// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
 var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
-	checkStubs: depIsStubsModule,
+	checkStubs:                    depIsStubsModule,
+	checkApexModule:               depIsApexModule,
+	checkInCommonApexes:           belongsToCommonApexes,
+	checkApexIsNonUpdatable:       belongsToNonUpdatableApex,
+	checkNotDynamicDepTag:         depIsNotDynamicDepTag,
+	checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
+	checkGlobalAllowlistedDep:     depIsGloballyAllowlisted,
 }
 
 // ----------------------------------------------------------------------------
@@ -108,13 +178,40 @@
 	return false
 }
 
+type unstableInfo struct {
+	// Determines if the module contains the private APIs of the platform.
+	ContainsPlatformPrivateApis bool
+}
+
+var unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
+
+func determineUnstableModule(mctx ModuleContext) bool {
+	module := mctx.Module()
+	unstableModule := module.Name() == "framework-minus-apex"
+	if installable, ok := module.(InstallableModule); ok {
+		for _, staticDepTag := range installable.StaticDependencyTags() {
+			mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) {
+				if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
+					unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
+				}
+			})
+		}
+	}
+	return unstableModule
+}
+
+var unstableContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
+	return determineUnstableModule(mctx)
+}
+
 // Map of [*container] to the [containerBoundaryFunc]
 var containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
-	VendorContainer:  vendorContainerBoundaryFunc,
-	SystemContainer:  systemContainerBoundaryFunc,
-	ProductContainer: productContainerBoundaryFunc,
-	ApexContainer:    apexContainerBoundaryFunc,
-	CtsContainer:     ctsContainerBoundaryFunc,
+	VendorContainer:   vendorContainerBoundaryFunc,
+	SystemContainer:   systemContainerBoundaryFunc,
+	ProductContainer:  productContainerBoundaryFunc,
+	ApexContainer:     apexContainerBoundaryFunc,
+	CtsContainer:      ctsContainerBoundaryFunc,
+	UnstableContainer: unstableContainerBoundaryFunc,
 }
 
 // ----------------------------------------------------------------------------
@@ -122,7 +219,9 @@
 // ----------------------------------------------------------------------------
 
 type InstallableModule interface {
-	EnforceApiContainerChecks() bool
+	ContainersInfo() ContainersInfo
+	StaticDependencyTags() []blueprint.DependencyTag
+	DynamicDependencyTags() []blueprint.DependencyTag
 }
 
 type restriction struct {
@@ -160,7 +259,11 @@
 					"not allowed to depend on the vendor partition module, in order to support " +
 					"independent development/update cycles and to support the Generic System " +
 					"Image. Try depending on HALs, VNDK or AIDL instead.",
-				allowedExceptions: []exceptionHandleFuncLabel{},
+				allowedExceptions: []exceptionHandleFuncLabel{
+					checkStubs,
+					checkNotDynamicDepTag,
+					checkGlobalAllowlistedDep,
+				},
 			},
 		},
 	}
@@ -173,7 +276,11 @@
 				errorMessage: "Module belonging to the product partition is not allowed to " +
 					"depend on the vendor partition module, as this may lead to security " +
 					"vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
-				allowedExceptions: []exceptionHandleFuncLabel{},
+				allowedExceptions: []exceptionHandleFuncLabel{
+					checkStubs,
+					checkNotDynamicDepTag,
+					checkGlobalAllowlistedDep,
+				},
 			},
 		},
 	}
@@ -184,22 +291,34 @@
 		name: "cts",
 		restricted: []restriction{
 			{
-				dependency: SystemContainer,
-				errorMessage: "CTS module should not depend on the modules belonging to the " +
-					"system partition, including \"framework\". Depending on the system " +
-					"partition may lead to disclosure of implementation details and regression " +
-					"due to API changes across platform versions. Try depending on the stubs instead.",
-				allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
+				dependency: UnstableContainer,
+				errorMessage: "CTS module should not depend on the modules that contain the " +
+					"platform implementation details, including \"framework\". Depending on these " +
+					"modules may lead to disclosure of implementation details and regression " +
+					"due to API changes across platform versions. Try depending on the stubs instead " +
+					"and ensure that the module sets an appropriate 'sdk_version'.",
+				allowedExceptions: []exceptionHandleFuncLabel{
+					checkStubs,
+					checkNotStaticOrDynamicDepTag,
+					checkGlobalAllowlistedDep,
+				},
 			},
 		},
 	}
 
+	// Container signifying that the module contains unstable platform private APIs
+	UnstableContainer = &container{
+		name:       "unstable",
+		restricted: nil,
+	}
+
 	allContainers = []*container{
 		VendorContainer,
 		SystemContainer,
 		ProductContainer,
 		ApexContainer,
 		CtsContainer,
+		UnstableContainer,
 	}
 )
 
@@ -213,7 +332,14 @@
 					"modules belonging to the system partition. Either statically depend on the " +
 					"module or convert the depending module to java_sdk_library and depend on " +
 					"the stubs.",
-				allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
+				allowedExceptions: []exceptionHandleFuncLabel{
+					checkStubs,
+					checkApexModule,
+					checkInCommonApexes,
+					checkApexIsNonUpdatable,
+					checkNotStaticOrDynamicDepTag,
+					checkGlobalAllowlistedDep,
+				},
 			},
 		},
 	}
@@ -224,7 +350,12 @@
 			"modules belonging to other Apex(es). Either include the depending " +
 			"module in the Apex or convert the depending module to java_sdk_library " +
 			"and depend on its stubs.",
-		allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
+		allowedExceptions: []exceptionHandleFuncLabel{
+			checkStubs,
+			checkInCommonApexes,
+			checkNotStaticOrDynamicDepTag,
+			checkGlobalAllowlistedDep,
+		},
 	})
 
 	return apexContainer
@@ -280,9 +411,24 @@
 	}
 }
 
+func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
+	if ctx.Module() == module {
+		return module.ContainersInfo(), true
+	}
+
+	return OtherModuleProvider(ctx, module, ContainersInfoProvider)
+}
+
 func setContainerInfo(ctx ModuleContext) {
+	// Required to determine the unstable container. This provider is set here instead of the
+	// unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
+	SetProvider(ctx, unstableInfoProvider, unstableInfo{
+		ContainsPlatformPrivateApis: determineUnstableModule(ctx),
+	})
+
 	if _, ok := ctx.Module().(InstallableModule); ok {
 		containersInfo := generateContainerInfo(ctx)
+		ctx.Module().base().containersInfo = containersInfo
 		SetProvider(ctx, ContainersInfoProvider, containersInfo)
 	}
 }
diff --git a/android/deapexer.go b/android/deapexer.go
index 61ae64e..dcae3e4 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -181,7 +181,11 @@
 			// An err has been found. Do not visit further.
 			return
 		}
-		c, _ := OtherModuleProvider(ctx, m, DeapexerProvider)
+		c, ok := OtherModuleProvider(ctx, m, DeapexerProvider)
+		if !ok {
+			ctx.ModuleErrorf("Expected all deps with DeapexerTag to have a DeapexerProvider, but module %q did not", m.Name())
+			return
+		}
 		p := &c
 		if di != nil {
 			// If two DeapexerInfo providers have been found then check if they are
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 8056189..cd69749 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -33,7 +33,7 @@
 	}, "args")
 )
 
-func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
+func buildLicenseMetadata(ctx *moduleContext, licenseMetadataFile WritablePath) {
 	base := ctx.Module().base()
 
 	if !base.Enabled(ctx) {
@@ -52,8 +52,8 @@
 	// Only pass the last installed file to isContainerFromFileExtensions so a *.zip file in test data
 	// doesn't mark the whole module as a container.
 	var installFiles InstallPaths
-	if len(base.installFiles) > 0 {
-		installFiles = InstallPaths{base.installFiles[len(base.installFiles)-1]}
+	if len(ctx.installFiles) > 0 {
+		installFiles = InstallPaths{ctx.installFiles[len(ctx.installFiles)-1]}
 	}
 
 	isContainer := isContainerFromFileExtensions(installFiles, outputFiles)
@@ -92,7 +92,7 @@
 
 			allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
 
-			if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 {
+			if depInstallFiles := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider).InstallFiles; len(depInstallFiles) > 0 {
 				allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...)
 			} else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil {
 				depOutputFiles = PathsIfNonNil(depOutputFiles...)
@@ -162,7 +162,7 @@
 
 	// Installed files
 	args = append(args,
-		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(ctx.installFiles.Strings()), "-i "))
 
 	if isContainer {
 		args = append(args, "--is_container")
diff --git a/android/makevars.go b/android/makevars.go
index ff43cc5..810eb38 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -279,10 +279,11 @@
 		}
 
 		if m.ExportedToMake() {
-			katiInstalls = append(katiInstalls, m.base().katiInstalls...)
+			info := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider)
+			katiInstalls = append(katiInstalls, info.KatiInstalls...)
 			katiInitRcInstalls = append(katiInitRcInstalls, m.base().katiInitRcInstalls...)
 			katiVintfManifestInstalls = append(katiVintfManifestInstalls, m.base().katiVintfInstalls...)
-			katiSymlinks = append(katiSymlinks, m.base().katiSymlinks...)
+			katiSymlinks = append(katiSymlinks, info.KatiSymlinks...)
 		}
 	})
 
diff --git a/android/module.go b/android/module.go
index 63df6f7..664ac5c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -111,15 +111,16 @@
 	RequiredModuleNames(ctx ConfigAndErrorContext) []string
 	HostRequiredModuleNames() []string
 	TargetRequiredModuleNames() []string
-
-	FilesToInstall() InstallPaths
-	PackagingSpecs() []PackagingSpec
+	VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string
 
 	// TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive
 	// dependencies with dependency tags for which IsInstallDepNeeded() returns true.
 	TransitivePackagingSpecs() []PackagingSpec
 
 	ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator
+
+	// Get the information about the containers this module belongs to.
+	ContainersInfo() ContainersInfo
 }
 
 // Qualified id for a module
@@ -497,6 +498,9 @@
 
 	// The team (defined by the owner/vendor) who owns the property.
 	Team *string `android:"path"`
+
+	// vintf_fragment Modules required from this module.
+	Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"`
 }
 
 type distProperties struct {
@@ -832,20 +836,12 @@
 	primaryLicensesProperty applicableLicensesProperty
 
 	noAddressSanitizer   bool
-	installFiles         InstallPaths
 	installFilesDepSet   *DepSet[InstallPath]
-	checkbuildFiles      Paths
-	packagingSpecs       []PackagingSpec
 	packagingSpecsDepSet *DepSet[PackagingSpec]
-	// katiInstalls tracks the install rules that were created by Soong but are being exported
-	// to Make to convert to ninja rules so that Make can add additional dependencies.
-	katiInstalls katiInstalls
 	// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
 	// allowed to have duplicates across modules and variants.
 	katiInitRcInstalls katiInstalls
 	katiVintfInstalls  katiInstalls
-	katiSymlinks       katiInstalls
-	testData           []DataPath
 
 	// The files to copy to the dist as explicitly specified in the .bp file.
 	distFiles TaggedDistFiles
@@ -892,6 +888,10 @@
 	// complianceMetadataInfo is for different module types to dump metadata.
 	// See android.ModuleContext interface.
 	complianceMetadataInfo *ComplianceMetadataInfo
+
+	// containersInfo stores the information about the containers and the information of the
+	// apexes the module belongs to.
+	containersInfo ContainersInfo
 }
 
 func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1028,6 +1028,7 @@
 	fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil
 	if fullManifest {
 		addRequiredDeps(ctx)
+		addVintfFragmentDeps(ctx)
 	}
 }
 
@@ -1105,6 +1106,16 @@
 	}
 }
 
+var vintfDepTag = struct {
+	blueprint.BaseDependencyTag
+	InstallAlwaysNeededDependencyTag
+}{}
+
+func addVintfFragmentDeps(ctx BottomUpMutatorContext) {
+	mod := ctx.Module()
+	ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...)
+}
+
 // AddProperties "registers" the provided props
 // each value in props MUST be a pointer to a struct
 func (m *ModuleBase) AddProperties(props ...interface{}) {
@@ -1476,14 +1487,6 @@
 	return IsInstallDepNeededTag(tag)
 }
 
-func (m *ModuleBase) FilesToInstall() InstallPaths {
-	return m.installFiles
-}
-
-func (m *ModuleBase) PackagingSpecs() []PackagingSpec {
-	return m.packagingSpecs
-}
-
 func (m *ModuleBase) TransitivePackagingSpecs() []PackagingSpec {
 	return m.packagingSpecsDepSet.ToList()
 }
@@ -1597,6 +1600,10 @@
 	return m.base().commonProperties.Target_required
 }
 
+func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string {
+	return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
+}
+
 func (m *ModuleBase) InitRc() Paths {
 	return append(Paths{}, m.initRcPaths...)
 }
@@ -1615,18 +1622,26 @@
 	m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
 }
 
-func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
+func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) {
 	var allInstalledFiles InstallPaths
 	var allCheckbuildFiles Paths
 	ctx.VisitAllModuleVariants(func(module Module) {
 		a := module.base()
-		allInstalledFiles = append(allInstalledFiles, a.installFiles...)
+		var checkBuilds Paths
+		if a == m {
+			allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
+			checkBuilds = ctx.checkbuildFiles
+		} else {
+			info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider)
+			allInstalledFiles = append(allInstalledFiles, info.InstallFiles...)
+			checkBuilds = info.CheckbuildFiles
+		}
 		// A module's -checkbuild phony targets should
 		// not be created if the module is not exported to make.
 		// Those could depend on the build target and fail to compile
 		// for the current build target.
 		if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a) {
-			allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...)
+			allCheckbuildFiles = append(allCheckbuildFiles, checkBuilds...)
 		}
 	})
 
@@ -1763,6 +1778,19 @@
 
 }
 
+type InstallFilesInfo struct {
+	InstallFiles    InstallPaths
+	CheckbuildFiles Paths
+	PackagingSpecs  []PackagingSpec
+	// katiInstalls tracks the install rules that were created by Soong but are being exported
+	// to Make to convert to ninja rules so that Make can add additional dependencies.
+	KatiInstalls katiInstalls
+	KatiSymlinks katiInstalls
+	TestData     []DataPath
+}
+
+var InstallFilesProvider = blueprint.NewProvider[InstallFilesInfo]()
+
 func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
 	ctx := &moduleContext{
 		module:            m.module,
@@ -1944,12 +1972,14 @@
 			return
 		}
 
-		m.installFiles = append(m.installFiles, ctx.installFiles...)
-		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
-		m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...)
-		m.katiInstalls = append(m.katiInstalls, ctx.katiInstalls...)
-		m.katiSymlinks = append(m.katiSymlinks, ctx.katiSymlinks...)
-		m.testData = append(m.testData, ctx.testData...)
+		SetProvider(ctx, InstallFilesProvider, InstallFilesInfo{
+			InstallFiles:    ctx.installFiles,
+			CheckbuildFiles: ctx.checkbuildFiles,
+			PackagingSpecs:  ctx.packagingSpecs,
+			KatiInstalls:    ctx.katiInstalls,
+			KatiSymlinks:    ctx.katiSymlinks,
+			TestData:        ctx.testData,
+		})
 	} else if ctx.Config().AllowMissingDependencies() {
 		// If the module is not enabled it will not create any build rules, nothing will call
 		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -1965,15 +1995,15 @@
 		}
 	}
 
-	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, m.installFiles, dependencyInstallFiles)
-	m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, m.packagingSpecs, dependencyPackagingSpecs)
+	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
+	m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs)
 
 	buildLicenseMetadata(ctx, m.licenseMetadataFile)
 
 	if m.moduleInfoJSON != nil {
 		var installed InstallPaths
-		installed = append(installed, m.katiInstalls.InstallPaths()...)
-		installed = append(installed, m.katiSymlinks.InstallPaths()...)
+		installed = append(installed, ctx.katiInstalls.InstallPaths()...)
+		installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
 		installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
 		installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
 		installedStrings := installed.Strings()
@@ -1986,7 +2016,7 @@
 		}
 
 		var data []string
-		for _, d := range m.testData {
+		for _, d := range ctx.testData {
 			data = append(data, d.ToRelativeInstallPath())
 		}
 
@@ -2068,6 +2098,10 @@
 	return variant
 }
 
+func (m *ModuleBase) ContainersInfo() ContainersInfo {
+	return m.containersInfo
+}
+
 // Check the supplied dist structure to make sure that it is valid.
 //
 // property - the base property, e.g. dist or dists[1], which is combined with the
@@ -2666,7 +2700,7 @@
 	ctx.VisitAllModules(func(module Module) {
 		if module.Enabled(ctx) {
 			key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross}
-			osDeps[key] = append(osDeps[key], module.base().checkbuildFiles...)
+			osDeps[key] = append(osDeps[key], OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).CheckbuildFiles...)
 		}
 	})
 
diff --git a/android/module_context.go b/android/module_context.go
index 253bebd..f619da2 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -231,8 +231,8 @@
 	module          Module
 	phonies         map[string]Paths
 
-	katiInstalls []katiInstall
-	katiSymlinks []katiInstall
+	katiInstalls katiInstalls
+	katiSymlinks katiInstalls
 
 	testData []DataPath
 
diff --git a/android/provider.go b/android/provider.go
index 327f224..5ded4cc 100644
--- a/android/provider.go
+++ b/android/provider.go
@@ -32,6 +32,11 @@
 	return value.(K), ok
 }
 
+func OtherModuleProviderOrDefault[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) K {
+	value, _ := OtherModuleProvider(ctx, module, provider)
+	return value
+}
+
 // ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
 // TopDownMutatorContext for use in ModuleProvider.
 type ModuleProviderContext interface {
diff --git a/android/test_suites.go b/android/test_suites.go
index ff75f26..936d2b6 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -47,7 +47,8 @@
 					files[testSuite] = make(map[string]InstallPaths)
 				}
 				name := ctx.ModuleName(m)
-				files[testSuite][name] = append(files[testSuite][name], tsm.FilesToInstall()...)
+				files[testSuite][name] = append(files[testSuite][name],
+					OtherModuleProviderOrDefault(ctx, tsm, InstallFilesProvider).InstallFiles...)
 			}
 		}
 	})
diff --git a/android/testing.go b/android/testing.go
index a3e35cb..79d0c9b 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -126,6 +126,10 @@
 	ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc)
 })
 
+var PrepareForTestVintfFragmentModules = FixtureRegisterWithContext(func(ctx RegistrationContext) {
+	registerVintfFragmentComponents(ctx)
+})
+
 // Test fixture preparer that will register most java build components.
 //
 // Singletons and mutators should only be added here if they are needed for a majority of java
@@ -149,6 +153,7 @@
 	PrepareForTestWithPackageModule,
 	PrepareForTestWithPrebuilts,
 	PrepareForTestWithVisibility,
+	PrepareForTestVintfFragmentModules,
 )
 
 // Prepares an integration test with all build components from the android package.
diff --git a/android/variable.go b/android/variable.go
index 4025607..c141437 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -513,6 +513,11 @@
 	ProductPropFiles   []string `json:",omitempty"`
 
 	EnableUffdGc *string `json:",omitempty"`
+
+	BoardAvbEnable                         *bool    `json:",omitempty"`
+	BoardAvbSystemAddHashtreeFooterArgs    []string `json:",omitempty"`
+	DeviceFrameworkCompatibilityMatrixFile []string `json:",omitempty"`
+	DeviceProductCompatibilityMatrixFile   []string `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
diff --git a/android/variable_test.go b/android/variable_test.go
index 928bca6..73dc052 100644
--- a/android/variable_test.go
+++ b/android/variable_test.go
@@ -199,9 +199,7 @@
 			ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct {
 				Foo []string
 			}{}))
-			ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-				ctx.BottomUp("variable", VariableMutator).Parallel()
-			})
+			registerVariableBuildComponents(ctx)
 		}),
 		FixtureWithRootAndroidBp(bp),
 	).RunTest(t)
@@ -210,14 +208,14 @@
 var testProductVariableDefaultsProperties = struct {
 	Product_variables struct {
 		Eng struct {
-			Foo []string
+			Foo []string `android:"arch_variant"`
 			Bar []string
-		}
-	}
+		} `android:"arch_variant"`
+	} `android:"arch_variant"`
 }{}
 
 type productVariablesDefaultsTestProperties struct {
-	Foo []string
+	Foo []string `android:"arch_variant"`
 }
 
 type productVariablesDefaultsTestProperties2 struct {
@@ -242,7 +240,7 @@
 	module := &productVariablesDefaultsTestModule{}
 	module.AddProperties(&module.properties)
 	module.variableProperties = testProductVariableDefaultsProperties
-	InitAndroidModule(module)
+	InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
 	InitDefaultableModule(module)
 	return module
 }
@@ -324,3 +322,46 @@
 		})
 	}
 }
+
+// Test a defaults module that supports more product variable properties than the target module.
+func TestProductVariablesArch(t *testing.T) {
+	bp := `
+		test {
+			name: "foo",
+			arch: {
+				arm: {
+					product_variables: {
+						eng: {
+							foo: ["arm"],
+						},
+					},
+				},
+				arm64: {
+					product_variables: {
+						eng: {
+							foo: ["arm64"],
+						},
+					},
+				},
+			},
+			foo: ["module"],
+		}
+	`
+
+	result := GroupFixturePreparers(
+		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.Eng = boolPtr(true)
+		}),
+		PrepareForTestWithArchMutator,
+		PrepareForTestWithVariables,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
+		}),
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
+
+	foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*productVariablesDefaultsTestModule)
+
+	want := []string{"module", "arm64"}
+	AssertDeepEquals(t, "foo", want, foo.properties.Foo)
+}
diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go
new file mode 100644
index 0000000..329eac9
--- /dev/null
+++ b/android/vintf_fragment.go
@@ -0,0 +1,84 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+type vintfFragmentProperties struct {
+	// Vintf fragment XML file.
+	Src string `android:"path"`
+}
+
+type vintfFragmentModule struct {
+	ModuleBase
+
+	properties vintfFragmentProperties
+
+	installDirPath InstallPath
+	outputFilePath OutputPath
+}
+
+func init() {
+	registerVintfFragmentComponents(InitRegistrationContext)
+}
+
+func registerVintfFragmentComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("vintf_fragment", vintfLibraryFactory)
+}
+
+// vintf_fragment module processes vintf fragment file and installs under etc/vintf/manifest.
+// Vintf fragment files formerly listed in vintf_fragment property would be transformed into
+// this module type.
+func vintfLibraryFactory() Module {
+	m := &vintfFragmentModule{}
+	m.AddProperties(
+		&m.properties,
+	)
+	InitAndroidArchModule(m, DeviceSupported, MultilibFirst)
+
+	return m
+}
+
+func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	builder := NewRuleBuilder(pctx, ctx)
+	srcVintfFragment := PathForModuleSrc(ctx, m.properties.Src)
+	processedVintfFragment := PathForModuleOut(ctx, srcVintfFragment.Base())
+
+	// Process vintf fragment source file with assemble_vintf tool
+	builder.Command().
+		Flag("VINTF_IGNORE_TARGET_FCM_VERSION=true").
+		BuiltTool("assemble_vintf").
+		FlagWithInput("-i ", srcVintfFragment).
+		FlagWithOutput("-o ", processedVintfFragment)
+
+	builder.Build("assemble_vintf", "Process vintf fragment "+processedVintfFragment.String())
+
+	m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf", "manifest")
+	m.outputFilePath = processedVintfFragment.OutputPath
+
+	ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment)
+}
+
+// Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files
+func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries {
+	return []AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: OptionalPathForPath(m.outputFilePath),
+		ExtraEntries: []AndroidMkExtraEntriesFunc{
+			func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_PATH", m.installDirPath.String())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", m.outputFilePath.Base())
+			},
+		},
+	}}
+}
diff --git a/android/vintf_fragment_test.go b/android/vintf_fragment_test.go
new file mode 100644
index 0000000..8be534c
--- /dev/null
+++ b/android/vintf_fragment_test.go
@@ -0,0 +1,36 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestVintfManifestBuildAction(t *testing.T) {
+	bp := `
+	vintf_fragment {
+		name: "test_vintf_fragment",
+		src: "test_vintf_file",
+	}
+	`
+
+	testResult := PrepareForTestWithAndroidBuildComponents.RunTestWithBp(t, bp)
+
+	vintfFragmentBuild := testResult.TestContext.ModuleForTests("test_vintf_fragment", "android_arm64_armv8-a").Rule("assemble_vintf")
+	if !strings.Contains(vintfFragmentBuild.RuleParams.Command, "assemble_vintf") {
+		t.Errorf("Vintf_manifest build command does not process with assemble_vintf : " + vintfFragmentBuild.RuleParams.Command)
+	}
+}
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 373e883..a2486fd 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -46,6 +46,9 @@
 
 	outputBaseName string
 	outputFile     android.OptionalPath
+
+	// TODO(b/357908583): Temp field, remove this once we support Android Mk providers
+	installFile android.InstallPath
 }
 
 type remapProperties struct {
@@ -234,14 +237,18 @@
 
 	s.outputBaseName = name
 	s.outputFile = android.OptionalPathForPath(outputZipFile)
-	ctx.InstallFile(android.PathForModuleInstall(ctx, "sdk-repo"), name+".zip", outputZipFile)
+	installPath := android.PathForModuleInstall(ctx, "sdk-repo")
+	name = name + ".zip"
+	ctx.InstallFile(installPath, name, outputZipFile)
+	// TODO(b/357908583): Temp field, remove this once we support Android Mk providers
+	s.installFile = installPath.Join(ctx, name)
 }
 
 func (s *sdkRepoHost) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			fmt.Fprintln(w, ".PHONY:", name, "sdk_repo", "sdk-repo-"+name)
-			fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", strings.Join(s.FilesToInstall().Strings(), " "))
+			fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", s.installFile.String())
 
 			fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-FILE_NAME_TAG_PLACEHOLDER.zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
 		},
diff --git a/apex/apex.go b/apex/apex.go
index fc0500a..dd1c0b5 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2370,6 +2370,7 @@
 	a.providePrebuiltInfo(ctx)
 
 	a.required = a.RequiredModuleNames(ctx)
+	a.required = append(a.required, a.VintfFragmentModuleNames(ctx)...)
 
 	a.setOutputFiles(ctx)
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d6c8a8a..c37c7d0 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -384,7 +384,7 @@
 			symlink_preferred_arch: true,
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex", "com.android.gki.*" ],
+			apex_available: [ "myapex" ],
 		}
 
 		rust_binary {
@@ -432,14 +432,6 @@
 			apex_available: ["myapex"],
 		}
 
-		apex {
-			name: "com.android.gki.fake",
-			binaries: ["foo"],
-			key: "myapex.key",
-			file_contexts: ":myapex-file_contexts",
-			updatable: false,
-		}
-
 		cc_library_shared {
 			name: "mylib2",
 			srcs: ["mylib.cpp"],
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 20a13c3..8cdfb89 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -516,7 +516,7 @@
 	// This cannot be marked as `android:"arch_variant"` because the `prebuilt_apex` is only mutated
 	// for android_common. That is so that it will have the same arch variant as, and so be compatible
 	// with, the source `apex` module type that it replaces.
-	Src  *string `android:"path"`
+	Src  proptools.Configurable[string] `android:"path,replace_instead_of_append"`
 	Arch struct {
 		Arm struct {
 			Src *string `android:"path"`
@@ -566,7 +566,7 @@
 		src = String(p.Arch.X86_64.Src)
 	}
 	if src == "" {
-		src = String(p.Src)
+		src = p.Src.GetOrDefault(ctx, "")
 	}
 
 	if src == "" {
@@ -779,7 +779,7 @@
 func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
 	if p.hasExportedDeps() {
 		// Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
-		// The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars)
+		// The deapexer will return a provider which will be used to determine the exported artfifacts from this prebuilt.
 		ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.Name()))
 	}
 }
diff --git a/cc/builder.go b/cc/builder.go
index a05a16d..cd535c1 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -22,6 +22,7 @@
 	"fmt"
 	"path/filepath"
 	"runtime"
+	"slices"
 	"strconv"
 	"strings"
 
@@ -910,6 +911,16 @@
 		"ldFlags":       flags.globalLdFlags + " " + flags.localLdFlags,
 		"crtEnd":        strings.Join(crtEnd.Strings(), " "),
 	}
+
+	// On Windows, we always generate a PDB file
+	// --strip-debug is needed to also keep COFF symbols which are needed when
+	// we patch binaries with symbol_inject.
+	if ctx.Windows() {
+		pdb := outputFile.ReplaceExtension(ctx, "pdb")
+		args["ldFlags"] = args["ldFlags"] + " -Wl,--strip-debug -Wl,--pdb=" + pdb.String() + " "
+		implicitOutputs = append(slices.Clone(implicitOutputs), pdb)
+	}
+
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
 		rule = ldRE
 		args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",")
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index 8f3ad96..600ac47 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -476,7 +476,8 @@
 		var prebuiltsList android.Paths
 
 		ctx.VisitDirectDepsWithTag(cmakeSnapshotPrebuiltTag, func(dep android.Module) {
-			for _, file := range dep.FilesToInstall() {
+			for _, file := range android.OtherModuleProviderOrDefault(
+				ctx, dep, android.InstallFilesProvider).InstallFiles {
 				prebuiltsList = append(prebuiltsList, file)
 			}
 		})
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 1e61b01..ea7d342 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -43,6 +43,10 @@
 		"-mno-ms-bitfields",
 
 		"--sysroot ${WindowsGccRoot}/${WindowsGccTriple}",
+
+		// Windows flags to generate PDB
+		"-g",
+		"-gcodeview",
 	}
 
 	windowsIncludeFlags = []string{
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 57a3b3a..e002931 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -18,6 +18,7 @@
 	"path/filepath"
 
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 )
 
@@ -44,7 +45,7 @@
 }
 
 // Returns the NDK base include path for use with sdk_version current. Usable with -I.
-func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath {
+func getCurrentIncludePath(ctx android.PathContext) android.OutputPath {
 	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
 }
 
@@ -73,6 +74,13 @@
 
 	// Path to the NOTICE file associated with the headers.
 	License *string `android:"path"`
+
+	// Set to true if the headers installed by this module should skip
+	// verification. This step ensures that each header is self-contained (can
+	// be #included alone) and is valid C. This should not be disabled except in
+	// rare cases. Outside bionic and external, if you're using this option
+	// you've probably made a mistake.
+	Skip_verification *bool
 }
 
 type headerModule struct {
@@ -309,6 +317,13 @@
 
 	// Path to the NOTICE file associated with the headers.
 	License *string
+
+	// Set to true if the headers installed by this module should skip
+	// verification. This step ensures that each header is self-contained (can
+	// be #included alone) and is valid C. This should not be disabled except in
+	// rare cases. Outside bionic and external, if you're using this option
+	// you've probably made a mistake.
+	Skip_verification *bool
 }
 
 type preprocessedHeadersModule struct {
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 3c48f68..f571523 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -54,7 +54,22 @@
 
 import (
 	"android/soong/android"
+	"fmt"
+	"path/filepath"
 	"strings"
+
+	"github.com/google/blueprint"
+)
+
+var (
+	verifyCCompat = pctx.AndroidStaticRule("verifyCCompat",
+		blueprint.RuleParams{
+			Command:     "$ccCmd -x c -fsyntax-only $flags $in && touch $out",
+			CommandDeps: []string{"$ccCmd"},
+		},
+		"ccCmd",
+		"flags",
+	)
 )
 
 func init() {
@@ -103,6 +118,45 @@
 	return android.PathForOutput(ctx, "ndk_abi_headers.txt")
 }
 
+func verifyNdkHeaderIsCCompatible(ctx android.SingletonContext,
+	src android.Path, dest android.Path) android.Path {
+	sysrootInclude := getCurrentIncludePath(ctx)
+	baseOutputDir := android.PathForOutput(ctx, "c-compat-verification")
+	installRelPath, err := filepath.Rel(sysrootInclude.String(), dest.String())
+	if err != nil {
+		ctx.Errorf("filepath.Rel(%q, %q) failed: %s", dest, sysrootInclude, err)
+	}
+	output := baseOutputDir.Join(ctx, installRelPath)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        verifyCCompat,
+		Description: fmt.Sprintf("Verifying C compatibility of %s", src),
+		Output:      output,
+		Input:       dest,
+		// Ensures that all the headers in the sysroot are already installed
+		// before testing any of the headers for C compatibility, and also that
+		// the check will be re-run whenever the sysroot changes. This is
+		// necessary because many of the NDK headers depend on other NDK
+		// headers, but we don't have explicit dependency tracking for that.
+		Implicits: []android.Path{getNdkHeadersTimestampFile(ctx)},
+		Args: map[string]string{
+			"ccCmd": "${config.ClangBin}/clang",
+			"flags": fmt.Sprintf(
+				// Ideally we'd check each ABI, multiple API levels,
+				// fortify/non-fortify, and a handful of other variations. It's
+				// a lot more difficult to do that though, and would eat up more
+				// build time. All the problems we've seen so far that this
+				// check would catch have been in arch-generic and
+				// minSdkVersion-generic code in frameworks though, so this is a
+				// good place to start.
+				"-target aarch64-linux-android%d --sysroot %s",
+				android.FutureApiLevel.FinalOrFutureInt(),
+				getNdkSysrootBase(ctx).String(),
+			),
+		},
+	})
+	return output
+}
+
 func NdkSingleton() android.Singleton {
 	return &ndkSingleton{}
 }
@@ -143,10 +197,17 @@
 
 type ndkSingleton struct{}
 
+type srcDestPair struct {
+	src  android.Path
+	dest android.Path
+}
+
 func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var staticLibInstallPaths android.Paths
 	var headerSrcPaths android.Paths
 	var headerInstallPaths android.Paths
+	var headersToVerify []srcDestPair
+	var headerCCompatVerificationTimestampPaths android.Paths
 	var installPaths android.Paths
 	var licensePaths android.Paths
 	ctx.VisitAllModules(func(module android.Module) {
@@ -157,6 +218,14 @@
 		if m, ok := module.(*headerModule); ok {
 			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
 			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
+			if !Bool(m.properties.Skip_verification) {
+				for i, installPath := range m.installPaths {
+					headersToVerify = append(headersToVerify, srcDestPair{
+						src:  m.srcPaths[i],
+						dest: installPath,
+					})
+				}
+			}
 			installPaths = append(installPaths, m.installPaths...)
 			licensePaths = append(licensePaths, m.licensePath)
 		}
@@ -164,6 +233,10 @@
 		if m, ok := module.(*versionedHeaderModule); ok {
 			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
 			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
+			// Verification intentionally not done for headers that go through
+			// versioner. It'd be nice to have, but the only user is bionic, and
+			// that one module would also need to use skip_verification, so it
+			// wouldn't help at all.
 			installPaths = append(installPaths, m.installPaths...)
 			licensePaths = append(licensePaths, m.licensePath)
 		}
@@ -171,6 +244,14 @@
 		if m, ok := module.(*preprocessedHeadersModule); ok {
 			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
 			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
+			if !Bool(m.properties.Skip_verification) {
+				for i, installPath := range m.installPaths {
+					headersToVerify = append(headersToVerify, srcDestPair{
+						src:  m.srcPaths[i],
+						dest: installPath,
+					})
+				}
+			}
 			installPaths = append(installPaths, m.installPaths...)
 			licensePaths = append(licensePaths, m.licensePath)
 		}
@@ -223,6 +304,12 @@
 		Implicits: headerInstallPaths,
 	})
 
+	for _, srcDestPair := range headersToVerify {
+		headerCCompatVerificationTimestampPaths = append(
+			headerCCompatVerificationTimestampPaths,
+			verifyNdkHeaderIsCCompatible(ctx, srcDestPair.src, srcDestPair.dest))
+	}
+
 	writeNdkAbiSrcFilter(ctx, headerSrcPaths, getNdkABIHeadersFile(ctx))
 
 	fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))
@@ -235,6 +322,6 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:      android.Touch,
 		Output:    getNdkFullTimestampFile(ctx),
-		Implicits: fullDepPaths,
+		Implicits: append(fullDepPaths, headerCCompatVerificationTimestampPaths...),
 	})
 }
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 47c6cb9..f15a604 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -39,8 +39,9 @@
 }
 
 // Get target file name to be installed from this module
-func getInstalledFileName(m *Module) string {
-	for _, ps := range m.PackagingSpecs() {
+func getInstalledFileName(ctx android.SingletonContext, m *Module) string {
+	for _, ps := range android.OtherModuleProviderOrDefault(
+		ctx, m.Module(), android.InstallFilesProvider).PackagingSpecs {
 		if name := ps.FileName(); name != "" {
 			return name
 		}
@@ -53,7 +54,7 @@
 	ctx.VisitAllModules(func(module android.Module) {
 		if m, ok := module.(*Module); ok {
 			if IsStubTarget(m) {
-				if name := getInstalledFileName(m); name != "" {
+				if name := getInstalledFileName(ctx, m); name != "" {
 					s.stubLibraryMap[name] = true
 					if m.InVendor() {
 						s.stubVendorLibraryMap[name] = true
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 69d922d..a8fd368 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -61,7 +61,8 @@
 
 	deps := s.gatherFilteredPackagingSpecs(ctx)
 	ctx.WalkDeps(func(child, parent android.Module) bool {
-		for _, ps := range child.PackagingSpecs() {
+		for _, ps := range android.OtherModuleProviderOrDefault(
+			ctx, child, android.InstallFilesProvider).PackagingSpecs {
 			if _, ok := deps[ps.RelPathInPackage()]; ok {
 				modulesInPackageByModule[child] = true
 				modulesInPackageByName[child.Name()] = true
diff --git a/java/aar.go b/java/aar.go
index c8563c8..e6ad502 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1154,8 +1154,9 @@
 
 	if Bool(a.properties.Jetifier) {
 		inputFile := a.aarPath
-		a.aarPath = android.PathForModuleOut(ctx, "jetifier", aarName)
-		TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile)
+		jetifierPath := android.PathForModuleOut(ctx, "jetifier", aarName)
+		TransformJetifier(ctx, jetifierPath, inputFile)
+		a.aarPath = jetifierPath
 	}
 
 	jarName := ctx.ModuleName() + ".jar"
@@ -1306,11 +1307,12 @@
 		addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary)
 	})
 
-	var implementationJarFile android.OutputPath
+	var implementationJarFile android.Path
 	if len(staticJars) > 0 {
 		combineJars := append(android.Paths{classpathFile}, staticJars...)
-		implementationJarFile = android.PathForModuleOut(ctx, "combined", jarName).OutputPath
-		TransformJarsToJar(ctx, implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+		combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName).OutputPath
+		TransformJarsToJar(ctx, combinedImplementationJar, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+		implementationJarFile = combinedImplementationJar
 	} else {
 		implementationJarFile = classpathFile
 	}
@@ -1329,7 +1331,7 @@
 	implementationAndResourcesJar := implementationJarFile
 	if resourceJarFile != nil {
 		jars := android.Paths{resourceJarFile, implementationAndResourcesJar}
-		combinedJar := android.PathForModuleOut(ctx, "withres", jarName).OutputPath
+		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
 		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
 			false, nil, nil)
 		implementationAndResourcesJar = combinedJar
diff --git a/java/app.go b/java/app.go
index 19dc8d5..1ebf658 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1109,7 +1109,7 @@
 						coverageFile:   dep.CoverageOutputFile(),
 						unstrippedFile: dep.UnstrippedOutputFile(),
 						partition:      dep.Partition(),
-						installPaths:   dep.FilesToInstall(),
+						installPaths:   android.OtherModuleProviderOrDefault(ctx, dep, android.InstallFilesProvider).InstallFiles,
 					})
 				} else if ctx.Config().AllowMissingDependencies() {
 					ctx.AddMissingDependencies([]string{otherName})
diff --git a/java/base.go b/java/base.go
index 8a4c64d..4ab82c5 100644
--- a/java/base.go
+++ b/java/base.go
@@ -222,6 +222,13 @@
 	// the stubs via libs, but should be set to true when the module depends on
 	// the stubs via static libs.
 	Is_stubs_module *bool
+
+	// If true, enable the "Ravenizer" tool on the output jar.
+	// "Ravenizer" is a tool for Ravenwood tests, but it can also be enabled on other kinds
+	// of java targets.
+	Ravenizer struct {
+		Enabled *bool
+	}
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -558,13 +565,23 @@
 	// List of soong module dependencies required to compile the current module.
 	// This information is printed out to `Dependencies` field in module_bp_java_deps.json
 	compileDepNames []string
+
+	ravenizer struct {
+		enabled bool
+	}
 }
 
 var _ android.InstallableModule = (*Module)(nil)
 
 // To satisfy the InstallableModule interface
-func (j *Module) EnforceApiContainerChecks() bool {
-	return true
+func (j *Module) StaticDependencyTags() []blueprint.DependencyTag {
+	return []blueprint.DependencyTag{staticLibTag}
+}
+
+// To satisfy the InstallableModule interface
+func (j *Module) DynamicDependencyTags() []blueprint.DependencyTag {
+	return []blueprint.DependencyTag{libTag, sdkLibTag, bootClasspathTag, systemModulesTag,
+		instrumentationForTag, java9LibTag}
 }
 
 // Overrides android.ModuleBase.InstallInProduct()
@@ -875,9 +892,12 @@
 	if j.hasSrcExt(".kt") {
 		// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
 		// Kotlin files
-		ctx.AddVariationDependencies(nil, kotlinStdlibTag,
-			"kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
-		ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
+		tag := staticLibTag
+		if !BoolDefault(j.properties.Static_kotlin_stdlib, true) {
+			tag = libTag
+		}
+		ctx.AddVariationDependencies(nil, tag,
+			"kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8", "kotlin-annotations")
 	}
 
 	// Framework libraries need special handling in static coverage builds: they should not have
@@ -1113,7 +1133,6 @@
 }
 
 func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
-
 	// Auto-propagating jarjar rules
 	jarjarProviderData := j.collectJarJarRules(ctx)
 	if jarjarProviderData != nil {
@@ -1130,6 +1149,10 @@
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
+	if re := proptools.Bool(j.properties.Ravenizer.Enabled); re {
+		j.ravenizer.enabled = re
+	}
+
 	deps := j.collectDeps(ctx)
 	flags := j.collectBuilderFlags(ctx, deps)
 
@@ -1211,7 +1234,6 @@
 
 	var kotlinJars android.Paths
 	var kotlinHeaderJars android.Paths
-	var kotlinExtraJars android.Paths
 
 	// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
 	// any dependencies so that it can override any non-final R classes from dependencies with the
@@ -1290,9 +1312,6 @@
 		// Collect common .kt files for AIDEGen
 		j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...)
 
-		flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
-		flags.classpath = append(flags.classpath, deps.kotlinAnnotations...)
-
 		flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...)
 		flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...)
 
@@ -1322,8 +1341,6 @@
 
 		kotlinJars = append(kotlinJars, kotlinJarPath)
 		kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
-		kotlinExtraJars = append(kotlinExtraJars, deps.kotlinStdlib...)
-		kotlinExtraJars = append(kotlinExtraJars, deps.kotlinAnnotations...)
 	}
 
 	jars := slices.Clone(kotlinJars)
@@ -1342,9 +1359,6 @@
 			// with sharding enabled. See: b/77284273.
 		}
 		extraJars := slices.Clone(kotlinHeaderJars)
-		if BoolDefault(j.properties.Static_kotlin_stdlib, true) {
-			extraJars = append(extraJars, kotlinExtraJars...)
-		}
 		extraJars = append(extraJars, extraCombinedJars...)
 		var combinedHeaderJarFile android.Path
 		headerJarFileWithoutDepsOrJarjar, combinedHeaderJarFile =
@@ -1423,13 +1437,6 @@
 		}
 	}
 
-	// Jar kotlin classes into the final jar after javac
-	if BoolDefault(j.properties.Static_kotlin_stdlib, true) {
-		jars = append(jars, kotlinExtraJars...)
-	} else {
-		flags.dexClasspath = append(flags.dexClasspath, kotlinExtraJars...)
-	}
-
 	jars = append(jars, extraCombinedJars...)
 
 	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
@@ -1568,6 +1575,18 @@
 		return
 	}
 
+	if j.ravenizer.enabled {
+		ravenizerInput := outputFile
+		ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", jarName)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        ravenizer,
+			Description: "ravenizer",
+			Input:       ravenizerInput,
+			Output:      ravenizerOutput,
+		})
+		outputFile = ravenizerOutput
+	}
+
 	// Check package restrictions if necessary.
 	if len(j.properties.Permitted_packages) > 0 {
 		// Time stamp file created by the package check rule.
@@ -2343,10 +2362,6 @@
 				} else {
 					ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
 				}
-			case kotlinStdlibTag:
-				deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...)
-			case kotlinAnnotationsTag:
-				deps.kotlinAnnotations = dep.HeaderJars
 			case kotlinPluginTag:
 				deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...)
 			case syspropPublicStubDepTag:
@@ -2570,8 +2585,6 @@
 					return RenameUseInclude, "tagswitch"
 				case exportedPluginTag:
 					return RenameUseInclude, "tagswitch"
-				case kotlinStdlibTag, kotlinAnnotationsTag:
-					return RenameUseExclude, "tagswitch"
 				case kotlinPluginTag:
 					return RenameUseInclude, "tagswitch"
 				default:
diff --git a/java/builder.go b/java/builder.go
index 5d84d0b..49207e5 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -156,7 +156,7 @@
 	turbine, turbineRE = pctx.RemoteStaticRules("turbine",
 		blueprint.RuleParams{
 			Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} $outputFlags ` +
-				`--sources @$out.rsp  --source_jars $srcJars ` +
+				`--sources @$out.rsp ` +
 				`--javacopts ${config.CommonJdkFlags} ` +
 				`$javacFlags -source $javaVersion -target $javaVersion -- $turbineFlags && ` +
 				`(for o in $outputs; do if cmp -s $${o}.tmp $${o} ; then rm $${o}.tmp ; else mv $${o}.tmp $${o} ; fi; done )`,
@@ -170,13 +170,13 @@
 		},
 		&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
 			ExecStrategy:    "${config.RETurbineExecStrategy}",
-			Inputs:          []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
-			RSPFiles:        []string{"${out}.rsp"},
+			Inputs:          []string{"${config.TurbineJar}", "${out}.rsp", "$rbeInputs"},
+			RSPFiles:        []string{"$out.rsp", "$rspFiles"},
 			OutputFiles:     []string{"$rbeOutputs"},
 			ToolchainInputs: []string{"${config.JavaCmd}"},
 			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		},
-		[]string{"javacFlags", "turbineFlags", "outputFlags", "javaVersion", "outputs", "rbeOutputs", "srcJars"}, []string{"implicits"})
+		[]string{"javacFlags", "turbineFlags", "outputFlags", "javaVersion", "outputs", "rbeOutputs"}, []string{"rbeInputs", "rspFiles"})
 
 	jar, jarRE = pctx.RemoteStaticRules("jar",
 		blueprint.RuleParams{
@@ -258,6 +258,13 @@
 		},
 	)
 
+	ravenizer = pctx.AndroidStaticRule("ravenizer",
+		blueprint.RuleParams{
+			Command:     "rm -f $out && ${ravenizer} --in-jar $in --out-jar $out",
+			CommandDeps: []string{"${ravenizer}"},
+		},
+	)
+
 	zipalign = pctx.AndroidStaticRule("zipalign",
 		blueprint.RuleParams{
 			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
@@ -307,6 +314,7 @@
 	pctx.Import("android/soong/java/config")
 
 	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("ravenizer", "ravenizer")
 	pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
 }
 
@@ -428,53 +436,72 @@
 		})
 }
 
-func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string) (string, android.Paths) {
-	var deps android.Paths
+func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string, srcJars android.Paths) (string, android.Paths, android.Paths, android.Paths) {
+	var implicits android.Paths
+	var rbeInputs android.Paths
+	var rspFiles android.Paths
 
 	classpath := flags.classpath
 
-	var bootClasspath string
+	srcJarArgs := strings.Join(srcJars.Strings(), " ")
+	implicits = append(implicits, srcJars...)
+	const srcJarArgsLimit = 32 * 1024
+	if len(srcJarArgs) > srcJarArgsLimit {
+		srcJarRspFile := android.PathForModuleOut(ctx, "turbine", "srcjars.rsp")
+		android.WriteFileRule(ctx, srcJarRspFile, srcJarArgs)
+		srcJarArgs = "@" + srcJarRspFile.String()
+		implicits = append(implicits, srcJarRspFile)
+		rbeInputs = append(rbeInputs, srcJarRspFile)
+	} else {
+		rbeInputs = append(rbeInputs, srcJars...)
+	}
+
+	var bootClasspathFlags string
 	if flags.javaVersion.usesJavaModules() {
 		var systemModuleDeps android.Paths
-		bootClasspath, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device())
-		deps = append(deps, systemModuleDeps...)
+		bootClasspathFlags, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device())
+		implicits = append(implicits, systemModuleDeps...)
+		rbeInputs = append(rbeInputs, systemModuleDeps...)
 		classpath = append(flags.java9Classpath, classpath...)
 	} else {
-		deps = append(deps, flags.bootClasspath...)
+		implicits = append(implicits, flags.bootClasspath...)
+		rbeInputs = append(rbeInputs, flags.bootClasspath...)
 		if len(flags.bootClasspath) == 0 && ctx.Device() {
 			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
 			// ensure turbine does not fall back to the default bootclasspath.
-			bootClasspath = `--bootclasspath ""`
+			bootClasspathFlags = `--bootclasspath ""`
 		} else {
-			bootClasspath = flags.bootClasspath.FormTurbineClassPath("--bootclasspath ")
+			bootClasspathFlags = flags.bootClasspath.FormTurbineClassPath("--bootclasspath ")
 		}
 	}
 
-	deps = append(deps, classpath...)
-	turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ")
-
-	const flagsLimit = 32 * 1024
-	if len(turbineFlags) > flagsLimit {
-		flagsRspFile := android.PathForModuleOut(ctx, dir, "turbine-flags.rsp")
-		android.WriteFileRule(ctx, flagsRspFile, turbineFlags)
-		turbineFlags = "@" + flagsRspFile.String()
-		deps = append(deps, flagsRspFile)
+	classpathFlags := classpath.FormTurbineClassPath("")
+	implicits = append(implicits, classpath...)
+	const classpathLimit = 32 * 1024
+	if len(classpathFlags) > classpathLimit {
+		classpathRspFile := android.PathForModuleOut(ctx, dir, "classpath.rsp")
+		android.WriteFileRule(ctx, classpathRspFile, classpathFlags)
+		classpathFlags = "@" + classpathRspFile.String()
+		implicits = append(implicits, classpathRspFile)
+		rspFiles = append(rspFiles, classpathRspFile)
+		rbeInputs = append(rbeInputs, classpathRspFile)
+	} else {
+		rbeInputs = append(rbeInputs, classpath...)
 	}
 
-	return turbineFlags, deps
+	turbineFlags := "--source_jars " + srcJarArgs + " " + bootClasspathFlags + " --classpath " + classpathFlags
+
+	return turbineFlags, implicits, rbeInputs, rspFiles
 }
 
 func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
 
-	turbineFlags, deps := turbineFlags(ctx, flags, "turbine")
-
-	deps = append(deps, srcJars...)
+	turbineFlags, implicits, rbeInputs, rspFiles := turbineFlags(ctx, flags, "turbine", srcJars)
 
 	rule := turbine
 	args := map[string]string{
 		"javacFlags":   flags.javacFlags,
-		"srcJars":      strings.Join(srcJars.Strings(), " "),
 		"javaVersion":  flags.javaVersion.String(),
 		"turbineFlags": turbineFlags,
 		"outputFlags":  "--output " + outputFile.String() + ".tmp",
@@ -482,15 +509,16 @@
 	}
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
 		rule = turbineRE
-		args["implicits"] = strings.Join(deps.Strings(), ",")
+		args["rbeInputs"] = strings.Join(rbeInputs.Strings(), ",")
 		args["rbeOutputs"] = outputFile.String() + ".tmp"
+		args["rspFiles"] = strings.Join(rspFiles.Strings(), ",")
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "turbine",
 		Output:      outputFile,
 		Inputs:      srcFiles,
-		Implicits:   deps,
+		Implicits:   implicits,
 		Args:        args,
 	})
 }
@@ -499,11 +527,10 @@
 func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath,
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
 
-	turbineFlags, deps := turbineFlags(ctx, flags, "kapt")
+	turbineFlags, implicits, rbeInputs, rspFiles := turbineFlags(ctx, flags, "turbine-apt", srcJars)
 
-	deps = append(deps, srcJars...)
-
-	deps = append(deps, flags.processorPath...)
+	implicits = append(implicits, flags.processorPath...)
+	rbeInputs = append(rbeInputs, flags.processorPath...)
 	turbineFlags += " " + flags.processorPath.FormTurbineClassPath("--processorpath ")
 	turbineFlags += " --processors " + strings.Join(flags.processors, " ")
 
@@ -514,7 +541,6 @@
 	rule := turbine
 	args := map[string]string{
 		"javacFlags":   flags.javacFlags,
-		"srcJars":      strings.Join(srcJars.Strings(), " "),
 		"javaVersion":  flags.javaVersion.String(),
 		"turbineFlags": turbineFlags,
 		"outputFlags":  outputFlags,
@@ -522,8 +548,9 @@
 	}
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
 		rule = turbineRE
-		args["implicits"] = strings.Join(deps.Strings(), ",")
+		args["rbeInputs"] = strings.Join(rbeInputs.Strings(), ",")
 		args["rbeOutputs"] = outputSrcJar.String() + ".tmp," + outputResJar.String() + ".tmp"
+		args["rspFiles"] = strings.Join(rspFiles.Strings(), ",")
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            rule,
@@ -531,7 +558,7 @@
 		Output:          outputs[0],
 		ImplicitOutputs: outputs[1:],
 		Inputs:          srcFiles,
-		Implicits:       deps,
+		Implicits:       implicits,
 		Args:            args,
 	})
 }
@@ -746,6 +773,16 @@
 	})
 }
 
+func TransformRavenizer(ctx android.ModuleContext, outputFile android.WritablePath,
+	inputFile android.Path) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        ravenizer,
+		Description: "ravenizer",
+		Output:      outputFile,
+		Input:       inputFile,
+	})
+}
+
 func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) {
 	android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
 }
diff --git a/java/config/config.go b/java/config/config.go
index 66e857c..a50c1b4 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -47,7 +47,7 @@
 		"services",
 		"android.car",
 		"android.car7",
-		"android.car.builtin",
+		"android.car.builtin.impl",
 		"conscrypt",
 		"core-icu4j",
 		"core-oj",
diff --git a/java/container_test.go b/java/container_test.go
index 3441855..25cfa4c 100644
--- a/java/container_test.go
+++ b/java/container_test.go
@@ -65,6 +65,18 @@
 				"general-tests",
 			],
 		}
+		java_library {
+			name: "bar",
+			static_libs: [
+				"framework-minus-apex",
+			],
+		}
+		java_library {
+			name: "baz",
+			static_libs: [
+				"bar",
+			],
+		}
 	`)
 
 	testcases := []struct {
@@ -73,6 +85,7 @@
 		isVendorContainer  bool
 		isProductContainer bool
 		isCts              bool
+		isUnstable         bool
 	}{
 		{
 			moduleName:         "foo",
@@ -80,6 +93,7 @@
 			isVendorContainer:  false,
 			isProductContainer: false,
 			isCts:              false,
+			isUnstable:         false,
 		},
 		{
 			moduleName:         "foo_vendor",
@@ -87,6 +101,7 @@
 			isVendorContainer:  true,
 			isProductContainer: false,
 			isCts:              false,
+			isUnstable:         false,
 		},
 		{
 			moduleName:         "foo_soc_specific",
@@ -94,6 +109,7 @@
 			isVendorContainer:  true,
 			isProductContainer: false,
 			isCts:              false,
+			isUnstable:         false,
 		},
 		{
 			moduleName:         "foo_product_specific",
@@ -101,6 +117,7 @@
 			isVendorContainer:  false,
 			isProductContainer: true,
 			isCts:              false,
+			isUnstable:         false,
 		},
 		{
 			moduleName:         "foo_cts_test",
@@ -108,6 +125,7 @@
 			isVendorContainer:  false,
 			isProductContainer: false,
 			isCts:              true,
+			isUnstable:         false,
 		},
 		{
 			moduleName:         "foo_non_cts_test",
@@ -115,6 +133,23 @@
 			isVendorContainer:  false,
 			isProductContainer: false,
 			isCts:              false,
+			isUnstable:         false,
+		},
+		{
+			moduleName:         "bar",
+			isSystemContainer:  true,
+			isVendorContainer:  false,
+			isProductContainer: false,
+			isCts:              false,
+			isUnstable:         true,
+		},
+		{
+			moduleName:         "baz",
+			isSystemContainer:  true,
+			isVendorContainer:  false,
+			isProductContainer: false,
+			isCts:              false,
+			isUnstable:         true,
 		},
 	}
 
@@ -125,5 +160,7 @@
 		checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers))
 		checkContainerMatch(t, c.moduleName, "vendor", c.isVendorContainer, android.InList(android.VendorContainer, belongingContainers))
 		checkContainerMatch(t, c.moduleName, "product", c.isProductContainer, android.InList(android.ProductContainer, belongingContainers))
+		checkContainerMatch(t, c.moduleName, "cts", c.isCts, android.InList(android.CtsContainer, belongingContainers))
+		checkContainerMatch(t, c.moduleName, "unstable", c.isUnstable, android.InList(android.UnstableContainer, belongingContainers))
 	}
 }
diff --git a/java/java.go b/java/java.go
index 126d8f3..258ebba 100644
--- a/java/java.go
+++ b/java/java.go
@@ -421,8 +421,6 @@
 	bootClasspathTag        = dependencyTag{name: "bootclasspath", runtimeLinked: true}
 	systemModulesTag        = dependencyTag{name: "system modules", runtimeLinked: true}
 	frameworkResTag         = dependencyTag{name: "framework-res"}
-	kotlinStdlibTag         = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true}
-	kotlinAnnotationsTag    = dependencyTag{name: "kotlin-annotations", runtimeLinked: true}
 	kotlinPluginTag         = dependencyTag{name: "kotlin-plugin", toolchain: true}
 	proguardRaiseTag        = dependencyTag{name: "proguard-raise"}
 	certificateTag          = dependencyTag{name: "certificate"}
@@ -458,8 +456,6 @@
 		bootClasspathTag,
 		systemModulesTag,
 		java9LibTag,
-		kotlinStdlibTag,
-		kotlinAnnotationsTag,
 		kotlinPluginTag,
 		syspropPublicStubDepTag,
 		instrumentationForTag,
@@ -568,8 +564,6 @@
 	srcJars                 android.Paths
 	systemModules           *systemModules
 	aidlPreprocess          android.OptionalPath
-	kotlinStdlib            android.Paths
-	kotlinAnnotations       android.Paths
 	kotlinPlugins           android.Paths
 	aconfigProtoFiles       android.Paths
 
@@ -2640,6 +2634,7 @@
 
 	j.collectTransitiveHeaderJars(ctx)
 	var staticJars android.Paths
+	var staticResourceJars android.Paths
 	var staticHeaderJars android.Paths
 	ctx.VisitDirectDeps(func(module android.Module) {
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -2650,7 +2645,8 @@
 				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
 			case staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
-				staticJars = append(staticJars, dep.ImplementationAndResourcesJars...)
+				staticJars = append(staticJars, dep.ImplementationJars...)
+				staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
 				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
@@ -2670,43 +2666,67 @@
 
 	// Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output
 	// file of the module to be named jarName.
-	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
+	var outputFile android.Path
+	combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName)
 	implementationJars := append(slices.Clone(jars), staticJars...)
-	TransformJarsToJar(ctx, outputFile, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
+	TransformJarsToJar(ctx, combinedImplementationJar, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
 		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+	outputFile = combinedImplementationJar
 
 	// If no dependencies have separate header jars then there is no need to create a separate
 	// header jar for this module.
 	reuseImplementationJarAsHeaderJar := slices.Equal(staticJars, staticHeaderJars)
 
-	var headerOutputFile android.ModuleOutPath
+	var resourceJarFile android.Path
+	if len(staticResourceJars) > 1 {
+		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{},
+			false, nil, nil)
+		resourceJarFile = combinedJar
+	} else if len(staticResourceJars) == 1 {
+		resourceJarFile = staticResourceJars[0]
+	}
+
+	var headerJar android.Path
 	if reuseImplementationJarAsHeaderJar {
-		headerOutputFile = outputFile
+		headerJar = outputFile
 	} else {
 		headerJars := append(slices.Clone(jars), staticHeaderJars...)
-		headerOutputFile = android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		headerOutputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
 		TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
 			false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+		headerJar = headerOutputFile
 	}
 
 	if Bool(j.properties.Jetifier) {
-		inputFile := outputFile
-		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
-		TransformJetifier(ctx, outputFile, inputFile)
+		jetifierOutputFile := android.PathForModuleOut(ctx, "jetifier", jarName)
+		TransformJetifier(ctx, jetifierOutputFile, outputFile)
+		outputFile = jetifierOutputFile
 
 		if !reuseImplementationJarAsHeaderJar {
-			headerInputFile := headerOutputFile
-			headerOutputFile = android.PathForModuleOut(ctx, "jetifier-headers", jarName)
-			TransformJetifier(ctx, headerOutputFile, headerInputFile)
+			jetifierHeaderJar := android.PathForModuleOut(ctx, "jetifier-headers", jarName)
+			TransformJetifier(ctx, jetifierHeaderJar, headerJar)
+			headerJar = jetifierHeaderJar
 		} else {
-			headerOutputFile = outputFile
+			headerJar = outputFile
 		}
 	}
 
+	implementationJarFile := outputFile
+
+	// merge implementation jar with resources if necessary
+	if resourceJarFile != nil {
+		jars := android.Paths{resourceJarFile, outputFile}
+		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+			false, nil, nil)
+		outputFile = combinedJar
+	}
+
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource.
 	// Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check
 	// in a module that depends on this module considers them equal.
-	j.combinedHeaderFile = headerOutputFile.WithoutRel()
+	j.combinedHeaderFile = headerJar.WithoutRel()
 	j.combinedImplementationFile = outputFile.WithoutRel()
 
 	j.maybeInstall(ctx, jarName, outputFile)
@@ -2796,7 +2816,8 @@
 		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
 		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
-		ImplementationJars:             android.PathsIfNonNil(j.combinedImplementationFile),
+		ImplementationJars:             android.PathsIfNonNil(implementationJarFile.WithoutRel()),
+		ResourceJars:                   android.PathsIfNonNil(resourceJarFile),
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
 		StubsLinkType:                  j.stubsLinkType,
 		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 933fc51..844e974 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"slices"
 	"strconv"
 	"strings"
 	"testing"
@@ -23,10 +24,11 @@
 )
 
 func TestKotlin(t *testing.T) {
-	ctx, _ := testJava(t, `
+	bp := `
 		java_library {
 			name: "foo",
 			srcs: ["a.java", "b.kt"],
+			static_libs: ["quz"],
 		}
 
 		java_library {
@@ -39,85 +41,156 @@
 		java_library {
 			name: "baz",
 			srcs: ["c.java"],
+			static_libs: ["quz"],
 		}
-		`)
 
-	kotlinStdlib := ctx.ModuleForTests("kotlin-stdlib", "android_common").
-		Output("turbine-combined/kotlin-stdlib.jar").Output
-	kotlinStdlibJdk7 := ctx.ModuleForTests("kotlin-stdlib-jdk7", "android_common").
-		Output("turbine-combined/kotlin-stdlib-jdk7.jar").Output
-	kotlinStdlibJdk8 := ctx.ModuleForTests("kotlin-stdlib-jdk8", "android_common").
-		Output("turbine-combined/kotlin-stdlib-jdk8.jar").Output
-	kotlinAnnotations := ctx.ModuleForTests("kotlin-annotations", "android_common").
-		Output("turbine-combined/kotlin-annotations.jar").Output
+		java_library {
+			name: "quz",
+			srcs: ["d.kt"],
+		}`
 
-	fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
-	fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
-	fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar")
-
-	fooKotlincClasses := fooKotlinc.Output
-	fooKotlincHeaderClasses := fooKotlinc.ImplicitOutput
-
-	if len(fooKotlinc.Inputs) != 2 || fooKotlinc.Inputs[0].String() != "a.java" ||
-		fooKotlinc.Inputs[1].String() != "b.kt" {
-		t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, fooKotlinc.Inputs)
+	kotlinStdlibTurbineCombinedJars := []string{
+		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine-combined/kotlin-stdlib.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine-combined/kotlin-stdlib-jdk7.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine-combined/kotlin-stdlib-jdk8.jar",
+		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine-combined/kotlin-annotations.jar",
 	}
 
-	if len(fooJavac.Inputs) != 1 || fooJavac.Inputs[0].String() != "a.java" {
-		t.Errorf(`foo inputs %v != ["a.java"]`, fooJavac.Inputs)
+	kotlinStdlibJavacJars := []string{
+		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/javac/kotlin-stdlib-jdk8.jar",
+		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/javac/kotlin-annotations.jar",
 	}
 
-	if !strings.Contains(fooJavac.Args["classpath"], fooKotlincHeaderClasses.String()) {
-		t.Errorf("foo classpath %v does not contain %q",
-			fooJavac.Args["classpath"], fooKotlincHeaderClasses.String())
+	bootclasspathTurbineCombinedJars := []string{
+		"out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine-combined/stable.core.platform.api.stubs.jar",
+		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine-combined/core-lambda-stubs.jar",
 	}
 
-	if !inList(fooKotlincClasses.String(), fooJar.Inputs.Strings()) {
-		t.Errorf("foo jar inputs %v does not contain %q",
-			fooJar.Inputs.Strings(), fooKotlincClasses.String())
+	frameworkTurbineCombinedJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
 	}
 
-	if !inList(kotlinStdlib.String(), fooJar.Inputs.Strings()) {
-		t.Errorf("foo jar inputs %v does not contain %v",
-			fooJar.Inputs.Strings(), kotlinStdlib.String())
+	testCases := []struct {
+		name string
+
+		preparer android.FixturePreparer
+
+		fooKotlincInputs        []string
+		fooJavacInputs          []string
+		fooKotlincClasspath     []string
+		fooJavacClasspath       []string
+		fooCombinedInputs       []string
+		fooHeaderCombinedInputs []string
+
+		barKotlincInputs        []string
+		barKotlincClasspath     []string
+		barCombinedInputs       []string
+		barHeaderCombinedInputs []string
+	}{
+		{
+			name:             "normal",
+			preparer:         android.NullFixturePreparer,
+			fooKotlincInputs: []string{"a.java", "b.kt"},
+			fooJavacInputs:   []string{"a.java"},
+			fooKotlincClasspath: slices.Concat(
+				bootclasspathTurbineCombinedJars,
+				frameworkTurbineCombinedJars,
+				[]string{"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar"},
+				kotlinStdlibTurbineCombinedJars,
+			),
+			fooJavacClasspath: slices.Concat(
+				[]string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
+				frameworkTurbineCombinedJars,
+				[]string{"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar"},
+				kotlinStdlibTurbineCombinedJars,
+			),
+			fooCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
+					"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+					"out/soong/.intermediates/quz/android_common/combined/quz.jar",
+				},
+				kotlinStdlibJavacJars,
+			),
+			fooHeaderCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+					"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+				},
+				kotlinStdlibTurbineCombinedJars,
+			),
+
+			barKotlincInputs: []string{"b.kt"},
+			barKotlincClasspath: slices.Concat(
+				bootclasspathTurbineCombinedJars,
+				frameworkTurbineCombinedJars,
+				[]string{
+					"out/soong/.intermediates/foo/android_common/turbine-combined/foo.jar",
+					"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+				},
+				kotlinStdlibTurbineCombinedJars,
+			),
+			barCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
+					"out/soong/.intermediates/baz/android_common/combined/baz.jar",
+				},
+				kotlinStdlibJavacJars,
+				[]string{},
+			),
+			barHeaderCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
+					"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+				},
+				kotlinStdlibTurbineCombinedJars,
+			),
+		},
 	}
 
-	if !inList(kotlinStdlibJdk7.String(), fooJar.Inputs.Strings()) {
-		t.Errorf("foo jar inputs %v does not contain %v",
-			fooJar.Inputs.Strings(), kotlinStdlibJdk7.String())
-	}
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				tt.preparer,
+			).RunTestWithBp(t, bp)
+			foo := result.ModuleForTests("foo", "android_common")
+			fooKotlinc := foo.Rule("kotlinc")
+			android.AssertPathsRelativeToTopEquals(t, "foo kotlinc inputs", tt.fooKotlincInputs, fooKotlinc.Inputs)
 
-	if !inList(kotlinStdlibJdk8.String(), fooJar.Inputs.Strings()) {
-		t.Errorf("foo jar inputs %v does not contain %v",
-			fooJar.Inputs.Strings(), kotlinStdlibJdk8.String())
-	}
+			fooKotlincClasspath := android.ContentFromFileRuleForTests(t, result.TestContext, foo.Output("kotlinc/classpath.rsp"))
+			android.AssertStringPathsRelativeToTopEquals(t, "foo kotlinc classpath", result.Config, tt.fooKotlincClasspath, strings.Fields(fooKotlincClasspath))
 
-	if !inList(kotlinAnnotations.String(), fooJar.Inputs.Strings()) {
-		t.Errorf("foo jar inputs %v does not contain %v",
-			fooJar.Inputs.Strings(), kotlinAnnotations.String())
-	}
+			fooJavac := foo.Rule("javac")
+			android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs)
 
-	if !inList(fooKotlincHeaderClasses.String(), fooHeaderJar.Inputs.Strings()) {
-		t.Errorf("foo header jar inputs %v does not contain %q",
-			fooHeaderJar.Inputs.Strings(), fooKotlincHeaderClasses.String())
-	}
+			fooJavacClasspath := fooJavac.Args["classpath"]
+			android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath,
+				strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":"))
 
-	bazHeaderJar := ctx.ModuleForTests("baz", "android_common").Output("turbine-combined/baz.jar")
-	barKotlinc := ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
+			fooCombinedJar := foo.Output("combined/foo.jar")
+			android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs)
 
-	if len(barKotlinc.Inputs) != 1 || barKotlinc.Inputs[0].String() != "b.kt" {
-		t.Errorf(`bar kotlinc inputs %v != ["b.kt"]`, barKotlinc.Inputs)
-	}
+			fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar")
+			android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs)
 
-	if !inList(fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
-		t.Errorf(`expected %q in bar implicits %v`,
-			fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
-	}
+			bar := result.ModuleForTests("bar", "android_common")
+			barKotlinc := bar.Rule("kotlinc")
+			android.AssertPathsRelativeToTopEquals(t, "bar kotlinc inputs", tt.barKotlincInputs, barKotlinc.Inputs)
 
-	if !inList(bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
-		t.Errorf(`expected %q in bar implicits %v`,
-			bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
+			barKotlincClasspath := android.ContentFromFileRuleForTests(t, result.TestContext, bar.Output("kotlinc/classpath.rsp"))
+			android.AssertStringPathsRelativeToTopEquals(t, "bar kotlinc classpath", result.Config, tt.barKotlincClasspath, strings.Fields(barKotlincClasspath))
+
+			barCombinedJar := bar.Output("combined/bar.jar")
+			android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs)
+
+			barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar")
+			android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs)
+		})
 	}
 }
 
diff --git a/java/ravenwood.go b/java/ravenwood.go
index a52f405..bb136cf 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -143,6 +143,9 @@
 		HostTemplate:           "${RavenwoodTestConfigTemplate}",
 	})
 
+	// Always enable Ravenizer for ravenwood tests.
+	r.Library.ravenizer.enabled = true
+
 	r.Library.GenerateAndroidBuildActions(ctx)
 
 	// Start by depending on all files installed by dependencies
@@ -152,7 +155,8 @@
 	var runtimeJniModuleNames map[string]bool
 
 	if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil {
-		for _, installFile := range utils.FilesToInstall() {
+		for _, installFile := range android.OtherModuleProviderOrDefault(
+			ctx, utils, android.InstallFilesProvider).InstallFiles {
 			installDeps = append(installDeps, installFile)
 		}
 		jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider)
@@ -162,7 +166,8 @@
 	}
 
 	if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil {
-		for _, installFile := range runtime.FilesToInstall() {
+		for _, installFile := range android.OtherModuleProviderOrDefault(
+			ctx, runtime, android.InstallFilesProvider).InstallFiles {
 			installDeps = append(installDeps, installFile)
 		}
 		jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider)
@@ -191,7 +196,8 @@
 
 	resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks")
 	if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 {
-		for _, installFile := range resApk[0].FilesToInstall() {
+		for _, installFile := range android.OtherModuleProviderOrDefault(
+			ctx, resApk[0], android.InstallFilesProvider).InstallFiles {
 			installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile)
 			installDeps = append(installDeps, installResApk)
 		}
diff --git a/java/testing.go b/java/testing.go
index e1bf537..0e85022 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -542,6 +542,16 @@
 			},
 			compile_dex: true,
 		}
+		java_library {
+			name: "framework-minus-apex",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "stable-core-platform-api-stubs-system-modules",
+			aidl: {
+				export_include_dirs: ["framework/aidl"],
+			},
+			compile_dex: true,
+		}
 
 		android_app {
 			name: "framework-res",
diff --git a/kernel/prebuilt_kernel_modules_test.go b/kernel/prebuilt_kernel_modules_test.go
index 90b9886..7b81869 100644
--- a/kernel/prebuilt_kernel_modules_test.go
+++ b/kernel/prebuilt_kernel_modules_test.go
@@ -49,7 +49,8 @@
 	}
 
 	var actual []string
-	for _, ps := range ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().PackagingSpecs() {
+	for _, ps := range android.OtherModuleProviderOrDefault(
+		ctx, ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module(), android.InstallFilesProvider).PackagingSpecs {
 		actual = append(actual, ps.RelPathInPackage())
 	}
 	actual = android.SortedUniqueStrings(actual)
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 87c0814..533ec62 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -105,7 +105,8 @@
 	var provideLibs []string
 	for _, m := range provideModules {
 		if c, ok := m.(*cc.Module); ok && (cc.IsStubTarget(c) || c.HasLlndkStubs()) {
-			for _, ps := range c.PackagingSpecs() {
+			for _, ps := range android.OtherModuleProviderOrDefault(
+				ctx, c, android.InstallFilesProvider).PackagingSpecs {
 				provideLibs = append(provideLibs, ps.FileName())
 			}
 		}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index b5e74b4..8ca62d3 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -229,6 +229,7 @@
 			"BUILD_BROKEN_INCORRECT_PARTITION_IMAGES",
 			"SOONG_USE_N2",
 			"RUST_BACKTRACE",
+			"RUST_LOG",
 		}, config.BuildBrokenNinjaUsesEnvVars()...)...)
 	}