Add vendor-ramdisk image to Soong.

Add vendor_ramdisk_available and vendor_ramdisk attribute to
various rules. When a vendor_ramdisk variant of a module is
generated, it is installed to $OUT/vendor-ramdisk.

It is similar to a ramdisk image.
Test: m nothing -j

Change-Id: Ib2d16459f3094dbe21c3bdb7c016cb4b2bf62765
diff --git a/android/arch.go b/android/arch.go
index 616cead..98ff07a 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -914,8 +914,8 @@
 		osTargets = targets
 	}
 
-	// only the primary arch in the ramdisk / recovery partition
-	if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk()) {
+	// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
+	if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk()) {
 		osTargets = []Target{osTargets[0]}
 	}
 
diff --git a/android/image.go b/android/image.go
index 061bfa5..1a1a423 100644
--- a/android/image.go
+++ b/android/image.go
@@ -26,6 +26,10 @@
 	// ramdisk partition).
 	RamdiskVariantNeeded(ctx BaseModuleContext) bool
 
+	// VendorRamdiskVariantNeeded should return true if the module needs a vendor ramdisk variant (installed on the
+	// vendor ramdisk partition).
+	VendorRamdiskVariantNeeded(ctx BaseModuleContext) bool
+
 	// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
 	// recovery partition).
 	RecoveryVariantNeeded(ctx BaseModuleContext) bool
@@ -53,6 +57,9 @@
 
 	// RamdiskVariation means a module to be installed to ramdisk image.
 	RamdiskVariation string = "ramdisk"
+
+	// VendorRamdiskVariation means a module to be installed to vendor ramdisk image.
+	VendorRamdiskVariation string = "vendor_ramdisk"
 )
 
 // imageMutator creates variants for modules that implement the ImageInterface that
@@ -73,6 +80,9 @@
 		if m.RamdiskVariantNeeded(ctx) {
 			variations = append(variations, RamdiskVariation)
 		}
+		if m.VendorRamdiskVariantNeeded(ctx) {
+			variations = append(variations, VendorRamdiskVariation)
+		}
 		if m.RecoveryVariantNeeded(ctx) {
 			variations = append(variations, RecoveryVariation)
 		}
diff --git a/android/module.go b/android/module.go
index 70a343e..d677406 100644
--- a/android/module.go
+++ b/android/module.go
@@ -348,6 +348,7 @@
 	InstallInTestcases() bool
 	InstallInSanitizerDir() bool
 	InstallInRamdisk() bool
+	InstallInVendorRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
@@ -403,6 +404,7 @@
 	InstallInTestcases() bool
 	InstallInSanitizerDir() bool
 	InstallInRamdisk() bool
+	InstallInVendorRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
@@ -623,6 +625,9 @@
 	// Whether this module is installed to ramdisk
 	Ramdisk *bool
 
+	// Whether this module is installed to vendor ramdisk
+	Vendor_ramdisk *bool
+
 	// Whether this module is built for non-native architecures (also known as native bridge binary)
 	Native_bridge_supported *bool `android:"arch_variant"`
 
@@ -1274,6 +1279,10 @@
 	return Bool(m.commonProperties.Ramdisk)
 }
 
+func (m *ModuleBase) InstallInVendorRamdisk() bool {
+	return Bool(m.commonProperties.Vendor_ramdisk)
+}
+
 func (m *ModuleBase) InstallInRecovery() bool {
 	return Bool(m.commonProperties.Recovery)
 }
@@ -1323,6 +1332,10 @@
 	return m.base().commonProperties.ImageVariation == RamdiskVariation
 }
 
+func (m *ModuleBase) InVendorRamdisk() bool {
+	return m.base().commonProperties.ImageVariation == VendorRamdiskVariation
+}
+
 func (m *ModuleBase) InRecovery() bool {
 	return m.base().commonProperties.ImageVariation == RecoveryVariation
 }
@@ -2224,6 +2237,10 @@
 	return m.module.InstallInRamdisk()
 }
 
+func (m *moduleContext) InstallInVendorRamdisk() bool {
+	return m.module.InstallInVendorRamdisk()
+}
+
 func (m *moduleContext) InstallInRecovery() bool {
 	return m.module.InstallInRecovery()
 }
