Merge "Allowlist chre_api to resolve bp2build failure" into main
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 09944ae..f411026 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -255,6 +255,7 @@
 		"hardware/interfaces/audio/aidl/common":                   Bp2BuildDefaultTrue,
 		"hardware/interfaces/audio/aidl/default":                  Bp2BuildDefaultTrue,
 		"hardware/interfaces/audio/aidl/sounddose":                Bp2BuildDefaultTrue,
+		"hardware/interfaces/camera/metadata/aidl":                Bp2BuildDefaultTrueRecursively,
 		"hardware/interfaces/common/aidl":                         Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/fmq/aidl":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/support":                      Bp2BuildDefaultTrue,
@@ -396,6 +397,7 @@
 		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/alsa_utils":                                Bp2BuildDefaultTrueRecursively,
 		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
+		"system/media/camera":                                    Bp2BuildDefaultTrueRecursively,
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
 		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
@@ -437,6 +439,7 @@
 		// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
 		// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
 		"external/bazelbuild-rules_android":/* recursive = */ true,
+		"external/bazelbuild-rules_cc":/* recursive = */ true,
 		"external/bazelbuild-rules_java":/* recursive = */ true,
 		"external/bazelbuild-rules_license":/* recursive = */ true,
 		"external/bazelbuild-rules_go":/* recursive = */ true,
diff --git a/android/bazel.go b/android/bazel.go
index e4fada0..94b36e3 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -689,3 +689,21 @@
 	})
 	return validatedOutputFilePath
 }
+
+func RunsOn(hostSupported bool, deviceSupported bool, unitTest bool) []string {
+	var runsOn []string
+
+	if hostSupported && deviceSupported {
+		runsOn = []string{"host_without_device", "device"}
+	} else if hostSupported {
+		if unitTest {
+			runsOn = []string{"host_without_device"}
+		} else {
+			runsOn = []string{"host_with_device"}
+		}
+	} else if deviceSupported {
+		runsOn = []string{"device"}
+	}
+
+	return runsOn
+}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 02ae5ca..86829ce 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -205,6 +205,21 @@
 	return labels
 }
 
+func BazelLabelForSrcPatternExcludes(ctx BazelConversionPathContext, dir, pattern string, excludes []string) bazel.LabelList {
+	topRelPaths, err := ctx.GlobWithDeps(filepath.Join(dir, pattern), excludes)
+	if err != nil {
+		ctx.ModuleErrorf("Could not search dir: %s for pattern %s due to %v\n", dir, pattern, err)
+	}
+	// An intermediate list of labels relative to `dir` that assumes that there no subpacakges beneath `dir`
+	dirRelLabels := []bazel.Label{}
+	for _, topRelPath := range topRelPaths {
+		dirRelPath := Rel(ctx, dir, topRelPath)
+		dirRelLabels = append(dirRelLabels, bazel.Label{Label: "./" + dirRelPath})
+	}
+	// Return the package boudary resolved labels
+	return TransformSubpackagePaths(ctx.Config(), dir, bazel.MakeLabelList(dirRelLabels))
+}
+
 // Returns true if a prefix + components[:i] is a package boundary.
 //
 // A package boundary is determined by a BUILD file in the directory. This can happen in 2 cases:
diff --git a/android/bazel_paths_test.go b/android/bazel_paths_test.go
index 75b77a3..bed719c 100644
--- a/android/bazel_paths_test.go
+++ b/android/bazel_paths_test.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"fmt"
 	"path/filepath"
 	"testing"
 
@@ -114,8 +115,9 @@
 
 type TestBazelConversionPathContext struct {
 	TestBazelConversionContext
-	moduleDir string
-	cfg       Config
+	moduleDir       string
+	cfg             Config
+	mockGlobResults *[]string
 }
 
 func (ctx *TestBazelConversionPathContext) AddNinjaFileDeps(...string) {
@@ -123,7 +125,10 @@
 }
 
 func (ctx *TestBazelConversionPathContext) GlobWithDeps(string, []string) ([]string, error) {
-	panic("Unimplemented")
+	if ctx.mockGlobResults == nil {
+		return []string{}, fmt.Errorf("Set mock glob results first")
+	}
+	return *ctx.mockGlobResults, nil
 }
 
 func (ctx *TestBazelConversionPathContext) PropertyErrorf(string, string, ...interface{}) {
@@ -190,3 +195,46 @@
 		}
 	}
 }
