Merge "Fix SBOM integration test" into main
diff --git a/android/base_module_context.go b/android/base_module_context.go
index d8558d0..4b90083 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -254,6 +254,9 @@
 }
 
 func getWrappedModule(module blueprint.Module) blueprint.Module {
+	if mp, isProxy := module.(*ModuleProxy); isProxy {
+		return mp.module
+	}
 	if mp, isProxy := module.(ModuleProxy); isProxy {
 		return mp.module
 	}
@@ -291,7 +294,7 @@
 }
 
 func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
-	return b.bp.OtherModuleProvider(m, provider)
+	return b.bp.OtherModuleProvider(getWrappedModule(m), provider)
 }
 
 func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool {
diff --git a/android/variable.go b/android/variable.go
index 4b61827..969055f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -699,6 +699,10 @@
 	PrivateRecoveryUiProperties map[string]string `json:",omitempty"`
 
 	PrebuiltBootloader string `json:",omitempty"`
+
+	ProductFsCasefold    string `json:",omitempty"`
+	ProductQuotaProjid   string `json:",omitempty"`
+	ProductFsCompression string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 83cac74..c8c5354 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -145,7 +145,7 @@
 	a.buildTargetFilesZip(ctx)
 	var deps []android.Path
 	if proptools.String(a.partitionProps.Super_partition_name) != "" {
-		superImage := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+		superImage := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
 		if info, ok := android.OtherModuleProvider(ctx, superImage, SuperImageProvider); ok {
 			assertUnset := func(prop *string, propName string) {
 				if prop != nil && *prop != "" {
@@ -182,7 +182,7 @@
 			ctx.ModuleErrorf("Expected super image dep to provide SuperImageProvider")
 		}
 	}
-	ctx.VisitDirectDepsWithTag(filesystemDepTag, func(m android.Module) {
+	ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(m android.ModuleProxy) {
 		imageOutput, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider)
 		if !ok {
 			ctx.ModuleErrorf("Partition module %s doesn't set OutputfilesProvider", m.Name())
@@ -274,7 +274,7 @@
 	}
 	// Get additional filesystems from super_partition dependency
 	if a.partitionProps.Super_partition_name != nil {
-		superPartition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+		superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
 		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
 			for _, partition := range android.SortedStringKeys(info.SubImageInfo) {
 				filesystemsToCopy = append(
@@ -305,7 +305,7 @@
 	}
 	// Copy cmdline, kernel etc. files of boot images
 	if a.partitionProps.Vendor_boot_partition_name != nil {
-		bootImg := ctx.GetDirectDepWithTag(proptools.String(a.partitionProps.Vendor_boot_partition_name), filesystemDepTag)
+		bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Vendor_boot_partition_name), filesystemDepTag)
 		bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
 		builder.Command().Textf("echo %s > %s/VENDOR_BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir)
 		builder.Command().Textf("echo %s > %s/VENDOR_BOOT/vendor_cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir)
@@ -317,7 +317,7 @@
 		}
 	}
 	if a.partitionProps.Boot_partition_name != nil {
-		bootImg := ctx.GetDirectDepWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag)
+		bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag)
 		bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
 		builder.Command().Textf("echo %s > %s/BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir)
 		if bootImgInfo.Dtb != nil {
@@ -374,9 +374,9 @@
 	})
 
 	if a.partitionProps.Super_partition_name != nil {
-		superPartition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+		superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
 		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
-			for _, partition := range android.SortedStringKeys(info.SubImageInfo) {
+			for _, partition := range android.SortedKeys(info.SubImageInfo) {
 				builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].Output).Textf(" %s/IMAGES/", targetFilesDir.String())
 			}
 		} else {
@@ -386,7 +386,7 @@
 }
 
 func (a *androidDevice) getFilesystemInfo(ctx android.ModuleContext, depName string) FilesystemInfo {
-	fsMod := ctx.GetDirectDepWithTag(depName, filesystemDepTag)
+	fsMod := ctx.GetDirectDepProxyWithTag(depName, filesystemDepTag)
 	fsInfo, ok := android.OtherModuleProvider(ctx, fsMod, FilesystemProvider)
 	if !ok {
 		ctx.ModuleErrorf("Expected dependency %s to be a filesystem", depName)
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index a315160..85facee 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -222,6 +222,15 @@
 	// The size of the partition on the device. It will be a build error if this built partition
 	// image exceeds this size.
 	Partition_size *int64
+
+	// Whether to format f2fs and ext4 in a way that supports casefolding
+	Support_casefolding *bool
+
+	// Whether to format f2fs and ext4 in a way that supports project quotas
+	Support_project_quota *bool
+
+	// Whether to enable per-file compression in f2fs
+	Enable_compression *bool
 }
 
 type AndroidFilesystemDeps struct {
@@ -789,12 +798,11 @@
 		addStr("hash_seed", uuid)
 	}
 
-	// TODO(b/381120092): This should only be added if none of the size-related properties are set,
-	// but currently soong built partitions don't have size properties. Make code:
-	// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2262;drc=39cd33701c9278db0e7e481a090605f428d5b12d
-	// Make uses system_disable_sparse but disable_sparse has the same effect, and we shouldn't need
-	// to qualify it because each partition gets its own property file built.
-	addStr("disable_sparse", "true")
+	// Disable sparse only when partition size is not defined. disable_sparse has the same
+	// effect as <partition name>_disable_sparse.
+	if f.properties.Partition_size == nil {
+		addStr("disable_sparse", "true")
+	}
 
 	fst := f.fsType(ctx)
 	switch fst {
@@ -821,6 +829,18 @@
 		addStr("partition_size", strconv.FormatInt(*f.properties.Partition_size, 10))
 	}
 
+	if proptools.BoolDefault(f.properties.Support_casefolding, false) {
+		addStr("needs_casefold", "1")
+	}
+
+	if proptools.BoolDefault(f.properties.Support_project_quota, false) {
+		addStr("needs_projid", "1")
+	}
+
+	if proptools.BoolDefault(f.properties.Enable_compression, false) {
+		addStr("needs_compress", "1")
+	}
+
 	propFilePreProcessing := android.PathForModuleOut(ctx, "prop_pre_processing")
 	android.WriteFileRuleVerbatim(ctx, propFilePreProcessing, propFileString.String())
 	propFile := android.PathForModuleOut(ctx, "prop")
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 8dfbd64..9aed460 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -381,7 +381,26 @@
 				panic(fmt.Sprintf("Partition size must be an int, got %s", vars.BoardPartitionSize))
 			}
 			fsProps.Partition_size = &parsed
+			// Disable avb for userdata partition
+			fsProps.Use_avb = nil
 		}
+		// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2265;drc=7f50a123045520f2c5e18e9eb4e83f92244a1459
+		if s, err := strconv.ParseBool(partitionVars.ProductFsCasefold); err == nil {
+			fsProps.Support_casefolding = proptools.BoolPtr(s)
+		} else if len(partitionVars.ProductFsCasefold) > 0 {
+			ctx.ModuleErrorf("Unrecognized PRODUCT_FS_CASEFOLD value %s", partitionVars.ProductFsCasefold)
+		}
+		if s, err := strconv.ParseBool(partitionVars.ProductQuotaProjid); err == nil {
+			fsProps.Support_project_quota = proptools.BoolPtr(s)
+		} else if len(partitionVars.ProductQuotaProjid) > 0 {
+			ctx.ModuleErrorf("Unrecognized PRODUCT_QUOTA_PROJID value %s", partitionVars.ProductQuotaProjid)
+		}
+		if s, err := strconv.ParseBool(partitionVars.ProductFsCompression); err == nil {
+			fsProps.Enable_compression = proptools.BoolPtr(s)
+		} else if len(partitionVars.ProductFsCompression) > 0 {
+			ctx.ModuleErrorf("Unrecognized PRODUCT_FS_COMPRESSION value %s", partitionVars.ProductFsCompression)
+		}
+
 	case "ramdisk":
 		// Following the logic in https://cs.android.com/android/platform/superproject/main/+/c3c5063df32748a8806ce5da5dd0db158eab9ad9:build/make/core/Makefile;l=1307
 		fsProps.Dirs = android.NewSimpleConfigurable([]string{
diff --git a/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go
index 11c5759..d146cbb 100644
--- a/fsgen/vbmeta_partitions.go
+++ b/fsgen/vbmeta_partitions.go
@@ -154,8 +154,8 @@
 			// Already handled by a chained vbmeta partition
 			continue
 		}
-		if strings.Contains(partitionType, "ramdisk") || strings.Contains(partitionType, "boot") {
-			// ramdisk is never signed with avb information
+		if strings.Contains(partitionType, "ramdisk") || strings.Contains(partitionType, "boot") || partitionType == "userdata" {
+			// ramdisk and userdata are never signed with avb information
 			// boot partitions just have the avb footer, and don't have a corresponding vbmeta
 			// partition.
 			continue