Merge "Propagate DirectlyInAnyApex to transitive dependencies" into main
diff --git a/android/apex.go b/android/apex.go
index fcbd13e..2ac6ed0 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -350,7 +350,8 @@
 // ApexModuleBase provides the default implementation for the ApexModule interface. APEX-aware
 // modules are expected to include this struct and call InitApexModule().
 type ApexModuleBase struct {
-	ApexProperties ApexProperties
+	ApexProperties     ApexProperties
+	apexPropertiesLock sync.Mutex // protects ApexProperties during parallel apexDirectlyInAnyMutator
 
 	canHaveApexVariants bool
 
@@ -761,18 +762,22 @@
 
 // UpdateDirectlyInAnyApex uses the final module to store if any variant of this module is directly
 // in any APEX, and then copies the final value to all the modules. It also copies the
-// DirectlyInAnyApex value to any direct dependencies with a CopyDirectlyInAnyApexTag dependency
-// tag.
+// DirectlyInAnyApex value to any transitive dependencies with a CopyDirectlyInAnyApexTag
+// dependency tag.
 func UpdateDirectlyInAnyApex(mctx BottomUpMutatorContext, am ApexModule) {
 	base := am.apexModuleBase()
-	// Copy DirectlyInAnyApex and InAnyApex from any direct dependencies with a
+	// Copy DirectlyInAnyApex and InAnyApex from any transitive dependencies with a
 	// CopyDirectlyInAnyApexTag dependency tag.
-	mctx.VisitDirectDeps(func(dep Module) {
-		if _, ok := mctx.OtherModuleDependencyTag(dep).(CopyDirectlyInAnyApexTag); ok {
-			depBase := dep.(ApexModule).apexModuleBase()
+	mctx.WalkDeps(func(child, parent Module) bool {
+		if _, ok := mctx.OtherModuleDependencyTag(child).(CopyDirectlyInAnyApexTag); ok {
+			depBase := child.(ApexModule).apexModuleBase()
+			depBase.apexPropertiesLock.Lock()
+			defer depBase.apexPropertiesLock.Unlock()
 			depBase.ApexProperties.DirectlyInAnyApex = base.ApexProperties.DirectlyInAnyApex
 			depBase.ApexProperties.InAnyApex = base.ApexProperties.InAnyApex
+			return true
 		}
+		return false
 	})
 
 	if base.ApexProperties.DirectlyInAnyApex {
diff --git a/java/base.go b/java/base.go
index d04e97c..b9e236c 100644
--- a/java/base.go
+++ b/java/base.go
@@ -716,11 +716,7 @@
 	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
 
-	isApexVariantSdkLibImplLib := j.SdkLibraryName() != nil &&
-		strings.HasSuffix(j.Name(), ".impl") &&
-		len(apexInfo.InApexVariants) > 0
-
-	if (j.DirectlyInAnyApex() || isApexVariantSdkLibImplLib) && !isJacocoAgent && !apexInfo.IsForPlatform() {
+	if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
 		if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
 			return true
 		} else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8c91288..72eb6e3 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1506,6 +1506,12 @@
 
 var _ android.InstallNeededDependencyTag = sdkLibraryComponentTag{}
 
+// To satisfy the CopyDirectlyInAnyApexTag interface. Implementation library of the sdk library
+// in an apex is considered to be directly in the apex, as if it was listed in java_libs.
+func (t sdkLibraryComponentTag) CopyDirectlyInAnyApex() {}
+
+var _ android.CopyDirectlyInAnyApexTag = implLibraryTag
+
 func (t sdkLibraryComponentTag) InstallDepNeeded() bool {
 	return t.name == "xml-permissions-file" || t.name == "impl-library"
 }