Merge "Introduce new Arm64 arch variant with dot product features"
diff --git a/android/api_levels.go b/android/api_levels.go
index b6296d8..0872066 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -73,6 +73,7 @@
 			"O-MR1": 27,
 			"P":     28,
 			"Q":     29,
+			"R":     30,
 		}
 		for i, codename := range config.PlatformVersionActiveCodenames() {
 			apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/arch.go b/android/arch.go
index 828f86e..4141138 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -23,6 +23,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -560,6 +561,15 @@
 	}
 }()
 
+var BuildArch = func() ArchType {
+	switch runtime.GOARCH {
+	case "amd64":
+		return X86_64
+	default:
+		panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
+	}
+}()
+
 var (
 	OsTypeList      []OsType
 	commonTargetMap = make(map[string]Target)
@@ -578,7 +588,7 @@
 
 	osArchTypeMap = map[OsType][]ArchType{
 		Linux:       []ArchType{X86, X86_64},
-		LinuxBionic: []ArchType{X86_64},
+		LinuxBionic: []ArchType{Arm64, X86_64},
 		Darwin:      []ArchType{X86_64},
 		Windows:     []ArchType{X86, X86_64},
 		Android:     []ArchType{Arm, Arm64, X86, X86_64},
@@ -698,13 +708,31 @@
 	}
 }
 
-func osMutator(mctx BottomUpMutatorContext) {
+func osMutator(bpctx blueprint.BottomUpMutatorContext) {
 	var module Module
 	var ok bool
-	if module, ok = mctx.Module().(Module); !ok {
+	if module, ok = bpctx.Module().(Module); !ok {
+		if bootstrap.IsBootstrapModule(bpctx.Module()) {
+			// Bootstrap Go modules are always the build OS or linux bionic.
+			config := bpctx.Config().(Config)
+			osNames := []string{config.BuildOSTarget.OsVariation()}
+			for _, hostCrossTarget := range config.Targets[LinuxBionic] {
+				if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType {
+					osNames = append(osNames, hostCrossTarget.OsVariation())
+				}
+			}
+			osNames = FirstUniqueStrings(osNames)
+			bpctx.CreateVariations(osNames...)
+		}
 		return
 	}
 
+	// Bootstrap Go module support above requires this mutator to be a
+	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
+	// filters out non-Soong modules.  Now that we've handled them, create a
+	// normal android.BottomUpMutatorContext.
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+
 	base := module.base()
 
 	if !base.ArchSpecific() {
@@ -828,13 +856,23 @@
 //
 // Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
 // but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
-func archMutator(mctx BottomUpMutatorContext) {
+func archMutator(bpctx blueprint.BottomUpMutatorContext) {
 	var module Module
 	var ok bool
-	if module, ok = mctx.Module().(Module); !ok {
+	if module, ok = bpctx.Module().(Module); !ok {
+		if bootstrap.IsBootstrapModule(bpctx.Module()) {
+			// Bootstrap Go modules are always the build architecture.
+			bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation())
+		}
 		return
 	}
 
+	// Bootstrap Go module support above requires this mutator to be a
+	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
+	// filters out non-Soong modules.  Now that we've handled them, create a
+	// normal android.BottomUpMutatorContext.
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+
 	base := module.base()
 
 	if !base.ArchSpecific() {
@@ -912,7 +950,7 @@
 	modules := mctx.CreateVariations(targetNames...)
 	for i, m := range modules {
 		addTargetProperties(m, targets[i], multiTargets, i == 0)
-		m.(Module).base().setArchProperties(mctx)
+		m.base().setArchProperties(mctx)
 	}
 }
 
@@ -1405,20 +1443,15 @@
 			//         key: value,
 			//     },
 			// },
-			// TODO(ccross): is this still necessary with native bridge?
 			if os.Class == Device {
-				if (arch.ArchType == X86 && (hasArmAbi(arch) ||
-					hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
-					(arch.ArchType == Arm &&
-						hasX86AndroidArch(ctx.Config().Targets[Android])) {
+				if arch.ArchType == X86 && (hasArmAbi(arch) ||
+					hasArmAndroidArch(ctx.Config().Targets[Android])) {
 					field := "Arm_on_x86"
 					prefix := "target.arm_on_x86"
 					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
-				if (arch.ArchType == X86_64 && (hasArmAbi(arch) ||
-					hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
-					(arch.ArchType == Arm &&
-						hasX8664AndroidArch(ctx.Config().Targets[Android])) {
+				if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
+					hasArmAndroidArch(ctx.Config().Targets[Android])) {
 					field := "Arm_on_x86_64"
 					prefix := "target.arm_on_x86_64"
 					m.appendProperties(ctx, genProps, targetProp, field, prefix)
@@ -1565,27 +1598,7 @@
 // hasArmArch returns true if targets has at least non-native_bridge arm Android arch
 func hasArmAndroidArch(targets []Target) bool {
 	for _, target := range targets {
-		if target.Os == Android && target.Arch.ArchType == Arm && target.NativeBridge == NativeBridgeDisabled {
-			return true
-		}
-	}
-	return false
-}
-
-// hasX86Arch returns true if targets has at least x86 Android arch
-func hasX86AndroidArch(targets []Target) bool {
-	for _, target := range targets {
-		if target.Os == Android && target.Arch.ArchType == X86 {
-			return true
-		}
-	}
-	return false
-}
-
-// hasX8664Arch returns true if targets has at least x86_64 Android arch
-func hasX8664AndroidArch(targets []Target) bool {
-	for _, target := range targets {
-		if target.Os == Android && target.Arch.ArchType == X86_64 {
+		if target.Os == Android && target.Arch.ArchType == Arm {
 			return true
 		}
 	}
diff --git a/android/config.go b/android/config.go
index a1e97c9..dd622e5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -35,6 +35,7 @@
 
 var Bool = proptools.Bool
 var String = proptools.String
+var StringDefault = proptools.StringDefault
 
 const FutureApiLevel = 10000
 
@@ -958,6 +959,10 @@
 	return String(c.config.productVariables.DeviceVndkVersion)
 }
 
+func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
+	return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
+}
+
 func (c *deviceConfig) PlatformVndkVersion() string {
 	return String(c.config.productVariables.Platform_vndk_version)
 }
@@ -1393,7 +1398,7 @@
 	if len(pair) == 2 {
 		return pair[0], pair[1]
 	} else {
-		reportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
+		ReportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
 		return "error-apex", "error-jar"
 	}
 }
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/makevars.go b/android/makevars.go
index 86f4b42..003a9df 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -234,7 +234,7 @@
 	}
 
 	ctx.VisitAllModules(func(m Module) {
-		if provider, ok := m.(ModuleMakeVarsProvider); ok {
+		if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() {
 			mctx := &makeVarsContext{
 				SingletonContext: ctx,
 			}
diff --git a/android/module.go b/android/module.go
index b689a87..5bc7a17 100644
--- a/android/module.go
+++ b/android/module.go
@@ -61,18 +61,44 @@
 // EarlyModuleContext provides methods that can be called early, as soon as the properties have
 // been parsed into the module and before any mutators have run.
 type EarlyModuleContext interface {
+	// Module returns the current module as a Module.  It should rarely be necessary, as the module already has a
+	// reference to itself.
 	Module() Module
+
+	// ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
+	// the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
 	ModuleName() string
+
+	// ModuleDir returns the path to the directory that contains the definition of the module.
 	ModuleDir() string
+
+	// ModuleType returns the name of the module type that was used to create the module, as specified in
+	// RegisterModuleType.
 	ModuleType() string
+
+	// BlueprintFile returns the name of the blueprint file that contains the definition of this
+	// module.
 	BlueprintsFile() string
 
+	// ContainsProperty returns true if the specified property name was set in the module definition.
 	ContainsProperty(name string) bool
+
+	// Errorf reports an error at the specified position of the module definition file.
 	Errorf(pos scanner.Position, fmt string, args ...interface{})
+
+	// ModuleErrorf reports an error at the line number of the module type in the module definition.
 	ModuleErrorf(fmt string, args ...interface{})
+
+	// PropertyErrorf reports an error at the line number of a property in the module definition.
 	PropertyErrorf(property, fmt string, args ...interface{})
+
+	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating
+	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
+	// has prevented the module from creating necessary data it can return early when Failed returns true.
 	Failed() bool
 
+	// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest.  The
+	// primary builder will be rerun whenever the specified files are modified.
 	AddNinjaFileDeps(deps ...string)
 
 	DeviceSpecific() bool
@@ -98,6 +124,8 @@
 	IsSymlink(path Path) bool
 	Readlink(path Path) string
 
+	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
+	// default SimpleNameInterface if Context.SetNameInterface was not called.
 	Namespace() *Namespace
 }
 
@@ -110,29 +138,109 @@
 
 	blueprintBaseModuleContext() blueprint.BaseModuleContext
 
+	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
 	OtherModuleName(m blueprint.Module) string
+
+	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
 	OtherModuleDir(m blueprint.Module) string
+
+	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
 	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
+
+	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
+	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
+	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+
+	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
+	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
 	OtherModuleExists(name string) bool
+
+	// OtherModuleDependencyVariantExists returns true if a module with the
+	// specified name and variant exists. The variant must match the given
+	// variations. It must also match all the non-local variations of the current
+	// module. In other words, it checks for the module AddVariationDependencies
+	// would add a dependency on with the same arguments.
 	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
+
+	// OtherModuleReverseDependencyVariantExists returns true if a module with the
+	// specified name exists with the same variations as the current module. In
+	// other words, it checks for the module AddReverseDependency would add a
+	// dependency on with the same argument.
 	OtherModuleReverseDependencyVariantExists(name string) bool
+
+	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
 	OtherModuleType(m blueprint.Module) string
 
 	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
+
+	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
+	// none exists.  It panics if the dependency does not have the specified tag.  It skips any
+	// dependencies that are not an android.Module.
 	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+
+	// GetDirectDep returns the Module and DependencyTag for the  direct dependency with the specified
+	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns
+	// the first DependencyTag.  It skips any dependencies that are not an android.Module.
 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
 
+	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
 	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+
+	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.  It skips any
+	// dependencies that are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
 	VisitDirectDeps(visit func(Module))
+
 	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
+
+	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
+	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
+	// OtherModuleDependencyTag will return a different tag for each.  It skips any
+	// dependencies that are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit function, it may be
+	// invalidated by future mutators.
 	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
 	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
 	VisitDepsDepthFirst(visit func(Module))
 	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
 	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
+
+	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
+	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
+	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
+	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips
+	// any dependencies that are not an android.Module.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
 	WalkDeps(visit func(Module, Module) bool)
+
+	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
+	// tree in top down order.  visit may be called multiple times for the same (child, parent)
+	// pair if there are multiple direct dependencies between the child and parent with different
+	// tags.  OtherModuleDependencyTag will return the tag for the currently visited
+	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down
+	// to child.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
 	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
+
 	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
 	// and returns a top-down dependency path from a start module to current child module.
 	GetWalkPath() []Module
@@ -198,7 +306,7 @@
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
-	InstallForceOS() *OsType
+	InstallForceOS() (*OsType, *ArchType)
 
 	RequiredModuleNames() []string
 	HostRequiredModuleNames() []string
@@ -216,10 +324,26 @@
 	// additional dependencies.
 	Phony(phony string, deps ...Path)
 
+	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
+	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
+	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
+	// only done once for all variants of a module.
 	PrimaryModule() Module
+
+	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
+	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
+	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
+	// singleton actions that are only done once for all variants of a module.
 	FinalModule() Module
+
+	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
+	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
+	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
+	// data modified by the current mutator.
 	VisitAllModuleVariants(visit func(Module))
 
+	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
+	// but do not exist.
 	GetMissingDependencies() []string
 }
 
@@ -247,6 +371,7 @@
 	Disable()
 	Enabled() bool
 	Target() Target
+	Owner() string
 	InstallInData() bool
 	InstallInTestcases() bool
 	InstallInSanitizerDir() bool
@@ -254,10 +379,12 @@
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
-	InstallForceOS() *OsType
+	InstallForceOS() (*OsType, *ArchType)
 	SkipInstall()
 	IsSkipInstall() bool
 	MakeUninstallable()
+	ReplacedByPrebuilt()
+	IsReplacedByPrebuilt() bool
 	ExportedToMake() bool
 	InitRc() Paths
 	VintfFragments() Paths
@@ -490,14 +617,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
@@ -550,6 +669,9 @@
 
 	SkipInstall bool `blueprint:"mutated"`
 
+	// Whether the module has been replaced by a prebuilt
+	ReplacedByPrebuilt bool `blueprint:"mutated"`
+
 	// Disabled by mutators. If set to true, it overrides Enabled property.
 	ForcedDisabled bool `blueprint:"mutated"`
 
@@ -566,6 +688,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 +793,8 @@
 
 	m.AddProperties(
 		&base.nameProperties,
-		&base.commonProperties)
+		&base.commonProperties,
+		&base.distProperties)
 
 	initProductVariableModule(m)
 
@@ -752,6 +885,7 @@
 
 	nameProperties          nameProperties
 	commonProperties        commonProperties
+	distProperties          distProperties
 	variableProperties      interface{}
 	hostAndDeviceProperties hostAndDeviceProperties
 	generalProperties       []interface{}
@@ -861,13 +995,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
 	}
 }
 
@@ -1063,6 +1197,15 @@
 	m.SkipInstall()
 }
 
+func (m *ModuleBase) ReplacedByPrebuilt() {
+	m.commonProperties.ReplacedByPrebuilt = true
+	m.SkipInstall()
+}
+
+func (m *ModuleBase) IsReplacedByPrebuilt() bool {
+	return m.commonProperties.ReplacedByPrebuilt
+}
+
 func (m *ModuleBase) ExportedToMake() bool {
 	return m.commonProperties.NamespaceExportedToMake
 }
@@ -1116,8 +1259,8 @@
 	return false
 }
 
-func (m *ModuleBase) InstallForceOS() *OsType {
-	return nil
+func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) {
+	return nil, nil
 }
 
 func (m *ModuleBase) Owner() string {
@@ -1344,20 +1487,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.")
 		}
 	}
@@ -2017,7 +2160,7 @@
 	return m.module.InstallBypassMake()
 }
 
-func (m *moduleContext) InstallForceOS() *OsType {
+func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
 	return m.module.InstallForceOS()
 }
 
@@ -2246,7 +2389,7 @@
 		return nil
 	}
 	if len(paths) > 1 {
-		reportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
+		ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
 			pathContextName(ctx, module))
 		return nil
 	}
diff --git a/android/mutator.go b/android/mutator.go
index 40e61de..738b2ba 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -75,6 +75,7 @@
 type RegisterMutatorsContext interface {
 	TopDown(name string, m TopDownMutator) MutatorHandle
 	BottomUp(name string, m BottomUpMutator) MutatorHandle
+	BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
 }
 
 type RegisterMutatorFunc func(RegisterMutatorsContext)
@@ -143,9 +144,9 @@
 }
 
 func registerArchMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("os", osMutator).Parallel()
+	ctx.BottomUpBlueprint("os", osMutator).Parallel()
 	ctx.BottomUp("image", imageMutator).Parallel()
-	ctx.BottomUp("arch", archMutator).Parallel()
+	ctx.BottomUpBlueprint("arch", archMutator).Parallel()
 }
 
 var preDeps = []RegisterMutatorFunc{
@@ -178,15 +179,24 @@
 	finalDeps = append(finalDeps, f)
 }
 
+type BaseMutatorContext interface {
+	BaseModuleContext
+
+	// MutatorName returns the name that this mutator was registered with.
+	MutatorName() string
+
+	// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
+	// AddDependency or OtherModuleName until after this mutator pass is complete.
+	Rename(name string)
+}
+
 type TopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
-	BaseModuleContext
+	BaseMutatorContext
 
-	MutatorName() string
-
-	Rename(name string)
-
+	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
+	// the specified property structs to it as if the properties were set in a blueprint file.
 	CreateModule(ModuleFactory, ...interface{}) Module
 }
 
@@ -198,24 +208,97 @@
 type BottomUpMutator func(BottomUpMutatorContext)
 
 type BottomUpMutatorContext interface {
-	BaseModuleContext
+	BaseMutatorContext
 
-	MutatorName() string
-
-	Rename(name string)
-
+	// AddDependency adds a dependency to the given module.
+	// Does not affect the ordering of the current mutator pass, but will be ordered
+	// correctly for all future mutator passes.
 	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
+
+	// AddReverseDependency adds a dependency from the destination to the given module.
+	// Does not affect the ordering of the current mutator pass, but will be ordered
+	// correctly for all future mutator passes.  All reverse dependencies for a destination module are
+	// collected until the end of the mutator pass, sorted by name, and then appended to the destination
+	// module's dependency list.
 	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
+
+	// CreateVariations splits  a module into multiple variants, one for each name in the variationNames
+	// parameter.  It returns a list of new modules in the same order as the variationNames
+	// list.
+	//
+	// If any of the dependencies of the module being operated on were already split
+	// by calling CreateVariations with the same name, the dependency will automatically
+	// be updated to point the matching variant.
+	//
+	// If a module is split, and then a module depending on the first module is not split
+	// when the Mutator is later called on it, the dependency of the depending module will
+	// automatically be updated to point to the first variant.
 	CreateVariations(...string) []Module
+
+	// CreateLocationVariations splits a module into multiple variants, one for each name in the variantNames
+	// parameter.  It returns a list of new modules in the same order as the variantNames
+	// list.
+	//
+	// Local variations do not affect automatic dependency resolution - dependencies added
+	// to the split module via deps or DynamicDependerModule must exactly match a variant
+	// that contains all the non-local variations.
 	CreateLocalVariations(...string) []Module
+
+	// SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
+	// with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
 	SetDependencyVariation(string)
+
+	// SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
+	// during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
 	SetDefaultDependencyVariation(*string)
+
+	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
+	// argument to select which variant of the dependency to use.  A variant of the dependency must
+	// exist that matches the all of the non-local variations of the current module, plus the variations
+	// argument.
 	AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+
+	// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
+	// variations argument to select which variant of the dependency to use.  A variant of the
+	// dependency must exist that matches the variations argument, but may also have other variations.
+	// For any unspecified variation the first variant will be used.
+	//
+	// Unlike AddVariationDependencies, the variations of the current module are ignored - the
+	// dependency only needs to match the supplied variations.
 	AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+
+	// AddInterVariantDependency adds a dependency between two variants of the same module.  Variants are always
+	// ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change
+	// that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
+	// WalkDeps, etc.
 	AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
+
+	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
+	// specified name with the current variant of this module.  Replacements don't take effect until
+	// after the mutator pass is finished.
 	ReplaceDependencies(string)
+
+	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
+	// specified name with the current variant of this module as long as the supplied predicate returns
+	// true.
+	//
+	// Replacements don't take effect until after the mutator pass is finished.
 	ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate)
+
+	// AliasVariation takes a variationName that was passed to CreateVariations for this module,
+	// and creates an alias from the current variant (before the mutator has run) to the new
+	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
+	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
+	// be used to add dependencies on the newly created variant using the variant map from
+	// before CreateVariations was run.
 	AliasVariation(variationName string)
+
+	// CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this
+	// module, and creates an alias from a new fromVariationName variant the toVariationName
+	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
+	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
+	// be used to add dependencies on the toVariationName variant using the fromVariationName
+	// variant.
 	CreateAliasVariation(fromVariationName, toVariationName string)
 }
 
@@ -225,16 +308,21 @@
 	finalPhase bool
 }
 
+func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
+	finalPhase bool) BottomUpMutatorContext {
+
+	return &bottomUpMutatorContext{
+		bp:                ctx,
+		baseModuleContext: a.base().baseModuleContextFactory(ctx),
+		finalPhase:        finalPhase,
+	}
+}
+
 func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
 	finalPhase := x.finalPhase
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			actx := &bottomUpMutatorContext{
-				bp:                ctx,
-				baseModuleContext: a.base().baseModuleContextFactory(ctx),
-				finalPhase:        finalPhase,
-			}
-			m(actx)
+			m(bottomUpMutatorContextFactory(ctx, a, finalPhase))
 		}
 	}
 	mutator := &mutator{name: name, bottomUpMutator: f}
@@ -242,6 +330,12 @@
 	return mutator
 }
 
+func (x *registerMutatorsContext) BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle {
+	mutator := &mutator{name: name, bottomUpMutator: m}
+	x.mutators = append(x.mutators, mutator)
+	return mutator
+}
+
 func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle {
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
diff --git a/android/neverallow.go b/android/neverallow.go
index aaea920..8b8e1ac 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -199,6 +199,7 @@
 		"prebuilts/ndk",
 		"tools/test/graphicsbenchmark/apps/sample_app",
 		"tools/test/graphicsbenchmark/functional_tests/java",
+		"vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests",
 	}
 
 	platformVariantPropertiesAllowedList := []string{
@@ -274,6 +275,10 @@
 			continue
 		}
 
+		if !n.appliesToBootclasspathJar(ctx) {
+			continue
+		}
+
 		ctx.ModuleErrorf("violates " + n.String())
 	}
 }
@@ -332,6 +337,18 @@
 	return ".regexp(" + m.re.String() + ")"
 }
 
+type notInListMatcher struct {
+	allowed []string
+}
+
+func (m *notInListMatcher) Test(value string) bool {
+	return !InList(value, m.allowed)
+}
+
+func (m *notInListMatcher) String() string {
+	return ".not-in-list(" + strings.Join(m.allowed, ",") + ")"
+}
+
 type isSetMatcher struct{}
 
 func (m *isSetMatcher) Test(value string) bool {
@@ -363,6 +380,8 @@
 
 	NotModuleType(types ...string) Rule
 
+	BootclasspathJar() Rule
+
 	With(properties, value string) Rule
 
 	WithMatcher(properties string, matcher ValueMatcher) Rule
@@ -390,6 +409,8 @@
 
 	props       []ruleProperty
 	unlessProps []ruleProperty
+
+	onlyBootclasspathJar bool
 }
 
 // Create a new NeverAllow rule.
@@ -465,6 +486,11 @@
 	return r
 }
 
+func (r *rule) BootclasspathJar() Rule {
+	r.onlyBootclasspathJar = true
+	return r
+}
+
 func (r *rule) String() string {
 	s := "neverallow"
 	for _, v := range r.paths {
@@ -491,6 +517,9 @@
 	for _, v := range r.osClasses {
 		s += " os:" + v.String()
 	}
+	if r.onlyBootclasspathJar {
+		s += " inBcp"
+	}
 	if len(r.reason) != 0 {
 		s += " which is restricted because " + r.reason
 	}
@@ -519,6 +548,14 @@
 	return matches
 }
 
+func (r *rule) appliesToBootclasspathJar(ctx BottomUpMutatorContext) bool {
+	if !r.onlyBootclasspathJar {
+		return true
+	}
+
+	return InList(ctx.ModuleName(), ctx.Config().BootJars())
+}
+
 func (r *rule) appliesToOsClass(osClass OsClass) bool {
 	if len(r.osClasses) == 0 {
 		return true
@@ -555,6 +592,10 @@
 	return &regexMatcher{r}
 }
 
+func NotInList(allowed []string) ValueMatcher {
+	return &notInListMatcher{allowed}
+}
+
 // assorted utils
 
 func cleanPaths(paths []string) []string {
diff --git a/android/paths.go b/android/paths.go
index 65f129c..3825d45 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -61,7 +61,7 @@
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
-	InstallForceOS() *OsType
+	InstallForceOS() (*OsType, *ArchType)
 }
 
 var _ ModuleInstallPathContext = ModuleContext(nil)
@@ -86,13 +86,13 @@
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
 func reportPathError(ctx PathContext, err error) {
-	reportPathErrorf(ctx, "%s", err.Error())
+	ReportPathErrorf(ctx, "%s", err.Error())
 }
 
-// reportPathErrorf will register an error with the attached context. It
+// ReportPathErrorf will register an error with the attached context. It
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
-func reportPathErrorf(ctx PathContext, format string, args ...interface{}) {
+func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
 	if mctx, ok := ctx.(moduleErrorf); ok {
 		mctx.ModuleErrorf(format, args...)
 	} else if ectx, ok := ctx.(errorfContext); ok {
@@ -155,7 +155,7 @@
 	if path, ok := p.(genPathProvider); ok {
 		return path.genPathWithExt(ctx, subdir, ext)
 	}
-	reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
+	ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
 	return PathForModuleGen(ctx)
 }
 
@@ -165,7 +165,7 @@
 	if path, ok := p.(objPathProvider); ok {
 		return path.objPathWithExt(ctx, subdir, ext)
 	}
-	reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
+	ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
 	return PathForModuleObj(ctx)
 }
 
@@ -176,7 +176,7 @@
 	if path, ok := p.(resPathProvider); ok {
 		return path.resPathWithName(ctx, name)
 	}
-	reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
+	ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
 	return PathForModuleRes(ctx)
 }
 
@@ -416,9 +416,9 @@
 	} else {
 		p := pathForModuleSrc(ctx, s)
 		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
-			reportPathErrorf(ctx, "%s: %s", p, err.Error())
+			ReportPathErrorf(ctx, "%s: %s", p, err.Error())
 		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
-			reportPathErrorf(ctx, "module source path %q does not exist", p)
+			ReportPathErrorf(ctx, "module source path %q does not exist", p)
 		}
 
 		if InList(p.String(), expandedExcludes) {
@@ -445,7 +445,7 @@
 		}
 		path := filepath.Clean(p)
 		if !strings.HasPrefix(path, prefix) {
-			reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
+			ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
 			continue
 		}
 
@@ -801,7 +801,7 @@
 	}
 
 	if pathtools.IsGlob(path.String()) {
-		reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
 	}
 
 	if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
@@ -813,9 +813,9 @@
 			modCtx.AddMissingDependencies([]string{path.String()})
 		}
 	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
-		reportPathErrorf(ctx, "%s: %s", path, err.Error())
+		ReportPathErrorf(ctx, "%s: %s", path, err.Error())
 	} else if !exists && !ctx.Config().testAllowNonExistentPaths {
-		reportPathErrorf(ctx, "source path %q does not exist", path)
+		ReportPathErrorf(ctx, "source path %q does not exist", path)
 	}
 	return path
 }
@@ -831,7 +831,7 @@
 	}
 
 	if pathtools.IsGlob(path.String()) {
-		reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
 		return OptionalPath{}
 	}
 
@@ -876,17 +876,17 @@
 	if srcPath, ok := path.(SourcePath); ok {
 		relDir = srcPath.path
 	} else {
-		reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
+		ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
 		return OptionalPath{}
 	}
 	dir := filepath.Join(p.config.srcDir, p.path, relDir)
 	// Use Glob so that we are run again if the directory is added.
 	if pathtools.IsGlob(dir) {
-		reportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
+		ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
 	}
 	paths, err := ctx.GlobWithDeps(dir, nil)
 	if err != nil {
-		reportPathErrorf(ctx, "glob: %s", err.Error())
+		ReportPathErrorf(ctx, "glob: %s", err.Error())
 		return OptionalPath{}
 	}
 	if len(paths) == 0 {
@@ -977,7 +977,7 @@
 // ReplaceExtension creates a new OutputPath with the extension replaced with ext.
 func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
 	if strings.Contains(ext, "/") {
-		reportPathErrorf(ctx, "extension %q cannot contain /", ext)
+		ReportPathErrorf(ctx, "extension %q cannot contain /", ext)
 	}
 	ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
 	ret.rel = pathtools.ReplaceExtension(p.rel, ext)
@@ -1030,10 +1030,10 @@
 		}
 		return nil
 	} else if len(paths) == 0 {
-		reportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
+		ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
 		return nil
 	} else if len(paths) > 1 {
-		reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
+		ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
 	}
 	return paths[0]
 }
@@ -1278,12 +1278,17 @@
 // module appended with paths...
 func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
 	os := ctx.Os()
-	if forceOS := ctx.InstallForceOS(); forceOS != nil {
+	arch := ctx.Arch().ArchType
+	forceOS, forceArch := ctx.InstallForceOS()
+	if forceOS != nil {
 		os = *forceOS
 	}
+	if forceArch != nil {
+		arch = *forceArch
+	}
 	partition := modulePartition(ctx, os)
 
-	ret := pathForInstall(ctx, os, partition, ctx.Debug(), pathComponents...)
+	ret := pathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
 
 	if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
 		ret = ret.ToMakePath()
@@ -1292,7 +1297,7 @@
 	return ret
 }
 
