Merge "Make the names of 'soong_config_module_type_import' modules unique."
diff --git a/README.md b/README.md
index b1bb425..3eac87b 100644
--- a/README.md
+++ b/README.md
@@ -419,7 +419,8 @@
     name: "acme_cc_defaults",
     module_type: "cc_defaults",
     config_namespace: "acme",
-    variables: ["board", "feature"],
+    variables: ["board"],
+    bool_variables: ["feature"],
     properties: ["cflags", "srcs"],
 }
 
@@ -427,10 +428,6 @@
     name: "board",
     values: ["soc_a", "soc_b"],
 }
-
-soong_config_bool_variable {
-    name: "feature",
-}
 ```
 
 This example describes a new `acme_cc_defaults` module type that extends the
diff --git a/android/apex.go b/android/apex.go
index eabe059..9bf6fc7 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,8 @@
 	"sort"
 	"strconv"
 	"sync"
+
+	"github.com/google/blueprint"
 )
 
 const (
@@ -32,6 +34,14 @@
 	MinSdkVersion int
 }
 
+// Extracted from ApexModule to make it easier to define custom subsets of the
+// ApexModule interface and improve code navigation within the IDE.
+type DepIsInSameApex interface {
+	// DepIsInSameApex tests if the other module 'dep' is installed to the same
+	// APEX as this module
+	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+}
+
 // ApexModule is the interface that a module type is expected to implement if
 // the module has to be built differently depending on whether the module
 // is destined for an apex or not (installed to one of the regular partitions).
@@ -49,6 +59,8 @@
 // respectively.
 type ApexModule interface {
 	Module
+	DepIsInSameApex
+
 	apexModuleBase() *ApexModuleBase
 
 	// Marks that this module should be built for the specified APEXes.
@@ -88,16 +100,10 @@
 	// Tests if this module is available for the specified APEX or ":platform"
 	AvailableFor(what string) bool
 
-	// DepIsInSameApex tests if the other module 'dep' is installed to the same
-	// APEX as this module
-	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
-
-	// Returns the highest version which is <= min_sdk_version.
-	// For example, with min_sdk_version is 10 and versionList is [9,11]
-	// it returns 9.
-	ChooseSdkVersion(versionList []string, useLatest bool) (string, error)
-
-	ShouldSupportAndroid10() bool
+	// Returns the highest version which is <= maxSdkVersion.
+	// For example, with maxSdkVersion is 10 and versionList is [9,11]
+	// it returns 9 as string
+	ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error)
 }
 
 type ApexProperties struct {
@@ -113,6 +119,15 @@
 	Info ApexInfo `blueprint:"mutated"`
 }
 
+// Marker interface that identifies dependencies that are excluded from APEX
+// contents.
+type ExcludeFromApexContentsTag interface {
+	blueprint.DependencyTag
+
+	// Method that differentiates this interface from others.
+	ExcludeFromApexContents()
+}
+
 // Provides default implementation for the ApexModule interface. APEX-aware
 // modules are expected to include this struct and call InitApexModule().
 type ApexModuleBase struct {
@@ -193,22 +208,14 @@
 	return true
 }
 
-func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, useLatest bool) (string, error) {
-	if useLatest {
-		return versionList[len(versionList)-1], nil
-	}
-	minSdkVersion := m.ApexProperties.Info.MinSdkVersion
+func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) {
 	for i := range versionList {
 		ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
-		if ver <= minSdkVersion {
+		if ver <= maxSdkVersion {
 			return versionList[len(versionList)-i-1], nil
 		}
 	}
-	return "", fmt.Errorf("min_sdk_version is set %v, but not found in %v", minSdkVersion, versionList)
-}
-
-func (m *ApexModuleBase) ShouldSupportAndroid10() bool {
-	return !m.IsForPlatform() && (m.ApexProperties.Info.MinSdkVersion <= SdkVersion_Android10)
+	return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList)
 }
 
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
diff --git a/android/defs.go b/android/defs.go
index 5c815e6..4552224 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -100,6 +100,9 @@
 	// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
 	localPool = blueprint.NewBuiltinPool("local_pool")
 
+	// Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja.
+	remotePool = blueprint.NewBuiltinPool("remote_pool")
+
 	// Used for processes that need significant RAM to ensure there are not too many running in parallel.
 	highmemPool = blueprint.NewBuiltinPool("highmem_pool")
 )
diff --git a/android/module.go b/android/module.go
index d57abd1..02b2c89 100644
--- a/android/module.go
+++ b/android/module.go
@@ -128,6 +128,13 @@
 	// and returns a top-down dependency path from a start module to current child module.
 	GetWalkPath() []Module
 
+	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency tags path from a start module to current child module.
+	// It has one less entry than GetWalkPath() as it contains the dependency tags that
+	// exist between each adjacent pair of modules in the GetWalkPath().
+	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
+	GetTagPath() []blueprint.DependencyTag
+
 	AddMissingDependencies(missingDeps []string)
 
 	Target() Target
@@ -220,6 +227,7 @@
 	InstallBypassMake() bool
 	InstallForceOS() *OsType
 	SkipInstall()
+	IsSkipInstall() bool
 	ExportedToMake() bool
 	InitRc() Paths
 	VintfFragments() Paths
@@ -908,7 +916,7 @@
 		// partition at "system/vendor/odm".
 		if config.OdmPath() == "odm" {
 			partition = "odm"
-		} else if strings.HasPrefix(config.OdmPath (), "vendor/") {
+		} else if strings.HasPrefix(config.OdmPath(), "vendor/") {
 			partition = "vendor"
 		}
 	} else if m.ProductSpecific() {
@@ -943,6 +951,10 @@
 	m.commonProperties.SkipInstall = true
 }
 
+func (m *ModuleBase) IsSkipInstall() bool {
+	return m.commonProperties.SkipInstall == true
+}
+
 func (m *ModuleBase) ExportedToMake() bool {
 	return m.commonProperties.NamespaceExportedToMake
 }
@@ -1400,6 +1412,7 @@
 	debug         bool
 
 	walkPath []Module
+	tagPath  []blueprint.DependencyTag
 
 	strictVisitDeps bool // If true, enforce that all dependencies are enabled
 }
@@ -1506,10 +1519,17 @@
 func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
 
-	if m.config.UseRemoteBuild() && params.Pool == nil {
-		// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
-		// jobs to the local parallelism value
-		params.Pool = localPool
+	if m.config.UseRemoteBuild() {
+		if params.Pool == nil {
+			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+			// jobs to the local parallelism value
+			params.Pool = localPool
+		} else if params.Pool == remotePool {
+			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+			// parallelism.
+			params.Pool = nil
+		}
 	}
 
 	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
@@ -1689,6 +1709,7 @@
 
 func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
 	b.walkPath = []Module{b.Module()}
+	b.tagPath = []blueprint.DependencyTag{}
 	b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
 		childAndroidModule, _ := child.(Module)
 		parentAndroidModule, _ := parent.(Module)
@@ -1696,8 +1717,10 @@
 			// record walkPath before visit
 			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
 				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+				b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
 			}
 			b.walkPath = append(b.walkPath, childAndroidModule)
+			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
 			return visit(childAndroidModule, parentAndroidModule)
 		} else {
 			return false
@@ -1709,6 +1732,10 @@
 	return b.walkPath
 }
 
+func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
+	return b.tagPath
+}
+
 func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
 	m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
 		visit(module.(Module))
diff --git a/android/prebuilt.go b/android/prebuilt.go
index c902ec8..82745a4 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -39,6 +39,12 @@
 // Mark this tag so dependencies that use it are excluded from visibility enforcement.
 func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {}
 
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t prebuiltDependencyTag) ExcludeFromApexContents() {}
+
+var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag
+var _ ExcludeFromApexContentsTag = PrebuiltDepTag
+
 type PrebuiltProperties struct {
 	// When prefer is set to true the prebuilt will be used instead of any source module with
 	// a matching name.
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 9005f07..6226548 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -446,7 +446,8 @@
 	if ctx.Config().UseGoma() && r.remoteable.Goma {
 		// When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
 	} else if ctx.Config().UseRBE() && r.remoteable.RBE {
-		// When USE_RBE=true is set and the rule is supported by RBE, allow jobs to run outside the local pool.
+		// When USE_RBE=true is set and the rule is supported by RBE, use the remotePool.
+		pool = remotePool
 	} else if r.highmem {
 		pool = highmemPool
 	} else if ctx.Config().UseRemoteBuild() {
diff --git a/android/sdk.go b/android/sdk.go
index 66094cd..6f62f55 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -22,17 +22,30 @@
 	"github.com/google/blueprint/proptools"
 )
 
+// Extracted from SdkAware to make it easier to define custom subsets of the
+// SdkAware interface and improve code navigation within the IDE.
+//
+// In addition to its use in SdkAware this interface must also be implemented by
+// APEX to specify the SDKs required by that module and its contents. e.g. APEX
+// is expected to implement RequiredSdks() by reading its own properties like
+// `uses_sdks`.
+type RequiredSdks interface {
+	// The set of SDKs required by an APEX and its contents.
+	RequiredSdks() SdkRefs
+}
+
 // SdkAware is the interface that must be supported by any module to become a member of SDK or to be
 // built with SDK
 type SdkAware interface {
 	Module
+	RequiredSdks
+
 	sdkBase() *SdkBase
 	MakeMemberOf(sdk SdkRef)
 	IsInAnySdk() bool
 	ContainingSdk() SdkRef
 	MemberName() string
 	BuildWithSdks(sdks SdkRefs)
-	RequiredSdks() SdkRefs
 }
 
 // SdkRef refers to a version of an SDK
diff --git a/android/singleton.go b/android/singleton.go
index 45a9b82..568398c 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -128,10 +128,17 @@
 }
 
 func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
-	if s.Config().UseRemoteBuild() && params.Pool == nil {
-		// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
-		// jobs to the local parallelism value
-		params.Pool = localPool
+	if s.Config().UseRemoteBuild() {
+		if params.Pool == nil {
+			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+			// jobs to the local parallelism value
+			params.Pool = localPool
+		} else if params.Pool == remotePool {
+			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+			// parallelism.
+			params.Pool = nil
+		}
 	}
 	rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
 	if s.Config().captureBuild {
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 8fc08ad..6ce609a 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -88,7 +88,8 @@
 //         name: "acme_cc_defaults",
 //         module_type: "cc_defaults",
 //         config_namespace: "acme",
-//         variables: ["board", "feature"],
+//         variables: ["board"],
+//         bool_variables: ["feature"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -97,10 +98,6 @@
 //         values: ["soc_a", "soc_b"],
 //     }
 //
-//     soong_config_bool_variable {
-//         name: "feature",
-//     }
-//
 // If an acme BoardConfig.mk file contained:
 //
 //     SOONG_CONFIG_NAMESPACES += acme
@@ -152,7 +149,8 @@
 //         name: "acme_cc_defaults",
 //         module_type: "cc_defaults",
 //         config_namespace: "acme",
-//         variables: ["board", "feature"],
+//         variables: ["board"],
+//         bool_variables: ["feature"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -161,10 +159,6 @@
 //         values: ["soc_a", "soc_b"],
 //     }
 //
-//     soong_config_bool_variable {
-//         name: "feature",
-//     }
-//
 //     acme_cc_defaults {
 //         name: "acme_defaults",
 //         cflags: ["-DGENERIC"],
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 6ad88a2..1cf060d 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -43,7 +43,8 @@
 			name: "acme_test_defaults",
 			module_type: "test_defaults",
 			config_namespace: "acme",
-			variables: ["board", "feature1", "feature2", "FEATURE3"],
+			variables: ["board", "feature1", "FEATURE3"],
+			bool_variables: ["feature2"],
 			properties: ["cflags", "srcs"],
 		}
 
@@ -57,10 +58,6 @@
 		}
 
 		soong_config_bool_variable {
-			name: "feature2",
-		}
-
-		soong_config_bool_variable {
 			name: "FEATURE3",
 		}
 	`
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index aa4f5c5..2d6063d 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -109,6 +109,9 @@
 	// the list of SOONG_CONFIG variables that this module type will read
 	Variables []string
 
