Merge "Add $(build_number_file) support to genrules" into main
diff --git a/android/all_teams.go b/android/all_teams.go
index e3c2e70..01be396 100644
--- a/android/all_teams.go
+++ b/android/all_teams.go
@@ -1,6 +1,7 @@
 package android
 
 import (
+	"path"
 	"path/filepath"
 
 	"android/soong/android/team_proto"
@@ -153,6 +154,11 @@
 		} else {
 			teamProperties, found = t.lookupDefaultTeam(m.bpFile)
 		}
+		// Deal with one blueprint file including another by looking up the default
+		// in the main Android.bp rather than one listed with "build = [My.bp]"
+		if !found {
+			teamProperties, found = t.lookupDefaultTeam(path.Join(path.Dir(m.bpFile), "Android.bp"))
+		}
 
 		trendy_team_id := ""
 		if found {
diff --git a/android/all_teams_test.go b/android/all_teams_test.go
index 96ed92f..fa8c048 100644
--- a/android/all_teams_test.go
+++ b/android/all_teams_test.go
@@ -264,6 +264,84 @@
 	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
 }
 
+func TestPackageLookupForIncludedBlueprintFiles(t *testing.T) {
+	t.Parallel()
+	rootBp := `
+                package { default_team: "team_top"}
+		team {
+			name: "team_top",
+			trendy_team_id: "trendy://team_top",
+		}
+                build = ["include.bp"]
+ `
+	includeBp := `
+		fake {
+			name: "IncludedModule",
+		} `
+
+	ctx := GroupFixturePreparers(
+		prepareForTestWithTeamAndFakes,
+		PrepareForTestWithPackageModule,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
+		}),
+		FixtureAddTextFile("Android.bp", rootBp),
+		FixtureAddTextFile("include.bp", includeBp),
+	).RunTest(t)
+
+	var teams *team_proto.AllTeams
+	teams = getTeamProtoOutput(t, ctx)
+
+	// map of module name -> trendy team name.
+	actualTeams := make(map[string]*string)
+	for _, teamProto := range teams.Teams {
+		actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
+	}
+	expectedTeams := map[string]*string{
+		"IncludedModule": proto.String("trendy://team_top"),
+	}
+	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
+}
+
+func TestPackageLookupForIncludedBlueprintFilesWithPackageInChildBlueprint(t *testing.T) {
+	t.Parallel()
+	rootBp := `
+		team {
+			name: "team_top",
+			trendy_team_id: "trendy://team_top",
+		}
+                build = ["include.bp"]
+ `
+	includeBp := `
+                package { default_team: "team_top"}
+		fake {
+			name: "IncludedModule",
+		} `
+
+	ctx := GroupFixturePreparers(
+		prepareForTestWithTeamAndFakes,
+		PrepareForTestWithPackageModule,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
+		}),
+		FixtureAddTextFile("Android.bp", rootBp),
+		FixtureAddTextFile("include.bp", includeBp),
+	).RunTest(t)
+
+	var teams *team_proto.AllTeams
+	teams = getTeamProtoOutput(t, ctx)
+
+	// map of module name -> trendy team name.
+	actualTeams := make(map[string]*string)
+	for _, teamProto := range teams.Teams {
+		actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
+	}
+	expectedTeams := map[string]*string{
+		"IncludedModule": proto.String("trendy://team_top"),
+	}
+	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
+}
+
 type fakeForTests struct {
 	ModuleBase
 
diff --git a/android/androidmk.go b/android/androidmk.go
index f88a226..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 {
diff --git a/android/apex.go b/android/apex.go
index ecab8e3..028be57 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -280,7 +280,7 @@
 	//
 	// "//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.".
+	// Prefix pattern (com.foo.*) can be used to match with any APEX name with the prefix(com.foo.).
 	// Default is ["//apex_available:platform"].
 	Apex_available []string
 
@@ -473,14 +473,12 @@
 const (
 	AvailableToPlatform = "//apex_available:platform"
 	AvailableToAnyApex  = "//apex_available:anyapex"
-	AvailableToGkiApex  = "com.android.gki.*"
 )
 
 var (
 	AvailableToRecognziedWildcards = []string{
 		AvailableToPlatform,
 		AvailableToAnyApex,
-		AvailableToGkiApex,
 	}
 )
 
@@ -494,11 +492,27 @@
 	if len(apex_available) == 0 {
 		return what == AvailableToPlatform
 	}
-	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
+
+	// TODO b/248601389
+	if what == "com.google.mainline.primary.libs" || what == "com.google.mainline.go.primary.libs" {
+		return true
+	}
+
+	for _, apex_name := range apex_available {
+		// exact match.
+		if apex_name == what {
+			return true
+		}
+		// //apex_available:anyapex matches with any apex name, but not //apex_available:platform
+		if apex_name == AvailableToAnyApex && what != AvailableToPlatform {
+			return true
+		}
+		// prefix match.
+		if strings.HasSuffix(apex_name, ".*") && strings.HasPrefix(what, strings.TrimSuffix(apex_name, "*")) {
+			return true
+		}
+	}
+	return false
 }
 
 // Implements ApexModule
@@ -524,7 +538,20 @@
 // 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
+		}
+		// Prefix pattern should end with .* and has at least two components.
+		if strings.Contains(n, "*") {
+			if !strings.HasSuffix(n, ".*") {
+				mctx.PropertyErrorf("apex_available", "Wildcard should end with .* like com.foo.*")
+			}
+			if strings.Count(n, ".") < 2 {
+				mctx.PropertyErrorf("apex_available", "Wildcard requires two or more components like com.foo.*")
+			}
+			if strings.Count(n, "*") != 1 {
+				mctx.PropertyErrorf("apex_available", "Wildcard is not allowed in the middle.")
+			}
 			continue
 		}
 		if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index 5cdd302..4c92f71 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -187,8 +187,8 @@
 
 		var installed InstallPaths
 		installed = append(installed, ctx.installFiles...)
