Merge "Change enforceAppUpdatability to use ModuleProxy." into main
diff --git a/android/module.go b/android/module.go
index d703c19..7dda9ab 100644
--- a/android/module.go
+++ b/android/module.go
@@ -338,7 +338,6 @@
 		}
 		Android struct {
 			Compile_multilib *string
-			Enabled          *bool
 		}
 	}
 
diff --git a/android/neverallow.go b/android/neverallow.go
index e0af981..566d73c 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -245,6 +245,10 @@
 			Without("name", "librecovery_ui_ext").
 			With("install_in_root", "true").
 			NotModuleType("prebuilt_root").
+			NotModuleType("prebuilt_vendor").
+			NotModuleType("prebuilt_sbin").
+			NotModuleType("prebuilt_system").
+			NotModuleType("prebuilt_first_stage_ramdisk").
 			Because("install_in_root is only for init_first_stage or librecovery_ui_ext."),
 	}
 }
@@ -349,6 +353,9 @@
 			"prebuilt_optee",
 			"prebuilt_tvconfig",
 			"prebuilt_vendor",
+			"prebuilt_sbin",
+			"prebuilt_system",
+			"prebuilt_first_stage_ramdisk",
 		).
 		DefinedInBpFile().
 		Because("module type not allowed to be defined in bp file")
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 27c0340..282cd1d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -12149,34 +12149,32 @@
 			},
 			dependencyPath: []string{"myapex", "libjni", "libbar", "libplatform"},
 		},
-		// TODO: embedded JNI in apps should be checked too, but Soong currently just packages the transitive
-		//  JNI libraries even if they came from another apex.
-		//{
-		//	name:           "app jni library dependency in other apex",
-		//	bpModifier:     addToSharedLibs("libembeddedjni", "libotherapex#impl"),
-		//	dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libotherapex"},
-		//},
-		//{
-		//	name: "transitive app jni library dependency in other apex",
-		//	bpModifier: func(bp *bpmodify.Blueprint) {
-		//		addToSharedLibs("libembeddedjni", "libbar")(bp)
-		//		addToSharedLibs("libbar", "libotherapex#impl")(bp)
-		//	},
-		//	dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libotherapex"},
-		//},
-		//{
-		//	name:           "app jni library dependency in platform",
-		//	bpModifier:     addToSharedLibs("libembeddedjni", "libplatform#impl"),
-		//	dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libplatform"},
-		//},
-		//{
-		//	name: "transitive app jni library dependency in platform",
-		//	bpModifier: func(bp *bpmodify.Blueprint) {
-		//		addToSharedLibs("libembeddedjni", "libbar")(bp)
-		//		addToSharedLibs("libbar", "libplatform#impl")(bp)
-		//	},
-		//	dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libplatform"},
-		//},
+		{
+			name:           "app jni library dependency in other apex",
+			bpModifier:     addToSharedLibs("libembeddedjni", "libotherapex#impl"),
+			dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libotherapex"},
+		},
+		{
+			name: "transitive app jni library dependency in other apex",
+			bpModifier: func(bp *bpmodify.Blueprint) {
+				addToSharedLibs("libembeddedjni", "libbar")(bp)
+				addToSharedLibs("libbar", "libotherapex#impl")(bp)
+			},
+			dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libotherapex"},
+		},
+		{
+			name:           "app jni library dependency in platform",
+			bpModifier:     addToSharedLibs("libembeddedjni", "libplatform#impl"),
+			dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libplatform"},
+		},
+		{
+			name: "transitive app jni library dependency in platform",
+			bpModifier: func(bp *bpmodify.Blueprint) {
+				addToSharedLibs("libembeddedjni", "libbar")(bp)
+				addToSharedLibs("libbar", "libplatform#impl")(bp)
+			},
+			dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libplatform"},
+		},
 		{
 			name:           "binary dependency in other apex",
 			bpModifier:     addToSharedLibs("mybin", "libotherapex#impl"),
diff --git a/cc/cc.go b/cc/cc.go
index 65ab686..03f738f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3345,17 +3345,17 @@
 	return depPaths
 }
 