+	// the list of boolean SOONG_CONFIG variables that this module type will read
+	Bool_variables []string
+
 	// the list of properties that this module type will extend.
 	Properties []string
 }
@@ -146,6 +149,18 @@
 	}
 	v.ModuleTypes[props.Name] = mt
 
+	for _, name := range props.Bool_variables {
+		if name == "" {
+			return []error{fmt.Errorf("bool_variable name must not be blank")}
+		}
+
+		mt.Variables = append(mt.Variables, &boolVariable{
+			baseVariable: baseVariable{
+				variable: name,
+			},
+		})
+	}
+
 	return nil
 }
 
diff --git a/android/variable.go b/android/variable.go
index 8357d2f..612d138 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -95,6 +95,9 @@
 			Sanitize struct {
 				Address *bool
 			}
+			Optimize struct {
+				Enabled *bool
+			}
 		}
 
 		Pdk struct {
diff --git a/apex/apex.go b/apex/apex.go
index 446cad8..5a56185 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"path"
 	"path/filepath"
+	"regexp"
 	"sort"
 	"strconv"
 	"strings"
@@ -94,16 +95,9 @@
 	// Module separator
 	//
 	m["com.android.adbd"] = []string{
-		"adbd",
-		"libadbconnection_server",
-		"libadbd",
 		"libadbd_auth",
-		"libadbd_core",
-		"libadbd_services",
-		"libasyncio",
 		"libbuildversion",
 		"libcap",
-		"libdiagnose_usb",
 		"libmdnssd",
 		"libminijail",
 		"libminijail_gen_constants",
@@ -114,7 +108,6 @@
 		"libpackagelistparser",
 		"libpcre2",
 		"libprocessgroup_headers",
-		"libqemu_pipe",
 	}
 	//
 	// Module separator
@@ -819,22 +812,6 @@
 		"libprofile-extras",
 		"libprofile-extras_ndk",
 		"libunwind_llvm",
-		"ndk_crtbegin_dynamic.27",
-		"ndk_crtbegin_so.16",
-		"ndk_crtbegin_so.19",
-		"ndk_crtbegin_so.21",
-		"ndk_crtbegin_so.24",
-		"ndk_crtbegin_so.27",
-		"ndk_crtend_android.27",
-		"ndk_crtend_so.16",
-		"ndk_crtend_so.19",
-		"ndk_crtend_so.21",
-		"ndk_crtend_so.24",
-		"ndk_crtend_so.27",
-		"ndk_libandroid_support",
-		"ndk_libc++_static",
-		"ndk_libc++abi",
-		"ndk_libunwind",
 	}
 	return m
 }
@@ -889,20 +866,28 @@
 		return
 	}
 
-	cur := mctx.Module().(interface {
-		DepIsInSameApex(android.BaseModuleContext, android.Module) bool
-	})
+	cur := mctx.Module().(android.DepIsInSameApex)
 
 	mctx.VisitDirectDeps(func(child android.Module) {
 		depName := mctx.OtherModuleName(child)
 		if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
-			cur.DepIsInSameApex(mctx, child) {
+			(cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) {
 			android.UpdateApexDependency(apexBundles, depName, directDep)
 			am.BuildForApexes(apexBundles)
 		}
 	})
 }
 
+// If a module in an APEX depends on a module from an SDK then it needs an APEX
+// specific variant created for it. Refer to sdk.sdkDepsReplaceMutator.
+func inAnySdk(module android.Module) bool {
+	if sa, ok := module.(android.SdkAware); ok {
+		return sa.IsInAnySdk()
+	}
+
+	return false
+}
+
 // Create apex variations if a module is included in APEX(s).
 func apexMutator(mctx android.BottomUpMutatorContext) {
 	if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
@@ -1791,9 +1776,13 @@
 	return true
 }
 
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
+
 // Visit dependencies that contributes to the payload of this APEX
-func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
-	do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		am, ok := child.(android.ApexModule)
 		if !ok || !am.CanHaveApexVariants() {
@@ -1803,22 +1792,18 @@
 		// Check for the direct dependencies that contribute to the payload
 		if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
 			if dt.payload {
-				do(ctx, parent, am, false /* externalDep */)
-				return true
+				return do(ctx, parent, am, false /* externalDep */)
 			}
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
 			return false
 		}
 
 		// Check for the indirect dependencies if it is considered as part of the APEX
 		if am.ApexName() != "" {
-			do(ctx, parent, am, false /* externalDep */)
-			return true
+			return do(ctx, parent, am, false /* externalDep */)
 		}
 
-		do(ctx, parent, am, true /* externalDep */)
-
-		// As soon as the dependency graph crosses the APEX boundary, don't go further.
-		return false
+		return do(ctx, parent, am, true /* externalDep */)
 	})
 }
 