-		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()...)
 		complianceMetadataInfo.SetListValue(ComplianceMetadataProp.INSTALLED_FILES, FirstUniqueStrings(installed.Strings()))
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/license_metadata.go b/android/license_metadata.go
index c12a01c..cd69749 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -92,7 +92,7 @@
 
 			allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
 
-			if depInstallFiles := ModuleFilesToInstall(ctx, dep); 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...)
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 9f06045..664ac5c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -113,13 +113,14 @@
 	TargetRequiredModuleNames() []string
 	VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string
 
-	PackagingSpecs() []PackagingSpec
-
 	// 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
@@ -763,14 +764,6 @@
 	m.base().commonProperties.CreateCommonOSVariant = true
 }
 
-func ModuleFilesToInstall(ctx OtherModuleProviderContext, m blueprint.Module) InstallPaths {
-	var filesToInstall InstallPaths
-	if info, ok := OtherModuleProvider(ctx, m, InstallFilesProvider); ok {
-		filesToInstall = info.InstallFiles
-	}
-	return filesToInstall
-}
-
 // A ModuleBase object contains the properties that are common to all Android
 // modules.  It should be included as an anonymous field in every module
 // struct definition.  InitAndroidModule should then be called from the module's
@@ -844,18 +837,11 @@
 
 	noAddressSanitizer   bool
 	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
@@ -902,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{}) {
@@ -1497,10 +1487,6 @@
 	return IsInstallDepNeededTag(tag)
 }
 
-func (m *ModuleBase) PackagingSpecs() []PackagingSpec {
-	return m.packagingSpecs
-}
-
 func (m *ModuleBase) TransitivePackagingSpecs() []PackagingSpec {
 	return m.packagingSpecsDepSet.ToList()
 }
@@ -1641,17 +1627,21 @@
 	var allCheckbuildFiles Paths
 	ctx.VisitAllModuleVariants(func(module Module) {
 		a := module.base()
+		var checkBuilds Paths
 		if a == m {
 			allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
+			checkBuilds = ctx.checkbuildFiles
 		} else {
-			allInstalledFiles = append(allInstalledFiles, ModuleFilesToInstall(ctx, module)...)
+			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...)
 		}
 	})
 
@@ -1789,7 +1779,14 @@
 }
 
 type InstallFilesInfo struct {
-	InstallFiles InstallPaths
+	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]()
@@ -1975,14 +1972,13 @@
 			return
 		}
 
