Merge "Add the Tradefed binary (suite) rules to soong"
diff --git a/OWNERS b/OWNERS
index 8355d10..3a5a8a7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,13 +1,20 @@
-per-file * = asmundak@google.com
-per-file * = ccross@android.com
-per-file * = dwillemsen@google.com
-per-file * = eakammer@google.com
-per-file * = jungjw@google.com
-per-file * = patricearruda@google.com
-per-file * = paulduffin@google.com
+# This file is included by several other projects as the list of people
+# approving build related projects.
 
-per-file ndk_*.go = danalbert@google.com
-per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
-per-file tidy.go = srhines@google.com, chh@google.com
-per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
-per-file docs/map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
+ahumesky@google.com
+asmundak@google.com
+ccross@android.com
+cparsons@google.com
+dwillemsen@google.com
+eakammer@google.com
+jingwen@google.com
+joeo@google.com
+jungjw@google.com
+lberki@google.com
+patricearruda@google.com
+ruperts@google.com
+
+# To expedite LON reviews
+hansson@google.com
+paulduffin@google.com
+
diff --git a/android/Android.bp b/android/Android.bp
index a1b5159..2de0ca9 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -15,6 +15,7 @@
         "apex.go",
         "api_levels.go",
         "arch.go",
+        "bazel_handler.go",
         "bazel_overlay.go",
         "config.go",
         "csuite_config.go",
@@ -54,7 +55,6 @@
         "util.go",
         "variable.go",
         "visibility.go",
-        "vts_config.go",
         "writedocs.go",
 
         // Lock down environment access last
@@ -63,6 +63,7 @@
     testSrcs: [
         "android_test.go",
         "androidmk_test.go",
+        "apex_test.go",
         "arch_test.go",
         "config_test.go",
         "csuite_config_test.go",
@@ -82,6 +83,5 @@
         "util_test.go",
         "variable_test.go",
         "visibility_test.go",
-        "vts_config_test.go",
     ],
 }
diff --git a/android/apex.go b/android/apex.go
index c886962..3039e79 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -28,21 +28,30 @@
 	SdkVersion_Android10 = uncheckedFinalApiLevel(29)
 )
 
+// ApexInfo describes the metadata common to all modules in an apexBundle.
 type ApexInfo struct {
-	// Name of the apex variation that this module is mutated into
+	// Name of the apex variation that this module is mutated into, or "" for
+	// a platform variant.  Note that a module can be included in multiple APEXes,
+	// in which case, the module is mutated into one or more variants, each of
+	// which is for one or more APEXes.
 	ApexVariationName string
 
 	// Serialized ApiLevel. Use via MinSdkVersion() method. Cannot be stored in
 	// its struct form because this is cloned into properties structs, and
 	// ApiLevel has private members.
 	MinSdkVersionStr string
-	Updatable        bool
-	RequiredSdks     SdkRefs
 
-	InApexes []string
+	// True if the module comes from an updatable APEX.
+	Updatable    bool
+	RequiredSdks SdkRefs
+
+	InApexes     []string
+	ApexContents []*ApexContents
 }
 
-func (i ApexInfo) mergedName(ctx EarlyModuleContext) string {
+var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
+
+func (i ApexInfo) mergedName(ctx PathContext) string {
 	name := "apex" + strconv.Itoa(i.MinSdkVersion(ctx).FinalOrFutureInt())
 	for _, sdk := range i.RequiredSdks {
 		name += "_" + sdk.Name + "_" + sdk.Version
@@ -50,10 +59,22 @@
 	return name
 }
 
-func (this *ApexInfo) MinSdkVersion(ctx EarlyModuleContext) ApiLevel {
+func (this *ApexInfo) MinSdkVersion(ctx PathContext) ApiLevel {
 	return ApiLevelOrPanic(ctx, this.MinSdkVersionStr)
 }
 
+func (i ApexInfo) IsForPlatform() bool {
+	return i.ApexVariationName == ""
+}
+
+// ApexTestForInfo stores the contents of APEXes for which this module is a test and thus has
+// access to APEX internals.
+type ApexTestForInfo struct {
+	ApexContents []*ApexContents
+}
+
+var ApexTestForInfoProvider = blueprint.NewMutatorProvider(ApexTestForInfo{}, "apex_test_for")
+
 // 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 {
@@ -87,23 +108,18 @@
 	// Call this before apex.apexMutator is run.
 	BuildForApex(apex ApexInfo)
 
-	// Returns the name of APEX variation that this module will be built for.
-	// Empty string is returned when 'IsForPlatform() == true'. Note that a
-	// module can beincluded in multiple APEXes, in which case, the module
-	// is mutated into one or more variants, each of which is for one or
-	// more APEXes.  This method returns the name of the APEX variation of
-	// the module.
+	// Returns true if this module is present in any APEXes
+	// directly or indirectly.
 	// Call this after apex.apexMutator is run.
-	ApexVariationName() string
+	InAnyApex() bool
 
-	// Returns the name of the APEX modules that this variant of this module
-	// is present in.
+	// Returns true if this module is directly in any APEXes.
 	// Call this after apex.apexMutator is run.
-	InApexes() []string
+	DirectlyInAnyApex() bool
 
-	// Tests whether this module will be built for the platform or not.
-	// This is a shortcut for ApexVariationName() == ""
-	IsForPlatform() bool
+	// Returns true if any variant of this module is directly in any APEXes.
+	// Call this after apex.apexMutator is run.
+	AnyVariantDirectlyInAnyApex() bool
 
 	// Tests if this module could have APEX variants. APEX variants are
 	// created only for the modules that returns true here. This is useful
@@ -116,10 +132,6 @@
 	// libs.
 	IsInstallableToApex() bool
 
-	// Mutate this module into one or more variants each of which is built
-	// for an APEX marked via BuildForApex().
-	CreateApexVariations(mctx BottomUpMutatorContext) []Module
-
 	// Tests if this module is available for the specified APEX or ":platform"
 	AvailableFor(what string) bool
 
@@ -133,14 +145,6 @@
 	// check-platform-availability mutator in the apex package.
 	SetNotAvailableForPlatform()
 
-	// Returns the highest version which is <= maxSdkVersion.
-	// For example, with maxSdkVersion is 10 and versionList is [9,11]
-	// it returns 9 as string
-	ChooseSdkVersion(ctx BaseModuleContext, versionList []string, maxSdkVersion ApiLevel) (string, error)
-
-	// Tests if the module comes from an updatable APEX.
-	Updatable() bool
-
 	// List of APEXes that this module tests. The module has access to
 	// the private part of the listed APEXes even when it is not included in the
 	// APEXes.
@@ -153,11 +157,6 @@
 	// Returns true if this module needs a unique variation per apex, for example if
 	// use_apex_name_macro is set.
 	UniqueApexVariations() bool
-
-	// UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies
-	// that are in the same APEX have unique APEX variations so that the module can link against
-	// the right variant.
-	UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext)
 }
 
 type ApexProperties struct {
@@ -171,7 +170,21 @@
 	// Default is ["//apex_available:platform"].
 	Apex_available []string
 
-	Info ApexInfo `blueprint:"mutated"`
+	// AnyVariantDirectlyInAnyApex is true in the primary variant of a module if _any_ variant
+	// of the module is directly in any apex.  This includes host, arch, asan, etc. variants.
+	// It is unused in any variant that is not the primary variant.
+	// Ideally this wouldn't be used, as it incorrectly mixes arch variants if only one arch
+	// is in an apex, but a few places depend on it, for example when an ASAN variant is
+	// created before the apexMutator.
+	AnyVariantDirectlyInAnyApex bool `blueprint:"mutated"`
+
+	// DirectlyInAnyApex is true if any APEX variant (including the "" variant used for the
+	// platform) of this module is directly in any APEX.
+	DirectlyInAnyApex bool `blueprint:"mutated"`
+
+	// DirectlyInAnyApex is true if any APEX variant (including the "" variant used for the
+	// platform) of this module is directly or indirectly in any APEX.
+	InAnyApex bool `blueprint:"mutated"`
 
 	NotAvailableForPlatform bool `blueprint:"mutated"`
 
@@ -187,6 +200,15 @@
 	ExcludeFromApexContents()
 }
 
+// Marker interface that identifies dependencies that should inherit the DirectlyInAnyApex
+// state from the parent to the child.  For example, stubs libraries are marked as
+// DirectlyInAnyApex if their implementation is in an apex.
+type CopyDirectlyInAnyApexTag interface {
+	blueprint.DependencyTag
+
+	CopyDirectlyInAnyApex()
+}
+
 // Provides default implementation for the ApexModule interface. APEX-aware
 // modules are expected to include this struct and call InitApexModule().
 type ApexModuleBase struct {
@@ -215,43 +237,6 @@
 	return false
 }
 
-func (m *ApexModuleBase) UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) {
-	// anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes list
-	// in common.  It is used instead of DepIsInSameApex because it needs to determine if the dep
-	// is in the same APEX due to being directly included, not only if it is included _because_ it
-	// is a dependency.
-	anyInSameApex := func(a, b []ApexInfo) bool {
-		collectApexes := func(infos []ApexInfo) []string {
-			var ret []string
-			for _, info := range infos {
-				ret = append(ret, info.InApexes...)
-			}
-			return ret
-		}
-
-		aApexes := collectApexes(a)
-		bApexes := collectApexes(b)
-		sort.Strings(bApexes)
-		for _, aApex := range aApexes {
-			index := sort.SearchStrings(bApexes, aApex)
-			if index < len(bApexes) && bApexes[index] == aApex {
-				return true
-			}
-		}
-		return false
-	}
-
-	mctx.VisitDirectDeps(func(dep Module) {
-		if depApexModule, ok := dep.(ApexModule); ok {
-			if anyInSameApex(depApexModule.apexModuleBase().apexVariations, m.apexVariations) &&
-				(depApexModule.UniqueApexVariations() ||
-					depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) {
-				m.ApexProperties.UniqueApexVariationsForDeps = true
-			}
-		}
-	})
-}
-
 func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
 	m.apexVariationsLock.Lock()
 	defer m.apexVariationsLock.Unlock()
@@ -263,16 +248,16 @@
 	m.apexVariations = append(m.apexVariations, apex)
 }
 