@@ -1834,6 +1819,24 @@
 	return android.FutureApiLevel
 }
 
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
+
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+	// Use tag's custom String() method if available.
+	if stringer, ok := tag.(fmt.Stringer); ok {
+		return stringer.String()
+	}
+
+	// Otherwise, get a default string representation of the tag's struct.
+	tagString := fmt.Sprintf("%#v", tag)
+
+	// Remove the boilerplate from BaseDependencyTag as it adds no value.
+	tagString = tagCleaner.ReplaceAllString(tagString, "")
+	return tagString
+}
+
 // Ensures that the dependencies are marked as available for this APEX
 func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
 	// Let's be practical. Availability for test, host, and the VNDK apex isn't important
@@ -1848,28 +1851,47 @@
 		return
 	}
 
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+		if externalDep {
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
+		}
+
 		apexName := ctx.ModuleName()
 		fromName := ctx.OtherModuleName(from)
 		toName := ctx.OtherModuleName(to)
-		if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
-			return
+
+		// If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
+		// do any of its dependencies.
+		if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
+		}
+
+		if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
+			return true
 		}
 		message := ""
-		for _, m := range ctx.GetWalkPath()[1:] {
-			message = fmt.Sprintf("%s\n    -> %s", message, m.String())
+		tagPath := ctx.GetTagPath()
+		// Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf().
+		walkPath := ctx.GetWalkPath()[1:]
+		for i, m := range walkPath {
+			message = fmt.Sprintf("%s\n           via tag %s\n    -> %s", message, PrettyPrintTag(tagPath[i]), m.String())
 		}
 		ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
+		// Visit this module's dependencies to check and report any issues with their availability.
+		return true
 	})
 }
 
 // Collects the list of module names that directly or indirectly contributes to the payload of this APEX
 func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
 	a.depInfos = make(map[string]depInfo)
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if from.Name() == to.Name() {
 			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
-			return
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return !externalDep
 		}
 
 		if info, exists := a.depInfos[to.Name()]; exists {
@@ -1885,6 +1907,9 @@
 				isExternal: externalDep,
 			}
 		}
+
+		// As soon as the dependency graph crosses the APEX boundary, don't go further.
+		return !externalDep
 	})
 }
 
@@ -1961,6 +1986,9 @@
 	// TODO(jiyong) do this using walkPayloadDeps
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
 		depTag := ctx.OtherModuleDependencyTag(child)
+		if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+			return false
+		}
 		depName := ctx.OtherModuleName(child)
 		if _, isDirectDep := parent.(*apexBundle); isDirectDep {
 			switch depTag {
@@ -2129,7 +2157,7 @@
 						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
 					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
-					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+					ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
 				}
 			}
 		}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c01ba14..f942c82 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -27,6 +27,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/dexpreopt"
 	"android/soong/java"
 )
 
@@ -158,6 +159,7 @@
 		"my_include":                                 nil,
 		"foo/bar/MyClass.java":                       nil,
 		"prebuilt.jar":                               nil,
+		"prebuilt.so":                                nil,
 		"vendor/foo/devkeys/test.x509.pem":           nil,
 		"vendor/foo/devkeys/test.pk8":                nil,
 		"testkey.x509.pem":                           nil,
@@ -367,7 +369,7 @@
 			apex_available: [ "myapex" ],
 		}
 
-		cc_library {
+		cc_library_shared {
 			name: "mylib2",
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
@@ -381,6 +383,16 @@
 			],
 		}
 
+		cc_prebuilt_library_shared {
+			name: "mylib2",
+			srcs: ["prebuilt.so"],
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+    }
+
 		cc_library_static {
 			name: "libstatic",
 			srcs: ["mylib.cpp"],
@@ -882,7 +894,7 @@
 		shouldNotLink []string
 	}{
 		{
-			name:          "should link to test latest",
+			name:          "should link to the latest",
 			minSdkVersion: "current",
 			shouldLink:    "30",
 			shouldNotLink: []string{"29"},
@@ -1222,7 +1234,7 @@
 	expectNoLink("libz", "shared", "libz", "shared")
 }
 
-func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) {
+func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -1249,16 +1261,18 @@
 				versions: ["29", "30"],
 			},
 		}
-	`)
+	`, func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+	})
 	expectLink := func(from, from_variant, to, to_variant string) {
 		ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
 		libFlags := ld.Args["libFlags"]
 		ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
 	}
-	expectLink("libx", "shared_myapex", "libbar", "shared_30")
+	expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30")
 }
 
-func TestQTargetApexUseStaticUnwinder(t *testing.T) {
+func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -1277,8 +1291,7 @@
 			name: "libx",
 			apex_available: [ "myapex" ],
 		}
-
-	`, withUnbundledBuild)
+	`)
 
 	// ensure apex variant of c++ is linked with static unwinder
 	cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