-func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
+func ShouldUseStubForApex(ctx android.ModuleContext, parent, dep android.Module) bool {
 	inVendorOrProduct := false
 	bootstrap := false
-	if linkable, ok := ctx.Module().(LinkableInterface); !ok {
-		panic(fmt.Errorf("Not a Linkable module: %q", ctx.ModuleName()))
+	if linkable, ok := parent.(LinkableInterface); !ok {
+		ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName())
 	} else {
 		inVendorOrProduct = linkable.InVendorOrProduct()
 		bootstrap = linkable.Bootstrap()
 	}
 
-	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	apexInfo, _ := android.OtherModuleProvider(ctx, parent, android.ApexInfoProvider)
 
 	useStubs := false
 
@@ -3402,7 +3402,7 @@
 
 	if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
 		// when to use (unspecified) stubs, use the latest one.
-		if ShouldUseStubForApex(ctx, dep) {
+		if ShouldUseStubForApex(ctx, ctx.Module(), dep) {
 			stubs := sharedLibraryStubsInfo.SharedStubLibraries
 			toUse := stubs[len(stubs)-1]
 			sharedLibraryInfo = toUse.SharedLibraryInfo
diff --git a/cc/linkable.go b/cc/linkable.go
index ef204eb..1a9a9ab 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -135,6 +135,10 @@
 	// IsNdk returns true if the library is in the configs known NDK list.
 	IsNdk(config android.Config) bool
 
+	// HasStubsVariants true if this module is a stub or has a sibling variant
+	// that is a stub.
+	HasStubsVariants() bool
+
 	// IsStubs returns true if the this is a stubs library.
 	IsStubs() bool
 
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index dd274ad..2bcbde1 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -82,6 +82,9 @@
 	ctx.RegisterModuleType("prebuilt_optee", PrebuiltOpteeFactory)
 	ctx.RegisterModuleType("prebuilt_tvconfig", PrebuiltTvConfigFactory)
 	ctx.RegisterModuleType("prebuilt_vendor", PrebuiltVendorFactory)
+	ctx.RegisterModuleType("prebuilt_sbin", PrebuiltSbinFactory)
+	ctx.RegisterModuleType("prebuilt_system", PrebuiltSystemFactory)
+	ctx.RegisterModuleType("prebuilt_first_stage_ramdisk", PrebuiltFirstStageRamdiskFactory)
 
 	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 
@@ -574,6 +577,7 @@
 	p.installDirBase = dirBase
 	p.AddProperties(&p.properties)
 	p.AddProperties(&p.subdirProperties)
+	p.AddProperties(&p.rootProperties)
 }
 
 func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -983,3 +987,33 @@
 	android.InitDefaultableModule(module)
 	return module
 }
+
+// prebuilt_sbin installs files in <partition>/sbin directory.
+func PrebuiltSbinFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "sbin")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
+// prebuilt_system installs files in <partition>/system directory.
+func PrebuiltSystemFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "system")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
+// prebuilt_first_stage_ramdisk installs files in <partition>/first_stage_ramdisk directory.
+func PrebuiltFirstStageRamdiskFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "first_stage_ramdisk")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index b5f7e48..fbc8089 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -677,11 +677,10 @@
 	switch fst {
 	case erofsType:
 		// Add erofs properties
-		if compressor := f.properties.Erofs.Compressor; compressor != nil {
-			addStr("erofs_default_compressor", proptools.String(compressor))
-		}
-		if compressHints := f.properties.Erofs.Compress_hints; compressHints != nil {
-			addPath("erofs_default_compress_hints", android.PathForModuleSrc(ctx, *compressHints))
+		addStr("erofs_default_compressor", proptools.StringDefault(f.properties.Erofs.Compressor, "lz4hc,9"))
+		if f.properties.Erofs.Compress_hints != nil {
+			src := android.PathForModuleSrc(ctx, *f.properties.Erofs.Compress_hints)
+			addPath("erofs_default_compress_hints", src)
 		}
 		if proptools.BoolDefault(f.properties.Erofs.Sparse, true) {
 			// https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2292;bpv=1;bpt=0;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index ec52f61..cd29dfd 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -69,6 +69,7 @@
 		avbpubkeyGenerated := createAvbpubkeyModule(ctx)
 		createFsGenState(ctx, generatedPrebuiltEtcModuleNames, avbpubkeyGenerated)
 		module.createAvbKeyFilegroups(ctx)
+		module.createMiscFilegroups(ctx)
 		module.createInternalModules(ctx)
 	})
 
@@ -506,6 +507,29 @@
 	}
 }
 
