Merge "Disable "__builtin_func" when converting mk to bp" into main
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 392e819..d29e312 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -137,18 +137,22 @@
 	inputFiles := make([]android.Path, len(declarationFiles))
 	copy(inputFiles, declarationFiles)
 	inputFiles = append(inputFiles, valuesFiles...)
+	args := map[string]string{
+		"release_version":    ctx.Config().ReleaseVersion(),
+		"package":            module.properties.Package,
+		"declarations":       android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
+		"values":             joinAndPrefix(" --values ", module.properties.Values),
+		"default-permission": optionalVariable(" --default-permission ", defaultPermission),
+	}
+	if len(module.properties.Container) > 0 {
+		args["container"] = "--container " + module.properties.Container
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aconfigRule,
 		Output:      intermediateCacheFilePath,
 		Inputs:      inputFiles,
 		Description: "aconfig_declarations",
-		Args: map[string]string{
-			"release_version":    ctx.Config().ReleaseVersion(),
-			"package":            module.properties.Package,
-			"declarations":       android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
-			"values":             joinAndPrefix(" --values ", module.properties.Values),
-			"default-permission": optionalVariable(" --default-permission ", defaultPermission),
-		},
+		Args:        args,
 	})
 
 	intermediateDumpFilePath := android.PathForModuleOut(ctx, "intermediate.txt")
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
index 1fe3c86..5201fed 100644
--- a/aconfig/aconfig_declarations_test.go
+++ b/aconfig/aconfig_declarations_test.go
@@ -69,3 +69,38 @@
 	depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
 	android.AssertBoolEquals(t, "exportable", depData.Exportable, false)
 }
+
+func TestAconfigDeclarationsWithContainer(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"foo.aconfig",
+			],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "")
+	rule := module.Rule("aconfig")
+	android.AssertStringEquals(t, "rule must contain container", rule.Args["container"], "--container com.android.foo")
+}
+
+func TestAconfigDeclarationsWithoutContainer(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name",
+			package: "com.example.package",
+			srcs: [
+				"foo.aconfig",
+			],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "")
+	rule := module.Rule("aconfig")
+	android.AssertIntEquals(t, "rule must not contain container", len(rule.Args["container"]), 0)
+}
diff --git a/aconfig/init.go b/aconfig/init.go
index 4625128..4655467 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -28,6 +28,7 @@
 		blueprint.RuleParams{
 			Command: `${aconfig} create-cache` +
 				` --package ${package}` +
+				` ${container}` +
 				` ${declarations}` +
 				` ${values}` +
 				` ${default-permission}` +
@@ -38,7 +39,7 @@
 				"${aconfig}",
 			},
 			Restat: true,
-		}, "release_version", "package", "declarations", "values", "default-permission")
+		}, "release_version", "package", "container", "declarations", "values", "default-permission")
 
 	// For create-device-config-sysprops: Generate aconfig flag value map text file
 	aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
diff --git a/android/api_levels.go b/android/api_levels.go
index 1130c3e..fab5fc7 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -289,6 +289,8 @@
 
 var ApiLevelR = uncheckedFinalApiLevel(30)
 
+var ApiLevelUpsideDownCake = uncheckedFinalApiLevel(34)
+
 // ReplaceFinalizedCodenames returns the API level number associated with that API level
 // if the `raw` input is the codename of an API level has been finalized.
 // If the input is *not* a finalized codename, the input is returned unmodified.
diff --git a/android/base_module_context.go b/android/base_module_context.go
index dd38a4e..9be3fad 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -305,6 +305,12 @@
 	AllowDisabledModuleDependency(target Module) bool
 }
 
+type AlwaysAllowDisabledModuleDependencyTag struct{}
+
+func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependency(Module) bool {
+	return true
+}
+
 func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool, ignoreBlueprint bool) Module {
 	aModule, _ := module.(Module)
 
diff --git a/android/config.go b/android/config.go
index 567ebd8..10c30d4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -168,7 +168,10 @@
 // Thus, verify_overlaps is disabled when RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE is set to false.
 // TODO(b/308174018): Re-enable verify_overlaps for both builr from source/mainline prebuilts.
 func (c Config) DisableVerifyOverlaps() bool {
-	return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || !c.ReleaseDefaultModuleBuildFromSource()
+	if c.IsEnvFalse("DISABLE_VERIFY_OVERLAPS") && c.ReleaseDisableVerifyOverlaps() {
+		panic("The current release configuration does not support verify_overlaps. DISABLE_VERIFY_OVERLAPS cannot be set to false")
+	}
+	return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || c.ReleaseDisableVerifyOverlaps() || !c.ReleaseDefaultModuleBuildFromSource()
 }
 
 // MaxPageSizeSupported returns the max page size supported by the device. This
@@ -209,6 +212,10 @@
 		Bool(c.config.productVariables.ReleaseDefaultModuleBuildFromSource)
 }
 
+func (c Config) ReleaseDisableVerifyOverlaps() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_DISABLE_VERIFY_OVERLAPS_CHECK")
+}
+
 // Enables flagged apis annotated with READ_WRITE aconfig flags to be included in the stubs
 // and hiddenapi flags so that they are accessible at runtime
 func (c Config) ReleaseExportRuntimeApis() bool {
diff --git a/android/filegroup.go b/android/filegroup.go
index bc881ed..86d7b4b 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"maps"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -97,6 +98,25 @@
 	}
 	SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
 	CollectDependencyAconfigFiles(ctx, &fg.mergedAconfigFiles)
+
+	var aconfigDeclarations []string
+	var intermediateCacheOutputPaths Paths
+	var srcjars Paths
+	modeInfos := make(map[string]ModeInfo)
+	ctx.VisitDirectDeps(func(module Module) {
+		if dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok {
+			aconfigDeclarations = append(aconfigDeclarations, dep.AconfigDeclarations...)
+			intermediateCacheOutputPaths = append(intermediateCacheOutputPaths, dep.IntermediateCacheOutputPaths...)
+			srcjars = append(srcjars, dep.Srcjars...)
+			maps.Copy(modeInfos, dep.ModeInfos)
+		}
+	})
+	SetProvider(ctx, CodegenInfoProvider, CodegenInfo{
+		AconfigDeclarations:          aconfigDeclarations,
+		IntermediateCacheOutputPaths: intermediateCacheOutputPaths,
+		Srcjars:                      srcjars,
+		ModeInfos:                    modeInfos,
+	})
 }
 
 func (fg *fileGroup) Srcs() Paths {
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 463fd07..eabb1b1 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -77,6 +77,11 @@
 		if ctx.OtherModuleDependencyTag(dep) == DefaultsDepTag {
 			return
 		}
+		// The required dependencies just say modules A and B should be installed together.
+		// It doesn't mean that one is built using the other.
+		if ctx.OtherModuleDependencyTag(dep) == RequiredDepTag {
+			return
+		}
 
 		if info, ok := OtherModuleProvider(ctx, dep, LicenseMetadataProvider); ok {
 			allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
diff --git a/android/module.go b/android/module.go
index 000476c..cce4fa6 100644
--- a/android/module.go
+++ b/android/module.go
@@ -542,6 +542,15 @@
 
 var teamDepTag = TeamDepTagType{}
 
+// Dependency tag for required, host_required, and target_required modules.
+var RequiredDepTag = struct {
+	blueprint.BaseDependencyTag
+	InstallAlwaysNeededDependencyTag
+	// Requiring disabled module has been supported (as a side effect of this being implemented
+	// in Make). We may want to make it an error, but for now, let's keep the existing behavior.
+	AlwaysAllowDisabledModuleDependencyTag
+}{}
+
 // CommonTestOptions represents the common `test_options` properties in
 // Android.bp.
 type CommonTestOptions struct {
@@ -1007,6 +1016,87 @@
 	if m.Team() != "" {
 		ctx.AddDependency(ctx.Module(), teamDepTag, m.Team())
 	}
+
+	// TODO(jiyong): remove below case. This is to work around build errors happening
+	// on branches with reduced manifest like aosp_kernel-build-tools.
+	// In the branch, a build error occurs as follows.
+	// 1. aosp_kernel-build-tools is a reduced manifest branch. It doesn't have some git
+	// projects like external/bouncycastle
+	// 2. `boot_signer` is `required` by modules like `build_image` which is explicitly list as
+	// the top-level build goal (in the shell file that invokes Soong).
+	// 3. `boot_signer` depends on `bouncycastle-unbundled` which is in the missing git project.
+	// 4. aosp_kernel-build-tools invokes soong with `--skip-make`. Therefore, the absence of
+	// ALLOW_MISSING_DEPENDENCIES didn't cause a problem.
+	// 5. Now, since Soong understands `required` deps, it tries to build `boot_signer` and the
+	// absence of external/bouncycastle fails the build.
+	//
+	// Unfortunately, there's no way for Soong to correctly determine if it's running in a
+	// reduced manifest branch. Instead, here, we use the absence of DeviceArch or DeviceName as
+	// a strong signal, because that's very common across reduced manifest branches.
+	pv := ctx.Config().productVariables
+	fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil
+	if fullManifest {
+		m.addRequiredDeps(ctx)
+	}
+}
+
+// addRequiredDeps adds required, target_required, and host_required as dependencies.
+func (m *ModuleBase) addRequiredDeps(ctx BottomUpMutatorContext) {
+	addDep := func(target Target, depName string) {
+		if !ctx.OtherModuleExists(depName) {
+			if ctx.Config().AllowMissingDependencies() {
+				return
+			}
+		}
+
+		// If Android native module requires another Android native module, ensure that
+		// they have the same bitness. This mimics the policy in select-bitness-of-required-modules
+		// in build/make/core/main.mk.
+		// TODO(jiyong): the Make-side does this only when the required module is a shared
+		// library or a native test.
+		bothInAndroid := m.Device() && target.Os.Class == Device
+		nativeArch := m.Arch().ArchType.Multilib != string(MultilibCommon)
+		sameBitness := m.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib
+		if bothInAndroid && nativeArch && !sameBitness {
+			return
+		}
+
+		variation := target.Variations()
+		if ctx.OtherModuleFarDependencyVariantExists(variation, depName) {
+			ctx.AddFarVariationDependencies(variation, RequiredDepTag, depName)
+		}
+	}
+
+	if m.Device() {
+		for _, depName := range m.RequiredModuleNames() {
+			for _, target := range ctx.Config().Targets[Android] {
+				addDep(target, depName)
+			}
+		}
+		for _, depName := range m.HostRequiredModuleNames() {
+			for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
+				addDep(target, depName)
+			}
+		}
+	}
+
+	if m.Host() {
+		for _, depName := range m.RequiredModuleNames() {
+			for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
+				// When a host module requires another host module, don't make a
+				// dependency if they have different OSes (i.e. hostcross).
+				if m.Target().HostCross != target.HostCross {
+					continue
+				}
+				addDep(target, depName)
+			}
+		}
+		for _, depName := range m.TargetRequiredModuleNames() {
+			for _, target := range ctx.Config().Targets[Android] {
+				addDep(target, depName)
+			}
+		}
+	}
 }
 
 // AddProperties "registers" the provided props
diff --git a/android/singleton.go b/android/singleton.go
index ccddeaf..5f93996 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -251,7 +251,7 @@
 
 func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
 	// get module reference for visibility enforcement
-	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), s.ModuleType(referer))
+	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer)
 
 	modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
 	result := make([]Module, 0, len(modules))
diff --git a/android/visibility.go b/android/visibility.go
index 79a534f..89c0adc 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -58,19 +58,14 @@
 var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
 
 type visibilityModuleReference struct {
-	name              qualifiedModuleName
-	isPartitionModule bool
+	name   qualifiedModuleName
+	module Module
 }
 
-func createVisibilityModuleReference(name, dir, typ string) visibilityModuleReference {
-	isPartitionModule := false
-	switch typ {
-	case "android_filesystem", "android_system_image":
-		isPartitionModule = true
-	}
+func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference {
 	return visibilityModuleReference{
-		name:              createQualifiedModuleName(name, dir),
-		isPartitionModule: isPartitionModule,
+		name:   createQualifiedModuleName(name, dir),
+		module: module,
 	}
 }
 
@@ -214,21 +209,37 @@
 	return "//visibility:private"
 }
 
+var anyPartitionRegex = regexp.MustCompile("^any_(system|system_ext|vendor|product|data|odm)_partition$")
+
 // visibilityRule for //visibility:any_partition
-type anyPartitionRule struct{}
+type anyPartitionRule struct {
+	partitionType string
+}
 
 var _ visibilityRule = anyPartitionRule{}
 
+type PartitionTypeInterface interface {
+	PartitionType() string
+}
+
 func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
-	return m.isPartitionModule
+	if m2, ok := m.module.(PartitionTypeInterface); ok {
+		return m2.PartitionType() == r.partitionType
+	}
+	return false
 }
 
 func (r anyPartitionRule) String() string {
-	return "//visibility:any_partition"
+	return "//visibility:any_" + r.partitionType + "_partition"
 }
 
 var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
 
+type visibilityRulesForModule struct {
+	rule                   compositeRule
+	implicitPartitionRules compositeRule
+}
+
 // The map from qualifiedModuleName to visibilityRule.
 func moduleToVisibilityRuleMap(config Config) *sync.Map {
 	return config.Once(visibilityRuleMap, func() interface{} {
@@ -304,9 +315,6 @@
 		if pkg == "visibility" {
 			switch name {
 			case "private", "public":
-			case "any_partition":
-				// any_partition can be used with another visibility fields
-				continue
 			case "legacy_public":
 				ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
 				continue
@@ -314,6 +322,10 @@
 				// This keyword does not create a rule so pretend it does not exist.
 				ruleCount -= 1
 			default:
+				if anyPartitionRegex.MatchString(name) {
+					// any_*_partition can be used with another visibility fields
+					continue
+				}
 				ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
 				continue
 			}
@@ -352,15 +364,20 @@
 
 	// Parse the visibility rules that control access to the module and store them by id
 	// for use when enforcing the rules.
+	var rule compositeRule
 	primaryProperty := m.base().primaryVisibilityProperty
 	if primaryProperty != nil {
 		if visibility := primaryProperty.getStrings(); visibility != nil {
-			rule := parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
-			if rule != nil {
-				moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
-			}
+			rule = parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
 		}
 	}
+	ipr := implicitPartitionRules(ctx)
+	if rule != nil || ipr != nil {
+		moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, visibilityRulesForModule{
+			rule:                   rule,
+			implicitPartitionRules: ipr,
+		})
+	}
 }
 
 func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
@@ -392,8 +409,13 @@
 				hasNonPrivateRule = false
 				// This does not actually create a rule so continue onto the next rule.
 				continue
-			case "any_partition":
-				r = anyPartitionRule{}
+			default:
+				match := anyPartitionRegex.FindStringSubmatch(name)
+				if match != nil {
+					r = anyPartitionRule{
+						partitionType: match[1],
+					}
+				}
 			}
 		} else {
 			switch name {
@@ -432,6 +454,22 @@
 	return rules
 }
 
+func implicitPartitionRules(ctx BaseModuleContext) compositeRule {
+	var result compositeRule
+	if ctx.SocSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "vendor"})
+	} else if ctx.ProductSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "product"})
+	} else if ctx.Module().InstallInData() {
+		result = append(result, anyPartitionRule{partitionType: "data"})
+	} else if ctx.SystemExtSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "system_ext"})
+	} else if ctx.DeviceSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "odm"})
+	}
+	return result
+}
+
 func isAllowedFromOutsideVendor(pkg string, name string) bool {
 	if pkg == "vendor" {
 		return name == "__subpackages__"
@@ -470,7 +508,7 @@
 }
 
 func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
-	qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.ModuleType())
+	qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
 
 	// Visit all the dependencies making sure that this module has access to them all.
 	ctx.VisitDirectDeps(func(dep Module) {
@@ -505,10 +543,13 @@
 // which is currently //visibility:public.
 func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
 	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
-	value, ok := moduleToVisibilityRule.Load(qualified)
+	value := visibilityRulesForModule{}
+	if valueRaw, ok := moduleToVisibilityRule.Load(qualified); ok {
+		value = valueRaw.(visibilityRulesForModule)
+	}
 	var rule compositeRule
-	if ok {
-		rule = value.(compositeRule)
+	if value.rule != nil {
+		rule = value.rule
 	} else {
 		rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
 	}
@@ -518,6 +559,20 @@
 	if rule == nil {
 		rule = defaultVisibility
 	}
+
+	// If a partition rule wasn't specified, add implicit partition visibility
+	// rules based on the partition properties like vendor: true.
+	foundPartitionRule := false
+	for _, r := range rule {
+		if _, ok := r.(anyPartitionRule); ok {
+			foundPartitionRule = true
+			break
+		}
+	}
+	if !foundPartitionRule {
+		rule = append(rule, value.implicitPartitionRules...)
+	}
+
 	return rule
 }
 
@@ -531,7 +586,7 @@
 	for {
 		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
 		if ok {
-			return value.(compositeRule)
+			return value.(visibilityRulesForModule).rule
 		}
 
 		if packageQualifiedId.isRootPackage() {
@@ -605,7 +660,7 @@
 
 	rule := effectiveVisibilityRules(ctx.Config(), qualified)
 
-	currentModule := createVisibilityModuleReference(moduleName, dir, ctx.OtherModuleType(module))
+	currentModule := createVisibilityModuleReference(moduleName, dir, module)
 
 	// Modules are implicitly visible to other modules in the same package,
 	// without checking the visibility rules. Here we need to add that visibility
diff --git a/android/visibility_test.go b/android/visibility_test.go
index bb43b1f..1a2eeca 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1905,7 +1905,7 @@
 		},
 	},
 	{
-		name: "any_partition visibility works",
+		name: "any_system_partition visibility works",
 		fs: MockFS{
 			"top/Android.bp": []byte(`
 				android_filesystem {
@@ -1916,12 +1916,12 @@
 				package(default_visibility=["//visibility:private"])
 				mock_library {
 					name: "bar",
-					visibility: ["//visibility:any_partition"],
+					visibility: ["//visibility:any_system_partition"],
 				}`),
 		},
 	},
 	{
-		name: "any_partition visibility works with the other visibility",
+		name: "any_system_partition visibility works with the other visibility",
 		fs: MockFS{
 			"top/Android.bp": []byte(`
 				android_filesystem {
@@ -1935,13 +1935,13 @@
 					name: "bar",
 					visibility: [
 						"//top2",
-						"//visibility:any_partition"
+						"//visibility:any_system_partition"
 					],
 				}`),
 		},
 	},
 	{
-		name: "any_partition visibility doesn't work for non-partitions",
+		name: "any_system_partition visibility doesn't work for non-partitions",
 		fs: MockFS{
 			"top/Android.bp": []byte(`
 				mock_library {
@@ -1951,11 +1951,77 @@
 			"top/nested/Android.bp": []byte(`
 				mock_library {
 					name: "bar",
-					visibility: ["//visibility:any_partition"],
+					visibility: ["//visibility:any_system_partition"],
 				}`),
 		},
 		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
 	},
+	{
+		name: "any_system_partition visibility doesn't work for vendor partitions",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					partition_type: "vendor",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_system_partition"],
+				}`),
+		},
+		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
+	},
+	{
+		name: "Vendor modules are visible to any vendor partition by default",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					partition_type: "vendor",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					vendor: true,
+				}`),
+		},
+	},
+	{
+		name: "Not visible to vendor partitions when using any_system_partiton, even if vendor: true",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					partition_type: "vendor",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					vendor: true,
+					visibility: ["//visibility:any_system_partition"],
+				}`),
+		},
+		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
+	},
+	{
+		name: "unknown any_partition specs throw errors",
+		fs: MockFS{
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_unknown_partition"],
+				}`),
+		},
+		expectedErrors: []string{`unrecognized visibility rule "//visibility:any_unknown_partition"`},
+	},
 }
 
 func TestVisibility(t *testing.T) {
@@ -1977,8 +2043,7 @@
 					ctx.RegisterModuleType("mock_library", newMockLibraryModule)
 					ctx.RegisterModuleType("mock_parent", newMockParentFactory)
 					ctx.RegisterModuleType("mock_defaults", defaultsFactory)
-					// For testing //visibility:any_partition. The module type doesn't matter, just that it's registered under the name "android_filesystem"
-					ctx.RegisterModuleType("android_filesystem", newMockLibraryModule)
+					ctx.RegisterModuleType("android_filesystem", newMockFilesystemModule)
 				}),
 				prepareForTestWithFakePrebuiltModules,
 				// Add additional files to the mock filesystem
@@ -2032,6 +2097,37 @@
 func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
 }
 
+type mockFilesystemModuleProperties struct {
+	Partition_type *string
+	Deps           []string
+}
+
+type mockFilesystemModule struct {
+	ModuleBase
+	properties mockFilesystemModuleProperties
+}
+
+func (j *mockFilesystemModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
+}
+
+func (p *mockFilesystemModule) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+func (p *mockFilesystemModule) PartitionType() string {
+	if p.properties.Partition_type == nil {
+		return "system"
+	}
+	return *p.properties.Partition_type
+}
+
+func newMockFilesystemModule() Module {
+	m := &mockFilesystemModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, DeviceSupported, MultilibCommon)
+	return m
+}
+
 type mockDefaults struct {
 	ModuleBase
 	DefaultsModuleBase
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index fb6be38..8a20bb0 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -413,6 +413,9 @@
 				p.accept('\t')
 				newLine = false
 				continue loop
+			} else if p.tok == '\n' {
+				p.accept('\n')
+				continue loop
 			} else if p.parseDirective() {
 				newLine = false
 				continue
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
index 9efebf8..db3313d 100644
--- a/androidmk/parser/parser_test.go
+++ b/androidmk/parser/parser_test.go
@@ -84,6 +84,22 @@
 			},
 		},
 	},
+	{
+		name: "Blank line in rule's command",
+		in:   `all:
+	echo first line
+
+	echo second line`,
+		out: []Node{
+			&Rule{
+				Target: SimpleMakeString("all", NoPos),
+				RecipePos: NoPos,
+				Recipe: "echo first line\necho second line",
+				Prerequisites: SimpleMakeString("", NoPos),
+			},
+		},
+	},
+
 }
 
 func TestParse(t *testing.T) {
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
index be98d45..a179dbf 100644
--- a/apex/aconfig_test.go
+++ b/apex/aconfig_test.go
@@ -193,6 +193,70 @@
 					mode: "exported",
 				}`,
 		},