-		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,
+			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
@@ -2000,14 +1996,14 @@
 	}
 
 	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
-	m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, m.packagingSpecs, dependencyPackagingSpecs)
+	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()
@@ -2020,7 +2016,7 @@
 		}
 
 		var data []string
-		for _, d := range m.testData {
+		for _, d := range ctx.testData {
 			data = append(data, d.ToRelativeInstallPath())
 		}
 
@@ -2102,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
@@ -2700,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/sdk.go b/android/sdk.go
index 4bcbe2e..d3f04a4 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -813,6 +813,7 @@
 
 // SdkMemberContext provides access to information common to a specific member.
 type SdkMemberContext interface {
+	ConfigAndErrorContext
 
 	// SdkModuleContext returns the module context of the sdk common os variant which is creating the
 	// snapshot.
diff --git a/android/test_suites.go b/android/test_suites.go
index c0dc17e..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], ModuleFilesToInstall(ctx, tsm)...)
+				files[testSuite][name] = append(files[testSuite][name],
+					OtherModuleProviderOrDefault(ctx, tsm, InstallFilesProvider).InstallFiles...)
 			}
 		}
 	})
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/apex/apex.go b/apex/apex.go
index dd1c0b5..77ebf26 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2767,10 +2767,21 @@
 		if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) {
 			return true
 		}
+
+		// Let's give some hint for apex_available
+		hint := fmt.Sprintf("%q", apexName)
+
+		if strings.HasPrefix(apexName, "com.") && !strings.HasPrefix(apexName, "com.android.") && strings.Count(apexName, ".") >= 2 {
+			// In case of a partner APEX, prefix format might be an option.
+			components := strings.Split(apexName, ".")
+			components[len(components)-1] = "*"
+			hint += fmt.Sprintf(" or %q", strings.Join(components, "."))
+		}
+
 		ctx.ModuleErrorf("%q requires %q that doesn't list the APEX under 'apex_available'."+
 			"\n\nDependency path:%s\n\n"+
-			"Consider adding %q to 'apex_available' property of %q",
-			fromName, toName, ctx.GetPathString(true), apexName, toName)
+			"Consider adding %s to 'apex_available' property of %q",
+			fromName, toName, ctx.GetPathString(true), hint, toName)
 		// Visit this module's dependencies to check and report any issues with their availability.
 		return true
 	})
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d6c8a8a..6b9944d 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"],
@@ -6730,6 +6722,99 @@
 	}
 }
 
+func TestApexAvailable_PrefixMatch(t *testing.T) {
+
+	for _, tc := range []struct {
+		name          string
+		apexAvailable string
+		expectedError string
+	}{
+		{
+			name:          "prefix matches correctly",
+			apexAvailable: "com.foo.*",
+		},
+		{
+			name:          "prefix doesn't match",
+			apexAvailable: "com.bar.*",
+			expectedError: `Consider .* "com.foo\.\*"`,
+		},
+		{
+			name:          "short prefix",
+			apexAvailable: "com.*",
+			expectedError: "requires two or more components",
+		},
+		{
+			name:          "wildcard not in the end",
+			apexAvailable: "com.*.foo",
+			expectedError: "should end with .*",
+		},
+		{
+			name:          "wildcard in the middle",
+			apexAvailable: "com.foo*.*",
+			expectedError: "not allowed in the middle",
+		},
+		{
+			name:          "hint with prefix pattern",
+			apexAvailable: "//apex_available:platform",
+			expectedError: "Consider adding \"com.foo.bar\" or \"com.foo.*\"",
+		},
+	} {
+		t.Run(tc.name, func(t *testing.T) {
+			errorHandler := android.FixtureExpectsNoErrors
+			if tc.expectedError != "" {
+				errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError)
+			}
+			context := android.GroupFixturePreparers(
+				prepareForApexTest,
+				android.FixtureMergeMockFs(android.MockFS{
+					"system/sepolicy/apex/com.foo.bar-file_contexts": nil,
+				}),
+			).ExtendWithErrorHandler(errorHandler)
+
+			context.RunTestWithBp(t, `
+				apex {
+					name: "com.foo.bar",
+					key: "myapex.key",
+					native_shared_libs: ["libfoo"],
+					updatable: false,
+				}
+
+				apex_key {
+					name: "myapex.key",
+					public_key: "testkey.avbpubkey",
+					private_key: "testkey.pem",
+				}
+
+				cc_library {
+					name: "libfoo",
+					stl: "none",
+					system_shared_libs: [],
+					apex_available: ["`+tc.apexAvailable+`"],
+				}`)
+		})
+	}
+	testApexError(t, `Consider adding "com.foo" to`, `
+		apex {
+			name: "com.foo", // too short for a partner apex
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libfoo",
+			stl: "none",
+			system_shared_libs: [],
+		}
+	`)
+}
+
 func TestOverrideApex(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 71e0cd8..8a7ea88 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -132,7 +132,7 @@
 
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
-		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps)
 
 		p.SharedLibs = specifiedDeps.sharedLibs
 		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