+// Creates filegroups for miscellaneous other files
+func (f *filesystemCreator) createMiscFilegroups(ctx android.LoadHookContext) {
+	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+	if partitionVars.BoardErofsCompressorHints != "" {
+		dir := filepath.Dir(partitionVars.BoardErofsCompressorHints)
+		base := filepath.Base(partitionVars.BoardErofsCompressorHints)
+		ctx.CreateModuleInDirectory(
+			android.FileGroupFactory,
+			dir,
+			&struct {
+				Name       *string
+				Srcs       []string
+				Visibility []string
+			}{
+				Name:       proptools.StringPtr("soong_generated_board_erofs_compress_hints_filegroup"),
+				Srcs:       []string{base},
+				Visibility: []string{"//visibility:public"},
+			},
+		)
+	}
+}
+
 // createPrebuiltKernelModules creates `prebuilt_kernel_modules`. These modules will be added to deps of the
 // autogenerated *_dlkm filsystem modules. Each _dlkm partition should have a single prebuilt_kernel_modules dependency.
 // This ensures that the depmod artifacts (modules.* installed in /lib/modules/) are generated with a complete view.
@@ -705,6 +729,15 @@
 		return nil, false
 	}
 
+	if *fsProps.Type == "erofs" {
+		if partitionVars.BoardErofsCompressor != "" {
+			fsProps.Erofs.Compressor = proptools.StringPtr(partitionVars.BoardErofsCompressor)
+		}
+		if partitionVars.BoardErofsCompressorHints != "" {
+			fsProps.Erofs.Compress_hints = proptools.StringPtr(":soong_generated_board_erofs_compress_hints_filegroup")
+		}
+	}
+
 	// Don't build this module on checkbuilds, the soong-built partitions are still in-progress
 	// and sometimes don't build.
 	fsProps.Unchecked_module = proptools.BoolPtr(true)
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index f217744..e028b1d 100644
--- a/fsgen/prebuilt_etc_modules_gen.go
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -36,6 +36,7 @@
 	system_ext map[string][]srcBaseFileInstallBaseFileTuple
 	product    map[string][]srcBaseFileInstallBaseFileTuple
 	vendor     map[string][]srcBaseFileInstallBaseFileTuple
+	recovery   map[string][]srcBaseFileInstallBaseFileTuple
 }
 
 func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
@@ -44,6 +45,7 @@
 		system_ext: map[string][]srcBaseFileInstallBaseFileTuple{},
 		product:    map[string][]srcBaseFileInstallBaseFileTuple{},
 		vendor:     map[string][]srcBaseFileInstallBaseFileTuple{},
+		recovery:   map[string][]srcBaseFileInstallBaseFileTuple{},
 	}
 }
 
@@ -73,6 +75,8 @@
 				srcMap = srcGroup.product
 			case "vendor":
 				srcMap = srcGroup.vendor
