Merge "Allow non-SDK Java libraries to masquerade as <uses-library>."
diff --git a/android/defaults.go b/android/defaults.go
index 81e340e..0892adf 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -115,11 +115,6 @@
 
 type DefaultsModuleBase struct {
 	DefaultableModuleBase
-
-	// Container for defaults of the common properties
-	commonProperties commonProperties
-
-	defaultsVisibilityProperties DefaultsVisibilityProperties
 }
 
 // The common pattern for defaults modules is to register separate instances of
@@ -153,12 +148,6 @@
 	properties() []interface{}
 
 	productVariableProperties() interface{}
-
-	// Return the defaults common properties.
-	common() *commonProperties
-
-	// Return the defaults visibility properties.
-	defaultsVisibility() *DefaultsVisibilityProperties
 }
 
 func (d *DefaultsModuleBase) isDefaults() bool {
@@ -178,24 +167,17 @@
 	return d.defaultableVariableProperties
 }
 
-func (d *DefaultsModuleBase) common() *commonProperties {
-	return &d.commonProperties
-}
-
-func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties {
-	return &d.defaultsVisibilityProperties
-}
-
 func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
 }
 
 func InitDefaultsModule(module DefaultsModule) {
-	commonProperties := module.common()
+	commonProperties := &commonProperties{}
 
 	module.AddProperties(
 		&hostAndDeviceProperties{},
 		commonProperties,
-		&ApexProperties{})
+		&ApexProperties{},
+		&distProperties{})
 
 	initAndroidModuleBase(module)
 	initProductVariableModule(module)
@@ -204,7 +186,7 @@
 
 	// Add properties that will not have defaults applied to them.
 	base := module.base()
-	defaultsVisibility := module.defaultsVisibility()
+	defaultsVisibility := &DefaultsVisibilityProperties{}
 	module.AddProperties(&base.nameProperties, defaultsVisibility)
 
 	// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
diff --git a/android/module.go b/android/module.go
index 17bc205..3374e1d 100644
--- a/android/module.go
+++ b/android/module.go
@@ -490,14 +490,6 @@
 	// relative path to a file to include in the list of notices for the device
 	Notice *string `android:"path"`
 
-	// configuration to distribute output files from this module to the distribution
-	// directory (default: $OUT/dist, configurable with $DIST_DIR)
-	Dist Dist `android:"arch_variant"`
-
-	// a list of configurations to distribute output files from this module to the
-	// distribution directory (default: $OUT/dist, configurable with $DIST_DIR)
-	Dists []Dist `android:"arch_variant"`
-
 	// The OsType of artifacts that this module variant is responsible for creating.
 	//
 	// Set by osMutator
@@ -566,6 +558,16 @@
 	ImageVariation string `blueprint:"mutated"`
 }
 
+type distProperties struct {
+	// configuration to distribute output files from this module to the distribution
+	// directory (default: $OUT/dist, configurable with $DIST_DIR)
+	Dist Dist `android:"arch_variant"`
+
+	// a list of configurations to distribute output files from this module to the
+	// distribution directory (default: $OUT/dist, configurable with $DIST_DIR)
+	Dists []Dist `android:"arch_variant"`
+}
+
 // A map of OutputFile tag keys to Paths, for disting purposes.
 type TaggedDistFiles map[string]Paths
 
@@ -661,7 +663,8 @@
 
 	m.AddProperties(
 		&base.nameProperties,
-		&base.commonProperties)
+		&base.commonProperties,
+		&base.distProperties)
 
 	initProductVariableModule(m)
 
@@ -752,6 +755,7 @@
 
 	nameProperties          nameProperties
 	commonProperties        commonProperties
+	distProperties          distProperties
 	variableProperties      interface{}
 	hostAndDeviceProperties hostAndDeviceProperties
 	generalProperties       []interface{}
@@ -861,13 +865,13 @@
 }
 
 func (m *ModuleBase) Dists() []Dist {
-	if len(m.commonProperties.Dist.Targets) > 0 {
+	if len(m.distProperties.Dist.Targets) > 0 {
 		// Make a copy of the underlying Dists slice to protect against
 		// backing array modifications with repeated calls to this method.
-		distsCopy := append([]Dist(nil), m.commonProperties.Dists...)
-		return append(distsCopy, m.commonProperties.Dist)
+		distsCopy := append([]Dist(nil), m.distProperties.Dists...)
+		return append(distsCopy, m.distProperties.Dist)
 	} else {
-		return m.commonProperties.Dists
+		return m.distProperties.Dists
 	}
 }
 
@@ -1344,20 +1348,20 @@
 	ctx.Variable(pctx, "moduleDescSuffix", s)
 
 	// Some common property checks for properties that will be used later in androidmk.go
-	if m.commonProperties.Dist.Dest != nil {
-		_, err := validateSafePath(*m.commonProperties.Dist.Dest)
+	if m.distProperties.Dist.Dest != nil {
+		_, err := validateSafePath(*m.distProperties.Dist.Dest)
 		if err != nil {
 			ctx.PropertyErrorf("dist.dest", "%s", err.Error())
 		}
 	}
-	if m.commonProperties.Dist.Dir != nil {
-		_, err := validateSafePath(*m.commonProperties.Dist.Dir)
+	if m.distProperties.Dist.Dir != nil {
+		_, err := validateSafePath(*m.distProperties.Dist.Dir)
 		if err != nil {
 			ctx.PropertyErrorf("dist.dir", "%s", err.Error())
 		}
 	}
-	if m.commonProperties.Dist.Suffix != nil {
-		if strings.Contains(*m.commonProperties.Dist.Suffix, "/") {
+	if m.distProperties.Dist.Suffix != nil {
+		if strings.Contains(*m.distProperties.Dist.Suffix, "/") {
 			ctx.PropertyErrorf("dist.suffix", "Suffix may not contain a '/' character.")
 		}
 	}
diff --git a/apex/Android.bp b/apex/Android.bp
index 144f441..1a5f683 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -5,6 +5,7 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-bpf",
         "soong-cc",
         "soong-java",
         "soong-python",
diff --git a/apex/apex.go b/apex/apex.go
index f3699b0..62d91da 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -26,6 +26,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bpf"
 	"android/soong/cc"
 	prebuilt_etc "android/soong/etc"
 	"android/soong/java"
@@ -66,6 +67,7 @@
 	usesTag        = dependencyTag{name: "uses"}
 	androidAppTag  = dependencyTag{name: "androidApp", payload: true}
 	rroTag         = dependencyTag{name: "rro", payload: true}
+	bpfTag         = dependencyTag{name: "bpf", payload: true}
 
 	apexAvailBaseline = makeApexAvailableBaseline()
 
@@ -961,6 +963,9 @@
 	// List of prebuilt files that are embedded inside this APEX bundle
 	Prebuilts []string
 
+	// List of BPF programs inside APEX
+	Bpfs []string
+
 	// Name of the apex_key module that provides the private key to sign APEX
 	Key *string
 
@@ -1336,26 +1341,30 @@
 	// conflicting variations with this module. This is required since
 	// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
 	// for native shared libs.
-	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-		{Mutator: "image", Variation: imageVariation},
-		{Mutator: "link", Variation: "shared"},
-		{Mutator: "version", Variation: ""}, // "" is the non-stub variant
-	}...), sharedLibTag, nativeModules.Native_shared_libs...)
 
-	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-		{Mutator: "image", Variation: imageVariation},
-		{Mutator: "link", Variation: "shared"},
-		{Mutator: "version", Variation: ""}, // "" is the non-stub variant
-	}...), jniLibTag, nativeModules.Jni_libs...)
+	binVariations := target.Variations()
+	libVariations := append(target.Variations(),
+		blueprint.Variation{Mutator: "link", Variation: "shared"})
+	testVariations := append(target.Variations(),
+		blueprint.Variation{Mutator: "test_per_src", Variation: ""}) // "" is the all-tests variant
 