-func (m *ApexModuleBase) ApexVariationName() string {
-	return m.ApexProperties.Info.ApexVariationName
+func (m *ApexModuleBase) DirectlyInAnyApex() bool {
+	return m.ApexProperties.DirectlyInAnyApex
 }
 
-func (m *ApexModuleBase) InApexes() []string {
-	return m.ApexProperties.Info.InApexes
+func (m *ApexModuleBase) AnyVariantDirectlyInAnyApex() bool {
+	return m.ApexProperties.AnyVariantDirectlyInAnyApex
 }
 
-func (m *ApexModuleBase) IsForPlatform() bool {
-	return m.ApexProperties.Info.ApexVariationName == ""
+func (m *ApexModuleBase) InAnyApex() bool {
+	return m.ApexProperties.InAnyApex
 }
 
 func (m *ApexModuleBase) CanHaveApexVariants() bool {
@@ -320,20 +305,6 @@
 	return true
 }
 
-func (m *ApexModuleBase) ChooseSdkVersion(ctx BaseModuleContext, versionList []string, maxSdkVersion ApiLevel) (string, error) {
-	for i := range versionList {
-		version := versionList[len(versionList)-i-1]
-		ver, err := ApiLevelFromUser(ctx, version)
-		if err != nil {
-			return "", err
-		}
-		if ver.LessThanOrEqualTo(maxSdkVersion) {
-			return version, nil
-		}
-	}
-	return "", fmt.Errorf("not found a version(<=%s) in versionList: %v", maxSdkVersion, versionList)
-}
-
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
 	for _, n := range m.ApexProperties.Apex_available {
 		if n == AvailableToPlatform || n == AvailableToAnyApex || n == AvailableToGkiApex {
@@ -345,10 +316,6 @@
 	}
 }
 
-func (m *ApexModuleBase) Updatable() bool {
-	return m.ApexProperties.Info.Updatable
-}
-
 type byApexName []ApexInfo
 
 func (a byApexName) Len() int           { return len(a) }
@@ -358,7 +325,7 @@
 // mergeApexVariations deduplicates APEX variations that would build identically into a common
 // variation.  It returns the reduced list of variations and a list of aliases from the original
 // variation names to the new variation names.
-func mergeApexVariations(ctx EarlyModuleContext, apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
+func mergeApexVariations(ctx PathContext, apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
 	sort.Sort(byApexName(apexVariations))
 	seen := make(map[string]int)
 	for _, apexInfo := range apexVariations {
@@ -366,11 +333,13 @@
 		mergedName := apexInfo.mergedName(ctx)
 		if index, exists := seen[mergedName]; exists {
 			merged[index].InApexes = append(merged[index].InApexes, apexName)
+			merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
 			merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
 		} else {
 			seen[mergedName] = len(merged)
 			apexInfo.ApexVariationName = apexInfo.mergedName(ctx)
 			apexInfo.InApexes = CopyOf(apexInfo.InApexes)
+			apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
 			merged = append(merged, apexInfo)
 		}
 		aliases = append(aliases, [2]string{apexName, mergedName})
@@ -378,17 +347,23 @@
 	return merged, aliases
 }
 
-func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
-	if len(m.apexVariations) > 0 {
-		m.checkApexAvailableProperty(mctx)
+func CreateApexVariations(mctx BottomUpMutatorContext, module ApexModule) []Module {
+	base := module.apexModuleBase()
+	if len(base.apexVariations) > 0 {
+		base.checkApexAvailableProperty(mctx)
 
 		var apexVariations []ApexInfo
 		var aliases [][2]string
-		if !mctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps {
-			apexVariations, aliases = mergeApexVariations(mctx, m.apexVariations)
+		if !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
+			apexVariations, aliases = mergeApexVariations(mctx, base.apexVariations)
 		} else {
-			apexVariations = m.apexVariations
+			apexVariations = base.apexVariations
 		}
+		// base.apexVariations is only needed to propagate the list of apexes from
+		// apexDepsMutator to apexMutator.  It is no longer accurate after
+		// mergeApexVariations, and won't be copied to all but the first created
+		// variant.  Clear it so it doesn't accidentally get used later.
+		base.apexVariations = nil
 
 		sort.Sort(byApexName(apexVariations))
 		variations := []string{}
@@ -400,6 +375,16 @@
 		defaultVariation := ""
 		mctx.SetDefaultDependencyVariation(&defaultVariation)
 
+		var inApex ApexMembership
+		for _, a := range apexVariations {
+			for _, apexContents := range a.ApexContents {
+				inApex = inApex.merge(apexContents.contents[mctx.ModuleName()])
+			}
+		}
+
+		base.ApexProperties.InAnyApex = true
+		base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex
+
 		modules := mctx.CreateVariations(variations...)
 		for i, mod := range modules {
 			platformVariation := i == 0
@@ -410,7 +395,7 @@
 				mod.MakeUninstallable()
 			}
 			if !platformVariation {
-				mod.(ApexModule).apexModuleBase().ApexProperties.Info = apexVariations[i-1]
+				mctx.SetVariationProvider(mod, ApexInfoProvider, apexVariations[i-1])
 			}
 		}
 
@@ -423,116 +408,139 @@
 	return nil
 }
 
-var apexData OncePer
-var apexNamesMapMutex sync.Mutex
-var apexNamesKey = NewOnceKey("apexNames")
+// UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies
+// that are in the same APEX have unique APEX variations so that the module can link against
+// the right variant.
+func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) {
+	// anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes list
+	// in common.  It is used instead of DepIsInSameApex because it needs to determine if the dep
+	// is in the same APEX due to being directly included, not only if it is included _because_ it
+	// is a dependency.
+	anyInSameApex := func(a, b []ApexInfo) bool {
+		collectApexes := func(infos []ApexInfo) []string {
+			var ret []string
+			for _, info := range infos {
+				ret = append(ret, info.InApexes...)
+			}
+			return ret
+		}
 
-// This structure maintains the global mapping in between modules and APEXes.
-// Examples:
-//
-// apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar
-// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
-// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar
-func apexNamesMap() map[string]map[string]bool {
-	return apexData.Once(apexNamesKey, func() interface{} {
-		return make(map[string]map[string]bool)
-	}).(map[string]map[string]bool)
+		aApexes := collectApexes(a)
+		bApexes := collectApexes(b)
+		sort.Strings(bApexes)
+		for _, aApex := range aApexes {
+			index := sort.SearchStrings(bApexes, aApex)
+			if index < len(bApexes) && bApexes[index] == aApex {
+				return true
+			}
+		}
+		return false
+	}
+
+	mctx.VisitDirectDeps(func(dep Module) {
+		if depApexModule, ok := dep.(ApexModule); ok {
+			if anyInSameApex(depApexModule.apexModuleBase().apexVariations, am.apexModuleBase().apexVariations) &&
+				(depApexModule.UniqueApexVariations() ||
+					depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) {
+				am.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps = true
+			}
+		}
+	})
 }
 
-// Update the map to mark that a module named moduleName is directly or indirectly
-// depended on by the specified APEXes. Directly depending means that a module
-// is explicitly listed in the build definition of the APEX via properties like
-// native_shared_libs, java_libs, etc.
-func UpdateApexDependency(apex ApexInfo, moduleName string, directDep bool) {
-	apexNamesMapMutex.Lock()
-	defer apexNamesMapMutex.Unlock()
-	apexesForModule, ok := apexNamesMap()[moduleName]
-	if !ok {
-		apexesForModule = make(map[string]bool)
-		apexNamesMap()[moduleName] = apexesForModule
+// UpdateDirectlyInAnyApex uses the final module to store if any variant of this
+// module is directly in any APEX, and then copies the final value to all the modules.
+// It also copies the DirectlyInAnyApex value to any direct dependencies with a
+// CopyDirectlyInAnyApexTag dependency tag.
+func UpdateDirectlyInAnyApex(mctx BottomUpMutatorContext, am ApexModule) {
+	base := am.apexModuleBase()
+	// Copy DirectlyInAnyApex and InAnyApex from any direct dependencies with a
+	// CopyDirectlyInAnyApexTag dependency tag.
+	mctx.VisitDirectDeps(func(dep Module) {
+		if _, ok := mctx.OtherModuleDependencyTag(dep).(CopyDirectlyInAnyApexTag); ok {
+			depBase := dep.(ApexModule).apexModuleBase()
+			base.ApexProperties.DirectlyInAnyApex = depBase.ApexProperties.DirectlyInAnyApex
+			base.ApexProperties.InAnyApex = depBase.ApexProperties.InAnyApex
+		}
+	})
+
+	if base.ApexProperties.DirectlyInAnyApex {
+		// Variants of a module are always visited sequentially in order, so it is safe to
+		// write to another variant of this module.
+		// For a BottomUpMutator the PrimaryModule() is visited first and FinalModule() is
+		// visited last.
+		mctx.FinalModule().(ApexModule).apexModuleBase().ApexProperties.AnyVariantDirectlyInAnyApex = true
 	}
-	apexesForModule[apex.ApexVariationName] = apexesForModule[apex.ApexVariationName] || directDep
-	for _, apexName := range apex.InApexes {
-		apexesForModule[apexName] = apexesForModule[apex.ApexVariationName] || directDep
+
+	// If this is the FinalModule (last visited module) copy AnyVariantDirectlyInAnyApex to
+	// all the other variants
+	if am == mctx.FinalModule().(ApexModule) {
+		mctx.VisitAllModuleVariants(func(variant Module) {
+			variant.(ApexModule).apexModuleBase().ApexProperties.AnyVariantDirectlyInAnyApex =
+				base.ApexProperties.AnyVariantDirectlyInAnyApex
+		})
 	}
 }
 
-// TODO(b/146393795): remove this when b/146393795 is fixed
-func ClearApexDependency() {
-	m := apexNamesMap()
-	for k := range m {
-		delete(m, k)
+type ApexMembership int
+
+const (
+	notInApex        ApexMembership = 0
+	indirectlyInApex                = iota
+	directlyInApex
+)
+
+// Each apexBundle has an apexContents, and modules in that apex have a provider containing the
+// apexContents of each apexBundle they are part of.
+type ApexContents struct {
+	ApexName string
+	contents map[string]ApexMembership
+}
+
+func NewApexContents(name string, contents map[string]ApexMembership) *ApexContents {
+	return &ApexContents{
+		ApexName: name,
+		contents: contents,
 	}
 }
 
-// Tests whether a module named moduleName is directly depended on by an APEX
-// named apexName.
-func DirectlyInApex(apexName string, moduleName string) bool {
-	apexNamesMapMutex.Lock()
-	defer apexNamesMapMutex.Unlock()
-	if apexNamesForModule, ok := apexNamesMap()[moduleName]; ok {
-		return apexNamesForModule[apexName]
+func (i ApexMembership) Add(direct bool) ApexMembership {
+	if direct || i == directlyInApex {
+		return directlyInApex
 	}
-	return false
+	return indirectlyInApex
+}
+
+func (i ApexMembership) merge(other ApexMembership) ApexMembership {
+	if other == directlyInApex || i == directlyInApex {
+		return directlyInApex
+	}
+
+	if other == indirectlyInApex || i == indirectlyInApex {
+		return indirectlyInApex
+	}
+	return notInApex
+}
+
+func (ac *ApexContents) DirectlyInApex(name string) bool {
+	return ac.contents[name] == directlyInApex
+}
+
+func (ac *ApexContents) InApex(name string) bool {
+	return ac.contents[name] != notInApex
 }
 
 // Tests whether a module named moduleName is directly depended on by all APEXes
-// in a list of apexNames.
-func DirectlyInAllApexes(apexNames []string, moduleName string) bool {
-	apexNamesMapMutex.Lock()
-	defer apexNamesMapMutex.Unlock()
-	for _, apexName := range apexNames {
-		apexNamesForModule := apexNamesMap()[moduleName]
-		if !apexNamesForModule[apexName] {
+// in an ApexInfo.
+func DirectlyInAllApexes(apexInfo ApexInfo, moduleName string) bool {
+	for _, contents := range apexInfo.ApexContents {
+		if !contents.DirectlyInApex(moduleName) {
 			return false
 		}
 	}
 	return true
 }
 
-type hostContext interface {
-	Host() bool
-}
-
-// Tests whether a module named moduleName is directly depended on by any APEX.
-func DirectlyInAnyApex(ctx hostContext, moduleName string) bool {
-	if ctx.Host() {
-		// Host has no APEX.
-		return false
-	}
-	apexNamesMapMutex.Lock()
-	defer apexNamesMapMutex.Unlock()
-	if apexNames, ok := apexNamesMap()[moduleName]; ok {
-		for an := range apexNames {
-			if apexNames[an] {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-// Tests whether a module named module is depended on (including both
-// direct and indirect dependencies) by any APEX.
-func InAnyApex(moduleName string) bool {
-	apexNamesMapMutex.Lock()
-	defer apexNamesMapMutex.Unlock()
-	apexNames, ok := apexNamesMap()[moduleName]
-	return ok && len(apexNames) > 0
-}
-
-func GetApexesForModule(moduleName string) []string {
-	ret := []string{}
-	apexNamesMapMutex.Lock()
-	defer apexNamesMapMutex.Unlock()
-	if apexNames, ok := apexNamesMap()[moduleName]; ok {
-		for an := range apexNames {
-			ret = append(ret, an)
-		}
-	}
-	return ret
-}
-
 func InitApexModule(m ApexModule) {
 	base := m.apexModuleBase()
 	base.canHaveApexVariants = true
diff --git a/android/apex_test.go b/android/apex_test.go
index db02833..512b50f 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -29,10 +29,10 @@
 		{
 			name: "single",
 			in: []ApexInfo{
-				{"foo", 10000, false, nil, []string{"foo"}},
+				{"foo", "current", false, nil, []string{"foo"}, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", 10000, false, nil, []string{"foo"}},
+				{"apex10000", "current", false, nil, []string{"foo"}, nil},
 			},
 			wantAliases: [][2]string{
 				{"foo", "apex10000"},
@@ -41,12 +41,11 @@
 		{
 			name: "merge",
 			in: []ApexInfo{
-				{"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
-				{"bar", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar"}},
+				{"foo", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil},
+				{"bar", "current", false, SdkRefs{{"baz", "1"}}, []string{"bar"}, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}},
-			},
+				{"apex10000_baz_1", "current", false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, nil}},
 			wantAliases: [][2]string{
 				{"bar", "apex10000_baz_1"},
 				{"foo", "apex10000_baz_1"},
@@ -55,12 +54,12 @@
 		{
 			name: "don't merge version",
 			in: []ApexInfo{
-				{"foo", 10000, false, nil, []string{"foo"}},
-				{"bar", 30, false, nil, []string{"bar"}},
+				{"foo", "current", false, nil, []string{"foo"}, nil},
+				{"bar", "30", false, nil, []string{"bar"}, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex30", 30, false, nil, []string{"bar"}},
-				{"apex10000", 10000, false, nil, []string{"foo"}},
+				{"apex30", "30", false, nil, []string{"bar"}, nil},
+				{"apex10000", "current", false, nil, []string{"foo"}, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex30"},
@@ -70,11 +69,11 @@
 		{
 			name: "merge updatable",
 			in: []ApexInfo{
-				{"foo", 10000, false, nil, []string{"foo"}},
-				{"bar", 10000, true, nil, []string{"bar"}},
+				{"foo", "current", false, nil, []string{"foo"}, nil},
+				{"bar", "current", true, nil, []string{"bar"}, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", 10000, true, nil, []string{"bar", "foo"}},
+				{"apex10000", "current", true, nil, []string{"bar", "foo"}, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -84,12 +83,12 @@
 		{
 			name: "don't merge sdks",
 			in: []ApexInfo{
-				{"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
-				{"bar", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+				{"foo", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil},
+				{"bar", "current", false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000_baz_2", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
-				{"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+				{"apex10000_baz_2", "current", false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil},
+				{"apex10000_baz_1", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000_baz_2"},
@@ -99,7 +98,9 @@
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			gotMerged, gotAliases := mergeApexVariations(tt.in)
+			config := TestConfig(buildDir, nil, "", nil)
+			ctx := &configErrorWrapper{config: config}
+			gotMerged, gotAliases := mergeApexVariations(ctx, tt.in)
 			if !reflect.DeepEqual(gotMerged, tt.wantMerged) {
 				t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged)
 			}
diff --git a/android/api_levels.go b/android/api_levels.go
index 9768340..bace3d4 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -152,7 +152,7 @@
 // * "30" -> "30"
 // * "R" -> "30"
 // * "S" -> "S"
-func ReplaceFinalizedCodenames(ctx EarlyModuleContext, raw string) string {
+func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
 	num, ok := getFinalCodenamesMap(ctx.Config())[raw]
 	if !ok {
 		return raw
@@ -175,7 +175,7 @@
 //
 // Inputs that are not "current", known previews, or convertible to an integer
 // will return an error.
-func ApiLevelFromUser(ctx EarlyModuleContext, raw string) (ApiLevel, error) {
+func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
 	if raw == "" {
 		panic("API level string must be non-empty")
 	}
@@ -203,7 +203,7 @@
 // Converts an API level string `raw` into an ApiLevel in the same method as
 // `ApiLevelFromUser`, but the input is assumed to have no errors and any errors
 // will panic instead of returning an error.
-func ApiLevelOrPanic(ctx EarlyModuleContext, raw string) ApiLevel {
+func ApiLevelOrPanic(ctx PathContext, raw string) ApiLevel {
 	value, err := ApiLevelFromUser(ctx, raw)
 	if err != nil {
 		panic(err.Error())
diff --git a/android/arch.go b/android/arch.go
index f4b0d66..f505ec6 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -811,10 +811,16 @@
 	}
 }
 
-// Identifies the dependency from CommonOS variant to the os specific variants.
-type commonOSTag struct{ blueprint.BaseDependencyTag }
+type archDepTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
 
-var commonOsToOsSpecificVariantTag = commonOSTag{}
+// Identifies the dependency from CommonOS variant to the os specific variants.
+var commonOsToOsSpecificVariantTag = archDepTag{name: "common os to os specific"}
+
+// Identifies the dependency from arch variant to the common variant for a "common_first" multilib.
+var firstArchToCommonArchDepTag = archDepTag{name: "first arch to common arch"}
 
 // Get the OsType specific variants for the current CommonOS variant.
 //
@@ -831,7 +837,6 @@
 			}
 		}
 	})
-
 	return variants
 }
 
@@ -955,6 +960,12 @@
 		addTargetProperties(m, targets[i], multiTargets, i == 0)
 		m.base().setArchProperties(mctx)
 	}
+
+	if multilib == "common_first" && len(modules) >= 2 {
+		for i := range modules[1:] {
+			mctx.AddInterVariantDependency(firstArchToCommonArchDepTag, modules[i+1], modules[0])
+		}
+	}
 }
 
 func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
new file mode 100644
index 0000000..210d67a8
--- /dev/null
+++ b/android/bazel_handler.go
@@ -0,0 +1,268 @@
+// 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 android
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"sync"
+
+	"github.com/google/blueprint/bootstrap"
+)
+
+// Map key to describe bazel cquery requests.
+type cqueryKey struct {
+	label        string
+	starlarkExpr string
+}
+
+type BazelContext interface {
+	// The below methods involve queuing cquery requests to be later invoked
+	// by bazel. If any of these methods return (_, false), then the request
+	// has been queued to be run later.
+
+	// Returns result files built by building the given bazel target label.
+	GetAllFiles(label string) ([]string, bool)
+
+	// TODO(cparsons): Other cquery-related methods should be added here.
+	// ** End cquery methods
+
+	// Issues commands to Bazel to receive results for all cquery requests
+	// queued in the BazelContext.
+	InvokeBazel() error
+
+	// Returns true if bazel is enabled for the given configuration.
+	BazelEnabled() bool
+}
+
+// A context object which tracks queued requests that need to be made to Bazel,
+// and their results after the requests have been made.
+type bazelContext struct {
+	homeDir      string
+	bazelPath    string
+	outputBase   string
+	workspaceDir string
+
+	requests     map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
+	requestMutex sync.Mutex         // requests can be written in parallel
+
+	results map[cqueryKey]string // Results of cquery requests after Bazel invocations
+}
+
+var _ BazelContext = &bazelContext{}
+
+// A bazel context to use when Bazel is disabled.
+type noopBazelContext struct{}
+
+var _ BazelContext = noopBazelContext{}
+
+// A bazel context to use for tests.
+type MockBazelContext struct {
+	AllFiles map[string][]string
+}
+
+func (m MockBazelContext) GetAllFiles(label string) ([]string, bool) {
+	result, ok := m.AllFiles[label]
+	return result, ok
+}
+
+func (m MockBazelContext) InvokeBazel() error {
+	panic("unimplemented")
+}
+
+func (m MockBazelContext) BazelEnabled() bool {
+	return true
+}
+
+var _ BazelContext = MockBazelContext{}
+
+func (bazelCtx *bazelContext) GetAllFiles(label string) ([]string, bool) {
+	starlarkExpr := "', '.join([f.path for f in target.files.to_list()])"
+	result, ok := bazelCtx.cquery(label, starlarkExpr)
+	if ok {
+		bazelOutput := strings.TrimSpace(result)
+		return strings.Split(bazelOutput, ", "), true
+	} else {
+		return nil, false
+	}
+}
+
+func (n noopBazelContext) GetAllFiles(label string) ([]string, bool) {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) InvokeBazel() error {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) BazelEnabled() bool {
+	return false
+}
+
+func NewBazelContext(c *config) (BazelContext, error) {
+	if c.Getenv("USE_BAZEL") != "1" {
+		return noopBazelContext{}, nil
+	}
+
+	bazelCtx := bazelContext{requests: make(map[cqueryKey]bool)}
+	missingEnvVars := []string{}
+	if len(c.Getenv("BAZEL_HOME")) > 1 {
+		bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
+	} else {
+		missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
+	}
+	if len(c.Getenv("BAZEL_PATH")) > 1 {
+		bazelCtx.bazelPath = c.Getenv("BAZEL_PATH")
+	} else {
+		missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
+	}
+	if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
+		bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
+	} else {
+		missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
+	}
+	if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
+		bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
+	} else {
+		missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
+	}
+	if len(missingEnvVars) > 0 {
+		return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
+	} else {
+		return &bazelCtx, nil
+	}
+}
+
+func (context *bazelContext) BazelEnabled() bool {
+	return true
+}
+
+// Adds a cquery request to the Bazel request queue, to be later invoked, or
+// returns the result of the given request if the request was already made.
+// If the given request was already made (and the results are available), then
+// returns (result, true). If the request is queued but no results are available,
+// then returns ("", false).
+func (context *bazelContext) cquery(label string, starlarkExpr string) (string, bool) {
+	key := cqueryKey{label, starlarkExpr}
+	if result, ok := context.results[key]; ok {
+		return result, true
+	} else {
+		context.requestMutex.Lock()
+		defer context.requestMutex.Unlock()
+		context.requests[key] = true
+		return "", false
+	}
+}
+
+func pwdPrefix() string {
+	// Darwin doesn't have /proc
+	if runtime.GOOS != "darwin" {
+		return "PWD=/proc/self/cwd"
+	}
+	return ""
+}
+
+func (context *bazelContext) issueBazelCommand(command string, labels []string,
+	extraFlags ...string) (string, error) {
+
+	cmdFlags := []string{"--output_base=" + context.outputBase, command}
+	cmdFlags = append(cmdFlags, labels...)
+	cmdFlags = append(cmdFlags, extraFlags...)
+
+	bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
+	bazelCmd.Dir = context.workspaceDir
+	bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix())
+
+	stderr := &bytes.Buffer{}
+	bazelCmd.Stderr = stderr
+
+	if output, err := bazelCmd.Output(); err != nil {
+		return "", fmt.Errorf("bazel command failed. command: [%s], error [%s]", bazelCmd, stderr)
+	} else {
+		return string(output), nil
+	}
+}
+
+// Issues commands to Bazel to receive results for all cquery requests
+// queued in the BazelContext.
+func (context *bazelContext) InvokeBazel() error {
+	context.results = make(map[cqueryKey]string)
+
+	var labels []string
+	var cqueryOutput string
+	var err error
+	for val, _ := range context.requests {
+		labels = append(labels, val.label)
+
+		// TODO(cparsons): Combine requests into a batch cquery request.
+		// TODO(cparsons): Use --query_file to avoid command line limits.
+		cqueryOutput, err = context.issueBazelCommand("cquery", []string{val.label},
+			"--output=starlark",
+			"--starlark:expr="+val.starlarkExpr)
+
+		if err != nil {
+			return err
+		} else {
+			context.results[val] = string(cqueryOutput)
+		}
+	}
+
+	// Issue a build command.
+	// TODO(cparsons): Invoking bazel execution during soong_build should be avoided;
+	// bazel actions should either be added to the Ninja file and executed later,
+	// or bazel should handle execution.
+	// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
+	_, err = context.issueBazelCommand("build", labels)
+
+	if err != nil {
+		return err
+	}
+
+	// Clear requests.
+	context.requests = map[cqueryKey]bool{}
+	return nil
+}
+
+// Singleton used for registering BUILD file ninja dependencies (needed
+// for correctness of builds which use Bazel.
+func BazelSingleton() Singleton {
+	return &bazelSingleton{}
+}
+
+type bazelSingleton struct{}
+
+func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
+	if ctx.Config().BazelContext.BazelEnabled() {
+		bazelBuildList := absolutePath(filepath.Join(
+			filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
+		ctx.AddNinjaFileDeps(bazelBuildList)
+
+		data, err := ioutil.ReadFile(bazelBuildList)
+		if err != nil {
+			ctx.Errorf(err.Error())
+		}
+		files := strings.Split(strings.TrimSpace(string(data)), "\n")
+		for _, file := range files {
+			ctx.AddNinjaFileDeps(file)
+		}
+	}
+}
diff --git a/android/config.go b/android/config.go
index 8df65f7..cf6d596 100644
--- a/android/config.go
+++ b/android/config.go
@@ -85,14 +85,17 @@
 	// Only available on configs created by TestConfig
 	TestProductVariables *productVariables
 
+	BazelContext BazelContext
+
 	PrimaryBuilder           string
 	ConfigFileName           string
 	ProductVariablesFileName string
 
-	Targets             map[OsType][]Target
-	BuildOSTarget       Target // the Target for tools run on the build machine
-	BuildOSCommonTarget Target // the Target for common (java) tools run on the build machine
-	AndroidCommonTarget Target // the Target for common modules for the Android device
+	Targets                  map[OsType][]Target
+	BuildOSTarget            Target // the Target for tools run on the build machine
+	BuildOSCommonTarget      Target // the Target for common (java) tools run on the build machine
+	AndroidCommonTarget      Target // the Target for common modules for the Android device
+	AndroidFirstDeviceTarget Target // the first Target for modules for the Android device
 
 	// multilibConflicts for an ArchType is true if there is earlier configured device architecture with the same
 	// multilib value.
@@ -248,6 +251,8 @@
 		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
 		// passed to PathForSource or PathForModuleSrc.
 		testAllowNonExistentPaths: true,
+
+		BazelContext: noopBazelContext{},
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
@@ -316,6 +321,7 @@
 	config.BuildOSTarget = config.Targets[BuildOs][0]
 	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
 	config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+	config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
 	config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
 	config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
@@ -324,6 +330,20 @@
 	return testConfig
 }
 
+// Returns a config object which is "reset" for another bootstrap run.
+// Only per-run data is reset. Data which needs to persist across multiple
+// runs in the same program execution is carried over (such as Bazel context
+// or environment deps).
+func ConfigForAdditionalRun(c Config) (Config, error) {
+	newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile)
+	if err != nil {
+		return Config{}, err
+	}
+	newConfig.BazelContext = c.BazelContext
+	newConfig.envDeps = c.envDeps
+	return newConfig, nil
+}
+
 // New creates a new Config object.  The srcDir argument specifies the path to
 // the root source directory. It also loads the config file, if found.
 func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) {
@@ -411,6 +431,7 @@
 	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
 	if len(config.Targets[Android]) > 0 {
 		config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+		config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	}
 
 	if err := config.fromEnv(); err != nil {
@@ -425,6 +446,10 @@
 		Bool(config.productVariables.GcovCoverage) ||
 			Bool(config.productVariables.ClangCoverage))
 
+	config.BazelContext, err = NewBazelContext(config)
+	if err != nil {
+		return Config{}, err
+	}
 	return Config{config}, nil
 }
 
@@ -916,6 +941,10 @@
 	return false
 }
 
+func (c *config) EnforceRROExemptedForModule(name string) bool {
+	return InList(name, c.productVariables.EnforceRROExemptedTargets)
+}
+
 func (c *config) EnforceRROExcludedOverlay(path string) bool {
 	excluded := c.productVariables.EnforceRROExcludedOverlays
 	if len(excluded) > 0 {
@@ -1116,12 +1145,12 @@
 	return c.config.productVariables.BoardOdmSepolicyDirs
 }
 
-func (c *deviceConfig) PlatPublicSepolicyDirs() []string {
-	return c.config.productVariables.BoardPlatPublicSepolicyDirs
+func (c *deviceConfig) SystemExtPublicSepolicyDirs() []string {
+	return c.config.productVariables.SystemExtPublicSepolicyDirs
 }
 
-func (c *deviceConfig) PlatPrivateSepolicyDirs() []string {
-	return c.config.productVariables.BoardPlatPrivateSepolicyDirs
+func (c *deviceConfig) SystemExtPrivateSepolicyDirs() []string {
+	return c.config.productVariables.SystemExtPrivateSepolicyDirs
 }
 
 func (c *deviceConfig) SepolicyM4Defs() []string {
diff --git a/android/defaults.go b/android/defaults.go
index 0892adf..eb013d7 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -95,6 +95,8 @@
 	module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
 
 	module.AddProperties(module.defaults())
+
+	module.base().customizableProperties = module.GetProperties()
 }
 
 // A restricted subset of context methods, similar to LoadHookContext.
diff --git a/android/depset.go b/android/depset.go
index f707094..60ebcac 100644
--- a/android/depset.go
+++ b/android/depset.go
@@ -71,24 +71,26 @@
 // NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
 func NewDepSet(order DepSetOrder, direct Paths, transitive []*DepSet) *DepSet {
 	var directCopy Paths
-	var transitiveCopy []*DepSet
+	transitiveCopy := make([]*DepSet, 0, len(transitive))
+
+	for _, dep := range transitive {
+		if dep != nil {
+			if dep.order != order {
+				panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
+					order, dep.order))
+			}
+			transitiveCopy = append(transitiveCopy, dep)
+		}
+	}
+
 	if order == TOPOLOGICAL {
 		directCopy = ReversePaths(direct)
-		transitiveCopy = reverseDepSets(transitive)
+		reverseDepSetsInPlace(transitiveCopy)
 	} else {
 		// Use copy instead of append(nil, ...) to make a slice that is exactly the size of the input
 		// slice.  The DepSet is immutable, there is no need for additional capacity.
 		directCopy = make(Paths, len(direct))
 		copy(directCopy, direct)
-		transitiveCopy = make([]*DepSet, len(transitive))
-		copy(transitiveCopy, transitive)
-	}
-
-	for _, dep := range transitive {
-		if dep.order != order {
-			panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
-				order, dep.order))
-		}
 	}
 
 	return &DepSet{
@@ -157,6 +159,9 @@
 // its transitive dependencies, in which case the ordering of the duplicated element is not
 // guaranteed).
 func (d *DepSet) ToList() Paths {
+	if d == nil {
+		return nil
+	}
 	var list Paths
 	d.walk(func(paths Paths) {
 		list = append(list, paths...)
@@ -181,10 +186,9 @@
 	}
 }
 
-func reverseDepSets(list []*DepSet) []*DepSet {
-	ret := make([]*DepSet, len(list))
-	for i := range list {
-		ret[i] = list[len(list)-1-i]
+func reverseDepSetsInPlace(list []*DepSet) {
+	for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
+		list[i], list[j] = list[j], list[i]
 	}
-	return ret
+
 }
diff --git a/android/makevars.go b/android/makevars.go
index 374986e..3ca7792 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -128,7 +128,7 @@
 type MakeVarsProvider func(ctx MakeVarsContext)
 
 func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
-	makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
+	makeVarsInitProviders = append(makeVarsInitProviders, makeVarsProvider{pctx, provider})
 }
 
 // SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
@@ -142,7 +142,8 @@
 // registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to the list of
 // MakeVarsProviders to run.
 func registerSingletonMakeVarsProvider(singleton SingletonMakeVarsProvider) {
-	makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, SingletonmakeVarsProviderAdapter(singleton)})
+	singletonMakeVarsProviders = append(singletonMakeVarsProviders,
+		makeVarsProvider{pctx, SingletonmakeVarsProviderAdapter(singleton)})
 }
 
 // SingletonmakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
@@ -171,7 +172,11 @@
 	call MakeVarsProvider
 }
 
-var makeVarsProviders []makeVarsProvider
+// Collection of makevars providers that are registered in init() methods.
+var makeVarsInitProviders []makeVarsProvider
+
+// Collection of singleton makevars providers that are not registered as part of init() methods.
+var singletonMakeVarsProviders []makeVarsProvider
 
 type makeVarsContext struct {
 	SingletonContext
@@ -219,7 +224,7 @@
 	var vars []makeVarsVariable
 	var dists []dist
 	var phonies []phony
-	for _, provider := range makeVarsProviders {
+	for _, provider := range append(makeVarsInitProviders) {
 		mctx := &makeVarsContext{
 			SingletonContext: ctx,
 			pctx:             provider.pctx,
@@ -232,6 +237,25 @@
 		dists = append(dists, mctx.dists...)
 	}
 
+	for _, provider := range append(singletonMakeVarsProviders) {
+		mctx := &makeVarsContext{
+			SingletonContext: ctx,
+			pctx:             provider.pctx,
+		}
+
+		provider.call(mctx)
+
+		vars = append(vars, mctx.vars...)
+		phonies = append(phonies, mctx.phonies...)
+		dists = append(dists, mctx.dists...)
+	}
+
+	// Clear singleton makevars providers after use. Since these are in-memory
+	// singletons, this ensures state is reset if the build tree is processed
+	// multiple times.
+	// TODO(cparsons): Clean up makeVarsProviders to be part of the context.
+	singletonMakeVarsProviders = nil
+
 	ctx.VisitAllModules(func(m Module) {
 		if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() {
 			mctx := &makeVarsContext{
diff --git a/android/module.go b/android/module.go
index c4e43c2..822e5bd 100644
--- a/android/module.go
+++ b/android/module.go
@@ -435,7 +435,7 @@
 	HostRequiredModuleNames() []string
 	TargetRequiredModuleNames() []string
 
-	filesToInstall() InstallPaths
+	FilesToInstall() InstallPaths
 }
 
 // Qualified id for a module
@@ -1241,14 +1241,14 @@
 	// TODO(ccross): we need to use WalkDeps and have some way to know which dependencies require installation
 	ctx.VisitDepsDepthFirst(func(m blueprint.Module) {
 		if a, ok := m.(Module); ok {
-			result = append(result, a.filesToInstall()...)
+			result = append(result, a.FilesToInstall()...)
 		}
 	})
 
 	return result
 }
 
-func (m *ModuleBase) filesToInstall() InstallPaths {
+func (m *ModuleBase) FilesToInstall() InstallPaths {
 	return m.installFiles
 }
 
@@ -1499,8 +1499,8 @@
 	if !ctx.PrimaryArch() {
 		suffix = append(suffix, ctx.Arch().ArchType.String())
 	}
-	if apex, ok := m.module.(ApexModule); ok && !apex.IsForPlatform() {
-		suffix = append(suffix, apex.ApexVariationName())
+	if apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo); !apexInfo.IsForPlatform() {
+		suffix = append(suffix, apexInfo.ApexVariationName)
 	}
 
 	ctx.Variable(pctx, "moduleDesc", desc)
diff --git a/android/paths_test.go b/android/paths_test.go
index d099f65..108bd6c 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1260,7 +1260,7 @@
 	// boot.art boot.oat
 }
 
-func ExampleOutputPath_FileInSameDir() {
+func ExampleOutputPath_InSameDir() {
 	ctx := &configErrorWrapper{
 		config: TestConfig("out", nil, "", nil),
 	}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 734871b..294a6e0 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -93,7 +93,7 @@
 // more modules like this.
 func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
 	if p.srcsSupplier != nil {
-		srcs := p.srcsSupplier()
+		srcs := p.srcsSupplier(ctx)
 
 		if len(srcs) == 0 {
 			ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
@@ -122,7 +122,7 @@
 // Called to provide the srcs value for the prebuilt module.
 //
 // Return the src value or nil if it is not available.
-type PrebuiltSrcsSupplier func() []string
+type PrebuiltSrcsSupplier func(ctx BaseModuleContext) []string
 
 // Initialize the module as a prebuilt module that uses the provided supplier to access the
 // prebuilt sources of the module.
@@ -156,7 +156,7 @@
 		panic(fmt.Errorf("srcs must not be nil"))
 	}
 
-	srcsSupplier := func() []string {
+	srcsSupplier := func(ctx BaseModuleContext) []string {
 		return *srcs
 	}
 
@@ -177,7 +177,7 @@
 	srcFieldIndex := srcStructField.Index
 	srcPropertyName := proptools.PropertyNameForField(srcField)
 
-	srcsSupplier := func() []string {
+	srcsSupplier := func(ctx BaseModuleContext) []string {
 		value := srcPropsValue.FieldByIndex(srcFieldIndex)
 		if value.Kind() == reflect.Ptr {
 			value = value.Elem()
@@ -287,7 +287,7 @@
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
 func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
-	if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
+	if p.srcsSupplier != nil && len(p.srcsSupplier(ctx)) == 0 {
 		return false
 	}
 
diff --git a/android/register.go b/android/register.go
index 036a811..ad3df7e 100644
--- a/android/register.go
+++ b/android/register.go
@@ -104,6 +104,8 @@
 
 	registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)
 
+	ctx.RegisterSingletonType("bazeldeps", SingletonFactoryAdaptor(BazelSingleton))
+
 	// Register phony just before makevars so it can write out its phony rules as Make rules
 	ctx.RegisterSingletonType("phony", SingletonFactoryAdaptor(phonySingletonFactory))
 
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index f905b1a..9677f34 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -19,8 +19,24 @@
 	"testing"
 )
 
+type soongConfigTestDefaultsModuleProperties struct {
+}
+
+type soongConfigTestDefaultsModule struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func soongConfigTestDefaultsModuleFactory() Module {
+	m := &soongConfigTestDefaultsModule{}
+	m.AddProperties(&soongConfigTestModuleProperties{})
+	InitDefaultsModule(m)
+	return m
+}
+
 type soongConfigTestModule struct {
 	ModuleBase
+	DefaultableModuleBase
 	props soongConfigTestModuleProperties
 }
 
@@ -32,6 +48,7 @@
 	m := &soongConfigTestModule{}
 	m.AddProperties(&m.props)
 	InitAndroidModule(m)
+	InitDefaultableModule(m)
 	return m
 }
 
@@ -40,13 +57,13 @@
 func TestSoongConfigModule(t *testing.T) {
 	configBp := `
 		soong_config_module_type {
-			name: "acme_test_defaults",
-			module_type: "test_defaults",
+			name: "acme_test",
+			module_type: "test",
 			config_namespace: "acme",
 			variables: ["board", "feature1", "FEATURE3"],
 			bool_variables: ["feature2"],
 			value_variables: ["size"],
-			properties: ["cflags", "srcs"],
+			properties: ["cflags", "srcs", "defaults"],
 		}
 
 		soong_config_string_variable {
@@ -66,14 +83,20 @@
 	importBp := `
 		soong_config_module_type_import {
 			from: "SoongConfig.bp",
-			module_types: ["acme_test_defaults"],
+			module_types: ["acme_test"],
 		}
 	`
 
 	bp := `
-		acme_test_defaults {
+		test_defaults {
+			name: "foo_defaults",
+			cflags: ["DEFAULT"],
+		}
+
+		acme_test {
 			name: "foo",
 			cflags: ["-DGENERIC"],
+			defaults: ["foo_defaults"],
 			soong_config_variables: {
 				board: {
 					soc_a: {
@@ -97,6 +120,46 @@
 				},
 			},
 		}
+
+		test_defaults {
+			name: "foo_defaults_a",
+			cflags: ["DEFAULT_A"],
+		}
+
+		test_defaults {
+			name: "foo_defaults_b",
+			cflags: ["DEFAULT_B"],
+		}
+
+		acme_test {
+			name: "foo_with_defaults",
+			cflags: ["-DGENERIC"],
+			defaults: ["foo_defaults"],
+			soong_config_variables: {
+				board: {
+					soc_a: {
+						cflags: ["-DSOC_A"],
+						defaults: ["foo_defaults_a"],
+					},
+					soc_b: {
+						cflags: ["-DSOC_B"],
+						defaults: ["foo_defaults_b"],
+					},
+				},
+				size: {
+					cflags: ["-DSIZE=%s"],
+				},
+				feature1: {
+					cflags: ["-DFEATURE1"],
+				},
+				feature2: {
+					cflags: ["-DFEATURE2"],
+				},
+				FEATURE3: {
+					cflags: ["-DFEATURE3"],
+				},
+			},
+		}
     `
 
 	run := func(t *testing.T, bp string, fs map[string][]byte) {
@@ -117,7 +180,9 @@
 		ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
 		ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
 		ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
-		ctx.RegisterModuleType("test_defaults", soongConfigTestModuleFactory)
+		ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
+		ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
+		ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
 		ctx.Register(config)
 
 		_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -125,10 +190,18 @@
 		_, errs = ctx.PrepareBuildActions(config)
 		FailIfErrored(t, errs)
 
+		basicCFlags := []string{"DEFAULT", "-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}
+
 		foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
-		if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
+		if g, w := foo.props.Cflags, basicCFlags; !reflect.DeepEqual(g, w) {
 			t.Errorf("wanted foo cflags %q, got %q", w, g)
 		}
+
+		fooDefaults := ctx.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule)
+		if g, w := fooDefaults.props.Cflags, append([]string{"DEFAULT_A"}, basicCFlags...); !reflect.DeepEqual(g, w) {
+			t.Errorf("wanted foo_with_defaults cflags %q, got %q", w, g)
+		}
+
 	}
 
 	t.Run("single file", func(t *testing.T) {
diff --git a/android/test_suites.go b/android/test_suites.go
index 34e487e..19444a8 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -41,7 +41,7 @@
 					files[testSuite] = make(map[string]InstallPaths)
 				}
 				name := ctx.ModuleName(m)
-				files[testSuite][name] = append(files[testSuite][name], tsm.filesToInstall()...)
+				files[testSuite][name] = append(files[testSuite][name], tsm.FilesToInstall()...)
 			}
 		}
 	})
diff --git a/android/variable.go b/android/variable.go
index ce523ed..a9495cc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -304,8 +304,8 @@
 
 	BoardVendorSepolicyDirs      []string `json:",omitempty"`
 	BoardOdmSepolicyDirs         []string `json:",omitempty"`
-	BoardPlatPublicSepolicyDirs  []string `json:",omitempty"`
-	BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
+	SystemExtPublicSepolicyDirs  []string `json:",omitempty"`
+	SystemExtPrivateSepolicyDirs []string `json:",omitempty"`
 	BoardSepolicyM4Defs          []string `json:",omitempty"`
 
 	VendorVars map[string]map[string]string `json:",omitempty"`
@@ -390,7 +390,7 @@
 		AAPTPrebuiltDPI:     []string{"xhdpi", "xxhdpi"},
 
 		Malloc_not_svelte:            boolPtr(true),
-		Malloc_zero_contents:         boolPtr(false),
+		Malloc_zero_contents:         boolPtr(true),
 		Malloc_pattern_fill_contents: boolPtr(false),
 		Safestack:                    boolPtr(false),
 	}
diff --git a/android/vts_config.go b/android/vts_config.go
deleted file mode 100644
index 77fb9fe..0000000
--- a/android/vts_config.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 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 android
-
-import (
-	"fmt"
-	"io"
-	"strings"
-)
-
-func init() {
-	RegisterModuleType("vts_config", VtsConfigFactory)
-}
-
-type vtsConfigProperties struct {
-	// Override the default (AndroidTest.xml) test manifest file name.
-	Test_config *string
-	// Additional test suites to add the test to.
-	Test_suites []string `android:"arch_variant"`
-}
-
-type VtsConfig struct {
-	ModuleBase
-	properties     vtsConfigProperties
-	OutputFilePath OutputPath
-}
-
-func (me *VtsConfig) GenerateAndroidBuildActions(ctx ModuleContext) {
-	me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName()).OutputPath
-}
-
-func (me *VtsConfig) AndroidMk() AndroidMkData {
-	androidMkData := AndroidMkData{
-		Class:      "FAKE",
-		Include:    "$(BUILD_SYSTEM)/suite_host_config.mk",
-		OutputFile: OptionalPathForPath(me.OutputFilePath),
-	}
-	androidMkData.Extra = []AndroidMkExtraFunc{
-		func(w io.Writer, outputFile Path) {
-			if me.properties.Test_config != nil {
-				fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
-					*me.properties.Test_config)
-			}
-			fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts10 %s\n",
-				strings.Join(me.properties.Test_suites, " "))
-		},
-	}
-	return androidMkData
-}
-
-func InitVtsConfigModule(me *VtsConfig) {
-	me.AddProperties(&me.properties)
-}
-
-// vts_config generates a Vendor Test Suite (VTS10) configuration file from the
-// <test_config> xml file and stores it in a subdirectory of $(HOST_OUT).
-func VtsConfigFactory() Module {
-	module := &VtsConfig{}
-	InitVtsConfigModule(module)
-	InitAndroidArchModule(module /*TODO: or HostAndDeviceSupported? */, HostSupported, MultilibFirst)
-	return module
-}
diff --git a/android/vts_config_test.go b/android/vts_config_test.go
deleted file mode 100644
index 254fa92..0000000
--- a/android/vts_config_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 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 android
-
-import (
-	"testing"
-)
-
-func testVtsConfig(test *testing.T, bpFileContents string) *TestContext {
-	config := TestArchConfig(buildDir, nil, bpFileContents, nil)
-
-	ctx := NewTestArchContext()
-	ctx.RegisterModuleType("vts_config", VtsConfigFactory)
-	ctx.Register(config)
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	FailIfErrored(test, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	FailIfErrored(test, errs)
-	return ctx
-}
-
-func TestVtsConfig(t *testing.T) {
-	ctx := testVtsConfig(t, `
-vts_config { name: "plain"}
-vts_config { name: "with_manifest", test_config: "manifest.xml" }
-`)
-
-	variants := ctx.ModuleVariantsForTests("plain")
-	if len(variants) > 1 {
-		t.Errorf("expected 1, got %d", len(variants))
-	}
-	expectedOutputFilename := ctx.ModuleForTests(
-		"plain", variants[0]).Module().(*VtsConfig).OutputFilePath.Base()
-	if expectedOutputFilename != "plain" {
-		t.Errorf("expected plain, got %q", expectedOutputFilename)
-	}
-}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index eaf06c5..739a965 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -953,8 +953,7 @@
 var soongModuleTypes = map[string]bool{}
 
 var includePathToModule = map[string]string{
-	"test/vts/tools/build/Android.host_config.mk": "vts_config",
-	// The rest will be populated dynamically in androidScope below
+	// The content will be populated dynamically in androidScope below
 }
 
 func mapIncludePath(path string) (string, bool) {
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 2448acc..16cb138 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1257,19 +1257,6 @@
 `,
 	},
 	{
-		desc: "vts_config",
-		in: `
-include $(CLEAR_VARS)
-LOCAL_MODULE := vtsconf
-include test/vts/tools/build/Android.host_config.mk
-`,
-		expected: `
-vts_config {
-	name: "vtsconf",
-}
-`,
-	},
-	{
 		desc: "comment with ESC",
 		in: `
 # Comment line 1 \
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 87e96ea..cd4b056 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -124,6 +124,7 @@
 apache-commons-compress(minSdkVersion:current)
 art.module.public.api.stubs(minSdkVersion:(no version))
 bcm_object(minSdkVersion:29)
+bionic_libc_platform_headers(minSdkVersion:29)
 boringssl_self_test(minSdkVersion:29)
 bouncycastle_ike_digests(minSdkVersion:current)
 brotli-java(minSdkVersion:current)
@@ -138,12 +139,19 @@
 conscrypt.module.public.api.stubs(minSdkVersion:(no version))
 core-lambda-stubs(minSdkVersion:(no version))
 core.current.stubs(minSdkVersion:(no version))
+crtbegin_dynamic(minSdkVersion:16)
 crtbegin_dynamic(minSdkVersion:apex_inherit)
+crtbegin_dynamic1(minSdkVersion:16)
 crtbegin_dynamic1(minSdkVersion:apex_inherit)
+crtbegin_so(minSdkVersion:16)
 crtbegin_so(minSdkVersion:apex_inherit)
+crtbegin_so1(minSdkVersion:16)
 crtbegin_so1(minSdkVersion:apex_inherit)
+crtbrand(minSdkVersion:16)
 crtbrand(minSdkVersion:apex_inherit)
+crtend_android(minSdkVersion:16)
 crtend_android(minSdkVersion:apex_inherit)
+crtend_so(minSdkVersion:16)
 crtend_so(minSdkVersion:apex_inherit)
 datastallprotosnano(minSdkVersion:29)
 derive_sdk(minSdkVersion:current)
@@ -186,6 +194,7 @@
 libadb_pairing_connection(minSdkVersion:(no version))
 libadb_pairing_server(minSdkVersion:(no version))
 libadb_protos(minSdkVersion:(no version))
+libadb_sysdeps(minSdkVersion:apex_inherit)
 libadb_tls_connection(minSdkVersion:(no version))
 libadbconnection_client(minSdkVersion:(no version))
 libadbconnection_server(minSdkVersion:(no version))
@@ -273,6 +282,7 @@
 libFLAC-headers(minSdkVersion:29)
 libflacextractor(minSdkVersion:29)
 libfmq(minSdkVersion:29)
+libfmq-base(minSdkVersion:29)
 libFraunhoferAAC(minSdkVersion:29)
 libgav1(minSdkVersion:29)
 libgcc_stripped(minSdkVersion:(no version))
@@ -289,6 +299,7 @@
 libhidlbase(minSdkVersion:29)
 libhidlmemory(minSdkVersion:29)
 libhwbinder-impl-internal(minSdkVersion:29)
+libhwbinder_headers(minSdkVersion:29)
 libion(minSdkVersion:29)
 libjavacrypto(minSdkVersion:29)
 libjsoncpp(minSdkVersion:29)
diff --git a/apex/androidmk.go b/apex/androidmk.go
index f76181d..ee8b2b3 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -264,6 +264,10 @@
 						postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
 					}
 				}
+
+				// File_contexts of flattened APEXes should be merged into file_contexts.bin
+				fmt.Fprintln(w, "LOCAL_FILE_CONTEXTS :=", a.fileContexts)
+
 				if len(postInstallCommands) > 0 {
 					fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
 				}
diff --git a/apex/apex.go b/apex/apex.go
index 0108c0f..a9a58a6 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -19,7 +19,6 @@
 	"path/filepath"
 	"sort"
 	"strings"
-	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
@@ -68,6 +67,7 @@
 	androidAppTag  = dependencyTag{name: "androidApp", payload: true}
 	rroTag         = dependencyTag{name: "rro", payload: true}
 	bpfTag         = dependencyTag{name: "bpf", payload: true}
+	testForTag     = dependencyTag{name: "test for"}
 
 	apexAvailBaseline = makeApexAvailableBaseline()
 
@@ -743,12 +743,6 @@
 	android.PreDepsMutators(RegisterPreDepsMutators)
 	android.PostDepsMutators(RegisterPostDepsMutators)
 
-	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
-		apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
-		sort.Strings(*apexFileContextsInfos)
-		ctx.Strict("APEX_FILE_CONTEXTS_INFOS", strings.Join(*apexFileContextsInfos, " "))
-	})
-
 	android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...)
 	android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...)
 }
@@ -776,7 +770,10 @@
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
 	ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
+	ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
+	ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
 	ctx.BottomUp("apex", apexMutator).Parallel()
+	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
 	ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
 	ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
 	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
@@ -792,13 +789,6 @@
 	if !ok || a.vndkApex {
 		return
 	}
-	apexInfo := android.ApexInfo{
-		ApexVariationName: mctx.ModuleName(),
-		MinSdkVersionStr:  a.minSdkVersion(mctx).String(),
-		RequiredSdks:      a.RequiredSdks(),
-		Updatable:         a.Updatable(),
-		InApexes:          []string{mctx.ModuleName()},
-	}
 
 	useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
 	excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
@@ -807,7 +797,9 @@
 		return
 	}
 
-	mctx.WalkDeps(func(child, parent android.Module) bool {
+	contents := make(map[string]android.ApexMembership)
+
+	continueApexDepsWalk := func(child, parent android.Module) bool {
 		am, ok := child.(android.ApexModule)
 		if !ok || !am.CanHaveApexVariants() {
 			return false
@@ -820,12 +812,41 @@
 				return false
 			}
 		}
+		return true
+	}
+
+	mctx.WalkDeps(func(child, parent android.Module) bool {
+		if !continueApexDepsWalk(child, parent) {
+			return false
+		}
 
 		depName := mctx.OtherModuleName(child)
 		// If the parent is apexBundle, this child is directly depended.
 		_, directDep := parent.(*apexBundle)
-		android.UpdateApexDependency(apexInfo, depName, directDep)
-		am.BuildForApex(apexInfo)
+		contents[depName] = contents[depName].Add(directDep)
+		return true
+	})
+
+	apexContents := android.NewApexContents(mctx.ModuleName(), contents)
+	mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+		Contents: apexContents,
+	})
+
+	apexInfo := android.ApexInfo{
+		ApexVariationName: mctx.ModuleName(),
+		MinSdkVersionStr:  a.minSdkVersion(mctx).String(),
+		RequiredSdks:      a.RequiredSdks(),
+		Updatable:         a.Updatable(),
+		InApexes:          []string{mctx.ModuleName()},
+		ApexContents:      []*android.ApexContents{apexContents},
+	}
+
+	mctx.WalkDeps(func(child, parent android.Module) bool {
+		if !continueApexDepsWalk(child, parent) {
+			return false
+		}
+
+		child.(android.ApexModule).BuildForApex(apexInfo)
 		return true
 	})
 }
@@ -837,7 +858,40 @@
 	if am, ok := mctx.Module().(android.ApexModule); ok {
 		// Check if any dependencies use unique apex variations.  If so, use unique apex variations
 		// for this module.
-		am.UpdateUniqueApexVariationsForDeps(mctx)
+		android.UpdateUniqueApexVariationsForDeps(mctx, am)
+	}
+}
+
+func apexTestForDepsMutator(mctx android.BottomUpMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
+	// Check if this module is a test for an apex.  If so, add a dependency on the apex
+	// in order to retrieve its contents later.
+	if am, ok := mctx.Module().(android.ApexModule); ok {
+		if testFor := am.TestFor(); len(testFor) > 0 {
+			mctx.AddFarVariationDependencies([]blueprint.Variation{
+				{Mutator: "os", Variation: am.Target().OsVariation()},
+				{"arch", "common"},
+			}, testForTag, testFor...)
+		}
+	}
+}
+
+func apexTestForMutator(mctx android.BottomUpMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
+
+	if _, ok := mctx.Module().(android.ApexModule); ok {
+		var contents []*android.ApexContents
+		for _, testFor := range mctx.GetDirectDepsWithTag(testForTag) {
+			abInfo := mctx.OtherModuleProvider(testFor, ApexBundleInfoProvider).(ApexBundleInfo)
+			contents = append(contents, abInfo.Contents)
+		}
+		mctx.SetProvider(android.ApexTestForInfoProvider, android.ApexTestForInfo{
+			ApexContents: contents,
+		})
 	}
 }
 
@@ -898,8 +952,9 @@
 	if !mctx.Module().Enabled() {
 		return
 	}
+
 	if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
-		am.CreateApexVariations(mctx)
+		android.CreateApexVariations(mctx, am)
 	} else if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
 		// apex bundle itself is mutated so that it and its modules have same
 		// apex variant.
@@ -916,22 +971,13 @@
 
 }
 
-var (
-	apexFileContextsInfosKey   = android.NewOnceKey("apexFileContextsInfosKey")
-	apexFileContextsInfosMutex sync.Mutex
-)
-
-func apexFileContextsInfos(config android.Config) *[]string {
-	return config.Once(apexFileContextsInfosKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-func addFlattenedFileContextsInfos(ctx android.BaseModuleContext, fileContextsInfo string) {
-	apexFileContextsInfosMutex.Lock()
-	defer apexFileContextsInfosMutex.Unlock()
-	apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
-	*apexFileContextsInfos = append(*apexFileContextsInfos, fileContextsInfo)
+func apexDirectlyInAnyMutator(mctx android.BottomUpMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
+	if am, ok := mctx.Module().(android.ApexModule); ok {
+		android.UpdateDirectlyInAnyApex(mctx, am)
+	}
 }
 
 func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
@@ -1143,6 +1189,12 @@
 	Payload_fs_type *string
 }
 
+type ApexBundleInfo struct {
+	Contents *android.ApexContents
+}
+
+var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_deps")
+
 type apexTargetBundleProperties struct {
 	Target struct {
 		// Multilib properties only for android.
@@ -1933,6 +1985,8 @@
 			return false
 		}
 
+		childApexInfo := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
+
 		dt := ctx.OtherModuleDependencyTag(child)
 
 		if _, ok := dt.(android.ExcludeFromApexContentsTag); ok {
@@ -1949,7 +2003,7 @@
 		}
 
 		// Check for the indirect dependencies if it is considered as part of the APEX
-		if android.InList(ctx.ModuleName(), am.InApexes()) {
+		if android.InList(ctx.ModuleName(), childApexInfo.InApexes) {
 			return do(ctx, parent, am, false /* externalDep */)
 		}
 
@@ -2057,6 +2111,8 @@
 		return
 	}
 
+	abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+
 	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if ccm, ok := to.(*cc.Module); ok {
 			apexName := ctx.ModuleName()
@@ -2077,7 +2133,7 @@
 				return false
 			}
 
-			isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !android.DirectlyInApex(apexName, toName)
+			isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !abInfo.Contents.DirectlyInApex(toName)
 			if isStubLibraryFromOtherApex && !externalDep {
 				ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+
 					"It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false))
@@ -2316,7 +2372,8 @@
 						}
 						af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
 						af.transitiveDep = true
-						if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
+						abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+						if !a.Host() && !abInfo.Contents.DirectlyInApex(depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
 							// If the dependency is a stubs lib, don't include it in this APEX,
 							// but make sure that the lib is installed on the device.
 							// In case no APEX is having the lib, the lib is installed to the system
@@ -2324,7 +2381,7 @@
 							//
 							// Always include if we are a host-apex however since those won't have any
 							// system libraries.
-							if !android.DirectlyInAnyApex(ctx, depName) {
+							if !am.DirectlyInAnyApex() {
 								// we need a module name for Make
 								name := cc.BaseModuleName() + cc.Properties.SubName
 								if proptools.Bool(a.properties.Use_vendor) {
@@ -2363,6 +2420,8 @@
 					if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
 						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
 					}
+				} else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
+					// nothing
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 					ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
 				}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index afb739c..803e0c5 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -72,8 +72,11 @@
 	updatableFlatLists := android.Paths{}
 	ctx.VisitAllModules(func(module android.Module) {
 		if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
-			if path := binaryInfo.FlatListPath(); path != nil && binaryInfo.Updatable() {
-				updatableFlatLists = append(updatableFlatLists, path)
+			apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+			if path := binaryInfo.FlatListPath(); path != nil {
+				if binaryInfo.Updatable() || apexInfo.Updatable {
+					updatableFlatLists = append(updatableFlatLists, path)
+				}
 			}
 		}
 	})
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 71c4aa2..c52fd04 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -125,8 +125,6 @@
 }
 
 func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
-	android.ClearApexDependency()
-
 	bp = bp + `
 		filegroup {
 			name: "myapex-file_contexts",
@@ -1321,6 +1319,7 @@
 		cc_library {
 			name: "mylib",
 			srcs: ["mylib.cpp"],
+			system_shared_libs: ["libc", "libm"],
 			shared_libs: ["libdl#27"],
 			stl: "none",
 			apex_available: [ "myapex" ],
@@ -1607,10 +1606,12 @@
 	`)
 
 	expectLink := func(from, from_variant, to, to_variant string) {
+		t.Helper()
 		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
 		ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
 	}
 	expectNoLink := func(from, from_variant, to, to_variant string) {
+		t.Helper()
 		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
 		ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
 	}
@@ -3643,16 +3644,13 @@
 	// Ensure that the platform variant ends with _shared
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared")
 
-	if !android.InAnyApex("mylib_common") {
+	if !ctx.ModuleForTests("mylib_common", "android_arm64_armv8-a_shared_apex10000").Module().(*cc.Module).InAnyApex() {
 		t.Log("Found mylib_common not in any apex!")
 		t.Fail()
 	}
 }
 
 func TestTestApex(t *testing.T) {
-	if android.InAnyApex("mylib_common_test") {
-		t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!")
-	}
 	ctx, _ := testApex(t, `
 		apex_test {
 			name: "myapex",
@@ -5600,6 +5598,36 @@
 	ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$")
 }
 
+func TestAppSetBundlePrebuilt(t *testing.T) {
+	ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+		bp := `
+		apex_set {
+			name: "myapex",
+			filename: "foo_v2.apex",
+			sanitized: {
+				none: { set: "myapex.apks", },
+				hwaddress: { set: "myapex.hwasan.apks", },
+			},
+		}`
+		fs["Android.bp"] = []byte(bp)
+
+		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+	})
+
+	m := ctx.ModuleForTests("myapex", "android_common")
+	extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex")
+
+	actual := extractedApex.Inputs
+	if len(actual) != 1 {
+		t.Errorf("expected a single input")
+	}
+
+	expected := "myapex.hwasan.apks"
+	if actual[0].String() != expected {
+		t.Errorf("expected %s, got %s", expected, actual[0].String())
+	}
+}
+
 func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
 	t.Helper()
 
@@ -5845,7 +5873,6 @@
 
 func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) {
 	t.Helper()
-	android.ClearApexDependency()
 	bp += `
 	apex_key {
 		name: "myapex.key",
diff --git a/apex/builder.go b/apex/builder.go
index b0f0c82..7c125ef 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -257,15 +257,34 @@
 
 	output := android.PathForModuleOut(ctx, "file_contexts")
 	rule := android.NewRuleBuilder()
-	// remove old file
-	rule.Command().Text("rm").FlagWithOutput("-f ", output)
-	// copy file_contexts
-	rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
-	// new line
-	rule.Command().Text("echo").Text(">>").Output(output)
-	// force-label /apex_manifest.pb and / as system_file so that apexd can read them
-	rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
-	rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+
+	if a.properties.ApexType == imageApex {
+		// remove old file
+		rule.Command().Text("rm").FlagWithOutput("-f ", output)
+		// copy file_contexts
+		rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+		// new line
+		rule.Command().Text("echo").Text(">>").Output(output)
+		// force-label /apex_manifest.pb and / as system_file so that apexd can read them
+		rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+		rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+	} else {
+		// For flattened apexes, install path should be prepended.
+		// File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
+		// so that it can be merged into file_contexts.bin
+		apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
+		apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
+		// remove old file
+		rule.Command().Text("rm").FlagWithOutput("-f ", output)
+		// copy file_contexts
+		rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
+		// new line
+		rule.Command().Text("echo").Text(">>").Output(output)
+		// force-label /apex_manifest.pb and / as system_file so that apexd can read them
+		rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
+		rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+	}
+
 	rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts")
 
 	a.fileContexts = output.OutputPath
@@ -689,14 +708,7 @@
 	// instead of `android.PathForOutput`) to return the correct path to the flattened
 	// APEX (as its contents is installed by Make, not Soong).
 	factx := flattenedApexContext{ctx}
-	apexBundleName := a.Name()
-	a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName)
-
-	if a.installable() {
-		installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName)
-		devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
-		addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String())
-	}
+	a.outputFile = android.PathForModuleInstall(&factx, "apex", a.Name())
 	a.buildFilesInfo(ctx)
 }
 
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9f6c8ad..ce16d73 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -50,6 +50,10 @@
 	properties prebuiltCommonProperties
 }
 
+type sanitizedPrebuilt interface {
+	hasSanitizedSource(sanitizer string) bool
+}
+
 type prebuiltCommonProperties struct {
 	ForceDisable bool `blueprint:"mutated"`
 }
@@ -75,9 +79,10 @@
 	forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled()
 	forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
 
-	// b/137216042 don't use prebuilts when address sanitizer is on
-	forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) ||
-		android.InList("hwaddress", ctx.Config().SanitizeDevice())
+	// b/137216042 don't use prebuilts when address sanitizer is on, unless the prebuilt has a sanitized source
+	sanitized := ctx.Module().(sanitizedPrebuilt)
+	forceDisable = forceDisable || (android.InList("address", ctx.Config().SanitizeDevice()) && !sanitized.hasSanitizedSource("address"))
+	forceDisable = forceDisable || (android.InList("hwaddress", ctx.Config().SanitizeDevice()) && !sanitized.hasSanitizedSource("hwaddress"))
 
 	if forceDisable && p.prebuilt.SourceExists() {
 		p.properties.ForceDisable = true
@@ -135,6 +140,10 @@
 	Overrides []string
 }
 
+func (a *Prebuilt) hasSanitizedSource(sanitizer string) bool {
+	return false
+}
+
 func (p *Prebuilt) installable() bool {
 	return p.properties.Installable == nil || proptools.Bool(p.properties.Installable)
 }
@@ -266,6 +275,18 @@
 	// the .apks file path that contains prebuilt apex files to be extracted.
 	Set *string
 
+	Sanitized struct {
+		None struct {
+			Set *string
+		}
+		Address struct {
+			Set *string
+		}
+		Hwaddress struct {
+			Set *string
+		}
+	}
+
 	// whether the extracted apex file installable.
 	Installable *bool
 
@@ -284,6 +305,41 @@
 	Prerelease *bool
 }
 
+func (a *ApexSet) prebuiltSrcs(ctx android.BaseModuleContext) []string {
+	var srcs []string
+	if a.properties.Set != nil {
+		srcs = append(srcs, *a.properties.Set)
+	}
+
+	var sanitizers []string
+	if ctx.Host() {
+		sanitizers = ctx.Config().SanitizeHost()
+	} else {
+		sanitizers = ctx.Config().SanitizeDevice()
+	}
+
+	if android.InList("address", sanitizers) && a.properties.Sanitized.Address.Set != nil {
+		srcs = append(srcs, *a.properties.Sanitized.Address.Set)
+	} else if android.InList("hwaddress", sanitizers) && a.properties.Sanitized.Hwaddress.Set != nil {
+		srcs = append(srcs, *a.properties.Sanitized.Hwaddress.Set)
+	} else if a.properties.Sanitized.None.Set != nil {
+		srcs = append(srcs, *a.properties.Sanitized.None.Set)
+	}
+
+	return srcs
+}
+
+func (a *ApexSet) hasSanitizedSource(sanitizer string) bool {
+	if sanitizer == "address" {
+		return a.properties.Sanitized.Address.Set != nil
+	}
+	if sanitizer == "hwaddress" {
+		return a.properties.Sanitized.Hwaddress.Set != nil
+	}
+
+	return false
+}
+
 func (a *ApexSet) installable() bool {
 	return a.properties.Installable == nil || proptools.Bool(a.properties.Installable)
 }
@@ -304,7 +360,12 @@
 func apexSetFactory() android.Module {
 	module := &ApexSet{}
 	module.AddProperties(&module.properties)
-	android.InitSingleSourcePrebuiltModule(module, &module.properties, "Set")
+
+	srcsSupplier := func(ctx android.BaseModuleContext) []string {
+		return module.prebuiltSrcs(ctx)
+	}
+
+	android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "set")
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
diff --git a/bazel/bazelenv.sh b/bazel/bazelenv.sh
new file mode 100755
index 0000000..2ca8baf
--- /dev/null
+++ b/bazel/bazelenv.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+# 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.
+
+# Helper script for setting environment variables required for Bazel/Soong
+# mixed builds prototype. For development use only.
+#
+# Usage:
+#   export BAZEL_PATH=[some_bazel_path] && source bazelenv.sh
+#
+# If BAZEL_PATH is not set, `which bazel` will be used
+# to locate the appropriate bazel to use.
+
+
+# Function to find top of the source tree (if $TOP isn't set) by walking up the
+# tree.
+function gettop
+{
+    local TOPFILE=build/soong/root.bp
+    if [ -n "${TOP-}" -a -f "${TOP-}/${TOPFILE}" ] ; then
+        # The following circumlocution ensures we remove symlinks from TOP.
+        (cd $TOP; PWD= /bin/pwd)
+    else
+        if [ -f $TOPFILE ] ; then
+            # The following circumlocution (repeated below as well) ensures
+            # that we record the true directory name and not one that is
+            # faked up with symlink names.
+            PWD= /bin/pwd
+        else
+            local HERE=$PWD
+            T=
+            while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+                \cd ..
+                T=`PWD= /bin/pwd -P`
+            done
+            \cd $HERE
+            if [ -f "$T/$TOPFILE" ]; then
+                echo $T
+            fi
+        fi
+    fi
+}
+
+BASE_DIR="$(mktemp -d)"
+
+if [ -z "$BAZEL_PATH" ] ; then
+    export BAZEL_PATH="$(which bazel)"
+fi
+
+export USE_BAZEL=1
+export BAZEL_HOME="$BASE_DIR/bazelhome"
+export BAZEL_OUTPUT_BASE="$BASE_DIR/output"
+export BAZEL_WORKSPACE="$(gettop)"
+
+echo "USE_BAZEL=${USE_BAZEL}"
+echo "BAZEL_PATH=${BAZEL_PATH}"
+echo "BAZEL_HOME=${BAZEL_HOME}"
+echo "BAZEL_OUTPUT_BASE=${BAZEL_OUTPUT_BASE}"
+echo "BAZEL_WORKSPACE=${BAZEL_WORKSPACE}"
+
+mkdir -p $BAZEL_HOME
+mkdir -p $BAZEL_OUTPUT_BASE
diff --git a/bazel/master.WORKSPACE.bazel b/bazel/master.WORKSPACE.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bazel/master.WORKSPACE.bazel
diff --git a/cc/OWNERS b/cc/OWNERS
new file mode 100644
index 0000000..6d7c30a
--- /dev/null
+++ b/cc/OWNERS
@@ -0,0 +1,4 @@
+per-file ndk_*.go = danalbert@google.com
+per-file tidy.go = srhines@google.com, chh@google.com
+per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
+
diff --git a/cc/androidmk.go b/cc/androidmk.go
index d92fabc..e58a172 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -33,7 +33,6 @@
 )
 
 type AndroidMkContext interface {
-	BaseModuleName() string
 	Target() android.Target
 	subAndroidMk(*android.AndroidMkEntries, interface{})
 	Arch() android.Arch
@@ -44,6 +43,7 @@
 	static() bool
 	InRamdisk() bool
 	InRecovery() bool
+	AnyVariantDirectlyInAnyApex() bool
 }
 
 type subAndroidMkProvider interface {
@@ -63,7 +63,7 @@
 }
 
 func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
-	if c.Properties.HideFromMake || !c.IsForPlatform() {
+	if c.hideApexVariantFromMake || c.Properties.HideFromMake {
 		return []android.AndroidMkEntries{{
 			Disabled: true,
 		}}
@@ -186,17 +186,17 @@
 }
 
 func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
-	exportedFlags := library.exportedFlags()
-	for _, dir := range library.exportedDirs() {
+	exportedFlags := library.flagExporter.flags
+	for _, dir := range library.flagExporter.dirs {
 		exportedFlags = append(exportedFlags, "-I"+dir.String())
 	}
-	for _, dir := range library.exportedSystemDirs() {
+	for _, dir := range library.flagExporter.systemDirs {
 		exportedFlags = append(exportedFlags, "-isystem "+dir.String())
 	}
 	if len(exportedFlags) > 0 {
 		entries.AddStrings("LOCAL_EXPORT_CFLAGS", exportedFlags...)
 	}
-	exportedDeps := library.exportedDeps()
+	exportedDeps := library.flagExporter.deps
 	if len(exportedDeps) > 0 {
 		entries.AddStrings("LOCAL_EXPORT_C_INCLUDE_DEPS", exportedDeps.Strings()...)
 	}
@@ -277,9 +277,8 @@
 			}
 		})
 	}
-	if len(library.Properties.Stubs.Versions) > 0 &&
-		android.DirectlyInAnyApex(ctx, ctx.BaseModuleName()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
-		!ctx.static() {
+	if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.AnyVariantDirectlyInAnyApex() &&
+		!ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() && !ctx.static() {
 		if library.buildStubs() && library.isLatestStubVersion() {
 			// reference the latest version via its name without suffix when it is provided by apex
 			entries.SubName = ""
@@ -443,6 +442,11 @@
 	entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String()
 	entries.Class = "SHARED_LIBRARIES"
 
+	if !c.buildStubs() {
+		entries.Disabled = true
+		return
+	}
+
 	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(c.installPath.String())
 		stem, suffix, _ := android.SplitFileExt(file)
diff --git a/cc/binary.go b/cc/binary.go
index b3ce5ff..7f7b619 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -445,7 +445,9 @@
 	// The original path becomes a symlink to the corresponding file in the
 	// runtime APEX.
 	translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
-	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
+	if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !ctx.Host() && ctx.directlyInAnyApex() &&
+		!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 55e400e..ebf89ea 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -40,19 +40,14 @@
 
 func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
 	targets := mctx.MultiTargets()
-	for _, lib := range names {
+	for _, bin := range names {
 		for _, target := range targets {
-			name, version := StubsLibNameAndVersion(lib)
-			if version == "" {
-				version = "latest"
-			}
 			variations := target.Variations()
 			if mctx.Device() {
 				variations = append(variations,
-					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
-					blueprint.Variation{Mutator: "version", Variation: version})
+					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
 			}
-			mctx.AddFarVariationDependencies(variations, dependencyTag, name)
+			mctx.AddFarVariationDependencies(variations, dependencyTag, bin)
 		}
 	}
 }
diff --git a/cc/builder.go b/cc/builder.go
index 81c09b1..8c8aa17 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -44,14 +44,14 @@
 		blueprint.RuleParams{
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
-			Command:     "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
+			Command:     "${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
 		},
 		"ccCmd", "cFlags")
 
 	ccNoDeps = pctx.AndroidStaticRule("ccNoDeps",
 		blueprint.RuleParams{
-			Command:     "$relPwd $ccCmd -c $cFlags -o $out $in",
+			Command:     "$ccCmd -c $cFlags -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
 		},
 		"ccCmd", "cFlags")
@@ -220,7 +220,7 @@
 			Labels:       map[string]string{"type": "abi-dump", "tool": "header-abi-dumper"},
 			ExecStrategy: "${config.REAbiDumperExecStrategy}",
 			Platform: map[string]string{
-				remoteexec.PoolKey:      "${config.RECXXPool}",
+				remoteexec.PoolKey: "${config.RECXXPool}",
 			},
 		}, []string{"cFlags", "exportDirs"}, nil)
 
diff --git a/cc/cc.go b/cc/cc.go
index e18349c..dbe6346 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -45,7 +45,6 @@
 		ctx.BottomUp("sdk", sdkMutator).Parallel()
 		ctx.BottomUp("vndk", VndkMutator).Parallel()
 		ctx.BottomUp("link", LinkageMutator).Parallel()
-		ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
 		ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version_selector", versionSelectorMutator).Parallel()
 		ctx.BottomUp("version", versionMutator).Parallel()
@@ -130,6 +129,9 @@
 	// Paths to .a files
 	StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
 
+	// Transitive static library dependencies of static libraries for use in ordering.
+	TranstiveStaticLibrariesForOrdering *android.DepSet
+
 	// Paths to .o files
 	Objs Objects
 	// Paths to .o files in dependencies that provide them. Note that these lists
@@ -366,6 +368,7 @@
 	bootstrap() bool
 	mustUseVendorVariant() bool
 	nativeCoverage() bool
+	directlyInAnyApex() bool
 }
 
 type ModuleContext interface {
@@ -545,8 +548,15 @@
 	dataLibDepTag         = dependencyTag{name: "data lib"}
 	runtimeDepTag         = dependencyTag{name: "runtime lib"}
 	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
+	stubImplDepTag        = dependencyTag{name: "stub_impl"}
 )
 
+type copyDirectlyInAnyApexDependencyTag dependencyTag
+
+func (copyDirectlyInAnyApexDependencyTag) CopyDirectlyInAnyApex() {}
+
+var _ android.CopyDirectlyInAnyApexTag = copyDirectlyInAnyApexDependencyTag{}
+
 func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
 	ccLibDepTag, ok := depTag.(libraryDependencyTag)
 	return ok && ccLibDepTag.shared()
@@ -608,13 +618,8 @@
 	// Flags used to compile this module
 	flags Flags
 
-	// When calling a linker, if module A depends on module B, then A must precede B in its command
-	// line invocation. depsInLinkOrder stores the proper ordering of all of the transitive
-	// deps of this module
-	depsInLinkOrder android.Paths
-
 	// only non-nil when this is a shared library that reuses the objects of a static library
-	staticVariant LinkableInterface
+	staticAnalogue *StaticLibraryInfo
 
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
@@ -622,6 +627,8 @@
 
 	// For apex variants, this is set as apex.min_sdk_version
 	apexSdkVersion android.ApiLevel
+
+	hideApexVariantFromMake bool
 }
 
 func (c *Module) Toc() android.OptionalPath {
@@ -697,6 +704,9 @@
 }
 
 func (c *Module) SplitPerApiLevel() bool {
+	if !c.canUseSdk() {
+		return false
+	}
 	if linker, ok := c.linker.(*objectLinker); ok {
 		return linker.isCrt()
 	}
@@ -707,42 +717,9 @@
 	return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
 }
 
-func (c *Module) IncludeDirs() android.Paths {
-	if c.linker != nil {
-		if library, ok := c.linker.(exportedFlagsProducer); ok {
-			return library.exportedDirs()
-		}
-	}
-	panic(fmt.Errorf("IncludeDirs called on non-exportedFlagsProducer module: %q", c.BaseModuleName()))
-}
-
-func (c *Module) HasStaticVariant() bool {
-	if c.staticVariant != nil {
-		return true
-	}
-	return false
-}
-
-func (c *Module) GetStaticVariant() LinkableInterface {
-	return c.staticVariant
-}
-
-func (c *Module) SetDepsInLinkOrder(depsInLinkOrder []android.Path) {
-	c.depsInLinkOrder = depsInLinkOrder
-}
-
-func (c *Module) GetDepsInLinkOrder() []android.Path {
-	return c.depsInLinkOrder
-}
-
-func (c *Module) StubsVersions() []string {
-	if c.linker != nil {
-		if library, ok := c.linker.(*libraryDecorator); ok {
-			return library.Properties.Stubs.Versions
-		}
-		if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-			return library.Properties.Stubs.Versions
-		}
+func (c *Module) StubsVersions(ctx android.BaseMutatorContext) []string {
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		return versioned.stubsVersions(ctx)
 	}
 	panic(fmt.Errorf("StubsVersions called on non-library module: %q", c.BaseModuleName()))
 }
@@ -771,100 +748,48 @@
 }
 
 func (c *Module) SetBuildStubs() {
-	if c.linker != nil {
-		if library, ok := c.linker.(*libraryDecorator); ok {
-			library.MutatedProperties.BuildStubs = true
-			c.Properties.HideFromMake = true
-			c.sanitize = nil
-			c.stl = nil
-			c.Properties.PreventInstall = true
-			return
-		}
-		if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-			library.MutatedProperties.BuildStubs = true
-			c.Properties.HideFromMake = true
-			c.sanitize = nil
-			c.stl = nil
-			c.Properties.PreventInstall = true
-			return
-		}
-		if _, ok := c.linker.(*llndkStubDecorator); ok {
-			c.Properties.HideFromMake = true
-			return
-		}
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		versioned.setBuildStubs()
+		c.Properties.HideFromMake = true
+		c.sanitize = nil
+		c.stl = nil
+		c.Properties.PreventInstall = true
+		return
 	}
 	panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName()))
 }
 
 func (c *Module) BuildStubs() bool {
-	if c.linker != nil {
-		if library, ok := c.linker.(*libraryDecorator); ok {
-			return library.buildStubs()
-		}
-		if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-			return library.buildStubs()
-		}
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		return versioned.buildStubs()
 	}
 	panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName()))
 }
 
 func (c *Module) SetAllStubsVersions(versions []string) {
-	if library, ok := c.linker.(*libraryDecorator); ok {
-		library.MutatedProperties.AllStubsVersions = versions
-		return
-	}
-	if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-		library.MutatedProperties.AllStubsVersions = versions
-		return
-	}
-	if llndk, ok := c.linker.(*llndkStubDecorator); ok {
-		llndk.libraryDecorator.MutatedProperties.AllStubsVersions = versions
-		return
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		versioned.setAllStubsVersions(versions)
 	}
 }
 
 func (c *Module) AllStubsVersions() []string {
-	if library, ok := c.linker.(*libraryDecorator); ok {
-		return library.MutatedProperties.AllStubsVersions
-	}
-	if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-		return library.MutatedProperties.AllStubsVersions
-	}
-	if llndk, ok := c.linker.(*llndkStubDecorator); ok {
-		return llndk.libraryDecorator.MutatedProperties.AllStubsVersions
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		return versioned.allStubsVersions()
 	}
 	return nil
 }
 
 func (c *Module) SetStubsVersion(version string) {
-	if c.linker != nil {
-		if library, ok := c.linker.(*libraryDecorator); ok {
-			library.MutatedProperties.StubsVersion = version
-			return
-		}
-		if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-			library.MutatedProperties.StubsVersion = version
-			return
-		}
-		if llndk, ok := c.linker.(*llndkStubDecorator); ok {
-			llndk.libraryDecorator.MutatedProperties.StubsVersion = version
-			return
-		}
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		versioned.setStubsVersion(version)
+		return
 	}
 	panic(fmt.Errorf("SetStubsVersion called on non-library module: %q", c.BaseModuleName()))
 }
 
 func (c *Module) StubsVersion() string {
-	if c.linker != nil {
-		if library, ok := c.linker.(*libraryDecorator); ok {
-			return library.MutatedProperties.StubsVersion
-		}
-		if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-			return library.MutatedProperties.StubsVersion
-		}
-		if llndk, ok := c.linker.(*llndkStubDecorator); ok {
-			return llndk.libraryDecorator.MutatedProperties.StubsVersion
-		}
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		return versioned.stubsVersion()
 	}
 	panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName()))
 }
@@ -1026,7 +951,7 @@
 
 func (c *Module) UseSdk() bool {
 	if c.canUseSdk() {
-		return String(c.Properties.Sdk_version) != "" || c.SplitPerApiLevel()
+		return String(c.Properties.Sdk_version) != ""
 	}
 	return false
 }
@@ -1102,22 +1027,15 @@
 }
 
 func (c *Module) IsStubs() bool {
-	if library, ok := c.linker.(*libraryDecorator); ok {
-		return library.buildStubs()
-	} else if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-		return library.buildStubs()
-	} else if _, ok := c.linker.(*llndkStubDecorator); ok {
-		return true
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		return versioned.buildStubs()
 	}
 	return false
 }
 
 func (c *Module) HasStubsVariants() bool {
-	if library, ok := c.linker.(*libraryDecorator); ok {
-		return len(library.Properties.Stubs.Versions) > 0
-	}
-	if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-		return len(library.Properties.Stubs.Versions) > 0
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		return versioned.hasStubsVariants()
 	}
 	return false
 }
@@ -1141,41 +1059,6 @@
 	return false
 }
 
-func (c *Module) ExportedIncludeDirs() android.Paths {
-	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
-		return flagsProducer.exportedDirs()
-	}
-	return nil
-}
-
-func (c *Module) ExportedSystemIncludeDirs() android.Paths {
-	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
-		return flagsProducer.exportedSystemDirs()
-	}
-	return nil
-}
-
-func (c *Module) ExportedFlags() []string {
-	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
-		return flagsProducer.exportedFlags()
-	}
-	return nil
-}
-
-func (c *Module) ExportedDeps() android.Paths {
-	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
-		return flagsProducer.exportedDeps()
-	}
-	return nil
-}
-
-func (c *Module) ExportedGeneratedHeaders() android.Paths {
-	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
-		return flagsProducer.exportedGeneratedHeaders()
-	}
-	return nil
-}
-
 func (c *Module) ExcludeFromVendorSnapshot() bool {
 	return Bool(c.Properties.Exclude_from_vendor_snapshot)
 }
@@ -1360,11 +1243,11 @@
 }
 
 func (ctx *moduleContextImpl) isForPlatform() bool {
-	return ctx.mod.IsForPlatform()
+	return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
 }
 
 func (ctx *moduleContextImpl) apexVariationName() string {
-	return ctx.mod.ApexVariationName()
+	return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
 }
 
 func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel {
@@ -1387,6 +1270,10 @@
 	return ctx.mod.nativeCoverage()
 }
 
+func (ctx *moduleContextImpl) directlyInAnyApex() bool {
+	return ctx.mod.DirectlyInAnyApex()
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -1435,65 +1322,6 @@
 	return nil
 }
 
-// orderDeps reorders dependencies into a list such that if module A depends on B, then
-// A will precede B in the resultant list.
-// This is convenient for passing into a linker.
-// Note that directSharedDeps should be the analogous static library for each shared lib dep
-func orderDeps(directStaticDeps []android.Path, directSharedDeps []android.Path, allTransitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
-	// If A depends on B, then
-	//   Every list containing A will also contain B later in the list
-	//   So, after concatenating all lists, the final instance of B will have come from the same
-	//     original list as the final instance of A
-	//   So, the final instance of B will be later in the concatenation than the final A
-	//   So, keeping only the final instance of A and of B ensures that A is earlier in the output
-	//     list than B
-	for _, dep := range directStaticDeps {
-		orderedAllDeps = append(orderedAllDeps, dep)
-		orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
-	}
-	for _, dep := range directSharedDeps {
-		orderedAllDeps = append(orderedAllDeps, dep)
-		orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
-	}
-
-	orderedAllDeps = android.LastUniquePaths(orderedAllDeps)
-
-	// We don't want to add any new dependencies into directStaticDeps (to allow the caller to
-	// intentionally exclude or replace any unwanted transitive dependencies), so we limit the
-	// resultant list to only what the caller has chosen to include in directStaticDeps
-	_, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directStaticDeps)
-
-	return orderedAllDeps, orderedDeclaredDeps
-}
-
-func orderStaticModuleDeps(module LinkableInterface, staticDeps []LinkableInterface, sharedDeps []LinkableInterface) (results []android.Path) {
-	// convert Module to Path
-	var depsInLinkOrder []android.Path
-	allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
-	staticDepFiles := []android.Path{}
-	for _, dep := range staticDeps {
-		// The OutputFile may not be valid for a variant not present, and the AllowMissingDependencies flag is set.
-		if dep.OutputFile().Valid() {
-			allTransitiveDeps[dep.OutputFile().Path()] = dep.GetDepsInLinkOrder()
-			staticDepFiles = append(staticDepFiles, dep.OutputFile().Path())
-		}
-	}
-	sharedDepFiles := []android.Path{}
-	for _, sharedDep := range sharedDeps {
-		if sharedDep.HasStaticVariant() {
-			staticAnalogue := sharedDep.GetStaticVariant()
-			allTransitiveDeps[staticAnalogue.OutputFile().Path()] = staticAnalogue.GetDepsInLinkOrder()
-			sharedDepFiles = append(sharedDepFiles, staticAnalogue.OutputFile().Path())
-		}
-	}
-
-	// reorder the dependencies based on transitive dependencies
-	depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
-	module.SetDepsInLinkOrder(depsInLinkOrder)
-
-	return results
-}
-
 func (c *Module) IsTestPerSrcAllTestsVariation() bool {
 	test, ok := c.linker.(testPerSrc)
 	return ok && test.isAllTestsVariation()
@@ -1542,6 +1370,11 @@
 		return
 	}
 
+	apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if !apexInfo.IsForPlatform() {
+		c.hideApexVariantFromMake = true
+	}
+
 	c.makeLinkType = c.getMakeLinkType(actx)
 
 	c.Properties.SubName = ""
@@ -1673,8 +1506,7 @@
 		// force anything in the make world to link against the stubs library.
 		// (unless it is explicitly referenced via .bootstrap suffix or the
 		// module is marked with 'bootstrap: true').
-		if c.HasStubsVariants() &&
-			android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) && !c.InRamdisk() &&
+		if c.HasStubsVariants() && c.AnyVariantDirectlyInAnyApex() && !c.InRamdisk() &&
 			!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
 			c.IsStubs() {
 			c.Properties.HideFromMake = false // unhide
@@ -1683,13 +1515,13 @@
 
 		// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current.
 		if i, ok := c.linker.(snapshotLibraryInterface); ok && ctx.DeviceConfig().VndkVersion() == "current" {
-			if isSnapshotAware(ctx, c) {
+			if isSnapshotAware(ctx, c, apexInfo) {
 				i.collectHeadersForSnapshot(ctx)
 			}
 		}
 	}
 
-	if c.installable() {
+	if c.installable(apexInfo) {
 		c.installer.install(ctx, c.outputFile.Path())
 		if ctx.Failed() {
 			return
@@ -1855,7 +1687,7 @@
 	if m.UseSdk() {
 		return []blueprint.Variation{
 			{Mutator: "sdk", Variation: "sdk"},
-			{Mutator: "ndk_api", Variation: m.SdkVersion()},
+			{Mutator: "version", Variation: m.SdkVersion()},
 		}
 	}
 	return []blueprint.Variation{
@@ -1868,34 +1700,16 @@
 
 	variations = append([]blueprint.Variation(nil), variations...)
 
-	if version != "" && VersionVariantAvailable(c) {
+	if version != "" && CanBeOrLinkAgainstVersionVariants(c) {
 		// Version is explicitly specified. i.e. libFoo#30
 		variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
 		depTag.explicitlyVersioned = true
 	}
-	var deps []blueprint.Module
-	if far {
-		deps = ctx.AddFarVariationDependencies(variations, depTag, name)
-	} else {
-		deps = ctx.AddVariationDependencies(variations, depTag, name)
-	}
 
-	// If the version is not specified, add dependency to all stubs libraries.
-	// The stubs library will be used when the depending module is built for APEX and
-	// the dependent module is not in the same APEX.
-	if version == "" && VersionVariantAvailable(c) {
-		if dep, ok := deps[0].(*Module); ok {
-			for _, ver := range dep.AllStubsVersions() {
-				// Note that depTag.ExplicitlyVersioned is false in this case.
-				versionVariations := append(variations,
-					blueprint.Variation{Mutator: "version", Variation: ver})
-				if far {
-					ctx.AddFarVariationDependencies(versionVariations, depTag, name)
-				} else {
-					ctx.AddVariationDependencies(versionVariations, depTag, name)
-				}
-			}
-		}
+	if far {
+		ctx.AddFarVariationDependencies(variations, depTag, name)
+	} else {
+		ctx.AddVariationDependencies(variations, depTag, name)
 	}
 }
 
@@ -1993,16 +1807,9 @@
 	}
 
 	buildStubs := false
-	if c.linker != nil {
-		if library, ok := c.linker.(*libraryDecorator); ok {
-			if library.buildStubs() {
-				buildStubs = true
-			}
-		}
-		if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
-			if library.buildStubs() {
-				buildStubs = true
-			}
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		if versioned.buildStubs() {
+			buildStubs = true
 		}
 	}
 
@@ -2146,11 +1953,10 @@
 		actx.AddDependency(c, depTag, gen)
 	}
 
-	actx.AddVariationDependencies(nil, objDepTag, deps.ObjFiles...)
-
 	vendorSnapshotObjects := vendorSnapshotObjects(actx.Config())
 
 	crtVariations := GetCrtVariations(ctx, c)
+	actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
 	if deps.CrtBegin != "" {
 		actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
 			rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects))
@@ -2170,13 +1976,13 @@
 
 	ndkStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, ndk: true, makeSuffix: "." + version}
 	actx.AddVariationDependencies([]blueprint.Variation{
-		{Mutator: "ndk_api", Variation: version},
+		{Mutator: "version", Variation: version},
 		{Mutator: "link", Variation: "shared"},
 	}, ndkStubDepTag, variantNdkLibs...)
 
 	ndkLateStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency, ndk: true, makeSuffix: "." + version}
 	actx.AddVariationDependencies([]blueprint.Variation{
-		{Mutator: "ndk_api", Variation: version},
+		{Mutator: "version", Variation: version},
 		{Mutator: "link", Variation: "shared"},
 	}, ndkLateStubDepTag, variantLateNdkLibs...)
 
@@ -2361,25 +2167,56 @@
 	}
 }
 
+// Returns the highest version which is <= maxSdkVersion.
+// For example, with maxSdkVersion is 10 and versionList is [9,11]
+// it returns 9 as string.  The list of stubs must be in order from
+// oldest to newest.
+func (c *Module) chooseSdkVersion(ctx android.PathContext, stubsInfo []SharedLibraryStubsInfo,
+	maxSdkVersion android.ApiLevel) (SharedLibraryStubsInfo, error) {
+
+	for i := range stubsInfo {
+		stubInfo := stubsInfo[len(stubsInfo)-i-1]
+		var ver android.ApiLevel
+		if stubInfo.Version == "" {
+			ver = android.FutureApiLevel
+		} else {
+			var err error
+			ver, err = android.ApiLevelFromUser(ctx, stubInfo.Version)
+			if err != nil {
+				return SharedLibraryStubsInfo{}, err
+			}
+		}
+		if ver.LessThanOrEqualTo(maxSdkVersion) {
+			return stubInfo, nil
+		}
+	}
+	var versionList []string
+	for _, stubInfo := range stubsInfo {
+		versionList = append(versionList, stubInfo.Version)
+	}
+	return SharedLibraryStubsInfo{}, fmt.Errorf("not found a version(<=%s) in versionList: %v", maxSdkVersion.String(), versionList)
+}
+
 // Convert dependencies to paths.  Returns a PathDeps containing paths
 func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
-	directStaticDeps := []LinkableInterface{}
-	directSharedDeps := []LinkableInterface{}
+	var directStaticDeps []StaticLibraryInfo
+	var directSharedDeps []SharedLibraryInfo
 
-	reexportExporter := func(exporter exportedFlagsProducer) {
-		depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, exporter.exportedDirs()...)
-		depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.exportedSystemDirs()...)
-		depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, exporter.exportedFlags()...)
-		depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, exporter.exportedDeps()...)
-		depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.exportedGeneratedHeaders()...)
+	reexportExporter := func(exporter FlagExporterInfo) {
+		depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, exporter.IncludeDirs...)
+		depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.SystemIncludeDirs...)
+		depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, exporter.Flags...)
+		depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, exporter.Deps...)
+		depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.GeneratedHeaders...)
 	}
 
 	// For the dependency from platform to apex, use the latest stubs
 	c.apexSdkVersion = android.FutureApiLevel
-	if !c.IsForPlatform() {
-		c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion(ctx)
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if !apexInfo.IsForPlatform() {
+		c.apexSdkVersion = apexInfo.MinSdkVersion(ctx)
 	}
 
 	if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
@@ -2457,24 +2294,14 @@
 			return
 		}
 
-		// re-exporting flags
 		if depTag == reuseObjTag {
 			// reusing objects only make sense for cc.Modules.
-			if ccReuseDep, ok := ccDep.(*Module); ok && ccDep.CcLibraryInterface() {
-				c.staticVariant = ccDep
-				objs, exporter := ccReuseDep.compiler.(libraryInterface).reuseObjs()
-				depPaths.Objs = depPaths.Objs.Append(objs)
-				reexportExporter(exporter)
-				return
-			}
-		}
-
-		if depTag == staticVariantTag {
-			// staticVariants are a cc.Module specific concept.
-			if _, ok := ccDep.(*Module); ok && ccDep.CcLibraryInterface() {
-				c.staticVariant = ccDep
-				return
-			}
+			staticAnalogue := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
+			objs := staticAnalogue.ReuseObjects
+			depPaths.Objs = depPaths.Objs.Append(objs)
+			depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+			reexportExporter(depExporterInfo)
+			return
 		}
 
 		checkLinkType(ctx, c, ccDep, depTag)
@@ -2487,102 +2314,7 @@
 				return
 			}
 
-			if ccDep.CcLibrary() && !libDepTag.static() {
-				depIsStubs := ccDep.BuildStubs()
-				depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants()
-				depInSameApexes := android.DirectlyInAllApexes(c.InApexes(), depName)
-				depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
-
-				var useThisDep bool
-				if depIsStubs && libDepTag.explicitlyVersioned {
-					// Always respect dependency to the versioned stubs (i.e. libX#10)
-					useThisDep = true
-				} else if !depHasStubs {
-					// Use non-stub variant if that is the only choice
-					// (i.e. depending on a lib without stubs.version property)
-					useThisDep = true
-				} else if c.IsForPlatform() {
-					// If not building for APEX, use stubs only when it is from
-					// an APEX (and not from platform)
-					useThisDep = (depInPlatform != depIsStubs)
-					if c.bootstrap() {
-						// However, for host, ramdisk, recovery or bootstrap modules,
-						// always link to non-stub variant
-						useThisDep = !depIsStubs
-					}
-					for _, testFor := range c.TestFor() {
-						// Another exception: if this module is bundled with an APEX, then
-						// it is linked with the non-stub variant of a module in the APEX
-						// as if this is part of the APEX.
-						if android.DirectlyInApex(testFor, depName) {
-							useThisDep = !depIsStubs
-							break
-						}
-					}
-				} else {
-					// If building for APEX, use stubs when the parent is in any APEX that
-					// the child is not in.
-					useThisDep = (depInSameApexes != depIsStubs)
-				}
-
-				// when to use (unspecified) stubs, check min_sdk_version and choose the right one
-				if useThisDep && depIsStubs && !libDepTag.explicitlyVersioned {
-					versionToUse, err := c.ChooseSdkVersion(ctx, ccDep.StubsVersions(), c.apexSdkVersion)
-					if err != nil {
-						ctx.OtherModuleErrorf(dep, err.Error())
-						return
-					}
-					if versionToUse != ccDep.StubsVersion() {
-						useThisDep = false
-					}
-				}
-
-				if !useThisDep {
-					return // stop processing this dep
-				}
-			}
-			if c.UseVndk() {
-				if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK
-					// by default, use current version of LLNDK
-					versionToUse := ""
-					versions := m.AllStubsVersions()
-					if c.ApexVariationName() != "" && len(versions) > 0 {
-						// 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
-						versionToUse, err = c.ChooseSdkVersion(ctx, versions, c.apexSdkVersion)
-						if err != nil {
-							ctx.OtherModuleErrorf(dep, err.Error())
-							return
-						}
-					}
-					if versionToUse != ccDep.StubsVersion() {
-						return
-					}
-				}
-			}
-
-			depPaths.IncludeDirs = append(depPaths.IncludeDirs, ccDep.IncludeDirs()...)
-
-			// Exporting flags only makes sense for cc.Modules
-			if _, ok := ccDep.(*Module); ok {
-				if i, ok := ccDep.(*Module).linker.(exportedFlagsProducer); ok {
-					depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
-					depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, i.exportedDeps()...)
-					depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
-
-					if libDepTag.reexportFlags {
-						reexportExporter(i)
-						// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
-						// Re-exported shared library headers must be included as well since they can help us with type information
-						// about template instantiations (instantiated from their headers).
-						// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
-						// scripts.
-						c.sabi.Properties.ReexportedIncludes = append(
-							c.sabi.Properties.ReexportedIncludes, i.exportedDirs().Strings()...)
-					}
-				}
-			}
+			depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
 
 			var ptr *android.Paths
 			var depPtr *android.Paths
@@ -2593,6 +2325,64 @@
 			case libDepTag.header():
 				// nothing
 			case libDepTag.shared():
+				if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
+					if !ctx.Config().AllowMissingDependencies() {
+						ctx.ModuleErrorf("module %q is not a shared library", depName)
+					} else {
+						ctx.AddMissingDependencies([]string{depName})
+					}
+					return
+				}
+				sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
+				sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryImplementationStubsInfoProvider).(SharedLibraryImplementationStubsInfo)
+
+				if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedLibraryStubsInfos) > 0 {
+					useStubs := false
+					if m, ok := ccDep.(*Module); ok && m.IsStubs() && c.UseVndk() { // LLNDK
+						if !apexInfo.IsForPlatform() {
+							// For platform libraries, use current version of LLNDK
+							// If this is for use_vendor apex we will apply the same rules
+							// of apex sdk enforcement below to choose right version.
+							useStubs = true
+						}
+					} else if apexInfo.IsForPlatform() {
+						// If not building for APEX, use stubs only when it is from
+						// an APEX (and not from platform)
+						// However, for host, ramdisk, recovery or bootstrap modules,
+						// always link to non-stub variant
+						useStubs = dep.(android.ApexModule).AnyVariantDirectlyInAnyApex() && !c.bootstrap()
+						// Another exception: if this module is bundled with an APEX, then
+						// it is linked with the non-stub variant of a module in the APEX
+						// as if this is part of the APEX.
+						testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+						for _, apexContents := range testFor.ApexContents {
+							if apexContents.DirectlyInApex(depName) {
+								useStubs = false
+								break
+							}
+						}
+					} else {
+						// If building for APEX, use stubs when the parent is in any APEX that
+						// the child is not in.
+						useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
+					}
+
+					// when to use (unspecified) stubs, check min_sdk_version and choose the right one
+					if useStubs {
+						sharedLibraryStubsInfo, err :=
+							c.chooseSdkVersion(ctx, sharedLibraryStubsInfo.SharedLibraryStubsInfos, c.apexSdkVersion)
+						if err != nil {
+							ctx.OtherModuleErrorf(dep, err.Error())
+							return
+						}
+						sharedLibraryInfo = sharedLibraryStubsInfo.SharedLibraryInfo
+						depExporterInfo = sharedLibraryStubsInfo.FlagExporterInfo
+					}
+				}
+
+				linkFile = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
+				depFile = sharedLibraryInfo.TableOfContents
+
 				ptr = &depPaths.SharedLibs
 				switch libDepTag.Order {
 				case earlyLibraryDependency:
@@ -2601,47 +2391,41 @@
 				case normalLibraryDependency:
 					ptr = &depPaths.SharedLibs
 					depPtr = &depPaths.SharedLibsDeps
-					directSharedDeps = append(directSharedDeps, ccDep)
+					directSharedDeps = append(directSharedDeps, sharedLibraryInfo)
 				case lateLibraryDependency:
 					ptr = &depPaths.LateSharedLibs
 					depPtr = &depPaths.LateSharedLibsDeps
 				default:
 					panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
 				}
-				depFile = ccDep.Toc()
 			case libDepTag.static():
+				if !ctx.OtherModuleHasProvider(dep, StaticLibraryInfoProvider) {
+					if !ctx.Config().AllowMissingDependencies() {
+						ctx.ModuleErrorf("module %q is not a static library", depName)
+					} else {
+						ctx.AddMissingDependencies([]string{depName})
+					}
+					return
+				}
+				staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
+				linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
 				if libDepTag.wholeStatic {
 					ptr = &depPaths.WholeStaticLibs
-					if !ccDep.CcLibraryInterface() || !ccDep.Static() {
-						ctx.ModuleErrorf("module %q not a static library", depName)
-						return
-					}
-
-					// Because the static library objects are included, this only makes sense
-					// in the context of proper cc.Modules.
-					if ccWholeStaticLib, ok := ccDep.(*Module); ok {
-						staticLib := ccWholeStaticLib.linker.(libraryInterface)
-						if objs := staticLib.objs(); len(objs.objFiles) > 0 {
-							depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(objs)
-						} else {
-							// This case normally catches prebuilt static
-							// libraries, but it can also occur when
-							// AllowMissingDependencies is on and the
-							// dependencies has no sources of its own
-							// but has a whole_static_libs dependency
-							// on a missing library.  We want to depend
-							// on the .a file so that there is something
-							// in the dependency tree that contains the
-							// error rule for the missing transitive
-							// dependency.
-							depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path())
-						}
+					if len(staticLibraryInfo.Objects.objFiles) > 0 {
+						depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLibraryInfo.Objects)
 					} else {
-						ctx.ModuleErrorf(
-							"non-cc.Modules cannot be included as whole static libraries.", depName)
-						return
+						// This case normally catches prebuilt static
+						// libraries, but it can also occur when
+						// AllowMissingDependencies is on and the
+						// dependencies has no sources of its own
+						// but has a whole_static_libs dependency
+						// on a missing library.  We want to depend
+						// on the .a file so that there is something
+						// in the dependency tree that contains the
+						// error rule for the missing transitive
+						// dependency.
+						depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path())
 					}
-
 				} else {
 					switch libDepTag.Order {
 					case earlyLibraryDependency:
@@ -2650,7 +2434,7 @@
 						// static dependencies will be handled separately so they can be ordered
 						// using transitive dependencies.
 						ptr = nil
-						directStaticDeps = append(directStaticDeps, ccDep)
+						directStaticDeps = append(directStaticDeps, staticLibraryInfo)
 					case lateLibraryDependency:
 						ptr = &depPaths.LateStaticLibs
 					default:
@@ -2674,10 +2458,10 @@
 						staticLib.objs().coverageFiles...)
 					depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
 						staticLib.objs().sAbiDumpFiles...)
-				} else if c, ok := ccDep.(LinkableInterface); ok {
+				} else {
 					// Handle non-CC modules here
 					depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
-						c.CoverageFiles()...)
+						ccDep.CoverageFiles()...)
 				}
 			}
 
@@ -2701,6 +2485,22 @@
 				*depPtr = append(*depPtr, dep.Path())
 			}
 
+			depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
+			depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
+			depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, depExporterInfo.Deps...)
+			depPaths.Flags = append(depPaths.Flags, depExporterInfo.Flags...)
+
+			if libDepTag.reexportFlags {
+				reexportExporter(depExporterInfo)
+				// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
+				// Re-exported shared library headers must be included as well since they can help us with type information
+				// about template instantiations (instantiated from their headers).
+				// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
+				// scripts.
+				c.sabi.Properties.ReexportedIncludes = append(
+					c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...)
+			}
+
 			makeLibName := c.makeLibName(ctx, ccDep, depName) + libDepTag.makeSuffix
 			switch {
 			case libDepTag.header():
@@ -2708,10 +2508,11 @@
 					c.Properties.AndroidMkHeaderLibs, makeLibName)
 			case libDepTag.shared():
 				if ccDep.CcLibrary() {
-					if ccDep.BuildStubs() && android.InAnyApex(depName) {
+					if ccDep.BuildStubs() && dep.(android.ApexModule).InAnyApex() {
 						// Add the dependency to the APEX(es) providing the library so that
 						// m <module> can trigger building the APEXes as well.
-						for _, an := range android.GetApexesForModule(depName) {
+						depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
+						for _, an := range depApexInfo.InApexes {
 							c.Properties.ApexesProvidingSharedLibs = append(
 								c.Properties.ApexesProvidingSharedLibs, an)
 						}
@@ -2753,7 +2554,9 @@
 	})
 
 	// use the ordered dependencies as this module's dependencies
-	depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps, directSharedDeps)...)
+	orderedStaticPaths, transitiveStaticLibs := orderStaticModuleDeps(directStaticDeps, directSharedDeps)
+	depPaths.TranstiveStaticLibrariesForOrdering = transitiveStaticLibs
+	depPaths.StaticLibs = append(depPaths.StaticLibs, orderedStaticPaths...)
 
 	// Dedup exported flags from dependencies
 	depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
@@ -2773,6 +2576,38 @@
 	return depPaths
 }
 
+// orderStaticModuleDeps rearranges the order of the static library dependencies of the module
+// to match the topological order of the dependency tree, including any static analogues of
+// direct shared libraries.  It returns the ordered static dependencies, and an android.DepSet
+// of the transitive dependencies.
+func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive *android.DepSet) {
+	transitiveStaticLibsBuilder := android.NewDepSetBuilder(android.TOPOLOGICAL)
+	var staticPaths android.Paths
+	for _, staticDep := range staticDeps {
+		staticPaths = append(staticPaths, staticDep.StaticLibrary)
+		transitiveStaticLibsBuilder.Transitive(staticDep.TransitiveStaticLibrariesForOrdering)
+	}
+	for _, sharedDep := range sharedDeps {
+		if sharedDep.StaticAnalogue != nil {
+			transitiveStaticLibsBuilder.Transitive(sharedDep.StaticAnalogue.TransitiveStaticLibrariesForOrdering)
+		}
+	}
+	transitiveStaticLibs := transitiveStaticLibsBuilder.Build()
+
+	orderedTransitiveStaticLibs := transitiveStaticLibs.ToList()
+
+	// reorder the dependencies based on transitive dependencies
+	staticPaths = android.FirstUniquePaths(staticPaths)
+	_, orderedStaticPaths := android.FilterPathList(orderedTransitiveStaticLibs, staticPaths)
+
+	if len(orderedStaticPaths) != len(staticPaths) {
+		missing, _ := android.FilterPathList(staticPaths, orderedStaticPaths)
+		panic(fmt.Errorf("expected %d ordered static paths , got %d, missing %q %q %q", len(staticPaths), len(orderedStaticPaths), missing, orderedStaticPaths, staticPaths))
+	}
+
+	return orderedStaticPaths, transitiveStaticLibs
+}
+
 // baseLibName trims known prefixes and suffixes
 func baseLibName(depName string) string {
 	libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
@@ -3015,7 +2850,7 @@
 		c.installer.everInstallable()
 }
 
-func (c *Module) installable() bool {
+func (c *Module) installable(apexInfo android.ApexInfo) bool {
 	ret := c.EverInstallable() &&
 		// Check to see whether the module has been configured to not be installed.
 		proptools.BoolDefault(c.Properties.Installable, true) &&
@@ -3024,7 +2859,7 @@
 	// The platform variant doesn't need further condition. Apex variants however might not
 	// be installable because it will likely to be included in the APEX and won't appear
 	// in the system partition.
-	if c.IsForPlatform() {
+	if apexInfo.IsForPlatform() {
 		return ret
 	}
 
@@ -3070,8 +2905,8 @@
 			return false
 		}
 	}
-	if depTag == llndkImplDep {
-		// We don't track beyond LLNDK
+	if depTag == stubImplDepTag || depTag == llndkImplDep {
+		// We don't track beyond LLNDK or from an implementation library to its stubs.
 		return false
 	}
 	return true
diff --git a/cc/cc_test.go b/cc/cc_test.go
index e0d4640..d1780cd 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,7 +20,6 @@
 	"os"
 	"path/filepath"
 	"reflect"
-	"sort"
 	"strings"
 	"testing"
 
@@ -2890,59 +2889,6 @@
 	return modulesInOrder, allDeps
 }
 
-func TestLinkReordering(t *testing.T) {
-	for _, testCase := range staticLinkDepOrderTestCases {
-		errs := []string{}
-
-		// parse testcase
-		_, givenTransitiveDeps := parseModuleDeps(testCase.inStatic)
-		expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
-		if testCase.allOrdered == "" {
-			// allow the test case to skip specifying allOrdered
-			testCase.allOrdered = testCase.outOrdered
-		}
-		_, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
-		_, givenAllSharedDeps := parseModuleDeps(testCase.inShared)
-
-		// For each module whose post-reordered dependencies were specified, validate that
-		// reordering the inputs produces the expected outputs.
-		for _, moduleName := range expectedModuleNames {
-			moduleDeps := givenTransitiveDeps[moduleName]
-			givenSharedDeps := givenAllSharedDeps[moduleName]
-			orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenSharedDeps, givenTransitiveDeps)
-
-			correctAllOrdered := expectedAllDeps[moduleName]
-			if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
-				errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
-					"\nin static:%q"+
-					"\nin shared:%q"+
-					"\nmodule:   %v"+
-					"\nexpected: %s"+
-					"\nactual:   %s",
-					testCase.inStatic, testCase.inShared, moduleName, correctAllOrdered, orderedAllDeps))
-			}
-
-			correctOutputDeps := expectedTransitiveDeps[moduleName]
-			if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
-				errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
-					"\nin static:%q"+
-					"\nin shared:%q"+
-					"\nmodule:   %v"+
-					"\nexpected: %s"+
-					"\nactual:   %s",
-					testCase.inStatic, testCase.inShared, moduleName, correctOutputDeps, orderedDeclaredDeps))
-			}
-		}
-
-		if len(errs) > 0 {
-			sort.Strings(errs)
-			for _, err := range errs {
-				t.Error(err)
-			}
-		}
-	}
-}
-
 func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
 	for _, moduleName := range moduleNames {
 		module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
@@ -2977,8 +2923,8 @@
 
 	variant := "android_arm64_armv8-a_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := moduleA.depsInLinkOrder
-	expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
+	actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).TransitiveStaticLibrariesForOrdering.ToList()
+	expected := getOutputPaths(ctx, variant, []string{"a", "c", "b", "d"})
 
 	if !reflect.DeepEqual(actual, expected) {
 		t.Errorf("staticDeps orderings were not propagated correctly"+
@@ -3011,8 +2957,8 @@
 
 	variant := "android_arm64_armv8-a_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := moduleA.depsInLinkOrder
-	expected := getOutputPaths(ctx, variant, []string{"c", "b"})
+	actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).TransitiveStaticLibrariesForOrdering.ToList()
+	expected := getOutputPaths(ctx, variant, []string{"a", "c", "b"})
 
 	if !reflect.DeepEqual(actual, expected) {
 		t.Errorf("staticDeps orderings did not account for shared libs"+
@@ -3048,12 +2994,12 @@
 	`)
 	actual := ctx.ModuleVariantsForTests("libllndk.llndk")
 	expected := []string{
-		"android_vendor.VER_arm64_armv8-a_shared",
 		"android_vendor.VER_arm64_armv8-a_shared_1",
 		"android_vendor.VER_arm64_armv8-a_shared_2",
-		"android_vendor.VER_arm_armv7-a-neon_shared",
+		"android_vendor.VER_arm64_armv8-a_shared",
 		"android_vendor.VER_arm_armv7-a-neon_shared_1",
 		"android_vendor.VER_arm_armv7-a-neon_shared_2",
+		"android_vendor.VER_arm_armv7-a-neon_shared",
 	}
 	checkEquals(t, "variants for llndk stubs", expected, actual)
 
@@ -3582,7 +3528,7 @@
 		cc_binary {
 			name: "mybin",
 			srcs: ["foo.c"],
-			static_libs: ["libfooB"],
+			static_libs: ["libfooC", "libfooB"],
 			static_executable: true,
 			stl: "none",
 		}
@@ -3603,8 +3549,8 @@
 			},
 		}`)
 
-	mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a").Module().(*Module)
-	actual := mybin.depsInLinkOrder
+	mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a").Rule("ld")
+	actual := mybin.Implicits[:2]
 	expected := getOutputPaths(ctx, "android_arm64_armv8-a_static", []string{"libfooB", "libfooC"})
 
 	if !reflect.DeepEqual(actual, expected) {
diff --git a/cc/config/OWNERS b/cc/config/OWNERS
index b2f54e5..701db92 100644
--- a/cc/config/OWNERS
+++ b/cc/config/OWNERS
@@ -1 +1,3 @@
 per-file vndk.go = smoreland@google.com, victoryang@google.com
+per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
+
diff --git a/cc/config/global.go b/cc/config/global.go
index d4c6266..1aa2621 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -53,6 +53,13 @@
 		"-Werror=pragma-pack",
 		"-Werror=pragma-pack-suspicious-include",
 		"-Werror=unreachable-code-loop-increment",
+
+		// -fdebug-compilation-dir=. is used to make both the action command line and the output
+		// independent of the working directory of the action.
+		// Using cc1 flags since RBE's input processor does not yet have the updated version
+		// of LLVM that promotes the cc1 flag to driver level flag.
+		// See: https://reviews.llvm.org/D63387
+		"-Xclang,-fdebug-compilation-dir,.",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -150,10 +157,6 @@
 var pctx = android.NewPackageContext("android/soong/cc/config")
 
 func init() {
-	if android.BuildOs == android.Linux {
-		commonGlobalCflags = append(commonGlobalCflags, "-fdebug-prefix-map=/proc/self/cwd=")
-	}
-
 	pctx.StaticVariable("CommonGlobalConlyflags", strings.Join(commonGlobalConlyflags, " "))
 	pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " "))
 	pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " "))
@@ -205,6 +208,7 @@
 	pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I",
 		[]string{
 			"system/core/include",
+			"system/logging/liblog/include",
 			"system/media/audio/include",
 			"hardware/libhardware/include",
 			"hardware/libhardware_legacy/include",
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 6f2e807..d18ae25 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -25,6 +25,7 @@
 	"android.hardware.power-ndk_platform",
 	"android.hardware.rebootescrow-ndk_platform",
 	"android.hardware.vibrator-ndk_platform",
+	"android.system.keystore2-unstable-ndk_platform",
 	"libbinder",
 	"libcrypto",
 	"libexpat",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 0453847..e81b40f 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -167,7 +167,9 @@
 // that should be installed in the fuzz target output directories. This function
 // returns true, unless:
 //  - The module is not a shared library, or
-//  - The module is a header, stub, or vendor-linked library.
+//  - The module is a header, stub, or vendor-linked library, or
+//  - The module is a prebuilt and its source is available, or
+//  - The module is a versioned member of an SDK snapshot.
 func isValidSharedDependency(dependency android.Module) bool {
 	// TODO(b/144090547): We should be parsing these modules using
 	// ModuleDependencyTag instead of the current brute-force checking.
@@ -190,6 +192,20 @@
 		}
 	}
 
+	// If the same library is present both as source and a prebuilt we must pick
+	// only one to avoid a conflict. Always prefer the source since the prebuilt
+	// probably won't be built with sanitizers enabled.
+	if prebuilt, ok := dependency.(android.PrebuiltInterface); ok &&
+		prebuilt.Prebuilt() != nil && prebuilt.Prebuilt().SourceExists() {
+		return false
+	}
+
+	// Discard versioned members of SDK snapshots, because they will conflict with
+	// unversioned ones.
+	if sdkMember, ok := dependency.(android.SdkAware); ok && !sdkMember.ContainingSdk().Unversioned() {
+		return false
+	}
+
 	return true
 }
 
diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go
index 796de62..9ea988a 100644
--- a/cc/kernel_headers.go
+++ b/cc/kernel_headers.go
@@ -26,6 +26,7 @@
 	if ctx.Device() {
 		f := &stub.libraryDecorator.flagExporter
 		f.reexportSystemDirs(android.PathsForSource(ctx, ctx.DeviceConfig().DeviceKernelHeaderDirs())...)
+		f.setProvider(ctx)
 	}
 	return stub.libraryDecorator.linkStatic(ctx, flags, deps, objs)
 }
diff --git a/cc/library.go b/cc/library.go
index bf7868f..090abf9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -121,7 +121,10 @@
 }
 
 type StaticOrSharedProperties struct {
-	Srcs   []string `android:"path,arch_variant"`
+	Srcs []string `android:"path,arch_variant"`
+
+	Sanitized Sanitized `android:"arch_variant"`
+
 	Cflags []string `android:"arch_variant"`
 
 	Enabled            *bool    `android:"arch_variant"`
@@ -291,36 +294,16 @@
 	f.headers = append(f.headers, headers...)
 }
 
-func (f *flagExporter) exportedDirs() android.Paths {
-	return f.dirs
+func (f *flagExporter) setProvider(ctx android.ModuleContext) {
+	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
+		IncludeDirs:       f.dirs,
+		SystemIncludeDirs: f.systemDirs,
+		Flags:             f.flags,
+		Deps:              f.deps,
+		GeneratedHeaders:  f.headers,
+	})
 }
 
-func (f *flagExporter) exportedSystemDirs() android.Paths {
-	return f.systemDirs
-}
-
-func (f *flagExporter) exportedFlags() []string {
-	return f.flags
-}
-
-func (f *flagExporter) exportedDeps() android.Paths {
-	return f.deps
-}
-
-func (f *flagExporter) exportedGeneratedHeaders() android.Paths {
-	return f.headers
-}
-
-type exportedFlagsProducer interface {
-	exportedDirs() android.Paths
-	exportedSystemDirs() android.Paths
-	exportedFlags() []string
-	exportedDeps() android.Paths
-	exportedGeneratedHeaders() android.Paths
-}
-
-var _ exportedFlagsProducer = (*flagExporter)(nil)
-
 // libraryDecorator wraps baseCompiler, baseLinker and baseInstaller to provide library-specific
 // functionality: static vs. shared linkage, reusing object files for shared libraries
 type libraryDecorator struct {
@@ -366,7 +349,7 @@
 	// Location of the file that should be copied to dist dir when requested
 	distFile android.Path
 
-	versionScriptPath android.ModuleGenPath
+	versionScriptPath android.OptionalPath
 
 	post_install_cmds []string
 
@@ -375,6 +358,8 @@
 	useCoreVariant       bool
 	checkSameCoreVariant bool
 
+	skipAPIDefine bool
+
 	// Decorated interfaces
 	*baseCompiler
 	*baseLinker
@@ -396,7 +381,7 @@
 	// can't be globbed, and they should be manually collected.
 	// So, we first filter out intermediate directories (which contains generated headers)
 	// from exported directories, and then glob headers under remaining directories.
-	for _, path := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
+	for _, path := range append(android.CopyOfPaths(l.flagExporter.dirs), l.flagExporter.systemDirs...) {
 		dir := path.String()
 		// Skip if dir is for generated headers
 		if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
@@ -448,7 +433,7 @@
 	}
 
 	// Collect generated headers
-	for _, header := range append(l.exportedGeneratedHeaders(), l.exportedDeps()...) {
+	for _, header := range append(android.CopyOfPaths(l.flagExporter.headers), l.flagExporter.deps...) {
 		// TODO(b/148123511): remove exportedDeps after cleaning up genrule
 		if strings.HasSuffix(header.Base(), "-phony") {
 			continue
@@ -628,7 +613,7 @@
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if library.buildStubs() {
 		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
-		library.versionScriptPath = versionScript
+		library.versionScriptPath = android.OptionalPathForPath(versionScript)
 		return objs
 	}
 
@@ -678,10 +663,12 @@
 }
 
 type libraryInterface interface {
+	versionedInterface
+
 	static() bool
 	shared() bool
 	objs() Objects
-	reuseObjs() (Objects, exportedFlagsProducer)
+	reuseObjs() Objects
 	toc() android.OptionalPath
 
 	// Returns true if the build options for the module have selected a static or shared build
@@ -698,6 +685,21 @@
 	availableFor(string) bool
 }
 
+type versionedInterface interface {
+	buildStubs() bool
+	setBuildStubs()
+	hasStubsVariants() bool
+	setStubsVersion(string)
+	stubsVersion() string
+
+	stubsVersions(ctx android.BaseMutatorContext) []string
+	setAllStubsVersions([]string)
+	allStubsVersions() []string
+}
+
+var _ libraryInterface = (*libraryDecorator)(nil)
+var _ versionedInterface = (*libraryDecorator)(nil)
+
 func (library *libraryDecorator) getLibNameHelper(baseModuleName string, useVndk bool) string {
 	name := library.libName
 	if name == "" {
@@ -886,6 +888,17 @@
 
 	ctx.CheckbuildFile(outputFile)
 
+	ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		StaticLibrary: outputFile,
+		ReuseObjects:  library.reuseObjects,
+		Objects:       library.objects,
+
+		TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
+			Direct(outputFile).
+			Transitive(deps.TranstiveStaticLibrariesForOrdering).
+			Build(),
+	})
+
 	return outputFile
 }
 
@@ -922,15 +935,15 @@
 			linkerDeps = append(linkerDeps, forceWeakSymbols.Path())
 		}
 	}
-	if library.buildStubs() {
+	if library.versionScriptPath.Valid() {
 		linkerScriptFlags := "-Wl,--version-script," + library.versionScriptPath.String()
 		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlags)
-		linkerDeps = append(linkerDeps, library.versionScriptPath)
+		linkerDeps = append(linkerDeps, library.versionScriptPath.Path())
 	}
 
 	fileName := library.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
 	outputFile := android.PathForModuleOut(ctx, fileName)
-	ret := outputFile
+	unstrippedOutputFile := outputFile
 
 	var implicitOutputs android.WritablePaths
 	if ctx.Windows() {
@@ -1012,9 +1025,42 @@
 	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
 
 	library.coverageOutputFile = TransformCoverageFilesToZip(ctx, objs, library.getLibName(ctx))
-	library.linkSAbiDumpFiles(ctx, objs, fileName, ret)
+	library.linkSAbiDumpFiles(ctx, objs, fileName, unstrippedOutputFile)
 
-	return ret
+	var staticAnalogue *StaticLibraryInfo
+	if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 {
+		s := ctx.OtherModuleProvider(static[0], StaticLibraryInfoProvider).(StaticLibraryInfo)
+		staticAnalogue = &s
+	}
+
+	ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+		TableOfContents:         android.OptionalPathForPath(tocFile),
+		SharedLibrary:           unstrippedOutputFile,
+		UnstrippedSharedLibrary: library.unstrippedOutputFile,
+		CoverageSharedLibrary:   library.coverageOutputFile,
+		StaticAnalogue:          staticAnalogue,
+	})
+
+	stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
+	if len(stubs) > 0 {
+		var stubsInfo []SharedLibraryStubsInfo
+		for _, stub := range stubs {
+			stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
+			flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+			stubsInfo = append(stubsInfo, SharedLibraryStubsInfo{
+				Version:           stub.(*Module).StubsVersion(),
+				SharedLibraryInfo: stubInfo,
+				FlagExporterInfo:  flagInfo,
+			})
+		}
+		ctx.SetProvider(SharedLibraryImplementationStubsInfoProvider, SharedLibraryImplementationStubsInfo{
+			SharedLibraryStubsInfos: stubsInfo,
+
+			IsLLNDK: ctx.isLlndk(ctx.Config()),
+		})
+	}
+
+	return unstrippedOutputFile
 }
 
 func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
@@ -1158,10 +1204,12 @@
 		library.addExportedGeneratedHeaders(library.baseCompiler.pathDeps...)
 	}
 
-	if library.buildStubs() {
-		library.reexportFlags("-D" + versioningMacroName(ctx.ModuleName()) + "=" + library.stubsVersion())
+	if library.buildStubs() && !library.skipAPIDefine {
+		library.reexportFlags("-D" + versioningMacroName(ctx.baseModuleName()) + "=" + library.stubsVersion())
 	}
 
+	library.flagExporter.setProvider(ctx)
+
 	return out
 }
 
@@ -1179,8 +1227,8 @@
 	return library.objects
 }
 
-func (library *libraryDecorator) reuseObjs() (Objects, exportedFlagsProducer) {
-	return library.reuseObjects, &library.flagExporter
+func (library *libraryDecorator) reuseObjs() Objects {
+	return library.reuseObjects
 }
 
 func (library *libraryDecorator) toc() android.OptionalPath {
@@ -1231,18 +1279,19 @@
 					library.baseInstaller.subDir += "-" + vndkVersion
 				}
 			}
-		} else if len(library.Properties.Stubs.Versions) > 0 && android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
+		} else if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.directlyInAnyApex() {
 			// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
 			// 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()) && !library.buildStubs() && !translatedArch && !ctx.inRamdisk() && !ctx.inRecovery() {
+			if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() &&
+				!translatedArch && !ctx.inRamdisk() && !ctx.inRecovery() {
 				if ctx.Device() {
 					library.installSymlinkToRuntimeApex(ctx, file)
 				}
 				library.baseInstaller.subDir = "bootstrap"
 			}
-		} else if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && ctx.isLlndk(ctx.Config()) && !isBionic(ctx.baseModuleName()) {
+		} else if ctx.directlyInAnyApex() && ctx.isLlndk(ctx.Config()) && !isBionic(ctx.baseModuleName()) {
 			// Skip installing LLNDK (non-bionic) libraries moved to APEX.
 			ctx.Module().SkipInstall()
 		}
@@ -1323,10 +1372,34 @@
 	return nil
 }
 
+func (library *libraryDecorator) hasStubsVariants() bool {
+	return len(library.Properties.Stubs.Versions) > 0
+}
+
+func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+	return library.Properties.Stubs.Versions
+}
+
+func (library *libraryDecorator) setStubsVersion(version string) {
+	library.MutatedProperties.StubsVersion = version
+}
+
 func (library *libraryDecorator) stubsVersion() string {
 	return library.MutatedProperties.StubsVersion
 }
 
+func (library *libraryDecorator) setBuildStubs() {
+	library.MutatedProperties.BuildStubs = true
+}
+
+func (library *libraryDecorator) setAllStubsVersions(versions []string) {
+	library.MutatedProperties.AllStubsVersions = versions
+}
+
+func (library *libraryDecorator) allStubsVersions() []string {
+	return library.MutatedProperties.AllStubsVersions
+}
+
 func (library *libraryDecorator) isLatestStubVersion() bool {
 	versions := library.Properties.Stubs.Versions
 	return versions[len(versions)-1] == library.stubsVersion()
@@ -1422,10 +1495,10 @@
 				sharedCompiler.baseCompiler.Properties.Srcs
 			sharedCompiler.baseCompiler.Properties.Srcs = nil
 			sharedCompiler.baseCompiler.Properties.Generated_sources = nil
-		} else {
-			// This dep is just to reference static variant from shared variant
-			mctx.AddInterVariantDependency(staticVariantTag, shared, static)
 		}
+
+		// This dep is just to reference static variant from shared variant
+		mctx.AddInterVariantDependency(staticVariantTag, shared, static)
 	}
 }
 
@@ -1524,13 +1597,15 @@
 
 func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
 	// "" is for the non-stubs (implementation) variant.
-	variants := append([]string{""}, versions...)
+	variants := append(android.CopyOf(versions), "")
 
 	modules := mctx.CreateLocalVariations(variants...)
 	for i, m := range modules {
 		if variants[i] != "" {
 			m.(LinkableInterface).SetBuildStubs()
 			m.(LinkableInterface).SetStubsVersion(variants[i])
+			// The implementation depends on the stubs
+			mctx.AddInterVariantDependency(stubImplDepTag, modules[len(modules)-1], modules[i])
 		}
 	}
 	mctx.AliasVariation("")
@@ -1541,7 +1616,22 @@
 	mctx.CreateAliasVariation("latest", latestVersion)
 }
 
-func VersionVariantAvailable(module interface {
+func createPerApiVersionVariations(mctx android.BottomUpMutatorContext, minSdkVersion string) {
+	from, err := nativeApiLevelFromUser(mctx, minSdkVersion)
+	if err != nil {
+		mctx.PropertyErrorf("min_sdk_version", err.Error())
+		return
+	}
+
+	versionStrs := ndkLibraryVersions(mctx, from)
+	modules := mctx.CreateLocalVariations(versionStrs...)
+
+	for i, module := range modules {
+		module.(*Module).Properties.Sdk_version = StringPtr(versionStrs[i])
+	}
+}
+
+func CanBeOrLinkAgainstVersionVariants(module interface {
 	Host() bool
 	InRamdisk() bool
 	InRecovery() bool
@@ -1549,32 +1639,34 @@
 	return !module.Host() && !module.InRamdisk() && !module.InRecovery()
 }
 
+func CanBeVersionVariant(module interface {
+	Host() bool
+	InRamdisk() bool
+	InRecovery() bool
+	CcLibraryInterface() bool
+	Shared() bool
+	Static() bool
+}) bool {
+	return CanBeOrLinkAgainstVersionVariants(module) &&
+		module.CcLibraryInterface() && (module.Shared() || module.Static())
+}
+
 // versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
 // and propagates the value from implementation libraries to llndk libraries with the same name.
 func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
-	if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
-		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
-			!library.IsSdkVariant() {
-
-			versions := library.StubsVersions()
-			normalizeVersions(mctx, versions)
-			if mctx.Failed() {
+	if library, ok := mctx.Module().(LinkableInterface); ok && CanBeVersionVariant(library) {
+		if library.CcLibraryInterface() && library.BuildSharedVariant() {
+			versions := library.StubsVersions(mctx)
+			if len(versions) > 0 {
+				normalizeVersions(mctx, versions)
+				if mctx.Failed() {
+					return
+				}
+				// Set the versions on the pre-mutated module so they can be read by any llndk modules that
+				// depend on the implementation library and haven't been mutated yet.
+				library.SetAllStubsVersions(versions)
 				return
 			}
-			// Set the versions on the pre-mutated module so they can be read by any llndk modules that
-			// depend on the implementation library and haven't been mutated yet.
-			library.SetAllStubsVersions(versions)
-			return
-		}
-
-		if c, ok := library.(*Module); ok && c.IsStubs() {
-			// Get the versions from the implementation module.
-			impls := mctx.GetDirectDepsWithTag(llndkImplDep)
-			if len(impls) > 1 {
-				panic(fmt.Errorf("Expected single implmenetation library, got %d", len(impls)))
-			} else if len(impls) == 1 {
-				c.SetAllStubsVersions(impls[0].(*Module).AllStubsVersions())
-			}
 		}
 	}
 }
@@ -1582,8 +1674,18 @@
 // versionMutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func versionMutator(mctx android.BottomUpMutatorContext) {
-	if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
+	if library, ok := mctx.Module().(LinkableInterface); ok && CanBeVersionVariant(library) {
 		createVersionVariations(mctx, library.AllStubsVersions())
+		return
+	}
+
+	if m, ok := mctx.Module().(*Module); ok {
+		if m.SplitPerApiLevel() && m.IsSdkVariant() {
+			if mctx.Os() != android.Android {
+				return
+			}
+			createPerApiVersionVariations(mctx, m.MinSdkVersion())
+		}
 	}
 }
 
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 41ce294..fcf6069 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -85,8 +85,11 @@
 			variations := target.Variations()
 			if mctx.Device() {
 				variations = append(variations,
-					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
-					blueprint.Variation{Mutator: "version", Variation: version})
+					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
+				if mt.linkTypes != nil {
+					variations = append(variations,
+						blueprint.Variation{Mutator: "version", Variation: version})
+				}
 			}
 			if mt.linkTypes == nil {
 				mctx.AddFarVariationDependencies(variations, dependencyTag, name)
@@ -388,10 +391,12 @@
 		p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
 	}
 
+	exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo)
+
 	// Separate out the generated include dirs (which are arch specific) from the
 	// include dirs (which may not be).
 	exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
-		ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
+		exportedInfo.IncludeDirs, isGeneratedHeaderDirectory)
 
 	p.name = variant.Name()
 	p.archType = ccModule.Target().Arch.ArchType.String()
@@ -402,10 +407,10 @@
 
 	// Take a copy before filtering out duplicates to avoid changing the slice owned by the
 	// ccModule.
-	dirs := append(android.Paths(nil), ccModule.ExportedSystemIncludeDirs()...)
+	dirs := append(android.Paths(nil), exportedInfo.SystemIncludeDirs...)
 	p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs)
 
-	p.ExportedFlags = ccModule.ExportedFlags()
+	p.ExportedFlags = exportedInfo.Flags
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
 		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
@@ -416,7 +421,7 @@
 		}
 		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
 	}
-	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+	p.exportedGeneratedHeaders = exportedInfo.GeneratedHeaders
 
 	if ccModule.HasStubsVariants() {
 		// TODO(b/169373910): 1. Only output the specific version (from
diff --git a/cc/linkable.go b/cc/linkable.go
index 6d8a4b7..4eb7220 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -14,16 +14,9 @@
 	OutputFile() android.OptionalPath
 	CoverageFiles() android.Paths
 
-	IncludeDirs() android.Paths
-	SetDepsInLinkOrder([]android.Path)
-	GetDepsInLinkOrder() []android.Path
-
-	HasStaticVariant() bool
-	GetStaticVariant() LinkableInterface
-
 	NonCcVariants() bool
 
-	StubsVersions() []string
+	StubsVersions(android.BaseMutatorContext) []string
 	BuildStubs() bool
 	SetBuildStubs()
 	SetStubsVersion(string)
@@ -63,6 +56,8 @@
 	ToolchainLibrary() bool
 	NdkPrebuiltStl() bool
 	StubDecorator() bool
+
+	SplitPerApiLevel() bool
 }
 
 var (
@@ -78,3 +73,54 @@
 func StaticDepTag() blueprint.DependencyTag {
 	return libraryDependencyTag{Kind: staticLibraryDependency}
 }
+
+type SharedLibraryInfo struct {
+	SharedLibrary           android.Path
+	UnstrippedSharedLibrary android.Path
+
+	TableOfContents       android.OptionalPath
+	CoverageSharedLibrary android.OptionalPath
+
+	StaticAnalogue *StaticLibraryInfo
+}
+
+var SharedLibraryInfoProvider = blueprint.NewProvider(SharedLibraryInfo{})
+
+type SharedLibraryImplementationStubsInfo struct {
+	SharedLibraryStubsInfos []SharedLibraryStubsInfo
+
+	IsLLNDK bool
+}
+
+var SharedLibraryImplementationStubsInfoProvider = blueprint.NewProvider(SharedLibraryImplementationStubsInfo{})
+
+type SharedLibraryStubsInfo struct {
+	Version           string
+	SharedLibraryInfo SharedLibraryInfo
+	FlagExporterInfo  FlagExporterInfo
+}
+
+var SharedLibraryStubsInfoProvider = blueprint.NewProvider(SharedLibraryStubsInfo{})
+
+type StaticLibraryInfo struct {
+	StaticLibrary android.Path
+	Objects       Objects
+	ReuseObjects  Objects
+
+	// This isn't the actual transitive DepSet, shared library dependencies have been
+	// converted into static library analogues.  It is only used to order the static
+	// library dependencies that were specified for the current module.
+	TransitiveStaticLibrariesForOrdering *android.DepSet
+}
+
+var StaticLibraryInfoProvider = blueprint.NewProvider(StaticLibraryInfo{})
+
+type FlagExporterInfo struct {
+	IncludeDirs       android.Paths
+	SystemIncludeDirs android.Paths
+	Flags             []string
+	Deps              android.Paths
+	GeneratedHeaders  android.Paths
+}
+
+var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index b3f9d61..4425a10 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -15,17 +15,14 @@
 package cc
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
 	"android/soong/android"
-
-	"github.com/google/blueprint"
 )
 
-var llndkImplDep = struct {
-	blueprint.DependencyTag
-}{}
+var llndkImplDep = dependencyTag{name: "llndk impl"}
 
 var (
 	llndkLibrarySuffix = ".llndk"
@@ -72,8 +69,7 @@
 
 	Properties llndkLibraryProperties
 
-	exportHeadersTimestamp android.OptionalPath
-	versionScriptPath      android.ModuleGenPath
+	movedToApex bool
 }
 
 func (stub *llndkStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -91,7 +87,9 @@
 		vndkVer = stub.stubsVersion()
 	}
 	objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), vndkVer, "--llndk")
-	stub.versionScriptPath = versionScript
+	if !Bool(stub.Properties.Unversioned) {
+		stub.versionScriptPath = android.OptionalPathForPath(versionScript)
+	}
 	return objs
 }
 
@@ -135,10 +133,9 @@
 func (stub *llndkStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
 	objs Objects) android.Path {
 
-	if !Bool(stub.Properties.Unversioned) {
-		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
-		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
-		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
+	impl := ctx.GetDirectDepWithTag(ctx.baseModuleName(), llndkImplDep)
+	if implApexModule, ok := impl.(android.ApexModule); ok {
+		stub.movedToApex = implApexModule.DirectlyInAnyApex()
 	}
 
 	if len(stub.Properties.Export_preprocessed_headers) > 0 {
@@ -163,10 +160,6 @@
 		stub.libraryDecorator.flagExporter.Properties.Export_include_dirs = []string{}
 	}
 
-	if stub.stubsVersion() != "" {
-		stub.reexportFlags("-D" + versioningMacroName(ctx.baseModuleName()) + "=" + stub.stubsVersion())
-	}
-
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
@@ -174,6 +167,21 @@
 	return false
 }
 
+func (stub *llndkStubDecorator) buildStubs() bool {
+	return true
+}
+
+func (stub *llndkStubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+	// Get the versions from the implementation module.
+	impls := ctx.GetDirectDepsWithTag(llndkImplDep)
+	if len(impls) > 1 {
+		panic(fmt.Errorf("Expected single implmenetation library, got %d", len(impls)))
+	} else if len(impls) == 1 {
+		return impls[0].(*Module).AllStubsVersions()
+	}
+	return nil
+}
+
 func NewLLndkStubLibrary() *Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyShared()
diff --git a/cc/lto.go b/cc/lto.go
index abd8dfb..a3b28d9 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -71,7 +71,8 @@
 	} else if ctx.Config().IsEnvTrue("GLOBAL_THINLTO") {
 		staticLib := ctx.static() && !ctx.staticBinary()
 		hostBin := ctx.Host()
-		if !staticLib && !hostBin {
+		vndk := ctx.isVndk() // b/169217596
+		if !staticLib && !hostBin && !vndk {
 			if !lto.Never() && !lto.FullLTO() {
 				lto.Properties.Lto.Thin = boolPtr(true)
 			}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 5682d1c..f2ad652 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -80,9 +80,6 @@
 	// https://github.com/android-ndk/ndk/issues/265.
 	Unversioned_until *string
 
-	// Use via apiLevel on the stubDecorator.
-	ApiLevel string `blueprint:"mutated"`
-
 	// True if this API is not yet ready to be shipped in the NDK. It will be
 	// available in the platform for testing, but will be excluded from the
 	// sysroot provided to the NDK proper.
@@ -107,9 +104,7 @@
 	return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil)
 }
 
-func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module,
-	from android.ApiLevel, perSplit func(*Module, android.ApiLevel)) {
-
+func ndkLibraryVersions(ctx android.BaseMutatorContext, from android.ApiLevel) []string {
 	var versions []android.ApiLevel
 	versionStrs := []string{}
 	for _, version := range ctx.Config().AllSupportedApiLevels() {
@@ -118,56 +113,26 @@
 			versionStrs = append(versionStrs, version.String())
 		}
 	}
-	versions = append(versions, android.FutureApiLevel)
 	versionStrs = append(versionStrs, android.FutureApiLevel.String())
 
-	modules := ctx.CreateVariations(versionStrs...)
-	for i, module := range modules {
-		perSplit(module.(*Module), versions[i])
-	}
+	return versionStrs
 }
 
-func NdkApiMutator(ctx android.BottomUpMutatorContext) {
-	if m, ok := ctx.Module().(*Module); ok {
-		if m.Enabled() {
-			if compiler, ok := m.compiler.(*stubDecorator); ok {
-				if ctx.Os() != android.Android {
-					// These modules are always android.DeviceEnabled only, but
-					// those include Fuchsia devices, which we don't support.
-					ctx.Module().Disable()
-					return
-				}
-				firstVersion, err := nativeApiLevelFromUser(ctx,
-					String(compiler.properties.First_version))
-				if err != nil {
-					ctx.PropertyErrorf("first_version", err.Error())
-					return
-				}
-				generatePerApiVariants(ctx, m, firstVersion,
-					func(m *Module, version android.ApiLevel) {
-						m.compiler.(*stubDecorator).properties.ApiLevel =
-							version.String()
-					})
-			} else if m.SplitPerApiLevel() && m.IsSdkVariant() {
-				if ctx.Os() != android.Android {
-					return
-				}
-				from, err := nativeApiLevelFromUser(ctx, m.MinSdkVersion())
-				if err != nil {
-					ctx.PropertyErrorf("min_sdk_version", err.Error())
-					return
-				}
-				generatePerApiVariants(ctx, m, from,
-					func(m *Module, version android.ApiLevel) {
-						m.Properties.Sdk_version = StringPtr(version.String())
-					})
-			}
-		}
+func (this *stubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+	if !ctx.Module().Enabled() {
+		return nil
 	}
+	firstVersion, err := nativeApiLevelFromUser(ctx,
+		String(this.properties.First_version))
+	if err != nil {
+		ctx.PropertyErrorf("first_version", err.Error())
+		return nil
+	}
+	return ndkLibraryVersions(ctx, firstVersion)
 }
 
 func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool {
-	this.apiLevel = nativeApiLevelOrPanic(ctx, this.properties.ApiLevel)
+	this.apiLevel = nativeApiLevelOrPanic(ctx, this.stubsVersion())
 
 	var err error
 	this.firstVersion, err = nativeApiLevelFromUser(ctx,
@@ -280,6 +245,11 @@
 		ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
 	}
 
+	if !c.buildStubs() {
+		// NDK libraries have no implementation variant, nothing to do
+		return Objects{}
+	}
+
 	if !c.initializeProperties(ctx) {
 		// Emits its own errors, so we don't need to.
 		return Objects{}
@@ -311,12 +281,18 @@
 func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
 	objs Objects) android.Path {
 
+	if !stub.buildStubs() {
+		// NDK libraries have no implementation variant, nothing to do
+		return nil
+	}
+
 	if shouldUseVersionScript(ctx, stub) {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
 		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
 		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 
+	stub.libraryDecorator.skipAPIDefine = true
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index acdc581..793ab37 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -166,7 +166,7 @@
 		ctx.ModuleErrorf("NDK prebuilt libraries must have an ndk_lib prefixed name")
 	}
 
-	ndk.exportIncludesAsSystem(ctx)
+	ndk.libraryDecorator.flagExporter.exportIncludesAsSystem(ctx)
 
 	libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
 	libExt := flags.Toolchain.ShlibSuffix()
@@ -175,5 +175,23 @@
 	}
 
 	libDir := getNdkStlLibDir(ctx)
-	return libDir.Join(ctx, libName+libExt)
+	lib := libDir.Join(ctx, libName+libExt)
+
+	ndk.libraryDecorator.flagExporter.setProvider(ctx)
+
+	if ndk.static() {
+		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(lib).Build()
+		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+			StaticLibrary: lib,
+
+			TransitiveStaticLibrariesForOrdering: depSet,
+		})
+	} else {
+		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+			SharedLibrary:           lib,
+			UnstrippedSharedLibrary: lib,
+		})
+	}
+
+	return lib
 }
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 56fd54b..b6733c2 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -131,7 +131,7 @@
 		}
 
 		if m, ok := module.(*Module); ok {
-			if installer, ok := m.installer.(*stubDecorator); ok {
+			if installer, ok := m.installer.(*stubDecorator); ok && m.BuildStubs() {
 				if ctx.Config().ExcludeDraftNdkApis() &&
 					installer.properties.Draft {
 					return
diff --git a/cc/object.go b/cc/object.go
index 778d131..ab2672b 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -96,11 +96,6 @@
 func (*objectLinker) linkerInit(ctx BaseModuleContext) {}
 
 func (object *objectLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	if ctx.useVndk() && ctx.toolchain().Bionic() {
-		// Needed for VNDK builds where bionic headers aren't automatically added.
-		deps.LateSharedLibs = append(deps.LateSharedLibs, "libc")
-	}
-
 	deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs...)
 	deps.ObjFiles = append(deps.ObjFiles, object.Properties.Objs...)
 	return deps
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 9d1b016..45d3eb1 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -38,10 +38,11 @@
 }
 
 type prebuiltLinkerProperties struct {
-
 	// a prebuilt library or binary. Can reference a genrule module that generates an executable file.
 	Srcs []string `android:"path,arch_variant"`
 
+	Sanitized Sanitized `android:"arch_variant"`
+
 	// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
 	// symbols, etc), default true.
 	Check_elf_files *bool
@@ -97,15 +98,17 @@
 func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
-	p.libraryDecorator.exportIncludes(ctx)
-	p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
-	p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
-	p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
-	p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
-	p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+	p.libraryDecorator.flagExporter.exportIncludes(ctx)
+	p.libraryDecorator.flagExporter.reexportDirs(deps.ReexportedDirs...)
+	p.libraryDecorator.flagExporter.reexportSystemDirs(deps.ReexportedSystemDirs...)
+	p.libraryDecorator.flagExporter.reexportFlags(deps.ReexportedFlags...)
+	p.libraryDecorator.flagExporter.reexportDeps(deps.ReexportedDeps...)
+	p.libraryDecorator.flagExporter.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+
+	p.libraryDecorator.flagExporter.setProvider(ctx)
 
 	// TODO(ccross): verify shared library dependencies
-	srcs := p.prebuiltSrcs()
+	srcs := p.prebuiltSrcs(ctx)
 	if len(srcs) > 0 {
 		builderFlags := flagsToBuilderFlags(flags)
 
@@ -117,6 +120,12 @@
 		in := android.PathForModuleSrc(ctx, srcs[0])
 
 		if p.static() {
+			depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
+			ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+				StaticLibrary: in,
+
+				TransitiveStaticLibrariesForOrdering: depSet,
+			})
 			return in
 		}
 
@@ -170,6 +179,13 @@
 				},
 			})
 
+			ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+				SharedLibrary:           outputFile,
+				UnstrippedSharedLibrary: p.unstrippedOutputFile,
+
+				TableOfContents: p.tocFile,
+			})
+
 			return outputFile
 		}
 	}
@@ -177,15 +193,18 @@
 	return nil
 }
 
-func (p *prebuiltLibraryLinker) prebuiltSrcs() []string {
+func (p *prebuiltLibraryLinker) prebuiltSrcs(ctx android.BaseModuleContext) []string {
+	sanitize := ctx.Module().(*Module).sanitize
 	srcs := p.properties.Srcs
+	srcs = append(srcs, srcsForSanitizer(sanitize, p.properties.Sanitized)...)
 	if p.static() {
 		srcs = append(srcs, p.libraryDecorator.StaticProperties.Static.Srcs...)
+		srcs = append(srcs, srcsForSanitizer(sanitize, p.libraryDecorator.StaticProperties.Static.Sanitized)...)
 	}
 	if p.shared() {
 		srcs = append(srcs, p.libraryDecorator.SharedProperties.Shared.Srcs...)
+		srcs = append(srcs, srcsForSanitizer(sanitize, p.libraryDecorator.SharedProperties.Shared.Sanitized)...)
 	}
-
 	return srcs
 }
 
@@ -212,8 +231,8 @@
 
 	module.AddProperties(&prebuilt.properties)
 
-	srcsSupplier := func() []string {
-		return prebuilt.prebuiltSrcs()
+	srcsSupplier := func(ctx android.BaseModuleContext) []string {
+		return prebuilt.prebuiltSrcs(ctx)
 	}
 
 	android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
@@ -425,3 +444,28 @@
 	android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
 	return module, binary
 }
+
+type Sanitized struct {
+	None struct {
+		Srcs []string `android:"path,arch_variant"`
+	} `android:"arch_variant"`
+	Address struct {
+		Srcs []string `android:"path,arch_variant"`
+	} `android:"arch_variant"`
+	Hwaddress struct {
+		Srcs []string `android:"path,arch_variant"`
+	} `android:"arch_variant"`
+}
+
+func srcsForSanitizer(sanitize *sanitize, sanitized Sanitized) []string {
+	if sanitize == nil {
+		return nil
+	}
+	if Bool(sanitize.Properties.Sanitize.Address) && sanitized.Address.Srcs != nil {
+		return sanitized.Address.Srcs
+	}
+	if Bool(sanitize.Properties.Sanitize.Hwaddress) && sanitized.Hwaddress.Srcs != nil {
+		return sanitized.Hwaddress.Srcs
+	}
+	return sanitized.None.Srcs
+}
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 52416ac..1f070a5 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -23,7 +23,7 @@
 	"github.com/google/blueprint"
 )
 
-func testPrebuilt(t *testing.T, bp string, fs map[string][]byte) *android.TestContext {
+func testPrebuilt(t *testing.T, bp string, fs map[string][]byte, handlers ...configCustomizer) *android.TestContext {
 	config := TestConfig(buildDir, android.Android, nil, bp, fs)
 	ctx := CreateTestContext()
 
@@ -34,6 +34,10 @@
 	android.RegisterAndroidMkBuildComponents(ctx)
 	android.SetInMakeForTests(config)
 
+	for _, handler := range handlers {
+		handler(config)
+	}
+
 	ctx.Register(config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -42,6 +46,8 @@
 	return ctx
 }
 
+type configCustomizer func(config android.Config)
+
 func TestPrebuilt(t *testing.T) {
 	bp := `
 		cc_library {
@@ -321,3 +327,62 @@
 	assertString(t, libfooDep.String(),
 		filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so"))
 }
+
+func TestPrebuiltLibrarySanitized(t *testing.T) {
+	bp := `cc_prebuilt_library {
+	name: "libtest",
+		static: {
+                        sanitized: { none: { srcs: ["libf.a"], }, hwaddress: { srcs: ["libf.hwasan.a"], }, },
+		},
+		shared: {
+                        sanitized: { none: { srcs: ["libf.so"], }, hwaddress: { srcs: ["hwasan/libf.so"], }, },
+		},
+	}
+	cc_prebuilt_library_static {
+		name: "libtest_static",
+                sanitized: { none: { srcs: ["libf.a"], }, hwaddress: { srcs: ["libf.hwasan.a"], }, },
+	}
+	cc_prebuilt_library_shared {
+		name: "libtest_shared",
+                sanitized: { none: { srcs: ["libf.so"], }, hwaddress: { srcs: ["hwasan/libf.so"], }, },
+	}`
+
+	fs := map[string][]byte{
+		"libf.a":         nil,
+		"libf.hwasan.a":  nil,
+		"libf.so":        nil,
+		"hwasan/libf.so": nil,
+	}
+
+	// Without SANITIZE_TARGET.
+	ctx := testPrebuilt(t, bp, fs)
+
+	shared_rule := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Rule("android/soong/cc.strip")
+	assertString(t, shared_rule.Input.String(), "libf.so")
+
+	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+	assertString(t, static.OutputFile().Path().Base(), "libf.a")
+
+	shared_rule2 := ctx.ModuleForTests("libtest_shared", "android_arm64_armv8-a_shared").Rule("android/soong/cc.strip")
+	assertString(t, shared_rule2.Input.String(), "libf.so")
+
+	static2 := ctx.ModuleForTests("libtest_static", "android_arm64_armv8-a_static").Module().(*Module)
+	assertString(t, static2.OutputFile().Path().Base(), "libf.a")
+
+	// With SANITIZE_TARGET=hwaddress
+	ctx = testPrebuilt(t, bp, fs, func(config android.Config) {
+		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+	})
+
+	shared_rule = ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip")
+	assertString(t, shared_rule.Input.String(), "hwasan/libf.so")
+
+	static = ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static_hwasan").Module().(*Module)
+	assertString(t, static.OutputFile().Path().Base(), "libf.hwasan.a")
+
+	shared_rule2 = ctx.ModuleForTests("libtest_shared", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip")
+	assertString(t, shared_rule2.Input.String(), "hwasan/libf.so")
+
+	static2 = ctx.ModuleForTests("libtest_static", "android_arm64_armv8-a_static_hwasan").Module().(*Module)
+	assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a")
+}
diff --git a/cc/sdk.go b/cc/sdk.go
index b68baad..ec57f06 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -32,11 +32,11 @@
 	switch m := ctx.Module().(type) {
 	case LinkableInterface:
 		if m.AlwaysSdk() {
-			if !m.UseSdk() {
+			if !m.UseSdk() && !m.SplitPerApiLevel() {
 				ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
 			}
 			ctx.CreateVariations("sdk")
-		} else if m.UseSdk() {
+		} else if m.UseSdk() || m.SplitPerApiLevel() {
 			modules := ctx.CreateVariations("", "sdk")
 			modules[0].(*Module).Properties.Sdk_version = nil
 			modules[1].(*Module).Properties.IsSdkVariant = true
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index f27d166..238508d 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -22,7 +22,6 @@
 )
 
 type snapshotLibraryInterface interface {
-	exportedFlagsProducer
 	libraryInterface
 	collectHeadersForSnapshot(ctx android.ModuleContext)
 	snapshotHeaders() android.Paths
@@ -58,10 +57,10 @@
 	return snapshot, found
 }
 
-func isSnapshotAware(ctx android.ModuleContext, m *Module) bool {
-	if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok {
+func isSnapshotAware(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
+	if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo); ok {
 		return ctx.Config().VndkSnapshotBuildArtifacts()
-	} else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir())) {
+	} else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) {
 		return true
 	}
 	return false
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 19f5ea4..8c546c5 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -84,24 +84,31 @@
 	}
 
 	srcPath := android.PathForSource(ctx, *library.Properties.Src)
-
-	if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
-		fileName := ctx.ModuleName() + staticLibraryExtension
-		outputFile := android.PathForModuleOut(ctx, fileName)
-		stripFlags := flagsToStripFlags(flags)
-		library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags)
-		return outputFile
-	}
+	outputFile := android.Path(srcPath)
 
 	if library.Properties.Repack_objects_to_keep != nil {
 		fileName := ctx.ModuleName() + staticLibraryExtension
-		outputFile := android.PathForModuleOut(ctx, fileName)
-		TransformArchiveRepack(ctx, srcPath, outputFile, library.Properties.Repack_objects_to_keep)
-
-		return outputFile
+		repackedPath := android.PathForModuleOut(ctx, fileName)
+		TransformArchiveRepack(ctx, outputFile, repackedPath, library.Properties.Repack_objects_to_keep)
+		outputFile = repackedPath
 	}
 
-	return srcPath
+	if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
+		fileName := ctx.ModuleName() + staticLibraryExtension
+		strippedPath := android.PathForModuleOut(ctx, fileName)
+		stripFlags := flagsToStripFlags(flags)
+		library.stripper.StripStaticLib(ctx, outputFile, strippedPath, stripFlags)
+		outputFile = strippedPath
+	}
+
+	depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(outputFile).Build()
+	ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		StaticLibrary: outputFile,
+
+		TransitiveStaticLibrariesForOrdering: depSet,
+	})
+
+	return outputFile
 }
 
 func (library *toolchainLibraryDecorator) nativeCoverage() bool {
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 2819f49..4c206e6 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -223,6 +223,22 @@
 		tocFile := android.PathForModuleOut(ctx, libName+".toc")
 		p.tocFile = android.OptionalPathForPath(tocFile)
 		TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+
+		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+			SharedLibrary:           in,
+			UnstrippedSharedLibrary: p.unstrippedOutputFile,
+
+			TableOfContents: p.tocFile,
+		})
+	}
+
+	if p.static() {
+		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
+		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+			StaticLibrary: in,
+
+			TransitiveStaticLibrariesForOrdering: depSet,
+		})
 	}
 
 	return in
@@ -537,7 +553,7 @@
 // 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, inVendorProprietaryPath bool) bool {
+func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool, apexInfo android.ApexInfo) bool {
 	if !m.Enabled() || m.Properties.HideFromMake {
 		return false
 	}
@@ -562,7 +578,7 @@
 		return false
 	}
 	// the module must be installed in /vendor
-	if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() {
+	if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() {
 		return false
 	}
 	// skip kernel_headers which always depend on vendor
@@ -735,13 +751,14 @@
 		var propOut string
 
 		if l, ok := m.linker.(snapshotLibraryInterface); ok {
+			exporterInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
 
 			// library flags
-			prop.ExportedFlags = l.exportedFlags()
-			for _, dir := range l.exportedDirs() {
+			prop.ExportedFlags = exporterInfo.Flags
+			for _, dir := range exporterInfo.IncludeDirs {
 				prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
 			}
-			for _, dir := range l.exportedSystemDirs() {
+			for _, dir := range exporterInfo.SystemIncludeDirs {
 				prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
 			}
 			// shared libs dependencies aren't meaningful on static or header libs
@@ -825,6 +842,7 @@
 
 		moduleDir := ctx.ModuleDir(module)
 		inVendorProprietaryPath := isVendorProprietaryPath(moduleDir)
+		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
 
 		if m.ExcludeFromVendorSnapshot() {
 			if inVendorProprietaryPath {
@@ -842,7 +860,7 @@
 			}
 		}
 
-		if !isVendorSnapshotModule(m, inVendorProprietaryPath) {
+		if !isVendorSnapshotModule(m, inVendorProprietaryPath, apexInfo) {
 			return
 		}
 
diff --git a/cc/vndk.go b/cc/vndk.go
index 9a2fa09..981e039 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -300,6 +300,7 @@
 	if !Bool(lib.Properties.Vendor_available) {
 		vndkPrivateLibraries(mctx.Config())[name] = filename
 	}
+
 	if mctx.OtherModuleExists(name) {
 		mctx.AddFarVariationDependencies(m.Target().Variations(), llndkImplDep, name)
 	}
@@ -533,11 +534,13 @@
 	vndkSnapshotZipFile android.OptionalPath
 }
 
-func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
+func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module,
+	apexInfo android.ApexInfo) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
+
 	if m.Target().NativeBridge == android.NativeBridgeEnabled {
 		return nil, "", false
 	}
-	if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
+	if !m.inVendor() || !m.installable(apexInfo) || m.isSnapshotPrebuilt() {
 		return nil, "", false
 	}
 	l, ok := m.linker.(snapshotLibraryInterface)
@@ -617,7 +620,7 @@
 
 	var headers android.Paths
 
-	installVndkSnapshotLib := func(m *Module, l snapshotLibraryInterface, vndkType string) (android.Paths, bool) {
+	installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) {
 		var ret android.Paths
 
 		targetArch := "arch-" + m.Target().Arch.ArchType.String()
@@ -636,9 +639,10 @@
 				ExportedFlags       []string `json:",omitempty"`
 				RelativeInstallPath string   `json:",omitempty"`
 			}{}
-			prop.ExportedFlags = l.exportedFlags()
-			prop.ExportedDirs = l.exportedDirs().Strings()
-			prop.ExportedSystemDirs = l.exportedSystemDirs().Strings()
+			exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
+			prop.ExportedFlags = exportedInfo.Flags
+			prop.ExportedDirs = exportedInfo.IncludeDirs.Strings()
+			prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings()
 			prop.RelativeInstallPath = m.RelativeInstallPath()
 
 			propOut := snapshotLibOut + ".json"
@@ -659,14 +663,16 @@
 			return
 		}
 
-		l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m)
+		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+
+		l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo)
 		if !ok {
 			return
 		}
 
 		// install .so files for appropriate modules.
 		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
-		libs, ok := installVndkSnapshotLib(m, l, vndkType)
+		libs, ok := installVndkSnapshotLib(m, vndkType)
 		if !ok {
 			return
 		}
@@ -823,14 +829,21 @@
 func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
 	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
 	// they been moved to an apex.
-	movedToApexLlndkLibraries := []string{}
-	for lib := range llndkLibraries(ctx.Config()) {
-		// Skip bionic libs, they are handled in different manner
-		if android.DirectlyInAnyApex(&notOnHostContext{}, lib) && !isBionic(lib) {
-			movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib)
+	movedToApexLlndkLibraries := make(map[string]bool)
+	ctx.VisitAllModules(func(module android.Module) {
+		if m, ok := module.(*Module); ok {
+			if llndk, ok := m.linker.(*llndkStubDecorator); ok {
+				// Skip bionic libs, they are handled in different manner
+				name := m.BaseModuleName()
+				if llndk.movedToApex && !isBionic(m.BaseModuleName()) {
+					movedToApexLlndkLibraries[name] = true
+				}
+			}
 		}
-	}
-	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " "))
+	})
+
+	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
+		strings.Join(android.SortedStringKeys(movedToApexLlndkLibraries), " "))
 
 	// Make uses LLNDK_LIBRARIES to determine which libraries to install.
 	// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 9484760..7c47ef4 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -162,6 +162,13 @@
 			p.androidMkSuffix = ""
 		}
 
+		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+			SharedLibrary:           in,
+			UnstrippedSharedLibrary: p.unstrippedOutputFile,
+
+			TableOfContents: p.tocFile,
+		})
+
 		return in
 	}
 
diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go
index 72e0fbd..b149e80 100644
--- a/cmd/soong_build/bazel_overlay.go
+++ b/cmd/soong_build/bazel_overlay.go
@@ -149,31 +149,6 @@
 		"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
@@ -439,8 +414,19 @@
 				attrs += propToAttr(prop, prop.Name)
 			}
 
-			for propName, propType := range additionalPropTypes[moduleTypeTemplate.Name] {
-				attrs += fmt.Sprintf("        %q: attr.%s(),\n", propName, propType)
+			moduleTypeName := moduleTypeTemplate.Name
+
+			// Certain SDK-related module types dynamically inject properties, instead of declaring
+			// them as structs. These properties are registered in an SdkMemberTypesRegistry. If
+			// the module type name matches, add these properties into the rule definition.
+			var registeredTypes []android.SdkMemberType
+			if moduleTypeName == "module_exports" || moduleTypeName == "module_exports_snapshot" {
+				registeredTypes = android.ModuleExportsMemberTypes.RegisteredTypes()
+			} else if moduleTypeName == "sdk" || moduleTypeName == "sdk_snapshot" {
+				registeredTypes = android.SdkMemberTypes.RegisteredTypes()
+			}
+			for _, memberType := range registeredTypes {
+				attrs += fmt.Sprintf("        %q: attr.string_list(),\n", memberType.SdkPropertyName())
 			}
 
 			attrs += "    },"
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 01a39a2..7ae1c37 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -51,30 +51,34 @@
 	return android.NewNameResolver(exportFilter)
 }
 
+func newContext(srcDir string, configuration android.Config) *android.Context {
+	ctx := android.NewContext()
+	ctx.Register()
+	if !shouldPrepareBuildActions() {
+		configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
+	}
+	ctx.SetNameInterface(newNameResolver(configuration))
+	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
+	return ctx
+}
+
+func newConfig(srcDir string) android.Config {
+	configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir, bootstrap.ModuleListFile)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "%s", err)
+		os.Exit(1)
+	}
+	return configuration
+}
+
 func main() {
 	android.ReexecWithDelveMaybe()
 	flag.Parse()
 
 	// The top-level Blueprints file is passed as the first argument.
 	srcDir := filepath.Dir(flag.Arg(0))
-
-	ctx := android.NewContext()
-	ctx.Register()
-
-	configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir, bootstrap.ModuleListFile)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "%s", err)
-		os.Exit(1)
-	}
-
-	if !shouldPrepareBuildActions() {
-		configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
-	}
-
-	ctx.SetNameInterface(newNameResolver(configuration))
-
-	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
-
+	var ctx *android.Context
+	configuration := newConfig(srcDir)
 	extraNinjaDeps := []string{configuration.ConfigFileName, configuration.ProductVariablesFileName}
 
 	// Read the SOONG_DELVE again through configuration so that there is a dependency on the environment variable
@@ -84,9 +88,31 @@
 		// enabled even if it completed successfully.
 		extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
 	}
-
-	bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
-
+	if configuration.BazelContext.BazelEnabled() {
+		// Bazel-enabled mode. Soong runs in two passes.
+		// First pass: Analyze the build tree, but only store all bazel commands
+		// needed to correctly evaluate the tree in the second pass.
+		// TODO(cparsons): Don't output any ninja file, as the second pass will overwrite
+		// the incorrect results from the first pass, and file I/O is expensive.
+		firstCtx := newContext(srcDir, configuration)
+		bootstrap.Main(firstCtx.Context, configuration, extraNinjaDeps...)
+		// Invoke bazel commands and save results for second pass.
+		if err := configuration.BazelContext.InvokeBazel(); err != nil {
+			fmt.Fprintf(os.Stderr, "%s", err)
+			os.Exit(1)
+		}
+		// Second pass: Full analysis, using the bazel command results. Output ninja file.
+		secondPassConfig, err := android.ConfigForAdditionalRun(configuration)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "%s", err)
+			os.Exit(1)
+		}
+		ctx = newContext(srcDir, secondPassConfig)
+		bootstrap.Main(ctx.Context, secondPassConfig, extraNinjaDeps...)
+	} else {
+		ctx = newContext(srcDir, configuration)
+		bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
+	}
 	if bazelOverlayDir != "" {
 		if err := createBazelOverlay(ctx, bazelOverlayDir); err != nil {
 			fmt.Fprintf(os.Stderr, "%s", err)
@@ -105,7 +131,7 @@
 	//  to affect the command line of the primary builder.
 	if shouldPrepareBuildActions() {
 		metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb")
-		err = android.WriteMetrics(configuration, metricsFile)
+		err := android.WriteMetrics(configuration, metricsFile)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
 			os.Exit(1)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 69e4f69..774a872 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -119,9 +119,9 @@
 func main() {
 	buildStarted := time.Now()
 
-	c, args := getCommand(os.Args)
-	if c == nil {
-		fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
+	c, args, err := getCommand(os.Args)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error parsing `soong` args: %s.\n", err)
 		os.Exit(1)
 	}
 
@@ -173,6 +173,7 @@
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
 	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
 	defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+	build.PrintOutDirWarning(buildCtx, config)
 
 	os.MkdirAll(logsDir, 0777)
 	log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
@@ -478,14 +479,14 @@
 
 // getCommand finds the appropriate command based on args[1] flag. args[0]
 // is the soong_ui filename.
-func getCommand(args []string) (*command, []string) {
+func getCommand(args []string) (*command, []string, error) {
 	if len(args) < 2 {
-		return nil, args
+		return nil, nil, fmt.Errorf("Too few arguments: %q", args)
 	}
 
 	for _, c := range commands {
 		if c.flag == args[1] {
-			return &c, args[2:]
+			return &c, args[2:], nil
 		}
 
 		// special case for --make-mode: if soong_ui was called from
@@ -494,11 +495,11 @@
 		// TODO: Remove this hack once it has been fixed.
 		if c.flag == makeModeFlagName {
 			if inList(makeModeFlagName, args) {
-				return &c, args[1:]
+				return &c, args[1:], nil
 			}
 		}
 	}
 
 	// command not found
-	return nil, args
+	return nil, nil, fmt.Errorf("Command not found: %q", args)
 }
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 4dbda49..814b75d 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -218,13 +218,21 @@
 	return m[sdkVer]
 }
 
-func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) bool {
+func (m classLoaderContextMap) addLibs(ctx android.PathContext, sdkVer int, module *ModuleConfig, libs ...string) bool {
 	clc := m.getValue(sdkVer)
 	for _, lib := range libs {
-		if p := pathForLibrary(module, lib); p != nil {
+		if p, ok := module.LibraryPaths[lib]; ok && p.Host != nil && p.Device != UnknownInstallLibraryPath {
 			clc.Host = append(clc.Host, p.Host)
 			clc.Target = append(clc.Target, p.Device)
 		} else {
+			if sdkVer == anySdkVersion {
+				// Fail the build if dexpreopt doesn't know paths to one of the <uses-library>
+				// dependencies. In the future we may need to relax this and just disable dexpreopt.
+				android.ReportPathErrorf(ctx, "dexpreopt cannot find path for <uses-library> '%s'", lib)
+			} else {
+				// No error for compatibility libraries, as Soong doesn't know if they are needed
+				// (this depends on the targetSdkVersion in the manifest).
+			}
 			return false
 		}
 	}
@@ -270,14 +278,14 @@
 	} else if module.EnforceUsesLibraries {
 		// Unconditional class loader context.
 		usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
-		if !classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) {
+		if !classLoaderContexts.addLibs(ctx, 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) {
+			if !classLoaderContexts.addLibs(ctx, 28, module, httpLegacy) {
 				return nil
 			}
 		}
@@ -287,14 +295,14 @@
 			"android.hidl.base-V1.0-java",
 			"android.hidl.manager-V1.0-java",
 		}
-		if !classLoaderContexts.addLibs(29, module, usesLibs29...) {
+		if !classLoaderContexts.addLibs(ctx, 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) {
+			if !classLoaderContexts.addLibs(ctx, 30, module, testBase) {
 				return nil
 			}
 		}
@@ -589,14 +597,6 @@
 	return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String()))
 }
 
-func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath {
-	if path, ok := module.LibraryPaths[lib]; ok && path.Host != nil && path.Device != "error" {
-		return path
-	} else {
-		return nil
-	}
-}
-
 func makefileMatch(pattern, s string) bool {
 	percent := strings.IndexByte(pattern, '%')
 	switch percent {
diff --git a/docs/OWNERS b/docs/OWNERS
new file mode 100644
index 0000000..d143317
--- /dev/null
+++ b/docs/OWNERS
@@ -0,0 +1 @@
+per-file map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 8e35679..664cb51 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -214,6 +214,13 @@
 		Output: p.outputFilePath,
 		Input:  p.sourceFilePath,
 	})
+
+	if p.Installable() {
+		installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
+		for _, sl := range p.properties.Symlinks {
+			ctx.InstallSymlink(p.installDirPath, sl, installPath)
+		}
+	}
 }
 
 func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/finder/finder.go b/finder/finder.go
index 6513fa3..5413fa6 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -103,6 +103,9 @@
 
 	// IncludeFiles are file names to include as matches
 	IncludeFiles []string
+
+	// IncludeSuffixes are filename suffixes to include as matches.
+	IncludeSuffixes []string
 }
 
 // a cacheConfig stores the inputs that determine what should be included in the cache
@@ -1310,6 +1313,20 @@
 	return stats
 }
 
+func (f *Finder) shouldIncludeFile(fileName string) bool {
+	for _, includedName := range f.cacheMetadata.Config.IncludeFiles {
+		if fileName == includedName {
+			return true
+		}
+	}
+	for _, includeSuffix := range f.cacheMetadata.Config.IncludeSuffixes {
+		if strings.HasSuffix(fileName, includeSuffix) {
+			return true
+		}
+	}
+	return false
+}
+
 // pruneCacheCandidates removes the items that we don't want to include in our persistent cache
 func (f *Finder) pruneCacheCandidates(items *DirEntries) {
 
@@ -1326,13 +1343,9 @@
 	// remove any files that aren't the ones we want to include
 	writeIndex := 0
 	for _, fileName := range items.FileNames {
-		// include only these files
-		for _, includedName := range f.cacheMetadata.Config.IncludeFiles {
-			if fileName == includedName {
-				items.FileNames[writeIndex] = fileName
-				writeIndex++
-				break
-			}
+		if f.shouldIncludeFile(fileName) {
+			items.FileNames[writeIndex] = fileName
+			writeIndex++
 		}
 	}
 	// resize
diff --git a/finder/finder_test.go b/finder/finder_test.go
index 88b0c05..788dbdd 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -21,6 +21,7 @@
 	"os"
 	"path/filepath"
 	"sort"
+	"strings"
 	"testing"
 
 	"android/soong/finder/fs"
@@ -92,6 +93,7 @@
 			nil,
 			nil,
 			[]string{"findme.txt", "skipme.txt"},
+			nil,
 		},
 	)
 	defer finder.Shutdown()
@@ -104,6 +106,46 @@
 	fs.AssertSameResponse(t, foundPaths, absoluteMatches)
 }
 
+// runTestWithSuffixes creates a few files, searches for findme.txt or any file
+// with suffix `.findme_ext` and checks for the expected matches
+func runTestWithSuffixes(t *testing.T, existentPaths []string, expectedMatches []string) {
+	filesystem := newFs()
+	root := "/tmp"
+	filesystem.MkDirs(root)
+	for _, path := range existentPaths {
+		fs.Create(t, filepath.Join(root, path), filesystem)
+	}
+
+	finder := newFinder(t,
+		filesystem,
+		CacheParams{
+			"/cwd",
+			[]string{root},
+			nil,
+			nil,
+			[]string{"findme.txt", "skipme.txt"},
+			[]string{".findme_ext"},
+		},
+	)
+	defer finder.Shutdown()
+
+	foundPaths := finder.FindMatching(root,
+		func(entries DirEntries) (dirs []string, files []string) {
+			matches := []string{}
+			for _, foundName := range entries.FileNames {
+				if foundName == "findme.txt" || strings.HasSuffix(foundName, ".findme_ext") {
+					matches = append(matches, foundName)
+				}
+			}
+			return entries.DirNames, matches
+		})
+	absoluteMatches := []string{}
+	for i := range expectedMatches {
+		absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
+	}
+	fs.AssertSameResponse(t, foundPaths, absoluteMatches)
+}
+
 // testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
 func testAgainstSeveralThreadcounts(t *testing.T, tester func(t *testing.T, numThreads int)) {
 	// test singlethreaded, multithreaded, and also using the same number of threads as
@@ -135,6 +177,13 @@
 	)
 }
 
+func TestIncludeFilesAndSuffixes(t *testing.T) {
+	runTestWithSuffixes(t,
+		[]string{"findme.txt", "skipme.txt", "alsome.findme_ext"},
+		[]string{"findme.txt", "alsome.findme_ext"},
+	)
+}
+
 func TestNestedDirectories(t *testing.T) {
 	runSimpleTest(t,
 		[]string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt"},
@@ -142,6 +191,13 @@
 	)
 }
 
+func TestNestedDirectoriesWithSuffixes(t *testing.T) {
+	runTestWithSuffixes(t,
+		[]string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt", "subdir/alsome.findme_ext"},
+		[]string{"findme.txt", "subdir/findme.txt", "subdir/alsome.findme_ext"},
+	)
+}
+
 func TestEmptyDirectory(t *testing.T) {
 	runSimpleTest(t,
 		[]string{},
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 4a2f810..99d6207 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -81,6 +81,12 @@
 	label string
 }
 
+// TODO(cparsons): Move to a common location when there is more than just
+// genrule with a bazel_module property.
+type bazelModuleProperties struct {
+	Label string
+}
+
 type generatorProperties struct {
 	// The command to run on one or more input files. Cmd supports substitution of a few variables
 	//
@@ -113,8 +119,10 @@
 
 	// input files to exclude
 	Exclude_srcs []string `android:"path,arch_variant"`
-}
 
+	// in bazel-enabled mode, the bazel label to evaluate instead of this module
+	Bazel_module bazelModuleProperties
+}
 type Module struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -186,6 +194,20 @@
 	}
 }
 
+// Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
+func (c *Module) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+	bazelCtx := ctx.Config().BazelContext
+	filePaths, ok := bazelCtx.GetAllFiles(label)
+	if ok {
+		var bazelOutputFiles android.Paths
+		for _, bazelOutputFile := range filePaths {
+			bazelOutputFiles = append(bazelOutputFiles, android.PathForSource(ctx, bazelOutputFile))
+		}
+		c.outputFiles = bazelOutputFiles
+		c.outputDeps = bazelOutputFiles
+	}
+	return ok
+}
 func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	g.subName = ctx.ModuleSubDir()
 
@@ -456,26 +478,29 @@
 
 	g.outputFiles = outputFiles.Paths()
 
-	// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
-	// the genrules on AOSP. That will make things simpler to look at the graph in the common
-	// case. For larger sets of outputs, inject a phony target in between to limit ninja file
-	// growth.
-	if len(g.outputFiles) <= 6 {
-		g.outputDeps = g.outputFiles
-	} else {
-		phonyFile := android.PathForModuleGen(ctx, "genrule-phony")
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   blueprint.Phony,
-			Output: phonyFile,
-			Inputs: g.outputFiles,
-		})
-
-		g.outputDeps = android.Paths{phonyFile}
+	bazelModuleLabel := g.properties.Bazel_module.Label
+	bazelActionsUsed := false
+	if ctx.Config().BazelContext.BazelEnabled() && len(bazelModuleLabel) > 0 {
+		bazelActionsUsed = g.generateBazelBuildActions(ctx, bazelModuleLabel)
 	}
-
+	if !bazelActionsUsed {
+		// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
+		// the genrules on AOSP. That will make things simpler to look at the graph in the common
+		// case. For larger sets of outputs, inject a phony target in between to limit ninja file
+		// growth.
+		if len(g.outputFiles) <= 6 {
+			g.outputDeps = g.outputFiles
+		} else {
+			phonyFile := android.PathForModuleGen(ctx, "genrule-phony")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   blueprint.Phony,
+				Output: phonyFile,
+				Inputs: g.outputFiles,
+			})
+			g.outputDeps = android.Paths{phonyFile}
+		}
+	}
 }
-
 func hashSrcFiles(srcFiles android.Paths) string {
 	h := sha256.New()
 	for _, src := range srcFiles {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 4b36600..fdbb9d9 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -721,6 +721,39 @@
 	}
 }
 
+func TestGenruleWithBazel(t *testing.T) {
+	bp := `
+		genrule {
+				name: "foo",
+				out: ["one.txt", "two.txt"],
+				bazel_module: { label: "//foo/bar:bar" },
+		}
+	`
+
+	config := testConfig(bp, nil)
+	config.BazelContext = android.MockBazelContext{
+		AllFiles: map[string][]string{
+			"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
+
+	ctx := testContext(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if errs == nil {
+		_, errs = ctx.PrepareBuildActions(config)
+	}
+	if errs != nil {
+		t.Fatal(errs)
+	}
+	gen := ctx.ModuleForTests("foo", "").Module().(*Module)
+
+	expectedOutputFiles := []string{"bazelone.txt", "bazeltwo.txt"}
+	if !reflect.DeepEqual(gen.outputFiles.Strings(), expectedOutputFiles) {
+		t.Errorf("Expected output files: %q, actual: %q", expectedOutputFiles, gen.outputFiles)
+	}
+	if !reflect.DeepEqual(gen.outputDeps.Strings(), expectedOutputFiles) {
+		t.Errorf("Expected output deps: %q, actual: %q", expectedOutputFiles, gen.outputDeps)
+	}
+}
+
 type testTool struct {
 	android.ModuleBase
 	outputFile android.Path
diff --git a/java/aar.go b/java/aar.go
index 9cab0bd..f1f6848 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -34,10 +34,16 @@
 	ExportedStaticPackages() android.Paths
 	ExportedManifests() android.Paths
 	ExportedAssets() android.OptionalPath
+	SetRROEnforcedForDependent(enforce bool)
+	IsRROEnforced(ctx android.BaseModuleContext) bool
 }
 
 func init() {
 	RegisterAARBuildComponents(android.InitRegistrationContext)
+
+	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel()
+	})
 }
 
 func RegisterAARBuildComponents(ctx android.RegistrationContext) {
@@ -82,6 +88,9 @@
 
 	// do not include AndroidManifest from dependent libraries
 	Dont_merge_manifests *bool
+
+	// true if RRO is enforced for any of the dependent modules
+	RROEnforcedForDependent bool `blueprint:"mutated"`
 }
 
 type aapt struct {
@@ -117,6 +126,18 @@
 	path   android.Path
 }
 
+// Propagate RRO enforcement flag to static lib dependencies transitively.
+func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) {
+	m := ctx.Module()
+	if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) {
+		ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
+			if a, ok := d.(AndroidLibraryDependency); ok {
+				a.SetRROEnforcedForDependent(true)
+			}
+		})
+	}
+}
+
 func (a *aapt) ExportPackage() android.Path {
 	return a.exportPackage
 }
@@ -133,6 +154,17 @@
 	return a.assetPackage
 }
 
