Merge changes from topic "product_soong_only" into main

* changes:
  Add PRODUCT_SOONG_ONLY
  Remove --skip-make
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index bb90607..9086c93 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -19,6 +19,8 @@
 	"slices"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 // A singleton module that collects all of the aconfig flags declared in the
@@ -41,7 +43,7 @@
 }
 
 type allAconfigReleaseDeclarationsProperties struct {
-	Api_files []string `android:"arch_variant,path"`
+	Api_files proptools.Configurable[[]string] `android:"arch_variant,path"`
 }
 
 type allAconfigDeclarationsSingleton struct {
@@ -62,7 +64,7 @@
 
 func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	apiFiles := android.Paths{}
-	for _, apiFile := range this.properties.Api_files {
+	for _, apiFile := range this.properties.Api_files.GetOrDefault(ctx, nil) {
 		if path := android.PathForModuleSrc(ctx, apiFile); path != nil {
 			apiFiles = append(apiFiles, path)
 		}
diff --git a/bin/mm b/bin/mm
index 6461b1e..6f1c934 100755
--- a/bin/mm
+++ b/bin/mm
@@ -19,6 +19,6 @@
 
 require_top
 
-_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir-no-deps --dir="$(pwd)" "$@"
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir --dir="$(pwd)" "$@"
 
 exit $?
diff --git a/bin/mmm b/bin/mmm
index ab3a632..d9190e5 100755
--- a/bin/mmm
+++ b/bin/mmm
@@ -19,6 +19,6 @@
 
 require_top
 
-_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs-no-deps --dir="$(pwd)" "$@"
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs --dir="$(pwd)" "$@"
 
 exit $?
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 7926292..a884964 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -471,20 +471,6 @@
 		description: "Build action: build from the top of the source tree.",
 		action:      build.BUILD_MODULES,
 	}, {
-		// This is redirecting to mma build command behaviour. Once it has soaked for a
-		// while, the build command is deleted from here once it has been removed from the
-		// envsetup.sh.
-		name:        "modules-in-a-dir-no-deps",
-		description: "Build action: builds all of the modules in the current directory without their dependencies.",
-		action:      build.BUILD_MODULES_IN_A_DIRECTORY,
-	}, {
-		// This is redirecting to mmma build command behaviour. Once it has soaked for a
-		// while, the build command is deleted from here once it has been removed from the
-		// envsetup.sh.
-		name:        "modules-in-dirs-no-deps",
-		description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
-		action:      build.BUILD_MODULES_IN_DIRECTORIES,
-	}, {
 		name:        "modules-in-a-dir",
 		description: "Build action: builds all of the modules in the current directory and their dependencies.",
 		action:      build.BUILD_MODULES_IN_A_DIRECTORY,
diff --git a/java/app.go b/java/app.go
index 34a172e..557ba28 100644
--- a/java/app.go
+++ b/java/app.go
@@ -70,6 +70,8 @@
 
 	// EmbeddedJNILibs is the list of paths to JNI libraries that were embedded in the APK.
 	EmbeddedJNILibs android.Paths
+
+	MergedManifestFile android.Path
 }
 
 var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
@@ -419,9 +421,10 @@
 		}
 	}
 	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
-		Updatable:       Bool(a.appProperties.Updatable),
-		TestHelperApp:   false,
-		EmbeddedJNILibs: embeddedJniLibs,
+		Updatable:          Bool(a.appProperties.Updatable),
+		TestHelperApp:      false,
+		EmbeddedJNILibs:    embeddedJniLibs,
+		MergedManifestFile: a.mergedManifest,
 	})
 
 	a.requiredModuleNames = a.getRequiredModuleNames(ctx)
@@ -707,7 +710,7 @@
 	return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
 }
 
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path, *JavaInfo) {
 	a.dexpreopter.installPath = a.installPath(ctx)
 	a.dexpreopter.isApp = true
 	if a.dexProperties.Uncompress_dex == nil {
@@ -753,12 +756,8 @@
 			packageResources = binaryResources
 		}
 	}
-	if javaInfo != nil {
-		setExtraJavaInfo(ctx, a, javaInfo)
-		android.SetProvider(ctx, JavaInfoProvider, javaInfo)
-	}
 
