Merge changes I8081fb3e,I235fa688 into main

* changes:
  Remove ApexContents
  Remove DirectlyInAnyApex
diff --git a/android/config.go b/android/config.go
index 27d3b87..dff3ea5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -285,6 +285,10 @@
 	return c.config.productVariables.GetBuildFlagBool("RELEASE_CREATE_ACONFIG_STORAGE_FILE")
 }
 
+func (c Config) ReleaseUseSystemFeatureBuildFlags() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS")
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
@@ -1834,6 +1838,10 @@
 	return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps()
 }
 
+func (c *config) DefaultApexPayloadType() string {
+	return StringDefault(c.productVariables.DefaultApexPayloadType, "ext4")
+}
+
 func (c *config) UseSoongSystemImage() bool {
 	return Bool(c.productVariables.UseSoongSystemImage)
 }
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 403c184..a157386 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -611,6 +611,7 @@
 		nsjailCmd.WriteString(" -m none:/tmp:tmpfs:size=1073741824") // 1GB, should be enough
 		nsjailCmd.WriteString(" -D nsjail_build_sandbox")
 		nsjailCmd.WriteString(" --disable_rlimits")
+		nsjailCmd.WriteString(" --skip_setsid") // ABFS relies on process-groups to track file operations
 		nsjailCmd.WriteString(" -q")
 		nsjailCmd.WriteString(" -- ")
 		nsjailCmd.WriteString("/bin/bash -c ")
diff --git a/android/sbom.go b/android/sbom.go
index 2a5499e..f2b9c0f 100644
--- a/android/sbom.go
+++ b/android/sbom.go
@@ -15,9 +15,7 @@
 package android
 
 import (
-	"io"
 	"path/filepath"
-	"strings"
 
 	"github.com/google/blueprint"
 )
@@ -55,21 +53,7 @@
 	if !ctx.Config().HasDeviceProduct() {
 		return
 	}
-	// Get all METADATA files and add them as implicit input
-	metadataFileListFile := PathForArbitraryOutput(ctx, ".module_paths", "METADATA.list")
-	f, err := ctx.Config().fs.Open(metadataFileListFile.String())
-	if err != nil {
-		panic(err)
-	}
-	b, err := io.ReadAll(f)
-	if err != nil {
-		panic(err)
-	}
-	allMetadataFiles := strings.Split(string(b), "\n")
-	implicits := []Path{metadataFileListFile}
-	for _, path := range allMetadataFiles {
-		implicits = append(implicits, PathForSource(ctx, path))
-	}
+	implicits := []Path{}
 	prodVars := ctx.Config().productVariables
 	buildFingerprintFile := PathForArbitraryOutput(ctx, "target", "product", String(prodVars.DeviceName), "build_fingerprint.txt")
 	implicits = append(implicits, buildFingerprintFile)
diff --git a/android/variable.go b/android/variable.go
index 88cf5a5..7ae9a43 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -408,9 +408,10 @@
 
 	Ndk_abis *bool `json:",omitempty"`
 
-	ForceApexSymlinkOptimization *bool `json:",omitempty"`
-	CompressedApex               *bool `json:",omitempty"`
-	Aml_abis                     *bool `json:",omitempty"`
+	ForceApexSymlinkOptimization *bool   `json:",omitempty"`
+	CompressedApex               *bool   `json:",omitempty"`
+	DefaultApexPayloadType       *string `json:",omitempty"`
+	Aml_abis                     *bool   `json:",omitempty"`
 
 	DexpreoptGlobalConfig *string `json:",omitempty"`
 
@@ -612,6 +613,7 @@
 	// Boot image stuff
 	BuildingRamdiskImage            bool   `json:",omitempty"`
 	ProductBuildBootImage           bool   `json:",omitempty"`
+	ProductBuildVendorBootImage     string `json:",omitempty"`
 	ProductBuildInitBootImage       bool   `json:",omitempty"`
 	BoardUsesRecoveryAsBoot         bool   `json:",omitempty"`
 	BoardPrebuiltBootimage          string `json:",omitempty"`
@@ -620,6 +622,7 @@
 	BoardInitBootimagePartitionSize string `json:",omitempty"`
 	BoardBootHeaderVersion          string `json:",omitempty"`
 	TargetKernelPath                string `json:",omitempty"`