-func pathForInstall(ctx PathContext, os OsType, partition string, debug bool,
+func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool,
 	pathComponents ...string) InstallPath {
 
 	var outPaths []string
@@ -1300,15 +1305,21 @@
 	if os.Class == Device {
 		outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
 	} else {
-		switch os {
-		case Linux:
-			outPaths = []string{"host", "linux-x86", partition}
-		case LinuxBionic:
-			// TODO: should this be a separate top level, or shared with linux-x86?
-			outPaths = []string{"host", "linux_bionic-x86", partition}
-		default:
-			outPaths = []string{"host", os.String() + "-x86", partition}
+		osName := os.String()
+		if os == Linux {
+			// instead of linux_glibc
+			osName = "linux"
 		}
+		// SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
+		// and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem
+		// to have a plan to fix it (see the comment in build/make/core/envsetup.mk).
+		// Let's keep using x86 for the existing cases until we have a need to support
+		// other architectures.
+		archName := arch.String()
+		if os.Class == Host && (arch == X86_64 || arch == Common) {
+			archName = "x86"
+		}
+		outPaths = []string{"host", osName + "-" + archName, partition}
 	}
 	if debug {
 		outPaths = append([]string{"debug"}, outPaths...)
@@ -1447,7 +1458,7 @@
 
 func PathForPhony(ctx PathContext, phony string) WritablePath {
 	if strings.ContainsAny(phony, "$/") {
-		reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
+		ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
 	}
 	return PhonyPath{basePath{phony, ctx.Config(), ""}}
 }
@@ -1513,7 +1524,7 @@
 func Rel(ctx PathContext, basePath string, targetPath string) string {
 	rel, isRel := MaybeRel(ctx, basePath, targetPath)
 	if !isRel {
-		reportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
+		ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
 		return ""
 	}
 	return rel
diff --git a/android/paths_test.go b/android/paths_test.go
index a9cd22b..d099f65 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -207,6 +207,7 @@
 	inRecovery     bool
 	inRoot         bool
 	forceOS        *OsType
+	forceArch      *ArchType
 }
 
 func (m moduleInstallPathContextImpl) Config() Config {
@@ -243,8 +244,8 @@
 	return false
 }
 
-func (m moduleInstallPathContextImpl) InstallForceOS() *OsType {
-	return m.forceOS
+func (m moduleInstallPathContextImpl) InstallForceOS() (*OsType, *ArchType) {
+	return m.forceOS, m.forceArch
 }
 
 func pathTestConfig(buildDir string) Config {
@@ -254,8 +255,8 @@
 func TestPathForModuleInstall(t *testing.T) {
 	testConfig := pathTestConfig("")
 
-	hostTarget := Target{Os: Linux}
-	deviceTarget := Target{Os: Android}
+	hostTarget := Target{Os: Linux, Arch: Arch{ArchType: X86}}
+	deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
 
 	testCases := []struct {
 		name string
@@ -635,6 +636,7 @@
 				},
 				inTestcases: true,
 				forceOS:     &Linux,
+				forceArch:   &X86,
 			},
 			in:  []string{"my_test", "my_test_bin"},
 			out: "host/linux-x86/testcases/my_test/my_test_bin",
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 269ad5d..734871b 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -253,7 +253,7 @@
 			p := m.(PrebuiltInterface).Prebuilt()
 			if p.usePrebuilt(ctx, s) {
 				p.properties.UsePrebuilt = true
-				s.SkipInstall()
+				s.ReplacedByPrebuilt()
 			}
 		})
 	}
diff --git a/android/test_suites.go b/android/test_suites.go
index 79d0fbc..34e487e 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -60,7 +60,7 @@
 	for _, module := range SortedStringKeys(files) {
 		installedPaths = append(installedPaths, files[module]...)
 	}
-	testCasesDir := pathForInstall(ctx, BuildOs, "testcases", false).ToMakePath()
+	testCasesDir := pathForInstall(ctx, BuildOs, X86, "testcases", false).ToMakePath()
 
 	outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
 	rule := NewRuleBuilder()
diff --git a/android/testing.go b/android/testing.go
index 8a9134c..8ea4168 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -187,19 +187,21 @@
 	}
 }
 
-func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
+func maybeBuildParamsFromRule(provider testBuildProvider, rule string) (TestingBuildParams, []string) {
+	var searchedRules []string
 	for _, p := range provider.BuildParamsForTests() {
+		searchedRules = append(searchedRules, p.Rule.String())
 		if strings.Contains(p.Rule.String(), rule) {
-			return newTestingBuildParams(provider, p)
+			return newTestingBuildParams(provider, p), searchedRules
 		}
 	}
-	return TestingBuildParams{}
+	return TestingBuildParams{}, searchedRules
 }
 
 func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
-	p := maybeBuildParamsFromRule(provider, rule)
+	p, searchRules := maybeBuildParamsFromRule(provider, rule)
 	if p.Rule == nil {
-		panic(fmt.Errorf("couldn't find rule %q", rule))
+		panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules))
 	}
 	return p
 }
@@ -275,7 +277,8 @@
 // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Returns an empty
 // BuildParams if no rule is found.
 func (m TestingModule) MaybeRule(rule string) TestingBuildParams {
-	return maybeBuildParamsFromRule(m.module, rule)
+	r, _ := maybeBuildParamsFromRule(m.module, rule)
+	return r
 }
 
 // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Panics if no rule is found.
@@ -328,7 +331,8 @@
 // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Returns an empty
 // BuildParams if no rule is found.
 func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams {
-	return maybeBuildParamsFromRule(s.provider, rule)
+	r, _ := maybeBuildParamsFromRule(s.provider, rule)
+	return r
 }
 
 // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Panics if no rule is found.
diff --git a/android/variable.go b/android/variable.go
index 1f21f34..53f081e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -166,13 +166,14 @@
 	Platform_min_supported_target_sdk_version *string  `json:",omitempty"`
 	Platform_base_os                          *string  `json:",omitempty"`
 
-	DeviceName              *string  `json:",omitempty"`
-	DeviceArch              *string  `json:",omitempty"`
-	DeviceArchVariant       *string  `json:",omitempty"`
-	DeviceCpuVariant        *string  `json:",omitempty"`
-	DeviceAbi               []string `json:",omitempty"`
-	DeviceVndkVersion       *string  `json:",omitempty"`
-	DeviceSystemSdkVersions []string `json:",omitempty"`
+	DeviceName                            *string  `json:",omitempty"`
+	DeviceArch                            *string  `json:",omitempty"`
+	DeviceArchVariant                     *string  `json:",omitempty"`
+	DeviceCpuVariant                      *string  `json:",omitempty"`
+	DeviceAbi                             []string `json:",omitempty"`
+	DeviceVndkVersion                     *string  `json:",omitempty"`
+	DeviceCurrentApiLevelForVendorModules *string  `json:",omitempty"`
+	DeviceSystemSdkVersions               []string `json:",omitempty"`
 
 	DeviceSecondaryArch        *string  `json:",omitempty"`
 	DeviceSecondaryArchVariant *string  `json:",omitempty"`
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/androidmk.go b/apex/androidmk.go
index 5c6d6cc..1b53a67 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -36,7 +36,9 @@
 	return a.androidMkForType()
 }
 
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string,
+	apexAndroidMkData android.AndroidMkData) []string {
+
 	// apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property.
 	// An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName>
 	// In many cases, the two names are the same, but could be different in general.
@@ -108,6 +110,9 @@
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 		}
 		fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName)
+		if fi.module != nil && fi.module.Owner() != "" {
+			fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.module.Owner())
+		}
 		// /apex/<apex_name>/{lib|framework|...}
 		pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir)
 		var modulePath string
@@ -233,6 +238,17 @@
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem())
 			if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
 				if a.primaryApexType {
+					// To install companion files (init_rc, vintf_fragments)
+					// Copy some common properties of apexBundle to apex_manifest
+					commonProperties := []string{
+						"LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+					}
+					for _, name := range commonProperties {
+						if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok {
+							fmt.Fprintln(w, name+" := "+strings.Join(value, " "))
+						}
+					}
+
 					// Make apex_manifest.pb module for this APEX to override all other
 					// modules in the APEXes being overridden by this APEX
 					var patterns []string
@@ -291,7 +307,7 @@
 			apexType := a.properties.ApexType
 			if a.installable() {
 				apexName := proptools.StringDefault(a.properties.Apex_name, name)
-				moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir)
+				moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir, data)
 			}
 
 			if apexType == flattenedApex {
diff --git a/apex/apex.go b/apex/apex.go
index 84a1e75..8e35e07 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"
@@ -41,6 +42,9 @@
 	imageApexType     = "image"
 	zipApexType       = "zip"
 	flattenedApexType = "flattened"
+
+	ext4FsType = "ext4"
+	f2fsFsType = "f2fs"
 )
 
 type dependencyTag struct {
@@ -63,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()
 
@@ -95,6 +100,13 @@
 	//
 	// Module separator
 	//
+	m["com.android.appsearch"] = []string{
+		"icing-java-proto-lite",
+		"libprotobuf-java-lite",
+	}
+	//
+	// Module separator
+	//
 	m["com.android.bluetooth.updatable"] = []string{
 		"android.hardware.audio.common@5.0",
 		"android.hardware.bluetooth.a2dp@1.0",
@@ -177,6 +189,19 @@
 	//
 	// Module separator
 	//
+	m["com.android.extservices"] = []string{
+		"error_prone_annotations",
+		"ExtServices-core",
+		"ExtServices",
+		"libtextclassifier-java",
+		"libz_current",
+		"textclassifier-statsd",
+		"TextClassifierNotificationLibNoManifest",
+		"TextClassifierServiceLibNoManifest",
+	}
+	//
+	// Module separator
+	//
 	m["com.android.neuralnetworks"] = []string{
 		"android.hardware.neuralnetworks@1.0",
 		"android.hardware.neuralnetworks@1.1",
@@ -292,7 +317,6 @@
 		"libpdx_headers",
 		"libpdx_uds",
 		"libprocinfo",
-		"libsonivox",
 		"libspeexresampler",
 		"libspeexresampler",
 		"libstagefright_esds",
@@ -329,6 +353,7 @@
 		"android.hardware.configstore@1.1",
 		"android.hardware.graphics.allocator@2.0",
 		"android.hardware.graphics.allocator@3.0",
+		"android.hardware.graphics.allocator@4.0",
 		"android.hardware.graphics.bufferqueue@1.0",
 		"android.hardware.graphics.bufferqueue@2.0",
 		"android.hardware.graphics.common-ndk_platform",
@@ -341,6 +366,7 @@
 		"android.hardware.graphics.mapper@4.0",
 		"android.hardware.media.bufferpool@2.0",
 		"android.hardware.media.c2@1.0",
+		"android.hardware.media.c2@1.1",
 		"android.hardware.media.omx@1.0",
 		"android.hardware.media@1.0",
 		"android.hardware.media@1.0",
@@ -434,6 +460,7 @@
 		"libpdx_headers",
 		"libscudo_wrapper",
 		"libsfplugin_ccodec_utils",
+		"libspeexresampler",
 		"libstagefright_amrnb_common",
 		"libstagefright_amrnbdec",
 		"libstagefright_amrnbenc",
@@ -476,6 +503,8 @@
 	// Module separator
 	//
 	m["com.android.permission"] = []string{
+		"car-ui-lib",
+		"iconloader",
 		"kotlin-annotations",
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
@@ -485,6 +514,17 @@
 		"kotlinx-coroutines-core",
 		"kotlinx-coroutines-core-nodeps",
 		"permissioncontroller-statsd",
+		"GooglePermissionController",
+		"PermissionController",
+		"SettingsLibActionBarShadow",
+		"SettingsLibAppPreference",
+		"SettingsLibBarChartPreference",
+		"SettingsLibLayoutPreference",
+		"SettingsLibProgressBar",
+		"SettingsLibSearchWidget",
+		"SettingsLibSettingsTheme",
+		"SettingsLibRestrictedLockUtils",
+		"SettingsLibHelpUtils",
 	}
 	//
 	// Module separator
@@ -643,6 +683,55 @@
 	return m
 }
 
+// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
+// Adding code to the bootclasspath in new packages will cause issues on module update.
+func qModulesPackages() map[string][]string {
+	return map[string][]string{
+		"com.android.conscrypt": []string{
+			"android.net.ssl",
+			"com.android.org.conscrypt",
+		},
+		"com.android.media": []string{
+			"android.media",
+		},
+	}
+}
+
+// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
+// Adding code to the bootclasspath in new packages will cause issues on module update.
+func rModulesPackages() map[string][]string {
+	return map[string][]string{
+		"com.android.mediaprovider": []string{
+			"android.provider",
+		},
+		"com.android.permission": []string{
+			"android.permission",
+			"android.app.role",
+			"com.android.permission",
+			"com.android.role",
+		},
+		"com.android.sdkext": []string{
+			"android.os.ext",
+		},
+		"com.android.os.statsd": []string{
+			"android.app",
+			"android.os",
+			"android.util",
+			"com.android.internal.statsd",
+			"com.android.server.stats",
+		},
+		"com.android.wifi": []string{
+			"com.android.server.wifi",
+			"com.android.wifi.x",
+			"android.hardware.wifi",
+			"android.net.wifi",
+		},
+		"com.android.tethering": []string{
+			"android.net",
+		},
+	}
+}
+
 func init() {
 	android.RegisterModuleType("apex", BundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -660,6 +749,24 @@
 		sort.Strings(*apexFileContextsInfos)
 		ctx.Strict("APEX_FILE_CONTEXTS_INFOS", strings.Join(*apexFileContextsInfos, " "))
 	})
+
+	android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...)
+	android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...)
+}
+
+func createApexPermittedPackagesRules(modules_packages map[string][]string) []android.Rule {
+	rules := make([]android.Rule, 0, len(modules_packages))
+	for module_name, module_packages := range modules_packages {
+		permitted_packages_rule := android.NeverAllow().
+			BootclasspathJar().
+			With("apex_available", module_name).
+			WithMatcher("permitted_packages", android.NotInList(module_packages)).
+			Because("jars that are part of the " + module_name +
+				" module may only allow these packages: " + strings.Join(module_packages, ",") +
+				". Please jarjar or move code around.")
+		rules = append(rules, permitted_packages_rule)
+	}
+	return rules
 }
 
 func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
@@ -747,18 +854,6 @@
 	if am, ok := mctx.Module().(android.ApexModule); ok {
 		availableToPlatform := am.AvailableFor(android.AvailableToPlatform)
 
-		// In a rare case when a lib is marked as available only to an apex
-		// but the apex doesn't exist. This can happen in a partial manifest branch
-		// like master-art. Currently, libstatssocket in the stats APEX is causing
-		// this problem.
-		// Include the lib in platform because the module SDK that ought to provide
-		// it doesn't exist, so it would otherwise be left out completely.
-		// TODO(b/154888298) remove this by adding those libraries in module SDKS and skipping
-		// this check for libraries provided by SDKs.
-		if !availableToPlatform && !android.InAnyApex(am.Name()) {
-			availableToPlatform = true
-		}
-
 		// If any of the dep is not available to platform, this module is also considered
 		// as being not available to platform even if it has "//apex_available:platform"
 		mctx.VisitDirectDeps(func(child android.Module) {
@@ -970,6 +1065,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
 
@@ -1040,6 +1138,10 @@
 	// Should be only used in non-system apexes (e.g. vendor: true).
 	// Default is false.
 	Use_vndk_as_stable *bool
+
+	// The type of filesystem to use for an image apex. Either 'ext4' or 'f2fs'.
+	// Default 'ext4'.
+	Payload_fs_type *string
 }
 
 type apexTargetBundleProperties struct {
@@ -1189,6 +1291,8 @@
 	overriddenPackageName   string           // only for apps
 
 	isJniLib bool
+
+	noticeFiles android.Paths
 }
 
 func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile {
@@ -1204,6 +1308,7 @@
 		ret.requiredModuleNames = module.RequiredModuleNames()
 		ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
 		ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
+		ret.noticeFiles = module.NoticeFiles()
 	}
 	return ret
 }
@@ -1247,6 +1352,24 @@
 	return false
 }
 
+type fsType int
+
+const (
+	ext4 fsType = iota
+	f2fs
+)
+
+func (f fsType) string() string {
+	switch f {
+	case ext4:
+		return ext4FsType
+	case f2fs:
+		return f2fsFsType
+	default:
+		panic(fmt.Errorf("unknown APEX payload type %d", f))
+	}
+}
+
 type apexBundle struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -1312,6 +1435,8 @@
 
 	// Optional list of lint report zip files for apexes that contain java or app modules
 	lintReports android.Paths
+
+	payloadFsType fsType
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -1321,26 +1446,26 @@
 	// 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"})
 
-	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
+	}
 
-	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(binVariations, testTag, nativeModules.Tests...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -1458,6 +1583,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(),
@@ -1725,7 +1853,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)
 }
@@ -1778,6 +1906,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
@@ -1936,13 +2069,6 @@
 				return false
 			}
 
-			// TODO(jiyong) remove this check when R is published to AOSP. Currently, libstatssocket
-			// is capable of providing a stub variant, but is being statically linked from the bluetooth
-			// APEX.
-			if toName == "libstatssocket" {
-				return false
-			}
-
 			// The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule.
 			// It can't make the static dependencies dynamic because it can't
 			// do the dynamic linking for itself.
@@ -2113,6 +2239,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))
@@ -2284,6 +2419,15 @@
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
+	switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
+	case ext4FsType:
+		a.payloadFsType = ext4
+	case f2fsFsType:
+		a.payloadFsType = f2fs
+	default:
+		ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs]", *a.properties.Payload_fs_type)
+	}
+
 	// Optimization. If we are building bundled APEX, for the files that are gathered due to the
 	// transitive dependencies, don't place them inside the APEX, but place a symlink pointing
 	// the same library in the system partition, thus effectively sharing the same libraries
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 70464fc..610f667 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 {
@@ -5399,29 +5435,6 @@
 	}
 }
 
-func TestApexWithJniLibs_Errors(t *testing.T) {
-	testApexError(t, `jni_libs: "xxx" is not a cc_library`, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			jni_libs: ["xxx"],
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		prebuilt_etc {
-			name: "xxx",
-			src: "xxx",
-		}
-	`, withFiles(map[string][]byte{
-		"xxx": nil,
-	}))
-}
-
 func TestAppBundle(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -5727,6 +5740,141 @@
 	})
 }
 
+func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) {
+	t.Helper()
+	android.ClearApexDependency()
+	bp += `
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}`
+	fs := map[string][]byte{
+		"lib1/src/A.java": nil,
+		"lib2/src/B.java": nil,
+		"system/sepolicy/apex/myapex-file_contexts": nil,
+	}
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("apex", BundleFactory)
+	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	cc.RegisterRequiredBuildComponentsForTest(ctx)
+	java.RegisterJavaBuildComponents(ctx)
+	java.RegisterSystemModulesBuildComponents(ctx)
+	java.RegisterDexpreoptBootJarsComponents(ctx)
+	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+	ctx.PreDepsMutators(RegisterPreDepsMutators)
+	ctx.PostDepsMutators(RegisterPostDepsMutators)
+	ctx.PostDepsMutators(android.RegisterNeverallowMutator)
+
+	config := android.TestArchConfig(buildDir, nil, bp, fs)
+	android.SetTestNeverallowRules(config, rules)
+	updatableBootJars := make([]string, 0, len(apexBootJars))
+	for _, apexBootJar := range apexBootJars {
+		updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar)
+	}
+	config.TestProductVariables.UpdatableBootJars = updatableBootJars
+
+	ctx.Register(config)
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	android.FailIfErrored(t, errs)
+
+	_, errs = ctx.PrepareBuildActions(config)
+	if errmsg == "" {
+		android.FailIfErrored(t, errs)
+	} else if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, errmsg, errs)
+		return
+	} else {
+		t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
+	}
+}
+
+func TestApexPermittedPackagesRules(t *testing.T) {
+	testcases := []struct {
+		name            string
+		expectedError   string
+		bp              string
+		bootJars        []string
+		modulesPackages map[string][]string
+	}{
+
+		{
+			name:          "Non-Bootclasspath apex jar not satisfying allowed module packages.",
+			expectedError: "",
+			bp: `
+				java_library {
+					name: "bcp_lib1",
+					srcs: ["lib1/src/*.java"],
+					permitted_packages: ["foo.bar"],
+					apex_available: ["myapex"],
+					sdk_version: "none",
+					system_modules: "none",
+				}
+				java_library {
+					name: "nonbcp_lib2",
+					srcs: ["lib2/src/*.java"],
+					apex_available: ["myapex"],
+					permitted_packages: ["a.b"],
+					sdk_version: "none",
+					system_modules: "none",
+				}
+				apex {
+					name: "myapex",
+					key: "myapex.key",
+					java_libs: ["bcp_lib1", "nonbcp_lib2"],
+				}`,
+			bootJars: []string{"bcp_lib1"},
+			modulesPackages: map[string][]string{
+				"myapex": []string{
+					"foo.bar",
+				},
+			},
+		},
+		{
+			name:          "Bootclasspath apex jar not satisfying allowed module packages.",
+			expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`,
+			bp: `
+				java_library {
+					name: "bcp_lib1",
+					srcs: ["lib1/src/*.java"],
+					apex_available: ["myapex"],
+					permitted_packages: ["foo.bar"],
+					sdk_version: "none",
+					system_modules: "none",
+				}
+				java_library {
+					name: "bcp_lib2",
+					srcs: ["lib2/src/*.java"],
+					apex_available: ["myapex"],
+					permitted_packages: ["foo.bar", "bar.baz"],
+					sdk_version: "none",
+					system_modules: "none",
+				}
+				apex {
+					name: "myapex",
+					key: "myapex.key",
+					java_libs: ["bcp_lib1", "bcp_lib2"],
+				}
+			`,
+			bootJars: []string{"bcp_lib1", "bcp_lib2"},
+			modulesPackages: map[string][]string{
+				"myapex": []string{
+					"foo.bar",
+				},
+			},
+		},
+	}
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			rules := createApexPermittedPackagesRules(tc.modulesPackages)
+			testApexPermittedPackagesRules(t, tc.expectedError, tc.bp, tc.bootJars, rules)
+		})
+	}
+}
+
 func TestTestFor(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -5794,8 +5942,10 @@
 		}
 	`, func(fs map[string][]byte, config android.Config) {
 		config.TestProductVariables.Platform_sdk_version = intPtr(30)
-		config.TestProductVariables.DeviceArch = proptools.StringPtr("arm")
-		config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm64")
+		config.Targets[android.Android] = []android.Target{
+			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}},
+			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}},
+		}
 	})
 
 	m := ctx.ModuleForTests("myapex", "android_common")
diff --git a/apex/builder.go b/apex/builder.go
index 0a1ec3e..c5680ad 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -63,6 +63,8 @@
 	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 	pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
 	pctx.HostBinToolVariable("extract_apks", "extract_apks")
+	pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
+	pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
 }
 
 var (
@@ -116,12 +118,12 @@
 			`--payload_type image ` +
 			`--key ${key} ${opt_flags} ${image_dir} ${out} `,
 		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
-			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
+			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}",
 			"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
 		Rspfile:        "${out}.copy_commands",
 		RspfileContent: "${copy_commands}",
 		Description:    "APEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest")
+	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -193,7 +195,7 @@
 	// collect jniLibs. Notice that a.filesInfo is already sorted
 	var jniLibs []string
 	for _, fi := range a.filesInfo {
-		if fi.isJniLib {
+		if fi.isJniLib && !android.InList(fi.Stem(), jniLibs) {
 			jniLibs = append(jniLibs, fi.Stem())
 		}
 	}
@@ -284,6 +286,10 @@
 		return true
 	})
 
+	for _, fi := range a.filesInfo {
+		noticeFiles = append(noticeFiles, fi.noticeFiles...)
+	}
+
 	if len(noticeFiles) == 0 {
 		return android.NoticeOutputs{}
 	}
@@ -582,6 +588,8 @@
 			optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
 		}
 
+		optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
+
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        apexRule,
 			Implicits:   implicitInputs,
@@ -648,7 +656,7 @@
 		a.container_certificate_file,
 		a.container_private_key_file,
 	}
-	if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
 		rule = java.SignapkRE
 		args["implicits"] = strings.Join(implicits.Strings(), ",")
 		args["outCommaList"] = a.outputFile.String()
@@ -682,7 +690,7 @@
 	apexBundleName := a.Name()
 	a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName)
 
-	if a.installable() && a.GetOverriddenBy() == "" {
+	if a.installable() {
 		installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName)
 		devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
 		addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String())
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index d459f87..37457e9 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -257,6 +257,9 @@
 	// list of commands to create symlinks for backward compatibility.
 	// these commands will be attached as LOCAL_POST_INSTALL_CMD
 	compatSymlinks []string
+
+	hostRequired        []string
+	postInstallCommands []string
 }
 
 type ApexSetProperties struct {
@@ -343,21 +346,43 @@
 	for _, overridden := range a.properties.Overrides {
 		a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
 	}
+
+	if ctx.Config().InstallExtraFlattenedApexes() {
+		// flattened apex should be in /system_ext/apex
+		flattenedApexDir := android.PathForModuleInstall(&systemExtContext{ctx}, "apex", a.BaseModuleName())
+		a.postInstallCommands = append(a.postInstallCommands,
+			fmt.Sprintf("$(HOST_OUT_EXECUTABLES)/deapexer --debugfs_path $(HOST_OUT_EXECUTABLES)/debugfs extract %s %s",
+				a.outputApex.String(),
+				flattenedApexDir.ToMakePath().String(),
+			))
+		a.hostRequired = []string{"deapexer", "debugfs"}
+	}
+}
+
+type systemExtContext struct {
+	android.ModuleContext
+}
+
+func (*systemExtContext) SystemExtSpecific() bool {
+	return true
 }
 
 func (a *ApexSet) AndroidMkEntries() []android.AndroidMkEntries {
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "ETC",
-		OutputFile: android.OptionalPathForPath(a.outputApex),
-		Include:    "$(BUILD_PREBUILT)",
+		Class:         "ETC",
+		OutputFile:    android.OptionalPathForPath(a.outputApex),
+		Include:       "$(BUILD_PREBUILT)",
+		Host_required: a.hostRequired,
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
 				entries.SetString("LOCAL_MODULE_PATH", a.installDir.ToMakePath().String())
 				entries.SetString("LOCAL_MODULE_STEM", a.installFilename)
 				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !a.installable())
 				entries.AddStrings("LOCAL_OVERRIDES_MODULES", a.properties.Overrides...)
-				if len(a.compatSymlinks) > 0 {
-					entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(a.compatSymlinks, " && "))
+				postInstallCommands := append([]string{}, a.postInstallCommands...)
+				postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
+				if len(postInstallCommands) > 0 {
+					entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
 				}
 			},
 		},
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/androidmk.go b/cc/androidmk.go
index c899cdd..380b4e9 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -377,6 +377,7 @@
 		if !BoolDefault(test.Properties.Auto_gen_config, true) {
 			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
+		entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
 	})
 
 	androidMkWriteTestData(test.data, ctx, entries)
diff --git a/cc/binary.go b/cc/binary.go
index 6769fa7..b3ce5ff 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -83,7 +83,7 @@
 type binaryDecorator struct {
 	*baseLinker
 	*baseInstaller
-	stripper
+	stripper Stripper
 
 	Properties BinaryLinkerProperties
 
@@ -317,14 +317,14 @@
 	}
 
 	builderFlags := flagsToBuilderFlags(flags)
-
-	if binary.stripper.needsStrip(ctx) {
+	stripFlags := flagsToStripFlags(flags)
+	if binary.stripper.NeedsStrip(ctx) {
 		if ctx.Darwin() {
-			builderFlags.stripUseGnuStrip = true
+			stripFlags.StripUseGnuStrip = true
 		}
 		strippedOutputFile := outputFile
 		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
-		binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
+		binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags)
 	}
 
 	binary.unstrippedOutputFile = outputFile
@@ -333,7 +333,7 @@
 		afterPrefixSymbols := outputFile
 		outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName)
 		TransformBinaryPrefixSymbols(ctx, String(binary.Properties.Prefix_symbols), outputFile,
-			flagsToBuilderFlags(flags), afterPrefixSymbols)
+			builderFlags, afterPrefixSymbols)
 	}
 
 	outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName)
@@ -347,10 +347,10 @@
 			versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
 			binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile)
 
-			if binary.stripper.needsStrip(ctx) {
+			if binary.stripper.NeedsStrip(ctx) {
 				out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
 				binary.distFiles = android.MakeDefaultDistFiles(out)
-				binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
+				binary.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags)
 			}
 
 			binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -445,7 +445,7 @@
 	// The original path becomes a symlink to the corresponding file in the
 	// runtime APEX.
 	translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
-	if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
+	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
 		if ctx.Device() && isBionic(ctx.baseModuleName()) {
 			binary.installSymlinkToRuntimeApex(ctx, file)
 		}
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 f2bab8c..ef65348 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")
 
@@ -349,18 +350,22 @@
 
 	groupStaticLibs bool
 
-	stripKeepSymbols              bool
-	stripKeepSymbolsList          string
-	stripKeepSymbolsAndDebugFrame bool
-	stripKeepMiniDebugInfo        bool
-	stripAddGnuDebuglink          bool
-	stripUseGnuStrip              bool
-
 	proto            android.ProtoFlags
 	protoC           bool
 	protoOptionsFile bool
 
 	yacc *YaccProperties
+	lex  *LexProperties
+}
+
+type StripFlags struct {
+	Toolchain                     config.Toolchain
+	StripKeepSymbols              bool
+	StripKeepSymbolsList          string
+	StripKeepSymbolsAndDebugFrame bool
+	StripKeepMiniDebugInfo        bool
+	StripAddGnuDebuglink          bool
+	StripUseGnuStrip              bool
 }
 
 type Objects struct {
@@ -579,7 +584,7 @@
 			tidyFiles = append(tidyFiles, tidyFile)
 
 			rule := clangTidy
-			if ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") {
+			if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") {
 				rule = clangTidyRE
 			}
 
@@ -605,7 +610,7 @@
 			sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
 
 			dumpRule := sAbiDump
-			if ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") {
+			if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") {
 				dumpRule = sAbiDumpRE
 			}
 			ctx.Build(pctx, android.BuildParams{
@@ -740,9 +745,10 @@
 		"ldFlags":       flags.globalLdFlags + " " + flags.localLdFlags,
 		"crtEnd":        crtEnd.String(),
 	}
-	if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
+	if ctx.Config().UseRBE() && 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{
@@ -783,7 +789,7 @@
 		"arch":                ctx.Arch().ArchType.Name,
 		"exportedHeaderFlags": exportedHeaderFlags,
 	}
-	if ctx.Config().IsEnvTrue("RBE_ABI_LINKER") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") {
 		rule = sAbiLinkRE
 		rbeImplicits := implicits.Strings()
 		for _, p := range strings.Split(exportedHeaderFlags, " ") {
@@ -792,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,
@@ -906,9 +912,10 @@
 		"ldCmd":   ldCmd,
 		"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
 	}
-	if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
+	if ctx.Config().UseRBE() && 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,
@@ -939,26 +946,26 @@
 }
 
 func TransformStrip(ctx android.ModuleContext, inputFile android.Path,
-	outputFile android.WritablePath, flags builderFlags) {
+	outputFile android.WritablePath, flags StripFlags) {
 
-	crossCompile := gccCmd(flags.toolchain, "")
+	crossCompile := gccCmd(flags.Toolchain, "")
 	args := ""
-	if flags.stripAddGnuDebuglink {
+	if flags.StripAddGnuDebuglink {
 		args += " --add-gnu-debuglink"
 	}
-	if flags.stripKeepMiniDebugInfo {
+	if flags.StripKeepMiniDebugInfo {
 		args += " --keep-mini-debug-info"
 	}
-	if flags.stripKeepSymbols {
+	if flags.StripKeepSymbols {
 		args += " --keep-symbols"
 	}
-	if flags.stripKeepSymbolsList != "" {
-		args += " -k" + flags.stripKeepSymbolsList
+	if flags.StripKeepSymbolsList != "" {
+		args += " -k" + flags.StripKeepSymbolsList
 	}
-	if flags.stripKeepSymbolsAndDebugFrame {
+	if flags.StripKeepSymbolsAndDebugFrame {
 		args += " --keep-symbols-and-debug-frame"
 	}
-	if flags.stripUseGnuStrip {
+	if flags.StripUseGnuStrip {
 		args += " --use-gnu-strip"
 	}
 
diff --git a/cc/cc.go b/cc/cc.go
index 9bf9c84..70229be 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -210,6 +210,7 @@
 	protoOptionsFile bool // Whether to look for a .options file next to the .proto
 
 	Yacc *YaccProperties
+	Lex  *LexProperties
 }
 
 // Properties used to compile all C or C++ modules
@@ -279,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 {
@@ -1107,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..a4c0677 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())
@@ -930,7 +946,7 @@
 	`)
 }
 