+func (a *aapt) SetRROEnforcedForDependent(enforce bool) {
+	a.aaptProperties.RROEnforcedForDependent = enforce
+}
+
+func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool {
+	// True if RRO is enforced for this module or...
+	return ctx.Config().EnforceRROForModule(ctx.ModuleName()) ||
+		// if RRO is enforced for any of its dependents, and this module is not exempted.
+		(a.aaptProperties.RROEnforcedForDependent && !ctx.Config().EnforceRROExemptedForModule(ctx.ModuleName()))
+}
+
 func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
 	manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
 	resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
@@ -156,7 +188,7 @@
 			dir:   dir,
 			files: androidResourceGlob(ctx, dir),
 		})
-		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, a, dir)
 		overlayDirs = append(overlayDirs, resOverlayDirs...)
 		rroDirs = append(rroDirs, resRRODirs...)
 	}
@@ -412,14 +444,16 @@
 					assets = append(assets, aarDep.ExportedAssets().Path())
 				}
 
-			outer:
-				for _, d := range aarDep.ExportedRRODirs() {
-					for _, e := range staticRRODirs {
-						if d.path == e.path {
-							continue outer
+				if !ctx.Config().EnforceRROExemptedForModule(ctx.ModuleName()) {
+				outer:
+					for _, d := range aarDep.ExportedRRODirs() {
+						for _, e := range staticRRODirs {
+							if d.path == e.path {
+								continue outer
+							}
 						}
+						staticRRODirs = append(staticRRODirs, d)
 					}
-					staticRRODirs = append(staticRRODirs, d)
 				}
 			}
 		}
@@ -477,6 +511,8 @@
 	a.aapt.buildActions(ctx, sdkContext(a))
 	a.exportedSdkLibs = a.aapt.sdkLibraries
 
+	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+
 	ctx.CheckbuildFile(a.proguardOptionsFile)
 	ctx.CheckbuildFile(a.exportPackage)
 	ctx.CheckbuildFile(a.aaptSrcJar)
@@ -569,6 +605,24 @@
 	manifest              android.WritablePath
 
 	exportedStaticPackages android.Paths
+
+	hideApexVariantFromMake bool
+
+	aarPath android.Path
+}
+
+var _ android.OutputFileProducer = (*AARImport)(nil)
+
+// For OutputFileProducer interface
+func (a *AARImport) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case ".aar":
+		return []android.Path{a.aarPath}, nil
+	case "":
+		return []android.Path{a.classpathFile}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 func (a *AARImport) sdkVersion() sdkSpec {
@@ -621,6 +675,17 @@
 	return android.OptionalPath{}
 }
 