diff --git a/android/paths.go b/android/paths.go
index 3825d45..8fd2e88 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -58,6 +58,7 @@
 	InstallInTestcases() bool
 	InstallInSanitizerDir() bool
 	InstallInRamdisk() bool
+	InstallInVendorRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
@@ -1376,6 +1377,9 @@
 			if !ctx.InstallInRoot() {
 				partition += "/system"
 			}
+		} else if ctx.InstallInVendorRamdisk() {
+			// TODO(elsk): Should be conditional on move_recovery_res_to_vendor_boot
+			partition = "vendor-ramdisk"
 		} else if ctx.InstallInRecovery() {
 			if ctx.InstallInRoot() {
 				partition = "recovery/root"
diff --git a/android/paths_test.go b/android/paths_test.go
index 108bd6c..9ecf4a1 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -200,14 +200,15 @@
 type moduleInstallPathContextImpl struct {
 	baseModuleContext
 
-	inData         bool
-	inTestcases    bool
-	inSanitizerDir bool
-	inRamdisk      bool
-	inRecovery     bool
-	inRoot         bool
-	forceOS        *OsType
-	forceArch      *ArchType
+	inData          bool
+	inTestcases     bool
+	inSanitizerDir  bool
+	inRamdisk       bool
+	inVendorRamdisk bool
+	inRecovery      bool
+	inRoot          bool
+	forceOS         *OsType
+	forceArch       *ArchType
 }
 
 func (m moduleInstallPathContextImpl) Config() Config {
@@ -232,6 +233,10 @@
 	return m.inRamdisk
 }
 
+func (m moduleInstallPathContextImpl) InstallInVendorRamdisk() bool {
+	return m.inVendorRamdisk
+}
+
 func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
 	return m.inRecovery
 }
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 5c55053..eccc4c9 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -24,12 +24,13 @@
 )
 
 var (
-	nativeBridgeSuffix = ".native_bridge"
-	productSuffix      = ".product"
-	vendorSuffix       = ".vendor"
-	ramdiskSuffix      = ".ramdisk"
-	recoverySuffix     = ".recovery"
-	sdkSuffix          = ".sdk"
+	nativeBridgeSuffix  = ".native_bridge"
+	productSuffix       = ".product"
+	vendorSuffix        = ".vendor"
+	ramdiskSuffix       = ".ramdisk"
+	vendorRamdiskSuffix = ".vendor_ramdisk"
+	recoverySuffix      = ".recovery"
+	sdkSuffix           = ".sdk"
 )
 
 type AndroidMkContext interface {
@@ -42,6 +43,7 @@
 	VndkVersion() string
 	static() bool
 	InRamdisk() bool
+	InVendorRamdisk() bool
 	InRecovery() bool
 	AnyVariantDirectlyInAnyApex() bool
 }
@@ -278,7 +280,7 @@
 		})
 	}
 	if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.AnyVariantDirectlyInAnyApex() &&