-	ctx.AddFarVariationDependencies(append(target.Variations(),
-		blueprint.Variation{Mutator: "image", Variation: imageVariation}),
-		executableTag, nativeModules.Binaries...)
+	if ctx.Device() {
+		binVariations = append(binVariations,
+			blueprint.Variation{Mutator: "image", Variation: imageVariation})
+		libVariations = append(libVariations,
+			blueprint.Variation{Mutator: "image", Variation: imageVariation},
+			blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant
+		testVariations = append(testVariations,
+			blueprint.Variation{Mutator: "image", Variation: imageVariation})
+	}
 
-	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-		{Mutator: "image", Variation: imageVariation},
-		{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
-	}...), testTag, nativeModules.Tests...)
+	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
+
+	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
+
+	ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...)
+
+	ctx.AddFarVariationDependencies(testVariations, testTag, nativeModules.Tests...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -1473,6 +1482,9 @@
 	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
 		javaLibTag, a.properties.Java_libs...)
 
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		bpfTag, a.properties.Bpfs...)
+
 	// With EMMA_INSTRUMENT_FRAMEWORK=true the ART boot image includes jacoco library.
 	if a.artApex && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
 		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
@@ -1740,7 +1752,7 @@
 }
 
 func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile {
-	dirInApex := filepath.Join("etc", prebuilt.SubDir())
+	dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
 	fileToCopy := prebuilt.OutputFile()
 	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
 }
@@ -1793,6 +1805,11 @@
 	return af
 }
 
+func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, bpfProgram bpf.BpfModule) apexFile {
+	dirInApex := filepath.Join("etc", "bpf")
+	return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram)
+}
+
 // Context "decorator", overriding the InstallBypassMake method to always reply `true`.
 type flattenedApexContext struct {
 	android.ModuleContext
@@ -2128,6 +2145,15 @@
 				} else {
 					ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
 				}
+			case bpfTag:
+				if bpfProgram, ok := child.(bpf.BpfModule); ok {
+					filesToCopy, _ := bpfProgram.OutputFiles("")
+					for _, bpfFile := range filesToCopy {
+						filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, bpfProgram))
+					}
+				} else {
+					ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
+				}
 			case prebuiltTag:
 				if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
 					filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e9843fc..2950c6a 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -27,6 +27,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bpf"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
 	prebuilt_etc "android/soong/etc"
@@ -248,7 +249,7 @@
 	ctx.RegisterModuleType("cc_test", cc.TestFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
-	ctx.RegisterModuleType("prebuilt_etc", prebuilt_etc.PrebuiltEtcFactory)
+	prebuilt_etc.RegisterPrebuiltEtcBuildComponents(ctx)
 	ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
 	ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
@@ -257,6 +258,7 @@
 	java.RegisterAppBuildComponents(ctx)
 	java.RegisterSdkLibraryBuildComponents(ctx)
 	ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
+	ctx.RegisterModuleType("bpf", bpf.BpfFactory)
 
 	ctx.PreDepsMutators(RegisterPreDepsMutators)
 	ctx.PostDepsMutators(RegisterPostDepsMutators)
@@ -606,6 +608,7 @@
 			java_libs: ["myjar"],
 			apps: ["AppFoo"],
 			rros: ["rro"],
+			bpfs: ["bpf"],
 		}
 
 		prebuilt_etc {
@@ -652,6 +655,11 @@
 			theme: "blue",
 		}
 