+// RRO enforcement is not available on aar_import since its RRO dirs are not
+// exported.
+func (a *AARImport) SetRROEnforcedForDependent(enforce bool) {
+}
+
+// RRO enforcement is not available on aar_import since its RRO dirs are not
+// exported.
+func (a *AARImport) IsRROEnforced(ctx android.BaseModuleContext) bool {
+	return false
+}
+
 func (a *AARImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
@@ -662,13 +727,15 @@
 		return
 	}
 
+	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+
 	aarName := ctx.ModuleName() + ".aar"
-	var aar android.Path
-	aar = android.PathForModuleSrc(ctx, a.properties.Aars[0])
+	a.aarPath = android.PathForModuleSrc(ctx, a.properties.Aars[0])
+
 	if Bool(a.properties.Jetifier) {
-		inputFile := aar
-		aar = android.PathForModuleOut(ctx, "jetifier", aarName)
-		TransformJetifier(ctx, aar.(android.WritablePath), inputFile)
+		inputFile := a.aarPath
+		a.aarPath = android.PathForModuleOut(ctx, "jetifier", aarName)
+		TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile)
 	}
 
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
@@ -678,7 +745,7 @@
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        unzipAAR,
-		Input:       aar,
+		Input:       a.aarPath,
 		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest},
 		Description: "unzip AAR",
 		Args: map[string]string{
@@ -692,7 +759,7 @@
 	compileFlags := []string{"--pseudo-localize"}
 	compiledResDir := android.PathForModuleOut(ctx, "flat-res")
 	flata := compiledResDir.Join(ctx, "gen_res.flata")
-	aapt2CompileZip(ctx, flata, aar, "res", compileFlags)
+	aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags)
 
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
 	// the subdir "android" is required to be filtered by package names