-		!ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() && !ctx.static() {
+		!ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() && !ctx.static() {
 		if library.buildStubs() && library.isLatestStubVersion() {
 			// reference the latest version via its name without suffix when it is provided by apex
 			entries.SubName = ""
diff --git a/cc/binary.go b/cc/binary.go
index 7f7b619..70cf5ff 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -251,7 +251,7 @@
 				} else {
 					switch ctx.Os() {
 					case android.Android:
-						if ctx.bootstrap() && !ctx.inRecovery() && !ctx.inRamdisk() {
+						if ctx.bootstrap() && !ctx.inRecovery() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() {
 							flags.DynamicLinker = "/system/bin/bootstrap/linker"
 						} else {
 							flags.DynamicLinker = "/system/bin/linker"
@@ -446,7 +446,8 @@
 	// runtime APEX.
 	translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
 	if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !ctx.Host() && ctx.directlyInAnyApex() &&
-		!translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
+		!translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() &&
+		!ctx.inVendorRamdisk() {
 
 		if ctx.Device() && isBionic(ctx.baseModuleName()) {
 			binary.installSymlinkToRuntimeApex(ctx, file)
diff --git a/cc/cc.go b/cc/cc.go
index dbe6346..910d610 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -257,14 +257,18 @@
 	// Make this module available when building for ramdisk
 	Ramdisk_available *bool
 
+	// Make this module available when building for vendor ramdisk
+	Vendor_ramdisk_available *bool
+
 	// Make this module available when building for recovery
 	Recovery_available *bool
 
 	// Set by imageMutator
-	CoreVariantNeeded     bool     `blueprint:"mutated"`
-	RamdiskVariantNeeded  bool     `blueprint:"mutated"`
-	RecoveryVariantNeeded bool     `blueprint:"mutated"`
-	ExtraVariants         []string `blueprint:"mutated"`
+	CoreVariantNeeded          bool     `blueprint:"mutated"`
+	RamdiskVariantNeeded       bool     `blueprint:"mutated"`
+	VendorRamdiskVariantNeeded bool     `blueprint:"mutated"`
+	RecoveryVariantNeeded      bool     `blueprint:"mutated"`
+	ExtraVariants              []string `blueprint:"mutated"`
 
 	// Allows this module to use non-APEX version of libraries. Useful
 	// for building binaries that are started before APEXes are activated.
@@ -352,6 +356,7 @@
 	inProduct() bool
 	inVendor() bool
 	inRamdisk() bool
+	inVendorRamdisk() bool
 	inRecovery() bool
 	shouldCreateSourceAbiDump() bool
 	selectedStl() string
@@ -946,7 +951,7 @@
 }
 
 func (c *Module) canUseSdk() bool {
-	return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery()
+	return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk()
 }
 
 func (c *Module) UseSdk() bool {
@@ -1396,6 +1401,8 @@
 		c.Properties.SubName += vendorSuffix
 	} else if c.InRamdisk() && !c.OnlyInRamdisk() {
 		c.Properties.SubName += ramdiskSuffix
+	} else if c.InVendorRamdisk() && !c.OnlyInVendorRamdisk() {
+		c.Properties.SubName += vendorRamdiskSuffix
 	} else if c.InRecovery() && !c.OnlyInRecovery() {
 		c.Properties.SubName += recoverySuffix
 	} else if c.IsSdkVariant() && (c.Properties.SdkAndPlatformVariantVisibleToMake || c.SplitPerApiLevel()) {
@@ -1508,7 +1515,7 @@
 		// module is marked with 'bootstrap: true').
 		if c.HasStubsVariants() && c.AnyVariantDirectlyInAnyApex() && !c.InRamdisk() &&
 			!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
-			c.IsStubs() {
+			c.IsStubs() && !c.InVendorRamdisk() {
 			c.Properties.HideFromMake = false // unhide
 			// Note: this is still non-installable
 		}
@@ -2044,6 +2051,10 @@
 		// Ramdisk code is not NDK
 		return
 	}
+	if from.InVendorRamdisk() {
+		// Vendor ramdisk code is not NDK
+		return
+	}
 	if from.InRecovery() {
 		// Recovery code is not NDK
 		return
@@ -2348,7 +2359,7 @@
 					} else if apexInfo.IsForPlatform() {
 						// If not building for APEX, use stubs only when it is from
 						// an APEX (and not from platform)
-						// However, for host, ramdisk, recovery or bootstrap modules,
+						// However, for host, ramdisk, vendor_ramdisk, recovery or bootstrap modules,
 						// always link to non-stub variant
 						useStubs = dep.(android.ApexModule).AnyVariantDirectlyInAnyApex() && !c.bootstrap()
 						// Another exception: if this module is bundled with an APEX, then
@@ -2642,7 +2653,8 @@
 		}
 	}
 
-	if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() {
+	if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() &&
+		!c.InRamdisk() && !c.InVendorRamdisk() && !c.InRecovery() {
 		// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 		// core module instead.
 		return libName
@@ -2654,6 +2666,8 @@
 		return libName + vendorPublicLibrarySuffix
 	} else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
 		return libName + ramdiskSuffix
+	} else if ccDep.InVendorRamdisk() && !ccDep.OnlyInVendorRamdisk() {
+		return libName + vendorRamdiskSuffix
 	} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
 		return libName + recoverySuffix
 	} else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
@@ -2684,6 +2698,10 @@
 	return c.InRamdisk()
 }
 
+func (c *Module) InstallInVendorRamdisk() bool {
+	return c.InVendorRamdisk()
+}
+
 func (c *Module) InstallInRecovery() bool {
 	return c.InRecovery()
 }
@@ -2784,6 +2802,8 @@
 		return "native:vendor"
 	} else if c.InRamdisk() {
 		return "native:ramdisk"
+	} else if c.InVendorRamdisk() {
+		return "native:vendor_ramdisk"
 	} else if c.InRecovery() {
 		return "native:recovery"
 	} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
diff --git a/cc/fuzz.go b/cc/fuzz.go
index e81b40f..681e3bc 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -388,10 +388,10 @@
 			return
 		}
 
-		// Discard ramdisk + recovery modules, they're duplicates of
+		// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
 		// fuzz targets we're going to package anyway.
 		if !ccModule.Enabled() || ccModule.Properties.PreventInstall ||
-			ccModule.InRamdisk() || ccModule.InRecovery() {
+			ccModule.InRamdisk() || ccModule.InVendorRamdisk() || ccModule.InRecovery() {
 			return
 		}
 
diff --git a/cc/genrule.go b/cc/genrule.go
index cce4a83..a5a58d2 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -24,10 +24,11 @@
 }
 
 type GenruleExtraProperties struct {
-	Vendor_available   *bool
-	Ramdisk_available  *bool
-	Recovery_available *bool
-	Sdk_version        *string
+	Vendor_available         *bool
+	Ramdisk_available        *bool
+	Vendor_ramdisk_available *bool
+	Recovery_available       *bool
+	Sdk_version              *string
 }
 
 // cc_genrule is a genrule that can depend on other cc_* objects.
@@ -68,6 +69,10 @@
 	return Bool(g.Ramdisk_available)
 }
 
+func (g *GenruleExtraProperties) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return Bool(g.Vendor_ramdisk_available)
+}
+
 func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return Bool(g.Recovery_available)
 }
