Merge "Change depVisitor to use providers instead of type-asserting to interfaces directly, the next step is to change it to use ModuleProxy once IsDepInSameApex is ready." into main
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 4b90083..cdee96f 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -88,6 +88,11 @@
 	// This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead.
 	otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
 
+	// OtherModuleHasProvider returns true if the module has the given provider set. This
+	// can avoid copying the provider if the caller only cares about the existence of
+	// the provider.
+	OtherModuleHasProvider(m blueprint.Module, provider blueprint.AnyProviderKey) bool
+
 	// OtherModuleIsAutoGenerated returns true if the module is auto generated by another module
 	// instead of being defined in Android.bp file.
 	OtherModuleIsAutoGenerated(m blueprint.Module) bool
@@ -297,6 +302,10 @@
 	return b.bp.OtherModuleProvider(getWrappedModule(m), provider)
 }
 
+func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.AnyProviderKey) bool {
+	return b.bp.OtherModuleHasProvider(getWrappedModule(m), provider)
+}
+
 func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool {
 	return b.bp.OtherModuleIsAutoGenerated(m)
 }
diff --git a/android/module.go b/android/module.go
index 0ffb6cb..c4a8377 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1908,12 +1908,17 @@
 	// is used to avoid adding install or packaging dependencies into libraries provided
 	// by apexes.
 	UninstallableApexPlatformVariant bool
-	HideFromMake                     bool
-	SkipInstall                      bool
-	IsStubsModule                    bool
-	Host                             bool
 	MinSdkVersionSupported           ApiLevel
 	ModuleWithMinSdkVersionCheck     bool
+	// Tests if this module can be installed to APEX as a file. For example, this would return
+	// true for shared libs while return false for static libs because static libs are not
+	// installable module (but it can still be mutated for APEX)
+	IsInstallableToApex bool
+	HideFromMake        bool
+	SkipInstall         bool
+	IsStubsModule       bool
+	Host                bool
+	IsApexModule        bool
 }
 
 type ApiLevelOrPlatform struct {
@@ -2252,7 +2257,6 @@
 		ReplacedByPrebuilt:               m.commonProperties.ReplacedByPrebuilt,
 		Target:                           m.commonProperties.CompileTarget,
 		SkipAndroidMkProcessing:          shouldSkipAndroidMkProcessing(ctx, m),
-		BaseModuleName:                   m.BaseModuleName(),
 		UninstallableApexPlatformVariant: m.commonProperties.UninstallableApexPlatformVariant,
 		HideFromMake:                     m.commonProperties.HideFromMake,
 		SkipInstall:                      m.commonProperties.SkipInstall,
@@ -2295,6 +2299,8 @@
 		commonData.NotAvailableForPlatform = am.NotAvailableForPlatform()
 		commonData.NotInPlatform = am.NotInPlatform()
 		commonData.MinSdkVersionSupported = am.MinSdkVersionSupported(ctx)
+		commonData.IsInstallableToApex = am.IsInstallableToApex()
+		commonData.IsApexModule = true
 	}
 
 	if _, ok := m.module.(ModuleWithMinSdkVersionCheck); ok {
@@ -2304,6 +2310,9 @@
 	if st, ok := m.module.(StubsAvailableModule); ok {
 		commonData.IsStubsModule = st.IsStubsModule()
 	}
+	if mm, ok := m.module.(interface{ BaseModuleName() string }); ok {
+		commonData.BaseModuleName = mm.BaseModuleName()
+	}
 	SetProvider(ctx, CommonModuleInfoKey, commonData)
 	if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil {
 		SetProvider(ctx, PrebuiltModuleInfoProvider, PrebuiltModuleInfo{
diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go
index 49cf999..4a29fee 100644
--- a/android/vintf_fragment.go
+++ b/android/vintf_fragment.go
@@ -14,6 +14,8 @@
 
 package android
 
+import "github.com/google/blueprint"
+
 type vintfFragmentProperties struct {
 	// Vintf fragment XML file.
 	Src string `android:"path"`
@@ -37,6 +39,12 @@
 	ctx.RegisterModuleType("vintf_fragment", vintfLibraryFactory)
 }
 
+type VintfFragmentInfo struct {
+	OutputFile Path
+}
+
+var VintfFragmentInfoProvider = blueprint.NewProvider[VintfFragmentInfo]()
+
 // vintf_fragment module processes vintf fragment file and installs under etc/vintf/manifest.
 // Vintf fragment files formerly listed in vintf_fragment property would be transformed into
 // this module type.
@@ -68,6 +76,10 @@
 	m.outputFilePath = processedVintfFragment
 
 	ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment)
+
+	SetProvider(ctx, VintfFragmentInfoProvider, VintfFragmentInfo{
+		OutputFile: m.OutputFile(),
+	})
 }
 
 func (m *VintfFragmentModule) OutputFile() Path {
diff --git a/apex/apex.go b/apex/apex.go
index 4d0e3f1..4b510f8 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -624,7 +624,8 @@
 }
 
 // TODO(jiyong): shorten the arglist using an option struct
-func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile {
+func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string,
+	installDir string, class apexFileClass, module android.Module) apexFile {
 	ret := apexFile{
 		builtFile:           builtFile,
 		installDir:          installDir,
@@ -1375,24 +1376,29 @@
 	}
 }
 
+func setDirInApexForNativeBridge(commonInfo *android.CommonModuleInfo, dir *string) {
+	if commonInfo.Target.NativeBridge == android.NativeBridgeEnabled {
+		*dir = filepath.Join(*dir, commonInfo.Target.NativeBridgeRelativePath)
+	}
+}
+
 // apexFileFor<Type> functions below create an apexFile struct for a given Soong module. The
 // returned apexFile saves information about the Soong module that will be used for creating the
 // build rules.
-func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod cc.VersionedLinkableInterface, handleSpecialLibs bool) apexFile {
+func apexFileForNativeLibrary(ctx android.BaseModuleContext, module android.Module,
+	commonInfo *android.CommonModuleInfo, ccMod *cc.LinkableInfo, handleSpecialLibs bool) apexFile {
 	// Decide the APEX-local directory by the multilib of the library In the future, we may
 	// query this to the module.
 	// TODO(jiyong): use the new PackagingSpec
 	var dirInApex string
-	switch ccMod.Multilib() {
+	switch ccMod.Multilib {
 	case "lib32":
 		dirInApex = "lib"
 	case "lib64":
 		dirInApex = "lib64"
 	}
-	if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
-		dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
-	}
-	if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), ctx.Config()) {
+	setDirInApexForNativeBridge(commonInfo, &dirInApex)
+	if handleSpecialLibs && cc.InstallToBootstrap(commonInfo.BaseModuleName, ctx.Config()) {
 		// Special case for Bionic libs and other libs installed with them. This is to
 		// prevent those libs from being included in the search path
 		// /apex/com.android.runtime/${LIB}. This exclusion is required because those libs
@@ -1407,66 +1413,68 @@
 	// This needs to go after the runtime APEX handling because otherwise we would get
 	// weird paths like lib64/rel_install_path/bionic rather than
 	// lib64/bionic/rel_install_path.
-	dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
+	dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath)
 
-	fileToCopy := android.OutputFileForModule(ctx, ccMod, "")
-	androidMkModuleName := ccMod.BaseModuleName() + ccMod.SubName()
-	return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod)
+	fileToCopy := android.OutputFileForModule(ctx, module, "")
+	androidMkModuleName := commonInfo.BaseModuleName + ccMod.SubName
+	return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, module)
 }
 
-func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFile {
+func apexFileForExecutable(ctx android.BaseModuleContext, module android.Module,
+	commonInfo *android.CommonModuleInfo, ccInfo *cc.CcInfo) apexFile {
+	linkableInfo := android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoProvider)
 	dirInApex := "bin"
-	if cc.Target().NativeBridge == android.NativeBridgeEnabled {
-		dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
-	}
-	dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
-	fileToCopy := android.OutputFileForModule(ctx, cc, "")
-	androidMkModuleName := cc.BaseModuleName() + cc.Properties.SubName
-	af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, cc)
-	af.symlinks = cc.Symlinks()
-	af.dataPaths = cc.DataPaths()
+	setDirInApexForNativeBridge(commonInfo, &dirInApex)
+	dirInApex = filepath.Join(dirInApex, linkableInfo.RelativeInstallPath)
+	fileToCopy := android.OutputFileForModule(ctx, module, "")
+	androidMkModuleName := commonInfo.BaseModuleName + linkableInfo.SubName
+	af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, module)
+	af.symlinks = linkableInfo.Symlinks
+	af.dataPaths = ccInfo.DataPaths
 	return af
 }
 
-func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module) apexFile {
+func apexFileForRustExecutable(ctx android.BaseModuleContext, module android.Module,
+	commonInfo *android.CommonModuleInfo) apexFile {
+	linkableInfo := android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoProvider)
 	dirInApex := "bin"
-	if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
-		dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
-	}
-	dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
-	fileToCopy := android.OutputFileForModule(ctx, rustm, "")
-	androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
-	af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm)
+	setDirInApexForNativeBridge(commonInfo, &dirInApex)
+	dirInApex = filepath.Join(dirInApex, linkableInfo.RelativeInstallPath)
+	fileToCopy := android.OutputFileForModule(ctx, module, "")
+	androidMkModuleName := commonInfo.BaseModuleName + linkableInfo.SubName
+	af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, module)
 	return af
 }
 