diff --git a/java/android_resources.go b/java/android_resources.go
index c2bc746..97f7679 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -66,13 +66,13 @@
 	files android.Paths
 }
 
-func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+func overlayResourceGlob(ctx android.ModuleContext, a *aapt, dir android.Path) (res []globbedResourceDir,
 	rroDirs []rroDir) {
 
 	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
 
 	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
-	rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
+	rroEnabled := a.IsRROEnforced(ctx)
 
 	for _, data := range overlayData {
 		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
diff --git a/java/androidmk.go b/java/androidmk.go
index 65c44a3..c21c83a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -23,8 +23,7 @@
 
 func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
 	hostDexNeeded := Bool(library.deviceProperties.Hostdex) && !library.Host()
-	if !library.IsForPlatform() {
-		// Don't emit hostdex modules from the APEX variants
+	if library.hideApexVariantFromMake {
 		hostDexNeeded = false
 	}
 
@@ -61,22 +60,15 @@
 func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
 	var entriesList []android.AndroidMkEntries
 
-	mainEntries := android.AndroidMkEntries{Disabled: true}
-
-	// For a java library built for an APEX, we don't need Make module
-	hideFromMake := !library.IsForPlatform()
-	// If not available for platform, don't emit to make.
-	if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
-		hideFromMake = true
-	}
-	if hideFromMake {
-		// May still need to add some additional dependencies. This will be called
-		// once for the platform variant (even if it is not being used) and once each
-		// for the APEX specific variants. In order to avoid adding the dependency
-		// multiple times only add it for the platform variant.
+	if library.hideApexVariantFromMake {
+		// For a java library built for an APEX we don't need Make module
+		entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
+	} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
+		// Platform variant.  If not available for the platform, we don't need Make module.
+		// May still need to add some additional dependencies.
 		checkedModulePaths := library.additionalCheckedModules
-		if library.IsForPlatform() && len(checkedModulePaths) != 0 {
-			mainEntries = android.AndroidMkEntries{
+		if len(checkedModulePaths) != 0 {
+			entriesList = append(entriesList, android.AndroidMkEntries{
 				Class: "FAKE",
 				// Need at least one output file in order for this to take effect.
 				OutputFile: android.OptionalPathForPath(checkedModulePaths[0]),
@@ -86,10 +78,12 @@
 						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...)
 					},
 				},
-			}
+			})
+		} else {
+			entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
 		}
 	} else {
-		mainEntries = android.AndroidMkEntries{
+		entriesList = append(entriesList, android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
 			DistFiles:  library.distFiles,
 			OutputFile: android.OptionalPathForPath(library.outputFile),
@@ -134,12 +128,11 @@
 					entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports)
 				},
 			},