-	return a.dexJarFile.PathOrNil(), packageResources
+	return a.dexJarFile.PathOrNil(), packageResources, javaInfo
 }
 
 func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath {
@@ -965,7 +964,7 @@
 	a.linter.resources = a.aapt.resourceFiles
 	a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
 
-	dexJarFile, packageResources := a.dexBuildActions(ctx)
+	dexJarFile, packageResources, javaInfo := a.dexBuildActions(ctx)
 
 	// No need to check the SDK version of the JNI deps unless we embed them
 	checkNativeSdkVersion := a.shouldEmbedJnis(ctx) && !Bool(a.appProperties.Jni_uses_platform_apis)
@@ -1081,6 +1080,12 @@
 		},
 	)
 
+	if javaInfo != nil {
+		javaInfo.OutputFile = a.outputFile
+		setExtraJavaInfo(ctx, a, javaInfo)
+		android.SetProvider(ctx, JavaInfoProvider, javaInfo)
+	}
+
 	a.setOutputFiles(ctx)
 }
 
diff --git a/java/base.go b/java/base.go
index ddb2be8..b55c938 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1975,6 +1975,7 @@
 		StubsLinkType:                       j.stubsLinkType,
 		AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles,
 		SdkVersion:                          j.SdkVersion(ctx),
+		OutputFile:                          j.outputFile,
 	}
 }
 
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index efca913..24e5f50 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -204,7 +204,7 @@
 	}
 	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	psi := android.PrebuiltSelectionInfoMap{}
-	ctx.VisitDirectDeps(func(am android.Module) {
+	ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) {
 		if prebuiltSelectionInfo, ok := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); ok {
 			psi = prebuiltSelectionInfo
 		}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index f2edd06..e0c2e63 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -657,7 +657,7 @@
 	for _, sdkDir := range sdkDirs {
 		for _, dir := range dirs {
 			addPattern := func(jarFilename string) {
-				cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:level}/%s/%s", dir, sdkDir, jarFilename))
+				cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:major.minor?}/%s/%s", dir, sdkDir, jarFilename))
 			}
 
 			if sdkDir == "module-lib" || sdkDir == "system-server" {
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index ad47210..75a0a31 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -88,7 +88,7 @@
 		cmdline := String(sboxProto.Commands[0].Command)
 		android.AssertStringContainsEquals(t, "api-versions generation flag", cmdline, "--generate-api-levels", c.generate_xml)
 		if c.expectedJarFilename != "" {
-			expected := "--android-jar-pattern ./{version:level}/public/" + c.expectedJarFilename
+			expected := "--android-jar-pattern ./{version:major.minor?}/public/" + c.expectedJarFilename
 			if !strings.Contains(cmdline, expected) {
 				t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, cmdline)
 			}
@@ -142,8 +142,8 @@
 	patterns := getAndroidJarPatternsForDroidstubs(t, "public")
 
 	android.AssertArrayString(t, "order of patterns", []string{
-		"--android-jar-pattern somedir/{version:level}/public/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/public/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
 	}, patterns)
 }
 
@@ -151,10 +151,10 @@
 	patterns := getAndroidJarPatternsForDroidstubs(t, "system")
 
 	android.AssertArrayString(t, "order of patterns", []string{
-		"--android-jar-pattern somedir/{version:level}/system/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/system/android.jar",
-		"--android-jar-pattern somedir/{version:level}/public/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/public/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
 	}, patterns)
 }
 
@@ -162,12 +162,12 @@
 	patterns := getAndroidJarPatternsForDroidstubs(t, "module-lib")
 
 	android.AssertArrayString(t, "order of patterns", []string{
-		"--android-jar-pattern somedir/{version:level}/module-lib/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/module-lib/android.jar",
-		"--android-jar-pattern somedir/{version:level}/system/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/system/android.jar",
-		"--android-jar-pattern somedir/{version:level}/public/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/public/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
 	}, patterns)
 }
 
@@ -175,14 +175,14 @@
 	patterns := getAndroidJarPatternsForDroidstubs(t, "system-server")
 
 	android.AssertArrayString(t, "order of patterns", []string{
-		"--android-jar-pattern somedir/{version:level}/system-server/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/system-server/android.jar",
-		"--android-jar-pattern somedir/{version:level}/module-lib/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/module-lib/android.jar",
-		"--android-jar-pattern somedir/{version:level}/system/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/system/android.jar",
-		"--android-jar-pattern somedir/{version:level}/public/android.jar",
-		"--android-jar-pattern someotherdir/{version:level}/public/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/system-server/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/system-server/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
+		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
+		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
 	}, patterns)
 }
 
