Merge "Change bazel_module property to be of struct type instead of string"
diff --git a/android/apex.go b/android/apex.go
index c01b716..3039e79 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -145,11 +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)
-
 	// 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.
@@ -310,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 {
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
index d4f6e4c..210d67a8 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -18,11 +18,15 @@
 	"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.
@@ -188,8 +192,8 @@
 	bazelCmd.Dir = context.workspaceDir
 	bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix())
 
-	var stderr bytes.Buffer
-	bazelCmd.Stderr = &stderr
+	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)
@@ -237,3 +241,28 @@
 	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 33735f8..cf6d596 100644
--- a/android/config.go
+++ b/android/config.go
@@ -941,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 {
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/module.go b/android/module.go
index 056b0a5..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
 }
 
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 d752aec..a9495cc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -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/apex/apex_test.go b/apex/apex_test.go
index cf2c953..c52fd04 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1319,6 +1319,7 @@
 		cc_library {
 			name: "mylib",
 			srcs: ["mylib.cpp"],
+			system_shared_libs: ["libc", "libm"],
 			shared_libs: ["libdl#27"],
 			stl: "none",
 			apex_available: [ "myapex" ],
@@ -5597,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()
 
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/cc/androidmk.go b/cc/androidmk.go
index a2549b8..e58a172 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -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()...)
 	}
@@ -442,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/cc.go b/cc/cc.go
index 8188550..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
@@ -546,9 +548,7 @@
 	dataLibDepTag         = dependencyTag{name: "data lib"}
 	runtimeDepTag         = dependencyTag{name: "runtime lib"}
 	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
-	testForDepTag         = dependencyTag{name: "test for apex"}
-
-	stubImplDepTag = copyDirectlyInAnyApexDependencyTag{name: "stub_impl"}
+	stubImplDepTag        = dependencyTag{name: "stub_impl"}
 )
 
 type copyDirectlyInAnyApexDependencyTag dependencyTag
@@ -618,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
@@ -722,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()))
 }
@@ -786,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()))
 }
@@ -1117,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
 }
@@ -1156,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)
 }
@@ -1454,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()
@@ -1878,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{
@@ -1896,29 +1705,11 @@
 		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 == "" && CanBeOrLinkAgainstVersionVariants(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)
 	}
 }
 
@@ -2016,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
 		}
 	}
 
@@ -2169,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))
@@ -2193,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...)
 
@@ -2384,19 +2167,49 @@
 	}
 }
 
+// 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
@@ -2481,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)
@@ -2511,103 +2314,7 @@
 				return
 			}
 
-			if ccDep.CcLibrary() && !libDepTag.static() {
-				depIsStubs := ccDep.BuildStubs()
-				depHasStubs := CanBeOrLinkAgainstVersionVariants(c) && ccDep.HasStubsVariants()
-				depInSameApexes := android.DirectlyInAllApexes(apexInfo, depName)
-				depInPlatform := !dep.(android.ApexModule).AnyVariantDirectlyInAnyApex()
-
-				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 apexInfo.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
-					}
-					// 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) {
-							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 apexInfo.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
@@ -2618,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:
@@ -2626,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:
@@ -2675,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:
@@ -2699,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()...)
 				}
 			}
 
@@ -2726,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():
@@ -2779,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)
@@ -2799,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)
@@ -3096,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/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 35828aa..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 {
@@ -1324,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()
@@ -1423,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)
 	}
 }
 
@@ -1525,15 +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 stubs depend on the implementation
-			mctx.AddInterVariantDependency(stubImplDepTag, modules[i], modules[0])
+			// The implementation depends on the stubs
+			mctx.AddInterVariantDependency(stubImplDepTag, modules[len(modules)-1], modules[i])
 		}
 	}
 	mctx.AliasVariation("")
@@ -1544,20 +1616,33 @@
 	mctx.CreateAliasVariation("latest", latestVersion)
 }
 
+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
-	UseSdk() bool
 }) bool {
-	return !module.Host() && !module.InRamdisk() && !module.InRecovery() && !module.UseSdk()
+	return !module.Host() && !module.InRamdisk() && !module.InRecovery()
 }
 
 func CanBeVersionVariant(module interface {
 	Host() bool
 	InRamdisk() bool
 	InRecovery() bool
-	UseSdk() bool
 	CcLibraryInterface() bool
 	Shared() bool
 	Static() bool
@@ -1570,29 +1655,18 @@
 // 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 && CanBeVersionVariant(library) {
-
-		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
-			!library.IsSdkVariant() {
-
-			versions := library.StubsVersions()
-			normalizeVersions(mctx, versions)
-			if mctx.Failed() {
+		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())
-			}
 		}
 	}
 }