-		}
+		})
 	}
 
-	hostDexEntries := library.AndroidMkEntriesHostDex()
+	entriesList = append(entriesList, library.AndroidMkEntriesHostDex())
 
-	entriesList = append(entriesList, mainEntries, hostDexEntries)
 	return entriesList
 }
 
@@ -189,7 +182,7 @@
 }
 
 func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
-	if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().Unversioned() {
+	if prebuilt.hideApexVariantFromMake || !prebuilt.ContainingSdk().Unversioned() {
 		return []android.AndroidMkEntries{android.AndroidMkEntries{
 			Disabled: true,
 		}}
@@ -211,7 +204,7 @@
 }
 
 func (prebuilt *DexImport) AndroidMkEntries() []android.AndroidMkEntries {
-	if !prebuilt.IsForPlatform() {
+	if prebuilt.hideApexVariantFromMake {
 		return []android.AndroidMkEntries{android.AndroidMkEntries{
 			Disabled: true,
 		}}
@@ -239,7 +232,7 @@
 }
 
 func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries {
-	if !prebuilt.IsForPlatform() {
+	if prebuilt.hideApexVariantFromMake {
 		return []android.AndroidMkEntries{{
 			Disabled: true,
 		}}
@@ -309,7 +302,7 @@
 }
 
 func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
-	if !app.IsForPlatform() || app.appProperties.HideFromMake {
+	if app.hideApexVariantFromMake || app.appProperties.HideFromMake {
 		return []android.AndroidMkEntries{android.AndroidMkEntries{
 			Disabled: true,
 		}}
@@ -458,7 +451,7 @@
 }
 
 func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries {
-	if !a.IsForPlatform() {
+	if a.hideApexVariantFromMake {
 		return []android.AndroidMkEntries{{
 			Disabled: true,
 		}}
@@ -556,9 +549,6 @@
 				if dstubs.annotationsZip != nil {
 					entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.annotationsZip)
 				}
-				if dstubs.jdiffDocZip != nil {
-					entries.SetPath("LOCAL_DROIDDOC_JDIFF_DOC_ZIP", dstubs.jdiffDocZip)
-				}
 				if dstubs.metadataZip != nil {
 					entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.metadataZip)
 				}
@@ -638,7 +628,7 @@
 }
 
 func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries {
-	if !a.IsForPlatform() {
+	if a.hideApexVariantFromMake {
 		// The non-platform variant is placed inside APEX. No reason to
 		// make it available to Make.
 		return nil
diff --git a/java/app.go b/java/app.go
index 13d08b9..46ca969 100755
--- a/java/app.go
+++ b/java/app.go
@@ -379,7 +379,6 @@
 			"can only be set for modules that set sdk_version")
 	}
 
-	tag := &jniDependencyTag{}
 	for _, jniTarget := range ctx.MultiTargets() {
 		variation := append(jniTarget.Variations(),
 			blueprint.Variation{Mutator: "link", Variation: "shared"})
@@ -393,7 +392,7 @@
 			Bool(a.appProperties.Jni_uses_sdk_apis) {
 			variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
 		}
-		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+		ctx.AddFarVariationDependencies(variation, jniLibTag, a.appProperties.Jni_libs...)
 	}
 
 	a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
@@ -480,8 +479,9 @@
 		ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
 	}
 
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	return (minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
-		!a.IsForPlatform()
+		!apexInfo.IsForPlatform()
 }
 
 // Returns whether this module should have the dex file stored uncompressed in the APK.
@@ -504,8 +504,9 @@
 }
 
 func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
-		!a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
+		!apexInfo.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
 }
 
 func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string {
@@ -641,7 +642,7 @@
 					// Work with the team to come up with a new format that handles multilib modules properly
 					// and change this.
 					if len(ctx.Config().Targets[android.Android]) == 1 ||
-						ctx.Config().Targets[android.Android][0].Arch.ArchType == jni.target.Arch.ArchType {
+						ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType == jni.target.Arch.ArchType {
 						a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
 					}
 				}
@@ -756,6 +757,10 @@
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
 	var apkDeps android.Paths
 
+	if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
+		a.hideApexVariantFromMake = true
+	}
+
 	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
 	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 
@@ -850,8 +855,10 @@
 	BuildBundleModule(ctx, bundleFile, a.exportPackage, jniJarFile, dexJarFile)
 	a.bundleFile = bundleFile
 
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+
 	// Install the app package.
-	if (Bool(a.Module.properties.Installable) || ctx.Host()) && a.IsForPlatform() {
+	if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() {
 		ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile)
 		for _, extra := range a.extraOutputFiles {
 			ctx.InstallFile(a.installDir, extra.Base(), extra)
@@ -979,7 +986,7 @@
 }
 
 func (a *AndroidApp) Updatable() bool {
-	return Bool(a.appProperties.Updatable) || a.ApexModuleBase.Updatable()
+	return Bool(a.appProperties.Updatable)
 }
 
 func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
@@ -1335,6 +1342,8 @@
 	preprocessed bool
 
 	installPath android.InstallPath
+
+	hideApexVariantFromMake bool
 }
 
 type AndroidAppImportProperties struct {
@@ -1392,7 +1401,7 @@
 	}
 
 	archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
-	archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
+	archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
 	MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
 }
 
@@ -1481,6 +1490,11 @@
 }
 
 func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if !apexInfo.IsForPlatform() {
+		a.hideApexVariantFromMake = true
+	}
+
 	numCertPropsSet := 0
 	if String(a.properties.Certificate) != "" {
 		numCertPropsSet++
@@ -1569,7 +1583,7 @@
 
 	// TODO: Optionally compress the output apk.
 
-	if a.IsForPlatform() {
+	if apexInfo.IsForPlatform() {
 		a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
 	}
 
diff --git a/java/app_test.go b/java/app_test.go
index 4347db8..49ed3aa 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -848,19 +848,17 @@
 				"lib": {
 					buildDir + "/.intermediates/lib2/android_common/package-res.apk",
 					"lib/res/res/values/strings.xml",
-					"device/vendor/blah/overlay/lib/res/values/strings.xml",
 				},
 			},
 
 			rroDirs: map[string][]string{
 				"foo": {
 					"device:device/vendor/blah/overlay/foo/res",
-					// Enforce RRO on "foo" could imply RRO on static dependencies, but for now it doesn't.
-					// "device/vendor/blah/overlay/lib/res",
 					"product:product/vendor/blah/overlay/foo/res",
+					"device:device/vendor/blah/overlay/lib/res",
 				},
 				"bar": nil,
-				"lib": nil,
+				"lib": {"device:device/vendor/blah/overlay/lib/res"},
 			},
 		},
 		{
@@ -2754,19 +2752,6 @@
 		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"],
@@ -2797,7 +2782,6 @@
 	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.
@@ -2828,7 +2812,7 @@
 		t.Errorf("wanted %q in %q", w, cmd)
 	}
 
-	// Test that all present libraries are preopted, including implicit SDK dependencies
+	// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
 	cmd = app.Rule("dexpreopt").RuleParams.Command
 	w := `--target-classpath-for-sdk any` +
 		` /system/framework/foo.jar` +
@@ -2840,11 +2824,6 @@
 		t.Errorf("wanted %q in %q", w, cmd)
 	}
 
-	// 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)
@@ -3401,3 +3380,114 @@
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag)
 	}
 }
+
+func TestEnforceRRO_propagatesToDependencies(t *testing.T) {
+	testCases := []struct {
+		name                    string
+		enforceRROTargets       []string
+		enforceRROExemptTargets []string
+		rroDirs                 map[string][]string
+	}{
+		{
+			name:                    "no RRO",
+			enforceRROTargets:       nil,
+			enforceRROExemptTargets: nil,
+			rroDirs: map[string][]string{
+				"foo": nil,
+				"bar": nil,
+			},
+		},
+		{
+			name:                    "enforce RRO on all",
+			enforceRROTargets:       []string{"*"},
+			enforceRROExemptTargets: nil,
+			rroDirs: map[string][]string{
+				"foo": {"product/vendor/blah/overlay/lib2/res"},
+				"bar": {"product/vendor/blah/overlay/lib2/res"},
+			},
+		},
+		{
+			name:                    "enforce RRO on foo",
+			enforceRROTargets:       []string{"foo"},
+			enforceRROExemptTargets: nil,
+			rroDirs: map[string][]string{
+				"foo": {"product/vendor/blah/overlay/lib2/res"},
+				"bar": {"product/vendor/blah/overlay/lib2/res"},
+			},
+		},
+		{
+			name:                    "enforce RRO on foo, bar exempted",
+			enforceRROTargets:       []string{"foo"},
+			enforceRROExemptTargets: []string{"bar"},
+			rroDirs: map[string][]string{
+				"foo": {"product/vendor/blah/overlay/lib2/res"},
+				"bar": nil,
+			},
+		},
+	}
+
+	productResourceOverlays := []string{
+		"product/vendor/blah/overlay",
+	}
+
+	fs := map[string][]byte{
+		"lib2/res/values/strings.xml":                             nil,
+		"product/vendor/blah/overlay/lib2/res/values/strings.xml": nil,
+	}
+
+	bp := `
+			android_app {
+				name: "foo",
+				sdk_version: "current",
+				resource_dirs: [],
+				static_libs: ["lib"],
+			}
+
+			android_app {
+				name: "bar",
+				sdk_version: "current",
+				resource_dirs: [],
+				static_libs: ["lib"],
+			}
+
+			android_library {
+				name: "lib",
+				sdk_version: "current",
+				resource_dirs: [],
+				static_libs: ["lib2"],
+			}
+
+			android_library {
+				name: "lib2",
+				sdk_version: "current",
+				resource_dirs: ["lib2/res"],
+			}
+		`
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			config := testAppConfig(nil, bp, fs)
+			config.TestProductVariables.ProductResourceOverlays = productResourceOverlays
+			if testCase.enforceRROTargets != nil {
+				config.TestProductVariables.EnforceRROTargets = testCase.enforceRROTargets
+			}
+			if testCase.enforceRROExemptTargets != nil {
+				config.TestProductVariables.EnforceRROExemptedTargets = testCase.enforceRROExemptTargets
+			}
+
+			ctx := testContext()
+			run(t, ctx, config)
+
+			modules := []string{"foo", "bar"}
+			for _, moduleName := range modules {
+				module := ctx.ModuleForTests(moduleName, "android_common")
+				mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0]
+				actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"]
+				if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) {
+					t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q",
+						moduleName, testCase.rroDirs[moduleName], actualRRODirs)
+				}
+			}
+		})
+	}
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index f1b7178..20dbc66 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -94,7 +94,7 @@
 	}
 
 	// Don't preopt APEX variant module
-	if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() {
+	if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
 		return true
 	}
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 3addc1a..9f49786 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -238,6 +238,13 @@
 	dumpOatRules(ctx, d.defaultBootImage)
 }
 
+func isHostdex(module android.Module) bool {
+	if lib, ok := module.(*Library); ok {
+		return Bool(lib.deviceProperties.Hostdex)
+	}
+	return false
+}
+
 // 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.
@@ -259,12 +266,13 @@
 	}
 
 	// Check that this module satisfies constraints for a particular boot image.
-	apex, isApexModule := module.(android.ApexModule)
-	fromUpdatableApex := isApexModule && apex.Updatable()
+	_, isApexModule := module.(android.ApexModule)
+	apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+	fromUpdatableApex := isApexModule && apexInfo.Updatable
 	if image.name == artBootImageName {
-		if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") {
+		if isApexModule && len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art.") {
 			// ok: found the jar in the ART apex
-		} else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
+		} else if isApexModule && apexInfo.IsForPlatform() && isHostdex(module) {
 			// exception (skip and continue): special "hostdex" platform variant
 			return -1, nil
 		} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
@@ -272,7 +280,7 @@
 			return -1, nil
 		} else if fromUpdatableApex {
 			// error: this jar is part of an updatable apex other than ART
-			ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apex.InApexes())
+			ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apexInfo.InApexes)
 		} else {
 			// error: this jar is part of the platform or a non-updatable apex
 			ctx.Errorf("module %q is not allowed in the ART boot image", name)
@@ -282,7 +290,7 @@
 			// ok: this jar is part of the platform or a non-updatable apex
 		} else {
 			// error: this jar is part of an updatable apex
-			ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apex.InApexes())
+			ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apexInfo.InApexes)
 		}
 	} else {
 		panic("unknown boot image: " + image.name)
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 33f422d..344b15e 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -274,10 +274,6 @@
 	// 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
-
-	// If set to true, .xml based public API file will be also generated, and
-	// JDiff tool will be invoked to genreate javadoc files. Defaults to false.
-	Jdiff_enabled *bool
 }
 
 //
@@ -586,9 +582,8 @@
 	srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages)
 
 	// While metalava needs package html files, it does not need them to be explicit on the command
-	// line. More importantly, the metalava rsp file is also used by the subsequent jdiff action if
-	// jdiff_enabled=true. javadoc complains if it receives html files on the command line. The filter
-	// below excludes html files from the rsp file for both metalava and jdiff. Note that the html
+	// line. javadoc complains if it receives html files on the command line. The filter
+	// below excludes html files from the rsp file metalava. Note that the html
 	// files are still included as implicit inputs for successful remote execution and correct
 	// incremental builds.
 	filterHtml := func(srcs []android.Path) []android.Path {
@@ -1021,10 +1016,8 @@
 	annotationsZip android.WritablePath
 	apiVersionsXml android.WritablePath
 
-	apiFilePath android.Path
-
-	jdiffDocZip      android.WritablePath
-	jdiffStubsSrcJar android.WritablePath
+	apiFilePath        android.Path
+	removedApiFilePath android.Path
 
 	metadataZip android.WritablePath
 	metadataDir android.WritablePath
@@ -1064,6 +1057,10 @@
 		return android.Paths{d.stubsSrcJar}, nil
 	case ".docs.zip":
 		return android.Paths{d.docZip}, nil
+	case ".api.txt":
+		return android.Paths{d.apiFilePath}, nil
+	case ".removed-api.txt":
+		return android.Paths{d.removedApiFilePath}, nil
 	case ".annotations.zip":
 		return android.Paths{d.annotationsZip}, nil
 	case ".api_versions.xml":
@@ -1078,7 +1075,7 @@
 }
 
 func (d *Droidstubs) RemovedApiFilePath() android.Path {
-	return d.removedApiFile
+	return d.removedApiFilePath
 }
 
 func (d *Droidstubs) StubsSrcJar() android.Path {
@@ -1129,6 +1126,9 @@
 		d.apiFile = android.PathForModuleOut(ctx, filename)
 		cmd.FlagWithOutput("--api ", d.apiFile)
 		d.apiFilePath = d.apiFile
+	} else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
+		// If check api is disabled then make the source file available for export.
+		d.apiFilePath = android.PathForModuleSrc(ctx, sourceApiFile)
 	}
 
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
@@ -1137,6 +1137,10 @@
 		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
 		d.removedApiFile = android.PathForModuleOut(ctx, filename)
 		cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
+		d.removedApiFilePath = d.removedApiFile
+	} else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
+		// If check api is disabled then make the source removed api file available for export.
+		d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
 	}
 
 	if String(d.properties.Removed_dex_api_filename) != "" {
@@ -1254,26 +1258,6 @@
 	})
 }
 
-func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
-	if Bool(d.properties.Jdiff_enabled) && d.apiFile != nil {
-		if d.apiFile.String() == "" {
-			ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
-		}
-
-		d.apiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.xml")
-		cmd.FlagWithOutput("--api-xml ", d.apiXmlFile)
-
-		if String(d.properties.Check_api.Last_released.Api_file) == "" {
-			ctx.PropertyErrorf("check_api.last_released.api_file",
-				"has to be non-empty if jdiff was enabled!")
-		}
-
-		lastReleasedApi := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
-		d.lastReleasedApiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_last_released_api.xml")
-		cmd.FlagWithInput("--convert-to-jdiff ", lastReleasedApi).Output(d.lastReleasedApiXmlFile)
-	}
-}
-
 func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
 	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicitsRsp android.WritablePath, sandbox bool) *android.RuleBuilderCommand {
 	// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
@@ -1382,7 +1366,6 @@
 	d.annotationsFlags(ctx, cmd)
 	d.inclusionAnnotationsFlags(ctx, cmd)
 	d.apiLevelsAnnotationsFlags(ctx, cmd)
-	d.apiToXmlFlags(ctx, cmd)
 
 	if android.InList("--generate-documentation", d.Javadoc.args) {
 		// Currently Metalava have the ability to invoke Javadoc in a seperate process.
@@ -1659,74 +1642,6 @@
 
 		rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check")
 	}
-
-	if Bool(d.properties.Jdiff_enabled) {
-		if len(d.Javadoc.properties.Out) > 0 {
-			ctx.PropertyErrorf("out", "out property may not be combined with jdiff")
-		}
-
-		outDir := android.PathForModuleOut(ctx, "jdiff-out")
-		srcJarDir := android.PathForModuleOut(ctx, "jdiff-srcjars")
-		stubsDir := android.PathForModuleOut(ctx, "jdiff-stubsDir")
-
-		rule := android.NewRuleBuilder()
-
-		// Please sync with android-api-council@ before making any changes for the name of jdiffDocZip below
-		// since there's cron job downstream that fetch this .zip file periodically.
-		// See b/116221385 for reference.
-		d.jdiffDocZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-docs.zip")
-		d.jdiffStubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-stubs.srcjar")
-
-		jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar")
-
-		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)
-
-		cmd := javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList,
-			deps.bootClasspath, deps.classpath, d.sourcepaths)
-
-		cmd.Flag("-J-Xmx1600m").
-			Flag("-XDignore.symbol.file").
-			FlagWithArg("-doclet ", "jdiff.JDiff").
-			FlagWithInput("-docletpath ", jdiff).
-			Flag("-quiet")
-
-		if d.apiXmlFile != nil {
-			cmd.FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
-				FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
-				Implicit(d.apiXmlFile)
-		}
-
-		if d.lastReleasedApiXmlFile != nil {
-			cmd.FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
-				FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
-				Implicit(d.lastReleasedApiXmlFile)
-		}
-
-		rule.Command().
-			BuiltTool(ctx, "soong_zip").
-			Flag("-write_if_changed").
-			Flag("-d").
-			FlagWithOutput("-o ", d.jdiffDocZip).
-			FlagWithArg("-C ", outDir.String()).
-			FlagWithArg("-D ", outDir.String())
-
-		rule.Command().
-			BuiltTool(ctx, "soong_zip").
-			Flag("-write_if_changed").
-			Flag("-jar").
-			FlagWithOutput("-o ", d.jdiffStubsSrcJar).
-			FlagWithArg("-C ", stubsDir.String()).
-			FlagWithArg("-D ", stubsDir.String())
-
-		rule.Restat()
-
-		zipSyncCleanupCmd(rule, srcJarDir)
-
-		rule.Build(pctx, ctx, "jdiff", "jdiff")
-	}
 }
 
 //
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 61a9b97..9d07e41 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -18,6 +18,7 @@
 	"fmt"
 
 	"android/soong/android"
+	"android/soong/genrule"
 )
 
 func init() {
@@ -161,10 +162,9 @@
 				// For a java lib included in an APEX, only take the one built for
 				// the platform variant, and skip the variants for APEXes.
 				// Otherwise, the hiddenapi tool will complain about duplicated classes
-				if a, ok := module.(android.ApexModule); ok {
-					if android.InAnyApex(module.Name()) && !a.IsForPlatform() {
-						return
-					}
+				apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+				if !apexInfo.IsForPlatform() {
+					return
 				}
 
 				bootDexJars = append(bootDexJars, jar)
@@ -224,30 +224,26 @@
 // the unsupported API.
 func flagsRule(ctx android.SingletonContext) android.Path {
 	var flagsCSV android.Paths
-	var greylistRemovedApis android.Paths
+	var combinedRemovedApis android.Path
 
 	ctx.VisitAllModules(func(module android.Module) {
 		if h, ok := module.(hiddenAPIIntf); ok {
 			if csv := h.flagsCSV(); csv != nil {
 				flagsCSV = append(flagsCSV, csv)
 			}
-		} else if ds, ok := module.(*Droidstubs); ok {
-			// 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 moduleForGreyListRemovedApis(ctx, module) {
-				greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile)
+		} else if g, ok := module.(*genrule.Module); ok {
+			if ctx.ModuleName(module) == "combined-removed-dex" {
+				if len(g.GeneratedSourceFiles()) != 1 || combinedRemovedApis != nil {
+					ctx.Errorf("Expected 1 combined-removed-dex module that generates 1 output file.")
+				}
+				combinedRemovedApis = g.GeneratedSourceFiles()[0]
 			}
 		}
 	})
 
-	combinedRemovedApis := android.PathForOutput(ctx, "hiddenapi", "combined-removed-dex.txt")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cat,
-		Inputs:      greylistRemovedApis,
-		Output:      combinedRemovedApis,
-		Description: "Combine removed apis for " + combinedRemovedApis.String(),
-	})
+	if combinedRemovedApis == nil {
+		ctx.Errorf("Failed to find combined-removed-dex.")
+	}
 
 	rule := android.NewRuleBuilder()
 
diff --git a/java/java.go b/java/java.go
index 1d7eaa7..a973bab 100644
--- a/java/java.go
+++ b/java/java.go
@@ -451,6 +451,8 @@
 
 	// Collect the module directory for IDE info in java/jdeps.go.
 	modulePaths []string
+
+	hideApexVariantFromMake bool
 }
 
 func (j *Module) addHostProperties() {
@@ -545,13 +547,8 @@
 	name string
 }
 
-type jniDependencyTag struct {
-	blueprint.BaseDependencyTag
-}
-
 func IsJniDepTag(depTag blueprint.DependencyTag) bool {
-	_, ok := depTag.(*jniDependencyTag)
-	return ok
+	return depTag == jniLibTag
 }
 
 var (
@@ -571,6 +568,7 @@
 	instrumentationForTag = dependencyTag{name: "instrumentation_for"}
 	usesLibTag            = dependencyTag{name: "uses-library"}
 	extraLintCheckTag     = dependencyTag{name: "extra-lint-check"}
+	jniLibTag             = dependencyTag{name: "jnilib"}
 )
 
 func IsLibDepTag(depTag blueprint.DependencyTag) bool {
@@ -638,8 +636,9 @@
 	// Force enable the instrumentation for java code that is built for APEXes ...
 	// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
 	// doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
-	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+	if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
 		if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
 			return true
 		} else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
@@ -735,9 +734,21 @@
 		return ret
 	}
 
-	ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...)
+	libDeps := ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...)
 	ctx.AddVariationDependencies(nil, staticLibTag, rewriteSyspropLibs(j.properties.Static_libs, "static_libs")...)
 
+	// For library dependencies that are component libraries (like stubs), add the implementation
+	// as a dependency (dexpreopt needs to be against the implementation library, not stubs).
+	for _, dep := range libDeps {
+		if dep != nil {
+			if component, ok := dep.(SdkLibraryComponentDependency); ok {
+				if lib := component.OptionalSdkLibraryImplementation(); lib != nil {
+					ctx.AddVariationDependencies(nil, usesLibTag, *lib)
+				}
+			}
+		}
+	}
+
 	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
 	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...)
 
@@ -986,7 +997,7 @@
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
 
-		if _, ok := tag.(*jniDependencyTag); ok {
+		if IsJniDepTag(tag) {
 			// Handled by AndroidApp.collectAppDeps
 			return
 		}
@@ -1590,7 +1601,8 @@
 	j.implementationAndResourcesJar = implementationAndResourcesJar
 
 	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
-	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() {
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
 		if j.dexProperties.Compile_dex == nil {
 			j.dexProperties.Compile_dex = proptools.BoolPtr(true)
 		}
@@ -1672,7 +1684,7 @@
 		j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion())
 		j.linter.javaLanguageLevel = flags.javaVersion.String()
 		j.linter.kotlinLanguageLevel = "1.3"
-		if j.ApexVariationName() != "" && ctx.Config().UnbundledBuildApps() {
+		if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
 			j.linter.buildModuleReportZip = true
 		}
 		j.linter.lint(ctx)
@@ -1934,7 +1946,7 @@
 
 func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
 	// Store uncompressed (and aligned) any dex files from jars in APEXes.
-	if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() {
+	if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
 		return true
 	}
 
@@ -1956,6 +1968,11 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if !apexInfo.IsForPlatform() {
+		j.hideApexVariantFromMake = true
+	}
+
 	j.checkSdkVersions(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
@@ -1970,7 +1987,7 @@
 	// Collect the module directory for IDE info in java/jdeps.go.
 	j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
 
-	exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform()
+	exclusivelyForApex := !apexInfo.IsForPlatform()
 	if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
 		var extraInstallDeps android.Paths
 		if j.InstallMixin != nil {
@@ -2415,6 +2432,10 @@
 
 	// Name of the class containing main to be inserted into the manifest as Main-Class.
 	Main_class *string
+
+	// Names of modules containing JNI libraries that should be installed alongside the host
+	// variant of the binary.
+	Jni_libs []string
 }
 
 type Binary struct {
@@ -2455,18 +2476,21 @@
 			j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
 		}
 
-		// Depend on the installed jar so that the wrapper doesn't get executed by
-		// another build rule before the jar has been installed.
-		jarFile := ctx.PrimaryModule().(*Binary).installFile
-
+		// The host installation rules make the installed wrapper depend on all the dependencies
+		// of the wrapper variant, which will include the common variant's jar file and any JNI
+		// libraries.  This is verified by TestBinary.
 		j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
-			ctx.ModuleName(), j.wrapperFile, jarFile)
+			ctx.ModuleName(), j.wrapperFile)
 	}
 }
 
 func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	if ctx.Arch().ArchType == android.Common {
 		j.deps(ctx)
+	} else {
+		// This dependency ensures the host installation rules will install the jni libraries
+		// when the wrapper is installed.
+		ctx.AddVariationDependencies(nil, jniLibTag, j.binaryProperties.Jni_libs...)
 	}
 }
 