@@ -1289,7 +1302,7 @@
 }
 
 func TestInvalidMinSdkVersion(t *testing.T) {
-	testApexError(t, `"libz" .*: min_sdk_version is set 29.*`, `
+	testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1319,9 +1332,9 @@
 				versions: ["30"],
 			},
 		}
-	`, withUnbundledBuild)
+	`)
 
-	testApexError(t, `"myapex" .*: min_sdk_version: should be .*`, `
+	testApexError(t, `"myapex" .*: min_sdk_version: should be "current" or <number>`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1842,7 +1855,7 @@
 	// non-APEX variant does not have __ANDROID_APEX__ defined
 	mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
 
 	// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
@@ -3539,12 +3552,12 @@
 func TestApexAvailable_IndirectDep(t *testing.T) {
 	// libbbaz is an indirect dep
 	testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
+.*via tag apex\.dependencyTag.*"sharedLib".*
 .*-> libfoo.*link:shared.*
-.*-> libfoo.*link:static.*
+.*via tag cc\.DependencyTag.*"shared".*
 .*-> libbar.*link:shared.*
-.*-> libbar.*link:static.*
-.*-> libbaz.*link:shared.*
-.*-> libbaz.*link:static.*`, `
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbaz.*link:shared.*`, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -4191,6 +4204,175 @@
 	ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
 }
 
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+	t.Helper()
+
+	bp = bp + `
+		filegroup {
+			name: "some-updatable-apex-file_contexts",
+			srcs: [
+				"system/sepolicy/apex/some-updatable-apex-file_contexts",
+			],
+		}
+	`
+	bp += cc.GatherRequiredDepsForTest(android.Android)
+	bp += java.GatherRequiredDepsForTest()
+	bp += dexpreopt.BpToolModulesForTest()
+
+	fs := map[string][]byte{
+		"a.java":                             nil,
+		"a.jar":                              nil,
+		"build/make/target/product/security": nil,
+		"apex_manifest.json":                 nil,
+		"AndroidManifest.xml":                nil,
+		"system/sepolicy/apex/some-updatable-apex-file_contexts":       nil,
+		"system/sepolicy/apex/com.android.art.something-file_contexts": nil,
+		"framework/aidl/a.aidl": nil,
+	}
+	cc.GatherRequiredFilesForTest(fs)
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("apex", BundleFactory)
+	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	cc.RegisterRequiredBuildComponentsForTest(ctx)
+	java.RegisterJavaBuildComponents(ctx)
+	java.RegisterSystemModulesBuildComponents(ctx)
+	java.RegisterAppBuildComponents(ctx)
+	java.RegisterDexpreoptBootJarsComponents(ctx)
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+	ctx.PreDepsMutators(RegisterPreDepsMutators)
+	ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+	config := android.TestArchConfig(buildDir, nil, bp, fs)
+	ctx.Register(config)
+
+	_ = dexpreopt.GlobalSoongConfigForTests(config)
+	dexpreopt.RegisterToolModulesForTest(ctx)
+	pathCtx := android.PathContextForTesting(config)
+	dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+	transformDexpreoptConfig(dexpreoptConfig)
+	dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+	_, 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 TestNoUpdatableJarsInBootImage(t *testing.T) {
+	bp := `
+		java_library {
+			name: "some-updatable-apex-lib",
+			srcs: ["a.java"],
+			apex_available: [
+				"some-updatable-apex",
+			],
+		}
+
+		java_library {
+			name: "some-platform-lib",
+			srcs: ["a.java"],
+			installable: true,
+		}
+
+		java_library {
+			name: "some-art-lib",
+			srcs: ["a.java"],
+			apex_available: [
+				"com.android.art.something",
+			],
+			hostdex: true,
+		}
+
+		apex {
+			name: "some-updatable-apex",
+			key: "some-updatable-apex.key",
+			java_libs: ["some-updatable-apex-lib"],
+		}
+
+		apex_key {
+			name: "some-updatable-apex.key",
+		}
+
+		apex {
+			name: "com.android.art.something",
+			key: "com.android.art.something.key",
+			java_libs: ["some-art-lib"],
+		}
+
+		apex_key {
+			name: "com.android.art.something.key",
+		}
+	`
+
+	var error string
+	var transform func(*dexpreopt.GlobalConfig)
+
+	// updatable jar from ART apex in the ART boot image => ok
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"some-art-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, "", bp, transform)
+
+	// updatable jar from ART apex in the framework boot image => error
+	error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"some-art-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// updatable jar from some other apex in the ART boot image => error
+	error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"some-updatable-apex-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// updatable jar from some other apex in the framework boot image => error
+	error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"some-updatable-apex-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// nonexistent jar in the ART boot image => error
+	error = "failed to find a dex jar path for module 'nonexistent'"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"nonexistent"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// nonexistent jar in the framework boot image => error
+	error = "failed to find a dex jar path for module 'nonexistent'"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"nonexistent"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// platform jar in the ART boot image => error
+	error = "module 'some-platform-lib' is part of the platform and not allowed in the ART boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"some-platform-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// platform jar in the framework boot image => ok
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"some-platform-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, "", bp, transform)
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 67bc206..5a2134a 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -230,12 +230,16 @@
 func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
 	var noticeFiles android.Paths
 
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if externalDep {
-			return
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
 		}
+
 		notices := to.NoticeFiles()
 		noticeFiles = append(noticeFiles, notices...)
+
+		return true
 	})
 
 	if len(noticeFiles) == 0 {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 0516279..a1c5de1 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -124,6 +124,10 @@
 		Name: "removeHidlInterfaceTypes",
 		Fix:  removeHidlInterfaceTypes,
 	},
+	{
+		Name: "removeSoongConfigBoolVariable",
+		Fix:  removeSoongConfigBoolVariable,
+	},
 }
 
 func NewFixRequest() FixRequest {
@@ -714,6 +718,78 @@
 	return nil
 }
 
+func removeSoongConfigBoolVariable(f *Fixer) error {
+	found := map[string]bool{}
+	newDefs := make([]parser.Definition, 0, len(f.tree.Defs))
+	for _, def := range f.tree.Defs {
+		if mod, ok := def.(*parser.Module); ok && mod.Type == "soong_config_bool_variable" {
+			if name, ok := getLiteralStringPropertyValue(mod, "name"); ok {
+				found[name] = true
+			} else {
+				return fmt.Errorf("Found soong_config_bool_variable without a name")
+			}
+		} else {
+			newDefs = append(newDefs, def)
+		}
+	}
+	f.tree.Defs = newDefs
+
+	if len(found) == 0 {
+		return nil
+	}
+
+	return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+		if mod.Type != "soong_config_module_type" {
+			return nil
+		}
+
+		variables, ok := getLiteralListProperty(mod, "variables")
+		if !ok {
+			return nil
+		}
+
+		boolValues := strings.Builder{}
+		empty := true
+		for _, item := range variables.Values {
+			nameValue, ok := item.(*parser.String)
+			if !ok {
+				empty = false
+				continue
+			}
+			if found[nameValue.Value] {
+				patchList.Add(item.Pos().Offset, item.End().Offset+2, "")
+
+				boolValues.WriteString(`"`)
+				boolValues.WriteString(nameValue.Value)
+				boolValues.WriteString(`",`)
+			} else {
+				empty = false
+			}
+		}
+		if empty {
+			*patchList = parser.PatchList{}
+
+			prop, _ := mod.GetProperty("variables")
+			patchList.Add(prop.Pos().Offset, prop.End().Offset+2, "")
+		}
+		if boolValues.Len() == 0 {
+			return nil
+		}
+
+		bool_variables, ok := getLiteralListProperty(mod, "bool_variables")
+		if ok {
+			patchList.Add(bool_variables.RBracePos.Offset, bool_variables.RBracePos.Offset, ","+boolValues.String())
+		} else {
+			patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2,
+				fmt.Sprintf(`bool_variables: [%s],`, boolValues.String()))
+		}
+
+		return nil
+	})(f)
+
+	return nil
+}
+
 // Converts the default source list property, 'srcs', to a single source property with a given name.
 // "LOCAL_MODULE" reference is also resolved during the conversion process.
 func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 38cefdd..64a7b93 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -918,3 +918,67 @@
 		})
 	}
 }
