Merge d2e544028f18f22b71c9ff930f35dc3066853422 on remote branch

Change-Id: I0c2563dd1b555291c64ea29f3b4dbab8d9009250
diff --git a/android/config.go b/android/config.go
index d63f3ae..28d9de9 100644
--- a/android/config.go
+++ b/android/config.go
@@ -85,10 +85,11 @@
 	ConfigFileName           string
 	ProductVariablesFileName string
 
-	Targets             map[OsType][]Target
-	BuildOSTarget       Target // the Target for tools run on the build machine
-	BuildOSCommonTarget Target // the Target for common (java) tools run on the build machine
-	AndroidCommonTarget Target // the Target for common modules for the Android device
+	Targets                  map[OsType][]Target
+	BuildOSTarget            Target // the Target for tools run on the build machine
+	BuildOSCommonTarget      Target // the Target for common (java) tools run on the build machine
+	AndroidCommonTarget      Target // the Target for common modules for the Android device
+	AndroidFirstDeviceTarget Target // the first Target for modules for the Android device
 
 	// multilibConflicts for an ArchType is true if there is earlier configured device architecture with the same
 	// multilib value.
@@ -309,6 +310,7 @@
 	config.BuildOSTarget = config.Targets[BuildOs][0]
 	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
 	config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+	config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
 	config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
 	config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
@@ -403,6 +405,7 @@
 	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
 	if len(config.Targets[Android]) > 0 {
 		config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+		config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	}
 
 	if err := config.fromEnv(); err != nil {
@@ -999,6 +1002,10 @@
 	return String(c.config.productVariables.RecoverySnapshotVersion)
 }
 
+func (c *deviceConfig) RamdiskSnapshotVersion() string {
+	return String(c.config.productVariables.RamdiskSnapshotVersion)
+}
+
 func (c *deviceConfig) PlatformVndkVersion() string {
 	return String(c.config.productVariables.Platform_vndk_version)
 }
@@ -1322,3 +1329,67 @@
 func (c *deviceConfig) RecoverySnapshotModules() map[string]bool {
 	return c.config.productVariables.RecoverySnapshotModules
 }
+
+func (c *deviceConfig) DirectedRamdiskSnapshot() bool {
+	return c.config.productVariables.DirectedRamdiskSnapshot
+}
+
+func (c *deviceConfig) RamdiskSnapshotModules() map[string]bool {
+	return c.config.productVariables.RamdiskSnapshotModules
+}
+
+func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) {
+	var ret = make(map[string]bool)
+	for _, dir := range dirs {
+		clean := filepath.Clean(dir)
+		if previous[clean] || ret[clean] {
+			return nil, fmt.Errorf("Duplicate entry %s", dir)
+		}
+		ret[clean] = true
+	}
+	return ret, nil
+}
+
+func (c *deviceConfig) createDirsMapOnce(onceKey OnceKey, previous map[string]bool, dirs []string) map[string]bool {
+	dirMap := c.Once(onceKey, func() interface{} {
+		ret, err := createDirsMap(previous, dirs)
+		if err != nil {
+			panic(fmt.Errorf("%s: %w", *onceKey.key.(*string), err))
+		}
+		return ret
+	})
+	if dirMap == nil {
+		return nil
+	}
+	return dirMap.(map[string]bool)
+}
+
+var vendorSnapshotDirsExcludedKey = NewOnceKey("VendorSnapshotDirsExcludedMap")
+
+func (c *deviceConfig) VendorSnapshotDirsExcludedMap() map[string]bool {
+	return c.createDirsMapOnce(vendorSnapshotDirsExcludedKey, nil,
+		c.config.productVariables.VendorSnapshotDirsExcluded)
+}
+
+var vendorSnapshotDirsIncludedKey = NewOnceKey("VendorSnapshotDirsIncludedMap")
+
+func (c *deviceConfig) VendorSnapshotDirsIncludedMap() map[string]bool {
+	excludedMap := c.VendorSnapshotDirsExcludedMap()
+	return c.createDirsMapOnce(vendorSnapshotDirsIncludedKey, excludedMap,
+		c.config.productVariables.VendorSnapshotDirsIncluded)
+}
+
+var recoverySnapshotDirsExcludedKey = NewOnceKey("RecoverySnapshotDirsExcludedMap")
+
+func (c *deviceConfig) RecoverySnapshotDirsExcludedMap() map[string]bool {
+	return c.createDirsMapOnce(recoverySnapshotDirsExcludedKey, nil,
+		c.config.productVariables.RecoverySnapshotDirsExcluded)
+}
+
+var recoverySnapshotDirsIncludedKey = NewOnceKey("RecoverySnapshotDirsIncludedMap")
+
+func (c *deviceConfig) RecoverySnapshotDirsIncludedMap() map[string]bool {
+	excludedMap := c.RecoverySnapshotDirsExcludedMap()
+	return c.createDirsMapOnce(recoverySnapshotDirsIncludedKey, excludedMap,
+		c.config.productVariables.RecoverySnapshotDirsIncluded)
+}
diff --git a/android/variable.go b/android/variable.go
index 9961180..34d145e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -151,9 +151,9 @@
 		}
 
 		Device_support_hwfde struct {
-			Cflags []string
-			Header_libs  []string
-			Shared_libs  []string
+			Cflags      []string
+			Header_libs []string
+			Shared_libs []string
 		}
 
 		Device_support_hwfde_perf struct {
@@ -192,6 +192,7 @@
 	DeviceSystemSdkVersions []string `json:",omitempty"`
 
 	RecoverySnapshotVersion *string `json:",omitempty"`
+	RamdiskSnapshotVersion  *string `json:",omitempty"`
 
 	DeviceSecondaryArch        *string  `json:",omitempty"`
 	DeviceSecondaryArchVariant *string  `json:",omitempty"`
@@ -233,10 +234,10 @@
 
 	AppsDefaultVersionName *string `json:",omitempty"`
 
-	Real_hal                   *bool `json:",omitempty"`
-	Qmaa_hal                   *bool `json:",omitempty"`
-	Device_support_hwfde       *bool `json:",omitempty"`
-	Device_support_hwfde_perf  *bool `json:",omitempty"`
+	Real_hal                         *bool `json:",omitempty"`
+	Qmaa_hal                         *bool `json:",omitempty"`
+	Device_support_hwfde             *bool `json:",omitempty"`
+	Device_support_hwfde_perf        *bool `json:",omitempty"`
 	Allow_missing_dependencies       *bool `json:",omitempty"`
 	Unbundled_build                  *bool `json:",omitempty"`
 	Unbundled_build_sdks_from_source *bool `json:",omitempty"`
@@ -336,6 +337,14 @@
 	DirectedRecoverySnapshot bool            `json:",omitempty"`
 	RecoverySnapshotModules  map[string]bool `json:",omitempty"`
 
+	DirectedRamdiskSnapshot bool            `json:",omitempty"`
+	RamdiskSnapshotModules  map[string]bool `json:",omitempty"`
+
+	VendorSnapshotDirsIncluded   []string `json:",omitempty"`
+	VendorSnapshotDirsExcluded   []string `json:",omitempty"`
+	RecoverySnapshotDirsExcluded []string `json:",omitempty"`
+	RecoverySnapshotDirsIncluded []string `json:",omitempty"`
+
 	BoardVendorSepolicyDirs      []string `json:",omitempty"`
 	BoardOdmSepolicyDirs         []string `json:",omitempty"`
 	BoardPlatPublicSepolicyDirs  []string `json:",omitempty"`
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 077ad2b..0ad2fcf 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -95,9 +95,9 @@
 				if len(c.Properties.AndroidMkHeaderLibs) > 0 {
 					entries.AddStrings("LOCAL_HEADER_LIBRARIES", c.Properties.AndroidMkHeaderLibs...)
 				}
-                                if lib, ok := c.compiler.(*libraryDecorator); ok {
-                                       entries.AddStrings("LOCAL_SRC_FILES", lib.baseCompiler.srcsBeforeGen.Strings()...)
-                                }
+				if lib, ok := c.compiler.(*libraryDecorator); ok {
+					entries.AddStrings("LOCAL_SRC_FILES", lib.baseCompiler.srcsBeforeGen.Strings()...)
+				}
 				entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
 				if c.UseVndk() {
 					entries.SetBool("LOCAL_USE_VNDK", true)
@@ -520,7 +520,10 @@
 			entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
 			entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
 			entries.SetString("LOCAL_MODULE_STEM", stem)
-			if c.shared() {
+			// TODO(b/181815415) remove isLlndk() when possible
+			if c.isLlndk() {
+				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+			} else if c.shared() {
 				entries.SetString("LOCAL_MODULE_PATH", path)
 			}
 			if c.tocFile.Valid() {
diff --git a/cc/cc.go b/cc/cc.go
index f0e10b0..bc1e5ec 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -54,6 +54,8 @@
 		ctx.BottomUp("vendor_snapshot_source", VendorSnapshotSourceMutator).Parallel()
 		ctx.BottomUp("recovery_snapshot", RecoverySnapshotMutator).Parallel()
 		ctx.BottomUp("recovery_snapshot_source", RecoverySnapshotSourceMutator).Parallel()
+		ctx.BottomUp("ramdisk_snapshot", RamdiskSnapshotMutator).Parallel()
+		ctx.BottomUp("ramdisk_snapshot_source", RamdiskSnapshotSourceMutator).Parallel()
 	})
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -291,6 +293,13 @@
 	// allows a partner to exclude a module normally thought of as a
 	// framework module from the recovery snapshot.
 	Exclude_from_recovery_snapshot *bool
+
+    // Normally Soong uses the directory structure to decide which modules
+	// should be included (framework) or excluded (non-framework) from the
+	// different snapshots (vendor, recovery, etc.), but this property
+	// allows a partner to exclude a module normally thought of as a
+	// framework module from the ramdisk snapshot.
+	Exclude_from_ramdisk_snapshot *bool
 }
 
 type VendorProperties struct {
@@ -1032,6 +1041,11 @@
 	return Bool(c.Properties.Exclude_from_recovery_snapshot)
 }
 
+func (c *Module) ExcludeFromRamdiskSnapshot() bool {
+	return Bool(c.Properties.Exclude_from_ramdisk_snapshot)
+}
+
+
 func isBionic(name string) bool {
 	switch name {
 	case "libc", "libm", "libdl", "libdl_android", "linker":
@@ -1518,7 +1532,7 @@
 		}
 
 		// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or
-		// RECOVERY_SNAPSHOT_VERSION is current.
+		// RECOVERY_SNAPSHOT_VERSION is current or RAMDISK_SNAPSHOT_VERSION is current.
 		if i, ok := c.linker.(snapshotLibraryInterface); ok {
 			if shouldCollectHeadersForSnapshot(ctx, c) {
 				i.collectHeadersForSnapshot(ctx)
@@ -1720,21 +1734,23 @@
 		vendorPublicLibraries := vendorPublicLibraries(actx.Config())
 		vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config())
 		recoverySnapshotSharedLibs := recoverySnapshotSharedLibs(actx.Config())
+		ramdiskSnapshotSharedLibs := ramdiskSnapshotSharedLibs(actx.Config())
 
 		rewriteVendorLibs := func(lib string) string {
+			// Only a module with BOARD_VNDK_VERSION uses snapshot.
+			// We check this before checking if the library is an
+			// llndk so that the snapshot can contain llndk
+			// libraries.
+			if c.VndkVersion() == actx.DeviceConfig().VndkVersion() {
+				if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok {
+					return snapshot
+				}
+			}
+
 			if isLlndkLibrary(lib, ctx.Config()) {
 				return lib + llndkLibrarySuffix
 			}
 
-			// only modules with BOARD_VNDK_VERSION uses snapshot.
-			if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
-				return lib
-			}
-
-			if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok {
-				return snapshot
-			}
-
 			return lib
 		}
 
@@ -1756,6 +1772,18 @@
 					} else {
 						nonvariantLibs = append(nonvariantLibs, name)
 					}
+				} else if c.InRamdisk() {
+					ramdiskSnapshotVersion :=
+						actx.DeviceConfig().RamdiskSnapshotVersion()
+					if ramdiskSnapshotVersion == "current" ||
+						ramdiskSnapshotVersion == "" {
+						nonvariantLibs = append(nonvariantLibs, name)
+					} else if snapshot, ok := ramdiskSnapshotSharedLibs.get(
+						name, actx.Arch().ArchType); ok {
+						nonvariantLibs = append(nonvariantLibs, snapshot)
+					} else {
+						nonvariantLibs = append(nonvariantLibs, name)
+					}
 				} else if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) {
 					if !inList(name, ndkMigratedLibs) {
 						nonvariantLibs = append(nonvariantLibs, name+".ndk."+version)
@@ -1837,6 +1865,25 @@
 		snapshotObjects = recoverySnapshotObjects(actx.Config())
 	}
 
+	if c.InRamdisk() {
+		rewriteSnapshotLibs = func(lib string, snapshotMap *snapshotMap) string {
+			ramdiskSnapshotVersion :=
+				actx.DeviceConfig().RamdiskSnapshotVersion()
+			if ramdiskSnapshotVersion == "current" ||
+				ramdiskSnapshotVersion == "" {
+				return lib
+			} else if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok {
+				return snapshot
+			}
+
+			return lib
+		}
+
+		snapshotHeaderLibs = ramdiskSnapshotHeaderLibs(actx.Config())
+		snapshotStaticLibs = ramdiskSnapshotStaticLibs(actx.Config())
+		snapshotObjects = ramdiskSnapshotObjects(actx.Config())
+	}
+
 	for _, lib := range deps.HeaderLibs {
 		depTag := headerDepTag
 		if inList(lib, deps.ReexportHeaderLibHeaders) {
@@ -2606,6 +2653,7 @@
 func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string {
 	vendorSuffixModules := vendorSuffixModules(ctx.Config())
 	recoverySuffixModules := recoverySuffixModules(ctx.Config())
+	ramdiskSuffixModules := ramdiskSuffixModules(ctx.Config())
 	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
 
 	libName := baseLibName(depName)
@@ -2626,6 +2674,8 @@
 				return baseName + ".vendor"
 			} else if c.InRecovery() && recoverySuffixModules[baseName] {
 				return baseName + ".recovery"
+			} else if c.InRamdisk() && ramdiskSuffixModules[baseName] {
+				return baseName + ".ramdisk"
 			} else {
 				return baseName
 			}
diff --git a/cc/config/global.go b/cc/config/global.go
index cb543e1..b633a72 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -141,7 +141,7 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r383902b"
+	ClangDefaultVersion      = "clang-r383902b1"
 	ClangDefaultShortVersion = "11.0.2"
 
 	// Directories with warnings from Android.bp files.
diff --git a/cc/genrule.go b/cc/genrule.go
index 07ec12a..e6ef62a 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -64,9 +64,7 @@
 	return Bool(g.Vendor_available) || !(ctx.SocSpecific() || ctx.DeviceSpecific())
 }
 
-func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return Bool(g.Ramdisk_available)
-}
+
 
 func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	// If the build is using a snapshot, the recovery variant under AOSP directories
@@ -79,6 +77,17 @@
 		return Bool(g.Recovery_available)
 	}
 }