+
+// Check that the files in a specific directory are returned with labels that respect package boundaries
+// Since the test uses a mock for GlobWithDeps, the params passed to BazelLabelForSrcPatternExcludes are no-ops
+func TestBazelLabelForSrcPatternExcludes(t *testing.T) {
+	cfg := NullConfig("out", "out/soong")
+	cfg.fs = pathtools.MockFs(map[string][]byte{
+		"x/Android.bp":   nil,
+		"x/y/Android.bp": nil,
+		// .proto files
+		"foo.proto":     nil,
+		"x/bar.proto":   nil,
+		"x/baz.proto":   nil,
+		"x/y/qux.proto": nil,
+	})
+
+	var ctx BazelConversionPathContext = &TestBazelConversionPathContext{
+		cfg: cfg,
+	}
+
+	// Root dir
+	ctx.(*TestBazelConversionPathContext).mockGlobResults = &[]string{"foo.proto", "x/bar.proto", "x/baz.proto", "x/y/qux.proto"}
+	actualLabelsFromRoot := BazelLabelForSrcPatternExcludes(ctx, ".", "**/*.proto", []string{})
+	expectedLabelsAsString := []string{"foo.proto", "//x:bar.proto", "//x:baz.proto", "//x/y:qux.proto"}
+	for i, actual := range actualLabelsFromRoot.Includes {
+		AssertStringEquals(t, "Error in finding src labels relative to root directory", expectedLabelsAsString[i], actual.Label)
+	}
+
+	// x dir
+	ctx.(*TestBazelConversionPathContext).mockGlobResults = &[]string{"x/bar.proto", "x/baz.proto", "x/y/qux.proto"}
+	actualLabelsFromRoot = BazelLabelForSrcPatternExcludes(ctx, "x", "**/*.proto", []string{})
+	expectedLabelsAsString = []string{"bar.proto", "baz.proto", "//x/y:qux.proto"}
+	for i, actual := range actualLabelsFromRoot.Includes {
+		AssertStringEquals(t, "Error in finding src labels relative to x directory", expectedLabelsAsString[i], actual.Label)
+	}
+
+	// y dir
+	ctx.(*TestBazelConversionPathContext).mockGlobResults = &[]string{"x/y/qux.proto"}
+	actualLabelsFromRoot = BazelLabelForSrcPatternExcludes(ctx, "x/y", "**/*.proto", []string{})
+	expectedLabelsAsString = []string{"qux.proto"}
+	for i, actual := range actualLabelsFromRoot.Includes {
+		AssertStringEquals(t, "Error in finding src labels relative to x/y directory", expectedLabelsAsString[i], actual.Label)
+	}
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8368db1..da059eb 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3870,6 +3870,7 @@
 			}
 		`+vndkLibrariesTxtFiles("current"), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = proptools.StringPtr(tc.vndkVersion)
+				variables.KeepVndk = proptools.BoolPtr(true)
 			}))
 			ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", tc.expectedFiles)
 		})
diff --git a/apex/vndk.go b/apex/vndk.go
index 095e89d..68b3a40 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -80,6 +80,10 @@
 			// config targets the 'current' VNDK (see `vndkVersion`).
 			ab.Disable()
 		}
+		if proptools.String(ab.vndkProperties.Vndk_version) != "" &&
+			apiLevel.GreaterThanOrEqualTo(android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())) {
+			ab.Disable()
+		}
 	}
 }
 
@@ -103,7 +107,7 @@
 		}
 	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
 		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
-		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion)...)
+		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...)
 	}
 }
 
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 21526c3..4327a61 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -51,6 +51,7 @@
 	`+vndkLibrariesTxtFiles("current"),
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.DeviceVndkVersion = proptools.StringPtr("")
+			variables.KeepVndk = proptools.BoolPtr(true)
 		}),
 	)
 	// VNDK-Lite contains only core variants of VNDK-Sp libraries
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 3c037b4..abceac8 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -135,6 +135,10 @@
         "//build/bazel/platforms/os:linux_musl": ["linux.cpp"],
         "//conditions:default": [],
     })`,
+				"runs_on": `[
+        "host_without_device",
+        "device",
+    ]`,
 			},
 			},
 		},
@@ -158,6 +162,10 @@
 				"gtest":          "False",
 				"local_includes": `["."]`,
 				"srcs":           `["test.cpp"]`,
+				"runs_on": `[
+        "host_without_device",
+        "device",
+    ]`,
 			},
 			},
 		},
@@ -185,6 +193,10 @@
         ":libgtest_main",
         ":libgtest",
     ]`,