+		bpf {
+			name: "bpf",
+			srcs: ["bpf.c", "bpf2.c"],
+		}
+
 	`)
 	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
 		"etc/myetc",
@@ -659,6 +667,8 @@
 		"lib64/mylib.so",
 		"app/AppFoo/AppFoo.apk",
 		"overlay/blue/rro.apk",
+		"etc/bpf/bpf.o",
+		"etc/bpf/bpf2.o",
 	})
 }
 
@@ -2272,6 +2282,32 @@
 	ensureListContains(t, requireNativeLibs, ":vndk")
 }
 
+func TestVendorApex_withPrebuiltFirmware(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			prebuilts: ["myfirmware"],
+			vendor: true,
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+		prebuilt_firmware {
+			name: "myfirmware",
+			src: "myfirmware.bin",
+			filename_from_src: true,
+			vendor: true,
+		}
+	`)
+
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"firmware/myfirmware.bin",
+	})
+}
+
 func TestAndroidMk_UseVendorRequired(t *testing.T) {
 	ctx, config := testApex(t, `
 		apex {
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 4cdfb31..297e13a 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -26,7 +26,7 @@
 )
 
 func init() {
-	android.RegisterModuleType("bpf", bpfFactory)
+	android.RegisterModuleType("bpf", BpfFactory)
 	pctx.Import("android/soong/cc/config")
 }
 
@@ -43,6 +43,13 @@
 		"ccCmd", "cFlags")
 )
 
+// BpfModule interface is used by the apex package to gather information from a bpf module.
+type BpfModule interface {
+	android.Module
+
+	OutputFiles(tag string) (android.Paths, error)
+}
+
 type BpfProperties struct {
 	Srcs         []string `android:"path"`
 	Cflags       []string
@@ -141,7 +148,7 @@
 
 var _ android.OutputFileProducer = (*bpf)(nil)
 
-func bpfFactory() android.Module {
+func BpfFactory() android.Module {
 	module := &bpf{}
 
 	module.AddProperties(&module.properties)
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index eeca057..d06d7d1 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -59,7 +59,7 @@
 
 func testContext(config android.Config) *android.TestContext {
 	ctx := cc.CreateTestContext()
-	ctx.RegisterModuleType("bpf", bpfFactory)
+	ctx.RegisterModuleType("bpf", BpfFactory)
 	ctx.Register(config)
 
 	return ctx
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 337de55..a1abc72 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -46,9 +46,13 @@
 			if version == "" {
 				version = LatestStubsVersionFor(mctx.Config(), name)
 			}
-			mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-				{Mutator: "version", Variation: version},
-			}...), dependencyTag, name)
+			variations := target.Variations()
+			if mctx.Device() {
+				variations = append(variations,
+					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
+					blueprint.Variation{Mutator: "version", Variation: version})
+			}
+			mctx.AddFarVariationDependencies(variations, dependencyTag, name)
 		}
 	}
 }
diff --git a/cc/builder.go b/cc/builder.go
index 8f2da34..81d2f1e 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -69,12 +69,12 @@
 		&remoteexec.REParams{
 			Labels:          map[string]string{"type": "link", "tool": "clang"},
 			ExecStrategy:    "${config.RECXXLinksExecStrategy}",
-			Inputs:          []string{"${out}.rsp"},
+			Inputs:          []string{"${out}.rsp", "$implicitInputs"},
 			RSPFile:         "${out}.rsp",
 			OutputFiles:     []string{"${out}", "$implicitOutputs"},
 			ToolchainInputs: []string{"$ldCmd"},
 			Platform:        map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
-		}, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitOutputs"})
+		}, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitInputs", "implicitOutputs"})
 
 	partialLd, partialLdRE = remoteexec.StaticRules(pctx, "partialLd",
 		blueprint.RuleParams{
@@ -83,12 +83,13 @@
 			Command:     "$reTemplate$ldCmd -fuse-ld=lld -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}",
 			CommandDeps: []string{"$ldCmd"},
 		}, &remoteexec.REParams{
-			Labels:       map[string]string{"type": "link", "tool": "clang"},
-			ExecStrategy: "${config.RECXXLinksExecStrategy}", Inputs: []string{"$inCommaList"},
+			Labels:          map[string]string{"type": "link", "tool": "clang"},
+			ExecStrategy:    "${config.RECXXLinksExecStrategy}",
+			Inputs:          []string{"$inCommaList", "$implicitInputs"},
 			OutputFiles:     []string{"${out}", "$implicitOutputs"},
 			ToolchainInputs: []string{"$ldCmd"},
 			Platform:        map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
-		}, []string{"ldCmd", "ldFlags"}, []string{"inCommaList", "implicitOutputs"})
+		}, []string{"ldCmd", "ldFlags"}, []string{"implicitInputs", "inCommaList", "implicitOutputs"})
 
 	ar = pctx.AndroidStaticRule("ar",
 		blueprint.RuleParams{
@@ -236,12 +237,12 @@
 		}, &remoteexec.REParams{
 			Labels:          map[string]string{"type": "tool", "name": "abi-linker"},
 			ExecStrategy:    "${config.REAbiLinkerExecStrategy}",
-			Inputs:          []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicits"},
+			Inputs:          []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicitInputs"},
 			RSPFile:         "${out}.rsp",
 			OutputFiles:     []string{"$out"},
 			ToolchainInputs: []string{"$sAbiLinker"},
 			Platform:        map[string]string{remoteexec.PoolKey: "${config.RECXXPool}"},
-		}, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicits"})
+		}, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicitInputs"})
 
 	_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
 
@@ -747,6 +748,7 @@
 	if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
 		rule = ldRE
 		args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",")
+		args["implicitInputs"] = strings.Join(deps.Strings(), ",")
 	}
 
 	ctx.Build(pctx, android.BuildParams{
@@ -796,7 +798,7 @@
 				rbeImplicits = append(rbeImplicits, p[2:])
 			}
 		}
-		args["implicits"] = strings.Join(rbeImplicits, ",")
+		args["implicitInputs"] = strings.Join(rbeImplicits, ",")
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
@@ -913,6 +915,7 @@
 	if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
 		rule = partialLdRE
 		args["inCommaList"] = strings.Join(objFiles.Strings(), ",")
+		args["implicitInputs"] = strings.Join(deps.Strings(), ",")
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
diff --git a/cc/cc.go b/cc/cc.go
index 9196d47..70229be 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -280,6 +280,13 @@
 	// Set when both SDK and platform variants are exported to Make to trigger renaming the SDK
 	// variant to have a ".sdk" suffix.
 	SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
+
+	// Normally Soong uses the directory structure to decide which modules
+	// should be included (framework) or excluded (non-framework) from the
+	// vendor snapshot, but this property allows a partner to exclude a
+	// module normally thought of as a framework module from the vendor
+	// snapshot.
+	Exclude_from_vendor_snapshot *bool
 }
 
 type VendorProperties struct {
@@ -1108,6 +1115,10 @@
 	return nil
 }
 
+func (c *Module) ExcludeFromVendorSnapshot() bool {
+	return Bool(c.Properties.Exclude_from_vendor_snapshot)
+}
+
 func isBionic(name string) bool {
 	switch name {
 	case "libc", "libm", "libdl", "libdl_android", "linker":
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 77b5c52..78d8428 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -258,7 +258,8 @@
 	}
 }
 
-func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool) {
+	t.Helper()
 	mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
 	if !ok {
 		t.Errorf("%q must have output\n", moduleName)
@@ -271,12 +272,27 @@
 	}
 	snapshotPath := filepath.Join(subDir, snapshotFilename)
 
-	out := singleton.Output(snapshotPath)
-	if out.Input.String() != outputFiles[0].String() {
-		t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
+	if include {
+		out := singleton.Output(snapshotPath)
+		if out.Input.String() != outputFiles[0].String() {
+			t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
+		}
+	} else {
+		out := singleton.MaybeOutput(snapshotPath)
+		if out.Rule != nil {
+			t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0])
+		}
 	}
 }
 
+func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true)
+}
+
+func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false)
+}
+
 func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
 	t.Helper()
 	assertString(t, params.Rule.String(), android.WriteFile.String())
@@ -1096,6 +1112,203 @@
 	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
 }
 
+func assertExcludeFromVendorSnapshotIs(t *testing.T, c *Module, expected bool) {
+	t.Helper()
+	if c.ExcludeFromVendorSnapshot() != expected {
+		t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", c.String(), expected)
+	}
+}
+
+func TestVendorSnapshotExclude(t *testing.T) {
+
+	// This test verifies that the exclude_from_vendor_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 vendor snapshot based on their path (framework or
+	// vendor) and the exclude_from_vendor_snapshot property.
+
+	frameworkBp := `
+		cc_library_shared {
+			name: "libinclude",
+			srcs: ["src/include.cpp"],
+			vendor_available: true,
+		}
+		cc_library_shared {
+			name: "libexclude",
+			srcs: ["src/exclude.cpp"],
+			vendor: true,
+			exclude_from_vendor_snapshot: true,
+		}
+	`
+
+	vendorProprietaryBp := `
+		cc_library_shared {
+			name: "libvendor",
+			srcs: ["vendor.cpp"],
+			vendor: 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/vendor.cpp":     nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext()
+	ctx.Register(config)
+
+	_, 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.
+	assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false)
+	assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", vendorVariant).Module().(*Module), false)
+	assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libexclude", vendorVariant).Module().(*Module), true)
+
+	// A vendor module is excluded, but by its path, not the
+	// exclude_from_vendor_snapshot property.
+	assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libvendor", vendorVariant).Module().(*Module), false)
+
+	// Verify the content of the vendor snapshot.
+
+	snapshotDir := "vendor-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
+
+	var includeJsonFiles []string
+	var excludeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+		[]string{"arm", "armv7-a-neon"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_vendor.VER_%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, "libvendor", "libvendor.so", sharedDir, sharedVariant)
+		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.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 TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) {
+
+	// This test verifies that using the exclude_from_vendor_snapshot
+	// property on a module in a vendor proprietary path generates an
+	// error. These modules are already excluded, so we prohibit using the
+	// property in this way, which could add to confusion.
+
+	vendorProprietaryBp := `
+		cc_library_shared {
+			name: "libvendor",
+			srcs: ["vendor.cpp"],
+			vendor: true,
+			exclude_from_vendor_snapshot: true,
+		}
+	`
+
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":   []byte(depsBp),
+		"device/Android.bp": []byte(vendorProprietaryBp),
+		"device/vendor.cpp": nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext()
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"})
+	android.FailIfErrored(t, errs)
+
+	_, errs = ctx.PrepareBuildActions(config)
+	android.CheckErrorsAgainstExpectations(t, errs, []string{
+		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+	})
+}
+
+func TestVendorSnapshotExcludeWithVendorAvailable(t *testing.T) {
+
+	// This test verifies that using the exclude_from_vendor_snapshot
+	// property on a module that is vendor available generates an error. A
+	// vendor available module must be captured in the vendor snapshot and
+	// must not built from source when building the vendor image against
+	// the vendor snapshot.
+
+	frameworkBp := `
+		cc_library_shared {
+			name: "libinclude",
+			srcs: ["src/include.cpp"],
+			vendor_available: true,
+			exclude_from_vendor_snapshot: true,
+		}
+	`
+
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":       []byte(depsBp),
+		"framework/Android.bp":  []byte(frameworkBp),
+		"framework/include.cpp": nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext()
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp"})
+	android.FailIfErrored(t, errs)
+
+	_, errs = ctx.PrepareBuildActions(config)
+	android.CheckErrorsAgainstExpectations(t, errs, []string{
+		`module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+		`module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+		`module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+		`module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+	})
+}
+
 func TestDoubleLoadableDepError(t *testing.T) {
 	// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
 	testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
diff --git a/cc/genrule.go b/cc/genrule.go
index 66d1784..cce4a83 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -84,7 +84,7 @@
 		// If not, we assume modules under proprietary paths are compatible for
 		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
 		// PLATFORM_VNDK_VERSION.
-		if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) {
+		if vndkVersion == "current" || !isVendorProprietaryModule(ctx) {
 			variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
 		} else {
 			variants = append(variants, VendorVariationPrefix+vndkVersion)
diff --git a/cc/image.go b/cc/image.go
index 4daed7c..ea6f567 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -223,7 +223,7 @@
 		// We assume that modules under proprietary paths are compatible for
 		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
 		// PLATFORM_VNDK_VERSION.
-		if isVendorProprietaryPath(mctx.ModuleDir()) {
+		if isVendorProprietaryModule(mctx) {
 			vendorVariants = append(vendorVariants, boardVndkVersion)
 		} else {
 			vendorVariants = append(vendorVariants, platformVndkVersion)
@@ -249,7 +249,7 @@
 				platformVndkVersion,
 				boardVndkVersion,
 			)
-		} else if isVendorProprietaryPath(mctx.ModuleDir()) {
+		} else if isVendorProprietaryModule(mctx) {
 			vendorVariants = append(vendorVariants, boardVndkVersion)
 		} else {
 			vendorVariants = append(vendorVariants, platformVndkVersion)
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 9328a25..665a649 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -82,18 +82,19 @@
 			if version == "" {
 				version = LatestStubsVersionFor(mctx.Config(), name)
 			}
+			variations := target.Variations()
+			if mctx.Device() {
+				variations = append(variations,
+					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
+					blueprint.Variation{Mutator: "version", Variation: version})
+			}
 			if mt.linkTypes == nil {
-				mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-					{Mutator: "image", Variation: android.CoreVariation},
-					{Mutator: "version", Variation: version},
-				}...), dependencyTag, name)
+				mctx.AddFarVariationDependencies(variations, dependencyTag, name)
 			} else {
 				for _, linkType := range mt.linkTypes {
-					mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-						{Mutator: "image", Variation: android.CoreVariation},
-						{Mutator: "link", Variation: linkType},
-						{Mutator: "version", Variation: version},
-					}...), dependencyTag, name)
+					libVariations := append(variations,
+						blueprint.Variation{Mutator: "link", Variation: linkType})
+					mctx.AddFarVariationDependencies(libVariations, dependencyTag, name)
 				}
 			}
 		}