+func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	// If the build is using a snapshot, the ramdisk variant under AOSP directories
+	// is not needed.
+	ramdiskSnapshotVersion := ctx.DeviceConfig().RamdiskSnapshotVersion()
+	if ramdiskSnapshotVersion != "current" && ramdiskSnapshotVersion != "" &&
+		!isRamdiskProprietaryModule(ctx) {
+		return false
+	} else {
+		return Bool(g.Ramdisk_available)
+	}
+}
 
 func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string {
 	if ctx.DeviceConfig().VndkVersion() == "" {
diff --git a/cc/image.go b/cc/image.go
index 2772c72..6b3b083 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -176,12 +176,16 @@
 	recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
 	usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
 		recoverySnapshotVersion != ""
+	ramdiskSnapshotVersion := mctx.DeviceConfig().RamdiskSnapshotVersion()
+	usingRamdiskSnapshot := ramdiskSnapshotVersion != "current" &&
+		ramdiskSnapshotVersion != ""
 	if boardVndkVersion == "current" {
 		boardVndkVersion = platformVndkVersion
 	}
 	if productVndkVersion == "current" {
 		productVndkVersion = platformVndkVersion
 	}
+	usingVendorSnapshot := boardVndkVersion != platformVndkVersion
 
 	if boardVndkVersion == "" {
 		// If the device isn't compiling against the VNDK, we always
@@ -190,20 +194,44 @@
 	} else if _, ok := m.linker.(*llndkStubDecorator); ok {
 		// LL-NDK stubs only exist in the vendor and product variants,
 		// since the real libraries will be used in the core variant.
-		vendorVariants = append(vendorVariants,
-			platformVndkVersion,
-			boardVndkVersion,
-		)
+
+		if usingVendorSnapshot {
+			// If we're using the vendor snapshot, avoid providing
+			// the boardVndkVersion. This requires that the vendor
+			// snapshot provide the library instead, which happens
+			// below as a snapshot prebuilt.
+			vendorVariants = append(vendorVariants,
+				platformVndkVersion,
+			)
+		} else {
+			vendorVariants = append(vendorVariants,
+				platformVndkVersion,
+				boardVndkVersion,
+			)
+		}
+
 		productVariants = append(productVariants,
 			platformVndkVersion,
 			productVndkVersion,
 		)
 	} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
 		// ... and LL-NDK headers as well
-		vendorVariants = append(vendorVariants,
-			platformVndkVersion,
-			boardVndkVersion,
-		)
+
+		if usingVendorSnapshot {
+			// If we're using the vendor snapshot, avoid providing
+			// the boardVndkVersion. This requires that the vendor
+			// snapshot provide the headers instead, which happens
+			// below as a snapshot prebuilt.
+			vendorVariants = append(vendorVariants,
+				platformVndkVersion,
+			)
+		} else {
+			vendorVariants = append(vendorVariants,
+				platformVndkVersion,
+				boardVndkVersion,
+			)
+		}
+
 		productVariants = append(productVariants,
 			platformVndkVersion,
 			productVndkVersion,
@@ -216,6 +244,8 @@
 		}); ok {
 			if m.InstallInRecovery() {
 				recoveryVariantNeeded = true
+			} else if m.InstallInRamdisk() {
+				ramdiskVariantNeeded = true
 			} else {
 				vendorVariants = append(vendorVariants, snapshot.version())
 			}
@@ -307,6 +337,12 @@
 		!isRecoveryProprietaryModule(mctx) {
 		recoveryVariantNeeded = false
 	}
+	if _, ok := m.linker.(*kernelHeadersDecorator); !ok &&
+		!m.isSnapshotPrebuilt() &&
+		usingRamdiskSnapshot &&
+		!isRamdiskProprietaryModule(mctx) {
+		ramdiskVariantNeeded = false
+	}
 
 	for _, variant := range android.FirstUniqueStrings(vendorVariants) {
 		m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant)
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 71c9204..19f5641 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -116,6 +116,7 @@
 	srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
 	srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
 
+	var depPaths []android.Path
 	var installPaths []android.WritablePath
 	for _, header := range srcFiles {
 		headerDir := filepath.Dir(header.String())
@@ -126,9 +127,14 @@
 			continue
 		}
 
-		installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
+		outputPath := outDir.Join(ctx, relHeaderDir, header.Base())
+		depPaths = append(depPaths, outputPath)
+		installPaths = append(installPaths, outputPath)
 	}
 
+	// Add the processed, exported headers so that they can be collected in
+	// a snapshot later, if necessary.
+	stub.addExportedGeneratedHeaders(depPaths...)
 	return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths)
 }
 
diff --git a/cc/makevars.go b/cc/makevars.go
index f80df64..3c8c355 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -103,6 +103,7 @@
 
 	ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
 	ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion())
+	ctx.Strict("RAMDISK_SNAPSHOT_VERSION", ctx.DeviceConfig().RamdiskSnapshotVersion())
 
 	// Filter vendor_public_library that are exported to make
 	exportedVendorPublicLibraries := []string{}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 2749a0b..5989dd8 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -18,6 +18,7 @@
 // snapshot mutators and snapshot information maps which are also defined in this file.
 
 import (
+	"path/filepath"
 	"strings"
 	"sync"
 
@@ -49,9 +50,9 @@
 	// directory, such as device/, vendor/, etc.
 	//
 	// For a given snapshot (e.g., vendor, recovery, etc.) if
-	// isProprietaryPath(dir) returns true, then the module in dir will be
-	// built from sources.
-	isProprietaryPath(dir string) bool
+	// isProprietaryPath(dir, deviceConfig) returns true, then the module in dir
+	// will be built from sources.
+	isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool
 
 	// Whether to include VNDK in the snapshot for this image.
 	includeVndk() bool
@@ -91,6 +92,34 @@
 
 type vendorSnapshotImage struct{}
 type recoverySnapshotImage struct{}
+type ramdiskSnapshotImage struct{}
+
+type directoryMap map[string]bool
+
+var (
+	// Modules under following directories are ignored. They are OEM's and vendor's
+	// proprietary modules(device/, kernel/, vendor/, and hardware/).
+	defaultDirectoryExcludedMap = directoryMap{
+		"device":   true,
+		"hardware": true,
+		"kernel":   true,
+		"vendor":   true,
+		// QC specific directories to be ignored
+		"disregard": true,
+	}
+
+	// Modules under following directories are included as they are in AOSP,
+	// although hardware/ and kernel/ are normally for vendor's own.
+	defaultDirectoryIncludedMap = directoryMap{
+		"kernel/configs":              true,
+		"kernel/prebuilts":            true,
+		"kernel/tests":                true,
+		"hardware/interfaces":         true,
+		"hardware/libhardware":        true,
+		"hardware/libhardware_legacy": true,
+		"hardware/ril":                true,
+	}
+)
 
 func (vendorSnapshotImage) init() {
 	android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
@@ -116,8 +145,25 @@
 	return m.VendorProperties.Vendor_available
 }
 
-func (vendorSnapshotImage) isProprietaryPath(dir string) bool {
-	return isVendorProprietaryPath(dir)
+func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool {
+	if dir == "." || dir == "/" {
+		return false
+	}
+	if includedMap[dir] {
+		return false
+	} else if excludedMap[dir] {
+		return true
+	} else if defaultDirectoryIncludedMap[dir] {
+		return false
+	} else if defaultDirectoryExcludedMap[dir] {
+		return true
+	} else {
+		return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap)
+	}
+}
+
+func (vendorSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap())
 }
 
 // vendor snapshot includes static/header libraries with vndk: {enabled: true}.
@@ -190,10 +236,6 @@
 	if module.VndkVersion() != vndkVersion {
 		return true
 	}
-	// .. and also filter out llndk library
-	if module.isLlndk(ctx.Config()) {
-		return true
-	}
 	return false
 }
 
