Split DepIsInSameApex into outgoing and incoming

Prepare for calling DepIsInSameApex from the apex transition mutator
by splitting all the implementations in two, one that is called on the
outgoing module and only takes the depTag, and one that is called on the
incoming module and only takes the depTag.

apexBundle.depVisitor was passing the child into android.IsDepInSameApex
for both the parent and child paramters.  The parent field was only
used to find the type on which to call DepIsInSameApex, so this
effectively used the child's implementation of DepIsInSameApex.  That
used to be necessary when the parent and child were of different
module types, as the parent module type may not have been aware
of the rules for the child module type, but is no longer necessary
with split outgoing and incoming DepIsInSameApex.

Bug: 372543712
Test: all soong tests pass
Change-Id: If7c81ec3f7b1ea69d77e9ad7694e238820194e59
diff --git a/android/apex.go b/android/apex.go
index 78511f9..db955b5 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -149,15 +149,25 @@
 // extracted from ApexModule to make it easier to define custom subsets of the ApexModule interface
 // and improve code navigation within the IDE.
 type DepIsInSameApex interface {
-	// DepIsInSameApex tests if the other module 'dep' is considered as part of the same APEX as
-	// this module. For example, a static lib dependency usually returns true here, while a
+	// OutgoingDepIsInSameApex tests if the module depended on via 'tag' is considered as part of
+	// the same APEX as this module. For example, a static lib dependency usually returns true here, while a
 	// shared lib dependency to a stub library returns false.
 	//
 	// This method must not be called directly without first ignoring dependencies whose tags
 	// implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps()
 	// are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use
 	// IsDepInSameApex instead.
-	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+	OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool
+
+	// IncomingDepIsInSameApex tests if this module depended on via 'tag' is considered as part of
+	// the same APEX as the depending module module. For example, a static lib dependency usually
+	// returns true here, while a shared lib dependency to a stub library returns false.
+	//
+	// This method must not be called directly without first ignoring dependencies whose tags
+	// implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps()
+	// are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use
+	// IsDepInSameApex instead.
+	IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool
 }
 
 func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool {
@@ -167,7 +177,14 @@
 		// apex as the parent.
 		return false
 	}
-	return module.(DepIsInSameApex).DepIsInSameApex(ctx, dep)
+
+	if m, ok := module.(DepIsInSameApex); ok && !m.OutgoingDepIsInSameApex(depTag) {
+		return false
+	}
+	if d, ok := dep.(DepIsInSameApex); ok && !d.IncomingDepIsInSameApex(depTag) {
+		return false
+	}
+	return true
 }
 
 // ApexModule is the interface that a module type is expected to implement if the module has to be
@@ -385,7 +402,15 @@
 }
 
 // Implements ApexModule