diff --git a/cc/pgo.go b/cc/pgo.go
index 674e1bb..6bf0ad0 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -290,17 +290,16 @@
 
 	// Add flags to profile this module based on its profile_kind
 	if props.ShouldProfileModule && props.isInstrumentation() {
-		props.addInstrumentationProfileGatherFlags(ctx, flags)
 		// Instrumentation PGO use and gather flags cannot coexist.
-		return flags
+		return props.addInstrumentationProfileGatherFlags(ctx, flags)
 	} else if props.ShouldProfileModule && props.isSampling() {
-		props.addSamplingProfileGatherFlags(ctx, flags)
+		flags = props.addSamplingProfileGatherFlags(ctx, flags)
 	} else if ctx.DeviceConfig().SamplingPGO() {
-		props.addSamplingProfileGatherFlags(ctx, flags)
+		flags = props.addSamplingProfileGatherFlags(ctx, flags)
 	}
 
 	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
-		props.addProfileUseFlags(ctx, flags)
+		flags = props.addProfileUseFlags(ctx, flags)
 	}
 
 	return flags
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 2243082..cee9d84 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -738,7 +738,7 @@
 // as vendor snapshot. Such modules must create both cfi and non-cfi variants,
 // except for ones which explicitly disable cfi.
 func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
-	if isVendorProprietaryPath(mctx.ModuleDir()) {
+	if isVendorProprietaryModule(mctx) {
 		return false
 	}
 
@@ -1011,10 +1011,12 @@
 
 				// static executable gets static runtime libs
 				depTag := libraryDependencyTag{Kind: staticLibraryDependency}
-				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
-					{Mutator: "link", Variation: "static"},
-					c.ImageVariation(),
-				}...), depTag, deps...)
+				variations := append(mctx.Target().Variations(),
+					blueprint.Variation{Mutator: "link", Variation: "static"})
+				if c.Device() {
+					variations = append(variations, c.ImageVariation())
+				}
+				mctx.AddFarVariationDependencies(variations, depTag, deps...)
 			} else if !c.static() && !c.header() {
 				// If we're using snapshots and in vendor, redirect to snapshot whenever possible
 				if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
@@ -1026,10 +1028,12 @@
 
 				// dynamic executable and shared libs get shared runtime libs
 				depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: earlyLibraryDependency}