-func TestVendorSnapshot(t *testing.T) {
+func TestVendorSnapshotCapture(t *testing.T) {
 	bp := `
 	cc_library {
 		name: "libvndk",
@@ -1063,6 +1079,215 @@
 	}
 }
 
+func TestVendorSnapshotUse(t *testing.T) {
+	frameworkBp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+		compile_multilib: "64",
+	}
+
+	cc_library {
+		name: "libvendor",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_binary {
+		name: "bin",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+`
+
+	vndkBp := `
+	vndk_prebuilt_shared {
+		name: "libvndk",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+		arch: {
+			arm64: {
+				srcs: ["libvndk.so"],
+			},
+		},
+	}
+`
+
+	vendorProprietaryBp := `
+	cc_library {
+		name: "libvendor_without_snapshot",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_library_shared {
+		name: "libclient",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		shared_libs: ["libvndk"],
+		static_libs: ["libvendor", "libvendor_without_snapshot"],
+		compile_multilib: "64",
+	}
+
+	cc_binary {
+		name: "bin_without_snapshot",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		static_libs: ["libvndk"],
+		compile_multilib: "64",
+	}
+
+	vendor_snapshot_static {
+		name: "libvndk",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvndk.a",
+			},
+		},
+	}
+
+	vendor_snapshot_shared {
+		name: "libvendor",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor.so",
+			},
+		},
+	}
+
+	vendor_snapshot_static {
+		name: "libvendor",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor.a",
+			},
+		},
+	}
+
+	vendor_snapshot_binary {
+		name: "bin",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "bin",
+			},
+		},
+	}
+`
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":      []byte(depsBp),
+		"framework/Android.bp": []byte(frameworkBp),
+		"vendor/Android.bp":    []byte(vendorProprietaryBp),
+		"vendor/libvndk.a":     nil,
+		"vendor/libvendor.a":   nil,
+		"vendor/libvendor.so":  nil,
+		"vendor/bin":           nil,
+		"vndk/Android.bp":      []byte(vndkBp),
+		"vndk/libvndk.so":      nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext()
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
+	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
+	binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
+
+	// libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
+	libclientLdRule := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld")
+	libclientFlags := libclientLdRule.Args["libFlags"]
+
+	for _, input := range [][]string{
+		[]string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
+		[]string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
+		[]string{staticVariant, "libvendor_without_snapshot"},
+	} {
+		outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
+		if !strings.Contains(libclientFlags, outputPaths[0].String()) {
+			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientFlags)
+		}
+	}
+
+	// bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
+	binWithoutSnapshotLdRule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld")
+	binWithoutSnapshotFlags := binWithoutSnapshotLdRule.Args["libFlags"]
+	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
+	if !strings.Contains(binWithoutSnapshotFlags, libVndkStaticOutputPaths[0].String()) {
+		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
+			libVndkStaticOutputPaths[0], binWithoutSnapshotFlags)
+	}
+
+	// libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64
+	ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
+
+	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
+	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
+
+	// bin is installed by bin.vendor_binary.BOARD.arm64
+	ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
+
+	// bin_without_snapshot is installed by bin_without_snapshot
+	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
+
+	// libvendor and bin don't have vendor.BOARD variant
+	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
+	if inList(sharedVariant, libvendorVariants) {
+		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
+	}
+
+	binVariants := ctx.ModuleVariantsForTests("bin")
+	if inList(binaryVariant, binVariants) {
+		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
+	}
+}
+
 func TestVendorSnapshotSanitizer(t *testing.T) {
 	bp := `
 	vendor_snapshot_static {
@@ -1096,6 +1321,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/compiler.go b/cc/compiler.go
index e06243b..f745820 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -111,6 +111,7 @@
 	Gnu_extensions *bool
 
 	Yacc *YaccProperties
+	Lex  *LexProperties
 
 	Aidl struct {
 		// list of directories that will be added to the aidl include paths.
@@ -189,8 +190,14 @@
 	// Build and link with OpenMP
 	Openmp *bool `android:"arch_variant"`
 
+	// Deprecated.
 	// Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__
 	Use_apex_name_macro *bool
+
+	// Adds two macros for apex variants in addition to __ANDROID_APEX__
+	// * __ANDROID_APEX_COM_ANDROID_FOO__
+	// * __ANDROID_APEX_NAME__="com.android.foo"
+	UseApexNameMacro bool `blueprint:"mutated"`
 }
 
 func NewBaseCompiler() *baseCompiler {
@@ -254,6 +261,10 @@
 	return deps
 }
 
+func (compiler *baseCompiler) useApexNameMacro() bool {
+	return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro
+}
+
 // Return true if the module is in the WarningAllowedProjects.
 func warningsAreAllowed(subdir string) bool {
 	subdir += "/"
@@ -289,6 +300,7 @@
 	flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...)
 
 	flags.Yacc = compiler.Properties.Yacc
+	flags.Lex = compiler.Properties.Lex
 
 	// Include dir cflags
 	localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
@@ -337,14 +349,19 @@
 
 	if ctx.apexVariationName() != "" {
 		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__")
-		if Bool(compiler.Properties.Use_apex_name_macro) {
+		if compiler.useApexNameMacro() {
 			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__")
+			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'")
 		}
 		if ctx.Device() {
 			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion()))
 		}
 	}
 
+	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_NATIVE_BRIDGE__")
+	}
+
 	instructionSet := String(compiler.Properties.Instruction_set)
 	if flags.RequiredInstructionSet != "" {
 		instructionSet = flags.RequiredInstructionSet
@@ -557,13 +574,15 @@
 }
 
 func (compiler *baseCompiler) uniqueApexVariations() bool {
-	return Bool(compiler.Properties.Use_apex_name_macro)
+	return compiler.useApexNameMacro()
 }
 
+var invalidDefineCharRegex = regexp.MustCompile("[^a-zA-Z0-9_]")
+
 // makeDefineString transforms a name of an APEX module into a value to be used as value for C define
 // For example, com.android.foo => COM_ANDROID_FOO
 func makeDefineString(name string) string {
-	return strings.ReplaceAll(strings.ToUpper(name), ".", "_")
+	return invalidDefineCharRegex.ReplaceAllString(strings.ToUpper(name), "_")
 }
 
 var gnuToCReplacer = strings.NewReplacer("gnu", "c")
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 6275064..ce4bdfb 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -23,6 +23,8 @@
         "x86_linux_host.go",
         "x86_linux_bionic_host.go",
         "x86_windows_host.go",
+
+        "arm64_linux_host.go",
     ],
     testSrcs: [
         "tidy_test.go",
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
new file mode 100644
index 0000000..74642c2
--- /dev/null
+++ b/cc/config/arm64_linux_host.go
@@ -0,0 +1,94 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+	"android/soong/android"
+	"strings"
+)
+
+var (
+	// This is a host toolchain but flags for device toolchain are required
+	// as the flags are actually for Bionic-based builds.
+	linuxCrossCflags = ClangFilterUnknownCflags(append(deviceGlobalCflags,
+		// clang by default enables PIC when the clang triple is set to *-android.
+		// See toolchain/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp#920.
+		// However, for this host target, we don't set "-android" to avoid __ANDROID__ macro
+		// which stands for "Android device target". Keeping PIC on is required because
+		// many modules we have (e.g. Bionic) assume PIC.
+		"-fpic",
+	))
+
+	linuxCrossLdflags = ClangFilterUnknownCflags([]string{
+		"-Wl,-z,noexecstack",
+		"-Wl,-z,relro",
+		"-Wl,-z,now",
+		"-Wl,--build-id=md5",
+		"-Wl,--warn-shared-textrel",
+		"-Wl,--fatal-warnings",
+		"-Wl,--hash-style=gnu",
+		"-Wl,--no-undefined-version",
+	})
+)
+
+func init() {
+	pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " "))
+	pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " "))
+}
+
+// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android
+// target. The overridden methods below show the differences.
+type toolchainLinuxArm64 struct {
+	toolchainArm64
+}
+
+func (toolchainLinuxArm64) ClangTriple() string {
+	// Note the absence of "-android" suffix. The compiler won't define __ANDROID__
+	return "aarch64-linux"
+}
+
+func (toolchainLinuxArm64) ClangCflags() string {
+	// The inherited flags + extra flags
+	return "${config.Arm64ClangCflags} ${config.LinuxBionicArm64Cflags}"
+}
+
+func linuxArm64ToolchainFactory(arch android.Arch) Toolchain {
+	archVariant := "armv8-a" // for host, default to armv8-a
+	toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[archVariant]}
+
+	// We don't specify CPU architecture for host. Conservatively assume
+	// the host CPU needs the fix
+	extraLdflags := "-Wl,--fix-cortex-a53-843419"
+
+	ret := toolchainLinuxArm64{}
+
+	// add the extra ld and lld flags
+	ret.toolchainArm64.ldflags = strings.Join([]string{
+		"${config.Arm64Ldflags}",
+		"${config.LinuxBionicArm64Ldflags}",
+		extraLdflags,
+	}, " ")
+	ret.toolchainArm64.lldflags = strings.Join([]string{
+		"${config.Arm64Lldflags}",
+		"${config.LinuxBionicArm64Ldflags}",
+		extraLdflags,
+	}, " ")
+	ret.toolchainArm64.toolchainClangCflags = strings.Join(toolchainClangCflags, " ")
+	return &ret
+}
+
+func init() {
+	registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory)
+}
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 54f693e..6f2e807 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -18,10 +18,12 @@
 // For these libraries, the vendor variants must be installed even if the device
 // has VndkUseCoreVariant set.
 var VndkMustUseVendorVariantList = []string{
+	"android.hardware.automotive.occupant_awareness-ndk_platform",
 	"android.hardware.light-ndk_platform",
 	"android.hardware.identity-ndk_platform",
 	"android.hardware.nfc@1.2",
 	"android.hardware.power-ndk_platform",
+	"android.hardware.rebootescrow-ndk_platform",
 	"android.hardware.vibrator-ndk_platform",
 	"libbinder",
 	"libcrypto",
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index cd0a508..b5b5553 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -49,7 +49,11 @@
 
 	windowsClangCppflags = []string{}
 
-	windowsX86ClangCppflags = []string{}
+	windowsX86ClangCppflags = []string{
+		// Use SjLj exceptions for 32-bit.  libgcc_eh implements SjLj
+		// exception model for 32-bit.
+		"-fsjlj-exceptions",
+	}
 
 	windowsX8664ClangCppflags = []string{}
 
diff --git a/cc/gen.go b/cc/gen.go
index b0aadc6..ccc3d0e 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -34,9 +34,9 @@
 var (
 	lex = pctx.AndroidStaticRule("lex",
 		blueprint.RuleParams{
-			Command:     "M4=$m4Cmd $lexCmd -o$out $in",
+			Command:     "M4=$m4Cmd $lexCmd $flags -o$out $in",
 			CommandDeps: []string{"$lexCmd", "$m4Cmd"},
-		})
+		}, "flags")
 
 	sysprop = pctx.AndroidStaticRule("sysprop",
 		blueprint.RuleParams{
@@ -153,12 +153,23 @@
 	}
 }
 
-func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) {
+type LexProperties struct {
+	// list of module-specific flags that will be used for .l and .ll compiles
+	Flags []string
+}
+
+func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) {
+	var flags []string
+	if props != nil {
+		flags = props.Flags
+	}
+	flagsString := strings.Join(flags[:], " ")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        lex,
 		Description: "lex " + lexFile.Rel(),
 		Output:      outFile,
 		Input:       lexFile,
+		Args:        map[string]string{"flags": flagsString},
 	})
 }
 
@@ -235,11 +246,11 @@
 		case ".l":
 			cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
 			srcFiles[i] = cFile
-			genLex(ctx, srcFile, cFile)
+			genLex(ctx, srcFile, cFile, buildFlags.lex)
 		case ".ll":
 			cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp")
 			srcFiles[i] = cppFile
-			genLex(ctx, srcFile, cppFile)
+			genLex(ctx, srcFile, cppFile, buildFlags.lex)
 		case ".proto":
 			ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
 			srcFiles[i] = ccFile
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.go b/cc/library.go
index 1c2b1ee..92853b5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -336,7 +336,7 @@
 	tocFile android.OptionalPath
 
 	flagExporter
-	stripper
+	stripper Stripper
 
 	// If we're used as a whole_static_lib, our missing dependencies need
 	// to be given
@@ -955,13 +955,14 @@
 	library.tocFile = android.OptionalPathForPath(tocFile)
 	TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
 
-	if library.stripper.needsStrip(ctx) {
+	stripFlags := flagsToStripFlags(flags)
+	if library.stripper.NeedsStrip(ctx) {
 		if ctx.Darwin() {
-			builderFlags.stripUseGnuStrip = true
+			stripFlags.StripUseGnuStrip = true
 		}
 		strippedOutputFile := outputFile
 		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
-		library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
+		library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags)
 	}
 	library.unstrippedOutputFile = outputFile
 
@@ -976,10 +977,10 @@
 			versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
 			library.distFile = versionedOutputFile
 
-			if library.stripper.needsStrip(ctx) {
+			if library.stripper.NeedsStrip(ctx) {
 				out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
 				library.distFile = out
-				library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
+				library.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags)
 			}
 
 			library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -1027,6 +1028,10 @@
 	return library.unstrippedOutputFile
 }
 
+func (library *libraryDecorator) disableStripping() {
+	library.stripper.StripProperties.Strip.None = BoolPtr(true)
+}
+
 func (library *libraryDecorator) nativeCoverage() bool {
 	if library.header() || library.buildStubs() {
 		return false
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 9328a25..ecfdc99 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)
 				}
 			}
 		}
@@ -118,6 +119,14 @@
 
 	ccModule := member.Variants()[0].(*Module)
 
+	if proptools.Bool(ccModule.Properties.Recovery_available) {
+		pbm.AddProperty("recovery_available", true)
+	}
+
+	if proptools.Bool(ccModule.VendorProperties.Vendor_available) {
+		pbm.AddProperty("vendor_available", true)
+	}
+
 	sdkVersion := ccModule.SdkVersion()
 	if sdkVersion != "" {
 		pbm.AddProperty("sdk_version", sdkVersion)
@@ -282,8 +291,8 @@
 	}
 
 	// Add the collated include dir properties to the output.
-	for property, dirs := range includeDirs {
-		outputProperties.AddProperty(property, dirs)
+	for _, property := range android.SortedStringKeys(includeDirs) {
+		outputProperties.AddProperty(property, includeDirs[property])
 	}
 
 	if len(libInfo.StubsVersion) > 0 {
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 71c9204..b3f9d61 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -179,7 +179,7 @@
 	library.BuildOnlyShared()
 	module.stl = nil
 	module.sanitize = nil
-	library.StripProperties.Strip.None = BoolPtr(true)
+	library.disableStripping()
 
 	stub := &llndkStubDecorator{
 		libraryDecorator: library,
diff --git a/cc/lto.go b/cc/lto.go
index 9868cdf..e034337 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -52,6 +52,9 @@
 
 	// Use clang lld instead of gnu ld.
 	Use_clang_lld *bool
+
+	// Use -fwhole-program-vtables cflag.
+	Whole_program_vtables *bool
 }
 
 type lto struct {
@@ -97,6 +100,10 @@
 		flags.Local.CFlags = append(flags.Local.CFlags, ltoFlag)
 		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoFlag)
 
+		if Bool(lto.Properties.Whole_program_vtables) {
+			flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
+		}
+
 		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && lto.useClangLld(ctx) {
 			// Set appropriate ThinLTO cache policy
 			cacheDirFormat := "-Wl,--thinlto-cache-dir="
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 58e742e..fe3efc0 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -405,7 +405,7 @@
 	library.BuildOnlyShared()
 	module.stl = nil
 	module.sanitize = nil
-	library.StripProperties.Strip.None = BoolPtr(true)
+	library.disableStripping()
 
 	stub := &stubDecorator{
 		libraryDecorator: library,
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/prebuilt.go b/cc/prebuilt.go
index baf43ce..1ee096e 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -125,9 +125,10 @@
 			outputFile := android.PathForModuleOut(ctx, libName)
 			var implicits android.Paths
 
-			if p.needsStrip(ctx) {
+			if p.stripper.NeedsStrip(ctx) {
+				stripFlags := flagsToStripFlags(flags)
 				stripped := android.PathForModuleOut(ctx, "stripped", libName)
-				p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+				p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
 				in = stripped
 			}
 
@@ -323,35 +324,68 @@
 type prebuiltBinaryLinker struct {
 	*binaryDecorator
 	prebuiltLinker
+
+	toolPath android.OptionalPath
 }
 
 var _ prebuiltLinkerInterface = (*prebuiltBinaryLinker)(nil)
 
+func (p *prebuiltBinaryLinker) hostToolPath() android.OptionalPath {
+	return p.toolPath
+}
+
 func (p *prebuiltBinaryLinker) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 	// TODO(ccross): verify shared library dependencies
 	if len(p.properties.Srcs) > 0 {
-		builderFlags := flagsToBuilderFlags(flags)
-
 		fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
 		in := p.Prebuilt.SingleSourcePath(ctx)
-
+		outputFile := android.PathForModuleOut(ctx, fileName)
 		p.unstrippedOutputFile = in
 
-		if p.needsStrip(ctx) {
-			stripped := android.PathForModuleOut(ctx, "stripped", fileName)
-			p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
-			in = stripped
-		}
+		if ctx.Host() {
+			// Host binaries are symlinked to their prebuilt source locations. That
+			// way they are executed directly from there so the linker resolves their
+			// shared library dependencies relative to that location (using
+			// $ORIGIN/../lib(64):$ORIGIN/lib(64) as RUNPATH). This way the prebuilt
+			// repository can supply the expected versions of the shared libraries
+			// without interference from what is in the out tree.
 
-		// Copy binaries to a name matching the final installed name
-		outputFile := android.PathForModuleOut(ctx, fileName)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        android.CpExecutable,
-			Description: "prebuilt",
-			Output:      outputFile,
-			Input:       in,
-		})
+			// These shared lib paths may point to copies of the libs in
+			// .intermediates, which isn't where the binary will load them from, but
+			// it's fine for dependency tracking. If a library dependency is updated,
+			// the symlink will get a new timestamp, along with any installed symlinks
+			// handled in make.
+			sharedLibPaths := deps.EarlySharedLibs
+			sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...)
+			sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...)
+
+			ctx.Build(pctx, android.BuildParams{
+				Rule:      android.Symlink,
+				Output:    outputFile,
+				Input:     in,
+				Implicits: sharedLibPaths,
+				Args: map[string]string{
+					"fromPath": "$$PWD/" + in.String(),
+				},
+			})
+
+			p.toolPath = android.OptionalPathForPath(outputFile)
+		} else {
+			if p.stripper.NeedsStrip(ctx) {
+				stripped := android.PathForModuleOut(ctx, "stripped", fileName)
+				p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags))
+				in = stripped
+			}
+
+			// Copy binaries to a name matching the final installed name
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        android.CpExecutable,
+				Description: "prebuilt",
+				Output:      outputFile,
+				Input:       in,
+			})
+		}
 
 		return outputFile
 	}
@@ -378,6 +412,7 @@
 		binaryDecorator: binary,
 	}
 	module.linker = prebuilt
+	module.installer = prebuilt
 
 	module.AddProperties(&prebuilt.properties)
 
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index adb44bd..52416ac 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"path/filepath"
 	"testing"
 
 	"android/soong/android"
@@ -271,3 +272,52 @@
 	shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module)
 	assertString(t, shared.OutputFile().Path().Base(), "libbar.so")
 }
+
+func TestPrebuiltSymlinkedHostBinary(t *testing.T) {
+	if android.BuildOs != android.Linux {
+		t.Skipf("Skipping host prebuilt testing that is only supported on %s not %s", android.Linux, android.BuildOs)
+	}
+
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library_shared {
+		name: "libfoo",
+		device_supported: false,
+		host_supported: true,
+		target: {
+			linux_glibc_x86_64: {
+				srcs: ["linux_glibc_x86_64/lib64/libfoo.so"],
+			},
+		},
+	}
+
+	cc_prebuilt_binary {
+		name: "foo",
+		device_supported: false,
+		host_supported: true,
+		shared_libs: ["libfoo"],
+		target: {
+			linux_glibc_x86_64: {
+				srcs: ["linux_glibc_x86_64/bin/foo"],
+			},
+		},
+	}
+	`, map[string][]byte{
+		"libfoo.so": nil,
+		"foo":       nil,
+	})
+
+	fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink")
+	assertString(t, fooRule.Output.String(),
+		filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo"))
+	assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo")
+
+	var libfooDep android.Path
+	for _, dep := range fooRule.Implicits {
+		if dep.Base() == "libfoo.so" {
+			libfooDep = dep
+			break
+		}
+	}
+	assertString(t, libfooDep.String(),
+		filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so"))
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 2243082..174dcfe 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -48,6 +48,10 @@
 		// higher number of "optimized out" stack variables.
 		// b/112437883.
 		"-mllvm", "-instcombine-lower-dbg-declare=0",
+		// TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
+		// GlobalISel is the default at -O0 on aarch64.
+		"-mllvm", "--aarch64-enable-global-isel-at-O=-1",
+		"-mllvm", "-fast-isel=false",
 	}
 
 	cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
@@ -738,7 +742,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 +1015,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 +1032,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/stl.go b/cc/stl.go
index 4e74c7f..e18fe95 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -239,11 +239,6 @@
 			flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
 			flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
 			if ctx.Windows() {
-				// Use SjLj exceptions for 32-bit.  libgcc_eh implements SjLj
-				// exception model for 32-bit.
-				if ctx.Arch().ArchType == android.X86 {
-					flags.Local.CppFlags = append(flags.Local.CppFlags, "-fsjlj-exceptions")
-				}
 				flags.Local.CppFlags = append(flags.Local.CppFlags,
 					// Disable visiblity annotations since we're using static
 					// libc++.
diff --git a/cc/strip.go b/cc/strip.go
index 7e560ec..18150dc 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -30,42 +30,42 @@
 	} `android:"arch_variant"`
 }
 
-type stripper struct {
+type Stripper struct {
 	StripProperties StripProperties
 }
 
-func (stripper *stripper) needsStrip(ctx ModuleContext) bool {
+func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool {
 	// TODO(ccross): enable host stripping when embedded in make?  Make never had support for stripping host binaries.
-	return (!ctx.Config().EmbeddedInMake() || ctx.Device()) && !Bool(stripper.StripProperties.Strip.None)
+	return (!actx.Config().EmbeddedInMake() || actx.Device()) && !Bool(stripper.StripProperties.Strip.None)
 }
 
-func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
-	flags builderFlags, isStaticLib bool) {
-	if ctx.Darwin() {
-		TransformDarwinStrip(ctx, in, out)
+func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
+	flags StripFlags, isStaticLib bool) {
+	if actx.Darwin() {
+		TransformDarwinStrip(actx, in, out)
 	} else {
 		if Bool(stripper.StripProperties.Strip.Keep_symbols) {
-			flags.stripKeepSymbols = true
+			flags.StripKeepSymbols = true
 		} else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) {
-			flags.stripKeepSymbolsAndDebugFrame = true
+			flags.StripKeepSymbolsAndDebugFrame = true
 		} else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
-			flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
+			flags.StripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
 		} else if !Bool(stripper.StripProperties.Strip.All) {
-			flags.stripKeepMiniDebugInfo = true
+			flags.StripKeepMiniDebugInfo = true
 		}
-		if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib {
-			flags.stripAddGnuDebuglink = true
+		if actx.Config().Debuggable() && !flags.StripKeepMiniDebugInfo && !isStaticLib {
+			flags.StripAddGnuDebuglink = true
 		}
-		TransformStrip(ctx, in, out, flags)
+		TransformStrip(actx, in, out, flags)
 	}
 }
 
-func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path,
-	out android.ModuleOutPath, flags builderFlags) {
-	stripper.strip(ctx, in, out, flags, false)
+func (stripper *Stripper) StripExecutableOrSharedLib(actx android.ModuleContext, in android.Path,
+	out android.ModuleOutPath, flags StripFlags) {
+	stripper.strip(actx, in, out, flags, false)
 }
 
-func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
-	flags builderFlags) {
-	stripper.strip(ctx, in, out, flags, true)
+func (stripper *Stripper) StripStaticLib(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
+	flags StripFlags) {
+	stripper.strip(actx, in, out, flags, true)
 }
diff --git a/cc/test.go b/cc/test.go
index a805647..619dc4d 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -223,6 +223,7 @@
 					tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src)
 					mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i])
 				}
+				mctx.AliasVariation("")
 			}
 		}
 	}
@@ -344,6 +345,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 +418,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/testing.go b/cc/testing.go
index 06e5f83..52f0829 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -527,7 +527,9 @@
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
+	ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
 	ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+	ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	android.RegisterPrebuiltMutators(ctx)
 	RegisterRequiredBuildComponentsForTest(ctx)
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 042e012..19f5ea4 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -36,8 +36,7 @@
 
 type toolchainLibraryDecorator struct {
 	*libraryDecorator
-
-	stripper
+	stripper Stripper
 
 	Properties toolchainLibraryProperties
 }
@@ -89,8 +88,8 @@
 	if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
 		fileName := ctx.ModuleName() + staticLibraryExtension
 		outputFile := android.PathForModuleOut(ctx, fileName)
-		buildFlags := flagsToBuilderFlags(flags)
-		library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags)
+		stripFlags := flagsToStripFlags(flags)
+		library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags)
 		return outputFile
 	}
 
diff --git a/cc/util.go b/cc/util.go
index af26268..40374bf 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -97,9 +97,14 @@
 		protoOptionsFile: in.protoOptionsFile,
 
 		yacc: in.Yacc,
+		lex:  in.Lex,
 	}
 }
 