+				"runs_on": `[
+        "host_without_device",
+        "device",
+    ]`,
 			},
 			},
 		},
@@ -215,6 +227,7 @@
         ":libgtest_main",
         ":libgtest",
     ]`,
+				"runs_on": `["device"]`,
 			},
 			},
 		},
@@ -244,6 +257,7 @@
         ":libgtest_main",
         ":libgtest",
     ]`,
+				"runs_on": `["device"]`,
 			},
 			},
 		},
@@ -280,6 +294,7 @@
 				"template_test_config":  `"test_config_template.xml"`,
 				"deps":                  `[":libgtest_isolated_main"]`,
 				"dynamic_deps":          `[":liblog"]`,
+				"runs_on":               `["device"]`,
 			},
 			},
 		},
@@ -306,6 +321,7 @@
         ":libgtest",
         ":libgtest_main",
     ]`,
+				"runs_on": `["device"]`,
 			},
 			},
 		},
@@ -331,6 +347,7 @@
 				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
 				"deps":                   `[":libgtest_isolated_main"]`,
 				"dynamic_deps":           `[":liblog"]`,
+				"runs_on":                `["device"]`,
 			},
 			},
 		},
@@ -361,12 +378,14 @@
     ]`,
 				"gtest":                  "True",
 				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"runs_on":                `["device"]`,
 			},
 			},
 			{"cc_test", "mytest_with_no_gtest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"gtest":                  "False",
 				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"runs_on":                `["device"]`,
 			},
 			},
 		},
diff --git a/cc/cc_test.go b/cc/cc_test.go
index d95ed3f..7ce0f37 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -654,6 +654,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
+	config.TestProductVariables.KeepVndk = BoolPtr(true)
 	ctx := testCcWithConfig(t, config)
 
 	module := ctx.ModuleForTests("llndk.libraries.txt", "android_common")
diff --git a/cc/test.go b/cc/test.go
index 0be2301..adc80c2 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -686,6 +686,8 @@
 
 	tidyAttributes
 	tradefed.TestConfigAttributes
+
+	Runs_on bazel.StringListAttribute
 }
 
 // testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's
@@ -730,6 +732,8 @@
 
 	addImplicitGtestDeps(ctx, &testBinaryAttrs, gtest, gtestIsolated)
 
+	var unitTest *bool
+
 	for _, testProps := range m.GetProperties() {
 		if p, ok := testProps.(*TestBinaryProperties); ok {
 			useVendor := false // TODO Bug: 262914724
@@ -745,9 +749,15 @@
 				&testInstallBase,
 			)
 			testBinaryAttrs.TestConfigAttributes = testConfigAttributes
+			unitTest = p.Test_options.Unit_test
 		}
 	}
 
+	testBinaryAttrs.Runs_on = bazel.MakeStringListAttribute(android.RunsOn(
+		m.ModuleBase.HostSupported(),
+		m.ModuleBase.DeviceSupported(),
+		gtest || (unitTest != nil && *unitTest)))
+
 	// TODO (b/262914724): convert to tradefed_cc_test and tradefed_cc_test_host
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
diff --git a/cc/vndk.go b/cc/vndk.go
index 7a2286e..82a2a4b 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -39,25 +39,34 @@
 	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
 )
 
-func VndkLibrariesTxtModules(vndkVersion string) []string {
+func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string {
 	if vndkVersion == "current" {
-		return []string{
-			llndkLibrariesTxt,
+		result := []string{
 			vndkCoreLibrariesTxt,
 			vndkSpLibrariesTxt,
 			vndkPrivateLibrariesTxt,
 			vndkProductLibrariesTxt,
 		}
+
+		// TODO(b/290159430) This part will not be required once deprecation of VNDK
+		// is handled with 'ro.vndk.version' property
+		if !ctx.Config().IsVndkDeprecated() {
+			result = append(result, llndkLibrariesTxt)
+		}
+
+		return result
 	}
 	// Snapshot vndks have their own *.libraries.VER.txt files.
 	// Note that snapshots don't have "vndkcorevariant.libraries.VER.txt"
-	return []string{
-		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
+	result := []string{
 		insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkSpLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkProductLibrariesTxt, vndkVersion),
+		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
 	}
+
+	return result
 }
 
 type VndkProperties struct {
@@ -352,11 +361,19 @@
 		return false
 	}
 
-	// prebuilt vndk modules should match with device
 	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
 	// When b/142675459 is landed, remove following check
-	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.MatchesWithDevice(mctx.DeviceConfig()) {
-		return false
+	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+		// prebuilt vndk modules should match with device
+		if !p.MatchesWithDevice(mctx.DeviceConfig()) {
+			return false
+		}
+
+		// ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
+		platformVndkApiLevel := android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())
+		if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
+			return false
+		}
 	}
 
 	if lib, ok := m.linker.(libraryInterface); ok {
@@ -519,11 +536,15 @@
 }
 
 func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	var filename string