+
+func TestRemoveSoongConfigBoolVariable(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "remove bool",
+			in: `
+				soong_config_module_type {
+					name: "foo",
+					variables: ["bar", "baz"],
+				}
+
+				soong_config_bool_variable {
+					name: "bar",
+				}
+
+				soong_config_string_variable {
+					name: "baz",
+				}
+			`,
+			out: `
+				soong_config_module_type {
+					name: "foo",
+					variables: [
+						"baz"
+					],
+					bool_variables: ["bar"],
+				}
+
+				soong_config_string_variable {
+					name: "baz",
+				}
+			`,
+		},
+		{
+			name: "existing bool_variables",
+			in: `
+				soong_config_module_type {
+					name: "foo",
+					variables: ["baz"],
+					bool_variables: ["bar"],
+				}
+
+				soong_config_bool_variable {
+					name: "baz",
+				}
+			`,
+			out: `
+				soong_config_module_type {
+					name: "foo",
+					bool_variables: ["bar", "baz"],
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, removeSoongConfigBoolVariable)
+		})
+	}
+}
diff --git a/cc/cc.go b/cc/cc.go
index de07229..88fede4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -488,6 +488,9 @@
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
 	kytheFiles android.Paths
+
+	// For apex variants, this is set as apex.min_sdk_version
+	apexSdkVersion int
 }
 
 func (c *Module) Toc() android.OptionalPath {
@@ -1209,7 +1212,7 @@
 }
 
 func (ctx *moduleContextImpl) apexSdkVersion() int {
-	return ctx.mod.ApexProperties.Info.MinSdkVersion
+	return ctx.mod.apexSdkVersion
 }
 
 func (ctx *moduleContextImpl) hasStubsVariants() bool {
@@ -1847,7 +1850,10 @@
 		}, depTag, lib)
 	}
 
-	if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+	// staticUnwinderDep is treated as staticDep for Q apexes
+	// so that native libraries/binaries are linked with static unwinder
+	// because Q libc doesn't have unwinder APIs
+	if deps.StaticUnwinderIfLegacy {
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, staticUnwinderDepTag, staticUnwinder(actx))
@@ -2231,9 +2237,22 @@
 			}
 		}
 
+		// For the dependency from platform to apex, use the latest stubs
+		c.apexSdkVersion = android.FutureApiLevel
+		if !c.IsForPlatform() {
+			c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion
+		}
+
+		if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+			// In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+			// so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+			// (b/144430859)
+			c.apexSdkVersion = android.FutureApiLevel
+		}
+
 		if depTag == staticUnwinderDepTag {
-			// Use static unwinder for legacy (min_sdk_version = 29) apexes  (b/144430859)
-			if c.ShouldSupportAndroid10() {
+			// Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
+			if c.apexSdkVersion <= android.SdkVersion_Android10 {
 				depTag = StaticDepTag
 			} else {
 				return
@@ -2287,8 +2306,7 @@
 
 				// when to use (unspecified) stubs, check min_sdk_version and choose the right one
 				if useThisDep && depIsStubs && !explicitlyVersioned {
-					useLatest := c.IsForPlatform() || (c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild())
-					versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), useLatest)
+					versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion)
 					if err != nil {
 						ctx.OtherModuleErrorf(dep, err.Error())
 						return
@@ -2311,8 +2329,7 @@
 						// if this is for use_vendor apex && dep has stubsVersions
 						// apply the same rule of apex sdk enforcement to choose right version
 						var err error
-						useLatest := c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild()
-						versionToUse, err = c.ChooseSdkVersion(versions, useLatest)
+						versionToUse, err = c.ChooseSdkVersion(versions, c.apexSdkVersion)
 						if err != nil {
 							ctx.OtherModuleErrorf(dep, err.Error())
 							return
diff --git a/cc/config/global.go b/cc/config/global.go
index 29020ab..5611a96 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -127,8 +127,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r377782c"
-	ClangDefaultShortVersion = "10.0.5"
+	ClangDefaultVersion      = "clang-r377782d"
+	ClangDefaultShortVersion = "10.0.6"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 25225b5..8eb79e3 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -15,9 +15,11 @@
 package config
 
 import (
+	"fmt"
 	"os/exec"
 	"path/filepath"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 )
@@ -89,28 +91,20 @@
 )
 
 func init() {
-	pctx.VariableFunc("macSdkPath", func(ctx android.PackageVarContext) string {
-		xcodeselect := ctx.Config().HostSystemTool("xcode-select")
-		bytes, err := exec.Command(xcodeselect, "--print-path").Output()
-		if err != nil {
-			ctx.Errorf("xcode-select failed with: %q", err.Error())
-		}
-		return strings.TrimSpace(string(bytes))
-	})
 	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
-		return xcrunSdk(ctx, "--show-sdk-path")
+		return getMacTools(ctx).sdkRoot
 	})
 	pctx.StaticVariable("macMinVersion", "10.10")
 	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
-		return xcrun(ctx, "--find", "ar")
+		return getMacTools(ctx).arPath
 	})
 
 	pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
-		return xcrun(ctx, "--find", "strip")
+		return getMacTools(ctx).stripPath
 	})
 
 	pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string {
-		return filepath.Dir(xcrun(ctx, "--find", "ld"))
+		return getMacTools(ctx).toolPath
 	})
 
 	pctx.StaticVariable("DarwinGccVersion", darwinGccVersion)
@@ -126,38 +120,66 @@
 	pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64")
 }
 
-func xcrun(ctx android.PackageVarContext, args ...string) string {
-	xcrun := ctx.Config().HostSystemTool("xcrun")
-	bytes, err := exec.Command(xcrun, args...).Output()
-	if err != nil {
-		ctx.Errorf("xcrun failed with: %q", err.Error())
-	}
-	return strings.TrimSpace(string(bytes))
+type macPlatformTools struct {
+	once sync.Once
+	err  error
+
+	sdkRoot   string
+	arPath    string
+	stripPath string
+	toolPath  string
 }
 
-func xcrunSdk(ctx android.PackageVarContext, arg string) string {
-	xcrun := ctx.Config().HostSystemTool("xcrun")
-	if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
-		if !inList(selected, darwinSupportedSdkVersions) {
-			ctx.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+var macTools = &macPlatformTools{}
+
+func getMacTools(ctx android.PackageVarContext) *macPlatformTools {
+	macTools.once.Do(func() {
+		xcrunTool := ctx.Config().HostSystemTool("xcrun")
+
+		xcrun := func(args ...string) string {
+			if macTools.err != nil {
+				return ""
+			}
+
+			bytes, err := exec.Command(xcrunTool, args...).Output()
+			if err != nil {
+				macTools.err = fmt.Errorf("xcrun %q failed with: %q", args, err)
+				return ""
+			}
+
+			return strings.TrimSpace(string(bytes))
+		}
+
+		xcrunSdk := func(arg string) string {
+			if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
+				if !inList(selected, darwinSupportedSdkVersions) {
+					macTools.err = fmt.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+					return ""
+				}
+
+				return xcrun("--sdk", "macosx"+selected, arg)
+			}
+
+			for _, sdk := range darwinSupportedSdkVersions {
+				bytes, err := exec.Command(xcrunTool, "--sdk", "macosx"+sdk, arg).Output()
+				if err == nil {
+					return strings.TrimSpace(string(bytes))
+				}
+			}
+			macTools.err = fmt.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
 			return ""
 		}
 
-		bytes, err := exec.Command(xcrun, "--sdk", "macosx"+selected, arg).Output()
-		if err != nil {
-			ctx.Errorf("MAC_SDK_VERSION %s is not installed", selected)
-		}
-		return strings.TrimSpace(string(bytes))
-	}
+		macTools.sdkRoot = xcrunSdk("--show-sdk-path")
 
-	for _, sdk := range darwinSupportedSdkVersions {
-		bytes, err := exec.Command(xcrun, "--sdk", "macosx"+sdk, arg).Output()
-		if err == nil {
-			return strings.TrimSpace(string(bytes))
-		}
+		macTools.arPath = xcrun("--find", "ar")
+		macTools.stripPath = xcrun("--find", "strip")
+		macTools.toolPath = filepath.Dir(xcrun("--find", "ld"))
+	})
+	if macTools.err != nil {
+		ctx.Errorf("%q", macTools.err)
 	}
-	ctx.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
-	return ""
+	return macTools
 }
 
 type toolchainDarwin struct {
diff --git a/cc/library.go b/cc/library.go
index b9f448b..439a2c0 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -376,7 +376,7 @@
 	useCoreVariant       bool
 	checkSameCoreVariant bool
 
-	// Decorated interafaces
+	// Decorated interfaces
 	*baseCompiler
 	*baseLinker
 	*baseInstaller
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 0a11af1..754b96a 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -269,6 +269,11 @@
 	for property, dirs := range includeDirs {
 		outputProperties.AddProperty(property, dirs)
 	}
+
+	if len(libInfo.StubsVersion) > 0 {
+		stubsSet := outputProperties.AddPropertySet("stubs")
+		stubsSet.AddProperty("versions", []string{libInfo.StubsVersion})
+	}
 }
 
 const (
@@ -335,6 +340,10 @@
 	// This field is exported as its contents may not be arch specific.
 	SystemSharedLibs []string
 
+	// The specific stubs version for the lib variant, or empty string if stubs
+	// are not in use.
+	StubsVersion string
+
 	// outputFile is not exported as it is always arch specific.
 	outputFile android.Path
 }
@@ -370,6 +379,10 @@
 		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
 	}
 	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+
+	if ccModule.HasStubsVariants() {
+		p.StubsVersion = ccModule.StubsVersion()
+	}
 }
 
 func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index e849aee..3a630d2 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -90,6 +90,11 @@
 	return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, objectExtension, ctx.sdkVersion())
 }
 
+func (*ndkPrebuiltObjectLinker) availableFor(what string) bool {
+	// ndk prebuilt objects are available to everywhere
+	return true
+}
+
 type ndkPrebuiltStlLinker struct {
 	*libraryDecorator
 }
@@ -103,6 +108,11 @@
 	return deps
 }
 
+func (*ndkPrebuiltStlLinker) availableFor(what string) bool {
+	// ndk prebuilt objects are available to everywhere
+	return true
+}
+
 // ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
 // library (stl) library for linking operation. The soong's module name format
 // is ndk_<NAME>.so where the library is located under
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 242d835..0b018c1 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -22,6 +22,25 @@
 	"github.com/google/blueprint"
 )
 
+func testPrebuilt(t *testing.T, bp string, fs map[string][]byte) *android.TestContext {
+	config := TestConfig(buildDir, android.Android, nil, bp, fs)
+	ctx := CreateTestContext()
+
+	// Enable androidmk support.
+	// * Register the singleton
+	// * Configure that we are inside make
+	// * Add CommonOS to ensure that androidmk processing works.
+	android.RegisterAndroidMkBuildComponents(ctx)
+	android.SetInMakeForTests(config)
+
+	ctx.Register(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+	return ctx
+}
+
 func TestPrebuilt(t *testing.T) {
 	bp := `
 		cc_library {
@@ -84,7 +103,15 @@
 		}
 	`
 
-	ctx := testPrebuilt(t, bp)
+	ctx := testPrebuilt(t, bp, map[string][]byte{
+		"liba.so": nil,
+		"libb.a":  nil,
+		"libd.so": nil,
+		"libe.a":  nil,
+		"libf.a":  nil,
+		"libf.so": nil,
+		"crtx.o":  nil,
+	})
 
 	// Verify that all the modules exist and that their dependencies were connected correctly
 	liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
@@ -143,35 +170,6 @@
 	}
 }
 
-func testPrebuilt(t *testing.T, bp string) *android.TestContext {
-
-	fs := map[string][]byte{
-		"liba.so": nil,
-		"libb.a":  nil,
-		"libd.so": nil,
-		"libe.a":  nil,
-		"libf.a":  nil,
-		"libf.so": nil,
-		"crtx.o":  nil,
-	}
-	config := TestConfig(buildDir, android.Android, nil, bp, fs)
-	ctx := CreateTestContext()
-
-	// Enable androidmk support.
-	// * Register the singleton
-	// * Configure that we are inside make
-	// * Add CommonOS to ensure that androidmk processing works.
-	android.RegisterAndroidMkBuildComponents(ctx)
-	android.SetInMakeForTests(config)
-
-	ctx.Register(config)
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-	return ctx
-}
-
 func TestPrebuiltLibraryShared(t *testing.T) {
 	ctx := testPrebuilt(t, `
 	cc_prebuilt_library_shared {
@@ -181,7 +179,9 @@
         none: true,
     },
 	}