+	BoardUsesGenericKernelImage     bool   `json:",omitempty"`
 
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 7f259a8..ed9e58a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1724,7 +1724,8 @@
 }
 
 func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) {
-	switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
+	defaultFsType := ctx.Config().DefaultApexPayloadType()
+	switch proptools.StringDefault(a.properties.Payload_fs_type, defaultFsType) {
 	case ext4FsType:
 		a.payloadFsType = ext4
 	case f2fsFsType:
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 226d95c..2249506 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -36,6 +36,8 @@
 
 	output     android.Path
 	installDir android.InstallPath
+
+	bootImageType bootImageType
 }
 
 type BootimgProperties struct {
@@ -56,9 +58,13 @@
 	// https://source.android.com/devices/bootloader/boot-image-header
 	Header_version *string
 
-	// Determines if this image is for the vendor_boot partition. Default is false. Refer to
-	// https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
-	Vendor_boot *bool
+	// Determines the specific type of boot image this module is building. Can be boot,
+	// vendor_boot or init_boot. Defaults to boot.
+	// Refer to https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
+	// for vendor_boot.
+	// Refer to https://source.android.com/docs/core/architecture/partitions/generic-boot for
+	// init_boot.
+	Boot_image_type *string
 
 	// Optional kernel commandline arguments
 	Cmdline []string `android:"arch_variant"`
@@ -67,6 +73,10 @@
 	// and `header_version` is greater than or equal to 4.
 	Bootconfig *string `android:"arch_variant,path"`
 
+	// 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
+
 	// When set to true, sign the image with avbtool. Default is false.
 	Use_avb *bool
 
@@ -81,6 +91,41 @@
 	Avb_algorithm *string
 }
 
+type bootImageType int
+
+const (
+	unsupported bootImageType = iota
+	boot
+	vendorBoot
+	initBoot
+)
+
+func toBootImageType(ctx android.ModuleContext, bootImageType string) bootImageType {
+	switch bootImageType {
+	case "boot":
+		return boot
+	case "vendor_boot":
+		return vendorBoot
+	case "init_boot":
+		return initBoot
+	default:
+		ctx.ModuleErrorf("Unknown boot_image_type %s. Must be one of \"boot\", \"vendor_boot\", or \"init_boot\"", bootImageType)
+	}
+	return unsupported
+}
+
+func (b bootImageType) isBoot() bool {
+	return b == boot
+}
+
+func (b bootImageType) isVendorBoot() bool {
+	return b == vendorBoot
+}
+
+func (b bootImageType) isInitBoot() bool {
+	return b == initBoot
+}
+
 // bootimg is the image for the boot partition. It consists of header, kernel, ramdisk, and dtb.
 func BootimgFactory() android.Module {
 	module := &bootimg{}
@@ -112,8 +157,8 @@
 }
 
 func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	vendor := proptools.Bool(b.properties.Vendor_boot)
-	unsignedOutput := b.buildBootImage(ctx, vendor)
+	b.bootImageType = toBootImageType(ctx, proptools.StringDefault(b.properties.Boot_image_type, "boot"))
+	unsignedOutput := b.buildBootImage(ctx)
 
 	output := unsignedOutput
 	if proptools.Bool(b.properties.Use_avb) {
@@ -127,18 +172,19 @@
 	b.output = output
 }
 
-func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.Path {
+func (b *bootimg) buildBootImage(ctx android.ModuleContext) android.Path {
 	output := android.PathForModuleOut(ctx, "unsigned", b.installFileName())
 
 	builder := android.NewRuleBuilder(pctx, ctx)
 	cmd := builder.Command().BuiltTool("mkbootimg")
 
 	kernel := proptools.String(b.properties.Kernel_prebuilt)
-	if vendor && kernel != "" {
+	if b.bootImageType.isVendorBoot() && kernel != "" {
 		ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
 		return output
 	}
-	if !vendor && kernel == "" {
+
+	if b.bootImageType.isBoot() && kernel == "" {
 		ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
 		return output
 	}
@@ -146,6 +192,12 @@
 		cmd.FlagWithInput("--kernel ", android.PathForModuleSrc(ctx, kernel))
 	}
 
+	// These arguments are passed for boot.img and init_boot.img generation
+	if b.bootImageType.isBoot() || b.bootImageType.isInitBoot() {
+		cmd.FlagWithArg("--os_version ", ctx.Config().PlatformVersionLastStable())
+		cmd.FlagWithArg("--os_patch_level ", ctx.Config().PlatformSecurityPatch())
+	}
+
 	dtbName := proptools.String(b.properties.Dtb_prebuilt)
 	if dtbName != "" {
 		dtb := android.PathForModuleSrc(ctx, dtbName)
@@ -155,7 +207,7 @@
 	cmdline := strings.Join(b.properties.Cmdline, " ")
 	if cmdline != "" {
 		flag := "--cmdline "
-		if vendor {
+		if b.bootImageType.isVendorBoot() {
 			flag = "--vendor_cmdline "
 		}
 		cmd.FlagWithArg(flag, proptools.ShellEscapeIncludingSpaces(cmdline))
@@ -182,7 +234,7 @@
 		ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep)
 		if filesystem, ok := ramdisk.(*filesystem); ok {
 			flag := "--ramdisk "
-			if vendor {
+			if b.bootImageType.isVendorBoot() {
 				flag = "--vendor_ramdisk "
 			}
 			cmd.FlagWithInput(flag, filesystem.OutputPath())
@@ -194,7 +246,7 @@
 
 	bootconfig := proptools.String(b.properties.Bootconfig)
 	if bootconfig != "" {
-		if !vendor {
+		if !b.bootImageType.isVendorBoot() {
 			ctx.PropertyErrorf("bootconfig", "requires vendor_boot: true")
 			return output
 		}
@@ -205,12 +257,17 @@
 		cmd.FlagWithInput("--vendor_bootconfig ", android.PathForModuleSrc(ctx, bootconfig))
 	}
 
+	// Output flag for boot.img and init_boot.img
 	flag := "--output "
-	if vendor {
+	if b.bootImageType.isVendorBoot() {
 		flag = "--vendor_boot "
 	}
 	cmd.FlagWithOutput(flag, output)
 
+	if b.properties.Partition_size != nil {
+		assertMaxImageSize(builder, output, *b.properties.Partition_size, proptools.Bool(b.properties.Use_avb))
+	}
+
 	builder.Build("build_bootimg", fmt.Sprintf("Creating %s", b.BaseModuleName()))
 	return output
 }
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index c346770..dadacae 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").
@@ -689,6 +710,7 @@
 	"odm_dlkm",
 	"system_dlkm",
 	"ramdisk",
+	"vendor_ramdisk",
 }
 
 func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) {
@@ -904,3 +926,26 @@
 
 	return provideModules, requireModules
 }
+
+// Checks that the given file doesn't exceed the given size, and will also print a warning
+// if it's nearing the maximum size. Equivalent to assert-max-image-size in make:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/definitions.mk;l=3455;drc=993c4de29a02a6accd60ceaaee153307e1a18d10
+func assertMaxImageSize(builder *android.RuleBuilder, image android.Path, maxSize int64, addAvbLater bool) {
+	if addAvbLater {
+		// The value 69632 is derived from MAX_VBMETA_SIZE + MAX_FOOTER_SIZE in avbtool.
+		// Logic copied from make:
+		// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=228;drc=a6a0007ef24e16c0b79f439beac4a118416717e6
+		maxSize -= 69632
+	}
+	cmd := builder.Command()
+	cmd.Textf(`file="%s"; maxsize="%d";`+
+		`total=$(stat -c "%%s" "$file" | tr -d '\n');`+
+		`if [ "$total" -gt "$maxsize" ]; then `+
+		`  echo "error: $file too large ($total > $maxsize)";`+
+		`  false;`+
+		`elif [ "$total" -gt $((maxsize - 32768)) ]; then `+
+		`  echo "WARNING: $file approaching size limit ($total now; limit $maxsize)";`+
+		`fi`,
+		image, maxSize)
+	cmd.Implicit(image)
+}
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"),
+	)
+}
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
index 66d9107..630aaff 100644
--- a/fsgen/boot_imgs.go
+++ b/fsgen/boot_imgs.go
@@ -3,7 +3,9 @@
 import (
 	"android/soong/android"
 	"android/soong/filesystem"
+	"fmt"
 	"path/filepath"
+	"strconv"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -34,12 +36,63 @@
 		},
 	)
 
+	var partitionSize *int64
+	if partitionVariables.BoardBootimagePartitionSize != "" {
+		parsed, err := strconv.ParseInt(partitionVariables.BoardBootimagePartitionSize, 10, 64)
+		if err != nil {
+			panic(fmt.Sprintf("BOARD_BOOTIMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardBootimagePartitionSize))
+		}
+		partitionSize = &parsed
+	}
+
 	bootImageName := generatedModuleNameForPartition(ctx.Config(), "boot")
 
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
 			Kernel_prebuilt: proptools.StringPtr(":" + kernelFilegroupName),
+			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+			Partition_size:  partitionSize,
+		},
+		&struct {
+			Name *string
+		}{
+			Name: proptools.StringPtr(bootImageName),
+		},
+	)
+	return true
+}
+
+func createVendorBootImage(ctx android.LoadHookContext) bool {
+	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+	bootImageName := generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
+
+	ctx.CreateModule(
+		filesystem.BootimgFactory,
+		&filesystem.BootimgProperties{
+			Boot_image_type: proptools.StringPtr("vendor_boot"),
+			Ramdisk_module:  proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_ramdisk")),
+			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+		},
+		&struct {
+			Name *string
+		}{
+			Name: proptools.StringPtr(bootImageName),
+		},
+	)
+	return true
+}
+
+func createInitBootImage(ctx android.LoadHookContext) bool {
+	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+	bootImageName := generatedModuleNameForPartition(ctx.Config(), "init_boot")
+
+	ctx.CreateModule(
+		filesystem.BootimgFactory,
+		&filesystem.BootimgProperties{
+			Boot_image_type: proptools.StringPtr("init_boot"),
 			Ramdisk_module:  proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")),
 			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
 		},
@@ -76,3 +129,44 @@
 
 	return false
 }
+
+// Returns the equivalent of the BUILDING_VENDOR_BOOT_IMAGE variable in make. Derived from this logic:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=518;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+func buildingVendorBootImage(partitionVars android.PartitionVariables) bool {
+	if v, exists := boardBootHeaderVersion(partitionVars); exists && v >= 3 {
+		x := partitionVars.ProductBuildVendorBootImage
+		if x == "" || x == "true" {
+			return true
+		}
+	}
+
+	return false
+}
+
+// Derived from: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=480;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+func buildingInitBootImage(partitionVars android.PartitionVariables) bool {
+	if !partitionVars.ProductBuildInitBootImage {
+		if partitionVars.BoardUsesRecoveryAsBoot || len(partitionVars.BoardPrebuiltInitBootimage) > 0 {
+			return false
+		} else if len(partitionVars.BoardInitBootimagePartitionSize) > 0 {
+			return true
+		}
+	} else {
+		if partitionVars.BoardUsesRecoveryAsBoot {
+			panic("PRODUCT_BUILD_INIT_BOOT_IMAGE is true, but so is BOARD_USES_RECOVERY_AS_BOOT. Use only one option.")
+		}
+		return true
+	}
+	return false
+}
+
+func boardBootHeaderVersion(partitionVars android.PartitionVariables) (int, bool) {
+	if len(partitionVars.BoardBootHeaderVersion) == 0 {
+		return 0, false
+	}
+	v, err := strconv.ParseInt(partitionVars.BoardBootHeaderVersion, 10, 32)
+	if err != nil {
+		panic(fmt.Sprintf("BOARD_BOOT_HEADER_VERSION must be an int, got: %q", partitionVars.BoardBootHeaderVersion))
+	}
+	return int(v), true
+}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 7daefcb..6bfb097 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -48,7 +48,9 @@
 	Vbmeta_module_names    []string `blueprint:"mutated"`
 	Vbmeta_partition_names []string `blueprint:"mutated"`
 
-	Boot_image string `blueprint:"mutated" android:"path_device_first"`
+	Boot_image        string `blueprint:"mutated" android:"path_device_first"`
+	Vendor_boot_image string `blueprint:"mutated" android:"path_device_first"`
+	Init_boot_image   string `blueprint:"mutated" android:"path_device_first"`
 }
 
 type filesystemCreator struct {
@@ -74,6 +76,7 @@
 }
 
 func generatedPartitions(ctx android.LoadHookContext) []string {
+	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
 	generatedPartitions := []string{"system"}
 	if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
 		generatedPartitions = append(generatedPartitions, "system_ext")
@@ -90,18 +93,21 @@
 	if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" {
 		generatedPartitions = append(generatedPartitions, "userdata")
 	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
+	if partitionVars.BuildingSystemDlkmImage {
 		generatedPartitions = append(generatedPartitions, "system_dlkm")
 	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingVendorDlkmImage {
+	if partitionVars.BuildingVendorDlkmImage {
 		generatedPartitions = append(generatedPartitions, "vendor_dlkm")
 	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingOdmDlkmImage {
+	if partitionVars.BuildingOdmDlkmImage {
 		generatedPartitions = append(generatedPartitions, "odm_dlkm")
 	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingRamdiskImage {
+	if partitionVars.BuildingRamdiskImage {
 		generatedPartitions = append(generatedPartitions, "ramdisk")
 	}
+	if buildingVendorBootImage(partitionVars) {
+		generatedPartitions = append(generatedPartitions, "vendor_ramdisk")
+	}
 	return generatedPartitions
 }
 
@@ -117,13 +123,28 @@
 		}
 	}
 
-	if buildingBootImage(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse) {
+	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	if buildingBootImage(partitionVars) {
 		if createBootImage(ctx) {
 			f.properties.Boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "boot")
 		} else {
 			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "boot")
 		}
 	}
+	if buildingVendorBootImage(partitionVars) {
+		if createVendorBootImage(ctx) {
+			f.properties.Vendor_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
+		} else {
+			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "vendor_boot")
+		}
+	}
+	if buildingInitBootImage(partitionVars) {
+		if createInitBootImage(ctx) {
+			f.properties.Init_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "init_boot")
+		} else {
+			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "init_boot")
+		}
+	}
 
 	for _, x := range createVbmetaPartitions(ctx, finalSoongGeneratedPartitions) {
 		f.properties.Vbmeta_module_names = append(f.properties.Vbmeta_module_names, x.moduleName)
@@ -182,13 +203,13 @@
 	ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps)
 }
 