-func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
-	dirInApex := filepath.Join("bin", sh.SubDir())
-	if sh.Target().NativeBridge == android.NativeBridgeEnabled {
-		dirInApex = filepath.Join(dirInApex, sh.Target().NativeBridgeRelativePath)
-	}
-	fileToCopy := sh.OutputFile()
-	af := newApexFile(ctx, fileToCopy, sh.BaseModuleName(), dirInApex, shBinary, sh)
-	af.symlinks = sh.Symlinks()
+func apexFileForShBinary(ctx android.BaseModuleContext, module android.Module,
+	commonInfo *android.CommonModuleInfo, sh *sh.ShBinaryInfo) apexFile {
+	dirInApex := filepath.Join("bin", sh.SubDir)
+	setDirInApexForNativeBridge(commonInfo, &dirInApex)
+	fileToCopy := sh.OutputFile
+	af := newApexFile(ctx, fileToCopy, commonInfo.BaseModuleName, dirInApex, shBinary, module)
+	af.symlinks = sh.Symlinks
 	return af
 }
 
-func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, outputFile android.Path) apexFile {
-	dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
+func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, module android.Module,
+	prebuilt *prebuilt_etc.PrebuiltEtcInfo, outputFile android.Path) apexFile {
+	dirInApex := filepath.Join(prebuilt.BaseDir, prebuilt.SubDir)
 	makeModuleName := strings.ReplaceAll(filepath.Join(dirInApex, outputFile.Base()), "/", "_")
-	return newApexFile(ctx, outputFile, makeModuleName, dirInApex, etc, prebuilt)
+	return newApexFile(ctx, outputFile, makeModuleName, dirInApex, etc, module)
 }
 
-func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
-	dirInApex := filepath.Join("etc", config.SubDir())
-	fileToCopy := config.CompatConfig()
-	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, config)
+func apexFileForCompatConfig(ctx android.BaseModuleContext, module android.Module,
+	config *java.PlatformCompatConfigInfo, depName string) apexFile {
+	dirInApex := filepath.Join("etc", config.SubDir)
+	fileToCopy := config.CompatConfig
+	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, module)
 }
 
-func apexFileForVintfFragment(ctx android.BaseModuleContext, vintfFragment *android.VintfFragmentModule) apexFile {
+func apexFileForVintfFragment(ctx android.BaseModuleContext, module android.Module,
+	commonInfo *android.CommonModuleInfo, vf *android.VintfFragmentInfo) apexFile {
 	dirInApex := filepath.Join("etc", "vintf")
 
-	return newApexFile(ctx, vintfFragment.OutputFile(), vintfFragment.BaseModuleName(), dirInApex, etc, vintfFragment)
+	return newApexFile(ctx, vf.OutputFile, commonInfo.BaseModuleName, dirInApex, etc, module)
 }
 
 // javaModule is an interface to handle all Java modules (java_library, dex_import, etc) in the same
@@ -1486,60 +1494,42 @@
 var _ javaModule = (*java.SdkLibraryImport)(nil)
 
 // apexFileForJavaModule creates an apexFile for a java module's dex implementation jar.
-func apexFileForJavaModule(ctx android.ModuleContext, module javaModule) apexFile {
-	return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath(ctx).PathOrNil())
+func apexFileForJavaModule(ctx android.ModuleContext, module android.Module, javaInfo *java.JavaInfo) apexFile {
+	return apexFileForJavaModuleWithFile(ctx, module, javaInfo, javaInfo.DexJarBuildPath.PathOrNil())
 }
 
 // apexFileForJavaModuleWithFile creates an apexFile for a java module with the supplied file.
-func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module javaModule, dexImplementationJar android.Path) apexFile {
+func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module android.Module,
+	javaInfo *java.JavaInfo, dexImplementationJar android.Path) apexFile {
 	dirInApex := "javalib"
-	af := newApexFile(ctx, dexImplementationJar, module.BaseModuleName(), dirInApex, javaSharedLib, module)
-	af.jacocoReportClassesFile = module.JacocoReportClassesFile()
+	commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey)
+	af := newApexFile(ctx, dexImplementationJar, commonInfo.BaseModuleName, dirInApex, javaSharedLib, module)
+	af.jacocoReportClassesFile = javaInfo.JacocoReportClassesFile
 	if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok {
 		af.lintInfo = lintInfo
 	}
-	af.customStem = module.Stem() + ".jar"
+	af.customStem = javaInfo.Stem + ".jar"
 	// Collect any system server dex jars and dexpreopt artifacts for installation alongside the apex.
 	// TODO: b/338641779 - Remove special casing of sdkLibrary once bcpf and sscpf depends
 	// on the implementation library
-	if sdkLib, ok := module.(*java.SdkLibrary); ok {
-		af.systemServerDexpreoptInstalls = append(af.systemServerDexpreoptInstalls, sdkLib.ApexSystemServerDexpreoptInstalls()...)
-		af.systemServerDexJars = append(af.systemServerDexJars, sdkLib.ApexSystemServerDexJars()...)
-	} else if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
-		af.systemServerDexpreoptInstalls = append(af.systemServerDexpreoptInstalls, dexpreopter.ApexSystemServerDexpreoptInstalls()...)
-		af.systemServerDexJars = append(af.systemServerDexJars, dexpreopter.ApexSystemServerDexJars()...)
+	if javaInfo.DexpreopterInfo != nil {
+		af.systemServerDexpreoptInstalls = append(af.systemServerDexpreoptInstalls, javaInfo.DexpreopterInfo.ApexSystemServerDexpreoptInstalls...)
+		af.systemServerDexJars = append(af.systemServerDexJars, javaInfo.DexpreopterInfo.ApexSystemServerDexJars...)
 	}
 	return af
 }
 