+			case "recovery":
+				srcMap = srcGroup.recovery
 			}
 			if srcMap != nil {
 				srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{
@@ -128,6 +132,7 @@
 	// System is intentionally added at the last to consider the scenarios where
 	// non-system partitions are installed as part of the system partition
 	partitionToInstallPathList := []partitionToInstallPath{
+		{name: "recovery", installPath: "recovery/root"},
 		{name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
 		{name: "product", installPath: ctx.DeviceConfig().ProductPath()},
 		{name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
@@ -155,6 +160,8 @@
 	Soc_specific        *bool
 	Product_specific    *bool
 	System_ext_specific *bool
+	Recovery            *bool
+	Ramdisk             *bool
 
 	Srcs []string
 	Dsts []string
@@ -174,43 +181,52 @@
 	Relative_install_path *string
 }
 
+// Split install_in_root to a separate struct as it is part of rootProperties instead of
+// properties
+type prebuiltInstallInRootProperties struct {
+	Install_in_root *bool
+}
+
 var (
 	etcInstallPathToFactoryList = map[string]android.ModuleFactory{
-		"":                etc.PrebuiltRootFactory,
-		"avb":             etc.PrebuiltAvbFactory,
-		"bin":             etc.PrebuiltBinaryFactory,
-		"bt_firmware":     etc.PrebuiltBtFirmwareFactory,
-		"cacerts":         etc.PrebuiltEtcCaCertsFactory,
-		"dsp":             etc.PrebuiltDSPFactory,
-		"etc":             etc.PrebuiltEtcFactory,
-		"etc/dsp":         etc.PrebuiltDSPFactory,
-		"etc/firmware":    etc.PrebuiltFirmwareFactory,
-		"firmware":        etc.PrebuiltFirmwareFactory,
-		"fonts":           etc.PrebuiltFontFactory,
-		"framework":       etc.PrebuiltFrameworkFactory,
-		"lib":             etc.PrebuiltRenderScriptBitcodeFactory,
-		"lib64":           etc.PrebuiltRenderScriptBitcodeFactory,
-		"lib/rfsa":        etc.PrebuiltRFSAFactory,
-		"media":           etc.PrebuiltMediaFactory,
-		"odm":             etc.PrebuiltOdmFactory,
-		"optee":           etc.PrebuiltOpteeFactory,
-		"overlay":         etc.PrebuiltOverlayFactory,
-		"priv-app":        etc.PrebuiltPrivAppFactory,
-		"res":             etc.PrebuiltResFactory,
-		"rfs":             etc.PrebuiltRfsFactory,
-		"tts":             etc.PrebuiltVoicepackFactory,
-		"tvconfig":        etc.PrebuiltTvConfigFactory,
-		"tvservice":       etc.PrebuiltTvServiceFactory,
-		"usr/share":       etc.PrebuiltUserShareFactory,
-		"usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory,
-		"usr/keylayout":   etc.PrebuiltUserKeyLayoutFactory,
-		"usr/keychars":    etc.PrebuiltUserKeyCharsFactory,
-		"usr/srec":        etc.PrebuiltUserSrecFactory,
-		"usr/idc":         etc.PrebuiltUserIdcFactory,
-		"vendor":          etc.PrebuiltVendorFactory,
-		"vendor_dlkm":     etc.PrebuiltVendorDlkmFactory,
-		"wallpaper":       etc.PrebuiltWallpaperFactory,
-		"wlc_upt":         etc.PrebuiltWlcUptFactory,
+		"":                    etc.PrebuiltRootFactory,
+		"avb":                 etc.PrebuiltAvbFactory,
+		"bin":                 etc.PrebuiltBinaryFactory,
+		"bt_firmware":         etc.PrebuiltBtFirmwareFactory,
+		"cacerts":             etc.PrebuiltEtcCaCertsFactory,
+		"dsp":                 etc.PrebuiltDSPFactory,
+		"etc":                 etc.PrebuiltEtcFactory,
+		"etc/dsp":             etc.PrebuiltDSPFactory,
+		"etc/firmware":        etc.PrebuiltFirmwareFactory,
+		"firmware":            etc.PrebuiltFirmwareFactory,
+		"first_stage_ramdisk": etc.PrebuiltFirstStageRamdiskFactory,
+		"fonts":               etc.PrebuiltFontFactory,
+		"framework":           etc.PrebuiltFrameworkFactory,
+		"lib":                 etc.PrebuiltRenderScriptBitcodeFactory,
+		"lib64":               etc.PrebuiltRenderScriptBitcodeFactory,
+		"lib/rfsa":            etc.PrebuiltRFSAFactory,
+		"media":               etc.PrebuiltMediaFactory,
+		"odm":                 etc.PrebuiltOdmFactory,
+		"optee":               etc.PrebuiltOpteeFactory,
+		"overlay":             etc.PrebuiltOverlayFactory,
+		"priv-app":            etc.PrebuiltPrivAppFactory,
+		"sbin":                etc.PrebuiltSbinFactory,
+		"system":              etc.PrebuiltSystemFactory,
+		"res":                 etc.PrebuiltResFactory,
+		"rfs":                 etc.PrebuiltRfsFactory,
+		"tts":                 etc.PrebuiltVoicepackFactory,
+		"tvconfig":            etc.PrebuiltTvConfigFactory,
+		"tvservice":           etc.PrebuiltTvServiceFactory,
+		"usr/share":           etc.PrebuiltUserShareFactory,
+		"usr/hyphen-data":     etc.PrebuiltUserHyphenDataFactory,
+		"usr/keylayout":       etc.PrebuiltUserKeyLayoutFactory,
+		"usr/keychars":        etc.PrebuiltUserKeyCharsFactory,
+		"usr/srec":            etc.PrebuiltUserSrecFactory,
+		"usr/idc":             etc.PrebuiltUserIdcFactory,
+		"vendor":              etc.PrebuiltVendorFactory,
+		"vendor_dlkm":         etc.PrebuiltVendorDlkmFactory,
+		"wallpaper":           etc.PrebuiltWallpaperFactory,
+		"wlc_upt":             etc.PrebuiltWlcUptFactory,
 	}
 )
 
@@ -243,7 +259,7 @@
 	return ret, maxLen
 }
 
-func prebuiltEtcModuleProps(moduleName, partition string) prebuiltModuleProperties {
+func prebuiltEtcModuleProps(ctx android.LoadHookContext, moduleName, partition, destDir string) prebuiltModuleProperties {
 	moduleProps := prebuiltModuleProperties{}
 	moduleProps.Name = proptools.StringPtr(moduleName)
 
@@ -255,6 +271,13 @@
 		moduleProps.Product_specific = proptools.BoolPtr(true)
 	case "vendor":
 		moduleProps.Soc_specific = proptools.BoolPtr(true)
+	case "recovery":
+		// To match the logic in modulePartition() in android/paths.go
+		if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && strings.HasPrefix(destDir, "first_stage_ramdisk") {
+			moduleProps.Ramdisk = proptools.BoolPtr(true)
+		} else {
+			moduleProps.Recovery = proptools.BoolPtr(true)
+		}
 	}
 
 	moduleProps.No_full_install = proptools.BoolPtr(true)
@@ -288,7 +311,7 @@
 		}
 
 		moduleName := generatedPrebuiltEtcModuleName(partition, srcDir, destDir, fileIndex)
-		moduleProps := prebuiltEtcModuleProps(moduleName, partition)
+		moduleProps := prebuiltEtcModuleProps(ctx, moduleName, partition, destDir)
 		modulePropsPtr := &moduleProps
 		propsList := []interface{}{modulePropsPtr}
 
@@ -302,6 +325,16 @@
 			installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
 		}
 
+		// Recovery partition-installed modules are installed to `recovery/root/system` by
+		// default (See modulePartition() in android/paths.go). If the destination file
+		// directory is not `recovery/root/system/...`, it should set install_in_root to true
+		// to prevent being installed in `recovery/root/system`.
+		if partition == "recovery" && !strings.HasPrefix(destDir, "system") {
+			propsList = append(propsList, &prebuiltInstallInRootProperties{
+				Install_in_root: proptools.BoolPtr(true),
+			})
+		}
+
 		// Set appropriate srcs, dsts, and releative_install_path based on
 		// the source and install file names
 		if allCopyFileNamesUnchanged {
@@ -347,6 +380,7 @@
 		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
 		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
 		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
+		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "recovery", srcDir, groupedSource.recovery)...)
 	}
 
 	return ret