diff --git a/cc/image.go b/cc/image.go
index 6710e94..ba091e1 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -27,12 +27,13 @@
 type imageVariantType string
 
 const (
-	coreImageVariant     imageVariantType = "core"
-	vendorImageVariant   imageVariantType = "vendor"
-	productImageVariant  imageVariantType = "product"
-	ramdiskImageVariant  imageVariantType = "ramdisk"
-	recoveryImageVariant imageVariantType = "recovery"
-	hostImageVariant     imageVariantType = "host"
+	coreImageVariant          imageVariantType = "core"
+	vendorImageVariant        imageVariantType = "vendor"
+	productImageVariant       imageVariantType = "product"
+	ramdiskImageVariant       imageVariantType = "ramdisk"
+	vendorRamdiskImageVariant imageVariantType = "vendor_ramdisk"
+	recoveryImageVariant      imageVariantType = "recovery"
+	hostImageVariant          imageVariantType = "host"
 )
 
 func (c *Module) getImageVariantType() imageVariantType {
@@ -44,6 +45,8 @@
 		return productImageVariant
 	} else if c.InRamdisk() {
 		return ramdiskImageVariant
+	} else if c.InVendorRamdisk() {
+		return vendorRamdiskImageVariant
 	} else if c.InRecovery() {
 		return recoveryImageVariant
 	} else {
@@ -83,6 +86,10 @@
 	return ctx.mod.InRamdisk()
 }
 
+func (ctx *moduleContextImpl) inVendorRamdisk() bool {
+	return ctx.mod.InVendorRamdisk()
+}
+
 func (ctx *moduleContextImpl) inRecovery() bool {
 	return ctx.mod.InRecovery()
 }
@@ -107,6 +114,10 @@
 	return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk()
 }
 
+func (c *Module) InVendorRamdisk() bool {
+	return c.ModuleBase.InVendorRamdisk() || c.ModuleBase.InstallInVendorRamdisk()
+}
+
 func (c *Module) InRecovery() bool {
 	return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery()
 }