-	if BoolDefault(txt.properties.Insert_vndk_version, true) {
+	filename := txt.Name()
+
+	shouldInsertVndkVersion := BoolDefault(txt.properties.Insert_vndk_version, true)
+	// llndk.libraries.txt file installed in the system image should not contain version info.
+	if ctx.Config().IsVndkDeprecated() && txt.Name() == llndkLibrariesTxt {
+		shouldInsertVndkVersion = false
+	}
+	if shouldInsertVndkVersion {
 		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
-	} else {
-		filename = txt.Name()
 	}
 
 	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 37819a4..5e526db 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -131,6 +131,12 @@
 
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
+	platformVndkApiLevel := android.ApiLevelOrPanic(ctx, ctx.DeviceConfig().PlatformVndkVersion())
+	if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
+		// This prebuilt VNDK module is not required for the current build
+		ctx.Module().HideFromMake()
+		return nil
+	}
 
 	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
 		ctx.Module().HideFromMake()
diff --git a/genrule/genrule.go b/genrule/genrule.go
index aa4295d..8e3f278 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -140,7 +140,7 @@
 	// prebuilts or scripts that do not need a module to build them.
 	Tools []string
 
-	// Local file that is used as the tool
+	// Local files that are used by the tool
 	Tool_files []string `android:"path"`
 
 	// List of directories to export generated headers from
@@ -403,7 +403,6 @@
 	}
 
 	addLabelsForInputs := func(propName string, include, exclude []string) android.Paths {
-
 		includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
 		var srcFiles android.Paths
 		for _, in := range include {
diff --git a/java/aar.go b/java/aar.go
index 308a48c..0216196 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -30,7 +30,6 @@
 )
 
 type AndroidLibraryDependency interface {
-	LibraryDependency
 	ExportPackage() android.Path
 	ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
 	RRODirsDepSet() *android.DepSet[rroDir]
@@ -778,17 +777,9 @@
 		ctx.CheckbuildFile(a.aarFile)
 	}
 
-	a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles,
-		android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...)
-
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			if lib, ok := m.(LibraryDependency); ok {
-				a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
-			}
-		}
-	})
-	a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
+	proguardSpecInfo := a.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
 
 	prebuiltJniPackages := android.Paths{}
 	ctx.VisitDirectDeps(func(module android.Module) {
@@ -939,10 +930,6 @@
 func (a *AARImport) ExportPackage() android.Path {
 	return a.exportPackage
 }
-func (a *AARImport) ExportedProguardFlagFiles() android.Paths {
-	return android.Paths{a.proguardFlags}
-}
-
 func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
 	return a.resourcesNodesDepSet
 }
@@ -1046,10 +1033,17 @@
 
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
 	a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
-	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
 	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
 	aarRTxt := extractedAARDir.Join(ctx, "R.txt")
 	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
+	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
+	ctx.SetProvider(ProguardSpecInfoProvider, ProguardSpecInfo{
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			android.Paths{a.proguardFlags},
+			nil,
+		),
+	})
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        unzipAAR,
diff --git a/java/app.go b/java/app.go
index 1d1ea97..7cf86c0 100755
--- a/java/app.go
+++ b/java/app.go
@@ -200,10 +200,6 @@
 	return Bool(a.properties.Installable)
 }
 
-func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
-	return nil
-}
-
 func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
 	return a.aapt.resourcesNodesDepSet
 }
@@ -482,8 +478,10 @@
 func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
 	var staticLibProguardFlagFiles android.Paths
 	ctx.VisitDirectDeps(func(m android.Module) {
-		if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
+		depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
+		staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...)
+		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
+			staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.ProguardFlagsFiles.ToList()...)
 		}
 	})
 
diff --git a/java/base.go b/java/base.go
index f5eb01c..a9b986b 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1670,6 +1670,49 @@
 	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
 }
 