@@ -1602,6 +1676,16 @@
 func versionMutator(mctx android.BottomUpMutatorContext) {
 	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 765fe71..fcf6069 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -391,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()
@@ -405,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)
@@ -419,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 a67cd4e..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)
@@ -80,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 a429063..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,9 +69,6 @@
 
 	Properties llndkLibraryProperties
 
-	exportHeadersTimestamp android.OptionalPath
-	versionScriptPath      android.ModuleGenPath
-
 	movedToApex bool
 }
 
@@ -93,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
 }
 
@@ -142,12 +138,6 @@
 		stub.movedToApex = implApexModule.DirectlyInAnyApex()
 	}
 
-	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)
-	}
-
 	if len(stub.Properties.Export_preprocessed_headers) > 0 {
 		genHeaderOutDir := android.PathForModuleGen(ctx, "include")
 
@@ -170,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)
 }
 
@@ -181,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/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/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/snapshot_utils.go b/cc/snapshot_utils.go
index b72af44..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
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 529ed60..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
@@ -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
diff --git a/cc/vndk.go b/cc/vndk.go
index 4169e21..981e039 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -620,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()
@@ -639,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"
@@ -671,7 +672,7 @@
 
 		// 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
 		}
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/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/java/aar.go b/java/aar.go
index 8d2a74a..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)
 				}
 			}
 		}
@@ -573,6 +607,22 @@
 	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 {
@@ -625,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
 }
@@ -669,12 +730,12 @@
 	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")
@@ -684,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{
@@ -698,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 f72ee37..c21c83a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -549,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)
 				}
diff --git a/java/app.go b/java/app.go
index e788ca9..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())
diff --git a/java/app_test.go b/java/app_test.go
index 31b422c..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"},
 			},
 		},
 		{
@@ -3382,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/droiddoc.go b/java/droiddoc.go
index b3bb5ab..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
@@ -1067,7 +1060,7 @@
 	case ".api.txt":
 		return android.Paths{d.apiFilePath}, nil
 	case ".removed-api.txt":
-		return android.Paths{d.removedApiFile}, nil
+		return android.Paths{d.removedApiFilePath}, nil
 	case ".annotations.zip":
 		return android.Paths{d.annotationsZip}, nil
 	case ".api_versions.xml":
@@ -1082,7 +1075,7 @@
 }
 
 func (d *Droidstubs) RemovedApiFilePath() android.Path {
-	return d.removedApiFile
+	return d.removedApiFilePath
 }
 
 func (d *Droidstubs) StubsSrcJar() android.Path {
@@ -1133,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") ||
@@ -1141,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) != "" {
@@ -1258,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.
@@ -1386,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.
@@ -1663,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/java.go b/java/java.go
index 2553a30..3ce1885 100644
--- a/java/java.go
+++ b/java/java.go
@@ -547,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 (
@@ -573,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 {
@@ -1001,7 +997,7 @@
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
 
-		if _, ok := tag.(*jniDependencyTag); ok {
+		if IsJniDepTag(tag) {
 			// Handled by AndroidApp.collectAppDeps
 			return
 		}
@@ -2436,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 {
@@ -2476,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...)
 	}
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index ea1e9ed..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)
 	}
 }
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 859dc8d..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
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/allowed_list.go b/rust/config/allowed_list.go
index 678f822..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,6 +11,7 @@
 		"external/crosvm",
 		"external/adhd",
 		"frameworks/native/libs/binder/rust",
+		"packages/modules/Virtualization",
 		"prebuilts/rust",
 		"system/extras/profcollectd",
 		"system/hardware/interfaces/keystore2",
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/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 ba8673c..1b999d7 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -302,9 +302,6 @@
 }
 
 type exportedFlagsProducer interface {
-	exportedLinkDirs() []string
-	exportedDepFlags() []string
-	exportedLinkObjects() []string
 	exportLinkDirs(...string)
 	exportDepFlags(...string)
 	exportLinkObjects(...string)
@@ -316,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...))
 }
@@ -340,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
 }
@@ -499,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 {
@@ -532,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 {
@@ -701,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())
 		}
 	}
 
@@ -846,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 {
@@ -889,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
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/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/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