-				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
-					{Mutator: "link", Variation: "shared"},
-					c.ImageVariation(),
-				}...), depTag, runtimeLibrary)
+				variations := append(mctx.Target().Variations(),
+					blueprint.Variation{Mutator: "link", Variation: "shared"})
+				if c.Device() {
+					variations = append(variations, c.ImageVariation())
+				}
+				mctx.AddFarVariationDependencies(variations, depTag, runtimeLibrary)
 			}
 			// static lib does not have dependency to the runtime library. The
 			// dependency will be added to the executables or shared libs using
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 4012def..f27d166 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -61,7 +61,7 @@
 func isSnapshotAware(ctx android.ModuleContext, m *Module) bool {
 	if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok {
 		return ctx.Config().VndkSnapshotBuildArtifacts()
-	} else if isVendorSnapshotModule(m, ctx.ModuleDir()) {
+	} else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir())) {
 		return true
 	}
 	return false
diff --git a/cc/test.go b/cc/test.go
index a805647..ee103ff 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -344,6 +344,12 @@
 }
 
 func (test *testBinary) install(ctx ModuleContext, file android.Path) {
+	// TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
+	testInstallBase := "/data/local/tmp"
+	if ctx.inVendor() || ctx.useVndk() {
+		testInstallBase = "/data/local/tests/vendor"
+	}
+
 	dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
 
 	for _, dataSrcPath := range dataSrcPaths {
@@ -411,7 +417,7 @@
 	}
 
 	test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
-		test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config)
+		test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config, testInstallBase)
 
 	test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs)
 
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 93aece4..0219b84 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -508,18 +508,46 @@
 	return false
 }
 
+func isVendorProprietaryModule(ctx android.BaseModuleContext) bool {
+
+	// Any module in a vendor proprietary path is a vendor proprietary
+	// module.
+
+	if isVendorProprietaryPath(ctx.ModuleDir()) {
+		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.ExcludeFromVendorSnapshot() {
+			return true
+		}
+	}
+
+	return false
+}
+
 // Determine if a module is going to be included in vendor snapshot or not.
 //
 // Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in
 // AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
 // depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
 // image and newer system image altogether.
-func isVendorSnapshotModule(m *Module, moduleDir string) bool {
+func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool) bool {
 	if !m.Enabled() || m.Properties.HideFromMake {
 		return false
 	}
 	// skip proprietary modules, but include all VNDK (static)
-	if isVendorProprietaryPath(moduleDir) && !m.IsVndk() {
+	if inVendorProprietaryPath && !m.IsVndk() {
+		return false
+	}
+	// If the module would be included based on its path, check to see if
+	// the module is marked to be excluded. If so, skip it.
+	if m.ExcludeFromVendorSnapshot() {
 		return false
 	}
 	if m.Target().Os.Class != android.Device {
@@ -791,7 +819,25 @@
 		}
 
 		moduleDir := ctx.ModuleDir(module)
-		if !isVendorSnapshotModule(m, moduleDir) {
+		inVendorProprietaryPath := isVendorProprietaryPath(moduleDir)
+
+		if m.ExcludeFromVendorSnapshot() {
+			if inVendorProprietaryPath {
+				// Error: exclude_from_vendor_snapshot applies
+				// to framework-path modules only.
+				ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir)
+				return
+			}
+			if Bool(m.VendorProperties.Vendor_available) {
+				// Error: may not combine "vendor_available:
+				// true" with "exclude_from_vendor_snapshot:
+				// true".
+				ctx.Errorf("module %q may not use both \"vendor_available: true\" and \"exclude_from_vendor_snapshot: true\"", m.String())
+				return
+			}
+		}
+
+		if !isVendorSnapshotModule(m, inVendorProprietaryPath) {
 			return
 		}
 
diff --git a/cc/vndk.go b/cc/vndk.go
index 23bb095..9a2fa09 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -505,18 +505,25 @@
 	}}
 }
 
