Use matching archtypes for cross partition shared lib deps.

ag/34726957 updated fsgen to add xpartition system_ext->system shared
library deps. Since this uses moduleName for the addition, it adds both
variants of a shared library (if they exist). This CL uses archType of
the parent binary/library to filter the matching xpartition shared lib
variant.

Test: go test ./fsgen
Test: diff test for lynx
Bug: 424804147
Change-Id: I1e2801a36aa9db891ea5aa6eff66a37038563f38
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index e7d9baa..25f8464 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -19,6 +19,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/etc"
 	"android/soong/filesystem"
 	"android/soong/java"
@@ -810,3 +811,50 @@
 		"mynamespace/some-permissions/android_arm64_armv8-a/default-permissions.xml",
 	)
 }
+
+func TestCrossPartitionSharedLibDeps(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		android.PrepareForIntegrationTestWithAndroid,
+		android.PrepareForTestWithAndroidBuildComponents,
+		android.PrepareForTestWithAllowMissingDependencies,
+		prepareForTestWithFsgenBuildComponents,
+		cc.PrepareForTestWithCcBuildComponents,
+		java.PrepareForTestWithJavaBuildComponents,
+		prepareMockRamdiksNodeList,
+		android.PrepareForTestWithNamespace,
+		android.FixtureMergeMockFs(android.MockFS{
+			"external/avb/test/data/testkey_rsa4096.pem": nil,
+			"build/soong/fsgen/Android.bp": []byte(`
+			soong_filesystem_creator {
+				name: "foo",
+			}
+		`),
+		}),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackagesSet = createProductPackagesSet([]string{"system_ext_bin"})
+		}),
+	).RunTestWithBp(t, `
+cc_binary {
+	name: "system_ext_bin",
+	shared_libs: ["system_lib"],
+	system_ext_specific: true,
+}
+cc_library_shared {
+	name: "system_lib",
+}
+`)
+	resolvedDeps := result.TestContext.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps["system"]
+	xPartitionSharedLib := (*resolvedDeps)["system_lib"]
+	android.AssertIntEquals(
+		t,
+		"Expected single arch variant of cross partition shared lib dependency",
+		1,
+		len(xPartitionSharedLib.Arch),
+	)
+	android.AssertStringEquals(
+		t,
+		"Expected primary arch variant of cross partition shared lib dependency",
+		"arm64",
+		xPartitionSharedLib.Arch[0].String(),
+	)
+}
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 7093a62..87ff1dc 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -130,6 +130,7 @@
 	CcAndRustSharedLibs []string
 	Partition           string
 	Namespace           string
+	ArchType            android.ArchType
 }
 
 func defaultDepCandidateProps(config android.Config) *depCandidateProps {
@@ -430,6 +431,7 @@
 			Overrides:           m.Overrides(),
 			Partition:           m.PartitionTag(mctx.DeviceConfig()),
 			Namespace:           mctx.Namespace().Path,
+			ArchType:            mctx.Target().Arch.ArchType,
 		})
 	}
 
@@ -494,8 +496,12 @@
 	defer fsGenState.fsDepsMutex.Unlock()
 	additionalCrossPartitionRequiredDeps := correctCrossPartitionRequiredDeps(mctx.Config())
 	fullyQualifiedModuleName := fullyQualifiedModuleName(mctx.ModuleName(), mctx.Namespace().Path)
-	if partition, ok := additionalCrossPartitionRequiredDeps[fullyQualifiedModuleName]; ok && mctx.Module().PartitionTag(mctx.DeviceConfig()) == partition {
-		appendDepIfAppropriate(mctx, fsGenState.fsDeps[partition], partition, android.NativeBridgeDisabled, mctx.ModuleName())
+	if xPartitionDep, ok := additionalCrossPartitionRequiredDeps[fullyQualifiedModuleName]; ok && mctx.Module().PartitionTag(mctx.DeviceConfig()) == xPartitionDep.partition {
+		// For shared libraries, add the dependency only if the archType of the dep and parent match.
+		addXPartitionDep := !xPartitionDep.isSharedLibDep || android.InList(mctx.Target().Arch.ArchType, xPartitionDep.archesOfRequiredSharedLibDep)
+		if addXPartitionDep {
+			appendDepIfAppropriate(mctx, fsGenState.fsDeps[xPartitionDep.partition], xPartitionDep.partition, android.NativeBridgeDisabled, mctx.ModuleName())
+		}
 	}
 }
 