+		{
+			name: "Rust lib passes for exported containers cross",
+			bp: apex_default_bp + `
+			apex {
+				name: "myapex",
+				manifest: ":myapex.manifest",
+				androidManifest: ":myapex.androidmanifest",
+				key: "myapex.key",
+				native_shared_libs: ["libmy_rust_library"],
+				binaries: ["my_rust_binary"],
+				updatable: false,
+			}
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_ffi_shared {
+				name: "libmy_rust_library",
+				srcs: ["src/lib.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_foo"],
+				crate_name: "my_rust_library",
+				apex_available: ["myapex"],
+			}
+			rust_binary {
+				name: "my_rust_binary",
+				srcs: ["foo/bar/MyClass.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_bar"],
+				apex_available: ["myapex"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_foo",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["foo.aconfig"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_bar",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["bar.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_foo",
+				aconfig_declarations: "my_aconfig_declarations_foo",
+				crate_name: "my_rust_aconfig_library_foo",
+				apex_available: ["myapex"],
+				mode: "exported",
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_bar",
+				aconfig_declarations: "my_aconfig_declarations_bar",
+				crate_name: "my_rust_aconfig_library_bar",
+				apex_available: ["myapex"],
+				mode: "exported",
+			}`,
+		},
 	}
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
@@ -394,6 +458,93 @@
 			expectedError: `.*my_cc_binary_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
 		},
 		{
+			name: "Rust lib fails for non-exported containers cross",
+			bp: apex_default_bp + `
+			apex {
+				name: "myapex",
+				manifest: ":myapex.manifest",
+				androidManifest: ":myapex.androidmanifest",
+				key: "myapex.key",
+				native_shared_libs: ["libmy_rust_library"],
+				updatable: false,
+			}
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_ffi_shared {
+				name: "libmy_rust_library",
+				srcs: ["src/lib.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_foo"],
+				crate_name: "my_rust_library",
+				apex_available: ["myapex"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_foo",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["foo.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_foo",
+				aconfig_declarations: "my_aconfig_declarations_foo",
+				crate_name: "my_rust_aconfig_library_foo",
+				apex_available: ["myapex"],
+			}`,
+			expectedError: `.*libmy_rust_aconfig_library_foo/myapex depends on libmy_rust_aconfig_library_foo/otherapex/production across containers`,
+		},
+		{
+			name: "Rust binary fails for non-exported containers cross",
+			bp: apex_default_bp + `
+			apex {
+				name: "myapex",
+				manifest: ":myapex.manifest",
+				androidManifest: ":myapex.androidmanifest",
+				key: "myapex.key",
+				binaries: ["my_rust_binary"],
+				updatable: false,
+			}
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_binary {
+				name: "my_rust_binary",
+				srcs: ["foo/bar/MyClass.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_bar"],
+				apex_available: ["myapex"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_bar",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["bar.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_bar",
+				aconfig_declarations: "my_aconfig_declarations_bar",
+				crate_name: "my_rust_aconfig_library_bar",
+				apex_available: ["myapex"],
+			}`,
+			expectedError: `.*libmy_rust_aconfig_library_bar/myapex depends on libmy_rust_aconfig_library_bar/otherapex/production across containers`,
+		},
+		{
 			name: "Aconfig validation propagate along sourceOrOutputDependencyTag",
 			bp: apex_default_bp + `
 				apex {
diff --git a/apex/apex.go b/apex/apex.go
index 32a3638..bc91407 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1648,10 +1648,9 @@
 	return af
 }
 
-func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile {
+func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, outputFile android.Path) apexFile {
 	dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
-	fileToCopy := prebuilt.OutputFile()
-	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
+	return newApexFile(ctx, outputFile, outputFile.Base(), dirInApex, etc, prebuilt)
 }
 
 func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
@@ -1821,6 +1820,9 @@
 		if dt, ok := depTag.(*dependencyTag); ok && !dt.payload {
 			return false
 		}
+		if depTag == android.RequiredDepTag {
+			return false
+		}
 
 		ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
 		externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
@@ -2120,7 +2122,10 @@
 			}
 		case prebuiltTag:
 			if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+				filesToCopy, _ := prebuilt.OutputFiles("")
+				for _, etcFile := range filesToCopy {
+					vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
+				}
 				addAconfigFiles(vctx, ctx, child)
 			} else {
 				ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
@@ -2263,7 +2268,10 @@
 		// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
 	} else if java.IsXmlPermissionsFileDepTag(depTag) {
 		if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
-			vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+			filesToCopy, _ := prebuilt.OutputFiles("")
+			for _, etcFile := range filesToCopy {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
+			}
 		}
 	} else if rust.IsDylibDepTag(depTag) {
 		if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
@@ -2314,6 +2322,8 @@
 		// nothing
 	} else if depTag == android.DarwinUniversalVariantTag {
 		// nothing
+	} else if depTag == android.RequiredDepTag {
+		// nothing
 	} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 		ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
 	}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 19b9d16..b7362b2 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -10047,7 +10047,6 @@
 			key: "myapex.key",
 			updatable: false,
 			java_libs: ["foo"],