+// PrebuiltEtcModule interface
 func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
 	return txt.outputFile
 }
 
-func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
-	return android.Paths{txt.outputFile}, nil
+// PrebuiltEtcModule interface
+func (txt *vndkLibrariesTxt) BaseDir() string {
+	return "etc"
 }
 
+// PrebuiltEtcModule interface
 func (txt *vndkLibrariesTxt) SubDir() string {
 	return ""
 }
 
+func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
+	return android.Paths{txt.outputFile}, nil
+}
+
 func VndkSnapshotSingleton() android.Singleton {
 	return &vndkSnapshotSingleton{}
 }
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 0f7b8df..5dd2a86 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -28,14 +28,17 @@
 
 func init() {
 	pctx.Import("android/soong/android")
+	RegisterPrebuiltEtcBuildComponents(android.InitRegistrationContext)
+}
 
-	android.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
-	android.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
-	android.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
-	android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
-	android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
-	android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
-	android.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
+func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
+	ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+	ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
+	ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+	ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
+	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+	ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
 }
 
 type prebuiltEtcProperties struct {
@@ -70,6 +73,7 @@
 
 type PrebuiltEtcModule interface {
 	android.Module
+	BaseDir() string
 	SubDir() string
 	OutputFile() android.OutputPath
 }
@@ -167,6 +171,16 @@
 	return proptools.String(p.properties.Relative_install_path)
 }
 
+func (p *PrebuiltEtc) BaseDir() string {
+	// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
+	// socInstallDirBase.
+	installBaseDir := p.installDirBase
+	if p.SocSpecific() && p.socInstallDirBase != "" {
+		installBaseDir = p.socInstallDirBase
+	}
+	return installBaseDir
+}
+
 func (p *PrebuiltEtc) Installable() bool {
 	return p.properties.Installable == nil || android.Bool(p.properties.Installable)
 }
@@ -191,13 +205,7 @@
 		ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
 	}
 
-	// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
-	// socInstallDirBase.
-	installBaseDir := p.installDirBase
-	if ctx.SocSpecific() && p.socInstallDirBase != "" {
-		installBaseDir = p.socInstallDirBase
-	}
-	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
+	p.installDirPath = android.PathForModuleInstall(ctx, p.BaseDir(), p.SubDir())
 
 	// This ensures that outputFilePath has the correct name for others to
 	// use, as the source file may have a different name.
diff --git a/java/android_manifest.go b/java/android_manifest.go
index f45ebe8..41fcafe 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -80,7 +80,7 @@
 		args = append(args, "--use-embedded-dex")
 	}
 
-	for usesLib, _ := range sdkLibraries {
+	for _, usesLib := range android.SortedStringKeys(sdkLibraries) {
 		if inList(usesLib, optionalUsesLibs) {
 			args = append(args, "--optional-uses-library", usesLib)
 		} else {
diff --git a/java/java.go b/java/java.go
index 22cf8c7..0690418 100644
--- a/java/java.go
+++ b/java/java.go
@@ -681,25 +681,29 @@
 	return j.ApexModuleBase.AvailableFor(what)
 }
 
+func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) {
+	sdkDep := decodeSdkDep(ctx, sdkContext)
+	if sdkDep.useModule {
+		ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
+		ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+		ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
+		if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
+			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+		}
+		if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
+			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
+		}
+	}
+	if sdkDep.systemModules != "" {
+		ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
+	}
+}
+
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		j.linter.deps(ctx)
 
-		sdkDep := decodeSdkDep(ctx, sdkContext(j))
-		if sdkDep.useModule {
-			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
-			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
-			ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
-			if j.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
-				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
-			}
-			if j.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
-				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
-			}
-		}
-		if sdkDep.systemModules != "" {
-			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-		}
+		sdkDeps(ctx, sdkContext(j), j.dexer)
 	}
 
 	syspropPublicStubs := syspropPublicStubs(ctx.Config())
@@ -2216,6 +2220,7 @@
 	prebuiltTestProperties prebuiltTestProperties
 
 	testConfig android.Path
+	dexJarFile android.Path
 }
 
 func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2538,8 +2543,14 @@
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
 
+	hiddenAPI
+	dexer
+
 	properties ImportProperties
 
+	// output file containing classes.dex and resources
+	dexJarFile android.Path
+
 	combinedClasspathFile android.Path
 	exportedSdkLibs       dexpreopt.LibraryPaths
 	exportAidlIncludeDirs android.Paths
@@ -2553,10 +2564,18 @@
 	return j.sdkVersion().raw
 }
 
+func (j *Import) systemModules() string {
+	return "none"
+}
+
 func (j *Import) minSdkVersion() sdkSpec {
 	return j.sdkVersion()
 }
 
+func (j *Import) targetSdkVersion() sdkSpec {
+	return j.sdkVersion()
+}
+
 func (j *Import) MinSdkVersion() string {
 	return j.minSdkVersion().version.String()
 }
@@ -2583,6 +2602,10 @@
 
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+
+	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
+		sdkDeps(ctx, sdkContext(j), j.dexer)
+	}
 }
 
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -2600,6 +2623,8 @@
 	j.combinedClasspathFile = outputFile
 	j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
 
+	var flags javaBuilderFlags
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -2608,12 +2633,16 @@
 		case Dependency:
 			switch tag {
 			case libTag, staticLibTag:
+				flags.classpath = append(flags.classpath, dep.HeaderJars()...)
 				// sdk lib names from dependencies are re-exported
 				j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
+			case bootClasspathTag:
+				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
 			}
 		case SdkLibraryDependency:
 			switch tag {
 			case libTag:
+				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 				// names of sdk libs that are directly depended are exported
 				j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			}
@@ -2633,6 +2662,26 @@
 	j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile)
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
+
+	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
+		sdkDep := decodeSdkDep(ctx, sdkContext(j))
+		if sdkDep.invalidVersion {
+			ctx.AddMissingDependencies(sdkDep.bootclasspath)
+			ctx.AddMissingDependencies(sdkDep.java9Classpath)
+		} else if sdkDep.useFiles {
+			// sdkDep.jar is actually equivalent to turbine header.jar.
+			flags.classpath = append(flags.classpath, sdkDep.jars...)
+		}
+
+		// Dex compilation
+		var dexOutputFile android.ModuleOutPath
+		dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName)
+		if ctx.Failed() {
+			return
+		}
+
+		j.dexJarFile = dexOutputFile
+	}
 }
 
 var _ Dependency = (*Import)(nil)
