Generate META/(root|vendor_boot)_filesystem_config.txt

Unlike other partitions like system, vendor, ..., the build rule for
this will be created in android_device, and will use the intermediates
directories assembled by android_device for target_files.zip creation.

The alternative would be to create this files in filesystem's
GenerateAndroidBuildActions, but it would require handling the following
- root_filesystem_config.txt: This can be created in system's
  GenerateAndroidBuildActions, but we would need to assemble a separate
"root" staging dir without "system" subdir
- vendor_boot_filesystem_config.txt: This can be created in
  vendor_ramdisk's GenerateAndroidBuildActions, but we would need to
copy the recovery files to the staging dir before running fs_config

Test: Verfied that vendor_boot_filesystem_config.txt is identical
Test: root_filesystem_config.txt has the following diffs
```
32d31
< odm_dlkm/etc 0 0 644 capabilities=0x0
47d45
< vendor_dlkm/etc 0 0 644 capabilities=0x0
```

This is due to a preexisting diff in Soong's target_files/ROOT
intermediates. I will debug this in followup work

Bug: 388633394

Change-Id: Ia21f1456cbc1a1641db1c01416cdc575600770cf
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index b3ad7a7..a2fa0f0 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -587,11 +587,22 @@
 		if android.InList(partition, []string{"userdata"}) {
 			continue
 		}
-		builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/%s", targetFilesDir.String(), a.filesystemConfigNameForTargetFiles(partition))
+		if partition != "vendor_ramdisk" {
+			// vendor_ramdisk will be handled separately.
+			builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/%s", targetFilesDir.String(), a.filesystemConfigNameForTargetFiles(partition))
+		}
 		if partition == "ramdisk" {
 			// Create an additional copy at boot_filesystem_config.txt
 			builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/boot_filesystem_config.txt", targetFilesDir.String())
 		}
+		if partition == "system" {
+			// Create root_filesystem_config from the assembled ROOT/ intermediates directory
+			a.generateFilesystemConfigForTargetFiles(ctx, builder, targetFilesDir.String(), targetFilesDir.String()+"/ROOT", "root_filesystem_config.txt")
+		}
+		if partition == "vendor_ramdisk" {
+			// Create vendor_boot_filesystem_config from the assembled VENDOR_BOOT/RAMDISK intermediates directory
+			a.generateFilesystemConfigForTargetFiles(ctx, builder, targetFilesDir.String(), targetFilesDir.String()+"/VENDOR_BOOT/RAMDISK", "vendor_boot_filesystem_config.txt")
+		}
 	}
 	// Copy ramdisk_node_list
 	if ramdiskNodeList := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Ramdisk_node_list)); ramdiskNodeList != nil {
@@ -619,6 +630,19 @@
 
 var ApexKeyPathInfoProvider = blueprint.NewProvider[ApexKeyPathInfo]()
 
+func (a *androidDevice) generateFilesystemConfigForTargetFiles(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir, stagingDir, filename string) {
+	fsConfigOut := android.PathForModuleOut(ctx, filename)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   fsConfigRule,
+		Output: fsConfigOut,
+		Args: map[string]string{
+			"rootDir": stagingDir,
+			"prefix":  "",
+		},
+	})
+	builder.Command().Textf("cp").Input(fsConfigOut).Textf(" %s/META/", targetFilesDir)
+}
+
 // Filenames for the partition specific fs_config files.
 // Hardcode the ramdisk files to their boot image prefix
 func (a *androidDevice) filesystemConfigNameForTargetFiles(partition string) string {