-			required: ["otherapex"],
 		}
 
 		apex_key {
@@ -11022,7 +11021,7 @@
 		}
 	`)
 
-	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("deps.zip").Implicits
+	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img").Implicits
 	android.AssertStringListDoesNotContain(t, "filesystem should not have libbar",
 		inputs.Strings(),
 		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
diff --git a/cc/cc.go b/cc/cc.go
index 0fa3457..90185ea 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2980,6 +2980,9 @@
 		if depTag == stubImplDepTag {
 			return false
 		}
+		if depTag == android.RequiredDepTag {
+			return false
+		}
 
 		// Even if target lib has no vendor variant, keep checking dependency
 		// graph in case it depends on vendor_available or product_available
@@ -3157,6 +3160,10 @@
 			return
 		}
 
+		if depTag == android.RequiredDepTag {
+			return
+		}
+
 		if dep.Target().Os != ctx.Os() {
 			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
 			return
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 0de9e05..10342a3 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -49,7 +49,6 @@
 	}
 
 	arm64Ldflags = []string{
-		"-Wl,--hash-style=gnu",
 		"-Wl,-z,separate-code",
 		"-Wl,-z,separate-loadable-segments",
 	}
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 335ad56..f7d190b 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -42,7 +42,6 @@
 		"-Wl,-z,now",
 		"-Wl,--build-id=md5",
 		"-Wl,--fatal-warnings",
-		"-Wl,--hash-style=gnu",
 		"-Wl,--no-undefined-version",
 	}
 
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 603bc6d..3284e4b 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -38,7 +38,6 @@
   }
 
 	armLdflags = []string{
-		"-Wl,--hash-style=gnu",
 		"-Wl,-m,armelf",
 		// Revert this after b/322359235 is fixed
 		"-Wl,-mllvm", "-Wl,-enable-shrink-wrap=false",
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index 6a84fee..47f0de1 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -23,24 +23,29 @@
 
 var (
 	riscv64Cflags = []string{
-		// Help catch common 32/64-bit errors.
+		// Help catch common 32/64-bit errors. (This is duplicated in all 64-bit
+		// architectures' cflags.)
 		"-Werror=implicit-function-declaration",
+		// This is already the driver's Android default, but duplicated here (and
+		// below) for ease of experimentation with additional extensions.
 		"-march=rv64gcv_zba_zbb_zbs",
-		"-munaligned-access",
-		// Until https://gitlab.com/qemu-project/qemu/-/issues/1976 is fixed...
+		// TODO: move to driver (https://github.com/google/android-riscv64/issues/111)
+		"-mno-strict-align",
+		// TODO: remove when qemu V works (https://gitlab.com/qemu-project/qemu/-/issues/1976)
+		// (Note that we'll probably want to wait for berberis to be good enough
+		// that most people don't care about qemu's V performance either!)
 		"-mno-implicit-float",
-		// (https://github.com/google/android-riscv64/issues/124)
+		// TODO: remove when clang default changed (https://github.com/google/android-riscv64/issues/124)
 		"-mllvm -jump-is-expensive=false",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
 
 	riscv64Ldflags = []string{
-		"-Wl,--hash-style=gnu",
+		// This is already the driver's Android default, but duplicated here (and
+		// above) for ease of experimentation with additional extensions.
 		"-march=rv64gcv_zba_zbb_zbs",
-		"-munaligned-access",
-		// We should change the default for this in clang, but for now...
-		// (https://github.com/google/android-riscv64/issues/124)
+		// TODO: remove when clang default changed (https://github.com/google/android-riscv64/issues/124)
 		"-Wl,-mllvm -Wl,-jump-is-expensive=false",
 	}
 
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 12119a7..ca2c2b7 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -30,7 +30,6 @@
 	x86_64Cppflags = []string{}
 
 	x86_64Ldflags = []string{
-		"-Wl,--hash-style=gnu",
 		"-Wl,-z,separate-loadable-segments",
 	}
 
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 2faa670..60b8339 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -33,9 +33,7 @@
 
 	x86Cppflags = []string{}
 
-	x86Ldflags = []string{
-		"-Wl,--hash-style=gnu",
-	}
+	x86Ldflags = []string{}
 
 	x86ArchVariantCflags = map[string][]string{
 		"": []string{
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index f80be99..99d4ebb 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -46,7 +46,6 @@
 		"-Wl,-z,now",
 		"-Wl,--build-id=md5",
 		"-Wl,--fatal-warnings",
-		"-Wl,--hash-style=gnu",
 		"-Wl,--no-undefined-version",
 
 		// Use the device gcc toolchain
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index 05c644f..0896206 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -210,3 +210,47 @@
 		t.Errorf(`expected product variant, but does not exist in %v`, variants)
 	}
 }
+
+// cc_genrule is initialized to android.InitAndroidArchModule
+// that is an architecture-specific Android module.
+// So testing properties tagged with `android:"arch_variant"`
+// for cc_genrule.
+func TestMultilibGenruleOut(t *testing.T) {
+	bp := `
+	cc_genrule {
+		name: "gen",
+		cmd: "cp $(in) $(out)",
+		srcs: ["foo"],
+		multilib: {
+			lib32: {
+				out: [
+					"subdir32/external-module32",
+				],
+			},
+			lib64: {
+				out: [
+					"subdir64/external-module64",
+				],
+			},
+		},
+	}
+	`
+	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp)
+	gen_32bit := result.ModuleForTests("gen", "android_arm_armv7-a-neon").OutputFiles(t, "")
+	android.AssertPathsEndWith(t,
+		"genrule_out",
+		[]string{
+			"subdir32/external-module32",
+		},
+		gen_32bit,
+	)
+
+	gen_64bit := result.ModuleForTests("gen", "android_arm64_armv8-a").OutputFiles(t, "")
+	android.AssertPathsEndWith(t,
+		"genrule_out",
+		[]string{
+			"subdir64/external-module64",
+		},
+		gen_64bit,
+	)
+}
diff --git a/cc/linker.go b/cc/linker.go
index 2c50db2..9686697 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -530,13 +530,6 @@
 		flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...)
 	}
 
-	if ctx.useSdk() {
-		// The bionic linker now has support gnu style hashes (which are much faster!), but shipping
-		// to older devices requires the old style hash. Fortunately, we can build with both and
-		// it'll work anywhere.
-		flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--hash-style=both")
-	}
-
 	flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags())
 
 	// Version_script is not needed when linking stubs lib where the version
diff --git a/cc/lto.go b/cc/lto.go
index 05fa8ee..a084db7 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -90,10 +90,6 @@
 	} else if ctx.testBinary() || ctx.testLibrary() {
 		// Do not enable LTO for tests for better debugging.
 		ltoEnabled = false
-	} else if ctx.isVndk() {
-		// FIXME: ThinLTO for VNDK produces different output.
-		// b/169217596
-		ltoEnabled = false
 	}
 
 	lto.Properties.LtoDefault = ltoDefault
diff --git a/cmd/symbols_map/Android.bp b/cmd/symbols_map/Android.bp
index 0ba3b07..e3ae6ed 100644
--- a/cmd/symbols_map/Android.bp
+++ b/cmd/symbols_map/Android.bp
@@ -5,17 +5,16 @@
 blueprint_go_binary {
     name: "symbols_map",
     srcs: [
-        "elf.go",
         "r8.go",
         "symbols_map.go",
     ],
     testSrcs: [
-        "elf_test.go",
         "r8_test.go",
     ],
     deps: [
         "blueprint-pathtools",
         "golang-protobuf-encoding-prototext",
+        "soong-elf",
         "soong-response",
         "symbols_map_proto",
     ],
diff --git a/cmd/symbols_map/symbols_map.go b/cmd/symbols_map/symbols_map.go
index 938446d..c56cf93 100644
--- a/cmd/symbols_map/symbols_map.go
+++ b/cmd/symbols_map/symbols_map.go
@@ -22,6 +22,7 @@
 	"strings"
 
 	"android/soong/cmd/symbols_map/symbols_map_proto"
+	"android/soong/elf"
 	"android/soong/response"
 
 	"github.com/google/blueprint/pathtools"
@@ -116,7 +117,7 @@
 	if *elfFile != "" {
 		typ = symbols_map_proto.Mapping_ELF
 		location = *elfFile
-		identifier, err = elfIdentifier(*elfFile, true)
+		identifier, err = elf.Identifier(*elfFile, true)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "error reading elf identifier: %s\n", err)
 			os.Exit(1)
diff --git a/elf/Android.bp b/elf/Android.bp
new file mode 100644
index 0000000..6450be1
--- /dev/null
+++ b/elf/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-elf",
+    pkgPath: "android/soong/elf",
+    srcs: [
+        "elf.go",
+    ],
+    testSrcs: [
+        "elf_test.go",
+    ],
+}
diff --git a/cmd/symbols_map/elf.go b/elf/elf.go
similarity index 94%
rename from cmd/symbols_map/elf.go
rename to elf/elf.go
index 950e3b2..e84a8ae 100644
--- a/cmd/symbols_map/elf.go
+++ b/elf/elf.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package elf
 
 import (
 	"debug/elf"
@@ -26,9 +26,9 @@
 
 const gnuBuildID = "GNU\x00"
 
-// elfIdentifier extracts the elf build ID from an elf file.  If allowMissing is true it returns
+// Identifier extracts the elf build ID from an elf file.  If allowMissing is true it returns
 // an empty identifier if the file exists but the build ID note does not.
-func elfIdentifier(filename string, allowMissing bool) (string, error) {
+func Identifier(filename string, allowMissing bool) (string, error) {
 	f, err := os.Open(filename)
 	if err != nil {
 		return "", fmt.Errorf("failed to open %s: %w", filename, err)
diff --git a/cmd/symbols_map/elf_test.go b/elf/elf_test.go
similarity index 99%
rename from cmd/symbols_map/elf_test.go
rename to elf/elf_test.go
index a94c87f..a220770 100644
--- a/cmd/symbols_map/elf_test.go
+++ b/elf/elf_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package elf
 
 import (
 	"bytes"
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 7642378..a42c576 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -71,10 +71,15 @@
 
 type prebuiltEtcProperties struct {
 	// Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax.
+	// Mutually exclusive with srcs.
 	Src *string `android:"path,arch_variant"`
 
+	// Source files of this prebuilt. Can reference a genrule type module with the ":module" syntax.
+	// Mutually exclusive with src. When used, filename_from_src is set to true.
+	Srcs []string `android:"path,arch_variant"`
+
 	// Optional name for the installed file. If unspecified, name of the module is used as the file
-	// name.
+	// name. Only available when using a single source (src).
 	Filename *string `android:"arch_variant"`
 
 	// When set to true, and filename property is not set, the name for the installed file
@@ -127,9 +132,9 @@
 	// Returns the sub install directory relative to BaseDir().
 	SubDir() string
 
-	// Returns an android.OutputPath to the intermeidate file, which is the renamed prebuilt source
+	// Returns an android.OutputPath to the intermediate file, which is the renamed prebuilt source
 	// file.
-	OutputFile() android.OutputPath
+	OutputFiles(tag string) (android.Paths, error)
 }
 
 type PrebuiltEtc struct {
@@ -142,8 +147,8 @@
 	properties       prebuiltEtcProperties
 	subdirProperties prebuiltSubdirProperties
 
-	sourceFilePath android.Path
-	outputFilePath android.OutputPath
+	sourceFilePaths android.Paths
+	outputFilePaths android.OutputPaths
 	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
 	installDirBase               string
 	installDirBase64             string
@@ -246,6 +251,9 @@
 }
 
 func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path {
+	if len(p.properties.Srcs) > 0 {
+		panic(fmt.Errorf("SourceFilePath not available on multi-source prebuilt %q", p.Name()))
+	}
 	return android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
 }
 
@@ -260,7 +268,10 @@
 }
 
 func (p *PrebuiltEtc) OutputFile() android.OutputPath {
-	return p.outputFilePath
+	if len(p.properties.Srcs) > 0 {
+		panic(fmt.Errorf("OutputFile not available on multi-source prebuilt %q", p.Name()))
+	}
+	return p.outputFilePaths[0]
 }
 
 var _ android.OutputFileProducer = (*PrebuiltEtc)(nil)
@@ -268,7 +279,7 @@
 func (p *PrebuiltEtc) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
-		return android.Paths{p.outputFilePath}, nil
+		return p.outputFilePaths.Paths(), nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -301,50 +312,7 @@
 	return false
 }
 
-func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	filename := proptools.String(p.properties.Filename)
-	filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
-	if p.properties.Src != nil {
-		p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
-
-		// Determine the output file basename.
-		// If Filename is set, use the name specified by the property.
-		// If Filename_from_src is set, use the source file name.
-		// Otherwise use the module name.
-		if filename != "" {
-			if filenameFromSrc {
-				ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
-				return
-			}
-		} else if filenameFromSrc {
-			filename = p.sourceFilePath.Base()
-		} else {
-			filename = ctx.ModuleName()
-		}
-	} else if ctx.Config().AllowMissingDependencies() {
-		// If no srcs was set and AllowMissingDependencies is enabled then
-		// mark the module as missing dependencies and set a fake source path
-		// and file name.
-		ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"})
-		p.sourceFilePath = android.PathForModuleSrc(ctx)
-		if filename == "" {
-			filename = ctx.ModuleName()
-		}
-	} else {
-		ctx.PropertyErrorf("src", "missing prebuilt source file")
-		return
-	}
-
-	if strings.Contains(filename, "/") {
-		ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
-		return
-	}
-
-	// Check that `sub_dir` and `relative_install_path` are not set at the same time.
-	if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
-		ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
-	}
-
+func (p *PrebuiltEtc) installBaseDir(ctx android.ModuleContext) string {
 	// If soc install dir was specified and SOC specific is set, set the installDirPath to the
 	// specified socInstallDirBase.
 	installBaseDir := p.installDirBase
@@ -357,47 +325,138 @@
 	if p.installAvoidMultilibConflict && !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
 		installBaseDir = filepath.Join(installBaseDir, ctx.Arch().ArchType.String())
 	}
+	return installBaseDir
+}
 
-	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
+func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	var installs []installProperties
 
-	// Call InstallFile even when uninstallable to make the module included in the package
-	ip := installProperties{
-		installable:    p.Installable(),
-		filename:       filename,
-		sourceFilePath: p.sourceFilePath,
-		symlinks:       p.properties.Symlinks,
+	if p.properties.Src != nil && len(p.properties.Srcs) > 0 {
+		ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
 	}
-	p.addInstallRules(ctx, ip)
+
+	// Check that `sub_dir` and `relative_install_path` are not set at the same time.
+	if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
+		ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
+	}
+	p.installDirPath = android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir())
+
+	filename := proptools.String(p.properties.Filename)
+	filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
+	if p.properties.Src != nil {
+		p.sourceFilePaths = android.PathsForModuleSrc(ctx, []string{proptools.String(p.properties.Src)})
+		// If the source was not found, set a fake source path to
+		// support AllowMissingDependencies executions.
+		if len(p.sourceFilePaths) == 0 {
+			p.sourceFilePaths = android.Paths{android.PathForModuleSrc(ctx)}
+		}
+
+		// Determine the output file basename.
+		// If Filename is set, use the name specified by the property.
+		// If Filename_from_src is set, use the source file name.
+		// Otherwise use the module name.
+		if filename != "" {
+			if filenameFromSrc {
+				ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
+				return
+			}
+		} else if filenameFromSrc {
+			filename = p.sourceFilePaths[0].Base()
+		} else {
+			filename = ctx.ModuleName()
+		}
+		if strings.Contains(filename, "/") {
+			ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
+			return
+		}
+		p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+
+		ip := installProperties{
+			filename:       filename,
+			sourceFilePath: p.sourceFilePaths[0],
+			outputFilePath: p.outputFilePaths[0],
+			installDirPath: p.installDirPath,
+			symlinks:       p.properties.Symlinks,
+		}
+		installs = append(installs, ip)
+	} else if len(p.properties.Srcs) > 0 {
+		if filename != "" {
+			ctx.PropertyErrorf("filename", "filename cannot be set when using srcs")
+		}
+		if len(p.properties.Symlinks) > 0 {
+			ctx.PropertyErrorf("symlinks", "symlinks cannot be set when using srcs")
+		}
+		if p.properties.Filename_from_src != nil {
+			ctx.PropertyErrorf("filename_from_src", "filename_from_src is implicitly set to true when using srcs")
+		}
+		p.sourceFilePaths = android.PathsForModuleSrc(ctx, p.properties.Srcs)
+		for _, src := range p.sourceFilePaths {
+			filename := src.Base()
+			output := android.PathForModuleOut(ctx, filename).OutputPath
+			ip := installProperties{
+				filename:       filename,
+				sourceFilePath: src,
+				outputFilePath: output,
+				installDirPath: p.installDirPath,
+			}
+			p.outputFilePaths = append(p.outputFilePaths, output)
+			installs = append(installs, ip)
+		}
+	} else if ctx.Config().AllowMissingDependencies() {
+		// If no srcs was set and AllowMissingDependencies is enabled then
+		// mark the module as missing dependencies and set a fake source path
+		// and file name.
+		ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"})
+		p.sourceFilePaths = android.Paths{android.PathForModuleSrc(ctx)}
+		if filename == "" {
+			filename = ctx.ModuleName()
+		}
+		p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+		ip := installProperties{
+			filename:       filename,
+			sourceFilePath: p.sourceFilePaths[0],
+			outputFilePath: p.outputFilePaths[0],
+			installDirPath: p.installDirPath,
+		}
+		installs = append(installs, ip)
+	} else {
+		ctx.PropertyErrorf("src", "missing prebuilt source file")
+		return
+	}
+
+	// Call InstallFile even when uninstallable to make the module included in the package.
+	if !p.Installable() {
+		p.SkipInstall()
+	}
+	for _, ip := range installs {
+		ip.addInstallRules(ctx)
+	}
 	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 type installProperties struct {
-	installable    bool
 	filename       string
 	sourceFilePath android.Path
+	outputFilePath android.OutputPath
+	installDirPath android.InstallPath
 	symlinks       []string
 }
 
 // utility function to add install rules to the build graph.
 // Reduces code duplication between Soong and Mixed build analysis
-func (p *PrebuiltEtc) addInstallRules(ctx android.ModuleContext, ip installProperties) {
-	if !ip.installable {
-		p.SkipInstall()
-	}
-
+func (ip *installProperties) addInstallRules(ctx android.ModuleContext) {
 	// Copy the file from src to a location in out/ with the correct `filename`
 	// This ensures that outputFilePath has the correct name for others to
 	// use, as the source file may have a different name.
-	p.outputFilePath = android.PathForModuleOut(ctx, ip.filename).OutputPath
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.Cp,
-		Output: p.outputFilePath,
+		Output: ip.outputFilePath,
 		Input:  ip.sourceFilePath,
 	})
 
-	installPath := ctx.InstallFile(p.installDirPath, ip.filename, p.outputFilePath)
+	installPath := ctx.InstallFile(ip.installDirPath, ip.filename, ip.outputFilePath)
 	for _, sl := range ip.symlinks {
-		ctx.InstallSymlink(p.installDirPath, sl, installPath)
+		ctx.InstallSymlink(ip.installDirPath, sl, installPath)
 	}
 }
 
@@ -421,15 +480,15 @@
 		class = "ETC"
 	}
 
-	return []android.AndroidMkEntries{android.AndroidMkEntries{
+	return []android.AndroidMkEntries{{
 		Class:      class,
 		SubName:    nameSuffix,
-		OutputFile: android.OptionalPathForPath(p.outputFilePath),
+		OutputFile: android.OptionalPathForPath(p.outputFilePaths[0]),
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetString("LOCAL_MODULE_TAGS", "optional")
 				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
-				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePaths[0].Base())
 				if len(p.properties.Symlinks) > 0 {
 					entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
 				}
@@ -700,7 +759,11 @@
 		targetArch := "arch-" + m.Target().Arch.ArchType.String()
 
 		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "etc", m.BaseModuleName())
-		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, m.OutputFile(), snapshotLibOut, s.Fake))
+		outputs, _ := m.OutputFiles("")
+		for _, output := range outputs {
+			cp := copyFile(ctx, output, snapshotLibOut, s.Fake)
+			snapshotOutputs = append(snapshotOutputs, cp)
+		}
 
 		prop := snapshot.SnapshotJsonFlags{}
 		propOut := snapshotLibOut + ".json"
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index df11709..1d9aa8e 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -96,7 +96,7 @@
 	`)
 
 	p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
-	android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePath.Base())
+	android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePaths[0].Base())
 }
 
 func TestPrebuiltEtcGlob(t *testing.T) {
@@ -113,10 +113,24 @@
 	`)
 
 	p := result.Module("my_foo", "android_arm64_armv8-a").(*PrebuiltEtc)
-	android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePath.Base())
+	android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePaths[0].Base())
 
 	p = result.Module("my_bar", "android_arm64_armv8-a").(*PrebuiltEtc)
-	android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePath.Base())
+	android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePaths[0].Base())
+}
+
+func TestPrebuiltEtcMultipleSrcs(t *testing.T) {
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+		prebuilt_etc {
+			name: "foo",
+			srcs: ["*.conf"],
+		}
+	`)
+
+	p := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
+	android.AssertStringEquals(t, "output file path", "bar.conf", p.outputFilePaths[0].Base())
+	android.AssertStringEquals(t, "output file path", "baz.conf", p.outputFilePaths[1].Base())
+	android.AssertStringEquals(t, "output file path", "foo.conf", p.outputFilePaths[2].Base())
 }
 
 func TestPrebuiltEtcAndroidMk(t *testing.T) {
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 795a0aa..efc889c 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -19,6 +19,7 @@
 	"fmt"
 	"io"
 	"path/filepath"
+	"slices"
 	"strings"
 
 	"android/soong/android"
@@ -87,6 +88,10 @@
 	// is ext4.
 	Type *string
 
+	// Identifies which partition this is for //visibility:any_system_image (and others) visibility
+	// checks, and will be used in the future for API surface checks.
+	Partition_type *string
+
 	// file_contexts file to make image. Currently, only ext4 is supported.
 	File_contexts *string `android:"path"`
 
@@ -109,6 +114,12 @@
 
 	// Mount point for this image. Default is "/"
 	Mount_point *string
+
+	// If set to the name of a partition ("system", "vendor", etc), this filesystem module
+	// will also include the contents of the make-built staging directories. If any soong
+	// modules would be installed to the same location as a make module, they will overwrite
+	// the make version.
+	Include_make_built_files string
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -168,6 +179,9 @@
 var pctx = android.NewPackageContext("android/soong/filesystem")
 
 func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if !android.InList(f.PartitionType(), validPartitions) {
+		ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, f.PartitionType())
+	}
 	switch f.fsType(ctx) {
 	case ext4Type:
 		f.output = f.buildImageUsingBuildImage(ctx)
@@ -183,13 +197,9 @@
 	ctx.InstallFile(f.installDir, f.installFileName(), f.output)
 }
 
-// root zip will contain extra files/dirs that are not from the `deps` property.
-func (f *filesystem) buildRootZip(ctx android.ModuleContext) android.OutputPath {
-	rootDir := android.PathForModuleGen(ctx, "root").OutputPath
-	builder := android.NewRuleBuilder(pctx, ctx)
-	builder.Command().Text("rm -rf").Text(rootDir.String())
-	builder.Command().Text("mkdir -p").Text(rootDir.String())
-
+// Copy extra files/dirs that are not from the `deps` property to `rootDir`, checking for conflicts with files
+// already in `rootDir`.
+func (f *filesystem) buildNonDepsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.OutputPath) {
 	// create dirs and symlinks
 	for _, dir := range f.properties.Dirs {
 		// OutputPath.Join verifies dir
@@ -212,65 +222,43 @@
 
 		// OutputPath.Join verifies name. don't need to verify target.
 		dst := rootDir.Join(ctx, name)
-
+		builder.Command().Textf("(! [ -e %s -o -L %s ] || (echo \"%s already exists from an earlier stage of the build\" && exit 1))", dst, dst, dst)
 		builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String()))
 		builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
 	}
 
 	// create extra files if there's any
-	rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
-	var extraFiles android.OutputPaths
 	if f.buildExtraFiles != nil {
-		extraFiles = f.buildExtraFiles(ctx, rootForExtraFiles)
+		rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
+		extraFiles := f.buildExtraFiles(ctx, rootForExtraFiles)
 		for _, f := range extraFiles {
-			rel, _ := filepath.Rel(rootForExtraFiles.String(), f.String())
-			if strings.HasPrefix(rel, "..") {
-				panic(fmt.Errorf("%q is not under %q\n", f, rootForExtraFiles))
+			rel, err := filepath.Rel(rootForExtraFiles.String(), f.String())
+			if err != nil || strings.HasPrefix(rel, "..") {
+				ctx.ModuleErrorf("can't make %q relative to %q", f, rootForExtraFiles)
 			}
 		}
-	}
-
-	// Zip them all
-	zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
-	zipCommand := builder.Command().BuiltTool("soong_zip")
-	zipCommand.FlagWithOutput("-o ", zipOut).
-		FlagWithArg("-C ", rootDir.String()).
-		Flag("-L 0"). // no compression because this will be unzipped soon
-		FlagWithArg("-D ", rootDir.String()).
-		Flag("-d") // include empty directories
-	if len(extraFiles) > 0 {
-		zipCommand.FlagWithArg("-C ", rootForExtraFiles.String())
-		for _, f := range extraFiles {
-			zipCommand.FlagWithInput("-f ", f)
+		if len(extraFiles) > 0 {
+			builder.Command().BuiltTool("merge_directories").
+				Implicits(extraFiles.Paths()).
+				Text(rootDir.String()).
+				Text(rootForExtraFiles.String())
 		}
 	}
-
-	builder.Command().Text("rm -rf").Text(rootDir.String())
-
-	builder.Build("zip_root", fmt.Sprintf("zipping root contents for %s", ctx.ModuleName()))
-	return zipOut
 }
 
 func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
-	depsZipFile := android.PathForModuleOut(ctx, "deps.zip").OutputPath
-	f.entries = f.CopyDepsToZip(ctx, f.gatherFilteredPackagingSpecs(ctx), depsZipFile)
-
-	builder := android.NewRuleBuilder(pctx, ctx)
-	depsBase := proptools.StringDefault(f.properties.Base_dir, ".")
-	rebasedDepsZip := android.PathForModuleOut(ctx, "rebased_deps.zip").OutputPath
-	builder.Command().
-		BuiltTool("zip2zip").
-		FlagWithInput("-i ", depsZipFile).
-		FlagWithOutput("-o ", rebasedDepsZip).
-		Text("**/*:" + proptools.ShellEscape(depsBase)) // zip2zip verifies depsBase
-
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
-	rootZip := f.buildRootZip(ctx)
-	builder.Command().
-		BuiltTool("zipsync").
-		FlagWithArg("-d ", rootDir.String()). // zipsync wipes this. No need to clear.
-		Input(rootZip).
-		Input(rebasedDepsZip)
+	rebasedDir := rootDir
+	if f.properties.Base_dir != nil {
+		rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
+	}
+	builder := android.NewRuleBuilder(pctx, ctx)
+	// Wipe the root dir to get rid of leftover files from prior builds
+	builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
+	f.entries = f.CopySpecsToDir(ctx, builder, f.gatherFilteredPackagingSpecs(ctx), rebasedDir)
+
+	f.buildNonDepsFiles(ctx, builder, rootDir)
+	f.addMakeBuiltFiles(ctx, builder, rootDir)
 
 	// run host_init_verifier
 	// Ideally we should have a concept of pluggable linters that verify the generated image.
@@ -388,25 +376,21 @@
 		ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.")
 	}
 
