Specify dev nodes list file for ramdisk partition generation

Ramdisk partition requires "-n" argument to be passed when generating
the image file. Given that the value is agnostic to the target product
and is set to a constant value, this is implicitly set internally in
filesystem module.

Test: inspect ramdisk.img build command
Bug: 379190521
Change-Id: I01d0c1bf06e087ab49c71bdb0cfe48a08b9c7fc9
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index c346770..ba5319f 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -162,6 +162,10 @@
 	// 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
+
+	// Path to the dev nodes description file. This is only needed for building the ramdisk
+	// partition and should not be explicitly specified.
+	Dev_nodes_description_file *string `android:"path" blueprint:"mutated"`
 }
 
 // Additional properties required to generate erofs FS partitions.
@@ -210,6 +214,10 @@
 	filesystemModule.PackagingBase.AllowHighPriorityDeps = true
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
+
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		filesystemModule.setDevNodesDescriptionProp()
+	})
 }
 
 type depTag struct {
@@ -229,6 +237,16 @@
 
 var dependencyTagWithVisibilityEnforcementBypass = depTagWithVisibilityEnforcementBypass{}
 
+// ramdiskDevNodesDescription is the name of the filegroup module that provides the file that
+// contains the description of dev nodes added to the CPIO archive for the ramdisk partition.
+const ramdiskDevNodesDescription = "ramdisk_node_list"
+
+func (f *filesystem) setDevNodesDescriptionProp() {
+	if proptools.String(f.properties.Partition_name) == "ramdisk" {
+		f.properties.Dev_nodes_description_file = proptools.StringPtr(":" + ramdiskDevNodesDescription)
+	}
+}
+
 func (f *filesystem) DepsMutator(ctx android.BottomUpMutatorContext) {
 	if proptools.Bool(f.properties.Is_auto_generated) {
 		f.AddDeps(ctx, dependencyTagWithVisibilityEnforcementBypass)
@@ -659,6 +677,9 @@
 	cmd := builder.Command().
 		BuiltTool("mkbootfs").
 		Text(rootDir.String()) // input directory
+	if nodeList := f.properties.Dev_nodes_description_file; nodeList != nil {
+		cmd.FlagWithInput("-n ", android.PathForModuleSrc(ctx, proptools.String(nodeList)))
+	}
 	if compressed {
 		cmd.Text("|").
 			BuiltTool("lz4").
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 7c342cc..746e4de 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -758,3 +758,28 @@
 	fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
 	android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\n", fileList)
 }
+
+func TestRamdiskPartitionSetsDevNodes(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		fixture,
+		android.FixtureMergeMockFs(android.MockFS{
+			"ramdisk_node_list": nil,
+		}),
+	).RunTestWithBp(t, `
+		android_filesystem {
+			name: "ramdisk_filesystem",
+			partition_name: "ramdisk",
+		}
+		filegroup {
+			name: "ramdisk_node_list",
+			srcs: ["ramdisk_node_list"],
+		}
+	`)
+
+	android.AssertBoolEquals(
+		t,
+		"Generated ramdisk image expected to depend on \"ramdisk_node_list\" module",
+		true,
+		java.CheckModuleHasDependency(t, result.TestContext, "ramdisk_filesystem", "android_common", "ramdisk_node_list"),
+	)
+}