+func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo {
+	transitiveUnconditionalExportedFlags := []*android.DepSet[android.Path]{}
+	transitiveProguardFlags := []*android.DepSet[android.Path]{}
+
+	ctx.VisitDirectDeps(func(m android.Module) {
+		depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
+		depTag := ctx.OtherModuleDependencyTag(m)
+
+		if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
+			transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+			transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+		}
+
+		if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil {
+			transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles)
+		}
+	})
+
+	directUnconditionalExportedFlags := android.Paths{}
+	proguardFlagsForThisModule := android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)
+	exportUnconditionally := proptools.Bool(j.dexProperties.Optimize.Export_proguard_flags_files)
+	if exportUnconditionally {
+		// if we explicitly export, then our unconditional exports are the same as our transitive flags
+		transitiveUnconditionalExportedFlags = transitiveProguardFlags
+		directUnconditionalExportedFlags = proguardFlagsForThisModule
+	}
+
+	return ProguardSpecInfo{
+		Export_proguard_flags_files: exportUnconditionally,
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			proguardFlagsForThisModule,
+			transitiveProguardFlags,
+		),
+		UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			directUnconditionalExportedFlags,
+			transitiveUnconditionalExportedFlags,
+		),
+	}
+
+}
+
 // Returns a copy of the supplied flags, but with all the errorprone-related
 // fields copied to the regular build's fields.
 func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
diff --git a/java/dex.go b/java/dex.go
index 7e7da00..df501bf 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -71,6 +71,10 @@
 
 		// Specifies the locations of files containing proguard flags.
 		Proguard_flags_files []string `android:"path"`
+
+		// If true, transitive reverse dependencies of this module will have this
+		// module's proguard spec appended to their optimization action
+		Export_proguard_flags_files *bool
 	}
 
 	// Keep the data uncompressed. We always need uncompressed dex for execution,
diff --git a/java/dex_test.go b/java/dex_test.go
index 2ba3831..ec1ef15 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -327,7 +328,7 @@
 		fooD8.Args["d8Flags"], staticLibHeader.String())
 }
 
-func TestProguardFlagsInheritance(t *testing.T) {
+func TestProguardFlagsInheritanceStatic(t *testing.T) {
 	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
 		android_app {
 			name: "app",
@@ -380,3 +381,246 @@
 	android.AssertStringDoesContain(t, "expected tertiary_lib's proguard flags from inherited dep",
 		appR8.Args["r8Flags"], "tertiary.flags")
 }
+
+func TestProguardFlagsInheritance(t *testing.T) {
+	directDepFlagsFileName := "direct_dep.flags"
+	transitiveDepFlagsFileName := "transitive_dep.flags"
+	bp := `
+		android_app {
+			name: "app",
+			static_libs: ["androidlib"], // this must be static_libs to initate dexing
+			platform_apis: true,
+		}
+
+		android_library {
+			name: "androidlib",
+			static_libs: ["app_dep"],
+		}
+
+		java_library {
+			name: "app_dep",
+			%s: ["dep"],
+		}
+
+		java_library {
+			name: "dep",
+			%s: ["transitive_dep"],
+			optimize: {
+				proguard_flags_files: ["direct_dep.flags"],
+				export_proguard_flags_files: %v,
+			},
+		}
+
+		java_library {
+			name: "transitive_dep",
+			optimize: {
+				proguard_flags_files: ["transitive_dep.flags"],
+				export_proguard_flags_files: %v,
+			},
+		}
+	`
+
+	testcases := []struct {
+		name                           string
+		depType                        string
+		depExportsFlagsFiles           bool
+		transitiveDepType              string
+		transitiveDepExportsFlagsFiles bool
+		expectedFlagsFiles             []string
+	}{
+		{
+			name:                           "libs_export_libs_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_libs_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_static_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_no-export_static_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_libs_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_libs_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_static_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{},
+		},
+		{
+			name:                           "static_no-export_static_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_libs_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_no-export_libs_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_static_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_static_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_libs_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{},
+		},
+		{
+			name:                           "static_no-export_libs_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_static_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_static_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+	}
+
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				android.FixtureMergeMockFs(android.MockFS{
+					directDepFlagsFileName:     nil,
+					transitiveDepFlagsFileName: nil,
+				}),
+			).RunTestWithBp(t,
+				fmt.Sprintf(
+					bp,
+					tc.depType,
+					tc.transitiveDepType,
+					tc.depExportsFlagsFiles,
+					tc.transitiveDepExportsFlagsFiles,
+				),
+			)
+			appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+
+			shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles)
+			if shouldHaveDepFlags {
+				android.AssertStringDoesContain(t, "expected deps's proguard flags",
+					appR8.Args["r8Flags"], directDepFlagsFileName)
+			} else {
+				android.AssertStringDoesNotContain(t, "app did not expect deps's proguard flags",
+					appR8.Args["r8Flags"], directDepFlagsFileName)
+			}
+
+			shouldHaveTransitiveDepFlags := android.InList(transitiveDepFlagsFileName, tc.expectedFlagsFiles)
+			if shouldHaveTransitiveDepFlags {
+				android.AssertStringDoesContain(t, "expected transitive deps's proguard flags",
+					appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+			} else {
+				android.AssertStringDoesNotContain(t, "app did not expect transitive deps's proguard flags",
+					appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+			}
+		})
+	}
+}
+
+func TestProguardFlagsInheritanceAppImport(t *testing.T) {
+	bp := `
+		android_app {
+			name: "app",
+			static_libs: ["aarimport"], // this must be static_libs to initate dexing
+			platform_apis: true,
+		}
+
+		android_library {
+			name: "androidlib",
+			static_libs: ["aarimport"],
+		}
+
+		android_library_import {
+			name: "aarimport",
+			aars: ["import.aar"],
+		}
+	`
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, bp)
+
+	appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+	android.AssertStringDoesContain(t, "expected aarimports's proguard flags",
+		appR8.Args["r8Flags"], "proguard.txt")
+}
diff --git a/java/java.go b/java/java.go
index 70aba8e..5f59fe4 100644
--- a/java/java.go
+++ b/java/java.go
@@ -225,6 +225,23 @@
 	}, "jar_name", "partition", "main_class")
 )
 