diff --git a/java/java.go b/java/java.go
index 37086fe..fafe9f9 100644
--- a/java/java.go
+++ b/java/java.go
@@ -360,6 +360,9 @@
 
 	SdkVersion android.SdkSpec
 
+	// output file of the module, which may be a classes jar or a dex jar
+	OutputFile android.Path
+
 	AndroidLibraryDependencyInfo *AndroidLibraryDependencyInfo
 
 	UsesLibraryDependencyInfo *UsesLibraryDependencyInfo
@@ -1658,17 +1661,17 @@
 
 	j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs)
 
-	ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) {
+	ctx.VisitDirectDepsProxyWithTag(dataNativeBinsTag, func(dep android.ModuleProxy) {
 		j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
 	})
 
-	ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+	ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) {
 		j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
 	})
 
 	var directImplementationDeps android.Paths
 	var transitiveImplementationDeps []depset.DepSet[android.Path]
-	ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
+	ctx.VisitDirectDepsProxyWithTag(jniLibTag, func(dep android.ModuleProxy) {
 		sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
 		if sharedLibInfo.SharedLibrary != nil {
 			// Copy to an intermediate output directory to append "lib[64]" to the path,
diff --git a/java/ravenwood.go b/java/ravenwood.go
index 84d6a9f..8c8d8e9 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -185,26 +185,24 @@
 	// All JNI libraries included in the runtime
 	var runtimeJniModuleNames map[string]bool
 
-	if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil {
-		for _, installFile := range android.OtherModuleProviderOrDefault(
-			ctx, utils, android.InstallFilesProvider).InstallFiles {
-			installDeps = append(installDeps, installFile)
-		}
-		jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider)
-		if ok {
-			runtimeJniModuleNames = jniDeps.names
-		}
+	utils := ctx.GetDirectDepsProxyWithTag(ravenwoodUtilsTag)[0]
+	for _, installFile := range android.OtherModuleProviderOrDefault(
+		ctx, utils, android.InstallFilesProvider).InstallFiles {
+		installDeps = append(installDeps, installFile)
+	}
+	jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider)
+	if ok {
+		runtimeJniModuleNames = jniDeps.names
 	}
 
-	if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil {
-		for _, installFile := range android.OtherModuleProviderOrDefault(
-			ctx, runtime, android.InstallFilesProvider).InstallFiles {
-			installDeps = append(installDeps, installFile)
-		}
-		jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider)
-		if ok {
-			runtimeJniModuleNames = jniDeps.names
-		}
+	runtime := ctx.GetDirectDepsProxyWithTag(ravenwoodRuntimeTag)[0]
+	for _, installFile := range android.OtherModuleProviderOrDefault(
+		ctx, runtime, android.InstallFilesProvider).InstallFiles {
+		installDeps = append(installDeps, installFile)
+	}
+	jniDeps, ok = android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider)
+	if ok {
+		runtimeJniModuleNames = jniDeps.names
 	}
 
 	// Also remember what JNI libs are in the runtime.
@@ -228,7 +226,7 @@
 	resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks")
 
 	copyResApk := func(tag blueprint.DependencyTag, toFileName string) {
-		if resApk := ctx.GetDirectDepsWithTag(tag); len(resApk) > 0 {
+		if resApk := ctx.GetDirectDepsProxyWithTag(tag); len(resApk) > 0 {
 			installFile := android.OutputFileForModule(ctx, resApk[0], "")
 			installResApk := ctx.InstallFile(resApkInstallPath, toFileName, installFile)
 			installDeps = append(installDeps, installResApk)
@@ -345,7 +343,7 @@
 	// Install our runtime into expected location for packaging
 	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
 	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
-		libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag)
+		libModule := ctx.GetDirectDepProxyWithTag(lib, ravenwoodLibContentTag)
 		if libModule == nil {
 			if ctx.Config().AllowMissingDependencies() {
 				ctx.AddMissingDependencies([]string{lib})
diff --git a/java/robolectric.go b/java/robolectric.go
index 6c74d08..ff0c850 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -29,6 +29,12 @@
 	RegisterRobolectricBuildComponents(android.InitRegistrationContext)
 }
 
+type RobolectricRuntimesInfo struct {
+	Runtimes []android.InstallPath
+}
+
+var RobolectricRuntimesInfoProvider = blueprint.NewProvider[RobolectricRuntimesInfo]()
+
 type roboRuntimeOnlyDependencyTag struct {
 	blueprint.BaseDependencyTag
 }
@@ -141,7 +147,7 @@
 	var options []tradefed.Option
 	options = append(options, tradefed.Option{Name: "java-flags", Value: "-Drobolectric=true"})
 	if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) {
-	    options = append(options, tradefed.Option{Name: "java-flags", Value: "-Drobolectric.strict.mode=true"})
+		options = append(options, tradefed.Option{Name: "java-flags", Value: "-Drobolectric.strict.mode=true"})
 	}
 
 	r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
@@ -159,25 +165,27 @@
 	r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_prefer32_data)...)
 
 	var ok bool
-	var instrumentedApp *AndroidApp
+	var instrumentedApp *JavaInfo
+	var appInfo *AppInfo
 
 	// TODO: this inserts paths to built files into the test, it should really be inserting the contents.
-	instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag)
+	instrumented := ctx.GetDirectDepsProxyWithTag(instrumentationForTag)
 
 	if len(instrumented) == 1 {
-		instrumentedApp, ok = instrumented[0].(*AndroidApp)
+		appInfo, ok = android.OtherModuleProvider(ctx, instrumented[0], AppInfoProvider)
 		if !ok {
 			ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
 		}
+		instrumentedApp = android.OtherModuleProviderOrDefault(ctx, instrumented[0], JavaInfoProvider)
 	} else if !ctx.Config().AllowMissingDependencies() {
 		panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
 	}
 
 	var resourceApk android.Path
 	var manifest android.Path