@@ -2562,6 +2586,8 @@
 	combinedClasspathFile android.Path
 	exportedSdkLibs       dexpreopt.LibraryPaths
 	exportAidlIncludeDirs android.Paths
+
+	hideApexVariantFromMake bool
 }
 
 func (j *Import) sdkVersion() sdkSpec {
@@ -2617,6 +2643,10 @@
 }
 
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
+		j.hideApexVariantFromMake = true
+	}
+
 	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
 
 	jarName := j.Stem() + ".jar"
@@ -2699,6 +2729,17 @@
 	}
 }
 
+func (j *Import) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "", ".jar":
+		return android.Paths{j.combinedClasspathFile}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
+var _ android.OutputFileProducer = (*Import)(nil)
+
 var _ Dependency = (*Import)(nil)
 
 func (j *Import) HeaderJars() android.Paths {
@@ -2849,6 +2890,8 @@
 	maybeStrippedDexJarFile android.Path
 
 	dexpreopter
+
+	hideApexVariantFromMake bool
 }
 
 func (j *DexImport) Prebuilt() *android.Prebuilt {
@@ -2884,6 +2927,11 @@
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
 	}
 
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if !apexInfo.IsForPlatform() {
+		j.hideApexVariantFromMake = true
+	}
+
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
 
@@ -2928,7 +2976,7 @@
 
 	j.maybeStrippedDexJarFile = dexOutputFile
 
-	if j.IsForPlatform() {
+	if apexInfo.IsForPlatform() {
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			j.Stem()+".jar", dexOutputFile)
 	}
diff --git a/java/java_test.go b/java/java_test.go
index f16639a..c751ea4 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -102,6 +102,10 @@
 
 	dexpreopt.RegisterToolModulesForTest(ctx)
 
+	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel()
+	})
+
 	return ctx
 }
 
@@ -456,6 +460,14 @@
 			name: "bar",
 			srcs: ["b.java"],
 			static_libs: ["foo"],
+			jni_libs: ["libjni"],
+		}
+
+		cc_library_shared {
+			name: "libjni",
+			host_supported: true,
+			device_supported: false,
+			stl: "none",
 		}
 	`)
 
@@ -466,10 +478,17 @@
 	barWrapper := ctx.ModuleForTests("bar", buildOS+"_x86_64")
 	barWrapperDeps := barWrapper.Output("bar").Implicits.Strings()
 
+	libjni := ctx.ModuleForTests("libjni", buildOS+"_x86_64_shared")
+	libjniSO := libjni.Rule("Cp").Output.String()
+
 	// Test that the install binary wrapper depends on the installed jar file
-	if len(barWrapperDeps) != 1 || barWrapperDeps[0] != barJar {
-		t.Errorf("expected binary wrapper implicits [%q], got %v",
-			barJar, barWrapperDeps)
+	if g, w := barWrapperDeps, barJar; !android.InList(w, g) {
+		t.Errorf("expected binary wrapper implicits to contain %q, got %q", w, g)
+	}
+
+	// Test that the install binary wrapper depends on the installed JNI libraries
+	if g, w := barWrapperDeps, libjniSO; !android.InList(w, g) {
+		t.Errorf("expected binary wrapper implicits to contain %q, got %q", w, g)
 	}
 }
 
@@ -1412,7 +1431,31 @@
 						name: "core",
 						sdk_version: "none",
 						system_modules: "none",
-				}`),
+				}
+
+				filegroup {
+					name: "core-jar",
+					srcs: [":core{.jar}"],
+				}
+`),
+	})
+	ctx := testContext()
+	run(t, ctx, config)
+}
+
+func TestJavaImport(t *testing.T) {
+	config := testConfig(nil, "", map[string][]byte{
+		"libcore/Android.bp": []byte(`
+				java_import {
+						name: "core",
+						sdk_version: "none",
+				}
+
+				filegroup {
+					name: "core-jar",
+					srcs: [":core{.jar}"],
+				}
+`),
 	})
 	ctx := testContext()
 	run(t, ctx, config)
@@ -1556,6 +1599,39 @@
 	}
 }
 
+func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_sdk_library {
+			name: "sdk_lib",
+			srcs: ["a.java"],
+			impl_only_libs: ["foo"],
+			stub_only_libs: ["bar"],
+		}
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+		java_library {
+			name: "bar",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+		`)
+
+	for _, implName := range []string{"sdk_lib", "sdk_lib.impl"} {
+		implJavacCp := ctx.ModuleForTests(implName, "android_common").Rule("javac").Args["classpath"]
+		if !strings.Contains(implJavacCp, "/foo.jar") || strings.Contains(implJavacCp, "/bar.jar") {
+			t.Errorf("%v javac classpath %v does not contain foo and not bar", implName, implJavacCp)
+		}
+	}
+	stubName := apiScopePublic.stubsLibraryModuleName("sdk_lib")
+	stubsJavacCp := ctx.ModuleForTests(stubName, "android_common").Rule("javac").Args["classpath"]
+	if strings.Contains(stubsJavacCp, "/foo.jar") || !strings.Contains(stubsJavacCp, "/bar.jar") {
+		t.Errorf("stubs javac classpath %v does not contain bar and not foo", stubsJavacCp)
+	}
+}
+
 func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_sdk_library {
diff --git a/java/lint.go b/java/lint.go
index 3a210cc..3df582f 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -451,10 +451,13 @@
 			return
 		}
 
-		if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() && apex.IsForPlatform() {
-			// There are stray platform variants of modules in apexes that are not available for
-			// the platform, and they sometimes can't be built.  Don't depend on them.
-			return
+		if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
+			apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+			if apexInfo.IsForPlatform() {
+				// There are stray platform variants of modules in apexes that are not available for
+				// the platform, and they sometimes can't be built.  Don't depend on them.
+				return
+			}
 		}
 
 		if l, ok := m.(lintOutputsIntf); ok {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 60924a6..d6ef4e9 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -257,7 +257,7 @@
 	})
 	apiScopeTest = initApiScope(&apiScope{
 		name:                "test",
-		extends:             apiScopePublic,
+		extends:             apiScopeSystem,
 		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
 		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
 			return &module.sdkLibraryProperties.Test
@@ -388,6 +388,9 @@
 	// visibility property.
 	Stubs_source_visibility []string
 
+	// List of Java libraries that will be in the classpath when building the implementation lib
+	Impl_only_libs []string `android:"arch_variant"`
+
 	// List of Java libraries that will be in the classpath when building stubs
 	Stub_only_libs []string `android:"arch_variant"`
 
@@ -870,6 +873,12 @@
 	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
 }
 
+// to satisfy SdkLibraryComponentDependency
+func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string {
+	// Currently implementation library name is the same as the SDK library name.
+	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
+}
+
 // Implemented by modules that are (or possibly could be) a component of a java_sdk_library
 // (including the java_sdk_library) itself.
 type SdkLibraryComponentDependency interface {
@@ -880,6 +889,9 @@
 	//
 	// Returns the name of the optional implicit SDK library or nil, if there isn't one.
 	OptionalImplicitSdkLibrary() *string
+
+	// The name of the implementation library for the optional SDK library or nil, if there isn't one.
+	OptionalSdkLibraryImplementation() *string
 }
 
 // Make sure that all the module types that are components of java_sdk_library/_import
@@ -1128,12 +1140,16 @@
 		Name              *string
 		Visibility        []string
 		Instrument        bool
+		Libs              []string
 		ConfigurationName *string
 	}{
 		Name:       proptools.StringPtr(module.implLibraryModuleName()),
 		Visibility: visibility,
 		// Set the instrument property to ensure it is instrumented when instrumentation is required.
 		Instrument: true,
+		// Set the impl_only libs. Note that the module's "Libs" get appended as well, via the
+		// addition of &module.properties below.
+		Libs: module.sdkLibraryProperties.Impl_only_libs,
 
 		// Make the created library behave as if it had the same name as this module.
 		ConfigurationName: moduleNamePtr,
@@ -1410,22 +1426,14 @@
 	return android.Paths{jarPath.Path()}
 }
 
-// Get the apex names for module, nil if it is for platform.
-func getApexNamesForModule(module android.Module) []string {
-	if apex, ok := module.(android.ApexModule); ok {
-		return apex.InApexes()
-	}
-
-	return nil
-}
-
 // Check to see if the other module is within the same set of named APEXes as this module.
 //
 // If either this or the other module are on the platform then this will return
 // false.
-func withinSameApexesAs(module android.ApexModule, other android.Module) bool {
-	names := module.InApexes()
-	return len(names) > 0 && reflect.DeepEqual(names, getApexNamesForModule(other))
+func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
+	return len(otherApexInfo.InApexes) > 0 && reflect.DeepEqual(apexInfo.InApexes, otherApexInfo.InApexes)
 }
 
 func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
@@ -1444,7 +1452,7 @@
 		// Only allow access to the implementation library in the following condition:
 		// * No sdk_version specified on the referencing module.
 		// * The referencing module is in the same apex as this.
-		if sdkVersion.kind == sdkPrivate || withinSameApexesAs(module, ctx.Module()) {
+		if sdkVersion.kind == sdkPrivate || withinSameApexesAs(ctx, module) {
 			if headerJars {
 				return module.HeaderJars()
 			} else {
@@ -1564,6 +1572,9 @@
 		defer javaSdkLibrariesLock.Unlock()
 		*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
 	}
+
+	// Add the impl_only_libs *after* we're done using the Libs prop in submodules.
+	module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...)
 }
 
 func (module *SdkLibrary) InitSdkLibraryProperties() {
@@ -1961,7 +1972,7 @@
 	// For consistency with SdkLibrary make the implementation jar available to libraries that
 	// are within the same APEX.
 	implLibraryModule := module.implLibraryModule
-	if implLibraryModule != nil && withinSameApexesAs(module, ctx.Module()) {
+	if implLibraryModule != nil && withinSameApexesAs(ctx, module) {
 		if headerJars {
 			return implLibraryModule.HeaderJars()
 		} else {
@@ -2057,6 +2068,8 @@
 
 	outputFilePath android.OutputPath
 	installDirPath android.InstallPath
+
+	hideApexVariantFromMake bool
 }
 
 type sdkLibraryXmlProperties struct {
@@ -2114,13 +2127,13 @@
 }
 
 // File path to the runtime implementation library
-func (module *sdkLibraryXml) implPath() string {
+func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
 	implName := proptools.String(module.properties.Lib_name)
-	if apexName := module.ApexVariationName(); apexName != "" {
+	if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
 		// TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
 		// In most cases, this works fine. But when apex_name is set or override_apex is used
 		// this can be wrong.
-		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName)
+		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.ApexVariationName, implName)
 	}
 	partition := "system"
 	if module.SocSpecific() {
@@ -2136,8 +2149,10 @@
 }
 
 func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+
 	libName := proptools.String(module.properties.Lib_name)
-	xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath())
+	xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath(ctx))
 
 	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
 	rule := android.NewRuleBuilder()
@@ -2151,7 +2166,7 @@
 }
 
 func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
-	if !module.IsForPlatform() {
+	if module.hideApexVariantFromMake {
 		return []android.AndroidMkEntries{android.AndroidMkEntries{
 			Disabled: true,
 		}}
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 5a33f77..29e4bd7 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -156,7 +156,7 @@
 }
 
 func (sourceProvider *BaseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	outFile := sourceProvider.OutputFile
+	outFile := sourceProvider.OutputFiles[0]
 	ret.Class = "ETC"
 	ret.OutputFile = android.OptionalPathForPath(outFile)
 	ret.SubName += sourceProvider.subName
diff --git a/rust/bindgen.go b/rust/bindgen.go
index ac33ff7..68f219e 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -202,7 +202,7 @@
 		},
 	})
 
-	b.BaseSourceProvider.OutputFile = outputFile
+	b.BaseSourceProvider.OutputFiles = android.Paths{outputFile}
 	return outputFile
 }
 
diff --git a/rust/config/OWNERS b/rust/config/OWNERS
new file mode 100644
index 0000000..dfff873
--- /dev/null
+++ b/rust/config/OWNERS
@@ -0,0 +1,2 @@
+per-file global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
+
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 483dddb..b9a879a 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -2,7 +2,7 @@
 
 var (
 	// When adding a new path below, add a rustfmt.toml file at the root of
-	// the repository and enable the rustfmt repo hook. See aosp/1347562
+	// the repository and enable the rustfmt repo hook. See aosp/1458238
 	// for an example.
 	// TODO(b/160223496): enable rustfmt globally.
 	RustAllowedPaths = []string{
@@ -11,8 +11,10 @@
 		"external/crosvm",
 		"external/adhd",
 		"frameworks/native/libs/binder/rust",
+		"packages/modules/Virtualization",
 		"prebuilts/rust",
 		"system/extras/profcollectd",
+		"system/hardware/interfaces/keystore2",
 		"system/security",
 		"system/tools/aidl",
 	}
diff --git a/rust/library.go b/rust/library.go
index 3bba089..ae33f0f 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -20,6 +20,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -484,11 +485,35 @@
 	library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
 
 	if library.rlib() || library.dylib() {
-		library.exportLinkDirs(deps.linkDirs...)
-		library.exportDepFlags(deps.depFlags...)
-		library.exportLinkObjects(deps.linkObjects...)
+		library.flagExporter.exportLinkDirs(deps.linkDirs...)
+		library.flagExporter.exportDepFlags(deps.depFlags...)
+		library.flagExporter.exportLinkObjects(deps.linkObjects...)
 	}
 
+	if library.static() || library.shared() {
+		ctx.SetProvider(cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+			IncludeDirs: library.includeDirs,
+		})
+	}
+
+	if library.shared() {
+		ctx.SetProvider(cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
+			SharedLibrary:           outputFile,
+			UnstrippedSharedLibrary: outputFile,
+		})
+	}
+
+	if library.static() {
+		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(outputFile).Build()
+		ctx.SetProvider(cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
+			StaticLibrary: outputFile,
+
+			TransitiveStaticLibrariesForOrdering: depSet,
+		})
+	}
+
+	library.flagExporter.setProvider(ctx)
+
 	return outputFile
 }
 
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index f9c8934..94fe1e5 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -93,7 +93,8 @@
 }
 
 func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
-	prebuilt.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
+	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
 	if len(paths) > 0 {
diff --git a/rust/project_json.go b/rust/project_json.go
index 8d161b2..5697408 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -93,7 +93,7 @@
 			return "", false
 		}
 	default:
-		if rModule.Target().String() != ctx.Config().Targets[android.Android][0].String() {
+		if rModule.Target().String() != ctx.Config().AndroidFirstDeviceTarget.String() {
 			return "", false
 		}
 	}
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index 11964f3..69288fc 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -22,22 +22,15 @@
 	"testing"
 
 	"android/soong/android"
-	"android/soong/cc"
 )
 
 // testProjectJson run the generation of rust-project.json. It returns the raw
 // content of the generated file.
-func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte {
-	cc.GatherRequiredFilesForTest(fs)
-
-	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
-	config := android.TestArchConfig(buildDir, env, bp, fs)
-	ctx := CreateTestContext()
-	ctx.Register(config)
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
+func testProjectJson(t *testing.T, bp string) []byte {
+	tctx := newTestRustCtx(t, bp)
+	tctx.env = map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
+	tctx.generateConfig()
+	tctx.parse(t)
 
 	// The JSON file is generated via WriteFileToOutputDir. Therefore, it
 	// won't appear in the Output of the TestingSingleton. Manually verify
@@ -87,12 +80,8 @@
 		crate_name: "b",
 		rlibs: ["liba"],
 	}
-	` + GatherRequiredDepsForTest()
-	fs := map[string][]byte{
-		"a/src/lib.rs": nil,
-		"b/src/lib.rs": nil,
-	}
-	jsonContent := testProjectJson(t, bp, fs)
+	`
+	jsonContent := testProjectJson(t, bp)
 	validateJsonCrates(t, jsonContent)
 }
 
@@ -123,11 +112,8 @@
 		source_stem: "bindings2",
 		wrapper_src: "src/any.h",
 	}
-	` + GatherRequiredDepsForTest()
-	fs := map[string][]byte{
-		"src/lib.rs": nil,
-	}
-	jsonContent := testProjectJson(t, bp, fs)
+	`
+	jsonContent := testProjectJson(t, bp)
 	crates := validateJsonCrates(t, jsonContent)
 	for _, c := range crates {
 		crate, ok := c.(map[string]interface{})
@@ -166,13 +152,8 @@
 		crate_name: "b",
 		rustlibs: ["liba1", "liba2"],
 	}
-	` + GatherRequiredDepsForTest()
-	fs := map[string][]byte{
-		"a1/src/lib.rs": nil,
-		"a2/src/lib.rs": nil,
-		"b/src/lib.rs":  nil,
-	}
-	jsonContent := testProjectJson(t, bp, fs)
+	`
+	jsonContent := testProjectJson(t, bp)
 	crates := validateJsonCrates(t, jsonContent)
 	for _, crate := range crates {
 		c := crate.(map[string]interface{})
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 897300f..ebb1c3c 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -61,15 +61,22 @@
 	}
 
 	outDir := android.PathForModuleOut(ctx)
-	depFile := android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".d")
-	outputs := android.WritablePaths{android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".rs")}
+	stem := proto.BaseSourceProvider.getStem(ctx)
+	// rust protobuf-codegen output <stem>.rs
+	stemFile := android.PathForModuleOut(ctx, stem+".rs")
+	// add mod_<stem>.rs to import <stem>.rs
+	modFile := android.PathForModuleOut(ctx, "mod_"+stem+".rs")
+	// mod_<stem>.rs is the main/first output file to be included/compiled
+	outputs := android.WritablePaths{modFile, stemFile}
+	depFile := android.PathForModuleOut(ctx, "mod_"+stem+".d")
 
 	rule := android.NewRuleBuilder()
 	android.ProtoRule(ctx, rule, protoFile.Path(), protoFlags, protoFlags.Deps, outDir, depFile, outputs)
+	rule.Command().Text("printf '// @generated\\npub mod %s;\\n' '" + stem + "' >").Output(modFile)
 	rule.Build(pctx, ctx, "protoc_"+protoFile.Path().Rel(), "protoc "+protoFile.Path().Rel())
 
-	proto.BaseSourceProvider.OutputFile = outputs[0]
-	return outputs[0]
+	proto.BaseSourceProvider.OutputFiles = android.Paths{modFile, stemFile}
+	return modFile
 }
 
 func (proto *protobufDecorator) SourceProviderProps() []interface{} {
diff --git a/rust/rust.go b/rust/rust.go
index f7207aa..1b999d7 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -221,6 +221,10 @@
 	return false
 }
 
+func (mod *Module) SplitPerApiLevel() bool {
+	return false
+}
+
 func (mod *Module) ToolchainLibrary() bool {
 	return false
 }
@@ -298,9 +302,6 @@
 }
 
 type exportedFlagsProducer interface {
-	exportedLinkDirs() []string
-	exportedDepFlags() []string
-	exportedLinkObjects() []string
 	exportLinkDirs(...string)
 	exportDepFlags(...string)
 	exportLinkObjects(...string)
@@ -312,18 +313,6 @@
 	linkObjects []string
 }
 
-func (flagExporter *flagExporter) exportedLinkDirs() []string {
-	return flagExporter.linkDirs
-}
-
-func (flagExporter *flagExporter) exportedDepFlags() []string {
-	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...))
 }
@@ -336,16 +325,28 @@
 	flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
 }
 
+func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
+	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
+		Flags:       flagExporter.depFlags,
+		LinkDirs:    flagExporter.linkDirs,
+		LinkObjects: flagExporter.linkObjects,
+	})
+}
+
 var _ exportedFlagsProducer = (*flagExporter)(nil)
 
 func NewFlagExporter() *flagExporter {
-	return &flagExporter{
-		depFlags:    []string{},
-		linkDirs:    []string{},
-		linkObjects: []string{},
-	}
+	return &flagExporter{}
 }
 
+type FlagExporterInfo struct {
+	Flags       []string
+	LinkDirs    []string // TODO: this should be android.Paths
+	LinkObjects []string // TODO: this should be android.Paths
+}
+
+var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
+
 func (mod *Module) isCoverageVariant() bool {
 	return mod.coverage.Properties.IsCoverageVariant
 }
@@ -495,22 +496,11 @@
 	panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", mod.BaseModuleName()))
 }
 
-// Rust module deps don't have a link order (?)
-func (mod *Module) SetDepsInLinkOrder([]android.Path) {}
-
-func (mod *Module) GetDepsInLinkOrder() []android.Path {
-	return []android.Path{}
-}
-
-func (mod *Module) GetStaticVariant() cc.LinkableInterface {
-	return nil
-}
-
 func (mod *Module) Module() android.Module {
 	return mod
 }
 
-func (mod *Module) StubsVersions() []string {
+func (mod *Module) StubsVersions(ctx android.BaseMutatorContext) []string {
 	// For now, Rust has no stubs versions.
 	if mod.compiler != nil {
 		if _, ok := mod.compiler.(libraryInterface); ok {
@@ -528,12 +518,6 @@
 	// For now, Rust has no notion of the recovery image
 	return false
 }
-func (mod *Module) HasStaticVariant() bool {
-	if mod.GetStaticVariant() != nil {
-		return true
-	}
-	return false
-}
 
 func (mod *Module) CoverageFiles() android.Paths {
 	if mod.compiler != nil {
@@ -697,15 +681,10 @@
 		if mod.compiler.(libraryInterface).source() {
 			mod.sourceProvider.GenerateSource(ctx, deps)
 			mod.sourceProvider.setSubName(ctx.ModuleSubDir())
-			if lib, ok := mod.compiler.(*libraryDecorator); ok {
-				lib.flagExporter.linkDirs = nil
-				lib.flagExporter.linkObjects = nil
-				lib.flagExporter.depFlags = nil
-			}
 		} else {
 			sourceMod := actx.GetDirectDepWithTag(mod.Name(), sourceDepTag)
 			sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
-			mod.sourceProvider.setOutputFile(sourceLib.sourceProvider.Srcs()[0])
+			mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
 		}
 	}
 
@@ -842,10 +821,11 @@
 			}
 
 			//Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS
-			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 != procMacroDepTag {
+				exportedInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+				depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
+				depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
+				depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
 			}
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -885,24 +865,22 @@
 			case cc.IsStaticDepTag(depTag):
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				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()...)
-				}
+				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
+				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
+				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
+				depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
 				depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
 			case cc.IsSharedDepTag(depTag):
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				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()...)
-				}
+				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
+				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
+				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
+				depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
@@ -995,11 +973,7 @@
 	}
 
 	deps := mod.deps(ctx)
-	commonDepVariations := []blueprint.Variation{}
-	if cc.VersionVariantAvailable(mod) {
-		commonDepVariations = append(commonDepVariations,
-			blueprint.Variation{Mutator: "version", Variation: ""})
-	}
+	var commonDepVariations []blueprint.Variation
 	if !mod.Host() {
 		commonDepVariations = append(commonDepVariations,
 			blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
@@ -1055,7 +1029,7 @@
 		blueprint.Variation{Mutator: "link", Variation: "static"}),
 		cc.StaticDepTag(), deps.StaticLibs...)
 
-	crtVariations := append(cc.GetCrtVariations(ctx, mod), commonDepVariations...)
+	crtVariations := cc.GetCrtVariations(ctx, mod)
 	if deps.CrtBegin != "" {
 		actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, deps.CrtBegin)
 	}
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 4842a4c..9b2f023 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -54,10 +54,58 @@
 	os.Exit(run())
 }
 
-func testConfig(bp string) android.Config {
-	bp = bp + GatherRequiredDepsForTest()
+// testRust returns a TestContext in which a basic environment has been setup.
+// This environment contains a few mocked files. See testRustCtx.useMockedFs
+// for the list of these files.
+func testRust(t *testing.T, bp string) *android.TestContext {
+	tctx := newTestRustCtx(t, bp)
+	tctx.useMockedFs()
+	tctx.generateConfig()
+	return tctx.parse(t)
+}
 
-	fs := map[string][]byte{
+// testRustCov returns a TestContext in which a basic environment has been
+// setup. This environment explicitly enables coverage.
+func testRustCov(t *testing.T, bp string) *android.TestContext {
+	tctx := newTestRustCtx(t, bp)
+	tctx.useMockedFs()
+	tctx.generateConfig()
+	tctx.enableCoverage(t)
+	return tctx.parse(t)
+}
+
+// testRustError ensures that at least one error was raised and its value
+// matches the pattern provided. The error can be either in the parsing of the
+// Blueprint or when generating the build actions.
+func testRustError(t *testing.T, pattern string, bp string) {
+	tctx := newTestRustCtx(t, bp)
+	tctx.useMockedFs()
+	tctx.generateConfig()
+	tctx.parseError(t, pattern)
+}
+
+// testRustCtx is used to build a particular test environment. Unless your
+// tests requires a specific setup, prefer the wrapping functions: testRust,
+// testRustCov or testRustError.
+type testRustCtx struct {
+	bp     string
+	fs     map[string][]byte
+	env    map[string]string
+	config *android.Config
+}
+
+// newTestRustCtx returns a new testRustCtx for the Blueprint definition argument.
+func newTestRustCtx(t *testing.T, bp string) *testRustCtx {
+	// TODO (b/140435149)
+	if runtime.GOOS != "linux" {
+		t.Skip("Rust Soong tests can only be run on Linux hosts currently")
+	}
+	return &testRustCtx{bp: bp}
+}
+
+// useMockedFs setup a default mocked filesystem for the test environment.
+func (tctx *testRustCtx) useMockedFs() {
+	tctx.fs = map[string][]byte{
 		"foo.rs":     nil,
 		"foo.c":      nil,
 		"src/bar.rs": nil,
@@ -66,57 +114,51 @@
 		"liby.so":    nil,
 		"libz.so":    nil,
 	}
-
-	cc.GatherRequiredFilesForTest(fs)
-
-	return android.TestArchConfig(buildDir, nil, bp, fs)
 }
 
-func testRust(t *testing.T, bp string) *android.TestContext {
-	return testRustContext(t, bp, false)
+// generateConfig creates the android.Config based on the bp, fs and env
+// attributes of the testRustCtx.
+func (tctx *testRustCtx) generateConfig() {
+	tctx.bp = tctx.bp + GatherRequiredDepsForTest()
+	cc.GatherRequiredFilesForTest(tctx.fs)
+	config := android.TestArchConfig(buildDir, tctx.env, tctx.bp, tctx.fs)
+	tctx.config = &config
 }
 
-func testRustCov(t *testing.T, bp string) *android.TestContext {
-	return testRustContext(t, bp, true)
-}
-
-func testRustContext(t *testing.T, bp string, coverage bool) *android.TestContext {
-	// TODO (b/140435149)
-	if runtime.GOOS != "linux" {
-		t.Skip("Only the Linux toolchain is supported for Rust")
+// enableCoverage configures the test to enable coverage.
+func (tctx *testRustCtx) enableCoverage(t *testing.T) {
+	if tctx.config == nil {
+		t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.")
 	}
+	tctx.config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
+	tctx.config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
+	tctx.config.TestProductVariables.NativeCoveragePaths = []string{"*"}
+}
 
-	t.Helper()
-	config := testConfig(bp)
-
-	if coverage {
-		config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
-		config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
-		config.TestProductVariables.NativeCoveragePaths = []string{"*"}
+// parse validates the configuration and parses the Blueprint file. It returns
+// a TestContext which can be used to retrieve the generated modules via
+// ModuleForTests.
+func (tctx testRustCtx) parse(t *testing.T) *android.TestContext {
+	if tctx.config == nil {
+		t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.")
 	}
-
 	ctx := CreateTestContext()
-	ctx.Register(config)
-
+	ctx.Register(*tctx.config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
+	_, errs = ctx.PrepareBuildActions(*tctx.config)
 	android.FailIfErrored(t, errs)
-
 	return ctx
 }
 
-func testRustError(t *testing.T, pattern string, bp string) {
-	// TODO (b/140435149)
-	if runtime.GOOS != "linux" {
-		t.Skip("Only the Linux toolchain is supported for Rust")
+// parseError parses the Blueprint file and ensure that at least one error
+// matching the provided pattern is observed.
+func (tctx testRustCtx) parseError(t *testing.T, pattern string) {
+	if tctx.config == nil {
+		t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.")
 	}
-
-	t.Helper()
-	config := testConfig(bp)
-
 	ctx := CreateTestContext()
-	ctx.Register(config)
+	ctx.Register(*tctx.config)
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	if len(errs) > 0 {
@@ -124,7 +166,7 @@
 		return
 	}
 
-	_, errs = ctx.PrepareBuildActions(config)
+	_, errs = ctx.PrepareBuildActions(*tctx.config)
 	if len(errs) > 0 {
 		android.FailIfNoMatchingErrors(t, pattern, errs)
 		return
diff --git a/rust/source_provider.go b/rust/source_provider.go
index 03adf9e..436518c 100644
--- a/rust/source_provider.go
+++ b/rust/source_provider.go
@@ -30,7 +30,7 @@
 type BaseSourceProvider struct {
 	Properties SourceProviderProperties
 
-	OutputFile       android.Path
+	OutputFiles      android.Paths
 	subAndroidMkOnce map[SubAndroidMkProvider]bool
 	subName          string
 }
@@ -43,11 +43,11 @@
 	SourceProviderProps() []interface{}
 	SourceProviderDeps(ctx DepsContext, deps Deps) Deps
 	setSubName(subName string)
-	setOutputFile(outputFile android.Path)
+	setOutputFiles(outputFiles android.Paths)
 }
 
 func (sp *BaseSourceProvider) Srcs() android.Paths {
-	return android.Paths{sp.OutputFile}
+	return sp.OutputFiles
 }
 
 func (sp *BaseSourceProvider) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
@@ -97,6 +97,6 @@
 	sp.subName = subName
 }
 
-func (sp *BaseSourceProvider) setOutputFile(outputFile android.Path) {
-	sp.OutputFile = outputFile
+func (sp *BaseSourceProvider) setOutputFiles(outputFiles android.Paths) {
+	sp.OutputFiles = outputFiles
 }
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 7c3cdbd..e807877 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -261,7 +261,7 @@
 	ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...),
 		shTestDataLibsTag, s.testProperties.Data_libs...)
 	if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 {
-		deviceVariations := ctx.Config().Targets[android.Android][0].Variations()
+		deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
 		ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
 		ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
 			shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...)
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index e1123e0..03e884a 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -80,6 +80,10 @@
 		return filepath.Join(hostOutPath, path)
 	}
 
+	hostCommonOut := func(path string) string {
+		return filepath.Join(config.hostOutRoot(), "common", path)
+	}
+
 	productOutPath := config.ProductOut()
 	productOut := func(path string) string {
 		return filepath.Join(productOutPath, path)
@@ -101,6 +105,7 @@
 		hostOut("vts"),
 		hostOut("vts10"),
 		hostOut("vts-core"),
+		hostCommonOut("obj/PACKAGING"),
 		productOut("*.img"),
 		productOut("*.zip"),
 		productOut("android-info.txt"),
@@ -122,6 +127,7 @@
 		productOut("system"),
 		productOut("system_other"),
 		productOut("vendor"),
+		productOut("vendor_dlkm"),
 		productOut("product"),
 		productOut("system_ext"),
 		productOut("oem"),
@@ -131,6 +137,7 @@
 		productOut("coverage"),
 		productOut("installer"),
 		productOut("odm"),
+		productOut("odm_dlkm"),
 		productOut("sysloader"),
 		productOut("testcases"))
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index fe74ace..fbe5cd2 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -303,6 +303,12 @@
 		UseRbe:       proto.Bool(config.UseRBE()),
 	}
 	ctx.Metrics.BuildConfig(b)
+
+	s := &smpb.SystemResourceInfo{
+		TotalPhysicalMemory: proto.Uint64(config.TotalRAM()),
+		AvailableCpus:       proto.Int32(int32(runtime.NumCPU())),
+	}
+	ctx.Metrics.SystemResourceInfo(s)
 }
 
 // getConfigArgs processes the command arguments based on the build action and creates a set of new
diff --git a/ui/build/finder.go b/ui/build/finder.go
index c019ea2..7a85657 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -63,10 +63,13 @@
 			"AndroidProducts.mk",
 			"Android.bp",
 			"Blueprints",
+			"BUILD.bazel",
 			"CleanSpec.mk",
 			"OWNERS",
 			"TEST_MAPPING",
+			"WORKSPACE",
 		},
+		IncludeSuffixes: []string{".bzl"},
 	}
 	dumpDir := config.FileListDir()
 	f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard),
@@ -77,6 +80,16 @@
 	return f
 }
 
+func findBazelFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
+	matches := []string{}
+	for _, foundName := range entries.FileNames {
+		if foundName == "BUILD.bazel" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") {
+			matches = append(matches, foundName)
+		}
+	}
+	return entries.DirNames, matches
+}
+
 // FindSources searches for source files known to <f> and writes them to the filesystem for
 // use later.
 func FindSources(ctx Context, config Config, f *finder.Finder) {
@@ -99,6 +112,12 @@
 		ctx.Fatalf("Could not export product list: %v", err)
 	}
 
+	bazelFiles := f.FindMatching(".", findBazelFiles)
+	err = dumpListToFile(ctx, config, bazelFiles, filepath.Join(dumpDir, "bazel.list"))
+	if err != nil {
+		ctx.Fatalf("Could not export bazel BUILD list: %v", err)
+	}
+
 	cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
 	err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
 	if err != nil {
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 182c544..64f3d4c 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -34,6 +34,8 @@
 
 	// RBE metrics proto buffer file
 	rbeMetricsPBFilename = "rbe_metrics.pb"
+
+	defaultOutDir = "out"
 )
 
 func rbeCommand(ctx Context, config Config, rbeCmd string) string {
@@ -151,3 +153,16 @@
 		ctx.Fatalf("failed to copy %q to %q: %v\n", metricsFile, filename, err)
 	}
 }
+
+// PrintOutDirWarning prints a warning to indicate to the user that
+// setting output directory to a path other than "out" in an RBE enabled
+// build can cause slow builds.
+func PrintOutDirWarning(ctx Context, config Config) {
+	if config.UseRBE() && config.OutDir() != defaultOutDir {
+		fmt.Fprintln(ctx.Writer, "")
+		fmt.Fprintln(ctx.Writer, "\033[33mWARNING:\033[0m")
+		fmt.Fprintln(ctx.Writer, fmt.Sprintf("Setting OUT_DIR to a path other than %v may result in slow RBE builds.", defaultOutDir))
+		fmt.Fprintln(ctx.Writer, "See http://go/android_rbe_out_dir for a workaround.")
+		fmt.Fprintln(ctx.Writer, "")
+	}
+}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index f5552a3..35d1976 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -70,6 +70,10 @@
 	m.metrics.BuildConfig = b
 }
 