+func flagsToStripFlags(in Flags) StripFlags {
+	return StripFlags{Toolchain: in.Toolchain}
+}
+
 func addPrefix(list []string, prefix string) []string {
 	for i := range list {
 		list[i] = prefix + list[i]
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index e9d1c73..85f514c 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -144,7 +144,7 @@
 	library.BuildOnlyShared()
 	module.stl = nil
 	module.sanitize = nil
-	library.StripProperties.Strip.None = BoolPtr(true)
+	library.disableStripping()
 
 	stub := &vendorPublicLibraryStubDecorator{
 		libraryDecorator: library,
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index e17a6d0..2819f49 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -264,7 +264,7 @@
 
 	module.stl = nil
 	module.sanitize = nil
-	library.StripProperties.Strip.None = BoolPtr(true)
+	library.disableStripping()
 
 	prebuilt := &vendorSnapshotLibraryDecorator{
 		libraryDecorator: library,
@@ -340,12 +340,12 @@
 	}
 
 	in := android.PathForModuleSrc(ctx, *p.properties.Src)
-	builderFlags := flagsToBuilderFlags(flags)
+	stripFlags := flagsToStripFlags(flags)
 	p.unstrippedOutputFile = in
 	binName := in.Base()
-	if p.needsStrip(ctx) {
+	if p.stripper.NeedsStrip(ctx) {
 		stripped := android.PathForModuleOut(ctx, "stripped", binName)
-		p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+		p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
 		in = stripped
 	}
 
@@ -508,18 +508,51 @@
 	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
 	}
+	// When android/prebuilt.go selects between source and prebuilt, it sets
+	// SkipInstall on the other one to avoid duplicate install rules in make.
+	if m.IsSkipInstall() {
+		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 +824,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/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 5a44c46..9484760 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -142,9 +142,10 @@
 		builderFlags := flagsToBuilderFlags(flags)
 		p.unstrippedOutputFile = in
 		libName := in.Base()
-		if p.needsStrip(ctx) {
+		if p.stripper.NeedsStrip(ctx) {
+			stripFlags := flagsToStripFlags(flags)
 			stripped := android.PathForModuleOut(ctx, "stripped", libName)
-			p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+			p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
 			in = stripped
 		}
 
@@ -213,7 +214,7 @@
 	library.BuildOnlyShared()
 	module.stl = nil
 	module.sanitize = nil
-	library.StripProperties.Strip.None = BoolPtr(true)
+	library.disableStripping()
 
 	prebuilt := &vndkPrebuiltLibraryDecorator{
 		libraryDecorator: library,
diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go
index e1d3d41..72e0fbd 100644
--- a/cmd/soong_build/bazel_overlay.go
+++ b/cmd/soong_build/bazel_overlay.go
@@ -24,42 +24,45 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/bootstrap/bpdoc"
 	"github.com/google/blueprint/proptools"
 )
 
 const (
+	// The default `load` preamble for every generated BUILD file.
 	soongModuleLoad = `package(default_visibility = ["//visibility:public"])
 load("//:soong_module.bzl", "soong_module")
 
 `
 
-	// A BUILD file target snippet representing a Soong module
+	// A macro call in the BUILD file representing a Soong module, with space
+	// for expanding more attributes.
 	soongModuleTarget = `soong_module(
     name = "%s",
     module_name = "%s",
     module_type = "%s",
     module_variant = "%s",
-    deps = %s,
+    module_deps = %s,
 %s)`
 
-	// The soong_module rule implementation in a .bzl file
-	soongModuleBzl = `SoongModuleInfo = provider(
+	// A simple provider to mark and differentiate Soong module rule shims from
+	// regular Bazel rules. Every Soong module rule shim returns a
+	// SoongModuleInfo provider, and can only depend on rules returning
+	// SoongModuleInfo in the `module_deps` attribute.
+	providersBzl = `SoongModuleInfo = provider(
     fields = {
         "name": "Name of module",
         "type": "Type of module",
         "variant": "Variant of module",
     },
 )
+`
 
-def _merge_dicts(*dicts):
-    """Adds a list of dictionaries into a single dictionary."""
+	// The soong_module rule implementation in a .bzl file.
+	soongModuleBzl = `
+%s
 
-    # If keys are repeated in multiple dictionaries, the latter one "wins".
-    result = {}
-    for d in dicts:
-        result.update(d)
-
-    return result
+load(":providers.bzl", "SoongModuleInfo")
 
 def _generic_soong_module_impl(ctx):
     return [
@@ -70,37 +73,31 @@
         ),
     ]
 
-_COMMON_ATTRS = {
-    "module_name": attr.string(mandatory = True),
-    "module_type": attr.string(mandatory = True),
-    "module_variant": attr.string(),
-    "deps": attr.label_list(providers = [SoongModuleInfo]),
-}
-
-
 generic_soong_module = rule(
     implementation = _generic_soong_module_impl,
-    attrs = _COMMON_ATTRS,
-)
-
-# TODO(jingwen): auto generate Soong module shims
-def _soong_filegroup_impl(ctx):
-    return [SoongModuleInfo(),]
-
-soong_filegroup = rule(
-    implementation = _soong_filegroup_impl,
-    # Matches https://cs.android.com/android/platform/superproject/+/master:build/soong/android/filegroup.go;l=25-40;drc=6a6478d49e78703ba22a432c41d819c8df79ef6c
-    attrs = _merge_dicts(_COMMON_ATTRS, {
-        "srcs": attr.string_list(doc = "srcs lists files that will be included in this filegroup"),
-        "exclude_srcs": attr.string_list(),
-        "path": attr.string(doc = "The base path to the files. May be used by other modules to determine which portion of the path to use. For example, when a filegroup is used as data in a cc_test rule, the base path is stripped off the path and the remaining path is used as the installation directory."),
-        "export_to_make_var": attr.string(doc = "Create a make variable with the specified name that contains the list of files in the filegroup, relative to the root of the source tree."),
-    })
+    attrs = {
+        "module_name": attr.string(mandatory = True),
+        "module_type": attr.string(mandatory = True),
+        "module_variant": attr.string(),
+        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+    },
 )
 
 soong_module_rule_map = {
-    "filegroup": soong_filegroup,
-}
+%s}
+
+_SUPPORTED_TYPES = ["bool", "int", "string"]
+
+def _is_supported_type(value):
+    if type(value) in _SUPPORTED_TYPES:
+        return True
+    elif type(value) == "list":
+        supported = True
+        for v in value:
+            supported = supported and type(v) in _SUPPORTED_TYPES
+        return supported
+    else:
+        return False
 
 # soong_module is a macro that supports arbitrary kwargs, and uses module_type to
 # expand to the right underlying shim.
@@ -115,15 +112,79 @@
             module_type = module_type,
             module_name = kwargs.pop("module_name", ""),
             module_variant = kwargs.pop("module_variant", ""),
-            deps = kwargs.pop("deps", []),
+            module_deps = kwargs.pop("module_deps", []),
         )
     else:
+        supported_kwargs = dict()
+        for key, value in kwargs.items():
+            if _is_supported_type(value):
+                supported_kwargs[key] = value
         soong_module_rule(
             name = name,
-            module_type = module_type,
-            **kwargs,
+            **supported_kwargs,
         )
 `
+
+	// A rule shim for representing a Soong module type and its properties.
+	moduleRuleShim = `
+def _%[1]s_impl(ctx):
+    return [SoongModuleInfo()]
+
+%[1]s = rule(
+    implementation = _%[1]s_impl,
+    attrs = %[2]s
+)
+`
+)
+
+var (
+	// An allowlist of prop types that are surfaced from module props to rule
+	// attributes. (nested) dictionaries are notably absent here, because while
+	// Soong supports multi value typed and nested dictionaries, Bazel's rule
+	// attr() API supports only single-level string_dicts.
+	allowedPropTypes = map[string]bool{
+		"int":         true, // e.g. 42
+		"bool":        true, // e.g. True
+		"string_list": true, // e.g. ["a", "b"]
+		"string":      true, // e.g. "a"
+	}
+
+	// TODO(b/166563303): Specific properties of some module types aren't
+	// recognized by the documentation generator. As a workaround, hardcode a
+	// mapping of the module type to prop name to prop type here, and ultimately
+	// fix the documentation generator to also parse these properties correctly.
+	additionalPropTypes = map[string]map[string]string{
+		// sdk and module_exports props are created at runtime using reflection.
+		// bpdocs isn't wired up to read runtime generated structs.
+		"sdk": {
+			"java_header_libs":    "string_list",
+			"java_sdk_libs":       "string_list",
+			"java_system_modules": "string_list",
+			"native_header_libs":  "string_list",
+			"native_libs":         "string_list",
+			"native_objects":      "string_list",
+			"native_shared_libs":  "string_list",
+			"native_static_libs":  "string_list",
+		},
+		"module_exports": {
+			"java_libs":          "string_list",
+			"java_tests":         "string_list",
+			"native_binaries":    "string_list",
+			"native_shared_libs": "string_list",
+		},
+	}
+
+	// Certain module property names are blocklisted/ignored here, for the reasons commented.
+	ignoredPropNames = map[string]bool{
+		"name":       true, // redundant, since this is explicitly generated for every target
+		"from":       true, // reserved keyword
+		"in":         true, // reserved keyword
+		"arch":       true, // interface prop type is not supported yet.
+		"multilib":   true, // interface prop type is not supported yet.
+		"target":     true, // interface prop type is not supported yet.
+		"visibility": true, // Bazel has native visibility semantics. Handle later.
+		"features":   true, // There is already a built-in attribute 'features' which cannot be overridden.
+	}
 )
 
 func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string {
@@ -206,9 +267,7 @@
 		structProps := extractStructProperties(propertyValue, indent)
 		for _, k := range android.SortedStringKeys(structProps) {
 			ret += makeIndent(indent + 1)
-			ret += "\"" + k + "\": "
-			ret += structProps[k]
-			ret += ",\n"
+			ret += fmt.Sprintf("%q: %s,\n", k, structProps[k])
 		}
 		ret += makeIndent(indent)
 		ret += "}"
@@ -223,6 +282,10 @@
 	return ret, nil
 }
 
+// Converts a reflected property struct value into a map of property names and property values,
+// which each property value correctly pretty-printed and indented at the right nest level,
+// since property structs can be nested. In Starlark, nested structs are represented as nested
+// dicts: https://docs.bazel.build/skylark/lib/dict.html
 func extractStructProperties(structValue reflect.Value, indent int) map[string]string {
 	if structValue.Kind() != reflect.Struct {
 		panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind()))
@@ -296,6 +359,102 @@
 	return ret
 }
 
+// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
+// testonly = True, forcing other rules that depend on _test rules to also be
+// marked as testonly = True. This semantic constraint is not present in Soong.
+// To work around, rename "*_test" rules to "*_test_".
+func canonicalizeModuleType(moduleName string) string {
+	if strings.HasSuffix(moduleName, "_test") {
+		return moduleName + "_"
+	}
+
+	return moduleName
+}
+
+type RuleShim struct {
+	// The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..]
+	rules []string
+
+	// The generated string content of the bzl file.
+	content string
+}
+
+// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and
+// user-specified Go plugins.
+//
+// This function reuses documentation generation APIs to ensure parity between modules-as-docs
+// and modules-as-code, including the names and types of module properties.
+func createRuleShims(packages []*bpdoc.Package) (map[string]RuleShim, error) {
+	var propToAttr func(prop bpdoc.Property, propName string) string
+	propToAttr = func(prop bpdoc.Property, propName string) string {
+		// dots are not allowed in Starlark attribute names. Substitute them with double underscores.
+		propName = strings.ReplaceAll(propName, ".", "__")
+		if !shouldGenerateAttribute(propName) {
+			return ""
+		}
+
+		// Canonicalize and normalize module property types to Bazel attribute types
+		starlarkAttrType := prop.Type
+		if starlarkAttrType == "list of strings" {
+			starlarkAttrType = "string_list"
+		} else if starlarkAttrType == "int64" {
+			starlarkAttrType = "int"
+		} else if starlarkAttrType == "" {
+			var attr string
+			for _, nestedProp := range prop.Properties {
+				nestedAttr := propToAttr(nestedProp, propName+"__"+nestedProp.Name)
+				if nestedAttr != "" {
+					// TODO(b/167662930): Fix nested props resulting in too many attributes.
+					// Let's still generate these, but comment them out.
+					attr += "# " + nestedAttr
+				}
+			}
+			return attr
+		}
+
+		if !allowedPropTypes[starlarkAttrType] {
+			return ""
+		}
+
+		return fmt.Sprintf("        %q: attr.%s(),\n", propName, starlarkAttrType)
+	}
+
+	ruleShims := map[string]RuleShim{}
+	for _, pkg := range packages {
+		content := "load(\":providers.bzl\", \"SoongModuleInfo\")\n"
+
+		bzlFileName := strings.ReplaceAll(pkg.Path, "android/soong/", "")
+		bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_")
+		bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_")
+
+		rules := []string{}
+
+		for _, moduleTypeTemplate := range moduleTypeDocsToTemplates(pkg.ModuleTypes) {
+			attrs := `{
+        "module_name": attr.string(mandatory = True),
+        "module_variant": attr.string(),
+        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+`
+			for _, prop := range moduleTypeTemplate.Properties {
+				attrs += propToAttr(prop, prop.Name)
+			}
+
+			for propName, propType := range additionalPropTypes[moduleTypeTemplate.Name] {
+				attrs += fmt.Sprintf("        %q: attr.%s(),\n", propName, propType)
+			}
+
+			attrs += "    },"
+
+			rule := canonicalizeModuleType(moduleTypeTemplate.Name)
+			content += fmt.Sprintf(moduleRuleShim, rule, attrs)
+			rules = append(rules, rule)
+		}
+
+		ruleShims[bzlFileName] = RuleShim{content: content, rules: rules}
+	}
+	return ruleShims, nil
+}
+
 func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error {
 	blueprintCtx := ctx.Context
 	blueprintCtx.VisitAllModules(func(module blueprint.Module) {
@@ -316,21 +475,50 @@
 		return err
 	}
 
-	return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", soongModuleBzl)
+	if err := writeReadOnlyFile(bazelOverlayDir, "providers.bzl", providersBzl); err != nil {
+		return err
+	}
+
+	packages, err := getPackages(ctx)
+	if err != nil {
+		return err
+	}
+	ruleShims, err := createRuleShims(packages)
+	if err != nil {
+		return err
+	}
+
+	for bzlFileName, ruleShim := range ruleShims {
+		if err := writeReadOnlyFile(bazelOverlayDir, bzlFileName+".bzl", ruleShim.content); err != nil {
+			return err
+		}
+	}
+
+	return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))
 }
 
-var ignoredProps map[string]bool = map[string]bool{
-	"name":       true, // redundant, since this is explicitly generated for every target
-	"from":       true, // reserved keyword
-	"in":         true, // reserved keyword
-	"arch":       true, // interface prop type is not supported yet.
-	"multilib":   true, // interface prop type is not supported yet.
-	"target":     true, // interface prop type is not supported yet.
-	"visibility": true, // Bazel has native visibility semantics. Handle later.
+// Generate the content of soong_module.bzl with the rule shim load statements
+// and mapping of module_type to rule shim map for every module type in Soong.
+func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
+	var loadStmts string
+	var moduleRuleMap string
+	for bzlFileName, ruleShim := range bzlLoads {
+		loadStmt := "load(\"//:"
+		loadStmt += bzlFileName
+		loadStmt += ".bzl\""
+		for _, rule := range ruleShim.rules {
+			loadStmt += fmt.Sprintf(", %q", rule)
+			moduleRuleMap += "    \"" + rule + "\": " + rule + ",\n"
+		}
+		loadStmt += ")\n"
+		loadStmts += loadStmt
+	}
+
+	return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap)
 }
 
 func shouldGenerateAttribute(prop string) bool {
-	return !ignoredProps[prop]
+	return !ignoredPropNames[prop]
 }
 
 // props is an unsorted map. This function ensures that
@@ -367,9 +555,7 @@
 
 	depLabelList := "[\n"
 	for depLabel, _ := range depLabels {
-		depLabelList += "        \""
-		depLabelList += depLabel
-		depLabelList += "\",\n"
+		depLabelList += fmt.Sprintf("        %q,\n", depLabel)
 	}
 	depLabelList += "    ]"
 
@@ -377,7 +563,7 @@
 		soongModuleTarget,
 		targetNameWithVariant(blueprintCtx, module),
 		blueprintCtx.ModuleName(module),
-		blueprintCtx.ModuleType(module),
+		canonicalizeModuleType(blueprintCtx.ModuleType(module)),
 		blueprintCtx.ModuleSubDir(module),
 		depLabelList,
 		attributes)
@@ -410,11 +596,12 @@
 	return f, nil
 }
 
-// The overlay directory should be read-only, sufficient for bazel query.
+// The overlay directory should be read-only, sufficient for bazel query. The files
+// are not intended to be edited by end users.
 func writeReadOnlyFile(dir string, baseName string, content string) error {
-	workspaceFile := filepath.Join(bazelOverlayDir, baseName)
+	pathToFile := filepath.Join(bazelOverlayDir, baseName)
 	// 0444 is read-only
-	return ioutil.WriteFile(workspaceFile, []byte(content), 0444)
+	return ioutil.WriteFile(pathToFile, []byte(content), 0444)
 }
 
 func isZero(value reflect.Value) bool {
diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go
index 67599c0..f0c8515 100644
--- a/cmd/soong_build/bazel_overlay_test.go
+++ b/cmd/soong_build/bazel_overlay_test.go
@@ -18,7 +18,10 @@
 	"android/soong/android"
 	"io/ioutil"
 	"os"
+	"strings"
 	"testing"
+
+	"github.com/google/blueprint/bootstrap/bpdoc"
 )
 
 var buildDir string
@@ -75,7 +78,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
 )`,
 		},
@@ -90,7 +93,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
     ramdisk = True,
 )`,
@@ -106,7 +109,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
     owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
 )`,
@@ -122,7 +125,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
     required = [
         "bar",
@@ -140,7 +143,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
     target_required = [
         "qux",
@@ -168,7 +171,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
     dist = {
         "tag": ".foo",
@@ -206,7 +209,7 @@
     module_name = "foo",
     module_type = "custom",
     module_variant = "",
-    deps = [
+    module_deps = [
     ],
     dists = [
         {
@@ -253,3 +256,209 @@
 		}
 	}
 }
+
+func createPackageFixtures() []*bpdoc.Package {
+	properties := []bpdoc.Property{
+		bpdoc.Property{
+			Name: "int64_prop",
+			Type: "int64",
+		},
+		bpdoc.Property{
+			Name: "int_prop",
+			Type: "int",
+		},
+		bpdoc.Property{
+			Name: "bool_prop",
+			Type: "bool",
+		},
+		bpdoc.Property{
+			Name: "string_prop",
+			Type: "string",
+		},
+		bpdoc.Property{
+			Name: "string_list_prop",
+			Type: "list of strings",
+		},
+		bpdoc.Property{
+			Name: "nested_prop",
+			Type: "",
+			Properties: []bpdoc.Property{
+				bpdoc.Property{
+					Name: "int_prop",
+					Type: "int",
+				},
+				bpdoc.Property{
+					Name: "bool_prop",
+					Type: "bool",
+				},
+				bpdoc.Property{
+					Name: "string_prop",
+					Type: "string",
+				},
+			},
+		},
+		bpdoc.Property{
+			Name: "unknown_type",
+			Type: "unknown",
+		},
+	}
+
+	fooPropertyStruct := &bpdoc.PropertyStruct{
+		Name:       "FooProperties",
+		Properties: properties,
+	}
+
+	moduleTypes := []*bpdoc.ModuleType{
+		&bpdoc.ModuleType{
+			Name: "foo_library",
+			PropertyStructs: []*bpdoc.PropertyStruct{
+				fooPropertyStruct,
+			},
+		},
+
+		&bpdoc.ModuleType{
+			Name: "foo_binary",
+			PropertyStructs: []*bpdoc.PropertyStruct{
+				fooPropertyStruct,
+			},
+		},
+		&bpdoc.ModuleType{
+			Name: "foo_test",
+			PropertyStructs: []*bpdoc.PropertyStruct{
+				fooPropertyStruct,
+			},
+		},
+	}
+
+	return [](*bpdoc.Package){
+		&bpdoc.Package{
+			Name:        "foo_language",
+			Path:        "android/soong/foo",
+			ModuleTypes: moduleTypes,
+		},
+	}
+}
+
+func TestGenerateModuleRuleShims(t *testing.T) {
+	ruleShims, err := createRuleShims(createPackageFixtures())
+	if err != nil {
+		panic(err)
+	}
+
+	if len(ruleShims) != 1 {
+		t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
+	}
+
+	fooRuleShim := ruleShims["foo"]
+	expectedRules := []string{"foo_binary", "foo_library", "foo_test_"}
+
+	if len(fooRuleShim.rules) != 3 {
+		t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules))
+	}
+
+	for i, rule := range fooRuleShim.rules {
+		if rule != expectedRules[i] {
+			t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
+		}
+	}
+
+	expectedBzl := `load(":providers.bzl", "SoongModuleInfo")
+
+def _foo_binary_impl(ctx):
+    return [SoongModuleInfo()]
+
+foo_binary = rule(
+    implementation = _foo_binary_impl,
+    attrs = {
+        "module_name": attr.string(mandatory = True),
+        "module_variant": attr.string(),
+        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "bool_prop": attr.bool(),
+        "int64_prop": attr.int(),
+        "int_prop": attr.int(),
+#         "nested_prop__int_prop": attr.int(),
+#         "nested_prop__bool_prop": attr.bool(),
+#         "nested_prop__string_prop": attr.string(),
+        "string_list_prop": attr.string_list(),
+        "string_prop": attr.string(),
+    },
+)
+
+def _foo_library_impl(ctx):
+    return [SoongModuleInfo()]
+
+foo_library = rule(
+    implementation = _foo_library_impl,
+    attrs = {
+        "module_name": attr.string(mandatory = True),
+        "module_variant": attr.string(),
+        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "bool_prop": attr.bool(),
+        "int64_prop": attr.int(),
+        "int_prop": attr.int(),
+#         "nested_prop__int_prop": attr.int(),
+#         "nested_prop__bool_prop": attr.bool(),
+#         "nested_prop__string_prop": attr.string(),
+        "string_list_prop": attr.string_list(),
+        "string_prop": attr.string(),
+    },
+)
+
+def _foo_test__impl(ctx):
+    return [SoongModuleInfo()]
+
+foo_test_ = rule(
+    implementation = _foo_test__impl,
+    attrs = {
+        "module_name": attr.string(mandatory = True),
+        "module_variant": attr.string(),
+        "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "bool_prop": attr.bool(),
+        "int64_prop": attr.int(),
+        "int_prop": attr.int(),
+#         "nested_prop__int_prop": attr.int(),
+#         "nested_prop__bool_prop": attr.bool(),
+#         "nested_prop__string_prop": attr.string(),
+        "string_list_prop": attr.string_list(),
+        "string_prop": attr.string(),
+    },
+)
+`
+
+	if fooRuleShim.content != expectedBzl {
+		t.Errorf(
+			"Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
+			expectedBzl,
+			fooRuleShim.content)
+	}
+}
+
+func TestGenerateSoongModuleBzl(t *testing.T) {
+	ruleShims, err := createRuleShims(createPackageFixtures())
+	if err != nil {
+		panic(err)
+	}
+	actualSoongModuleBzl := generateSoongModuleBzl(ruleShims)
+
+	expectedLoad := "load(\"//:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")"
+	expectedRuleMap := `soong_module_rule_map = {
+    "foo_binary": foo_binary,
+    "foo_library": foo_library,
+    "foo_test_": foo_test_,
+}`
+	if !strings.Contains(actualSoongModuleBzl, expectedLoad) {
+		t.Errorf(
+			"Generated soong_module.bzl:\n\n%s\n\n"+
+				"Could not find the load statement in the generated soong_module.bzl:\n%s",
+			actualSoongModuleBzl,
+			expectedLoad)
+	}
+
+	if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) {
+		t.Errorf(
+			"Generated soong_module.bzl:\n\n%s\n\n"+
+				"Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
+			actualSoongModuleBzl,
+			expectedRuleMap)
+	}
+}
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index c136846..5fb6e6b 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -95,14 +95,17 @@
 	return result
 }
 
-func writeDocs(ctx *android.Context, filename string) error {
+func getPackages(ctx *android.Context) ([]*bpdoc.Package, error) {
 	moduleTypeFactories := android.ModuleTypeFactories()
 	bpModuleTypeFactories := make(map[string]reflect.Value)
 	for moduleType, factory := range moduleTypeFactories {
 		bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
 	}
+	return bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
+}
 
-	packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
+func writeDocs(ctx *android.Context, filename string) error {
+	packages, err := getPackages(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 78f91df..21f7bb3 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -100,6 +100,21 @@
 	ConstructContext android.Path
 }
 
+// These libs are added as optional dependencies (<uses-library> with android:required set to false).
+// This is because they haven't existed prior to certain SDK version, but classes in them were in
+// bootclasspath jars, etc. So making them hard dependencies (android:required=true) would prevent
+// apps from being installed to such legacy devices.
+var OptionalCompatUsesLibs = []string{
+	"org.apache.http.legacy",
+	"android.test.base",
+	"android.test.mock",
+}
+
+var CompatUsesLibs = []string{
+	"android.hidl.base-V1.0-java",
+	"android.hidl.manager-V1.0-java",
+}
+
 const UnknownInstallLibraryPath = "error"
 
 // LibraryPath contains paths to the library DEX jar on host and on device.
@@ -111,12 +126,31 @@
 // LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
 type LibraryPaths map[string]*LibraryPath
 
-// Add a new path to the map of library paths, unless a path for this library already exists.
-func (libPaths LibraryPaths) AddLibraryPath(ctx android.PathContext, lib *string, hostPath, installPath android.Path) {
-	if lib == nil {
-		return
+// Add a new library path to the map, unless a path for this library already exists.
+// If necessary, check that the build and install paths exist.
+func (libPaths LibraryPaths) addLibraryPath(ctx android.ModuleContext, lib string,
+	hostPath, installPath android.Path, strict bool) {
+
+	// If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is
+	// not found. However, this is likely to result is disabling dexpreopt, as it won't be
+	// possible to construct class loader context without on-host and on-device library paths.
+	strict = strict && !ctx.Config().AllowMissingDependencies()
+
+	if hostPath == nil && strict {
+		android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
 	}
-	if _, present := libPaths[*lib]; !present {
+
+	if installPath == nil {
+		if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) {
+			// Assume that compatibility libraries are installed in /system/framework.
+			installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar")
+		} else if strict {
+			android.ReportPathErrorf(ctx, "unknown install path to <uses-library> '%s'", lib)
+		}
+	}
+
+	// Add a library only if the build and install path to it is known.
+	if _, present := libPaths[lib]; !present {
 		var devicePath string
 		if installPath != nil {
 			devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
@@ -127,9 +161,22 @@
 			// but we cannot use if for dexpreopt.
 			devicePath = UnknownInstallLibraryPath
 		}
-		libPaths[*lib] = &LibraryPath{hostPath, devicePath}
+		libPaths[lib] = &LibraryPath{hostPath, devicePath}
 	}
-	return
+}
+
+// Add a new library path to the map. Enforce checks that the library paths exist.
+func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleContext, lib string, hostPath, installPath android.Path) {
+	libPaths.addLibraryPath(ctx, lib, hostPath, installPath, true)
+}
+
+// Add a new library path to the map, if the library exists (name is not nil).
+// Don't enforce checks that the library paths exist. Some libraries may be missing from the build,
+// but their names still need to be added to <uses-library> tags in the manifest.
+func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.ModuleContext, lib *string, hostPath, installPath android.Path) {
+	if lib != nil {
+		libPaths.addLibraryPath(ctx, *lib, hostPath, installPath, false)
+	}
 }
 
 // Add library paths from the second map to the first map (do not override existing entries).
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 8deb0a3..4dbda49 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -81,15 +81,14 @@
 	}
 
 	if !dexpreoptDisabled(ctx, global, module) {
-		// Don't preopt individual boot jars, they will be preopted together.
-		if !global.BootJars.ContainsJar(module.Name) {
+		if clc := genClassLoaderContext(ctx, global, module); clc != nil {
 			appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
 				!module.NoCreateAppImage
 
 			generateDM := shouldGenerateDM(module, global)
 
 			for archIdx, _ := range module.Archs {
-				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
+				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, *clc, profile, appImage, generateDM)
 			}
 		}
 	}
@@ -102,6 +101,11 @@
 		return true
 	}
 
+	// Don't preopt individual boot jars, they will be preopted together.
+	if global.BootJars.ContainsJar(module.Name) {
+		return true
+	}
+
 	// Don't preopt system server jars that are updatable.
 	if global.UpdatableSystemServerJars.ContainsJar(module.Name) {
 		return true
@@ -214,13 +218,17 @@
 	return m[sdkVer]
 }
 
