Revert^4 "Set the appropriate deps property for the soong generated fs modules"

This change relands https://r.android.com/3304859.

Test: m nothing --no-skip-soong-tests && ABTD
Bug: 372771060
Change-Id: Ie798fee2a71c14d5e8ac5e2433394bbb090cd595
diff --git a/android/module.go b/android/module.go
index 3079b07..e3dabcc 100644
--- a/android/module.go
+++ b/android/module.go
@@ -113,6 +113,10 @@
 	VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string
 
 	ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator
+
+	// The usage of this method is experimental and should not be used outside of fsgen package.
+	// This will be removed once product packaging migration to Soong is complete.
+	DecodeMultilib(ctx ConfigContext) (string, string)
 }
 
 // Qualified id for a module
@@ -2282,6 +2286,10 @@
 	return proptools.Bool(m.commonProperties.Native_bridge_supported)
 }
 
+func (m *ModuleBase) DecodeMultilib(ctx ConfigContext) (string, string) {
+	return decodeMultilib(ctx, m)
+}
+
 type ConfigContext interface {
 	Config() Config
 }
diff --git a/android/module_proxy.go b/android/module_proxy.go
index bc5090e..0f552dd 100644
--- a/android/module_proxy.go
+++ b/android/module_proxy.go
@@ -201,3 +201,7 @@
 func (m ModuleProxy) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator {
 	panic("method is not implemented on ModuleProxy")
 }
+
+func (m ModuleProxy) DecodeMultilib(ctx ConfigContext) (string, string) {
+	panic("method is not implemented on ModuleProxy")
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 041c9a0..439fe2d 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -61,6 +61,7 @@
 	AddNeverAllowRules(createProhibitHeaderOnlyRule())
 	AddNeverAllowRules(createLimitNdkExportRule()...)
 	AddNeverAllowRules(createLimitDirgroupRule()...)
+	AddNeverAllowRules(createFilesystemIsAutoGeneratedRule())
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -293,6 +294,14 @@
 	}
 }
 
+func createFilesystemIsAutoGeneratedRule() Rule {
+	return NeverAllow().
+		NotIn("build/soong/fsgen").
+		ModuleType("filesystem", "android_system_image").
+		WithMatcher("is_auto_generated", isSetMatcherInstance).
+		Because("is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory")
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 192c924..caec8c7 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -359,6 +359,21 @@
 			`headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`,
 		},
 	},
+	// Test for the rule restricting use of is_auto_generated
+	{
+		name: `"is_auto_generated" outside allowed directory`,
+		fs: map[string][]byte{
+			"a/b/Android.bp": []byte(`
+				filesystem {
+					name: "baaz",
+					is_auto_generated: true,
+				}
+			`),
+		},
+		expectedErrors: []string{
+			`is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory`,
+		},
+	},
 }
 
 var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -367,6 +382,7 @@
 		ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
 		ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
 		ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
+		ctx.RegisterModuleType("filesystem", newMockFilesystemModule)
 	}),
 )
 
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 1a2eeca..277be0f 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -2098,8 +2098,9 @@
 }
 
 type mockFilesystemModuleProperties struct {
-	Partition_type *string
-	Deps           []string
+	Partition_type    *string
+	Deps              []string
+	Is_auto_generated *bool
 }
 
 type mockFilesystemModule struct {
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 8c59df3..4bdd0a4 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -145,6 +145,10 @@
 	Unchecked_module *bool `blueprint:"mutated"`
 
 	Erofs ErofsProperties
+
+	// Determines if the module is auto-generated from Soong or not. If the module is
+	// auto-generated, its deps are exempted from visibility enforcement.
+	Is_auto_generated *bool
 }
 
 // Additional properties required to generate erofs FS partitions.
@@ -179,13 +183,29 @@
 	android.InitDefaultableModule(module)
 }
 