-func partitionSpecificFsProps(fsProps *filesystem.FilesystemProperties, partitionType string) {
+func partitionSpecificFsProps(fsProps *filesystem.FilesystemProperties, partitionVars android.PartitionVariables, partitionType string) {
 	switch partitionType {
 	case "system":
 		fsProps.Build_logtags = proptools.BoolPtr(true)
 		// https://source.corp.google.com/h/googleplex-android/platform/build//639d79f5012a6542ab1f733b0697db45761ab0f3:core/packaging/flags.mk;l=21;drc=5ba8a8b77507f93aa48cc61c5ba3f31a4d0cbf37;bpv=1;bpt=0
 		fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
-		// Identical to that of the generic_system_image
+		// Identical to that of the aosp_shared_system_image
 		fsProps.Fsverity.Inputs = []string{
 			"etc/boot-image.prof",
 			"etc/dirty-image-objects",
@@ -248,7 +269,28 @@
 		}
 	case "userdata":
 		fsProps.Base_dir = proptools.StringPtr("data")
-
+	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{
+			"debug_ramdisk",
+			"dev",
+			"metadata",
+			"mnt",
+			"proc",
+			"second_stage_resources",
+			"sys",
+		})
+		if partitionVars.BoardUsesGenericKernelImage {
+			fsProps.Dirs.AppendSimpleValue([]string{
+				"first_stage_ramdisk/debug_ramdisk",
+				"first_stage_ramdisk/dev",
+				"first_stage_ramdisk/metadata",
+				"first_stage_ramdisk/mnt",
+				"first_stage_ramdisk/proc",
+				"first_stage_ramdisk/second_stage_resources",
+				"first_stage_ramdisk/sys",
+			})
+		}
 	}
 }
 