@@ -230,8 +272,8 @@
 	return m.Properties.Recovery_available
 }
 
-func (recoverySnapshotImage) isProprietaryPath(dir string) bool {
-	return isRecoveryProprietaryPath(dir)
+func (recoverySnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap())
 }
 
 // recovery snapshot does NOT treat vndk specially.
@@ -298,12 +340,105 @@
 	return !cfg.RecoverySnapshotModules()[name]
 }
 
+func (ramdiskSnapshotImage) init() {
+	android.RegisterSingletonType("ramdisk-snapshot", RamdiskSnapshotSingleton)
+	android.RegisterModuleType("ramdisk_snapshot_shared", RamdiskSnapshotSharedFactory)
+	android.RegisterModuleType("ramdisk_snapshot_static", RamdiskSnapshotStaticFactory)
+	android.RegisterModuleType("ramdisk_snapshot_header", RamdiskSnapshotHeaderFactory)
+	android.RegisterModuleType("ramdisk_snapshot_binary", RamdiskSnapshotBinaryFactory)
+	android.RegisterModuleType("ramdisk_snapshot_object", RamdiskSnapshotObjectFactory)
+}
+
+func (ramdiskSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
+	// RAMDISK_SNAPSHOT_VERSION must be set to 'current' in order to generate a
+	// snapshot.
+	return ctx.DeviceConfig().RamdiskSnapshotVersion() == "current"
+}
+
+func (ramdiskSnapshotImage) inImage(m *Module) func() bool {
+	return m.InRamdisk
+}
+
+func (ramdiskSnapshotImage) available(m *Module) *bool {
+	return m.Properties.Ramdisk_available
+}
+
+func (ramdiskSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return isDirectoryExcluded(dir, nil, nil)
+}
+
+// ramdisk snapshot does NOT treat vndk specially.
+func (ramdiskSnapshotImage) includeVndk() bool {
+	return false
+}
+
+func (ramdiskSnapshotImage) excludeFromSnapshot(m *Module) bool {
+	return m.ExcludeFromRamdiskSnapshot()
+}
+
+func (ramdiskSnapshotImage) getSnapshotMap(m *Module, cfg android.Config) *snapshotMap {
+	if lib, ok := m.linker.(libraryInterface); ok {
+		if lib.static() {
+			return ramdiskSnapshotStaticLibs(cfg)
+		} else if lib.shared() {
+			return ramdiskSnapshotSharedLibs(cfg)
+		} else {
+			// header
+			return ramdiskSnapshotHeaderLibs(cfg)
+		}
+	} else if m.binary() {
+		return ramdiskSnapshotBinaries(cfg)
+	} else if m.object() {
+		return ramdiskSnapshotObjects(cfg)
+	} else {
+		return nil
+	}
+}
+
+func (ramdiskSnapshotImage) getMutex() *sync.Mutex {
+	return &ramdiskSnapshotsLock
+}
+
+func (ramdiskSnapshotImage) suffixModules(config android.Config) map[string]bool {
+	return ramdiskSuffixModules(config)
+}
+
+func (ramdiskSnapshotImage) shouldBeAddedToSuffixModules(module *Module) bool {
+	return proptools.BoolDefault(module.Properties.Ramdisk_available, false)
+}
+
+func (ramdiskSnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool {
+	ramdiskSnapshotVersion := cfg.RamdiskSnapshotVersion()
+	return ramdiskSnapshotVersion != "current" && ramdiskSnapshotVersion != ""
+}
+
+func (ramdiskSnapshotImage) skipModuleMutator(ctx android.BottomUpMutatorContext) bool {
+	module, ok := ctx.Module().(*Module)
+	return !ok || !module.InRamdisk()
+}
+
+func (ramdiskSnapshotImage) skipSourceMutator(ctx android.BottomUpMutatorContext) bool {
+	module, ok := ctx.Module().(*Module)
+	return !ok || !module.InRamdisk()
+}
+
+func (ramdiskSnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
+	// If we're using full snapshot, not directed snapshot, capture every module
+	if !cfg.DirectedRamdiskSnapshot() {
+		return false
+	}
+	// Else, checks if name is in RAMDSIK_SNAPSHOT_MODULES.
+	return !cfg.RamdiskSnapshotModules()[name]
+}
+
 var vendorSnapshotImageSingleton vendorSnapshotImage
 var recoverySnapshotImageSingleton recoverySnapshotImage
+var ramdiskSnapshotImageSingleton ramdiskSnapshotImage
 
 func init() {
 	vendorSnapshotImageSingleton.init()
 	recoverySnapshotImageSingleton.init()
+	ramdiskSnapshotImageSingleton.init()
 }
 
 const (
@@ -322,6 +457,14 @@
 	recoverySnapshotObjectSuffix = ".recovery_object."
 )
 
+const (
+	ramdiskSnapshotHeaderSuffix = ".ramdisk_header."
+	ramdiskSnapshotSharedSuffix = ".ramdisk_shared."
+	ramdiskSnapshotStaticSuffix = ".ramdisk_static."
+	ramdiskSnapshotBinarySuffix = ".ramdisk_binary."
+	ramdiskSnapshotObjectSuffix = ".ramdisk_object."
+)
+
 var (
 	vendorSnapshotsLock         sync.Mutex
 	vendorSuffixModulesKey      = android.NewOnceKey("vendorSuffixModules")
@@ -341,6 +484,15 @@
 	recoverySnapshotBinariesKey   = android.NewOnceKey("recoverySnapshotBinaries")
 	recoverySnapshotObjectsKey    = android.NewOnceKey("recoverySnapshotObjects")
 )
+var (
+	ramdiskSnapshotsLock         sync.Mutex
+	ramdiskSuffixModulesKey      = android.NewOnceKey("ramdiskSuffixModules")
+	ramdiskSnapshotHeaderLibsKey = android.NewOnceKey("ramdiskSnapshotHeaderLibs")
+	ramdiskSnapshotStaticLibsKey = android.NewOnceKey("ramdiskSnapshotStaticLibs")
+	ramdiskSnapshotSharedLibsKey = android.NewOnceKey("ramdiskSnapshotSharedLibs")
+	ramdiskSnapshotBinariesKey   = android.NewOnceKey("ramdiskSnapshotBinaries")
+	ramdiskSnapshotObjectsKey    = android.NewOnceKey("ramdiskSnapshotObjects")
+)
 
 // vendorSuffixModules holds names of modules whose vendor variants should have the vendor suffix.
 // This is determined by source modules, and then this will be used when exporting snapshot modules
@@ -424,6 +576,42 @@
 	}).(*snapshotMap)
 }
 
+func ramdiskSuffixModules(config android.Config) map[string]bool {
+	return config.Once(ramdiskSuffixModulesKey, func() interface{} {
+		return make(map[string]bool)
+	}).(map[string]bool)
+}
+
+func ramdiskSnapshotHeaderLibs(config android.Config) *snapshotMap {
+	return config.Once(ramdiskSnapshotHeaderLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func ramdiskSnapshotSharedLibs(config android.Config) *snapshotMap {
+	return config.Once(ramdiskSnapshotSharedLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func ramdiskSnapshotStaticLibs(config android.Config) *snapshotMap {
+	return config.Once(ramdiskSnapshotStaticLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func ramdiskSnapshotBinaries(config android.Config) *snapshotMap {
+	return config.Once(ramdiskSnapshotBinariesKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func ramdiskSnapshotObjects(config android.Config) *snapshotMap {
+	return config.Once(ramdiskSnapshotObjectsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
 type baseSnapshotDecoratorProperties struct {
 	// snapshot version.
 	Version string
@@ -527,6 +715,10 @@
 
 	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
 	Sanitize_minimal_dep *bool `android:"arch_variant"`
+
+	// TODO(b/181815415) remove Is_llndk when possible
+	// Whether this prebuilt is a snapshot of an llndk library.
+	Is_llndk *bool
 }
 
 type snapshotSanitizer interface {
@@ -573,8 +765,9 @@
 		p.androidMkSuffix = vendorSuffix
 	} else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = recoverySuffix
+	} else if m.InRamdisk() && ramdiskSuffixModules(ctx.Config())[m.BaseModuleName()] {
+		p.androidMkSuffix = ramdiskSuffix
 	}
-
 	if p.header() {
 		return p.libraryDecorator.link(ctx, flags, deps, objs)
 	}
@@ -639,6 +832,11 @@
 	}
 }
 
+// TODO(b/181815415) remove isLlndk() when possible
+func (p *snapshotLibraryDecorator) isLlndk() bool {
+	return Bool(p.properties.Is_llndk)
+}
+
 func snapshotLibraryFactory(suffix string) (*Module, *snapshotLibraryDecorator) {
 	module, library := NewLibrary(android.DeviceSupported)
 
@@ -691,6 +889,16 @@
 	return module.Init()
 }
 
+// ramdisk_snapshot_shared is a special prebuilt shared library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_shared
+// overrides the ramdisk variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RamdiskSnapshotSharedFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(ramdiskSnapshotSharedSuffix)
+	prebuilt.libraryDecorator.BuildOnlyShared()
+	return module.Init()
+}
+
 // vendor_snapshot_static is a special prebuilt static library which is auto-generated by
 // development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_static
 // overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION
@@ -711,6 +919,16 @@
 	return module.Init()
 }
 
+// ramdisk_snapshot_static is a special prebuilt static library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_static
+// overrides the ramdisk variant of the cc static library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RamdiskSnapshotStaticFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(ramdiskSnapshotStaticSuffix)
+	prebuilt.libraryDecorator.BuildOnlyStatic()
+	return module.Init()
+}
+
 // vendor_snapshot_header is a special header library which is auto-generated by
 // development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_header
 // overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION
@@ -731,6 +949,16 @@
 	return module.Init()
 }
 
+// ramdisk_snapshot_header is a special header library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_header
+// overrides the ramdisk variant of the cc header library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RamdiskSnapshotHeaderFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(ramdiskSnapshotHeaderSuffix)
+	prebuilt.libraryDecorator.HeaderOnly()
+	return module.Init()
+}
+
 var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
 
 //
@@ -778,6 +1006,8 @@
 		p.androidMkSuffix = vendorSuffix
 	} else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = recoverySuffix
+	} else if m.InRamdisk() && ramdiskSuffixModules(ctx.Config())[m.BaseModuleName()] {
+		p.androidMkSuffix = ramdiskSuffix
 
 	}
 
@@ -811,6 +1041,13 @@
 	return snapshotBinaryFactory(recoverySnapshotBinarySuffix)
 }
 
+// ramdisk_snapshot_binary is a special prebuilt executable binary which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_binary
+// overrides the ramdisk variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
+func RamdiskSnapshotBinaryFactory() android.Module {
+	return snapshotBinaryFactory(ramdiskSnapshotBinarySuffix)
+}
+
 func snapshotBinaryFactory(suffix string) android.Module {
 	module, binary := NewBinary(android.DeviceSupported)
 	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
@@ -877,6 +1114,8 @@
 		p.androidMkSuffix = vendorSuffix
 	} else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = recoverySuffix
+	} else if m.InRamdisk() && ramdiskSuffixModules(ctx.Config())[m.BaseModuleName()] {
+		p.androidMkSuffix = ramdiskSuffix
 	}
 
 	return android.PathForModuleSrc(ctx, *p.properties.Src)
@@ -922,6 +1161,24 @@
 	return module.Init()
 }
 