-var dependencyTag = struct {
+type depTag struct {
 	blueprint.BaseDependencyTag
 	android.PackagingItemAlwaysDepTag
-}{}
+}
+
+var dependencyTag = depTag{}
+
+type depTagWithVisibilityEnforcementBypass struct {
+	depTag
+}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = (*depTagWithVisibilityEnforcementBypass)(nil)
+
+func (t depTagWithVisibilityEnforcementBypass) ExcludeFromVisibilityEnforcement() {}
+
+var dependencyTagWithVisibilityEnforcementBypass = depTagWithVisibilityEnforcementBypass{}
 
 func (f *filesystem) DepsMutator(ctx android.BottomUpMutatorContext) {
-	f.AddDeps(ctx, dependencyTag)
+	if proptools.Bool(f.properties.Is_auto_generated) {
+		f.AddDeps(ctx, dependencyTagWithVisibilityEnforcementBypass)
+	} else {
+		f.AddDeps(ctx, dependencyTag)
+	}
 }
 
 type fsType int
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index d5e0c58..c94df09 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -43,49 +43,222 @@
 
 func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
+	ctx.BottomUp("fs_set_deps", setDepsMutator)
 }
 
-var fsDepsMutex = sync.Mutex{}
-var collectFsDepsOnceKey = android.NewOnceKey("CollectFsDeps")
-var depCandidatesOnceKey = android.NewOnceKey("DepCandidates")
+var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
+
+// Map of partition module name to its partition that may be generated by Soong.
+// Note that it is not guaranteed that all modules returned by this function are successfully
+// created.
+func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
+	ret := map[string]string{}
+	for _, partition := range partitions {
+		ret[generatedModuleNameForPartition(config, partition)] = partition
+	}
+	return ret
+}
+
+type depCandidateProps struct {
+	Namespace string
+	Multilib  string
+	Arch      []android.ArchType
+}
+
+// Map of module name to depCandidateProps
+type multilibDeps *map[string]*depCandidateProps
+
+// Information necessary to generate the filesystem modules, including details about their
+// dependencies
+type FsGenState struct {
+	// List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
+	depCandidates []string
+	// Map of names of partition to the information of modules to be added as deps
+	fsDeps map[string]multilibDeps
+	// List of name of partitions to be generated by the filesystem_creator module
+	soongGeneratedPartitions []string
+	// Mutex to protect the fsDeps
+	fsDepsMutex sync.Mutex
+}
+
+func newMultilibDeps() multilibDeps {
+	return &map[string]*depCandidateProps{}
+}
+
+func defaultDepCandidateProps(config android.Config) *depCandidateProps {
+	return &depCandidateProps{
+		Namespace: ".",
+		Arch:      []android.ArchType{config.BuildArch},
+	}
+}
+
+func createFsGenState(ctx android.LoadHookContext) *FsGenState {
+	return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
+		partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+		candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug))
+
+		generatedPartitions := []string{"system"}
+		if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
+			generatedPartitions = append(generatedPartitions, "system_ext")
+		}
+
+		return &FsGenState{
+			depCandidates: candidates,
+			fsDeps: map[string]multilibDeps{
+				// These additional deps are added according to the cuttlefish system image bp.
+				"system": &map[string]*depCandidateProps{
+					"com.android.apex.cts.shim.v1_prebuilt":     defaultDepCandidateProps(ctx.Config()),
+					"dex_bootjars":                              defaultDepCandidateProps(ctx.Config()),
+					"framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
+					"idc_data":                     defaultDepCandidateProps(ctx.Config()),
+					"init.environ.rc-soong":        defaultDepCandidateProps(ctx.Config()),
+					"keychars_data":                defaultDepCandidateProps(ctx.Config()),
+					"keylayout_data":               defaultDepCandidateProps(ctx.Config()),
+					"libclang_rt.asan":             defaultDepCandidateProps(ctx.Config()),
+					"libcompiler_rt":               defaultDepCandidateProps(ctx.Config()),
+					"libdmabufheap":                defaultDepCandidateProps(ctx.Config()),
+					"libgsi":                       defaultDepCandidateProps(ctx.Config()),
+					"llndk.libraries.txt":          defaultDepCandidateProps(ctx.Config()),
+					"logpersist.start":             defaultDepCandidateProps(ctx.Config()),
+					"preloaded-classes":            defaultDepCandidateProps(ctx.Config()),
+					"public.libraries.android.txt": defaultDepCandidateProps(ctx.Config()),
+					"update_engine_sideload":       defaultDepCandidateProps(ctx.Config()),
+				},
+				"vendor":     newMultilibDeps(),
+				"odm":        newMultilibDeps(),
+				"product":    newMultilibDeps(),
+				"system_ext": newMultilibDeps(),
+			},
+			soongGeneratedPartitions: generatedPartitions,
+			fsDepsMutex:              sync.Mutex{},
+		}
+	}).(*FsGenState)
+}
+
+func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps map[string]*depCandidateProps, module string, partitionName string) {
+	otherNamespace := mctx.Namespace().Path
+	if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
+		mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
+	}
+}
+
+func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *map[string]*depCandidateProps, installPartition string) {
+	checkDepModuleInMultipleNamespaces(mctx, *deps, mctx.Module().Name(), installPartition)
+	if _, ok := (*deps)[mctx.Module().Name()]; ok {
+		// Prefer the namespace-specific module over the platform module
+		if mctx.Namespace().Path != "." {
+			(*deps)[mctx.Module().Name()].Namespace = mctx.Namespace().Path
+		}
+		(*deps)[mctx.Module().Name()].Arch = append((*deps)[mctx.Module().Name()].Arch, mctx.Module().Target().Arch.ArchType)
+	} else {
+		multilib, _ := mctx.Module().DecodeMultilib(mctx)
+		(*deps)[mctx.Module().Name()] = &depCandidateProps{
+			Namespace: mctx.Namespace().Path,
+			Multilib:  multilib,
+			Arch:      []android.ArchType{mctx.Module().Target().Arch.ArchType},
+		}
+	}
+}
 
 func collectDepsMutator(mctx android.BottomUpMutatorContext) {
-	// These additional deps are added according to the cuttlefish system image bp.
-	fsDeps := mctx.Config().Once(collectFsDepsOnceKey, func() interface{} {
-		deps := []string{
-			"android_vintf_manifest",
-			"com.android.apex.cts.shim.v1_prebuilt",
-			"dex_bootjars",
-			"framework_compatibility_matrix.device.xml",
-			"idc_data",
-			"init.environ.rc-soong",
-			"keychars_data",
-			"keylayout_data",
-			"libclang_rt.asan",
-			"libcompiler_rt",
-			"libdmabufheap",
-			"libgsi",
-			"llndk.libraries.txt",
-			"logpersist.start",
-			"preloaded-classes",
-			"public.libraries.android.txt",
-			"update_engine_sideload",
-		}
-		return &deps
-	}).(*[]string)
-
-	depCandidates := mctx.Config().Once(depCandidatesOnceKey, func() interface{} {
-		partitionVars := mctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
-		candidates := slices.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug)
-		return &candidates
-	}).(*[]string)
+	fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
 
 	m := mctx.Module()