diff --git a/java/aar.go b/java/aar.go
index 1e5c95a..e0e642e 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -588,16 +588,14 @@
 		}
 	}
 
+	for _, dir := range overlayDirs {
+		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files,
+			compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...)
+	}
+
 	var compiledRro, compiledRroOverlay android.Paths
 	if opts.rroDirs != nil {
 		compiledRro, compiledRroOverlay = a.compileResInDir(ctx, *opts.rroDirs, compileFlags, opts.aconfigTextFiles)
-	} else {
-		// RRO enforcement is done based on module name. Compile the overlayDirs only if rroDirs is nil.
-		// This ensures that the autogenerated RROs do not compile the overlay dirs twice.
-		for _, dir := range overlayDirs {
-			compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files,
-				compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...)
-		}
 	}
 
 	var splitPackages android.WritablePaths
diff --git a/java/androidmk.go b/java/androidmk.go
index 35024c1..2ad30b1 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -307,11 +307,15 @@
 			Disabled: true,
 		}}
 	}
+	var required []string
+	if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) {
+		required = []string{app.productCharacteristicsRROPackageName()}
+	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "APPS",
 		OutputFile: android.OptionalPathForPath(app.outputFile),
 		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
-		Required:   app.requiredModuleNames,
+		Required:   required,
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				// App module names can be overridden.
@@ -346,6 +350,31 @@
 					entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true)
 				}
 