+// ramdisk_snapshot_object is a special prebuilt compiled object file which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of ramdisk snapshot, ramdisk_snapshot_object
+// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
+func RamdiskSnapshotObjectFactory() android.Module {
+	module := newObject()
+
+	prebuilt := &snapshotObjectLinker{
+		objectLinker: objectLinker{
+			baseLinker: NewBaseLinker(nil),
+		},
+	}
+	module.linker = prebuilt
+
+	prebuilt.init(module, ramdiskSnapshotObjectSuffix)
+	module.AddProperties(&prebuilt.properties)
+	return module.Init()
+}
+
 type snapshotInterface interface {
 	matchesWithDevice(config android.DeviceConfig) bool
 }
@@ -952,6 +1209,10 @@
 	snapshotMutator(ctx, recoverySnapshotImageSingleton)
 }
 
+func RamdiskSnapshotMutator(ctx android.BottomUpMutatorContext) {
+	snapshotMutator(ctx, ramdiskSnapshotImageSingleton)
+}
+
 func snapshotMutator(ctx android.BottomUpMutatorContext, image snapshotImage) {
 	if !image.isUsingSnapshot(ctx.DeviceConfig()) {
 		return
@@ -996,6 +1257,9 @@
 func RecoverySnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
 	snapshotSourceMutator(ctx, recoverySnapshotImageSingleton)
 }
+func RamdiskSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
+	snapshotSourceMutator(ctx, ramdiskSnapshotImageSingleton)
+}
 
 func snapshotSourceMutator(ctx android.BottomUpMutatorContext, image snapshotImage) {
 	if !ctx.Device() {
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 89133ee..2739a78 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -62,15 +62,16 @@
 // If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions.
 func shouldCollectHeadersForSnapshot(ctx android.ModuleContext, m *Module) bool {
 	if ctx.DeviceConfig().VndkVersion() != "current" &&
-		ctx.DeviceConfig().RecoverySnapshotVersion() != "current" {
+		ctx.DeviceConfig().RecoverySnapshotVersion() != "current" &&
+		ctx.DeviceConfig().RamdiskSnapshotVersion() != "current" {
 		return false
 	}
 	if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok {
 		return ctx.Config().VndkSnapshotBuildArtifacts()
 	}
-
-	for _, image := range []snapshotImage{vendorSnapshotImageSingleton, recoverySnapshotImageSingleton} {
-		if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir()), image) {
+	for _, image := range []snapshotImage{vendorSnapshotImageSingleton, recoverySnapshotImageSingleton,
+                                              ramdiskSnapshotImageSingleton } {
+		if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), image) {
 			return true
 		}
 	}
diff --git a/cc/testing.go b/cc/testing.go
index 8370ab9..a8c494b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -473,6 +473,7 @@
 	ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
 	ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
 	ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
+	ctx.RegisterSingletonType("ramdisk-snapshot", RamdiskSnapshotSingleton)
 
 	return ctx
 }
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index c30a18d..ed2c370 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -31,6 +31,7 @@
 	true,
 	vendorSnapshotImageSingleton,
 	false, /* fake */
+	true,  /* usesLlndkLibraries */
 }
 
 var vendorFakeSnapshotSingleton = snapshotSingleton{
@@ -40,6 +41,7 @@
 	true,
 	vendorSnapshotImageSingleton,
 	true, /* fake */
+	true, /* usesLlndkLibraries */
 }
 
 var recoverySnapshotSingleton = snapshotSingleton{
@@ -49,6 +51,17 @@
 	false,
 	recoverySnapshotImageSingleton,
 	false, /* fake */
+	false, /* usesLlndkLibraries */
+}
+
+var ramdiskSnapshotSingleton = snapshotSingleton{
+	"ramdisk",
+	"SOONG_RAMDISK_SNAPSHOT_ZIP",
+	android.OptionalPath{},
+	false,
+	ramdiskSnapshotImageSingleton,
+	false, /* fake */
+	false, /* usesLlndkLibraries */
 }
 
 func VendorSnapshotSingleton() android.Singleton {
@@ -63,6 +76,10 @@
 	return &recoverySnapshotSingleton
 }
 
+func RamdiskSnapshotSingleton() android.Singleton {
+	return &ramdiskSnapshotSingleton
+}
+
 type snapshotSingleton struct {
 	// Name, e.g., "vendor", "recovery", "ramdisk".
 	name string
@@ -86,79 +103,36 @@
 	// Fake snapshot is a snapshot whose prebuilt binaries and headers are empty.
 	// It is much faster to generate, and can be used to inspect dependencies.
 	fake bool
+
+	// Whether the image uses llndk libraries.
+	usesLlndkLibraries bool
 }
 
-var (
-	// Modules under following directories are ignored. They are OEM's and vendor's
-	// proprietary modules(device/, kernel/, vendor/, and hardware/).
-	// TODO(b/65377115): Clean up these with more maintainable way
-	vendorProprietaryDirs = []string{
-		"device",
-		"kernel",
-		"vendor",
-		"hardware",
-		"disregard",
-	}
-
-	// Modules under following directories are ignored. They are OEM's and vendor's
-	// proprietary modules(device/, kernel/, vendor/, and hardware/).
-	// TODO(b/65377115): Clean up these with more maintainable way
-	recoveryProprietaryDirs = []string{
-		"device",
-		"hardware",
-		"kernel",
-		"vendor",
-	}
-
-	// Modules under following directories are included as they are in AOSP,
-	// although hardware/ and kernel/ are normally for vendor's own.
-	// TODO(b/65377115): Clean up these with more maintainable way
-	aospDirsUnderProprietary = []string{
-		"kernel/configs",
-		"kernel/prebuilts",
-		"kernel/tests",
-		"hardware/interfaces",
-		"hardware/libhardware",
-		"hardware/libhardware_legacy",
-		"hardware/ril",
-	}
-)
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
-// device/, vendor/, etc.
-func isVendorProprietaryPath(dir string) bool {
-	return isProprietaryPath(dir, vendorProprietaryDirs)
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on vendor snapshot configuration
+// Examples: device/, vendor/
+func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return VendorSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
 }
 
-func isRecoveryProprietaryPath(dir string) bool {
-	return isProprietaryPath(dir, recoveryProprietaryDirs)
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on recovery snapshot configuration
+// Examples: device/, vendor/
+func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return RecoverySnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
 }
 
-// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
-// device/, vendor/, etc.
-func isProprietaryPath(dir string, proprietaryDirs []string) bool {
-	for _, p := range proprietaryDirs {
-		if strings.HasPrefix(dir, p) {
-			// filter out AOSP defined directories, e.g. hardware/interfaces/
-			aosp := false
-			for _, p := range aospDirsUnderProprietary {
-				if strings.HasPrefix(dir, p) {
-					aosp = true
-					break
-				}
-			}
-			if !aosp {
-				return true
-			}
-		}
-	}
-	return false
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on ramdisk snapshot configuration
+// Examples: device/, vendor/
+func isRamdiskProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return RamdiskSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
 }
 
 func isVendorProprietaryModule(ctx android.BaseModuleContext) bool {
 	// Any module in a vendor proprietary path is a vendor proprietary
 	// module.
-	if isVendorProprietaryPath(ctx.ModuleDir()) {
+	if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
 		return true
 	}
 
@@ -179,7 +153,7 @@
 
 	// Any module in a vendor proprietary path is a vendor proprietary
 	// module.
-	if isRecoveryProprietaryPath(ctx.ModuleDir()) {
+	if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
 		return true
 	}
 
@@ -196,6 +170,27 @@
 
 	return false
 }