-	if slices.Contains(*depCandidates, m.Name()) {
-		if installInSystem(mctx, m) {
-			fsDepsMutex.Lock()
-			*fsDeps = append(*fsDeps, m.Name())
-			fsDepsMutex.Unlock()
+	if slices.Contains(fsGenState.depCandidates, m.Name()) {
+		installPartition := m.PartitionTag(mctx.DeviceConfig())
+		fsGenState.fsDepsMutex.Lock()
+		// Only add the module as dependency when:
+		// - its enabled
+		// - its namespace is included in PRODUCT_SOONG_NAMESPACES
+		if m.Enabled(mctx) && m.ExportedToMake() {
+			appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition)
+		}
+		fsGenState.fsDepsMutex.Unlock()
+	}
+}
+
+type depsStruct struct {
+	Deps []string
+}
+
+type multilibDepsStruct struct {
+	Common   depsStruct
+	Lib32    depsStruct
+	Lib64    depsStruct
+	Both     depsStruct
+	Prefer32 depsStruct
+}
+
+type packagingPropsStruct struct {
+	Deps     []string
+	Multilib multilibDepsStruct
+}
+
+func fullyQualifiedModuleName(moduleName, namespace string) string {
+	if namespace == "." {
+		return moduleName
+	}
+	return fmt.Sprintf("//%s:%s", namespace, moduleName)
+}
+
+// Returns the sorted unique list of module names with namespace, if the module specifies one.
+func fullyQualifiedModuleNames(modules multilibDeps) (ret []string) {
+	for moduleName, moduleProp := range *modules {
+		ret = append(ret, fullyQualifiedModuleName(moduleName, moduleProp.Namespace))
+	}
+	return android.SortedUniqueStrings(ret)
+}
+
+func getBitness(archTypes []android.ArchType) (ret []string) {
+	for _, archType := range archTypes {
+		if archType.Multilib == "" {
+			ret = append(ret, android.COMMON_VARIANT)
+		} else {
+			ret = append(ret, archType.Bitness())
+		}
+	}
+	return ret
+}
+
+func setDepsMutator(mctx android.BottomUpMutatorContext) {
+	fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+	fsDeps := fsGenState.fsDeps
+	soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
+	m := mctx.Module()
+	if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
+		depsStruct := packagingPropsStruct{}
+		for depName, depProps := range *fsDeps[partition] {
+			bitness := getBitness(depProps.Arch)
+			fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
+			if android.InList("32", bitness) && android.InList("64", bitness) {
+				// If both 32 and 64 bit variants are enabled for this module
+				switch depProps.Multilib {
+				case string(android.MultilibBoth):
+					depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+				case string(android.MultilibCommon), string(android.MultilibFirst):
+					depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
+				case "32":
+					depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+				case "64", "darwin_universal":
+					depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+				case "prefer32", "first_prefer32":
+					depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
+				default:
+					depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+				}
+			} else if android.InList("64", bitness) {
+				// If only 64 bit variant is enabled
+				depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+			} else if android.InList("32", bitness) {
+				// If only 32 bit variant is enabled
+				depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+			} else {
+				// If only common variant is enabled
+				depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
+			}
+		}
+		if err := proptools.AppendMatchingProperties(m.GetProperties(), &depsStruct, nil); err != nil {
+			mctx.ModuleErrorf(err.Error())
 		}
 	}
 }