-	depsZipFile := android.PathForModuleOut(ctx, "deps.zip").OutputPath
-	f.entries = f.CopyDepsToZip(ctx, f.gatherFilteredPackagingSpecs(ctx), depsZipFile)
-
-	builder := android.NewRuleBuilder(pctx, ctx)
-	depsBase := proptools.StringDefault(f.properties.Base_dir, ".")
-	rebasedDepsZip := android.PathForModuleOut(ctx, "rebased_deps.zip").OutputPath
-	builder.Command().
-		BuiltTool("zip2zip").
-		FlagWithInput("-i ", depsZipFile).
-		FlagWithOutput("-o ", rebasedDepsZip).
-		Text("**/*:" + proptools.ShellEscape(depsBase)) // zip2zip verifies depsBase
+	if f.properties.Include_make_built_files != "" {
+		ctx.PropertyErrorf("include_make_built_files", "include_make_built_files is not supported for compressed cpio image.")
+	}
 
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
-	rootZip := f.buildRootZip(ctx)
-	builder.Command().
-		BuiltTool("zipsync").
-		FlagWithArg("-d ", rootDir.String()). // zipsync wipes this. No need to clear.
-		Input(rootZip).
-		Input(rebasedDepsZip)
+	rebasedDir := rootDir
+	if f.properties.Base_dir != nil {
+		rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
+	}
+	builder := android.NewRuleBuilder(pctx, ctx)
+	// Wipe the root dir to get rid of leftover files from prior builds
+	builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
+	f.entries = f.CopySpecsToDir(ctx, builder, f.gatherFilteredPackagingSpecs(ctx), rebasedDir)
+
+	f.buildNonDepsFiles(ctx, builder, rootDir)
 
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 	cmd := builder.Command().
@@ -429,6 +413,45 @@
 	return output
 }
 
+var validPartitions = []string{
+	"system",
+	"userdata",
+	"cache",
+	"system_other",
+	"vendor",
+	"product",
+	"system_ext",
+	"odm",
+	"vendor_dlkm",
+	"odm_dlkm",
+	"system_dlkm",
+}
+
+func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) {
+	partition := f.properties.Include_make_built_files
+	if partition == "" {
+		return
+	}
+	if !slices.Contains(validPartitions, partition) {
+		ctx.PropertyErrorf("include_make_built_files", "Expected one of %#v, found %q", validPartitions, partition)
+		return
+	}
+	stampFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/staging_dir.stamp", ctx.Config().DeviceName(), partition)
+	fileListFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partition)
+	stagingDir := fmt.Sprintf("target/product/%s/%s", ctx.Config().DeviceName(), partition)
+
+	builder.Command().BuiltTool("merge_directories").
+		Implicit(android.PathForArbitraryOutput(ctx, stampFile)).
+		Text("--ignore-duplicates").
+		FlagWithInput("--file-list", android.PathForArbitraryOutput(ctx, fileListFile)).
+		Text(rootDir.String()).
+		Text(android.PathForArbitraryOutput(ctx, stagingDir).String())
+}
+
+func (f *filesystem) PartitionType() string {
+	return proptools.StringDefault(f.properties.Partition_type, "system")
+}
+
 var _ android.AndroidMkEntriesProvider = (*filesystem)(nil)
 
 // Implements android.AndroidMkEntriesProvider
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index c448105..74c79e3 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"os"
+	"path/filepath"
 	"testing"
 
 	"android/soong/android"
@@ -75,6 +76,11 @@
 
 		cc_library {
 			name: "libbar",
+			required: ["libbaz"],
+		}
+
+		cc_library {
+			name: "libbaz",
 		}
 	`)
 
@@ -86,6 +92,7 @@
 		"bin/foo",
 		"lib/libbar.so",
 		"lib64/libbar.so",
+		"lib64/libbaz.so",
 		"etc/bpf/bpf.o",
 	}
 	for _, e := range expected {
@@ -93,6 +100,22 @@
 	}
 }
 
+func TestIncludeMakeBuiltFiles(t *testing.T) {
+	result := fixture.RunTestWithBp(t, `
+		android_filesystem {
+			name: "myfilesystem",
+			include_make_built_files: "system",
+		}
+	`)
+
+	output := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
+
+	stampFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp")
+	fileListFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt")
+	android.AssertStringListContains(t, "deps of filesystem must include the staging dir stamp file", output.Implicits.Strings(), stampFile)
+	android.AssertStringListContains(t, "deps of filesystem must include the staging dir file list", output.Implicits.Strings(), fileListFile)
+}
+
 func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
 	result := fixture.RunTestWithBp(t, `
 		android_system_image {
@@ -270,7 +293,7 @@
 		}
 	`)
 
-	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("deps.zip").Implicits
+	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img").Implicits
 	android.AssertStringListContains(t, "filesystem should have libbar even for unbundled build",
 		inputs.Strings(),
 		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
@@ -314,7 +337,7 @@
 	`)
 
 	filesystem := result.ModuleForTests("myfilesystem", "android_common_cov")
-	inputs := filesystem.Output("deps.zip").Implicits
+	inputs := filesystem.Output("myfilesystem.img").Implicits
 	android.AssertStringListContains(t, "filesystem should have libfoo(cov)",
 		inputs.Strings(),
 		"out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so")
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 34f4ffb..5028a49 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -43,6 +43,9 @@
 }
 
 func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
+	if s.filesystem.properties.Partition_type != nil {
+		ctx.PropertyErrorf("partition_type", "partition_type must be unset on an android_system_image module. It is assumed to be 'system'.")
+	}
 	lc := s.buildLinkerConfigFile(ctx, root)
 	// Add more files if needed
 	return []android.OutputPath{lc}
@@ -53,19 +56,40 @@
 	output := root.Join(ctx, "system", "etc", "linker.config.pb")
 
 	// we need "Module"s for packaging items
-	var otherModules []android.Module
+	modulesInPackageByModule := make(map[android.Module]bool)
+	modulesInPackageByName := make(map[string]bool)
+
 	deps := s.gatherFilteredPackagingSpecs(ctx)
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		for _, ps := range child.PackagingSpecs() {
 			if _, ok := deps[ps.RelPathInPackage()]; ok {
-				otherModules = append(otherModules, child)
+				modulesInPackageByModule[child] = true
+				modulesInPackageByName[child.Name()] = true
+				return true
 			}
 		}
 		return true
 	})
 
+	provideModules := make([]android.Module, 0, len(modulesInPackageByModule))
+	for mod := range modulesInPackageByModule {
+		provideModules = append(provideModules, mod)
+	}
+
+	var requireModules []android.Module
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		_, parentInPackage := modulesInPackageByModule[parent]
+		_, childInPackageName := modulesInPackageByName[child.Name()]
+
+		// When parent is in the package, and child (or its variant) is not, this can be from an interface.
+		if parentInPackage && !childInPackageName {
+			requireModules = append(requireModules, child)
+		}
+		return true
+	})
+
 	builder := android.NewRuleBuilder(pctx, ctx)
-	linkerconfig.BuildLinkerConfig(ctx, builder, input, otherModules, output)
+	linkerconfig.BuildLinkerConfig(ctx, builder, input, provideModules, requireModules, output)
 	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
 	return output
 }
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 60b1366..7c71b77 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -21,9 +21,4 @@
 		"com.google.pixel.camera.hal.manifest",
 		// go/keep-sorted end
 	}
-
-	SandboxingDenyPathList = []string{
-		// go/keep-sorted start
-		// go/keep-sorted end
-	}
 )
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6f66088..43f4fe5 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -317,7 +317,17 @@
 						// required relative locations of the tool and its dependencies, use those
 						// instead.  They will be copied to those relative locations in the sbox
 						// sandbox.
-						packagedTools = append(packagedTools, specs...)
+						// Care must be taken since TransitivePackagingSpec may return device-side
+						// paths via the required property. Filter them out.
+						for i, ps := range specs {
+							if ps.Partition() != "" {
+								if i == 0 {
+									panic("first PackagingSpec is assumed to be the host-side tool")
+								}
+								continue
+							}
+							packagedTools = append(packagedTools, ps)
+						}
 						// Assume that the first PackagingSpec of the module is the tool.
 						addLocationLabel(tag.label, packagedToolLocation{specs[0]})
 					} else {
@@ -808,7 +818,7 @@
 
 type genRuleProperties struct {
 	// names of the output files that will be generated
-	Out []string
+	Out []string `android:"arch_variant"`
 }
 
 var Bool = proptools.Bool
@@ -842,19 +852,15 @@
 
 type sandboxingAllowlistSets struct {
 	sandboxingDenyModuleSet map[string]bool
-	sandboxingDenyPathSet   map[string]bool
 }
 
 func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSets {
 	return ctx.Config().Once(sandboxingAllowlistKey, func() interface{} {
 		sandboxingDenyModuleSet := map[string]bool{}
-		sandboxingDenyPathSet := map[string]bool{}
 
 		android.AddToStringSet(sandboxingDenyModuleSet, SandboxingDenyModuleList)
-		android.AddToStringSet(sandboxingDenyPathSet, SandboxingDenyPathList)
 		return &sandboxingAllowlistSets{
 			sandboxingDenyModuleSet: sandboxingDenyModuleSet,
-			sandboxingDenyPathSet:   sandboxingDenyPathSet,
 		}
 	}).(*sandboxingAllowlistSets)
 }
@@ -864,8 +870,7 @@
 		return r.SandboxTools()
 	}
 	sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
-	if sandboxingAllowlistSets.sandboxingDenyPathSet[ctx.ModuleDir()] ||
-		sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
+	if sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
 		return r.SandboxTools()
 	}
 	return r.SandboxInputs()
diff --git a/java/aar.go b/java/aar.go
index 27dd38b..1734da9 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -104,6 +104,9 @@
 
 	// Filter only specified product and ignore other products
 	Filter_product *string `blueprint:"mutated"`
+
+	// Names of aconfig_declarations modules that specify aconfig flags that the module depends on.
+	Flags_packages []string
 }
 
 type aapt struct {
@@ -348,6 +351,7 @@
 	classLoaderContexts            dexpreopt.ClassLoaderContextMap
 	excludedLibs                   []string
 	enforceDefaultTargetSdkVersion bool
+	forceNonFinalResourceIDs       bool
 	extraLinkFlags                 []string
 	aconfigTextFiles               android.Paths
 }
@@ -383,11 +387,6 @@
 	// Add additional manifest files to transitive manifests.
 	additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
 	transitiveManifestPaths := append(android.Paths{manifestPath}, additionalManifests...)
-	// TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import
-	// modules.  Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies
-	// of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of
-	// android_library_import modules.  If this is fixed, staticManifestsDepSet can be dropped completely in favor of
-	// staticResourcesNodesDepSet.manifests()
 	transitiveManifestPaths = append(transitiveManifestPaths, staticManifestsDepSet.ToList()...)
 
 	if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
@@ -541,7 +540,8 @@
 
 	if a.useResourceProcessorBusyBox(ctx) {
 		rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
-		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary, a.aaptProperties.Aaptflags)
+		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary, a.aaptProperties.Aaptflags,
+			opts.forceNonFinalResourceIDs)
 		aapt2ExtractExtraPackages(ctx, extraPackages, rJar)
 		transitiveRJars = append(transitiveRJars, rJar)
 		a.rJar = rJar
@@ -605,7 +605,8 @@
 // using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and
 // supports producing classes for static dependencies that only include resources from that dependency.
 func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path,
-	rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool, aaptFlags []string) {
+	rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool, aaptFlags []string,
+	forceNonFinalIds bool) {
 
 	var args []string
 	var deps android.Paths
@@ -615,6 +616,9 @@
 		// to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
 		// package.
 		args, deps = transitiveDeps.resourceProcessorDeps()
+		if forceNonFinalIds {
+			args = append(args, "--finalFields=false")
+		}
 	} else {
 		// When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this
 		// library.  Pass --finalFields=false so that the R.class file contains non-final fields so they don't get
@@ -754,7 +758,8 @@
 	// reverse later.
 	// NOTE: this is legacy and probably incorrect behavior, for most other cases (e.g. conflicting classes in
 	// dependencies) the highest priority dependency is listed first, but for resources the highest priority
-	// dependency has to be listed last.
+	// dependency has to be listed last.  This is also inconsistent with the way manifests from the same
+	// transitive dependencies are merged.
 	staticResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
 		android.ReverseSliceInPlace(staticResourcesNodeDepSets))
 	sharedResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
@@ -804,6 +809,10 @@
 		a.aapt.deps(ctx, sdkDep)
 	}
 	a.usesLibrary.deps(ctx, false)
+
+	for _, aconfig_declaration := range a.aaptProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -817,13 +826,14 @@
 			sdkContext:                     android.SdkContext(a),
 			classLoaderContexts:            a.classLoaderContexts,
 			enforceDefaultTargetSdkVersion: false,
+			aconfigTextFiles:               getAconfigFilePaths(ctx),
 		},
 	)
 
 	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	a.hideApexVariantFromMake = !apexInfo.IsForPlatform()
 
-	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+	a.stem = proptools.StringDefault(a.overridableProperties.Stem, ctx.ModuleName())
 
 	ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
 	ctx.CheckbuildFile(a.aapt.exportPackage)
@@ -964,7 +974,8 @@
 
 	properties AARImportProperties
 
-	classpathFile                      android.WritablePath
+	headerJarFile                      android.WritablePath
+	implementationJarFile              android.WritablePath
 	proguardFlags                      android.WritablePath
 	exportPackage                      android.WritablePath
 	transitiveAaptResourcePackagesFile android.Path
@@ -985,6 +996,9 @@
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.ApiLevel
 
+	usesLibrary
+	classLoaderContexts dexpreopt.ClassLoaderContextMap
+
 	// Single aconfig "cache file" merged from this module and all dependencies.
 	mergedAconfigFiles map[string]android.Paths
 }
@@ -997,7 +1011,7 @@
 	case ".aar":
 		return []android.Path{a.aarPath}, nil
 	case "":
-		return []android.Path{a.classpathFile}, nil
+		return []android.Path{a.implementationJarFile}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -1080,6 +1094,8 @@
 
 	ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
+
+	a.usesLibrary.deps(ctx, false)
 }
 
 type JniPackageInfo struct {
@@ -1138,7 +1154,7 @@
 	}
 
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
-	a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
+	classpathFile := extractedAARDir.Join(ctx, "classes-combined.jar")
 	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
 	a.rTxt = extractedAARDir.Join(ctx, "R.txt")
 	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
@@ -1154,11 +1170,11 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        unzipAAR,
 		Input:       a.aarPath,
-		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, a.rTxt},
+		Outputs:     android.WritablePaths{classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, a.rTxt},
 		Description: "unzip AAR",
 		Args: map[string]string{
 			"outDir":             extractedAARDir.String(),
-			"combinedClassesJar": a.classpathFile.String(),
+			"combinedClassesJar": classpathFile.String(),
 			"assetsPackage":      a.assetsPackage.String(),
 		},
 	})
@@ -1213,7 +1229,7 @@
 		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
 
 	a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
-	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true, nil)
+	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true, nil, false)
 
 	aapt2ExtractExtraPackages(ctx, a.extraAaptPackagesFile, a.rJar)
 
@@ -1231,13 +1247,7 @@
 	a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
 
 	manifestDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(a.manifest)
-	// TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import
-	// modules.  Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies
-	// of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of
-	// android_library_import modules.  If this is fixed, AndroidLibraryDependency.ManifestsDepSet can be dropped
-	// completely in favor of AndroidLibraryDependency.ResourceNodesDepSet.manifest
-	//manifestDepSetBuilder.Transitive(transitiveStaticDeps.manifests)
-	_ = staticManifestsDepSet
+	manifestDepSetBuilder.Transitive(staticManifestsDepSet)
 	a.manifestsDepSet = manifestDepSetBuilder.Build()
 
 	transitiveAaptResourcePackages := staticDeps.resPackages().Strings()
@@ -1249,12 +1259,45 @@
 	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 
 	a.collectTransitiveHeaderJars(ctx)
+
+	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+
+	var staticJars android.Paths
+	var staticHeaderJars android.Paths
+	ctx.VisitDirectDeps(func(module android.Module) {
+		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+			tag := ctx.OtherModuleDependencyTag(module)
+			switch tag {
+			case staticLibTag:
+				staticJars = append(staticJars, dep.ImplementationJars...)
+				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
+			}
+		}
+		addCLCFromDep(ctx, module, a.classLoaderContexts)
+	})
+
+	if len(staticJars) > 0 {
+		combineJars := append(android.Paths{classpathFile}, staticJars...)
+		a.implementationJarFile = android.PathForModuleOut(ctx, "combined", ctx.ModuleName()+".jar")
+		TransformJarsToJar(ctx, a.implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+	} else {
+		a.implementationJarFile = classpathFile
+	}
+
+	if len(staticHeaderJars) > 0 {
+		combineJars := append(android.Paths{classpathFile}, staticHeaderJars...)
+		a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", ctx.ModuleName()+".jar")
+		TransformJarsToJar(ctx, a.headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil)
+	} else {
+		a.headerJarFile = classpathFile
+	}
+
 	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
+		HeaderJars:                     android.PathsIfNonNil(a.headerJarFile),
 		TransitiveLibsHeaderJars:       a.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
-		ImplementationJars:             android.PathsIfNonNil(a.classpathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationJarFile),
+		ImplementationJars:             android.PathsIfNonNil(a.implementationJarFile),
 		StubsLinkType:                  Implementation,
 		// TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
@@ -1287,15 +1330,15 @@
 }
 
 func (a *AARImport) HeaderJars() android.Paths {
-	return android.Paths{a.classpathFile}
+	return android.Paths{a.headerJarFile}
 }
 
 func (a *AARImport) ImplementationAndResourcesJars() android.Paths {
-	return android.Paths{a.classpathFile}
+	return android.Paths{a.implementationJarFile}
 }
 
-func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path {
-	return nil
+func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
+	return OptionalDexJarPath{}
 }
 
 func (a *AARImport) DexJarInstallPath() android.Path {
@@ -1303,9 +1346,11 @@
 }
 
 func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
-	return nil
+	return a.classLoaderContexts
 }
 
+var _ UsesLibraryDependency = (*AARImport)(nil)
+
 var _ android.ApexModule = (*AARImport)(nil)
 
 // Implements android.ApexModule
@@ -1314,7 +1359,7 @@
 }
 
 // Implements android.ApexModule
-func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
+func (a *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	return nil
 }
@@ -1328,7 +1373,10 @@
 func AARImportFactory() android.Module {
 	module := &AARImport{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(
+		&module.properties,
+		&module.usesLibrary.usesLibraryProperties,
+	)
 
 	android.InitPrebuiltModule(module, &module.properties.Aars)
 	android.InitApexModule(module)
diff --git a/java/aar_test.go b/java/aar_test.go
index 4d4e5d0..6bd53f2 100644
--- a/java/aar_test.go
+++ b/java/aar_test.go
@@ -81,3 +81,50 @@
 		})
 	}
 }