-func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) {
+func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) bool {
 	clc := m.getValue(sdkVer)
 	for _, lib := range libs {
-		p := pathForLibrary(module, lib)
-		clc.Host = append(clc.Host, p.Host)
-		clc.Target = append(clc.Target, p.Device)
+		if p := pathForLibrary(module, lib); p != nil {
+			clc.Host = append(clc.Host, p.Host)
+			clc.Target = append(clc.Target, p.Device)
+		} else {
+			return false
+		}
 	}
+	return true
 }
 
 func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) {
@@ -231,9 +239,79 @@
 	}
 }
 
+// genClassLoaderContext generates host and target class loader context to be passed to the dex2oat
+// command for the dexpreopted module. There are three possible cases:
+//
+// 1. System server jars. They have a special class loader context that includes other system
+//    server jars.
+//
+// 2. Library jars or APKs which have precise list of their <uses-library> libs. Their class loader
+//    context includes build and on-device paths to these libs. In some cases it may happen that
+//    the path to a <uses-library> is unknown (e.g. the dexpreopted module may depend on stubs
+//    library, whose implementation library is missing from the build altogether). In such case
+//    dexpreopting with the <uses-library> is impossible, and dexpreopting without it is pointless,
+//    as the runtime classpath won't match and the dexpreopted code will be discarded. Therefore in
+//    such cases the function returns nil, which disables dexpreopt.
+//
+// 2. All other library jars or APKs for which the exact <uses-library> list is unknown. They use
+//    the unsafe &-classpath workaround that means empty class loader context and absence of runtime
+//    check that the class loader context provided by the PackageManager agrees with the stored
+//    class loader context recorded in the .odex file.
+//
+func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) *classLoaderContextMap {
+	classLoaderContexts := make(classLoaderContextMap)
+	systemServerJars := NonUpdatableSystemServerJars(ctx, global)
+
+	if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
+		// System server jars should be dexpreopted together: class loader context of each jar
+		// should include all preceding jars on the system server classpath.
+		classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
+
+	} else if module.EnforceUsesLibraries {
+		// Unconditional class loader context.
+		usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
+		if !classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) {
+			return nil
+		}
+
+		// Conditional class loader context for API version < 28.
+		const httpLegacy = "org.apache.http.legacy"
+		if !contains(usesLibs, httpLegacy) {
+			if !classLoaderContexts.addLibs(28, module, httpLegacy) {
+				return nil
+			}
+		}
+
+		// Conditional class loader context for API version < 29.
+		usesLibs29 := []string{
+			"android.hidl.base-V1.0-java",
+			"android.hidl.manager-V1.0-java",
+		}
+		if !classLoaderContexts.addLibs(29, module, usesLibs29...) {
+			return nil
+		}
+
+		// Conditional class loader context for API version < 30.
+		const testBase = "android.test.base"
+		if !contains(usesLibs, testBase) {
+			if !classLoaderContexts.addLibs(30, module, testBase) {
+				return nil
+			}
+		}
+
+	} else {
+		// Pass special class loader context to skip the classpath and collision check.
+		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
+		// Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
+		// to the &.
+	}
+
+	return &classLoaderContexts
+}
+
 func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
-	module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
-	appImage bool, generateDM bool) {
+	module *ModuleConfig, rule *android.RuleBuilder, archIdx int, classLoaderContexts classLoaderContextMap,
+	profile android.WritablePath, appImage bool, generateDM bool) {
 
 	arch := module.Archs[archIdx]
 
@@ -264,17 +342,12 @@
 
 	invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
 
-	classLoaderContexts := make(classLoaderContextMap)
 	systemServerJars := NonUpdatableSystemServerJars(ctx, global)
 
 	rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
 	rule.Command().FlagWithOutput("rm -f ", odexPath)
 
 	if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
-		// System server jars should be dexpreopted together: class loader context of each jar
-		// should include all preceding jars on the system server classpath.
-		classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
-
 		// Copy the system server jar to a predefined location where dex2oat will find it.
 		dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
 		rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
@@ -288,29 +361,6 @@
 			Implicits(clc.Host).
 			Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]")
 	} else if module.EnforceUsesLibraries {
-		// Unconditional class loader context.
-		usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
-		classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...)
-
-		// Conditional class loader context for API version < 28.
-		const httpLegacy = "org.apache.http.legacy"
-		if !contains(usesLibs, httpLegacy) {
-			classLoaderContexts.addLibs(28, module, httpLegacy)
-		}
-
-		// Conditional class loader context for API version < 29.
-		usesLibs29 := []string{
-			"android.hidl.base-V1.0-java",
-			"android.hidl.manager-V1.0-java",
-		}
-		classLoaderContexts.addLibs(29, module, usesLibs29...)
-
-		// Conditional class loader context for API version < 30.
-		const testBase = "android.test.base"
-		if !contains(usesLibs, testBase) {
-			classLoaderContexts.addLibs(30, module, testBase)
-		}
-
 		// Generate command that saves target SDK version in a shell variable.
 		if module.ManifestPath != nil {
 			rule.Command().Text(`target_sdk_version="$(`).
@@ -540,11 +590,11 @@
 }
 
 func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath {
-	path, ok := module.LibraryPaths[lib]
-	if !ok {
-		panic(fmt.Errorf("unknown library path for %q", lib))
+	if path, ok := module.LibraryPaths[lib]; ok && path.Host != nil && path.Device != "error" {
+		return path
+	} else {
+		return nil
 	}
-	return path
 }
 
 func makefileMatch(pattern, s string) bool {
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.bp b/java/Android.bp
index e345014..92e8ca4 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -59,6 +59,7 @@
         "device_host_converter_test.go",
         "dexpreopt_test.go",
         "dexpreopt_bootjars_test.go",
+        "hiddenapi_singleton_test.go",
         "java_test.go",
         "jdeps_test.go",
         "kotlin_test.go",
diff --git a/java/aar.go b/java/aar.go
index 5c19a9c..667dd9d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -378,6 +378,10 @@
 			exportPackage = aarDep.ExportPackage()
 		}
 
+		if dep, ok := module.(Dependency); ok {
+			sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs())
+		}
+
 		switch ctx.OtherModuleDependencyTag(module) {
 		case instrumentationForTag:
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
@@ -390,7 +394,7 @@
 			// (including the java_sdk_library) itself then append any implicit sdk library
 			// names to the list of sdk libraries to be added to the manifest.
 			if component, ok := module.(SdkLibraryComponentDependency); ok {
-				sdkLibraries.AddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(),
+				sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(),
 					component.DexJarBuildPath(), component.DexJarInstallPath())
 			}
 
@@ -399,9 +403,6 @@
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
 		case staticLibTag:
-			if dep, ok := module.(Dependency); ok {
-				sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs())
-			}
 			if exportPackage != nil {
 				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
 				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index f45ebe8..62cd112 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -42,16 +42,6 @@
 	},
 	"args", "libs")
 
-// These two libs are added as optional dependencies (<uses-library> with
-// android:required set to false). This is because they haven't existed in pre-P
-// devices, but classes in them were in bootclasspath jars, etc. So making them
-// hard dependencies (android:required=true) would prevent apps from being
-// installed to such legacy devices.
-var optionalUsesLibs = []string{
-	"android.test.base",
-	"android.test.mock",
-}
-
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
 func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths,
 	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
@@ -80,8 +70,8 @@
 		args = append(args, "--use-embedded-dex")
 	}
 
-	for usesLib, _ := range sdkLibraries {
-		if inList(usesLib, optionalUsesLibs) {
+	for _, usesLib := range android.SortedStringKeys(sdkLibraries) {
+		if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
 			args = append(args, "--optional-uses-library", usesLib)
 		} else {
 			args = append(args, "--uses-library", usesLib)
diff --git a/java/androidmk.go b/java/androidmk.go
index 2c02e5f..65c44a3 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -166,6 +166,7 @@
 		if !BoolDefault(j.testProperties.Auto_gen_config, true) {
 			entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true")
 		}
+		entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", j.testProperties.Test_mainline_modules...)
 	})
 
 	return entriesList
@@ -440,6 +441,7 @@
 		}
 		androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries)
 		androidMkWriteTestData(a.data, entries)
+		entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", a.testProperties.Test_mainline_modules...)
 	})
 
 	return entriesList
@@ -507,53 +509,14 @@
 func (ddoc *Droiddoc) AndroidMkEntries() []android.AndroidMkEntries {
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(ddoc.stubsSrcJar),
+		OutputFile: android.OptionalPathForPath(ddoc.Javadoc.docZip),
 		Include:    "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
-				if BoolDefault(ddoc.Javadoc.properties.Installable, true) && ddoc.Javadoc.docZip != nil {
+				if ddoc.Javadoc.docZip != nil {
 					entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", ddoc.Javadoc.docZip)
 				}
-				if ddoc.Javadoc.stubsSrcJar != nil {
-					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar)
-				}
-			},
-		},
-		ExtraFooters: []android.AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-				if ddoc.checkCurrentApiTimestamp != nil {
-					fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-current-api")
-					fmt.Fprintln(w, ddoc.Name()+"-check-current-api:",
-						ddoc.checkCurrentApiTimestamp.String())
-
-					fmt.Fprintln(w, ".PHONY: checkapi")
-					fmt.Fprintln(w, "checkapi:",
-						ddoc.checkCurrentApiTimestamp.String())
-
-					fmt.Fprintln(w, ".PHONY: droidcore")
-					fmt.Fprintln(w, "droidcore: checkapi")
-				}
-				if ddoc.updateCurrentApiTimestamp != nil {
-					fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-update-current-api")
-					fmt.Fprintln(w, ddoc.Name()+"-update-current-api:",
-						ddoc.updateCurrentApiTimestamp.String())
-
-					fmt.Fprintln(w, ".PHONY: update-api")
-					fmt.Fprintln(w, "update-api:",
-						ddoc.updateCurrentApiTimestamp.String())
-				}
-				if ddoc.checkLastReleasedApiTimestamp != nil {
-					fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-last-released-api")
-					fmt.Fprintln(w, ddoc.Name()+"-check-last-released-api:",
-						ddoc.checkLastReleasedApiTimestamp.String())
-
-					fmt.Fprintln(w, ".PHONY: checkapi")
-					fmt.Fprintln(w, "checkapi:",
-						ddoc.checkLastReleasedApiTimestamp.String())
-
-					fmt.Fprintln(w, ".PHONY: droidcore")
-					fmt.Fprintln(w, "droidcore: checkapi")
-				}
+				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !BoolDefault(ddoc.Javadoc.properties.Installable, true))
 			},
 		},
 	}}
diff --git a/java/app.go b/java/app.go
index 5e3a9d9..ae7373f 100755
--- a/java/app.go
+++ b/java/app.go
@@ -118,17 +118,17 @@
 }
 
 func SupportedAbis(ctx android.ModuleContext) []string {
-	abiName := func(archVar string, deviceArch string) string {
+	abiName := func(targetIdx int, deviceArch string) string {
 		if abi, found := TargetCpuAbi[deviceArch]; found {
 			return abi
 		}
-		ctx.ModuleErrorf("Invalid %s: %s", archVar, deviceArch)
+		ctx.ModuleErrorf("Target %d has invalid Arch: %s", targetIdx, deviceArch)
 		return "BAD_ABI"
 	}
 
-	result := []string{abiName("TARGET_ARCH", ctx.DeviceConfig().DeviceArch())}
-	if s := ctx.DeviceConfig().DeviceSecondaryArch(); s != "" {
-		result = append(result, abiName("TARGET_2ND_ARCH", s))
+	var result []string
+	for i, target := range ctx.Config().Targets[android.Android] {
+		result = append(result, abiName(i, target.Arch.ArchType.String()))
 	}
 	return result
 }
@@ -268,6 +268,9 @@
 
 	// the logging parent of this app.
 	Logging_parent *string
+
+	// Whether to rename the package in resources to the override name rather than the base name. Defaults to true.
+	Rename_resources_package *bool
 }
 
 // runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay
@@ -284,8 +287,6 @@
 	aapt
 	android.OverridableModuleBase
 
-	usesLibrary usesLibrary
-
 	certificate Certificate
 
 	appProperties appProperties
@@ -507,10 +508,23 @@
 		!a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
 }
 
+func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string {
+	aaptFlags := []string{"--rename-manifest-package " + packageName}
+	if renameResourcesPackage {
+		// Required to rename the package name in the resources table.
+		aaptFlags = append(aaptFlags, "--rename-resources-package "+packageName)
+	}
+	return aaptFlags
+}
+
 func (a *AndroidApp) OverriddenManifestPackageName() string {
 	return a.overriddenManifestPackageName
 }
 
+func (a *AndroidApp) renameResourcesPackage() bool {
+	return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true)
+}
+
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
 	a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
 
@@ -543,7 +557,7 @@
 		if !overridden {
 			manifestPackageName = *a.overridableAppProperties.Package_name
 		}
-		aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+		aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...)
 		a.overriddenManifestPackageName = manifestPackageName
 	}
 
@@ -586,7 +600,7 @@
 	return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
 }
 
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.LibraryPaths) android.Path {
 	a.dexpreopter.installPath = a.installPath(ctx)
 	if a.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
@@ -597,6 +611,7 @@
 	a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
 	a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
 	a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+	a.dexpreopter.libraryPaths.AddLibraryPaths(sdkLibs)
 	a.dexpreopter.manifestFile = a.mergedManifestFile
 	a.exportedSdkLibs = make(dexpreopt.LibraryPaths)
 
@@ -767,6 +782,15 @@
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
 
+	// The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
+	a.usesLibrary.freezeEnforceUsesLibraries()
+
+	// Add implicit SDK libraries to <uses-library> list.
+	for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) {
+		a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
+	}
+
+	// Check that the <uses-library> list is coherent with the manifest.
 	if a.usesLibrary.enforceUsesLibraries() {
 		manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile)
 		apkDeps = append(apkDeps, manifestCheckFile)
@@ -779,7 +803,7 @@
 	a.linter.resources = a.aapt.resourceFiles
 	a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
 
-	dexJarFile := a.dexBuildActions(ctx)
+	dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries)
 
 	jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
@@ -793,18 +817,32 @@
 
 	// Build a final signed app package.
 	packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
+	v4SigningRequested := Bool(a.Module.deviceProperties.V4_signature)
+	var v4SignatureFile android.WritablePath = nil
+	if v4SigningRequested {
+		v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+".apk.idsig")
+	}
 	var lineageFile android.Path
 	if lineage := String(a.overridableAppProperties.Lineage); lineage != "" {
 		lineageFile = android.PathForModuleSrc(ctx, lineage)
 	}
-	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, lineageFile)
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile)
 	a.outputFile = packageFile
+	if v4SigningRequested {
+		a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
+	}
 
 	for _, split := range a.aapt.splits {
 		// Sign the split APKs
 		packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk")
-		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, lineageFile)
+		if v4SigningRequested {
+			v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
+		}
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
+		if v4SigningRequested {
+			a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
+		}
 	}
 
 	// Build an app bundle.
@@ -1008,8 +1046,7 @@
 	module.AddProperties(
 		&module.aaptProperties,
 		&module.appProperties,
-		&module.overridableAppProperties,
-		&module.usesLibrary.usesLibraryProperties)
+		&module.overridableAppProperties)
 
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
@@ -1130,7 +1167,6 @@
 		&module.appProperties,
 		&module.appTestProperties,
 		&module.overridableAppProperties,
-		&module.usesLibrary.usesLibraryProperties,
 		&module.testProperties)
 
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -1179,8 +1215,7 @@
 		&module.aaptProperties,
 		&module.appProperties,
 		&module.appTestHelperAppProperties,
-		&module.overridableAppProperties,
-		&module.usesLibrary.usesLibraryProperties)
+		&module.overridableAppProperties)
 
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
@@ -1523,7 +1558,7 @@
 		if lineage := String(a.properties.Lineage); lineage != "" {
 			lineageFile = android.PathForModuleSrc(ctx, lineage)
 		}
-		SignAppPackage(ctx, signed, dexOutput, certificates, lineageFile)
+		SignAppPackage(ctx, signed, dexOutput, certificates, nil, lineageFile)
 		a.outputFile = signed
 	} else {
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
@@ -1694,7 +1729,6 @@
 	module := &AndroidTestImport{}
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.dexpreoptProperties)
-	module.AddProperties(&module.usesLibrary.usesLibraryProperties)
 	module.AddProperties(&module.testProperties)
 	module.AddProperties(&module.testImportProperties)
 	module.populateAllVariantStructs()
@@ -1797,7 +1831,7 @@
 		if !overridden {
 			manifestPackageName = *r.overridableProperties.Package_name
 		}
-		aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+		aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...)
 	}
 	if r.overridableProperties.Target_package_name != nil {
 		aaptLinkFlags = append(aaptLinkFlags,
@@ -1813,7 +1847,7 @@
 	if lineage := String(r.properties.Lineage); lineage != "" {
 		lineageFile = android.PathForModuleSrc(ctx, lineage)
 	}
-	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, lineageFile)
+	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile)
 	r.certificate = certificates[0]
 
 	r.outputFile = signed
@@ -1878,6 +1912,11 @@
 	// If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file.  Defaults
 	// to true if either uses_libs or optional_uses_libs is set.  Will unconditionally default to true in the future.
 	Enforce_uses_libs *bool
+
+	// Optional name of the <uses-library> provided by this module. This is needed for non-SDK
+	// libraries, because SDK ones are automatically picked up by Soong. The <uses-library> name
+	// normally is the same as the module name, but there are exceptions.
+	Provides_uses_lib *string
 }
 
 // usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
@@ -1888,6 +1927,16 @@
 	usesLibraryProperties UsesLibraryProperties
 }
 
+func (u *usesLibrary) addLib(lib string, optional bool) {
+	if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) {
+		if optional {
+			u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib)
+		} else {
+			u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib)
+		}
+	}
+}
+
 func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
 	if !ctx.Config().UnbundledBuild() {
 		ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
@@ -1898,11 +1947,8 @@
 		if hasFrameworkLibs {
 			// Dexpreopt needs paths to the dex jars of these libraries in order to construct
 			// class loader context for dex2oat. Add them as a dependency with a special tag.
-			ctx.AddVariationDependencies(nil, usesLibTag,
-				"org.apache.http.legacy",
-				"android.hidl.base-V1.0-java",
-				"android.hidl.manager-V1.0-java")
-			ctx.AddVariationDependencies(nil, usesLibTag, optionalUsesLibs...)
+			ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.CompatUsesLibs...)
+			ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.OptionalCompatUsesLibs...)
 		}
 	}
 }
@@ -1923,27 +1969,11 @@
 		ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
 			dep := ctx.OtherModuleName(m)
 			if lib, ok := m.(Dependency); ok {
-				buildPath := lib.DexJarBuildPath()
-				if buildPath == nil {
-					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+
-						" produce a dex jar, does it have installable: true?", dep)
-					return
-				}
-
-				var devicePath string
-				installPath := lib.DexJarInstallPath()
-				if installPath == nil {
-					devicePath = filepath.Join("/system/framework", dep+".jar")
-				} else {
-					devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
-				}
-
-				usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath}
+				usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath())
 			} else if ctx.Config().AllowMissingDependencies() {
 				ctx.AddMissingDependencies([]string{dep})
 			} else {
-				ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+
-					"a java library", dep)
+				ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
 			}
 		})
 	}
@@ -1960,6 +1990,12 @@
 	return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs)
 }
 
+// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`.
+func (u *usesLibrary) freezeEnforceUsesLibraries() {
+	enforce := u.enforceUsesLibraries()
+	u.usesLibraryProperties.Enforce_uses_libs = &enforce
+}
+
 // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified
 // in the uses_libs and optional_uses_libs properties.  It returns the path to a copy of the manifest.
 func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
diff --git a/java/app_builder.go b/java/app_builder.go
index 014bd54..69e462c 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -52,7 +52,7 @@
 	})
 
 func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, lineageFile android.Path) {
+	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
 	unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -73,10 +73,10 @@
 		Implicits: deps,
 	})
 
-	SignAppPackage(ctx, outputFile, unsignedApk, certificates, lineageFile)
+	SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile)
 }
 
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, lineageFile android.Path) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path) {
 
 	var certificateArgs []string
 	var deps android.Paths
@@ -87,6 +87,11 @@
 
 	outputFiles := android.WritablePaths{signedApk}
 	var flags []string
+	if v4SignatureFile != nil {
+		outputFiles = append(outputFiles, v4SignatureFile)
+		flags = append(flags, "--enable-v4")
+	}
+
 	if lineageFile != nil {
 		flags = append(flags, "--lineage", lineageFile.String())
 		deps = append(deps, lineageFile)
@@ -97,7 +102,7 @@
 		"certificates": strings.Join(certificateArgs, " "),
 		"flags":        strings.Join(flags, " "),
 	}
-	if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
 		rule = SignapkRE
 		args["implicits"] = strings.Join(deps.Strings(), ",")
 		args["outCommaList"] = strings.Join(outputFiles.Strings(), ",")
@@ -236,7 +241,7 @@
 	args := map[string]string{
 		"jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
 	}
-	if ctx.Config().IsEnvTrue("RBE_ZIP") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") {
 		rule = zipRE
 		args["implicits"] = strings.Join(deps.Strings(), ",")
 	}