+func (m *Metrics) SystemResourceInfo(b *soong_metrics_proto.SystemResourceInfo) {
+	m.metrics.SystemResourceInfo = b
+}
+
 func (m *Metrics) SetMetadataMetrics(metadata map[string]string) {
 	for k, v := range metadata {
 		switch k {
@@ -139,7 +143,12 @@
 }
 
 // exports the output to the file at outputPath
-func (m *Metrics) Dump(outputPath string) (err error) {
+func (m *Metrics) Dump(outputPath string) error {
+	// ignore the error if the hostname could not be retrieved as it
+	// is not a critical metric to extract.
+	if hostname, err := os.Hostname(); err == nil {
+		m.metrics.Hostname = proto.String(hostname)
+	}
 	m.metrics.HostOs = proto.String(runtime.GOOS)
 	return writeMessageToFile(&m.metrics, outputPath)
 }
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 05efe13..e824f6b 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -152,7 +152,7 @@
 }
 
 func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptor_6039342a2ba47b72, []int{3, 0}
+	return fileDescriptor_6039342a2ba47b72, []int{4, 0}
 }
 
 type MetricsBase struct {
@@ -197,12 +197,16 @@
 	// The metrics for calling Ninja.
 	NinjaRuns []*PerfInfo `protobuf:"bytes,20,rep,name=ninja_runs,json=ninjaRuns" json:"ninja_runs,omitempty"`
 	// The metrics for the whole build
-	Total                *PerfInfo          `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
-	SoongBuildMetrics    *SoongBuildMetrics `protobuf:"bytes,22,opt,name=soong_build_metrics,json=soongBuildMetrics" json:"soong_build_metrics,omitempty"`
-	BuildConfig          *BuildConfig       `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
-	XXX_unrecognized     []byte             `json:"-"`
-	XXX_sizecache        int32              `json:"-"`
+	Total             *PerfInfo          `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
+	SoongBuildMetrics *SoongBuildMetrics `protobuf:"bytes,22,opt,name=soong_build_metrics,json=soongBuildMetrics" json:"soong_build_metrics,omitempty"`
+	BuildConfig       *BuildConfig       `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
+	// The hostname of the machine.
+	Hostname *string `protobuf:"bytes,24,opt,name=hostname" json:"hostname,omitempty"`
+	// The system resource information such as total physical memory.
+	SystemResourceInfo   *SystemResourceInfo `protobuf:"bytes,25,opt,name=system_resource_info,json=systemResourceInfo" json:"system_resource_info,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}            `json:"-"`
+	XXX_unrecognized     []byte              `json:"-"`
+	XXX_sizecache        int32               `json:"-"`
 }
 
 func (m *MetricsBase) Reset()         { *m = MetricsBase{} }
@@ -396,6 +400,20 @@
 	return nil
 }
 
+func (m *MetricsBase) GetHostname() string {
+	if m != nil && m.Hostname != nil {
+		return *m.Hostname
+	}
+	return ""
+}
+
+func (m *MetricsBase) GetSystemResourceInfo() *SystemResourceInfo {
+	if m != nil {
+		return m.SystemResourceInfo
+	}
+	return nil
+}
+
 type BuildConfig struct {
 	UseGoma              *bool    `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"`
 	UseRbe               *bool    `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"`
@@ -451,6 +469,55 @@
 	return false
 }
 
+type SystemResourceInfo struct {
+	// The total physical memory in bytes.
+	TotalPhysicalMemory *uint64 `protobuf:"varint,1,opt,name=total_physical_memory,json=totalPhysicalMemory" json:"total_physical_memory,omitempty"`
+	// The total of available cores for building
+	AvailableCpus        *int32   `protobuf:"varint,2,opt,name=available_cpus,json=availableCpus" json:"available_cpus,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *SystemResourceInfo) Reset()         { *m = SystemResourceInfo{} }
+func (m *SystemResourceInfo) String() string { return proto.CompactTextString(m) }
+func (*SystemResourceInfo) ProtoMessage()    {}
+func (*SystemResourceInfo) Descriptor() ([]byte, []int) {
+	return fileDescriptor_6039342a2ba47b72, []int{2}
+}
+
+func (m *SystemResourceInfo) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_SystemResourceInfo.Unmarshal(m, b)
+}
+func (m *SystemResourceInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_SystemResourceInfo.Marshal(b, m, deterministic)
+}
+func (m *SystemResourceInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_SystemResourceInfo.Merge(m, src)
+}
+func (m *SystemResourceInfo) XXX_Size() int {
+	return xxx_messageInfo_SystemResourceInfo.Size(m)
+}
+func (m *SystemResourceInfo) XXX_DiscardUnknown() {
+	xxx_messageInfo_SystemResourceInfo.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SystemResourceInfo proto.InternalMessageInfo
+
+func (m *SystemResourceInfo) GetTotalPhysicalMemory() uint64 {
+	if m != nil && m.TotalPhysicalMemory != nil {
+		return *m.TotalPhysicalMemory
+	}
+	return 0
+}
+
+func (m *SystemResourceInfo) GetAvailableCpus() int32 {
+	if m != nil && m.AvailableCpus != nil {
+		return *m.AvailableCpus
+	}
+	return 0
+}
+
 type PerfInfo struct {
 	// The description for the phase/action/part while the tool running.
 	Desc *string `protobuf:"bytes,1,opt,name=desc" json:"desc,omitempty"`
@@ -473,7 +540,7 @@
 func (m *PerfInfo) String() string { return proto.CompactTextString(m) }
 func (*PerfInfo) ProtoMessage()    {}
 func (*PerfInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_6039342a2ba47b72, []int{2}
+	return fileDescriptor_6039342a2ba47b72, []int{3}
 }
 
 func (m *PerfInfo) XXX_Unmarshal(b []byte) error {
@@ -545,7 +612,7 @@
 func (m *ModuleTypeInfo) String() string { return proto.CompactTextString(m) }
 func (*ModuleTypeInfo) ProtoMessage()    {}
 func (*ModuleTypeInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_6039342a2ba47b72, []int{3}
+	return fileDescriptor_6039342a2ba47b72, []int{4}
 }
 
 func (m *ModuleTypeInfo) XXX_Unmarshal(b []byte) error {
@@ -603,7 +670,7 @@
 func (m *CriticalUserJourneyMetrics) String() string { return proto.CompactTextString(m) }
 func (*CriticalUserJourneyMetrics) ProtoMessage()    {}
 func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) {
-	return fileDescriptor_6039342a2ba47b72, []int{4}
+	return fileDescriptor_6039342a2ba47b72, []int{5}
 }
 
 func (m *CriticalUserJourneyMetrics) XXX_Unmarshal(b []byte) error {
@@ -650,7 +717,7 @@
 func (m *CriticalUserJourneysMetrics) String() string { return proto.CompactTextString(m) }
 func (*CriticalUserJourneysMetrics) ProtoMessage()    {}
 func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) {
-	return fileDescriptor_6039342a2ba47b72, []int{5}
+	return fileDescriptor_6039342a2ba47b72, []int{6}
 }
 
 func (m *CriticalUserJourneysMetrics) XXX_Unmarshal(b []byte) error {
@@ -698,7 +765,7 @@
 func (m *SoongBuildMetrics) String() string { return proto.CompactTextString(m) }
 func (*SoongBuildMetrics) ProtoMessage()    {}
 func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
-	return fileDescriptor_6039342a2ba47b72, []int{6}
+	return fileDescriptor_6039342a2ba47b72, []int{7}
 }
 
 func (m *SoongBuildMetrics) XXX_Unmarshal(b []byte) error {
@@ -760,6 +827,7 @@
 	proto.RegisterEnum("soong_build_metrics.ModuleTypeInfo_BuildSystem", ModuleTypeInfo_BuildSystem_name, ModuleTypeInfo_BuildSystem_value)
 	proto.RegisterType((*MetricsBase)(nil), "soong_build_metrics.MetricsBase")
 	proto.RegisterType((*BuildConfig)(nil), "soong_build_metrics.BuildConfig")
+	proto.RegisterType((*SystemResourceInfo)(nil), "soong_build_metrics.SystemResourceInfo")
 	proto.RegisterType((*PerfInfo)(nil), "soong_build_metrics.PerfInfo")
 	proto.RegisterType((*ModuleTypeInfo)(nil), "soong_build_metrics.ModuleTypeInfo")
 	proto.RegisterType((*CriticalUserJourneyMetrics)(nil), "soong_build_metrics.CriticalUserJourneyMetrics")
@@ -772,70 +840,76 @@
 }
 
 var fileDescriptor_6039342a2ba47b72 = []byte{
-	// 1036 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x4e, 0x1b, 0x47,
-	0x10, 0xcf, 0x61, 0x83, 0x7d, 0x73, 0xd8, 0x1c, 0x0b, 0x29, 0x97, 0x44, 0xa8, 0x96, 0xd5, 0x44,
-	0xa8, 0x6a, 0x48, 0x44, 0x23, 0x14, 0xa1, 0xa8, 0x12, 0x18, 0x44, 0x53, 0x04, 0x8e, 0x16, 0x4c,
-	0xa3, 0xf6, 0xc3, 0x69, 0x7d, 0xb7, 0x86, 0x4b, 0x7d, 0xb7, 0xd6, 0xee, 0x5e, 0x04, 0x79, 0x87,
-	0x3e, 0x55, 0x9f, 0xa5, 0xaf, 0x51, 0x55, 0x3b, 0x7b, 0x67, 0x1f, 0xad, 0xdb, 0xa0, 0x7c, 0xf3,
-	0xce, 0xef, 0xcf, 0xce, 0xec, 0xce, 0xce, 0x19, 0x5a, 0x29, 0xd7, 0x32, 0x89, 0xd4, 0xf6, 0x44,
-	0x0a, 0x2d, 0xc8, 0x9a, 0x12, 0x22, 0xbb, 0x0a, 0x87, 0x79, 0x32, 0x8e, 0xc3, 0x02, 0xea, 0xfe,
-	0x05, 0xe0, 0x9d, 0xda, 0xdf, 0x07, 0x4c, 0x71, 0xf2, 0x12, 0xd6, 0x2d, 0x21, 0x66, 0x9a, 0x87,
-	0x3a, 0x49, 0xb9, 0xd2, 0x2c, 0x9d, 0x04, 0x4e, 0xc7, 0xd9, 0xaa, 0x51, 0x82, 0xd8, 0x21, 0xd3,
-	0xfc, 0xa2, 0x44, 0xc8, 0x23, 0x68, 0x5a, 0x45, 0x12, 0x07, 0x0b, 0x1d, 0x67, 0xcb, 0xa5, 0x0d,
-	0x5c, 0xbf, 0x8d, 0xc9, 0x1e, 0x3c, 0x9a, 0x8c, 0x99, 0x1e, 0x09, 0x99, 0x86, 0x1f, 0xb9, 0x54,
-	0x89, 0xc8, 0xc2, 0x48, 0xc4, 0x3c, 0x63, 0x29, 0x0f, 0x6a, 0xc8, 0xdd, 0x28, 0x09, 0x97, 0x16,
-	0xef, 0x15, 0x30, 0x79, 0x0a, 0x6d, 0xcd, 0xe4, 0x15, 0xd7, 0xe1, 0x44, 0x8a, 0x38, 0x8f, 0x74,
-	0x50, 0x47, 0x41, 0xcb, 0x46, 0xdf, 0xd9, 0x20, 0x89, 0x61, 0xbd, 0xa0, 0xd9, 0x24, 0x3e, 0x32,
-	0x99, 0xb0, 0x4c, 0x07, 0x8b, 0x1d, 0x67, 0xab, 0xbd, 0xf3, 0x7c, 0x7b, 0x4e, 0xcd, 0xdb, 0x95,
-	0x7a, 0xb7, 0x0f, 0x0c, 0x72, 0x69, 0x45, 0x7b, 0xb5, 0xa3, 0xb3, 0x63, 0x4a, 0xac, 0x5f, 0x15,
-	0x20, 0x7d, 0xf0, 0x8a, 0x5d, 0x98, 0x8c, 0xae, 0x83, 0x25, 0x34, 0x7f, 0xfa, 0x59, 0xf3, 0x7d,
-	0x19, 0x5d, 0xef, 0x35, 0x06, 0x67, 0x27, 0x67, 0xfd, 0x9f, 0xcf, 0x28, 0x58, 0x0b, 0x13, 0x24,
-	0xdb, 0xb0, 0x56, 0x31, 0x9c, 0x66, 0xdd, 0xc0, 0x12, 0x57, 0x67, 0xc4, 0x32, 0x81, 0xef, 0xa0,
-	0x48, 0x2b, 0x8c, 0x26, 0xf9, 0x94, 0xde, 0x44, 0xba, 0x6f, 0x91, 0xde, 0x24, 0x2f, 0xd9, 0x27,
-	0xe0, 0x5e, 0x0b, 0x55, 0x24, 0xeb, 0x7e, 0x51, 0xb2, 0x4d, 0x63, 0x80, 0xa9, 0x52, 0x68, 0xa1,
-	0xd9, 0x4e, 0x16, 0x5b, 0x43, 0xf8, 0x22, 0x43, 0xcf, 0x98, 0xec, 0x64, 0x31, 0x7a, 0x6e, 0x40,
-	0x03, 0x3d, 0x85, 0x0a, 0x3c, 0xac, 0x61, 0xc9, 0x2c, 0xfb, 0x8a, 0x74, 0x8b, 0xcd, 0x84, 0x0a,
-	0xf9, 0x8d, 0x96, 0x2c, 0x58, 0x46, 0xd8, 0xb3, 0xf0, 0x91, 0x09, 0x4d, 0x39, 0x91, 0x14, 0x4a,
-	0x19, 0x8b, 0xd6, 0x8c, 0xd3, 0x33, 0xb1, 0xbe, 0x22, 0xcf, 0x60, 0xa5, 0xc2, 0xc1, 0xb4, 0xdb,
-	0xb6, 0x7d, 0xa6, 0x2c, 0x4c, 0xe4, 0x39, 0xac, 0x55, 0x78, 0xd3, 0x12, 0x57, 0xec, 0xc1, 0x4e,
-	0xb9, 0x95, 0xbc, 0x45, 0xae, 0xc3, 0x38, 0x91, 0x81, 0x6f, 0xf3, 0x16, 0xb9, 0x3e, 0x4c, 0x24,
-	0xf9, 0x01, 0x3c, 0xc5, 0x75, 0x3e, 0x09, 0xb5, 0x10, 0x63, 0x15, 0xac, 0x76, 0x6a, 0x5b, 0xde,
-	0xce, 0xe6, 0xdc, 0x23, 0x7a, 0xc7, 0xe5, 0xe8, 0x6d, 0x36, 0x12, 0x14, 0x50, 0x71, 0x61, 0x04,
-	0x64, 0x0f, 0xdc, 0xdf, 0x98, 0x4e, 0x42, 0x99, 0x67, 0x2a, 0x20, 0xf7, 0x51, 0x37, 0x0d, 0x9f,
-	0xe6, 0x99, 0x22, 0x6f, 0x00, 0x2c, 0x13, 0xc5, 0x6b, 0xf7, 0x11, 0xbb, 0x88, 0x96, 0xea, 0x2c,
-	0xc9, 0x3e, 0x30, 0xab, 0x5e, 0xbf, 0x97, 0x1a, 0x05, 0xa8, 0xfe, 0x1e, 0x16, 0xb5, 0xd0, 0x6c,
-	0x1c, 0x3c, 0xec, 0x38, 0x9f, 0x17, 0x5a, 0x2e, 0xb9, 0x84, 0x79, 0xa3, 0x28, 0xf8, 0x0a, 0x2d,
-	0x9e, 0xcd, 0xb5, 0x38, 0x37, 0x31, 0x7c, 0x92, 0x45, 0x87, 0xd1, 0x55, 0xf5, 0xcf, 0x10, 0xe9,
-	0xc1, 0xb2, 0x55, 0x45, 0x22, 0x1b, 0x25, 0x57, 0xc1, 0x06, 0x1a, 0x76, 0xe6, 0x1a, 0xa2, 0xb0,
-	0x87, 0x3c, 0xea, 0x0d, 0x67, 0x8b, 0xee, 0x4b, 0x58, 0xbe, 0xf3, 0xf4, 0x9b, 0x50, 0x1f, 0x9c,
-	0x1f, 0x51, 0xff, 0x01, 0x69, 0x81, 0x6b, 0x7e, 0x1d, 0x1e, 0x1d, 0x0c, 0x8e, 0x7d, 0x87, 0x34,
-	0xc0, 0x8c, 0x0b, 0x7f, 0xa1, 0xfb, 0x06, 0xea, 0xd8, 0x1c, 0x1e, 0x94, 0xcd, 0xee, 0x3f, 0x30,
-	0xe8, 0x3e, 0x3d, 0xf5, 0x1d, 0xe2, 0xc2, 0xe2, 0x3e, 0x3d, 0xdd, 0x7d, 0xe5, 0x2f, 0x98, 0xd8,
-	0xfb, 0xd7, 0xbb, 0x7e, 0x8d, 0x00, 0x2c, 0xbd, 0x7f, 0xbd, 0x1b, 0xee, 0xbe, 0xf2, 0xeb, 0xdd,
-	0x2b, 0xf0, 0x2a, 0xb9, 0x98, 0x69, 0x9a, 0x2b, 0x1e, 0x5e, 0x89, 0x94, 0xe1, 0xcc, 0x6d, 0xd2,
-	0x46, 0xae, 0xf8, 0xb1, 0x48, 0x99, 0x69, 0x3e, 0x03, 0xc9, 0x21, 0xc7, 0x39, 0xdb, 0xa4, 0x4b,
-	0xb9, 0xe2, 0x74, 0xc8, 0xc9, 0x37, 0xd0, 0x1e, 0x09, 0x19, 0xf1, 0x70, 0xaa, 0xac, 0x21, 0xbe,
-	0x8c, 0xd1, 0x81, 0x95, 0x77, 0x7f, 0x77, 0xa0, 0x59, 0xde, 0x04, 0x21, 0x50, 0x8f, 0xb9, 0x8a,
-	0x70, 0x0b, 0x97, 0xe2, 0x6f, 0x13, 0xc3, 0xc1, 0x6c, 0x87, 0x38, 0xfe, 0x26, 0x9b, 0x00, 0x4a,
-	0x33, 0xa9, 0xf1, 0x4b, 0x80, 0xb6, 0x75, 0xea, 0x62, 0xc4, 0x7c, 0x00, 0xc8, 0x13, 0x70, 0x25,
-	0x67, 0x63, 0x8b, 0xd6, 0x11, 0x6d, 0x9a, 0x00, 0x82, 0x9b, 0x00, 0x29, 0x4f, 0x85, 0xbc, 0x35,
-	0x79, 0xe1, 0x40, 0xae, 0x53, 0xd7, 0x46, 0x06, 0x8a, 0x77, 0xff, 0x74, 0xa0, 0x7d, 0x2a, 0xe2,
-	0x7c, 0xcc, 0x2f, 0x6e, 0x27, 0x1c, 0xb3, 0xfa, 0xb5, 0xbc, 0x40, 0x75, 0xab, 0x34, 0x4f, 0x31,
-	0xbb, 0xf6, 0xce, 0x8b, 0xf9, 0x93, 0xe6, 0x8e, 0xd4, 0xde, 0xe7, 0x39, 0xca, 0x2a, 0x33, 0x67,
-	0x38, 0x8b, 0x92, 0xaf, 0xc1, 0x4b, 0x51, 0x13, 0xea, 0xdb, 0x49, 0x59, 0x25, 0xa4, 0x53, 0x1b,
-	0x73, 0x8c, 0x59, 0x9e, 0x86, 0x62, 0x14, 0xda, 0xa0, 0xc2, 0x7a, 0x5b, 0x74, 0x39, 0xcb, 0xd3,
-	0xfe, 0xc8, 0xee, 0xa7, 0xba, 0x2f, 0x8a, 0xfb, 0x2a, 0x5c, 0xef, 0x5c, 0xba, 0x0b, 0x8b, 0xe7,
-	0xfd, 0xfe, 0x99, 0xe9, 0x8e, 0x26, 0xd4, 0x4f, 0xf7, 0x4f, 0x8e, 0xfc, 0x85, 0xee, 0x18, 0x1e,
-	0xf7, 0x64, 0xa2, 0x93, 0x88, 0x8d, 0x07, 0x8a, 0xcb, 0x9f, 0x44, 0x2e, 0x33, 0x7e, 0x5b, 0xf6,
-	0x6c, 0x79, 0xe8, 0x4e, 0xe5, 0xd0, 0xf7, 0xa0, 0x51, 0xbe, 0x89, 0x85, 0xff, 0x69, 0xe1, 0xca,
-	0xac, 0xa5, 0xa5, 0xa0, 0x3b, 0x84, 0x27, 0x73, 0x76, 0x53, 0xb3, 0x27, 0x52, 0x8f, 0xf2, 0x0f,
-	0x2a, 0x70, 0xf0, 0x9d, 0xcf, 0x3f, 0xd9, 0xff, 0xce, 0x96, 0xa2, 0xb8, 0xfb, 0x87, 0x03, 0xab,
-	0xff, 0x7a, 0x90, 0x24, 0x80, 0x46, 0x79, 0x6e, 0x0e, 0x9e, 0x5b, 0xb9, 0x24, 0x8f, 0xa1, 0x59,
-	0x7c, 0xb1, 0x6c, 0x41, 0x2d, 0x3a, 0x5d, 0x93, 0x6f, 0x61, 0x15, 0x87, 0x42, 0xc8, 0xc6, 0x63,
-	0x11, 0x85, 0x91, 0xc8, 0x33, 0x5d, 0xf4, 0xd9, 0x0a, 0x02, 0xfb, 0x26, 0xde, 0x33, 0x61, 0xb2,
-	0x05, 0x7e, 0x95, 0xab, 0x92, 0x4f, 0x65, 0xd3, 0xb5, 0x67, 0xd4, 0xf3, 0xe4, 0x13, 0x37, 0x9f,
-	0x88, 0x94, 0xdd, 0x84, 0xd7, 0x9c, 0x4d, 0x2c, 0xcd, 0x76, 0x9f, 0x97, 0xb2, 0x9b, 0x1f, 0x39,
-	0x9b, 0x18, 0xce, 0xc1, 0xc3, 0x5f, 0x8a, 0x29, 0x54, 0xd4, 0x1d, 0xe2, 0xbf, 0xa4, 0xbf, 0x03,
-	0x00, 0x00, 0xff, 0xff, 0x85, 0xc5, 0xe0, 0x4b, 0x35, 0x09, 0x00, 0x00,
+	// 1130 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x6f, 0x6f, 0xd4, 0x46,
+	0x13, 0xc7, 0xc9, 0x25, 0x77, 0x1e, 0xe7, 0x0e, 0x67, 0x13, 0x1e, 0x0c, 0x08, 0x3d, 0x91, 0x55,
+	0x68, 0x54, 0x95, 0x80, 0xae, 0x28, 0x42, 0x11, 0xaa, 0x94, 0x1c, 0x11, 0xa5, 0xe8, 0x72, 0x68,
+	0xc3, 0x51, 0xda, 0xbe, 0xb0, 0xf6, 0xec, 0xbd, 0xc4, 0xd4, 0xf6, 0x5a, 0xbb, 0x6b, 0xc4, 0xf1,
+	0x1d, 0xfa, 0xa9, 0xfa, 0x59, 0xfa, 0x11, 0xfa, 0xbe, 0xda, 0x59, 0xfb, 0xee, 0x28, 0xd7, 0x82,
+	0x78, 0x77, 0x9e, 0xdf, 0x9f, 0x9d, 0x19, 0x8f, 0x67, 0x0f, 0xba, 0x39, 0xd7, 0x32, 0x8d, 0xd5,
+	0x41, 0x29, 0x85, 0x16, 0x64, 0x47, 0x09, 0x51, 0x5c, 0x44, 0x93, 0x2a, 0xcd, 0x92, 0xa8, 0x86,
+	0xc2, 0xbf, 0x3c, 0xf0, 0x86, 0xf6, 0xf7, 0x09, 0x53, 0x9c, 0x3c, 0x80, 0x5d, 0x4b, 0x48, 0x98,
+	0xe6, 0x91, 0x4e, 0x73, 0xae, 0x34, 0xcb, 0xcb, 0xc0, 0xd9, 0x73, 0xf6, 0xd7, 0x29, 0x41, 0xec,
+	0x09, 0xd3, 0xfc, 0x65, 0x83, 0x90, 0x1b, 0xd0, 0xb1, 0x8a, 0x34, 0x09, 0xd6, 0xf6, 0x9c, 0x7d,
+	0x97, 0xb6, 0xf1, 0xf9, 0x59, 0x42, 0x8e, 0xe0, 0x46, 0x99, 0x31, 0x3d, 0x15, 0x32, 0x8f, 0xde,
+	0x72, 0xa9, 0x52, 0x51, 0x44, 0xb1, 0x48, 0x78, 0xc1, 0x72, 0x1e, 0xac, 0x23, 0xf7, 0x7a, 0x43,
+	0x78, 0x65, 0xf1, 0x41, 0x0d, 0x93, 0x3b, 0xd0, 0xd3, 0x4c, 0x5e, 0x70, 0x1d, 0x95, 0x52, 0x24,
+	0x55, 0xac, 0x83, 0x16, 0x0a, 0xba, 0x36, 0xfa, 0xc2, 0x06, 0x49, 0x02, 0xbb, 0x35, 0xcd, 0x26,
+	0xf1, 0x96, 0xc9, 0x94, 0x15, 0x3a, 0xd8, 0xd8, 0x73, 0xf6, 0x7b, 0xfd, 0x7b, 0x07, 0x2b, 0x6a,
+	0x3e, 0x58, 0xaa, 0xf7, 0xe0, 0xc4, 0x20, 0xaf, 0xac, 0xe8, 0x68, 0xfd, 0xf4, 0xec, 0x29, 0x25,
+	0xd6, 0x6f, 0x19, 0x20, 0x23, 0xf0, 0xea, 0x53, 0x98, 0x8c, 0x2f, 0x83, 0x4d, 0x34, 0xbf, 0xf3,
+	0x49, 0xf3, 0x63, 0x19, 0x5f, 0x1e, 0xb5, 0xc7, 0x67, 0xcf, 0xcf, 0x46, 0x3f, 0x9d, 0x51, 0xb0,
+	0x16, 0x26, 0x48, 0x0e, 0x60, 0x67, 0xc9, 0x70, 0x9e, 0x75, 0x1b, 0x4b, 0xdc, 0x5e, 0x10, 0x9b,
+	0x04, 0xbe, 0x85, 0x3a, 0xad, 0x28, 0x2e, 0xab, 0x39, 0xbd, 0x83, 0x74, 0xdf, 0x22, 0x83, 0xb2,
+	0x6a, 0xd8, 0xcf, 0xc1, 0xbd, 0x14, 0xaa, 0x4e, 0xd6, 0xfd, 0xa2, 0x64, 0x3b, 0xc6, 0x00, 0x53,
+	0xa5, 0xd0, 0x45, 0xb3, 0x7e, 0x91, 0x58, 0x43, 0xf8, 0x22, 0x43, 0xcf, 0x98, 0xf4, 0x8b, 0x04,
+	0x3d, 0xaf, 0x43, 0x1b, 0x3d, 0x85, 0x0a, 0x3c, 0xac, 0x61, 0xd3, 0x3c, 0x8e, 0x14, 0x09, 0xeb,
+	0xc3, 0x84, 0x8a, 0xf8, 0x3b, 0x2d, 0x59, 0xb0, 0x85, 0xb0, 0x67, 0xe1, 0x53, 0x13, 0x9a, 0x73,
+	0x62, 0x29, 0x94, 0x32, 0x16, 0xdd, 0x05, 0x67, 0x60, 0x62, 0x23, 0x45, 0xee, 0xc2, 0xd5, 0x25,
+	0x0e, 0xa6, 0xdd, 0xb3, 0xe3, 0x33, 0x67, 0x61, 0x22, 0xf7, 0x60, 0x67, 0x89, 0x37, 0x2f, 0xf1,
+	0xaa, 0x6d, 0xec, 0x9c, 0xbb, 0x94, 0xb7, 0xa8, 0x74, 0x94, 0xa4, 0x32, 0xf0, 0x6d, 0xde, 0xa2,
+	0xd2, 0x4f, 0x52, 0x49, 0xbe, 0x07, 0x4f, 0x71, 0x5d, 0x95, 0x91, 0x16, 0x22, 0x53, 0xc1, 0xf6,
+	0xde, 0xfa, 0xbe, 0xd7, 0xbf, 0xbd, 0xb2, 0x45, 0x2f, 0xb8, 0x9c, 0x3e, 0x2b, 0xa6, 0x82, 0x02,
+	0x2a, 0x5e, 0x1a, 0x01, 0x39, 0x02, 0xf7, 0x37, 0xa6, 0xd3, 0x48, 0x56, 0x85, 0x0a, 0xc8, 0xe7,
+	0xa8, 0x3b, 0x86, 0x4f, 0xab, 0x42, 0x91, 0xc7, 0x00, 0x96, 0x89, 0xe2, 0x9d, 0xcf, 0x11, 0xbb,
+	0x88, 0x36, 0xea, 0x22, 0x2d, 0xde, 0x30, 0xab, 0xde, 0xfd, 0x2c, 0x35, 0x0a, 0x50, 0xfd, 0x1d,
+	0x6c, 0x68, 0xa1, 0x59, 0x16, 0x5c, 0xdb, 0x73, 0x3e, 0x2d, 0xb4, 0x5c, 0xf2, 0x0a, 0x56, 0xad,
+	0xa2, 0xe0, 0x7f, 0x68, 0x71, 0x77, 0xa5, 0xc5, 0xb9, 0x89, 0xe1, 0x27, 0x59, 0x4f, 0x18, 0xdd,
+	0x56, 0xff, 0x0c, 0x91, 0x01, 0x6c, 0x59, 0x55, 0x2c, 0x8a, 0x69, 0x7a, 0x11, 0x5c, 0x47, 0xc3,
+	0xbd, 0x95, 0x86, 0x28, 0x1c, 0x20, 0x8f, 0x7a, 0x93, 0xc5, 0x03, 0xb9, 0x09, 0x38, 0xfa, 0xb8,
+	0xa2, 0x02, 0x7c, 0xc7, 0xf3, 0x67, 0xf2, 0x33, 0xec, 0xaa, 0x99, 0xd2, 0x3c, 0x8f, 0x24, 0x57,
+	0xa2, 0x92, 0x31, 0x8f, 0xd2, 0x62, 0x2a, 0x82, 0x1b, 0x78, 0xd0, 0xd7, 0xab, 0x33, 0x47, 0x01,
+	0xad, 0xf9, 0xd8, 0x06, 0xa2, 0x3e, 0x8a, 0x85, 0x0f, 0x60, 0xeb, 0x83, 0x8d, 0xd3, 0x81, 0xd6,
+	0xf8, 0xfc, 0x94, 0xfa, 0x57, 0x48, 0x17, 0x5c, 0xf3, 0xeb, 0xc9, 0xe9, 0xc9, 0xf8, 0xa9, 0xef,
+	0x90, 0x36, 0x98, 0x2d, 0xe5, 0xaf, 0x85, 0x8f, 0xa1, 0x85, 0x33, 0xe9, 0x41, 0xf3, 0x8d, 0xf9,
+	0x57, 0x0c, 0x7a, 0x4c, 0x87, 0xbe, 0x43, 0x5c, 0xd8, 0x38, 0xa6, 0xc3, 0xc3, 0x87, 0xfe, 0x9a,
+	0x89, 0xbd, 0x7e, 0x74, 0xe8, 0xaf, 0x13, 0x80, 0xcd, 0xd7, 0x8f, 0x0e, 0xa3, 0xc3, 0x87, 0x7e,
+	0x2b, 0xbc, 0x00, 0x6f, 0xa9, 0x05, 0x66, 0x89, 0x57, 0x8a, 0x47, 0x17, 0x22, 0x67, 0xb8, 0xea,
+	0x3b, 0xb4, 0x5d, 0x29, 0xfe, 0x54, 0xe4, 0xcc, 0xcc, 0xbc, 0x81, 0xe4, 0x84, 0xe3, 0x7a, 0xef,
+	0xd0, 0xcd, 0x4a, 0x71, 0x3a, 0xe1, 0xe4, 0x2b, 0xe8, 0x4d, 0x85, 0xe9, 0xc1, 0x5c, 0xb9, 0x8e,
+	0xf8, 0x16, 0x46, 0xc7, 0x56, 0x1e, 0x0a, 0x20, 0x1f, 0xb7, 0x80, 0xf4, 0xe1, 0x1a, 0xce, 0x42,
+	0x54, 0x5e, 0xce, 0x54, 0x1a, 0xb3, 0x2c, 0xca, 0x79, 0x2e, 0xe4, 0x0c, 0x0f, 0x6f, 0xd1, 0x1d,
+	0x04, 0x5f, 0xd4, 0xd8, 0x10, 0x21, 0x73, 0x23, 0xb0, 0xb7, 0x2c, 0xcd, 0xd8, 0x24, 0xe3, 0x66,
+	0x0d, 0x2a, 0xcc, 0x67, 0x83, 0x76, 0xe7, 0xd1, 0x41, 0x59, 0xa9, 0xf0, 0x77, 0x07, 0x3a, 0xcd,
+	0xc4, 0x11, 0x02, 0xad, 0x84, 0xab, 0x18, 0x6d, 0x5d, 0x8a, 0xbf, 0x4d, 0x0c, 0xdf, 0xae, 0xbd,
+	0xac, 0xf0, 0x37, 0xb9, 0x0d, 0xa0, 0x34, 0x93, 0x1a, 0x6f, 0x3c, 0xac, 0xa3, 0x45, 0x5d, 0x8c,
+	0x98, 0x8b, 0x8e, 0xdc, 0x02, 0x57, 0x72, 0x96, 0x59, 0xb4, 0x85, 0x68, 0xc7, 0x04, 0x10, 0xbc,
+	0x0d, 0x60, 0x93, 0x37, 0x8d, 0xc0, 0x8b, 0xa7, 0x45, 0x5d, 0x1b, 0x19, 0x2b, 0x1e, 0xfe, 0xe9,
+	0x40, 0x6f, 0x28, 0x92, 0x2a, 0xe3, 0x2f, 0x67, 0xa5, 0xad, 0xfe, 0xd7, 0x66, 0x50, 0xed, 0x20,
+	0x60, 0x76, 0xbd, 0xfe, 0xfd, 0xd5, 0x1b, 0xf5, 0x03, 0xa9, 0x9d, 0x5b, 0xdb, 0xd0, 0xa5, 0xdd,
+	0x3a, 0x59, 0x44, 0xc9, 0xff, 0xc1, 0xcb, 0x51, 0x13, 0xe9, 0x59, 0xd9, 0x54, 0x09, 0xf9, 0xdc,
+	0xc6, 0xbc, 0xb7, 0xa2, 0xca, 0x23, 0x31, 0x8d, 0x6c, 0x50, 0x61, 0xbd, 0x5d, 0xba, 0x55, 0x54,
+	0xf9, 0x68, 0x6a, 0xcf, 0x53, 0xe1, 0xfd, 0x7a, 0x40, 0x6a, 0xd7, 0x0f, 0xa6, 0xcc, 0x85, 0x8d,
+	0xf3, 0xd1, 0xe8, 0xcc, 0x8c, 0x63, 0x07, 0x5a, 0xc3, 0xe3, 0xe7, 0xa7, 0xfe, 0x5a, 0x98, 0xc1,
+	0xcd, 0x81, 0x4c, 0xb5, 0x79, 0x61, 0x63, 0xc5, 0xe5, 0x8f, 0xa2, 0x92, 0x05, 0x9f, 0x35, 0xdf,
+	0x66, 0xd3, 0x74, 0x67, 0xa9, 0xe9, 0x47, 0xd0, 0x6e, 0xbe, 0xfd, 0xb5, 0xff, 0xf8, 0x54, 0x97,
+	0xee, 0x14, 0xda, 0x08, 0xc2, 0x09, 0xdc, 0x5a, 0x71, 0x9a, 0x5a, 0xac, 0x82, 0x56, 0x5c, 0xbd,
+	0x51, 0x81, 0x83, 0xfb, 0x6c, 0x75, 0x67, 0xff, 0x3d, 0x5b, 0x8a, 0xe2, 0xf0, 0x0f, 0x07, 0xb6,
+	0x3f, 0x5a, 0x3c, 0x24, 0x80, 0x76, 0xd3, 0x37, 0x07, 0xfb, 0xd6, 0x3c, 0x9a, 0xd5, 0x51, 0xdf,
+	0xcc, 0xb6, 0xa0, 0x2e, 0x9d, 0x3f, 0x93, 0x6f, 0x60, 0xdb, 0x0e, 0x3c, 0xcb, 0x32, 0x11, 0x47,
+	0xb1, 0xa8, 0x0a, 0x5d, 0xcf, 0xd9, 0x55, 0x04, 0x8e, 0x4d, 0x7c, 0x60, 0xc2, 0x64, 0x1f, 0xfc,
+	0x65, 0xae, 0x4a, 0xdf, 0x37, 0x43, 0xd7, 0x5b, 0x50, 0xcf, 0xd3, 0xf7, 0xdc, 0x5c, 0x85, 0x39,
+	0x7b, 0x17, 0x5d, 0x72, 0x56, 0x5a, 0x9a, 0x9d, 0x3e, 0x2f, 0x67, 0xef, 0x7e, 0xe0, 0xac, 0x34,
+	0x9c, 0x93, 0x6b, 0xbf, 0xd4, 0xdb, 0xb6, 0xae, 0x3b, 0xc2, 0x7f, 0x83, 0x7f, 0x07, 0x00, 0x00,
+	0xff, 0xff, 0xa3, 0xdd, 0xbb, 0xb3, 0x1d, 0x0a, 0x00, 0x00,
 }
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 4d6118b..3586be0 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -96,6 +96,12 @@
   optional SoongBuildMetrics soong_build_metrics = 22;
 
   optional BuildConfig build_config = 23;
+
+  // The hostname of the machine.
+  optional string hostname = 24;
+
+  // The system resource information such as total physical memory.
+  optional SystemResourceInfo system_resource_info = 25;
 }
 
 message BuildConfig {
@@ -106,6 +112,14 @@
   optional bool force_use_goma = 3;
 }
 
+message SystemResourceInfo {
+  // The total physical memory in bytes.
+  optional uint64 total_physical_memory = 1;
+
+  // The total of available cores for building
+  optional int32 available_cpus = 2;
+}
+
 message PerfInfo {
   // The description for the phase/action/part while the tool running.
   optional string desc = 1;
diff --git a/ui/metrics/metrics_proto/regen.sh b/ui/metrics/metrics_proto/regen.sh
index 343c638..8eb2d74 100755
--- a/ui/metrics/metrics_proto/regen.sh
+++ b/ui/metrics/metrics_proto/regen.sh
@@ -1,3 +1,17 @@
 #!/bin/bash
 
-aprotoc --go_out=paths=source_relative:. metrics.proto
+# Generates the golang source file of metrics.proto protobuf file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+  die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. metrics.proto; then
+  die "build failed. ${error_msg}"
+fi