@@ -107,6 +280,7 @@
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	module.AddProperties(&module.properties)
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		createFsGenState(ctx)
 		module.createInternalModules(ctx)
 	})
 
@@ -114,21 +288,19 @@
 }
 
 func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) {
-	partitionTypes := []string{"system"}
-	if ctx.DeviceConfig().SystemExtPath() == "system_ext" { // system_ext exists
-		partitionTypes = append(partitionTypes, "system_ext")
-	}
-	for _, partitionType := range partitionTypes {
+	soongGeneratedPartitions := &ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions
+	for _, partitionType := range *soongGeneratedPartitions {
 		if f.createPartition(ctx, partitionType) {
 			f.properties.Generated_partition_types = append(f.properties.Generated_partition_types, partitionType)
 		} else {
 			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, partitionType)
+			_, *soongGeneratedPartitions = android.RemoveFromList(partitionType, *soongGeneratedPartitions)
 		}
 	}
 	f.createDeviceModule(ctx)
 }
 
-func (f *filesystemCreator) generatedModuleName(cfg android.Config, suffix string) string {
+func generatedModuleName(cfg android.Config, suffix string) string {
 	prefix := "soong"
 	if cfg.HasDeviceProduct() {
 		prefix = cfg.DeviceProduct()
@@ -136,24 +308,24 @@
 	return fmt.Sprintf("%s_generated_%s", prefix, suffix)
 }
 
-func (f *filesystemCreator) generatedModuleNameForPartition(cfg android.Config, partitionType string) string {
-	return f.generatedModuleName(cfg, fmt.Sprintf("%s_image", partitionType))
+func generatedModuleNameForPartition(cfg android.Config, partitionType string) string {
+	return generatedModuleName(cfg, fmt.Sprintf("%s_image", partitionType))
 }
 
 func (f *filesystemCreator) createDeviceModule(ctx android.LoadHookContext) {
 	baseProps := &struct {
 		Name *string
 	}{
-		Name: proptools.StringPtr(f.generatedModuleName(ctx.Config(), "device")),
+		Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "device")),
 	}
 
 	// Currently, only the system and system_ext partition module is created.
 	partitionProps := &filesystem.PartitionNameProperties{}
 	if android.InList("system", f.properties.Generated_partition_types) {
-		partitionProps.System_partition_name = proptools.StringPtr(f.generatedModuleNameForPartition(ctx.Config(), "system"))
+		partitionProps.System_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system"))
 	}
 	if android.InList("system_ext", f.properties.Generated_partition_types) {
-		partitionProps.System_ext_partition_name = proptools.StringPtr(f.generatedModuleNameForPartition(ctx.Config(), "system_ext"))
+		partitionProps.System_ext_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_ext"))
 	}
 
 	ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps)
@@ -168,9 +340,11 @@
 // it.
 func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partitionType string) bool {
 	baseProps := &struct {
-		Name *string
+		Name             *string
+		Compile_multilib *string
 	}{
-		Name: proptools.StringPtr(f.generatedModuleNameForPartition(ctx.Config(), partitionType)),
+		Name:             proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType)),
+		Compile_multilib: proptools.StringPtr("both"),
 	}
 
 	fsProps := &filesystem.FilesystemProperties{}