@@ -359,7 +401,7 @@
 	}
 	switch partitionType {
 	case "system_dlkm":
-		props.Srcs = ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules
+		props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules).Strings()
 		props.System_dlkm_specific = proptools.BoolPtr(true)
 		if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelLoadModules) == 0 {
 			// Create empty modules.load file for system
@@ -370,7 +412,7 @@
 			props.Blocklist_file = proptools.StringPtr(blocklistFile)
 		}
 	case "vendor_dlkm":
-		props.Srcs = ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelModules
+		props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelModules).Strings()
 		if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules) > 0 {
 			props.System_deps = []string{":" + generatedModuleName(ctx.Config(), "system_dlkm-kernel-modules") + "{.modules}"}
 		}
@@ -379,7 +421,7 @@
 			props.Blocklist_file = proptools.StringPtr(blocklistFile)
 		}
 	case "odm_dlkm":
-		props.Srcs = ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelModules
+		props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelModules).Strings()
 		props.Odm_dlkm_specific = proptools.BoolPtr(true)
 		if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelBlocklistFile; blocklistFile != "" {
 			props.Blocklist_file = proptools.StringPtr(blocklistFile)
@@ -564,11 +606,13 @@
 
 	fsProps.Partition_name = proptools.StringPtr(partitionType)
 
-	fsProps.Base_dir = proptools.StringPtr(partitionType)
+	if !strings.Contains(partitionType, "ramdisk") {
+		fsProps.Base_dir = proptools.StringPtr(partitionType)
+	}
 
 	fsProps.Is_auto_generated = proptools.BoolPtr(true)
 
-	partitionSpecificFsProps(fsProps, partitionType)
+	partitionSpecificFsProps(fsProps, partitionVars, partitionType)
 
 	// system_image properties that are not set:
 	// - filesystemProperties.Avb_hash_algorithm
@@ -699,6 +743,22 @@
 		diffTestFiles = append(diffTestFiles, diffTestFile)
 		ctx.Phony("soong_generated_boot_filesystem_test", diffTestFile)
 	}