diff --git a/java/app_test.go b/java/app_test.go
index 6b27124..5367971 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -176,16 +176,17 @@
 			set: "prebuilts/apks/app.apks",
 		}`
 	testCases := []struct {
-		name                string
-		deviceArch          *string
-		deviceSecondaryArch *string
-		aaptPrebuiltDPI     []string
-		sdkVersion          int
-		expected            map[string]string
+		name            string
+		targets         []android.Target
+		aaptPrebuiltDPI []string
+		sdkVersion      int
+		expected        map[string]string
 	}{
 		{
-			name:            "One",
-			deviceArch:      proptools.StringPtr("x86"),
+			name: "One",
+			targets: []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86}},
+			},
 			aaptPrebuiltDPI: []string{"ldpi", "xxhdpi"},
 			sdkVersion:      29,
 			expected: map[string]string{
@@ -197,11 +198,13 @@
 			},
 		},
 		{
-			name:                "Two",
-			deviceArch:          proptools.StringPtr("x86_64"),
-			deviceSecondaryArch: proptools.StringPtr("x86"),
-			aaptPrebuiltDPI:     nil,
-			sdkVersion:          30,
+			name: "Two",
+			targets: []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64}},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86}},
+			},
+			aaptPrebuiltDPI: nil,
+			sdkVersion:      30,
 			expected: map[string]string{
 				"abis":              "X86_64,X86",
 				"allow-prereleased": "false",
@@ -216,8 +219,7 @@
 		config := testAppConfig(nil, bp, nil)
 		config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
 		config.TestProductVariables.Platform_sdk_version = &test.sdkVersion
-		config.TestProductVariables.DeviceArch = test.deviceArch
-		config.TestProductVariables.DeviceSecondaryArch = test.deviceSecondaryArch
+		config.Targets[android.Android] = test.targets
 		ctx := testContext()
 		run(t, ctx, config)
 		module := ctx.ModuleForTests("foo", "android_common")
@@ -1038,6 +1040,35 @@
 	}
 }
 
+func checkSdkVersion(t *testing.T, config android.Config, expectedSdkVersion string) {
+	ctx := testContext()
+
+	run(t, ctx, config)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	link := foo.Output("package-res.apk")
+	linkFlags := strings.Split(link.Args["flags"], " ")
+	min := android.IndexList("--min-sdk-version", linkFlags)
+	target := android.IndexList("--target-sdk-version", linkFlags)
+
+	if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
+		t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
+	}
+
+	gotMinSdkVersion := linkFlags[min+1]
+	gotTargetSdkVersion := linkFlags[target+1]
+
+	if gotMinSdkVersion != expectedSdkVersion {
+		t.Errorf("incorrect --min-sdk-version, expected %q got %q",
+			expectedSdkVersion, gotMinSdkVersion)
+	}
+
+	if gotTargetSdkVersion != expectedSdkVersion {
+		t.Errorf("incorrect --target-sdk-version, expected %q got %q",
+			expectedSdkVersion, gotTargetSdkVersion)
+	}
+}
+
 func TestAppSdkVersion(t *testing.T) {
 	testCases := []struct {
 		name                  string
@@ -1107,38 +1138,85 @@
 				config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
 				config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
 				config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+				checkSdkVersion(t, config, test.expectedMinSdkVersion)
 
-				ctx := testContext()
-
-				run(t, ctx, config)
-
-				foo := ctx.ModuleForTests("foo", "android_common")
-				link := foo.Output("package-res.apk")
-				linkFlags := strings.Split(link.Args["flags"], " ")
-				min := android.IndexList("--min-sdk-version", linkFlags)
-				target := android.IndexList("--target-sdk-version", linkFlags)
-
-				if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
-					t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
-				}
-
-				gotMinSdkVersion := linkFlags[min+1]
-				gotTargetSdkVersion := linkFlags[target+1]
-
-				if gotMinSdkVersion != test.expectedMinSdkVersion {
-					t.Errorf("incorrect --min-sdk-version, expected %q got %q",
-						test.expectedMinSdkVersion, gotMinSdkVersion)
-				}
-
-				if gotTargetSdkVersion != test.expectedMinSdkVersion {
-					t.Errorf("incorrect --target-sdk-version, expected %q got %q",
-						test.expectedMinSdkVersion, gotTargetSdkVersion)
-				}
 			})
 		}
 	}
 }
 
+func TestVendorAppSdkVersion(t *testing.T) {
+	testCases := []struct {
+		name                                  string
+		sdkVersion                            string
+		platformSdkInt                        int
+		platformSdkCodename                   string
+		platformSdkFinal                      bool
+		deviceCurrentApiLevelForVendorModules string
+		expectedMinSdkVersion                 string
+	}{
+		{
+			name:                                  "current final SDK",
+			sdkVersion:                            "current",
+			platformSdkInt:                        29,
+			platformSdkCodename:                   "REL",
+			platformSdkFinal:                      true,
+			deviceCurrentApiLevelForVendorModules: "29",
+			expectedMinSdkVersion:                 "29",
+		},
+		{
+			name:                                  "current final SDK",
+			sdkVersion:                            "current",
+			platformSdkInt:                        29,
+			platformSdkCodename:                   "REL",
+			platformSdkFinal:                      true,
+			deviceCurrentApiLevelForVendorModules: "28",
+			expectedMinSdkVersion:                 "28",
+		},
+		{
+			name:                                  "current final SDK",
+			sdkVersion:                            "current",
+			platformSdkInt:                        29,
+			platformSdkCodename:                   "Q",
+			platformSdkFinal:                      false,
+			deviceCurrentApiLevelForVendorModules: "current",
+			expectedMinSdkVersion:                 "Q",
+		},
+		{
+			name:                                  "current final SDK",
+			sdkVersion:                            "current",
+			platformSdkInt:                        29,
+			platformSdkCodename:                   "Q",
+			platformSdkFinal:                      false,
+			deviceCurrentApiLevelForVendorModules: "28",
+			expectedMinSdkVersion:                 "28",
+		},
+	}
+
+	for _, moduleType := range []string{"android_app", "android_library"} {
+		for _, sdkKind := range []string{"", "system_"} {
+			for _, test := range testCases {
+				t.Run(moduleType+" "+test.name, func(t *testing.T) {
+					bp := fmt.Sprintf(`%s {
+						name: "foo",
+						srcs: ["a.java"],
+						sdk_version: "%s%s",
+						vendor: true,
+					}`, moduleType, sdkKind, test.sdkVersion)
+
+					config := testAppConfig(nil, bp, nil)
+					config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
+					config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
+					config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+					config.TestProductVariables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules
+					config.TestProductVariables.DeviceSystemSdkVersions = []string{"28", "29"}
+					checkSdkVersion(t, config, test.expectedMinSdkVersion)
+				})
+			}
+		}
+	}
+}
+
 func TestJNIABI(t *testing.T) {
 	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
@@ -1579,6 +1657,66 @@
 	}
 }
 
+func TestRequestV4SigningFlag(t *testing.T) {
+	testCases := []struct {
+		name     string
+		bp       string
+		expected string
+	}{
+		{
+			name: "default",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "current",
+				}
+			`,
+			expected: "",
+		},
+		{
+			name: "default",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "current",
+					v4_signature: false,
+				}
+			`,
+			expected: "",
+		},
+		{
+			name: "module certificate property",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "current",
+					v4_signature: true,
+				}
+			`,
+			expected: "--enable-v4",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			config := testAppConfig(nil, test.bp, nil)
+			ctx := testContext()
+
+			run(t, ctx, config)
+			foo := ctx.ModuleForTests("foo", "android_common")
+
+			signapk := foo.Output("foo.apk")
+			signFlags := signapk.Args["flags"]
+			if test.expected != signFlags {
+				t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags)
+			}
+		})
+	}
+}
+
 func TestPackageNameOverride(t *testing.T) {
 	testCases := []struct {
 		name                string
@@ -1701,52 +1839,125 @@
 			base: "foo",
 			package_name: "org.dandroid.bp",
 		}
+
+		override_android_app {
+			name: "baz_no_rename_resources",
+			base: "foo",
+			package_name: "org.dandroid.bp",
+			rename_resources_package: false,
+		}
+
+		android_app {
+			name: "foo_no_rename_resources",
+			srcs: ["a.java"],
+			certificate: "expiredkey",
+			overrides: ["qux"],
+			rename_resources_package: false,
+			sdk_version: "current",
+		}
+
+		override_android_app {
+			name: "baz_base_no_rename_resources",
+			base: "foo_no_rename_resources",
+			package_name: "org.dandroid.bp",
+		}
+
+		override_android_app {
+			name: "baz_override_base_rename_resources",
+			base: "foo_no_rename_resources",
+			package_name: "org.dandroid.bp",
+			rename_resources_package: true,
+		}
 		`)
 
 	expectedVariants := []struct {
-		moduleName     string
-		variantName    string
-		apkName        string
-		apkPath        string
-		certFlag       string
-		lineageFlag    string
-		overrides      []string
-		aaptFlag       string
-		logging_parent string
+		name            string
+		moduleName      string
+		variantName     string
+		apkName         string
+		apkPath         string
+		certFlag        string
+		lineageFlag     string
+		overrides       []string
+		packageFlag     string
+		renameResources bool
+		logging_parent  string
 	}{
 		{
-			moduleName:     "foo",
-			variantName:    "android_common",
-			apkPath:        "/target/product/test_device/system/app/foo/foo.apk",
-			certFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:    "",
-			overrides:      []string{"qux"},
-			aaptFlag:       "",
-			logging_parent: "",
+			name:            "foo",
+			moduleName:      "foo",
+			variantName:     "android_common",
+			apkPath:         "/target/product/test_device/system/app/foo/foo.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux"},
+			packageFlag:     "",
+			renameResources: false,
+			logging_parent:  "",
 		},
 		{
-			moduleName:     "bar",
-			variantName:    "android_common_bar",
-			apkPath:        "/target/product/test_device/system/app/bar/bar.apk",
-			certFlag:       "cert/new_cert.x509.pem cert/new_cert.pk8",
-			lineageFlag:    "--lineage lineage.bin",
-			overrides:      []string{"qux", "foo"},
-			aaptFlag:       "",
-			logging_parent: "bah",
+			name:            "foo",
+			moduleName:      "bar",
+			variantName:     "android_common_bar",
+			apkPath:         "/target/product/test_device/system/app/bar/bar.apk",
+			certFlag:        "cert/new_cert.x509.pem cert/new_cert.pk8",
+			lineageFlag:     "--lineage lineage.bin",
+			overrides:       []string{"qux", "foo"},
+			packageFlag:     "",
+			renameResources: false,
+			logging_parent:  "bah",
 		},
 		{
-			moduleName:     "baz",
-			variantName:    "android_common_baz",
-			apkPath:        "/target/product/test_device/system/app/baz/baz.apk",
-			certFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:    "",
-			overrides:      []string{"qux", "foo"},
-			aaptFlag:       "--rename-manifest-package org.dandroid.bp",
-			logging_parent: "",
+			name:            "foo",
+			moduleName:      "baz",
+			variantName:     "android_common_baz",
+			apkPath:         "/target/product/test_device/system/app/baz/baz.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: true,
+			logging_parent:  "",
+		},
+		{
+			name:            "foo",
+			moduleName:      "baz_no_rename_resources",
+			variantName:     "android_common_baz_no_rename_resources",
+			apkPath:         "/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: false,
+			logging_parent:  "",
+		},
+		{
+			name:            "foo_no_rename_resources",
+			moduleName:      "baz_base_no_rename_resources",
+			variantName:     "android_common_baz_base_no_rename_resources",
+			apkPath:         "/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo_no_rename_resources"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: false,
+			logging_parent:  "",
+		},
+		{
+			name:            "foo_no_rename_resources",
+			moduleName:      "baz_override_base_rename_resources",
+			variantName:     "android_common_baz_override_base_rename_resources",
+			apkPath:         "/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo_no_rename_resources"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: true,
+			logging_parent:  "",
 		},
 	}
 	for _, expected := range expectedVariants {
-		variant := ctx.ModuleForTests("foo", expected.variantName)
+		variant := ctx.ModuleForTests(expected.name, expected.variantName)
 
 		// Check the final apk name
 		outputs := variant.AllOutputs()
@@ -1792,9 +2003,12 @@
 		// Check the package renaming flag, if exists.
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
-		if !strings.Contains(aapt2Flags, expected.aaptFlag) {
-			t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags)
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+		expectedPackage := expected.packageFlag
+		if !expected.renameResources {
+			expectedPackage = ""
 		}
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage)
 	}
 }
 
@@ -1931,6 +2145,7 @@
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag)
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag)
 	}
 }
@@ -2542,6 +2757,19 @@
 		android_app {
 			name: "app",
 			srcs: ["a.java"],
+			libs: ["qux", "quuz"],
+			static_libs: ["static-runtime-helper"],
+			uses_libs: ["foo"],
+			sdk_version: "current",
+			optional_uses_libs: [
+				"bar",
+				"baz",
+			],
+		}
+
+		android_app {
+			name: "app_with_stub_deps",
+			srcs: ["a.java"],
 			libs: ["qux", "quuz.stubs"],
 			static_libs: ["static-runtime-helper"],
 			uses_libs: ["foo"],
@@ -2572,6 +2800,7 @@
 	run(t, ctx, config)
 
 	app := ctx.ModuleForTests("app", "android_common")
+	appWithStubDeps := ctx.ModuleForTests("app_with_stub_deps", "android_common")
 	prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
 
 	// Test that implicit dependencies on java_sdk_library instances are passed to the manifest.
@@ -2602,15 +2831,24 @@
 		t.Errorf("wanted %q in %q", w, cmd)
 	}
 
-	// Test that only present libraries are preopted
+	// Test that all present libraries are preopted, including implicit SDK dependencies
 	cmd = app.Rule("dexpreopt").RuleParams.Command
-
-	if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) {
+	w := `--target-classpath-for-sdk any` +
+		` /system/framework/foo.jar` +
+		`:/system/framework/quuz.jar` +
+		`:/system/framework/qux.jar` +
+		`:/system/framework/runtime-library.jar` +
+		`:/system/framework/bar.jar`
+	if !strings.Contains(cmd, w) {
 		t.Errorf("wanted %q in %q", w, cmd)
 	}
 
-	cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
+	// TODO(skvadrik) fix dexpreopt for stub libraries for which the implementation is present
+	if appWithStubDeps.MaybeRule("dexpreopt").RuleParams.Command != "" {
+		t.Errorf("dexpreopt should be disabled for apps with dependencies on stub libraries")
+	}
 
+	cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
 	if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) {
 		t.Errorf("wanted %q in %q", w, cmd)
 	}
@@ -3032,6 +3270,65 @@
 	}
 }
 
+func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_defaults {
+			name: "rro_defaults",
+			theme: "default_theme",
+			product_specific: true,
+			aaptflags: ["--keep-raw-values"],
+		}
+
+		runtime_resource_overlay {
+			name: "foo_with_defaults",
+			defaults: ["rro_defaults"],
+		}
+
+		runtime_resource_overlay {
+			name: "foo_barebones",
+		}
+		`)
+
+	//
+	// RRO module with defaults
+	//
+	m := ctx.ModuleForTests("foo_with_defaults", "android_common")
+
+	// Check AAPT2 link flags.
+	aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ")
+	expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
+	absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags)
+	if len(absentFlags) > 0 {
+		t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
+	}
+
+	// Check device location.
+	path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+	expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"}
+	if !reflect.DeepEqual(path, expectedPath) {
+		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath)
+	}
+
+	//
+	// RRO module without defaults
+	//
+	m = ctx.ModuleForTests("foo_barebones", "android_common")
+
+	// Check AAPT2 link flags.
+	aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ")
+	unexpectedFlags := "--keep-raw-values"
+	if inList(unexpectedFlags, aapt2Flags) {
+		t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags)
+	}
+
+	// Check device location.
+	path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+	expectedPath = []string{"/tmp/target/product/test_device/system/overlay"}
+	if !reflect.DeepEqual(path, expectedPath) {
+		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
+	}
+}
+
 func TestOverrideRuntimeResourceOverlay(t *testing.T) {
 	ctx, _ := testJava(t, `
 		runtime_resource_overlay {
@@ -3103,65 +3400,7 @@
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "")
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag)
 	}
 }
-
-func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
-	ctx, config := testJava(t, `
-		java_defaults {
-			name: "rro_defaults",
-			theme: "default_theme",
-			product_specific: true,
-			aaptflags: ["--keep-raw-values"],
-		}
-
-		runtime_resource_overlay {
-			name: "foo_with_defaults",
-			defaults: ["rro_defaults"],
-		}
-
-		runtime_resource_overlay {
-			name: "foo_barebones",
-		}
-		`)
-
-	//
-	// RRO module with defaults
-	//
-	m := ctx.ModuleForTests("foo_with_defaults", "android_common")
-
-	// Check AAPT2 link flags.
-	aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ")
-	expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
-	absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags)
-	if len(absentFlags) > 0 {
-		t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
-	}
-
-	// Check device location.
-	path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"}
-	if !reflect.DeepEqual(path, expectedPath) {
-		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath)
-	}
-
-	//
-	// RRO module without defaults
-	//
-	m = ctx.ModuleForTests("foo_barebones", "android_common")
-
-	// Check AAPT2 link flags.
-	aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ")
-	unexpectedFlags := "--keep-raw-values"
-	if inList(unexpectedFlags, aapt2Flags) {
-		t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags)
-	}
-
-	// Check device location.
-	path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath = []string{"/tmp/target/product/test_device/system/overlay"}
-	if !reflect.DeepEqual(path, expectedPath) {
-		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
-	}
-}
diff --git a/java/builder.go b/java/builder.go
index 7318fcb..3043e46 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -385,7 +385,7 @@
 		"outDir":        android.PathForModuleOut(ctx, "turbine", "classes").String(),
 		"javaVersion":   flags.javaVersion.String(),
 	}
-	if ctx.Config().IsEnvTrue("RBE_TURBINE") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
 		rule = turbineRE
 		args["implicits"] = strings.Join(deps.Strings(), ",")
 	}
@@ -452,7 +452,7 @@
 		annoDir = filepath.Join(shardDir, annoDir)
 	}
 	rule := javac
-	if ctx.Config().IsEnvTrue("RBE_JAVAC") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAVAC") {
 		rule = javacRE
 	}
 	ctx.Build(pctx, android.BuildParams{
@@ -480,7 +480,7 @@
 	jarArgs []string, deps android.Paths) {
 
 	rule := jar
-	if ctx.Config().IsEnvTrue("RBE_JAR") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAR") {
 		rule = jarRE
 	}
 	ctx.Build(pctx, android.BuildParams{
diff --git a/java/config/config.go b/java/config/config.go
index 05da3b5..31e2b0f 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -41,6 +41,7 @@
 
 	InstrumentFrameworkModules = []string{
 		"framework",
+		"framework-minus-apex",
 		"telephony-common",
 		"services",
 		"android.car",
@@ -51,6 +52,7 @@
 		"core-libart",
 		// TODO: Could this be all updatable bootclasspath jars?
 		"updatable-media",
+		"framework-mediaprovider",
 		"framework-sdkextensions",
 		"android.net.ipsec.ike",
 	}
diff --git a/java/dex.go b/java/dex.go
index c85914c..21a5926 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -38,6 +38,10 @@
 		// True if the module containing this has it set by default.
 		EnabledByDefault bool `blueprint:"mutated"`
 
+		// If true, runs R8 in Proguard compatibility mode (default).
+		// Otherwise, runs R8 in full mode.
+		Proguard_compatibility *bool
+
 		// If true, optimize for size by removing unused code.  Defaults to true for apps,
 		// false for libraries and tests.
 		Shrink *bool
@@ -113,7 +117,6 @@
 			`rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
 			`mkdir -p $$(dirname ${outUsage}) && ` +
 			`$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
-			`--force-proguard-compatibility ` +
 			`--no-data-resources ` +
 			`-printmapping ${outDict} ` +
 			`-printusage ${outUsage} ` +
@@ -230,6 +233,10 @@
 
 	r8Flags = append(r8Flags, opt.Proguard_flags...)
 
+	if BoolDefault(opt.Proguard_compatibility, true) {
+		r8Flags = append(r8Flags, "--force-proguard-compatibility")
+	}
+
 	// TODO(ccross): Don't shrink app instrumentation tests by default.
 	if !Bool(opt.Shrink) {
 		r8Flags = append(r8Flags, "-dontshrink")
@@ -288,7 +295,7 @@
 			"outUsageZip": proguardUsageZip.String(),
 			"outDir":      outDir.String(),
 		}
-		if ctx.Config().IsEnvTrue("RBE_R8") {
+		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
 			rule = r8RE
 			args["implicits"] = strings.Join(r8Deps.Strings(), ",")
 		}
@@ -304,7 +311,7 @@
 	} else {
 		d8Flags, d8Deps := d8Flags(flags)
 		rule := d8
-		if ctx.Config().IsEnvTrue("RBE_D8") {
+		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") {
 			rule = d8RE
 		}
 		ctx.Build(pctx, android.BuildParams{
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 4c5f66c..e39a556 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -70,10 +70,6 @@
 	// or .aidl files.
 	Srcs []string `android:"path,arch_variant"`
 
-	// list of directories rooted at the Android.bp file that will
-	// be added to the search paths for finding source files when passing package names.
-	Local_sourcepaths []string
-
 	// list of source files that should not be used to build the Java module.
 	// This is most useful in the arch/multilib variants to remove non-common files
 	// filegroup or genrule can be included within this property.
@@ -175,10 +171,6 @@
 	// resources output directory under out/soong/.intermediates.
 	Resourcesoutdir *string
 
-	// if set to true, collect the values used by the Dev tools and
-	// write them in files packaged with the SDK. Defaults to false.
-	Write_sdk_values *bool
-
 	// index.html under current module will be copied to docs out dir, if not null.
 	Static_doc_index_redirect *string `android:"path"`
 
@@ -189,28 +181,6 @@
 	// filegroup or genrule can be included within this property.
 	Knowntags []string `android:"path"`
 
-	// the generated public API filename by Doclava.
-	Api_filename *string
-
-	// the generated removed API filename by Doclava.
-	Removed_api_filename *string
-
-	// the generated removed Dex API filename by Doclava.
-	Removed_dex_api_filename *string
-
-	// if set to false, don't allow droiddoc to generate stubs source files. Defaults to false.
-	Create_stubs *bool
-
-	Check_api struct {
-		Last_released ApiToCheck
-
-		Current ApiToCheck
-
-		// do not perform API check against Last_released, in the case that both two specified API
-		// files by Last_released are modules which don't exist.
-		Ignore_missing_latest_api *bool `blueprint:"mutated"`
-	}
-
 	// if set to true, generate docs through Dokka instead of Doclava.
 	Dokka_enabled *bool
 
@@ -219,10 +189,10 @@
 }
 
 type DroidstubsProperties struct {
-	// the generated public API filename by Metalava.
+	// The generated public API filename by Metalava, defaults to <module>_api.txt
 	Api_filename *string
 
-	// the generated removed API filename by Metalava.
+	// the generated removed API filename by Metalava, defaults to <module>_removed.txt
 	Removed_api_filename *string
 
 	// the generated removed Dex API filename by Metalava.
@@ -639,10 +609,9 @@
 	j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
 	j.srcFiles = append(j.srcFiles, deps.srcs...)
 
-	if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 {
-		j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
+	if len(j.srcFiles) > 0 {
+		j.sourcepaths = android.PathsForModuleSrc(ctx, []string{"."})
 	}
-	j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
 
 	j.argFiles = android.PathsForModuleSrc(ctx, j.properties.Arg_files)
 	argFilesMap := map[string]string{}
@@ -748,17 +717,7 @@
 type Droiddoc struct {
 	Javadoc
 
-	properties        DroiddocProperties
-	apiFile           android.WritablePath
-	privateApiFile    android.WritablePath
-	removedApiFile    android.WritablePath
-	removedDexApiFile android.WritablePath
-
-	checkCurrentApiTimestamp      android.WritablePath
-	updateCurrentApiTimestamp     android.WritablePath
-	checkLastReleasedApiTimestamp android.WritablePath
-
-	apiFilePath android.Path
+	properties DroiddocProperties
 }
 
 // droiddoc converts .java source files to documentation using doclava or dokka.
@@ -783,17 +742,18 @@
 	return module
 }
 
-func (d *Droiddoc) ApiFilePath() android.Path {
-	return d.apiFilePath
+func (d *Droiddoc) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "", ".docs.zip":
+		return android.Paths{d.Javadoc.docZip}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) {
 	d.Javadoc.addDeps(ctx)
 
-	if Bool(d.properties.Check_api.Ignore_missing_latest_api) {
-		ignoreMissingModules(ctx, &d.properties.Check_api.Last_released)
-	}
-
 	if String(d.properties.Custom_template) != "" {
 		ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template))
 	}
@@ -873,41 +833,6 @@
 	}
 }
 
-func (d *Droiddoc) createStubs() bool {
-	return BoolDefault(d.properties.Create_stubs, false)
-}
-
-func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
-	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
-		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
-		String(d.properties.Api_filename) != "" {
-
-		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
-		cmd.FlagWithOutput("-api ", d.apiFile)
-		d.apiFilePath = d.apiFile
-	}
-
-	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
-		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
-		String(d.properties.Removed_api_filename) != "" {
-		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
-		cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
-	}
-
-	if String(d.properties.Removed_dex_api_filename) != "" {
-		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
-		cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
-	}
-
-	if d.createStubs() {
-		cmd.FlagWithArg("-stubs ", stubsDir.String())
-	}
-
-	if Bool(d.properties.Write_sdk_values) {
-		cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String())
-	}
-}
-
 func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) {
 	if String(d.properties.Static_doc_index_redirect) != "" {
 		staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect))
@@ -1010,22 +935,15 @@
 	deps := d.Javadoc.collectDeps(ctx)
 
 	d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
-	d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
 
 	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
 	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
-	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
-	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
 
 	outDir := android.PathForModuleOut(ctx, "out")
 	srcJarDir := android.PathForModuleOut(ctx, "srcjars")
-	stubsDir := android.PathForModuleOut(ctx, "stubsDir")
 
 	rule := android.NewRuleBuilder()
 
-	rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String())
-	rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String())
-
 	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
 
 	var cmd *android.RuleBuilderCommand
@@ -1036,8 +954,6 @@
 			deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
 	}
 
-	d.stubsFlags(ctx, cmd, stubsDir)
-
 	cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles)
 
 	if d.properties.Compat_config != nil {
@@ -1067,120 +983,11 @@
 		FlagWithArg("-C ", outDir.String()).
 		FlagWithArg("-D ", outDir.String())
 
-	rule.Command().
-		BuiltTool(ctx, "soong_zip").
-		Flag("-write_if_changed").
-		Flag("-jar").
-		FlagWithOutput("-o ", d.stubsSrcJar).
-		FlagWithArg("-C ", stubsDir.String()).
-		FlagWithArg("-D ", stubsDir.String())
-
 	rule.Restat()
 
 	zipSyncCleanupCmd(rule, srcJarDir)
 
 	rule.Build(pctx, ctx, "javadoc", desc)
-
-	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
-		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
-		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
-
-		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
-
-		rule := android.NewRuleBuilder()
-
-		rule.Command().Text("( true")
-
-		rule.Command().
-			BuiltTool(ctx, "apicheck").
-			Flag("-JXmx1024m").
-			FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
-			OptionalFlag(d.properties.Check_api.Current.Args).
-			Input(apiFile).
-			Input(d.apiFile).
-			Input(removedApiFile).
-			Input(d.removedApiFile)
-
-		msg := fmt.Sprintf(`\n******************************\n`+
-			`You have tried to change the API from what has been previously approved.\n\n`+
-			`To make these errors go away, you have two choices:\n`+
-			`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
-			`      errors above.\n\n`+
-			`   2. You can update current.txt by executing the following command:\n`+
-			`         make %s-update-current-api\n\n`+
-			`      To submit the revised current.txt to the main Android repository,\n`+
-			`      you will need approval.\n`+
-			`******************************\n`, ctx.ModuleName())
-
-		rule.Command().
-			Text("touch").Output(d.checkCurrentApiTimestamp).
-			Text(") || (").
-			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
-			Text("; exit 38").
-			Text(")")
-
-		rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API")
-
-		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
-
-		// update API rule
-		rule = android.NewRuleBuilder()
-
-		rule.Command().Text("( true")
-
-		rule.Command().
-			Text("cp").Flag("-f").
-			Input(d.apiFile).Flag(apiFile.String())
-
-		rule.Command().
-			Text("cp").Flag("-f").
-			Input(d.removedApiFile).Flag(removedApiFile.String())
-
-		msg = "failed to update public API"
-
-		rule.Command().
-			Text("touch").Output(d.updateCurrentApiTimestamp).
-			Text(") || (").
-			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
-			Text("; exit 38").
-			Text(")")
-
-		rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API")
-	}
-
-	if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
-		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
-		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
-
-		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
-
-		rule := android.NewRuleBuilder()
-
-		rule.Command().
-			Text("(").
-			BuiltTool(ctx, "apicheck").
-			Flag("-JXmx1024m").
-			FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
-			OptionalFlag(d.properties.Check_api.Last_released.Args).
-			Input(apiFile).
-			Input(d.apiFile).
-			Input(removedApiFile).
-			Input(d.removedApiFile)
-
-		msg := `\n******************************\n` +
-			`You have tried to change the API from what has been previously released in\n` +
-			`an SDK.  Please fix the errors listed above.\n` +
-			`******************************\n`
-
-		rule.Command().
-			Text("touch").Output(d.checkLastReleasedApiTimestamp).
-			Text(") || (").
-			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
-			Text("; exit 38").
-			Text(")")
-
-		rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API")
-	}
 }
 
 //
@@ -1314,7 +1121,8 @@
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Api_filename) != "" {
-		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
+		filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
+		d.apiFile = android.PathForModuleOut(ctx, filename)
 		cmd.FlagWithOutput("--api ", d.apiFile)
 		d.apiFilePath = d.apiFile
 	}
@@ -1322,7 +1130,8 @@
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Removed_api_filename) != "" {
-		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
+		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
+		d.removedApiFile = android.PathForModuleOut(ctx, filename)
 		cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
 	}
 
@@ -1464,7 +1273,7 @@
 	// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
 	rule.HighMem()
 	cmd := rule.Command()
-	if ctx.Config().IsEnvTrue("RBE_METALAVA") {
+	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
 		rule.Remoteable(android.RemoteRuleSupports{RBE: true})
 		pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
 		execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
@@ -1600,6 +1409,15 @@
 		d.apiLintReport = android.PathForModuleOut(ctx, "api_lint_report.txt")
 		cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO:  Change to ":api-lint"
 
+		// TODO(b/154317059): Clean up this whitelist by baselining and/or checking in last-released.
+		if d.Name() != "android.car-system-stubs-docs" &&
+			d.Name() != "android.car-stubs-docs" &&
+			d.Name() != "system-api-stubs-docs" &&
+			d.Name() != "test-api-stubs-docs" {
+			cmd.Flag("--lints-as-errors")
+			cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
+		}
+
 		baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
 		updatedBaselineOutput := android.PathForModuleOut(ctx, "api_lint_baseline.txt")
 		d.apiLintTimestamp = android.PathForModuleOut(ctx, "api_lint.timestamp")
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index ea3fbda..61a9b97 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -92,31 +92,34 @@
 // stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image
 // modules.
 func stubFlagsRule(ctx android.SingletonContext) {
-	// Public API stubs
-	publicStubModules := []string{
-		"android_stubs_current",
+	var publicStubModules []string
+	var systemStubModules []string
+	var testStubModules []string
+	var corePlatformStubModules []string
+
+	if ctx.Config().AlwaysUsePrebuiltSdks() {
+		// Build configuration mandates using prebuilt stub modules
+		publicStubModules = append(publicStubModules, "sdk_public_current_android")
+		systemStubModules = append(systemStubModules, "sdk_system_current_android")
+		testStubModules = append(testStubModules, "sdk_test_current_android")
+	} else {
+		// Use stub modules built from source
+		publicStubModules = append(publicStubModules, "android_stubs_current")
+		systemStubModules = append(systemStubModules, "android_system_stubs_current")
+		testStubModules = append(testStubModules, "android_test_stubs_current")
 	}
+	// We do not have prebuilts of the core platform api yet
+	corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
 
 	// Add the android.test.base to the set of stubs only if the android.test.base module is on
 	// the boot jars list as the runtime will only enforce hiddenapi access against modules on
 	// that list.
-	if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().AlwaysUsePrebuiltSdks() {
-		publicStubModules = append(publicStubModules, "android.test.base.stubs")
-	}
-
-	// System API stubs
-	systemStubModules := []string{
-		"android_system_stubs_current",
-	}
-
-	// Test API stubs
-	testStubModules := []string{
-		"android_test_stubs_current",
-	}
-
-	// Core Platform API stubs
-	corePlatformStubModules := []string{
-		"legacy.core.platform.api.stubs",
+	if inList("android.test.base", ctx.Config().BootJars()) {
+		if ctx.Config().AlwaysUsePrebuiltSdks() {
+			publicStubModules = append(publicStubModules, "sdk_public_current_android.test.base")
+		} else {
+			publicStubModules = append(publicStubModules, "android.test.base.stubs")
+		}
 	}
 
 	// Allow products to define their own stubs for custom product jars that apps can use.
@@ -163,6 +166,7 @@
 						return
 					}
 				}
+
 				bootDexJars = append(bootDexJars, jar)
 			}
 		}
@@ -207,6 +211,15 @@
 	rule.Build(pctx, ctx, "hiddenAPIStubFlagsFile", "hiddenapi stub flags")
 }
 
+func moduleForGreyListRemovedApis(ctx android.SingletonContext, module android.Module) bool {
+	switch ctx.ModuleName(module) {
+	case "api-stubs-docs", "system-api-stubs-docs", "android.car-stubs-docs", "android.car-system-stubs-docs":
+		return true
+	default:
+		return false
+	}
+}
+
 // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
 // the unsupported API.
 func flagsRule(ctx android.SingletonContext) android.Path {
@@ -222,7 +235,7 @@
 			// Track @removed public and system APIs via corresponding droidstubs targets.
 			// These APIs are not present in the stubs, however, we have to keep allowing access
 			// to them at runtime.
-			if m := ctx.ModuleName(module); m == "api-stubs-docs" || m == "system-api-stubs-docs" {
+			if moduleForGreyListRemovedApis(ctx, module) {
 				greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile)
 			}
 		}
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
new file mode 100644
index 0000000..dbdab7a
--- /dev/null
+++ b/java/hiddenapi_singleton_test.go
@@ -0,0 +1,219 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+func testConfigWithBootJars(bp string, bootJars []string) android.Config {
+	config := testConfig(nil, bp, nil)
+	config.TestProductVariables.BootJars = bootJars
+	return config
+}
+
+func testContextWithHiddenAPI() *android.TestContext {
+	ctx := testContext()
+	ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	return ctx
+}
+
+func testHiddenAPIWithConfig(t *testing.T, config android.Config) *android.TestContext {
+	t.Helper()
+
+	ctx := testContextWithHiddenAPI()
+
+	run(t, ctx, config)
+	return ctx
+}
+
+func testHiddenAPIBootJars(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) {
+	config := testConfigWithBootJars(bp, bootJars)
+
+	return testHiddenAPIWithConfig(t, config), config
+}
+
+func testHiddenAPIUnbundled(t *testing.T, unbundled bool) (*android.TestContext, android.Config) {
+	config := testConfig(nil, ``, nil)
+	config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(unbundled)
+
+	return testHiddenAPIWithConfig(t, config), config
+}
+
+func TestHiddenAPISingleton(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+	}
+	`, []string{":foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+	}
+	`, []string{":foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+	}
+
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+			prefer: false,
+	}
+	`, []string{":foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
+	}
+
+	prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
+	if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
+		t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+	}
+
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+			prefer: true,
+	}
+	`, []string{":foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
+	}
+
+	fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+	if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
+		t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonSdks(t *testing.T) {
+	testCases := []struct {
+		name             string
+		unbundledBuild   bool
+		publicStub       string
+		systemStub       string
+		testStub         string
+		corePlatformStub string
+	}{
+		{
+			name:             "testBundled",
+			unbundledBuild:   false,
+			publicStub:       "android_stubs_current",
+			systemStub:       "android_system_stubs_current",
+			testStub:         "android_test_stubs_current",
+			corePlatformStub: "legacy.core.platform.api.stubs",
+		}, {
+			name:             "testUnbundled",
+			unbundledBuild:   true,
+			publicStub:       "sdk_public_current_android",
+			systemStub:       "sdk_system_current_android",
+			testStub:         "sdk_test_current_android",
+			corePlatformStub: "legacy.core.platform.api.stubs",
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx, _ := testHiddenAPIUnbundled(t, tc.unbundledBuild)
+
+			hiddenAPI := ctx.SingletonForTests("hiddenapi")
+			hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+			wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantPublicStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantPublicStubs, hiddenapiRule.RuleParams.Command)
+			}
+
+			wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantSystemStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantSystemStubs, hiddenapiRule.RuleParams.Command)
+			}
+
+			wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantTestStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantTestStubs, hiddenapiRule.RuleParams.Command)
+			}
+
+			wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(tc.corePlatformStub)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantCorePlatformStubs, hiddenapiRule.RuleParams.Command)
+			}
+		})
+	}
+}
+
+func generateDexedPath(subDir, dex, module string) string {
+	return fmt.Sprintf("%s/.intermediates/%s/android_common/%s/%s.jar", buildDir, subDir, dex, module)
+}
+
+func generateDexPath(module string) string {
+	return generateDexedPath(module, "dex", module)
+}
+
+func generateSdkDexPath(module string, unbundled bool) string {
+	if unbundled {
+		return generateDexedPath("prebuilts/sdk/"+module, "dex", module)
+	}
+	return generateDexPath(module)
+}
diff --git a/java/java.go b/java/java.go
index 4d7d568..d67e9e0 100644
--- a/java/java.go
+++ b/java/java.go
@@ -324,6 +324,10 @@
 	Stem *string
 
 	IsSDKLibrary bool `blueprint:"mutated"`