+
+func TestLibraryFlagsPackages(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+		android_library {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			flags_packages: [
+				"bar",
+				"baz",
+			],
+		}
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package.bar",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		aconfig_declarations {
+			name: "baz",
+			package: "com.example.package.baz",
+			srcs: [
+				"baz.aconfig",
+			],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+
+	// android_library module depends on aconfig_declarations listed in flags_packages
+	android.AssertBoolEquals(t, "foo expected to depend on bar", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"))
+
+	android.AssertBoolEquals(t, "foo expected to depend on baz", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "baz"))
+
+	aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
+	linkInFlags := aapt2LinkRule.Args["inFlags"]
+	android.AssertStringDoesContain(t,
+		"aapt2 link command expected to pass feature flags arguments",
+		linkInFlags,
+		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+	)
+}
diff --git a/java/android_manifest_test.go b/java/android_manifest_test.go
index 5909b1e..7c91884 100644
--- a/java/android_manifest_test.go
+++ b/java/android_manifest_test.go
@@ -92,10 +92,9 @@
 			"out/soong/.intermediates/transitive/android_common/manifest_fixer/AndroidManifest.xml",
 			"transitive/AndroidManifest2.xml",
 			"out/soong/.intermediates/transitive_import/android_common/aar/AndroidManifest.xml",
+			"out/soong/.intermediates/transitive_import_dep/android_common/aar/AndroidManifest.xml",
 			"out/soong/.intermediates/direct_import/android_common/aar/AndroidManifest.xml",
-			// TODO(b/288358614): Soong has historically not merged manifests from dependencies of
-			// android_library_import modules.
-
+			"out/soong/.intermediates/direct_import_dep/android_common/aar/AndroidManifest.xml",
 		},
 		manifestMergerRule.Implicits)
 }
diff --git a/java/androidmk.go b/java/androidmk.go
index 498962f..a52d439 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -211,7 +211,7 @@
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:        "JAVA_LIBRARIES",
 		OverrideName: prebuilt.BaseModuleName(),
-		OutputFile:   android.OptionalPathForPath(prebuilt.combinedClasspathFile),
+		OutputFile:   android.OptionalPathForPath(prebuilt.combinedImplementationFile),
 		Include:      "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
@@ -219,8 +219,8 @@
 				if prebuilt.dexJarFile.IsSet() {
 					entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path())
 				}
-				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
-				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
+				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedHeaderFile)
+				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedImplementationFile)
 				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
 				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
@@ -262,13 +262,13 @@
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(prebuilt.classpathFile),
+		OutputFile: android.OptionalPathForPath(prebuilt.implementationJarFile),
 		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
-				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
+				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.headerJarFile)
+				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.implementationJarFile)
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
 				entries.SetPath("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackagesFile)
 				entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
diff --git a/java/app.go b/java/app.go
index 4f6f1f3..2abc451 100755
--- a/java/app.go
+++ b/java/app.go
@@ -169,9 +169,6 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
-
-	// Names of aconfig_declarations modules that specify aconfig flags that the app depends on.
-	Flags_packages []string
 }
 
 type AndroidApp struct {
@@ -290,6 +287,10 @@
 	}
 
 	a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
+
+	for _, aconfig_declaration := range a.aaptProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -317,10 +318,6 @@
 				`must be names of android_app_certificate modules in the form ":module"`)
 		}
 	}
-
-	for _, aconfig_declaration := range a.overridableAppProperties.Flags_packages {
-		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
-	}
 }
 
 func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -457,6 +454,21 @@
 	return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true)
 }
 
+func getAconfigFilePaths(ctx android.ModuleContext) (aconfigTextFilePaths android.Paths) {
+	ctx.VisitDirectDepsWithTag(aconfigDeclarationTag, func(dep android.Module) {
+		if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
+			aconfigTextFilePaths = append(aconfigTextFilePaths, provider.IntermediateDumpOutputPath)
+		} else {
+			ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+
+				"flags_packages property, but %s is not aconfig_declarations module type",
+				dep.Name(),
+			)
+		}
+	})
+
+	return aconfigTextFilePaths
+}
+
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
 	usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis)
 	if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule {
@@ -507,26 +519,17 @@
 		a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
 	}
 
-	var aconfigTextFilePaths android.Paths
-	ctx.VisitDirectDepsWithTag(aconfigDeclarationTag, func(dep android.Module) {
-		if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
-			aconfigTextFilePaths = append(aconfigTextFilePaths, provider.IntermediateDumpOutputPath)
-		} else {
-			ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+
-				"flags_packages property, but %s is not aconfig_declarations module type",
-				dep.Name(),
-			)
-		}
-	})
-
+	// Use non final ids if we are doing optimized shrinking and are using R8.
+	nonFinalIds := Bool(a.dexProperties.Optimize.Optimized_shrink_resources) && a.dexer.effectiveOptimizeEnabled()
 	a.aapt.buildActions(ctx,
 		aaptBuildActionOptions{
 			sdkContext:                     android.SdkContext(a),
 			classLoaderContexts:            a.classLoaderContexts,
 			excludedLibs:                   a.usesLibraryProperties.Exclude_uses_libs,
 			enforceDefaultTargetSdkVersion: a.enforceDefaultTargetSdkVersion(),
+			forceNonFinalResourceIDs:       nonFinalIds,
 			extraLinkFlags:                 aaptLinkFlags,
-			aconfigTextFiles:               aconfigTextFilePaths,
+			aconfigTextFiles:               getAconfigFilePaths(ctx),
 		},
 	)
 
@@ -547,7 +550,13 @@
 	staticLibProguardFlagFiles = android.FirstUniquePaths(staticLibProguardFlagFiles)
 
 	a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, staticLibProguardFlagFiles...)
-	a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, a.proguardOptionsFile)
+	if !Bool(a.dexProperties.Optimize.Optimized_shrink_resources) {
+		// When using the optimized shrinking the R8 enqueuer will traverse the xml files that become
+		// live for code references and (transitively) mark these as live.
+		// In this case we explicitly don't wan't the aapt2 generated keep files (which would keep the now
+		// dead code alive)
+		a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, a.proguardOptionsFile)
+	}
 }
 
 func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath {
@@ -580,7 +589,7 @@
 	var packageResources = a.exportPackage
 
 	if ctx.ModuleName() != "framework-res" {
-		if Bool(a.dexProperties.Optimize.Shrink_resources) {
+		if a.dexProperties.resourceShrinkingEnabled() {
 			protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk")
 			aapt2Convert(ctx, protoFile, packageResources, "proto")
 			a.dexer.resourcesInput = android.OptionalPathForPath(protoFile)
@@ -603,7 +612,7 @@
 		}
 
 		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
-		if Bool(a.dexProperties.Optimize.Shrink_resources) {
+		if a.dexProperties.resourceShrinkingEnabled() {
 			binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
 			aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
 			packageResources = binaryResources
@@ -755,7 +764,7 @@
 
 	// Unlike installApkName, a.stem should respect base module name for override_android_app.
 	// Therefore, use ctx.ModuleName() instead of a.Name().
-	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+	a.stem = proptools.StringDefault(a.overridableProperties.Stem, ctx.ModuleName())
 
 	// Check if the install APK name needs to be overridden.
 	// Both android_app and override_android_app module are expected to possess
@@ -763,7 +772,7 @@
 	// from the base module. Therefore, use a.Name() which represents
 	// the module name for both android_app and override_android_app.
 	a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(
-		proptools.StringDefault(a.overridableDeviceProperties.Stem, a.Name()))
+		proptools.StringDefault(a.overridableProperties.Stem, a.Name()))
 
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
@@ -1507,7 +1516,7 @@
 func OverrideAndroidAppModuleFactory() android.Module {
 	m := &OverrideAndroidApp{}
 	m.AddProperties(
-		&OverridableDeviceProperties{},
+		&OverridableProperties{},
 		&overridableAppProperties{},
 	)
 
diff --git a/java/app_test.go b/java/app_test.go
index 5d7b048..ca9d317 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -829,12 +829,12 @@
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -849,12 +849,12 @@
 			directClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
@@ -928,13 +928,13 @@
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -953,12 +953,12 @@
 				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
 				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
@@ -1034,13 +1034,13 @@
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			dontVerifyDirect:           true,
@@ -1075,12 +1075,12 @@
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -1098,12 +1098,12 @@
 				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
 				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			dontVerifyTransitive:       true,
@@ -1137,12 +1137,12 @@
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -1157,12 +1157,12 @@
 			directClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
@@ -4401,3 +4401,20 @@
 	dexpreopt := result.ModuleForTests("app", "android_common").MaybeRule("dexpreopt").Rule
 	android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil)
 }
+
+func TestAppStem(t *testing.T) {
+	ctx := testApp(t, `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					stem: "foo-new",
+					sdk_version: "current",
+				}`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	outputs := fmt.Sprint(foo.AllOutputs())
+	if !strings.Contains(outputs, "foo-new.apk") {
+		t.Errorf("Module output does not contain expected apk %s", "foo-new.apk")
+	}
+}
diff --git a/java/base.go b/java/base.go
index 69f88be..be286fe 100644
--- a/java/base.go
+++ b/java/base.go
@@ -305,8 +305,8 @@
 	HiddenAPIFlagFileProperties
 }
 
-// Device properties that can be overridden by overriding module (e.g. override_android_app)
-type OverridableDeviceProperties struct {
+// Properties that can be overridden by overriding module (e.g. override_android_app)
+type OverridableProperties struct {
 	// set the name of the output. If not set, `name` is used.
 	// To override a module with this property set, overriding module might need to set this as well.
 	// Otherwise, both the overridden and the overriding modules will have the same output name, which
@@ -434,7 +434,7 @@
 	protoProperties  android.ProtoProperties
 	deviceProperties DeviceProperties
 
-	overridableDeviceProperties OverridableDeviceProperties
+	overridableProperties OverridableProperties
 
 	// jar file containing header classes including static library dependencies, suitable for
 	// inserting into the bootclasspath/classpath of another compile
@@ -616,6 +616,7 @@
 func (j *Module) addHostProperties() {
 	j.AddProperties(
 		&j.properties,
+		&j.overridableProperties,
 		&j.protoProperties,
 		&j.usesLibraryProperties,
 	)
@@ -625,7 +626,6 @@
 	j.addHostProperties()
 	j.AddProperties(
 		&j.deviceProperties,
-		&j.overridableDeviceProperties,
 		&j.dexer.dexProperties,
 		&j.dexpreoptProperties,
 		&j.linter.properties,
@@ -1219,14 +1219,15 @@
 		}
 
 		android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
-			HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
-			TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
-			TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-			AidlIncludeDirs:                j.exportAidlIncludeDirs,
-			ExportedPlugins:                j.exportedPluginJars,
-			ExportedPluginClasses:          j.exportedPluginClasses,
-			ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
-			StubsLinkType:                  j.stubsLinkType,
+			HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
+			TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
+			TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+			AidlIncludeDirs:                     j.exportAidlIncludeDirs,
+			ExportedPlugins:                     j.exportedPluginJars,
+			ExportedPluginClasses:               j.exportedPluginClasses,
+			ExportedPluginDisableTurbine:        j.exportedDisableTurbine,
+			StubsLinkType:                       j.stubsLinkType,
+			AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles,
 		})
 
 		j.outputFile = j.headerJarFile
@@ -1729,22 +1730,23 @@
 	android.CollectDependencyAconfigFiles(ctx, &j.mergedAconfigFiles)
 
 	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
-		RepackagedHeaderJars:           android.PathsIfNonNil(j.repackagedHeaderJarFile),
-		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
-		ImplementationJars:             android.PathsIfNonNil(j.implementationJarFile),
-		ResourceJars:                   android.PathsIfNonNil(j.resourceJar),
-		AidlIncludeDirs:                j.exportAidlIncludeDirs,
-		SrcJarArgs:                     j.srcJarArgs,
-		SrcJarDeps:                     j.srcJarDeps,
-		TransitiveSrcFiles:             j.transitiveSrcFiles,
-		ExportedPlugins:                j.exportedPluginJars,
-		ExportedPluginClasses:          j.exportedPluginClasses,
-		ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
-		JacocoReportClassesFile:        j.jacocoReportClassesFile,
-		StubsLinkType:                  j.stubsLinkType,
+		HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
+		RepackagedHeaderJars:                android.PathsIfNonNil(j.repackagedHeaderJarFile),
+		TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
+		TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+		ImplementationAndResourcesJars:      android.PathsIfNonNil(j.implementationAndResourcesJar),
+		ImplementationJars:                  android.PathsIfNonNil(j.implementationJarFile),
+		ResourceJars:                        android.PathsIfNonNil(j.resourceJar),
+		AidlIncludeDirs:                     j.exportAidlIncludeDirs,
+		SrcJarArgs:                          j.srcJarArgs,
+		SrcJarDeps:                          j.srcJarDeps,
+		TransitiveSrcFiles:                  j.transitiveSrcFiles,
+		ExportedPlugins:                     j.exportedPluginJars,
+		ExportedPluginClasses:               j.exportedPluginClasses,
+		ExportedPluginDisableTurbine:        j.exportedDisableTurbine,
+		JacocoReportClassesFile:             j.jacocoReportClassesFile,
+		StubsLinkType:                       j.stubsLinkType,
+		AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles,
 	})
 
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
@@ -2295,6 +2297,7 @@
 				// annotation processor that generates API is incompatible with the turbine
 				// optimization.
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
+				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
 			case pluginTag:
 				if plugin, ok := module.(*Plugin); ok {
 					if plugin.pluginProperties.Processor_class != nil {
@@ -2353,6 +2356,8 @@
 				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
 			}
+		} else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
+			deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
 		} else {
 			switch tag {
 			case bootClasspathTag:
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 7c45d30..cc3da76 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -77,7 +77,7 @@
 		return javaSdkLibrarySdkMemberType
 	}
 
-	return javaBootLibsSdkMemberType
+	return JavaBootLibsSdkMemberType
 }
 
 func (b bootclasspathFragmentContentDependencyTag) ExportMember() bool {
diff --git a/java/dex.go b/java/dex.go
index 4474c63..6caaa7f 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -66,6 +66,12 @@
 		// If true, optimize for size by removing unused resources. Defaults to false.
 		Shrink_resources *bool
 
+		// If true, use optimized resource shrinking in R8, overriding the
+		// Shrink_resources setting. Defaults to false.
+		// Optimized shrinking means that R8 will trace and treeshake resources together with code
+		// and apply additional optimizations. This implies non final fields in the R classes.
+		Optimized_shrink_resources *bool
+
 		// Flags to pass to proguard.
 		Proguard_flags []string
 
@@ -105,6 +111,10 @@
 	return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
 }
 
+func (d *DexProperties) resourceShrinkingEnabled() bool {
+	return BoolDefault(d.Optimize.Optimized_shrink_resources, Bool(d.Optimize.Shrink_resources))
+}
+
 var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
@@ -351,10 +361,14 @@
 		r8Flags = append(r8Flags, "-ignorewarnings")
 	}
 
+	// resourcesInput is empty when we don't use resource shrinking, if on, pass these to R8
 	if d.resourcesInput.Valid() {
 		r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String())
 		r8Deps = append(r8Deps, d.resourcesInput.Path())
 		r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String())
+		if Bool(opt.Optimized_shrink_resources) {
+			r8Flags = append(r8Flags, "--optimized-resource-shrinking")
+		}
 	}
 
 	return r8Flags, r8Deps
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 76c8d88..9556e95 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -368,7 +368,7 @@
 		ret, err = nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
 	}
 	if ret == nil && err == nil {
-		err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
+		err = fmt.Errorf("api file is null for the stub type %s", stubsType.String())
 	}
 	return ret, err
 }
@@ -478,34 +478,41 @@
 }
 
 func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath, stubsType StubsType, checkApi bool) {
-	if checkApi || String(d.properties.Api_filename) != "" {
-		filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
-		uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), filename)
-		cmd.FlagWithOutput("--api ", uncheckedApiFile)
 
+	apiFileName := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
+	uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), apiFileName)
+	cmd.FlagWithOutput("--api ", uncheckedApiFile)
+	if checkApi || String(d.properties.Api_filename) != "" {
 		if stubsType == Everything {
 			d.apiFile = uncheckedApiFile
 		} else if stubsType == Exportable {
 			d.exportableApiFile = uncheckedApiFile
 		}
 	} else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
-		// If check api is disabled then make the source file available for export.
-		d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
+		if stubsType == Everything {
+			// If check api is disabled then make the source file available for export.
+			d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
+		} else if stubsType == Exportable {
+			d.exportableApiFile = uncheckedApiFile
+		}
 	}
 
+	removedApiFileName := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
+	uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), removedApiFileName)
+	cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
 	if checkApi || String(d.properties.Removed_api_filename) != "" {
-		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
-		uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), filename)
-		cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
-
 		if stubsType == Everything {
 			d.removedApiFile = uncheckedRemovedFile
 		} else if stubsType == Exportable {
 			d.exportableRemovedApiFile = uncheckedRemovedFile
 		}
 	} else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
-		// If check api is disabled then make the source removed api file available for export.
-		d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
+		if stubsType == Everything {
+			// If check api is disabled then make the source removed api file available for export.
+			d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
+		} else if stubsType == Exportable {
+			d.exportableRemovedApiFile = uncheckedRemovedFile
+		}
 	}
 
 	if stubsDir.Valid() {
diff --git a/java/java.go b/java/java.go
index e606993..72536cd 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,6 +21,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"slices"
 	"sort"
 	"strings"
 
@@ -82,8 +83,8 @@
 	// Register sdk member types.
 	android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
 	android.RegisterSdkMemberType(javaLibsSdkMemberType)
-	android.RegisterSdkMemberType(javaBootLibsSdkMemberType)
-	android.RegisterSdkMemberType(javaSystemserverLibsSdkMemberType)
+	android.RegisterSdkMemberType(JavaBootLibsSdkMemberType)
+	android.RegisterSdkMemberType(JavaSystemserverLibsSdkMemberType)
 	android.RegisterSdkMemberType(javaTestSdkMemberType)
 }
 
@@ -154,7 +155,7 @@
 	// either java_libs, or java_header_libs would end up exporting more information than was strictly
 	// necessary. The java_boot_libs property to allow those modules to be exported as part of the
 	// sdk/module_exports without exposing any unnecessary information.