+	if f.properties.Vendor_boot_image != "" {
+		diffTestFile := android.PathForModuleOut(ctx, "vendor_boot_diff_test.txt")
+		soongBootImg := android.PathForModuleSrc(ctx, f.properties.Vendor_boot_image)
+		makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/vendor_boot.img", ctx.Config().DeviceName()))
+		createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage)
+		diffTestFiles = append(diffTestFiles, diffTestFile)
+		ctx.Phony("soong_generated_vendor_boot_filesystem_test", diffTestFile)
+	}
+	if f.properties.Init_boot_image != "" {
+		diffTestFile := android.PathForModuleOut(ctx, "init_boot_diff_test.txt")
+		soongBootImg := android.PathForModuleSrc(ctx, f.properties.Init_boot_image)
+		makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/init_boot.img", ctx.Config().DeviceName()))
+		createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage)
+		diffTestFiles = append(diffTestFiles, diffTestFile)
+		ctx.Phony("soong_generated_init_boot_filesystem_test", diffTestFile)
+	}
 	ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
 }
 
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 0d18660..12f9956 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -146,7 +146,8 @@
 					"fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
 					"odm_dlkm-build.prop":      defaultDepCandidateProps(ctx.Config()),
 				},
-				"ramdisk": {},
+				"ramdisk":        {},
+				"vendor_ramdisk": {},
 			},
 			fsDepsMutex:                     sync.Mutex{},
 			moduleToInstallationProps:       map[string]installationProperties{},
