Auto generate userdata.img

Test: CI and unit tests
Bug: 377563861
Change-Id: I42582db31377600412d2acf0dceab5ee9e15bc58
diff --git a/android/config.go b/android/config.go
index d9db64e..10bddf7 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1599,6 +1599,17 @@
 	return "oem"
 }
 
+func (c *deviceConfig) UserdataPath() string {
+	if c.config.productVariables.UserdataPath != nil {
+		return *c.config.productVariables.UserdataPath
+	}
+	return "data"
+}
+
+func (c *deviceConfig) BuildingUserdataImage() bool {
+	return proptools.Bool(c.config.productVariables.BuildingUserdataImage)
+}
+
 func (c *deviceConfig) BtConfigIncludeDir() string {
 	return String(c.config.productVariables.BtConfigIncludeDir)
 }
diff --git a/android/variable.go b/android/variable.go
index f82c9ca..037037d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -338,17 +338,19 @@
 	HWASanIncludePaths []string `json:",omitempty"`
 	HWASanExcludePaths []string `json:",omitempty"`
 
-	VendorPath           *string `json:",omitempty"`
-	VendorDlkmPath       *string `json:",omitempty"`
-	BuildingVendorImage  *bool   `json:",omitempty"`
-	OdmPath              *string `json:",omitempty"`
-	BuildingOdmImage     *bool   `json:",omitempty"`
-	OdmDlkmPath          *string `json:",omitempty"`
-	ProductPath          *string `json:",omitempty"`
-	BuildingProductImage *bool   `json:",omitempty"`
-	SystemExtPath        *string `json:",omitempty"`
-	SystemDlkmPath       *string `json:",omitempty"`
-	OemPath              *string `json:",omitempty"`
+	VendorPath            *string `json:",omitempty"`
+	VendorDlkmPath        *string `json:",omitempty"`
+	BuildingVendorImage   *bool   `json:",omitempty"`
+	OdmPath               *string `json:",omitempty"`
+	BuildingOdmImage      *bool   `json:",omitempty"`
+	OdmDlkmPath           *string `json:",omitempty"`
+	ProductPath           *string `json:",omitempty"`
+	BuildingProductImage  *bool   `json:",omitempty"`
+	SystemExtPath         *string `json:",omitempty"`
+	SystemDlkmPath        *string `json:",omitempty"`
+	OemPath               *string `json:",omitempty"`
+	UserdataPath          *string `json:",omitempty"`
+	BuildingUserdataImage *bool   `json:",omitempty"`
 
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 2645dc4..ab1b96e 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -36,6 +36,8 @@
 	Odm_partition_name *string
 	// The vbmeta partition and its "chained" partitions
 	Vbmeta_partitions []string
+	// Name of the Userdata partition filesystem module
+	Userdata_partition_name *string
 }
 
 type androidDevice struct {
@@ -70,6 +72,7 @@
 	addDependencyIfDefined(a.partitionProps.Product_partition_name)
 	addDependencyIfDefined(a.partitionProps.Vendor_partition_name)
 	addDependencyIfDefined(a.partitionProps.Odm_partition_name)
+	addDependencyIfDefined(a.partitionProps.Userdata_partition_name)
 	for _, vbmetaPartition := range a.partitionProps.Vbmeta_partitions {
 		ctx.AddDependency(ctx.Module(), filesystemDepTag, vbmetaPartition)
 	}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index c9bbf3f..bcf2361 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -130,6 +130,9 @@
 	if android.InList("odm", generatedPartitionTypes) {
 		partitionProps.Odm_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "odm"))
 	}
+	if android.InList("userdata", f.properties.Generated_partition_types) {
+		partitionProps.Userdata_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "userdata"))
+	}
 	partitionProps.Vbmeta_partitions = vbmetaPartitions
 
 	ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps)
@@ -202,6 +205,8 @@
 			},
 		}
 		fsProps.Base_dir = proptools.StringPtr("odm")
+	case "userdata":
+		fsProps.Base_dir = proptools.StringPtr("data")
 
 	}
 }
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 92ea128..e530a5b 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -93,6 +93,9 @@
 	if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
 		generatedPartitions = append(generatedPartitions, "odm")
 	}
+	if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" {
+		generatedPartitions = append(generatedPartitions, "userdata")
+	}
 	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
 		generatedPartitions = append(generatedPartitions, "system_dlkm")
 	}
@@ -144,6 +147,7 @@
 					"com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
 				},
 				"system_dlkm": {},
+				"userdata":    {},
 			},
 			fsDepsMutex:               sync.Mutex{},
 			moduleToInstallationProps: map[string]installationProperties{},