+
+	// If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file.
+	// Defaults to false.
+	V4_signature *bool
 }
 
 // Functionality common to Module and Import
@@ -437,6 +441,7 @@
 	hiddenAPI
 	dexer
 	dexpreopter
+	usesLibrary
 	linter
 
 	// list of the xref extraction files
@@ -452,6 +457,7 @@
 	j.AddProperties(
 		&j.properties,
 		&j.protoProperties,
+		&j.usesLibraryProperties,
 	)
 }
 
@@ -679,25 +685,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())
@@ -991,7 +1001,7 @@
 			case libTag:
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 				// names of sdk libs that are directly depended are exported
-				j.exportedSdkLibs.AddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath())
+				j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
 			}
@@ -1483,7 +1493,7 @@
 		args := map[string]string{
 			"jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
 		}
-		if ctx.Config().IsEnvTrue("RBE_ZIP") {
+		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") {
 			rule = zipRE
 			args["implicits"] = strings.Join(services.Strings(), ",")
 		}
@@ -1604,6 +1614,9 @@
 
 		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()
 
 		// Hidden API CSV generation and dex encoding
 		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
@@ -1970,7 +1983,12 @@
 	// add the name of that java_sdk_library to the exported sdk libs to make sure
 	// that, if necessary, a <uses-library> element for that java_sdk_library is
 	// added to the Android manifest.
-	j.exportedSdkLibs.AddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath())
+	j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath())
+
+	// A non-SDK library may provide a <uses-library> (the name may be different from the module name).
+	if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" {
+		j.exportedSdkLibs.AddLibraryPath(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
+	}
 
 	j.distFiles = j.GenerateTaggedDistFiles(ctx)
 }
@@ -2209,6 +2227,7 @@
 	prebuiltTestProperties prebuiltTestProperties
 
 	testConfig android.Path
+	dexJarFile android.Path
 }
 
 func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2531,8 +2550,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
@@ -2546,10 +2571,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()
 }
@@ -2576,6 +2609,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) {
@@ -2593,6 +2630,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)
@@ -2601,14 +2640,18 @@
 		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())
+				j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			}
 		}
 	})
@@ -2623,9 +2666,36 @@
 	// add the name of that java_sdk_library to the exported sdk libs to make sure
 	// that, if necessary, a <uses-library> element for that java_sdk_library is
 	// added to the Android manifest.
-	j.exportedSdkLibs.AddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile)
+	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
+		}
+
+		configurationName := j.BaseModuleName()
+		primary := j.Prebuilt().UsePrebuilt()
+
+		// Hidden API CSV generation and dex encoding
+		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile,
+			proptools.Bool(j.dexProperties.Uncompress_dex))
+
+		j.dexJarFile = dexOutputFile
+	}
 }
 
 var _ Dependency = (*Import)(nil)
@@ -2656,7 +2726,7 @@
 }
 
 func (j *Import) DexJarBuildPath() android.Path {
-	return nil
+	return j.dexJarFile
 }
 
 func (j *Import) DexJarInstallPath() android.Path {
@@ -2724,10 +2794,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..9e63577 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")
 }
 
@@ -1082,16 +1097,26 @@
 		    srcs: ["bar-doc/IBar.aidl"],
 		    path: "bar-doc",
 		}
-		droiddoc {
-		    name: "bar-doc",
+		droidstubs {
+		    name: "bar-stubs",
 		    srcs: [
 		        "bar-doc/a.java",
-		        "bar-doc/IFoo.aidl",
-		        ":bar-doc-aidl-srcs",
 		    ],
 		    exclude_srcs: [
 		        "bar-doc/b.java"
 		    ],
+		    api_levels_annotations_dirs: [
+		      "droiddoc-templates-sdk",
+		    ],
+		    api_levels_annotations_enabled: true,
+		}
+		droiddoc {
+		    name: "bar-doc",
+		    srcs: [
+		        ":bar-stubs",
+		        "bar-doc/IFoo.aidl",
+		        ":bar-doc-aidl-srcs",
+		    ],
 		    custom_template: "droiddoc-templates-sdk",
 		    hdf: [
 		        "android.whichdoc offline",
@@ -1108,23 +1133,29 @@
 			"bar-doc/a.java": nil,
 			"bar-doc/b.java": nil,
 		})
-	barDocModule := ctx.ModuleForTests("bar-doc", "android_common")
-	barDoc := barDocModule.Rule("javadoc")
-	notExpected := " -stubs "
-	if strings.Contains(barDoc.RuleParams.Command, notExpected) {
-		t.Errorf("bar-doc command contains flag %q to create stubs, but should not", notExpected)
+	barStubs := ctx.ModuleForTests("bar-stubs", "android_common")
+	barStubsOutputs, err := barStubs.Module().(*Droidstubs).OutputFiles("")
+	if err != nil {
+		t.Errorf("Unexpected error %q retrieving \"bar-stubs\" output file", err)
+	}
+	if len(barStubsOutputs) != 1 {
+		t.Errorf("Expected one output from \"bar-stubs\" got %s", barStubsOutputs)
 	}
 
-	var javaSrcs []string
-	for _, i := range barDoc.Inputs {
-		javaSrcs = append(javaSrcs, i.Base())
-	}
-	if len(javaSrcs) != 1 || javaSrcs[0] != "a.java" {
-		t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs)
+	barStubsOutput := barStubsOutputs[0]
+	barDoc := ctx.ModuleForTests("bar-doc", "android_common")
+	javaDoc := barDoc.Rule("javadoc")
+	if g, w := javaDoc.Implicits.Strings(), barStubsOutput.String(); !inList(w, g) {
+		t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
 	}
 
-	aidl := barDocModule.Rule("aidl")
-	if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
+	expected := "-sourcepath " + buildDir + "/.intermediates/bar-doc/android_common/srcjars "
+	if !strings.Contains(javaDoc.RuleParams.Command, expected) {
+		t.Errorf("bar-doc command does not contain flag %q, but should\n%q", expected, javaDoc.RuleParams.Command)
+	}
+
+	aidl := barDoc.Rule("aidl")
+	if g, w := javaDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
 		t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
 	}
 
@@ -1144,16 +1175,26 @@
 		    srcs: ["bar-doc/IBar.aidl"],
 		    path: "bar-doc",
 		}
-		droiddoc {
-		    name: "bar-doc",
+		droidstubs {
+		    name: "bar-stubs",
 		    srcs: [
 		        "bar-doc/a.java",
-		        "bar-doc/IFoo.aidl",
-		        ":bar-doc-aidl-srcs",
 		    ],
 		    exclude_srcs: [
 		        "bar-doc/b.java"
 		    ],
+		    api_levels_annotations_dirs: [
+		      "droiddoc-templates-sdk",
+		    ],
+		    api_levels_annotations_enabled: true,
+		}
+		droiddoc {
+		    name: "bar-doc",
+		    srcs: [
+		        ":bar-stubs",
+		        "bar-doc/IFoo.aidl",
+		        ":bar-doc-aidl-srcs",
+		    ],
 		    custom_template: "droiddoc-templates-sdk",
 		    hdf: [
 		        "android.whichdoc offline",
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 8af66d0..021920a 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -19,6 +19,10 @@
 	"android/soong/java/config"
 )
 
+// This variable is effectively unused in pre-master branches, and is
+// included (with the same value as it has in AOSP) only to ease
+// merges between branches (see the comment in the
+// useLegacyCorePlatformApi() function):
 var legacyCorePlatformApiModules = []string{
 	"ahat-test-dump",
 	"android.car",
@@ -132,6 +136,10 @@
 	"wifi-service",
 }
 
+// This variable is effectively unused in pre-master branches, and is
+// included (with the same value as it has in AOSP) only to ease
+// merges between branches (see the comment in the
+// useLegacyCorePlatformApi() function):
 var legacyCorePlatformApiLookup = make(map[string]struct{})
 
 func init() {
@@ -141,8 +149,12 @@
 }
 
 func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool {
-	_, found := legacyCorePlatformApiLookup[ctx.ModuleName()]
-	return found
+	// In pre-master branches, we don't attempt to force usage of the stable
+	// version of the core/platform API. Instead, we always use the legacy
+	// version --- except in tests, where we always use stable, so that we
+	// can make the test assertions the same as other branches.
+	// This should be false in tests and true otherwise:
+	return ctx.Config().TestProductVariables == nil
 }
 
 func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
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/robolectric.go b/java/robolectric.go
index 3fe6626..04fc117 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -31,7 +31,6 @@
 }
 
 var robolectricDefaultLibs = []string{
-	"robolectric_android-all-stub",
 	"Robolectric_all-target",
 	"mockito-robolectric-prebuilt",
 	"truth-prebuilt",
@@ -99,7 +98,8 @@
 
 	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
 
-	ctx.AddVariationDependencies(nil, roboRuntimesTag, "robolectric-android-all-prebuilts")
+	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
+		roboRuntimesTag, "robolectric-android-all-prebuilts")
 }
 
 func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -326,14 +326,16 @@
 	return module
 }
 
-func (r *robolectricTest) InstallBypassMake() bool         { return true }
-func (r *robolectricTest) InstallInTestcases() bool        { return true }
-func (r *robolectricTest) InstallForceOS() *android.OsType { return &android.BuildOs }
+func (r *robolectricTest) InstallBypassMake() bool  { return true }
+func (r *robolectricTest) InstallInTestcases() bool { return true }
+func (r *robolectricTest) InstallForceOS() (*android.OsType, *android.ArchType) {
+	return &android.BuildOs, &android.BuildArch
+}
 
 func robolectricRuntimesFactory() android.Module {
 	module := &robolectricRuntimes{}
 	module.AddProperties(&module.props)
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibCommon)
 	return module
 }
 
@@ -363,6 +365,10 @@
 }
 
 func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if ctx.Target().Os != ctx.Config().BuildOSCommonTarget.Os {
+		return
+	}
+
 	files := android.PathsForModuleSrc(ctx, r.props.Jars)
 
 	androidAllDir := android.PathForModuleInstall(ctx, "android-all")
@@ -390,6 +396,8 @@
 	}
 }
 
-func (r *robolectricRuntimes) InstallBypassMake() bool         { return true }
-func (r *robolectricRuntimes) InstallInTestcases() bool        { return true }
-func (r *robolectricRuntimes) InstallForceOS() *android.OsType { return &android.BuildOs }
+func (r *robolectricRuntimes) InstallBypassMake() bool  { return true }
+func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
+func (r *robolectricRuntimes) InstallForceOS() (*android.OsType, *android.ArchType) {
+	return &android.BuildOs, &android.BuildArch
+}
diff --git a/java/sdk.go b/java/sdk.go
index b44cd8e1..56fa12b 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -191,6 +191,26 @@
 	return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform
 }
 
+func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec {
+	// If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value,
+	// use it instead of "current" for the vendor partition.
+	currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules()
+	if currentSdkVersion == "current" {
+		return s
+	}
+
+	if s.kind == sdkPublic || s.kind == sdkSystem {
+		if s.version.isCurrent() {
+			if i, err := strconv.Atoi(currentSdkVersion); err == nil {
+				version := sdkVersion(i)
+				return sdkSpec{s.kind, version, s.raw}
+			}
+			panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
+		}
+	}
+	return s
+}
+
 // usePrebuilt determines whether prebuilt SDK should be used for this sdkSpec with the given context.
 func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool {
 	if s.version.isCurrent() {
@@ -216,6 +236,10 @@
 	if !s.valid() {
 		return s.version, fmt.Errorf("invalid sdk version %q", s.raw)
 	}
+
+	if ctx.DeviceSpecific() || ctx.SocSpecific() {
+		s = s.forVendorPartition(ctx)
+	}
 	if s.version.isNumbered() {
 		return s.version, nil
 	}
@@ -330,6 +354,10 @@
 		return sdkDep{}
 	}
 
+	if ctx.DeviceSpecific() || ctx.SocSpecific() {
+		sdkVersion = sdkVersion.forVendorPartition(ctx)
+	}
+
 	if !sdkVersion.validateSystemSdk(ctx) {
 		return sdkDep{}
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index a5db56c..1a5ef54 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
@@ -572,9 +575,7 @@
 type commonToSdkLibraryAndImportProperties struct {
 	// The naming scheme to use for the components that this module creates.
 	//
-	// If not specified then it defaults to "default". The other allowable value is
-	// "framework-modules" which matches the scheme currently used by framework modules
-	// for the equivalent components represented as separate Soong modules.
+	// If not specified then it defaults to "default".
 	//
 	// This is a temporary mechanism to simplify conversion from separate modules for each
 	// component that follow a different naming pattern to the default one.
@@ -618,8 +619,6 @@
 	switch schemeProperty {
 	case "default":
 		c.namingScheme = &defaultNamingScheme{}
-	case "framework-modules":
-		c.namingScheme = &frameworkModulesNamingScheme{}
 	default:
 		ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
 		return false
@@ -1086,11 +1085,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 +1111,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 +1158,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 +1167,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 +1206,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 +1239,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 +1252,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
 
@@ -1574,31 +1584,6 @@
 
 var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
 
-type frameworkModulesNamingScheme struct {
-}
-
-func (s *frameworkModulesNamingScheme) moduleSuffix(scope *apiScope) string {
-	suffix := scope.name
-	if scope == apiScopeModuleLib {
-		suffix = "module_libs_"
-	}
-	return suffix
-}
-
-func (s *frameworkModulesNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
-	return fmt.Sprintf("%s-stubs-%sapi", baseName, s.moduleSuffix(scope))
-}
-
-func (s *frameworkModulesNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
-	return fmt.Sprintf("%s-stubs-srcs-%sapi", baseName, s.moduleSuffix(scope))
-}
-
-func (s *frameworkModulesNamingScheme) apiModuleName(scope *apiScope, baseName string) string {
-	return fmt.Sprintf("%s-api-%sapi", baseName, s.moduleSuffix(scope))
-}
-
-var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil)
-
 func moduleStubLinkType(name string) (stub bool, ret linkType) {
 	// This suffix-based approach is fragile and could potentially mis-trigger.
 	// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
@@ -2070,6 +2055,11 @@
 }
 
 // from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) BaseDir() string {
+	return "etc"
+}
+
+// from android.PrebuiltEtcModule
 func (module *sdkLibraryXml) SubDir() string {
 	return "permissions"
 }
diff --git a/java/testing.go b/java/testing.go
index 1e725fa..a472413 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -44,6 +44,9 @@
 		"prebuilts/sdk/17/public/android.jar":                      nil,
 		"prebuilts/sdk/17/public/framework.aidl":                   nil,
 		"prebuilts/sdk/17/system/android.jar":                      nil,
+		"prebuilts/sdk/28/public/android.jar":                      nil,
+		"prebuilts/sdk/28/public/framework.aidl":                   nil,
+		"prebuilts/sdk/28/system/android.jar":                      nil,
 		"prebuilts/sdk/29/public/android.jar":                      nil,
 		"prebuilts/sdk/29/public/framework.aidl":                   nil,
 		"prebuilts/sdk/29/system/android.jar":                      nil,
@@ -85,18 +88,17 @@
 		"prebuilts/sdk/30/system/api/bar-removed.txt":              nil,
 		"prebuilts/sdk/30/test/api/bar-removed.txt":                nil,
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":                nil,
-		"prebuilts/sdk/Android.bp":                                 []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
+		"prebuilts/sdk/Android.bp":                                 []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"], imports_sdk_version: "none", imports_compile_dex:true,}`),
 
 		"bin.py": nil,
 		python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
 		MAIN_FILE = '%main%'`),
 
 		// For java_sdk_library
-		"api/module-lib-current.txt":                        nil,
-		"api/module-lib-removed.txt":                        nil,
-		"api/system-server-current.txt":                     nil,
-		"api/system-server-removed.txt":                     nil,
-		"build/soong/scripts/gen-java-current-api-files.sh": nil,
+		"api/module-lib-current.txt":    nil,
+		"api/module-lib-removed.txt":    nil,
+		"api/system-server-current.txt": nil,
+		"api/system-server-removed.txt": nil,
 	}
 
 	cc.GatherRequiredFilesForTest(mockFS)
@@ -143,6 +145,7 @@
 				srcs: ["a.java"],
 				sdk_version: "none",
 				system_modules: "stable-core-platform-api-stubs-system-modules",
+				compile_dex: true,
 			}
 		`, extra)
 	}
diff --git a/rust/Android.bp b/rust/Android.bp
index bbeb28d..8618207 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -19,7 +19,9 @@
         "prebuilt.go",
         "proc_macro.go",
         "project_json.go",
+        "protobuf.go",
         "rust.go",
+        "strip.go",
         "source_provider.go",
         "test.go",
         "testing.go",
@@ -33,6 +35,7 @@
         "coverage_test.go",
         "library_test.go",
         "project_json_test.go",
+        "protobuf_test.go",
         "rust_test.go",
         "source_provider_test.go",
         "test_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index fda0a25..edae0e6 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -96,7 +96,6 @@
 
 	ret.Class = "EXECUTABLES"
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
 		if binary.coverageOutputZipFile.Valid() {
 			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+binary.coverageOutputZipFile.String())
 		}
@@ -139,9 +138,6 @@
 	}
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		if !library.rlib() {
-			fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
-		}
 		if library.coverageOutputZipFile.Valid() {
 			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+library.coverageOutputZipFile.String())
 		}
@@ -169,23 +165,32 @@
 		stem, suffix, _ := android.SplitFileExt(file)
 		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
 		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 	})
 }
 
 func (bindgen *bindgenDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ctx.SubAndroidMk(ret, bindgen.BaseSourceProvider)
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-	})
+}
+
+func (proto *protobufDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.SubAndroidMk(ret, proto.BaseSourceProvider)
 }
 
 func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	var unstrippedOutputFile android.OptionalPath
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
 	if ctx.Target().Os.Class == android.Host {
 		ret.OutputFile = android.OptionalPathForPath(compiler.path)
+	} else if compiler.strippedOutputFile.Valid() {
+		unstrippedOutputFile = ret.OutputFile
+		ret.OutputFile = compiler.strippedOutputFile
 	}
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		if compiler.strippedOutputFile.Valid() {
+			fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", unstrippedOutputFile)
+		}
 		path, file := filepath.Split(compiler.path.ToMakePath().String())
 		stem, suffix, _ := android.SplitFileExt(file)
 		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
diff --git a/rust/binary.go b/rust/binary.go
index 1a82c92..1d02453 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -24,13 +24,11 @@
 }
 
 type BinaryCompilerProperties struct {
-	// passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib
-	// (assuming it has no dylib dependencies already)
-	Prefer_dynamic *bool
 }
 
 type binaryDecorator struct {
 	*baseCompiler
+	stripper Stripper
 
 	Properties BinaryCompilerProperties
 }
@@ -60,10 +58,6 @@
 	return module, binary
 }
 
-func (binary *binaryDecorator) preferDynamic() bool {
-	return Bool(binary.Properties.Prefer_dynamic)
-}
-
 func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = binary.baseCompiler.compilerFlags(ctx, flags)
 
@@ -76,9 +70,6 @@
 			"-Wl,--no-undefined-version")
 	}
 
-	if binary.preferDynamic() {
-		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
-	}
 	return flags
 }
 
@@ -96,7 +87,8 @@
 
 func (binary *binaryDecorator) compilerProps() []interface{} {
 	return append(binary.baseCompiler.compilerProps(),
-		&binary.Properties)
+		&binary.Properties,
+		&binary.stripper.StripProperties)
 }
 
 func (binary *binaryDecorator) nativeCoverage() bool {
@@ -105,15 +97,20 @@
 
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
-
 	srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
-
 	outputFile := android.PathForModuleOut(ctx, fileName)
-	binary.unstrippedOutputFile = outputFile
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+
+	if binary.stripper.NeedsStrip(ctx) {
+		strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
+		binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+		binary.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+	}
+
 	binary.coverageFile = outputs.coverageFile
 
 	var coverageFiles android.Paths
@@ -132,8 +129,9 @@
 	return binary.coverageOutputZipFile
 }
 
-func (binary *binaryDecorator) autoDep() autoDep {
-	if binary.preferDynamic() {
+func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep {
+	// Binaries default to dylib dependencies for device, rlib for host.
+	if ctx.Device() {
 		return dylibAutoDep
 	} else {
 		return rlibAutoDep
diff --git a/rust/binary_test.go b/rust/binary_test.go
index b9c8698..cfef57a 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -17,44 +17,112 @@
 import (
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
-// Test that the prefer_dynamic property is handled correctly.
-func TestPreferDynamicBinary(t *testing.T) {
+// Test that rustlibs default linkage is correct for binaries.
+func TestBinaryLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "fizz-buzz",
+			srcs: ["foo.rs"],
+			rustlibs: ["libfoo"],
+			host_supported: true,
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			host_supported: true,
+		}`)
+
+	fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+	fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
+
+	if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules")
+	}
+
+	if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
+		t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
+	}
+}
+
+// Test that the path returned by HostToolPath is correct
+func TestHostToolPath(t *testing.T) {
 	ctx := testRust(t, `
 		rust_binary_host {
-			name: "fizz-buzz-dynamic",
+			name: "fizz-buzz",
 			srcs: ["foo.rs"],
-			prefer_dynamic: true,
-		}
+		}`)
 
+	path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath()
+	if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) {
+		t.Errorf("wrong host tool path, expected %q got %q", w, g)
+	}
+}
+
+// Test that the flags being passed to rust_binary modules are as expected
+func TestBinaryFlags(t *testing.T) {
+	ctx := testRust(t, `
 		rust_binary_host {
 			name: "fizz-buzz",
 			srcs: ["foo.rs"],
 		}`)
 
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
-	fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic")
 
-	path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath()
-	if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) {
-		t.Errorf("wrong host tool path, expected %q got %q", w, g)
-	}
-
-	// Do not compile binary modules with the --test flag.
-	flags := fizzBuzzDynamic.Args["rustcFlags"]
+	flags := fizzBuzz.Args["rustcFlags"]
 	if strings.Contains(flags, "--test") {
 		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
 	}
-	if !strings.Contains(flags, "prefer-dynamic") {
-		t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags)
+}
+
+func TestLinkObjects(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "fizz-buzz",
+			srcs: ["foo.rs"],
+			shared_libs: ["libfoo"],
+		}
+		cc_library {
+			name: "libfoo",
+		}`)
+
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz")
+	linkFlags := fizzBuzz.Args["linkFlags"]
+	if !strings.Contains(linkFlags, "/libfoo.so") {
+		t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
+	}
+}
+
+// Test that stripped versions are correctly generated and used.
+func TestStrippedBinary(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "foo",
+			srcs: ["foo.rs"],
+		}
+		rust_binary {
+			name: "bar",
+			srcs: ["foo.rs"],
+			strip: {
+				none: true
+			}
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a")
+	foo.Output("stripped/foo")
+	// Check that the `cp` rules is using the stripped version as input.
+	cp := foo.Rule("android.Cp")
+	if !strings.HasSuffix(cp.Input.String(), "stripped/foo") {
+		t.Errorf("installed binary not based on stripped version: %v", cp.Input)
 	}
 
-	flags = fizzBuzz.Args["rustcFlags"]
-	if strings.Contains(flags, "--test") {
-		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
-	}
-	if strings.Contains(flags, "prefer-dynamic") {
-		t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags)
+	fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("stripped/bar")
+	if fizzBar.Rule != nil {
+		t.Errorf("stripped version of bar has been generated")
 	}
 }
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 9b09e61..cafdb8b 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -21,22 +21,20 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	ccConfig "android/soong/cc/config"
 )
 
 var (
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion  = "clang-r383902c"
-	bindgenLibClangSoGit = "11git"
+	bindgenClangVersion = "clang-r383902c"
 
 	//TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
 	_ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen")
 	_ = pctx.SourcePathVariable("bindgenClang",
-		"${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang")
+		"${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang")
 	_ = pctx.SourcePathVariable("bindgenLibClang",
-		"${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/libclang.so."+bindgenLibClangSoGit)
+		"${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/")
 
 	//TODO(ivanlozano) Switch this to RuleBuilder
 	bindgen = pctx.AndroidStaticRule("bindgen",
@@ -92,24 +90,23 @@
 	Properties BindgenProperties
 }
 
-func (b *bindgenDecorator) GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path {
-	ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch())
+func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
+	ccToolchain := ctx.RustModule().ccToolchain(ctx)
 
 	var cflags []string
 	var implicits android.Paths
 
-	implicits = append(implicits, deps.depIncludePaths...)
-	implicits = append(implicits, deps.depSystemIncludePaths...)
+	implicits = append(implicits, deps.depGeneratedHeaders...)
 
 	// Default clang flags
-	cflags = append(cflags, "${ccConfig.CommonClangGlobalCflags}")
+	cflags = append(cflags, "${cc_config.CommonClangGlobalCflags}")
 	if ctx.Device() {
-		cflags = append(cflags, "${ccConfig.DeviceClangGlobalCflags}")
+		cflags = append(cflags, "${cc_config.DeviceClangGlobalCflags}")
 	}
 
 	// Toolchain clang flags
 	cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
-	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig."))
+	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${cc_config."))
 
 	// Dependency clang flags and include paths
 	cflags = append(cflags, deps.depClangFlags...)
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/rust/compiler.go b/rust/compiler.go
index ef7fb8c..664578d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -129,8 +129,9 @@
 	location installLocation
 
 	coverageOutputZipFile android.OptionalPath
-	unstrippedOutputFile  android.Path
 	distFile              android.OptionalPath
+	// Stripped output file. If Valid(), this file will be installed instead of outputFile.
+	strippedOutputFile android.OptionalPath
 }
 
 func (compiler *baseCompiler) Disabled() bool {
@@ -145,6 +146,10 @@
 	panic("baseCompiler does not implement coverageOutputZipPath()")
 }
 
+func (compiler *baseCompiler) static() bool {
+	return false
+}
+
 var _ compiler = (*baseCompiler)(nil)
 
 func (compiler *baseCompiler) inData() bool {
@@ -211,12 +216,20 @@
 
 	if !Bool(compiler.Properties.No_stdlibs) {
 		for _, stdlib := range config.Stdlibs {
-			// If we're building for the primary host target, use the compiler's stdlibs
-			if ctx.Host() && ctx.TargetPrimary() {
+			// If we're building for the primary arch of the build host, use the compiler's stdlibs
+			if ctx.Target().Os == android.BuildOs && ctx.TargetPrimary() {
 				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
 			}
 
-			deps.Rustlibs = append(deps.Rustlibs, stdlib)
+			// For devices, we always link stdlibs in as dylibs except for ffi static libraries.
+			// (rustc does not support linking libstd as a dylib for ffi static libraries)
+			if ctx.Host() {
+				deps.Rustlibs = append(deps.Rustlibs, stdlib)
+			} else if ctx.RustModule().compiler.static() {
+				deps.Rlibs = append(deps.Rlibs, stdlib)
+			} else {
+				deps.Dylibs = append(deps.Dylibs, stdlib)
+			}
 		}
 	}
 	return deps
@@ -257,8 +270,12 @@
 	return false
 }
 
-func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
-	compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
+func (compiler *baseCompiler) install(ctx ModuleContext) {
+	path := ctx.RustModule().outputFile
+	if compiler.strippedOutputFile.Valid() {
+		path = compiler.strippedOutputFile
+	}
+	compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path())
 }
 
 func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index 8b9fccc..56a8ef8 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -177,3 +177,30 @@
 		})
 	}
 }
+
+// Test that devices are linking the stdlib dynamically
+func TestStdDeviceLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "fizz",
+			srcs: ["foo.rs"],
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
+	fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module)
+	fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
+
+	if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) {
+		t.Errorf("libstd is not linked dynamically for device binaries")
+	}
+	if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) {
+		t.Errorf("libstd is not linked dynamically for rlibs")
+	}
+	if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) {
+		t.Errorf("libstd is not linked dynamically for dylibs")
+	}
+}
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index bcfac7c..e0cc4ce 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -16,5 +16,6 @@
         "x86_linux_host.go",
         "x86_device.go",
         "x86_64_device.go",