-	`)
+	`, map[string][]byte{
+		"libf.so": nil,
+	})
 
 	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
 	assertString(t, shared.OutputFile().String(), "libf.so")
@@ -193,7 +193,9 @@
 		name: "libtest",
 		srcs: ["libf.a"],
 	}
-	`)
+	`, map[string][]byte{
+		"libf.a": nil,
+	})
 
 	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
 	assertString(t, static.OutputFile().String(), "libf.a")
@@ -213,7 +215,10 @@
         none: true,
     },
 	}
-	`)
+	`, map[string][]byte{
+		"libf.a":  nil,
+		"libf.so": nil,
+	})
 
 	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
 	assertString(t, shared.OutputFile().String(), "libf.so")
diff --git a/cc/testing.go b/cc/testing.go
index e9739ff..f85795b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -67,6 +67,20 @@
 			src: "",
 		}
 
+		cc_prebuilt_library_shared {
+			name: "libclang_rt.hwasan-aarch64-android",
+			nocrt: true,
+			vendor_available: true,
+			recovery_available: true,
+			system_shared_libs: [],
+			stl: "none",
+			srcs: [""],
+			check_elf_files: false,
+			sanitize: {
+				never: true,
+			},
+		}
+
 		toolchain_library {
 			name: "libclang_rt.builtins-i686-android",
 			vendor_available: true,
diff --git a/cmd/zipsync/zipsync.go b/cmd/zipsync/zipsync.go
index a6023d3..294e5ef 100644
--- a/cmd/zipsync/zipsync.go
+++ b/cmd/zipsync/zipsync.go
@@ -115,7 +115,7 @@
 
 			filename := filepath.Join(*outputDir, name)
 			if f.FileInfo().IsDir() {
-				must(os.MkdirAll(filename, f.FileInfo().Mode()))
+				must(os.MkdirAll(filename, 0777))
 			} else {
 				must(os.MkdirAll(filepath.Dir(filename), 0777))
 				in, err := f.Open()
diff --git a/java/androidmk.go b/java/androidmk.go
index ee2437a..136bb36 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -72,6 +72,7 @@
 	if !hideFromMake {
 		mainEntries = android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
+			DistFile:   android.OptionalPathForPath(library.distFile),
 			OutputFile: android.OptionalPathForPath(library.outputFile),
 			Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index acc6bf0..7daa624 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -133,3 +134,38 @@
 		t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual)
 	}
 }