-	if instrumentedApp != nil {
-		manifest = instrumentedApp.mergedManifestFile
-		resourceApk = instrumentedApp.outputFile
+	if appInfo != nil {
+		manifest = appInfo.MergedManifestFile
+		resourceApk = instrumentedApp.OutputFile
 	}
 
 	roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
@@ -185,7 +193,7 @@
 
 	extraCombinedJars := android.Paths{roboTestConfigJar}
 
-	handleLibDeps := func(dep android.Module) {
+	handleLibDeps := func(dep android.ModuleProxy) {
 		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
 			if m, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
 				extraCombinedJars = append(extraCombinedJars, m.ImplementationAndResourcesJars...)
@@ -193,19 +201,19 @@
 		}
 	}
 
-	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+	for _, dep := range ctx.GetDirectDepsProxyWithTag(libTag) {
 		handleLibDeps(dep)
 	}
-	for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) {
+	for _, dep := range ctx.GetDirectDepsProxyWithTag(sdkLibTag) {
 		handleLibDeps(dep)
 	}
 	// handle the runtimeOnly tag for strict_mode
-	for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyDepTag) {
+	for _, dep := range ctx.GetDirectDepsProxyWithTag(roboRuntimeOnlyDepTag) {
 		handleLibDeps(dep)
 	}
 
-	if instrumentedApp != nil {
-		extraCombinedJars = append(extraCombinedJars, instrumentedApp.implementationAndResourcesJar)
+	if appInfo != nil {
+		extraCombinedJars = append(extraCombinedJars, instrumentedApp.ImplementationAndResourcesJars...)
 	}
 
 	r.stem = proptools.StringDefault(r.overridableProperties.Stem, ctx.ModuleName())
@@ -233,8 +241,8 @@
 		installDeps = append(installDeps, installedResourceApk)
 	}
 
-	runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
-	for _, runtime := range runtimes.(*robolectricRuntimes).runtimes {
+	runtimes := ctx.GetDirectDepProxyWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
+	for _, runtime := range android.OtherModuleProviderOrDefault(ctx, runtimes, RobolectricRuntimesInfoProvider).Runtimes {
 		installDeps = append(installDeps, runtime)
 	}
 
@@ -368,7 +376,7 @@
 	}
 
 	if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil {
-		runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag)
+		runtimeFromSourceModule := ctx.GetDirectDepProxyWithTag(String(r.props.Lib), libTag)
 		if runtimeFromSourceModule == nil {
 			if ctx.Config().AllowMissingDependencies() {
 				ctx.AddMissingDependencies([]string{String(r.props.Lib)})
@@ -386,6 +394,10 @@
 		installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
 		r.runtimes = append(r.runtimes, installedRuntime)
 	}
+
+	android.SetProvider(ctx, RobolectricRuntimesInfoProvider, RobolectricRuntimesInfo{
+		Runtimes: r.runtimes,
+	})
 }
 
 func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
diff --git a/python/binary.go b/python/binary.go
index 5f60761..a3acb34 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -22,8 +22,14 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/cc"
+	"github.com/google/blueprint"
 )
 