@@ -624,20 +630,28 @@
 type directDepWithParentPartition struct {
 	// name of the install partition of the parent module
 	parentPartition string
+	parentArchType  android.ArchType
 	// fully qualified module name of the "required" direct dep
 	directDepName string
 	// whether this is a rustlib or native shared lib dependency
 	isSharedLibDep bool
 }
 
+type crossPartitionRequiredDep struct {
+	partition      string
+	isSharedLibDep bool
+	// Arches of the binary that requested the cross partition dependency.
+	archesOfRequiredSharedLibDep []android.ArchType
+}
+
 // This function is run only once to compute the list of transitive "required" dependencies
 // where the install partition differs from that of the direct reverse dependency (i.e. parent
 // module). Note that this is done via a graph walk from the top level deps of the autogenerated
 // filesystem modules. Thus, the module will not be included in the returning map even when the
 // install partition differs from that of the parent module if the module is not installed
 // for the target product.
-// The return value is a mapping of fully qualified module names to their install partition.
-func correctCrossPartitionRequiredDeps(config android.Config) map[string]string {
+// The return value is a mapping of fully qualified module name to their install partition and arch types.
+func correctCrossPartitionRequiredDeps(config android.Config) map[string]crossPartitionRequiredDep {
 	return config.Once(fsGenCrossPartitionRequiredDepsOnceKey, func() interface{} {
 		fsGenState := config.Get(fsGenStateOnceKey).(*FsGenState)
 		fsDeps := fsGenState.fsDeps
@@ -646,7 +660,7 @@
 		// Mapping of fully qualified module name to its list of install partition
 		// Given that a single module cannot be listed as deps of multiple filesystem modules,
 		// the key is a single string value instead of a list of strings
-		ret := make(map[string]string)
+		ret := make(map[string]crossPartitionRequiredDep)
 
 		// Add the pair of:
 		// 1. install partition of the top level dep module
@@ -659,6 +673,7 @@
 					for _, requiredModule := range props.Required {
 						moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
 							parentPartition: partition,
+							parentArchType:  props.ArchType,
 							directDepName:   fullyQualifiedModuleName(requiredModule, props.Namespace),
 						})
 					}
@@ -671,6 +686,7 @@
 						for _, sharedLibModule := range props.CcAndRustSharedLibs {
 							moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
 								parentPartition: partition,
+								parentArchType:  props.ArchType,
 								directDepName:   fullyQualifiedModuleName(sharedLibModule, props.Namespace),
 								isSharedLibDep:  true,
 							})
@@ -700,7 +716,16 @@
 			if moduleProps, ok := moduleToInstallationProps.GetFromFullyQualifiedModuleName(visitingModule.directDepName); ok {
 				if moduleProps.Partition != visitingModule.parentPartition {
 					if !visitingModule.isSharedLibDep || moduleProps.Partition == "system" {
-						ret[visitingModule.directDepName] = moduleProps.Partition
+						if entry, exists := ret[visitingModule.directDepName]; exists {
+							archesOfRequiredSharedLibDep := append(entry.archesOfRequiredSharedLibDep, visitingModule.parentArchType)
+							entry.archesOfRequiredSharedLibDep = archesOfRequiredSharedLibDep
+						} else {
+							ret[visitingModule.directDepName] = crossPartitionRequiredDep{
+								partition:                    moduleProps.Partition,
+								isSharedLibDep:               visitingModule.isSharedLibDep,
+								archesOfRequiredSharedLibDep: []android.ArchType{visitingModule.parentArchType},
+							}
+						}
 					}
 				}
 				if _, ok := traversalMap[visitingModule.directDepName]; !ok {
@@ -724,7 +749,7 @@
 			}
 		}
 		return ret
-	}).(map[string]string)
+	}).(map[string]crossPartitionRequiredDep)
 }
 
 var HighPriorityDeps = []string{}