+
+func TestDistWithTag(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo_without_tag",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dist: {
+				targets: ["hi"],
+			},
+		}
+		java_library {
+			name: "foo_with_tag",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dist: {
+				targets: ["hi"],
+				tag: ".jar",
+			},
+		}
+	`)
+
+	without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
+	with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
+
+	if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 {
+		t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries))
+	}
+	if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") {
+		t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile)
+	}
+	if without_tag_entries[0].DistFile.Valid() {
+		t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
+	}
+}
diff --git a/java/app.go b/java/app.go
index 3f6c1d9..0a4d9e4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -529,14 +529,28 @@
 
 	// Build a final signed app package.
 	packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
-	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps)
+	v4SigningRequested := Bool(a.Module.deviceProperties.V4_signature)
+	var v4SignatureFile android.WritablePath = nil
+	if v4SigningRequested {
+		v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+".apk.idsig")
+	}
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile)
 	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)
+		if v4SigningRequested {
+			v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
+		}
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
+		if v4SigningRequested {
+			a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
+		}
 	}
 
 	// Build an app bundle.
@@ -1156,7 +1170,7 @@
 		}
 		a.certificate = certificates[0]
 		signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
-		SignAppPackage(ctx, signed, dexOutput, certificates)
+		SignAppPackage(ctx, signed, dexOutput, certificates, nil)
 		a.outputFile = signed
 	} else {
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
@@ -1361,7 +1375,7 @@
 	_, certificates := collectAppDeps(ctx, false, false)
 	certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
-	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates)
+	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil)
 	r.certificate = certificates[0]
 
 	r.outputFile = signed
diff --git a/java/app_builder.go b/java/app_builder.go
index 5e7fbe6..b2780bc 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -45,7 +45,7 @@
 	})
 
 func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths) {
+	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
 	unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -66,10 +66,10 @@
 		Implicits: deps,
 	})
 
-	SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+	SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile)
 }
 
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath) {
 
 	var certificateArgs []string
 	var deps android.Paths
@@ -78,14 +78,22 @@
 		deps = append(deps, c.Pem, c.Key)
 	}
 
+	outputFiles := android.WritablePaths{signedApk}
+	var flag string = ""
+	if v4SignatureFile != nil {
+		outputFiles = append(outputFiles, v4SignatureFile)
+		flag = "--enable-v4"
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        Signapk,
 		Description: "signapk",
-		Output:      signedApk,
+		Outputs:     outputFiles,
 		Input:       unsignedApk,
 		Implicits:   deps,
 		Args: map[string]string{
 			"certificates": strings.Join(certificateArgs, " "),
+			"flags":        flag,
 		},
 	})
 }
diff --git a/java/app_test.go b/java/app_test.go
index 0c6da7a..f3cd070 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1074,6 +1074,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
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 4db62b3..543b233 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -25,7 +26,7 @@
 )
 
 func init() {
-	android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+	RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
 }
 
 // Target-independent description of pre-compiled boot image.
@@ -173,6 +174,10 @@
 	return &dexpreoptBootJars{}
 }
 
+func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
+	ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+}
+
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
 	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
 		return true
@@ -241,16 +246,66 @@
 	dumpOatRules(ctx, d.defaultBootImage)
 }
 
+// Inspect this module to see if it contains a bootclasspath dex jar.
+// Note that the same jar may occur in multiple modules.
+// This logic is tested in the apex package to avoid import cycle apex <-> java.
+func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
+	// All apex Java libraries have non-installable platform variants, skip them.
+	if module.IsSkipInstall() {
+		return -1, nil
+	}
+
+	jar, hasJar := module.(interface{ DexJar() android.Path })
+	if !hasJar {
+		return -1, nil
+	}
+
+	name := ctx.ModuleName(module)
+	index := android.IndexList(name, image.modules)
+	if index == -1 {
+		return -1, nil
+	}
+
+	// Check that this module satisfies constraints for a particular boot image.
+	apex, isApexModule := module.(android.ApexModule)
+	if image.name == artBootImageName {
+		if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") {
+			// ok, found the jar in the ART apex
+		} else if isApexModule && !apex.IsForPlatform() {
+			// this jar is part of an updatable apex other than ART, fail immediately
+			ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName())
+		} else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
+			// this is a special "hostdex" variant, skip it and resume search
+			return -1, nil
+		} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+			// this is Jacoco platform variant for a coverage build, skip it and resume search
+			return -1, nil
+		} else {
+			// this (installable) jar is part of the platform, fail immediately
+			ctx.Errorf("module '%s' is part of the platform and not allowed in the ART boot image", name)
+		}
+	} else if image.name == frameworkBootImageName {
+		if !isApexModule || apex.IsForPlatform() {
+			// ok, this jar is part of the platform
+		} else {
+			// this jar is part of an updatable apex, fail immediately
+			ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName())
+		}
+	} else {
+		panic("unknown boot image: " + image.name)
+	}
+
+	return index, jar.DexJar()
+}
+
 // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
 func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
+	// Collect dex jar paths for the boot image modules.
+	// This logic is tested in the apex package to avoid import cycle apex <-> java.
 	bootDexJars := make(android.Paths, len(image.modules))
 	ctx.VisitAllModules(func(module android.Module) {
-		// Collect dex jar paths for the modules listed above.
-		if j, ok := module.(interface{ DexJar() android.Path }); ok {
-			name := ctx.ModuleName(module)
-			if i := android.IndexList(name, image.modules); i != -1 {
-				bootDexJars[i] = j.DexJar()
-			}
+		if i, j := getBootImageJar(ctx, image, module); i != -1 {
+			bootDexJars[i] = j
 		}
 	})
 
@@ -262,7 +317,8 @@
 				missingDeps = append(missingDeps, image.modules[i])
 				bootDexJars[i] = android.PathForOutput(ctx, "missing")
 			} else {
-				ctx.Errorf("failed to find dex jar path for module %q",
+				ctx.Errorf("failed to find a dex jar path for module '%s'"+
+					", note that some jars may be filtered out by module constraints",
 					image.modules[i])
 			}
 		}
@@ -281,6 +337,7 @@
 
 	profile := bootImageProfileRule(ctx, image, missingDeps)
 	bootFrameworkProfileRule(ctx, image, missingDeps)
+	updatableBcpPackagesRule(ctx, image, missingDeps)
 
 	var allFiles android.Paths
 	for _, variant := range image.variants {
@@ -549,6 +606,61 @@
 
 var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
 
+func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+	if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+		return nil
+	}
+
+	return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
+		global := dexpreopt.GetGlobalConfig(ctx)
+		updatableModules := dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)
+
+		// Collect `permitted_packages` for updatable boot jars.
+		var updatablePackages []string
+		ctx.VisitAllModules(func(module android.Module) {
+			if j, ok := module.(*Library); ok {
+				name := ctx.ModuleName(module)
+				if i := android.IndexList(name, updatableModules); i != -1 {
+					pp := j.properties.Permitted_packages
+					if len(pp) > 0 {
+						updatablePackages = append(updatablePackages, pp...)
+					} else {
+						ctx.Errorf("Missing permitted_packages for %s", name)
+					}
+					// Do not match the same library repeatedly.
+					updatableModules = append(updatableModules[:i], updatableModules[i+1:]...)
+				}
+			}
+		})
+
+		// Sort updatable packages to ensure deterministic ordering.
+		sort.Strings(updatablePackages)
+
+		updatableBcpPackagesName := "updatable-bcp-packages.txt"
+		updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.WriteFile,
+			Output: updatableBcpPackages,
+			Args: map[string]string{
+				// WriteFile automatically adds the last end-of-line.
+				"content": strings.Join(updatablePackages, "\\n"),
+			},
+		})
+
+		rule := android.NewRuleBuilder()
+		rule.MissingDeps(missingDeps)
+		rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
+		// TODO: Rename `profileInstalls` to `extraInstalls`?
+		// Maybe even move the field out of the bootImageConfig into some higher level type?
+		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+
+		return updatableBcpPackages
+	}).(android.WritablePath)
+}
+
+var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule")
+
 func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
 	var allPhonies android.Paths
 	for _, image := range image.variants {
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 94ca8bb..127c201 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -53,7 +53,7 @@
 
 	ctx := testContext()
 
-	ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+	RegisterDexpreoptBootJarsComponents(ctx)
 
 	run(t, ctx, config)
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 1315aba..066694c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -81,7 +81,7 @@
 
 func getDexLocation(ctx android.PathContext, target android.Target, subdir string, name string) string {
 	if target.Os.Class == android.Host {
-		return filepath.Join("out", "host", ctx.Config().PrebuiltOS(), subdir, name)
+		return filepath.Join(ctx.Config().Getenv("OUT_DIR"), "host", ctx.Config().PrebuiltOS(), subdir, name)
 	} else {
 		return filepath.Join("/", subdir, name)
 	}
diff --git a/java/java.go b/java/java.go
index 7645d85..a8ca3ff 100644
--- a/java/java.go
+++ b/java/java.go
@@ -325,6 +325,10 @@
 
 	UncompressDex bool `blueprint:"mutated"`
 	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
 }
 
 func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool {
@@ -421,6 +425,8 @@
 
 	// list of the xref extraction files
 	kytheFiles android.Paths
+
+	distFile android.Path
 }
 
 func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -1754,11 +1760,6 @@
 	if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
 		return true
 	}
-	// Also, a dependency to an sdk member is also considered as such. This is required because
-	// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
-	if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
-		return true
-	}
 	return false
 }
 
@@ -1778,9 +1779,18 @@
 // Java libraries (.jar file)
 //
 
+type LibraryProperties struct {
+	Dist struct {
+		// The tag of the output of this module that should be output.
+		Tag *string `android:"arch_variant"`
+	} `android:"arch_variant"`
+}
+
 type Library struct {
 	Module
 
+	libraryProperties LibraryProperties
+
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
@@ -1824,6 +1834,15 @@
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...)
 	}
+
+	// Verify Dist.Tag is set to a supported output
+	if j.libraryProperties.Dist.Tag != nil {
+		distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag)
+		if err != nil {
+			ctx.PropertyErrorf("dist.tag", "%s", err.Error())
+		}
+		j.distFile = distFiles[0]
+	}
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1944,7 +1963,8 @@
 		&module.Module.properties,
 		&module.Module.deviceProperties,
 		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties)
+		&module.Module.protoProperties,
+		&module.libraryProperties)
 
 	android.InitApexModule(module)
 	android.InitSdkAwareModule(module)
@@ -2488,11 +2508,6 @@
 	if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
 		return true
 	}
-	// Also, a dependency to an sdk member is also considered as such. This is required because
-	// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
-	if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
-		return true
-	}
 	return false
 }
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 6921114..efee7da 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -18,7 +18,6 @@
 	"android/soong/android"
 
 	"fmt"
-	"io"
 	"path"
 	"path/filepath"
 	"sort"
@@ -87,6 +86,9 @@
 	// *current. Older stubs library built with a numbered SDK version is created from
 	// the prebuilt jar.
 	sdkVersion string
+
+	// Extra arguments to pass to droidstubs for this scope.
+	droidstubsArgs []string
 }
 
 // Initialize a scope, creating and adding appropriate dependency tags
@@ -132,6 +134,7 @@
 		moduleSuffix:              sdkSystemApiSuffix,
 		apiFileMakeVariableSuffix: "_SYSTEM",
 		sdkVersion:                "system_current",
+		droidstubsArgs:            []string{"-showAnnotation android.annotation.SystemApi"},
 	})
 	apiScopeTest = initApiScope(&apiScope{
 		name:                      "test",
@@ -139,6 +142,7 @@
 		moduleSuffix:              sdkTestApiSuffix,
 		apiFileMakeVariableSuffix: "_TEST",
 		sdkVersion:                "test_current",
+		droidstubsArgs:            []string{"-showAnnotation android.annotation.TestApi"},
 	})
 	allApiScopes = apiScopes{
 		apiScopePublic,
@@ -328,41 +332,6 @@
 	entriesList := module.Library.AndroidMkEntries()
 	entries := &entriesList[0]
 	entries.Required = append(entries.Required, module.xmlFileName())
-
-	entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
-		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-			if !Bool(module.sdkLibraryProperties.No_dist) {
-				// Create a phony module that installs the impl library, for the case when this lib is
-				// in PRODUCT_PACKAGES.
-				owner := module.ModuleBase.Owner()
-				if owner == "" {
-					if Bool(module.sdkLibraryProperties.Core_lib) {
-						owner = "core"
-					} else {
-						owner = "android"
-					}
-				}
-
-				// Create dist rules to install the stubs libs and api files to the dist dir
-				for _, apiScope := range module.getActiveApiScopes() {
-					if scopePaths, ok := module.scopePaths[apiScope]; ok {
-						if len(scopePaths.stubsHeaderPath) == 1 {
-							fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-								scopePaths.stubsImplPath.Strings()[0]+
-								":"+path.Join("apistubs", owner, apiScope.name,
-								module.BaseModuleName()+".jar")+")")
-						}
-						if scopePaths.apiFilePath != nil {
-							fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-								scopePaths.apiFilePath.String()+
-								":"+path.Join("apistubs", owner, apiScope.name, "api",
-								module.BaseModuleName()+".txt")+")")
-						}
-					}
-				}
-			}
-		},
-	}
 	return entriesList
 }
 
@@ -386,6 +355,17 @@
 	return module.BaseModuleName() + sdkXmlFileSuffix
 }
 
+// The dist path of the stub artifacts
+func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
+	if module.ModuleBase.Owner() != "" {
+		return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name)
+	} else if Bool(module.sdkLibraryProperties.Core_lib) {
+		return path.Join("apistubs", "core", apiScope.name)
+	} else {
+		return path.Join("apistubs", "android", apiScope.name)
+	}
+}
+
 // Get the sdk version for use when compiling the stubs library.
 func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -438,6 +418,12 @@
 			Srcs       []string
 			Javacflags []string
 		}
+		Dist struct {
+			Targets []string
+			Dest    *string
+			Dir     *string
+			Tag     *string
+		}
 	}{}
 
 	props.Name = proptools.StringPtr(module.stubsName(apiScope))
@@ -466,11 +452,18 @@
 	} else if module.SystemExtSpecific() {
 		props.System_ext_specific = proptools.BoolPtr(true)
 	}
+	// Dist the class jar artifact for sdk builds.
+	if !Bool(module.sdkLibraryProperties.No_dist) {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.BaseModuleName()))
+		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+		props.Dist.Tag = proptools.StringPtr(".jar")
+	}
 
 	mctx.CreateModule(LibraryFactory, &props)
 }
 
-// Creates a droiddoc module that creates stubs source files from the given full source
+// Creates a droidstubs module that creates stubs source files from the given full source
 // files
 func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
 	props := struct {
@@ -497,6 +490,11 @@
 			Include_dirs       []string
 			Local_include_dirs []string
 		}
+		Dist struct {
+			Targets []string
+			Dest    *string
+			Dir     *string
+		}
 	}{}
 
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -523,15 +521,15 @@
 	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
 	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
 
-	droiddocArgs := []string{}
+	droidstubsArgs := []string{}
 	if len(module.sdkLibraryProperties.Api_packages) != 0 {
-		droiddocArgs = append(droiddocArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
+		droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
 	}
 	if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
-		droiddocArgs = append(droiddocArgs,
+		droidstubsArgs = append(droidstubsArgs,
 			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
 	}
-	droiddocArgs = append(droiddocArgs, module.sdkLibraryProperties.Droiddoc_options...)
+	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
 	disabledWarnings := []string{
 		"MissingPermission",
 		"BroadcastBehavior",
@@ -543,16 +541,12 @@
 		"Todo",
 		"Typo",
 	}
-	droiddocArgs = append(droiddocArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
+	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
 
-	switch apiScope {
-	case apiScopeSystem:
-		droiddocArgs = append(droiddocArgs, "-showAnnotation android.annotation.SystemApi")
-	case apiScopeTest:
-		droiddocArgs = append(droiddocArgs, " -showAnnotation android.annotation.TestApi")
-	}
+	// Add in scope specific arguments.
+	droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...)
 	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
-	props.Args = proptools.StringPtr(strings.Join(droiddocArgs, " "))
+	props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
 
 	// List of APIs identified from the provided source files are created. They are later
 	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
@@ -578,6 +572,13 @@
 		module.latestRemovedApiFilegroupName(apiScope))
 	props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
 
+	// Dist the api txt artifact for sdk builds.
+	if !Bool(module.sdkLibraryProperties.No_dist) {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
+		props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+	}
+
 	mctx.CreateModule(DroidstubsFactory, &props)
 }
 
diff --git a/rust/compiler.go b/rust/compiler.go
index 4593165..81b258c 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -222,7 +222,10 @@
 	if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
 		dir = compiler.dir64
 	}
-	if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
+	}
+	if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
 		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
 	return android.PathForModuleInstall(ctx, dir, compiler.subDir,
diff --git a/rust/library.go b/rust/library.go
index 0cf2dd0..bf863bb 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -318,6 +318,8 @@
 
 	if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
 		deps = library.baseCompiler.bionicDeps(ctx, deps)
+		deps.CrtBegin = "crtbegin_so"
+		deps.CrtEnd = "crtend_so"
 	}
 
 	return deps
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index 7e3a82c..35a6ff3 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -58,6 +58,7 @@
 
     "DeviceName": "generic_arm64",
     "HostArch": "x86_64",
+    "HostSecondaryArch": "x86",
     "Aml_abis": true,
 
     "UseGoma": ${USE_GOMA}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index eb64bcc..780da9f 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -32,6 +32,7 @@
 		"arm64/include/Arm64Test.h":     nil,
 		"libfoo.so":                     nil,
 		"aidl/foo/bar/Test.aidl":        nil,
+		"some/where/stubslib.map.txt":   nil,
 	}
 	return testSdkWithFs(t, bp, fs)
 }
@@ -1739,3 +1740,63 @@
 }
 `))
 }