-func apexFileForJavaModuleProfile(ctx android.BaseModuleContext, module javaModule) *apexFile {
-	if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
-		if profilePathOnHost := dexpreopter.OutputProfilePathOnHost(); profilePathOnHost != nil {
-			dirInApex := "javalib"
-			af := newApexFile(ctx, profilePathOnHost, module.BaseModuleName()+"-profile", dirInApex, etc, nil)
-			af.customStem = module.Stem() + ".jar.prof"
-			return &af
-		}
+func apexFileForJavaModuleProfile(ctx android.BaseModuleContext, commonInfo *android.CommonModuleInfo,
+	javaInfo *java.JavaInfo) *apexFile {
+	if profilePathOnHost := javaInfo.DexpreopterInfo.OutputProfilePathOnHost; profilePathOnHost != nil {
+		dirInApex := "javalib"
+		af := newApexFile(ctx, profilePathOnHost, commonInfo.BaseModuleName+"-profile", dirInApex, etc, nil)
+		af.customStem = javaInfo.Stem + ".jar.prof"
+		return &af
 	}
 	return nil
 }
 
-// androidApp is an interface to handle all app modules (android_app, android_app_import, etc.) in
-// the same way.
-type androidApp interface {
-	android.Module
-	Privileged() bool
-	InstallApkName() string
-	OutputFile() android.Path
-	JacocoReportClassesFile() android.Path
-	Certificate() java.Certificate
-	BaseModuleName() string
-	PrivAppAllowlist() android.OptionalPath
-}
-
-var _ androidApp = (*java.AndroidApp)(nil)
-var _ androidApp = (*java.AndroidAppImport)(nil)
-
 func sanitizedBuildIdForPath(ctx android.BaseModuleContext) string {
 	buildId := ctx.Config().BuildId()
 
@@ -1555,36 +1545,35 @@
 	return buildId
 }
 
-func apexFilesForAndroidApp(ctx android.BaseModuleContext, aapp androidApp) []apexFile {
+func apexFilesForAndroidApp(ctx android.BaseModuleContext, module android.Module,
+	commonInfo *android.CommonModuleInfo, aapp *java.AppInfo) []apexFile {
 	appDir := "app"
-	if aapp.Privileged() {
+	if aapp.Privileged {
 		appDir = "priv-app"
 	}
 
 	// TODO(b/224589412, b/226559955): Ensure that the subdirname is suffixed
 	// so that PackageManager correctly invalidates the existing installed apk
 	// in favour of the new APK-in-APEX.  See bugs for more information.
-	dirInApex := filepath.Join(appDir, aapp.InstallApkName()+"@"+sanitizedBuildIdForPath(ctx))
-	fileToCopy := aapp.OutputFile()
+	dirInApex := filepath.Join(appDir, aapp.InstallApkName+"@"+sanitizedBuildIdForPath(ctx))
+	fileToCopy := aapp.OutputFile
 
-	af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
-	af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
-	if lintInfo, ok := android.OtherModuleProvider(ctx, aapp, java.LintProvider); ok {
+	af := newApexFile(ctx, fileToCopy, commonInfo.BaseModuleName, dirInApex, app, module)
+	af.jacocoReportClassesFile = aapp.JacocoReportClassesFile
+	if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok {
 		af.lintInfo = lintInfo
 	}
-	af.certificate = aapp.Certificate()
+	af.certificate = aapp.Certificate
 
-	if app, ok := aapp.(interface {
-		OverriddenManifestPackageName() string
-	}); ok {
-		af.overriddenPackageName = app.OverriddenManifestPackageName()
+	if aapp.OverriddenManifestPackageName != nil {
+		af.overriddenPackageName = *aapp.OverriddenManifestPackageName
 	}
 
 	apexFiles := []apexFile{}
 
-	if allowlist := aapp.PrivAppAllowlist(); allowlist.Valid() {
+	if allowlist := aapp.PrivAppAllowlist; allowlist.Valid() {
 		dirInApex := filepath.Join("etc", "permissions")
-		privAppAllowlist := newApexFile(ctx, allowlist.Path(), aapp.BaseModuleName()+"_privapp", dirInApex, etc, aapp)
+		privAppAllowlist := newApexFile(ctx, allowlist.Path(), commonInfo.BaseModuleName+"_privapp", dirInApex, etc, module)
 		apexFiles = append(apexFiles, privAppAllowlist)
 	}
 
@@ -1593,29 +1582,24 @@
 	return apexFiles
 }
 
-func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, rro java.RuntimeResourceOverlayModule) apexFile {
+func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, module android.Module, rro java.RuntimeResourceOverlayInfo) apexFile {
 	rroDir := "overlay"
-	dirInApex := filepath.Join(rroDir, rro.Theme())
-	fileToCopy := rro.OutputFile()
-	af := newApexFile(ctx, fileToCopy, rro.Name(), dirInApex, app, rro)
-	af.certificate = rro.Certificate()
+	dirInApex := filepath.Join(rroDir, rro.Theme)
+	fileToCopy := rro.OutputFile
+	af := newApexFile(ctx, fileToCopy, module.Name(), dirInApex, app, module)
+	af.certificate = rro.Certificate
 
-	if a, ok := rro.(interface {
-		OverriddenManifestPackageName() string
-	}); ok {
-		af.overriddenPackageName = a.OverriddenManifestPackageName()
-	}
 	return af
 }
 
-func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, apex_sub_dir string, bpfProgram bpf.BpfModule) apexFile {
+func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, apex_sub_dir string, bpfProgram android.Module) apexFile {
 	dirInApex := filepath.Join("etc", "bpf", apex_sub_dir)
 	return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram)
 }
 
-func apexFileForFilesystem(ctx android.BaseModuleContext, buildFile android.Path, fs filesystem.Filesystem) apexFile {
+func apexFileForFilesystem(ctx android.BaseModuleContext, buildFile android.Path, module android.Module) apexFile {
 	dirInApex := filepath.Join("etc", "fs")
-	return newApexFile(ctx, buildFile, buildFile.Base(), dirInApex, etc, fs)
+	return newApexFile(ctx, buildFile, buildFile.Base(), dirInApex, etc, module)
 }
 
 // WalkPayloadDeps visits dependencies that contributes to the payload of this APEX. For each of the
@@ -1864,11 +1848,12 @@
 	if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
 		return false
 	}
-	if !child.Enabled(ctx) {
+	commonInfo := android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey)
+	if !commonInfo.Enabled {
 		return false
 	}
 	depName := ctx.OtherModuleName(child)
-	if _, isDirectDep := parent.(*apexBundle); isDirectDep {
+	if ctx.EqualModules(parent, ctx.Module()) {
 		switch depTag {
 		case sharedLibTag, jniLibTag:
 			isJniLib := depTag == jniLibTag
@@ -1877,17 +1862,17 @@
 				propertyName = "jni_libs"
 			}
 
-			if ch, ok := child.(cc.VersionedLinkableInterface); ok {
-				if ch.IsStubs() {
+			if ch, ok := android.OtherModuleProvider(ctx, child, cc.LinkableInfoProvider); ok {
+				if ch.IsStubs {
 					ctx.PropertyErrorf(propertyName, "%q is a stub. Remove it from the list.", depName)
 				}
-				fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+				fi := apexFileForNativeLibrary(ctx, child, &commonInfo, ch, vctx.handleSpecialLibs)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
 				// Collect the list of stub-providing libs except:
 				// - VNDK libs are only for vendors
 				// - bootstrap bionic libs are treated as provided by system
-				if ch.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(ch.BaseModuleName(), ctx.Config()) {
+				if ch.HasStubsVariants && !a.vndkApex && !cc.InstallToBootstrap(commonInfo.BaseModuleName, ctx.Config()) {
 					vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem())
 				}
 				return true // track transitive dependencies
@@ -1897,34 +1882,33 @@
 			}
 
 		case executableTag:
-			switch ch := child.(type) {
-			case *cc.Module:
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
+			if ccInfo, ok := android.OtherModuleProvider(ctx, child, cc.CcInfoProvider); ok {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, child, &commonInfo, ccInfo))
 				return true // track transitive dependencies
-			case *rust.Module:
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
+			}
+			if _, ok := android.OtherModuleProvider(ctx, child, rust.RustInfoProvider); ok {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, child, &commonInfo))
 				return true // track transitive dependencies
-			default:
+			} else {
 				ctx.PropertyErrorf("binaries",
 					"%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
 			}
 		case shBinaryTag:
-			if csh, ok := child.(*sh.ShBinary); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, csh))
+			if csh, ok := android.OtherModuleProvider(ctx, child, sh.ShBinaryInfoProvider); ok {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, child, &commonInfo, &csh))
 			} else {
 				ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
 			}
 		case bcpfTag:
-			_, ok := child.(*java.BootclasspathFragmentModule)
+			_, ok := android.OtherModuleProvider(ctx, child, java.BootclasspathFragmentInfoProvider)
 			if !ok {
 				ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
 				return false
 			}
-
 			vctx.filesInfo = append(vctx.filesInfo, apexBootclasspathFragmentFiles(ctx, child)...)
 			return true
 		case sscpfTag:
-			if _, ok := child.(*java.SystemServerClasspathModule); !ok {
+			if _, ok := android.OtherModuleProvider(ctx, child, java.LibraryNameToPartitionInfoProvider); !ok {
 				ctx.PropertyErrorf("systemserverclasspath_fragments",
 					"%q is not a systemserverclasspath_fragment module", depName)
 				return false
@@ -1934,83 +1918,84 @@
 			}
 			return true
 		case javaLibTag:
-			switch child.(type) {
-			case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
-				af := apexFileForJavaModule(ctx, child.(javaModule))
+			if ctx.OtherModuleHasProvider(child, java.JavaLibraryInfoProvider) ||
+				ctx.OtherModuleHasProvider(child, java.JavaDexImportInfoProvider) ||
+				ctx.OtherModuleHasProvider(child, java.SdkLibraryInfoProvider) {
+				javaInfo := android.OtherModuleProviderOrDefault(ctx, child, java.JavaInfoProvider)
+				af := apexFileForJavaModule(ctx, child, javaInfo)
 				if !af.ok() {
 					ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
 					return false
 				}
 				vctx.filesInfo = append(vctx.filesInfo, af)
 				return true // track transitive dependencies
-			default:
+			} else {
 				ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
 			}
 		case androidAppTag:
-			switch ap := child.(type) {
-			case *java.AndroidApp:
-				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				return true // track transitive dependencies
-			case *java.AndroidAppImport:
-				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-			case *java.AndroidTestHelperApp:
-				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-			case *java.AndroidAppSet:
-				appDir := "app"
-				if ap.Privileged() {
-					appDir = "priv-app"
+			if appInfo, ok := android.OtherModuleProvider(ctx, child, java.AppInfoProvider); ok {
+				if appInfo.AppSet {
+					appDir := "app"
+					if appInfo.Privileged {
+						appDir = "priv-app"
+					}
+					// TODO(b/224589412, b/226559955): Ensure that the dirname is
+					// suffixed so that PackageManager correctly invalidates the
+					// existing installed apk in favour of the new APK-in-APEX.
+					// See bugs for more information.
+					appDirName := filepath.Join(appDir, commonInfo.BaseModuleName+"@"+sanitizedBuildIdForPath(ctx))
+					af := newApexFile(ctx, appInfo.OutputFile, commonInfo.BaseModuleName, appDirName, appSet, child)
+					af.certificate = java.PresignedCertificate
+					vctx.filesInfo = append(vctx.filesInfo, af)
+				} else {
+					vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, child, &commonInfo, appInfo)...)
+					if !appInfo.Prebuilt && !appInfo.TestHelperApp {
+						return true // track transitive dependencies
+					}
 				}
-				// TODO(b/224589412, b/226559955): Ensure that the dirname is
-				// suffixed so that PackageManager correctly invalidates the
-				// existing installed apk in favour of the new APK-in-APEX.
-				// See bugs for more information.
-				appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
-				af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
-				af.certificate = java.PresignedCertificate
-				vctx.filesInfo = append(vctx.filesInfo, af)
-			default:
+			} else {
 				ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 			}
 		case rroTag:
-			if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
+			if rro, ok := android.OtherModuleProvider(ctx, child, java.RuntimeResourceOverlayInfoProvider); ok {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForRuntimeResourceOverlay(ctx, child, rro))
 			} else {
 				ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
 			}
 		case bpfTag:
-			if bpfProgram, ok := child.(bpf.BpfModule); ok {
-				filesToCopy := android.OutputFilesForModule(ctx, bpfProgram, "")
-				apex_sub_dir := bpfProgram.SubDir()
+			if bpfProgram, ok := android.OtherModuleProvider(ctx, child, bpf.BpfInfoProvider); ok {
+				filesToCopy := android.OutputFilesForModule(ctx, child, "")
+				apex_sub_dir := bpfProgram.SubDir
 				for _, bpfFile := range filesToCopy {
-					vctx.filesInfo = append(vctx.filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
+					vctx.filesInfo = append(vctx.filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, child))
 				}
 			} else {
 				ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
 			}
 		case fsTag:
-			if fs, ok := child.(filesystem.Filesystem); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
+			if fs, ok := android.OtherModuleProvider(ctx, child, filesystem.FilesystemProvider); ok {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForFilesystem(ctx, fs.Output, child))
 			} else {
 				ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
 			}
 		case prebuiltTag:
-			if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
-				filesToCopy := android.OutputFilesForModule(ctx, prebuilt, "")
+			if prebuilt, ok := android.OtherModuleProvider(ctx, child, prebuilt_etc.PrebuiltEtcInfoProvider); ok {
+				filesToCopy := android.OutputFilesForModule(ctx, child, "")
 				for _, etcFile := range filesToCopy {
-					vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
+					vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, child, &prebuilt, etcFile))
 				}
 			} else {
 				ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
 			}
 		case compatConfigTag:
-			if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
+			if compatConfig, ok := android.OtherModuleProvider(ctx, child, java.PlatformCompatConfigInfoProvider); ok {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForCompatConfig(ctx, child, &compatConfig, depName))
 			} else {
 				ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
 			}
 		case testTag:
-			if ccTest, ok := child.(*cc.Module); ok {
-				af := apexFileForExecutable(ctx, ccTest)
+			if ccInfo, ok := android.OtherModuleProvider(ctx, child, cc.CcInfoProvider); ok {
+				af := apexFileForExecutable(ctx, child, &commonInfo, ccInfo)
 				af.class = nativeTest
 				vctx.filesInfo = append(vctx.filesInfo, af)
 				return true // track transitive dependencies
@@ -2018,14 +2003,14 @@
 				ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
 			}
 		case keyTag:
-			if key, ok := child.(*apexKey); ok {
-				a.privateKeyFile = key.privateKeyFile
-				a.publicKeyFile = key.publicKeyFile
+			if key, ok := android.OtherModuleProvider(ctx, child, ApexKeyInfoProvider); ok {
+				a.privateKeyFile = key.PrivateKeyFile
+				a.publicKeyFile = key.PublicKeyFile
 			} else {
 				ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
 			}
 		case certificateTag:
-			if dep, ok := child.(*java.AndroidAppCertificate); ok {
+			if dep, ok := android.OtherModuleProvider(ctx, child, java.AndroidAppCertificateInfoProvider); ok {
 				a.containerCertificateFile = dep.Certificate.Pem
 				a.containerPrivateKeyFile = dep.Certificate.Key
 			} else {
@@ -2040,18 +2025,17 @@
 	}
 
 	// indirect dependencies
-	am, ok := child.(android.ApexModule)
-	if !ok {
+	if !commonInfo.IsApexModule {
 		return false
 	}
 	// We cannot use a switch statement on `depTag` here as the checked
 	// tags used below are private (e.g. `cc.sharedDepTag`).
 	if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
-		if ch, ok := child.(cc.VersionedLinkableInterface); ok {
-			af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+		if ch, ok := android.OtherModuleProvider(ctx, child, cc.LinkableInfoProvider); ok {
+			af := apexFileForNativeLibrary(ctx, child, &commonInfo, ch, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 
-			if ch.IsStubs() || ch.HasStubsVariants() {
+			if ch.IsStubs || ch.HasStubsVariants {
 				// If the dependency is a stubs lib, don't include it in this APEX,
 				// but make sure that the lib is installed on the device.
 				// In case no APEX is having the lib, the lib is installed to the system
@@ -2062,10 +2046,10 @@
 				//
 				// Skip the dependency in unbundled builds where the device image is not
 				// being built.
-				if ch.VersionedInterface().IsStubsImplementationRequired() &&
-					!am.NotInPlatform() && !ctx.Config().UnbundledBuild() {
+				if ch.IsStubsImplementationRequired &&
+					!commonInfo.NotInPlatform && !ctx.Config().UnbundledBuild() {
 					// we need a module name for Make
-					name := ch.ImplementationModuleNameForMake(ctx) + ch.SubName()
+					name := ch.ImplementationModuleNameForMake + ch.SubName
 					if !android.InList(name, a.makeModulesToInstall) {
 						a.makeModulesToInstall = append(a.makeModulesToInstall, name)
 					}
@@ -2084,7 +2068,7 @@
 			// like to record requiredNativeLibs even when
 			// DepIsInSameAPex is false. We also shouldn't do
 			// this for host.
-			if !android.IsDepInSameApex(ctx, parent, am) {
+			if !android.IsDepInSameApex(ctx, parent, child) {
 				return false
 			}
 
@@ -2096,19 +2080,21 @@
 	} else if java.IsJniDepTag(depTag) {
 		// 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 {
-			filesToCopy := android.OutputFilesForModule(ctx, prebuilt, "")
+		if prebuilt, ok := android.OtherModuleProvider(ctx, child, prebuilt_etc.PrebuiltEtcInfoProvider); ok {
+			filesToCopy := android.OutputFilesForModule(ctx, child, "")
 			for _, etcFile := range filesToCopy {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, child, &prebuilt, etcFile))
 			}
 		}
 	} else if rust.IsDylibDepTag(depTag) {
-		if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
-			if !android.IsDepInSameApex(ctx, am, am) {
+		if _, ok := android.OtherModuleProvider(ctx, child, rust.RustInfoProvider); ok &&
+			commonInfo.IsInstallableToApex {
+			if !android.IsDepInSameApex(ctx, parent, child) {
 				return false
 			}
 
-			af := apexFileForNativeLibrary(ctx, child.(cc.VersionedLinkableInterface), vctx.handleSpecialLibs)
+			linkableInfo := android.OtherModuleProviderOrDefault(ctx, child, cc.LinkableInfoProvider)
+			af := apexFileForNativeLibrary(ctx, child, &commonInfo, linkableInfo, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
 			return true // track transitive dependencies
@@ -2119,10 +2105,9 @@
 		return true
 	} else if java.IsBootclasspathFragmentContentDepTag(depTag) {
 		// Add the contents of the bootclasspath fragment to the apex.
-		switch child.(type) {
-		case *java.Library, *java.SdkLibrary:
-			javaModule := child.(javaModule)
-			af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
+		if ctx.OtherModuleHasProvider(child, java.JavaLibraryInfoProvider) ||
+			ctx.OtherModuleHasProvider(child, java.SdkLibraryInfoProvider) {
+			af := apexFileForBootclasspathFragmentContentModule(ctx, parent, child)
 			if !af.ok() {
 				ctx.PropertyErrorf("bootclasspath_fragments",
 					"bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
@@ -2130,21 +2115,22 @@
 			}
 			vctx.filesInfo = append(vctx.filesInfo, af)
 			return true // track transitive dependencies
-		default:
+		} else {
 			ctx.PropertyErrorf("bootclasspath_fragments",
 				"bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
 		}
 	} else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
 		// Add the contents of the systemserverclasspath fragment to the apex.
-		switch child.(type) {
-		case *java.Library, *java.SdkLibrary:
-			af := apexFileForJavaModule(ctx, child.(javaModule))
+		if ctx.OtherModuleHasProvider(child, java.JavaLibraryInfoProvider) ||
+			ctx.OtherModuleHasProvider(child, java.SdkLibraryInfoProvider) {
+			javaInfo := android.OtherModuleProviderOrDefault(ctx, child, java.JavaInfoProvider)
+			af := apexFileForJavaModule(ctx, child, javaInfo)
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
+			if profileAf := apexFileForJavaModuleProfile(ctx, &commonInfo, javaInfo); profileAf != nil {
 				vctx.filesInfo = append(vctx.filesInfo, *profileAf)
 			}
 			return true // track transitive dependencies
-		default:
+		} else {
 			ctx.PropertyErrorf("systemserverclasspath_fragments",
 				"systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
 		}
@@ -2152,11 +2138,11 @@
 		// nothing
 	} else if depTag == android.RequiredDepTag {
 		// nothing
-	} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
+	} else if commonInfo.IsInstallableToApex {
 		ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
 	} else if android.IsVintfDepTag(depTag) {
-		if vf, ok := child.(*android.VintfFragmentModule); ok {
-			apexFile := apexFileForVintfFragment(ctx, vf)
+		if vf, ok := android.OtherModuleProvider(ctx, child, android.VintfFragmentInfoProvider); ok {
+			apexFile := apexFileForVintfFragment(ctx, child, &commonInfo, &vf)
 			vctx.filesInfo = append(vctx.filesInfo, apexFile)
 		}
 	}
@@ -2325,8 +2311,8 @@
 		// checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
 		mctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
 			if appInfo, ok := android.OtherModuleProvider(mctx, module, java.AppInfoProvider); ok {
-				// ignore android_test_app
-				if !appInfo.TestHelperApp && !appInfo.Updatable {
+				// ignore android_test_app and android_app_import
+				if !appInfo.TestHelperApp && !appInfo.Prebuilt && !appInfo.Updatable {
 					mctx.ModuleErrorf("app dependency %s must have updatable: true", mctx.OtherModuleName(module))
 				}
 			}
@@ -2336,7 +2322,7 @@
 
 // apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that
 // the bootclasspath_fragment contributes to the apex.
-func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.Module) []apexFile {
+func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module android.Module) []apexFile {
 	bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, module, java.BootclasspathFragmentApexContentInfoProvider)
 	var filesToAdd []apexFile
 
@@ -2385,7 +2371,7 @@
 
 // apexClasspathFragmentProtoFile returns *apexFile structure defining the classpath.proto config that
 // the module contributes to the apex; or nil if the proto config was not generated.
-func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) *apexFile {
+func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module android.Module) *apexFile {
 	info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider)
 	if !info.ClasspathFragmentProtoGenerated {
 		return nil
@@ -2397,7 +2383,7 @@
 
 // apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
 // content module, i.e. a library that is part of the bootclasspath.
-func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile {
+func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule, javaModule android.Module) apexFile {
 	bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragmentModule, java.BootclasspathFragmentApexContentInfoProvider)
 
 	// Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the
@@ -2409,7 +2395,8 @@
 
 	// Create an apexFile as for a normal java module but with the dex boot jar provided by the
 	// bootclasspath_fragment.
-	af := apexFileForJavaModuleWithFile(ctx, javaModule, dexBootJar)
+	javaInfo := android.OtherModuleProviderOrDefault(ctx, javaModule, java.JavaInfoProvider)
+	af := apexFileForJavaModuleWithFile(ctx, javaModule, javaInfo, dexBootJar)
 	return af
 }
 
@@ -2896,14 +2883,14 @@
 		if !inApex && !inApkInApex {
 			ctx.ModuleErrorf("library in apex transitively linked against implementation library %q not in apex", lib)
 			var depPath []android.Module
-			ctx.WalkDeps(func(child, parent android.Module) bool {
+			ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
 				if depPath != nil {
 					return false
 				}
 
 				tag := ctx.OtherModuleDependencyTag(child)
 
-				if parent == ctx.Module() {
+				if ctx.EqualModules(parent, ctx.Module()) {
 					if !checkApexTag(tag) {
 						return false
 					}
diff --git a/apex/key.go b/apex/key.go
index 1622c65..cc66a13 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -33,6 +33,13 @@
 	ctx.RegisterParallelSingletonModuleType("all_apex_certs", allApexCertsFactory)
 }
 
+type ApexKeyInfo struct {
+	PublicKeyFile  android.Path
+	PrivateKeyFile android.Path
+}
+
+var ApexKeyInfoProvider = blueprint.NewProvider[ApexKeyInfo]()
+
 type apexKey struct {
 	android.ModuleBase
 
@@ -95,6 +102,11 @@
 			m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName)
 		return
 	}
+
+	android.SetProvider(ctx, ApexKeyInfoProvider, ApexKeyInfo{
+		PublicKeyFile:  m.publicKeyFile,
+		PrivateKeyFile: m.privateKeyFile,
+	})
 }
 
 type apexKeyEntry struct {
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 3f34382..deb465d 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -60,6 +60,12 @@
 	ctx.RegisterModuleType("bpf", BpfFactory)
 }
 
+type BpfInfo struct {
+	SubDir string
+}
+
+var BpfInfoProvider = blueprint.NewProvider[BpfInfo]()
+
 var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents)
 
 // BpfModule interface is used by the apex package to gather information from a bpf module.
@@ -230,6 +236,10 @@
 		ctx.PackageFile(installDir, obj.Base(), obj)
 	}
 
+	android.SetProvider(ctx, BpfInfoProvider, BpfInfo{
+		SubDir: bpf.SubDir(),
+	})
+
 	ctx.SetOutputFiles(bpf.objs, "")
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index d31b3e2..45538b4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -117,6 +117,7 @@
 	IsPrebuilt             bool
 	CmakeSnapshotSupported bool
 	HasLlndkStubs          bool
+	DataPaths              []android.DataPath
 	CompilerInfo           *CompilerInfo
 	LinkerInfo             *LinkerInfo
 	SnapshotInfo           *SnapshotInfo
@@ -148,10 +149,8 @@
 	CrateName string
 	// DepFlags returns a slice of Rustc string flags
 	ExportedCrateLinkDirs []string
-	// This can be different from the one on CommonModuleInfo
-	BaseModuleName       string
-	HasNonSystemVariants bool
-	IsLlndk              bool
+	HasNonSystemVariants  bool
+	IsLlndk               bool
 	// True if the library is in the configs known NDK list.
 	IsNdk             bool
 	InVendorOrProduct bool
@@ -169,7 +168,12 @@
 	// TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
 	RustApexExclude bool
 	// Bootstrap tests if this module is allowed to use non-APEX version of libraries.
-	Bootstrap bool
+	Bootstrap                       bool
+	Multilib                        string
+	ImplementationModuleNameForMake string
+	IsStubsImplementationRequired   bool
+	// Symlinks returns a list of symlinks that should be created for this module.
+	Symlinks []string
 }
 
 var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]()
@@ -1576,7 +1580,7 @@
 // where the Soong name is prebuilt_foo, this returns foo (which works in Make
 // under the premise that the prebuilt module overrides its source counterpart
 // if it is exposed to Make).
-func (c *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
+func (c *Module) ImplementationModuleNameForMake() string {
 	name := c.BaseModuleName()
 	if versioned, ok := c.linker.(VersionedInterface); ok {
 		name = versioned.ImplementationModuleName(name)
@@ -2293,6 +2297,7 @@
 		IsPrebuilt:             c.IsPrebuilt(),
 		CmakeSnapshotSupported: proptools.Bool(c.Properties.Cmake_snapshot_supported),
 		HasLlndkStubs:          c.HasLlndkStubs(),
+		DataPaths:              c.DataPaths(),
 	}
 	if c.compiler != nil {
 		cflags := c.compiler.baseCompilerProps().Cflags
@@ -2365,7 +2370,7 @@
 }
 
 func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableInterface) *LinkableInfo {
-	return &LinkableInfo{
+	info := &LinkableInfo{
 		StaticExecutable:     mod.StaticExecutable(),
 		HasStubsVariants:     mod.HasStubsVariants(),
 		OutputFile:           mod.OutputFile(),
@@ -2376,7 +2381,6 @@
 		CcLibrary:            mod.CcLibrary(),
 		CcLibraryInterface:   mod.CcLibraryInterface(),
 		RustLibraryInterface: mod.RustLibraryInterface(),
-		BaseModuleName:       mod.BaseModuleName(),
 		IsLlndk:              mod.IsLlndk(),
 		IsNdk:                mod.IsNdk(ctx.Config()),
 		HasNonSystemVariants: mod.HasNonSystemVariants(),
@@ -2391,9 +2395,16 @@
 		Installable:          mod.Installable(),
 		RelativeInstallPath:  mod.RelativeInstallPath(),
 		// TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
-		RustApexExclude: mod.RustApexExclude(),
-		Bootstrap:       mod.Bootstrap(),
+		RustApexExclude:                 mod.RustApexExclude(),
+		Bootstrap:                       mod.Bootstrap(),
+		Multilib:                        mod.Multilib(),
+		ImplementationModuleNameForMake: mod.ImplementationModuleNameForMake(),
+		Symlinks:                        mod.Symlinks(),
 	}
+	if mod.VersionedInterface() != nil {
+		info.IsStubsImplementationRequired = mod.VersionedInterface().IsStubsImplementationRequired()
+	}
+	return info
 }
 
 func setOutputFilesIfNotEmpty(ctx ModuleContext, files android.Paths, tag string) {
@@ -3582,7 +3593,7 @@
 					c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...)
 			}
 
-			makeLibName := MakeLibName(ccInfo, linkableInfo, &commonInfo, linkableInfo.BaseModuleName) + libDepTag.makeSuffix
+			makeLibName := MakeLibName(ccInfo, linkableInfo, &commonInfo, commonInfo.BaseModuleName) + libDepTag.makeSuffix
 			switch {
 			case libDepTag.header():
 				c.Properties.AndroidMkHeaderLibs = append(
@@ -3609,7 +3620,8 @@
 			switch depTag {
 			case runtimeDepTag:
 				c.Properties.AndroidMkRuntimeLibs = append(
-					c.Properties.AndroidMkRuntimeLibs, MakeLibName(ccInfo, linkableInfo, &commonInfo, linkableInfo.BaseModuleName)+libDepTag.makeSuffix)
+					c.Properties.AndroidMkRuntimeLibs, MakeLibName(ccInfo, linkableInfo, &commonInfo,
+						commonInfo.BaseModuleName)+libDepTag.makeSuffix)
 			case objDepTag:
 				depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
 			case CrtBeginDepTag:
@@ -3771,7 +3783,7 @@
 	if ccInfo != nil {
 		// Use base module name for snapshots when exporting to Makefile.
 		if ccInfo.SnapshotInfo != nil {
-			return linkableInfo.BaseModuleName + ccInfo.SnapshotInfo.SnapshotAndroidMkSuffix
+			return commonInfo.BaseModuleName + ccInfo.SnapshotInfo.SnapshotAndroidMkSuffix
 		}
 	}
 
diff --git a/cc/linkable.go b/cc/linkable.go
index 337b459..f3aff15 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -83,7 +83,7 @@
 	SetSdkVersion(string)
 	SetMinSdkVersion(version string)
 	ApexSdkVersion() android.ApiLevel
-	ImplementationModuleNameForMake(ctx android.BaseModuleContext) string
+	ImplementationModuleNameForMake() string
 
 	// RustApexExclude returns ApexExclude() for Rust modules; always returns false for all non-Rust modules.
 	// TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 5586576..8ca3ca1 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -147,6 +147,8 @@
 	ctx.InstallFile(installPath, filename, txt.outputFile)
 
 	ctx.SetOutputFiles(android.Paths{txt.outputFile}, "")
+
+	etc.SetCommonPrebuiltEtcInfo(ctx, txt)
 }
 
 func getVndkFileName(m *Module) (string, error) {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e7598e7..b704ef4 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1901,6 +1901,8 @@
 
 	ctx.SetOutputFiles(android.Paths{outputFile}, "")
 	txt.outputFile = outputFile
+
+	etc.SetCommonPrebuiltEtcInfo(ctx, txt)
 }
 
 func (txt *sanitizerLibrariesTxtModule) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index bf54c09..a440c91 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -32,6 +32,7 @@
 	"path/filepath"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -90,6 +91,15 @@
 
 }
 
+type PrebuiltEtcInfo struct {
+	// Returns the base install directory, such as "etc", "usr/share".
+	BaseDir string
+	// Returns the sub install directory relative to BaseDir().
+	SubDir string
+}
+
+var PrebuiltEtcInfoProvider = blueprint.NewProvider[PrebuiltEtcInfo]()
+
 var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents)
 
 type PrebuiltEtcProperties struct {
@@ -502,6 +512,15 @@
 	p.updateModuleInfoJSON(ctx)
 
 	ctx.SetOutputFiles(p.outputFilePaths.Paths(), "")
+
+	SetCommonPrebuiltEtcInfo(ctx, p)
+}
+
+func SetCommonPrebuiltEtcInfo(ctx android.ModuleContext, p PrebuiltEtcModule) {
+	android.SetProvider(ctx, PrebuiltEtcInfoProvider, PrebuiltEtcInfo{
+		BaseDir: p.BaseDir(),
+		SubDir:  p.SubDir(),
+	})
 }
 
 func (p *PrebuiltEtc) updateModuleInfoJSON(ctx android.ModuleContext) {
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index f32993c..c1e03cb 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -149,6 +149,8 @@
 	a.installDir = android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(a.installDir, a.installFileName(), output)
 	a.output = output
+
+	setCommonFilesystemInfo(ctx, a)
 }
 
 func addAvbProp(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, prop avbProp) {
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 6d6c15c..effbd65 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -230,6 +230,8 @@
 		ramdiskModule := ctx.GetDirectDepWithTag(ramdisk, bootimgRamdiskDep)
 		fsInfo, _ := android.OtherModuleProvider(ctx, ramdiskModule, FilesystemProvider)
 		android.SetProvider(ctx, FilesystemProvider, fsInfo)
+	} else {
+		setCommonFilesystemInfo(ctx, b)
 	}
 
 	// Set BootimgInfo for building target_files.zip
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index c78061a..c0fb636 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -387,6 +387,9 @@
 type FilesystemInfo struct {
 	// The built filesystem image
 	Output android.Path
+	// Returns the output file that is signed by avbtool. If this module is not signed, returns
+	// nil.
+	SignedOutputPath android.Path
 	// An additional hermetic filesystem image.
 	// e.g. this will contain inodes with pinned timestamps.
 	// This will be copied to target_files.zip
@@ -659,7 +662,8 @@
 	}
 
 	fsInfo := FilesystemInfo{
-		Output:                 f.output,
+		Output:                 f.OutputPath(),
+		SignedOutputPath:       f.SignedOutputPath(),
 		OutputHermetic:         outputHermetic,
 		FileListFile:           fileListFile,
 		RootDir:                rootDir,
@@ -1504,3 +1508,10 @@
 		ctx.StrictRaw("SOONG_DEFINED_SYSTEM_IMAGE_PATH", f.output.String())
 	}
 }
+
+func setCommonFilesystemInfo(ctx android.ModuleContext, m Filesystem) {
+	android.SetProvider(ctx, FilesystemProvider, FilesystemInfo{
+		Output:           m.OutputPath(),
+		SignedOutputPath: m.SignedOutputPath(),
+	})
+}
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index d0888a9..1fd2e76 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -198,6 +198,8 @@
 
 	ctx.SetOutputFiles([]android.Path{output}, "")
 	l.output = output
+
+	setCommonFilesystemInfo(ctx, l)
 }
 
 // Add a rule that converts the filesystem for the given partition to the given rule builder. The
diff --git a/filesystem/raw_binary.go b/filesystem/raw_binary.go
index 707fba0..6ca155a 100644
--- a/filesystem/raw_binary.go
+++ b/filesystem/raw_binary.go
@@ -88,6 +88,8 @@
 
 	ctx.SetOutputFiles([]android.Path{outputFile}, "")
 	r.output = outputFile
+
+	setCommonFilesystemInfo(ctx, r)
 }
 
 var _ android.AndroidMkEntriesProvider = (*rawBinary)(nil)
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index e5809d3..01b453e 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -306,6 +306,8 @@
 
 	ctx.SetOutputFiles([]android.Path{output}, "")
 	v.output = output
+
+	setCommonFilesystemInfo(ctx, v)
 }
 
 // Returns the embedded shell command that prints the rollback index
diff --git a/java/app.go b/java/app.go
index 02e65be..9b10bf3 100644
--- a/java/app.go
+++ b/java/app.go
@@ -72,6 +72,16 @@
 	EmbeddedJNILibs android.Paths
 
 	MergedManifestFile android.Path
+
+	Prebuilt                      bool
+	AppSet                        bool
+	Privileged                    bool
+	OutputFile                    android.Path
+	InstallApkName                string
+	JacocoReportClassesFile       android.Path
+	Certificate                   Certificate
+	PrivAppAllowlist              android.OptionalPath
+	OverriddenManifestPackageName *string
 }
 
 var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
@@ -401,10 +411,12 @@
 	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
 		TestOnly: true,
 	})
-	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
+	appInfo := &AppInfo{
 		Updatable:     Bool(a.appProperties.Updatable),
 		TestHelperApp: true,
-	})
+	}
+	setCommonAppInfo(appInfo, a)
+	android.SetProvider(ctx, AppInfoProvider, appInfo)
 
 	moduleInfoJSON := ctx.ModuleInfoJSON()
 	moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests")
@@ -428,12 +440,16 @@
 			embeddedJniLibs = append(embeddedJniLibs, jni.path)
 		}
 	}
-	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
-		Updatable:          Bool(a.appProperties.Updatable),
-		TestHelperApp:      false,
-		EmbeddedJNILibs:    embeddedJniLibs,
-		MergedManifestFile: a.mergedManifest,
-	})
+	overriddenName := a.OverriddenManifestPackageName()
+	appInfo := &AppInfo{
+		Updatable:                     Bool(a.appProperties.Updatable),
+		TestHelperApp:                 false,
+		EmbeddedJNILibs:               embeddedJniLibs,
+		MergedManifestFile:            a.mergedManifest,
+		OverriddenManifestPackageName: &overriddenName,
+	}
+	setCommonAppInfo(appInfo, a)
+	android.SetProvider(ctx, AppInfoProvider, appInfo)
 
 	a.requiredModuleNames = a.getRequiredModuleNames(ctx)
 }