@@ -2663,7 +2712,7 @@
 }
 
 func (j *Import) DexJarBuildPath() android.Path {
-	return nil
+	return j.dexJarFile
 }
 
 func (j *Import) DexJarInstallPath() android.Path {
@@ -2731,10 +2780,15 @@
 func ImportFactory() android.Module {
 	module := &Import{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(
+		&module.properties,
+		&module.dexer.dexProperties,
+	)
 
 	module.initModuleAndImport(&module.ModuleBase)
 
+	module.dexProperties.Optimize.EnabledByDefault = false
+
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
 	android.InitSdkAwareModule(module)
diff --git a/java/java_test.go b/java/java_test.go
index 0e93611..3f7bab1 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -525,6 +525,8 @@
 		java_import {
 			name: "baz",
 			jars: ["b.jar"],
+			sdk_version: "current",
+			compile_dex: true,
 		}
 
 		dex_import {
@@ -555,8 +557,10 @@
 	fooModule := ctx.ModuleForTests("foo", "android_common")
 	javac := fooModule.Rule("javac")
 	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
-	barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output
-	bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output
+	barModule := ctx.ModuleForTests("bar", "android_common")
+	barJar := barModule.Rule("combineJar").Output
+	bazModule := ctx.ModuleForTests("baz", "android_common")
+	bazJar := bazModule.Rule("combineJar").Output
 	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
 
 	fooLibrary := fooModule.Module().(*Library)
@@ -571,6 +575,11 @@
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
 	}
 
+	barDexJar := barModule.Module().(*Import).DexJarBuildPath()
+	if barDexJar != nil {
+		t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar)
+	}
+
 	if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
 	}
@@ -579,6 +588,12 @@
 		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
 	}
 
+	bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().String()
+	expectedDexJar := buildDir + "/.intermediates/baz/android_common/dex/baz.jar"
+	if bazDexJar != expectedDexJar {
+		t.Errorf("baz dex jar build path expected %q, got %q", expectedDexJar, bazDexJar)
+	}
+
 	ctx.ModuleForTests("qux", "android_common").Rule("Cp")
 }
 
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index ac8337d..bcc6cc0 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -38,6 +38,9 @@
 	// The sdk_version of java_import modules generated based on jar files.
 	// Defaults to "current"
 	Imports_sdk_version *string
+
+	// If set to true, compile dex for java_import modules. Defaults to false.
+	Imports_compile_dex *bool
 }
 
 type prebuiltApis struct {
@@ -78,17 +81,19 @@
 	return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module
 }
 
-func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk_version string) {
+func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdkVersion string, compileDex bool) {
 	props := struct {
 		Name        *string
 		Jars        []string
 		Sdk_version *string
 		Installable *bool
+		Compile_dex *bool
 	}{}
 	props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver))
 	props.Jars = append(props.Jars, path)
-	props.Sdk_version = proptools.StringPtr(sdk_version)
+	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.Installable = proptools.BoolPtr(false)
+	props.Compile_dex = proptools.BoolPtr(compileDex)
 
 	mctx.CreateModule(ImportFactory, &props)
 }
@@ -124,13 +129,14 @@
 	// <apiver>/<scope>/<module>.jar
 	files := getPrebuiltFiles(mctx, p, "*.jar")
 
-	sdk_version := proptools.StringDefault(p.properties.Imports_sdk_version, "current")
+	sdkVersion := proptools.StringDefault(p.properties.Imports_sdk_version, "current")
+	compileDex := proptools.BoolDefault(p.properties.Imports_compile_dex, false)
 
 	for _, f := range files {
 		// create a Import module for each jar file
 		localPath := strings.TrimPrefix(f, mydir)
 		module, apiver, scope := parseJarPath(localPath)
-		createImport(mctx, module, scope, apiver, localPath, sdk_version)
+		createImport(mctx, module, scope, apiver, localPath, sdkVersion, compileDex)
 	}
 }
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index a5db56c..88cf468 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -419,6 +419,9 @@
 	//  $(location <label>): the path to the droiddoc_option_files with name <label>
 	Droiddoc_options []string
 
+	// is set to true, Metalava will allow framework SDK to contain annotations.
+	Annotations_enabled *bool
+
 	// a list of top-level directories containing files to merge qualifier annotations
 	// (i.e. those intended to be included in the stubs written) from.
 	Merge_annotations_dirs []string
@@ -1086,11 +1089,25 @@
 	return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
 }
 
+func childModuleVisibility(childVisibility []string) []string {
+	if childVisibility == nil {
+		// No child visibility set. The child will use the visibility of the sdk_library.
+		return nil
+	}
+
+	// Prepend an override to ignore the sdk_library's visibility, and rely on the child visibility.
+	var visibility []string
+	visibility = append(visibility, "//visibility:override")
+	visibility = append(visibility, childVisibility...)
+	return visibility
+}
+
 // Creates the implementation java library
 func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
-
 	moduleNamePtr := proptools.StringPtr(module.BaseModuleName())
 
+	visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
+
 	props := struct {
 		Name              *string
 		Visibility        []string
@@ -1098,7 +1115,7 @@
 		ConfigurationName *string
 	}{
 		Name:       proptools.StringPtr(module.implLibraryModuleName()),
-		Visibility: module.sdkLibraryProperties.Impl_library_visibility,
+		Visibility: visibility,
 		// Set the instrument property to ensure it is instrumented when instrumentation is required.
 		Instrument: true,
 
@@ -1145,12 +1162,7 @@
 	}{}
 
 	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
-
-	// If stubs_library_visibility is not set then the created module will use the
-	// visibility of this module.
-	visibility := module.sdkLibraryProperties.Stubs_library_visibility
-	props.Visibility = visibility
-
+	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
 	// sources are generated from the droiddoc
 	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
@@ -1159,6 +1171,11 @@
 	props.Patch_module = module.properties.Patch_module
 	props.Installable = proptools.BoolPtr(false)
 	props.Libs = module.sdkLibraryProperties.Stub_only_libs
+	// The stub-annotations library contains special versions of the annotations
+	// with CLASS retention policy, so that they're kept.
+	if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) {
+		props.Libs = append(props.Libs, "stub-annotations")
+	}
 	props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
 	props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
 	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