+
+func TestStubsLibrary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: ["stubslib"],
+		}
+
+		cc_library {
+			name: "stubslib",
+			stubs: {
+				symbol_file: "some/where/stubslib.map.txt",
+				versions: ["1", "2", "3"],
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_stubslib@current",
+    sdk_member_name: "stubslib",
+    installable: false,
+    stubs: {
+        versions: ["3"],
+    },
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/stubslib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/stubslib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "stubslib",
+    prefer: false,
+    stubs: {
+        versions: ["3"],
+    },
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/stubslib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/stubslib.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_shared_libs: ["mysdk_stubslib@current"],
+}
+`))
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index cbffb50..4a2c053 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -53,30 +53,18 @@
 			system_modules: "none",
 			sdk_version: "none",
 			host_supported: true,
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
 		}
 
 		java_import {
 			name: "sdkmember_mysdk_1",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
 		}
 
 		java_import {
 			name: "sdkmember_mysdk_2",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
 		}
 
 		java_library {
diff --git a/sdk/sdk.go b/sdk/sdk.go
index dabdf85..cb5a605 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -312,7 +312,7 @@
 	ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
 }
 
-// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
+// RegisterPostDepsMutators registers post-deps mutators to support modules implementing SdkAware
 // interface and the sdk module type. This function has been made public to be called by tests
 // outside of the sdk package
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
@@ -431,23 +431,31 @@
 	}
 }
 
-// Step 6: ensure that the dependencies from outside of the APEX are all from the required SDKs
+// Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs
 func sdkRequirementsMutator(mctx android.TopDownMutatorContext) {
 	if m, ok := mctx.Module().(interface {
-		DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool
-		RequiredSdks() android.SdkRefs
+		android.DepIsInSameApex
+		android.RequiredSdks
 	}); ok {
 		requiredSdks := m.RequiredSdks()
 		if len(requiredSdks) == 0 {
 			return
 		}
 		mctx.VisitDirectDeps(func(dep android.Module) {
-			if mctx.OtherModuleDependencyTag(dep) == android.DefaultsDepTag {
+			tag := mctx.OtherModuleDependencyTag(dep)
+			if tag == android.DefaultsDepTag {
 				// dependency to defaults is always okay
 				return
 			}
 
-			// If the dep is from outside of the APEX, but is not in any of the
+			// Ignore the dependency from the unversioned member to any versioned members as an
+			// apex that depends on the unversioned member will not also be depending on a versioned
+			// member.
+			if _, ok := tag.(sdkMemberVersionedDepTag); ok {
+				return
+			}
+
+			// If the dep is outside of the APEX, but is not in any of the
 			// required SDKs, we know that the dep is a violation.
 			if sa, ok := dep.(android.SdkAware); ok {
 				if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) {
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 2de772b..4c3bac3 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -54,6 +54,9 @@
 
 	working bool
 	group   string
+	srcDir  string
+	outDir  string
+	distDir string
 }
 
 func (c *Cmd) sandboxSupported() bool {
@@ -72,15 +75,34 @@
 			sandboxConfig.group = "nobody"
 		}
 
-		cmd := exec.CommandContext(c.ctx.Context, nsjailPath,
+		sandboxConfig.srcDir = absPath(c.ctx, ".")
+		sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
+		sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
+
+		sandboxArgs := []string{
 			"-H", "android-build",
 			"-e",
 			"-u", "nobody",
 			"-g", sandboxConfig.group,
-			"-B", "/",
+			"-R", "/",
+			"-B", sandboxConfig.srcDir,
+			"-B", "/tmp",
+			"-B", sandboxConfig.outDir,
+		}
+
+		if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
+			//Mount dist dir as read-write if it already exists
+			sandboxArgs = append(sandboxArgs, "-B",
+				sandboxConfig.distDir)
+		}
+
+		sandboxArgs = append(sandboxArgs,
 			"--disable_clone_newcgroup",
 			"--",
 			"/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
+
+		cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
+
 		cmd.Env = c.config.Environment().Environ()
 
 		c.ctx.Verboseln(cmd.Args)
@@ -144,8 +166,17 @@
 		"--rlimit_fsize", "soft",
 		"--rlimit_nofile", "soft",
 
-		// For now, just map everything. Eventually we should limit this, especially to make most things readonly.
-		"-B", "/",
+		// For now, just map everything. Make most things readonly.
+		"-R", "/",
+
+		// Mount source are read-write
+		"-B", sandboxConfig.srcDir,
+
+		//Mount out dir as read-write
+		"-B", sandboxConfig.outDir,
+
+		// Mount a writable tmp dir
+		"-B", "/tmp",
 
 		// Disable newcgroup for now, since it may require newer kernels
 		// TODO: try out cgroups
@@ -155,6 +186,11 @@
 		"-q",
 	}
 
+	if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
+		//Mount dist dir as read-write if it already exists
+		sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+	}
+
 	if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
 		c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
 		c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())