@@ -2048,7 +2064,7 @@
 			if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok {
 				// Skip java_sdk_library dependencies that provide stubs, but not an implementation.
 				// This will be restricted to optional_uses_libs
-				if tag == usesLibOptTag && lib.DexJarBuildPath.PathOrNil() == nil {
+				if tag == usesLibOptTag && javaInfo.DexJarBuildPath.PathOrNil() == nil {
 					u.shouldDisableDexpreopt = true
 					return
 				}
@@ -2058,7 +2074,7 @@
 				libName = *ulib.ProvidesUsesLib
 			}
 			clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional,
-				lib.DexJarBuildPath.PathOrNil(), lib.DexJarInstallPath,
+				javaInfo.DexJarBuildPath.PathOrNil(), lib.DexJarInstallPath,
 				lib.ClassLoaderContexts)
 		} else if ctx.Config().AllowMissingDependencies() {
 			ctx.AddMissingDependencies([]string{dep})
@@ -2151,3 +2167,29 @@
 	classLoaderContexts *dexpreopt.ClassLoaderContextMap) {
 	u.verifyUsesLibraries(ctx, apk, nil, classLoaderContexts) // for APKs manifest_check does not write output file
 }
+
+// androidApp is an interface to handle all app modules (android_app, android_app_import, etc.) in
+// the same way.
+type androidApp interface {
+	android.Module
+	Privileged() bool
+	InstallApkName() string
+	OutputFile() android.Path
+	JacocoReportClassesFile() android.Path
+	Certificate() Certificate
+	BaseModuleName() string
+	PrivAppAllowlist() android.OptionalPath
+}
+
+var _ androidApp = (*AndroidApp)(nil)
+var _ androidApp = (*AndroidAppImport)(nil)
+var _ androidApp = (*AndroidTestHelperApp)(nil)
+
+func setCommonAppInfo(appInfo *AppInfo, m androidApp) {
+	appInfo.Privileged = m.Privileged()
+	appInfo.OutputFile = m.OutputFile()
+	appInfo.InstallApkName = m.InstallApkName()
+	appInfo.JacocoReportClassesFile = m.JacocoReportClassesFile()
+	appInfo.Certificate = m.Certificate()
+	appInfo.PrivAppAllowlist = m.PrivAppAllowlist()
+}
diff --git a/java/app_import.go b/java/app_import.go
index 919266f..37c673c 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -354,6 +354,12 @@
 
 func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.generateAndroidBuildActions(ctx)