+type PythonBinaryInfo struct{}
+
+var PythonBinaryInfoProvider = blueprint.NewProvider[PythonBinaryInfo]()
+
 func init() {
 	registerPythonBinaryComponents(android.InitRegistrationContext)
 }
@@ -103,6 +109,9 @@
 	p.buildBinary(ctx)
 	p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
 		p.installSource.Base(), p.installSource)
+
+	android.SetProvider(ctx, PythonBinaryInfoProvider, PythonBinaryInfo{})
+
 	ctx.SetOutputFiles(android.Paths{p.installSource}, "")
 }
 
@@ -116,13 +125,13 @@
 
 	var launcherPath android.OptionalPath
 	if embeddedLauncher {
-		ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
-			if provider, ok := m.(IntermPathProvider); ok {
+		ctx.VisitDirectDepsProxyWithTag(launcherTag, func(m android.ModuleProxy) {
+			if provider, ok := android.OtherModuleProvider(ctx, m, cc.LinkableInfoProvider); ok {
 				if launcherPath.Valid() {
 					panic(fmt.Errorf("launcher path was found before: %q",
 						launcherPath))
 				}
-				launcherPath = provider.IntermPathForModuleOut()
+				launcherPath = provider.OutputFile
 			}
 		})
 	}
@@ -140,7 +149,7 @@
 	var sharedLibs []string
 	// if embedded launcher is enabled, we need to collect the shared library dependencies of the
 	// launcher
-	for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
+	for _, dep := range ctx.GetDirectDepsProxyWithTag(launcherSharedLibTag) {
 		sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
 	}
 	p.androidMkSharedLibs = sharedLibs
diff --git a/python/python.go b/python/python.go
index 914b77e..09af62e 100644
--- a/python/python.go
+++ b/python/python.go
@@ -22,12 +22,23 @@
 	"regexp"
 	"strings"
 
+	"android/soong/cc"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
 
+type PythonLibraryInfo struct {
+	SrcsPathMappings   []pathMapping
+	DataPathMappings   []pathMapping
+	SrcsZip            android.Path
+	PrecompiledSrcsZip android.Path
+	PkgPath            string
+}
+
+var PythonLibraryInfoProvider = blueprint.NewProvider[PythonLibraryInfo]()
+
 func init() {
 	registerPythonMutators(android.InitRegistrationContext)
 }
@@ -173,16 +184,6 @@
 	}
 }
 
-// interface implemented by Python modules to provide source and data mappings and zip to python
-// modules that depend on it
-type pythonDependency interface {
-	getSrcsPathMappings() []pathMapping
-	getDataPathMappings() []pathMapping
-	getSrcsZip() android.Path
-	getPrecompiledSrcsZip() android.Path
-	getPkgPath() string
-}
-
 // getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination
 func (p *PythonLibraryModule) getSrcsPathMappings() []pathMapping {
 	return p.srcsPathMappings
@@ -212,8 +213,6 @@
 	return &p.properties
 }
 
-var _ pythonDependency = (*PythonLibraryModule)(nil)
-
 func (p *PythonLibraryModule) init() android.Module {
 	p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
@@ -464,7 +463,7 @@
 	expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_first_data)...)
 
 	// Emulate the data property for java_data dependencies.
-	for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
+	for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) {
 		expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
 	}
 
@@ -492,6 +491,14 @@
 	// generate the zipfile of all source and data files
 	p.srcsZip = p.createSrcsZip(ctx, pkgPath)
 	p.precompiledSrcsZip = p.precompileSrcs(ctx)