@@ -115,6 +126,10 @@
 	return c.ModuleBase.InstallInRamdisk()
 }
 
+func (c *Module) OnlyInVendorRamdisk() bool {
+	return c.ModuleBase.InstallInVendorRamdisk()
+}
+
 func (c *Module) OnlyInRecovery() bool {
 	return c.ModuleBase.InstallInRecovery()
 }
@@ -165,6 +180,7 @@
 
 	var coreVariantNeeded bool = false
 	var ramdiskVariantNeeded bool = false
+	var vendorRamdiskVariantNeeded bool = false
 	var recoveryVariantNeeded bool = false
 
 	var vendorVariants []string
@@ -283,6 +299,15 @@
 		coreVariantNeeded = false
 	}
 
+	if Bool(m.Properties.Vendor_ramdisk_available) {
+		vendorRamdiskVariantNeeded = true
+	}
+
+	if m.ModuleBase.InstallInVendorRamdisk() {
+		vendorRamdiskVariantNeeded = true
+		coreVariantNeeded = false
+	}
+
 	if Bool(m.Properties.Recovery_available) {
 		recoveryVariantNeeded = true
 	}
@@ -301,6 +326,7 @@
 	}
 
 	m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded
+	m.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded
 	m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
 	m.Properties.CoreVariantNeeded = coreVariantNeeded
 }
@@ -313,6 +339,10 @@
 	return c.Properties.RamdiskVariantNeeded
 }
 
+func (c *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return c.Properties.VendorRamdiskVariantNeeded
+}
+
 func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return c.Properties.RecoveryVariantNeeded
 }
@@ -323,7 +353,7 @@
 
 func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
 	m := module.(*Module)