+        "arm64_linux_host.go",
     ],
 }
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index cecf10c..21b22a4 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -23,12 +23,7 @@
 var (
 	Arm64RustFlags            = []string{}
 	Arm64ArchFeatureRustFlags = map[string][]string{}
-	Arm64LinkFlags            = []string{
-		"-Wl,--icf=safe",
-		"-Wl,-z,max-page-size=4096",
-
-		"-Wl,-z,separate-code",
-	}
+	Arm64LinkFlags            = []string{}
 
 	Arm64ArchVariantRustFlags = map[string][]string{
 		"armv8-a":  []string{},
@@ -60,7 +55,8 @@
 }
 
 func (t *toolchainArm64) ToolchainLinkFlags() string {
-	return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${config.DeviceGlobalLinkFlags} ${cc_config.Arm64Lldflags} ${config.Arm64ToolchainLinkFlags}"
 }
 
 func (t *toolchainArm64) ToolchainRustFlags() string {
@@ -76,9 +72,16 @@
 }
 
 func Arm64ToolchainFactory(arch android.Arch) Toolchain {
+	archVariant := arch.ArchVariant
+	if archVariant == "" {
+		// arch variants defaults to armv8-a. This is mostly for
+		// the host target which borrows toolchain configs from here.
+		archVariant = "armv8-a"
+	}
+
 	toolchainRustFlags := []string{
 		"${config.Arm64ToolchainRustFlags}",
-		"${config.Arm64" + arch.ArchVariant + "VariantRustFlags}",
+		"${config.Arm64" + archVariant + "VariantRustFlags}",
 	}
 
 	toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
diff --git a/rust/config/arm64_linux_host.go b/rust/config/arm64_linux_host.go
new file mode 100644
index 0000000..baf9cf8
--- /dev/null
+++ b/rust/config/arm64_linux_host.go
@@ -0,0 +1,24 @@
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+	"android/soong/android"
+)
+
+func init() {
+	// Linux_cross-arm64 uses the same rust toolchain as the Android-arm64
+	registerToolchainFactory(android.LinuxBionic, android.Arm64, Arm64ToolchainFactory)
+}
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
index ac2580b..ac4f1c6 100644
--- a/rust/config/arm_device.go
+++ b/rust/config/arm_device.go
@@ -23,10 +23,7 @@
 var (
 	ArmRustFlags            = []string{}
 	ArmArchFeatureRustFlags = map[string][]string{}
-	ArmLinkFlags            = []string{
-		"-Wl,--icf=safe",
-		"-Wl,-m,armelf",
-	}
+	ArmLinkFlags            = []string{}
 
 	ArmArchVariantRustFlags = map[string][]string{
 		"armv7-a":      []string{},
@@ -59,7 +56,8 @@
 }
 
 func (t *toolchainArm) ToolchainLinkFlags() string {
-	return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${config.DeviceGlobalLinkFlags} ${cc_config.ArmLldflags} ${config.ArmToolchainLinkFlags}"
 }
 
 func (t *toolchainArm) ToolchainRustFlags() string {
diff --git a/rust/config/global.go b/rust/config/global.go
index 97de676..71c4240 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var pctx = android.NewPackageContext("android/soong/rust/config")
 
 var (
-	RustDefaultVersion = "1.45.2"
+	RustDefaultVersion = "1.46.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2018"
 	Stdlibs            = []string{
@@ -42,21 +42,18 @@
 	deviceGlobalRustFlags = []string{}
 
 	deviceGlobalLinkFlags = []string{
+		// Prepend the lld flags from cc_config so we stay in sync with cc
+		"${cc_config.DeviceGlobalLldflags}",
+
+		// Override cc's --no-undefined-version to allow rustc's generated alloc functions
+		"-Wl,--undefined-version",
+
 		"-Bdynamic",
 		"-nostdlib",
-		"-Wl,-z,noexecstack",
-		"-Wl,-z,relro",
-		"-Wl,-z,now",
-		"-Wl,--build-id=md5",
-		"-Wl,--warn-shared-textrel",
-		"-Wl,--fatal-warnings",
-
 		"-Wl,--pack-dyn-relocs=android+relr",
+		"-Wl,--use-android-relr-tags",
 		"-Wl,--no-undefined",
-		"-Wl,--hash-style=gnu",
-
-		"-B${ccConfig.ClangBin}",
-		"-fuse-ld=lld",
+		"-B${cc_config.ClangBin}",
 	}
 )
 
@@ -81,8 +78,8 @@
 	pctx.StaticVariable("RustPath", "${RustBase}/${HostPrebuiltTag}/${RustVersion}")
 	pctx.StaticVariable("RustBin", "${RustPath}/bin")
 
-	pctx.ImportAs("ccConfig", "android/soong/cc/config")
-	pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++")
+	pctx.ImportAs("cc_config", "android/soong/cc/config")
+	pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++")
 	pctx.StaticVariable("RustLinkerArgs", "")
 
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index 9a6c00b..5f6e85a 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -61,7 +61,8 @@
 }
 
 func (t *toolchainX86_64) ToolchainLinkFlags() string {
-	return "${config.DeviceGlobalLinkFlags} ${config.X86_64ToolchainLinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${config.DeviceGlobalLinkFlags} ${cc_config.X86_64Lldflags} ${config.X86_64ToolchainLinkFlags}"
 }
 
 func (t *toolchainX86_64) ToolchainRustFlags() string {
diff --git a/rust/config/x86_darwin_host.go b/rust/config/x86_darwin_host.go
index 4104400..ddd93e8 100644
--- a/rust/config/x86_darwin_host.go
+++ b/rust/config/x86_darwin_host.go
@@ -23,7 +23,7 @@
 var (
 	DarwinRustFlags     = []string{}
 	DarwinRustLinkFlags = []string{
-		"-B${ccConfig.MacToolPath}",
+		"-B${cc_config.MacToolPath}",
 	}
 	darwinX8664Rustflags = []string{}
 	darwinX8664Linkflags = []string{}
@@ -77,7 +77,8 @@
 }
 
 func (t *toolchainDarwinX8664) ToolchainLinkFlags() string {
-	return "${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${cc_config.DarwinClangLldflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}"
 }
 
 func (t *toolchainDarwinX8664) ToolchainRustFlags() string {
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index ec19b3c..daeeb14 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -64,7 +64,8 @@
 }
 
 func (t *toolchainX86) ToolchainLinkFlags() string {
-	return "${config.DeviceGlobalLinkFlags} ${config.X86ToolchainLinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${config.DeviceGlobalLinkFlags} ${cc_config.X86ClangLldflags} ${config.X86ToolchainLinkFlags}"
 }
 
 func (t *toolchainX86) ToolchainRustFlags() string {
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
index acc99e1..e7f26ce 100644
--- a/rust/config/x86_linux_host.go
+++ b/rust/config/x86_linux_host.go
@@ -23,8 +23,9 @@
 var (
 	LinuxRustFlags     = []string{}
 	LinuxRustLinkFlags = []string{
-		"-B${ccConfig.ClangBin}",
+		"-B${cc_config.ClangBin}",
 		"-fuse-ld=lld",
+		"-Wl,--undefined-version",
 	}
 	linuxX86Rustflags   = []string{}
 	linuxX86Linkflags   = []string{}
@@ -77,7 +78,9 @@
 }
 
 func (t *toolchainLinuxX8664) ToolchainLinkFlags() string {
-	return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${cc_config.LinuxClangLldflags} ${cc_config.LinuxX8664ClangLldflags} " +
+		"${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
 }
 
 func (t *toolchainLinuxX8664) ToolchainRustFlags() string {
@@ -105,7 +108,9 @@
 }
 
 func (t *toolchainLinuxX86) ToolchainLinkFlags() string {
-	return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${cc_config.LinuxClangLldflags} ${cc_config.LinuxX86ClangLldflags} " +
+		"${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
 }
 
 func (t *toolchainLinuxX86) ToolchainRustFlags() string {
diff --git a/rust/coverage.go b/rust/coverage.go
index 223ba4f..26375f5 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -53,7 +53,7 @@
 		flags.Coverage = true
 		coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
 		flags.RustFlags = append(flags.RustFlags,
-			"-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads")
+			"-Z profile", "-g", "-C opt-level=0", "-C link-dead-code")
 		flags.LinkFlags = append(flags.LinkFlags,
 			"--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv")
 		deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 357c2e8..73673d0 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -56,7 +56,7 @@
 	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
 	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
 
-	rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"}
+	rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"}
 	for _, flag := range rustcCoverageFlags {
 		missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
diff --git a/rust/library.go b/rust/library.go
index 6766d61..a442933 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -78,6 +78,7 @@
 type libraryDecorator struct {
 	*baseCompiler
 	*flagExporter
+	stripper Stripper
 
 	Properties        LibraryCompilerProperties
 	MutatedProperties LibraryMutatedProperties
@@ -176,13 +177,13 @@
 	library.MutatedProperties.VariantIsDylib = false
 }
 
-func (library *libraryDecorator) autoDep() autoDep {
+func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep {
 	if library.rlib() || library.static() {
 		return rlibAutoDep
 	} else if library.dylib() || library.shared() {
 		return dylibAutoDep
 	} else {
-		return rlibAutoDep
+		panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.")
 	}
 }
 
@@ -338,7 +339,8 @@
 func (library *libraryDecorator) compilerProps() []interface{} {
 	return append(library.baseCompiler.compilerProps(),
 		&library.Properties,
-		&library.MutatedProperties)
+		&library.MutatedProperties,
+		&library.stripper.StripProperties)
 }
 
 func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
@@ -371,7 +373,8 @@
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
-	var outputFile android.WritablePath
+	var outputFile android.ModuleOutPath
+	var fileName string
 	var srcPath android.Path
 
 	if library.sourceProvider != nil {
@@ -381,6 +384,7 @@
 	}
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if library.dylib() {
 		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -390,31 +394,37 @@
 	}
 
 	if library.rlib() {
-		fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+		fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
 		outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 		library.coverageFile = outputs.coverageFile
 	} else if library.dylib() {
-		fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
+		fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
 		outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 		library.coverageFile = outputs.coverageFile
 	} else if library.static() {
-		fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
+		fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
 		outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 		library.coverageFile = outputs.coverageFile
 	} else if library.shared() {
-		fileName := library.sharedLibFilename(ctx)
+		fileName = library.sharedLibFilename(ctx)
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
 		outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 		library.coverageFile = outputs.coverageFile
 	}
 
+	if !library.rlib() && library.stripper.NeedsStrip(ctx) {
+		strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
+		library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+		library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+	}
+
 	var coverageFiles android.Paths
 	if library.coverageFile != nil {
 		coverageFiles = append(coverageFiles, library.coverageFile)
@@ -427,8 +437,8 @@
 	if library.rlib() || library.dylib() {
 		library.exportLinkDirs(deps.linkDirs...)
 		library.exportDepFlags(deps.depFlags...)
+		library.exportLinkObjects(deps.linkObjects...)
 	}
-	library.unstrippedOutputFile = outputFile
 
 	return outputFile
 }
diff --git a/rust/library_test.go b/rust/library_test.go
index 8a91cf1..f1bc050 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -144,6 +144,22 @@
 	}
 }
 
+func TestStaticLibraryLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_ffi_static {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
+
+	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
+		t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
+			libfoo.Module().(*Module).Properties.AndroidMkDylibs)
+	}
+}
+
 // Test that variants pull in the right type of rustlib autodep
 func TestAutoDeps(t *testing.T) {
 
@@ -190,3 +206,35 @@
 
 	}
 }
+
+// Test that stripped versions are correctly generated and used.
+func TestStrippedLibrary(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_dylib {
+			name: "libfoo",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+		}
+		rust_library_dylib {
+			name: "libbar",
+			crate_name: "bar",
+			srcs: ["foo.rs"],
+			strip: {
+				none: true
+			}
+		}
+	`)
+
+	foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib")
+	foo.Output("stripped/libfoo.dylib.so")
+	// Check that the `cp` rule is using the stripped version as input.
+	cp := foo.Rule("android.Cp")
+	if !strings.HasSuffix(cp.Input.String(), "stripped/libfoo.dylib.so") {
+		t.Errorf("installed binary not based on stripped version: %v", cp.Input)
+	}
+
+	fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("stripped/libbar.dylib.so")
+	if fizzBar.Rule != nil {
+		t.Errorf("stripped version of bar has been generated")
+	}
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 3d081c1..f9c8934 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -99,9 +99,6 @@
 	if len(paths) > 0 {
 		ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
 	}
-
-	prebuilt.unstrippedOutputFile = srcPath
-
 	return srcPath
 }
 
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 3dd2521..0c6ec99 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -66,9 +66,6 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
 	srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
-
-	procMacro.unstrippedOutputFile = outputFile
-
 	TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	return outputFile
 }
@@ -80,6 +77,6 @@
 	return stem + String(procMacro.baseCompiler.Properties.Suffix)
 }
 
-func (procMacro *procMacroDecorator) autoDep() autoDep {
+func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep {
 	return rlibAutoDep
 }
diff --git a/rust/protobuf.go b/rust/protobuf.go
new file mode 100644
index 0000000..897300f
--- /dev/null
+++ b/rust/protobuf.go
@@ -0,0 +1,109 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"android/soong/android"
+)
+
+var (
+	defaultProtobufFlags = []string{""}
+)
+
+func init() {
+	android.RegisterModuleType("rust_protobuf", RustProtobufFactory)
+	android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
+}
+
+var _ SourceProvider = (*protobufDecorator)(nil)
+
+type ProtobufProperties struct {
+	// Path to the proto file that will be used to generate the source
+	Proto *string `android:"path,arch_variant"`
+
+	// List of additional flags to pass to aprotoc
+	Proto_flags []string `android:"arch_variant"`
+}
+
+type protobufDecorator struct {
+	*BaseSourceProvider
+
+	Properties ProtobufProperties
+}
+
+func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
+	var protoFlags android.ProtoFlags
+	pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+
+	protoFlags.OutTypeFlag = "--rust_out"
+
+	protoFlags.Flags = append(protoFlags.Flags, " --plugin="+pluginPath.String())
+	protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...)
+	protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...)
+
+	protoFlags.Deps = append(protoFlags.Deps, pluginPath)
+
+	protoFile := android.OptionalPathForModuleSrc(ctx, proto.Properties.Proto)
+	if !protoFile.Valid() {
+		ctx.PropertyErrorf("proto", "invalid path to proto file")
+	}
+
+	outDir := android.PathForModuleOut(ctx)
+	depFile := android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".d")
+	outputs := android.WritablePaths{android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".rs")}
+
+	rule := android.NewRuleBuilder()
+	android.ProtoRule(ctx, rule, protoFile.Path(), protoFlags, protoFlags.Deps, outDir, depFile, outputs)
+	rule.Build(pctx, ctx, "protoc_"+protoFile.Path().Rel(), "protoc "+protoFile.Path().Rel())
+
+	proto.BaseSourceProvider.OutputFile = outputs[0]
+	return outputs[0]
+}
+
+func (proto *protobufDecorator) SourceProviderProps() []interface{} {
+	return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties)
+}
+
+func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
+	deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
+	deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
+	return deps
+}
+
+// rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for
+// protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will
+// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
+// properties of other modules.
+func RustProtobufFactory() android.Module {
+	module, _ := NewRustProtobuf(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+// A host-only variant of rust_protobuf. Refer to rust_protobuf for more details.
+func RustProtobufHostFactory() android.Module {
+	module, _ := NewRustProtobuf(android.HostSupported)
+	return module.Init()
+}
+
+func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
+	protobuf := &protobufDecorator{
+		BaseSourceProvider: NewSourceProvider(),
+		Properties:         ProtobufProperties{},
+	}
+
+	module := NewSourceProviderModule(hod, protobuf, false)
+
+	return module, protobuf
+}
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
new file mode 100644
index 0000000..a9dbf39
--- /dev/null
+++ b/rust/protobuf_test.go
@@ -0,0 +1,39 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"android/soong/android"
+	"testing"
+)
+
+func TestRustProtobuf(t *testing.T) {
+	ctx := testRust(t, `
+		rust_protobuf {
+			name: "librust_proto",
+			proto: "buf.proto",
+			crate_name: "rust_proto",
+			source_stem: "buf",
+		}
+	`)
+	// Check that there's a rule to generate the expected output
+	_ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Output("buf.rs")
+
+	// Check that libprotobuf is added as a dependency.
+	librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
+	if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
+		t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
+	}
+}
diff --git a/rust/rust.go b/rust/rust.go
index b697869..b98992c 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -23,6 +23,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	cc_config "android/soong/cc/config"
 	"android/soong/rust/config"
 )
 
@@ -42,7 +43,7 @@
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
-	pctx.ImportAs("ccConfig", "android/soong/cc/config")
+	pctx.ImportAs("cc_config", "android/soong/cc/config")
 }
 
 type Flags struct {
@@ -244,18 +245,20 @@
 }
 
 type PathDeps struct {
-	DyLibs     RustLibraries
-	RLibs      RustLibraries
-	SharedLibs android.Paths
-	StaticLibs android.Paths
-	ProcMacros RustLibraries
-	linkDirs   []string
-	depFlags   []string
+	DyLibs      RustLibraries
+	RLibs       RustLibraries
+	SharedLibs  android.Paths
+	StaticLibs  android.Paths
+	ProcMacros  RustLibraries
+	linkDirs    []string
+	depFlags    []string
+	linkObjects []string
 	//ReexportedDeps android.Paths
 
 	// Used by bindgen modules which call clang
 	depClangFlags         []string
 	depIncludePaths       android.Paths
+	depGeneratedHeaders   android.Paths
 	depSystemIncludePaths android.Paths
 
 	coverageFiles android.Paths
@@ -282,25 +285,30 @@
 	crateName() string
 
 	inData() bool
-	install(ctx ModuleContext, path android.Path)
+	install(ctx ModuleContext)
 	relativeInstallPath() string
 
 	nativeCoverage() bool
 
 	Disabled() bool
 	SetDisabled()
+
+	static() bool
 }
 
 type exportedFlagsProducer interface {
 	exportedLinkDirs() []string
 	exportedDepFlags() []string
+	exportedLinkObjects() []string
 	exportLinkDirs(...string)
 	exportDepFlags(...string)
+	exportLinkObjects(...string)
 }
 
 type flagExporter struct {
-	depFlags []string
-	linkDirs []string
+	depFlags    []string
+	linkDirs    []string
+	linkObjects []string
 }
 
 func (flagExporter *flagExporter) exportedLinkDirs() []string {
@@ -311,6 +319,10 @@
 	return flagExporter.depFlags
 }
 
+func (flagExporter *flagExporter) exportedLinkObjects() []string {
+	return flagExporter.linkObjects
+}
+
 func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
 	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
 }
@@ -319,12 +331,17 @@
 	flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...))
 }
 
+func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
+	flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
+}
+
 var _ exportedFlagsProducer = (*flagExporter)(nil)
 
 func NewFlagExporter() *flagExporter {
 	return &flagExporter{
-		depFlags: []string{},
-		linkDirs: []string{},
+		depFlags:    []string{},
+		linkDirs:    []string{},
+		linkObjects: []string{},
 	}
 }
 
@@ -543,21 +560,6 @@
 	android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
 
 	android.InitDefaultableModule(mod)
-
-	// Explicitly disable unsupported targets.
-	android.AddLoadHook(mod, func(ctx android.LoadHookContext) {
-		disableTargets := struct {
-			Target struct {
-				Linux_bionic struct {
-					Enabled *bool
-				}
-			}
-		}{}
-		disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
-
-		ctx.AppendProperties(&disableTargets)
-	})
-
 	return mod
 }
 
@@ -641,6 +643,10 @@
 	return mod.cachedToolchain
 }
 
+func (mod *Module) ccToolchain(ctx android.BaseModuleContext) cc_config.Toolchain {
+	return cc_config.FindToolchain(ctx.Os(), ctx.Arch())
+}
+
 func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
@@ -684,7 +690,7 @@
 
 		mod.outputFile = android.OptionalPathForPath(outputFile)
 		if mod.outputFile.Valid() && !mod.Properties.PreventInstall {
-			mod.compiler.install(ctx, mod.outputFile.Path())
+			mod.compiler.install(ctx)
 		}
 	}
 }
@@ -740,7 +746,7 @@
 )
 
 type autoDeppable interface {
-	autoDep() autoDep
+	autoDep(ctx BaseModuleContext) autoDep
 }
 
 func (mod *Module) begin(ctx BaseModuleContext) {
@@ -811,6 +817,7 @@
 			if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok && depTag != procMacroDepTag {
 				depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedLinkDirs()...)
 				depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, lib.exportedLinkObjects()...)
 			}
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -838,51 +845,49 @@
 					return
 				}
 			}
-			linkFile := ccDep.OutputFile()
-			linkPath := linkPathFromFilePath(linkFile.Path())
-			libName := libNameFromFilePath(linkFile.Path())
-			depFlag := "-l" + libName
+			linkObject := ccDep.OutputFile()
+			linkPath := linkPathFromFilePath(linkObject.Path())
 
-			if !linkFile.Valid() {
+			if !linkObject.Valid() {
 				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
 			}
 
 			exportDep := false
 			switch {
 			case cc.IsStaticDepTag(depTag):
-				depFlag = "-lstatic=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.depFlags = append(depPaths.depFlags, depFlag)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...)
 				if mod, ok := ccDep.(*cc.Module); ok {
 					depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...)
 					depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...)
+					depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, mod.ExportedGeneratedHeaders()...)
 				}
 				depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
 			case cc.IsSharedDepTag(depTag):
-				depFlag = "-ldylib=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.depFlags = append(depPaths.depFlags, depFlag)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...)
 				if mod, ok := ccDep.(*cc.Module); ok {
 					depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...)
 					depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...)
+					depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, mod.ExportedGeneratedHeaders()...)
 				}
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
 			case depTag == cc.CrtBeginDepTag:
-				depPaths.CrtBegin = linkFile
+				depPaths.CrtBegin = linkObject
 			case depTag == cc.CrtEndDepTag:
-				depPaths.CrtEnd = linkFile
+				depPaths.CrtEnd = linkObject
 			}
 
 			// Make sure these dependencies are propagated
 			if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
 				lib.exportLinkDirs(linkPath)
-				lib.exportDepFlags(depFlag)
+				lib.exportLinkObjects(linkObject.String())
 			}
 		}
 
@@ -956,14 +961,6 @@
 	return strings.Split(filepath.String(), filepath.Base())[0]
 }
 
-func libNameFromFilePath(filepath android.Path) string {
-	libName := strings.TrimSuffix(filepath.Base(), filepath.Ext())
-	if strings.HasPrefix(libName, "lib") {
-		libName = libName[3:]
-	}
-	return libName
-}
-
 func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
 	ctx := &depsContext{
 		BottomUpMutatorContext: actx,
@@ -988,8 +985,8 @@
 			{Mutator: "rust_libraries", Variation: "dylib"}}...),
 		dylibDepTag, deps.Dylibs...)
 
-	if deps.Rustlibs != nil {
-		autoDep := mod.compiler.(autoDeppable).autoDep()
+	if deps.Rustlibs != nil && !mod.compiler.Disabled() {
+		autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
 		actx.AddVariationDependencies(
 			append(commonDepVariations, []blueprint.Variation{
 				{Mutator: "rust_libraries", Variation: autoDep.variation}}...),
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 04de48b..89ce359 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -62,6 +62,7 @@
 		"foo.c":      nil,
 		"src/bar.rs": nil,
 		"src/any.h":  nil,
+		"buf.proto":  nil,
 		"liby.so":    nil,
 		"libz.so":    nil,
 	}
@@ -132,25 +133,6 @@
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
 }
 
-// Test that we can extract the lib name from a lib path.
-func TestLibNameFromFilePath(t *testing.T) {
-	libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so")
-	libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
-
-	libBarName := libNameFromFilePath(libBarPath)
-	libLibName := libNameFromFilePath(libLibPath)
-
-	expectedResult := "bar.so"
-	if libBarName != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
-	}
-
-	expectedResult = "lib.dylib"
-	if libLibName != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath)
-	}
-}
-
 // Test that we can extract the link path from a lib path.
 func TestLinkPathFromFilePath(t *testing.T) {
 	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
diff --git a/rust/source_provider.go b/rust/source_provider.go
index e168718..755a369 100644
--- a/rust/source_provider.go
+++ b/rust/source_provider.go
@@ -38,7 +38,7 @@
 var _ SourceProvider = (*BaseSourceProvider)(nil)
 
 type SourceProvider interface {
-	GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path
+	GenerateSource(ctx ModuleContext, deps PathDeps) android.Path
 	Srcs() android.Paths
 	SourceProviderProps() []interface{}
 	SourceProviderDeps(ctx DepsContext, deps Deps) Deps
@@ -49,7 +49,7 @@
 	return android.Paths{sp.OutputFile}
 }
 
-func (sp *BaseSourceProvider) GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path {
+func (sp *BaseSourceProvider) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
 	panic("BaseSourceProviderModule does not implement GenerateSource()")
 }
 
diff --git a/rust/strip.go b/rust/strip.go
new file mode 100644
index 0000000..d1bbba6
--- /dev/null
+++ b/rust/strip.go
@@ -0,0 +1,30 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+// Stripper encapsulates cc.Stripper.
+type Stripper struct {
+	cc.Stripper
+}
+
+func (s *Stripper) StripExecutableOrSharedLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath) {
+	ccFlags := cc.StripFlags{Toolchain: ctx.RustModule().ccToolchain(ctx)}
+	s.Stripper.StripExecutableOrSharedLib(ctx, in, out, ccFlags)
+}
diff --git a/rust/test.go b/rust/test.go
index 05c361e..d93fc31 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -88,7 +88,7 @@
 	return append(test.binaryDecorator.compilerProps(), &test.Properties)
 }
 
-func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
+func (test *testDecorator) install(ctx ModuleContext) {
 	test.testConfig = tradefed.AutoGenRustTestConfig(ctx,
 		test.Properties.Test_config,
 		test.Properties.Test_config_template,
@@ -103,7 +103,7 @@
 		ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
 	}
 
-	test.binaryDecorator.install(ctx, file)
+	test.binaryDecorator.install(ctx)
 }
 
 func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
@@ -114,7 +114,7 @@
 	return flags
 }
 
-func (test *testDecorator) autoDep() autoDep {
+func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep {
 	return rlibAutoDep
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index 80e4148..0144c82 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -91,6 +91,12 @@
 			host_supported: true,
                         native_coverage: false,
 		}
+		rust_library {
+			name: "libprotobuf",
+			crate_name: "protobuf",
+			srcs: ["foo.rs"],
+			host_supported: true,
+		}
 
 ` + cc.GatherRequiredDepsForTest(android.NoOsType)
 	return bp
@@ -120,6 +126,8 @@
 	ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
 	ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
 	ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
+	ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
+	ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
 	ctx.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory)
 	ctx.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
 	ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 84b905c..8c9e228 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -1672,6 +1672,8 @@
 			],
 			export_include_dirs: ["include"],
 			stl: "none",
+			recovery_available: true,
+			vendor_available: true,
 		}
 	`)
 
@@ -1683,6 +1685,8 @@
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
     installable: false,
+    recovery_available: true,
+    vendor_available: true,
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
@@ -1709,6 +1713,8 @@
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
+    recovery_available: true,
+    vendor_available: true,
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 5911c71..a7ee8d1 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1534,7 +1534,7 @@
 			apex_available: ["//apex_available:anyapex"],
 			srcs: ["Test.java"],
 			sdk_version: "current",
-			naming_scheme: "framework-modules",
+			naming_scheme: "default",
 			public: {
 				enabled: true,
 			},
@@ -1549,7 +1549,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     apex_available: ["//apex_available:anyapex"],
-    naming_scheme: "framework-modules",
+    naming_scheme: "default",
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1564,7 +1564,7 @@
     name: "myjavalib",
     prefer: false,
     apex_available: ["//apex_available:anyapex"],
-    naming_scheme: "framework-modules",
+    naming_scheme: "default",
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1581,9 +1581,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib-stubs-publicapi/android_common/javac/myjavalib-stubs-publicapi.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 217a4e1..f3f4a4a 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -64,6 +64,12 @@
 
 	// install symlinks to the binary
 	Symlinks []string `android:"arch_variant"`
+
+	// Make this module available when building for ramdisk.
+	Ramdisk_available *bool
+
+	// Make this module available when building for recovery.
+	Recovery_available *bool
 }
 
 type TestProperties struct {
@@ -158,6 +164,29 @@
 	return s.properties.Symlinks
 }
 
+var _ android.ImageInterface = (*ShBinary)(nil)
+
+func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk()
+}
+
+func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk()
+}
+
+func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+	return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
+}
+
+func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	return nil
+}
+
+func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
+
 func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) {
 	s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src))
 	filename := proptools.String(s.properties.Filename)
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