+				filterRRO := func(filter overlayType) android.Paths {
+					var paths android.Paths
+					seen := make(map[android.Path]bool)
+					for _, d := range app.rroDirsDepSet.ToList() {
+						if d.overlayType == filter {
+							if seen[d.path] {
+								continue
+							}
+							seen[d.path] = true
+							paths = append(paths, d.path)
+						}
+					}
+					// Reverse the order, Soong stores rroDirs in aapt2 order (low to high priority), but Make
+					// expects it in LOCAL_RESOURCE_DIRS order (high to low priority).
+					return android.ReversePaths(paths)
+				}
+				deviceRRODirs := filterRRO(device)
+				if len(deviceRRODirs) > 0 {
+					entries.AddStrings("LOCAL_SOONG_DEVICE_RRO_DIRS", deviceRRODirs.Strings()...)
+				}
+				productRRODirs := filterRRO(product)
+				if len(productRRODirs) > 0 {
+					entries.AddStrings("LOCAL_SOONG_PRODUCT_RRO_DIRS", productRRODirs.Strings()...)
+				}
+
 				entries.SetBoolIfTrue("LOCAL_EXPORT_PACKAGE_RESOURCES", Bool(app.appProperties.Export_package_resources))
 
 				entries.SetPath("LOCAL_FULL_MANIFEST_FILE", app.manifestPath)
diff --git a/java/app.go b/java/app.go
index 34884d7..4dea7dc 100644
--- a/java/app.go
+++ b/java/app.go
@@ -223,8 +223,6 @@
 	javaApiUsedByOutputFile android.ModuleOutPath
 
 	privAppAllowlist android.OptionalPath
-
-	requiredModuleNames []string
 }
 
 func (a *AndroidApp) IsInstallable() bool {
@@ -423,24 +421,6 @@
 		TestHelperApp:   false,
 		EmbeddedJNILibs: embeddedJniLibs,
 	})
-
-	a.requiredModuleNames = a.getRequiredModuleNames(ctx)
-}
-
-func (a *AndroidApp) getRequiredModuleNames(ctx android.ModuleContext) []string {
-	var required []string
-	if proptools.Bool(a.appProperties.Generate_product_characteristics_rro) {
-		required = []string{a.productCharacteristicsRROPackageName()}
-	}
-	// Install the vendor overlay variant if this app is installed.
-	if len(filterRRO(a.rroDirsDepSet, device)) > 0 {
-		required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "vendor"))
-	}
-	// Install the product overlay variant if this app is installed.
-	if len(filterRRO(a.rroDirsDepSet, product)) > 0 {
-		required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "product"))
-	}
-	return required
 }
 
 func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -1102,7 +1082,18 @@
 			app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
 	}
 	jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps,
-		checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() })
+		checkNativeSdkVersion, func(parent, child android.Module) bool {
+			apkInApex := ctx.Module().(android.ApexModule).NotInPlatform()
+			childLinkable, _ := child.(cc.LinkableInterface)
+			parentLinkable, _ := parent.(cc.LinkableInterface)
+			useStubsOfDep := childLinkable.IsStubs()
+			if apkInApex && parentLinkable != nil {
+				// APK-in-APEX
+				// If the parent is a linkable interface, use stubs if the dependency edge crosses an apex boundary.
+				useStubsOfDep = useStubsOfDep || (childLinkable.HasStubsVariants() && cc.ShouldUseStubForApex(ctx, parent, child))
+			}
+			return !childLinkable.IsNdk(ctx.Config()) && !useStubsOfDep
+		})
 
 	var certificates []Certificate
 
@@ -1137,7 +1128,7 @@
 func collectJniDeps(ctx android.ModuleContext,
 	shouldCollectRecursiveNativeDeps bool,
 	checkNativeSdkVersion bool,
-	filter func(cc.LinkableInterface) bool) ([]jniLib, android.Paths) {
+	filter func(parent, child android.Module) bool) ([]jniLib, android.Paths) {
 	var jniLibs []jniLib
 	var prebuiltJniPackages android.Paths
 	seenModulePaths := make(map[string]bool)
@@ -1148,7 +1139,7 @@
 
 		if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
 			if dep, ok := module.(cc.LinkableInterface); ok {
-				if filter != nil && !filter(dep) {
+				if filter != nil && !filter(parent, module) {
 					return false
 				}
 
@@ -1397,11 +1388,6 @@
 			}
 		}
 		ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties)