diff --git a/java/app.go b/java/app.go
index 8bb73cb..7f80160 100644
--- a/java/app.go
+++ b/java/app.go
@@ -164,7 +164,7 @@
 type overridableAppProperties struct {
 	// The name of a certificate in the default certificate directory, blank to use the default product certificate,
 	// or an android_app_certificate module name in the form ":module".
-	Certificate *string
+	Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
 
 	// Name of the signing certificate lineage file or filegroup module.
 	Lineage *string `android:"path"`
@@ -1252,7 +1252,7 @@
 	if overridden {
 		return ":" + certificate
 	}
-	return String(a.overridableAppProperties.Certificate)
+	return a.overridableAppProperties.Certificate.GetOrDefault(ctx, "")
 }
 
 func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
diff --git a/java/app_import.go b/java/app_import.go
index f044c68..8951c7d 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -97,7 +97,7 @@
 
 	// The name of a certificate in the default certificate directory or an android_app_certificate
 	// module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
-	Certificate *string
+	Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
 
 	// Names of extra android_app_certificate modules to sign the apk with in the form ":module".
 	Additional_certificates []string
@@ -240,7 +240,7 @@
 }
 
 func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
-	cert := android.SrcIsModule(String(a.properties.Certificate))
+	cert := android.SrcIsModule(a.properties.Certificate.GetOrDefault(ctx, ""))
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
@@ -323,7 +323,7 @@
 	}
 
 	numCertPropsSet := 0