@@ -209,6 +383,8 @@
 
 	fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(android.InList(partitionType, partitionsWithAconfig))
 
+	fsProps.Is_auto_generated = proptools.BoolPtr(true)
+
 	// Identical to that of the generic_system_image
 	fsProps.Fsverity.Inputs = []string{
 		"etc/boot-image.prof",
@@ -245,7 +421,7 @@
 }
 
 func (f *filesystemCreator) createDiffTest(ctx android.ModuleContext, partitionType string) android.Path {
-	partitionModuleName := f.generatedModuleNameForPartition(ctx.Config(), partitionType)
+	partitionModuleName := generatedModuleNameForPartition(ctx.Config(), partitionType)
 	systemImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag)
 	filesystemInfo, ok := android.OtherModuleProvider(ctx, systemImage, filesystem.FilesystemProvider)
 	if !ok {
@@ -289,7 +465,7 @@
 
 func (f *filesystemCreator) DepsMutator(ctx android.BottomUpMutatorContext) {
 	for _, partitionType := range f.properties.Generated_partition_types {
-		ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, f.generatedModuleNameForPartition(ctx.Config(), partitionType))
+		ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, generatedModuleNameForPartition(ctx.Config(), partitionType))
 	}
 }
 
@@ -314,13 +490,6 @@
 	ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
 }
 
-func installInSystem(ctx android.BottomUpMutatorContext, m android.Module) bool {
-	return m.PartitionTag(ctx.DeviceConfig()) == "system" && !m.InstallInData() &&
-		!m.InstallInTestcases() && !m.InstallInSanitizerDir() && !m.InstallInVendorRamdisk() &&
-		!m.InstallInDebugRamdisk() && !m.InstallInRecovery() && !m.InstallInOdm() &&
-		!m.InstallInVendor()
-}
-
 // TODO: assemble baseProps and fsProps here
 func generateBpContent(ctx android.EarlyModuleContext, partitionType string) string {
 	// Currently only system partition is supported
@@ -328,9 +497,9 @@
 		return ""
 	}
 