+func isRamdiskProprietaryModule(ctx android.BaseModuleContext) bool {
+
+	// Any module in a vendor proprietary path is a vendor proprietary
+	// module.
+	if isRamdiskProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
+		return true
+	}
+
+	// However if the module is not in a vendor proprietary path, it may
+	// still be a vendor proprietary module. This happens for cc modules
+	// that are excluded from the vendor snapshot, and it means that the
+	// vendor has assumed control of the framework-provided module.
+
+	if c, ok := ctx.Module().(*Module); ok {
+		if c.ExcludeFromRamdiskSnapshot() {
+			return true
+		}
+	}
+
+	return false
+}
 
 // Determines if the module is a candidate for snapshot.
 func isSnapshotAware(cfg android.DeviceConfig, m *Module, inProprietaryPath bool, image snapshotImage) bool {
@@ -231,13 +226,6 @@
 	if _, ok := m.linker.(*kernelHeadersDecorator); ok {
 		return false
 	}
-	// skip llndk_library and llndk_headers which are backward compatible
-	if _, ok := m.linker.(*llndkStubDecorator); ok {
-		return false
-	}
-	if _, ok := m.linker.(*llndkHeadersDecorator); ok {
-		return false
-	}
 
 	// Libraries
 	if l, ok := m.linker.(snapshotLibraryInterface); ok {
@@ -368,6 +356,7 @@
 			Sanitize           string   `json:",omitempty"`
 			SanitizeMinimalDep bool     `json:",omitempty"`
 			SanitizeUbsanDep   bool     `json:",omitempty"`
+			IsLlndk            bool     `json:",omitempty"`
 
 			// binary flags
 			Symlinks []string `json:",omitempty"`
@@ -383,7 +372,12 @@
 		}{}
 
 		// Common properties among snapshots.
-		prop.ModuleName = ctx.ModuleName(m)
+		if m.isLlndk(ctx.Config()) && c.usesLlndkLibraries {
+			prop.ModuleName = m.BaseModuleName()
+			prop.IsLlndk = true
+		} else {
+			prop.ModuleName = ctx.ModuleName(m)
+		}
 		if c.supportsVndkExt && m.isVndkExt() {
 			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
 			if m.isVndkSp() {
@@ -504,7 +498,7 @@
 		}
 
 		moduleDir := ctx.ModuleDir(module)
-		inProprietaryPath := c.image.isProprietaryPath(moduleDir)
+		inProprietaryPath := c.image.isProprietaryPath(moduleDir, ctx.DeviceConfig())
 
 		if c.image.excludeFromSnapshot(m) {
 			if inProprietaryPath {
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 7e283fb..67f2b3d 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -1133,3 +1133,324 @@
 		}
 	}
 }
+
+func TestRamdiskSnapshotCapture(t *testing.T) {
+	bp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		ramdisk_available: true,
+		product_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libramdisk",
+		ramdisk: true,
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libramdisk_available",
+		ramdisk_available: true,
+		nocrt: true,
+	}
+
+	cc_library_headers {
+		name: "libramdisk_headers",
+		ramdisk_available: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "ramdisk_bin",
+		ramdisk: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "ramdisk_available_bin",
+		ramdisk_available: true,
+		nocrt: true,
+	}
+
+	toolchain_library {
+		name: "libb",
+		ramdisk_available: true,
+		src: "libb.a",
+	}
+
+	cc_object {
+		name: "obj",
+		ramdisk_available: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.RamdiskSnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, config)
+
+	// Check Ramdisk snapshot output.
+
+	snapshotDir := "ramdisk-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("ramdisk-snapshot")
+
+	var jsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		// For shared libraries, only ramdisk_available modules are captured.
+		sharedVariant := fmt.Sprintf("android_ramdisk_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libramdisk_available", "libramdisk_available.so", sharedDir, sharedVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(sharedDir, "libvndk.so.json"),
+			filepath.Join(sharedDir, "libramdisk.so.json"),
+			filepath.Join(sharedDir, "libramdisk_available.so.json"))
+
+		// For static libraries, all ramdisk:true and ramdisk_available modules are captured.
+		staticVariant := fmt.Sprintf("android_ramdisk_%s_%s_static", archType, archVariant)
+		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libramdisk_available", "libramdisk_available.a", staticDir, staticVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(staticDir, "libb.a.json"),
+			filepath.Join(staticDir, "libramdisk.a.json"),
+			filepath.Join(staticDir, "libramdisk_available.a.json"))
+
+		// For binary executables, all ramdisk:true and ramdisk_available modules are captured.
+		if archType == "arm64" {
+			binaryVariant := fmt.Sprintf("android_ramdisk_%s_%s", archType, archVariant)
+			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+			checkSnapshot(t, ctx, snapshotSingleton, "ramdisk_bin", "ramdisk_bin", binaryDir, binaryVariant)
+			checkSnapshot(t, ctx, snapshotSingleton, "ramdisk_available_bin", "ramdisk_available_bin", binaryDir, binaryVariant)
+			jsonFiles = append(jsonFiles,
+				filepath.Join(binaryDir, "ramdisk_bin.json"),
+				filepath.Join(binaryDir, "ramdisk_available_bin.json"))
+		}
+
+		// For header libraries, all vendor:true and vendor_available modules are captured.
+		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
+		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libramdisk_headers.json"))
+
+		// For object modules, all vendor:true and vendor_available modules are captured.
+		objectVariant := fmt.Sprintf("android_ramdisk_%s_%s", archType, archVariant)
+		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
+		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
+		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
+	}
+
+	for _, jsonFile := range jsonFiles {
+		// verify all json files exist
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("%q expected but not found", jsonFile)
+		}
+	}
+}
+
+func TestRamdiskSnapshotExclude(t *testing.T) {
+	// This test verifies that the exclude_from_ramdisk_snapshot property
+	// makes its way from the Android.bp source file into the module data
+	// structure. It also verifies that modules are correctly included or
+	// excluded in the ramdisk snapshot based on their path (framework or
+	// vendor) and the exclude_from_ramdisk_snapshot property.
+
+	frameworkBp := `
+		cc_library_shared {
+			name: "libinclude",
+			srcs: ["src/include.cpp"],
+			ramdisk_available: true,
+		}
+		cc_library_shared {
+			name: "libexclude",
+			srcs: ["src/exclude.cpp"],
+			ramdisk: true,
+			exclude_from_ramdisk_snapshot: true,
+		}
+		cc_library_shared {
+			name: "libavailable_exclude",
+			srcs: ["src/exclude.cpp"],
+			ramdisk_available: true,
+			exclude_from_ramdisk_snapshot: true,
+		}
+	`
+
+	vendorProprietaryBp := `
+		cc_library_shared {
+			name: "libramdisk",
+			srcs: ["ramdisk.cpp"],
+			ramdisk: true,
+		}
+	`
+
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":       []byte(depsBp),
+		"framework/Android.bp":  []byte(frameworkBp),
+		"framework/include.cpp": nil,
+		"framework/exclude.cpp": nil,
+		"device/Android.bp":     []byte(vendorProprietaryBp),
+		"device/ramdisk.cpp":   nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.RamdiskSnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext(config)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	// Test an include and exclude framework module.
+	assertExcludeFromRamdiskSnapshotIs(t, ctx, "libinclude", false)
+	assertExcludeFromRamdiskSnapshotIs(t, ctx, "libexclude", true)
+	assertExcludeFromRamdiskSnapshotIs(t, ctx, "libavailable_exclude", true)
+
+	// A ramdisk module is excluded, but by its path, not the
+	// exclude_from_ramdisk_snapshot property.
+	assertExcludeFromRamdiskSnapshotIs(t, ctx, "libramdisk", false)
+
+	// Verify the content of the ramdisk snapshot.
+
+	snapshotDir := "ramdisk-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("ramdisk-snapshot")
+
+	var includeJsonFiles []string
+	var excludeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_ramdisk_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
+
+		// Excluded modules
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libramdisk.so.json"))
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+
+	// Verify that each json file for an excluded module has no rule.
+	for _, jsonFile := range excludeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+			t.Errorf("exclude json file %q found", jsonFile)
+		}
+	}
+}
+
+func TestRamdiskSnapshotDirected(t *testing.T) {
+	bp := `
+	cc_library_shared {
+		name: "libramdisk",
+		ramdisk: true,
+		nocrt: true,
+	}
+
+	cc_library_shared {
+		name: "libramdisk_available",
+		ramdisk_available: true,
+		nocrt: true,
+	}
+
+	genrule {
+		name: "libfoo_gen",
+		cmd: "",
+		out: ["libfoo.so"],
+	}
+
+	cc_prebuilt_library_shared {
+		name: "libfoo",
+		ramdisk: true,
+		prefer: true,
+		srcs: [":libfoo_gen"],
+	}
+
+	cc_library_shared {
+		name: "libfoo",
+		ramdisk: true,
+		nocrt: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.RamdiskSnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DirectedRamdiskSnapshot = true
+	config.TestProductVariables.RamdiskSnapshotModules = make(map[string]bool)
+	config.TestProductVariables.RamdiskSnapshotModules["libramdisk"] = true
+	config.TestProductVariables.RamdiskSnapshotModules["libfoo"] = true
+	ctx := testCcWithConfig(t, config)
+
+	// Check ramdisk snapshot output.
+
+	snapshotDir := "ramdisk-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("ramdisk-snapshot")
+
+	var includeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_ramdisk_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "libramdisk", "libramdisk.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libramdisk.so.json"))
+		// Check that snapshot captures "prefer: true" prebuilt
+		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
+
+		// Excluded modules. Modules not included in the directed ramdisk snapshot
+		// are still include as fake modules.
+		checkSnapshotRule(t, ctx, snapshotSingleton, "libramdisk_available", "libramdisk_available.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libramdisk_available.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+}
diff --git a/java/app.go b/java/app.go
index 971f275..0c9fb9a 100755
--- a/java/app.go
+++ b/java/app.go
@@ -969,6 +969,8 @@
 	switch tag {
 	case ".aapt.srcjar":
 		return []android.Path{a.aaptSrcJar}, nil
+	case ".export-package.apk":
+		return []android.Path{a.exportPackage}, nil
 	}
 	return a.Library.OutputFiles(tag)
 }
diff --git a/java/java.go b/java/java.go
index 1de5252..adeb0f7 100644
--- a/java/java.go
+++ b/java/java.go
@@ -533,7 +533,6 @@
 	bootClasspathTag      = dependencyTag{name: "bootclasspath"}
 	systemModulesTag      = dependencyTag{name: "system modules"}
 	frameworkResTag       = dependencyTag{name: "framework-res"}
-	frameworkApkTag       = dependencyTag{name: "framework-apk"}
 	kotlinStdlibTag       = dependencyTag{name: "kotlin-stdlib"}
 	kotlinAnnotationsTag  = dependencyTag{name: "kotlin-annotations"}
 	proguardRaiseTag      = dependencyTag{name: "proguard-raise"}
@@ -670,12 +669,6 @@
 	if sdkDep.systemModules != "" {
 		ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
 	}
-
-	if ctx.ModuleName() == "android_stubs_current" ||
-		ctx.ModuleName() == "android_system_stubs_current" ||
-		ctx.ModuleName() == "android_test_stubs_current" {
-		ctx.AddVariationDependencies(nil, frameworkApkTag, "framework-res")
-	}
 }
 
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
@@ -1031,26 +1024,6 @@
 				} else {
 					ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
 				}
-			case frameworkApkTag:
-				if ctx.ModuleName() == "android_stubs_current" ||
-					ctx.ModuleName() == "android_system_stubs_current" ||
-					ctx.ModuleName() == "android_test_stubs_current" {
-					// framework stubs.jar need to depend on framework-res.apk, in order to pull the
-					// resource files out of there for aapt.
-					//
-					// Normally the package rule runs aapt, which includes the resource,
-					// but we're not running that in our package rule so just copy in the
-					// resource files here.
-					var exportPackage android.Path
-					if androidAppImport, ok := dep.(*AndroidAppImport); ok {
-						exportPackage = androidAppImport.ExportPackage()
-					} else {
-						exportPackage = dep.(*AndroidApp).exportPackage
-					}
-					if exportPackage != nil {
-						deps.staticResourceJars = append(deps.staticResourceJars, exportPackage)
-					}
-				}
 			case kotlinStdlibTag:
 				deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...)
 			case kotlinAnnotationsTag:
@@ -1610,9 +1583,22 @@
 
 		configurationName := j.ConfigurationName()
 		primary := configurationName == ctx.ModuleName()
-		// If the prebuilt is being used rather than the from source, skip this
-		// module to prevent duplicated classes
-		primary = primary && !j.IsReplacedByPrebuilt()
+
+		// A source module that has been replaced by a prebuilt can never be the primary module
+		// as long as the prebuilt actually provides a build dex jar. If it doesn't then use
+		// the source module for now.
+		if j.IsReplacedByPrebuilt() {
+			ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(prebuilt android.Module) {
+				if h, ok := prebuilt.(hiddenAPIIntf); ok && h.bootDexJar() != nil {
+					// It is safe to ignore the source module as the prebuilt module provides an
+					// appropriate boot dex jar.
+					primary = false
+				} else {
+					// The prebuilt doesn't provide a suitable boot dex jar so keep using the
+					// source module instead.
+				}
+			})
+		}
 
 		// Hidden API CSV generation and dex encoding
 		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
diff --git a/sh/Android.bp b/sh/Android.bp
index 0f40c5f..e5ffeef 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -5,6 +5,7 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-cc",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index ab0490a..e61c719 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -17,11 +17,14 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/tradefed"
 )
 
@@ -88,6 +91,20 @@
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
 	// explicitly.
 	Auto_gen_config *bool
+
+	// list of binary modules that should be installed alongside the test
+	Data_bins []string `android:"path,arch_variant"`
+
+	// list of library modules that should be installed alongside the test
+	Data_libs []string `android:"path,arch_variant"`
+
+	// list of device binary modules that should be installed alongside the test.
+	// Only available for host sh_test modules.
+	Data_device_bins []string `android:"path,arch_variant"`
+
+	// list of device library modules that should be installed alongside the test.
+	// Only available for host sh_test modules.
+	Data_device_libs []string `android:"path,arch_variant"`
 }
 
 type ShBinary struct {
@@ -109,6 +126,8 @@
 
 	data       android.Paths
 	testConfig android.Path
+
+	dataModules map[string]android.Path
 }
 
 func (s *ShBinary) HostToolPath() android.OptionalPath {
@@ -190,6 +209,50 @@
 	}
 }
 
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+var (
+	shTestDataBinsTag       = dependencyTag{name: "dataBins"}
+	shTestDataLibsTag       = dependencyTag{name: "dataLibs"}
+	shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
+	shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"}
+)
+
+var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}}
+
+func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	s.ShBinary.DepsMutator(ctx)
+
+	ctx.AddFarVariationDependencies(ctx.Target().Variations(), shTestDataBinsTag, s.testProperties.Data_bins...)
+	ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...),
+		shTestDataLibsTag, s.testProperties.Data_libs...)
+	if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 {
+		deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
+		ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
+		ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
+			shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...)
+	} else if ctx.Target().Os.Class != android.Host {
+		if len(s.testProperties.Data_device_bins) > 0 {
+			ctx.PropertyErrorf("data_device_bins", "only available for host modules")
+		}
+		if len(s.testProperties.Data_device_libs) > 0 {
+			ctx.PropertyErrorf("data_device_libs", "only available for host modules")
+		}
+	}
+}
+
+func (s *ShTest) addToDataModules(ctx android.ModuleContext, relPath string, path android.Path) {
+	if _, exists := s.dataModules[relPath]; exists {
+		ctx.ModuleErrorf("data modules have a conflicting installation path, %v - %s, %s",
+			relPath, s.dataModules[relPath].String(), path.String())
+		return
+	}
+	s.dataModules[relPath] = path
+}
+
 func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	s.ShBinary.generateAndroidBuildActions(ctx)
 	testDir := "nativetest"
@@ -215,6 +278,50 @@
 	}
 	s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config,
 		s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base())
+
+	s.dataModules = make(map[string]android.Path)
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		depTag := ctx.OtherModuleDependencyTag(dep)
+		switch depTag {
+		case shTestDataBinsTag, shTestDataDeviceBinsTag:
+			if cc, isCc := dep.(*cc.Module); isCc {
+				s.addToDataModules(ctx, cc.OutputFile().Path().Base(), cc.OutputFile().Path())
+				return
+			}
+			property := "data_bins"
+			if depTag == shTestDataDeviceBinsTag {
+				property = "data_device_bins"
+			}
+			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+		case shTestDataLibsTag, shTestDataDeviceLibsTag:
+			if cc, isCc := dep.(*cc.Module); isCc {
+				// Copy to an intermediate output directory to append "lib[64]" to the path,
+				// so that it's compatible with the default rpath values.
+				var relPath string
+				if cc.Arch().ArchType.Multilib == "lib64" {
+					relPath = filepath.Join("lib64", cc.OutputFile().Path().Base())
+				} else {
+					relPath = filepath.Join("lib", cc.OutputFile().Path().Base())
+				}
+				if _, exist := s.dataModules[relPath]; exist {
+					return
+				}
+				relocatedLib := android.PathForModuleOut(ctx, "relocated", relPath)
+				ctx.Build(pctx, android.BuildParams{
+					Rule:   android.Cp,
+					Input:  cc.OutputFile().Path(),
+					Output: relocatedLib,
+				})
+				s.addToDataModules(ctx, relPath, relocatedLib)
+				return
+			}
+			property := "data_libs"
+			if depTag == shTestDataDeviceBinsTag {
+				property = "data_device_libs"
+			}
+			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+		}
+	})
 }
 
 func (s *ShTest) InstallInData() bool {
@@ -243,6 +350,15 @@
 					path = strings.TrimSuffix(path, rel)
 					entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
 				}
+				relPaths := make([]string, 0)
+				for relPath, _ := range s.dataModules {
+					relPaths = append(relPaths, relPath)
+				}
+				sort.Strings(relPaths)
+				for _, relPath := range relPaths {
+					dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
+					entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
+				}
 			},
 		},
 	}}
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 6c0d96a..232a281 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -3,10 +3,12 @@
 import (
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"reflect"
 	"testing"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var buildDir string
@@ -46,6 +48,9 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("sh_test", ShTestFactory)
 	ctx.RegisterModuleType("sh_test_host", ShTestHostFactory)
+
+	cc.RegisterRequiredBuildComponentsForTest(ctx)
+
 	ctx.Register(config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -78,6 +83,65 @@
 	}
 }
 
+func TestShTest_dataModules(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test {
+			name: "foo",
+			src: "test.sh",
+			host_supported: true,
+			data_bins: ["bar"],
+			data_libs: ["libbar"],
+		}
+
+		cc_binary {
+			name: "bar",
+			host_supported: true,
+			shared_libs: ["libbar"],
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libbar",
+			host_supported: true,
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+	arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"}
+	for _, arch := range arches {
+		variant := ctx.ModuleForTests("foo", arch)
+
+		libExt := ".so"
+		if arch == "darwin_x86_64" {
+			libExt = ".dylib"
+		}
+		relocated := variant.Output("relocated/lib64/libbar" + libExt)
+		expectedInput := filepath.Join(buildDir, ".intermediates/libbar/"+arch+"_shared/libbar"+libExt)
+		if relocated.Input.String() != expectedInput {
+			t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
+				expectedInput, relocated.Input.String())
+		}
+
+		mod := variant.Module().(*ShTest)
+		entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+		expectedData := []string{
+			filepath.Join(buildDir, ".intermediates/bar", arch, ":bar"),
+			filepath.Join(buildDir, ".intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
+		}
+		actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+		if !reflect.DeepEqual(expectedData, actualData) {
+			t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
+		}
+	}
+}
+
 func TestShTestHost(t *testing.T) {
 	ctx, _ := testShBinary(t, `
 		sh_test_host {
@@ -97,3 +161,53 @@
 		t.Errorf("host bit is not set for a sh_test_host module.")
 	}
 }