diff --git a/cc/cc.go b/cc/cc.go
index b3cac62..947dc1a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -613,7 +613,7 @@
 	coverageOutputFilePath() android.OptionalPath
 
 	// Get the deps that have been explicitly specified in the properties.
-	linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+	linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps
 
 	moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
 }
diff --git a/cc/cmake_module_cc.txt b/cc/cmake_module_cc.txt
index 0dc45ae..0f6e62f 100644
--- a/cc/cmake_module_cc.txt
+++ b/cc/cmake_module_cc.txt
@@ -2,10 +2,10 @@
 <<$includeDirs := getIncludeDirs .Ctx .M>>
 <<$cflags := getCflagsProperty .Ctx .M>>
 <<$deps := mapLibraries .Ctx .M (concat5
-(getLinkerProperties .M).Whole_static_libs
-(getLinkerProperties .M).Static_libs
-(getLinkerProperties .M).Shared_libs
-(getLinkerProperties .M).Header_libs
+(getWholeStaticLibsProperty .Ctx .M)
+(getStaticLibsProperty .Ctx .M)
+(getSharedLibsProperty .Ctx .M)
+(getHeaderLibsProperty .Ctx .M)
 (getExtraLibs .M)
 ) .Pprop.LibraryMapping>>
 <<$moduleType := getModuleType .M>>
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index 9159156..61fa46d 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -204,12 +204,28 @@
 			return m.compiler.baseCompilerProps()
 		},
 		"getCflagsProperty": func(ctx android.ModuleContext, m *Module) []string {
-			cflags := m.compiler.baseCompilerProps().Cflags
-			return cflags.GetOrDefault(ctx, nil)
+			prop := m.compiler.baseCompilerProps().Cflags
+			return prop.GetOrDefault(ctx, nil)
 		},
 		"getLinkerProperties": func(m *Module) BaseLinkerProperties {
 			return m.linker.baseLinkerProps()
 		},