-	if variant == android.RamdiskVariation {
+	if variant == android.RamdiskVariation || variant == android.VendorRamdiskVariation {
 		m.MakeAsPlatform()
 	} else if variant == android.RecoveryVariation {
 		m.MakeAsPlatform()
diff --git a/cc/library.go b/cc/library.go
index 1b7e1ed..e9a59d5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1194,7 +1194,8 @@
 			isVendor := ctx.useVndk()
 			isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
 
-			if !ctx.inRamdisk() && !ctx.inRecovery() && (isProduct || (isOwnerPlatform == isVendor)) {
+			if !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() &&
+				(isProduct || (isOwnerPlatform == isVendor)) {
 				dir = android.PathForModuleGen(ctx, "sysprop/public", "include")
 			}
 		}
@@ -1286,7 +1287,7 @@
 			// runtime APEX.
 			translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
 			if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() &&
-				!translatedArch && !ctx.inRamdisk() && !ctx.inRecovery() {
+				!translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() {
 				if ctx.Device() {
 					library.installSymlinkToRuntimeApex(ctx, file)
 				}
@@ -1301,7 +1302,7 @@
 	}
 
 	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
-		!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
+		!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
 		library.baseLinker.sanitize.isUnsanitizedVariant() &&
 		!library.buildStubs() && ctx.sdkVersion() == "" {
 		installPath := getNdkSysrootBase(ctx).Join(
@@ -1635,14 +1636,16 @@
 func CanBeOrLinkAgainstVersionVariants(module interface {
 	Host() bool
 	InRamdisk() bool
+	InVendorRamdisk() bool
 	InRecovery() bool
 }) bool {
-	return !module.Host() && !module.InRamdisk() && !module.InRecovery()
+	return !module.Host() && !module.InRamdisk() && !module.InVendorRamdisk() && !module.InRecovery()
 }
 
 func CanBeVersionVariant(module interface {
 	Host() bool
 	InRamdisk() bool
+	InVendorRamdisk() bool
 	InRecovery() bool
 	CcLibraryInterface() bool
 	Shared() bool
diff --git a/cc/linkable.go b/cc/linkable.go
index 4eb7220..177e0c4 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -40,6 +40,9 @@
 	InRamdisk() bool
 	OnlyInRamdisk() bool
 
+	InVendorRamdisk() bool
+	OnlyInVendorRamdisk() bool
+
 	InRecovery() bool
 	OnlyInRecovery() bool
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 43198c1..b1326d9 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -376,8 +376,8 @@
 	}
 
 	// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
-	// Keep libc instrumented so that ramdisk / recovery can run hwasan-instrumented code if necessary.
-	if (ctx.inRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
+	// Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
+	if (ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
 		s.Hwaddress = nil
 	}
 
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 64e3ea8..78bde38 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -1005,9 +1005,10 @@
 		// But we can't just check SocSpecific() since we already passed the image mutator.
 		// Check ramdisk and recovery to see if we are real "vendor: true" module.
 		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
+		vendor_ramdisk_available := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
 		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
 
-		if !ramdisk_available && !recovery_available {
+		if !ramdisk_available && !recovery_available && !vendor_ramdisk_available {
 			vendorSnapshotsLock.Lock()
 			defer vendorSnapshotsLock.Unlock()
 
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 664cb51..337ad88 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -61,6 +61,9 @@
 	// Make this module available when building for ramdisk.
 	Ramdisk_available *bool
 
+	// Make this module available when building for vendor ramdisk.
+	Vendor_ramdisk_available *bool
+
 	// Make this module available when building for recovery.
 	Recovery_available *bool
 
@@ -105,6 +108,18 @@
 	return p.inRamdisk()
 }
 
+func (p *PrebuiltEtc) inVendorRamdisk() bool {
+	return p.ModuleBase.InVendorRamdisk() || p.ModuleBase.InstallInVendorRamdisk()
+}
+
+func (p *PrebuiltEtc) onlyInVendorRamdisk() bool {
+	return p.ModuleBase.InstallInVendorRamdisk()
+}
+
+func (p *PrebuiltEtc) InstallInVendorRamdisk() bool {
+	return p.inVendorRamdisk()
+}
+
 func (p *PrebuiltEtc) inRecovery() bool {
 	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
 }
@@ -122,13 +137,18 @@
 func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {}
 
 func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk()
+	return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() &&
+		!p.ModuleBase.InstallInVendorRamdisk()
 }
 
 func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
 	return proptools.Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk()
 }
 
+func (p *PrebuiltEtc) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return proptools.Bool(p.properties.Vendor_ramdisk_available) || p.ModuleBase.InstallInVendorRamdisk()
+}
+
 func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
 }
@@ -228,6 +248,9 @@
 	if p.inRamdisk() && !p.onlyInRamdisk() {
 		nameSuffix = ".ramdisk"
 	}
+	if p.inVendorRamdisk() && !p.onlyInVendorRamdisk() {
+		nameSuffix = ".vendor_ramdisk"
+	}
 	if p.inRecovery() && !p.onlyInRecovery() {
 		nameSuffix = ".recovery"
 	}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 99d6207..b09c195 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -605,6 +605,7 @@
 func (x noopImageInterface) ImageMutatorBegin(android.BaseModuleContext)                 {}
 func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool            { return false }
 func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool         { return false }
+func (x noopImageInterface) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool   { return false }
 func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool        { return false }
 func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
 func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
diff --git a/rust/rust.go b/rust/rust.go
index 1b999d7..77d9a90 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -118,6 +118,10 @@
 	return mod.InRamdisk()
 }
 
+func (mod *Module) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool {
+	return mod.InVendorRamdisk()
+}
+
 func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
 	return mod.InRecovery()
 }
@@ -185,6 +189,10 @@
 	return false
 }
 
+func (mod *Module) OnlyInVendorRamdisk() bool {
+	return false
+}
+
 func (mod *Module) OnlyInRecovery() bool {
 	return false
 }
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index e807877..6f40ae4 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -68,6 +68,9 @@
 	// Make this module available when building for ramdisk.
 	Ramdisk_available *bool
 
+	// Make this module available when building for vendor ramdisk.
+	Vendor_ramdisk_available *bool
+
 	// Make this module available when building for recovery.
 	Recovery_available *bool
 }
@@ -176,6 +179,10 @@
 	return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk()
 }
 
+func (s *ShBinary) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return proptools.Bool(s.properties.Vendor_ramdisk_available) || s.ModuleBase.InstallInVendorRamdisk()
+}
+
 func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
 }