-
-	})
-
-	module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
-		createInternalRuntimeOverlays(ctx, module.ModuleBase)
 	})
 
 	return module
@@ -1411,68 +1397,6 @@
 	return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().DeviceProduct(), partition)
 }
 
-type createModuleContext interface {
-	android.EarlyModuleContext
-	CreateModule(android.ModuleFactory, ...interface{}) android.Module
-}
-
-func createInternalRuntimeOverlays(ctx createModuleContext, a android.ModuleBase) {
-	if !ctx.Config().HasDeviceProduct() {
-		return
-	}
-	// vendor
-	vendorOverlayProps := struct {
-		Name                *string
-		Base                *string
-		Vendor              *bool
-		Product_specific    *bool
-		System_ext_specific *bool
-		Manifest            *string
-		Sdk_version         *string
-		Compile_multilib    *string
-		Enabled             proptools.Configurable[bool]
-	}{
-		Name:                proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "vendor")),
-		Base:                proptools.StringPtr(a.Name()),
-		Vendor:              proptools.BoolPtr(true),
-		Product_specific:    proptools.BoolPtr(false),
-		System_ext_specific: proptools.BoolPtr(false),
-		Manifest:            proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"),
-		Sdk_version:         proptools.StringPtr("current"),
-		Compile_multilib:    proptools.StringPtr("first"),
-		Enabled:             a.EnabledProperty().Clone(),
-	}
-	ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &vendorOverlayProps)
-
-	// product
-	productOverlayProps := struct {
-		Name                *string
-		Base                *string
-		Vendor              *bool
-		Proprietary         *bool
-		Soc_specific        *bool
-		Product_specific    *bool
-		System_ext_specific *bool
-		Manifest            *string
-		Sdk_version         *string
-		Compile_multilib    *string
-		Enabled             proptools.Configurable[bool]
-	}{
-		Name:                proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "product")),
-		Base:                proptools.StringPtr(a.Name()),
-		Vendor:              proptools.BoolPtr(false),
-		Proprietary:         proptools.BoolPtr(false),
-		Soc_specific:        proptools.BoolPtr(false),
-		Product_specific:    proptools.BoolPtr(true),
-		System_ext_specific: proptools.BoolPtr(false),
-		Manifest:            proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"),
-		Sdk_version:         proptools.StringPtr("current"),
-		Compile_multilib:    proptools.StringPtr("first"),
-		Enabled:             a.EnabledProperty().Clone(),
-	}
-	ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &productOverlayProps)
-}
-
 // A dictionary of values to be overridden in the manifest.
 type Manifest_values struct {
 	// Overrides the value of package_name in the manifest
@@ -1783,10 +1707,6 @@
 
 	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	android.InitOverrideModule(m)
-	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
-		createInternalRuntimeOverlays(ctx, m.ModuleBase)
-	})
-
 	return m
 }
 
diff --git a/java/app_test.go b/java/app_test.go
index 61b718d..3d83ea1 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -4727,74 +4727,3 @@
 		"out/soong/.intermediates/foo/android_common/aapt2/res/values_strings.(test.package.flag1).arsc.flat",
 	)
 }