+
+func TestShTestHost_dataDeviceModules(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test_host {
+			name: "foo",
+			src: "test.sh",
+			data_device_bins: ["bar"],
+			data_device_libs: ["libbar"],
+		}
+
+		cc_binary {
+			name: "bar",
+			shared_libs: ["libbar"],
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libbar",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+	variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
+
+	relocated := variant.Output("relocated/lib64/libbar.so")
+	expectedInput := filepath.Join(buildDir, ".intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
+	if relocated.Input.String() != expectedInput {
+		t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
+			expectedInput, relocated.Input.String())
+	}
+
+	mod := variant.Module().(*ShTest)
+	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+	expectedData := []string{
+		filepath.Join(buildDir, ".intermediates/bar/android_arm64_armv8-a/:bar"),
+		// libbar has been relocated, and so has a variant that matches the host arch.
+		filepath.Join(buildDir, ".intermediates/foo/"+buildOS+"_x86_64/relocated/:lib64/libbar.so"),
+	}
+	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+	if !reflect.DeepEqual(expectedData, actualData) {
+		t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
+	}
+}
diff --git a/ui/build/config.go b/ui/build/config.go
index 4490e1e..7f28d3a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -186,15 +186,9 @@
 		"EMPTY_NINJA_FILE",
 	)
 
-	if ret.UseGoma() {
-		ctx.Println("Goma for Android is being deprecated and replaced with RBE. See go/rbe_for_android for instructions on how to use RBE.")
-		ctx.Println()
-		ctx.Println("See go/goma_android_exceptions for exceptions.")
-		ctx.Fatalln("USE_GOMA flag is no longer supported.")
-	}
-
-	if ret.ForceUseGoma() {
-		ret.environ.Set("USE_GOMA", "true")
+	if ret.UseGoma() || ret.ForceUseGoma() {
+		ctx.Println("Goma for Android has been deprecated and replaced with RBE. See go/rbe_for_android for instructions on how to use RBE.")
+		ctx.Fatalln("USE_GOMA / FORCE_USE_GOMA flag is no longer supported.")
 	}
 
 	// Tell python not to spam the source tree with .pyc files.
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 65cae4a..1018eb3 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -139,7 +139,12 @@
 }
 
 // exports the output to the file at outputPath
-func (m *Metrics) Dump(outputPath string) (err error) {
+func (m *Metrics) Dump(outputPath string) error {
+	// ignore the error if the hostname could not be retrieved as it
+	// is not a critical metric to extract.
+	if hostname, err := os.Hostname(); err == nil {
+		m.metrics.Hostname = proto.String(hostname)
+	}
 	m.metrics.HostOs = proto.String(runtime.GOOS)
 	return writeMessageToFile(&m.metrics, outputPath)
 }
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 84706b2..5e214a8 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -197,11 +197,13 @@
 	// The metrics for calling Ninja.
 	NinjaRuns []*PerfInfo `protobuf:"bytes,20,rep,name=ninja_runs,json=ninjaRuns" json:"ninja_runs,omitempty"`
 	// The metrics for the whole build
-	Total                *PerfInfo    `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
-	BuildConfig          *BuildConfig `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}     `json:"-"`
-	XXX_unrecognized     []byte       `json:"-"`
-	XXX_sizecache        int32        `json:"-"`
+	Total       *PerfInfo    `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
+	BuildConfig *BuildConfig `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
+	// The hostname of the machine.
+	Hostname             *string  `protobuf:"bytes,24,opt,name=hostname" json:"hostname,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
 func (m *MetricsBase) Reset()         { *m = MetricsBase{} }
@@ -388,6 +390,13 @@
 	return nil
 }
 
+func (m *MetricsBase) GetHostname() string {
+	if m != nil && m.Hostname != nil {
+		return *m.Hostname
+	}
+	return ""
+}
+
 type BuildConfig struct {
 	UseGoma              *bool    `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"`
 	UseRbe               *bool    `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"`