-func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool {
+func (m *ApexModuleBase) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	// By default, if there is a dependency from A to B, we try to include both in the same
+	// APEX, unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning
+	// true. This is overridden by some module types like apex.ApexBundle, cc.Module,
+	// java.Module, etc.
+	return true
+}
+
+func (m *ApexModuleBase) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool {
 	// By default, if there is a dependency from A to B, we try to include both in the same
 	// APEX, unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning
 	// true. This is overridden by some module types like apex.ApexBundle, cc.Module,
@@ -661,7 +686,7 @@
 // variant.
 func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) {
 	// anyInSameApex returns true if the two ApexInfo lists contain any values in an
-	// InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to
+	// InApexVariants list in common. It is used instead of OutgoingDepIsInSameApex because it needs to
 	// determine if the dep is in the same APEX due to being directly included, not only if it
 	// is included _because_ it is a dependency.
 	anyInSameApex := func(a, b ApexModule) bool {
@@ -813,7 +838,7 @@
 			// dependencies.
 			return false
 		}
-		if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+		if !IsDepInSameApex(ctx, from, to) {
 			return false
 		}
 		if m, ok := to.(ModuleWithMinSdkVersionCheck); ok {
diff --git a/apex/apex.go b/apex/apex.go
index 912780d..fb0d730 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1222,7 +1222,13 @@
 var _ android.DepIsInSameApex = (*apexBundle)(nil)
 
 // Implements android.DepInInSameApex
-func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
+func (a *apexBundle) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	// direct deps of an APEX bundle are all part of the APEX bundle
+	// TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
+	return true
+}
+
+func (a *apexBundle) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool {
 	// direct deps of an APEX bundle are all part of the APEX bundle
 	// TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
 	return true
@@ -2109,17 +2115,14 @@
 			// like to record requiredNativeLibs even when
 			// DepIsInSameAPex is false. We also shouldn't do
 			// this for host.
-			//
-			// TODO(jiyong): explain why the same module is passed in twice.
-			// Switching the first am to parent breaks lots of tests.
-			if !android.IsDepInSameApex(ctx, am, am) {
+			if !android.IsDepInSameApex(ctx, parent, am) {
 				return false
 			}
 
 			vctx.filesInfo = append(vctx.filesInfo, af)
 			return true // track transitive dependencies
 		} else if rm, ok := child.(*rust.Module); ok {
-			if !android.IsDepInSameApex(ctx, am, am) {
+			if !android.IsDepInSameApex(ctx, parent, am) {
 				return false
 			}
 
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index f93eada..aaf2cb7 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -274,12 +274,15 @@
 }
 
 // Implements android.DepInInSameApex
-func (p *prebuiltCommon) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	tag := ctx.OtherModuleDependencyTag(dep)
+func (p *prebuiltCommon) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
 	_, ok := tag.(exportedDependencyTag)
 	return ok
 }
 
+func (p *prebuiltCommon) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	return true
+}
+
 // apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
 // specific variant and checks that they are supported.
 //
diff --git a/cc/cc.go b/cc/cc.go
index 85b45d0..04b66d4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3761,35 +3761,7 @@
 var _ android.ApexModule = (*Module)(nil)
 
 // Implements android.ApexModule
-func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	depTag := ctx.OtherModuleDependencyTag(dep)
-	libDepTag, isLibDepTag := depTag.(libraryDependencyTag)
-
-	if cc, ok := dep.(*Module); ok {
-		if cc.HasStubsVariants() {
-			if isLibDepTag && libDepTag.shared() {
-				// dynamic dep to a stubs lib crosses APEX boundary
-				return false
-			}
-			if IsRuntimeDepTag(depTag) {
-				// runtime dep to a stubs lib also crosses APEX boundary
-				return false
-			}
-		}
-		if cc.IsLlndk() {
-			return false
-		}
-		if isLibDepTag && libDepTag.fromStatic && libDepTag.shared() {
-			// shared_lib dependency from a static lib is considered as crossing
-			// the APEX boundary because the dependency doesn't actually is
-			// linked; the dependency is used only during the compilation phase.
-			return false
-		}
-
-		if isLibDepTag && libDepTag.excludeInApex {
-			return false
-		}
-	}
+func (c *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
 	if depTag == stubImplDepTag {
 		// We don't track from an implementation library to its stubs.
 		return false
@@ -3803,6 +3775,39 @@
 	return true
 }
 
+func (c *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
+	libDepTag, isLibDepTag := depTag.(libraryDependencyTag)
+
+	if c.HasStubsVariants() {
+		if IsSharedDepTag(depTag) {
+			// dynamic dep to a stubs lib crosses APEX boundary
+			return false
+		}
+		if IsRuntimeDepTag(depTag) {
+			// runtime dep to a stubs lib also crosses APEX boundary
+			return false
+		}
+		if IsHeaderDepTag(depTag) {
+			return false
+		}
+	}
+	if c.IsLlndk() {
+		return false
+	}
+	if isLibDepTag && libDepTag.fromStatic && libDepTag.shared() {
+		// shared_lib dependency from a static lib is considered as crossing
+		// the APEX boundary because the dependency doesn't actually is
+		// linked; the dependency is used only during the compilation phase.
+		return false
+	}
+
+	if isLibDepTag && libDepTag.excludeInApex {
+		return false
+	}
+
+	return true
+}
+
 // Implements android.ApexModule
 func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
diff --git a/java/aar.go b/java/aar.go
index b668766..d9a8c0e 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1603,8 +1603,8 @@
 var _ android.ApexModule = (*AARImport)(nil)
 
 // Implements android.ApexModule
-func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	return a.depIsInSameApex(ctx, dep)
+func (a *AARImport) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	return a.depIsInSameApex(tag)
 }
 
 // Implements android.ApexModule
diff --git a/java/app.go b/java/app.go
index 276e960..b8c85fb 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1209,7 +1209,10 @@
 
 func (a *AndroidApp) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
 	ctx.WalkDeps(func(child, parent android.Module) bool {
-		isExternal := !a.DepIsInSameApex(ctx, child)
+		// TODO(ccross): Should this use android.DepIsInSameApex?  Right now it is applying the android app
+		// heuristics to every transitive dependency, when it should probably be using the heuristics of the
+		// immediate parent.
+		isExternal := !a.OutgoingDepIsInSameApex(ctx.OtherModuleDependencyTag(child))
 		if am, ok := child.(android.ApexModule); ok {
 			if !do(ctx, parent, am, isExternal) {
 				return false
@@ -1286,11 +1289,11 @@
 	return a.overridableAppProperties.Certificate.GetOrDefault(ctx, "")
 }
 
-func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	if IsJniDepTag(ctx.OtherModuleDependencyTag(dep)) {
+func (a *AndroidApp) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	if IsJniDepTag(tag) {
 		return true
 	}
-	return a.Library.DepIsInSameApex(ctx, dep)
+	return a.Library.OutgoingDepIsInSameApex(tag)
 }
 
 func (a *AndroidApp) Privileged() bool {
diff --git a/java/app_import.go b/java/app_import.go
index 8951c7d..f593c02 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -538,7 +538,7 @@
 	return Bool(a.properties.Privileged)
 }
 
-func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
+func (a *AndroidAppImport) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
 	// android_app_import might have extra dependencies via uses_libs property.
 	// Don't track the dependency as we don't automatically add those libraries
 	// to the classpath. It should be explicitly added to java_libs property of APEX
diff --git a/java/base.go b/java/base.go
index b579a5d..215285f 100644
--- a/java/base.go
+++ b/java/base.go
@@ -365,13 +365,13 @@
 	e.initSdkLibraryComponent(module)
 }
 
-// Module/Import's DepIsInSameApex(...) delegates to this method.
+// Module/Import's OutgoingDepIsInSameApex(...) delegates to this method.
 //
-// This cannot implement DepIsInSameApex(...) directly as that leads to ambiguity with
+// This cannot implement OutgoingDepIsInSameApex(...) directly as that leads to ambiguity with
 // the one provided by ApexModuleBase.
-func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (e *embeddableInModuleAndImport) depIsInSameApex(tag blueprint.DependencyTag) bool {
 	// dependencies other than the static linkage are all considered crossing APEX boundary
-	if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+	if tag == staticLibTag {
 		return true
 	}
 	return false
@@ -2214,8 +2214,8 @@
 }
 
 // Implements android.ApexModule
-func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	return j.depIsInSameApex(ctx, dep)
+func (j *Module) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	return j.depIsInSameApex(tag)
 }
 
 // Implements android.ApexModule
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 375a1aa..d6777e5 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -393,11 +393,9 @@
 	return i.profileInstallPathInApex
 }
 
-func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	tag := ctx.OtherModuleDependencyTag(dep)
-
+func (b *BootclasspathFragmentModule) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
 	// If the module is a default module, do not check the tag
-	if _, ok := dep.(*Defaults); ok {
+	if tag == android.DefaultsDepTag {
 		return true
 	}
 	if IsBootclasspathFragmentContentDepTag(tag) {
@@ -414,7 +412,7 @@
 		return false
 
 	}
-	panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
+	panic(fmt.Errorf("boot_image module %q should not have a dependency tag %s", b, android.PrettyPrintTag(tag)))
 }
 
 func (b *BootclasspathFragmentModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
diff --git a/java/java.go b/java/java.go
index ee112c1..64bc959 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2959,8 +2959,8 @@
 var _ android.ApexModule = (*Import)(nil)
 
 // Implements android.ApexModule
-func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	return j.depIsInSameApex(ctx, dep)
+func (j *Import) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool {
+	return j.depIsInSameApex(tag)
 }
 
 // Implements android.ApexModule
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 7891776..991f847 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1282,7 +1282,7 @@
 func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) {
 	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) {
 		ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
-			isExternal := !module.depIsInSameApex(ctx, child)
+			isExternal := !android.IsDepInSameApex(ctx, module, child)
 			if am, ok := child.(android.ApexModule); ok {
 				if !do(ctx, parent, am, isExternal) {
 					return false
@@ -1636,15 +1636,14 @@
 }
 
 // Implements android.ApexModule
-func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
-	depTag := mctx.OtherModuleDependencyTag(dep)
+func (module *SdkLibrary) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
 	if depTag == xmlPermissionsFileTag {
 		return true
 	}
-	if dep.Name() == module.implLibraryModuleName() {
+	if depTag == implLibraryTag {
 		return true
 	}
-	return module.Library.DepIsInSameApex(mctx, dep)
+	return module.Library.OutgoingDepIsInSameApex(depTag)
 }
 
 // Implements android.ApexModule
@@ -2059,8 +2058,7 @@
 var _ android.ApexModule = (*SdkLibraryImport)(nil)
 
 // Implements android.ApexModule
-func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
-	depTag := mctx.OtherModuleDependencyTag(dep)
+func (module *SdkLibraryImport) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
 	if depTag == xmlPermissionsFileTag {
 		return true
 	}
diff --git a/rust/rust.go b/rust/rust.go
index 1417c08..64cfa40 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -1824,43 +1824,18 @@
 }
 
 // Implements android.ApexModule
-func (mod *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	depTag := ctx.OtherModuleDependencyTag(dep)
-
-	if ccm, ok := dep.(*cc.Module); ok {
-		if ccm.HasStubsVariants() {
-			if cc.IsSharedDepTag(depTag) {
-				// dynamic dep to a stubs lib crosses APEX boundary
-				return false
-			}
-			if cc.IsRuntimeDepTag(depTag) {
-				// runtime dep to a stubs lib also crosses APEX boundary
-				return false
-			}
-
-			if cc.IsHeaderDepTag(depTag) {
-				return false
-			}
-		}
-		if mod.Static() && cc.IsSharedDepTag(depTag) {
-			// shared_lib dependency from a static lib is considered as crossing
-			// the APEX boundary because the dependency doesn't actually is
-			// linked; the dependency is used only during the compilation phase.
-			return false
-		}
-	}
-
+func (mod *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
 	if depTag == procMacroDepTag || depTag == customBindgenDepTag {
 		return false
 	}
 
-	if rustDep, ok := dep.(*Module); ok && rustDep.ApexExclude() {
-		return false
-	}
-
 	return true
 }
 
+func (mod *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
+	return !mod.ApexExclude()
+}
+
 // Overrides ApexModule.IsInstallabeToApex()
 func (mod *Module) IsInstallableToApex() bool {
 	if mod.compiler != nil {