-	deps := ctx.Config().Get(collectFsDepsOnceKey).(*[]string)
+	deps := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps
 	depProps := &android.PackagingProperties{
-		Deps: android.NewSimpleConfigurable(android.SortedUniqueStrings(*deps)),
+		Deps: android.NewSimpleConfigurable(fullyQualifiedModuleNames(deps[partitionType])),
 	}
 
 	result, err := proptools.RepackProperties([]interface{}{depProps})
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index 554b66b..484cc38 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/filesystem"
+	"android/soong/java"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
@@ -28,6 +29,7 @@
 	result := android.GroupFixturePreparers(
 		android.PrepareForIntegrationTestWithAndroid,
 		android.PrepareForTestWithAndroidBuildComponents,
+		android.PrepareForTestWithAllowMissingDependencies,
 		filesystem.PrepareForTestWithFilesystemBuildComponents,
 		prepareForTestWithFsgenBuildComponents,
 		android.FixtureModifyConfig(func(config android.Config) {
@@ -86,3 +88,132 @@
 		proptools.String(fooSystem.FsProps().Type),
 	)
 }
+
+func TestFileSystemCreatorSetPartitionDeps(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		android.PrepareForIntegrationTestWithAndroid,
+		android.PrepareForTestWithAndroidBuildComponents,
+		android.PrepareForTestWithAllowMissingDependencies,
+		filesystem.PrepareForTestWithFilesystemBuildComponents,
+		prepareForTestWithFsgenBuildComponents,
+		java.PrepareForTestWithJavaBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"bar", "baz"}
+			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+				map[string]android.PartitionQualifiedVariablesType{
+					"system": {
+						BoardFileSystemType: "ext4",
+					},
+				}
+		}),
+		android.FixtureMergeMockFs(android.MockFS{
+			"external/avb/test/data/testkey_rsa4096.pem": nil,
+			"build/soong/fsgen/Android.bp": []byte(`
+			soong_filesystem_creator {
+				name: "foo",
+			}
+			`),
+		}),
+	).RunTestWithBp(t, `
+	java_library {
+		name: "bar",
+		srcs: ["A.java"],
+	}
+	java_library {
+		name: "baz",
+		srcs: ["A.java"],
+		product_specific: true,
+	}
+	`)
+
+	android.AssertBoolEquals(
+		t,
+		"Generated system image expected to depend on system partition installed \"bar\"",
+		true,
+		java.CheckModuleHasDependency(t, result.TestContext, "test_product_generated_system_image", "android_common", "bar"),
+	)
+	android.AssertBoolEquals(
+		t,
+		"Generated system image expected to not depend on product partition installed \"baz\"",
+		false,
+		java.CheckModuleHasDependency(t, result.TestContext, "test_product_generated_system_image", "android_common", "baz"),
+	)
+}
+
+func TestFileSystemCreatorDepsWithNamespace(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		android.PrepareForIntegrationTestWithAndroid,
+		android.PrepareForTestWithAndroidBuildComponents,
+		android.PrepareForTestWithAllowMissingDependencies,
+		android.PrepareForTestWithNamespace,
+		android.PrepareForTestWithArchMutator,
+		filesystem.PrepareForTestWithFilesystemBuildComponents,
+		prepareForTestWithFsgenBuildComponents,
+		java.PrepareForTestWithJavaBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"bar"}
+			config.TestProductVariables.NamespacesToExport = []string{"a/b"}
+			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+				map[string]android.PartitionQualifiedVariablesType{
+					"system": {
+						BoardFileSystemType: "ext4",
+					},
+				}
+			config.Targets[android.Android] = []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: "", HostCross: false},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: "", HostCross: false},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64", HostCross: false},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm", HostCross: false},
+			}
+		}),
+		android.FixtureMergeMockFs(android.MockFS{
+			"external/avb/test/data/testkey_rsa4096.pem": nil,
+			"build/soong/fsgen/Android.bp": []byte(`
+			soong_filesystem_creator {
+				name: "foo",
+			}
+			`),
+			"a/b/Android.bp": []byte(`
+			soong_namespace{
+			}
+			java_library {
+				name: "bar",
+				srcs: ["A.java"],
+				compile_multilib: "64",
+			}
+			`),
+			"c/d/Android.bp": []byte(`
+			soong_namespace{
+			}
+			java_library {
+				name: "bar",
+				srcs: ["A.java"],
+			}
+			`),
+		}),
+	).RunTest(t)
+
+	var packagingProps android.PackagingProperties
+	for _, prop := range result.ModuleForTests("test_product_generated_system_image", "android_common").Module().GetProperties() {
+		if packagingPropStruct, ok := prop.(*android.PackagingProperties); ok {
+			packagingProps = *packagingPropStruct
+		}
+	}
+	moduleDeps := packagingProps.Multilib.Lib64.Deps
+
+	eval := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringListContains(
+		t,
+		"Generated system image expected to depend on \"bar\" defined in \"a/b\" namespace",
+		moduleDeps.GetOrDefault(eval, nil),
+		"//a/b:bar",
+	)
+	android.AssertStringListDoesNotContain(
+		t,
+		"Generated system image expected to not depend on \"bar\" defined in \"c/d\" namespace",
+		moduleDeps.GetOrDefault(eval, nil),
+		"//c/d:bar",
+	)
+}