-	javaBootLibsSdkMemberType = &librarySdkMemberType{
+	JavaBootLibsSdkMemberType = &librarySdkMemberType{
 		android.SdkMemberTypeBase{
 			PropertyName: "java_boot_libs",
 			SupportsSdk:  true,
@@ -193,7 +194,7 @@
 	// either java_libs, or java_header_libs would end up exporting more information than was strictly
 	// necessary. The java_systemserver_libs property to allow those modules to be exported as part of
 	// the sdk/module_exports without exposing any unnecessary information.
-	javaSystemserverLibsSdkMemberType = &librarySdkMemberType{
+	JavaSystemserverLibsSdkMemberType = &librarySdkMemberType{
 		android.SdkMemberTypeBase{
 			PropertyName: "java_systemserver_libs",
 			SupportsSdk:  true,
@@ -309,6 +310,10 @@
 	// implementation jars. If the provider is set by java_sdk_library, the link type is "unknown"
 	// and selection between the stub jar vs implementation jar is deferred to SdkLibrary.sdkJars(...)
 	StubsLinkType StubsLinkType
+
+	// AconfigIntermediateCacheOutputPaths is a path to the cache files collected from the
+	// java_aconfig_library modules that are statically linked to this module.
+	AconfigIntermediateCacheOutputPaths android.Paths
 }
 
 var JavaInfoProvider = blueprint.NewProvider[JavaInfo]()
@@ -897,7 +902,7 @@
 		}
 	}
 
-	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+	j.stem = proptools.StringDefault(j.overridableProperties.Stem, ctx.ModuleName())
 
 	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
 	android.SetProvider(ctx, ProguardSpecInfoProvider, proguardSpecInfo)
@@ -1694,7 +1699,7 @@
 }
 
 func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+	j.stem = proptools.StringDefault(j.overridableProperties.Stem, ctx.ModuleName())
 
 	if ctx.Arch().ArchType == android.Common {
 		// Compile the jar
@@ -2333,6 +2338,9 @@
 	// List of shared java libs that this module has dependencies to
 	Libs []string
 
+	// List of static java libs that this module has dependencies to
+	Static_libs []string
+
 	// List of files to remove from the jar file(s)
 	Exclude_files []string
 
@@ -2385,9 +2393,10 @@
 	dexJarFileErr     error
 	dexJarInstallFile android.Path
 
-	combinedClasspathFile android.Path
-	classLoaderContexts   dexpreopt.ClassLoaderContextMap
-	exportAidlIncludeDirs android.Paths
+	combinedImplementationFile android.Path
+	combinedHeaderFile         android.Path
+	classLoaderContexts        dexpreopt.ClassLoaderContextMap
+	exportAidlIncludeDirs      android.Paths
 
 	hideApexVariantFromMake bool
 
@@ -2471,6 +2480,7 @@
 
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
 
 	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
 		sdkDeps(ctx, android.SdkContext(j), j.dexer)
@@ -2500,23 +2510,13 @@
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.commonBuildActions(ctx)
 
-	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
-
-	jarName := j.Stem() + ".jar"
-	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
-	TransformJarsToJar(ctx, outputFile, "for prebuilts", jars, android.OptionalPath{},
-		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
-	if Bool(j.properties.Jetifier) {
-		inputFile := outputFile
-		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
-		TransformJetifier(ctx, outputFile, inputFile)
-	}
-	j.combinedClasspathFile = outputFile
 	j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
 
 	var flags javaBuilderFlags
 
 	j.collectTransitiveHeaderJars(ctx)
+	var staticJars android.Paths
+	var staticHeaderJars android.Paths
 	ctx.VisitDirectDeps(func(module android.Module) {
 		tag := ctx.OtherModuleDependencyTag(module)
 		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
@@ -2526,6 +2526,8 @@
 				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
 			case staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
+				staticJars = append(staticJars, dep.ImplementationAndResourcesJars...)
+				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
 			}
@@ -2539,6 +2541,46 @@
 		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
+	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
+	jarName := j.Stem() + ".jar"
+
+	// 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)
+	implementationJars := append(slices.Clone(jars), staticJars...)
+	TransformJarsToJar(ctx, outputFile, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
+		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+
+	// 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.WritablePath
+	if reuseImplementationJarAsHeaderJar {
+		headerOutputFile = outputFile
+	} else {
+		headerJars := append(slices.Clone(jars), staticHeaderJars...)
+		headerOutputFile = android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
+			false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+	}
+
+	if Bool(j.properties.Jetifier) {
+		inputFile := outputFile
+		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
+		TransformJetifier(ctx, outputFile, inputFile)
+
+		if !reuseImplementationJarAsHeaderJar {
+			headerInputFile := headerOutputFile
+			headerOutputFile = android.PathForModuleOut(ctx, "jetifier-headers", jarName)
+			TransformJetifier(ctx, headerOutputFile, headerInputFile)
+		} else {
+			headerOutputFile = outputFile
+		}
+	}
+	j.combinedHeaderFile = headerOutputFile
+	j.combinedImplementationFile = outputFile
+
 	j.maybeInstall(ctx, jarName, outputFile)
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -2622,11 +2664,11 @@
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(j.combinedClasspathFile),
+		HeaderJars:                     android.PathsIfNonNil(j.combinedHeaderFile),
 		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile),
-		ImplementationJars:             android.PathsIfNonNil(j.combinedClasspathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
+		ImplementationJars:             android.PathsIfNonNil(j.combinedImplementationFile),
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
 		StubsLinkType:                  j.stubsLinkType,
 		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
@@ -2654,7 +2696,7 @@
 func (j *Import) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "", ".jar":
-		return android.Paths{j.combinedClasspathFile}, nil
+		return android.Paths{j.combinedImplementationFile}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -2663,17 +2705,11 @@
 var _ android.OutputFileProducer = (*Import)(nil)
 
 func (j *Import) HeaderJars() android.Paths {
-	if j.combinedClasspathFile == nil {
-		return nil
-	}
-	return android.Paths{j.combinedClasspathFile}
+	return android.PathsIfNonNil(j.combinedHeaderFile)
 }
 
 func (j *Import) ImplementationAndResourcesJars() android.Paths {
-	if j.combinedClasspathFile == nil {
-		return nil
-	}
-	return android.Paths{j.combinedClasspathFile}
+	return android.PathsIfNonNil(j.combinedImplementationFile)
 }
 
 func (j *Import) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
@@ -3005,7 +3041,7 @@
 	module.AddProperties(
 		&CommonProperties{},
 		&DeviceProperties{},
-		&OverridableDeviceProperties{},
+		&OverridableProperties{},
 		&DexProperties{},
 		&DexpreoptProperties{},
 		&android.ProtoProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 2f3ccb9..2676aa5 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -588,10 +588,11 @@
 	javac := fooModule.Rule("javac")
 	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
 	barModule := ctx.ModuleForTests("bar", "android_common")
-	barJar := barModule.Rule("combineJar").Output
+	barJar := barModule.Output("combined/bar.jar").Output
 	bazModule := ctx.ModuleForTests("baz", "android_common")
 	bazJar := bazModule.Rule("combineJar").Output
-	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
+	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").
+		Output("combined/sdklib.stubs.jar").Output
 
 	fooLibrary := fooModule.Module().(*Library)
 	assertDeepEquals(t, "foo unique sources incorrect",
@@ -1035,7 +1036,7 @@
 	}
 }
 
-func TestJavaLibrary(t *testing.T) {
+func TestJavaLibraryOutputFiles(t *testing.T) {
 	testJavaWithFS(t, "", map[string][]byte{
 		"libcore/Android.bp": []byte(`
 				java_library {
@@ -1052,7 +1053,7 @@
 	})
 }
 
-func TestJavaImport(t *testing.T) {
+func TestJavaImportOutputFiles(t *testing.T) {
 	testJavaWithFS(t, "", map[string][]byte{
 		"libcore/Android.bp": []byte(`
 				java_import {
@@ -1068,6 +1069,85 @@
 	})
 }
 
+func TestJavaImport(t *testing.T) {
+	bp := `
+		java_library {
+			name: "source_library",
+			srcs: ["source.java"],
+		}
+
+		java_import {
+			name: "import_with_no_deps",
+			jars: ["no_deps.jar"],
+		}
+
+		java_import {
+			name: "import_with_source_deps",
+			jars: ["source_deps.jar"],
+			static_libs: ["source_library"],
+		}
+
+		java_import {
+			name: "import_with_import_deps",
+			jars: ["import_deps.jar"],
+			static_libs: ["import_with_no_deps"],
+		}
+	`
+	ctx := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, bp)
+
+	source := ctx.ModuleForTests("source_library", "android_common")
+	sourceJar := source.Output("javac/source_library.jar")
+	sourceHeaderJar := source.Output("turbine-combined/source_library.jar")
+	sourceJavaInfo, _ := android.SingletonModuleProvider(ctx, source.Module(), JavaInfoProvider)
+
+	// The source library produces separate implementation and header jars
+	android.AssertPathsRelativeToTopEquals(t, "source library implementation jar",
+		[]string{sourceJar.Output.String()}, sourceJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "source library header jar",
+		[]string{sourceHeaderJar.Output.String()}, sourceJavaInfo.HeaderJars)
+
+	importWithNoDeps := ctx.ModuleForTests("import_with_no_deps", "android_common")
+	importWithNoDepsJar := importWithNoDeps.Output("combined/import_with_no_deps.jar")
+	importWithNoDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithNoDeps.Module(), JavaInfoProvider)
+
+	// An import with no deps produces a single jar used as both the header and implementation jar.
+	android.AssertPathsRelativeToTopEquals(t, "import with no deps implementation jar",
+		[]string{importWithNoDepsJar.Output.String()}, importWithNoDepsJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with no deps header jar",
+		[]string{importWithNoDepsJar.Output.String()}, importWithNoDepsJavaInfo.HeaderJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with no deps combined inputs",
+		[]string{"no_deps.jar"}, importWithNoDepsJar.Inputs)
+
+	importWithSourceDeps := ctx.ModuleForTests("import_with_source_deps", "android_common")
+	importWithSourceDepsJar := importWithSourceDeps.Output("combined/import_with_source_deps.jar")
+	importWithSourceDepsHeaderJar := importWithSourceDeps.Output("turbine-combined/import_with_source_deps.jar")
+	importWithSourceDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithSourceDeps.Module(), JavaInfoProvider)
+
+	// An import with source deps produces separate header and implementation jars.
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps implementation jar",
+		[]string{importWithSourceDepsJar.Output.String()}, importWithSourceDepsJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps header jar",
+		[]string{importWithSourceDepsHeaderJar.Output.String()}, importWithSourceDepsJavaInfo.HeaderJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps combined implementation jar inputs",
+		[]string{"source_deps.jar", sourceJar.Output.String()}, importWithSourceDepsJar.Inputs)
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps combined header jar inputs",
+		[]string{"source_deps.jar", sourceHeaderJar.Output.String()}, importWithSourceDepsHeaderJar.Inputs)
+
+	importWithImportDeps := ctx.ModuleForTests("import_with_import_deps", "android_common")
+	importWithImportDepsJar := importWithImportDeps.Output("combined/import_with_import_deps.jar")
+	importWithImportDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithImportDeps.Module(), JavaInfoProvider)
+
+	// An import with only import deps produces a single jar used as both the header and implementation jar.
+	android.AssertPathsRelativeToTopEquals(t, "import with import deps implementation jar",
+		[]string{importWithImportDepsJar.Output.String()}, importWithImportDepsJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with import deps header jar",
+		[]string{importWithImportDepsJar.Output.String()}, importWithImportDepsJavaInfo.HeaderJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with import deps combined implementation jar inputs",
+		[]string{"import_deps.jar", importWithNoDepsJar.Output.String()}, importWithImportDepsJar.Inputs)
+}
+
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
@@ -2643,6 +2723,70 @@
 	}
 }
 
+func TestMultiplePlatformCompatConfigPrebuilts(t *testing.T) {
+	bp := `
+		// multiple variations of platform_compat_config
+		// source
+		platform_compat_config {
+			name: "myconfig",
+		}
+		// prebuilt "v1"
+		prebuilt_platform_compat_config {
+			name: "myconfig",
+			metadata: "myconfig.xml",
+		}
+		// prebuilt "v2"
+		prebuilt_platform_compat_config {
+			name: "myconfig.v2",
+			source_module_name: "myconfig", // without source_module_name, the singleton will merge two .xml files
+			metadata: "myconfig.v2.xml",
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["%v"],
+		}
+	`
+	testCases := []struct {
+		desc                            string
+		selectedDependencyName          string
+		expectedPlatformCompatConfigXml string
+	}{
+		{
+			desc:                            "Source platform_compat_config is selected using apex_contributions",
+			selectedDependencyName:          "myconfig",
+			expectedPlatformCompatConfigXml: "out/soong/.intermediates/myconfig/android_common/myconfig_meta.xml",
+		},
+		{
+			desc:                            "Prebuilt platform_compat_config v1 is selected using apex_contributions",
+			selectedDependencyName:          "prebuilt_myconfig",
+			expectedPlatformCompatConfigXml: "myconfig.xml",
+		},
+		{
+			desc:                            "Prebuilt platform_compat_config v2 is selected using apex_contributions",
+			selectedDependencyName:          "prebuilt_myconfig.v2",
+			expectedPlatformCompatConfigXml: "myconfig.v2.xml",
+		},
+	}
+
+	for _, tc := range testCases {
+		ctx := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			PrepareForTestWithPlatformCompatConfig,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		mergedGlobalConfig := ctx.SingletonForTests("platform_compat_config_singleton").Output("compat_config/merged_compat_config.xml")
+		android.AssertIntEquals(t, "The merged compat config file should only have a single dependency", 1, len(mergedGlobalConfig.Implicits))
+		android.AssertStringEquals(t, "The merged compat config file is missing the appropriate platform compat config", mergedGlobalConfig.Implicits[0].String(), tc.expectedPlatformCompatConfigXml)
+	}
+}
+
 func TestApiLibraryAconfigDeclarations(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForJavaTest,
@@ -2693,3 +2837,38 @@
 	cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
 	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt")
 }
+
+func TestJavaLibHostWithStem(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library_host {
+			name: "foo",
+			srcs: ["a.java"],
+			stem: "foo-new",
+		}
+	`)
+
+	buildOS := ctx.Config().BuildOS.String()
+	foo := ctx.ModuleForTests("foo", buildOS+"_common")
+
+	outputs := fmt.Sprint(foo.AllOutputs())
+	if !strings.Contains(outputs, "foo-new.jar") {
+		t.Errorf("Module output does not contain expected jar %s", "foo-new.jar")
+	}
+}
+
+func TestJavaLibWithStem(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			stem: "foo-new",
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	outputs := fmt.Sprint(foo.AllOutputs())
+	if !strings.Contains(outputs, "foo-new.jar") {
+		t.Errorf("Module output does not contain expected jar %s", "foo-new.jar")
+	}
+}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 2197304..2fc6c02 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -184,6 +185,11 @@
 
 type prebuiltCompatConfigProperties struct {
 	Metadata *string `android:"path"`
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 }
 
 func (module *prebuiltCompatConfigModule) Prebuilt() *android.Prebuilt {
@@ -198,6 +204,10 @@
 	return module.metadataFile
 }
 
+func (module *prebuiltCompatConfigModule) BaseModuleName() string {
+	return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name())
+}
+
 var _ platformCompatConfigMetadataProvider = (*prebuiltCompatConfigModule)(nil)
 
 func (module *prebuiltCompatConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 94e9c6c..6a79e58 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -158,6 +158,21 @@
 	mctx.CreateModule(genrule.GenRuleFactory, &genruleProps)
 }
 
+func createCombinedApiFilegroupModule(mctx android.LoadHookContext, name string, srcs []string) {
+	filegroupProps := struct {
+		Name *string
+		Srcs []string
+	}{}
+	filegroupProps.Name = proptools.StringPtr(name)
+
+	var transformedSrcs []string
+	for _, src := range srcs {
+		transformedSrcs = append(transformedSrcs, ":"+src)
+	}
+	filegroupProps.Srcs = transformedSrcs
+	mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
+}
+
 func createLatestApiModuleExtensionVersionFile(mctx android.LoadHookContext, name string, version string) {
 	genruleProps := struct {
 		Name *string
@@ -252,6 +267,10 @@
 	return module + ".api." + scope + "." + version
 }
 
+func PrebuiltApiCombinedModuleName(module, scope, version string) string {
+	return module + ".api.combined." + scope + "." + version
+}
+
 func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
 	// <apiver>/<scope>/api/<module>.txt
 	apiLevelFiles := globApiDirs(mctx, p, "api/*.txt")
@@ -307,7 +326,9 @@
 	}
 
 	// Sort the keys in order to make build.ninja stable
-	for _, k := range android.SortedKeys(latest) {
+	sortedLatestKeys := android.SortedKeys(latest)
+
+	for _, k := range sortedLatestKeys {
 		info := latest[k]
 		name := PrebuiltApiModuleName(info.module, info.scope, "latest")
 		latestExtensionVersionModuleName := PrebuiltApiModuleName(info.module, info.scope, "latest.extension_version")
@@ -333,11 +354,25 @@
 		}
 	}
 	// Create empty incompatibilities files for remaining modules
-	for _, k := range android.SortedKeys(latest) {
+	// If the incompatibility module has been created, create a corresponding combined module
+	for _, k := range sortedLatestKeys {
 		if _, ok := incompatibilities[k]; !ok {
 			createEmptyFile(mctx, PrebuiltApiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
 		}
 	}
+
+	// Create combined latest api and removed api files modules.
+	// The combined modules list all api files of the api scope and its subset api scopes.
+	for _, k := range sortedLatestKeys {
+		info := latest[k]
+		name := PrebuiltApiCombinedModuleName(info.module, info.scope, "latest")
+
+		var srcs []string
+		currentApiScope := scopeByName[info.scope]
+		srcs = append(srcs, PrebuiltApiModuleName(info.module, currentApiScope.name, "latest"))
+
+		createCombinedApiFilegroupModule(mctx, name, srcs)
+	}
 }
 
 func createPrebuiltApiModules(mctx android.LoadHookContext) {
diff --git a/java/rro.go b/java/rro.go
index 3e0f8e9..72170fc 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -122,6 +122,10 @@
 
 	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
 	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
+
+	for _, aconfig_declaration := range r.aaptProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -151,6 +155,7 @@
 			sdkContext:                     r,
 			enforceDefaultTargetSdkVersion: false,
 			extraLinkFlags:                 aaptLinkFlags,
+			aconfigTextFiles:               getAconfigFilePaths(ctx),
 		},
 	)
 
diff --git a/java/rro_test.go b/java/rro_test.go
index c4a4d04..d697ec6 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -405,3 +405,49 @@
 		android.AssertPathRelativeToTopEquals(t, "Install dir is not correct for "+testCase.name, testCase.expectedPath, mod.installDir)
 	}
 }
+
+func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+		runtime_resource_overlay {
+			name: "foo",
+			sdk_version: "current",
+			flags_packages: [
+				"bar",
+				"baz",
+			],
+		}
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package.bar",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		aconfig_declarations {
+			name: "baz",
+			package: "com.example.package.baz",
+			srcs: [
+				"baz.aconfig",
+			],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+
+	// runtime_resource_overlay module depends on aconfig_declarations listed in flags_packages
+	android.AssertBoolEquals(t, "foo expected to depend on bar", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"))
+
+	android.AssertBoolEquals(t, "foo expected to depend on baz", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "baz"))
+
+	aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
+	linkInFlags := aapt2LinkRule.Args["inFlags"]
+	android.AssertStringDoesContain(t,
+		"aapt2 link command expected to pass feature flags arguments",
+		linkInFlags,
+		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+	)
+}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index cdd0448..5ddc675 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -30,6 +30,7 @@
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
+	"android/soong/etc"
 )
 
 const (
@@ -1672,12 +1673,16 @@
 	return PrebuiltApiModuleName(name, apiScope.name, "latest")
 }
 
+func latestPrebuiltApiCombinedModuleName(name string, apiScope *apiScope) string {
+	return PrebuiltApiCombinedModuleName(name, apiScope.name, "latest")
+}
+
 func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
 	return ":" + module.latestApiModuleName(apiScope)
 }
 
 func (module *SdkLibrary) latestApiModuleName(apiScope *apiScope) string {
-	return latestPrebuiltApiModuleName(module.distStem(), apiScope)
+	return latestPrebuiltApiCombinedModuleName(module.distStem(), apiScope)
 }
 
 func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
@@ -1685,7 +1690,7 @@
 }
 
 func (module *SdkLibrary) latestRemovedApiModuleName(apiScope *apiScope) string {
-	return latestPrebuiltApiModuleName(module.distStem()+"-removed", apiScope)
+	return latestPrebuiltApiCombinedModuleName(module.distStem()+"-removed", apiScope)
 }
 
 func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string {
@@ -1993,20 +1998,25 @@
 	if !Bool(module.sdkLibraryProperties.No_dist) {
 		// Dist the api txt and removed api txt artifacts for sdk builds.
 		distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+		stubsTypeTagPrefix := ""
+		if mctx.Config().ReleaseHiddenApiExportableStubs() {
+			stubsTypeTagPrefix = ".exportable"
+		}
 		for _, p := range []struct {
 			tag     string
 			pattern string
 		}{
 			// "exportable" api files are copied to the dist directory instead of the
-			// "everything" api files.
-			{tag: ".exportable.api.txt", pattern: "%s.txt"},
-			{tag: ".exportable.removed-api.txt", pattern: "%s-removed.txt"},
+			// "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag
+			// is set. Otherwise, the "everything" api files are copied to the dist directory.
+			{tag: "%s.api.txt", pattern: "%s.txt"},
+			{tag: "%s.removed-api.txt", pattern: "%s-removed.txt"},
 		} {
 			props.Dists = append(props.Dists, android.Dist{
 				Targets: []string{"sdk", "win_sdk"},
 				Dir:     distDir,
 				Dest:    proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
-				Tag:     proptools.StringPtr(p.tag),
+				Tag:     proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)),
 			})
 		}
 	}
@@ -2079,7 +2089,7 @@
 	mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
-func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
+func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties {
 	props := libraryProperties{}
 
 	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
@@ -2095,13 +2105,22 @@
 	}
 	props.Compile_dex = compileDex
 
+	if !Bool(module.sdkLibraryProperties.No_dist) && doDist {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
+		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+		props.Dist.Tag = proptools.StringPtr(".jar")
+	}
+
 	return props
 }
 
 func (module *SdkLibrary) createTopLevelStubsLibrary(
 	mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
 
-	props := module.topLevelStubsLibraryProps(mctx, apiScope)
+	// Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false
+	doDist := !mctx.Config().ReleaseHiddenApiExportableStubs()
+	props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
 	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
 
 	// Add the stub compiling java_library/java_api_library as static lib based on build config
@@ -2117,18 +2136,11 @@
 func (module *SdkLibrary) createTopLevelExportableStubsLibrary(
 	mctx android.DefaultableHookContext, apiScope *apiScope) {
 
-	props := module.topLevelStubsLibraryProps(mctx, apiScope)
+	// Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true
+	doDist := mctx.Config().ReleaseHiddenApiExportableStubs()
+	props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
 	props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
 
-	// Dist the class jar artifact for sdk builds.
-	// "exportable" stubs are copied to dist for sdk builds instead of the "everything" stubs.
-	if !Bool(module.sdkLibraryProperties.No_dist) {
-		props.Dist.Targets = []string{"sdk", "win_sdk"}
-		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
-		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
-		props.Dist.Tag = proptools.StringPtr(".jar")
-	}
-
 	staticLib := module.exportableSourceStubsLibraryModuleName(apiScope)
 	props.Static_libs = append(props.Static_libs, staticLib)
 
@@ -3163,10 +3175,12 @@
 }
 
 // from android.PrebuiltEtcModule
-func (module *sdkLibraryXml) OutputFile() android.OutputPath {
-	return module.outputFilePath
+func (module *sdkLibraryXml) OutputFiles(tag string) (android.Paths, error) {
+	return android.OutputPaths{module.outputFilePath}.Paths(), nil
 }
 
+var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil)
+
 // from android.ApexModule
 func (module *sdkLibraryXml) AvailableFor(what string) bool {
 	return true
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 93ef408..fb584c5 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -139,10 +139,10 @@
 
 	exportedComponentsInfo, _ := android.SingletonModuleProvider(result, foo.Module(), android.ExportedComponentsInfoProvider)
 	expectedFooExportedComponents := []string{
-		"foo-removed.api.public.latest",
-		"foo-removed.api.system.latest",
-		"foo.api.public.latest",
-		"foo.api.system.latest",
+		"foo-removed.api.combined.public.latest",
+		"foo-removed.api.combined.system.latest",
+		"foo.api.combined.public.latest",
+		"foo.api.combined.system.latest",
 		"foo.stubs",
 		"foo.stubs.exportable",
 		"foo.stubs.exportable.system",
@@ -556,8 +556,8 @@
 
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
 		`dex2oatd`,
-		`sdklib-removed.api.public.latest`,
-		`sdklib.api.public.latest`,
+		`sdklib-removed.api.combined.public.latest`,
+		`sdklib.api.combined.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
 		`sdklib.stubs.exportable`,
@@ -960,8 +960,8 @@
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
 		`dex2oatd`,
 		`prebuilt_sdklib`,
-		`sdklib-removed.api.public.latest`,
-		`sdklib.api.public.latest`,
+		`sdklib-removed.api.combined.public.latest`,
+		`sdklib.api.combined.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
 		`sdklib.stubs.exportable`,
@@ -1039,8 +1039,8 @@
 
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
 		`prebuilt_sdklib`,
-		`sdklib-removed.api.public.latest`,
-		`sdklib.api.public.latest`,
+		`sdklib-removed.api.combined.public.latest`,
+		`sdklib.api.combined.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
 		`sdklib.stubs.exportable`,
@@ -1393,6 +1393,11 @@
 			"sdklib_group_foo",
 			"sdklib_owner_foo",
 			"foo"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "sdklib_no_group",
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 59c5466..b291e70 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -189,7 +189,7 @@
 		return javaSdkLibrarySdkMemberType
 	}
 
-	return javaSystemserverLibsSdkMemberType
+	return JavaSystemserverLibsSdkMemberType
 }
 
 func (b systemServerClasspathFragmentContentDependencyTag) ExportMember() bool {
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 78b62d9..98aa408 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -89,7 +89,7 @@
 	output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
 
 	builder := android.NewRuleBuilder(pctx, ctx)
-	BuildLinkerConfig(ctx, builder, input, nil, output)
+	BuildLinkerConfig(ctx, builder, input, nil, nil, output)
 	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
 
 	l.outputFilePath = output
@@ -101,7 +101,7 @@
 }
 
 func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