+type ProguardSpecInfo struct {
+	// If true, proguard flags files will be exported to reverse dependencies across libs edges
+	// If false, proguard flags files will only be exported to reverse dependencies across
+	// static_libs edges.
+	Export_proguard_flags_files bool
+
+	// TransitiveDepsProguardSpecFiles is a depset of paths to proguard flags files that are exported from
+	// all transitive deps. This list includes all proguard flags files from transitive static dependencies,
+	// and all proguard flags files from transitive libs dependencies which set `export_proguard_spec: true`.
+	ProguardFlagsFiles *android.DepSet[android.Path]
+
+	// implementation detail to store transitive proguard flags files from exporting shared deps
+	UnconditionallyExportedProguardFlags *android.DepSet[android.Path]
+}
+
+var ProguardSpecInfoProvider = blueprint.NewProvider(ProguardSpecInfo{})
+
 // JavaInfo contains information about a java module for use by modules that depend on it.
 type JavaInfo struct {
 	// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
@@ -310,11 +327,6 @@
 	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 }
 
-// Provides transitive Proguard flag files to downstream DEX jars.
-type LibraryDependency interface {
-	ExportedProguardFlagFiles() android.Paths
-}
-
 // TODO(jungjw): Move this to kythe.go once it's created.
 type xref interface {
 	XrefJavaFiles() android.Paths
@@ -626,12 +638,6 @@
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
-var _ LibraryDependency = (*Library)(nil)
-
-func (j *Library) ExportedProguardFlagFiles() android.Paths {
-	return j.exportedProguardFlagFiles
-}
-
 var _ android.ApexModule = (*Library)(nil)
 
 // Provides access to the list of permitted packages from apex boot jars.
@@ -730,15 +736,9 @@
 		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 
-	j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles,
-		android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)...)
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
-		}
-	})
-	j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
-
+	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/rust/config/lints.go b/rust/config/lints.go
index ef6b315..9322981 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -46,6 +46,7 @@
 		"-A deprecated",
 		"-D missing-docs",
 		"-D warnings",
+		"-D unsafe_op_in_unsafe_fn",
 	}
 	// Default Clippy lints. These are applied on top of defaultRustcLints.
 	// It should be assumed that any warning lint will be promoted to a
@@ -55,6 +56,7 @@
 		"-A clippy::unnecessary-wraps",
 		"-A clippy::unusual-byte-groupings",
 		"-A clippy::upper-case-acronyms",
+		"-D clippy::undocumented_unsafe_blocks",
 	}
 
 	// Rust lints for vendor code.