+		"getWholeStaticLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
+			prop := m.linker.baseLinkerProps().Whole_static_libs
+			return prop.GetOrDefault(ctx, nil)
+		},
+		"getStaticLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
+			prop := m.linker.baseLinkerProps().Static_libs
+			return prop.GetOrDefault(ctx, nil)
+		},
+		"getSharedLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
+			prop := m.linker.baseLinkerProps().Shared_libs
+			return prop.GetOrDefault(ctx, nil)
+		},
+		"getHeaderLibsProperty": func(ctx android.ModuleContext, m *Module) []string {
+			prop := m.linker.baseLinkerProps().Header_libs
+			return prop.GetOrDefault(ctx, nil)
+		},
 		"getExtraLibs":   getExtraLibs,
 		"getIncludeDirs": getIncludeDirs,
 		"mapLibraries": func(ctx android.ModuleContext, m *Module, libs []string, mapping map[string]LibraryMappingProperty) []string {
@@ -476,7 +492,8 @@
 		var prebuiltsList android.Paths
 
 		ctx.VisitDirectDepsWithTag(cmakeSnapshotPrebuiltTag, func(dep android.Module) {
-			for _, file := range android.ModuleFilesToInstall(ctx, dep) {
+			for _, file := range android.OtherModuleProviderOrDefault(
+				ctx, dep, android.InstallFilesProvider).InstallFiles {
 				prebuiltsList = append(prebuiltsList, file)
 			}
 		})
diff --git a/cc/compiler.go b/cc/compiler.go
index 0e0b9a7..396ec88 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -798,13 +798,13 @@
 	Local_include_dirs []string `android:"arch_variant,variant_prepend"`
 
 	// list of static libraries that provide headers for this binding.
-	Static_libs []string `android:"arch_variant,variant_prepend"`
+	Static_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of shared libraries that provide headers for this binding.
-	Shared_libs []string `android:"arch_variant"`
+	Shared_libs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// List of libraries which export include paths required for this module
-	Header_libs []string `android:"arch_variant,variant_prepend"`
+	Header_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of clang flags required to correctly interpret the headers.
 	Cflags proptools.Configurable[[]string] `android:"arch_variant"`
diff --git a/cc/library.go b/cc/library.go
index de0070a..6017848 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -152,11 +152,11 @@
 
 	Cflags proptools.Configurable[[]string] `android:"arch_variant"`
 
-	Enabled            *bool    `android:"arch_variant"`
-	Whole_static_libs  []string `android:"arch_variant"`
-	Static_libs        []string `android:"arch_variant"`
-	Shared_libs        []string `android:"arch_variant"`
-	System_shared_libs []string `android:"arch_variant"`
+	Enabled            *bool                            `android:"arch_variant"`
+	Whole_static_libs  proptools.Configurable[[]string] `android:"arch_variant"`
+	Static_libs        proptools.Configurable[[]string] `android:"arch_variant"`
+	Shared_libs        proptools.Configurable[[]string] `android:"arch_variant"`
+	System_shared_libs []string                         `android:"arch_variant"`
 
 	Export_shared_lib_headers []string `android:"arch_variant"`
 	Export_static_lib_headers []string `android:"arch_variant"`
@@ -837,9 +837,9 @@
 
 	if library.static() {
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs,
-			library.StaticProperties.Static.Whole_static_libs...)
-		deps.StaticLibs = append(deps.StaticLibs, library.StaticProperties.Static.Static_libs...)
-		deps.SharedLibs = append(deps.SharedLibs, library.StaticProperties.Static.Shared_libs...)
+			library.StaticProperties.Static.Whole_static_libs.GetOrDefault(ctx, nil)...)
+		deps.StaticLibs = append(deps.StaticLibs, library.StaticProperties.Static.Static_libs.GetOrDefault(ctx, nil)...)
+		deps.SharedLibs = append(deps.SharedLibs, library.StaticProperties.Static.Shared_libs.GetOrDefault(ctx, nil)...)
 
 		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.StaticProperties.Static.Export_shared_lib_headers...)
 		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...)
@@ -852,9 +852,9 @@
 		if library.baseLinker.Properties.crtPadSegment() {
 			deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtPadSegmentSharedLibrary()...)
 		}
-		deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
-		deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
-		deps.SharedLibs = append(deps.SharedLibs, library.SharedProperties.Shared.Shared_libs...)
+		deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs.GetOrDefault(ctx, nil)...)
+		deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs.GetOrDefault(ctx, nil)...)
+		deps.SharedLibs = append(deps.SharedLibs, library.SharedProperties.Shared.Shared_libs.GetOrDefault(ctx, nil)...)
 
 		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.SharedProperties.Shared.Export_shared_lib_headers...)
 		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.SharedProperties.Shared.Export_static_lib_headers...)
@@ -900,8 +900,8 @@
 	return deps
 }
 
-func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
-	specifiedDeps = library.baseLinker.linkerSpecifiedDeps(specifiedDeps)
+func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+	specifiedDeps = library.baseLinker.linkerSpecifiedDeps(ctx, module, specifiedDeps)
 	var properties StaticOrSharedProperties
 	if library.static() {
 		properties = library.StaticProperties.Static
@@ -909,7 +909,8 @@
 		properties = library.SharedProperties.Shared
 	}
 
-	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
+	eval := module.ConfigurableEvaluator(ctx)
+	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs.GetOrDefault(eval, nil)...)
 
 	// Must distinguish nil and [] in system_shared_libs - ensure that [] in
 	// either input list doesn't come out as nil.
@@ -2079,12 +2080,12 @@
 		// include directories.
 		if len(sharedCompiler.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)) == 0 &&
 			len(sharedCompiler.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)) == 0 &&