-	input android.Path, otherModules []android.Module, output android.OutputPath) {
+	input android.Path, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) {
 
 	// First, convert the input json to protobuf format
 	interimOutput := android.PathForModuleOut(ctx, "temp.pb")
@@ -111,9 +111,9 @@
 		FlagWithInput("-s ", input).
 		FlagWithOutput("-o ", interimOutput)
 
-	// Secondly, if there's provideLibs gathered from otherModules, append them
+	// Secondly, if there's provideLibs gathered from provideModules, append them
 	var provideLibs []string
-	for _, m := range otherModules {
+	for _, m := range provideModules {
 		if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
 			for _, ps := range c.PackagingSpecs() {
 				provideLibs = append(provideLibs, ps.FileName())
@@ -122,18 +122,45 @@
 	}
 	provideLibs = android.FirstUniqueStrings(provideLibs)
 	sort.Strings(provideLibs)
+
+	var requireLibs []string
+	for _, m := range requireModules {
+		if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() {
+			requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so")
+		}
+	}
+
+	requireLibs = android.FirstUniqueStrings(requireLibs)
+	sort.Strings(requireLibs)
+
 	if len(provideLibs) > 0 {
+		prevOutput := interimOutput
+		interimOutput = android.PathForModuleOut(ctx, "temp_provideLibs.pb")
 		builder.Command().
 			BuiltTool("conv_linker_config").
 			Flag("append").
-			FlagWithInput("-s ", interimOutput).
-			FlagWithOutput("-o ", output).
+			FlagWithInput("-s ", prevOutput).
+			FlagWithOutput("-o ", interimOutput).
 			FlagWithArg("--key ", "provideLibs").
 			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
-	} else {
-		// If nothing to add, just cp to the final output
-		builder.Command().Text("cp").Input(interimOutput).Output(output)
+		builder.Temporary(prevOutput)
 	}
+	if len(requireLibs) > 0 {
+		prevOutput := interimOutput
+		interimOutput = android.PathForModuleOut(ctx, "temp_requireLibs.pb")
+		builder.Command().
+			BuiltTool("conv_linker_config").
+			Flag("append").
+			FlagWithInput("-s ", prevOutput).
+			FlagWithOutput("-o ", interimOutput).
+			FlagWithArg("--key ", "requireLibs").
+			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(requireLibs, " ")))
+		builder.Temporary(prevOutput)
+	}
+
+	// cp to the final output
+	builder.Command().Text("cp").Input(interimOutput).Output(output)
+
 	builder.Temporary(interimOutput)
 	builder.DeleteTemporaryFiles()
 }
diff --git a/rust/compiler.go b/rust/compiler.go
index c1bdbeb..03fdf2b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -75,6 +75,8 @@
 	strippedOutputFilePath() android.OptionalPath
 
 	checkedCrateRootPath() (android.Path, error)
+
+	Aliases() map[string]string
 }
 
 func (compiler *baseCompiler) edition() string {
@@ -140,6 +142,12 @@
 	// flags to pass to the linker
 	Ld_flags []string `android:"arch_variant"`
 
+	// Rust crate dependencies to rename. Each entry should be a string of the form "dependencyname:alias".
+	//
+	// "dependencyname" here should be the name of the crate, not the Android module. This is
+	// equivalent to writing `alias = { package = "dependencyname" }` in a `Cargo.toml`.
+	Aliases []string
+
 	// list of rust rlib crate dependencies
 	Rlibs []string `android:"arch_variant"`
 
@@ -281,6 +289,18 @@
 	return Bool(compiler.Properties.Prefer_rlib)
 }
 
+func (compiler *baseCompiler) Aliases() map[string]string {
+	aliases := map[string]string{}
+	for _, entry := range compiler.Properties.Aliases {
+		dep, alias, found := strings.Cut(entry, ":")
+		if !found {
+			panic(fmt.Errorf("invalid aliases entry %q missing ':'", entry))
+		}
+		aliases[dep] = alias
+	}
+	return aliases
+}
+
 func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
 	// For devices, we always link stdlibs in as dylibs by default.
 	if compiler.preferRlib() {
diff --git a/rust/config/global.go b/rust/config/global.go
index 418eca4..e28dbaa 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -25,7 +25,7 @@
 	pctx         = android.NewPackageContext("android/soong/rust/config")
 	ExportedVars = android.NewExportedVariables(pctx)
 
-	RustDefaultVersion = "1.75.0"
+	RustDefaultVersion = "1.76.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/library.go b/rust/library.go
index 7f004fc..3560d73 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -54,9 +54,13 @@
 	Shared VariantLibraryProperties `android:"arch_variant"`
 	Static VariantLibraryProperties `android:"arch_variant"`
 
-	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
+	// TODO: Remove this when all instances of Include_dirs have been removed from rust_ffi modules.
+	// path to include directories to pass to cc_* modules, only relevant for static/shared variants (deprecated, use export_include_dirs instead).
 	Include_dirs []string `android:"path,arch_variant"`
 
+	// path to include directories to export to cc_* modules, only relevant for static/shared variants.
+	Export_include_dirs []string `android:"path,arch_variant"`
+
 	// Whether this library is part of the Rust toolchain sysroot.
 	Sysroot *bool
 }
@@ -465,6 +469,7 @@
 	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
 	if library.shared() || library.static() {
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
+		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
 	}
 	if library.shared() {
 		if ctx.Darwin() {
diff --git a/rust/library_test.go b/rust/library_test.go
index e03074d..7275b66 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -403,3 +403,22 @@
 	}
 
 }
+
+func TestRustFFIExportedIncludes(t *testing.T) {
+	ctx := testRust(t, `
+		rust_ffi {
+			name: "libbar",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			export_include_dirs: ["rust_includes"],
+			host_supported: true,
+		}
+		cc_library_static {
+			name: "libfoo",
+			srcs: ["foo.cpp"],
+			shared_libs: ["libbar"],
+			host_supported: true,
+		}`)
+	libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Rule("cc")
+	android.AssertStringDoesContain(t, "cFlags for lib module", libfooStatic.Args["cFlags"], " -Irust_includes ")
+}
diff --git a/rust/rust.go b/rust/rust.go
index 245ed2e..7d81c72 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -1063,6 +1063,12 @@
 	return nil
 }
 
+func (d dependencyTag) PropagateAconfigValidation() bool {
+	return d == rlibDepTag || d == sourceDepTag
+}
+
+var _ android.PropagateAconfigValidationDependencyTag = dependencyTag{}
+
 var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
 
 var (
@@ -1136,6 +1142,7 @@
 		}
 	}
 }
+
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
@@ -1427,16 +1434,29 @@
 	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
 
 	var rlibDepFiles RustLibraries
+	aliases := mod.compiler.Aliases()
 	for _, dep := range directRlibDeps {
-		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+		crateName := dep.CrateName()
+		if alias, aliased := aliases[crateName]; aliased {
+			crateName = alias
+		}
+		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
 	}
 	var dylibDepFiles RustLibraries
 	for _, dep := range directDylibDeps {
-		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+		crateName := dep.CrateName()
+		if alias, aliased := aliases[crateName]; aliased {
+			crateName = alias
+		}
+		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
 	}
 	var procMacroDepFiles RustLibraries
 	for _, dep := range directProcMacroDeps {
-		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+		crateName := dep.CrateName()
+		if alias, aliased := aliases[crateName]; aliased {
+			crateName = alias
+		}
+		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
 	}
 
 	var staticLibDepFiles android.Paths
diff --git a/rust/rust_test.go b/rust/rust_test.go
index d609c2f..295a734 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -470,6 +470,35 @@
 	m.Output("libwaldo.dylib.so.bloaty.csv")
 }
 