+
+	appInfo := &AppInfo{
+		Prebuilt: true,
+	}
+	setCommonAppInfo(appInfo, a)
+	android.SetProvider(ctx, AppInfoProvider, appInfo)
 }
 
 func (a *AndroidAppImport) InstallApkName() string {
diff --git a/java/app_set.go b/java/app_set.go
index 7997570..2e9d314 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -192,6 +192,11 @@
 		},
 	)
 
+	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
+		AppSet:     true,
+		Privileged: as.Privileged(),
+		OutputFile: as.OutputFile(),
+	})
 }
 
 func (as *AndroidAppSet) InstallBypassMake() bool { return true }
diff --git a/java/base.go b/java/base.go
index 21ad73f..fccc806 100644
--- a/java/base.go
+++ b/java/base.go
@@ -658,11 +658,11 @@
 	// See rank() for details.
 	ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
 		tag := ctx.OtherModuleDependencyTag(module)
-		_, isJavaLibrary := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider)
+		libInfo, isJavaLibrary := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider)
 		_, isAndroidLibrary := android.OtherModuleProvider(ctx, module, AndroidLibraryInfoProvider)
 		_, isJavaAconfigLibrary := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider)
 		// Exclude java_aconfig_library modules to maintain consistency with existing behavior.