-
-func TestAutogeneratedStaticRro(t *testing.T) {
-	t.Parallel()
-	bp := `
-android_app {
-	name: "foo",
-	srcs: ["foo.java"],
-	platform_apis: true,
-}
-override_android_app {
-	name: "override_foo",
-	base: "foo",
-}
-`
-	testCases := []struct {
-		desc               string
-		preparer           android.FixturePreparer
-		overlayApkExpected bool
-	}{
-		{
-			desc:               "No DEVICE_PACKAGE_OVERLAYS, no overlay .apk file",
-			overlayApkExpected: false,
-		},
-		{
-			desc:               "DEVICE_PACKAGE_OVERLAYS exists, but the directory is empty",
-			overlayApkExpected: false,
-			preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.DeviceResourceOverlays = []string{"device/company/test_product"}
-			}),
-		},
-		{
-			desc:               "DEVICE_PACKAGE_OVERLAYS exists, directory is non-empty, but does not contain a matching resource dir",
-			overlayApkExpected: false,
-			preparer: android.GroupFixturePreparers(
-				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-					variables.DeviceResourceOverlays = []string{"device/company/test_product"}
-				}),
-				android.MockFS{
-					"res/foo.xml": nil,
-					"device/company/test_product/different_res/foo.xml": nil, // different dir
-				}.AddToFixture(),
-			),
-		},
-		{
-			desc:               "DEVICE_PACKAGE_OVERLAYS and the directory contain a matching resource dir",
-			overlayApkExpected: true,
-			preparer: android.GroupFixturePreparers(
-				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-					variables.DeviceResourceOverlays = []string{"device/company/test_product"}
-				}),
-				android.MockFS{
-					"res/foo.xml": nil,
-					"device/company/test_product/res/foo.xml": nil,
-				}.AddToFixture(),
-			),
-		},
-	}
-	for _, tc := range testCases {
-		result := android.GroupFixturePreparers(
-			PrepareForTestWithJavaDefaultModules,
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.EnforceRROTargets = []string{"*"}
-			}),
-			android.OptionalFixturePreparer(tc.preparer),
-		).RunTestWithBp(t, bp)
-		vendorOverlayApk := result.ModuleForTests("foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("foo__test_product__auto_generated_rro_vendor.apk")
-		android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, vendorOverlayApk.Rule != nil)
-		overrideVendorOverlayApk := result.ModuleForTests("override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("override_foo__test_product__auto_generated_rro_vendor.apk")
-		android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.Rule != nil)
-	}
-}
diff --git a/java/rro_test.go b/java/rro_test.go
index 4d58bb4..4d79130 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -255,6 +255,103 @@
 	}
 }
 
+func TestEnforceRRO_propagatesToDependencies(t *testing.T) {
+	testCases := []struct {
+		name              string
+		enforceRROTargets []string
+		rroDirs           map[string][]string
+	}{
+		{
+			name:              "no RRO",
+			enforceRROTargets: nil,
+			rroDirs: map[string][]string{
+				"foo": nil,
+				"bar": nil,
+			},
+		},
+		{
+			name:              "enforce RRO on all",
+			enforceRROTargets: []string{"*"},
+			rroDirs: map[string][]string{
+				"foo": {"product/vendor/blah/overlay/lib2/res"},
+				"bar": {"product/vendor/blah/overlay/lib2/res"},
+			},
+		},
+		{
+			name:              "enforce RRO on foo",
+			enforceRROTargets: []string{"foo"},
+			rroDirs: map[string][]string{
+				"foo": {"product/vendor/blah/overlay/lib2/res"},
+				"bar": nil,
+			},
+		},
+	}
+
+	productResourceOverlays := []string{
+		"product/vendor/blah/overlay",
+	}
+
+	fs := android.MockFS{
+		"lib2/res/values/strings.xml":                             nil,
+		"product/vendor/blah/overlay/lib2/res/values/strings.xml": nil,
+	}
+
+	bp := `
+			android_app {
+				name: "foo",
+				sdk_version: "current",
+				resource_dirs: [],
+				static_libs: ["lib"],
+			}
+
+			android_app {
+				name: "bar",
+				sdk_version: "current",
+				resource_dirs: [],
+				static_libs: ["lib"],
+			}
+
+			android_library {
+				name: "lib",
+				sdk_version: "current",
+				resource_dirs: [],
+				static_libs: ["lib2"],
+			}
+
+			android_library {
+				name: "lib2",
+				sdk_version: "current",
+				resource_dirs: ["lib2/res"],
+			}
+		`
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				fs.AddToFixture(),
+				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+					variables.ProductResourceOverlays = productResourceOverlays
+					if testCase.enforceRROTargets != nil {
+						variables.EnforceRROTargets = testCase.enforceRROTargets
+					}
+				}),
+			).RunTestWithBp(t, bp)
+
+			modules := []string{"foo", "bar"}
+			for _, moduleName := range modules {
+				module := result.ModuleForTests(moduleName, "android_common")
+				mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
+				actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"]
+				if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) {
+					t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q",
+						moduleName, testCase.rroDirs[moduleName], actualRRODirs)
+				}
+			}
+		})
+	}
+}
+
 func TestRuntimeResourceOverlayPartition(t *testing.T) {
 	bp := `
 		runtime_resource_overlay {
diff --git a/rust/rust.go b/rust/rust.go
index 48f946e..eeb228c 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -722,6 +722,10 @@
 	return false
 }
 
+func (mod *Module) HasStubsVariants() bool {
+	return false
+}
+
 func (mod *Module) IsStubs() bool {
 	return false
 }