@@ -1193,6 +1210,7 @@
 		Arg_files                        []string
 		Args                             *string
 		Java_version                     *string
+		Annotations_enabled              *bool
 		Merge_annotations_dirs           []string
 		Merge_inclusion_annotations_dirs []string
 		Generate_stubs                   *bool
@@ -1225,12 +1243,7 @@
 	// * libs (static_libs/libs)
 
 	props.Name = proptools.StringPtr(name)
-
-	// If stubs_source_visibility is not set then the created module will use the
-	// visibility of this module.
-	visibility := module.sdkLibraryProperties.Stubs_source_visibility
-	props.Visibility = visibility
-
+	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
 	props.Srcs = append(props.Srcs, module.properties.Srcs...)
 	props.Sdk_version = module.deviceProperties.Sdk_version
 	props.System_modules = module.deviceProperties.System_modules
@@ -1243,6 +1256,7 @@
 	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
 	props.Java_version = module.properties.Java_version
 
+	props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled
 	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
 	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
 
@@ -2070,6 +2084,11 @@
 }
 
 // from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) BaseDir() string {
+	return "etc"
+}
+
+// from android.PrebuiltEtcModule
 func (module *sdkLibraryXml) SubDir() string {
 	return "permissions"
 }
diff --git a/rust/builder.go b/rust/builder.go
index 45cd268..654b1e6 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -31,9 +31,14 @@
 			Command: "$envVars $rustcCmd " +
 				"-C linker=${config.RustLinker} " +
 				"-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " +
-				"--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags",
+				"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
+				" && grep \"^$out:\" $out.d.raw > $out.d",
 			CommandDeps: []string{"$rustcCmd"},
 			// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
+			// Rustc emits unneeded dependency lines for the .d and input .rs files.
+			// Those extra lines cause ninja warning:
+			//     "warning: depfile has multiple output paths"
+			// For ninja, we keep/grep only the dependency rule for the rust $out file.
 			Deps:    blueprint.DepsGCC,
 			Depfile: "$out.d",
 		},
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 798fc40..b35f831 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -40,9 +40,9 @@
 }
 
 var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
-	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g' $template > $out",
+	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
 	CommandDeps: []string{"$template"},
-}, "name", "template", "extraConfigs", "outputFileName")
+}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase")
 
 func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
 	p := getTestConfig(ctx, prop)
@@ -107,15 +107,15 @@
 
 }
 
-func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) {
-	autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "")
+func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config, testInstallBase string) {
+	autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "", testInstallBase)
 }
 
-func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config) {
-	autogenTemplateWithNameAndOutputFile(ctx, name, output, template, configs, "")
+func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, testInstallBase string) {
+	autogenTemplateWithNameAndOutputFile(ctx, name, output, template, configs, "", testInstallBase)
 }
 
-func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string) {
+func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
 	var configStrings []string
 	for _, config := range configs {
 		configStrings = append(configStrings, config.Config())
@@ -128,26 +128,28 @@
 		Description: "test config",
 		Output:      output,
 		Args: map[string]string{
-			"name":           name,
-			"template":       template,
-			"extraConfigs":   extraConfigs,
-			"outputFileName": outputFileName,
+			"name":            name,
+			"template":        template,
+			"extraConfigs":    extraConfigs,
+			"outputFileName":  outputFileName,
+			"testInstallBase": testInstallBase,
 		},
 	})
 }
 
 func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
-	testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
+	testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, testInstallBase string) android.Path {
+
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), config)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), config, testInstallBase)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config)
+				autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config, testInstallBase)
 			} else {
-				autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config)
+				autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config, testInstallBase)
 			}
 		}
 		return autogenPath
@@ -161,9 +163,9 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName)
+			autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName, "")
 		} else {
-			autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName)
+			autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName, "")
 		}
 		return autogenPath
 	}
@@ -176,9 +178,9 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), configs)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), configs, "")
 		} else {
-			autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs)
+			autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs, "")
 		}
 		return autogenPath
 	}
@@ -191,12 +193,12 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil)
+				autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil, "")
 			} else {
-				autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil)
+				autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil, "")
 			}
 		}
 		return autogenPath
@@ -211,9 +213,9 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
 		} else {
-			autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil)
+			autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil, "")
 		}
 		return autogenPath
 	}
@@ -226,12 +228,12 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), config)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config)
+				autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config, "")
 			} else {
-				autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config)
+				autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config, "")
 			}
 		}
 		return autogenPath
@@ -245,9 +247,9 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
 		} else {
-			autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil)
+			autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil, "")
 		}
 		return autogenPath
 	}
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 67bcebb..c4b829d 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -19,6 +19,7 @@
 	"math/rand"
 	"os"
 	"path/filepath"
+	"syscall"
 	"time"
 
 	"android/soong/ui/metrics"
@@ -50,8 +51,25 @@
 	return cmdPath
 }
 
-func getRBEVars(ctx Context, config Config) map[string]string {
+func sockAddr(dir string) (string, error) {
+	maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
 	rand.Seed(time.Now().UnixNano())
+	base := fmt.Sprintf("reproxy_%v.sock", rand.Intn(1000))
+
+	name := filepath.Join(dir, base)
+	if len(name) < maxNameLen {
+		return name, nil
+	}
+
+	name = filepath.Join("/tmp", base)
+	if len(name) < maxNameLen {
+		return name, nil
+	}
+
+	return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
+}
+
+func getRBEVars(ctx Context, config Config) map[string]string {
 	vars := map[string]string{
 		"RBE_log_path":   config.rbeLogPath(),
 		"RBE_log_dir":    config.logDir(),
@@ -60,7 +78,12 @@
 		"RBE_output_dir": config.rbeStatsOutputDir(),
 	}
 	if config.StartRBE() {
-		vars["RBE_server_address"] = fmt.Sprintf("unix://%v/reproxy_%v.sock", absPath(ctx, config.TempDir()), rand.Intn(1000))
+		name, err := sockAddr(absPath(ctx, config.TempDir()))
+		if err != nil {
+			ctx.Fatalf("Error retrieving socket address: %v", err)
+			return nil
+		}
+		vars["RBE_server_address"] = fmt.Sprintf("unix://%v", name)
 	}
 	k, v := config.rbeAuth()
 	vars[k] = v