-		if (isJavaLibrary && !isJavaAconfigLibrary) || isAndroidLibrary {
+		if (isJavaLibrary && !libInfo.Prebuilt && !isJavaAconfigLibrary) || isAndroidLibrary {
 			// TODO(satayev): cover other types as well, e.g. imports
 			switch tag {
 			case bootClasspathTag, sdkLibTag, libTag, staticLibTag, java9LibTag:
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 7a3c21e..a09416d 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -41,6 +41,10 @@
 	ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory)
 }
 
+type BootclasspathFragmentInfo struct{}
+
+var BootclasspathFragmentInfoProvider = blueprint.NewProvider[BootclasspathFragmentInfo]()
+
 // BootclasspathFragmentSdkMemberType is the member type used to add bootclasspath_fragments to
 // the SDK snapshot. It is exported for use by apex.
 var BootclasspathFragmentSdkMemberType = &bootclasspathFragmentMemberType{
@@ -557,6 +561,8 @@
 	if !ctx.IsFinalModule(ctx.Module()) {
 		b.HideFromMake()
 	}
+
+	android.SetProvider(ctx, BootclasspathFragmentInfoProvider, BootclasspathFragmentInfo{})
 }
 
 // getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
diff --git a/java/java.go b/java/java.go
index af2b86e..45e55d5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -259,7 +259,6 @@
 }
 
 type UsesLibraryDependencyInfo struct {
-	DexJarBuildPath     OptionalDexJarPath
 	DexJarInstallPath   android.Path
 	ClassLoaderContexts dexpreopt.ClassLoaderContextMap
 }
@@ -403,13 +402,6 @@
 
 	BuiltInstalled string
 
-	// ApexSystemServerDexpreoptInstalls stores the list of dexpreopt artifacts if this is a system server
-	// jar in an apex.
-	ApexSystemServerDexpreoptInstalls []DexpreopterInstall
-
-	// ApexSystemServerDexJars stores the list of dex jars if this is a system server jar in an apex.
-	ApexSystemServerDexJars android.Paths
-
 	// The config is used for two purposes:
 	// - Passing dexpreopt information about libraries from Soong to Make. This is needed when
 	//   a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py).
@@ -418,10 +410,6 @@
 	//   dexpreopt another partition).
 	ConfigPath android.WritablePath
 
-	// The path to the profile on host that dexpreopter generates. This is used as the input for
-	// dex2oat.
-	OutputProfilePathOnHost android.Path
-
 	LogtagsSrcs android.Paths
 
 	ProguardDictionary android.OptionalPath
@@ -438,14 +426,39 @@
 
 	// True if profile-guided optimization is actually enabled.
 	ProfileGuided bool
+
+	Stem string
+
+	DexJarBuildPath OptionalDexJarPath
+
+	DexpreopterInfo *DexpreopterInfo
 }
 
 var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]()
 
-type JavaLibraryInfo struct{}
+type DexpreopterInfo struct {
+	// The path to the profile on host that dexpreopter generates. This is used as the input for
+	// dex2oat.
+	OutputProfilePathOnHost android.Path
+	// If the java module is to be installed into an APEX, this list contains information about the
+	// dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed
+	// outside of the APEX.
+	ApexSystemServerDexpreoptInstalls []DexpreopterInstall
+
+	// ApexSystemServerDexJars returns the list of dex jars if this is an apex system server jar.
+	ApexSystemServerDexJars android.Paths
+}
+
+type JavaLibraryInfo struct {
+	Prebuilt bool
+}
 
 var JavaLibraryInfoProvider = blueprint.NewProvider[JavaLibraryInfo]()
 
+type JavaDexImportInfo struct{}
+
+var JavaDexImportInfoProvider = blueprint.NewProvider[JavaDexImportInfo]()
+
 // SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to
 // the sysprop implementation library.
 type SyspropPublicStubInfo struct {
@@ -1127,7 +1140,9 @@
 		TopLevelTarget: j.sourceProperties.Top_level_test_target,
 	})
 
-	android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{})
+	android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{
+		Prebuilt: false,
+	})
 
 	if javaInfo != nil {
 		setExtraJavaInfo(ctx, j, javaInfo)
@@ -1137,11 +1152,8 @@
 		javaInfo.BootDexJarPath = j.bootDexJarPath
 		javaInfo.UncompressDexState = j.uncompressDexState
 		javaInfo.Active = j.active
-		javaInfo.ApexSystemServerDexpreoptInstalls = j.apexSystemServerDexpreoptInstalls
-		javaInfo.ApexSystemServerDexJars = j.apexSystemServerDexJars
 		javaInfo.BuiltInstalled = j.builtInstalled
 		javaInfo.ConfigPath = j.configPath
-		javaInfo.OutputProfilePathOnHost = j.outputProfilePathOnHost
 		javaInfo.LogtagsSrcs = j.logtagsSrcs
 		javaInfo.ProguardDictionary = j.proguardDictionary
 		javaInfo.ProguardUsageZip = j.proguardUsageZip
@@ -3233,6 +3245,10 @@
 	setExtraJavaInfo(ctx, j, javaInfo)
 	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
 
+	android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{
+		Prebuilt: true,
+	})
+
 	ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, "")
 	ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, ".jar")
 
@@ -3512,6 +3528,12 @@
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			j.Stem()+".jar", dexOutputFile)
 	}
+
+	javaInfo := &JavaInfo{}
+	setExtraJavaInfo(ctx, j, javaInfo)
+	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+
+	android.SetProvider(ctx, JavaDexImportInfoProvider, JavaDexImportInfo{})
 }
 
 func (j *DexImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
@@ -3699,7 +3721,7 @@
 			}
 		}
 		clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, optional,
-			dep.UsesLibraryDependencyInfo.DexJarBuildPath.PathOrNil(),
+			dep.DexJarBuildPath.PathOrNil(),
 			dep.UsesLibraryDependencyInfo.DexJarInstallPath, dep.UsesLibraryDependencyInfo.ClassLoaderContexts)
 	} else {
 		clcMap.AddContextMap(dep.UsesLibraryDependencyInfo.ClassLoaderContexts, depName)
@@ -3783,7 +3805,6 @@
 
 	if ulDep, ok := module.(UsesLibraryDependency); ok {
 		javaInfo.UsesLibraryDependencyInfo = &UsesLibraryDependencyInfo{
-			DexJarBuildPath:     ulDep.DexJarBuildPath(ctx),
 			DexJarInstallPath:   ulDep.DexJarInstallPath(),
 			ClassLoaderContexts: ulDep.ClassLoaderContexts(),
 		}
@@ -3812,4 +3833,22 @@
 			Stubs:       stubs,
 		}
 	}