@@ -685,63 +694,64 @@
 func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
 
 var fileDescriptor_6039342a2ba47b72 = []byte{
-	// 924 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdf, 0x6e, 0xdb, 0x36,
-	0x17, 0xaf, 0x62, 0x25, 0x96, 0x8e, 0x62, 0x57, 0x65, 0x52, 0x44, 0xfd, 0x8a, 0xe0, 0x33, 0x84,
-	0x75, 0xc8, 0xc5, 0x9a, 0x16, 0x59, 0x11, 0x14, 0x41, 0x31, 0x20, 0x71, 0x82, 0xa0, 0x0b, 0x6c,
-	0x17, 0x4c, 0xdc, 0x15, 0xdb, 0x85, 0x20, 0x4b, 0xb4, 0xa3, 0xce, 0x12, 0x0d, 0x92, 0x2a, 0xe6,
-	0x87, 0xd8, 0x6b, 0xec, 0xcd, 0xf6, 0x1e, 0x03, 0x0f, 0x25, 0x47, 0x01, 0x5c, 0x34, 0xe8, 0x9d,
-	0x74, 0x7e, 0x7f, 0xf8, 0x3b, 0x24, 0x75, 0x6c, 0xe8, 0xe4, 0x4c, 0x89, 0x2c, 0x91, 0x87, 0x0b,
-	0xc1, 0x15, 0x27, 0x3b, 0x92, 0xf3, 0x62, 0x16, 0x4d, 0xca, 0x6c, 0x9e, 0x46, 0x15, 0x14, 0xfe,
-	0x03, 0xe0, 0x0d, 0xcc, 0xf3, 0x59, 0x2c, 0x19, 0x79, 0x0d, 0xbb, 0x86, 0x90, 0xc6, 0x8a, 0x45,
-	0x2a, 0xcb, 0x99, 0x54, 0x71, 0xbe, 0x08, 0xac, 0x9e, 0x75, 0xd0, 0xa2, 0x04, 0xb1, 0xf3, 0x58,
-	0xb1, 0x9b, 0x1a, 0x21, 0xcf, 0xc0, 0x31, 0x8a, 0x2c, 0x0d, 0x36, 0x7a, 0xd6, 0x81, 0x4b, 0xdb,
-	0xf8, 0xfe, 0x3e, 0x25, 0x27, 0xf0, 0x6c, 0x31, 0x8f, 0xd5, 0x94, 0x8b, 0x3c, 0xfa, 0xc2, 0x84,
-	0xcc, 0x78, 0x11, 0x25, 0x3c, 0x65, 0x45, 0x9c, 0xb3, 0xa0, 0x85, 0xdc, 0xbd, 0x9a, 0xf0, 0xd1,
-	0xe0, 0xfd, 0x0a, 0x26, 0x2f, 0xa0, 0xab, 0x62, 0x31, 0x63, 0x2a, 0x5a, 0x08, 0x9e, 0x96, 0x89,
-	0x0a, 0x6c, 0x14, 0x74, 0x4c, 0xf5, 0x83, 0x29, 0x92, 0x14, 0x76, 0x2b, 0x9a, 0x09, 0xf1, 0x25,
-	0x16, 0x59, 0x5c, 0xa8, 0x60, 0xb3, 0x67, 0x1d, 0x74, 0x8f, 0x5e, 0x1e, 0xae, 0xe9, 0xf9, 0xb0,
-	0xd1, 0xef, 0xe1, 0x99, 0x46, 0x3e, 0x1a, 0xd1, 0x49, 0xeb, 0x62, 0x78, 0x49, 0x89, 0xf1, 0x6b,
-	0x02, 0x64, 0x04, 0x5e, 0xb5, 0x4a, 0x2c, 0x92, 0xdb, 0x60, 0x0b, 0xcd, 0x5f, 0x7c, 0xd3, 0xfc,
-	0x54, 0x24, 0xb7, 0x27, 0xed, 0xf1, 0xf0, 0x6a, 0x38, 0xfa, 0x6d, 0x48, 0xc1, 0x58, 0xe8, 0x22,
-	0x39, 0x84, 0x9d, 0x86, 0xe1, 0x2a, 0x75, 0x1b, 0x5b, 0x7c, 0x72, 0x47, 0xac, 0x03, 0xfc, 0x04,
-	0x55, 0xac, 0x28, 0x59, 0x94, 0x2b, 0xba, 0x83, 0x74, 0xdf, 0x20, 0xfd, 0x45, 0x59, 0xb3, 0xaf,
-	0xc0, 0xbd, 0xe5, 0xb2, 0x0a, 0xeb, 0x7e, 0x57, 0x58, 0x47, 0x1b, 0x60, 0x54, 0x0a, 0x1d, 0x34,
-	0x3b, 0x2a, 0x52, 0x63, 0x08, 0xdf, 0x65, 0xe8, 0x69, 0x93, 0xa3, 0x22, 0x45, 0xcf, 0x3d, 0x68,
-	0xa3, 0x27, 0x97, 0x81, 0x87, 0x3d, 0x6c, 0xe9, 0xd7, 0x91, 0x24, 0x61, 0xb5, 0x18, 0x97, 0x11,
-	0xfb, 0x4b, 0x89, 0x38, 0xd8, 0x46, 0xd8, 0x33, 0xf0, 0x85, 0x2e, 0xad, 0x38, 0x89, 0xe0, 0x52,
-	0x6a, 0x8b, 0xce, 0x1d, 0xa7, 0xaf, 0x6b, 0x23, 0x49, 0x7e, 0x84, 0xc7, 0x0d, 0x0e, 0xc6, 0xee,
-	0x9a, 0xeb, 0xb3, 0x62, 0x61, 0x90, 0x97, 0xb0, 0xd3, 0xe0, 0xad, 0x5a, 0x7c, 0x6c, 0x36, 0x76,
-	0xc5, 0x6d, 0xe4, 0xe6, 0xa5, 0x8a, 0xd2, 0x4c, 0x04, 0xbe, 0xc9, 0xcd, 0x4b, 0x75, 0x9e, 0x09,
-	0xf2, 0x0b, 0x78, 0x92, 0xa9, 0x72, 0x11, 0x29, 0xce, 0xe7, 0x32, 0x78, 0xd2, 0x6b, 0x1d, 0x78,
-	0x47, 0xfb, 0x6b, 0xb7, 0xe8, 0x03, 0x13, 0xd3, 0xf7, 0xc5, 0x94, 0x53, 0x40, 0xc5, 0x8d, 0x16,
-	0x90, 0x13, 0x70, 0xff, 0x8c, 0x55, 0x16, 0x89, 0xb2, 0x90, 0x01, 0x79, 0x88, 0xda, 0xd1, 0x7c,
-	0x5a, 0x16, 0x92, 0xbc, 0x03, 0x30, 0x4c, 0x14, 0xef, 0x3c, 0x44, 0xec, 0x22, 0x5a, 0xab, 0x8b,
-	0xac, 0xf8, 0x1c, 0x1b, 0xf5, 0xee, 0x83, 0xd4, 0x28, 0x40, 0xf5, 0xcf, 0xb0, 0xa9, 0xb8, 0x8a,
-	0xe7, 0xc1, 0xd3, 0x9e, 0xf5, 0x6d, 0xa1, 0xe1, 0x92, 0x3e, 0x6c, 0x1b, 0x42, 0xc2, 0x8b, 0x69,
-	0x36, 0x0b, 0xf6, 0x50, 0xdb, 0x5b, 0xab, 0xc5, 0xcf, 0xb0, 0x8f, 0x3c, 0xea, 0x4d, 0xee, 0x5e,
-	0xc2, 0xd7, 0xb0, 0x7d, 0xef, 0x13, 0x75, 0xc0, 0x1e, 0x5f, 0x5f, 0x50, 0xff, 0x11, 0xe9, 0x80,
-	0xab, 0x9f, 0xce, 0x2f, 0xce, 0xc6, 0x97, 0xbe, 0x45, 0xda, 0xa0, 0x3f, 0x6b, 0x7f, 0x23, 0x7c,
-	0x07, 0x36, 0x1e, 0xa2, 0x07, 0xf5, 0xa5, 0xf4, 0x1f, 0x69, 0xf4, 0x94, 0x0e, 0x7c, 0x8b, 0xb8,
-	0xb0, 0x79, 0x4a, 0x07, 0xc7, 0x6f, 0xfc, 0x0d, 0x5d, 0xfb, 0xf4, 0xf6, 0xd8, 0x6f, 0x11, 0x80,
-	0xad, 0x4f, 0x6f, 0x8f, 0xa3, 0xe3, 0x37, 0xbe, 0x1d, 0xce, 0xc0, 0x6b, 0x64, 0xd1, 0x53, 0xaf,
-	0x94, 0x2c, 0x9a, 0xf1, 0x3c, 0xc6, 0xd9, 0xe8, 0xd0, 0x76, 0x29, 0xd9, 0x25, 0xcf, 0x63, 0x7d,
-	0x49, 0x34, 0x24, 0x26, 0x0c, 0xe7, 0xa1, 0x43, 0xb7, 0x4a, 0xc9, 0xe8, 0x84, 0x91, 0x1f, 0xa0,
-	0x3b, 0xe5, 0x22, 0x61, 0xd1, 0x4a, 0xd9, 0x42, 0x7c, 0x1b, 0xab, 0x63, 0x23, 0x0f, 0xff, 0xb6,
-	0xc0, 0xa9, 0x77, 0x8c, 0x10, 0xb0, 0x53, 0x26, 0x13, 0x5c, 0xc2, 0xa5, 0xf8, 0xac, 0x6b, 0x38,
-	0x40, 0xcd, 0xb0, 0xc5, 0x67, 0xb2, 0x0f, 0x20, 0x55, 0x2c, 0x14, 0x4e, 0x6c, 0xb4, 0xb5, 0xa9,
-	0x8b, 0x15, 0x3d, 0xa8, 0xc9, 0x73, 0x70, 0x05, 0x8b, 0xe7, 0x06, 0xb5, 0x11, 0x75, 0x74, 0x01,
-	0xc1, 0x7d, 0x80, 0x9c, 0xe5, 0x5c, 0x2c, 0x75, 0x2e, 0x1c, 0x9c, 0x36, 0x75, 0x4d, 0x65, 0x2c,
-	0x59, 0xf8, 0xaf, 0x05, 0xdd, 0x01, 0x4f, 0xcb, 0x39, 0xbb, 0x59, 0x2e, 0x18, 0xa6, 0xfa, 0xa3,
-	0x3e, 0x40, 0xb9, 0x94, 0x8a, 0xe5, 0x98, 0xae, 0x7b, 0xf4, 0x6a, 0xfd, 0x44, 0xb8, 0x27, 0x35,
-	0xe7, 0x79, 0x8d, 0xb2, 0xc6, 0x6c, 0x98, 0xdc, 0x55, 0xc9, 0xff, 0xc1, 0xcb, 0x51, 0x13, 0xa9,
-	0xe5, 0xa2, 0xee, 0x12, 0xf2, 0x95, 0x8d, 0xde, 0xc6, 0xa2, 0xcc, 0x23, 0x3e, 0x8d, 0x4c, 0x51,
-	0x62, 0xbf, 0x1d, 0xba, 0x5d, 0x94, 0xf9, 0x68, 0x6a, 0xd6, 0x93, 0xe1, 0xab, 0xea, 0xbc, 0x2a,
-	0xd7, 0x7b, 0x87, 0xee, 0xc2, 0xe6, 0xf5, 0x68, 0x34, 0xd4, 0xb7, 0xc3, 0x01, 0x7b, 0x70, 0x7a,
-	0x75, 0xe1, 0x6f, 0x84, 0x73, 0xf8, 0x5f, 0x5f, 0x64, 0x2a, 0x4b, 0xe2, 0xf9, 0x58, 0x32, 0xf1,
-	0x2b, 0x2f, 0x45, 0xc1, 0x96, 0xd5, 0x40, 0x5b, 0x6d, 0xba, 0xd5, 0xd8, 0xf4, 0x13, 0x68, 0x57,
-	0x5d, 0x62, 0xca, 0xaf, 0x5d, 0xe1, 0xc6, 0x4c, 0xa4, 0xb5, 0x20, 0x9c, 0xc0, 0xf3, 0x35, 0xab,
-	0xc9, 0x7a, 0xb9, 0x3e, 0xd8, 0x49, 0xf9, 0x59, 0x06, 0x16, 0x7e, 0x8f, 0xeb, 0x77, 0xf6, 0xeb,
-	0x69, 0x29, 0x8a, 0xcf, 0x9e, 0xfe, 0x5e, 0xfd, 0xe4, 0x57, 0x8a, 0x08, 0xff, 0x07, 0xfc, 0x17,
-	0x00, 0x00, 0xff, 0xff, 0xdd, 0xe8, 0xec, 0xe5, 0x17, 0x08, 0x00, 0x00,
+	// 934 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x6f, 0x6b, 0xdb, 0x46,
+	0x18, 0xaf, 0x62, 0x25, 0x96, 0x1e, 0xc5, 0xae, 0x7a, 0x69, 0x89, 0xda, 0x12, 0x66, 0xc4, 0x3a,
+	0xf2, 0x62, 0x4d, 0x4b, 0x56, 0x42, 0x09, 0x65, 0x90, 0x38, 0x21, 0x74, 0x21, 0x71, 0xb9, 0xc4,
+	0x5d, 0xd9, 0x5e, 0x08, 0x59, 0x3a, 0x3b, 0xea, 0x2c, 0x9d, 0xb9, 0x3b, 0x95, 0xf9, 0x43, 0xec,
+	0x4b, 0xed, 0xbb, 0xec, 0x7b, 0x8c, 0x7b, 0x4e, 0x52, 0x14, 0x70, 0x69, 0xe8, 0x3b, 0xe9, 0xf9,
+	0xfd, 0xb9, 0xdf, 0x3d, 0x77, 0x7a, 0x10, 0xf4, 0x72, 0xa6, 0x44, 0x96, 0xc8, 0xbd, 0x85, 0xe0,
+	0x8a, 0x93, 0x2d, 0xc9, 0x79, 0x31, 0x8b, 0x26, 0x65, 0x36, 0x4f, 0xa3, 0x0a, 0x0a, 0xff, 0x05,
+	0xf0, 0x2e, 0xcc, 0xf3, 0x71, 0x2c, 0x19, 0x79, 0x0d, 0x8f, 0x0d, 0x21, 0x8d, 0x15, 0x8b, 0x54,
+	0x96, 0x33, 0xa9, 0xe2, 0x7c, 0x11, 0x58, 0x03, 0x6b, 0xb7, 0x43, 0x09, 0x62, 0x27, 0xb1, 0x62,
+	0xd7, 0x35, 0x42, 0x9e, 0x82, 0x63, 0x14, 0x59, 0x1a, 0xac, 0x0d, 0xac, 0x5d, 0x97, 0x76, 0xf1,
+	0xfd, 0x7d, 0x4a, 0x0e, 0xe1, 0xe9, 0x62, 0x1e, 0xab, 0x29, 0x17, 0x79, 0xf4, 0x85, 0x09, 0x99,
+	0xf1, 0x22, 0x4a, 0x78, 0xca, 0x8a, 0x38, 0x67, 0x41, 0x07, 0xb9, 0xdb, 0x35, 0xe1, 0xa3, 0xc1,
+	0x87, 0x15, 0x4c, 0x5e, 0x40, 0x5f, 0xc5, 0x62, 0xc6, 0x54, 0xb4, 0x10, 0x3c, 0x2d, 0x13, 0x15,
+	0xd8, 0x28, 0xe8, 0x99, 0xea, 0x07, 0x53, 0x24, 0x29, 0x3c, 0xae, 0x68, 0x26, 0xc4, 0x97, 0x58,
+	0x64, 0x71, 0xa1, 0x82, 0xf5, 0x81, 0xb5, 0xdb, 0xdf, 0x7f, 0xb9, 0xb7, 0x62, 0xcf, 0x7b, 0xad,
+	0xfd, 0xee, 0x1d, 0x6b, 0xe4, 0xa3, 0x11, 0x1d, 0x76, 0x4e, 0x2f, 0xcf, 0x28, 0x31, 0x7e, 0x6d,
+	0x80, 0x8c, 0xc0, 0xab, 0x56, 0x89, 0x45, 0x72, 0x13, 0x6c, 0xa0, 0xf9, 0x8b, 0x6f, 0x9a, 0x1f,
+	0x89, 0xe4, 0xe6, 0xb0, 0x3b, 0xbe, 0x3c, 0xbf, 0x1c, 0xfd, 0x7e, 0x49, 0xc1, 0x58, 0xe8, 0x22,
+	0xd9, 0x83, 0xad, 0x96, 0x61, 0x93, 0xba, 0x8b, 0x5b, 0x7c, 0x74, 0x4b, 0xac, 0x03, 0xfc, 0x0c,
+	0x55, 0xac, 0x28, 0x59, 0x94, 0x0d, 0xdd, 0x41, 0xba, 0x6f, 0x90, 0xe1, 0xa2, 0xac, 0xd9, 0xe7,
+	0xe0, 0xde, 0x70, 0x59, 0x85, 0x75, 0xbf, 0x2b, 0xac, 0xa3, 0x0d, 0x30, 0x2a, 0x85, 0x1e, 0x9a,
+	0xed, 0x17, 0xa9, 0x31, 0x84, 0xef, 0x32, 0xf4, 0xb4, 0xc9, 0x7e, 0x91, 0xa2, 0xe7, 0x36, 0x74,
+	0xd1, 0x93, 0xcb, 0xc0, 0xc3, 0x3d, 0x6c, 0xe8, 0xd7, 0x91, 0x24, 0x61, 0xb5, 0x18, 0x97, 0x11,
+	0xfb, 0x5b, 0x89, 0x38, 0xd8, 0x44, 0xd8, 0x33, 0xf0, 0xa9, 0x2e, 0x35, 0x9c, 0x44, 0x70, 0x29,
+	0xb5, 0x45, 0xef, 0x96, 0x33, 0xd4, 0xb5, 0x91, 0x24, 0x3f, 0xc1, 0xc3, 0x16, 0x07, 0x63, 0xf7,
+	0xcd, 0xf5, 0x69, 0x58, 0x18, 0xe4, 0x25, 0x6c, 0xb5, 0x78, 0xcd, 0x16, 0x1f, 0x9a, 0xc6, 0x36,
+	0xdc, 0x56, 0x6e, 0x5e, 0xaa, 0x28, 0xcd, 0x44, 0xe0, 0x9b, 0xdc, 0xbc, 0x54, 0x27, 0x99, 0x20,
+	0xbf, 0x82, 0x27, 0x99, 0x2a, 0x17, 0x91, 0xe2, 0x7c, 0x2e, 0x83, 0x47, 0x83, 0xce, 0xae, 0xb7,
+	0xbf, 0xb3, 0xb2, 0x45, 0x1f, 0x98, 0x98, 0xbe, 0x2f, 0xa6, 0x9c, 0x02, 0x2a, 0xae, 0xb5, 0x80,
+	0x1c, 0x82, 0xfb, 0x57, 0xac, 0xb2, 0x48, 0x94, 0x85, 0x0c, 0xc8, 0x7d, 0xd4, 0x8e, 0xe6, 0xd3,
+	0xb2, 0x90, 0xe4, 0x1d, 0x80, 0x61, 0xa2, 0x78, 0xeb, 0x3e, 0x62, 0x17, 0xd1, 0x5a, 0x5d, 0x64,
+	0xc5, 0xe7, 0xd8, 0xa8, 0x1f, 0xdf, 0x4b, 0x8d, 0x02, 0x54, 0xff, 0x02, 0xeb, 0x8a, 0xab, 0x78,
+	0x1e, 0x3c, 0x19, 0x58, 0xdf, 0x16, 0x1a, 0x2e, 0x19, 0xc2, 0xa6, 0x21, 0x24, 0xbc, 0x98, 0x66,
+	0xb3, 0x60, 0x1b, 0xb5, 0x83, 0x95, 0x5a, 0xfc, 0x0c, 0x87, 0xc8, 0xa3, 0xde, 0xe4, 0xf6, 0x85,
+	0x3c, 0x03, 0xbc, 0xa2, 0x38, 0x4a, 0x02, 0x3c, 0x8b, 0xe6, 0x3d, 0x7c, 0x0d, 0x9b, 0x77, 0x3e,
+	0x5f, 0x07, 0xec, 0xf1, 0xd5, 0x29, 0xf5, 0x1f, 0x90, 0x1e, 0xb8, 0xfa, 0xe9, 0xe4, 0xf4, 0x78,
+	0x7c, 0xe6, 0x5b, 0xa4, 0x0b, 0xfa, 0x93, 0xf7, 0xd7, 0xc2, 0x77, 0x60, 0xe3, 0x01, 0x7b, 0x50,
+	0x5f, 0x58, 0xff, 0x81, 0x46, 0x8f, 0xe8, 0x85, 0x6f, 0x11, 0x17, 0xd6, 0x8f, 0xe8, 0xc5, 0xc1,
+	0x1b, 0x7f, 0x4d, 0xd7, 0x3e, 0xbd, 0x3d, 0xf0, 0x3b, 0x04, 0x60, 0xe3, 0xd3, 0xdb, 0x83, 0xe8,
+	0xe0, 0x8d, 0x6f, 0x87, 0x33, 0xf0, 0x5a, 0x39, 0xf5, 0x44, 0x2c, 0x25, 0x8b, 0x66, 0x3c, 0x8f,
+	0x71, 0x6e, 0x3a, 0xb4, 0x5b, 0x4a, 0x76, 0xc6, 0xf3, 0x58, 0x5f, 0x20, 0x0d, 0x89, 0x09, 0xc3,
+	0x59, 0xe9, 0xd0, 0x8d, 0x52, 0x32, 0x3a, 0x61, 0xe4, 0x47, 0xe8, 0x4f, 0xb9, 0x48, 0x58, 0xd4,
+	0x28, 0x3b, 0x88, 0x6f, 0x62, 0x75, 0x6c, 0xe4, 0xe1, 0x3f, 0x16, 0x38, 0x75, 0x37, 0x09, 0x01,
+	0x3b, 0x65, 0x32, 0xc1, 0x25, 0x5c, 0x8a, 0xcf, 0xba, 0x86, 0x1d, 0x31, 0x83, 0x18, 0x9f, 0xc9,
+	0x0e, 0x80, 0x54, 0xb1, 0x50, 0x38, 0xcd, 0xd1, 0xd6, 0xa6, 0x2e, 0x56, 0xf4, 0x10, 0x27, 0xcf,
+	0xc1, 0x15, 0x2c, 0x9e, 0x1b, 0xd4, 0x46, 0xd4, 0xd1, 0x05, 0x04, 0x77, 0x00, 0x72, 0x96, 0x73,
+	0xb1, 0xd4, 0xb9, 0x70, 0xa8, 0xda, 0xd4, 0x35, 0x95, 0xb1, 0x64, 0xe1, 0x7f, 0x16, 0xf4, 0x2f,
+	0x78, 0x5a, 0xce, 0xd9, 0xf5, 0x72, 0xc1, 0x30, 0xd5, 0x9f, 0xf5, 0xe1, 0xca, 0xa5, 0x54, 0x2c,
+	0xc7, 0x74, 0xfd, 0xfd, 0x57, 0xab, 0xa7, 0xc5, 0x1d, 0xa9, 0x39, 0xeb, 0x2b, 0x94, 0xb5, 0xe6,
+	0xc6, 0xe4, 0xb6, 0x4a, 0x7e, 0x00, 0x2f, 0x47, 0x4d, 0xa4, 0x96, 0x8b, 0x7a, 0x97, 0x90, 0x37,
+	0x36, 0xba, 0x8d, 0x45, 0x99, 0x47, 0x7c, 0x1a, 0x99, 0xa2, 0xc4, 0xfd, 0xf6, 0xe8, 0x66, 0x51,
+	0xe6, 0xa3, 0xa9, 0x59, 0x4f, 0x86, 0xaf, 0xaa, 0xf3, 0xaa, 0x5c, 0xef, 0x1c, 0xba, 0x0b, 0xeb,
+	0x57, 0xa3, 0xd1, 0xa5, 0xbe, 0x1d, 0x0e, 0xd8, 0x17, 0x47, 0xe7, 0xa7, 0xfe, 0x5a, 0x38, 0x87,
+	0x67, 0x43, 0x91, 0xa9, 0x2c, 0x89, 0xe7, 0x63, 0xc9, 0xc4, 0x6f, 0xbc, 0x14, 0x05, 0x5b, 0x56,
+	0xc3, 0xae, 0x69, 0xba, 0xd5, 0x6a, 0xfa, 0x21, 0x74, 0xab, 0x5d, 0x62, 0xca, 0xaf, 0x5d, 0xef,
+	0xd6, 0xbc, 0xa4, 0xb5, 0x20, 0x9c, 0xc0, 0xf3, 0x15, 0xab, 0xc9, 0x7a, 0xb9, 0x21, 0xd8, 0x49,
+	0xf9, 0x59, 0x06, 0x16, 0x7e, 0xab, 0xab, 0x3b, 0xfb, 0xf5, 0xb4, 0x14, 0xc5, 0xc7, 0x4f, 0xfe,
+	0xa8, 0x7e, 0x07, 0x2a, 0x45, 0x84, 0xff, 0x08, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x7b,
+	0xda, 0x72, 0x33, 0x08, 0x00, 0x00,
 }
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 08f7d44..e96a2e9 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -94,6 +94,9 @@
   optional PerfInfo total = 21;
 
   optional BuildConfig build_config = 23;
+
+  // The hostname of the machine.
+  optional string hostname = 24;
 }
 
 message BuildConfig {