+// Test that aliases are respected.
+func TestRustAliases(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library {
+			name: "libbar",
+			crate_name: "bar",
+			srcs: ["src/lib.rs"],
+		}
+		rust_library {
+			name: "libbaz",
+			crate_name: "baz",
+			srcs: ["src/lib.rs"],
+		}
+		rust_binary {
+			name: "foo",
+			srcs: ["src/main.rs"],
+			rustlibs: ["libbar", "libbaz"],
+			aliases: ["bar:bar_renamed"],
+		}`)
+
+	fooRustc := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
+	if !strings.Contains(fooRustc.Args["libFlags"], "--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so") {
+		t.Errorf("--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
+	}
+	if !strings.Contains(fooRustc.Args["libFlags"], "--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so") {
+		t.Errorf("--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
+	}
+}
+
 func assertString(t *testing.T, got, expected string) {
 	t.Helper()
 	if got != expected {
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 7ebe66b..a6ed0e5 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -32,7 +32,7 @@
 		crate_name: "ffivendor_available",
 		srcs: ["lib.rs"],
 		vendor_available: true,
-		include_dirs: ["rust_headers/"],
+		export_include_dirs: ["rust_headers/"],
 	}
 
 	rust_ffi {
@@ -40,7 +40,7 @@
 		crate_name: "ffivendor",
 		srcs: ["lib.rs"],
 		vendor: true,
-		include_dirs: ["rust_headers/"],
+		export_include_dirs: ["rust_headers/"],
 	}
 
 	rust_library {
diff --git a/scripts/Android.bp b/scripts/Android.bp
index e2fd59f..f36329b 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -292,3 +292,16 @@
     name: "keep-flagged-apis",
     src: "keep-flagged-apis.sh",
 }
+
+python_binary_host {
+    name: "merge_directories",
+    main: "merge_directories.py",
+    srcs: [
+        "merge_directories.py",
+    ],
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
diff --git a/scripts/merge_directories.py b/scripts/merge_directories.py
new file mode 100755
index 0000000..3f8631b
--- /dev/null
+++ b/scripts/merge_directories.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+import argparse
+import os
+import shutil
+import sys
+
+def main():
+    parser = argparse.ArgumentParser(
+        description="Given a list of directories, this script will copy the contents of all of "
+        "them into the first directory, erroring out if any duplicate files are found."
+    )
+    parser.add_argument(
+        "--ignore-duplicates",
+        action="store_true",
+        help="Don't error out on duplicate files, just skip them. The file from the earliest "
+        "directory listed on the command line will be the winner."
+    )
+    parser.add_argument(
+        "--file-list",
+        help="Path to a text file containing paths relative to in_dir. Only these paths will be "
+        "copied out of in_dir."
+    )
+    parser.add_argument("out_dir")
+    parser.add_argument("in_dir")
+    args = parser.parse_args()
+
+    if not os.path.isdir(args.out_dir):
+        sys.exit(f"error: {args.out_dir} must be a directory")
+    if not os.path.isdir(args.in_dir):
+        sys.exit(f"error: {args.in_dir} must be a directory")
+
+    file_list = None
+    if args.file_list:
+        with open(file_list_file, "r") as f:
+            file_list = f.read().strip().splitlines()
+
+    in_dir = args.in_dir
+    for root, dirs, files in os.walk(in_dir):
+        rel_root = os.path.relpath(root, in_dir)
+        dst_root = os.path.join(args.out_dir, rel_root)
+        made_parent_dirs = False
+        for f in files:
+            src = os.path.join(root, f)
+            dst = os.path.join(dst_root, f)
+            p = os.path.normpath(os.path.join(rel_root, f))
+            if file_list is not None and p not in file_list:
+                continue
+            if os.path.lexists(dst):
+                if args.ignore_duplicates:
+                    continue
+                sys.exit(f"error: {p} exists in both {args.out_dir} and {in_dir}")
+
+            if not made_parent_dirs:
+                os.makedirs(dst_root, exist_ok=True)
+                made_parent_dirs = True
+
+            shutil.copy2(src, dst, follow_symlinks=False)
+
+if __name__ == "__main__":
+    main()
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 5d41958..8d3bbfa 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -152,6 +152,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "art-bootclasspath-fragment",
     prefer: false,
@@ -187,6 +192,7 @@
     apex_available: ["com.android.art"],
     jars: ["java_boot_libs/snapshot/jars/are/invalid/core2.jar"],
 }
+
 `),
 		checkAllCopyRules(`
 .intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
@@ -353,6 +359,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_myothersdklibrary",
+        "prebuilt_mysdklibrary",
+        "prebuilt_mycoreplatform",
+    ],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -642,6 +657,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mysdklibrary"],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -881,6 +901,14 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_mynewlibrary",
+        "prebuilt_mysdklibrary",
+    ],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -1008,6 +1036,9 @@
 		android.FixtureMergeEnv(map[string]string{
 			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+		}),
 
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.BuildFlags = map[string]string{
@@ -1226,6 +1257,9 @@
 		android.FixtureMergeEnv(map[string]string{
 			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+		}),
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 265579a..9490d12 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -123,6 +123,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_sdkmember"],
+}
+
 cc_prebuilt_library_shared {
     name: "sdkmember",
     prefer: false,
@@ -226,6 +231,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_crtobj"],
+}
+
 cc_prebuilt_object {
     name: "crtobj",
     prefer: false,
@@ -333,6 +343,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -406,6 +421,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -465,6 +485,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mymodule_exports.contributions",
+    contents: ["prebuilt_mynativebinary"],
+}
+
 cc_prebuilt_binary {
     name: "mynativebinary",
     prefer: false,
@@ -523,6 +548,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativebinary"],
+}
+
 cc_prebuilt_binary {
     name: "mynativebinary",
     prefer: false,
@@ -621,6 +651,14 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: [
+        "prebuilt_mynativebinary",
+        "prebuilt_mynativelib",
+    ],
+}
+
 cc_prebuilt_binary {
     name: "mynativebinary",
     prefer: false,
@@ -696,6 +734,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mymodule_exports.contributions",
+    contents: ["prebuilt_linker"],
+}
+
 cc_prebuilt_binary {
     name: "linker",
     prefer: false,
@@ -755,6 +798,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -856,6 +904,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_mynativelib",
+        "prebuilt_myothernativelib",
+        "prebuilt_mysystemnativelib",
+    ],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -953,6 +1010,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -1029,6 +1091,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -1095,6 +1162,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
@@ -1158,6 +1230,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
@@ -1222,6 +1299,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
@@ -1298,6 +1380,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
@@ -1394,6 +1481,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
@@ -1520,6 +1612,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
@@ -1572,6 +1669,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1594,6 +1696,9 @@
 		PrepareForTestWithSdkBuildComponents,
 		ccTestFs.AddToFixture(),
 		prepareForTestWithNativeBridgeTarget,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			android.RegisterApexContributionsBuildComponents(ctx)
+		}),
 	).RunTestWithBp(t, `
 		sdk {
 			name: "mysdk",
@@ -1616,6 +1721,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1679,6 +1789,9 @@
 			cc.PrepareForTestWithCcDefaultModules,
 			PrepareForTestWithSdkBuildComponents,
 			ccTestFs.AddToFixture(),
+			android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+				android.RegisterApexContributionsBuildComponents(ctx)
+			}),
 		).RunTestWithBp(t, fmt.Sprintf(`
 		sdk {
 			name: "mysdk",
@@ -1701,6 +1814,11 @@
 			checkAndroidBpContents(fmt.Sprintf(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1750,6 +1868,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1807,6 +1930,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1870,6 +1998,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_sslnil",
+        "prebuilt_sslempty",
+        "prebuilt_sslnonempty",
+    ],
+}
+
 cc_prebuilt_library_shared {
     name: "sslnil",
     prefer: false,
@@ -1943,6 +2080,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_sslvariants"],
+}
+
 cc_prebuilt_library_shared {
     name: "sslvariants",
     prefer: false,
@@ -2002,6 +2144,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_stubslib"],
+}
+
 cc_prebuilt_library_shared {
     name: "stubslib",
     prefer: false,
@@ -2056,6 +2203,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_stubslib"],
+}
+
 cc_prebuilt_library_shared {
     name: "stubslib",
     prefer: false,
@@ -2114,6 +2266,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mylib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mylib",
     prefer: false,
@@ -2178,6 +2335,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
diff --git a/sdk/compat_config_sdk_test.go b/sdk/compat_config_sdk_test.go
index 45e8e0e..75b5229 100644
--- a/sdk/compat_config_sdk_test.go
+++ b/sdk/compat_config_sdk_test.go
@@ -36,6 +36,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myconfig"],
+}
+
 prebuilt_platform_compat_config {
     name: "myconfig",
     prefer: false,
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index 2605fd1..9d0a242 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -46,6 +46,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 1b2b0f1..275860f 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -108,6 +108,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -154,6 +159,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -193,6 +203,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -245,6 +260,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -291,6 +311,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -313,6 +338,9 @@
 			android.FixtureMergeEnv(map[string]string{
 				"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
 			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+			}),
 		).RunTestWithBp(t, `
 		sdk {
 			name: "mysdk",
@@ -395,6 +423,11 @@
 			checkAndroidBpContents(fmt.Sprintf(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mylib"],
+}
+
 java_import {
     name: "mylib",
     prefer: false,
@@ -459,6 +492,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: [],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -504,6 +542,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -542,6 +585,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavatests"],
+}
+
 java_test_import {
     name: "myjavatests",
     prefer: false,
@@ -582,6 +630,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavatests"],
+}
+
 java_test_import {
     name: "myjavatests",
     prefer: false,
@@ -661,6 +714,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_exported-system-module",
+        "prebuilt_myjavalib",
+        "prebuilt_my-system-modules",
+    ],
+}
+
 java_import {
     name: "exported-system-module",
     prefer: false,
@@ -790,6 +852,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_my-system-modules"],
+}
+
 java_import {
     name: "mysdk_system-module",
     prefer: false,
@@ -854,6 +921,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: [
+        "prebuilt_hostjavalib",
+        "prebuilt_androidjavalib",
+        "prebuilt_myjavalib",
+    ],
+}
+
 java_import {
     name: "hostjavalib",
     prefer: false,
@@ -920,6 +996,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -993,6 +1074,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib-foo"],
+}
+
 java_sdk_library_import {
     name: "myjavalib-foo",
     prefer: false,
@@ -1046,6 +1132,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1093,6 +1184,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1147,6 +1243,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1204,6 +1305,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1272,6 +1378,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1320,6 +1431,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1371,6 +1487,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1436,6 +1557,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1509,6 +1635,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1569,6 +1700,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1626,6 +1762,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/license_sdk_test.go b/sdk/license_sdk_test.go
index 829edf1..754f019 100644
--- a/sdk/license_sdk_test.go
+++ b/sdk/license_sdk_test.go
@@ -69,6 +69,11 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/member_trait_test.go b/sdk/member_trait_test.go
index 99caf13..673d6fb 100644
--- a/sdk/member_trait_test.go
+++ b/sdk/member_trait_test.go
@@ -137,6 +137,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -202,6 +207,17 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_myjavalib",
+        "prebuilt_myjavalib_extra",
+        "prebuilt_myjavalib_special",
+        "prebuilt_anotherjavalib",
+        "prebuilt_anotherjavalib_special",
+    ],
+}
+
 java_test_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index c4df146..f9d49d9 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -118,6 +118,16 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_myjavalib",
+        "prebuilt_mypublicjavalib",
+        "prebuilt_mydefaultedjavalib",
+        "prebuilt_myprivatejavalib",
+    ],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -398,6 +408,11 @@
 			checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -453,6 +468,11 @@
 			checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mysdklibrary"],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 3c0b8ae..c1c4ed6 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -34,6 +34,9 @@
 				env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = targetBuildRelease
 			}
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+		}),
 		prepareForSdkTestWithApex,
 
 		android.FixtureWithRootAndroidBp(sdk+`
@@ -242,6 +245,11 @@
 	expectedLatestSnapshot := `
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mysdklibrary"],
+}
+
 java_sdk_library_import {
     name: "mysdklibrary",
     prefer: false,
diff --git a/sdk/update.go b/sdk/update.go
index a731414..b8ae38a 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -24,6 +24,7 @@
 
 	"android/soong/apex"
 	"android/soong/cc"
+	"android/soong/java"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -388,6 +389,7 @@
 
 	// Create the prebuilt modules for each of the member modules.
 	traits := s.gatherTraits()
+	memberNames := []string{} // soong module names of the members. contains the prebuilt_ prefix.
 	for _, member := range members {
 		memberType := member.memberType
 		if !memberType.ArePrebuiltsRequired() {
@@ -409,6 +411,38 @@
 
 		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
 		s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
+
+		if member.memberType != android.LicenseModuleSdkMemberType && !builder.isInternalMember(member.name) {
+			// More exceptions
+			// 1. Skip BCP and SCCP fragments
+			// 2. Skip non-sdk contents of BCP and SCCP fragments
+			//
+			// The non-sdk contents of BCP/SSCP fragments should only be used for dexpreopt and hiddenapi,
+			// and are not available to the rest of the build.
+			if android.InList(member.memberType,
+				[]android.SdkMemberType{
+					// bcp
+					java.BootclasspathFragmentSdkMemberType,
+					java.JavaBootLibsSdkMemberType,
+					// sscp
+					java.SystemServerClasspathFragmentSdkMemberType,
+					java.JavaSystemserverLibsSdkMemberType,
+				},
+			) {
+				continue
+			}
+
+			memberNames = append(memberNames, android.PrebuiltNameFromSource(member.name))
+		}
+	}
+
+	// create an apex_contributions_defaults for this module's sdk.
+	// this module type is supported in V and above.
+	if targetApiLevel.GreaterThan(android.ApiLevelUpsideDownCake) {
+		ac := newModule("apex_contributions_defaults")
+		ac.AddProperty("name", s.Name()+".contributions")
+		ac.AddProperty("contents", memberNames)
+		bpFile.AddModule(ac)
 	}
 
 	// Create a transformer that will transform a module by replacing any references
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 698aaf2..b9b68be 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -54,15 +54,13 @@
 }
 
 type syspropRustGenRule struct {
-	android.ModuleBase
+	*rust.BaseSourceProvider
 
-	properties syspropGenProperties
-
-	genSrcs android.Paths
+	properties rustLibraryProperties
 }
 
 var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil)
-var _ android.OutputFileProducer = (*syspropRustGenRule)(nil)
+var _ rust.SourceProvider = (*syspropRustGenRule)(nil)
 
 var (
 	syspropJava = pctx.AndroidStaticRule("syspropJava",
@@ -144,7 +142,7 @@
 
 // syspropRustGenRule module generates rust source files containing generated rust APIs.
 // It also depends on check api rule, so api check has to pass to use sysprop_library.
-func (g *syspropRustGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (g *syspropRustGenRule) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
 	var checkApiFileTimeStamp android.WritablePath
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
@@ -153,25 +151,47 @@
 		}
 	})
 
-	for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) {
-		syspropDir := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcrust")
-		outputDir := syspropDir.Join(ctx, "src")
-		libPath := syspropDir.Join(ctx, "src", "lib.rs")
+	outputDir := android.PathForModuleOut(ctx, "src")
+	libFile := outputDir.Join(ctx, "lib.rs")
+	g.BaseSourceProvider.OutputFiles = append(g.BaseSourceProvider.OutputFiles, libFile)
+	libFileLines := []string{"//! Autogenerated system property accessors."}
+
+	for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Sysprop_srcs) {
+		moduleName := syspropPathToRustModule(syspropFile)
+		moduleDir := outputDir.Join(ctx, moduleName)
+		modulePath := moduleDir.Join(ctx, "mod.rs")
 
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        syspropRust,
 			Description: "sysprop_rust " + syspropFile.Rel(),
-			Outputs:     android.WritablePaths{libPath},
+			Output:      modulePath,
 			Input:       syspropFile,
 			Implicit:    checkApiFileTimeStamp,
 			Args: map[string]string{
 				"scope":   g.properties.Scope,
-				"out_dir": outputDir.String(),
+				"out_dir": moduleDir.String(),
 			},
 		})
 
-		g.genSrcs = append(g.genSrcs, libPath)
+		g.BaseSourceProvider.OutputFiles = append(g.BaseSourceProvider.OutputFiles, modulePath)
+		libFileLines = append(libFileLines, fmt.Sprintf("pub mod %s;", moduleName))
 	}
+
+	libFileSource := strings.Join(libFileLines, "\n")
+	android.WriteFileRule(ctx, libFile, libFileSource)
+
+	return libFile
+}
+
+func (g *syspropRustGenRule) SourceProviderProps() []interface{} {
+	return append(g.BaseSourceProvider.SourceProviderProps(), &g.Properties)
+}
+
+// syspropPathToRustModule takes a path to a .sysprop file and returns the name to use for the
+// corresponding Rust module.
+func syspropPathToRustModule(syspropFilename android.Path) string {
+	filenameBase := strings.TrimSuffix(syspropFilename.Base(), ".sysprop")
+	return strings.ToLower(filenameBase)
 }
 
 func (g *syspropRustGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -180,15 +200,13 @@
 	ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api))
 }
 
-func (g *syspropRustGenRule) OutputFiles(_ string) (android.Paths, error) {
-	return g.genSrcs, nil
-}
-
 func syspropRustGenFactory() android.Module {
-	g := &syspropRustGenRule{}
-	g.AddProperties(&g.properties)
-	android.InitAndroidModule(g)
-	return g
+	g := &syspropRustGenRule{
+		BaseSourceProvider: rust.NewSourceProvider(),
+	}
+	sourceProvider := rust.NewSourceProviderModule(android.DeviceSupported, g, false, false)
+	sourceProvider.AddProperties(&g.properties)
+	return sourceProvider.Init()
 }
 
 type syspropLibrary struct {
@@ -308,10 +326,6 @@
 	return m.BaseModuleName() + "_java_gen_public"
 }
 
-func (m *syspropLibrary) rustGenModuleName() string {
-	return m.rustCrateName() + "_rust_gen"
-}
-
 func (m *syspropLibrary) rustGenStubName() string {
 	return "lib" + m.rustCrateName() + "_rust"
 }
@@ -528,6 +542,9 @@
 
 type rustLibraryProperties struct {
 	Name              *string
+	Sysprop_srcs      []string `android:"path"`
+	Scope             string
+	Check_api         *string
 	Srcs              []string
 	Installable       *bool
 	Crate_name        string
@@ -667,18 +684,15 @@
 	}
 
 	// Generate a Rust implementation library.
-	ctx.CreateModule(syspropRustGenFactory, &syspropGenProperties{
-		Srcs:      m.properties.Srcs,
-		Scope:     scope,
-		Name:      proptools.StringPtr(m.rustGenModuleName()),
-		Check_api: proptools.StringPtr(ctx.ModuleName()),
-	})
 	rustProps := rustLibraryProperties{
-		Name:        proptools.StringPtr(m.rustGenStubName()),
-		Srcs:        []string{":" + m.rustGenModuleName()},
-		Installable: proptools.BoolPtr(false),
-		Crate_name:  m.rustCrateName(),
+		Name:         proptools.StringPtr(m.rustGenStubName()),
+		Sysprop_srcs: m.properties.Srcs,
+		Scope:        scope,
+		Check_api:    proptools.StringPtr(ctx.ModuleName()),
+		Installable:  proptools.BoolPtr(false),
+		Crate_name:   m.rustCrateName(),
 		Rustlibs: []string{
+			"liblog_rust",
 			"librustutils",
 		},
 		Vendor_available:  m.properties.Vendor_available,
@@ -686,7 +700,7 @@
 		Apex_available:    m.ApexProperties.Apex_available,
 		Min_sdk_version:   proptools.StringPtr("29"),
 	}
-	ctx.CreateModule(rust.RustLibraryFactory, &rustProps)
+	ctx.CreateModule(syspropRustGenFactory, &rustProps)
 
 	// syspropLibraries will be used by property_contexts to check types.
 	// Record absolute paths of sysprop_library to prevent soong_namespace problem.
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 9dd696f..dfbbe7d 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -72,6 +72,15 @@
 			vendor_available: true,
 			min_sdk_version: "29",
 		}
+
+		rust_library {
+			name: "liblog_rust",
+			crate_name: "log",
+			srcs: ["log/src/lib.rs"],
+			product_available: true,
+			vendor_available: true,
+			min_sdk_version: "29",
+		}
 	`
 
 	mockFS := android.MockFS{
@@ -115,6 +124,7 @@
 		"com/android2/OdmProperties.sysprop":         nil,
 
 		"librustutils/lib.rs": nil,
+		"log/src/lib.rs":      nil,
 	}
 
 	result := android.GroupFixturePreparers(
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 2f25a8c..81c678d 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -94,7 +94,6 @@
 	"gcert":          Allowed,
 	"gcertstatus":    Allowed,
 	"gcloud":         Allowed,
-	"getopt":         Allowed,
 	"git":            Allowed,
 	"hexdump":        Allowed,
 	"jar":            Allowed,