+
+	if st, ok := module.(ModuleWithStem); ok {
+		javaInfo.Stem = st.Stem()
+	}
+
+	if mm, ok := module.(interface {
+		DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath
+	}); ok {
+		javaInfo.DexJarBuildPath = mm.DexJarBuildPath(ctx)
+	}
+
+	if di, ok := module.(DexpreopterInterface); ok {
+		javaInfo.DexpreopterInfo = &DexpreopterInfo{
+			OutputProfilePathOnHost:           di.OutputProfilePathOnHost(),
+			ApexSystemServerDexpreoptInstalls: di.ApexSystemServerDexpreoptInstalls(),
+			ApexSystemServerDexJars:           di.ApexSystemServerDexJars(),
+		}
+	}
 }
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index d4d2fb5..363521a 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -43,6 +43,13 @@
 	ctx.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
 }
 
+type PlatformCompatConfigInfo struct {
+	CompatConfig android.OutputPath
+	SubDir       string
+}
+
+var PlatformCompatConfigInfoProvider = blueprint.NewProvider[PlatformCompatConfigInfo]()
+
 var PrepareForTestWithPlatformCompatConfig = android.FixtureRegisterWithContext(registerPlatformCompatConfigBuildComponents)
 
 func platformCompatConfigPath(ctx android.PathContext) android.OutputPath {
@@ -124,6 +131,11 @@
 	rule.Build(configFileName, "Extract compat/compat_config.xml and install it")
 	ctx.InstallFile(p.installDirPath, p.configFile.Base(), p.configFile)
 	ctx.SetOutputFiles(android.Paths{p.configFile}, "")
+
+	android.SetProvider(ctx, PlatformCompatConfigInfoProvider, PlatformCompatConfigInfo{
+		CompatConfig: p.CompatConfig(),
+		SubDir:       p.SubDir(),
+	})
 }
 
 func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/java/rro.go b/java/rro.go
index d9f4ff7..f7f85f0 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -34,6 +34,15 @@
 	ctx.RegisterModuleType("override_runtime_resource_overlay", OverrideRuntimeResourceOverlayModuleFactory)
 }
 
+type RuntimeResourceOverlayInfo struct {
+	OutputFile                    android.Path
+	Certificate                   Certificate
+	Theme                         string
+	OverriddenManifestPackageName string
+}
+
+var RuntimeResourceOverlayInfoProvider = blueprint.NewProvider[RuntimeResourceOverlayInfo]()
+
 type RuntimeResourceOverlay struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -207,6 +216,12 @@
 		AconfigTextFiles: aconfigTextFilePaths,
 	})
 
+	android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{
+		OutputFile:  r.OutputFile(),
+		Certificate: r.Certificate(),
+		Theme:       r.Theme(),
+	})
+
 	buildComplianceMetadata(ctx)
 }
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index cf31b50..7944bb2 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -702,7 +702,7 @@
 		paths.stubsHeaderPath = lib.HeaderJars
 		paths.stubsImplPath = lib.ImplementationJars
 
-		libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo
+		libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider)
 		paths.stubsDexJarPath = libDep.DexJarBuildPath
 		paths.exportableStubsDexJarPath = libDep.DexJarBuildPath
 		return nil
@@ -718,7 +718,7 @@
 			paths.stubsImplPath = lib.ImplementationJars
 		}
 
-		libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo
+		libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider)
 		paths.stubsDexJarPath = libDep.DexJarBuildPath
 		return nil
 	} else {
@@ -732,7 +732,7 @@
 			paths.stubsImplPath = lib.ImplementationJars
 		}
 
-		libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo
+		libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider)
 		paths.exportableStubsDexJarPath = libDep.DexJarBuildPath
 		return nil
 	} else {
@@ -1017,10 +1017,6 @@
 		removedApiFilePaths[kind] = removedApiFilePath
 	}
 
-	javaInfo := &JavaInfo{}
-	setExtraJavaInfo(ctx, ctx.Module(), javaInfo)
-	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
-
 	return SdkLibraryInfo{
 		EverythingStubDexJarPaths: everythingStubPaths,
 		ExportableStubDexJarPaths: exportableStubPaths,
@@ -1227,6 +1223,8 @@
 
 	// Whether if this can be used as a shared library.
 	SharedLibrary bool
+
+	Prebuilt bool
 }
 
 var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]()
@@ -1513,10 +1511,10 @@
 		module.dexJarFile = makeDexJarPathFromPath(module.implLibraryInfo.DexJarFile.Path())
 		module.headerJarFile = module.implLibraryInfo.HeaderJars[0]
 		module.implementationAndResourcesJar = module.implLibraryInfo.ImplementationAndResourcesJars[0]
-		module.apexSystemServerDexpreoptInstalls = module.implLibraryInfo.ApexSystemServerDexpreoptInstalls
-		module.apexSystemServerDexJars = module.implLibraryInfo.ApexSystemServerDexJars
+		module.apexSystemServerDexpreoptInstalls = module.implLibraryInfo.DexpreopterInfo.ApexSystemServerDexpreoptInstalls
+		module.apexSystemServerDexJars = module.implLibraryInfo.DexpreopterInfo.ApexSystemServerDexJars
 		module.dexpreopter.configPath = module.implLibraryInfo.ConfigPath
-		module.dexpreopter.outputProfilePathOnHost = module.implLibraryInfo.OutputProfilePathOnHost
+		module.dexpreopter.outputProfilePathOnHost = module.implLibraryInfo.DexpreopterInfo.OutputProfilePathOnHost
 
 		// Properties required for Library.AndroidMkEntries
 		module.logtagsSrcs = module.implLibraryInfo.LogtagsSrcs
@@ -1582,7 +1580,12 @@
 		setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo)
 	}
 
+	javaInfo := &JavaInfo{}
+	setExtraJavaInfo(ctx, ctx.Module(), javaInfo)
+	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+
 	sdkLibInfo.GeneratingLibs = generatingLibs
+	sdkLibInfo.Prebuilt = false
 	android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo)
 }
 
@@ -2236,7 +2239,12 @@
 		setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo)
 	}
 
+	javaInfo := &JavaInfo{}
+	setExtraJavaInfo(ctx, ctx.Module(), javaInfo)
+	android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+
 	sdkLibInfo.GeneratingLibs = generatingLibs
+	sdkLibInfo.Prebuilt = true
 	android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo)
 }
 
diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go
index 5789692..f5feabe 100644
--- a/java/sdk_library_internal.go
+++ b/java/sdk_library_internal.go
@@ -936,6 +936,8 @@
 	ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath)
 
 	ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "")
+
+	etc.SetCommonPrebuiltEtcInfo(ctx, module)
 }
 
 func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 4f1ef9d..43fe8aa 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -86,6 +86,8 @@
 	ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
 
 	ctx.SetOutputFiles(android.Paths{l.outputFilePath}, "")
+
+	etc.SetCommonPrebuiltEtcInfo(ctx, l)
 }
 
 func BuildLinkerConfig(
diff --git a/rust/rust.go b/rust/rust.go
index 7a7b106..713cacc 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -841,7 +841,7 @@
 	return shared
 }
 
-func (mod *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
+func (mod *Module) ImplementationModuleNameForMake() string {
 	name := mod.BaseModuleName()
 	if versioned, ok := mod.compiler.(cc.VersionedInterface); ok {
 		name = versioned.ImplementationModuleName(name)
@@ -1411,7 +1411,7 @@
 	if rustInfo != nil {
 		// Use base module name for snapshots when exporting to Makefile.
 		if rustInfo.SnapshotInfo != nil {
-			baseName := linkableInfo.BaseModuleName
+			baseName := commonInfo.BaseModuleName
 			return baseName + rustInfo.SnapshotInfo.SnapshotAndroidMkSuffix + rustInfo.AndroidMkSuffix
 		}
 	}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 77066f1..c0c6ff2 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -41,6 +41,14 @@
 	registerShBuildComponents(android.InitRegistrationContext)
 }
 
+type ShBinaryInfo struct {
+	SubDir     string
+	OutputFile android.Path
+	Symlinks   []string
+}
+
+var ShBinaryInfoProvider = blueprint.NewProvider[ShBinaryInfo]()
+
 func registerShBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("sh_binary", ShBinaryFactory)
 	ctx.RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
@@ -314,6 +322,12 @@
 
 	s.properties.SubName = s.GetSubname(ctx)
 
+	android.SetProvider(ctx, ShBinaryInfoProvider, ShBinaryInfo{
+		SubDir:     s.SubDir(),
+		OutputFile: s.OutputFile(),
+		Symlinks:   s.Symlinks(),
+	})
+
 	ctx.SetOutputFiles(android.Paths{s.outputFilePath}, "")
 }