-			len(sharedCompiler.StaticProperties.Static.Whole_static_libs) == 0 &&
-			len(sharedCompiler.SharedProperties.Shared.Whole_static_libs) == 0 &&
-			len(sharedCompiler.StaticProperties.Static.Static_libs) == 0 &&
-			len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 &&
-			len(sharedCompiler.StaticProperties.Static.Shared_libs) == 0 &&
-			len(sharedCompiler.SharedProperties.Shared.Shared_libs) == 0 &&
+			len(sharedCompiler.StaticProperties.Static.Whole_static_libs.GetOrDefault(ctx, nil)) == 0 &&
+			len(sharedCompiler.SharedProperties.Shared.Whole_static_libs.GetOrDefault(ctx, nil)) == 0 &&
+			len(sharedCompiler.StaticProperties.Static.Static_libs.GetOrDefault(ctx, nil)) == 0 &&
+			len(sharedCompiler.SharedProperties.Shared.Static_libs.GetOrDefault(ctx, nil)) == 0 &&
+			len(sharedCompiler.StaticProperties.Static.Shared_libs.GetOrDefault(ctx, nil)) == 0 &&
+			len(sharedCompiler.SharedProperties.Shared.Shared_libs.GetOrDefault(ctx, nil)) == 0 &&
 			// Compare System_shared_libs properties with nil because empty lists are
 			// semantically significant for them.
 			sharedCompiler.StaticProperties.Static.System_shared_libs == nil &&
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index e8a9827..053c460 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -543,7 +543,7 @@
 	p.ExportedFlags = exportedInfo.Flags
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
-		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps)
 
 		if lib := ccModule.library; lib != nil {
 			if !lib.hasStubsVariants() {
diff --git a/cc/linker.go b/cc/linker.go
index d2974c2..0056817 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -37,16 +37,16 @@
 	// in their entirety.  For static library modules, all of the .o files from the intermediate
 	// directory of the dependency will be linked into this modules .a file.  For a shared library,
 	// the dependency's .a file will be linked into this module using -Wl,--whole-archive.
-	Whole_static_libs []string `android:"arch_variant,variant_prepend"`
+	Whole_static_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of modules that should be statically linked into this module.
-	Static_libs []string `android:"arch_variant,variant_prepend"`
+	Static_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of modules that should be dynamically linked into this module.
-	Shared_libs []string `android:"arch_variant"`
+	Shared_libs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// list of modules that should only provide headers for this module.
-	Header_libs []string `android:"arch_variant,variant_prepend"`
+	Header_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of module-specific flags that will be used for all link steps
 	Ldflags []string `android:"arch_variant"`
@@ -296,10 +296,10 @@
 }
 
 func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs...)
-	deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs...)
-	deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Static_libs...)
-	deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs...)
+	deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs.GetOrDefault(ctx, nil)...)
+	deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs.GetOrDefault(ctx, nil)...)
+	deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Static_libs.GetOrDefault(ctx, nil)...)
+	deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs.GetOrDefault(ctx, nil)...)
 	deps.RuntimeLibs = append(deps.RuntimeLibs, linker.Properties.Runtime_libs...)
 
 	deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, linker.Properties.Export_header_lib_headers...)
@@ -645,8 +645,9 @@
 	panic(fmt.Errorf("baseLinker doesn't know how to link"))
 }
 
-func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
-	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
+func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+	eval := module.ConfigurableEvaluator(ctx)
+	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs.GetOrDefault(eval, nil)...)
 
 	// Must distinguish nil and [] in system_shared_libs - ensure that [] in
 	// either input list doesn't come out as nil.
diff --git a/cc/object.go b/cc/object.go
index 8b23295..a4f4c84 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -19,6 +19,8 @@
 	"strings"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 //