+
+	android.SetProvider(ctx, PythonLibraryInfoProvider, PythonLibraryInfo{
+		SrcsPathMappings:   p.getSrcsPathMappings(),
+		DataPathMappings:   p.getDataPathMappings(),
+		SrcsZip:            p.getSrcsZip(),
+		PkgPath:            p.getPkgPath(),
+		PrecompiledSrcsZip: p.getPrecompiledSrcsZip(),
+	})
 }
 
 func isValidPythonPath(path string) error {
@@ -657,16 +664,16 @@
 		stdLib = p.srcsZip
 		stdLibPkg = p.getPkgPath()
 	} else {
-		ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) {
-			if dep, ok := module.(pythonDependency); ok {
-				stdLib = dep.getPrecompiledSrcsZip()
-				stdLibPkg = dep.getPkgPath()
+		ctx.VisitDirectDepsProxyWithTag(hostStdLibTag, func(module android.ModuleProxy) {
+			if dep, ok := android.OtherModuleProvider(ctx, module, PythonLibraryInfoProvider); ok {
+				stdLib = dep.PrecompiledSrcsZip
+				stdLibPkg = dep.PkgPath
 			}
 		})
 	}
-	ctx.VisitDirectDepsWithTag(hostLauncherTag, func(module android.Module) {
-		if dep, ok := module.(IntermPathProvider); ok {
-			optionalLauncher := dep.IntermPathForModuleOut()
+	ctx.VisitDirectDepsProxyWithTag(hostLauncherTag, func(module android.ModuleProxy) {
+		if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok {
+			optionalLauncher := dep.OutputFile
 			if optionalLauncher.Valid() {
 				launcher = optionalLauncher.Path()
 			}
@@ -674,9 +681,9 @@
 	})
 	var launcherSharedLibs android.Paths
 	var ldLibraryPath []string
-	ctx.VisitDirectDepsWithTag(hostlauncherSharedLibTag, func(module android.Module) {
-		if dep, ok := module.(IntermPathProvider); ok {
-			optionalPath := dep.IntermPathForModuleOut()
+	ctx.VisitDirectDepsProxyWithTag(hostlauncherSharedLibTag, func(module android.ModuleProxy) {
+		if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok {
+			optionalPath := dep.OutputFile
 			if optionalPath.Valid() {
 				launcherSharedLibs = append(launcherSharedLibs, optionalPath.Path())
 				ldLibraryPath = append(ldLibraryPath, filepath.Dir(optionalPath.Path().String()))
@@ -707,16 +714,6 @@
 	return out
 }
 
-// isPythonLibModule returns whether the given module is a Python library PythonLibraryModule or not
-func isPythonLibModule(module blueprint.Module) bool {
-	if _, ok := module.(*PythonLibraryModule); ok {
-		if _, ok := module.(*PythonBinaryModule); !ok {
-			return true
-		}
-	}
-	return false
-}
-
 // collectPathsFromTransitiveDeps checks for source/data files for duplicate paths
 // for module and its transitive dependencies and collects list of data/source file
 // zips for transitive dependencies.
@@ -737,7 +734,7 @@
 	var result android.Paths
 
 	// visit all its dependencies in depth first.
-	ctx.WalkDeps(func(child, parent android.Module) bool {
+	ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool {
 		// we only collect dependencies tagged as python library deps
 		if ctx.OtherModuleDependencyTag(child) != pythonLibTag {
 			return false
@@ -747,27 +744,29 @@
 		}
 		seen[child] = true
 		// Python modules only can depend on Python libraries.
-		if !isPythonLibModule(child) {
+		dep, isLibrary := android.OtherModuleProvider(ctx, child, PythonLibraryInfoProvider)
+		_, isBinary := android.OtherModuleProvider(ctx, child, PythonBinaryInfoProvider)
+		if !isLibrary || isBinary {
 			ctx.PropertyErrorf("libs",
 				"the dependency %q of module %q is not Python library!",
 				ctx.OtherModuleName(child), ctx.ModuleName())
 		}
 		// collect source and data paths, checking that there are no duplicate output file conflicts
-		if dep, ok := child.(pythonDependency); ok {
-			srcs := dep.getSrcsPathMappings()
+		if isLibrary {
+			srcs := dep.SrcsPathMappings
 			for _, path := range srcs {
 				checkForDuplicateOutputPath(ctx, destToPySrcs,
 					path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child))
 			}
-			data := dep.getDataPathMappings()
+			data := dep.DataPathMappings
 			for _, path := range data {
 				checkForDuplicateOutputPath(ctx, destToPyData,
 					path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child))
 			}
 			if precompiled {
-				result = append(result, dep.getPrecompiledSrcsZip())
+				result = append(result, dep.PrecompiledSrcsZip)
 			} else {
-				result = append(result, dep.getSrcsZip())
+				result = append(result, dep.SrcsZip)
 			}
 		}
 		return true
diff --git a/python/test.go b/python/test.go
index 37947dd..c780a6f 100644
--- a/python/test.go
+++ b/python/test.go
@@ -199,13 +199,13 @@
 	}
 
 	if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 {
-		ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+		ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) {
 			p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")})
 		})
 	}
 
 	// Emulate the data property for java_data dependencies.
-	for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
+	for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) {
 		for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") {
 			p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath})
 		}