-	if String(a.properties.Certificate) != "" {
+	if a.properties.Certificate.GetOrDefault(ctx, "") != "" {
 		numCertPropsSet++
 	}
 	if Bool(a.properties.Presigned) {
@@ -406,7 +406,7 @@
 		// If the certificate property is empty at this point, default_dev_cert must be set to true.
 		// Which makes processMainCert's behavior for the empty cert string WAI.
 		_, _, certificates := collectAppDeps(ctx, a, false, false)
-		a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
+		a.certificate, certificates = processMainCert(a.ModuleBase, a.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx)
 		signed := android.PathForModuleOut(ctx, "signed", apkFilename)
 		var lineageFile android.Path
 		if lineage := String(a.properties.Lineage); lineage != "" {
diff --git a/java/rro.go b/java/rro.go
index 8bb9be2..f225e1f 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -50,7 +50,7 @@
 type RuntimeResourceOverlayProperties struct {
 	// the name of a certificate in the default certificate directory or an android_app_certificate
 	// module name in the form ":module".
-	Certificate *string
+	Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
 
 	// Name of the signing certificate lineage file.
 	Lineage *string
@@ -119,7 +119,7 @@
 		r.aapt.deps(ctx, sdkDep)
 	}
 
-	cert := android.SrcIsModule(String(r.properties.Certificate))
+	cert := android.SrcIsModule(r.properties.Certificate.GetOrDefault(ctx, ""))
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
@@ -166,7 +166,7 @@
 
 	// Sign the built package
 	_, _, certificates := collectAppDeps(ctx, r, false, false)
-	r.certificate, certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
+	r.certificate, certificates = processMainCert(r.ModuleBase, r.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
 	var lineageFile android.Path
 	if lineage := String(r.properties.Lineage); lineage != "" {
diff --git a/systemfeatures/Android.bp b/systemfeatures/Android.bp
new file mode 100644
index 0000000..a65a6b6
--- /dev/null
+++ b/systemfeatures/Android.bp
@@ -0,0 +1,18 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-systemfeatures",
+    pkgPath: "android/soong/systemfeatures",
+    deps: [
+        "blueprint",
+        "blueprint-proptools",
+        "soong",
+        "soong-android",
+        "soong-java",
+    ],
+    srcs: ["system_features.go"],
+    testSrcs: ["system_features_test.go"],
+    pluginFor: ["soong_build"],
+}
diff --git a/systemfeatures/OWNERS b/systemfeatures/OWNERS
new file mode 100644
index 0000000..3e44806
--- /dev/null
+++ b/systemfeatures/OWNERS
@@ -0,0 +1,2 @@
+jdduke@google.com
+shayba@google.com
diff --git a/systemfeatures/system_features.go b/systemfeatures/system_features.go
new file mode 100644
index 0000000..0c1a566
--- /dev/null
+++ b/systemfeatures/system_features.go
@@ -0,0 +1,102 @@
+// Copyright 2024 Google Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package systemfeatures
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"android/soong/android"
+	"android/soong/genrule"
+)
+
+var (
+	pctx = android.NewPackageContext("android/soong/systemfeatures")
+)
+
+func init() {
+	registerSystemFeaturesComponents(android.InitRegistrationContext)
+}
+
+func registerSystemFeaturesComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("java_system_features_srcs", JavaSystemFeaturesSrcsFactory)
+}
+
+type javaSystemFeaturesSrcs struct {
+	android.ModuleBase
+	properties struct {
+		// The fully qualified class name for the generated code, e.g., com.android.Foo
+		Full_class_name string
+	}
+	outputFiles android.WritablePaths
+}
+
+var _ genrule.SourceFileGenerator = (*javaSystemFeaturesSrcs)(nil)
+var _ android.SourceFileProducer = (*javaSystemFeaturesSrcs)(nil)
+
+func (m *javaSystemFeaturesSrcs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Create a file name appropriate for the given fully qualified (w/ package) class name.
+	classNameParts := strings.Split(m.properties.Full_class_name, ".")
+	outputDir := android.PathForModuleGen(ctx)
+	outputFileName := classNameParts[len(classNameParts)-1] + ".java"
+	outputFile := android.PathForModuleGen(ctx, outputFileName).OutputPath
+
+	// Collect all RELEASE_SYSTEM_FEATURE_$K:$V build flags into a list of "$K:$V" pairs.
+	var features []string
+	for k, v := range ctx.Config().ProductVariables().BuildFlags {
+		if strings.HasPrefix(k, "RELEASE_SYSTEM_FEATURE_") {
+			shortFeatureName := strings.TrimPrefix(k, "RELEASE_SYSTEM_FEATURE_")
+			features = append(features, fmt.Sprintf("%s:%s", shortFeatureName, v))
+		}
+	}
+	// Ensure sorted outputs for consistency of flag ordering in ninja outputs.
+	sort.Strings(features)
+
+	rule := android.NewRuleBuilder(pctx, ctx)
+	rule.Command().Text("rm -rf").Text(outputDir.String())
+	rule.Command().Text("mkdir -p").Text(outputDir.String())
+	rule.Command().
+		BuiltTool("systemfeatures-gen-tool").
+		Flag(m.properties.Full_class_name).
+		FlagForEachArg("--feature=", features).
+		FlagWithArg("--readonly=", fmt.Sprint(ctx.Config().ReleaseUseSystemFeatureBuildFlags())).
+		FlagWithOutput(" > ", outputFile)
+	rule.Build(ctx.ModuleName(), "Generating systemfeatures srcs filegroup")
+
+	m.outputFiles = append(m.outputFiles, outputFile)
+}
+
+func (m *javaSystemFeaturesSrcs) Srcs() android.Paths {
+	return m.outputFiles.Paths()
+}
+
+func (m *javaSystemFeaturesSrcs) GeneratedSourceFiles() android.Paths {
+	return m.outputFiles.Paths()
+}
+
+func (m *javaSystemFeaturesSrcs) GeneratedDeps() android.Paths {
+	return m.outputFiles.Paths()
+}
+
+func (m *javaSystemFeaturesSrcs) GeneratedHeaderDirs() android.Paths {
+	return nil
+}
+
+func JavaSystemFeaturesSrcsFactory() android.Module {
+	module := &javaSystemFeaturesSrcs{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidModule(module)
+	return module
+}
diff --git a/systemfeatures/system_features_test.go b/systemfeatures/system_features_test.go
new file mode 100644
index 0000000..558bb95
--- /dev/null
+++ b/systemfeatures/system_features_test.go
@@ -0,0 +1,51 @@
+// Copyright 2024 Google Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package systemfeatures
+
+import (
+	"android/soong/android"
+
+	"testing"
+)
+
+func TestJavaSystemFeaturesSrcs(t *testing.T) {
+	bp := `
+java_system_features_srcs {
+    name: "system-features-srcs",
+	full_class_name: "com.android.test.RoSystemFeatures",
+}
+`
+
+	res := android.GroupFixturePreparers(
+		android.FixtureRegisterWithContext(registerSystemFeaturesComponents),
+		android.PrepareForTestWithBuildFlag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS", "true"),
+		android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE", "0"),
+		android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_TELEVISION", "UNAVAILABLE"),
+		android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_WATCH", ""),
+		android.PrepareForTestWithBuildFlag("RELEASE_NOT_SYSTEM_FEATURE_FOO", "BAR"),
+	).RunTestWithBp(t, bp)
+
+	module := res.ModuleForTests("system-features-srcs", "")
+	cmd := module.Rule("system-features-srcs").RuleParams.Command
+	android.AssertStringDoesContain(t, "Expected fully class name", cmd, " com.android.test.RoSystemFeatures ")
+	android.AssertStringDoesContain(t, "Expected readonly flag", cmd, "--readonly=true")
+	android.AssertStringDoesContain(t, "Expected AUTOMOTIVE feature flag", cmd, "--feature=AUTOMOTIVE:0 ")
+	android.AssertStringDoesContain(t, "Expected TELEVISION feature flag", cmd, "--feature=TELEVISION:UNAVAILABLE ")
+	android.AssertStringDoesContain(t, "Expected WATCH feature flag", cmd, "--feature=WATCH: ")
+	android.AssertStringDoesNotContain(t, "Unexpected FOO arg from non-system feature flag", cmd, "FOO")
+
+	systemFeaturesModule := module.Module().(*javaSystemFeaturesSrcs)
+	expectedOutputPath := "out/soong/.intermediates/system-features-srcs/gen/RoSystemFeatures.java"
+	android.AssertPathsRelativeToTopEquals(t, "Expected output file", []string{expectedOutputPath}, systemFeaturesModule.Srcs())
+}