@@ -50,13 +52,13 @@
 
 type ObjectLinkerProperties struct {
 	// list of static library modules that should only provide headers for this module.
-	Static_libs []string `android:"arch_variant,variant_prepend"`
+	Static_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of shared library modules should only provide headers for this module.
-	Shared_libs []string `android:"arch_variant,variant_prepend"`
+	Shared_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of modules that should only provide headers for this module.
-	Header_libs []string `android:"arch_variant,variant_prepend"`
+	Header_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"`
 
 	// list of default libraries that will provide headers for this module.  If unset, generally
 	// defaults to libc, libm, and libdl.  Set to [] to prevent using headers from the defaults.
@@ -116,9 +118,9 @@
 func (*objectLinker) linkerInit(ctx BaseModuleContext) {}
 
 func (object *objectLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs...)
-	deps.SharedLibs = append(deps.SharedLibs, object.Properties.Shared_libs...)
-	deps.StaticLibs = append(deps.StaticLibs, object.Properties.Static_libs...)
+	deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs.GetOrDefault(ctx, nil)...)
+	deps.SharedLibs = append(deps.SharedLibs, object.Properties.Shared_libs.GetOrDefault(ctx, nil)...)
+	deps.StaticLibs = append(deps.StaticLibs, object.Properties.Static_libs.GetOrDefault(ctx, nil)...)
 	deps.ObjFiles = append(deps.ObjFiles, object.Properties.Objs...)
 
 	deps.SystemSharedLibs = object.Properties.System_shared_libs
@@ -201,8 +203,9 @@
 	return outputFile
 }
 
-func (object *objectLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
-	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, object.Properties.Shared_libs...)
+func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps {
+	eval := module.ConfigurableEvaluator(ctx)
+	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, object.Properties.Shared_libs.GetOrDefault(eval, nil)...)
 
 	// Must distinguish nil and [] in system_shared_libs - ensure that [] in
 	// either input list doesn't come out as nil.
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 a8eaaa4..1ebf658 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1109,7 +1109,7 @@
 						coverageFile:   dep.CoverageOutputFile(),
 						unstrippedFile: dep.UnstrippedOutputFile(),
 						partition:      dep.Partition(),
-						installPaths:   android.ModuleFilesToInstall(ctx, dep),
+						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/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 d65be52..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 android.ModuleFilesToInstall(ctx, utils) {
+		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 android.ModuleFilesToInstall(ctx, runtime) {
+		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 android.ModuleFilesToInstall(ctx, resApk[0]) {
+		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/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 78ab771..2e408b7 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -72,6 +72,7 @@
 	"add_soong_config_namespace":           &simpleCallParser{name: baseName + ".soong_config_namespace", returnType: starlarkTypeVoid, addGlobals: true},
 	"add_soong_config_var_value":           &simpleCallParser{name: baseName + ".soong_config_set", returnType: starlarkTypeVoid, addGlobals: true},
 	soongConfigAssign:                      &simpleCallParser{name: baseName + ".soong_config_set", returnType: starlarkTypeVoid, addGlobals: true},
+	"soong_config_set_bool":                &simpleCallParser{name: baseName + ".soong_config_set_bool", returnType: starlarkTypeVoid, addGlobals: true},
 	soongConfigAppend:                      &simpleCallParser{name: baseName + ".soong_config_append", returnType: starlarkTypeVoid, addGlobals: true},
 	"soong_config_get":                     &simpleCallParser{name: baseName + ".soong_config_get", returnType: starlarkTypeString, addGlobals: true},
 	"add-to-product-copy-files-if-exists":  &simpleCallParser{name: baseName + ".copy_if_exists", returnType: starlarkTypeList},
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 0c4d213..c295c40 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -853,6 +853,7 @@
 $(call add_soong_config_namespace,snsconfig)
 $(call add_soong_config_var_value,snsconfig,imagetype,odm_image)
 $(call soong_config_set, snsconfig, foo, foo_value)
+$(call soong_config_set_bool, snsconfig, bar, true)
 $(call soong_config_append, snsconfig, bar, bar_value)
 PRODUCT_COPY_FILES := $(call copy-files,$(wildcard foo*.mk),etc)
 PRODUCT_COPY_FILES := $(call product-copy-files-by-pattern,from/%,to/%,a b c)
@@ -880,6 +881,7 @@
   rblf.soong_config_namespace(g, "snsconfig")
   rblf.soong_config_set(g, "snsconfig", "imagetype", "odm_image")
   rblf.soong_config_set(g, "snsconfig", "foo", "foo_value")
+  rblf.soong_config_set_bool(g, "snsconfig", "bar", "true")
   rblf.soong_config_append(g, "snsconfig", "bar", "bar_value")
   cfg["PRODUCT_COPY_FILES"] = rblf.copy_files(rblf.expand_wildcard("foo*.mk"), "etc")
   cfg["PRODUCT_COPY_FILES"] = rblf.product_copy_files_by_pattern("from/%", "to/%", "a b c")
diff --git a/rust/bindgen.go b/rust/bindgen.go
index a81024a..31aa137 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -393,8 +393,8 @@
 		deps.StaticLibs = append(deps.StaticLibs, String(b.Properties.Static_inline_library))
 	}
 
-	deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs...)
-	deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs...)
-	deps.HeaderLibs = append(deps.HeaderLibs, b.ClangProperties.Header_libs...)
+	deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs.GetOrDefault(ctx, nil)...)
+	deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs.GetOrDefault(ctx, nil)...)
+	deps.HeaderLibs = append(deps.HeaderLibs, b.ClangProperties.Header_libs.GetOrDefault(ctx, nil)...)
 	return deps
 }
