Merge "Enable dex container (DEX v41) for the main branch" into main
diff --git a/android/module.go b/android/module.go
index 3bf4f0c..67dab4f 100644
--- a/android/module.go
+++ b/android/module.go
@@ -117,6 +117,7 @@
 	HostRequiredModuleNames() []string
 	TargetRequiredModuleNames() []string
 	VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string
+	VintfFragments(ctx ConfigurableEvaluatorContext) []string
 
 	ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator
 
@@ -1384,6 +1385,8 @@
 		}
 	} else if m.InstallInRamdisk() {
 		partition = "ramdisk"
+	} else if m.InstallInVendorRamdisk() {
+		partition = "vendor_ramdisk"
 	}
 	return partition
 }
@@ -1626,6 +1629,10 @@
 	return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
 }
 
+func (m *ModuleBase) VintfFragments(ctx ConfigurableEvaluatorContext) []string {
+	return m.base().commonProperties.Vintf_fragments.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
+}
+
 func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) {
 	namespacePrefix := ctx.Namespace().id
 	if namespacePrefix != "" {
diff --git a/android/module_proxy.go b/android/module_proxy.go
index 1f96799..30459b9 100644
--- a/android/module_proxy.go
+++ b/android/module_proxy.go
@@ -9,6 +9,8 @@
 	module blueprint.ModuleProxy
 }
 
+var _ Module = (*ModuleProxy)(nil)
+
 func (m ModuleProxy) Name() string {
 	return m.module.Name()
 }
@@ -225,3 +227,7 @@
 func (m ModuleProxy) Overrides() []string {
 	panic("method is not implemented on ModuleProxy")
 }
+
+func (m ModuleProxy) VintfFragments(ctx ConfigurableEvaluatorContext) []string {
+	panic("method is not implemented on ModuleProxy")
+}
diff --git a/android/variable.go b/android/variable.go
index 36ddc1c..50d1fcd 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -629,6 +629,8 @@
 	InitBootSecurityPatch           string   `json:",omitempty"`
 	BoardIncludeDtbInBootimg        bool     `json:",omitempty"`
 	InternalKernelCmdline           []string `json:",omitempty"`
+	InternalBootconfig              []string `json:",omitempty"`
+	InternalBootconfigFile          string   `json:",omitempty"`
 
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
@@ -658,6 +660,10 @@
 	BuildingOdmDlkmImage      bool     `json:",omitempty"`
 	OdmKernelModules          []string `json:",omitempty"`
 	OdmKernelBlocklistFile    string   `json:",omitempty"`
+
+	VendorRamdiskKernelModules       []string `json:",omitempty"`
+	VendorRamdiskKernelBlocklistFile string   `json:",omitempty"`
+	VendorRamdiskKernelLoadModules   []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/apex.go b/apex/apex.go
index 0e40d7c..72a0455 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -614,9 +614,6 @@
 		}
 		ret.moduleDir = ctx.OtherModuleDir(module)
 		ret.partition = module.PartitionTag(ctx.DeviceConfig())
-		ret.requiredModuleNames = module.RequiredModuleNames(ctx)
-		ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
-		ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
 		ret.multilib = module.Target().Arch.ArchType.Multilib
 	}
 	return ret