diff --git a/sdk/update.go b/sdk/update.go
index 198c8d4..a4b1967 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -1989,6 +1989,14 @@
 	return m.builder.targetBuildRelease.EarlierThan(buildReleaseT)
 }
 
+func (m *memberContext) Config() android.Config {
+	return m.sdkMemberContext.Config()
+}
+
+func (m *memberContext) OtherModulePropertyErrorf(module android.Module, property string, fmt string, args ...interface{}) {
+	m.sdkMemberContext.OtherModulePropertyErrorf(module, property, fmt, args)
+}
+
 var _ android.SdkMemberContext = (*memberContext)(nil)
 
 func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
diff --git a/ui/build/config.go b/ui/build/config.go
index b8fcb6b..dfe0dfe 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1041,7 +1041,7 @@
 
 func (c *configImpl) UsedEnvFile(tag string) string {
 	if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
-		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+"."+tag)
+		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+c.CoverageSuffix()+"."+tag)
 	}
 	return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
 }
@@ -1149,6 +1149,13 @@
 	return "", fmt.Errorf("TARGET_PRODUCT is not defined")
 }
 
+func (c *configImpl) CoverageSuffix() string {
+	if v := c.environ.IsEnvTrue("EMMA_INSTRUMENT"); v {
+		return ".coverage"
+	}
+	return ""
+}
+
 func (c *configImpl) TargetDevice() string {
 	return c.targetDevice
 }
@@ -1520,7 +1527,7 @@
 	if err != nil {
 		return filepath.Join(c.SoongOutDir(), "soong.variables")
 	} else {
-		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
+		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+c.CoverageSuffix()+".variables")
 	}
 }
 
@@ -1529,7 +1536,7 @@
 	if err != nil {
 		return filepath.Join(c.SoongOutDir(), "soong.extra.variables")
 	} else {
-		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".extra.variables")
+		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+c.CoverageSuffix()+".extra.variables")
 	}
 }
 
@@ -1538,7 +1545,7 @@
 	if err != nil {
 		return filepath.Join(c.SoongOutDir(), "build.ninja")
 	} else {
-		return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
+		return filepath.Join(c.SoongOutDir(), "build."+targetProduct+c.CoverageSuffix()+".ninja")
 	}
 }
 
@@ -1550,11 +1557,11 @@
 }
 
 func (c *configImpl) SoongAndroidMk() string {
-	return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+".mk")
+	return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+c.CoverageSuffix()+".mk")
 }
 
 func (c *configImpl) SoongMakeVarsMk() string {
-	return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
+	return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+c.CoverageSuffix()+".mk")
 }
 
 func (c *configImpl) SoongBuildMetrics() string {
diff --git a/ui/build/kati.go b/ui/build/kati.go
index a0efd2c..5743ff7 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -41,7 +41,7 @@
 // arguments.
 func genKatiSuffix(ctx Context, config Config) {
 	// Construct the base suffix.
-	katiSuffix := "-" + config.TargetProduct()
+	katiSuffix := "-" + config.TargetProduct() + config.CoverageSuffix()
 
 	// Append kati arguments to the suffix.
 	if args := config.KatiArgs(); len(args) > 0 {