@@ -1755,7 +1752,13 @@
 }
 
 func (a *apexBundle) isCompressable() bool {
-	return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
+	if a.testApex {
+		return false
+	}
+	if a.payloadFsType == erofs {
+		return false
+	}
+	return proptools.Bool(a.overridableProperties.Compressible)
 }
 
 func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 6e92959..6cdb225 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7938,46 +7938,6 @@
 	`)
 }
 
-func TestCarryRequiredModuleNames(t *testing.T) {
-	t.Parallel()
-	ctx := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			native_shared_libs: ["mylib"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "mylib",
-			srcs: ["mylib.cpp"],
-			system_shared_libs: [],
-			stl: "none",
-			required: ["a", "b"],
-			host_required: ["c", "d"],
-			target_required: ["e", "f"],
-			apex_available: [ "myapex" ],
-		}
-	`)
-
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
-	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
-	name := apexBundle.BaseModuleName()
-	prefix := "TARGET_"
-	var builder strings.Builder
-	data.Custom(&builder, name, prefix, "", data)
-	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := mylib.myapex:64 a b\n")
-	ensureContains(t, androidMk, "LOCAL_HOST_REQUIRED_MODULES := c d\n")
-	ensureContains(t, androidMk, "LOCAL_TARGET_REQUIRED_MODULES := e f\n")
-}
-
 func TestSymlinksFromApexToSystem(t *testing.T) {
 	t.Parallel()
 	bp := `
@@ -9094,6 +9054,33 @@
 	ensureContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.capex\n")
 }
 
+func TestCompressedApexIsDisabledWhenUsingErofs(t *testing.T) {
+	t.Parallel()
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			compressible: true,
+			updatable: false,
+			payload_fs_type: "erofs",
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.CompressedApex = proptools.BoolPtr(true)
+		}),
+	)
+
+	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").MaybeRule("compressRule")
+	if compressRule.Rule != nil {
+		t.Error("erofs apex should not be compressed")
+	}
+}
+
 func TestApexSet_ShouldRespectCompressedApexFlag(t *testing.T) {
 	t.Parallel()
 	for _, compressionEnabled := range []bool{true, false} {
diff --git a/cc/config/global.go b/cc/config/global.go
index 27aac95..dcc7719 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -238,6 +238,7 @@
 	// opting into the warning.
 	noOverrideGlobalCflags = []string{
 		"-Werror=bool-operation",
+		"-Werror=dangling",
 		"-Werror=format-insufficient-args",
 		"-Werror=implicit-int-float-conversion",
 		"-Werror=int-in-bool-context",
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 23ec3da..bbb3ea7 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -20,6 +20,7 @@
         "avb_add_hash_footer.go",
         "avb_gen_vbmeta_image.go",
         "bootimg.go",
+        "bootconfig.go",
         "filesystem.go",
         "fsverity_metadata.go",
         "logical_partition.go",
diff --git a/filesystem/bootconfig.go b/filesystem/bootconfig.go
new file mode 100644
index 0000000..b125824
--- /dev/null
+++ b/filesystem/bootconfig.go
@@ -0,0 +1,80 @@
+// 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 filesystem
+
+import (
+	"android/soong/android"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	android.RegisterModuleType("bootconfig", BootconfigModuleFactory)
+	pctx.Import("android/soong/android")
+}
+
+type bootconfigProperty struct {
+	// List of bootconfig parameters that will be written as a line separated list in the output
+	// file.
+	Boot_config []string
+	// Path to the file that contains the list of bootconfig parameters. This will be appended
+	// to the output file, after the entries in boot_config.
+	Boot_config_file *string `android:"path"`
+}
+
+type BootconfigModule struct {
+	android.ModuleBase
+
+	properties bootconfigProperty
+}
+
+// bootconfig module generates the `vendor-bootconfig.img` file, which lists the bootconfig
+// parameters and can be passed as a `--vendor_bootconfig` value in mkbootimg invocation.
+func BootconfigModuleFactory() android.Module {
+	module := &BootconfigModule{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+func (m *BootconfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	bootConfig := m.properties.Boot_config
+	bootConfigFileStr := proptools.String(m.properties.Boot_config_file)
+	if len(bootConfig) == 0 && len(bootConfigFileStr) == 0 {
+		return
+	}
+
+	var bootConfigFile android.Path
+	if len(bootConfigFileStr) > 0 {
+		bootConfigFile = android.PathForModuleSrc(ctx, bootConfigFileStr)
+	}
+
+	outputPath := android.PathForModuleOut(ctx, ctx.ModuleName(), "vendor-bootconfig.img")
+	bootConfigOutput := android.PathForModuleOut(ctx, ctx.ModuleName(), "bootconfig.txt")
+	android.WriteFileRule(ctx, bootConfigOutput, strings.Join(bootConfig, "\n"))
+
+	bcFiles := android.Paths{bootConfigOutput}
+	if bootConfigFile != nil {
+		bcFiles = append(bcFiles, bootConfigFile)
+	}
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cat,
+		Description: "concatenate bootconfig parameters",
+		Inputs:      bcFiles,
+		Output:      outputPath,
+	})
+	ctx.SetOutputFiles(android.Paths{outputPath}, "")
+}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index dadacae..5b217ae 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -71,6 +71,10 @@
 	// For example, GSI system.img contains system_ext and product artifacts and their
 	// relPathInPackage need to be rebased to system/system_ext and system/system_product.
 	ModifyPackagingSpec(spec *android.PackagingSpec)
+
+	// Function to check if the filesystem should not use `vintf_fragments` property,
+	// but use `vintf_fragment` module type instead
+	ShouldUseVintfFragmentModuleOnly() bool
 }
 
 var _ filesystemBuilder = (*filesystem)(nil)
@@ -343,6 +347,9 @@
 
 func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	validatePartitionType(ctx, f)
+	if f.filesystemBuilder.ShouldUseVintfFragmentModuleOnly() {
+		f.validateVintfFragments(ctx)
+	}
 	switch f.fsType(ctx) {
 	case ext4Type, erofsType, f2fsType:
 		f.output = f.buildImageUsingBuildImage(ctx)
@@ -371,6 +378,43 @@
 	}
 }
 
+func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) {
+	visitedModule := map[string]bool{}
+	packagingSpecs := f.gatherFilteredPackagingSpecs(ctx)
+
+	moduleInFileSystem := func(mod android.Module) bool {
+		for _, ps := range android.OtherModuleProviderOrDefault(
+			ctx, mod, android.InstallFilesProvider).PackagingSpecs {
+			if _, ok := packagingSpecs[ps.RelPathInPackage()]; ok {
+				return true
+			}
+		}
+		return false
+	}
+
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		if visitedModule[child.Name()] {
+			return false
+		}
+		if !moduleInFileSystem(child) {
+			visitedModule[child.Name()] = true
+			return true
+		}
+		if vintfFragments := child.VintfFragments(ctx); vintfFragments != nil {
+			ctx.PropertyErrorf(
+				"vintf_fragments",
+				"Module %s is referenced by soong-defined filesystem %s with property vintf_fragments(%s) in use."+
+					" Use vintf_fragment_modules property instead.",
+				child.Name(),
+				f.BaseModuleName(),
+				strings.Join(vintfFragments, ", "),
+			)
+		}
+		visitedModule[child.Name()] = true
+		return true
+	})
+}
+
 func (f *filesystem) appendToEntry(ctx android.ModuleContext, installedFile android.Path) {
 	partitionBaseDir := android.PathForModuleOut(ctx, "root", f.partitionName()).String() + "/"
 
@@ -594,6 +638,13 @@
 		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")
+
 	fst := f.fsType(ctx)
 	switch fst {
 	case erofsType:
@@ -779,6 +830,10 @@
 	f.appendToEntry(ctx, output)
 }
 
+func (f *filesystem) ShouldUseVintfFragmentModuleOnly() bool {
+	return false
+}
+
 type partition interface {
 	PartitionType() string
 }
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index d03eab4..60a5133 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -63,3 +63,7 @@
 		(ps.Partition() == "system" || ps.Partition() == "root" ||
 			strings.HasPrefix(ps.Partition(), "system/"))
 }
+
+func (s *systemImage) ShouldUseVintfFragmentModuleOnly() bool {
+	return true
+}
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
index 799dbc9..4e80720 100644
--- a/fsgen/boot_imgs.go
+++ b/fsgen/boot_imgs.go
@@ -104,6 +104,11 @@
 
 	cmdline := partitionVariables.InternalKernelCmdline
 
+	var vendorBootConfigImg *string
+	if name, ok := createVendorBootConfigImg(ctx); ok {
+		vendorBootConfigImg = proptools.StringPtr(":" + name)
+	}
+
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
@@ -117,6 +122,7 @@
 			Avb_algorithm:      avbInfo.avbAlgorithm,
 			Dtb_prebuilt:       dtbPrebuilt,
 			Cmdline:            cmdline,
+			Bootconfig:         vendorBootConfigImg,
 		},
 		&struct {
 			Name *string
@@ -283,3 +289,29 @@
 	}
 	return dtbImg{include: false}
 }
+
+func createVendorBootConfigImg(ctx android.LoadHookContext) (string, bool) {
+	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	bootconfig := partitionVars.InternalBootconfig
+	bootconfigFile := partitionVars.InternalBootconfigFile
+	if len(bootconfig) == 0 && len(bootconfigFile) == 0 {
+		return "", false
+	}
+
+	vendorBootconfigImgModuleName := generatedModuleName(ctx.Config(), "vendor_bootconfig_image")
+
+	ctx.CreateModule(
+		filesystem.BootconfigModuleFactory,
+		&struct {
+			Name             *string
+			Boot_config      []string
+			Boot_config_file *string
+		}{
+			Name:             proptools.StringPtr(vendorBootconfigImgModuleName),
+			Boot_config:      bootconfig,
+			Boot_config_file: proptools.StringPtr(bootconfigFile),
+		},
+	)
+
+	return vendorBootconfigImgModuleName, true
+}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index e8b0a4f..556c4dc 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -222,9 +222,80 @@
 			"framework/oat/*/*", // framework/oat/{arch}
 		}
 		fsProps.Fsverity.Libs = []string{":framework-res{.export-package.apk}"}
+		// Most of the symlinks and directories listed here originate from create_root_structure.mk,
+		// but the handwritten generic system image also recreates them:
+		// https://cs.android.com/android/platform/superproject/main/+/main:build/make/target/product/generic/Android.bp;l=33;drc=db08311f1b6ef6cb0a4fbcc6263b89849360ce04
 		// TODO(b/377734331): only generate the symlinks if the relevant partitions exist
 		fsProps.Symlinks = []filesystem.SymlinkDefinition{
 			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/system/bin/init"),
+				Name:   proptools.StringPtr("init"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/system/etc"),
+				Name:   proptools.StringPtr("etc"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/system/bin"),
+				Name:   proptools.StringPtr("bin"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/data/user_de/0/com.android.shell/files/bugreports"),
+				Name:   proptools.StringPtr("bugreports"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/sys/kernel/debug"),
+				Name:   proptools.StringPtr("d"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/storage/self/primary"),
+				Name:   proptools.StringPtr("sdcard"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/product/etc/security/adb_keys"),
+				Name:   proptools.StringPtr("adb_keys"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/app"),
+				Name:   proptools.StringPtr("odm/app"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/bin"),
+				Name:   proptools.StringPtr("odm/bin"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/etc"),
+				Name:   proptools.StringPtr("odm/etc"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/firmware"),
+				Name:   proptools.StringPtr("odm/firmware"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/framework"),
+				Name:   proptools.StringPtr("odm/framework"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/lib"),
+				Name:   proptools.StringPtr("odm/lib"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/lib64"),
+				Name:   proptools.StringPtr("odm/lib64"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/overlay"),
+				Name:   proptools.StringPtr("odm/overlay"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/priv-app"),
+				Name:   proptools.StringPtr("odm/priv-app"),
+			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/vendor/odm/usr"),
+				Name:   proptools.StringPtr("odm/usr"),
+			},
+			filesystem.SymlinkDefinition{
 				Target: proptools.StringPtr("/product"),
 				Name:   proptools.StringPtr("system/product"),
 			},
@@ -240,7 +311,42 @@
 				Target: proptools.StringPtr("/system_dlkm/lib/modules"),
 				Name:   proptools.StringPtr("system/lib/modules"),
 			},
+			filesystem.SymlinkDefinition{
+				Target: proptools.StringPtr("/data/cache"),
+				Name:   proptools.StringPtr("cache"),
+			},
 		}
+		fsProps.Dirs = proptools.NewSimpleConfigurable([]string{
+			// From generic_rootdirs in build/make/target/product/generic/Android.bp
+			"acct",
+			"apex",
+			"bootstrap-apex",
+			"config",
+			"data",
+			"data_mirror",
+			"debug_ramdisk",
+			"dev",
+			"linkerconfig",
+			"metadata",
+			"mnt",
+			"odm",
+			"odm_dlkm",
+			"oem",
+			"postinstall",
+			"proc",
+			"second_stage_resources",
+			"storage",
+			"sys",
+			"system",
+			"system_dlkm",
+			"tmp",
+			"vendor",
+			"vendor_dlkm",
+
+			// from android_rootdirs in build/make/target/product/generic/Android.bp
+			"system_ext",
+			"product",
+		})
 	case "system_ext":
 		fsProps.Fsverity.Inputs = []string{
 			"framework/*",
@@ -321,7 +427,7 @@
 		}
 	}
 
-	if android.InList(partitionType, dlkmPartitions) {
+	if android.InList(partitionType, append(dlkmPartitions, "vendor_ramdisk")) {
 		f.createPrebuiltKernelModules(ctx, partitionType)
 	}
 
@@ -398,6 +504,7 @@
 		System_dlkm_specific *bool
 		Vendor_dlkm_specific *bool
 		Odm_dlkm_specific    *bool
+		Vendor_ramdisk       *bool
 		Load_by_default      *bool
 		Blocklist_file       *string
 	}{
@@ -430,6 +537,12 @@
 		if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelBlocklistFile; blocklistFile != "" {
 			props.Blocklist_file = proptools.StringPtr(blocklistFile)
 		}
+	case "vendor_ramdisk":
+		props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelModules).Strings()
+		props.Vendor_ramdisk = proptools.BoolPtr(true)
+		if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelBlocklistFile; blocklistFile != "" {
+			props.Blocklist_file = proptools.StringPtr(blocklistFile)
+		}
 	default:
 		ctx.ModuleErrorf("DLKM is not supported for %s\n", partitionType)
 	}
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 9472a50..0cc643e 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -95,15 +95,18 @@
 			fsDeps: map[string]*multilibDeps{
 				// These additional deps are added according to the cuttlefish system image bp.
 				"system": {
+					// keep-sorted start
 					"com.android.apex.cts.shim.v1_prebuilt":     defaultDepCandidateProps(ctx.Config()),
 					"dex_bootjars":                              defaultDepCandidateProps(ctx.Config()),
 					"framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
+					"init.environ.rc-soong":                     defaultDepCandidateProps(ctx.Config()),
 					"libcompiler_rt":                            defaultDepCandidateProps(ctx.Config()),
 					"libdmabufheap":                             defaultDepCandidateProps(ctx.Config()),
 					"libgsi":                                    defaultDepCandidateProps(ctx.Config()),
 					"llndk.libraries.txt":                       defaultDepCandidateProps(ctx.Config()),
 					"logpersist.start":                          defaultDepCandidateProps(ctx.Config()),
 					"update_engine_sideload":                    defaultDepCandidateProps(ctx.Config()),
+					// keep-sorted end
 				},
 				"vendor": {
 					"fs_config_files_vendor":                               defaultDepCandidateProps(ctx.Config()),
diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go
index 13d6482..001a1e7 100644
--- a/kernel/prebuilt_kernel_modules.go
+++ b/kernel/prebuilt_kernel_modules.go
@@ -58,6 +58,9 @@
 
 	Blocklist_file *string `android:"path"`
 
+	// Path to the kernel module options file
+	Options_file *string `android:"path"`
+
 	// Kernel version that these modules are for. Kernel modules are installed to
 	// /lib/modules/<kernel_version> directory in the corresponding partition. Default is "".
 	Kernel_version *string
@@ -100,6 +103,13 @@
 	strippedModules := stripDebugSymbols(ctx, modules)
 
 	installDir := android.PathForModuleInstall(ctx, "lib", "modules")
+	// Kernel module is installed to vendor_ramdisk/lib/modules regardless of product
+	// configuration. This matches the behavior in make and prevents the files from being
+	// installed in `vendor_ramdisk/first_stage_ramdisk`.
+	if pkm.InstallInVendorRamdisk() {
+		installDir = android.PathForModuleInPartitionInstall(ctx, "vendor_ramdisk", "lib", "modules")
+	}
+
 	if pkm.KernelVersion() != "" {
 		installDir = installDir.Join(ctx, pkm.KernelVersion())
 	}
@@ -112,6 +122,7 @@
 	ctx.InstallFile(installDir, "modules.softdep", depmodOut.modulesSoftdep)
 	ctx.InstallFile(installDir, "modules.alias", depmodOut.modulesAlias)
 	pkm.installBlocklistFile(ctx, installDir)
+	pkm.installOptionsFile(ctx, installDir)
 
 	ctx.SetOutputFiles(modules, ".modules")
 }
@@ -130,6 +141,20 @@
 	ctx.InstallFile(installDir, "modules.blocklist", blocklistOut)
 }
 
+func (pkm *prebuiltKernelModules) installOptionsFile(ctx android.ModuleContext, installDir android.InstallPath) {
+	if pkm.properties.Options_file == nil {
+		return
+	}
+	optionsOut := android.PathForModuleOut(ctx, "modules.options")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   processOptionsFile,
+		Input:  android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Options_file)),
+		Output: optionsOut,
+	})
+	ctx.InstallFile(installDir, "modules.options", optionsOut)
+}
+
 var (
 	pctx = android.NewPackageContext("android/soong/kernel")
 
@@ -189,6 +214,19 @@
 				` END { exit exit_status }'`,
 		},
 	)
+	// Remove empty lines. Raise an exception if line is _not_ formatted as `options $name.ko`
+	processOptionsFile = pctx.AndroidStaticRule("process_options_file",
+		blueprint.RuleParams{
+			Command: `rm -rf $out && awk <$in > $out` +
+				` '/^#/ { print; next }` +
+				` NF == 0 { next }` +
+				` NF < 2 || $$1 != "options"` +
+				` { print "Invalid options line " FNR ": " $$0 >"/dev/stderr";` +
+				` exit_status = 1; next }` +
+				` { $$1 = $$1; print }` +
+				` END { exit exit_status }'`,
+		},
+	)
 )
 
 // This is the path in soong intermediates where the .ko files will be copied.
diff --git a/sdk/update.go b/sdk/update.go
index 7f4f80a..5a899a2 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -1201,7 +1201,7 @@
 // the snapshot.
 func (s *snapshotBuilder) snapshotSdkMemberName(name string, required bool) string {
 	if _, ok := s.allMembersByName[name]; !ok {
-		if required {
+		if required && !s.ctx.Config().AllowMissingDependencies() {
 			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", name)
 		}
 		return name