Merge "Collect metrics from inside soong_build"
diff --git a/Android.bp b/Android.bp
index 0da48a2..78ec9d8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -188,14 +188,15 @@
         "cc/rs.go",
         "cc/sanitize.go",
         "cc/sabi.go",
+        "cc/snapshot_utils.go",
         "cc/stl.go",
         "cc/strip.go",
         "cc/sysprop.go",
         "cc/tidy.go",
         "cc/util.go",
+        "cc/vendor_snapshot.go",
         "cc/vndk.go",
         "cc/vndk_prebuilt.go",
-        "cc/xom.go",
 
         "cc/cflag_artifacts.go",
         "cc/cmakelists.go",
@@ -205,8 +206,10 @@
         "cc/linker.go",
 
         "cc/binary.go",
+        "cc/binary_sdk_member.go",
         "cc/fuzz.go",
         "cc/library.go",
+        "cc/library_headers.go",
         "cc/library_sdk_member.go",
         "cc/object.go",
         "cc/test.go",
@@ -232,6 +235,7 @@
         "cc/compiler_test.go",
         "cc/gen_test.go",
         "cc/genrule_test.go",
+        "cc/library_headers_test.go",
         "cc/library_test.go",
         "cc/object_test.go",
         "cc/prebuilt_test.go",
@@ -534,6 +538,7 @@
         "sdk/update.go",
     ],
     testSrcs: [
+        "sdk/bp_test.go",
         "sdk/cc_sdk_test.go",
         "sdk/exports_test.go",
         "sdk/java_sdk_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index dbf3aa8..a8153cc 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -236,8 +236,8 @@
 		}
 	}
 
-	if amod.noticeFile.Valid() {
-		a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
+	if len(amod.noticeFiles) > 0 {
+		a.SetString("LOCAL_NOTICE_FILE", strings.Join(amod.noticeFiles.Strings(), " "))
 	}
 
 	if host {
diff --git a/android/apex.go b/android/apex.go
index a4b6956..43a42df 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,14 @@
 	"sync"
 )
 
+type ApexInfo struct {
+	// Name of the apex variant that this module is mutated into
+	ApexName string
+
+	// Whether this apex variant needs to target Android 10
+	LegacyAndroid10Support bool
+}
+
 // ApexModule is the interface that a module type is expected to implement if
 // the module has to be built differently depending on whether the module
 // is destined for an apex or not (installed to one of the regular partitions).
@@ -38,9 +46,12 @@
 	Module
 	apexModuleBase() *ApexModuleBase
 
-	// Marks that this module should be built for the APEX of the specified name.
+	// Marks that this module should be built for the specified APEXes.
 	// Call this before apex.apexMutator is run.
-	BuildForApex(apexName string)
+	BuildForApexes(apexes []ApexInfo)
+
+	// Returns the APEXes that this module will be built for
+	ApexVariations() []ApexInfo
 
 	// Returns the name of APEX that this module will be built for. Empty string
 	// is returned when 'IsForPlatform() == true'. Note that a module can be
@@ -66,13 +77,9 @@
 	IsInstallableToApex() bool
 
 	// Mutate this module into one or more variants each of which is built
-	// for an APEX marked via BuildForApex().
+	// for an APEX marked via BuildForApexes().
 	CreateApexVariations(mctx BottomUpMutatorContext) []Module
 
-	// Sets the name of the apex variant of this module. Called inside
-	// CreateApexVariations.
-	setApexName(apexName string)
-
 	// Tests if this module is available for the specified APEX or ":platform"
 	AvailableFor(what string) bool
 
@@ -88,12 +95,10 @@
 	//
 	// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
 	// "//apex_available:platform" refers to non-APEX partitions like "system.img".
-	// Default is ["//apex_available:platform", "//apex_available:anyapex"].
-	// TODO(b/128708192) change the default to ["//apex_available:platform"]
+	// Default is ["//apex_available:platform"].
 	Apex_available []string
 
-	// Name of the apex variant that this module is mutated into
-	ApexName string `blueprint:"mutated"`
+	Info ApexInfo `blueprint:"mutated"`
 }
 
 // Provides default implementation for the ApexModule interface. APEX-aware
@@ -104,31 +109,37 @@
 	canHaveApexVariants bool
 
 	apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
-	apexVariations     []string
+	apexVariations     []ApexInfo
 }
 
 func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
 	return m
 }
 
-func (m *ApexModuleBase) BuildForApex(apexName string) {
+func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
 	m.apexVariationsLock.Lock()
 	defer m.apexVariationsLock.Unlock()
-	if !InList(apexName, m.apexVariations) {
-		m.apexVariations = append(m.apexVariations, apexName)
+nextApex:
+	for _, apex := range apexes {
+		for _, v := range m.apexVariations {
+			if v.ApexName == apex.ApexName {
+				continue nextApex
+			}
+		}
+		m.apexVariations = append(m.apexVariations, apex)
 	}
 }
 
+func (m *ApexModuleBase) ApexVariations() []ApexInfo {
+	return m.apexVariations
+}
+
 func (m *ApexModuleBase) ApexName() string {
-	return m.ApexProperties.ApexName
+	return m.ApexProperties.Info.ApexName
 }
 
 func (m *ApexModuleBase) IsForPlatform() bool {
-	return m.ApexProperties.ApexName == ""
-}
-
-func (m *ApexModuleBase) setApexName(apexName string) {
-	m.ApexProperties.ApexName = apexName
+	return m.ApexProperties.Info.ApexName == ""
 }
 
 func (m *ApexModuleBase) CanHaveApexVariants() bool {
@@ -177,25 +188,35 @@
 	}
 }
 
+type byApexName []ApexInfo
+
+func (a byApexName) Len() int           { return len(a) }
+func (a byApexName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName }
+
 func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
 	if len(m.apexVariations) > 0 {
 		m.checkApexAvailableProperty(mctx)
-		sort.Strings(m.apexVariations)
+
+		sort.Sort(byApexName(m.apexVariations))
 		variations := []string{}
-		availableForPlatform := mctx.Module().(ApexModule).AvailableFor(AvailableToPlatform) || mctx.Host()
-		if availableForPlatform {
-			variations = append(variations, "") // Original variation for platform
+		variations = append(variations, "") // Original variation for platform
+		for _, apex := range m.apexVariations {
+			variations = append(variations, apex.ApexName)
 		}
-		variations = append(variations, m.apexVariations...)
 
 		defaultVariation := ""
 		mctx.SetDefaultDependencyVariation(&defaultVariation)
+
 		modules := mctx.CreateVariations(variations...)
-		for i, m := range modules {
-			if availableForPlatform && i == 0 {
-				continue
+		for i, mod := range modules {
+			platformVariation := i == 0
+			if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
+				mod.SkipInstall()
 			}
-			m.(ApexModule).setApexName(variations[i])
+			if !platformVariation {
+				mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
+			}
 		}
 		return modules
 	}
@@ -219,18 +240,20 @@
 }
 
 // Update the map to mark that a module named moduleName is directly or indirectly
-// depended on by an APEX named apexName. Directly depending means that a module
+// depended on by the specified APEXes. Directly depending means that a module
 // is explicitly listed in the build definition of the APEX via properties like
 // native_shared_libs, java_libs, etc.
-func UpdateApexDependency(apexName string, moduleName string, directDep bool) {
+func UpdateApexDependency(apexes []ApexInfo, moduleName string, directDep bool) {
 	apexNamesMapMutex.Lock()
 	defer apexNamesMapMutex.Unlock()
-	apexNames, ok := apexNamesMap()[moduleName]
-	if !ok {
-		apexNames = make(map[string]bool)
-		apexNamesMap()[moduleName] = apexNames
+	for _, apex := range apexes {
+		apexesForModule, ok := apexNamesMap()[moduleName]
+		if !ok {
+			apexesForModule = make(map[string]bool)
+			apexNamesMap()[moduleName] = apexesForModule
+		}
+		apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep
 	}
-	apexNames[apexName] = apexNames[apexName] || directDep
 }
 
 // TODO(b/146393795): remove this when b/146393795 is fixed
diff --git a/android/arch.go b/android/arch.go
index 3657e6d..73a490d 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -765,7 +765,7 @@
 	}
 
 	if len(moduleOSList) == 0 {
-		base.commonProperties.Enabled = boolPtr(false)
+		base.Disable()
 		return
 	}
 
@@ -869,7 +869,7 @@
 	}
 
 	if len(targets) == 0 {
-		base.commonProperties.Enabled = boolPtr(false)
+		base.Disable()
 		return
 	}
 
@@ -1521,12 +1521,7 @@
 
 // hasArmAbi returns true if arch has at least one arm ABI
 func hasArmAbi(arch Arch) bool {
-	for _, abi := range arch.Abi {
-		if strings.HasPrefix(abi, "arm") {
-			return true
-		}
-	}
-	return false
+	return PrefixInList(arch.Abi, "arm")
 }
 
 // hasArmArch returns true if targets has at least non-native_bridge arm Android arch
diff --git a/android/config.go b/android/config.go
index d0ac4c3..b2bda2a 100644
--- a/android/config.go
+++ b/android/config.go
@@ -265,7 +265,7 @@
 
 	config.Targets = map[OsType][]Target{
 		Fuchsia: []Target{
-			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: ""}, NativeBridgeDisabled, "", ""},
+			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
 		},
 		BuildOs: []Target{
 			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
@@ -570,8 +570,8 @@
 	return String(c.productVariables.BuildId)
 }
 
-func (c *config) BuildNumberFromFile() string {
-	return String(c.productVariables.BuildNumberFromFile)
+func (c *config) BuildNumberFile(ctx PathContext) Path {
+	return PathForOutput(ctx, String(c.productVariables.BuildNumberFile))
 }
 
 // DeviceName returns the name of the current device target
@@ -790,14 +790,6 @@
 	return Bool(c.productVariables.DisableScudo)
 }
 
-func (c *config) EnableXOM() bool {
-	if c.productVariables.EnableXOM == nil {
-		return true
-	} else {
-		return Bool(c.productVariables.EnableXOM)
-	}
-}
-
 func (c *config) Android64() bool {
 	for _, t := range c.Targets[Android] {
 		if t.Arch.ArchType.Multilib == "lib64" {
@@ -898,11 +890,7 @@
 func (c *config) EnforceRROExcludedOverlay(path string) bool {
 	excluded := c.productVariables.EnforceRROExcludedOverlays
 	if excluded != nil {
-		for _, exclude := range excluded {
-			if strings.HasPrefix(path, exclude) {
-				return true
-			}
-		}
+		return HasAnyPrefix(path, excluded)
 	}
 	return false
 }
@@ -923,8 +911,23 @@
 	return c.productVariables.ModulesLoadedByPrivilegedModules
 }
 
+// Expected format for apexJarValue = <apex name>:<jar name>
+func SplitApexJarPair(apexJarValue string) (string, string) {
+	var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
+	if apexJarPair == nil || len(apexJarPair) != 2 {
+		panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
+			apexJarValue))
+	}
+	return apexJarPair[0], apexJarPair[1]
+}
+
 func (c *config) BootJars() []string {
-	return c.productVariables.BootJars
+	jars := c.productVariables.BootJars
+	for _, p := range c.productVariables.UpdatableBootJars {
+		_, jar := SplitApexJarPair(p)
+		jars = append(jars, jar)
+	}
+	return jars
 }
 
 func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
@@ -1043,12 +1046,12 @@
 func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
 	coverage := false
 	if c.config.productVariables.CoveragePaths != nil {
-		if InList("*", c.config.productVariables.CoveragePaths) || PrefixInList(path, c.config.productVariables.CoveragePaths) {
+		if InList("*", c.config.productVariables.CoveragePaths) || HasAnyPrefix(path, c.config.productVariables.CoveragePaths) {
 			coverage = true
 		}
 	}
 	if coverage && c.config.productVariables.CoverageExcludePaths != nil {
-		if PrefixInList(path, c.config.productVariables.CoverageExcludePaths) {
+		if HasAnyPrefix(path, c.config.productVariables.CoverageExcludePaths) {
 			coverage = false
 		}
 	}
@@ -1121,28 +1124,21 @@
 	if c.productVariables.IntegerOverflowExcludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, c.productVariables.IntegerOverflowExcludePaths)
+	return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths)
 }
 
 func (c *config) CFIDisabledForPath(path string) bool {
 	if c.productVariables.CFIExcludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, c.productVariables.CFIExcludePaths)
+	return HasAnyPrefix(path, c.productVariables.CFIExcludePaths)
 }
 
 func (c *config) CFIEnabledForPath(path string) bool {
 	if c.productVariables.CFIIncludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, c.productVariables.CFIIncludePaths)
-}
-
-func (c *config) XOMDisabledForPath(path string) bool {
-	if c.productVariables.XOMExcludePaths == nil {
-		return false
-	}
-	return PrefixInList(path, c.productVariables.XOMExcludePaths)
+	return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
 }
 
 func (c *config) VendorConfig(name string) VendorConfig {
diff --git a/android/defaults.go b/android/defaults.go
index 7597446..fd707a4 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
 package android
 
 import (
+	"reflect"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -30,16 +32,18 @@
 }
 
 type DefaultableModuleBase struct {
-	defaultsProperties    defaultsProperties
-	defaultableProperties []interface{}
+	defaultsProperties            defaultsProperties
+	defaultableProperties         []interface{}
+	defaultableVariableProperties interface{}
 }
 
 func (d *DefaultableModuleBase) defaults() *defaultsProperties {
 	return &d.defaultsProperties
 }
 
-func (d *DefaultableModuleBase) setProperties(props []interface{}) {
+func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) {
 	d.defaultableProperties = props
+	d.defaultableVariableProperties = variableProperties
 }
 
 // Interface that must be supported by any module to which defaults can be applied.
@@ -48,7 +52,7 @@
 	defaults() *defaultsProperties
 
 	// Set the property structures into which defaults will be added.
-	setProperties([]interface{})
+	setProperties(props []interface{}, variableProperties interface{})
 
 	// Apply defaults from the supplied Defaults to the property structures supplied to
 	// setProperties(...).
@@ -63,7 +67,10 @@
 var _ Defaultable = (*DefaultableModuleBase)(nil)
 
 func InitDefaultableModule(module DefaultableModule) {
-	module.setProperties(module.(Module).GetProperties())
+	if module.(Module).base().module == nil {
+		panic("InitAndroidModule must be called before InitDefaultableModule")
+	}
+	module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
 
 	module.AddProperties(module.defaults())
 }
@@ -114,6 +121,8 @@
 	// Get the structures containing the properties for which defaults can be provided.
 	properties() []interface{}
 
+	productVariableProperties() interface{}
+
 	// Return the defaults common properties.
 	common() *commonProperties
 
@@ -134,6 +143,10 @@
 	return d.defaultableProperties
 }
 
+func (d *DefaultsModuleBase) productVariableProperties() interface{} {
+	return d.defaultableVariableProperties
+}
+
 func (d *DefaultsModuleBase) common() *commonProperties {
 	return &d.commonProperties
 }
@@ -151,9 +164,10 @@
 	module.AddProperties(
 		&hostAndDeviceProperties{},
 		commonProperties,
-		&variableProperties{},
 		&ApexProperties{})
 
+	initAndroidModuleBase(module)
+	initProductVariableModule(module)
 	InitArchModule(module)
 	InitDefaultableModule(module)
 
@@ -185,16 +199,57 @@
 
 	for _, defaults := range defaultsList {
 		for _, prop := range defaultable.defaultableProperties {
-			for _, def := range defaults.properties() {
-				if proptools.TypeEqual(prop, def) {
-					err := proptools.PrependProperties(prop, def, nil)
-					if err != nil {
-						if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
-							ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
-						} else {
-							panic(err)
-						}
-					}
+			if prop == defaultable.defaultableVariableProperties {
+				defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
+			} else {
+				defaultable.applyDefaultProperties(ctx, defaults, prop)
+			}
+		}
+	}
+}
+
+// Product variable properties need special handling, the type of the filtered product variable
+// property struct may not be identical between the defaults module and the defaultable module.
+// Use PrependMatchingProperties to apply whichever properties match.
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
+	defaults Defaults, defaultableProp interface{}) {
+	if defaultableProp == nil {
+		return
+	}
+
+	defaultsProp := defaults.productVariableProperties()
+	if defaultsProp == nil {
+		return
+	}
+
+	dst := []interface{}{
+		defaultableProp,
+		// Put an empty copy of the src properties into dst so that properties in src that are not in dst
+		// don't cause a "failed to find property to extend" error.
+		proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
+	}
+
+	err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
+	if err != nil {
+		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+		} else {
+			panic(err)
+		}
+	}
+}
+
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+	defaults Defaults, defaultableProp interface{}) {
+
+	for _, def := range defaults.properties() {
+		if proptools.TypeEqual(defaultableProp, def) {
+			err := proptools.PrependProperties(defaultableProp, def, nil)
+			if err != nil {
+				if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+					ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+				} else {
+					panic(err)
 				}
 			}
 		}
diff --git a/android/defaults_test.go b/android/defaults_test.go
index ba607ef..d096b2f 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"reflect"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
@@ -40,8 +41,8 @@
 func defaultsTestModuleFactory() Module {
 	module := &defaultsTestModule{}
 	module.AddProperties(&module.properties)
-	InitDefaultableModule(module)
 	InitAndroidModule(module)
+	InitDefaultableModule(module)
 	return module
 }
 
@@ -57,6 +58,49 @@
 	return defaults
 }
 
+func TestDefaults(t *testing.T) {
+	bp := `
+		defaults {
+			name: "transitive",
+			foo: ["transitive"],
+		}
+
+		defaults {
+			name: "defaults",
+			defaults: ["transitive"],
+			foo: ["defaults"],
+		}
+
+		test {
+			name: "foo",
+			defaults: ["defaults"],
+			foo: ["module"],
+		}
+	`
+
+	config := TestConfig(buildDir, nil, bp, nil)
+
+	ctx := NewTestContext()
+
+	ctx.RegisterModuleType("test", defaultsTestModuleFactory)
+	ctx.RegisterModuleType("defaults", defaultsTestDefaultsFactory)
+
+	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	foo := ctx.ModuleForTests("foo", "").Module().(*defaultsTestModule)
+
+	if g, w := foo.properties.Foo, []string{"transitive", "defaults", "module"}; !reflect.DeepEqual(g, w) {
+		t.Errorf("expected foo %q, got %q", w, g)
+	}
+}
+
 func TestDefaultsAllowMissingDependencies(t *testing.T) {
 	bp := `
 		defaults {
diff --git a/android/module.go b/android/module.go
index 96c2e1e..1026bdf 100644
--- a/android/module.go
+++ b/android/module.go
@@ -172,6 +172,7 @@
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
+	InstallForceOS() *OsType
 
 	RequiredModuleNames() []string
 	HostRequiredModuleNames() []string
@@ -204,6 +205,7 @@
 	DepsMutator(BottomUpMutatorContext)
 
 	base() *ModuleBase
+	Disable()
 	Enabled() bool
 	Target() Target
 	InstallInData() bool
@@ -213,9 +215,12 @@
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
+	InstallForceOS() *OsType
 	SkipInstall()
 	ExportedToMake() bool
-	NoticeFile() OptionalPath
+	InitRc() Paths
+	VintfFragments() Paths
+	NoticeFiles() Paths
 
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
@@ -239,6 +244,8 @@
 	RequiredModuleNames() []string
 	HostRequiredModuleNames() []string
 	TargetRequiredModuleNames() []string
+
+	filesToInstall() InstallPaths
 }
 
 // Qualified id for a module
@@ -291,6 +298,12 @@
 
 type commonProperties struct {
 	// emit build rules for this module
+	//
+	// Disabling a module should only be done for those modules that cannot be built
+	// in the current environment. Modules that can build in the current environment
+	// but are not usually required (e.g. superceded by a prebuilt) should not be
+	// disabled as that will prevent them from being built by the checkbuild target
+	// and so prevent early detection of changes that have broken those modules.
 	Enabled *bool `android:"arch_variant"`
 
 	// Controls the visibility of this module to other modules. Allowable values are one or more of
@@ -537,16 +550,7 @@
 		&base.nameProperties,
 		&base.commonProperties)
 
-	// Allow tests to override the default product variables
-	if base.variableProperties == nil {
-		base.variableProperties = zeroProductVariables
-	}
-
-	// Filter the product variables properties to the ones that exist on this module
-	base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties)
-	if base.variableProperties != nil {
-		m.AddProperties(base.variableProperties)
-	}
+	initProductVariableModule(m)
 
 	base.generalProperties = m.GetProperties()
 	base.customizableProperties = m.GetProperties()
@@ -643,9 +647,9 @@
 	primaryVisibilityProperty visibilityProperty
 
 	noAddressSanitizer bool
-	installFiles       Paths
+	installFiles       InstallPaths
 	checkbuildFiles    Paths
-	noticeFile         OptionalPath
+	noticeFiles        Paths
 
 	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
 	// Only set on the final variant of each module
@@ -662,6 +666,9 @@
 	ruleParams  map[blueprint.Rule]blueprint.RuleParams
 	variables   map[string]string
 
+	initRcPaths         Paths
+	vintfFragmentsPaths Paths
+
 	prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
 }
 
@@ -834,6 +841,10 @@
 	return *m.commonProperties.Enabled
 }
 
+func (m *ModuleBase) Disable() {
+	m.commonProperties.Enabled = proptools.BoolPtr(false)
+}
+
 func (m *ModuleBase) SkipInstall() {
 	m.commonProperties.SkipInstall = true
 }
@@ -842,22 +853,20 @@
 	return m.commonProperties.NamespaceExportedToMake
 }
 
-func (m *ModuleBase) computeInstallDeps(
-	ctx blueprint.ModuleContext) Paths {
+func (m *ModuleBase) computeInstallDeps(ctx blueprint.ModuleContext) InstallPaths {
 
-	result := Paths{}
+	var result InstallPaths
 	// TODO(ccross): we need to use WalkDeps and have some way to know which dependencies require installation
-	ctx.VisitDepsDepthFirstIf(isFileInstaller,
-		func(m blueprint.Module) {
-			fileInstaller := m.(fileInstaller)
-			files := fileInstaller.filesToInstall()
-			result = append(result, files...)
-		})
+	ctx.VisitDepsDepthFirst(func(m blueprint.Module) {
+		if a, ok := m.(Module); ok {
+			result = append(result, a.filesToInstall()...)
+		}
+	})
 
 	return result
 }
 
-func (m *ModuleBase) filesToInstall() Paths {
+func (m *ModuleBase) filesToInstall() InstallPaths {
 	return m.installFiles
 }
 
@@ -893,12 +902,16 @@
 	return false
 }
 
+func (m *ModuleBase) InstallForceOS() *OsType {
+	return nil
+}
+
 func (m *ModuleBase) Owner() string {
 	return String(m.commonProperties.Owner)
 }
 
-func (m *ModuleBase) NoticeFile() OptionalPath {
-	return m.noticeFile
+func (m *ModuleBase) NoticeFiles() Paths {
+	return m.noticeFiles
 }
 
 func (m *ModuleBase) setImageVariation(variant string) {
@@ -932,9 +945,17 @@
 	return m.base().commonProperties.Target_required
 }
 
+func (m *ModuleBase) InitRc() Paths {
+	return append(Paths{}, m.initRcPaths...)
+}
+
+func (m *ModuleBase) VintfFragments() Paths {
+	return append(Paths{}, m.vintfFragmentsPaths...)
+}
+
 func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
-	allInstalledFiles := Paths{}
-	allCheckbuildFiles := Paths{}
+	var allInstalledFiles InstallPaths
+	var allCheckbuildFiles Paths
 	ctx.VisitAllModuleVariants(func(module Module) {
 		a := module.base()
 		allInstalledFiles = append(allInstalledFiles, a.installFiles...)
@@ -953,7 +974,7 @@
 		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
 			Output:    name,
-			Implicits: allInstalledFiles,
+			Implicits: allInstalledFiles.Paths(),
 			Default:   !ctx.Config().EmbeddedInMake(),
 		})
 		deps = append(deps, name)
@@ -1097,6 +1118,9 @@
 	if !ctx.PrimaryArch() {
 		suffix = append(suffix, ctx.Arch().ArchType.String())
 	}
+	if apex, ok := m.module.(ApexModule); ok && !apex.IsForPlatform() {
+		suffix = append(suffix, apex.ApexName())
+	}
 
 	ctx.Variable(pctx, "moduleDesc", desc)
 
@@ -1133,12 +1157,25 @@
 			}
 		})
 
-		notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
+		m.noticeFiles = make([]Path, 0)
+		optPath := OptionalPath{}
+		notice := proptools.StringDefault(m.commonProperties.Notice, "")
 		if module := SrcIsModule(notice); module != "" {
-			m.noticeFile = ctx.ExpandOptionalSource(&notice, "notice")
-		} else {
+			optPath = ctx.ExpandOptionalSource(&notice, "notice")
+		} else if notice != "" {
 			noticePath := filepath.Join(ctx.ModuleDir(), notice)
-			m.noticeFile = ExistentPathForSource(ctx, noticePath)
+			optPath = ExistentPathForSource(ctx, noticePath)
+		}
+		if optPath.Valid() {
+			m.noticeFiles = append(m.noticeFiles, optPath.Path())
+		} else {
+			for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} {
+				noticePath := filepath.Join(ctx.ModuleDir(), notice)
+				optPath = ExistentPathForSource(ctx, noticePath)
+				if optPath.Valid() {
+					m.noticeFiles = append(m.noticeFiles, optPath.Path())
+				}
+			}
 		}
 
 		m.module.GenerateAndroidBuildActions(ctx)
@@ -1148,6 +1185,8 @@
 
 		m.installFiles = append(m.installFiles, ctx.installFiles...)
 		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
+		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
 	} else if ctx.Config().AllowMissingDependencies() {
 		// If the module is not enabled it will not create any build rules, nothing will call
 		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -1261,7 +1300,7 @@
 func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { return b.bp.OtherModuleName(m) }
 func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string  { return b.bp.OtherModuleDir(m) }
 func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
-	b.bp.OtherModuleErrorf(m, fmt, args)
+	b.bp.OtherModuleErrorf(m, fmt, args...)
 }
 func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
 	return b.bp.OtherModuleDependencyTag(m)
@@ -1276,8 +1315,8 @@
 type moduleContext struct {
 	bp blueprint.ModuleContext
 	baseModuleContext
-	installDeps     Paths
-	installFiles    Paths
+	installDeps     InstallPaths
+	installFiles    InstallPaths
 	checkbuildFiles Paths
 	module          Module
 
@@ -1683,6 +1722,10 @@
 	return m.module.InstallBypassMake()
 }
 
+func (m *moduleContext) InstallForceOS() *OsType {
+	return m.module.InstallForceOS()
+}
+
 func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool {
 	if m.module.base().commonProperties.SkipInstall {
 		return true
@@ -1726,7 +1769,7 @@
 
 	if !m.skipInstall(fullInstallPath) {
 
-		deps = append(deps, m.installDeps...)
+		deps = append(deps, m.installDeps.Paths()...)
 
 		var implicitDeps, orderOnlyDeps Paths
 
@@ -1807,20 +1850,6 @@
 	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 }
 
-type fileInstaller interface {
-	filesToInstall() Paths
-}
-
-func isFileInstaller(m blueprint.Module) bool {
-	_, ok := m.(fileInstaller)
-	return ok
-}
-
-func isAndroidModule(m blueprint.Module) bool {
-	_, ok := m.(Module)
-	return ok
-}
-
 func findStringInSlice(str string, slice []string) int {
 	for i, s := range slice {
 		if s == str {
diff --git a/android/neverallow.go b/android/neverallow.go
index cef73fb..0cb2029 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -111,7 +111,9 @@
 
 		// TODO(b/67974785): always enforce the manifest
 		NeverAllow().
-			Without("name", "libhidltransport-impl-internal").
+			Without("name", "libhidlbase-combined-impl").
+			Without("name", "libhidlbase").
+			Without("name", "libhidlbase_pgo").
 			With("product_variables.enforce_vintf_manifest.cflags", "*").
 			Because("manifest enforcement should be independent of ."),
 
@@ -405,8 +407,8 @@
 }
 
 func (r *rule) appliesToPath(dir string) bool {
-	includePath := len(r.paths) == 0 || hasAnyPrefix(dir, r.paths)
-	excludePath := hasAnyPrefix(dir, r.unlessPaths)
+	includePath := len(r.paths) == 0 || HasAnyPrefix(dir, r.paths)
+	excludePath := HasAnyPrefix(dir, r.unlessPaths)
 	return includePath && !excludePath
 }
 
@@ -472,15 +474,6 @@
 	return names
 }
 
-func hasAnyPrefix(s string, prefixes []string) bool {
-	for _, prefix := range prefixes {
-		if strings.HasPrefix(s, prefix) {
-			return true
-		}
-	}
-	return false
-}
-
 func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
 	for _, v := range props {
 		if hasProperty(properties, v) {
diff --git a/android/paths.go b/android/paths.go
index 66725c6..8b373da 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -53,6 +53,7 @@
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
+	InstallForceOS() *OsType
 }
 
 var _ ModuleInstallPathContext = ModuleContext(nil)
@@ -1205,22 +1206,40 @@
 // PathForModuleInstall returns a Path representing the install path for the
 // module appended with paths...
 func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
+	os := ctx.Os()
+	if forceOS := ctx.InstallForceOS(); forceOS != nil {
+		os = *forceOS
+	}
+	partition := modulePartition(ctx, os)
+
+	ret := pathForInstall(ctx, os, partition, ctx.Debug(), pathComponents...)
+
+	if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
+		ret = ret.ToMakePath()
+	}
+
+	return ret
+}
+
+func pathForInstall(ctx PathContext, os OsType, partition string, debug bool,
+	pathComponents ...string) InstallPath {
+
 	var outPaths []string
-	if ctx.Device() {
-		partition := modulePartition(ctx)
+
+	if os.Class == Device {
 		outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
 	} else {
-		switch ctx.Os() {
+		switch os {
 		case Linux:
-			outPaths = []string{"host", "linux-x86"}
+			outPaths = []string{"host", "linux-x86", partition}
 		case LinuxBionic:
 			// TODO: should this be a separate top level, or shared with linux-x86?
-			outPaths = []string{"host", "linux_bionic-x86"}
+			outPaths = []string{"host", "linux_bionic-x86", partition}
 		default:
-			outPaths = []string{"host", ctx.Os().String() + "-x86"}
+			outPaths = []string{"host", os.String() + "-x86", partition}
 		}
 	}
-	if ctx.Debug() {
+	if debug {
 		outPaths = append([]string{"debug"}, outPaths...)
 	}
 	outPaths = append(outPaths, pathComponents...)
@@ -1231,9 +1250,6 @@
 	}
 
 	ret := InstallPath{basePath{path, ctx.Config(), ""}, ""}
-	if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
-		ret = ret.ToMakePath()
-	}
 
 	return ret
 }
@@ -1253,47 +1269,76 @@
 	return "/" + rel
 }
 
-func modulePartition(ctx ModuleInstallPathContext) string {
+func modulePartition(ctx ModuleInstallPathContext, os OsType) string {
 	var partition string
-	if ctx.InstallInData() {
-		partition = "data"
-	} else if ctx.InstallInTestcases() {
+	if ctx.InstallInTestcases() {
+		// "testcases" install directory can be used for host or device modules.
 		partition = "testcases"
-	} else if ctx.InstallInRamdisk() {
-		if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
-			partition = "recovery/root/first_stage_ramdisk"
+	} else if os.Class == Device {
+		if ctx.InstallInData() {
+			partition = "data"
+		} else if ctx.InstallInRamdisk() {
+			if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
+				partition = "recovery/root/first_stage_ramdisk"
+			} else {
+				partition = "ramdisk"
+			}
+			if !ctx.InstallInRoot() {
+				partition += "/system"
+			}
+		} else if ctx.InstallInRecovery() {
+			if ctx.InstallInRoot() {
+				partition = "recovery/root"
+			} else {
+				// the layout of recovery partion is the same as that of system partition
+				partition = "recovery/root/system"
+			}
+		} else if ctx.SocSpecific() {
+			partition = ctx.DeviceConfig().VendorPath()
+		} else if ctx.DeviceSpecific() {
+			partition = ctx.DeviceConfig().OdmPath()
+		} else if ctx.ProductSpecific() {
+			partition = ctx.DeviceConfig().ProductPath()
+		} else if ctx.SystemExtSpecific() {
+			partition = ctx.DeviceConfig().SystemExtPath()
+		} else if ctx.InstallInRoot() {
+			partition = "root"
 		} else {
-			partition = "ramdisk"
+			partition = "system"
 		}
-		if !ctx.InstallInRoot() {
-			partition += "/system"
+		if ctx.InstallInSanitizerDir() {
+			partition = "data/asan/" + partition
 		}
-	} else if ctx.InstallInRecovery() {
-		if ctx.InstallInRoot() {
-			partition = "recovery/root"
-		} else {
-			// the layout of recovery partion is the same as that of system partition
-			partition = "recovery/root/system"
-		}
-	} else if ctx.SocSpecific() {
-		partition = ctx.DeviceConfig().VendorPath()
-	} else if ctx.DeviceSpecific() {
-		partition = ctx.DeviceConfig().OdmPath()
-	} else if ctx.ProductSpecific() {
-		partition = ctx.DeviceConfig().ProductPath()
-	} else if ctx.SystemExtSpecific() {
-		partition = ctx.DeviceConfig().SystemExtPath()
-	} else if ctx.InstallInRoot() {
-		partition = "root"
-	} else {
-		partition = "system"
-	}
-	if ctx.InstallInSanitizerDir() {
-		partition = "data/asan/" + partition
 	}
 	return partition
 }
 
+type InstallPaths []InstallPath
+
+// Paths returns the InstallPaths as a Paths
+func (p InstallPaths) Paths() Paths {
+	if p == nil {
+		return nil
+	}
+	ret := make(Paths, len(p))
+	for i, path := range p {
+		ret[i] = path
+	}
+	return ret
+}
+
+// Strings returns the string forms of the install paths.
+func (p InstallPaths) Strings() []string {
+	if p == nil {
+		return nil
+	}
+	ret := make([]string, len(p))
+	for i, path := range p {
+		ret[i] = path.String()
+	}
+	return ret
+}
+
 // validateSafePath validates a path that we trust (may contain ninja variables).
 // Ensures that each path component does not attempt to leave its component.
 func validateSafePath(pathComponents ...string) (string, error) {
diff --git a/android/paths_test.go b/android/paths_test.go
index 7a32026..f1908ac 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -205,6 +205,7 @@
 	inRamdisk      bool
 	inRecovery     bool
 	inRoot         bool
+	forceOS        *OsType
 }
 
 func (m moduleInstallPathContextImpl) Config() Config {
@@ -241,6 +242,10 @@
 	return false
 }
 
+func (m moduleInstallPathContextImpl) InstallForceOS() *OsType {
+	return m.forceOS
+}
+
 func pathTestConfig(buildDir string) Config {
 	return TestConfig(buildDir, nil, "", nil)
 }
@@ -598,6 +603,40 @@
 			},
 			in:  []string{"nativetest", "my_test"},
 			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+		}, {
+			name: "device testcases",
+			ctx: &moduleInstallPathContextImpl{
+				baseModuleContext: baseModuleContext{
+					os:     deviceTarget.Os,
+					target: deviceTarget,
+				},
+				inTestcases: true,
+			},
+			in:  []string{"my_test", "my_test_bin"},
+			out: "target/product/test_device/testcases/my_test/my_test_bin",
+		}, {
+			name: "host testcases",
+			ctx: &moduleInstallPathContextImpl{
+				baseModuleContext: baseModuleContext{
+					os:     hostTarget.Os,
+					target: hostTarget,
+				},
+				inTestcases: true,
+			},
+			in:  []string{"my_test", "my_test_bin"},
+			out: "host/linux-x86/testcases/my_test/my_test_bin",
+		}, {
+			name: "forced host testcases",
+			ctx: &moduleInstallPathContextImpl{
+				baseModuleContext: baseModuleContext{
+					os:     deviceTarget.Os,
+					target: deviceTarget,
+				},
+				inTestcases: true,
+				forceOS:     &Linux,
+			},
+			in:  []string{"my_test", "my_test_bin"},
+			out: "host/linux-x86/testcases/my_test/my_test_bin",
 		},
 	}
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index c780cb2..2d16f65 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -62,6 +62,10 @@
 	return "prebuilt_" + name
 }
 
+func (p *Prebuilt) ForcePrefer() {
+	p.properties.Prefer = proptools.BoolPtr(true)
+}
+
 // The below source-related functions and the srcs, src fields are based on an assumption that
 // prebuilt modules have a static source property at the moment. Currently there is only one
 // exception, android_app_import, which chooses a source file depending on the product's DPI
diff --git a/android/rule_builder.go b/android/rule_builder.go
index b4f144a..9005f07 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -162,9 +162,10 @@
 	r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
 }
 
-// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such
-// as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput.  Inputs to a command
-// that are also outputs of another command in the same RuleBuilder are filtered out.
+// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
+// input paths, such as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or
+// RuleBuilderCommand.FlagWithInput.  Inputs to a command that are also outputs of another command
+// in the same RuleBuilder are filtered out.  The list is sorted and duplicates removed.
 func (r *RuleBuilder) Inputs() Paths {
 	outputs := r.outputSet()
 	depFiles := r.depFileSet()
@@ -193,6 +194,28 @@
 	return inputList
 }
 
+// OrderOnlys returns the list of paths that were passed to the RuleBuilderCommand.OrderOnly or
+// RuleBuilderCommand.OrderOnlys.  The list is sorted and duplicates removed.
+func (r *RuleBuilder) OrderOnlys() Paths {
+	orderOnlys := make(map[string]Path)
+	for _, c := range r.commands {
+		for _, orderOnly := range c.orderOnlys {
+			orderOnlys[orderOnly.String()] = orderOnly
+		}
+	}
+
+	var orderOnlyList Paths
+	for _, orderOnly := range orderOnlys {
+		orderOnlyList = append(orderOnlyList, orderOnly)
+	}
+
+	sort.Slice(orderOnlyList, func(i, j int) bool {
+		return orderOnlyList[i].String() < orderOnlyList[j].String()
+	})
+
+	return orderOnlyList
+}
+
 func (r *RuleBuilder) outputSet() map[string]WritablePath {
 	outputs := make(map[string]WritablePath)
 	for _, c := range r.commands {
@@ -203,8 +226,9 @@
 	return outputs
 }
 
-// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such
-// as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput.
+// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
+// output paths, such as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or
+// RuleBuilderCommand.FlagWithInput.  The list is sorted and duplicates removed.
 func (r *RuleBuilder) Outputs() WritablePaths {
 	outputs := r.outputSet()
 
@@ -262,7 +286,8 @@
 	return tools
 }
 
-// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method.
+// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method.  The
+// list is sorted and duplicates removed.
 func (r *RuleBuilder) Tools() Paths {
 	toolsSet := r.toolsSet()
 
@@ -337,6 +362,7 @@
 		ctx.Build(pctx, BuildParams{
 			Rule:        ErrorRule,
 			Outputs:     r.Outputs(),
+			OrderOnly:   r.OrderOnlys(),
 			Description: desc,
 			Args: map[string]string{
 				"error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
@@ -453,6 +479,7 @@
 type RuleBuilderCommand struct {
 	buf           strings.Builder
 	inputs        Paths
+	orderOnlys    Paths
 	outputs       WritablePaths
 	depFiles      WritablePaths
 	tools         Paths
@@ -475,6 +502,10 @@
 	return path.String()
 }
 
+func (c *RuleBuilderCommand) addOrderOnly(path Path) {
+	c.orderOnlys = append(c.orderOnlys, path)
+}
+
 func (c *RuleBuilderCommand) outputStr(path Path) string {
 	if c.sbox {
 		// Errors will be handled in RuleBuilder.Build where we have a context to report them
@@ -604,6 +635,22 @@
 	return c
 }
 
+// OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
+// without modifying the command line.
+func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
+	c.addOrderOnly(path)
+	return c
+}
+
+// OrderOnlys adds the specified input paths to the dependencies returned by RuleBuilder.OrderOnlys
+// without modifying the command line.
+func (c *RuleBuilderCommand) OrderOnlys(paths Paths) *RuleBuilderCommand {
+	for _, path := range paths {
+		c.addOrderOnly(path)
+	}
+	return c
+}
+
 // Output adds the specified output path to the command line.  The path will also be added to the outputs returned by
 // RuleBuilder.Outputs.
 func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index acf8127..c41b067 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -265,14 +265,16 @@
 
 func TestRuleBuilder(t *testing.T) {
 	fs := map[string][]byte{
-		"dep_fixer": nil,
-		"input":     nil,
-		"Implicit":  nil,
-		"Input":     nil,
-		"Tool":      nil,
-		"input2":    nil,
-		"tool2":     nil,
-		"input3":    nil,
+		"dep_fixer":  nil,
+		"input":      nil,
+		"Implicit":   nil,
+		"Input":      nil,
+		"OrderOnly":  nil,
+		"OrderOnlys": nil,
+		"Tool":       nil,
+		"input2":     nil,
+		"tool2":      nil,
+		"input3":     nil,
 	}
 
 	ctx := PathContextForTesting(TestConfig("out", nil, "", fs))
@@ -290,6 +292,7 @@
 			ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
 			Input(PathForSource(ctx, "Input")).
 			Output(PathForOutput(ctx, "Output")).
+			OrderOnly(PathForSource(ctx, "OrderOnly")).
 			Text("Text").
 			Tool(PathForSource(ctx, "Tool"))
 
@@ -298,6 +301,7 @@
 			DepFile(PathForOutput(ctx, "depfile2")).
 			Input(PathForSource(ctx, "input2")).
 			Output(PathForOutput(ctx, "output2")).
+			OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
 			Tool(PathForSource(ctx, "tool2"))
 
 		// Test updates to the first command after the second command has been started
@@ -317,6 +321,7 @@
 	wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
 	wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
 	wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
+	wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
 
 	t.Run("normal", func(t *testing.T) {
 		rule := NewRuleBuilder()
@@ -346,6 +351,9 @@
 		if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
 			t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
 		}
+		if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.OrderOnlys() = %#v\n                got %#v", w, g)
+		}
 
 		if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
 			t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
@@ -380,6 +388,9 @@
 		if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
 			t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
 		}
+		if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.OrderOnlys() = %#v\n                got %#v", w, g)
+		}
 
 		if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
 			t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
diff --git a/android/sdk.go b/android/sdk.go
index 27756ce..d13ad7d 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -180,6 +180,15 @@
 	// will only be used if the equivalently named non-prebuilt module is not
 	// present.
 	AddPrebuiltModule(member SdkMember, moduleType string) BpModule
+
+	// The property tag to use when adding a property to a BpModule that contains
+	// references to other sdk members. Using this will ensure that the reference
+	// is correctly output for both versioned and unversioned prebuilts in the
+	// snapshot.
+	//
+	// e.g.
+	// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag())
+	SdkMemberReferencePropertyTag() BpPropertyTag
 }
 
 type BpPropertyTag interface{}
@@ -264,6 +273,13 @@
 	// True if the member type supports the sdk/sdk_snapshot, false otherwise.
 	UsableWithSdkAndSdkSnapshot() bool
 
+	// Return true if modules of this type can have dependencies which should be
+	// treated as if they are sdk members.
+	//
+	// Any dependency that is to be treated as a member of the sdk needs to implement
+	// SdkAware and be added with an SdkMemberTypeDependencyTag tag.
+	HasTransitiveSdkMembers() bool
+
 	// Add dependencies from the SDK module to all the variants the member
 	// contributes to the SDK. The exact set of variants required is determined
 	// by the SDK and its properties. The dependencies must be added with the
@@ -291,8 +307,9 @@
 
 // Base type for SdkMemberType implementations.
 type SdkMemberTypeBase struct {
-	PropertyName string
-	SupportsSdk  bool
+	PropertyName         string
+	SupportsSdk          bool
+	TransitiveSdkMembers bool
 }
 
 func (b *SdkMemberTypeBase) SdkPropertyName() string {
@@ -303,6 +320,10 @@
 	return b.SupportsSdk
 }
 
+func (b *SdkMemberTypeBase) HasTransitiveSdkMembers() bool {
+	return b.TransitiveSdkMembers
+}
+
 // Encapsulates the information about registered SdkMemberTypes.
 type SdkMemberTypesRegistry struct {
 	// The list of types sorted by property name.
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index f54e774..198108d 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -303,6 +303,7 @@
 	}
 
 	return ctx.Config().Once(key, func() interface{} {
+		ctx.AddNinjaFileDeps(from)
 		r, err := ctx.Config().fs.Open(from)
 		if err != nil {
 			ctx.PropertyErrorf("from", "failed to open %q: %s", from, err)
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 66feba8..6ad88a2 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -43,7 +43,7 @@
 			name: "acme_test_defaults",
 			module_type: "test_defaults",
 			config_namespace: "acme",
-			variables: ["board", "feature1", "feature2", "feature3"],
+			variables: ["board", "feature1", "feature2", "FEATURE3"],
 			properties: ["cflags", "srcs"],
 		}
 
@@ -61,7 +61,7 @@
 		}
 
 		soong_config_bool_variable {
-			name: "feature3",
+			name: "FEATURE3",
 		}
 	`
 
@@ -91,7 +91,7 @@
 				feature2: {
 					cflags: ["-DFEATURE2"],
 				},
-				feature3: {
+				FEATURE3: {
 					cflags: ["-DFEATURE3"],
 				},
 			},
diff --git a/android/util.go b/android/util.go
index e985fc1..ade851e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -122,7 +122,7 @@
 }
 
 // Returns true if the given string s is prefixed with any string in the given prefix list.
-func PrefixInList(s string, prefixList []string) bool {
+func HasAnyPrefix(s string, prefixList []string) bool {
 	for _, prefix := range prefixList {
 		if strings.HasPrefix(s, prefix) {
 			return true
@@ -132,7 +132,7 @@
 }
 
 // Returns true if any string in the given list has the given prefix.
-func PrefixedStringInList(list []string, prefix string) bool {
+func PrefixInList(list []string, prefix string) bool {
 	for _, s := range list {
 		if strings.HasPrefix(s, prefix) {
 			return true
diff --git a/android/util_test.go b/android/util_test.go
index 90fefee..1f9ca36 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -252,7 +252,7 @@
 
 	for _, testCase := range testcases {
 		t.Run(testCase.str, func(t *testing.T) {
-			out := PrefixInList(testCase.str, prefixes)
+			out := HasAnyPrefix(testCase.str, prefixes)
 			if out != testCase.expected {
 				t.Errorf("incorrect output:")
 				t.Errorf("       str: %#v", testCase.str)
diff --git a/android/variable.go b/android/variable.go
index 9625a87..25c94bc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -25,7 +25,7 @@
 
 func init() {
 	PreDepsMutators(func(ctx RegisterMutatorsContext) {
-		ctx.BottomUp("variable", variableMutator).Parallel()
+		ctx.BottomUp("variable", VariableMutator).Parallel()
 	})
 }
 
@@ -127,21 +127,21 @@
 		} `android:"arch_variant"`
 
 		Native_coverage struct {
+			Src          *string  `android:"arch_variant"`
 			Srcs         []string `android:"arch_variant"`
 			Exclude_srcs []string `android:"arch_variant"`
 		} `android:"arch_variant"`
 	} `android:"arch_variant"`
 }
 
-var zeroProductVariables interface{} = variableProperties{}
+var defaultProductVariables interface{} = variableProperties{}
 
 type productVariables struct {
 	// Suffix to add to generated Makefiles
 	Make_suffix *string `json:",omitempty"`
 
-	BuildId             *string `json:",omitempty"`
-	BuildNumberFromFile *string `json:",omitempty"`
-	DateFromFile        *string `json:",omitempty"`
+	BuildId         *string `json:",omitempty"`
+	BuildNumberFile *string `json:",omitempty"`
 
 	Platform_version_name                     *string  `json:",omitempty"`
 	Platform_sdk_version                      *int     `json:",omitempty"`
@@ -229,7 +229,8 @@
 	UncompressPrivAppDex             *bool    `json:",omitempty"`
 	ModulesLoadedByPrivilegedModules []string `json:",omitempty"`
 
-	BootJars []string `json:",omitempty"`
+	BootJars          []string `json:",omitempty"`
+	UpdatableBootJars []string `json:",omitempty"`
 
 	IntegerOverflowExcludePaths []string `json:",omitempty"`
 
@@ -239,9 +240,6 @@
 
 	DisableScudo *bool `json:",omitempty"`
 
-	EnableXOM       *bool    `json:",omitempty"`
-	XOMExcludePaths []string `json:",omitempty"`
-
 	Experimental_mte *bool `json:",omitempty"`
 
 	VendorPath    *string `json:",omitempty"`
@@ -346,7 +344,7 @@
 
 func (v *productVariables) SetDefaultConfig() {
 	*v = productVariables{
-		BuildNumberFromFile: stringPtr("123456789"),
+		BuildNumberFile: stringPtr("build_number.txt"),
 
 		Platform_version_name:             stringPtr("Q"),
 		Platform_sdk_version:              intPtr(28),
@@ -384,7 +382,7 @@
 	}
 }
 
-func variableMutator(mctx BottomUpMutatorContext) {
+func VariableMutator(mctx BottomUpMutatorContext) {
 	var module Module
 	var ok bool
 	if module, ok = mctx.Module().(Module); !ok {
@@ -399,11 +397,9 @@
 	}
 
 	variableValues := reflect.ValueOf(a.variableProperties).Elem().FieldByName("Product_variables")
-	zeroValues := reflect.ValueOf(zeroProductVariables).FieldByName("Product_variables")
 
 	for i := 0; i < variableValues.NumField(); i++ {
 		variableValue := variableValues.Field(i)
-		zeroValue := zeroValues.Field(i)
 		name := variableValues.Type().Field(i).Name
 		property := "product_variables." + proptools.PropertyNameForField(name)
 
@@ -421,10 +417,9 @@
 		}
 
 		// Check if any properties were set for the module
-		if reflect.DeepEqual(variableValue.Interface(), zeroValue.Interface()) {
+		if variableValue.IsZero() {
 			continue
 		}
-
 		a.setVariableProperties(mctx, property, variableValue, val.Interface())
 	}
 }
@@ -542,6 +537,20 @@
 	return ret.Interface()
 }
 
+func initProductVariableModule(m Module) {
+	base := m.base()
+
+	// Allow tests to override the default product variables
+	if base.variableProperties == nil {
+		base.variableProperties = defaultProductVariables
+	}
+	// Filter the product variables properties to the ones that exist on this module
+	base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties)
+	if base.variableProperties != nil {
+		m.AddProperties(base.variableProperties)
+	}
+}
+
 // createVariableProperties takes the list of property structs for a module and returns a property struct that
 // contains the product variable properties that exist in the property structs, or nil if there are none.  It
 // caches the result.
diff --git a/android/variable_test.go b/android/variable_test.go
index cde2b1a..9cafedd 100644
--- a/android/variable_test.go
+++ b/android/variable_test.go
@@ -171,7 +171,7 @@
 		Foo []string
 	}{}))
 	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-		ctx.BottomUp("variable", variableMutator).Parallel()
+		ctx.BottomUp("variable", VariableMutator).Parallel()
 	})
 
 	// Test that a module can use one product variable even if it doesn't have all the properties
@@ -209,6 +209,115 @@
 	FailIfErrored(t, errs)
 }
 
+var testProductVariableDefaultsProperties = struct {
+	Product_variables struct {
+		Eng struct {
+			Foo []string
+			Bar []string
+		}
+	}
+}{}
+
+type productVariablesDefaultsTestProperties struct {
+	Foo []string
+}
+
+type productVariablesDefaultsTestProperties2 struct {
+	Foo []string
+	Bar []string
+}
+
+type productVariablesDefaultsTestModule struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties productVariablesDefaultsTestProperties
+}
+
+func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	ctx.Build(pctx, BuildParams{
+		Rule:   Touch,
+		Output: PathForModuleOut(ctx, "out"),
+	})
+}
+
+func productVariablesDefaultsTestModuleFactory() Module {
+	module := &productVariablesDefaultsTestModule{}
+	module.AddProperties(&module.properties)
+	module.variableProperties = testProductVariableDefaultsProperties
+	InitAndroidModule(module)
+	InitDefaultableModule(module)
+	return module
+}
+
+type productVariablesDefaultsTestDefaults struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func productVariablesDefaultsTestDefaultsFactory() Module {
+	defaults := &productVariablesDefaultsTestDefaults{}
+	defaults.AddProperties(&productVariablesDefaultsTestProperties{})
+	defaults.AddProperties(&productVariablesDefaultsTestProperties2{})
+	defaults.variableProperties = testProductVariableDefaultsProperties
+	InitDefaultsModule(defaults)
+	return defaults
+}
+
+// Test a defaults module that supports more product variable properties than the target module.
+func TestProductVariablesDefaults(t *testing.T) {
+	bp := `
+		defaults {
+			name: "defaults",
+			product_variables: {
+				eng: {
+					foo: ["product_variable_defaults"],
+					bar: ["product_variable_defaults"],
+				},
+			},
+			foo: ["defaults"],
+			bar: ["defaults"],
+		}
+
+		test {
+			name: "foo",
+			defaults: ["defaults"],
+			foo: ["module"],
+			product_variables: {
+				eng: {
+					foo: ["product_variable_module"],
+				},
+			},
+		}
+	`
+
+	config := TestConfig(buildDir, nil, bp, nil)
+	config.TestProductVariables.Eng = boolPtr(true)
+
+	ctx := NewTestContext()
+
+	ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
+	ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory)
+
+	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("variable", VariableMutator).Parallel()
+	})
+
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	foo := ctx.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule)
+
+	want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"}
+	if g, w := foo.properties.Foo, want; !reflect.DeepEqual(g, w) {
+		t.Errorf("expected foo %q, got %q", w, g)
+	}
+}
+
 func BenchmarkSliceToTypeArray(b *testing.B) {
 	for _, n := range []int{1, 2, 4, 8, 100} {
 		var propStructs []interface{}
diff --git a/android/visibility.go b/android/visibility.go
index a597687..3f04123 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -186,8 +186,8 @@
 var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
 
 // The map from qualifiedModuleName to visibilityRule.
-func moduleToVisibilityRuleMap(ctx BaseModuleContext) *sync.Map {
-	return ctx.Config().Once(visibilityRuleMap, func() interface{} {
+func moduleToVisibilityRuleMap(config Config) *sync.Map {
+	return config.Once(visibilityRuleMap, func() interface{} {
 		return &sync.Map{}
 	}).(*sync.Map)
 }
@@ -304,7 +304,7 @@
 	if visibility := m.visibility(); visibility != nil {
 		rule := parseRules(ctx, currentPkg, m.visibility())
 		if rule != nil {
-			moduleToVisibilityRuleMap(ctx).Store(qualifiedModuleId, rule)
+			moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
 		}
 	}
 }
@@ -312,6 +312,7 @@
 func parseRules(ctx BaseModuleContext, currentPkg string, visibility []string) compositeRule {
 	rules := make(compositeRule, 0, len(visibility))
 	hasPrivateRule := false
+	hasPublicRule := false
 	hasNonPrivateRule := false
 	for _, v := range visibility {
 		ok, pkg, name := splitRule(v, currentPkg)
@@ -328,6 +329,7 @@
 				isPrivateRule = true
 			case "public":
 				r = publicRule{}
+				hasPublicRule = true
 			}
 		} else {
 			switch name {
@@ -355,6 +357,11 @@
 		return compositeRule{privateRule{}}
 	}
 
+	if hasPublicRule {
+		// Public overrides all other rules so just return it.
+		return compositeRule{publicRule{}}
+	}
+
 	return rules
 }
 
@@ -415,21 +422,21 @@
 			return
 		}
 
-		rule := effectiveVisibilityRules(ctx, depQualified)
+		rule := effectiveVisibilityRules(ctx.Config(), depQualified)
 		if rule != nil && !rule.matches(qualified) {
 			ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
 		}
 	})
 }
 
-func effectiveVisibilityRules(ctx BaseModuleContext, qualified qualifiedModuleName) compositeRule {
-	moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
+	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
 	value, ok := moduleToVisibilityRule.Load(qualified)
 	var rule compositeRule
 	if ok {
 		rule = value.(compositeRule)
 	} else {
-		rule = packageDefaultVisibility(ctx, qualified)
+		rule = packageDefaultVisibility(config, qualified)
 	}
 	return rule
 }
@@ -441,8 +448,8 @@
 	return qualified
 }
 
-func packageDefaultVisibility(ctx BaseModuleContext, moduleId qualifiedModuleName) compositeRule {
-	moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule {
+	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
 	packageQualifiedId := moduleId.getContainingPackageId()
 	for {
 		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
@@ -469,7 +476,7 @@
 	dir := ctx.OtherModuleDir(module)
 	qualified := qualifiedModuleName{dir, moduleName}
 
-	rule := effectiveVisibilityRules(ctx, qualified)
+	rule := effectiveVisibilityRules(ctx.Config(), qualified)
 
 	return rule.Strings()
 }
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 6006072..8dd6a8f 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1,15 +1,17 @@
 package android
 
 import (
+	"reflect"
 	"testing"
 
 	"github.com/google/blueprint"
 )
 
 var visibilityTests = []struct {
-	name           string
-	fs             map[string][]byte
-	expectedErrors []string
+	name                string
+	fs                  map[string][]byte
+	expectedErrors      []string
+	effectiveVisibility map[qualifiedModuleName][]string
 }{
 	{
 		name: "invalid visibility: empty list",
@@ -493,6 +495,9 @@
 					deps: ["libexample"],
 				}`),
 		},
+		effectiveVisibility: map[qualifiedModuleName][]string{
+			qualifiedModuleName{pkg: "top", name: "libexample"}: {"//visibility:public"},
+		},
 	},
 	{
 		name: "//visibility:public mixed with other from different defaults 1",
@@ -903,13 +908,27 @@
 func TestVisibility(t *testing.T) {
 	for _, test := range visibilityTests {
 		t.Run(test.name, func(t *testing.T) {
-			_, errs := testVisibility(buildDir, test.fs)
+			ctx, errs := testVisibility(buildDir, test.fs)
 
 			CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
+
+			if test.effectiveVisibility != nil {
+				checkEffectiveVisibility(t, ctx, test.effectiveVisibility)
+			}
 		})
 	}
 }
 
+func checkEffectiveVisibility(t *testing.T, ctx *TestContext, effectiveVisibility map[qualifiedModuleName][]string) {
+	for moduleName, expectedRules := range effectiveVisibility {
+		rule := effectiveVisibilityRules(ctx.config, moduleName)
+		stringRules := rule.Strings()
+		if !reflect.DeepEqual(expectedRules, stringRules) {
+			t.Errorf("effective rules mismatch: expected %q, found %q", expectedRules, stringRules)
+		}
+	}
+}
+
 func testVisibility(buildDir string, fs map[string][]byte) (*TestContext, []error) {
 
 	// Create a new config per test as visibility information is stored in the config.
diff --git a/android/vts_config.go b/android/vts_config.go
index 86f6e72..9a1df7c 100644
--- a/android/vts_config.go
+++ b/android/vts_config.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"io"
+	"strings"
 )
 
 func init() {
@@ -26,6 +27,8 @@
 type vtsConfigProperties struct {
 	// Override the default (AndroidTest.xml) test manifest file name.
 	Test_config *string
+	// Additional test suites to add the test to.
+	Test_suites []string `android:"arch_variant"`
 }
 
 type VtsConfig struct {
@@ -50,7 +53,8 @@
 				fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
 					*me.properties.Test_config)
 			}
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := vts")
+			fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts %s\n",
+				strings.Join(me.properties.Test_suites, " "))
 		},
 	}
 	return androidMkData
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 8860984..b7c54b1 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -383,11 +383,15 @@
 	if err != nil {
 		return err
 	}
-	if val.(*bpparser.Bool).Value {
+	boolValue, ok := val.(*bpparser.Bool)
+	if !ok {
+		return fmt.Errorf("value should evaluate to boolean literal")
+	}
+	if boolValue.Value {
 		thirtyTwo := &bpparser.String{
 			Value: "32",
 		}
-		setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true)
+		return setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true)
 	}
 	return nil
 }
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 7e1a72c..3e1d486 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1341,6 +1341,25 @@
 }
 `,
 	},
+	{
+		desc: "undefined_boolean_var",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= a.cpp
+LOCAL_MODULE:= test
+LOCAL_32_BIT_ONLY := $(FLAG)
+include $(BUILD_EXECUTABLE)
+`,
+		expected: `
+cc_binary {
+    name: "test",
+    srcs: ["a.cpp"],
+    // ANDROIDMK TRANSLATION ERROR: value should evaluate to boolean literal
+    // LOCAL_32_BIT_ONLY := $(FLAG)
+
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 8929910..5c15e8e 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -42,7 +42,11 @@
 		}}
 }
 
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
+	// apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property.
+	// An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName>
+	// In many cases, the two names are the same, but could be different in general.
+
 	moduleNames := []string{}
 	apexType := a.properties.ApexType
 	// To avoid creating duplicate build rules, run this function only when primaryApexType is true
@@ -52,12 +56,21 @@
 		return moduleNames
 	}
 
+	// b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
+	// APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
+	// as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
+	// for the overriding VNDK APEXes.
+	symbolFilesNotNeeded := a.vndkApex && len(a.overridableProperties.Overrides) > 0
+	if symbolFilesNotNeeded && apexType != flattenedApex {
+		return moduleNames
+	}
+
 	var postInstallCommands []string
 	for _, fi := range a.filesInfo {
 		if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() {
 			// TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
 			linkTarget := filepath.Join("/system", fi.Path())
-			linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexName, fi.Path())
+			linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.Path())
 			mkdirCmd := "mkdir -p " + filepath.Dir(linkPath)
 			linkCmd := "ln -sfn " + linkTarget + " " + linkPath
 			postInstallCommands = append(postInstallCommands, mkdirCmd, linkCmd)
@@ -75,7 +88,7 @@
 		if linkToSystemLib {
 			moduleName = fi.moduleName
 		} else {
-			moduleName = fi.moduleName + "." + apexName + a.suffix
+			moduleName = fi.moduleName + "." + apexBundleName + a.suffix
 		}
 
 		if !android.InList(moduleName, moduleNames) {
@@ -99,16 +112,16 @@
 		if apexType == flattenedApex {
 			// /system/apex/<name>/{lib|framework|...}
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(),
-				apexName, fi.installDir))
-			if a.primaryApexType {
+				apexBundleName, fi.installDir))
+			if a.primaryApexType && !symbolFilesNotNeeded {
 				fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
 			}
 			if len(fi.symlinks) > 0 {
 				fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " "))
 			}
 
-			if fi.module != nil && fi.module.NoticeFile().Valid() {
-				fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", fi.module.NoticeFile().Path().String())
+			if fi.module != nil && len(fi.module.NoticeFiles()) > 0 {
+				fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(fi.module.NoticeFiles().Strings(), " "))
 			}
 		} else {
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated)
@@ -204,6 +217,12 @@
 			}
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 		}
+
+		// m <module_name> will build <module_name>.<apex_name> as well.
+		if fi.moduleName != moduleName && a.primaryApexType {
+			fmt.Fprintln(w, ".PHONY: "+fi.moduleName)
+			fmt.Fprintln(w, fi.moduleName+": "+moduleName)
+		}
 	}
 	return moduleNames
 }
@@ -236,7 +255,7 @@
 			apexType := a.properties.ApexType
 			if a.installable() {
 				apexName := proptools.StringDefault(a.properties.Apex_name, name)
-				moduleNames = a.androidMkForFiles(w, apexName, moduleDir)
+				moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir)
 			}
 
 			if apexType == flattenedApex {
@@ -289,7 +308,7 @@
 				}
 
 				if a.installedFilesFile != nil {
-					goal := "droidcore"
+					goal := "checkbuild"
 					distFile := name + "-installed-files.txt"
 					fmt.Fprintln(w, ".PHONY:", goal)
 					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
diff --git a/apex/apex.go b/apex/apex.go
index 53bdc12..c791162 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -45,18 +45,22 @@
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
 	name string
+
+	// determines if the dependent will be part of the APEX payload
+	payload bool
 }
 
 var (
-	sharedLibTag   = dependencyTag{name: "sharedLib"}
-	executableTag  = dependencyTag{name: "executable"}
-	javaLibTag     = dependencyTag{name: "javaLib"}
-	prebuiltTag    = dependencyTag{name: "prebuilt"}
-	testTag        = dependencyTag{name: "test"}
+	sharedLibTag   = dependencyTag{name: "sharedLib", payload: true}
+	jniLibTag      = dependencyTag{name: "jniLib", payload: true}
+	executableTag  = dependencyTag{name: "executable", payload: true}
+	javaLibTag     = dependencyTag{name: "javaLib", payload: true}
+	prebuiltTag    = dependencyTag{name: "prebuilt", payload: true}
+	testTag        = dependencyTag{name: "test", payload: true}
 	keyTag         = dependencyTag{name: "key"}
 	certificateTag = dependencyTag{name: "certificate"}
 	usesTag        = dependencyTag{name: "uses"}
-	androidAppTag  = dependencyTag{name: "androidApp"}
+	androidAppTag  = dependencyTag{name: "androidApp", payload: true}
 	apexAvailWl    = makeApexAvailableWhitelist()
 )
 
@@ -70,107 +74,322 @@
 	//
 	// Module separator
 	//
-	m["com.android.adbd"] = []string{"adbd", "libcrypto"}
+	m["com.android.adbd"] = []string{
+		"adbd",
+		"bcm_object",
+		"fmtlib",
+		"libadbconnection_server",
+		"libadbd",
+		"libadbd_auth",
+		"libadbd_core",
+		"libadbd_services",
+		"libasyncio",
+		"libbacktrace_headers",
+		"libbase",
+		"libbase_headers",
+		"libbuildversion",
+		"libc++",
+		"libcap",
+		"libcrypto",
+		"libcrypto_utils",
+		"libcutils",
+		"libcutils_headers",
+		"libdiagnose_usb",
+		"liblog_headers",
+		"libmdnssd",
+		"libminijail",
+		"libminijail_gen_constants",
+		"libminijail_gen_constants_obj",
+		"libminijail_gen_syscall",
+		"libminijail_gen_syscall_obj",
+		"libminijail_generated",
+		"libpackagelistparser",
+		"libpcre2",
+		"libprocessgroup_headers",
+		"libqemu_pipe",
+		"libselinux",
+		"libsystem_headers",
+		"libutils_headers",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.appsearch"] = []string{
+		"icing-java-proto-lite",
+		"libprotobuf-java-lite",
+	}
 	//
 	// Module separator
 	//
 	m["com.android.art"] = []string{
+		"art_cmdlineparser_headers",
+		"art_disassembler_headers",
+		"art_libartbase_headers",
+		"bcm_object",
+		"bionic_libc_platform_headers",
+		"core-repackaged-icu4j",
+		"cpp-define-generator-asm-support",
+		"cpp-define-generator-definitions",
+		"crtbegin_dynamic",
+		"crtbegin_dynamic1",
+		"crtbegin_so1",
+		"crtbrand",
+		"conscrypt.module.intra.core.api.stubs",
+		"dex2oat_headers",
+		"dt_fd_forward_export",
+		"fmtlib",
+		"icu4c_extra_headers",
 		"jacocoagent",
+		"javavm_headers",
+		"jni_platform_headers",
+		"libPlatformProperties",
+		"libadbconnection_client",
 		"libadbconnection_server",
+		"libandroidicuinit",
+		"libart_runtime_headers_ndk",
 		"libartd-disassembler",
+		"libasync_safe",
 		"libbacktrace",
 		"libbase",
+		"libbase_headers",
 		"libc++",
+		"libc++_static",
+		"libc++abi",
+		"libc++demangle",
+		"libc_headers",
 		"libcrypto",
+		"libdexfile_all_headers",
+		"libdexfile_external_headers",
 		"libdexfile_support",
+		"libdmabufinfo",
 		"libexpat",
+		"libfdlibm",
+		"libgtest_prod",
+		"libicui18n_headers",
 		"libicuuc",
+		"libicuuc_headers",
+		"libicuuc_stubdata",
+		"libjdwp_headers",
+		"liblog_headers",
+		"liblz4",
 		"liblzma",
 		"libmeminfo",
+		"libnativebridge-headers",
+		"libnativehelper_header_only",
+		"libnativeloader-headers",
+		"libnpt_headers",
+		"libopenjdkjvmti_headers",
+		"libperfetto_client_experimental",
 		"libprocinfo",
+		"libprotobuf-cpp-lite",
+		"libunwind_llvm",
 		"libunwindstack",
+		"libv8",
+		"libv8base",
+		"libv8gen",
+		"libv8platform",
+		"libv8sampler",
+		"libv8src",
 		"libvixl",
 		"libvixld",
 		"libz",
 		"libziparchive",
-		"prebuilt_libclang_rt",
+		"perfetto_trace_protos",
 	}
 	//
 	// Module separator
 	//
 	m["com.android.bluetooth.updatable"] = []string{
 		"android.hardware.audio.common@5.0",
-		"android.hardware.bluetooth@1.0",
-		"android.hardware.bluetooth@1.1",
 		"android.hardware.bluetooth.a2dp@1.0",
 		"android.hardware.bluetooth.audio@2.0",
+		"android.hardware.bluetooth@1.0",
+		"android.hardware.bluetooth@1.1",
+		"android.hardware.graphics.bufferqueue@1.0",
+		"android.hardware.graphics.bufferqueue@2.0",
+		"android.hardware.graphics.common@1.0",
+		"android.hardware.graphics.common@1.1",
+		"android.hardware.graphics.common@1.2",
+		"android.hardware.media@1.0",
 		"android.hidl.safe_union@1.0",
+		"android.hidl.token@1.0",
+		"android.hidl.token@1.0-utils",
+		"avrcp-target-service",
+		"avrcp_headers",
+		"bcm_object",
+		"bluetooth-protos-lite",
+		"bluetooth.mapsapi",
+		"com.android.vcard",
+		"fmtlib",
+		"guava",
+		"internal_include_headers",
+		"lib-bt-packets",
+		"lib-bt-packets-avrcp",
+		"lib-bt-packets-base",
+		"libFraunhoferAAC",
+		"libaudio-a2dp-hw-utils",
+		"libaudio-hearing-aid-hw-utils",
+		"libbacktrace_headers",
 		"libbase",
-		"libbinderthreadstate",
+		"libbase_headers",
+		"libbinder_headers",
 		"libbluetooth",
+		"libbluetooth-types",
+		"libbluetooth-types-header",
+		"libbluetooth_gd",
+		"libbluetooth_headers",
 		"libbluetooth_jni",
+		"libbt-audio-hal-interface",
+		"libbt-bta",
+		"libbt-common",
+		"libbt-hci",
+		"libbt-platform-protos-lite",
+		"libbt-protos-lite",
+		"libbt-sbc-decoder",
+		"libbt-sbc-encoder",
+		"libbt-stack",
+		"libbt-utils",
+		"libbtcore",
+		"libbtdevice",
+		"libbte",
+		"libbtif",
 		"libc++",
 		"libchrome",
 		"libcrypto",
 		"libcutils",
+		"libcutils_headers",
 		"libevent",
 		"libfmq",
+		"libg722codec",
+		"libgtest_prod",
+		"libgui_headers",
 		"libhidlbase",
+		"libhidlbase-impl-internal",
+		"libhidltransport-impl-internal",
+		"libhwbinder-impl-internal",
+		"libjsoncpp",
+		"liblog_headers",
+		"libmedia_headers",
+		"libmodpb64",
+		"libosi",
 		"libprocessgroup",
+		"libprocessgroup_headers",
 		"libprotobuf-cpp-lite",
+		"libprotobuf-java-lite",
+		"libprotobuf-java-micro",
+		"libstagefright_foundation_headers",
+		"libstagefright_headers",
 		"libstatslog",
+		"libstatssocket",
+		"libsystem_headers",
 		"libtinyxml2",
-		"libutils",
+		"libudrv-uipc",
+		"libutils_headers",
 		"libz",
+		"media_plugin_headers",
+		"sap-api-java-static",
+		"services.net",
 	}
 	//
 	// Module separator
 	//
-	m["com.android.conscrypt"] = []string{"boringssl_self_test", "libc++", "libcrypto", "libssl"}
+	m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
 	//
 	// Module separator
 	//
-	m["com.android.cronet"] = []string{"org.chromium.net.cronet", "prebuilt_libcronet.80.0.3986.0"}
+	m["com.android.conscrypt"] = []string{
+		"bcm_object",
+		"boringssl_self_test",
+		"libc++",
+		"libcrypto",
+		"libnativehelper_header_only",
+		"libssl",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.extservices"] = []string{
+		"flatbuffer_headers",
+		"liblua",
+		"libtextclassifier",
+		"libtextclassifier_hash_static",
+		"libtflite_static",
+		"libutf",
+		"libz_current",
+		"tensorflow_headers",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.cronet"] = []string{
+		"cronet_impl_common_java",
+		"cronet_impl_native_java",
+		"cronet_impl_platform_java",
+		"libcronet.80.0.3986.0",
+		"org.chromium.net.cronet",
+		"prebuilt_libcronet.80.0.3986.0",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.neuralnetworks"] = []string{
+		"android.hardware.neuralnetworks@1.0",
+		"android.hardware.neuralnetworks@1.1",
+		"android.hardware.neuralnetworks@1.2",
+		"android.hardware.neuralnetworks@1.3",
+		"android.hidl.allocator@1.0",
+		"android.hidl.memory.token@1.0",
+		"android.hidl.memory@1.0",
+		"android.hidl.safe_union@1.0",
+		"bcm_object",
+		"fmtlib",
+		"gemmlowp_headers",
+		"libarect",
+		"libbacktrace_headers",
+		"libbase",
+		"libbase_headers",
+		"libbuildversion",
+		"libc++",
+		"libcrypto",
+		"libcrypto_static",
+		"libcutils",
+		"libcutils_headers",
+		"libeigen",
+		"libfmq",
+		"libhidlbase",
+		"libhidlbase-impl-internal",
+		"libhidlmemory",
+		"libhidltransport-impl-internal",
+		"libhwbinder-impl-internal",
+		"libjsoncpp",
+		"liblog_headers",
+		"libmath",
+		"libneuralnetworks_common",
+		"libneuralnetworks_headers",
+		"libprocessgroup",
+		"libprocessgroup_headers",
+		"libprocpartition",
+		"libsync",
+		"libsystem_headers",
+		"libtextclassifier_hash",
+		"libtextclassifier_hash_headers",
+		"libtextclassifier_hash_static",
+		"libtflite_kernel_utils",
+		"libutils_headers",
+		"philox_random",
+		"philox_random_headers",
+		"tensorflow_headers",
+	}
 	//
 	// Module separator
 	//
 	m["com.android.media"] = []string{
-		"android.hardware.cas@1.0",
-		"android.hardware.cas.native@1.0",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"libaacextractor",
-		"libamrextractor",
-		"libbase",
-		"libbinderthreadstate",
-		"libc++",
-		"libcrypto",
-		"libcutils",
-		"libflacextractor",
-		"libhidlbase",
-		"libhidlmemory",
-		"libmidiextractor",
-		"libmkvextractor",
-		"libmp3extractor",
-		"libmp4extractor",
-		"libmpeg2extractor",
-		"liboggextractor",
-		"libprocessgroup",
-		"libutils",
-		"libwavextractor",
-		"updatable-media",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media.swcodec"] = []string{
 		"android.frameworks.bufferhub@1.0",
+		"android.hardware.cas.native@1.0",
+		"android.hardware.cas@1.0",
+		"android.hardware.configstore-utils",
 		"android.hardware.configstore@1.0",
 		"android.hardware.configstore@1.1",
-		"android.hardware.configstore-utils",
 		"android.hardware.graphics.allocator@2.0",
 		"android.hardware.graphics.allocator@3.0",
 		"android.hardware.graphics.bufferqueue@1.0",
@@ -181,23 +400,196 @@
 		"android.hardware.graphics.mapper@2.0",
 		"android.hardware.graphics.mapper@2.1",
 		"android.hardware.graphics.mapper@3.0",
+		"android.hardware.media.omx@1.0",
 		"android.hardware.media@1.0",
+		"android.hidl.allocator@1.0",
+		"android.hidl.memory.token@1.0",
+		"android.hidl.memory@1.0",
+		"android.hidl.token@1.0",
+		"android.hidl.token@1.0-utils",
+		"bcm_object",
+		"bionic_libc_platform_headers",
+		"fmtlib",
+		"gl_headers",
+		"libEGL",
+		"libEGL_blobCache",
+		"libEGL_getProcAddress",
+		"libFLAC",
+		"libFLAC-config",
+		"libFLAC-headers",
+		"libGLESv2",
+		"libaacextractor",
+		"libamrextractor",
+		"libarect",
+		"libasync_safe",
+		"libaudio_system_headers",
+		"libaudioclient",
+		"libaudioclient_headers",
+		"libaudiofoundation",
+		"libaudiofoundation_headers",
+		"libaudiomanager",
+		"libaudiopolicy",
+		"libaudioutils",
+		"libaudioutils_fixedfft",
+		"libbacktrace",
+		"libbacktrace_headers",
+		"libbase",
+		"libbase_headers",
+		"libbinder_headers",
+		"libbluetooth-types-header",
+		"libbufferhub",
+		"libbufferhub_headers",
+		"libbufferhubqueue",
+		"libc++",
+		"libc_headers",
+		"libc_malloc_debug_backtrace",
+		"libcamera_client",
+		"libcamera_metadata",
+		"libcrypto",
+		"libcutils",
+		"libcutils_headers",
+		"libdexfile_external_headers",
+		"libdexfile_support",
+		"libdvr_headers",
+		"libexpat",
+		"libfifo",
+		"libflacextractor",
+		"libgrallocusage",
+		"libgraphicsenv",
+		"libgui",
+		"libgui_headers",
+		"libhardware_headers",
+		"libhidlbase",
+		"libhidlbase-impl-internal",
+		"libhidlmemory",
+		"libhidltransport-impl-internal",
+		"libhwbinder-impl-internal",
+		"libinput",
+		"libjsoncpp",
+		"liblog_headers",
+		"liblzma",
+		"libmath",
+		"libmedia",
+		"libmedia_codeclist",
+		"libmedia_headers",
+		"libmedia_helper",
+		"libmedia_helper_headers",
+		"libmedia_midiiowrapper",
+		"libmedia_omx",
+		"libmediautils",
+		"libmidiextractor",
+		"libmkvextractor",
+		"libmp3extractor",
+		"libmp4extractor",
+		"libmpeg2extractor",
+		"libnativebase_headers",
+		"libnativebridge-headers",
+		"libnativebridge_lazy",
+		"libnativeloader-headers",
+		"libnativeloader_lazy",
+		"libnativewindow_headers",
+		"libnblog",
+		"liboggextractor",
+		"libpackagelistparser",
+		"libpcre2",
+		"libpdx",
+		"libpdx_default_transport",
+		"libpdx_headers",
+		"libpdx_uds",
+		"libprocessgroup",
+		"libprocessgroup_headers",
+		"libprocinfo",
+		"libselinux",
+		"libsonivox",
+		"libspeexresampler",
+		"libspeexresampler",
+		"libstagefright_esds",
+		"libstagefright_flacdec",
+		"libstagefright_flacdec",
+		"libstagefright_foundation",
+		"libstagefright_foundation_headers",
+		"libstagefright_foundation_without_imemory",
+		"libstagefright_headers",
+		"libstagefright_id3",
+		"libstagefright_metadatautils",
+		"libstagefright_mpeg2extractor",
+		"libstagefright_mpeg2support",
+		"libsync",
+		"libsystem_headers",
+		"libui",
+		"libui_headers",
+		"libunwindstack",
+		"libutils_headers",
+		"libvibrator",
+		"libvorbisidec",
+		"libwavextractor",
+		"libwebm",
+		"media_ndk_headers",
+		"media_plugin_headers",
+		"updatable-media",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.media.swcodec"] = []string{
+		"android.frameworks.bufferhub@1.0",
+		"android.hardware.common-ndk_platform",
+		"android.hardware.configstore-utils",
+		"android.hardware.configstore@1.0",
+		"android.hardware.configstore@1.1",
+		"android.hardware.graphics.allocator@2.0",
+		"android.hardware.graphics.allocator@3.0",
+		"android.hardware.graphics.bufferqueue@1.0",
+		"android.hardware.graphics.bufferqueue@2.0",
+		"android.hardware.graphics.common-ndk_platform",
+		"android.hardware.graphics.common@1.0",
+		"android.hardware.graphics.common@1.1",
+		"android.hardware.graphics.common@1.2",
+		"android.hardware.graphics.mapper@2.0",
+		"android.hardware.graphics.mapper@2.1",
+		"android.hardware.graphics.mapper@3.0",
+		"android.hardware.graphics.mapper@4.0",
 		"android.hardware.media.bufferpool@2.0",
 		"android.hardware.media.c2@1.0",
 		"android.hardware.media.omx@1.0",
-		"android.hidl.memory@1.0",
+		"android.hardware.media@1.0",
+		"android.hardware.media@1.0",
 		"android.hidl.memory.token@1.0",
+		"android.hidl.memory@1.0",
 		"android.hidl.safe_union@1.0",
 		"android.hidl.token@1.0",
 		"android.hidl.token@1.0-utils",
+		"fmtlib",
+		"libEGL",
+		"libFLAC",
+		"libFLAC-config",
+		"libFLAC-headers",
+		"libFraunhoferAAC",
+		"libarect",
+		"libasync_safe",
+		"libaudio_system_headers",
+		"libaudioutils",
+		"libaudioutils",
+		"libaudioutils_fixedfft",
+		"libavcdec",
+		"libavcenc",
+		"libavservices_minijail",
 		"libavservices_minijail",
 		"libbacktrace",
+		"libbacktrace_headers",
 		"libbase",
-		"libbinderthreadstate",
+		"libbase_headers",
+		"libbinder_headers",
+		"libbluetooth-types-header",
+		"libbufferhub_headers",
 		"libc++",
+		"libc_scudo",
 		"libcap",
 		"libcodec2",
+		"libcodec2_headers",
 		"libcodec2_hidl@1.0",
+		"libcodec2_hidl@1.1",
+		"libcodec2_internal",
 		"libcodec2_soft_aacdec",
 		"libcodec2_soft_aacenc",
 		"libcodec2_soft_amrnbdec",
@@ -230,73 +622,373 @@
 		"libcodec2_soft_vp9dec",
 		"libcodec2_soft_vp9enc",
 		"libcodec2_vndk",
-		"libc_scudo",
 		"libcutils",
+		"libcutils_headers",
 		"libdexfile_support",
-		"libEGL",
+		"libdvr_headers",
 		"libfmq",
+		"libfmq",
+		"libgav1",
+		"libgralloctypes",
+		"libgrallocusage",
 		"libgraphicsenv",
+		"libgsm",
+		"libgui_bufferqueue_static",
+		"libgui_headers",
 		"libhardware",
+		"libhardware_headers",
+		"libhevcdec",
+		"libhevcenc",
 		"libhidlbase",
+		"libhidlbase-impl-internal",
 		"libhidlmemory",
+		"libhidltransport-impl-internal",
+		"libhwbinder-impl-internal",
 		"libion",
+		"libjpeg",
+		"libjsoncpp",
+		"liblog_headers",
 		"liblzma",
+		"libmath",
 		"libmedia_codecserviceregistrant",
+		"libmedia_headers",
 		"libminijail",
+		"libminijail_gen_constants",
+		"libminijail_gen_constants_obj",
+		"libminijail_gen_syscall",
+		"libminijail_gen_syscall_obj",
+		"libminijail_generated",
+		"libmpeg2dec",
+		"libnativebase_headers",
 		"libnativebridge_lazy",
 		"libnativeloader_lazy",
+		"libnativewindow_headers",
 		"libopus",
+		"libpdx_headers",
 		"libprocessgroup",
+		"libprocessgroup_headers",
 		"libscudo_wrapper",
 		"libsfplugin_ccodec_utils",
 		"libstagefright_amrnb_common",
+		"libstagefright_amrnbdec",
+		"libstagefright_amrnbenc",
+		"libstagefright_amrwbdec",
+		"libstagefright_amrwbenc",
 		"libstagefright_bufferpool@2.0.1",
 		"libstagefright_bufferqueue_helper",
 		"libstagefright_enc_common",
 		"libstagefright_flacdec",
 		"libstagefright_foundation",
+		"libstagefright_foundation_headers",
+		"libstagefright_headers",
+		"libstagefright_m4vh263dec",
+		"libstagefright_m4vh263enc",
+		"libstagefright_mp3dec",
 		"libsync",
+		"libsystem_headers",
 		"libui",
+		"libui_headers",
 		"libunwindstack",
-		"libutils",
+		"libutils_headers",
 		"libvorbisidec",
 		"libvpx",
+		"libyuv",
+		"libyuv_static",
+		"media_ndk_headers",
+		"media_plugin_headers",
 		"mediaswcodec",
-		"prebuilt_libclang_rt",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.mediaprovider"] = []string{
+		"MediaProvider",
+		"MediaProviderGoogle",
+		"fmtlib_ndk",
+		"guava",
+		"libbase_ndk",
+		"libfuse",
+		"libfuse_jni",
+		"libnativehelper_header_only",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.permission"] = []string{
+		"androidx.annotation_annotation",
+		"androidx.annotation_annotation-nodeps",
+		"androidx.lifecycle_lifecycle-common",
+		"androidx.lifecycle_lifecycle-common-java8",
+		"androidx.lifecycle_lifecycle-common-java8-nodeps",
+		"androidx.lifecycle_lifecycle-common-nodeps",
+		"kotlin-annotations",
+		"kotlin-stdlib",
+		"kotlin-stdlib-jdk7",
+		"kotlin-stdlib-jdk8",
+		"kotlinx-coroutines-android",
+		"kotlinx-coroutines-android-nodeps",
+		"kotlinx-coroutines-core",
+		"kotlinx-coroutines-core-nodeps",
+		"libprotobuf-java-lite",
+		"permissioncontroller-statsd",
 	}
 	//
 	// Module separator
 	//
 	m["com.android.runtime"] = []string{
+		"bionic_libc_platform_headers",
+		"fmtlib",
+		"libarm-optimized-routines-math",
+		"libasync_safe",
+		"libasync_safe_headers",
+		"libbacktrace_headers",
+		"libbase",
+		"libbase_headers",
+		"libc++",
+		"libc_aeabi",
+		"libc_bionic",
+		"libc_bionic_ndk",
+		"libc_bootstrap",
+		"libc_common",
+		"libc_common_shared",
+		"libc_common_static",
+		"libc_dns",
+		"libc_dynamic_dispatch",
+		"libc_fortify",
+		"libc_freebsd",
+		"libc_freebsd_large_stack",
+		"libc_gdtoa",
+		"libc_headers",
+		"libc_init_dynamic",
+		"libc_init_static",
+		"libc_jemalloc_wrapper",
+		"libc_netbsd",
+		"libc_nomalloc",
+		"libc_nopthread",
+		"libc_openbsd",
+		"libc_openbsd_large_stack",
+		"libc_openbsd_ndk",
+		"libc_pthread",
+		"libc_static_dispatch",
+		"libc_syscalls",
+		"libc_tzcode",
+		"libc_unwind_static",
+		"libcutils",
+		"libcutils_headers",
+		"libdebuggerd",
+		"libdebuggerd_common_headers",
+		"libdebuggerd_handler_core",
+		"libdebuggerd_handler_fallback",
+		"libdexfile_external_headers",
+		"libdexfile_support",
+		"libdexfile_support_static",
+		"libgtest_prod",
+		"libjemalloc5",
+		"liblinker_main",
+		"liblinker_malloc",
+		"liblog_headers",
+		"liblz4",
+		"liblzma",
+		"libprocessgroup_headers",
+		"libprocinfo",
+		"libpropertyinfoparser",
+		"libscudo",
+		"libstdc++",
+		"libsystem_headers",
+		"libsystemproperties",
+		"libtombstoned_client_static",
+		"libunwindstack",
+		"libutils_headers",
+		"libz",
+		"libziparchive",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.resolv"] = []string{
+		"bcm_object",
+		"dnsresolver_aidl_interface-unstable-ndk_platform",
+		"fmtlib",
+		"libbacktrace_headers",
+		"libbase",
+		"libbase_headers",
+		"libc++",
+		"libcrypto",
+		"libcutils",
+		"libcutils_headers",
+		"libgtest_prod",
+		"libjsoncpp",
+		"liblog_headers",
+		"libnativehelper_header_only",
+		"libnetd_client_headers",
+		"libnetd_resolv",
+		"libnetdutils",
+		"libprocessgroup",
+		"libprocessgroup_headers",
+		"libprotobuf-cpp-lite",
+		"libssl",
+		"libstatslog_resolv",
+		"libstatspush_compat",
+		"libstatssocket",
+		"libstatssocket_headers",
+		"libsystem_headers",
+		"libsysutils",
+		"libutils_headers",
+		"netd_event_listener_interface-ndk_platform",
+		"server_configurable_flags",
+		"stats_proto",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.tethering"] = []string{
 		"libbase",
 		"libc++",
-		"libdexfile_support",
-		"liblzma",
-		"libunwindstack",
-		"prebuilt_libclang_rt",
+		"libnativehelper_compat_libc++",
+		"android.hardware.tetheroffload.config@1.0",
+		"fmtlib",
+		"libbacktrace_headers",
+		"libbase_headers",
+		"libcgrouprc",
+		"libcgrouprc_format",
+		"libcutils",
+		"libcutils_headers",
+		"libhidlbase",
+		"libhidlbase-impl-internal",
+		"libhidltransport-impl-internal",
+		"libhwbinder-impl-internal",
+		"libjsoncpp",
+		"liblog_headers",
+		"libprocessgroup",
+		"libprocessgroup_headers",
+		"libsystem_headers",
+		"libtetherutilsjni",
+		"libutils_headers",
+		"libvndksupport",
+		"tethering-aidl-interfaces-java",
 	}
 	//
 	// Module separator
 	//
-	m["com.android.resolv"] = []string{"libcrypto", "libnetd_resolv", "libssl"}
-	//
-	// Module separator
-	//
-	m["com.android.tethering"] = []string{"libbase", "libc++", "libnativehelper_compat_libc++"}
-	//
-	// Module separator
-	//
-	m["com.android.vndk"] = []string{
-		"libbacktrace",
-		"libbinderthreadstate",
-		"libblas",
-		"libcompiler_rt",
-		"libgui",
-		"libunwind",
+	m["com.android.wifi"] = []string{
+		"PlatformProperties",
+		"android.hardware.wifi-V1.0-java",
+		"android.hardware.wifi-V1.1-java",
+		"android.hardware.wifi-V1.2-java",
+		"android.hardware.wifi-V1.3-java",
+		"android.hardware.wifi-V1.4-java",
+		"android.hardware.wifi.hostapd-V1.0-java",
+		"android.hardware.wifi.hostapd-V1.1-java",
+		"android.hardware.wifi.hostapd-V1.2-java",
+		"android.hardware.wifi.supplicant-V1.0-java",
+		"android.hardware.wifi.supplicant-V1.1-java",
+		"android.hardware.wifi.supplicant-V1.2-java",
+		"android.hardware.wifi.supplicant-V1.3-java",
+		"android.hidl.base-V1.0-java",
+		"android.hidl.manager-V1.0-java",
+		"android.hidl.manager-V1.1-java",
+		"android.hidl.manager-V1.2-java",
+		"androidx.annotation_annotation",
+		"androidx.annotation_annotation-nodeps",
+		"bouncycastle-unbundled",
+		"dnsresolver_aidl_interface-V2-java",
+		"error_prone_annotations",
+		"ipmemorystore-aidl-interfaces-V3-java",
+		"ipmemorystore-aidl-interfaces-java",
+		"ksoap2",
+		"libbacktrace_headers",
+		"libbase",
+		"libbase_headers",
+		"libc++",
+		"libcutils",
+		"libcutils_headers",
+		"liblog_headers",
+		"libnanohttpd",
+		"libprocessgroup",
+		"libprocessgroup_headers",
+		"libprotobuf-java-lite",
+		"libprotobuf-java-nano",
+		"libsystem_headers",
+		"libutils_headers",
+		"libwifi-jni",
+		"net-utils-services-common",
+		"netd_aidl_interface-V2-java",
+		"netd_aidl_interface-unstable-java",
+		"netd_event_listener_interface-java",
+		"netlink-client",
+		"networkstack-aidl-interfaces-unstable-java",
+		"networkstack-client",
+		"services.net",
+		"wifi-lite-protos",
+		"wifi-nano-protos",
+		"wifi-service-pre-jarjar",
+		"wifi-service-resources",
+		"prebuilt_androidx.annotation_annotation-nodeps",
 	}
 	//
 	// Module separator
 	//
+	m["com.android.sdkext"] = []string{
+		"fmtlib_ndk",
+		"libbase_ndk",
+		"libprotobuf-cpp-lite-ndk",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.os.statsd"] = []string{
+		"libbacktrace_headers",
+		"libbase_headers",
+		"libc++",
+		"libcutils",
+		"libcutils_headers",
+		"liblog_headers",
+		"libprocessgroup_headers",
+		"libstatssocket",
+		"libsystem_headers",
+		"libutils_headers",
+	}
+	//
+	// Module separator
+	//
+	m["//any"] = []string{
+		"crtbegin_dynamic",
+		"crtbegin_dynamic1",
+		"crtbegin_so",
+		"crtbegin_so1",
+		"crtbegin_static",
+		"crtbrand",
+		"crtend_android",
+		"crtend_so",
+		"libatomic",
+		"libc++_static",
+		"libc++abi",
+		"libc++demangle",
+		"libc_headers",
+		"libclang_rt",
+		"libgcc_stripped",
+		"libprofile-clang-extras",
+		"libprofile-clang-extras_ndk",
+		"libprofile-extras",
+		"libprofile-extras_ndk",
+		"libunwind_llvm",
+		"ndk_crtbegin_dynamic.27",
+		"ndk_crtbegin_so.16",
+		"ndk_crtbegin_so.19",
+		"ndk_crtbegin_so.21",
+		"ndk_crtbegin_so.24",
+		"ndk_crtbegin_so.27",
+		"ndk_crtend_android.27",
+		"ndk_crtend_so.16",
+		"ndk_crtend_so.19",
+		"ndk_crtend_so.21",
+		"ndk_crtend_so.24",
+		"ndk_crtend_so.27",
+		"ndk_libandroid_support",
+		"ndk_libc++_static",
+		"ndk_libc++abi",
+		"ndk_libunwind",
+	}
 	return m
 }
 
@@ -324,7 +1016,7 @@
 }
 
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.BottomUp("apex_deps", apexDepsMutator)
+	ctx.TopDown("apex_deps", apexDepsMutator)
 	ctx.BottomUp("apex", apexMutator).Parallel()
 	ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
 	ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
@@ -332,29 +1024,29 @@
 
 // Mark the direct and transitive dependencies of apex bundles so that they
 // can be built for the apex bundles.
-func apexDepsMutator(mctx android.BottomUpMutatorContext) {
+func apexDepsMutator(mctx android.TopDownMutatorContext) {
+	var apexBundles []android.ApexInfo
+	var directDep bool
 	if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
-		apexBundleName := mctx.ModuleName()
-		mctx.WalkDeps(func(child, parent android.Module) bool {
-			depName := mctx.OtherModuleName(child)
-			// If the parent is apexBundle, this child is directly depended.
-			_, directDep := parent.(*apexBundle)
-			if a.installable() && !a.testApex {
-				// TODO(b/123892969): Workaround for not having any way to annotate test-apexs
-				// non-installable apex's cannot be installed and so should not prevent libraries from being
-				// installed to the system.
-				android.UpdateApexDependency(apexBundleName, depName, directDep)
-			}
-
-			if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
-				(directDep || am.DepIsInSameApex(mctx, child)) {
-				am.BuildForApex(apexBundleName)
-				return true
-			} else {
-				return false
-			}
-		})
+		apexBundles = []android.ApexInfo{{mctx.ModuleName(), proptools.Bool(a.properties.Legacy_android10_support)}}
+		directDep = true
+	} else if am, ok := mctx.Module().(android.ApexModule); ok {
+		apexBundles = am.ApexVariations()
+		directDep = false
 	}
+
+	if len(apexBundles) == 0 {
+		return
+	}
+
+	mctx.VisitDirectDeps(func(child android.Module) {
+		depName := mctx.OtherModuleName(child)
+		if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
+			(directDep || am.DepIsInSameApex(mctx, child)) {
+			android.UpdateApexDependency(apexBundles, depName, directDep)
+			am.BuildForApexes(apexBundles)
+		}
+	})
 }
 
 // Create apex variations if a module is included in APEX(s).
@@ -464,10 +1156,13 @@
 	})
 }
 
-type apexNativeDependencies struct {
+type ApexNativeDependencies struct {
 	// List of native libraries
 	Native_shared_libs []string
 
+	// List of JNI libraries
+	Jni_libs []string
+
 	// List of native executables
 	Binaries []string
 
@@ -477,19 +1172,19 @@
 
 type apexMultilibProperties struct {
 	// Native dependencies whose compile_multilib is "first"
-	First apexNativeDependencies
+	First ApexNativeDependencies
 
 	// Native dependencies whose compile_multilib is "both"
-	Both apexNativeDependencies
+	Both ApexNativeDependencies
 
 	// Native dependencies whose compile_multilib is "prefer32"
-	Prefer32 apexNativeDependencies
+	Prefer32 ApexNativeDependencies
 
 	// Native dependencies whose compile_multilib is "32"
-	Lib32 apexNativeDependencies
+	Lib32 ApexNativeDependencies
 
 	// Native dependencies whose compile_multilib is "64"
-	Lib64 apexNativeDependencies
+	Lib64 ApexNativeDependencies
 }
 
 type apexBundleProperties struct {
@@ -511,11 +1206,7 @@
 	// Default: /system/sepolicy/apex/<module_name>_file_contexts.
 	File_contexts *string `android:"path"`
 
-	// List of native shared libs that are embedded inside this APEX bundle
-	Native_shared_libs []string
-
-	// List of executables that are embedded inside this APEX bundle
-	Binaries []string
+	ApexNativeDependencies
 
 	// List of java libraries that are embedded inside this APEX bundle
 	Java_libs []string
@@ -523,9 +1214,6 @@
 	// List of prebuilt files that are embedded inside this APEX bundle
 	Prebuilts []string
 
-	// List of tests that are embedded inside this APEX bundle
-	Tests []string
-
 	// Name of the apex_key module that provides the private key to sign APEX
 	Key *string
 
@@ -584,6 +1272,14 @@
 	Legacy_android10_support *bool
 
 	IsCoverageVariant bool `blueprint:"mutated"`
+
+	// Whether this APEX is considered updatable or not. When set to true, this will enforce additional
+	// rules for making sure that the APEX is truely updatable. This will also disable the size optimizations
+	// like symlinking to the system libs. Default is false.
+	Updatable *bool
+
+	// The minimum SDK version that this apex must be compatibile with.
+	Min_sdk_version *string
 }
 
 type apexTargetBundleProperties struct {
@@ -620,6 +1316,9 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
+
+	// Logging Parent value
+	Logging_parent string
 }
 
 type apexPackaging int
@@ -711,6 +1410,8 @@
 
 	jacocoReportClassesFile android.Path     // only for javalibs and apps
 	certificate             java.Certificate // only for apps
+
+	isJniLib bool
 }
 
 func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile {
@@ -758,6 +1459,12 @@
 	return false
 }
 
+type depInfo struct {
+	to         string
+	from       []string
+	isExternal bool
+}
+
 type apexBundle struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -791,10 +1498,8 @@
 	// list of module names that should be installed along with this APEX
 	requiredDeps []string
 
-	// list of module names that this APEX is depending on (to be shown via *-deps-info target)
-	externalDeps []string
 	// list of module names that this APEX is including (to be shown via *-deps-info target)
-	internalDeps []string
+	depInfos map[string]depInfo
 
 	testApex        bool
 	vndkApex        bool
@@ -825,7 +1530,7 @@
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
-	native_shared_libs []string, binaries []string, tests []string,
+	nativeModules ApexNativeDependencies,
 	target android.Target, imageVariation string) {
 	// Use *FarVariation* to be able to depend on modules having
 	// conflicting variations with this module. This is required since
@@ -835,16 +1540,22 @@
 		{Mutator: "image", Variation: imageVariation},
 		{Mutator: "link", Variation: "shared"},
 		{Mutator: "version", Variation: ""}, // "" is the non-stub variant
-	}...), sharedLibTag, native_shared_libs...)
+	}...), sharedLibTag, nativeModules.Native_shared_libs...)
+
+	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+		{Mutator: "image", Variation: imageVariation},
+		{Mutator: "link", Variation: "shared"},
+		{Mutator: "version", Variation: ""}, // "" is the non-stub variant
+	}...), jniLibTag, nativeModules.Jni_libs...)
 
 	ctx.AddFarVariationDependencies(append(target.Variations(),
 		blueprint.Variation{Mutator: "image", Variation: imageVariation}),
-		executableTag, binaries...)
+		executableTag, nativeModules.Binaries...)
 
 	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 		{Mutator: "image", Variation: imageVariation},
 		{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
-	}...), testTag, tests...)
+	}...), testTag, nativeModules.Tests...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -877,41 +1588,39 @@
 		}
 	}
 	for i, target := range targets {
-		// When multilib.* is omitted for native_shared_libs, it implies
-		// multilib.both.
-		ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-			{Mutator: "image", Variation: a.getImageVariation(config)},
-			{Mutator: "link", Variation: "shared"},
-		}...), sharedLibTag, a.properties.Native_shared_libs...)
-
-		// When multilib.* is omitted for tests, it implies
-		// multilib.both.
-		ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-			{Mutator: "image", Variation: a.getImageVariation(config)},
-			{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
-		}...), testTag, a.properties.Tests...)
+		// When multilib.* is omitted for native_shared_libs/jni_libs/tests, it implies
+		// multilib.both
+		addDependenciesForNativeModules(ctx,
+			ApexNativeDependencies{
+				Native_shared_libs: a.properties.Native_shared_libs,
+				Tests:              a.properties.Tests,
+				Jni_libs:           a.properties.Jni_libs,
+				Binaries:           nil,
+			},
+			target, a.getImageVariation(config))
 
 		// Add native modules targetting both ABIs
 		addDependenciesForNativeModules(ctx,
-			a.properties.Multilib.Both.Native_shared_libs,
-			a.properties.Multilib.Both.Binaries,
-			a.properties.Multilib.Both.Tests,
+			a.properties.Multilib.Both,
 			target,
 			a.getImageVariation(config))
 
 		isPrimaryAbi := i == 0
 		if isPrimaryAbi {
 			// When multilib.* is omitted for binaries, it implies
-			// multilib.first.
-			ctx.AddFarVariationDependencies(append(target.Variations(),
-				blueprint.Variation{Mutator: "image", Variation: a.getImageVariation(config)}),
-				executableTag, a.properties.Binaries...)
+			// multilib.first
+			addDependenciesForNativeModules(ctx,
+				ApexNativeDependencies{
+					Native_shared_libs: nil,
+					Tests:              nil,
+					Jni_libs:           nil,
+					Binaries:           a.properties.Binaries,
+				},
+				target, a.getImageVariation(config))
 
 			// Add native modules targetting the first ABI
 			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.First.Native_shared_libs,
-				a.properties.Multilib.First.Binaries,
-				a.properties.Multilib.First.Tests,
+				a.properties.Multilib.First,
 				target,
 				a.getImageVariation(config))
 		}
@@ -920,32 +1629,24 @@
 		case "lib32":
 			// Add native modules targetting 32-bit ABI
 			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.Lib32.Native_shared_libs,
-				a.properties.Multilib.Lib32.Binaries,
-				a.properties.Multilib.Lib32.Tests,
+				a.properties.Multilib.Lib32,
 				target,
 				a.getImageVariation(config))
 
 			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.Prefer32.Native_shared_libs,
-				a.properties.Multilib.Prefer32.Binaries,
-				a.properties.Multilib.Prefer32.Tests,
+				a.properties.Multilib.Prefer32,
 				target,
 				a.getImageVariation(config))
 		case "lib64":
 			// Add native modules targetting 64-bit ABI
 			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.Lib64.Native_shared_libs,
-				a.properties.Multilib.Lib64.Binaries,
-				a.properties.Multilib.Lib64.Tests,
+				a.properties.Multilib.Lib64,
 				target,
 				a.getImageVariation(config))
 
 			if !has32BitTarget {
 				addDependenciesForNativeModules(ctx,
-					a.properties.Multilib.Prefer32.Native_shared_libs,
-					a.properties.Multilib.Prefer32.Binaries,
-					a.properties.Multilib.Prefer32.Tests,
+					a.properties.Multilib.Prefer32,
 					target,
 					a.getImageVariation(config))
 			}
@@ -954,8 +1655,8 @@
 				for _, sanitizer := range ctx.Config().SanitizeDevice() {
 					if sanitizer == "hwaddress" {
 						addDependenciesForNativeModules(ctx,
-							[]string{"libclang_rt.hwasan-aarch64-android"},
-							nil, nil, target, a.getImageVariation(config))
+							ApexNativeDependencies{[]string{"libclang_rt.hwasan-aarch64-android"}, nil, nil, nil},
+							target, a.getImageVariation(config))
 						break
 					}
 				}
@@ -1228,6 +1929,78 @@
 	return true
 }
 
+// Visit dependencies that contributes to the payload of this APEX
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
+	do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
+	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+		am, ok := child.(android.ApexModule)
+		if !ok || !am.CanHaveApexVariants() {
+			return false
+		}
+
+		// Check for the direct dependencies that contribute to the payload
+		if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
+			if dt.payload {
+				do(ctx, parent, am, false /* externalDep */)
+				return true
+			}
+			return false
+		}
+
+		// Check for the indirect dependencies if it is considered as part of the APEX
+		if am.DepIsInSameApex(ctx, am) {
+			do(ctx, parent, am, false /* externalDep */)
+			return true
+		}
+
+		do(ctx, parent, am, true /* externalDep */)
+
+		// As soon as the dependency graph crosses the APEX boundary, don't go further.
+		return false
+	})
+}
+
+// Ensures that the dependencies are marked as available for this APEX
+func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
+	// Let's be practical. Availability for test, host, and the VNDK apex isn't important
+	if ctx.Host() || a.testApex || a.vndkApex {
+		return
+	}
+
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+		apexName := ctx.ModuleName()
+		if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, to) {
+			return
+		}
+		ctx.ModuleErrorf("requires %q that is not available for the APEX.", to.Name())
+	})
+}
+
+// Collects the list of module names that directly or indirectly contributes to the payload of this APEX
+func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
+	a.depInfos = make(map[string]depInfo)
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+		if from.Name() == to.Name() {
+			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
+			return
+		}
+
+		if info, exists := a.depInfos[to.Name()]; exists {
+			if !android.InList(from.Name(), info.from) {
+				info.from = append(info.from, from.Name())
+			}
+			info.isExternal = info.isExternal && externalDep
+			a.depInfos[to.Name()] = info
+		} else {
+			a.depInfos[to.Name()] = depInfo{
+				to:         to.Name(),
+				from:       []string{from.Name()},
+				isExternal: externalDep,
+			}
+		}
+	})
+}
+
 func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
 	switch a.properties.ApexType {
@@ -1263,6 +2036,10 @@
 		return
 	}
 
+	a.checkApexAvailability(ctx)
+
+	a.collectDepsInfo(ctx)
+
 	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
 
 	// native lib dependencies
@@ -1294,23 +2071,29 @@
 	})
 
 	var filesInfo []apexFile
+	// TODO(jiyong) do this using walkPayloadDeps
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
 		depTag := ctx.OtherModuleDependencyTag(child)
 		depName := ctx.OtherModuleName(child)
 		if _, isDirectDep := parent.(*apexBundle); isDirectDep {
-			if depTag != keyTag && depTag != certificateTag {
-				a.internalDeps = append(a.internalDeps, depName)
-			}
 			switch depTag {
-			case sharedLibTag:
-				if cc, ok := child.(*cc.Module); ok {
-					if cc.HasStubsVariants() {
-						provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
+			case sharedLibTag, jniLibTag:
+				isJniLib := depTag == jniLibTag
+				if c, ok := child.(*cc.Module); ok {
+					// bootstrap bionic libs are treated as provided by system
+					if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
+						provideNativeLibs = append(provideNativeLibs, c.OutputFile().Path().Base())
 					}
-					filesInfo = append(filesInfo, apexFileForNativeLibrary(ctx, cc, handleSpecialLibs))
+					fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
+					fi.isJniLib = isJniLib
+					filesInfo = append(filesInfo, fi)
 					return true // track transitive dependencies
 				} else {
-					ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
+					propertyName := "native_shared_libs"
+					if isJniLib {
+						propertyName = "jni_libs"
+					}
+					ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
 				}
 			case executableTag:
 				if cc, ok := child.(*cc.Module); ok {
@@ -1341,13 +2124,6 @@
 						return false
 					}
 					filesInfo = append(filesInfo, af)
-
-					pf, _ := sdkLib.OutputFiles(".xml")
-					if len(pf) != 1 {
-						ctx.PropertyErrorf("java_libs", "%q failed to generate permission XML", depName)
-						return false
-					}
-					filesInfo = append(filesInfo, newApexFile(ctx, pf[0], pf[0].Base(), "etc/permissions", etc, nil))
 					return true // track transitive dependencies
 				} else {
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
@@ -1436,7 +2212,6 @@
 							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) {
 								a.requiredDeps = append(a.requiredDeps, cc.Name())
 							}
-							a.externalDeps = append(a.externalDeps, depName)
 							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
 							// Don't track further
 							return false
@@ -1444,8 +2219,6 @@
 						af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
 						af.transitiveDep = true
 						filesInfo = append(filesInfo, af)
-						a.internalDeps = append(a.internalDeps, depName)
-						a.internalDeps = append(a.internalDeps, cc.AllStaticDeps()...)
 						return true // track transitive dependencies
 					}
 				} else if cc.IsTestPerSrcDepTag(depTag) {
@@ -1462,10 +2235,12 @@
 						return true // track transitive dependencies
 					}
 				} else if java.IsJniDepTag(depTag) {
-					a.externalDeps = append(a.externalDeps, depName)
-					return true
-				} else if java.IsStaticLibDepTag(depTag) {
-					a.internalDeps = append(a.internalDeps, depName)
+					// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
+					return false
+				} else if java.IsXmlPermissionsFileDepTag(depTag) {
+					if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
+						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
 				}
@@ -1520,23 +2295,6 @@
 		return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
 	})
 
-	// check apex_available requirements
-	if !ctx.Host() && !a.testApex {
-		for _, fi := range filesInfo {
-			if am, ok := fi.module.(android.ApexModule); ok {
-				// vndk {enabled:true} implies visibility to the vndk apex
-				if ccm, ok := fi.module.(*cc.Module); ok && ccm.IsVndk() && a.vndkApex {
-					continue
-				}
-
-				if !am.AvailableFor(ctx.ModuleName()) && !whitelistedApexAvailable(ctx.ModuleName(), a.vndkApex, fi.module) {
-					ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name())
-					// don't stop so that we can report other violations in the same run
-				}
-			}
-		}
-	}
-
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
@@ -1565,6 +2323,17 @@
 		a.installable() &&
 		!proptools.Bool(a.properties.Use_vendor)
 
+	// We don't need the optimization for updatable APEXes, as it might give false signal
+	// to the system health when the APEXes are still bundled (b/149805758)
+	if proptools.Bool(a.properties.Updatable) && a.properties.ApexType == imageApex {
+		a.linkToSystemLib = false
+	}
+
+	// We also don't want the optimization for host APEXes, because it doesn't make sense.
+	if ctx.Host() {
+		a.linkToSystemLib = false
+	}
+
 	// prepare apex_manifest.json
 	a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
 
@@ -1580,22 +2349,31 @@
 	a.buildApexDependencyInfo(ctx)
 }
 
-func whitelistedApexAvailable(apex string, is_vndk bool, module android.Module) bool {
+func whitelistedApexAvailable(apex string, module android.Module) bool {
 	key := apex
 	key = strings.Replace(key, "test_", "", 1)
 	key = strings.Replace(key, "com.android.art.debug", "com.android.art", 1)
 	key = strings.Replace(key, "com.android.art.release", "com.android.art", 1)
 
 	moduleName := module.Name()
-	if strings.Contains(moduleName, "prebuilt_libclang_rt") {
-		// This module has variants that depend on the product being built.
-		moduleName = "prebuilt_libclang_rt"
+	// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
+	// system. Trim the prefix for the check since they are confusing
+	moduleName = strings.TrimPrefix(moduleName, "prebuilt_")
+	if strings.HasPrefix(moduleName, "libclang_rt.") {
+		// This module has many arch variants that depend on the product being built.
+		// We don't want to list them all
+		moduleName = "libclang_rt"
 	}
 
 	if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
 		return true
 	}
 
+	key = "//any"
+	if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+		return true
+	}
+
 	return false
 }
 
@@ -1621,12 +2399,16 @@
 	return bundle
 }
 
+// apex_test is an APEX for testing. The difference from the ordinary apex module type is that
+// certain compatibility checks such as apex_available are not done for apex_test.
 func testApexBundleFactory() android.Module {
 	bundle := newApexBundle()
 	bundle.testApex = true
 	return bundle
 }
 
+// apex packages other modules into an APEX file which is a packaging format for system-level
+// components like binaries, shared libraries, etc.
 func BundleFactory() android.Module {
 	return newApexBundle()
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 22f0f6f..8c5ca8b 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -99,112 +99,6 @@
 	android.ClearApexDependency()
 
 	bp = bp + `
-		toolchain_library {
-			name: "libcompiler_rt-extras",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-		}
-
-		toolchain_library {
-			name: "libatomic",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		toolchain_library {
-			name: "libgcc",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-		}
-
-		toolchain_library {
-			name: "libgcc_stripped",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-aarch64-android",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-arm-android",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-x86_64-android",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-i686-android",
-			src: "",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		cc_object {
-			name: "crtbegin_so",
-			stl: "none",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		cc_object {
-			name: "crtend_so",
-			stl: "none",
-			vendor_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-		}
-
-		cc_object {
-			name: "crtbegin_static",
-			stl: "none",
-		}
-
-		cc_object {
-			name: "crtend_android",
-			stl: "none",
-		}
-
-		llndk_library {
-			name: "libc",
-			symbol_file: "",
-			native_bridge_supported: true,
-		}
-
-		llndk_library {
-			name: "libm",
-			symbol_file: "",
-			native_bridge_supported: true,
-		}
-
-		llndk_library {
-			name: "libdl",
-			symbol_file: "",
-			native_bridge_supported: true,
-		}
-
 		filegroup {
 			name: "myapex-file_contexts",
 			srcs: [
@@ -213,6 +107,8 @@
 		}
 	`
 
+	bp = bp + cc.GatherRequiredDepsForTest(android.Android)
+
 	bp = bp + java.GatherRequiredDepsForTest()
 
 	fs := map[string][]byte{
@@ -223,6 +119,7 @@
 		"apex_manifest.json":                                  nil,
 		"AndroidManifest.xml":                                 nil,
 		"system/sepolicy/apex/myapex-file_contexts":           nil,
+		"system/sepolicy/apex/myapex.updatable-file_contexts": nil,
 		"system/sepolicy/apex/myapex2-file_contexts":          nil,
 		"system/sepolicy/apex/otherapex-file_contexts":        nil,
 		"system/sepolicy/apex/commonapex-file_contexts":       nil,
@@ -258,6 +155,8 @@
 		"dummy.txt":                                  nil,
 	}
 
+	cc.GatherRequiredFilesForTest(fs)
+
 	for _, handler := range handlers {
 		// The fs now needs to be populated before creating the config, call handlers twice
 		// for now, once to get any fs changes, and later after the config was created to
@@ -327,6 +226,14 @@
 	os.RemoveAll(buildDir)
 }
 
+// ensure that 'result' equals 'expected'
+func ensureEquals(t *testing.T, result string, expected string) {
+	t.Helper()
+	if result != expected {
+		t.Errorf("%q != %q", expected, result)
+	}
+}
+
 // ensure that 'result' contains 'expected'
 func ensureContains(t *testing.T, result string, expected string) {
 	t.Helper()
@@ -453,7 +360,6 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			compile_dex: true,
 			static_libs: ["myotherjar"],
 			libs: ["mysharedjar"],
 			// TODO: remove //apex_available:platform
@@ -468,7 +374,11 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			compile_dex: true,
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
 		}
 
 		java_library {
@@ -476,7 +386,6 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			compile_dex: true,
 		}
 	`)
 
@@ -544,10 +453,11 @@
 	ensureListContains(t, noticeInputs, "custom_notice")
 
 	depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n")
-	ensureListContains(t, depsInfo, "internal myjar")
-	ensureListContains(t, depsInfo, "internal mylib")
-	ensureListContains(t, depsInfo, "internal mylib2")
-	ensureListContains(t, depsInfo, "internal myotherjar")
+	ensureListContains(t, depsInfo, "myjar <- myapex")
+	ensureListContains(t, depsInfo, "mylib <- myapex")
+	ensureListContains(t, depsInfo, "mylib2 <- mylib")
+	ensureListContains(t, depsInfo, "myotherjar <- myjar")
+	ensureListContains(t, depsInfo, "mysharedjar (external) <- myjar")
 }
 
 func TestDefaults(t *testing.T) {
@@ -589,7 +499,6 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			compile_dex: true,
 			apex_available: [ "myapex" ],
 		}
 
@@ -760,7 +669,7 @@
 	ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so")
 
 	// Ensure that stubs libs are built without -include flags
-	mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+	mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylib2Cflags, "-include ")
 
 	// Ensure that genstub is invoked with --apex
@@ -791,6 +700,7 @@
 			name: "mylib",
 			srcs: ["mylib.cpp"],
 			shared_libs: ["libfoo#10"],
+			static_libs: ["libbaz"],
 			system_shared_libs: [],
 			stl: "none",
 			apex_available: [ "myapex2" ],
@@ -814,6 +724,14 @@
 			stl: "none",
 		}
 
+		cc_library_static {
+			name: "libbaz",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex2" ],
+		}
+
 	`)
 
 	apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule")
@@ -841,10 +759,10 @@
 	ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
 
 	depsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("myapex2-deps-info.txt").Args["content"], "\\n")
-	ensureListContains(t, depsInfo, "internal mylib")
-	ensureListContains(t, depsInfo, "external libfoo")
-	ensureListNotContains(t, depsInfo, "internal libfoo")
-	ensureListNotContains(t, depsInfo, "external mylib")
+
+	ensureListContains(t, depsInfo, "mylib <- myapex2")
+	ensureListContains(t, depsInfo, "libbaz <- mylib")
+	ensureListContains(t, depsInfo, "libfoo (external) <- mylib")
 }
 
 func TestApexWithRuntimeLibsDependency(t *testing.T) {
@@ -886,6 +804,7 @@
 			stubs: {
 				versions: ["10", "20", "30"],
 			},
+			apex_available: [ "myapex" ],
 		}
 
 		cc_library {
@@ -1001,47 +920,6 @@
 		}
 
 		cc_library {
-			name: "libc",
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			stubs: {
-				versions: ["27", "28", "29"],
-			},
-		}
-
-		cc_library {
-			name: "libm",
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			stubs: {
-				versions: ["27", "28", "29"],
-			},
-			apex_available: [
-				"//apex_available:platform",
-				"myapex"
-			],
-		}
-
-		cc_library {
-			name: "libdl",
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			stubs: {
-				versions: ["27", "28", "29"],
-			},
-			apex_available: [
-				"//apex_available:platform",
-				"myapex"
-			],
-		}
-
-		cc_library {
 			name: "libBootstrap",
 			srcs: ["mylib.cpp"],
 			stl: "none",
@@ -1573,6 +1451,7 @@
 			export_include_dirs: ["my_include"],
 			system_shared_libs: [],
 			stl: "none",
+			apex_available: [ "myapex" ],
 		}
 
 		cc_library {
@@ -1661,13 +1540,17 @@
 	var surplus []string
 	filesMatched := make(map[string]bool)
 	for _, file := range getFiles(t, ctx, moduleName, variant) {
+		mactchFound := false
 		for _, expected := range files {
 			if matched, _ := path.Match(expected, file.path); matched {
 				filesMatched[expected] = true
-				return
+				mactchFound = true
+				break
 			}
 		}
-		surplus = append(surplus, file.path)
+		if !mactchFound {
+			surplus = append(surplus, file.path)
+		}
 	}
 
 	if len(surplus) > 0 {
@@ -1734,8 +1617,10 @@
 	ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
 		"lib/libvndk.so",
 		"lib/libvndksp.so",
+		"lib/libc++.so",
 		"lib64/libvndk.so",
 		"lib64/libvndksp.so",
+		"lib64/libc++.so",
 		"etc/llndk.libraries.VER.txt",
 		"etc/vndkcore.libraries.VER.txt",
 		"etc/vndksp.libraries.VER.txt",
@@ -1795,6 +1680,8 @@
 		"lib/libvndk.so",
 		"lib/libvndk.arm.so",
 		"lib64/libvndk.so",
+		"lib/libc++.so",
+		"lib64/libc++.so",
 		"etc/*",
 	})
 }
@@ -2006,6 +1893,8 @@
 	ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
 		"lib/libvndk.so",
 		"lib64/libvndk.so",
+		"lib/libc++.so",
+		"lib64/libc++.so",
 		"etc/*",
 	})
 }
@@ -2210,11 +2099,12 @@
 }
 
 func TestApexName(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx, config := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
 			apex_name: "com.android.myapex",
+			native_shared_libs: ["mylib"],
 		}
 
 		apex_key {
@@ -2222,6 +2112,17 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
 	`)
 
 	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
@@ -2229,6 +2130,16 @@
 	ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
 	apexRule := module.Rule("apexRule")
 	ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname")
+
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+	name := apexBundle.BaseModuleName()
+	prefix := "TARGET_"
+	var builder strings.Builder
+	data.Custom(&builder, name, prefix, "", data)
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
 }
 
 func TestNonTestApex(t *testing.T) {
@@ -2332,11 +2243,6 @@
 
 	// Ensure that the platform variant ends with _shared
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared")
-
-	if android.InAnyApex("mylib_common_test") {
-		t.Log("Found mylib_common_test in some apex!")
-		t.Fail()
-	}
 }
 
 func TestApexWithTarget(t *testing.T) {
@@ -2958,7 +2864,6 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			compile_dex: true,
 			enabled: false,
 		}
 	`)
@@ -2984,26 +2889,39 @@
 		android_app {
 			name: "AppFoo",
 			srcs: ["foo/bar/MyClass.java"],
-			sdk_version: "none",
+			sdk_version: "current",
 			system_modules: "none",
 			jni_libs: ["libjni"],
+			stl: "none",
 			apex_available: [ "myapex" ],
 		}
 
 		android_app {
 			name: "AppFooPriv",
 			srcs: ["foo/bar/MyClass.java"],
-			sdk_version: "none",
+			sdk_version: "current",
 			system_modules: "none",
 			privileged: true,
+			stl: "none",
 			apex_available: [ "myapex" ],
 		}
 
 		cc_library_shared {
 			name: "libjni",
 			srcs: ["mylib.cpp"],
+			shared_libs: ["libfoo"],
 			stl: "none",
 			system_shared_libs: [],
+			apex_available: [ "myapex" ],
+			sdk_version: "current",
+		}
+
+		cc_library_shared {
+			name: "libfoo",
+			stl: "none",
+			system_shared_libs: [],
+			apex_available: [ "myapex" ],
+			sdk_version: "current",
 		}
 	`)
 
@@ -3014,16 +2932,19 @@
 	ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk")
 	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
 
-	// JNI libraries are embedded inside APK
-	appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni lib")
-	libjniOutput := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
-	ensureListContains(t, appZipRule.Implicits.Strings(), libjniOutput.String())
-	// ... uncompressed
+	appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs")
+	// JNI libraries are uncompressed
 	if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") {
-		t.Errorf("jni lib is not uncompressed for AppFoo")
+		t.Errorf("jni libs are not uncompressed for AppFoo")
 	}
-	// ... and not directly inside the APEX
-	ensureNotContains(t, copyCmds, "image.apex/lib64/libjni.so")
+	// JNI libraries including transitive deps are
+	for _, jni := range []string{"libjni", "libfoo"} {
+		jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
+		// ... embedded inside APK (jnilibs.zip)
+		ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
+		// ... and not directly inside the APEX
+		ensureNotContains(t, copyCmds, "image.apex/lib64/"+jni+".so")
+	}
 }
 
 func TestApexWithAppImports(t *testing.T) {
@@ -3259,10 +3180,15 @@
 	}`)
 
 	// check that libfoo and libbar are created only for myapex, but not for the platform
-	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
-	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
-	ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
-	ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
+	// TODO(jiyong) the checks for the platform variant are removed because we now create
+	// the platform variant regardless of the apex_availability. Instead, we will make sure that
+	// the platform variants are not used from other platform modules. When that is done,
+	// these checks will be replaced by expecting a specific error message that will be
+	// emitted when the platform variant is used.
+	//	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
+	//	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+	//	ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
+	//	ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
 
 	ctx, _ = testApex(t, `
 	apex {
@@ -3311,11 +3237,16 @@
 	}`)
 
 	// shared variant of libfoo is only available to myapex
-	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
-	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
-	// but the static variant is available to both myapex and the platform
-	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static_myapex")
-	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static")
+	// TODO(jiyong) the checks for the platform variant are removed because we now create
+	// the platform variant regardless of the apex_availability. Instead, we will make sure that
+	// the platform variants are not used from other platform modules. When that is done,
+	// these checks will be replaced by expecting a specific error message that will be
+	// emitted when the platform variant is used.
+	//	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
+	//	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+	//	// but the static variant is available to both myapex and the platform
+	//	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static_myapex")
+	//	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static")
 }
 
 func TestOverrideApex(t *testing.T) {
@@ -3332,6 +3263,7 @@
 			base: "myapex",
 			apps: ["override_app"],
 			overrides: ["unknownapex"],
+			logging_parent: "com.foo.bar",
 		}
 
 		apex_key {
@@ -3378,6 +3310,10 @@
 		t.Errorf("name should be \"override_myapex\", but was %q", name)
 	}
 
+	if apexBundle.overridableProperties.Logging_parent != "com.foo.bar" {
+		t.Errorf("override_myapex should have logging parent (com.foo.bar), but was %q.", apexBundle.overridableProperties.Logging_parent)
+	}
+
 	data := android.AndroidMkDataForTest(t, config, "", apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, name, "TARGET_", "", data)
@@ -3397,6 +3333,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			native_shared_libs: ["mylib"],
 			legacy_android10_support: true,
 		}
 
@@ -3405,12 +3342,32 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`)
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			stl: "libc++",
+			system_shared_libs: [],
+			apex_available: [ "myapex" ],
+		}
+	`, withUnbundledBuild)
 
 	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	args := module.Rule("apexRule").Args
 	ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
 	ensureNotContains(t, args["opt_flags"], "--no_hashtree")
+
+	// The copies of the libraries in the apex should have one more dependency than
+	// the ones outside the apex, namely the unwinder. Ideally we should check
+	// the dependency names directly here but for some reason the names are blank in
+	// this test.
+	for _, lib := range []string{"libc++", "mylib"} {
+		apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits
+		nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits
+		if len(apexImplicits) != len(nonApexImplicits)+1 {
+			t.Errorf("%q missing unwinder dep", lib)
+		}
+	}
 }
 
 func TestJavaSDKLibrary(t *testing.T) {
@@ -3448,8 +3405,8 @@
 		"etc/permissions/foo.xml",
 	})
 	// Permission XML should point to the activated path of impl jar of java_sdk_library
-	xml := ctx.ModuleForTests("foo", "android_common_myapex").Output("foo.xml")
-	ensureContains(t, xml.Args["content"], `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
+	sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml")
+	ensureContains(t, sdkLibrary.RuleParams.Command, `<library name=\"foo\" file=\"/apex/myapex/javalib/foo.jar\"`)
 }
 
 func TestCompatConfig(t *testing.T) {
@@ -3477,7 +3434,6 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			compile_dex: true,
 			apex_available: [ "myapex" ],
 		}
 	`)
@@ -3506,6 +3462,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
+			compile_dex: false,
 		}
 	`)
 }
@@ -3557,6 +3514,14 @@
 			java_libs: ["myjar"],
 		}
 
+		apex {
+			name: "myapex.updatable",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+			java_libs: ["myjar"],
+			updatable: true,
+		}
+
 		apex_key {
 			name: "myapex.key",
 			public_key: "testkey.avbpubkey",
@@ -3571,6 +3536,7 @@
 			stl: "none",
 			apex_available: [
 				"myapex",
+				"myapex.updatable",
 				"//apex_available:platform",
 			],
 		}
@@ -3582,6 +3548,7 @@
 			stl: "none",
 			apex_available: [
 				"myapex",
+				"myapex.updatable",
 				"//apex_available:platform",
 			],
 		}
@@ -3592,9 +3559,9 @@
 			sdk_version: "none",
 			system_modules: "none",
 			libs: ["myotherjar"],
-			compile_dex: true,
 			apex_available: [
 				"myapex",
+				"myapex.updatable",
 				"//apex_available:platform",
 			],
 		}
@@ -3606,6 +3573,7 @@
 			system_modules: "none",
 			apex_available: [
 				"myapex",
+				"myapex.updatable",
 				"//apex_available:platform",
 			],
 		}
@@ -3635,17 +3603,94 @@
 		t.Errorf("%q is not found", file)
 	}
 
+	// For unbundled build, symlink shouldn't exist regardless of whether an APEX
+	// is updatable or not
 	ctx, _ := testApex(t, bp, withUnbundledBuild)
 	files := getFiles(t, ctx, "myapex", "android_common_myapex_image")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")
 
+	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+	ensureRealfileExists(t, files, "javalib/myjar.jar")
+	ensureRealfileExists(t, files, "lib64/mylib.so")
+	ensureRealfileExists(t, files, "lib64/myotherlib.so")
+
+	// For bundled build, symlink to the system for the non-updatable APEXes only
 	ctx, _ = testApex(t, bp)
 	files = getFiles(t, ctx, "myapex", "android_common_myapex_image")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureSymlinkExists(t, files, "lib64/myotherlib.so") // this is symlink
+
+	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+	ensureRealfileExists(t, files, "javalib/myjar.jar")
+	ensureRealfileExists(t, files, "lib64/mylib.so")
+	ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
+}
+
+func TestApexWithJniLibs(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			jni_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["mylib2"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+	`)
+
+	rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	// Notice mylib2.so (transitive dep) is not added as a jni_lib
+	ensureEquals(t, rule.Args["opt"], "-a jniLibs mylib.so")
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"lib64/mylib.so",
+		"lib64/mylib2.so",
+	})
+}
+
+func TestApexWithJniLibs_Errors(t *testing.T) {
+	testApexError(t, `jni_libs: "xxx" is not a cc_library`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			jni_libs: ["xxx"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		prebuilt_etc {
+			name: "xxx",
+			src: "xxx",
+		}
+	`, withFiles(map[string][]byte{
+		"xxx": nil,
+	}))
 }
 
 func TestMain(m *testing.M) {
diff --git a/apex/builder.go b/apex/builder.go
index 53f39a6..8c81fb4 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -180,6 +180,17 @@
 		optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
 	}
 
+	// collect jniLibs. Notice that a.filesInfo is already sorted
+	var jniLibs []string
+	for _, fi := range a.filesInfo {
+		if fi.isJniLib {
+			jniLibs = append(jniLibs, fi.builtFile.Base())
+		}
+	}
+	if len(jniLibs) > 0 {
+		optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   apexManifestRule,
 		Input:  manifestSrc,
@@ -215,15 +226,15 @@
 	noticeFiles := []android.Path{}
 	for _, f := range a.filesInfo {
 		if f.module != nil {
-			notice := f.module.NoticeFile()
-			if notice.Valid() {
-				noticeFiles = append(noticeFiles, notice.Path())
+			notices := f.module.NoticeFiles()
+			if len(notices) > 0 {
+				noticeFiles = append(noticeFiles, notices...)
 			}
 		}
 	}
 	// append the notice file specified in the apex module itself
-	if a.NoticeFile().Valid() {
-		noticeFiles = append(noticeFiles, a.NoticeFile().Path())
+	if len(a.NoticeFiles()) > 0 {
+		noticeFiles = append(noticeFiles, a.NoticeFiles()...)
 	}
 
 	if len(noticeFiles) == 0 {
@@ -239,7 +250,7 @@
 	rule.Command().
 		Implicit(builtApex).
 		Text("(cd " + imageDir.String() + " ; ").
-		Text("find . -type f -printf \"%s %p\\n\") ").
+		Text("find . \\( -type f -o -type l \\) -printf \"%s %p\\n\") ").
 		Text(" | sort -nr > ").
 		Output(output)
 	rule.Build(pctx, ctx, "installed-files."+a.Name(), "Installed files")
@@ -383,6 +394,16 @@
 
 		targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
 		minSdkVersion := ctx.Config().DefaultAppTargetSdk()
+
+		if proptools.Bool(a.properties.Legacy_android10_support) {
+			if !java.UseApiFingerprint(ctx, targetSdkVersion) {
+				targetSdkVersion = "29"
+			}
+			if !java.UseApiFingerprint(ctx, minSdkVersion) {
+				minSdkVersion = "29"
+			}
+		}
+
 		if java.UseApiFingerprint(ctx, targetSdkVersion) {
 			targetSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
 			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
@@ -394,6 +415,10 @@
 		optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
 		optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
 
+		if a.overridableProperties.Logging_parent != "" {
+			optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
+		}
+
 		a.mergedNotices = a.buildNoticeFiles(ctx, a.Name()+suffix)
 		if a.mergedNotices.HtmlGzOutput.Valid() {
 			// If there's a NOTICE file, embed it as an asset file in the APEX.
@@ -508,13 +533,13 @@
 	// instead of `android.PathForOutput`) to return the correct path to the flattened
 	// APEX (as its contents is installed by Make, not Soong).
 	factx := flattenedApexContext{ctx}
-	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
-	a.outputFile = android.PathForModuleInstall(&factx, "apex", apexName)
+	apexBundleName := a.Name()
+	a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName)
 
 	if a.installable() && a.GetOverriddenBy() == "" {
-		installPath := android.PathForModuleInstall(ctx, "apex", apexName)
+		installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName)
 		devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
-		addFlattenedFileContextsInfos(ctx, apexName+":"+devicePath+":"+a.fileContexts.String())
+		addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String())
 	}
 	a.buildFilesInfo(ctx)
 }
@@ -550,9 +575,9 @@
 		a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey", ".", etc, nil))
 
 		if a.properties.ApexType == flattenedApex {
-			apexName := proptools.StringDefault(a.properties.Apex_name, a.Name())
+			apexBundleName := a.Name()
 			for _, fi := range a.filesInfo {
-				dir := filepath.Join("apex", apexName, fi.installDir)
+				dir := filepath.Join("apex", apexBundleName, fi.installDir)
 				target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
 				for _, sym := range fi.symlinks {
 					ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
@@ -596,19 +621,14 @@
 		return
 	}
 
-	internalDeps := a.internalDeps
-	externalDeps := a.externalDeps
-
-	internalDeps = android.SortedUniqueStrings(internalDeps)
-	externalDeps = android.SortedUniqueStrings(externalDeps)
-	externalDeps = android.RemoveListFromList(externalDeps, internalDeps)
-
 	var content strings.Builder
-	for _, name := range internalDeps {
-		fmt.Fprintf(&content, "internal %s\\n", name)
-	}
-	for _, name := range externalDeps {
-		fmt.Fprintf(&content, "external %s\\n", name)
+	for _, key := range android.SortedStringKeys(a.depInfos) {
+		info := a.depInfos[key]
+		toName := info.to
+		if info.isExternal {
+			toName = toName + " (external)"
+		}
+		fmt.Fprintf(&content, "%s <- %s\\n", toName, strings.Join(android.SortedUniqueStrings(info.from), ", "))
 	}
 
 	depsInfoFile := android.PathForOutput(ctx, a.Name()+"-deps-info.txt")
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index dd08f03..a9e26ad 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -68,6 +68,7 @@
 			cc_library {
 				name: "libprofile-extras",
 				vendor_available: true,
+				recovery_available: true,
 				native_coverage: false,
 				system_shared_libs: [],
 				stl: "none",
@@ -76,6 +77,23 @@
 			cc_library {
 				name: "libprofile-clang-extras",
 				vendor_available: true,
+				recovery_available: true,
+				native_coverage: false,
+				system_shared_libs: [],
+				stl: "none",
+				notice: "custom_notice",
+			}
+			cc_library {
+				name: "libprofile-extras_ndk",
+				vendor_available: true,
+				native_coverage: false,
+				system_shared_libs: [],
+				stl: "none",
+				notice: "custom_notice",
+			}
+			cc_library {
+				name: "libprofile-clang-extras_ndk",
+				vendor_available: true,
 				native_coverage: false,
 				system_shared_libs: [],
 				stl: "none",
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 1d792ef..59d1502 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -66,6 +66,8 @@
 		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
 		"-isystem bionic/libc/kernel/uapi/asm-arm64",
 		"-isystem bionic/libc/kernel/android/uapi",
+		// TODO(b/149785767): only give access to specific file with AID_* constants
+		"-I       system/core/libcutils/include",
 		"-I       system/bpf/progs/include",
 		"-I " + ctx.ModuleDir(),
 	}
diff --git a/build_kzip.bash b/build_kzip.bash
index 008030f..0018ea9 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -19,16 +19,20 @@
 # The extraction might fail for some source files, so run with -k and then check that
 # sufficiently many files were generated.
 declare -r out="${OUT_DIR:-out}"
+
 # Build extraction files for C++ and Java. Build `merge_zips` which we use later.
 build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java
-#Build extraction file for Go files in build/soong directory.
+
+# Build extraction file for Go the files in build/{blueprint,soong} directories.
 declare -r abspath_out=$(realpath "${out}")
 declare -r go_extractor=$(realpath prebuilts/build-tools/linux-x86/bin/go_extractor)
 declare -r go_root=$(realpath prebuilts/go/linux-x86)
+declare -r vnames_path=$(realpath build/soong/vnames.go.json)
+declare -r source_root=$PWD
 for dir in blueprint soong; do
   (cd "build/$dir";
-   "$go_extractor" --goroot="$go_root" --rules=vnames.go.json --canonicalize_package_corpus \
-    --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
+   KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" --rules="${vnames_path}" \
+   --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
   )
 done
 
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 137cb63..81004da 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -34,7 +34,7 @@
 type AndroidMkContext interface {
 	Name() string
 	Target() android.Target
-	subAndroidMk(*android.AndroidMkData, interface{})
+	subAndroidMk(*android.AndroidMkEntries, interface{})
 	Arch() android.Arch
 	Os() android.OsType
 	Host() bool
@@ -46,29 +46,29 @@
 }
 
 type subAndroidMkProvider interface {
-	AndroidMk(AndroidMkContext, *android.AndroidMkData)
+	AndroidMkEntries(AndroidMkContext, *android.AndroidMkEntries)
 }
 
-func (c *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (c *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) {
 	if c.subAndroidMkOnce == nil {
 		c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
 	}
 	if androidmk, ok := obj.(subAndroidMkProvider); ok {
 		if !c.subAndroidMkOnce[androidmk] {
 			c.subAndroidMkOnce[androidmk] = true
-			androidmk.AndroidMk(c, data)
+			androidmk.AndroidMkEntries(c, entries)
 		}
 	}
 }
 
-func (c *Module) AndroidMk() android.AndroidMkData {
+func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
 	if c.Properties.HideFromMake || !c.IsForPlatform() {
-		return android.AndroidMkData{
+		return []android.AndroidMkEntries{{
 			Disabled: true,
-		}
+		}}
 	}
 
-	ret := android.AndroidMkData{
+	entries := android.AndroidMkEntries{
 		OutputFile: c.outputFile,
 		// TODO(jiyong): add the APEXes providing shared libs to the required modules
 		// Currently, adding c.Properties.ApexesProvidingSharedLibs is causing multiple
@@ -77,29 +77,29 @@
 		Required: c.Properties.AndroidMkRuntimeLibs,
 		Include:  "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
 
-		Extra: []android.AndroidMkExtraFunc{
-			func(w io.Writer, outputFile android.Path) {
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
 				if len(c.Properties.Logtags) > 0 {
-					fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(c.Properties.Logtags, " "))
+					entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...)
 				}
 				if len(c.Properties.AndroidMkSharedLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(c.Properties.AndroidMkSharedLibs, " "))
+					entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
 				}
 				if len(c.Properties.AndroidMkStaticLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkStaticLibs, " "))
+					entries.AddStrings("LOCAL_STATIC_LIBRARIES", c.Properties.AndroidMkStaticLibs...)
 				}
 				if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
+					entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...)
 				}
-				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
+				entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
 				if c.UseVndk() {
-					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+					entries.SetBool("LOCAL_USE_VNDK", true)
 					if c.IsVndk() && !c.static() {
-						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.VndkVersion())
+						entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
 						// VNDK libraries available to vendor are not installed because
 						// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
 						if !c.isVndkExt() {
-							fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+							entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 						}
 					}
 				}
@@ -108,22 +108,22 @@
 	}
 
 	for _, feature := range c.features {
-		c.subAndroidMk(&ret, feature)
+		c.subAndroidMk(&entries, feature)
 	}
 
-	c.subAndroidMk(&ret, c.compiler)
-	c.subAndroidMk(&ret, c.linker)
+	c.subAndroidMk(&entries, c.compiler)
+	c.subAndroidMk(&entries, c.linker)
 	if c.sanitize != nil {
-		c.subAndroidMk(&ret, c.sanitize)
+		c.subAndroidMk(&entries, c.sanitize)
 	}
-	c.subAndroidMk(&ret, c.installer)
+	c.subAndroidMk(&entries, c.installer)
 
-	ret.SubName += c.Properties.SubName
+	entries.SubName += c.Properties.SubName
 
-	return ret
+	return []android.AndroidMkEntries{entries}
 }
 
-func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, ret *android.AndroidMkData) {
+func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	var testFiles []string
 	for _, d := range data {
 		rel := d.Rel()
@@ -135,8 +135,8 @@
 		testFiles = append(testFiles, path+":"+rel)
 	}
 	if len(testFiles) > 0 {
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(testFiles, " "))
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.AddStrings("LOCAL_TEST_DATA", testFiles...)
 		})
 	}
 }
@@ -153,7 +153,7 @@
 	return overrides
 }
 
-func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
+func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
 	exportedFlags := library.exportedFlags()
 	for _, dir := range library.exportedDirs() {
 		exportedFlags = append(exportedFlags, "-I"+dir.String())
@@ -162,75 +162,92 @@
 		exportedFlags = append(exportedFlags, "-isystem "+dir.String())
 	}
 	if len(exportedFlags) > 0 {
-		fmt.Fprintln(w, "LOCAL_EXPORT_CFLAGS :=", strings.Join(exportedFlags, " "))
+		entries.AddStrings("LOCAL_EXPORT_CFLAGS", exportedFlags...)
 	}
 	exportedDeps := library.exportedDeps()
 	if len(exportedDeps) > 0 {
-		fmt.Fprintln(w, "LOCAL_EXPORT_C_INCLUDE_DEPS :=", strings.Join(exportedDeps.Strings(), " "))
+		entries.AddStrings("LOCAL_EXPORT_C_INCLUDE_DEPS", exportedDeps.Strings()...)
 	}
 }
 
-func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
 	if library.sAbiOutputFile.Valid() {
-		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiOutputFile.String())
+		entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
+			"$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiOutputFile.String())
 		if library.sAbiDiff.Valid() && !library.static() {
-			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
-			fmt.Fprintln(w, "HEADER_ABI_DIFFS +=", library.sAbiDiff.String())
+			entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
+				"$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiDiff.String())
+			entries.SetString("HEADER_ABI_DIFFS",
+				"$(HEADER_ABI_DIFFS) "+library.sAbiDiff.String())
 		}
 	}
 }
 
-func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+// TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries
+func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+	if library.sAbiOutputFile.Valid() {
+		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
+			library.sAbiOutputFile.String())
+		if library.sAbiDiff.Valid() && !library.static() {
+			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
+				library.sAbiDiff.String())
+			fmt.Fprintln(w, "HEADER_ABI_DIFFS := $(HEADER_ABI_DIFFS) ",
+				library.sAbiDiff.String())
+		}
+	}
+}
+
+func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	if library.static() {
-		ret.Class = "STATIC_LIBRARIES"
+		entries.Class = "STATIC_LIBRARIES"
 	} else if library.shared() {
-		ret.Class = "SHARED_LIBRARIES"
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", library.toc().String())
+		entries.Class = "SHARED_LIBRARIES"
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
 			if !library.buildStubs() {
-				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+				entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
 			}
 			if len(library.Properties.Overrides) > 0 {
-				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
+				entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
 			}
 			if len(library.post_install_cmds) > 0 {
-				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
+				entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.post_install_cmds, "&& "))
 			}
 		})
 	} else if library.header() {
-		ret.Class = "HEADER_LIBRARIES"
+		entries.Class = "HEADER_LIBRARIES"
 	}
 
-	ret.DistFile = library.distFile
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		library.androidMkWriteExportedFlags(w)
-		library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+	entries.DistFile = library.distFile
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		library.androidMkWriteExportedFlags(entries)
+		library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
 
-		_, _, ext := android.SplitFileExt(outputFile.Base())
+		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
 
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
 
 		if library.coverageOutputFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", library.coverageOutputFile.String())
+			entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
 		}
 
 		if library.useCoreVariant {
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-			fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
-			fmt.Fprintln(w, "LOCAL_VNDK_DEPEND_ON_CORE_VARIANT := true")
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+			entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+			entries.SetBool("LOCAL_VNDK_DEPEND_ON_CORE_VARIANT", true)
 		}
 		if library.checkSameCoreVariant {
-			fmt.Fprintln(w, "LOCAL_CHECK_SAME_VNDK_VARIANTS := true")
+			entries.SetBool("LOCAL_CHECK_SAME_VNDK_VARIANTS", true)
 		}
 	})
 
 	if library.shared() && !library.buildStubs() {
-		ctx.subAndroidMk(ret, library.baseInstaller)
+		ctx.subAndroidMk(entries, library.baseInstaller)
 	} else {
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 			if library.buildStubs() {
-				fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+				entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
 			}
 		})
 	}
@@ -238,90 +255,91 @@
 		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
 		!ctx.static() {
 		if !library.buildStubs() {
-			ret.SubName = ".bootstrap"
+			entries.SubName = ".bootstrap"
 		}
 	}
 }
 
-func (object *objectLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-		out := ret.OutputFile.Path()
-		varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, data.SubName)
+func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "STATIC_LIBRARIES"
+	entries.ExtraFooters = append(entries.ExtraFooters,
+		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			out := entries.OutputFile.Path()
+			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
 
-		fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
-		fmt.Fprintln(w, ".KATI_READONLY: "+varname)
-	}
+			fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
+			fmt.Fprintln(w, ".KATI_READONLY: "+varname)
+		})
 }
 
-func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, binary.baseInstaller)
+func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, binary.baseInstaller)
 
-	ret.Class = "EXECUTABLES"
-	ret.DistFile = binary.distFile
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+	entries.Class = "EXECUTABLES"
+	entries.DistFile = binary.distFile
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
 		if len(binary.symlinks) > 0 {
-			fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(binary.symlinks, " "))
+			entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
 		}
 
 		if binary.coverageOutputFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", binary.coverageOutputFile.String())
+			entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
 		}
 
 		if len(binary.Properties.Overrides) > 0 {
-			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
+			entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
 		}
 		if len(binary.post_install_cmds) > 0 {
-			fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
+			entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.post_install_cmds, "&& "))
 		}
 	})
 }
 
-func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, benchmark.binaryDecorator)
-	ret.Class = "NATIVE_TESTS"
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, benchmark.binaryDecorator)
+	entries.Class = "NATIVE_TESTS"
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if len(benchmark.Properties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+			entries.SetString("LOCAL_COMPATIBILITY_SUITE",
 				strings.Join(benchmark.Properties.Test_suites, " "))
 		}
 		if benchmark.testConfig != nil {
-			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", benchmark.testConfig.String())
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
 		}
-		fmt.Fprintln(w, "LOCAL_NATIVE_BENCHMARK := true")
+		entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
 		if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
-			fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
+			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
 	})
 
-	androidMkWriteTestData(benchmark.data, ctx, ret)
+	androidMkWriteTestData(benchmark.data, ctx, entries)
 }
 
-func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, test.binaryDecorator)
-	ret.Class = "NATIVE_TESTS"
+func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, test.binaryDecorator)
+	entries.Class = "NATIVE_TESTS"
 	if Bool(test.Properties.Test_per_src) {
-		ret.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
+		entries.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
 	}
-
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if len(test.Properties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+			entries.SetString("LOCAL_COMPATIBILITY_SUITE",
 				strings.Join(test.Properties.Test_suites, " "))
 		}
 		if test.testConfig != nil {
-			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String())
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
 		}
 		if !BoolDefault(test.Properties.Auto_gen_config, true) {
-			fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
+			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
 	})
 
-	androidMkWriteTestData(test.data, ctx, ret)
+	androidMkWriteTestData(test.data, ctx, entries)
 }
 
-func (fuzz *fuzzBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, fuzz.binaryDecorator)
+func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, fuzz.binaryDecorator)
 
 	var fuzzFiles []string
 	for _, d := range fuzz.corpus {
@@ -344,142 +362,198 @@
 			filepath.Dir(fuzz.config.String())+":config.json")
 	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true")
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
 		if len(fuzzFiles) > 0 {
-			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
+			entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...)
 		}
 		if fuzz.installedSharedDeps != nil {
-			fmt.Fprintln(w, "LOCAL_FUZZ_INSTALLED_SHARED_DEPS :="+
-				strings.Join(fuzz.installedSharedDeps, " "))
+			entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
 		}
 	})
 }
 
-func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, test.libraryDecorator)
+func (test *testLibrary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, test.libraryDecorator)
 }
 
-func (library *toolchainLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "STATIC_LIBRARIES"
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		_, suffix, _ := android.SplitFileExt(outputFile.Base())
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+func (library *toolchainLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "STATIC_LIBRARIES"
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		_, suffix, _ := android.SplitFileExt(entries.OutputFile.Path().Base())
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
 	})
 }
 
-func (installer *baseInstaller) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
 	if ctx.Target().Os.Class == android.Host {
-		ret.OutputFile = android.OptionalPathForPath(installer.path)
+		entries.OutputFile = android.OptionalPathForPath(installer.path)
 	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(installer.path.ToMakePath().String())
 		stem, suffix, _ := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
 	})
 }
 
-func (c *stubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
-	ret.Class = "SHARED_LIBRARIES"
+func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
+	entries.Class = "SHARED_LIBRARIES"
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(c.installPath.String())
 		stem, suffix, _ := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
-		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
 	})
 }
 
-func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
+func (c *llndkStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
-		_, _, ext := android.SplitFileExt(outputFile.Base())
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
+		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
 
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
-		fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", c.toc().String())
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+		entries.SetString("LOCAL_SOONG_TOC", c.toc().String())
 	})
 }
 
-func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
+func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
 
-	ret.SubName = c.NameSuffix()
+	entries.SubName = c.androidMkSuffix
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
 
 		path, file := filepath.Split(c.path.ToMakePath().String())
 		stem, suffix, ext := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+		if c.tocFile.Valid() {
+			entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
+		}
 	})
 }
 
-func (c *ndkPrebuiltStlLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
-}
+func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	// Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current
+	// and the version of the prebuilt is same as BOARD_VNDK_VERSION.
+	if c.shared() {
+		entries.Class = "SHARED_LIBRARIES"
+	} else if c.static() {
+		entries.Class = "STATIC_LIBRARIES"
+	} else if c.header() {
+		entries.Class = "HEADER_LIBRARIES"
+	}
 
-func (c *vendorPublicLibraryStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
-	ret.SubName = vendorPublicLibrarySuffix
+	if c.androidMkVendorSuffix {
+		entries.SubName = vendorSuffix
+	} else {
+		entries.SubName = ""
+	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
-		_, _, ext := android.SplitFileExt(outputFile.Base())
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
 
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+		if c.shared() || c.static() {
+			path, file := filepath.Split(c.path.ToMakePath().String())
+			stem, suffix, ext := android.SplitFileExt(file)
+			entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+			entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+			entries.SetString("LOCAL_MODULE_STEM", stem)
+			if c.shared() {
+				entries.SetString("LOCAL_MODULE_PATH", path)
+			}
+			if c.tocFile.Valid() {
+				entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
+			}
+		}
+
+		if !c.shared() { // static or header
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		}
 	})
 }
 
-func (p *prebuiltLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+func (c *vendorSnapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "EXECUTABLES"
+
+	if c.androidMkVendorSuffix {
+		entries.SubName = vendorSuffix
+	} else {
+		entries.SubName = ""
+	}
+
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.AddStrings("LOCAL_MODULE_SYMLINKS", c.Properties.Symlinks...)
+	})
+}
+
+func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
+}
+
+func (c *vendorPublicLibraryStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
+	entries.SubName = vendorPublicLibrarySuffix
+
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
+		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
+
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+	})
+}
+
+func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if p.properties.Check_elf_files != nil {
-			fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES :=", *p.properties.Check_elf_files)
+			entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
 		} else {
 			// soong_cc_prebuilt.mk does not include check_elf_file.mk by default
 			// because cc_library_shared and cc_binary use soong_cc_prebuilt.mk as well.
 			// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
 			// true if `p.properties.Check_elf_files` is not specified.
-			fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := true")
+			entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
 		}
 	})
 }
 
-func (p *prebuiltLibraryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, p.libraryDecorator)
+func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, p.libraryDecorator)
 	if p.shared() {
-		ctx.subAndroidMk(ret, &p.prebuiltLinker)
-		androidMkWriteAllowUndefinedSymbols(p.baseLinker, ret)
+		ctx.subAndroidMk(entries, &p.prebuiltLinker)
+		androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
 	}
 }
 
-func (p *prebuiltBinaryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, p.binaryDecorator)
-	ctx.subAndroidMk(ret, &p.prebuiltLinker)
-	androidMkWriteAllowUndefinedSymbols(p.baseLinker, ret)
+func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, p.binaryDecorator)
+	ctx.subAndroidMk(entries, &p.prebuiltLinker)
+	androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
 }
 
-func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, ret *android.AndroidMkData) {
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		allow := linker.Properties.Allow_undefined_symbols
-		if allow != nil {
-			fmt.Fprintln(w, "LOCAL_ALLOW_UNDEFINED_SYMBOLS :=", *allow)
-		}
-	})
+func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, entries *android.AndroidMkEntries) {
+	allow := linker.Properties.Allow_undefined_symbols
+	if allow != nil {
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
+		})
+	}
 }
diff --git a/cc/binary.go b/cc/binary.go
index 280d17b..661264e 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -200,6 +200,11 @@
 	module.compiler = NewBaseCompiler()
 	module.linker = binary
 	module.installer = binary
+
+	// Allow module to be added as member of an sdk/module_exports.
+	module.sdkMemberTypes = []android.SdkMemberType{
+		ccBinarySdkMemberType,
+	}
 	return module, binary
 }
 
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
new file mode 100644
index 0000000..58d6ad0
--- /dev/null
+++ b/cc/binary_sdk_member.go
@@ -0,0 +1,160 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"path/filepath"
+	"strings"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+)
+
+func init() {
+	android.RegisterSdkMemberType(ccBinarySdkMemberType)
+}
+
+var ccBinarySdkMemberType = &binarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_binaries",
+	},
+}
+
+type binarySdkMemberType struct {
+	android.SdkMemberTypeBase
+}
+
+func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+	targets := mctx.MultiTargets()
+	for _, lib := range names {
+		for _, target := range targets {
+			name, version := StubsLibNameAndVersion(lib)
+			if version == "" {
+				version = LatestStubsVersionFor(mctx.Config(), name)
+			}
+			mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+				{Mutator: "version", Variation: version},
+			}...), dependencyTag, name)
+		}
+	}
+}
+
+func (mt *binarySdkMemberType) IsInstance(module android.Module) bool {
+	// Check the module to see if it can be used with this module type.
+	if m, ok := module.(*Module); ok {
+		for _, allowableMemberType := range m.sdkMemberTypes {
+			if allowableMemberType == mt {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+	info := mt.organizeVariants(member)
+	buildSharedNativeBinarySnapshot(info, builder, member)
+}
+
+// Organize the variants by architecture.
+func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
+	memberName := member.Name()
+	info := &nativeBinaryInfo{
+		name:       memberName,
+		memberType: mt,
+	}
+
+	for _, variant := range member.Variants() {
+		ccModule := variant.(*Module)
+
+		info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
+			name:       memberName,
+			archType:   ccModule.Target().Arch.ArchType.String(),
+			outputFile: ccModule.OutputFile().Path(),
+		})
+	}
+
+	// Initialize the unexported properties that will not be set during the
+	// extraction process.
+	info.commonProperties.name = memberName
+
+	// Extract common properties from the arch specific properties.
+	extractCommonProperties(&info.commonProperties, info.archVariantProperties)
+
+	return info
+}
+
+func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
+	pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
+	archVariantCount := len(info.archVariantProperties)
+
+	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+	var multilib string
+	if archVariantCount == 2 {
+		multilib = "both"
+	} else if archVariantCount == 1 {
+		if strings.HasSuffix(info.archVariantProperties[0].archType, "64") {
+			multilib = "64"
+		} else {
+			multilib = "32"
+		}
+	}
+	if multilib != "" {
+		pbm.AddProperty("compile_multilib", multilib)
+	}
+
+	archProperties := pbm.AddPropertySet("arch")
+	for _, av := range info.archVariantProperties {
+		archTypeProperties := archProperties.AddPropertySet(av.archType)
+		archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
+
+		builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
+	}
+}
+
+const (
+	nativeBinaryDir = "bin"
+)
+
+// path to the native binary. Relative to <sdk_root>/<api_dir>
+func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
+	return filepath.Join(lib.archType,
+		nativeBinaryDir, lib.outputFile.Base())
+}
+
+// nativeBinaryInfoProperties represents properties of a native binary
+//
+// The exported (capitalized) fields will be examined and may be changed during common value extraction.
+// The unexported fields will be left untouched.
+type nativeBinaryInfoProperties struct {
+	// The name of the library, is not exported as this must not be changed during optimization.
+	name string
+
+	// archType is not exported as if set (to a non default value) it is always arch specific.
+	// This is "" for common properties.
+	archType string
+
+	// outputFile is not exported as it is always arch specific.
+	outputFile android.Path
+}
+
+// nativeBinaryInfo represents a collection of arch-specific modules having the same name
+type nativeBinaryInfo struct {
+	name                  string
+	memberType            *binarySdkMemberType
+	archVariantProperties []nativeBinaryInfoProperties
+	commonProperties      nativeBinaryInfoProperties
+}
diff --git a/cc/builder.go b/cc/builder.go
index 3ecfe54..136263b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -55,9 +55,9 @@
 		},
 		"ccCmd", "cFlags")
 
-	ccNoDeps = pctx.AndroidRemoteStaticRule("ccNoDeps", android.RemoteRuleSupports{Goma: true},
+	ccNoDeps = pctx.AndroidStaticRule("ccNoDeps",
 		blueprint.RuleParams{
-			Command:     "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -o $out $in",
+			Command:     "$relPwd $ccCmd -c $cFlags -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
 		},
 		"ccCmd", "cFlags")
diff --git a/cc/cc.go b/cc/cc.go
index ce3a2ed..5af8459 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -49,6 +49,8 @@
 		ctx.BottomUp("version", VersionMutator).Parallel()
 		ctx.BottomUp("begin", BeginMutator).Parallel()
 		ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel()
+		ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel()
+		ctx.BottomUp("vendor_snapshot_source", VendorSnapshotSourceMutator).Parallel()
 	})
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -93,6 +95,8 @@
 	HeaderLibs                                  []string
 	RuntimeLibs                                 []string
 
+	StaticUnwinderIfLegacy bool
+
 	ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
 
 	ObjFiles []string
@@ -242,6 +246,10 @@
 	// Even if DeviceConfig().VndkUseCoreVariant() is set, this module must use vendor variant.
 	// see soong/cc/config/vndk.go
 	MustUseVendorVariant bool `blueprint:"mutated"`
+
+	// Used by vendor snapshot to record dependencies from snapshot modules.
+	SnapshotSharedLibs  []string `blueprint:"mutated"`
+	SnapshotRuntimeLibs []string `blueprint:"mutated"`
 }
 
 type VendorProperties struct {
@@ -379,6 +387,7 @@
 	lateSharedDepTag      = DependencyTag{Name: "late shared", Library: true, Shared: true}
 	staticExportDepTag    = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
 	lateStaticDepTag      = DependencyTag{Name: "late static", Library: true}
+	staticUnwinderDepTag  = DependencyTag{Name: "static unwinder", Library: true}
 	wholeStaticDepTag     = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true}
 	headerDepTag          = DependencyTag{Name: "header", Library: true}
 	headerExportDepTag    = DependencyTag{Name: "header", Library: true, ReexportFlags: true}
@@ -403,13 +412,6 @@
 	return ok && ccDepTag.Shared
 }
 
-func IsStaticDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(DependencyTag)
-	return ok && (ccDepTag == staticExportDepTag ||
-		ccDepTag == lateStaticDepTag ||
-		ccDepTag == wholeStaticDepTag)
-}
-
 func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
 	ccDepTag, ok := depTag.(DependencyTag)
 	return ok && ccDepTag == runtimeDepTag
@@ -451,9 +453,6 @@
 	vndkdep   *vndkdep
 	lto       *lto
 	pgo       *pgo
-	xom       *xom
-
-	androidMkSharedLibDeps []string
 
 	outputFile android.OptionalPath
 
@@ -475,9 +474,6 @@
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
 	kytheFiles android.Paths
-
-	// name of the modules that are direct or indirect static deps of this module
-	allStaticDeps []string
 }
 
 func (c *Module) Toc() android.OptionalPath {
@@ -740,9 +736,6 @@
 	if c.pgo != nil {
 		c.AddProperties(c.pgo.props()...)
 	}
-	if c.xom != nil {
-		c.AddProperties(c.xom.props()...)
-	}
 	for _, feature := range c.features {
 		c.AddProperties(feature.props()...)
 	}
@@ -930,6 +923,19 @@
 	return c.linker != nil && c.linker.nativeCoverage()
 }
 
+func (c *Module) isSnapshotPrebuilt() bool {
+	if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
+		return true
+	}
+	if _, ok := c.linker.(*vendorSnapshotLibraryDecorator); ok {
+		return true
+	}
+	if _, ok := c.linker.(*vendorSnapshotBinaryDecorator); ok {
+		return true
+	}
+	return false
+}
+
 func (c *Module) ExportedIncludeDirs() android.Paths {
 	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
 		return flagsProducer.exportedDirs()
@@ -1199,7 +1205,6 @@
 	module.vndkdep = &vndkdep{}
 	module.lto = &lto{}
 	module.pgo = &pgo{}
-	module.xom = &xom{}
 	return module
 }
 
@@ -1266,8 +1271,11 @@
 	allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
 	staticDepFiles := []android.Path{}
 	for _, dep := range staticDeps {
-		allTransitiveDeps[dep.OutputFile().Path()] = dep.GetDepsInLinkOrder()
-		staticDepFiles = append(staticDepFiles, dep.OutputFile().Path())
+		// 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 {
@@ -1285,15 +1293,6 @@
 	return results
 }
 
-func gatherTransitiveStaticDeps(staticDeps []LinkableInterface) []string {
-	var ret []string
-	for _, dep := range staticDeps {
-		ret = append(ret, dep.Module().Name())
-		ret = append(ret, dep.AllStaticDeps()...)
-	}
-	return android.FirstUniqueStrings(ret)
-}
-
 func (c *Module) IsTestPerSrcAllTestsVariation() bool {
 	test, ok := c.linker.(testPerSrc)
 	return ok && test.isAllTestsVariation()
@@ -1400,9 +1399,6 @@
 	if c.pgo != nil {
 		flags = c.pgo.flags(ctx, flags)
 	}
-	if c.xom != nil {
-		flags = c.xom.flags(ctx, flags)
-	}
 	for _, feature := range c.features {
 		flags = feature.flags(ctx, flags)
 	}
@@ -1621,6 +1617,10 @@
 }
 
 func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
+	if !c.Enabled() {
+		return
+	}
+
 	ctx := &depsContext{
 		BottomUpMutatorContext: actx,
 		moduleContextImpl: moduleContextImpl{
@@ -1636,7 +1636,7 @@
 	if ctx.Os() == android.Android {
 		version := ctx.sdkVersion()
 
-		// rewriteNdkLibs takes a list of names of shared libraries and scans it for three types
+		// rewriteLibs takes a list of names of shared libraries and scans it for three types
 		// of names:
 		//
 		// 1. Name of an NDK library that refers to a prebuilt module.
@@ -1652,7 +1652,26 @@
 		// nonvariantLibs
 
 		vendorPublicLibraries := vendorPublicLibraries(actx.Config())
-		rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
+		vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config())
+
+		rewriteVendorLibs := func(lib string) string {
+			if isLlndkLibrary(lib, ctx.Config()) {
+				return lib + llndkLibrarySuffix
+			}
+
+			// only modules with BOARD_VNDK_VERSION uses snapshot.
+			if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
+				return lib
+			}
+
+			if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok {
+				return snapshot
+			}
+
+			return lib
+		}
+
+		rewriteLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
 			variantLibs = []string{}
 			nonvariantLibs = []string{}
 			for _, entry := range list {
@@ -1664,8 +1683,8 @@
 					} else {
 						variantLibs = append(variantLibs, name+ndkLibrarySuffix)
 					}
-				} else if ctx.useVndk() && isLlndkLibrary(name, ctx.Config()) {
-					nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
+				} else if ctx.useVndk() {
+					nonvariantLibs = append(nonvariantLibs, rewriteVendorLibs(entry))
 				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
 					vendorPublicLib := name + vendorPublicLibrarySuffix
 					if actx.OtherModuleExists(vendorPublicLib) {
@@ -1684,9 +1703,14 @@
 			return nonvariantLibs, variantLibs
 		}
 
-		deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs)
-		deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs)
-		deps.ReexportSharedLibHeaders, _ = rewriteNdkLibs(deps.ReexportSharedLibHeaders)
+		deps.SharedLibs, variantNdkLibs = rewriteLibs(deps.SharedLibs)
+		deps.LateSharedLibs, variantLateNdkLibs = rewriteLibs(deps.LateSharedLibs)
+		deps.ReexportSharedLibHeaders, _ = rewriteLibs(deps.ReexportSharedLibHeaders)
+		if ctx.useVndk() {
+			for idx, lib := range deps.RuntimeLibs {
+				deps.RuntimeLibs[idx] = rewriteVendorLibs(lib)
+			}
+		}
 	}
 
 	buildStubs := false
@@ -1698,11 +1722,28 @@
 		}
 	}
 
+	rewriteSnapshotLibs := func(lib string, snapshotMap *snapshotMap) string {
+		// only modules with BOARD_VNDK_VERSION uses snapshot.
+		if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
+			return lib
+		}
+
+		if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok {
+			return snapshot
+		}
+
+		return lib
+	}
+
+	vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config())
 	for _, lib := range deps.HeaderLibs {
 		depTag := headerDepTag
 		if inList(lib, deps.ReexportHeaderLibHeaders) {
 			depTag = headerExportDepTag
 		}
+
+		lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs)
+
 		if buildStubs {
 			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
 				depTag, lib)
@@ -1718,12 +1759,16 @@
 	}
 
 	syspropImplLibraries := syspropImplLibraries(actx.Config())
+	vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config())
 
 	for _, lib := range deps.WholeStaticLibs {
 		depTag := wholeStaticDepTag
 		if impl, ok := syspropImplLibraries[lib]; ok {
 			lib = impl
 		}
+
+		lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)
+
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, depTag, lib)
@@ -1739,14 +1784,24 @@
 			lib = impl
 		}
 
+		lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)
+
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, depTag, lib)
 	}
 
-	actx.AddVariationDependencies([]blueprint.Variation{
-		{Mutator: "link", Variation: "static"},
-	}, lateStaticDepTag, deps.LateStaticLibs...)
+	if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+		actx.AddVariationDependencies([]blueprint.Variation{
+			{Mutator: "link", Variation: "static"},
+		}, staticUnwinderDepTag, staticUnwinder(actx))
+	}
+
+	for _, lib := range deps.LateStaticLibs {
+		actx.AddVariationDependencies([]blueprint.Variation{
+			{Mutator: "link", Variation: "static"},
+		}, lateStaticDepTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs))
+	}
 
 	addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
 		var variations []blueprint.Variation
@@ -1777,6 +1832,9 @@
 
 	for _, lib := range deps.SharedLibs {
 		depTag := SharedDepTag
+		if c.static() {
+			depTag = SharedFromStaticDepTag
+		}
 		if inList(lib, deps.ReexportSharedLibHeaders) {
 			depTag = sharedExportDepTag
 		}
@@ -2112,6 +2170,14 @@
 			}
 		}
 
+		if depTag == staticUnwinderDepTag {
+			if c.ApexProperties.Info.LegacyAndroid10Support {
+				depTag = StaticDepTag
+			} else {
+				return
+			}
+		}
+
 		// Extract ExplicitlyVersioned field from the depTag and reset it inside the struct.
 		// Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true
 		// won't be matched to SharedDepTag and lateSharedDepTag.
@@ -2194,7 +2260,7 @@
 		depFile := android.OptionalPath{}
 
 		switch depTag {
-		case ndkStubDepTag, SharedDepTag, sharedExportDepTag:
+		case ndkStubDepTag, SharedDepTag, SharedFromStaticDepTag, sharedExportDepTag:
 			ptr = &depPaths.SharedLibs
 			depPtr = &depPaths.SharedLibsDeps
 			depFile = ccDep.Toc()
@@ -2290,14 +2356,33 @@
 			*depPtr = append(*depPtr, dep.Path())
 		}
 
-		makeLibName := func(depName string) string {
+		vendorSuffixModules := vendorSuffixModules(ctx.Config())
+
+		baseLibName := func(depName string) string {
 			libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
 			libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
+			return libName
+		}
+
+		makeLibName := func(depName string) string {
+			libName := baseLibName(depName)
 			isLLndk := isLlndkLibrary(libName, ctx.Config())
 			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
 			bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
 
+			if c, ok := ccDep.(*Module); ok {
+				// Use base module name for snapshots when exporting to Makefile.
+				if c.isSnapshotPrebuilt() && !c.IsVndk() {
+					baseName := c.BaseModuleName()
+					if vendorSuffixModules[baseName] {
+						return baseName + ".vendor"
+					} else {
+						return baseName
+					}
+				}
+			}
+
 			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() {
 				// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 				// core module instead.
@@ -2337,6 +2422,8 @@
 			// they merely serve as Make dependencies and do not affect this lib itself.
 			c.Properties.AndroidMkSharedLibs = append(
 				c.Properties.AndroidMkSharedLibs, makeLibName(depName))
+			// Record baseLibName for snapshots.
+			c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName))
 		case ndkStubDepTag, ndkLateStubDepTag:
 			c.Properties.AndroidMkSharedLibs = append(
 				c.Properties.AndroidMkSharedLibs,
@@ -2347,6 +2434,8 @@
 		case runtimeDepTag:
 			c.Properties.AndroidMkRuntimeLibs = append(
 				c.Properties.AndroidMkRuntimeLibs, makeLibName(depName))
+			// Record baseLibName for snapshots.
+			c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName))
 		case wholeStaticDepTag:
 			c.Properties.AndroidMkWholeStaticLibs = append(
 				c.Properties.AndroidMkWholeStaticLibs, makeLibName(depName))
@@ -2372,8 +2461,6 @@
 		c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
 	}
 
-	c.allStaticDeps = gatherTransitiveStaticDeps(directStaticDeps)
-
 	return depPaths
 }
 
@@ -2533,10 +2620,6 @@
 	return false
 }
 
-func (c *Module) AllStaticDeps() []string {
-	return c.allStaticDeps
-}
-
 func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
 	if c.linker != nil {
 		if library, ok := c.linker.(*libraryDecorator); ok {
@@ -2547,9 +2630,17 @@
 
 func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	if depTag, ok := ctx.OtherModuleDependencyTag(dep).(DependencyTag); ok {
-		if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.Shared {
-			// dynamic dep to a stubs lib crosses APEX boundary
-			return false
+		if cc, ok := dep.(*Module); ok {
+			if cc.HasStubsVariants() && depTag.Shared && depTag.Library {
+				// dynamic dep to a stubs lib crosses APEX boundary
+				return false
+			}
+			if depTag.FromStatic {
+				// shared_lib dependency from a static lib is considered as crossing
+				// the APEX boundary because the dependency doesn't actually is
+				// linked; the dependency is used only during the compilation phase.
+				return false
+			}
 		}
 	}
 	return true
@@ -2601,7 +2692,6 @@
 		&VndkProperties{},
 		&LTOProperties{},
 		&PgoProperties{},
-		&XomProperties{},
 		&android.ProtoProperties{},
 	)
 
@@ -2719,10 +2809,16 @@
 			platformVndkVersion,
 			productVndkVersion,
 		)
-	} else if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+	} else if m.isSnapshotPrebuilt() {
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
-		vendorVariants = append(vendorVariants, lib.version())
+		if snapshot, ok := m.linker.(interface {
+			version() string
+		}); ok {
+			vendorVariants = append(vendorVariants, snapshot.version())
+		} else {
+			mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+		}
 	} else if m.HasVendorVariant() && !vendorSpecific {
 		// This will be available in /system, /vendor and /product
 		// or a /system directory that is available to vendor and product.
@@ -2819,6 +2915,14 @@
 		m.Properties.ImageVariationPrefix = VendorVariationPrefix
 		m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
 		squashVendorSrcs(m)
+
+		// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
+		// Hide other vendor variants to avoid collision.
+		vndkVersion := ctx.DeviceConfig().VndkVersion()
+		if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
+			m.Properties.HideFromMake = true
+			m.SkipInstall()
+		}
 	} else if strings.HasPrefix(variant, ProductVariationPrefix) {
 		m.Properties.ImageVariationPrefix = ProductVariationPrefix
 		m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 332cc45..30ba733 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -258,8 +258,8 @@
 	}
 }
 
-func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, moduleName, snapshotFilename, subDir, variant string) {
-	vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+func checkSnapshot(t *testing.T, ctx *android.TestContext, singletonName, moduleName, snapshotFilename, subDir, variant string) {
+	snapshotSingleton := ctx.SingletonForTests(singletonName)
 
 	mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
 	if !ok {
@@ -273,9 +273,9 @@
 	}
 	snapshotPath := filepath.Join(subDir, snapshotFilename)
 
-	out := vndkSnapshot.Output(snapshotPath)
+	out := snapshotSingleton.Output(snapshotPath)
 	if out.Input.String() != outputFiles[0].String() {
-		t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), outputFiles[0])
+		t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
 	}
 }
 
@@ -398,16 +398,16 @@
 	variant := "android_vendor.VER_arm64_armv8-a_shared"
 	variant2nd := "android_vendor.VER_arm_armv7-a-neon_shared"
 
-	checkVndkSnapshot(t, ctx, "libvndk", "libvndk.so", vndkCoreLibPath, variant)
-	checkVndkSnapshot(t, ctx, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
-	checkVndkSnapshot(t, ctx, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
-	checkVndkSnapshot(t, ctx, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
+	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLibPath, variant)
+	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
+	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
+	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
 
 	snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
-	checkVndkSnapshot(t, ctx, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
-	checkVndkSnapshot(t, ctx, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
-	checkVndkSnapshot(t, ctx, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
-	checkVndkSnapshot(t, ctx, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, "vndk-snapshot", "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, "vndk-snapshot", "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, "vndk-snapshot", "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, "vndk-snapshot", "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
 
 	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
 		"LLNDK: libc.so",
@@ -799,6 +799,88 @@
 	`)
 }
 
+func TestVendorSnapshot(t *testing.T) {
+	bp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libvendor",
+		vendor: true,
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libvendor_available",
+		vendor_available: true,
+		nocrt: true,
+	}
+
+	cc_library_headers {
+		name: "libvendor_headers",
+		vendor_available: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "vendor_bin",
+		vendor: true,
+		nocrt: true,
+	}
+
+	cc_binary {
+		name: "vendor_available_bin",
+		vendor_available: true,
+		nocrt: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, config)
+
+	// Check Vendor snapshot output.
+
+	snapshotDir := "vendor-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+		[]string{"arm", "armv7-a-neon"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		// For shared libraries, only non-VNDK vendor_available modules are captured
+		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+
+		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
+		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
+		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+		checkSnapshot(t, ctx, "vendor-snapshot", "libvndk", "libvndk.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
+
+		// For binary libraries, all vendor:true and vendor_available modules are captured.
+		if archType == "arm64" {
+			binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+			checkSnapshot(t, ctx, "vendor-snapshot", "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
+			checkSnapshot(t, ctx, "vendor-snapshot", "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
+		}
+	}
+}
+
 func TestDoubleLoadableDepError(t *testing.T) {
 	// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
 	testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
@@ -2592,20 +2674,20 @@
 		cc_binary {
 			name: "mybin",
 			srcs: ["foo.c"],
-			static_libs: ["libB"],
+			static_libs: ["libfooB"],
 			static_executable: true,
 			stl: "none",
 		}
 
 		cc_library {
-			name: "libB",
+			name: "libfooB",
 			srcs: ["foo.c"],
-			shared_libs: ["libC"],
+			shared_libs: ["libfooC"],
 			stl: "none",
 		}
 
 		cc_library {
-			name: "libC",
+			name: "libfooC",
 			srcs: ["foo.c"],
 			stl: "none",
 			stubs: {
@@ -2615,7 +2697,7 @@
 
 	mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a").Module().(*Module)
 	actual := mybin.depsInLinkOrder
-	expected := getOutputPaths(ctx, "android_arm64_armv8-a_static", []string{"libB", "libC"})
+	expected := getOutputPaths(ctx, "android_arm64_armv8-a_static", []string{"libfooB", "libfooC"})
 
 	if !reflect.DeepEqual(actual, expected) {
 		t.Errorf("staticDeps orderings were not propagated correctly"+
@@ -2751,3 +2833,42 @@
 		t.Errorf("libboth ar rule wanted %q, got %q", w, g)
 	}
 }
+
+func TestProductVariableDefaults(t *testing.T) {
+	bp := `
+		cc_defaults {
+			name: "libfoo_defaults",
+			srcs: ["foo.c"],
+			cppflags: ["-DFOO"],
+			product_variables: {
+				debuggable: {
+					cppflags: ["-DBAR"],
+				},
+			},
+		}
+
+		cc_library {
+			name: "libfoo",
+			defaults: ["libfoo_defaults"],
+		}
+	`
+
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.Debuggable = BoolPtr(true)
+
+	ctx := CreateTestContext()
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("variable", android.VariableMutator).Parallel()
+	})
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*Module)
+	if !android.InList("-DBAR", libfoo.flags.Local.CppFlags) {
+		t.Errorf("expected -DBAR in cppflags, got %q", libfoo.flags.Local.CppFlags)
+	}
+}
diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go
index b61f2a8..855ff25 100644
--- a/cc/cflag_artifacts.go
+++ b/cc/cflag_artifacts.go
@@ -41,12 +41,7 @@
 // filter.
 func allowedDir(subdir string) bool {
 	subdir += "/"
-	for _, prefix := range TrackedCFlagsDir {
-		if strings.HasPrefix(subdir, prefix) {
-			return true
-		}
-	}
-	return false
+	return android.HasAnyPrefix(subdir, TrackedCFlagsDir)
 }
 
 func (s *cflagArtifactsText) genFlagFilename(flag string) string {
diff --git a/cc/compiler.go b/cc/compiler.go
index 1ced451..c1a8d96 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -241,12 +241,7 @@
 // Return true if the module is in the WarningAllowedProjects.
 func warningsAreAllowed(subdir string) bool {
 	subdir += "/"
-	for _, prefix := range config.WarningAllowedProjects {
-		if strings.HasPrefix(subdir, prefix) {
-			return true
-		}
-	}
-	return false
+	return android.HasAnyPrefix(subdir, config.WarningAllowedProjects)
 }
 
 func addToModuleList(ctx ModuleContext, key android.OnceKey, module string) {
@@ -515,7 +510,7 @@
 
 	// Exclude directories from manual binder interface whitelisting.
 	//TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
-	if android.PrefixInList(ctx.ModuleDir(), allowedManualInterfacePaths) {
+	if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) {
 		flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES")
 	}
 
@@ -604,16 +599,12 @@
 func isThirdParty(path string) bool {
 	thirdPartyDirPrefixes := []string{"external/", "vendor/", "hardware/"}
 
-	for _, prefix := range thirdPartyDirPrefixes {
-		if strings.HasPrefix(path, prefix) {
-			for _, prefix := range thirdPartyDirPrefixExceptions {
-				if prefix.MatchString(path) {
-					return false
-				}
+	if android.HasAnyPrefix(path, thirdPartyDirPrefixes) {
+		for _, prefix := range thirdPartyDirPrefixExceptions {
+			if prefix.MatchString(path) {
+				return false
 			}
-			break
 		}
 	}
-
 	return true
 }
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 8618d09..d849906 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -169,6 +169,10 @@
 		"-Wno-reorder-init-list",
 		// http://b/145211066
 		"-Wno-implicit-int-float-conversion",
+		// New warnings to be fixed after clang-r377782.
+		"-Wno-int-in-bool-context",          // http://b/148287349
+		"-Wno-sizeof-array-div",             // http://b/148815709
+		"-Wno-tautological-overlap-compare", // http://b/148815696
 	}, " "))
 
 	// Extra cflags for external third-party projects to disable warnings that
diff --git a/cc/config/global.go b/cc/config/global.go
index 333885f..d01dd84 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -127,8 +127,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r370808b"
-	ClangDefaultShortVersion = "10.0.2"
+	ClangDefaultVersion      = "clang-r377782b"
+	ClangDefaultShortVersion = "10.0.4"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 52bd9f0..54f693e 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -18,48 +18,12 @@
 // For these libraries, the vendor variants must be installed even if the device
 // has VndkUseCoreVariant set.
 var VndkMustUseVendorVariantList = []string{
-	"android.hardware.automotive.evs@1.0",
-	"android.hardware.automotive.vehicle@2.0",
-	"android.hardware.broadcastradio@2.0",
-	"android.hardware.camera.device@1.0",
-	"android.hardware.camera.device@3.2",
-	"android.hardware.camera.device@3.3",
-	"android.hardware.camera.device@3.4",
-	"android.hardware.camera.provider@2.4",
-	"android.hardware.fastboot@1.0",
-	"android.hardware.media.bufferpool@1.0",
-	"android.hardware.neuralnetworks@1.0",
-	"android.hardware.neuralnetworks@1.1",
-	"android.hardware.neuralnetworks@1.2",
-	"android.hardware.neuralnetworks@1.3",
+	"android.hardware.light-ndk_platform",
+	"android.hardware.identity-ndk_platform",
 	"android.hardware.nfc@1.2",
-	"android.hardware.oemlock@1.0",
-	"android.hardware.power.stats@1.0",
 	"android.hardware.power-ndk_platform",
-	"android.hardware.power@1.0",
-	"android.hardware.power@1.1",
-	"android.hardware.radio@1.4",
-	"android.hardware.secure_element@1.0",
-	"android.hardware.sensors@1.0",
-	"android.hardware.soundtrigger@2.0",
-	"android.hardware.soundtrigger@2.0-core",
-	"android.hardware.soundtrigger@2.1",
-	"android.hardware.tetheroffload.config@1.0",
-	"android.hardware.tetheroffload.control@1.0",
 	"android.hardware.vibrator-ndk_platform",
-	"android.hardware.weaver@1.0",
-	"android.hardware.wifi.hostapd@1.0",
-	"android.hardware.wifi.offload@1.0",
-	"android.hardware.wifi.supplicant@1.0",
-	"android.hardware.wifi.supplicant@1.1",
-	"android.hardware.wifi@1.1",
-	"android.hardware.wifi@1.2",
-	"android.hardwareundtrigger@2.0",
-	"android.hardwareundtrigger@2.0-core",
-	"android.hardwareundtrigger@2.1",
-	"libaudioroute",
 	"libbinder",
-	"libcamera_metadata",
 	"libcrypto",
 	"libexpat",
 	"libgatekeeper",
@@ -68,45 +32,17 @@
 	"libkeymaster_messages",
 	"libkeymaster_portable",
 	"libmedia_omx",
-	"libprotobuf-cpp-full",
-	"libprotobuf-cpp-lite",
 	"libpuresoftkeymasterdevice",
 	"libselinux",
 	"libsoftkeymasterdevice",
 	"libsqlite",
 	"libssl",
-	"libstagefright_amrnb_common",
 	"libstagefright_bufferpool@2.0",
 	"libstagefright_bufferqueue_helper",
-	"libstagefright_enc_common",
-	"libstagefright_flacdec",
 	"libstagefright_foundation",
 	"libstagefright_omx",
 	"libstagefright_omx_utils",
-	"libstagefright_soft_aacdec",
-	"libstagefright_soft_aacenc",
-	"libstagefright_soft_amrdec",
-	"libstagefright_soft_amrnbenc",
-	"libstagefright_soft_amrwbenc",
-	"libstagefright_soft_avcdec",
-	"libstagefright_soft_avcenc",
-	"libstagefright_soft_flacdec",
-	"libstagefright_soft_flacenc",
-	"libstagefright_soft_g711dec",
-	"libstagefright_soft_gsmdec",
-	"libstagefright_soft_hevcdec",
-	"libstagefright_soft_mp3dec",
-	"libstagefright_soft_mpeg2dec",
-	"libstagefright_soft_mpeg4dec",
-	"libstagefright_soft_mpeg4enc",
-	"libstagefright_soft_opusdec",
-	"libstagefright_soft_rawdec",
-	"libstagefright_soft_vorbisdec",
-	"libstagefright_soft_vpxdec",
-	"libstagefright_soft_vpxenc",
 	"libstagefright_xmlparser",
 	"libui",
-	"libvorbisidec",
 	"libxml2",
-	"libyuv",
 }
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 63b9d48..25225b5 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -100,7 +100,7 @@
 	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
 		return xcrunSdk(ctx, "--show-sdk-path")
 	})
-	pctx.StaticVariable("macMinVersion", "10.8")
+	pctx.StaticVariable("macMinVersion", "10.10")
 	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
 		return xcrun(ctx, "--find", "ar")
 	})
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index f08a379..13b5511 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -234,7 +234,7 @@
 }
 
 func (toolchainLinuxX86) LibclangRuntimeLibraryArch() string {
-	return "i686"
+	return "i386"
 }
 
 func (toolchainLinuxX8664) LibclangRuntimeLibraryArch() string {
diff --git a/cc/gen.go b/cc/gen.go
index 17ab45f..b0aadc6 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -162,17 +162,19 @@
 	})
 }
 
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
 	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
 	publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
 	cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
 
+	headers := android.WritablePaths{headerFile, publicHeaderFile}
+
 	ctx.Build(pctx, android.BuildParams{
-		Rule:           sysprop,
-		Description:    "sysprop " + syspropFile.Rel(),
-		Output:         cppFile,
-		ImplicitOutput: headerFile,
-		Input:          syspropFile,
+		Rule:            sysprop,
+		Description:     "sysprop " + syspropFile.Rel(),
+		Output:          cppFile,
+		ImplicitOutputs: headers,
+		Input:           syspropFile,
 		Args: map[string]string{
 			"headerOutDir": filepath.Dir(headerFile.String()),
 			"publicOutDir": filepath.Dir(publicHeaderFile.String()),
@@ -181,7 +183,7 @@
 		},
 	})
 
-	return cppFile, headerFile
+	return cppFile, headers.Paths()
 }
 
 func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
@@ -259,9 +261,9 @@
 			srcFiles[i] = rcFile
 			deps = append(deps, headerFile)
 		case ".sysprop":
-			cppFile, headerFile := genSysprop(ctx, srcFile)
+			cppFile, headerFiles := genSysprop(ctx, srcFile)
 			srcFiles[i] = cppFile
-			deps = append(deps, headerFile)
+			deps = append(deps, headerFiles...)
 		}
 	}
 
diff --git a/cc/library.go b/cc/library.go
index 0bddab5..6ffb7fc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -183,7 +183,6 @@
 	ctx.RegisterModuleType("cc_library", LibraryFactory)
 	ctx.RegisterModuleType("cc_library_host_static", LibraryHostStaticFactory)
 	ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
-	ctx.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
 }
 
 // cc_library creates both static and/or shared libraries for a device and/or
@@ -233,16 +232,6 @@
 	return module.Init()
 }
 
-// cc_library_headers contains a set of c/c++ headers which are imported by
-// other soong cc modules using the header_libs property. For best practices,
-// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
-// Make.
-func LibraryHeaderFactory() android.Module {
-	module, library := NewLibrary(android.HostAndDeviceSupported)
-	library.HeaderOnly()
-	return module.Init()
-}
-
 type flagExporter struct {
 	Properties FlagExporterProperties
 
@@ -281,11 +270,9 @@
 }
 
 func (f *flagExporter) reexportFlags(flags ...string) {
-	for _, flag := range flags {
-		if strings.HasPrefix(flag, "-I") || strings.HasPrefix(flag, "-isystem") {
-			panic(fmt.Errorf("Exporting invalid flag %q: "+
-				"use reexportDirs or reexportSystemDirs to export directories", flag))
-		}
+	if android.PrefixInList(flags, "-I") || android.PrefixInList(flags, "-isystem") {
+		panic(fmt.Errorf("Exporting invalid flag %q: "+
+			"use reexportDirs or reexportSystemDirs to export directories", flag))
 	}
 	f.flags = append(f.flags, flags...)
 }
@@ -1316,22 +1303,28 @@
 	if cc_prebuilt {
 		library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
 
-		// Always create both the static and shared variants for prebuilt libraries, and then disable the one
-		// that is not being used.  This allows them to share the name of a cc_library module, which requires that
-		// all the variants of the cc_library also exist on the prebuilt.
-		modules := mctx.CreateLocalVariations("static", "shared")
-		static := modules[0].(*Module)
-		shared := modules[1].(*Module)
+		// Differentiate between header only and building an actual static/shared library
+		if library.buildStatic() || library.buildShared() {
+			// Always create both the static and shared variants for prebuilt libraries, and then disable the one
+			// that is not being used.  This allows them to share the name of a cc_library module, which requires that
+			// all the variants of the cc_library also exist on the prebuilt.
+			modules := mctx.CreateLocalVariations("static", "shared")
+			static := modules[0].(*Module)
+			shared := modules[1].(*Module)
 
-		static.linker.(prebuiltLibraryInterface).setStatic()
-		shared.linker.(prebuiltLibraryInterface).setShared()
+			static.linker.(prebuiltLibraryInterface).setStatic()
+			shared.linker.(prebuiltLibraryInterface).setShared()
 
-		if !library.buildStatic() {
-			static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			if !library.buildStatic() {
+				static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			}
+			if !library.buildShared() {
+				shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			}
+		} else {
+			// Header only
 		}
-		if !library.buildShared() {
-			shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
-		}
+
 	} else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
 
 		// Non-cc.Modules may need an empty variant for their mutators.
diff --git a/cc/library_headers.go b/cc/library_headers.go
new file mode 100644
index 0000000..88cf7af
--- /dev/null
+++ b/cc/library_headers.go
@@ -0,0 +1,56 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import "android/soong/android"
+
+func init() {
+	RegisterLibraryHeadersBuildComponents(android.InitRegistrationContext)
+
+	// Register sdk member types.
+	android.RegisterSdkMemberType(headersLibrarySdkMemberType)
+}
+
+var headersLibrarySdkMemberType = &librarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_header_libs",
+		SupportsSdk:  true,
+	},
+	prebuiltModuleType: "cc_prebuilt_library_headers",
+	linkTypes:          nil,
+}
+
+func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
+	ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory)
+}
+
+// cc_library_headers contains a set of c/c++ headers which are imported by
+// other soong cc modules using the header_libs property. For best practices,
+// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
+// Make.
+func LibraryHeaderFactory() android.Module {
+	module, library := NewLibrary(android.HostAndDeviceSupported)
+	library.HeaderOnly()
+	module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
+	return module.Init()
+}
+
+// cc_prebuilt_library_headers is a prebuilt version of cc_library_headers
+func prebuiltLibraryHeaderFactory() android.Module {
+	module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+	library.HeaderOnly()
+	return module.Init()
+}
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
new file mode 100644
index 0000000..564ef61
--- /dev/null
+++ b/cc/library_headers_test.go
@@ -0,0 +1,62 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestLibraryHeaders(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library_headers {
+		name: "headers",
+		export_include_dirs: ["my_include"],
+	}
+	cc_library_static {
+		name: "lib",
+		srcs: ["foo.c"],
+		header_libs: ["headers"],
+	}
+	`)
+
+	// test if header search paths are correctly added
+	cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, " -Imy_include ") {
+		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+	}
+}
+
+func TestPrebuiltLibraryHeaders(t *testing.T) {
+	ctx := testCc(t, `
+	cc_prebuilt_library_headers {
+		name: "headers",
+		export_include_dirs: ["my_include"],
+	}
+	cc_library_static {
+		name: "lib",
+		srcs: ["foo.c"],
+		header_libs: ["headers"],
+	}
+	`)
+
+	// test if header search paths are correctly added
+	cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, " -Imy_include ") {
+		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+	}
+}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 165901d..a36917e 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -65,12 +65,19 @@
 			if version == "" {
 				version = LatestStubsVersionFor(mctx.Config(), name)
 			}
-			for _, linkType := range mt.linkTypes {
+			if mt.linkTypes == nil {
 				mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 					{Mutator: "image", Variation: android.CoreVariation},
-					{Mutator: "link", Variation: linkType},
 					{Mutator: "version", Variation: version},
 				}...), dependencyTag, name)
+			} else {
+				for _, linkType := range mt.linkTypes {
+					mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+						{Mutator: "image", Variation: android.CoreVariation},
+						{Mutator: "link", Variation: linkType},
+						{Mutator: "version", Variation: version},
+					}...), dependencyTag, name)
+				}
 			}
 		}
 	}
@@ -92,7 +99,7 @@
 // copy exported header files and stub *.so files
 func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
 	info := mt.organizeVariants(member)
-	buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
+	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
 }
 
 // Organize the variants by architecture.
@@ -115,7 +122,7 @@
 			name:                         memberName,
 			archType:                     ccModule.Target().Arch.ArchType.String(),
 			ExportedIncludeDirs:          exportedIncludeDirs,
-			ExportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
+			exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
 			ExportedSystemIncludeDirs:    ccModule.ExportedSystemIncludeDirs(),
 			ExportedFlags:                ccModule.ExportedFlags(),
 			exportedGeneratedHeaders:     ccModule.ExportedGeneratedHeaders(),
@@ -197,85 +204,148 @@
 	}
 }
 
-func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
-	// a function for emitting include dirs
-	addExportedDirCopyCommandsForNativeLibs := func(lib nativeLibInfoProperties) {
-		// Do not include ExportedGeneratedIncludeDirs in the list of directories whose
-		// contents are copied as they are copied from exportedGeneratedHeaders below.
-		includeDirs := lib.ExportedIncludeDirs
-		includeDirs = append(includeDirs, lib.ExportedSystemIncludeDirs...)
-		for _, dir := range includeDirs {
-			// lib.ArchType is "" for common properties.
-			targetDir := filepath.Join(lib.archType, nativeIncludeDir)
-
-			// TODO(jiyong) copy headers having other suffixes
-			headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
-			for _, file := range headers {
-				src := android.PathForSource(sdkModuleContext, file)
-				dest := filepath.Join(targetDir, file)
-				builder.CopyToSnapshot(src, dest)
-			}
-		}
-
-		genHeaders := lib.exportedGeneratedHeaders
-		for _, file := range genHeaders {
-			// lib.ArchType is "" for common properties.
-			targetDir := filepath.Join(lib.archType, nativeGeneratedIncludeDir)
-
-			dest := filepath.Join(targetDir, lib.name, file.Rel())
-			builder.CopyToSnapshot(file, dest)
-		}
-	}
-
-	addExportedDirCopyCommandsForNativeLibs(info.commonProperties)
-
-	// for each architecture
-	for _, av := range info.archVariantProperties {
-		builder.CopyToSnapshot(av.outputFile, nativeLibraryPathFor(av))
-
-		addExportedDirCopyCommandsForNativeLibs(av)
-	}
-
-	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
-}
-
 func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
 
 	pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
 
-	addPossiblyArchSpecificProperties(info.commonProperties, pbm)
+	addPossiblyArchSpecificProperties(sdkModuleContext, builder, info.commonProperties, pbm)
 
 	archProperties := pbm.AddPropertySet("arch")
 	for _, av := range info.archVariantProperties {
 		archTypeProperties := archProperties.AddPropertySet(av.archType)
-		// Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
-		archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})
 
-		addPossiblyArchSpecificProperties(av, archTypeProperties)
+		// If the library has some link types then it produces an output binary file, otherwise it
+		// is header only.
+		if info.memberType.linkTypes != nil {
+			// Copy the generated library to the snapshot and add a reference to it in the .bp module.
+			nativeLibraryPath := nativeLibraryPathFor(av)
+			builder.CopyToSnapshot(av.outputFile, nativeLibraryPath)
+			archTypeProperties.AddProperty("srcs", []string{nativeLibraryPath})
+		}
+
+		// Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
+		addPossiblyArchSpecificProperties(sdkModuleContext, builder, av, archTypeProperties)
 	}
 	pbm.AddProperty("stl", "none")
 	pbm.AddProperty("system_shared_libs", []string{})
 }
 
-// Add properties that may, or may not, be arch specific.
-func addPossiblyArchSpecificProperties(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
-	addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
-	addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
+type includeDirsProperty struct {
+	// Accessor to retrieve the paths
+	pathsGetter func(libInfo nativeLibInfoProperties) android.Paths
+
+	// The name of the property in the prebuilt library, "" means there is no property.
+	propertyName string
+
+	// The directory within the snapshot directory into which items should be copied.
+	snapshotDir string
+
+	// True if the items on the path should be copied.
+	copy bool
+
+	// True if the paths represent directories, files if they represent files.
+	dirs bool
 }
 
-// a function for emitting include dirs
-func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
-	includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
-	if len(includeDirs) == 0 {
-		return
+var includeDirProperties = []includeDirsProperty{
+	{
+		// ExportedIncludeDirs lists directories that contains some header files to be
+		// copied into a directory in the snapshot. The snapshot directories must be added to
+		// the export_include_dirs property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
+		propertyName: "export_include_dirs",
+		snapshotDir:  nativeIncludeDir,
+		copy:         true,
+		dirs:         true,
+	},
+	{
+		// ExportedSystemIncludeDirs lists directories that contains some system header files to
+		// be copied into a directory in the snapshot. The snapshot directories must be added to
+		// the export_system_include_dirs property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
+		propertyName: "export_system_include_dirs",
+		snapshotDir:  nativeIncludeDir,
+		copy:         true,
+		dirs:         true,
+	},
+	{
+		// exportedGeneratedIncludeDirs lists directories that contains some header files
+		// that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
+		// of these directories do not need to be copied, but these directories do need adding to
+		// the export_include_dirs property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
+		propertyName: "export_include_dirs",
+		snapshotDir:  nativeGeneratedIncludeDir,
+		copy:         false,
+		dirs:         true,
+	},
+	{
+		// exportedGeneratedHeaders lists header files that are in one of the directories
+		// specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
+		// As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
+		// property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
+		propertyName: "",
+		snapshotDir:  nativeGeneratedIncludeDir,
+		copy:         true,
+		dirs:         false,
+	},
+}
+
+// Add properties that may, or may not, be arch specific.
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+
+	// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
+	includeDirs := make(map[string][]string)
+
+	// Iterate over each include directory property, copying files and collating property
+	// values where necessary.
+	for _, propertyInfo := range includeDirProperties {
+		// Calculate the base directory in the snapshot into which the files will be copied.
+		// lib.ArchType is "" for common properties.
+		targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
+
+		propertyName := propertyInfo.propertyName
+
+		// Iterate over each path in one of the include directory properties.
+		for _, path := range propertyInfo.pathsGetter(libInfo) {
+
+			// Copy the files/directories when necessary.
+			if propertyInfo.copy {
+				if propertyInfo.dirs {
+					// When copying a directory glob and copy all the headers within it.
+					// TODO(jiyong) copy headers having other suffixes
+					headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil)
+					for _, file := range headers {
+						src := android.PathForSource(sdkModuleContext, file)
+						dest := filepath.Join(targetDir, file)
+						builder.CopyToSnapshot(src, dest)
+					}
+				} else {
+					// Otherwise, just copy the files.
+					dest := filepath.Join(targetDir, libInfo.name, path.Rel())
+					builder.CopyToSnapshot(path, dest)
+				}
+			}
+
+			// Only directories are added to a property.
+			if propertyInfo.dirs {
+				var snapshotPath string
+				if isGeneratedHeaderDirectory(path) {
+					snapshotPath = filepath.Join(targetDir, libInfo.name)
+				} else {
+					snapshotPath = filepath.Join(targetDir, path.String())
+				}
+
+				includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath)
+			}
+		}
 	}
-	var propertyName string
-	if !systemInclude {
-		propertyName = "export_include_dirs"
-	} else {
-		propertyName = "export_system_include_dirs"
+
+	// Add the collated include dir properties to the output.
+	for property, dirs := range includeDirs {
+		outputProperties.AddProperty(property, dirs)
 	}
-	properties.AddProperty(propertyName, includeDirs)
 }
 
 const (
@@ -290,31 +360,6 @@
 		nativeStubDir, lib.outputFile.Base())
 }
 
-// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
-func nativeIncludeDirPathsFor(lib nativeLibInfoProperties, systemInclude bool) []string {
-	var result []string
-	var includeDirs []android.Path
-	if !systemInclude {
-		// Include the generated include dirs in the exported include dirs.
-		includeDirs = append(lib.ExportedIncludeDirs, lib.ExportedGeneratedIncludeDirs...)
-	} else {
-		includeDirs = lib.ExportedSystemIncludeDirs
-	}
-	for _, dir := range includeDirs {
-		var path string
-		if isGeneratedHeaderDirectory(dir) {
-			path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
-		} else {
-			path = filepath.Join(nativeIncludeDir, dir.String())
-		}
-
-		// lib.ArchType is "" for common properties.
-		path = filepath.Join(lib.archType, path)
-		result = append(result, path)
-	}
-	return result
-}
-
 // nativeLibInfoProperties represents properties of a native lib
 //
 // The exported (capitalized) fields will be examined and may be changed during common value extraction.
@@ -327,14 +372,31 @@
 	// This is "" for common properties.
 	archType string
 
-	ExportedIncludeDirs          android.Paths
-	ExportedGeneratedIncludeDirs android.Paths
-	ExportedSystemIncludeDirs    android.Paths
-	ExportedFlags                []string
+	// The list of possibly common exported include dirs.
+	//
+	// This field is exported as its contents may not be arch specific.
+	ExportedIncludeDirs android.Paths
 
-	// exportedGeneratedHeaders is not exported as if set it is always arch specific.
+	// The list of arch specific exported generated include dirs.
+	//
+	// This field is not exported as its contents are always arch specific.
+	exportedGeneratedIncludeDirs android.Paths
+
+	// The list of arch specific exported generated header files.
+	//
+	// This field is not exported as its contents are is always arch specific.
 	exportedGeneratedHeaders android.Paths
 
+	// The list of possibly common exported system include dirs.
+	//
+	// This field is exported as its contents may not be arch specific.
+	ExportedSystemIncludeDirs android.Paths
+
+	// The list of possibly common exported flags.
+	//
+	// This field is exported as its contents may not be arch specific.
+	ExportedFlags []string
+
 	// outputFile is not exported as it is always arch specific.
 	outputFile android.Path
 }
diff --git a/cc/linkable.go b/cc/linkable.go
index 3c46d9d..e4f034c 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -54,8 +54,6 @@
 	ToolchainLibrary() bool
 	NdkPrebuiltStl() bool
 	StubDecorator() bool
-
-	AllStaticDeps() []string
 }
 
 type DependencyTag struct {
@@ -67,12 +65,17 @@
 	ReexportFlags bool
 
 	ExplicitlyVersioned bool
+
+	FromStatic bool
 }
 
 var (
 	SharedDepTag = DependencyTag{Name: "shared", Library: true, Shared: true}
 	StaticDepTag = DependencyTag{Name: "static", Library: true}
 
+	// Same as SharedDepTag, but from a static lib
+	SharedFromStaticDepTag = DependencyTag{Name: "shared from static", Library: true, Shared: true, FromStatic: true}
+
 	CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
 	CrtEndDepTag   = DependencyTag{Name: "crtend"}
 )
diff --git a/cc/linker.go b/cc/linker.go
index 5a16cbd..a7b621a 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -101,6 +101,10 @@
 			// variant of the C/C++ module.
 			Shared_libs []string
 
+			// list of static libs that only should be used to build the vendor
+			// variant of the C/C++ module.
+			Static_libs []string
+
 			// list of shared libs that should not be used to build the vendor variant
 			// of the C/C++ module.
 			Exclude_shared_libs []string
@@ -222,6 +226,7 @@
 		deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Vendor.Shared_libs...)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor.Exclude_shared_libs)
+		deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Vendor.Static_libs...)
 		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
 		deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Vendor.Exclude_header_libs)
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs)
@@ -496,19 +501,21 @@
 var injectVersionSymbol = pctx.AndroidStaticRule("injectVersionSymbol",
 	blueprint.RuleParams{
 		Command: "$symbolInjectCmd -i $in -o $out -s soong_build_number " +
-			"-from 'SOONG BUILD NUMBER PLACEHOLDER' -v $buildNumberFromFile",
+			"-from 'SOONG BUILD NUMBER PLACEHOLDER' -v $$(cat $buildNumberFile)",
 		CommandDeps: []string{"$symbolInjectCmd"},
 	},
-	"buildNumberFromFile")
+	"buildNumberFile")
 
 func (linker *baseLinker) injectVersionSymbol(ctx ModuleContext, in android.Path, out android.WritablePath) {
+	buildNumberFile := ctx.Config().BuildNumberFile(ctx)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        injectVersionSymbol,
 		Description: "inject version symbol",
 		Input:       in,
 		Output:      out,
+		OrderOnly:   android.Paths{buildNumberFile},
 		Args: map[string]string{
-			"buildNumberFromFile": proptools.NinjaEscape(ctx.Config().BuildNumberFromFile()),
+			"buildNumberFile": buildNumberFile.String(),
 		},
 	})
 }
diff --git a/cc/pgo.go b/cc/pgo.go
index 8eb3400..d5c4b87 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -256,6 +256,12 @@
 		}
 	}
 
+	// PGO profile use is not feasible for a Clang coverage build because
+	// -fprofile-use and -fprofile-instr-generate are incompatible.
+	if ctx.DeviceConfig().ClangCoverageEnabled() {
+		return
+	}
+
 	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
 		proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
 		if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index b0cf489..2c18ac3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -87,15 +87,16 @@
 
 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...)
+
 	// TODO(ccross): verify shared library dependencies
 	if len(p.properties.Srcs) > 0 {
-		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...)
-
 		builderFlags := flagsToBuilderFlags(flags)
 
 		in := p.Prebuilt.SingleSourcePath(ctx)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 93c4b41..6e809bf 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -179,6 +179,7 @@
 	SanitizerEnabled  bool     `blueprint:"mutated"`
 	SanitizeDep       bool     `blueprint:"mutated"`
 	MinimalRuntimeDep bool     `blueprint:"mutated"`
+	BuiltinsDep       bool     `blueprint:"mutated"`
 	UbsanRuntimeDep   bool     `blueprint:"mutated"`
 	InSanitizerDir    bool     `blueprint:"mutated"`
 	Sanitizers        []string `blueprint:"mutated"`
@@ -334,8 +335,8 @@
 		s.Diag.Cfi = nil
 	}
 
-	// Disable sanitizers that depend on the UBSan runtime for host builds.
-	if ctx.Host() {
+	// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
+	if !ctx.Os().Linux() {
 		s.Cfi = nil
 		s.Diag.Cfi = nil
 		s.Misc_undefined = nil
@@ -350,6 +351,12 @@
 		s.Diag.Cfi = nil
 	}
 
+	// Also disable CFI if building against snapshot.
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	if ctx.useVndk() && vndkVersion != "current" && vndkVersion != "" {
+		s.Cfi = nil
+	}
+
 	// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
 	// Keep libc instrumented so that ramdisk / recovery can run hwasan-instrumented code if necessary.
 	if (ctx.inRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
@@ -433,12 +440,19 @@
 func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
 	minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
 	minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib
+	builtinsRuntimeLib := config.BuiltinsRuntimeLibrary(ctx.toolchain()) + ".a"
+	builtinsRuntimePath := "${config.ClangAsanLibDir}/" + builtinsRuntimeLib
 
-	if ctx.Device() && sanitize.Properties.MinimalRuntimeDep {
+	if sanitize.Properties.MinimalRuntimeDep {
 		flags.Local.LdFlags = append(flags.Local.LdFlags,
 			minimalRuntimePath,
 			"-Wl,--exclude-libs,"+minimalRuntimeLib)
 	}
+
+	if sanitize.Properties.BuiltinsDep {
+		flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...)
+	}
+
 	if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
 		return flags
 	}
@@ -541,11 +555,19 @@
 			// there will always be undefined symbols in intermediate libraries.
 			_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
 			flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg)
-		} else {
-			if enableMinimalRuntime(sanitize) {
-				flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
-				flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
-				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+
+			// non-Bionic toolchain prebuilts are missing UBSan's vptr and function sanitizers
+			if !ctx.toolchain().Bionic() {
+				flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
+			}
+		}
+
+		if enableMinimalRuntime(sanitize) {
+			flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
+			flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+			if !ctx.toolchain().Bionic() {
+				flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...)
 			}
 		}
 
@@ -587,18 +609,18 @@
 	return flags
 }
 
-func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (sanitize *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
 	// both the sanitized and non-sanitized variants to make without a name conflict.
-	if ret.Class == "STATIC_LIBRARIES" || ret.Class == "HEADER_LIBRARIES" {
+	if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
 		if Bool(sanitize.Properties.Sanitize.Cfi) {
-			ret.SubName += ".cfi"
+			entries.SubName += ".cfi"
 		}
 		if Bool(sanitize.Properties.Sanitize.Hwaddress) {
-			ret.SubName += ".hwasan"
+			entries.SubName += ".hwasan"
 		}
 		if Bool(sanitize.Properties.Sanitize.Scs) {
-			ret.SubName += ".scs"
+			entries.SubName += ".scs"
 		}
 	}
 }
@@ -739,13 +761,16 @@
 				return false
 			}
 
-			if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil {
+			d, ok := child.(*Module)
+			if !ok || !d.static() {
+				return false
+			}
+			if d.sanitize != nil {
 				if enableMinimalRuntime(d.sanitize) {
 					// If a static dependency is built with the minimal runtime,
 					// make sure we include the ubsan minimal runtime.
 					c.sanitize.Properties.MinimalRuntimeDep = true
-				} else if Bool(d.sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
-					len(d.sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0 {
+				} else if enableUbsanRuntime(d.sanitize) {
 					// If a static dependency runs with full ubsan diagnostics,
 					// make sure we include the ubsan runtime.
 					c.sanitize.Properties.UbsanRuntimeDep = true
@@ -757,10 +782,23 @@
 					return false
 				}
 
+				if c.Os() == android.Linux {
+					c.sanitize.Properties.BuiltinsDep = true
+				}
+
 				return true
-			} else {
-				return false
 			}
+
+			if p, ok := d.linker.(*vendorSnapshotLibraryDecorator); ok {
+				if Bool(p.properties.Sanitize_minimal_dep) {
+					c.sanitize.Properties.MinimalRuntimeDep = true
+				}
+				if Bool(p.properties.Sanitize_ubsan_dep) {
+					c.sanitize.Properties.UbsanRuntimeDep = true
+				}
+			}
+
+			return false
 		})
 	}
 }
@@ -884,11 +922,14 @@
 				runtimeLibrary = config.ScudoRuntimeLibrary(toolchain)
 			}
 		} else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep ||
-			Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
+			Bool(c.sanitize.Properties.Sanitize.Fuzzer) ||
+			Bool(c.sanitize.Properties.Sanitize.Undefined) ||
+			Bool(c.sanitize.Properties.Sanitize.All_undefined) {
 			runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)
 		}
 
-		if mctx.Device() && runtimeLibrary != "" {
+		if runtimeLibrary != "" && (toolchain.Bionic() || c.sanitize.Properties.UbsanRuntimeDep) {
+			// UBSan is supported on non-bionic linux host builds as well
 			if isLlndkLibrary(runtimeLibrary, mctx.Config()) && !c.static() && c.UseVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
@@ -901,12 +942,31 @@
 			// Note that by adding dependency with {static|shared}DepTag, the lib is
 			// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
 			if c.staticBinary() {
+				deps := append(extraStaticDeps, runtimeLibrary)
+				// If we're using snapshots and in vendor, redirect to snapshot whenever possible
+				if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
+					snapshots := vendorSnapshotStaticLibs(mctx.Config())
+					for idx, dep := range deps {
+						if lib, ok := snapshots.get(dep, mctx.Arch().ArchType); ok {
+							deps[idx] = lib
+						}
+					}
+				}
+
 				// static executable gets static runtime libs
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "static"},
 					c.ImageVariation(),
-				}...), StaticDepTag, append([]string{runtimeLibrary}, extraStaticDeps...)...)
+				}...), StaticDepTag, deps...)
 			} else if !c.static() && !c.header() {
+				// If we're using snapshots and in vendor, redirect to snapshot whenever possible
+				if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
+					snapshots := vendorSnapshotSharedLibs(mctx.Config())
+					if lib, ok := snapshots.get(runtimeLibrary, mctx.Arch().ArchType); ok {
+						runtimeLibrary = lib
+					}
+				}
+
 				// dynamic executable and shared libs get shared runtime libs
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "shared"},
@@ -1042,16 +1102,28 @@
 	if !Bool(sanitize.Properties.Sanitize.Address) &&
 		!Bool(sanitize.Properties.Sanitize.Hwaddress) &&
 		!Bool(sanitize.Properties.Sanitize.Fuzzer) &&
+
 		(Bool(sanitize.Properties.Sanitize.Integer_overflow) ||
-			len(sanitize.Properties.Sanitize.Misc_undefined) > 0) &&
+			len(sanitize.Properties.Sanitize.Misc_undefined) > 0 ||
+			Bool(sanitize.Properties.Sanitize.Undefined) ||
+			Bool(sanitize.Properties.Sanitize.All_undefined)) &&
+
 		!(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
 			Bool(sanitize.Properties.Sanitize.Diag.Cfi) ||
+			Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
 			len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0) {
+
 		return true
 	}
 	return false
 }
 
+func enableUbsanRuntime(sanitize *sanitize) bool {
+	return Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
+		Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
+		len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0
+}
+
 func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
 	cfiStaticLibs := cfiStaticLibs(ctx.Config())
 	sort.Strings(*cfiStaticLibs)
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
new file mode 100644
index 0000000..73388ce
--- /dev/null
+++ b/cc/snapshot_utils.go
@@ -0,0 +1,142 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package cc
+
+import (
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
+)
+
+type snapshotLibraryInterface interface {
+	exportedFlagsProducer
+	libraryInterface
+}
+
+var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
+var _ snapshotLibraryInterface = (*libraryDecorator)(nil)
+
+type snapshotMap struct {
+	snapshots map[string]string
+}
+
+func newSnapshotMap() *snapshotMap {
+	return &snapshotMap{
+		snapshots: make(map[string]string),
+	}
+}
+
+func snapshotMapKey(name string, arch android.ArchType) string {
+	return name + ":" + arch.String()
+}
+
+// Adds a snapshot name for given module name and architecture.
+// e.g. add("libbase", X86, "libbase.vndk.29.x86")
+func (s *snapshotMap) add(name string, arch android.ArchType, snapshot string) {
+	s.snapshots[snapshotMapKey(name, arch)] = snapshot
+}
+
+// Returns snapshot name for given module name and architecture, if found.
+// e.g. get("libcutils", X86) => "libcutils.vndk.29.x86", true
+func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, found bool) {
+	snapshot, found = s.snapshots[snapshotMapKey(name, arch)]
+	return snapshot, found
+}
+
+func exportedHeaders(ctx android.SingletonContext, l exportedFlagsProducer) android.Paths {
+	var ret android.Paths
+
+	// Headers in the source tree should be globbed. On the contrast, generated headers
+	// 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()...) {
+		dir := path.String()
+		// Skip if dir is for generated headers
+		if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
+			continue
+		}
+		exts := headerExts
+		// Glob all files under this special directory, because of C++ headers.
+		if strings.HasPrefix(dir, "external/libcxx/include") {
+			exts = []string{""}
+		}
+		for _, ext := range exts {
+			glob, err := ctx.GlobWithDeps(dir+"/**/*"+ext, nil)
+			if err != nil {
+				ctx.Errorf("%#v\n", err)
+				return nil
+			}
+			for _, header := range glob {
+				if strings.HasSuffix(header, "/") {
+					continue
+				}
+				ret = append(ret, android.PathForSource(ctx, header))
+			}
+		}
+	}
+
+	// Collect generated headers
+	for _, header := range append(l.exportedGeneratedHeaders(), l.exportedDeps()...) {
+		// TODO(b/148123511): remove exportedDeps after cleaning up genrule
+		if strings.HasSuffix(header.Base(), "-phony") {
+			continue
+		}
+		ret = append(ret, header)
+	}
+
+	return ret
+}
+
+func copyFile(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cp,
+		Input:       path,
+		Output:      outPath,
+		Description: "Cp " + out,
+		Args: map[string]string{
+			"cpFlags": "-f -L",
+		},
+	})
+	return outPath
+}
+
+func combineNotices(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cat,
+		Inputs:      paths,
+		Output:      outPath,
+		Description: "combine notices for " + out,
+	})
+	return outPath
+}
+
+func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      outPath,
+		Description: "WriteFile " + out,
+		Args: map[string]string{
+			"content": content,
+		},
+	})
+	return outPath
+}
diff --git a/cc/stl.go b/cc/stl.go
index af015f9..eda8a4f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -151,6 +151,14 @@
 	return version < 21
 }
 
+func staticUnwinder(ctx android.BaseModuleContext) string {
+	if ctx.Arch().ArchType == android.Arm {
+		return "libunwind_llvm"
+	} else {
+		return "libgcc_stripped"
+	}
+}
+
 func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
 	switch stl.Properties.SelectedStl {
 	case "libstdc++":
@@ -172,16 +180,16 @@
 		}
 		if ctx.toolchain().Bionic() {
 			if ctx.staticBinary() {
-				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
-				if ctx.Arch().ArchType == android.Arm {
-					deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm")
-				} else {
-					deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped")
-				}
+				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", staticUnwinder(ctx))
+			} else {
+				deps.StaticUnwinderIfLegacy = true
 			}
 		}
 	case "":
 		// None or error.
+		if ctx.toolchain().Bionic() && ctx.Module().Name() == "libc++" {
+			deps.StaticUnwinderIfLegacy = true
+		}
 	case "ndk_system":
 		// TODO: Make a system STL prebuilt for the NDK.
 		// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have
diff --git a/cc/test.go b/cc/test.go
index 05e6fe5..1085d3a 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -49,7 +49,7 @@
 
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test
-	Data []string `android:"path"`
+	Data []string `android:"path,arch_variant"`
 
 	// list of compatibility suites (for example "cts", "vts") that the module should be
 	// installed into.
diff --git a/cc/testing.go b/cc/testing.go
index ba8ed95..a22763a 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -25,10 +25,13 @@
 	RegisterCCBuildComponents(ctx)
 	RegisterBinaryBuildComponents(ctx)
 	RegisterLibraryBuildComponents(ctx)
+	RegisterLibraryHeadersBuildComponents(ctx)
 
 	ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
 	ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
+	ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
+	ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
 }
 
 func GatherRequiredDepsForTest(os android.OsType) string {
@@ -37,6 +40,7 @@
 			name: "libatomic",
 			vendor_available: true,
 			recovery_available: true,
+			native_bridge_supported: true,
 			src: "",
 		}
 
@@ -51,6 +55,7 @@
 			name: "libclang_rt.builtins-arm-android",
 			vendor_available: true,
 			recovery_available: true,
+			native_bridge_supported: true,
 			src: "",
 		}
 
@@ -58,6 +63,7 @@
 			name: "libclang_rt.builtins-aarch64-android",
 			vendor_available: true,
 			recovery_available: true,
+			native_bridge_supported: true,
 			src: "",
 		}
 
@@ -65,6 +71,7 @@
 			name: "libclang_rt.builtins-i686-android",
 			vendor_available: true,
 			recovery_available: true,
+			native_bridge_supported: true,
 			src: "",
 		}
 
@@ -72,6 +79,7 @@
 			name: "libclang_rt.builtins-x86_64-android",
 			vendor_available: true,
 			recovery_available: true,
+			native_bridge_supported: true,
 			src: "",
 		}
 
@@ -115,6 +123,7 @@
 			name: "libclang_rt.ubsan_standalone-aarch64-android",
 			vendor_available: true,
 			recovery_available: true,
+			system_shared_libs: [],
 			srcs: [""],
 		}
 
@@ -139,6 +148,9 @@
 			stl: "none",
 			system_shared_libs: [],
 			recovery_available: true,
+			stubs: {
+				versions: ["27", "28", "29"],
+			},
 		}
 		llndk_library {
 			name: "libc",
@@ -151,6 +163,13 @@
 			stl: "none",
 			system_shared_libs: [],
 			recovery_available: true,
+			stubs: {
+				versions: ["27", "28", "29"],
+			},
+			apex_available: [
+				"//apex_available:platform",
+				"myapex"
+			],
 		}
 		llndk_library {
 			name: "libm",
@@ -163,6 +182,13 @@
 			stl: "none",
 			system_shared_libs: [],
 			recovery_available: true,
+			stubs: {
+				versions: ["27", "28", "29"],
+			},
+			apex_available: [
+				"//apex_available:platform",
+				"myapex"
+			],
 		}
 		llndk_library {
 			name: "libdl",
@@ -188,6 +214,7 @@
 			stl: "none",
 			vendor_available: true,
 			recovery_available: true,
+			host_supported: true,
 		}
 		cc_library {
 			name: "libc++",
@@ -197,10 +224,15 @@
 			stl: "none",
 			vendor_available: true,
 			recovery_available: true,
+			host_supported: true,
 			vndk: {
 				enabled: true,
 				support_system_process: true,
 			},
+			apex_available: [
+				"//apex_available:platform",
+				"myapex"
+			],
 		}
 		cc_library {
 			name: "libc++demangle",
@@ -226,6 +258,7 @@
 			name: "crtbegin_so",
 			recovery_available: true,
 			vendor_available: true,
+			native_bridge_supported: true,
 			stl: "none",
 		}
 
@@ -233,18 +266,23 @@
 			name: "crtbegin_dynamic",
 			recovery_available: true,
 			vendor_available: true,
+			native_bridge_supported: true,
+			stl: "none",
 		}
 
 		cc_object {
 			name: "crtbegin_static",
 			recovery_available: true,
 			vendor_available: true,
+			native_bridge_supported: true,
+			stl: "none",
 		}
 
 		cc_object {
 			name: "crtend_so",
 			recovery_available: true,
 			vendor_available: true,
+			native_bridge_supported: true,
 			stl: "none",
 		}
 
@@ -252,12 +290,57 @@
 			name: "crtend_android",
 			recovery_available: true,
 			vendor_available: true,
+			native_bridge_supported: true,
+			stl: "none",
 		}
 
 		cc_library {
 			name: "libprotobuf-cpp-lite",
 		}
-		`
+
+		cc_library {
+			name: "ndk_libunwind",
+			sdk_version: "current",
+			stl: "none",
+			system_shared_libs: [],
+		}
+
+		cc_library {
+			name: "libc.ndk.current",
+			sdk_version: "current",
+			stl: "none",
+			system_shared_libs: [],
+		}
+
+		cc_library {
+			name: "libm.ndk.current",
+			sdk_version: "current",
+			stl: "none",
+			system_shared_libs: [],
+		}
+
+		cc_library {
+			name: "libdl.ndk.current",
+			sdk_version: "current",
+			stl: "none",
+			system_shared_libs: [],
+		}
+
+		ndk_prebuilt_object {
+			name: "ndk_crtbegin_so.27",
+			sdk_version: "27",
+		}
+
+		ndk_prebuilt_object {
+			name: "ndk_crtend_so.27",
+			sdk_version: "27",
+		}
+
+		ndk_prebuilt_shared_stl {
+			name: "ndk_libc++_shared",
+		}
+	`
+
 	if os == android.Fuchsia {
 		ret += `
 		cc_library {
@@ -273,6 +356,18 @@
 	return ret
 }
 
+func GatherRequiredFilesForTest(fs map[string][]byte) {
+	fs["prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtbegin_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtend_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtbegin_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtend_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtbegin_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtend_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtbegin_so.o"] = nil
+	fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtend_so.o"] = nil
+}
+
 func TestConfig(buildDir string, os android.OsType, env map[string]string,
 	bp string, fs map[string][]byte) android.Config {
 
@@ -293,6 +388,8 @@
 		"liba.so":     nil,
 	}
 
+	GatherRequiredFilesForTest(mockFS)
+
 	for k, v := range fs {
 		mockFS[k] = v
 	}
@@ -320,6 +417,7 @@
 	RegisterRequiredBuildComponentsForTest(ctx)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+	ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
 
 	return ctx
 }
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
new file mode 100644
index 0000000..20762a8
--- /dev/null
+++ b/cc/vendor_snapshot.go
@@ -0,0 +1,842 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package cc
+
+import (
+	"encoding/json"
+	"path/filepath"
+	"sort"
+	"strings"
+	"sync"
+
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+)
+
+const (
+	vendorSnapshotHeaderSuffix = ".vendor_header."
+	vendorSnapshotSharedSuffix = ".vendor_shared."
+	vendorSnapshotStaticSuffix = ".vendor_static."
+	vendorSnapshotBinarySuffix = ".vendor_binary."
+)
+
+var (
+	vendorSnapshotsLock         sync.Mutex
+	vendorSuffixModulesKey      = android.NewOnceKey("vendorSuffixModules")
+	vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
+	vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
+	vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
+	vendorSnapshotBinariesKey   = android.NewOnceKey("vendorSnapshotBinaries")
+)
+
+// vendor snapshot maps hold names of vendor snapshot modules per arch
+func vendorSuffixModules(config android.Config) map[string]bool {
+	return config.Once(vendorSuffixModulesKey, func() interface{} {
+		return make(map[string]bool)
+	}).(map[string]bool)
+}
+
+func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotBinaries(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotBinariesKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+type vendorSnapshotLibraryProperties struct {
+	// snapshot version.
+	Version string
+
+	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
+	Target_arch string
+
+	// Prebuilt file for each arch.
+	Src *string `android:"arch_variant"`
+
+	// list of flags that will be used for any module that links against this module.
+	Export_flags []string `android:"arch_variant"`
+
+	// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols,
+	// etc).
+	Check_elf_files *bool
+
+	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
+	Sanitize_ubsan_dep *bool `android:"arch_variant"`
+
+	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
+	Sanitize_minimal_dep *bool `android:"arch_variant"`
+}
+
+type vendorSnapshotLibraryDecorator struct {
+	*libraryDecorator
+	properties            vendorSnapshotLibraryProperties
+	androidMkVendorSuffix bool
+}
+
+func (p *vendorSnapshotLibraryDecorator) Name(name string) string {
+	return name + p.NameSuffix()
+}
+
+func (p *vendorSnapshotLibraryDecorator) NameSuffix() string {
+	versionSuffix := p.version()
+	if p.arch() != "" {
+		versionSuffix += "." + p.arch()
+	}
+
+	var linkageSuffix string
+	if p.buildShared() {
+		linkageSuffix = vendorSnapshotSharedSuffix
+	} else if p.buildStatic() {
+		linkageSuffix = vendorSnapshotStaticSuffix
+	} else {
+		linkageSuffix = vendorSnapshotHeaderSuffix
+	}
+
+	return linkageSuffix + versionSuffix
+}
+
+func (p *vendorSnapshotLibraryDecorator) version() string {
+	return p.properties.Version
+}
+
+func (p *vendorSnapshotLibraryDecorator) arch() string {
+	return p.properties.Target_arch
+}
+
+func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
+	return p.libraryDecorator.linkerFlags(ctx, flags)
+}
+
+func (p *vendorSnapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+	arches := config.Arches()
+	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+		return false
+	}
+	if !p.header() && p.properties.Src == nil {
+		return false
+	}
+	return true
+}
+
+func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext,
+	flags Flags, deps PathDeps, objs Objects) android.Path {
+	m := ctx.Module().(*Module)
+	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+	if p.header() {
+		return p.libraryDecorator.link(ctx, flags, deps, objs)
+	}
+
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+		return nil
+	}
+
+	p.libraryDecorator.exportIncludes(ctx)
+	p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
+
+	in := android.PathForModuleSrc(ctx, *p.properties.Src)
+	p.unstrippedOutputFile = in
+
+	if p.shared() {
+		libName := in.Base()
+		builderFlags := flagsToBuilderFlags(flags)
+
+		// Optimize out relinking against shared libraries whose interface hasn't changed by
+		// depending on a table of contents file instead of the library itself.
+		tocFile := android.PathForModuleOut(ctx, libName+".toc")
+		p.tocFile = android.OptionalPathForPath(tocFile)
+		TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+	}
+
+	return in
+}
+
+func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
+	return false
+}
+
+func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
+	if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
+		p.baseInstaller.install(ctx, file)
+	}
+}
+
+type vendorSnapshotInterface interface {
+	version() string
+}
+
+func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) {
+	if p.version() != ctx.DeviceConfig().VndkVersion() {
+		ctx.Module().Disable()
+		return
+	}
+}
+
+func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) {
+	module, library := NewLibrary(android.DeviceSupported)
+
+	module.stl = nil
+	module.sanitize = nil
+	library.StripProperties.Strip.None = BoolPtr(true)
+
+	prebuilt := &vendorSnapshotLibraryDecorator{
+		libraryDecorator: library,
+	}
+
+	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+	// Prevent default system libs (libc, libm, and libdl) from being linked
+	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
+		prebuilt.baseLinker.Properties.System_shared_libs = []string{}
+	}
+
+	module.compiler = nil
+	module.linker = prebuilt
+	module.installer = prebuilt
+
+	module.AddProperties(
+		&prebuilt.properties,
+	)
+
+	return module, prebuilt
+}
+
+func VendorSnapshotSharedFactory() android.Module {
+	module, prebuilt := vendorSnapshotLibrary()
+	prebuilt.libraryDecorator.BuildOnlyShared()
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		vendorSnapshotLoadHook(ctx, prebuilt)
+	})
+	return module.Init()
+}
+
+func VendorSnapshotStaticFactory() android.Module {
+	module, prebuilt := vendorSnapshotLibrary()
+	prebuilt.libraryDecorator.BuildOnlyStatic()
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		vendorSnapshotLoadHook(ctx, prebuilt)
+	})
+	return module.Init()
+}
+
+func VendorSnapshotHeaderFactory() android.Module {
+	module, prebuilt := vendorSnapshotLibrary()
+	prebuilt.libraryDecorator.HeaderOnly()
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		vendorSnapshotLoadHook(ctx, prebuilt)
+	})
+	return module.Init()
+}
+
+type vendorSnapshotBinaryProperties struct {
+	// snapshot version.
+	Version string
+
+	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
+	Target_arch string
+
+	// Prebuilt file for each arch.
+	Src *string `android:"arch_variant"`
+}
+
+type vendorSnapshotBinaryDecorator struct {
+	*binaryDecorator
+	properties            vendorSnapshotBinaryProperties
+	androidMkVendorSuffix bool
+}
+
+func (p *vendorSnapshotBinaryDecorator) Name(name string) string {
+	return name + p.NameSuffix()
+}
+
+func (p *vendorSnapshotBinaryDecorator) NameSuffix() string {
+	versionSuffix := p.version()
+	if p.arch() != "" {
+		versionSuffix += "." + p.arch()
+	}
+	return vendorSnapshotBinarySuffix + versionSuffix
+}
+
+func (p *vendorSnapshotBinaryDecorator) version() string {
+	return p.properties.Version
+}
+
+func (p *vendorSnapshotBinaryDecorator) arch() string {
+	return p.properties.Target_arch
+}
+
+func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+	if config.DeviceArch() != p.arch() {
+		return false
+	}
+	if p.properties.Src == nil {
+		return false
+	}
+	return true
+}
+
+func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext,
+	flags Flags, deps PathDeps, objs Objects) android.Path {
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+		return nil
+	}
+
+	in := android.PathForModuleSrc(ctx, *p.properties.Src)
+	builderFlags := flagsToBuilderFlags(flags)
+	p.unstrippedOutputFile = in
+	binName := in.Base()
+	if p.needsStrip(ctx) {
+		stripped := android.PathForModuleOut(ctx, "stripped", binName)
+		p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+		in = stripped
+	}
+
+	m := ctx.Module().(*Module)
+	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+	// use cpExecutable to make it executable
+	outputFile := android.PathForModuleOut(ctx, binName)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.CpExecutable,
+		Description: "prebuilt",
+		Output:      outputFile,
+		Input:       in,
+	})
+
+	return outputFile
+}
+
+func VendorSnapshotBinaryFactory() android.Module {
+	module, binary := NewBinary(android.DeviceSupported)
+	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	binary.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+	// Prevent default system libs (libc, libm, and libdl) from being linked
+	if binary.baseLinker.Properties.System_shared_libs == nil {
+		binary.baseLinker.Properties.System_shared_libs = []string{}
+	}
+
+	prebuilt := &vendorSnapshotBinaryDecorator{
+		binaryDecorator: binary,
+	}
+
+	module.compiler = nil
+	module.sanitize = nil
+	module.stl = nil
+	module.linker = prebuilt
+
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		vendorSnapshotLoadHook(ctx, prebuilt)
+	})
+
+	module.AddProperties(&prebuilt.properties)
+	return module.Init()
+}
+
+func init() {
+	android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+	android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
+	android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+	android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
+	android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
+}
+
+func VendorSnapshotSingleton() android.Singleton {
+	return &vendorSnapshotSingleton{}
+}
+
+type vendorSnapshotSingleton struct {
+	vendorSnapshotZipFile android.OptionalPath
+}
+
+var (
+	// Modules under following directories are ignored. They are OEM's and vendor's
+	// proprietary modules(device/, vendor/, and hardware/).
+	// TODO(b/65377115): Clean up these with more maintainable way
+	vendorProprietaryDirs = []string{
+		"device",
+		"vendor",
+		"hardware",
+	}
+
+	// Modules under following directories are included as they are in AOSP,
+	// although hardware/ is normally for vendor's own.
+	// TODO(b/65377115): Clean up these with more maintainable way
+	aospDirsUnderProprietary = []string{
+		"hardware/interfaces",
+		"hardware/libhardware",
+		"hardware/libhardware_legacy",
+		"hardware/ril",
+	}
+)
+
+// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
+// device/, vendor/, etc.
+func isVendorProprietaryPath(dir string) bool {
+	for _, p := range vendorProprietaryDirs {
+		if strings.HasPrefix(dir, p) {
+			// filter out AOSP defined directories, e.g. hardware/interfaces/
+			aosp := false
+			for _, p := range aospDirsUnderProprietary {
+				if strings.HasPrefix(dir, p) {
+					aosp = true
+					break
+				}
+			}
+			if !aosp {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// Determine if a module is going to be included in vendor snapshot or not.
+//
+// Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in
+// AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
+// depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
+// image and newer system image altogether.
+func isVendorSnapshotModule(ctx android.SingletonContext, m *Module) bool {
+	if !m.Enabled() {
+		return false
+	}
+	// skip proprietary modules, but include all VNDK (static)
+	if isVendorProprietaryPath(ctx.ModuleDir(m)) && !m.IsVndk() {
+		return false
+	}
+	if m.Target().Os.Class != android.Device {
+		return false
+	}
+	if m.Target().NativeBridge == android.NativeBridgeEnabled {
+		return false
+	}
+	// the module must be installed in /vendor
+	if !m.installable() || m.isSnapshotPrebuilt() || !m.inVendor() {
+		return false
+	}
+	// exclude test modules
+	if _, ok := m.linker.(interface{ gtest() bool }); ok {
+		return false
+	}
+	// TODO(b/65377115): add full support for sanitizer
+	if m.sanitize != nil && !m.sanitize.isUnsanitizedVariant() {
+		return false
+	}
+
+	// Libraries
+	if l, ok := m.linker.(snapshotLibraryInterface); ok {
+		if l.static() {
+			return proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+		}
+		if l.shared() {
+			return !m.IsVndk()
+		}
+		return true
+	}
+
+	// Binaries
+	_, ok := m.linker.(*binaryDecorator)
+	if !ok {
+		if _, ok := m.linker.(*prebuiltBinaryLinker); !ok {
+			return false
+		}
+	}
+	return proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+}
+
+func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot.
+	if ctx.DeviceConfig().VndkVersion() != "current" {
+		return
+	}
+
+	var snapshotOutputs android.Paths
+
+	/*
+		Vendor snapshot zipped artifacts directory structure:
+		{SNAPSHOT_ARCH}/
+			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
+				shared/
+					(.so shared libraries)
+				static/
+					(.a static libraries)
+				header/
+					(header only libraries)
+				binary/
+					(executable binaries)
+			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
+				shared/
+					(.so shared libraries)
+				static/
+					(.a static libraries)
+				header/
+					(header only libraries)
+				binary/
+					(executable binaries)
+			NOTICE_FILES/
+				(notice files, e.g. libbase.txt)
+			configs/
+				(config files, e.g. init.rc files, vintf_fragments.xml files, etc.)
+			include/
+				(header files of same directory structure with source tree)
+	*/
+
+	snapshotDir := "vendor-snapshot"
+	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+
+	includeDir := filepath.Join(snapshotArchDir, "include")
+	configsDir := filepath.Join(snapshotArchDir, "configs")
+	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+
+	installedNotices := make(map[string]bool)
+	installedConfigs := make(map[string]bool)
+
+	var headers android.Paths
+
+	type vendorSnapshotLibraryInterface interface {
+		exportedFlagsProducer
+		libraryInterface
+	}
+
+	var _ vendorSnapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
+	var _ vendorSnapshotLibraryInterface = (*libraryDecorator)(nil)
+
+	installSnapshot := func(m *Module) android.Paths {
+		targetArch := "arch-" + m.Target().Arch.ArchType.String()
+		if m.Target().Arch.ArchVariant != "" {
+			targetArch += "-" + m.Target().Arch.ArchVariant
+		}
+
+		var ret android.Paths
+
+		prop := struct {
+			ModuleName          string `json:",omitempty"`
+			RelativeInstallPath string `json:",omitempty"`
+
+			// library flags
+			ExportedDirs       []string `json:",omitempty"`
+			ExportedSystemDirs []string `json:",omitempty"`
+			ExportedFlags      []string `json:",omitempty"`
+			SanitizeMinimalDep bool     `json:",omitempty"`
+			SanitizeUbsanDep   bool     `json:",omitempty"`
+
+			// binary flags
+			Symlinks []string `json:",omitempty"`
+
+			// dependencies
+			SharedLibs  []string `json:",omitempty"`
+			RuntimeLibs []string `json:",omitempty"`
+			Required    []string `json:",omitempty"`
+
+			// extra config files
+			InitRc         []string `json:",omitempty"`
+			VintfFragments []string `json:",omitempty"`
+		}{}
+
+		// Common properties among snapshots.
+		prop.ModuleName = ctx.ModuleName(m)
+		prop.RelativeInstallPath = m.RelativeInstallPath()
+		prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
+		prop.Required = m.RequiredModuleNames()
+		for _, path := range m.InitRc() {
+			prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
+		}
+		for _, path := range m.VintfFragments() {
+			prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
+		}
+
+		// install config files. ignores any duplicates.
+		for _, path := range append(m.InitRc(), m.VintfFragments()...) {
+			out := filepath.Join(configsDir, path.Base())
+			if !installedConfigs[out] {
+				installedConfigs[out] = true
+				ret = append(ret, copyFile(ctx, path, out))
+			}
+		}
+
+		var propOut string
+
+		if l, ok := m.linker.(vendorSnapshotLibraryInterface); ok {
+			// library flags
+			prop.ExportedFlags = l.exportedFlags()
+			for _, dir := range l.exportedDirs() {
+				prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
+			}
+			for _, dir := range l.exportedSystemDirs() {
+				prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
+			}
+			// shared libs dependencies aren't meaningful on static or header libs
+			if l.shared() {
+				prop.SharedLibs = m.Properties.SnapshotSharedLibs
+			}
+			if l.static() && m.sanitize != nil {
+				prop.SanitizeMinimalDep = m.sanitize.Properties.MinimalRuntimeDep || enableMinimalRuntime(m.sanitize)
+				prop.SanitizeUbsanDep = m.sanitize.Properties.UbsanRuntimeDep || enableUbsanRuntime(m.sanitize)
+			}
+
+			var libType string
+			if l.static() {
+				libType = "static"
+			} else if l.shared() {
+				libType = "shared"
+			} else {
+				libType = "header"
+			}
+
+			var stem string
+
+			// install .a or .so
+			if libType != "header" {
+				libPath := m.outputFile.Path()
+				stem = libPath.Base()
+				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
+				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+			} else {
+				stem = ctx.ModuleName(m)
+			}
+
+			propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json")
+		} else {
+			// binary flags
+			prop.Symlinks = m.Symlinks()
+			prop.SharedLibs = m.Properties.SnapshotSharedLibs
+
+			// install bin
+			binPath := m.outputFile.Path()
+			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
+			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
+			propOut = snapshotBinOut + ".json"
+		}
+
+		j, err := json.Marshal(prop)
+		if err != nil {
+			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
+			return nil
+		}
+		ret = append(ret, writeStringToFile(ctx, string(j), propOut))
+
+		return ret
+	}
+
+	ctx.VisitAllModules(func(module android.Module) {
+		m, ok := module.(*Module)
+		if !ok || !isVendorSnapshotModule(ctx, m) {
+			return
+		}
+
+		snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
+		if l, ok := m.linker.(vendorSnapshotLibraryInterface); ok {
+			headers = append(headers, exportedHeaders(ctx, l)...)
+		}
+
+		if len(m.NoticeFiles()) > 0 {
+			noticeName := ctx.ModuleName(m) + ".txt"
+			noticeOut := filepath.Join(noticeDir, noticeName)
+			// skip already copied notice file
+			if !installedNotices[noticeOut] {
+				installedNotices[noticeOut] = true
+				snapshotOutputs = append(snapshotOutputs, combineNotices(
+					ctx, m.NoticeFiles(), noticeOut))
+			}
+		}
+	})
+
+	// install all headers after removing duplicates
+	for _, header := range android.FirstUniquePaths(headers) {
+		snapshotOutputs = append(snapshotOutputs, copyFile(
+			ctx, header, filepath.Join(includeDir, header.String())))
+	}
+
+	// All artifacts are ready. Sort them to normalize ninja and then zip.
+	sort.Slice(snapshotOutputs, func(i, j int) bool {
+		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
+	})
+
+	zipPath := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+".zip")
+	zipRule := android.NewRuleBuilder()
+
+	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
+	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+"_list")
+	zipRule.Command().
+		Text("tr").
+		FlagWithArg("-d ", "\\'").
+		FlagWithRspFileInputList("< ", snapshotOutputs).
+		FlagWithOutput("> ", snapshotOutputList)
+
+	zipRule.Temporary(snapshotOutputList)
+
+	zipRule.Command().
+		BuiltTool(ctx, "soong_zip").
+		FlagWithOutput("-o ", zipPath).
+		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
+		FlagWithInput("-l ", snapshotOutputList)
+
+	zipRule.Build(pctx, ctx, zipPath.String(), "vendor snapshot "+zipPath.String())
+	zipRule.DeleteTemporaryFiles()
+	c.vendorSnapshotZipFile = android.OptionalPathForPath(zipPath)
+}
+
+func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String())
+}
+
+type snapshotInterface interface {
+	matchesWithDevice(config android.DeviceConfig) bool
+}
+
+var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
+var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil)
+var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil)
+
+// gathers all snapshot modules for vendor, and disable unnecessary snapshots
+// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
+func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	// don't need snapshot if current
+	if vndkVersion == "current" || vndkVersion == "" {
+		return
+	}
+
+	module, ok := ctx.Module().(*Module)
+	if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
+		return
+	}
+
+	snapshot, ok := module.linker.(snapshotInterface)
+	if !ok {
+		return
+	}
+
+	if !snapshot.matchesWithDevice(ctx.DeviceConfig()) {
+		// Disable unnecessary snapshot module, but do not disable
+		// vndk_prebuilt_shared because they might be packed into vndk APEX
+		if !module.IsVndk() {
+			module.Disable()
+		}
+		return
+	}
+
+	var snapshotMap *snapshotMap
+
+	if lib, ok := module.linker.(libraryInterface); ok {
+		if lib.static() {
+			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+		} else if lib.shared() {
+			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+		} else {
+			// header
+			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+		}
+	} else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok {
+		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else {
+		return
+	}
+
+	vendorSnapshotsLock.Lock()
+	defer vendorSnapshotsLock.Unlock()
+	snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
+}
+
+// Disables source modules which have snapshots
+func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
+	if !ctx.Device() {
+		return
+	}
+
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	// don't need snapshot if current
+	if vndkVersion == "current" || vndkVersion == "" {
+		return
+	}
+
+	module, ok := ctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	// vendor suffix should be added to snapshots if the source module isn't vendor: true.
+	if !module.SocSpecific() {
+		// But we can't just check SocSpecific() since we already passed the image mutator.
+		// Check ramdisk and recovery to see if we are real "vendor: true" module.
+		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
+		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
+
+		if !ramdisk_available && !recovery_available {
+			vendorSnapshotsLock.Lock()
+			defer vendorSnapshotsLock.Unlock()
+
+			vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
+		}
+	}
+
+	if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
+		// only non-snapshot modules with BOARD_VNDK_VERSION
+		return
+	}
+
+	var snapshotMap *snapshotMap
+
+	if lib, ok := module.linker.(libraryInterface); ok {
+		if lib.static() {
+			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+		} else if lib.shared() {
+			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+		} else {
+			// header
+			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+		}
+	} else if _, ok := module.linker.(*binaryDecorator); ok {
+		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else if _, ok := module.linker.(*prebuiltBinaryLinker); ok {
+		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else {
+		return
+	}
+
+	if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
+		// Corresponding snapshot doesn't exist
+		return
+	}
+
+	// Disables source modules if corresponding snapshot exists.
+	if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
+		// But do not disable because the shared variant depends on the static variant.
+		module.SkipInstall()
+		module.Properties.HideFromMake = true
+	} else {
+		module.Disable()
+	}
+}
diff --git a/cc/vndk.go b/cc/vndk.go
index ab73035..d0492fc 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -229,8 +229,6 @@
 	vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibraries")
 	vndkMustUseVendorVariantListKey  = android.NewOnceKey("vndkMustUseVendorVariantListKey")
 	vndkLibrariesLock                sync.Mutex
-
-	headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
 )
 
 func vndkCoreLibraries(config android.Config) map[string]string {
@@ -548,29 +546,10 @@
 	snapshotDir := "vndk-snapshot"
 	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
 
-	targetArchDirMap := make(map[android.ArchType]string)
-	for _, target := range ctx.Config().Targets[android.Android] {
-		dir := snapshotArchDir
-		if ctx.DeviceConfig().BinderBitness() == "32" {
-			dir = filepath.Join(dir, "binder32")
-		}
-		arch := "arch-" + target.Arch.ArchType.String()
-		if target.Arch.ArchVariant != "" {
-			arch += "-" + target.Arch.ArchVariant
-		}
-		dir = filepath.Join(dir, arch)
-		targetArchDirMap[target.Arch.ArchType] = dir
-	}
 	configsDir := filepath.Join(snapshotArchDir, "configs")
 	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
 	includeDir := filepath.Join(snapshotArchDir, "include")
 
-	// set of include paths exported by VNDK libraries
-	exportedIncludes := make(map[string]bool)
-
-	// generated header files among exported headers.
-	var generatedHeaders android.Paths
-
 	// set of notice files copied.
 	noticeBuilt := make(map[string]bool)
 
@@ -581,67 +560,20 @@
 	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
 	moduleNames := make(map[string]string)
 
-	installSnapshotFileFromPath := func(path android.Path, out string) android.OutputPath {
-		outPath := android.PathForOutput(ctx, out)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        android.Cp,
-			Input:       path,
-			Output:      outPath,
-			Description: "vndk snapshot " + out,
-			Args: map[string]string{
-				"cpFlags": "-f -L",
-			},
-		})
-		return outPath
-	}
+	var headers android.Paths
 
-	installSnapshotFileFromContent := func(content, out string) android.OutputPath {
-		outPath := android.PathForOutput(ctx, out)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        android.WriteFile,
-			Output:      outPath,
-			Description: "vndk snapshot " + out,
-			Args: map[string]string{
-				"content": content,
-			},
-		})
-		return outPath
-	}
-
-	type vndkSnapshotLibraryInterface interface {
-		exportedFlagsProducer
-		libraryInterface
-	}
-
-	var _ vndkSnapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
-	var _ vndkSnapshotLibraryInterface = (*libraryDecorator)(nil)
-
-	installVndkSnapshotLib := func(m *Module, l vndkSnapshotLibraryInterface, vndkType string) (android.Paths, bool) {
-		targetArchDir, ok := targetArchDirMap[m.Target().Arch.ArchType]
-		if !ok {
-			return nil, false
-		}
-
+	installVndkSnapshotLib := func(m *Module, l snapshotLibraryInterface, vndkType string) (android.Paths, bool) {
 		var ret android.Paths
 
-		libPath := m.outputFile.Path()
-		stem := libPath.Base()
-		snapshotLibOut := filepath.Join(targetArchDir, "shared", vndkType, stem)
-		ret = append(ret, installSnapshotFileFromPath(libPath, snapshotLibOut))
-
-		moduleNames[stem] = ctx.ModuleName(m)
-		modulePaths[stem] = ctx.ModuleDir(m)
-
-		if m.NoticeFile().Valid() {
-			noticeName := stem + ".txt"
-			// skip already copied notice file
-			if _, ok := noticeBuilt[noticeName]; !ok {
-				noticeBuilt[noticeName] = true
-				ret = append(ret, installSnapshotFileFromPath(
-					m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName)))
-			}
+		targetArch := "arch-" + m.Target().Arch.ArchType.String()
+		if m.Target().Arch.ArchVariant != "" {
+			targetArch += "-" + m.Target().Arch.ArchVariant
 		}
 
+		libPath := m.outputFile.Path()
+		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
+		ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+
 		if ctx.Config().VndkSnapshotBuildArtifacts() {
 			prop := struct {
 				ExportedDirs        []string `json:",omitempty"`
@@ -661,19 +593,19 @@
 				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
 				return nil, false
 			}
-			ret = append(ret, installSnapshotFileFromContent(string(j), propOut))
+			ret = append(ret, writeStringToFile(ctx, string(j), propOut))
 		}
 		return ret, true
 	}
 
-	isVndkSnapshotLibrary := func(m *Module) (i vndkSnapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
+	isVndkSnapshotLibrary := func(m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
 		if m.Target().NativeBridge == android.NativeBridgeEnabled {
 			return nil, "", false
 		}
-		if !m.UseVndk() || !m.installable() || !m.inVendor() {
+		if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
 			return nil, "", false
 		}
-		l, ok := m.linker.(vndkSnapshotLibraryInterface)
+		l, ok := m.linker.(snapshotLibraryInterface)
 		if !ok || !l.shared() {
 			return nil, "", false
 		}
@@ -699,75 +631,38 @@
 			return
 		}
 
+		// install .so files for appropriate modules.
+		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
 		libs, ok := installVndkSnapshotLib(m, l, vndkType)
 		if !ok {
 			return
 		}
-
 		snapshotOutputs = append(snapshotOutputs, libs...)
 
-		// We glob headers from include directories inside source tree. So we first gather
-		// all include directories inside our source tree. On the contrast, we manually
-		// collect generated headers from dependencies as they can't globbed.
-		generatedHeaders = append(generatedHeaders, l.exportedGeneratedHeaders()...)
-		for _, dir := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
-			exportedIncludes[dir.String()] = true
+		// These are for generating module_names.txt and module_paths.txt
+		stem := m.outputFile.Path().Base()
+		moduleNames[stem] = ctx.ModuleName(m)
+		modulePaths[stem] = ctx.ModuleDir(m)
+
+		if len(m.NoticeFiles()) > 0 {
+			noticeName := stem + ".txt"
+			// skip already copied notice file
+			if _, ok := noticeBuilt[noticeName]; !ok {
+				noticeBuilt[noticeName] = true
+				snapshotOutputs = append(snapshotOutputs, combineNotices(
+					ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
+			}
+		}
+
+		if ctx.Config().VndkSnapshotBuildArtifacts() {
+			headers = append(headers, exportedHeaders(ctx, l)...)
 		}
 	})
 
-	if ctx.Config().VndkSnapshotBuildArtifacts() {
-		globbedHeaders := make(map[string]bool)
-
-		for _, dir := range android.SortedStringKeys(exportedIncludes) {
-			// Skip if dir is for generated headers
-			if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
-				continue
-			}
-			exts := headerExts
-			// Glob all files under this special directory, because of C++ headers.
-			if strings.HasPrefix(dir, "external/libcxx/include") {
-				exts = []string{""}
-			}
-			for _, ext := range exts {
-				glob, err := ctx.GlobWithDeps(dir+"/**/*"+ext, nil)
-				if err != nil {
-					ctx.Errorf("%#v\n", err)
-					return
-				}
-				for _, header := range glob {
-					if strings.HasSuffix(header, "/") {
-						continue
-					}
-					globbedHeaders[header] = true
-				}
-			}
-		}
-
-		for _, header := range android.SortedStringKeys(globbedHeaders) {
-			snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(
-				android.PathForSource(ctx, header), filepath.Join(includeDir, header)))
-		}
-
-		isHeader := func(path string) bool {
-			for _, ext := range headerExts {
-				if strings.HasSuffix(path, ext) {
-					return true
-				}
-			}
-			return false
-		}
-
-		// For generated headers, manually install one by one, rather than glob
-		for _, path := range android.PathsToDirectorySortedPaths(android.FirstUniquePaths(generatedHeaders)) {
-			header := path.String()
-
-			if !isHeader(header) {
-				continue
-			}
-
-			snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(
-				path, filepath.Join(includeDir, header)))
-		}
+	// install all headers after removing duplicates
+	for _, header := range android.FirstUniquePaths(headers) {
+		snapshotOutputs = append(snapshotOutputs, copyFile(
+			ctx, header, filepath.Join(includeDir, header.String())))
 	}
 
 	// install *.libraries.txt except vndkcorevariant.libraries.txt
@@ -776,7 +671,8 @@
 		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
 			return
 		}
-		snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(m.OutputFile(), filepath.Join(configsDir, m.Name())))
+		snapshotOutputs = append(snapshotOutputs, copyFile(
+			ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
 	})
 
 	/*
@@ -796,7 +692,7 @@
 			txtBuilder.WriteString(" ")
 			txtBuilder.WriteString(m[k])
 		}
-		return installSnapshotFileFromContent(txtBuilder.String(), path)
+		return writeStringToFile(ctx, txtBuilder.String(), path)
 	}
 
 	/*
@@ -827,14 +723,13 @@
 	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
 	zipRule := android.NewRuleBuilder()
 
-	// If output files are too many, soong_zip command can exceed ARG_MAX.
-	// So first dump file lists into a single list file, and then feed it to Soong
+	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with xargs
 	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
 	zipRule.Command().
-		Text("( xargs").
-		FlagWithRspFileInputList("-n1 echo < ", snapshotOutputs).
-		FlagWithOutput("| tr -d \\' > ", snapshotOutputList).
-		Text(")")
+		Text("tr").
+		FlagWithArg("-d ", "\\'").
+		FlagWithRspFileInputList("< ", snapshotOutputs).
+		FlagWithOutput("> ", snapshotOutputList)
 
 	zipRule.Temporary(snapshotOutputList)
 
@@ -845,6 +740,7 @@
 		FlagWithInput("-l ", snapshotOutputList)
 
 	zipRule.Build(pctx, ctx, zipPath.String(), "vndk snapshot "+zipPath.String())
+	zipRule.DeleteTemporaryFiles()
 	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
 }
 
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index c941c46..53b5181 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -31,7 +31,8 @@
 //
 // vndk_prebuilt_shared {
 //     name: "libfoo",
-//     version: "27.1.0",
+//     version: "27",
+//     target_arch: "arm64",
 //     vendor_available: true,
 //     vndk: {
 //         enabled: true,
@@ -61,10 +62,6 @@
 	// Prebuilt files for each arch.
 	Srcs []string `android:"arch_variant"`
 
-	// list of directories relative to the Blueprints file that will be added to the include
-	// path (using -isystem) for any module that links against this module.
-	Export_system_include_dirs []string `android:"arch_variant"`
-
 	// list of flags that will be used for any module that links against this module.
 	Export_flags []string `android:"arch_variant"`
 
@@ -75,7 +72,8 @@
 
 type vndkPrebuiltLibraryDecorator struct {
 	*libraryDecorator
-	properties vndkPrebuiltProperties
+	properties      vndkPrebuiltProperties
+	androidMkSuffix string
 }
 
 func (p *vndkPrebuiltLibraryDecorator) Name(name string) string {
@@ -137,11 +135,33 @@
 
 	if len(p.properties.Srcs) > 0 && p.shared() {
 		p.libraryDecorator.exportIncludes(ctx)
-		p.libraryDecorator.reexportSystemDirs(
-			android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
 		p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
 		// current VNDK prebuilts are only shared libs.
-		return p.singleSourcePath(ctx)
+
+		in := p.singleSourcePath(ctx)
+		builderFlags := flagsToBuilderFlags(flags)
+		p.unstrippedOutputFile = in
+		libName := in.Base()
+		if p.needsStrip(ctx) {
+			stripped := android.PathForModuleOut(ctx, "stripped", libName)
+			p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+			in = stripped
+		}
+
+		// Optimize out relinking against shared libraries whose interface hasn't changed by
+		// depending on a table of contents file instead of the library itself.
+		tocFile := android.PathForModuleOut(ctx, libName+".toc")
+		p.tocFile = android.OptionalPathForPath(tocFile)
+		TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+
+		p.androidMkSuffix = p.NameSuffix()
+
+		vndkVersion := ctx.DeviceConfig().VndkVersion()
+		if vndkVersion == p.version() {
+			p.androidMkSuffix = ""
+		}
+
+		return in
 	}
 
 	ctx.Module().SkipInstall()
@@ -220,7 +240,8 @@
 //
 //    vndk_prebuilt_shared {
 //        name: "libfoo",
-//        version: "27.1.0",
+//        version: "27",
+//        target_arch: "arm64",
 //        vendor_available: true,
 //        vndk: {
 //            enabled: true,
diff --git a/cc/xom.go b/cc/xom.go
deleted file mode 100644
index ce817aa..0000000
--- a/cc/xom.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cc
-
-import (
-	"android/soong/android"
-)
-
-type XomProperties struct {
-	Xom *bool
-}
-
-type xom struct {
-	Properties XomProperties
-}
-
-func (xom *xom) props() []interface{} {
-	return []interface{}{&xom.Properties}
-}
-
-func (xom *xom) begin(ctx BaseModuleContext) {}
-
-func (xom *xom) deps(ctx BaseModuleContext, deps Deps) Deps {
-	return deps
-}
-
-func (xom *xom) flags(ctx ModuleContext, flags Flags) Flags {
-	disableXom := false
-
-	if !ctx.Config().EnableXOM() || ctx.Config().XOMDisabledForPath(ctx.ModuleDir()) {
-		disableXom = true
-	}
-
-	if xom.Properties.Xom != nil && !*xom.Properties.Xom {
-		return flags
-	}
-
-	// If any static dependencies have XOM disabled, we should disable XOM in this module,
-	// the assumption being if it's been explicitly disabled then there's probably incompatible
-	// code in the library which may get pulled in.
-	if !disableXom {
-		ctx.VisitDirectDeps(func(m android.Module) {
-			cc, ok := m.(*Module)
-			if !ok || cc.xom == nil || !cc.static() {
-				return
-			}
-			if cc.xom.Properties.Xom != nil && !*cc.xom.Properties.Xom {
-				disableXom = true
-				return
-			}
-		})
-	}
-
-	// Enable execute-only if none of the dependencies disable it,
-	// also if it's explicitly set true (allows overriding dependencies disabling it).
-	if !disableXom || (xom.Properties.Xom != nil && *xom.Properties.Xom) {
-		// XOM is only supported on AArch64 when using lld.
-		if ctx.Arch().ArchType == android.Arm64 && ctx.useClangLld(ctx) {
-			flags.Local.LdFlags = append(flags.Local.LdFlags,
-				"-Wl,--execute-only",
-				"-Wl,-z,separate-code",
-			)
-		}
-	}
-
-	return flags
-}
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 7057b33..65a34fd 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -36,6 +36,7 @@
 	outputRoot    string
 	keepOutDir    bool
 	depfileOut    string
+	inputHash     string
 )
 
 func init() {
@@ -51,6 +52,8 @@
 	flag.StringVar(&depfileOut, "depfile-out", "",
 		"file path of the depfile to generate. This value will replace '__SBOX_DEPFILE__' in the command and will be treated as an output but won't be added to __SBOX_OUT_FILES__")
 
+	flag.StringVar(&inputHash, "input-hash", "",
+		"This option is ignored. Typical usage is to supply a hash of the list of input names so that the module will be rebuilt if the list (and thus the hash) changes.")
 }
 
 func usageViolation(violation string) {
@@ -59,7 +62,7 @@
 	}
 
 	fmt.Fprintf(os.Stderr,
-		"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
+		"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] [--input-hash hash] <outputFile> [<outputFile>...]\n"+
 			"\n"+
 			"Deletes <outputRoot>,"+
 			"runs <commandToRun>,"+
diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp
index c5f24e2..b8f7ea6 100644
--- a/dexpreopt/Android.bp
+++ b/dexpreopt/Android.bp
@@ -4,6 +4,7 @@
     srcs: [
         "config.go",
         "dexpreopt.go",
+        "testing.go",
     ],
     testSrcs: [
         "dexpreopt_test.go",
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 2a929c5..98850e5 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -16,22 +16,23 @@
 
 import (
 	"encoding/json"
+	"fmt"
 	"strings"
 
+	"github.com/google/blueprint"
+
 	"android/soong/android"
 )
 
 // GlobalConfig stores the configuration for dex preopting. The fields are set
-// from product variables via dex_preopt_config.mk, except for SoongConfig
-// which come from CreateGlobalSoongConfig.
+// from product variables via dex_preopt_config.mk.
 type GlobalConfig struct {
 	DisablePreopt        bool     // disable preopt for all modules
 	DisablePreoptModules []string // modules with preopt disabled by product-specific config
 
 	OnlyPreoptBootImageAndSystemServer bool // only preopt jars in the boot image or system server
 
-	GenerateApexImage bool // generate an extra boot image only containing jars from the runtime apex
-	UseApexImage      bool // use the apex image by default
+	UseArtImage bool // use the art image (use other boot class path dex files without image)
 
 	HasSystemOther        bool     // store odex files that match PatternsOnSystemOther on the system_other partition
 	PatternsOnSystemOther []string // patterns (using '%' to denote a prefix match) to put odex on the system_other partition
@@ -82,8 +83,6 @@
 	BootFlags         string               // extra flags to pass to dex2oat for the boot image
 	Dex2oatImageXmx   string               // max heap size for dex2oat for the boot image
 	Dex2oatImageXms   string               // initial heap size for dex2oat for the boot image
-
-	SoongConfig GlobalSoongConfig // settings read from dexpreopt_soong.config
 }
 
 // GlobalSoongConfig contains the global config that is generated from Soong,
@@ -179,14 +178,11 @@
 	return constructPath(ctx, path).(android.WritablePath)
 }
 
-// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig
-// struct, except the SoongConfig field which is set from the provided
-// soongConfig argument. LoadGlobalConfig is used directly in Soong and in
-// dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by
-// Make.
-func LoadGlobalConfig(ctx android.PathContext, data []byte, soongConfig GlobalSoongConfig) (GlobalConfig, error) {
+// ParseGlobalConfig parses the given data assumed to be read from the global
+// dexpreopt.config file into a GlobalConfig struct.
+func ParseGlobalConfig(ctx android.PathContext, data []byte) (*GlobalConfig, error) {
 	type GlobalJSONConfig struct {
-		GlobalConfig
+		*GlobalConfig
 
 		// Copies of entries in GlobalConfig that are not constructable without extra parameters.  They will be
 		// used to construct the real value manually below.
@@ -204,19 +200,70 @@
 	config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects))
 	config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles)
 
-	// Set this here to force the caller to provide a value for this struct (from
-	// either CreateGlobalSoongConfig or LoadGlobalSoongConfig).
-	config.GlobalConfig.SoongConfig = soongConfig
-
 	return config.GlobalConfig, nil
 }
 
-// LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct.  It is not used in Soong, which
-// receives a ModuleConfig struct directly from java/dexpreopt.go.  It is used in dexpreopt_gen called from oMake to
-// read the module dexpreopt.config written by Make.
-func LoadModuleConfig(ctx android.PathContext, data []byte) (ModuleConfig, error) {
+type globalConfigAndRaw struct {
+	global *GlobalConfig
+	data   []byte
+}
+
+// GetGlobalConfig returns the global dexpreopt.config that's created in the
+// make config phase. It is loaded once the first time it is called for any
+// ctx.Config(), and returns the same data for all future calls with the same
+// ctx.Config(). A value can be inserted for tests using
+// setDexpreoptTestGlobalConfig.
+func GetGlobalConfig(ctx android.PathContext) *GlobalConfig {
+	return getGlobalConfigRaw(ctx).global
+}
+
+// GetGlobalConfigRawData is the same as GetGlobalConfig, except that it returns
+// the literal content of dexpreopt.config.
+func GetGlobalConfigRawData(ctx android.PathContext) []byte {
+	return getGlobalConfigRaw(ctx).data
+}
+
+var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig")
+var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
+
+func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
+	return ctx.Config().Once(globalConfigOnceKey, func() interface{} {
+		if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
+			panic(err)
+		} else if data != nil {
+			globalConfig, err := ParseGlobalConfig(ctx, data)
+			if err != nil {
+				panic(err)
+			}
+			return globalConfigAndRaw{globalConfig, data}
+		}
+
+		// No global config filename set, see if there is a test config set
+		return ctx.Config().Once(testGlobalConfigOnceKey, func() interface{} {
+			// Nope, return a config with preopting disabled
+			return globalConfigAndRaw{&GlobalConfig{
+				DisablePreopt:          true,
+				DisableGenerateProfile: true,
+			}, nil}
+		})
+	}).(globalConfigAndRaw)
+}
+
+// SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig
+// will return. It must be called before the first call to GetGlobalConfig for
+// the config.
+func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) {
+	config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
+}
+
+// ParseModuleConfig parses a per-module dexpreopt.config file into a
+// ModuleConfig struct. It is not used in Soong, which receives a ModuleConfig
+// struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called
+// from Make to read the module dexpreopt.config written in the Make config
+// stage.
+func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) {
 	type ModuleJSONConfig struct {
-		ModuleConfig
+		*ModuleConfig
 
 		// Copies of entries in ModuleConfig that are not constructable without extra parameters.  They will be
 		// used to construct the real value manually below.
@@ -253,21 +300,63 @@
 	return config.ModuleConfig, nil
 }
 
-// CreateGlobalSoongConfig creates a GlobalSoongConfig from the current context.
-// Should not be used in dexpreopt_gen.
-func CreateGlobalSoongConfig(ctx android.PathContext) GlobalSoongConfig {
-	// Default to debug version to help find bugs.
+// dex2oatModuleName returns the name of the module to use for the dex2oat host
+// tool. It should be a binary module with public visibility that is compiled
+// and installed for host.
+func dex2oatModuleName(config android.Config) string {
+	// Default to the debug variant of dex2oat to help find bugs.
 	// Set USE_DEX2OAT_DEBUG to false for only building non-debug versions.
-	var dex2oatBinary string
-	if ctx.Config().Getenv("USE_DEX2OAT_DEBUG") == "false" {
-		dex2oatBinary = "dex2oat"
+	if config.Getenv("USE_DEX2OAT_DEBUG") == "false" {
+		return "dex2oat"
 	} else {
-		dex2oatBinary = "dex2oatd"
+		return "dex2oatd"
+	}
+}
+
+var dex2oatDepTag = struct {
+	blueprint.BaseDependencyTag
+}{}
+
+// RegisterToolDeps adds the necessary dependencies to binary modules for tools
+// that are required later when Get(Cached)GlobalSoongConfig is called. It
+// should be called from a mutator that's registered with
+// android.RegistrationContext.FinalDepsMutators.
+func RegisterToolDeps(ctx android.BottomUpMutatorContext) {
+	dex2oatBin := dex2oatModuleName(ctx.Config())
+	v := ctx.Config().BuildOSTarget.Variations()
+	ctx.AddFarVariationDependencies(v, dex2oatDepTag, dex2oatBin)
+}
+
+func dex2oatPathFromDep(ctx android.ModuleContext) android.Path {
+	dex2oatBin := dex2oatModuleName(ctx.Config())
+
+	dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag)
+	if dex2oatModule == nil {
+		// If this happens there's probably a missing call to AddToolDeps in DepsMutator.
+		panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin))
 	}
 
-	return GlobalSoongConfig{
+	dex2oatPath := dex2oatModule.(android.HostToolProvider).HostToolPath()
+	if !dex2oatPath.Valid() {
+		panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule))
+	}
+
+	return dex2oatPath.Path()
+}
+
+// createGlobalSoongConfig creates a GlobalSoongConfig from the current context.
+// Should not be used in dexpreopt_gen.
+func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig {
+	if ctx.Config().TestProductVariables != nil {
+		// If we're called in a test there'll be a confusing error from the path
+		// functions below that gets reported without a stack trace, so let's panic
+		// properly with a more helpful message.
+		panic("This should not be called from tests. Please call GlobalSoongConfigForTests somewhere in the test setup.")
+	}
+
+	return &GlobalSoongConfig{
 		Profman:          ctx.Config().HostToolPath(ctx, "profman"),
-		Dex2oat:          ctx.Config().HostToolPath(ctx, dex2oatBinary),
+		Dex2oat:          dex2oatPathFromDep(ctx),
 		Aapt:             ctx.Config().HostToolPath(ctx, "aapt"),
 		SoongZip:         ctx.Config().HostToolPath(ctx, "soong_zip"),
 		Zip2zip:          ctx.Config().HostToolPath(ctx, "zip2zip"),
@@ -276,6 +365,47 @@
 	}
 }
 
+// The main reason for this Once cache for GlobalSoongConfig is to make the
+// dex2oat path available to singletons. In ordinary modules we get it through a
+// dex2oatDepTag dependency, but in singletons there's no simple way to do the
+// same thing and ensure the right variant is selected, hence this cache to make
+// the resolved path available to singletons. This means we depend on there
+// being at least one ordinary module with a dex2oatDepTag dependency.
+//
+// TODO(b/147613152): Implement a way to deal with dependencies from singletons,
+// and then possibly remove this cache altogether (but the use in
+// GlobalSoongConfigForTests also needs to be rethought).
+var globalSoongConfigOnceKey = android.NewOnceKey("DexpreoptGlobalSoongConfig")
+
+// GetGlobalSoongConfig creates a GlobalSoongConfig the first time it's called,
+// and later returns the same cached instance.
+func GetGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig {
+	globalSoong := ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} {
+		return createGlobalSoongConfig(ctx)
+	}).(*GlobalSoongConfig)
+
+	// Always resolve the tool path from the dependency, to ensure that every
+	// module has the dependency added properly.
+	myDex2oat := dex2oatPathFromDep(ctx)
+	if myDex2oat != globalSoong.Dex2oat {
+		panic(fmt.Sprintf("Inconsistent dex2oat path in cached config: expected %s, got %s", globalSoong.Dex2oat, myDex2oat))
+	}
+
+	return globalSoong
+}
+
+// GetCachedGlobalSoongConfig returns a cached GlobalSoongConfig created by an
+// earlier GetGlobalSoongConfig call. This function works with any context
+// compatible with a basic PathContext, since it doesn't try to create a
+// GlobalSoongConfig with the proper paths (which requires a full
+// ModuleContext). If there has been no prior call to GetGlobalSoongConfig, nil
+// is returned.
+func GetCachedGlobalSoongConfig(ctx android.PathContext) *GlobalSoongConfig {
+	return ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} {
+		return (*GlobalSoongConfig)(nil)
+	}).(*GlobalSoongConfig)
+}
+
 type globalJsonSoongConfig struct {
 	Profman          string
 	Dex2oat          string
@@ -286,17 +416,18 @@
 	ConstructContext string
 }
 
-// LoadGlobalSoongConfig reads the dexpreopt_soong.config file into a
-// GlobalSoongConfig struct. It is only used in dexpreopt_gen.
-func LoadGlobalSoongConfig(ctx android.PathContext, data []byte) (GlobalSoongConfig, error) {
+// ParseGlobalSoongConfig parses the given data assumed to be read from the
+// global dexpreopt_soong.config file into a GlobalSoongConfig struct. It is
+// only used in dexpreopt_gen.
+func ParseGlobalSoongConfig(ctx android.PathContext, data []byte) (*GlobalSoongConfig, error) {
 	var jc globalJsonSoongConfig
 
 	err := json.Unmarshal(data, &jc)
 	if err != nil {
-		return GlobalSoongConfig{}, err
+		return &GlobalSoongConfig{}, err
 	}
 
-	config := GlobalSoongConfig{
+	config := &GlobalSoongConfig{
 		Profman:          constructPath(ctx, jc.Profman),
 		Dex2oat:          constructPath(ctx, jc.Dex2oat),
 		Aapt:             constructPath(ctx, jc.Aapt),
@@ -310,7 +441,17 @@
 }
 
 func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	config := CreateGlobalSoongConfig(ctx)
+	if GetGlobalConfig(ctx).DisablePreopt {
+		return
+	}
+
+	config := GetCachedGlobalSoongConfig(ctx)
+	if config == nil {
+		// No module has enabled dexpreopting, so we assume there will be no calls
+		// to dexpreopt_gen.
+		return
+	}
+
 	jc := globalJsonSoongConfig{
 		Profman:          config.Profman.String(),
 		Dex2oat:          config.Dex2oat.String(),
@@ -337,7 +478,14 @@
 }
 
 func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) {
-	config := CreateGlobalSoongConfig(ctx)
+	if GetGlobalConfig(ctx).DisablePreopt {
+		return
+	}
+
+	config := GetCachedGlobalSoongConfig(ctx)
+	if config == nil {
+		return
+	}
 
 	ctx.Strict("DEX2OAT", config.Dex2oat.String())
 	ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{
@@ -351,8 +499,8 @@
 	}, " "))
 }
 
-func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
-	return GlobalConfig{
+func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig {
+	return &GlobalConfig{
 		DisablePreopt:                      false,
 		DisablePreoptModules:               nil,
 		OnlyPreoptBootImageAndSystemServer: false,
@@ -390,7 +538,14 @@
 		BootFlags:                          "",
 		Dex2oatImageXmx:                    "",
 		Dex2oatImageXms:                    "",
-		SoongConfig: GlobalSoongConfig{
+	}
+}
+
+func GlobalSoongConfigForTests(config android.Config) *GlobalSoongConfig {
+	// Install the test GlobalSoongConfig in the Once cache so that later calls to
+	// Get(Cached)GlobalSoongConfig returns it without trying to create a real one.
+	return config.Once(globalSoongConfigOnceKey, func() interface{} {
+		return &GlobalSoongConfig{
 			Profman:          android.PathForTesting("profman"),
 			Dex2oat:          android.PathForTesting("dex2oat"),
 			Aapt:             android.PathForTesting("aapt"),
@@ -398,6 +553,6 @@
 			Zip2zip:          android.PathForTesting("zip2zip"),
 			ManifestCheck:    android.PathForTesting("manifest_check"),
 			ConstructContext: android.PathForTesting("construct_context.sh"),
-		},
-	}
+		}
+	}).(*GlobalSoongConfig)
 }
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index ac5b691..6cb9873 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -41,16 +41,25 @@
 
 	"android/soong/android"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 )
 
 const SystemPartition = "/system/"
 const SystemOtherPartition = "/system_other/"
 
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+var SystemServerDepTag = dependencyTag{name: "system-server-dep"}
+var SystemServerForcedDepTag = dependencyTag{name: "system-server-forced-dep"}
+
 // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
 // ModuleConfig.  The produced files and their install locations will be available through rule.Installs().
-func GenerateDexpreoptRule(ctx android.PathContext,
-	global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) {
+func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConfig,
+	global *GlobalConfig, module *ModuleConfig) (rule *android.RuleBuilder, err error) {
 
 	defer func() {
 		if r := recover(); r != nil {
@@ -72,13 +81,13 @@
 
 	var profile android.WritablePath
 	if generateProfile {
-		profile = profileCommand(ctx, global, module, rule)
+		profile = profileCommand(ctx, globalSoong, global, module, rule)
 	}
 	if generateBootProfile {
-		bootProfileCommand(ctx, global, module, rule)
+		bootProfileCommand(ctx, globalSoong, global, module, rule)
 	}
 
-	if !dexpreoptDisabled(global, module) {
+	if !dexpreoptDisabled(ctx, global, module) {
 		// Don't preopt individual boot jars, they will be preopted together.
 		if !contains(global.BootJars, module.Name) {
 			appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
@@ -87,7 +96,7 @@
 			generateDM := shouldGenerateDM(module, global)
 
 			for archIdx, _ := range module.Archs {
-				dexpreoptCommand(ctx, global, module, rule, archIdx, profile, appImage, generateDM)
+				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
 			}
 		}
 	}
@@ -95,14 +104,21 @@
 	return rule, nil
 }
 
-func dexpreoptDisabled(global GlobalConfig, module ModuleConfig) bool {
+func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) bool {
 	if contains(global.DisablePreoptModules, module.Name) {
 		return true
 	}
 
 	// Don't preopt system server jars that are updatable.
 	for _, p := range global.UpdatableSystemServerJars {
-		if _, jar := SplitApexJarPair(p); jar == module.Name {
+		if _, jar := android.SplitApexJarPair(p); jar == module.Name {
+			return true
+		}
+	}
+
+	// Don't preopt system server jars that are not Soong modules.
+	if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
+		if _, ok := ctx.(android.ModuleContext); !ok {
 			return true
 		}
 	}
@@ -119,8 +135,8 @@
 	return false
 }
 
-func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig,
-	rule *android.RuleBuilder) android.WritablePath {
+func profileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
+	module *ModuleConfig, rule *android.RuleBuilder) android.WritablePath {
 
 	profilePath := module.BuildPath.InSameDir(ctx, "profile.prof")
 	profileInstalledPath := module.DexLocation + ".prof"
@@ -131,7 +147,7 @@
 
 	cmd := rule.Command().
 		Text(`ANDROID_LOG_TAGS="*:e"`).
-		Tool(global.SoongConfig.Profman)
+		Tool(globalSoong.Profman)
 
 	if module.ProfileIsTextListing {
 		// The profile is a test listing of classes (used for framework jars).
@@ -158,8 +174,8 @@
 	return profilePath
 }
 
-func bootProfileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig,
-	rule *android.RuleBuilder) android.WritablePath {
+func bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
+	module *ModuleConfig, rule *android.RuleBuilder) android.WritablePath {
 
 	profilePath := module.BuildPath.InSameDir(ctx, "profile.bprof")
 	profileInstalledPath := module.DexLocation + ".bprof"
@@ -170,7 +186,7 @@
 
 	cmd := rule.Command().
 		Text(`ANDROID_LOG_TAGS="*:e"`).
-		Tool(global.SoongConfig.Profman)
+		Tool(globalSoong.Profman)
 
 	// The profile is a test listing of methods.
 	// We need to generate the actual binary profile.
@@ -190,8 +206,9 @@
 	return profilePath
 }
 
-func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
-	archIdx int, profile android.WritablePath, appImage bool, generateDM bool) {
+func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
+	module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
+	appImage bool, generateDM bool) {
 
 	arch := module.Archs[archIdx]
 
@@ -236,7 +253,8 @@
 	var conditionalClassLoaderContextHost29 android.Paths
 	var conditionalClassLoaderContextTarget29 []string
 
-	var classLoaderContextHostString string
+	var classLoaderContextHostString, classLoaderContextDeviceString string
+	var classLoaderDeps android.Paths
 
 	if module.EnforceUsesLibraries {
 		usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
@@ -282,6 +300,30 @@
 			filepath.Join("/system/framework", hidlBase+".jar"))
 
 		classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":")
+	} else if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
+		// We expect that all dexpreopted system server jars are Soong modules.
+		mctx, isModule := ctx.(android.ModuleContext)
+		if !isModule {
+			panic("Cannot dexpreopt system server jar that is not a soong module.")
+		}
+
+		// System server jars should be dexpreopted together: class loader context of each jar
+		// should include preceding jars (which can be found as dependencies of the current jar
+		// with a special tag).
+		var jarsOnHost android.Paths
+		var jarsOnDevice []string
+		mctx.VisitDirectDepsWithTag(SystemServerDepTag, func(dep android.Module) {
+			depName := mctx.OtherModuleName(dep)
+			if jar, ok := dep.(interface{ DexJar() android.Path }); ok {
+				jarsOnHost = append(jarsOnHost, jar.DexJar())
+				jarsOnDevice = append(jarsOnDevice, "/system/framework/"+depName+".jar")
+			} else {
+				mctx.ModuleErrorf("module \"%s\" is not a jar", depName)
+			}
+		})
+		classLoaderContextHostString = strings.Join(jarsOnHost.Strings(), ":")
+		classLoaderContextDeviceString = strings.Join(jarsOnDevice, ":")
+		classLoaderDeps = jarsOnHost
 	} else {
 		// Pass special class loader context to skip the classpath and collision check.
 		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
@@ -293,20 +335,25 @@
 	rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
 	rule.Command().FlagWithOutput("rm -f ", odexPath)
 	// Set values in the environment of the rule.  These may be modified by construct_context.sh.
-	rule.Command().FlagWithArg("class_loader_context_arg=--class-loader-context=", classLoaderContextHostString)
-	rule.Command().Text(`stored_class_loader_context_arg=""`)
+	if classLoaderContextHostString == `\&` {
+		rule.Command().Text(`class_loader_context_arg=--class-loader-context=\&`)
+		rule.Command().Text(`stored_class_loader_context_arg=""`)
+	} else {
+		rule.Command().Text("class_loader_context_arg=--class-loader-context=PCL[" + classLoaderContextHostString + "]")
+		rule.Command().Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + classLoaderContextDeviceString + "]")
+	}
 
 	if module.EnforceUsesLibraries {
 		if module.ManifestPath != nil {
 			rule.Command().Text(`target_sdk_version="$(`).
-				Tool(global.SoongConfig.ManifestCheck).
+				Tool(globalSoong.ManifestCheck).
 				Flag("--extract-target-sdk-version").
 				Input(module.ManifestPath).
 				Text(`)"`)
 		} else {
 			// No manifest to extract targetSdkVersion from, hope that DexJar is an APK
 			rule.Command().Text(`target_sdk_version="$(`).
-				Tool(global.SoongConfig.Aapt).
+				Tool(globalSoong.Aapt).
 				Flag("dump badging").
 				Input(module.DexPath).
 				Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
@@ -327,7 +374,7 @@
 			Implicits(conditionalClassLoaderContextHost29)
 		rule.Command().Textf(`conditional_target_libs_29="%s"`,
 			strings.Join(conditionalClassLoaderContextTarget29, " "))
-		rule.Command().Text("source").Tool(global.SoongConfig.ConstructContext).Input(module.DexPath)
+		rule.Command().Text("source").Tool(globalSoong.ConstructContext).Input(module.DexPath)
 	}
 
 	// Devices that do not have a product partition use a symlink from /product to /system/product.
@@ -340,7 +387,7 @@
 
 	cmd := rule.Command().
 		Text(`ANDROID_LOG_TAGS="*:e"`).
-		Tool(global.SoongConfig.Dex2oat).
+		Tool(globalSoong.Dex2oat).
 		Flag("--avoid-storing-invocation").
 		FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
 		Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatXms).
@@ -348,7 +395,7 @@
 		Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":").
 		Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
 		Flag("${class_loader_context_arg}").
-		Flag("${stored_class_loader_context_arg}").
+		Flag("${stored_class_loader_context_arg}").Implicits(classLoaderDeps).
 		FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
 		FlagWithInput("--dex-file=", module.DexPath).
 		FlagWithArg("--dex-location=", dexLocationArg).
@@ -379,7 +426,7 @@
 		cmd.FlagWithArg("--copy-dex-files=", "false")
 	}
 
-	if !anyHavePrefix(preoptFlags, "--compiler-filter=") {
+	if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
 		var compilerFilter string
 		if contains(global.SystemServerJars, module.Name) {
 			// Jars of system server, use the product option if it is set, speed otherwise.
@@ -409,7 +456,7 @@
 		dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm")
 		tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex")
 		rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath)
-		rule.Command().Tool(global.SoongConfig.SoongZip).
+		rule.Command().Tool(globalSoong.SoongZip).
 			FlagWithArg("-L", "9").
 			FlagWithOutput("-o", dmPath).
 			Flag("-j").
@@ -474,14 +521,14 @@
 	rule.Install(vdexPath, vdexInstallPath)
 }
 
-func shouldGenerateDM(module ModuleConfig, global GlobalConfig) bool {
+func shouldGenerateDM(module *ModuleConfig, global *GlobalConfig) bool {
 	// Generating DM files only makes sense for verify, avoid doing for non verify compiler filter APKs.
 	// No reason to use a dm file if the dex is already uncompressed.
 	return global.GenerateDMFiles && !module.UncompressedDex &&
 		contains(module.PreoptFlags, "--compiler-filter=verify")
 }
 
-func OdexOnSystemOtherByName(name string, dexLocation string, global GlobalConfig) bool {
+func OdexOnSystemOtherByName(name string, dexLocation string, global *GlobalConfig) bool {
 	if !global.HasSystemOther {
 		return false
 	}
@@ -503,7 +550,7 @@
 	return false
 }
 
-func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool {
+func odexOnSystemOther(module *ModuleConfig, global *GlobalConfig) bool {
 	return OdexOnSystemOtherByName(module.Name, module.DexLocation, global)
 }
 
@@ -516,7 +563,7 @@
 	return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String()))
 }
 
-func pathForLibrary(module ModuleConfig, lib string) android.Path {
+func pathForLibrary(module *ModuleConfig, lib string) android.Path {
 	path, ok := module.LibraryPaths[lib]
 	if !ok {
 		panic(fmt.Errorf("unknown library path for %q", lib))
@@ -537,19 +584,29 @@
 }
 
 // Expected format for apexJarValue = <apex name>:<jar name>
-func SplitApexJarPair(apexJarValue string) (string, string) {
-	var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
-	if apexJarPair == nil || len(apexJarPair) != 2 {
-		panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
-			apexJarValue))
-	}
-	return apexJarPair[0], apexJarPair[1]
+func GetJarLocationFromApexJarPair(apexJarValue string) string {
+	apex, jar := android.SplitApexJarPair(apexJarValue)
+	return filepath.Join("/apex", apex, "javalib", jar+".jar")
 }
 
-// Expected format for apexJarValue = <apex name>:<jar name>
-func GetJarLocationFromApexJarPair(apexJarValue string) string {
-	apex, jar := SplitApexJarPair(apexJarValue)
-	return filepath.Join("/apex", apex, "javalib", jar+".jar")
+func GetJarsFromApexJarPairs(apexJarPairs []string) []string {
+	modules := make([]string, len(apexJarPairs))
+	for i, p := range apexJarPairs {
+		_, jar := android.SplitApexJarPair(p)
+		modules[i] = jar
+	}
+	return modules
+}
+
+var nonUpdatableSystemServerJarsKey = android.NewOnceKey("nonUpdatableSystemServerJars")
+
+// TODO: eliminate the superficial global config parameter by moving global config definition
+// from java subpackage to dexpreopt.
+func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
+	return ctx.Config().Once(nonUpdatableSystemServerJarsKey, func() interface{} {
+		return android.RemoveListFromList(global.SystemServerJars,
+			GetJarsFromApexJarPairs(global.UpdatableSystemServerJars))
+	}).([]string)
 }
 
 func contains(l []string, s string) bool {
@@ -561,32 +618,4 @@
 	return false
 }
 
-// remove all elements in a from b, returning a new slice
-func filterOut(a []string, b []string) []string {
-	var ret []string
-	for _, x := range b {
-		if !contains(a, x) {
-			ret = append(ret, x)
-		}
-	}
-	return ret
-}
-
-func replace(l []string, from, to string) {
-	for i := range l {
-		if l[i] == from {
-			l[i] = to
-		}
-	}
-}
-
 var copyOf = android.CopyOf
-
-func anyHavePrefix(l []string, prefix string) bool {
-	for _, x := range l {
-		if strings.HasPrefix(x, prefix) {
-			return true
-		}
-	}
-	return false
-}
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index e2818bb..e89f045 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -80,13 +80,13 @@
 
 	globalSoongConfigData, err := ioutil.ReadFile(*globalSoongConfigPath)
 	if err != nil {
-		fmt.Fprintf(os.Stderr, "error reading global config %q: %s\n", *globalSoongConfigPath, err)
+		fmt.Fprintf(os.Stderr, "error reading global Soong config %q: %s\n", *globalSoongConfigPath, err)
 		os.Exit(2)
 	}
 
-	globalSoongConfig, err := dexpreopt.LoadGlobalSoongConfig(ctx, globalSoongConfigData)
+	globalSoongConfig, err := dexpreopt.ParseGlobalSoongConfig(ctx, globalSoongConfigData)
 	if err != nil {
-		fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalSoongConfigPath, err)
+		fmt.Fprintf(os.Stderr, "error parsing global Soong config %q: %s\n", *globalSoongConfigPath, err)
 		os.Exit(2)
 	}
 
@@ -96,9 +96,9 @@
 		os.Exit(2)
 	}
 
-	globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, globalConfigData, globalSoongConfig)
+	globalConfig, err := dexpreopt.ParseGlobalConfig(ctx, globalConfigData)
 	if err != nil {
-		fmt.Fprintf(os.Stderr, "error parse global config %q: %s\n", *globalConfigPath, err)
+		fmt.Fprintf(os.Stderr, "error parsing global config %q: %s\n", *globalConfigPath, err)
 		os.Exit(2)
 	}
 
@@ -108,9 +108,9 @@
 		os.Exit(2)
 	}
 
-	moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, moduleConfigData)
+	moduleConfig, err := dexpreopt.ParseModuleConfig(ctx, moduleConfigData)
 	if err != nil {
-		fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err)
+		fmt.Fprintf(os.Stderr, "error parsing module config %q: %s\n", *moduleConfigPath, err)
 		os.Exit(2)
 	}
 
@@ -130,12 +130,12 @@
 		}
 	}()
 
-	writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath)
+	writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
 }
 
-func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig,
-	dexpreoptScriptPath string) {
-	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, module)
+func writeScripts(ctx android.PathContext, globalSoong *dexpreopt.GlobalSoongConfig,
+	global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
+	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
 	if err != nil {
 		panic(err)
 	}
@@ -150,7 +150,7 @@
 		dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String()))
 		dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
 	}
-	dexpreoptRule.Command().Tool(global.SoongConfig.SoongZip).
+	dexpreoptRule.Command().Tool(globalSoong.SoongZip).
 		FlagWithArg("-o ", "$2").
 		FlagWithArg("-C ", installDir.String()).
 		FlagWithArg("-D ", installDir.String())
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index a128dc0..d239993 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -20,20 +20,20 @@
 	"testing"
 )
 
-func testSystemModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+func testSystemModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
 	return testModuleConfig(ctx, name, "system")
 }
 
-func testSystemProductModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+func testSystemProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
 	return testModuleConfig(ctx, name, "system/product")
 }
 
-func testProductModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+func testProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
 	return testModuleConfig(ctx, name, "product")
 }
 
-func testModuleConfig(ctx android.PathContext, name, partition string) ModuleConfig {
-	return ModuleConfig{
+func testModuleConfig(ctx android.PathContext, name, partition string) *ModuleConfig {
+	return &ModuleConfig{
 		Name:                            name,
 		DexLocation:                     fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
 		BuildPath:                       android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
@@ -61,10 +61,13 @@
 }
 
 func TestDexPreopt(t *testing.T) {
-	ctx := android.PathContextForTesting(android.TestConfig("out", nil, "", nil))
-	global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test")
+	config := android.TestConfig("out", nil, "", nil)
+	ctx := android.PathContextForTesting(config)
+	globalSoong := GlobalSoongConfigForTests(config)
+	global := GlobalConfigForTests(ctx)
+	module := testSystemModuleConfig(ctx, "test")
 
-	rule, err := GenerateDexpreoptRule(ctx, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -80,7 +83,9 @@
 }
 
 func TestDexPreoptSystemOther(t *testing.T) {
-	ctx := android.PathContextForTesting(android.TestConfig("out", nil, "", nil))
+	config := android.TestConfig("out", nil, "", nil)
+	ctx := android.PathContextForTesting(config)
+	globalSoong := GlobalSoongConfigForTests(config)
 	global := GlobalConfigForTests(ctx)
 	systemModule := testSystemModuleConfig(ctx, "Stest")
 	systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
@@ -89,7 +94,7 @@
 	global.HasSystemOther = true
 
 	type moduleTest struct {
-		module            ModuleConfig
+		module            *ModuleConfig
 		expectedPartition string
 	}
 	tests := []struct {
@@ -118,7 +123,7 @@
 	for _, test := range tests {
 		global.PatternsOnSystemOther = test.patterns
 		for _, mt := range test.moduleTests {
-			rule, err := GenerateDexpreoptRule(ctx, global, mt.module)
+			rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -138,12 +143,15 @@
 }
 
 func TestDexPreoptProfile(t *testing.T) {
-	ctx := android.PathContextForTesting(android.TestConfig("out", nil, "", nil))
-	global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test")
+	config := android.TestConfig("out", nil, "", nil)
+	ctx := android.PathContextForTesting(config)
+	globalSoong := GlobalSoongConfigForTests(config)
+	global := GlobalConfigForTests(ctx)
+	module := testSystemModuleConfig(ctx, "test")
 
 	module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
 
-	rule, err := GenerateDexpreoptRule(ctx, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
new file mode 100644
index 0000000..b572eb3
--- /dev/null
+++ b/dexpreopt/testing.go
@@ -0,0 +1,47 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dexpreopt
+
+import (
+	"android/soong/android"
+)
+
+type dummyToolBinary struct {
+	android.ModuleBase
+}
+
+func (m *dummyToolBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func (m *dummyToolBinary) HostToolPath() android.OptionalPath {
+	return android.OptionalPathForPath(android.PathForTesting("dex2oat"))
+}
+
+func dummyToolBinaryFactory() android.Module {
+	module := &dummyToolBinary{}
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	return module
+}
+
+func RegisterToolModulesForTest(ctx *android.TestContext) {
+	ctx.RegisterModuleType("dummy_tool_binary", dummyToolBinaryFactory)
+}
+
+func BpToolModulesForTest() string {
+	return `
+		dummy_tool_binary {
+			name: "dex2oatd",
+		}
+	`
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index a0008d3..fe877fe 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -26,6 +26,7 @@
 
 	"android/soong/android"
 	"android/soong/shared"
+	"crypto/sha256"
 	"path/filepath"
 )
 
@@ -309,6 +310,7 @@
 			addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
 		}
 
+		referencedIn := false
 		referencedDepfile := false
 
 		rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
@@ -333,6 +335,7 @@
 				}
 				return locationLabels[firstLabel][0], false, nil
 			case "in":
+				referencedIn = true
 				return "${in}", true, nil
 			case "out":
 				return "__SBOX_OUT_FILES__", false, nil
@@ -398,8 +401,16 @@
 		// Escape the command for the shell
 		rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
 		g.rawCommands = append(g.rawCommands, rawCommand)
-		sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
-			task.genDir, sandboxPath, task.genDir, rawCommand, depfilePlaceholder)
+
+		sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s",
+			task.genDir, sandboxPath, task.genDir)
+
+		if !referencedIn {
+			sandboxCommand = sandboxCommand + hashSrcFiles(srcFiles)
+		}
+
+		sandboxCommand = sandboxCommand + fmt.Sprintf(" -c %s %s $allouts",
+			rawCommand, depfilePlaceholder)
 
 		ruleParams := blueprint.RuleParams{
 			Command:     sandboxCommand,
@@ -463,6 +474,14 @@
 
 }
 
+func hashSrcFiles(srcFiles android.Paths) string {
+	h := sha256.New()
+	for _, src := range srcFiles {
+		h.Write([]byte(src.String()))
+	}
+	return fmt.Sprintf(" --input-hash %x", h.Sum(nil))
+}
+
 func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask, rule blueprint.Rule) {
 	desc := "generate"
 	if len(task.out) == 0 {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 7eb43ac..4b36600 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -502,6 +502,93 @@
 	}
 }
 
+func TestGenruleHashInputs(t *testing.T) {
+
+	// The basic idea here is to verify that the sbox command (which is
+	// in the Command field of the generate rule) contains a hash of the
+	// inputs, but only if $(in) is not referenced in the genrule cmd
+	// property.
+
+	// By including a hash of the inputs, we cause the rule to re-run if
+	// the list of inputs changes (because the sbox command changes).
+
+	// However, if the genrule cmd property already contains $(in), then
+	// the dependency is already expressed, so we don't need to include the
+	// hash in that case.
+
+	bp := `
+			genrule {
+				name: "hash0",
+				srcs: ["in1.txt", "in2.txt"],
+				out: ["out"],
+				cmd: "echo foo > $(out)",
+			}
+			genrule {
+				name: "hash1",
+				srcs: ["*.txt"],
+				out: ["out"],
+				cmd: "echo bar > $(out)",
+			}
+			genrule {
+				name: "hash2",
+				srcs: ["*.txt"],
+				out: ["out"],
+				cmd: "echo $(in) > $(out)",
+			}
+		`
+	testcases := []struct {
+		name         string
+		expectedHash string
+	}{
+		{
+			name: "hash0",
+			// sha256 value obtained from: echo -n 'in1.txtin2.txt' | sha256sum
+			expectedHash: "031097e11e0a8c822c960eb9742474f46336360a515744000d086d94335a9cb9",
+		},
+		{
+			name: "hash1",
+			// sha256 value obtained from: echo -n 'in1.txtin2.txtin3.txt' | sha256sum
+			expectedHash: "de5d22a4a7ab50d250cc59fcdf7a7e0775790d270bfca3a7a9e1f18a70dd996c",
+		},
+		{
+			name: "hash2",
+			// $(in) is present, option should not appear
+			expectedHash: "",
+		},
+	}
+
+	config := testConfig(bp, nil)
+	ctx := testContext(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if errs == nil {
+		_, errs = ctx.PrepareBuildActions(config)
+	}
+	if errs != nil {
+		t.Fatal(errs)
+	}
+
+	for _, test := range testcases {
+		t.Run(test.name, func(t *testing.T) {
+			gen := ctx.ModuleForTests(test.name, "")
+			command := gen.Rule("generator").RuleParams.Command
+
+			if len(test.expectedHash) > 0 {
+				// We add spaces before and after to make sure that
+				// this option doesn't abutt another sbox option.
+				expectedInputHashOption := " --input-hash " + test.expectedHash + " "
+
+				if !strings.Contains(command, expectedInputHashOption) {
+					t.Errorf("Expected command \"%s\" to contain \"%s\"", command, expectedInputHashOption)
+				}
+			} else {
+				if strings.Contains(command, "--input-hash") {
+					t.Errorf("Unexpected \"--input-hash\" found in command: \"%s\"", command)
+				}
+			}
+		})
+	}
+}
+
 func TestGenSrcs(t *testing.T) {
 	testcases := []struct {
 		name string
diff --git a/java/aar.go b/java/aar.go
index 24c5e7d..6e3b9e6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -101,6 +101,7 @@
 	usesNonSdkApis          bool
 	sdkLibraries            []string
 	hasNoCode               bool
+	LoggingParent           string
 
 	splitNames []string
 	splits     []split
@@ -134,15 +135,8 @@
 	manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
 	resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
 
-	hasVersionCode := false
-	hasVersionName := false
-	for _, f := range a.aaptProperties.Aaptflags {
-		if strings.HasPrefix(f, "--version-code") {
-			hasVersionCode = true
-		} else if strings.HasPrefix(f, "--version-name") {
-			hasVersionName = true
-		}
-	}
+	hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code")
+	hasVersionName := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-name")
 
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
@@ -241,7 +235,8 @@
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
-		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode)
+		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
+		a.LoggingParent)
 
 	// Add additional manifest files to transitive manifests.
 	additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
@@ -337,7 +332,7 @@
 
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
-	if android.PrefixedStringInList(linkFlags, "-A ") || len(assetPackages) > 0 {
+	if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 {
 		assets := android.PathForModuleOut(ctx, "assets.zip")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        extractAssetsRule,
diff --git a/java/android_manifest.go b/java/android_manifest.go
index e3646f5..9a71be2 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -53,7 +53,7 @@
 
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
 func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
-	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool) android.Path {
+	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
 
 	var args []string
 	if isLibrary {
@@ -91,6 +91,9 @@
 		args = append(args, "--has-no-code")
 	}
 
+	if loggingParent != "" {
+		args = append(args, "--logging-parent", loggingParent)
+	}
 	var deps android.Paths
 	targetSdkVersion, err := sdkContext.targetSdkVersion().effectiveVersionString(ctx)
 	if err != nil {
diff --git a/java/app.go b/java/app.go
index 6e0ffeb..ed4462c 100755
--- a/java/app.go
+++ b/java/app.go
@@ -79,6 +79,10 @@
 	// list of native libraries that will be provided in or alongside the resulting jar
 	Jni_libs []string `android:"arch_variant"`
 
+	// if true, allow JNI libraries that link against platform APIs even if this module sets
+	// sdk_version.
+	Jni_uses_platform_apis *bool
+
 	// STL library to use for JNI libraries.
 	Stl *string `android:"arch_variant"`
 
@@ -111,6 +115,9 @@
 
 	// the package name of this app. The package name in the manifest file is used if one was not given.
 	Package_name *string
+
+	// the logging parent of this app.
+	Logging_parent *string
 }
 
 type AndroidApp struct {
@@ -142,6 +149,10 @@
 	noticeOutputs android.NoticeOutputs
 }
 
+func (a *AndroidApp) IsInstallable() bool {
+	return Bool(a.properties.Installable)
+}
+
 func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
 	return nil
 }
@@ -269,13 +280,7 @@
 	aaptLinkFlags := []string{}
 
 	// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
-	hasProduct := false
-	for _, f := range a.aaptProperties.Aaptflags {
-		if strings.HasPrefix(f, "--product") {
-			hasProduct = true
-			break
-		}
-	}
+	hasProduct := android.PrefixInList(a.aaptProperties.Aaptflags, "--product")
 	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
 		aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
 	}
@@ -305,7 +310,7 @@
 
 	a.aapt.splitNames = a.appProperties.Package_splits
 	a.aapt.sdkLibraries = a.exportedSdkLibs
-
+	a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
 	a.aapt.buildActions(ctx, sdkContext(a), aaptLinkFlags...)
 
 	// apps manifests are handled by aapt, don't let Module see them
@@ -338,7 +343,6 @@
 		installDir = filepath.Join("app", a.installApkName)
 	}
 	a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
-	a.dexpreopter.isInstallable = Bool(a.properties.Installable)
 	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
 
 	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
@@ -386,16 +390,20 @@
 			return false
 		}
 
-		path := child.(android.Module).NoticeFile()
-		if path.Valid() {
-			noticePathSet[path.Path()] = true
+		paths := child.(android.Module).NoticeFiles()
+		if len(paths) > 0 {
+			for _, path := range paths {
+				noticePathSet[path] = true
+			}
 		}
 		return true
 	})
 
 	// If the app has one, add it too.
-	if a.NoticeFile().Valid() {
-		noticePathSet[a.NoticeFile().Path()] = true
+	if len(a.NoticeFiles()) > 0 {
+		for _, path := range a.NoticeFiles() {
+			noticePathSet[path] = true
+		}
 	}
 
 	if len(noticePathSet) == 0 {
@@ -487,7 +495,7 @@
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx))
+	jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
 
 	if ctx.Failed() {
@@ -523,7 +531,8 @@
 	}
 }
 
-func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool,
+	checkNativeSdkVersion bool) ([]jniLib, []Certificate) {
 	var jniLibs []jniLib
 	var certificates []Certificate
 	seenModulePaths := make(map[string]bool)
@@ -545,6 +554,18 @@
 				}
 				seenModulePaths[path.String()] = true
 
+				if checkNativeSdkVersion {
+					if app, ok := ctx.Module().(interface{ sdkVersion() sdkSpec }); ok {
+						if app.sdkVersion().specified() &&
+							app.sdkVersion().kind != sdkCorePlatform &&
+							dep.SdkVersion() == "" {
+							ctx.PropertyErrorf("jni_libs",
+								"JNI dependency %q uses platform APIs, but this module does not",
+								otherName)
+						}
+					}
+				}
+
 				if lib.Valid() {
 					jniLibs = append(jniLibs, jniLib{
 						name:   ctx.OtherModuleName(module),
@@ -583,6 +604,13 @@
 	return String(a.overridableAppProperties.Certificate)
 }
 
+func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+	if IsJniDepTag(ctx.OtherModuleDependencyTag(dep)) {
+		return true
+	}
+	return a.Library.DepIsInSameApex(ctx, dep)
+}
+
 // For OutputFileProducer interface
 func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
@@ -915,6 +943,10 @@
 	Filename *string
 }
 
+func (a *AndroidAppImport) IsInstallable() bool {
+	return true
+}
+
 // Updates properties with variant-specific values.
 func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
 	config := ctx.Config()
@@ -1030,7 +1062,7 @@
 		ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
 	}
 
-	_, certificates := collectAppDeps(ctx, false)
+	_, certificates := collectAppDeps(ctx, false, false)
 
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
@@ -1057,7 +1089,6 @@
 	}
 
 	a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
-	a.dexpreopter.isInstallable = true
 	a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
 	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
 
@@ -1286,7 +1317,7 @@
 	r.aapt.buildActions(ctx, r, "--no-resource-deduping", "--no-resource-removal")
 
 	// Sign the built package
-	_, certificates := collectAppDeps(ctx, false)
+	_, certificates := collectAppDeps(ctx, false, false)
 	certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
 	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates)
diff --git a/java/app_test.go b/java/app_test.go
index c86b038..0c6da7a 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -903,6 +903,7 @@
 			name: "libjni",
 			system_shared_libs: [],
 			stl: "none",
+			sdk_version: "current",
 		}
 
 		android_app {
@@ -1181,6 +1182,7 @@
 			name: "bar",
 			base: "foo",
 			certificate: ":new_certificate",
+			logging_parent: "bah",
 		}
 
 		android_app_certificate {
@@ -1196,37 +1198,41 @@
 		`)
 
 	expectedVariants := []struct {
-		moduleName  string
-		variantName string
-		apkName     string
-		apkPath     string
-		signFlag    string
-		overrides   []string
-		aaptFlag    string
+		moduleName     string
+		variantName    string
+		apkName        string
+		apkPath        string
+		signFlag       string
+		overrides      []string
+		aaptFlag       string
+		logging_parent string
 	}{
 		{
-			moduleName:  "foo",
-			variantName: "android_common",
-			apkPath:     "/target/product/test_device/system/app/foo/foo.apk",
-			signFlag:    "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			overrides:   []string{"qux"},
-			aaptFlag:    "",
+			moduleName:     "foo",
+			variantName:    "android_common",
+			apkPath:        "/target/product/test_device/system/app/foo/foo.apk",
+			signFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			overrides:      []string{"qux"},
+			aaptFlag:       "",
+			logging_parent: "",
 		},
 		{
-			moduleName:  "bar",
-			variantName: "android_common_bar",
-			apkPath:     "/target/product/test_device/system/app/bar/bar.apk",
-			signFlag:    "cert/new_cert.x509.pem cert/new_cert.pk8",
-			overrides:   []string{"qux", "foo"},
-			aaptFlag:    "",
+			moduleName:     "bar",
+			variantName:    "android_common_bar",
+			apkPath:        "/target/product/test_device/system/app/bar/bar.apk",
+			signFlag:       "cert/new_cert.x509.pem cert/new_cert.pk8",
+			overrides:      []string{"qux", "foo"},
+			aaptFlag:       "",
+			logging_parent: "bah",
 		},
 		{
-			moduleName:  "baz",
-			variantName: "android_common_baz",
-			apkPath:     "/target/product/test_device/system/app/baz/baz.apk",
-			signFlag:    "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			overrides:   []string{"qux", "foo"},
-			aaptFlag:    "--rename-manifest-package org.dandroid.bp",
+			moduleName:     "baz",
+			variantName:    "android_common_baz",
+			apkPath:        "/target/product/test_device/system/app/baz/baz.apk",
+			signFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			overrides:      []string{"qux", "foo"},
+			aaptFlag:       "--rename-manifest-package org.dandroid.bp",
+			logging_parent: "",
 		},
 	}
 	for _, expected := range expectedVariants {
@@ -1260,6 +1266,13 @@
 				expected.overrides, mod.appProperties.Overrides)
 		}
 
+		// Test Overridable property: Logging_parent
+		logging_parent := mod.aapt.LoggingParent
+		if expected.logging_parent != logging_parent {
+			t.Errorf("Incorrect overrides property value for logging parent, expected: %q, got: %q",
+				expected.logging_parent, logging_parent)
+		}
+
 		// Check the package renaming flag, if exists.
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
@@ -1847,42 +1860,6 @@
 func TestStl(t *testing.T) {
 	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
-			name: "ndk_libunwind",
-			sdk_version: "current",
-			stl: "none",
-			system_shared_libs: [],
-		}
-
-		cc_library {
-			name: "libc.ndk.current",
-			sdk_version: "current",
-			stl: "none",
-			system_shared_libs: [],
-		}
-
-		cc_library {
-			name: "libm.ndk.current",
-			sdk_version: "current",
-			stl: "none",
-			system_shared_libs: [],
-		}
-
-		cc_library {
-			name: "libdl.ndk.current",
-			sdk_version: "current",
-			stl: "none",
-			system_shared_libs: [],
-		}
-
-		cc_object {
-			name: "ndk_crtbegin_so.27",
-		}
-
-		cc_object {
-			name: "ndk_crtend_so.27",
-		}
-
-		cc_library {
 			name: "libjni",
 			sdk_version: "current",
 			stl: "c++_shared",
@@ -1902,10 +1879,6 @@
 			compile_multilib: "both",
 			sdk_version: "current",
 		}
-
-		ndk_prebuilt_shared_stl {
-			name: "ndk_libc++_shared",
-		}
 		`)
 
 	testCases := []struct {
@@ -2140,6 +2113,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			notice: "LIB_NOTICE",
+			sdk_version: "current",
 		}
 
 		java_library {
diff --git a/java/config/config.go b/java/config/config.go
index 7f446e5..54c89cd 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -48,7 +48,7 @@
 		// TODO: Could this be all updatable bootclasspath jars?
 		"updatable-media",
 		"framework-sdkextensions",
-		"ike",
+		"android.net.ipsec.ike",
 	}
 )
 
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index da68660..40cfe4f 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -19,6 +19,11 @@
 	"android/soong/dexpreopt"
 )
 
+type dexpreopterInterface interface {
+	IsInstallable() bool // Structs that embed dexpreopter must implement this.
+	dexpreoptDisabled(ctx android.BaseModuleContext) bool
+}
+
 type dexpreopter struct {
 	dexpreoptProperties DexpreoptProperties
 
@@ -26,7 +31,6 @@
 	uncompressedDex     bool
 	isSDKLibrary        bool
 	isTest              bool
-	isInstallable       bool
 	isPresignedPrebuilt bool
 
 	manifestFile     android.Path
@@ -58,8 +62,8 @@
 	}
 }
 
-func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool {
-	global := dexpreoptGlobalConfig(ctx)
+func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
+	global := dexpreopt.GetGlobalConfig(ctx)
 
 	if global.DisablePreopt {
 		return true
@@ -81,7 +85,11 @@
 		return true
 	}
 
-	if !d.isInstallable {
+	if !ctx.Module().(dexpreopterInterface).IsInstallable() {
+		return true
+	}
+
+	if ctx.Host() {
 		return true
 	}
 
@@ -95,43 +103,57 @@
 	return false
 }
 
+func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
+	if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
+		return
+	}
+	dexpreopt.RegisterToolDeps(ctx)
+}
+
 func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
-	return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreoptGlobalConfig(ctx))
+	return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
 }
 
 func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
-	if d.dexpreoptDisabled(ctx) {
+	// TODO(b/148690468): The check on d.installPath is to bail out in cases where
+	// the dexpreopter struct hasn't been fully initialized before we're called,
+	// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
+	// disabled, even if installable is true.
+	if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." {
 		return dexJarFile
 	}
 
-	global := dexpreoptGlobalConfig(ctx)
+	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
+	global := dexpreopt.GetGlobalConfig(ctx)
 	bootImage := defaultBootImageConfig(ctx)
-	if global.UseApexImage {
-		bootImage = frameworkJZBootImageConfig(ctx)
+	dexFiles := bootImage.dexPathsDeps.Paths()
+	dexLocations := bootImage.dexLocationsDeps
+	if global.UseArtImage {
+		bootImage = artBootImageConfig(ctx)
 	}
 
-	var archs []android.ArchType
-	for _, a := range ctx.MultiTargets() {
-		archs = append(archs, a.Arch.ArchType)
-	}
-	if len(archs) == 0 {
+	targets := ctx.MultiTargets()
+	if len(targets) == 0 {
 		// assume this is a java library, dexpreopt for all arches for now
 		for _, target := range ctx.Config().Targets[android.Android] {
 			if target.NativeBridge == android.NativeBridgeDisabled {
-				archs = append(archs, target.Arch.ArchType)
+				targets = append(targets, target)
 			}
 		}
 		if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary {
 			// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
-			archs = archs[:1]
+			targets = targets[:1]
 		}
 	}
 
+	var archs []android.ArchType
 	var images android.Paths
 	var imagesDeps []android.OutputPaths
-	for _, arch := range archs {
-		images = append(images, bootImage.images[arch])
-		imagesDeps = append(imagesDeps, bootImage.imagesDeps[arch])
+	for _, target := range targets {
+		archs = append(archs, target.Arch.ArchType)
+		variant := bootImage.getVariant(target)
+		images = append(images, variant.images)
+		imagesDeps = append(imagesDeps, variant.imagesDeps)
 	}
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
@@ -154,7 +176,7 @@
 		}
 	}
 
-	dexpreoptConfig := dexpreopt.ModuleConfig{
+	dexpreoptConfig := &dexpreopt.ModuleConfig{
 		Name:            ctx.ModuleName(),
 		DexLocation:     dexLocation,
 		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
@@ -178,8 +200,8 @@
 		DexPreoptImagesDeps:     imagesDeps,
 		DexPreoptImageLocations: bootImage.imageLocations,
 
-		PreoptBootClassPathDexFiles:     bootImage.dexPathsDeps.Paths(),
-		PreoptBootClassPathDexLocations: bootImage.dexLocationsDeps,
+		PreoptBootClassPathDexFiles:     dexFiles,
+		PreoptBootClassPathDexLocations: dexLocations,
 
 		PreoptExtractedApk: false,
 
@@ -189,7 +211,7 @@
 		PresignedPrebuilt: d.isPresignedPrebuilt,
 	}
 
-	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, dexpreoptConfig)
+	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
 	if err != nil {
 		ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
 		return dexJarFile
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 87f6d5e..d7adb40 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,7 +16,6 @@
 
 import (
 	"path/filepath"
-	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -48,6 +47,7 @@
 // The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
 // will then reconstruct the real path, so the rules must have a dependency on the real path.
 
+// Target-independent description of pre-compiled boot image.
 type bootImageConfig struct {
 	// Whether this image is an extension.
 	extension bool
@@ -67,9 +67,6 @@
 	// Subdirectory where the image files are installed.
 	installSubdir string
 
-	// Targets for which the image is generated.
-	targets []android.Target
-
 	// The names of jars that constitute this image.
 	modules []string
 
@@ -84,15 +81,43 @@
 	// The "locations" of the dependency images and in this image.
 	imageLocations []string
 
-	// Paths to image files (grouped by target).
-	images     map[android.ArchType]android.OutputPath  // first image file
-	imagesDeps map[android.ArchType]android.OutputPaths // all files
-
-	// Only for extensions, paths to the primary boot images (grouped by target).
-	primaryImages map[android.ArchType]android.OutputPath
-
 	// File path to a zip archive with all image files (or nil, if not needed).
 	zip android.WritablePath
+
+	// Rules which should be used in make to install the outputs.
+	profileInstalls android.RuleBuilderInstalls
+
+	// Target-dependent fields.
+	variants []*bootImageVariant
+}
+
+// Target-dependent description of pre-compiled boot image.
+type bootImageVariant struct {
+	*bootImageConfig
+
+	// Target for which the image is generated.
+	target android.Target
+
+	// Paths to image files.
+	images     android.OutputPath  // first image file
+	imagesDeps android.OutputPaths // all files
+
+	// Only for extensions, paths to the primary boot images.
+	primaryImages android.OutputPath
+
+	// Rules which should be used in make to install the outputs.
+	installs           android.RuleBuilderInstalls
+	vdexInstalls       android.RuleBuilderInstalls
+	unstrippedInstalls android.RuleBuilderInstalls
+}
+
+func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant {
+	for _, variant := range image.variants {
+		if variant.target.Os == target.Os && variant.target.Arch.ArchType == target.Arch.ArchType {
+			return variant
+		}
+	}
+	return nil
 }
 
 func (image bootImageConfig) moduleName(idx int) string {
@@ -126,28 +151,6 @@
 	return ret
 }
 
-type bootImage struct {
-	bootImageConfig
-
-	installs           map[android.ArchType]android.RuleBuilderInstalls
-	vdexInstalls       map[android.ArchType]android.RuleBuilderInstalls
-	unstrippedInstalls map[android.ArchType]android.RuleBuilderInstalls
-
-	profileInstalls android.RuleBuilderInstalls
-}
-
-func newBootImage(ctx android.PathContext, config bootImageConfig) *bootImage {
-	image := &bootImage{
-		bootImageConfig: config,
-
-		installs:           make(map[android.ArchType]android.RuleBuilderInstalls),
-		vdexInstalls:       make(map[android.ArchType]android.RuleBuilderInstalls),
-		unstrippedInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
-	}
-
-	return image
-}
-
 func concat(lists ...[]string) []string {
 	var size int
 	for _, l := range lists {
@@ -165,7 +168,7 @@
 }
 
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
-	if dexpreoptGlobalConfig(ctx).DisablePreopt {
+	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
 		return true
 	}
 
@@ -182,8 +185,8 @@
 }
 
 type dexpreoptBootJars struct {
-	defaultBootImage *bootImage
-	otherImages      []*bootImage
+	defaultBootImage *bootImageConfig
+	otherImages      []*bootImageConfig
 
 	dexpreoptConfigForMake android.WritablePath
 }
@@ -193,17 +196,11 @@
 	if skipDexpreoptBootJars(ctx) {
 		return nil
 	}
-
 	// Include dexpreopt files for the primary boot image.
-	files := artBootImageConfig(ctx).imagesDeps
-
-	// For JIT-zygote config, also include dexpreopt files for the primary JIT-zygote image.
-	if dexpreoptGlobalConfig(ctx).UseApexImage {
-		for arch, paths := range artJZBootImageConfig(ctx).imagesDeps {
-			files[arch] = append(files[arch], paths...)
-		}
+	files := map[android.ArchType]android.OutputPaths{}
+	for _, variant := range artBootImageConfig(ctx).variants {
+		files[variant.target.Arch.ArchType] = variant.imagesDeps
 	}
-
 	return files
 }
 
@@ -212,11 +209,15 @@
 	if skipDexpreoptBootJars(ctx) {
 		return
 	}
+	if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil {
+		// No module has enabled dexpreopting, so we assume there will be no boot image to make.
+		return
+	}
 
 	d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
 	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
 
-	global := dexpreoptGlobalConfig(ctx)
+	global := dexpreopt.GetGlobalConfig(ctx)
 
 	// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
 	// and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
@@ -232,19 +233,12 @@
 	d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx))
 	// Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
 	d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx)))
-	if global.GenerateApexImage {
-		// Create boot images for the JIT-zygote experiment.
-		d.otherImages = append(d.otherImages, buildBootImage(ctx, artJZBootImageConfig(ctx)))
-		d.otherImages = append(d.otherImages, buildBootImage(ctx, frameworkJZBootImageConfig(ctx)))
-	}
 
 	dumpOatRules(ctx, d.defaultBootImage)
 }
 
-// buildBootImage takes a bootImageConfig, creates rules to build it, and returns a *bootImage.
-func buildBootImage(ctx android.SingletonContext, config bootImageConfig) *bootImage {
-	image := newBootImage(ctx, config)
-
+// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
+func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
 	bootDexJars := make(android.Paths, len(image.modules))
 	ctx.VisitAllModules(func(module android.Module) {
 		// Collect dex jar paths for the modules listed above.
@@ -285,8 +279,8 @@
 	bootFrameworkProfileRule(ctx, image, missingDeps)
 
 	var allFiles android.Paths
-	for _, target := range image.targets {
-		files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+	for _, variant := range image.variants {
+		files := buildBootImageVariant(ctx, variant, profile, missingDeps)
 		allFiles = append(allFiles, files.Paths()...)
 	}
 
@@ -304,11 +298,13 @@
 	return image
 }
 
-func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage,
-	arch android.ArchType, profile android.Path, missingDeps []string) android.WritablePaths {
+func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant,
+	profile android.Path, missingDeps []string) android.WritablePaths {
 
-	global := dexpreoptGlobalConfig(ctx)
+	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+	global := dexpreopt.GetGlobalConfig(ctx)
 
+	arch := image.target.Arch.ArchType
 	symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String())
 	symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
 	outputDir := image.dir.Join(ctx, image.installSubdir, arch.String())
@@ -342,7 +338,7 @@
 
 	invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
 
-	cmd.Tool(global.SoongConfig.Dex2oat).
+	cmd.Tool(globalSoong.Dex2oat).
 		Flag("--avoid-storing-invocation").
 		FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
 		Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms).
@@ -358,7 +354,7 @@
 	}
 
 	if image.extension {
-		artImage := image.primaryImages[arch]
+		artImage := image.primaryImages
 		cmd.
 			Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
@@ -433,9 +429,9 @@
 	rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+arch.String(), "dexpreopt "+image.name+" jars "+arch.String())
 
 	// save output and installed files for makevars
-	image.installs[arch] = rule.Installs()
-	image.vdexInstalls[arch] = vdexInstalls
-	image.unstrippedInstalls[arch] = unstrippedInstalls
+	image.installs = rule.Installs()
+	image.vdexInstalls = vdexInstalls
+	image.unstrippedInstalls = unstrippedInstalls
 
 	return zipFiles
 }
@@ -444,8 +440,9 @@
 It is likely that the boot classpath is inconsistent.
 Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
 
-func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
-	global := dexpreoptGlobalConfig(ctx)
+func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+	global := dexpreopt.GetGlobalConfig(ctx)
 
 	if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
 		return nil
@@ -476,7 +473,7 @@
 
 		rule.Command().
 			Text(`ANDROID_LOG_TAGS="*:e"`).
-			Tool(global.SoongConfig.Profman).
+			Tool(globalSoong.Profman).
 			FlagWithInput("--create-profile-from=", bootImageProfile).
 			FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
 			FlagForEachArg("--dex-location=", image.dexLocationsDeps).
@@ -498,8 +495,9 @@
 
 var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
 
-func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
-	global := dexpreoptGlobalConfig(ctx)
+func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+	global := dexpreopt.GetGlobalConfig(ctx)
 
 	if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
 		return nil
@@ -525,7 +523,7 @@
 
 		rule.Command().
 			Text(`ANDROID_LOG_TAGS="*:e"`).
-			Tool(global.SoongConfig.Profman).
+			Tool(globalSoong.Profman).
 			Flag("--generate-boot-profile").
 			FlagWithInput("--create-profile-from=", bootFrameworkProfile).
 			FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
@@ -542,15 +540,10 @@
 
 var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
 
-func dumpOatRules(ctx android.SingletonContext, image *bootImage) {
-	var archs []android.ArchType
-	for arch := range image.images {
-		archs = append(archs, arch)
-	}
-	sort.Slice(archs, func(i, j int) bool { return archs[i].String() < archs[j].String() })
-
+func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
 	var allPhonies android.Paths
-	for _, arch := range archs {
+	for _, image := range image.variants {
+		arch := image.target.Arch.ArchType
 		// Create a rule to call oatdump.
 		output := android.PathForOutput(ctx, "boot."+arch.String()+".oatdump.txt")
 		rule := android.NewRuleBuilder()
@@ -559,7 +552,7 @@
 			BuiltTool(ctx, "oatdumpd").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
-			FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps[arch].Paths()).
+			FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
 		rule.Build(pctx, ctx, "dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
@@ -587,7 +580,7 @@
 }
 
 func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
-	data := dexpreoptGlobalConfigRaw(ctx).data
+	data := dexpreopt.GetGlobalConfigRawData(ctx)
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.WriteFile,
@@ -614,20 +607,13 @@
 		var imageNames []string
 		for _, current := range append(d.otherImages, image) {
 			imageNames = append(imageNames, current.name)
-			var arches []android.ArchType
-			for arch, _ := range current.images {
-				arches = append(arches, arch)
-			}
-
-			sort.Slice(arches, func(i, j int) bool { return arches[i].String() < arches[j].String() })
-
-			for _, arch := range arches {
-				sfx := current.name + "_" + arch.String()
-				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls[arch].String())
-				ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images[arch].String())
-				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps[arch].Strings(), " "))
-				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs[arch].String())
-				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls[arch].String())
+			for _, current := range current.variants {
+				sfx := current.name + "_" + current.target.Arch.ArchType.String()
+				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls.String())
+				ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images.String())
+				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps.Strings(), " "))
+				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs.String())
+				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls.String())
 			}
 
 			ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":"))
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 4ce30f6..c3b2133 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -49,7 +49,7 @@
 	pathCtx := android.PathContextForTesting(config)
 	dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
 	dexpreoptConfig.BootJars = []string{"foo", "bar", "baz"}
-	setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
+	dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
 
 	ctx := testContext()
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 637a32f..a06aec4 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -22,67 +23,36 @@
 	"android/soong/dexpreopt"
 )
 
-// dexpreoptGlobalConfig returns the global dexpreopt.config.  It is loaded once the first time it is called for any
-// ctx.Config(), and returns the same data for all future calls with the same ctx.Config().  A value can be inserted
-// for tests using setDexpreoptTestGlobalConfig.
-func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
-	return dexpreoptGlobalConfigRaw(ctx).global
-}
-
-type globalConfigAndRaw struct {
-	global dexpreopt.GlobalConfig
-	data   []byte
-}
-
-func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
-	return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
-		if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
-			panic(err)
-		} else if data != nil {
-			soongConfig := dexpreopt.CreateGlobalSoongConfig(ctx)
-			globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, data, soongConfig)
-			if err != nil {
-				panic(err)
-			}
-			return globalConfigAndRaw{globalConfig, data}
-		}
-
-		// No global config filename set, see if there is a test config set
-		return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} {
-			// Nope, return a config with preopting disabled
-			return globalConfigAndRaw{dexpreopt.GlobalConfig{
-				DisablePreopt:          true,
-				DisableGenerateProfile: true,
-			}, nil}
-		})
-	}).(globalConfigAndRaw)
-}
-
-// setDexpreoptTestGlobalConfig sets a GlobalConfig that future calls to dexpreoptGlobalConfig will return.  It must
-// be called before the first call to dexpreoptGlobalConfig for the config.
-func setDexpreoptTestGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) {
-	config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
-}
-
-var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
-var dexpreoptTestGlobalConfigKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
-
 // systemServerClasspath returns the on-device locations of the modules in the system server classpath.  It is computed
 // once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
 // ctx.Config().
-func systemServerClasspath(ctx android.PathContext) []string {
+func systemServerClasspath(ctx android.MakeVarsContext) []string {
 	return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
-		global := dexpreoptGlobalConfig(ctx)
-
+		global := dexpreopt.GetGlobalConfig(ctx)
 		var systemServerClasspathLocations []string
-		for _, m := range global.SystemServerJars {
+		var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config())
+		// 1) The jars that are dexpreopted.
+		for _, m := range dexpreoptJars {
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				filepath.Join("/system/framework", m+".jar"))
 		}
+		// 2) The jars that are from an updatable apex.
 		for _, m := range global.UpdatableSystemServerJars {
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				dexpreopt.GetJarLocationFromApexJarPair(m))
 		}
+		// 3) The jars from make (which are not updatable, not preopted).
+		for _, m := range dexpreopt.NonUpdatableSystemServerJars(ctx, global) {
+			if !android.InList(m, dexpreoptJars) {
+				systemServerClasspathLocations = append(systemServerClasspathLocations,
+					filepath.Join("/system/framework", m+".jar"))
+			}
+		}
+		if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
+			panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
+				len(systemServerClasspathLocations),
+				len(global.SystemServerJars)+len(global.UpdatableSystemServerJars)))
+		}
 		return systemServerClasspathLocations
 	})
 }
@@ -112,28 +82,17 @@
 	return moduleName
 }
 
-func getJarsFromApexJarPairs(apexJarPairs []string) []string {
-	modules := make([]string, len(apexJarPairs))
-	for i, p := range apexJarPairs {
-		_, jar := dexpreopt.SplitApexJarPair(p)
-		modules[i] = jar
-	}
-	return modules
-}
-
 var (
-	bootImageConfigKey       = android.NewOnceKey("bootImageConfig")
-	artBootImageName         = "art"
-	frameworkBootImageName   = "boot"
-	artJZBootImageName       = "jitzygote-art"
-	frameworkJZBootImageName = "jitzygote-boot"
+	bootImageConfigKey     = android.NewOnceKey("bootImageConfig")
+	artBootImageName       = "art"
+	frameworkBootImageName = "boot"
 )
 
 // Construct the global boot image configs.
 func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
 
-		global := dexpreoptGlobalConfig(ctx)
+		global := dexpreopt.GetGlobalConfig(ctx)
 		targets := dexpreoptTargets(ctx)
 		deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
 
@@ -143,7 +102,7 @@
 			artModules = append(artModules, "jacocoagent")
 		}
 		frameworkModules := android.RemoveListFromList(global.BootJars,
-			concat(artModules, getJarsFromApexJarPairs(global.UpdatableBootJars)))
+			concat(artModules, dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)))
 
 		artSubdir := "apex/com.android.art/javalib"
 		frameworkSubdir := "system/framework"
@@ -180,39 +139,13 @@
 			dexLocationsDeps: append(artLocations, frameworkLocations...),
 		}
 
-		// ART config for JIT-zygote boot image.
-		artJZCfg := bootImageConfig{
-			extension:        false,
-			name:             artJZBootImageName,
-			stem:             "apex",
-			installSubdir:    artSubdir,
-			modules:          artModules,
-			dexLocations:     artLocations,
-			dexLocationsDeps: artLocations,
-		}
-
-		// Framework config for JIT-zygote boot image extension.
-		frameworkJZCfg := bootImageConfig{
-			extension:        true,
-			name:             frameworkJZBootImageName,
-			stem:             "apex",
-			installSubdir:    frameworkSubdir,
-			modules:          frameworkModules,
-			dexLocations:     frameworkLocations,
-			dexLocationsDeps: append(artLocations, frameworkLocations...),
-		}
-
 		configs := map[string]*bootImageConfig{
-			artBootImageName:         &artCfg,
-			frameworkBootImageName:   &frameworkCfg,
-			artJZBootImageName:       &artJZCfg,
-			frameworkJZBootImageName: &frameworkJZCfg,
+			artBootImageName:       &artCfg,
+			frameworkBootImageName: &frameworkCfg,
 		}
 
 		// common to all configs
 		for _, c := range configs {
-			c.targets = targets
-
 			c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
 			c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
 
@@ -231,14 +164,17 @@
 			}
 			c.dexPathsDeps = c.dexPaths
 
-			c.images = make(map[android.ArchType]android.OutputPath)
-			c.imagesDeps = make(map[android.ArchType]android.OutputPaths)
-
+			// Create target-specific variants.
 			for _, target := range targets {
 				arch := target.Arch.ArchType
 				imageDir := c.dir.Join(ctx, c.installSubdir, arch.String())
-				c.images[arch] = imageDir.Join(ctx, imageName)
-				c.imagesDeps[arch] = c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex")
+				variant := &bootImageVariant{
+					bootImageConfig: c,
+					target:          target,
+					images:          imageDir.Join(ctx, imageName),
+					imagesDeps:      c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
+				}
+				c.variants = append(c.variants, variant)
 			}
 
 			c.zip = c.dir.Join(ctx, c.name+".zip")
@@ -246,37 +182,26 @@
 
 		// specific to the framework config
 		frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
-		frameworkCfg.primaryImages = artCfg.images
+		for i := range targets {
+			frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images
+		}
 		frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
 
-		// specific to the jitzygote-framework config
-		frameworkJZCfg.dexPathsDeps = append(artJZCfg.dexPathsDeps, frameworkJZCfg.dexPathsDeps...)
-		frameworkJZCfg.primaryImages = artJZCfg.images
-		frameworkJZCfg.imageLocations = append(artJZCfg.imageLocations, frameworkJZCfg.imageLocations...)
-
 		return configs
 	}).(map[string]*bootImageConfig)
 }
 
-func artBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return *genBootImageConfigs(ctx)[artBootImageName]
+func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
+	return genBootImageConfigs(ctx)[artBootImageName]
 }
 
-func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return *genBootImageConfigs(ctx)[frameworkBootImageName]
-}
-
-func artJZBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return *genBootImageConfigs(ctx)[artJZBootImageName]
-}
-
-func frameworkJZBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return *genBootImageConfigs(ctx)[frameworkJZBootImageName]
+func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
+	return genBootImageConfigs(ctx)[frameworkBootImageName]
 }
 
 func defaultBootclasspath(ctx android.PathContext) []string {
 	return ctx.Config().OnceStringSlice(defaultBootclasspathKey, func() []string {
-		global := dexpreoptGlobalConfig(ctx)
+		global := dexpreopt.GetGlobalConfig(ctx)
 		image := defaultBootImageConfig(ctx)
 
 		updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 098400b..5437499 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -534,6 +534,9 @@
 		ctx.AddMissingDependencies(sdkDep.java9Classpath)
 	} else if sdkDep.useFiles {
 		deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...)
+		deps.aidlPreprocess = sdkDep.aidl
+	} else {
+		deps.aidlPreprocess = sdkDep.aidl
 	}
 
 	ctx.VisitDirectDeps(func(module android.Module) {
@@ -544,10 +547,10 @@
 		case bootClasspathTag:
 			if dep, ok := module.(Dependency); ok {
 				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
-			} else if sm, ok := module.(*SystemModules); ok {
+			} else if sm, ok := module.(SystemModulesProvider); ok {
 				// A system modules dependency has been added to the bootclasspath
 				// so add its libs to the bootclasspath.
-				deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+				deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
 			} else {
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
@@ -575,11 +578,9 @@
 			if deps.systemModules != nil {
 				panic("Found two system module dependencies")
 			}
-			sm := module.(*SystemModules)
-			if sm.outputDir == nil && len(sm.outputDeps) == 0 {
-				panic("Missing directory for system module dependency")
-			}
-			deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
+			sm := module.(SystemModulesProvider)
+			outputDir, outputDeps := sm.OutputDirAndDeps()
+			deps.systemModules = &systemModules{outputDir, outputDeps}
 		}
 	})
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -602,11 +603,8 @@
 				continue
 			}
 			packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".")
-			for _, pkg := range filterPackages {
-				if strings.HasPrefix(packageName, pkg) {
-					filtered = append(filtered, src)
-					break
-				}
+			if android.HasAnyPrefix(packageName, filterPackages) {
+				filtered = append(filtered, src)
 			}
 		}
 		return filtered
@@ -775,6 +773,7 @@
 }
 
 func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) {
+	buildNumberFile := ctx.Config().BuildNumberFile(ctx)
 	// Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources.  For modules with 1.9
 	// sources, droiddoc will get sources produced by metalava which will have already stripped out the
 	// 1.9 language features.
@@ -784,7 +783,7 @@
 		Flag("-XDignore.symbol.file").
 		FlagWithArg("-doclet ", "com.google.doclava.Doclava").
 		FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
-		FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-"+ctx.Config().BuildNumberFromFile()).
+		FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
 		FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
 
 	if String(d.properties.Custom_template) == "" {
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 6020aba..884a757 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -28,9 +28,10 @@
 }, "outFlag", "stubAPIFlags")
 
 type hiddenAPI struct {
-	flagsCSVPath    android.Path
-	metadataCSVPath android.Path
 	bootDexJarPath  android.Path
+	flagsCSVPath    android.Path
+	indexCSVPath    android.Path
+	metadataCSVPath android.Path
 }
 
 func (h *hiddenAPI) flagsCSV() android.Path {
@@ -45,17 +46,21 @@
 	return h.bootDexJarPath
 }
 
+func (h *hiddenAPI) indexCSV() android.Path {
+	return h.indexCSVPath
+}
+
 type hiddenAPIIntf interface {
-	flagsCSV() android.Path
-	metadataCSV() android.Path
 	bootDexJar() android.Path
+	flagsCSV() android.Path
+	indexCSV() android.Path
+	metadataCSV() android.Path
 }
 
 var _ hiddenAPIIntf = (*hiddenAPI)(nil)
 
-func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath, implementationJar android.Path,
-	uncompressDex bool) android.ModuleOutPath {
-
+func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath,
+	implementationJar android.Path, uncompressDex bool) android.ModuleOutPath {
 	if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
 		name := ctx.ModuleName()
 
@@ -77,9 +82,8 @@
 			// Derive the greylist from classes jar.
 			flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
 			metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
-			hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, implementationJar)
-			h.flagsCSVPath = flagsCSV
-			h.metadataCSVPath = metadataCSV
+			indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv")
+			h.hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, indexCSV, implementationJar)
 
 			// If this module is actually on the boot jars list and not providing
 			// hiddenapi information for a module on the boot jars list then encode
@@ -96,9 +100,7 @@
 	return dexJar
 }
 
-func hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV android.WritablePath,
-	classesJar android.Path) {
-
+func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV, indexCSV android.WritablePath, classesJar android.Path) {
 	stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
 
 	ctx.Build(pctx, android.BuildParams{
@@ -112,6 +114,7 @@
 			"stubAPIFlags": stubFlagsCSV.String(),
 		},
 	})
+	h.flagsCSVPath = flagsCSV
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIGenerateCSVRule,
@@ -124,18 +127,26 @@
 			"stubAPIFlags": stubFlagsCSV.String(),
 		},
 	})
+	h.metadataCSVPath = metadataCSV
 
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		BuiltTool(ctx, "merge_csv").
+		FlagWithInput("--zip_input=", classesJar).
+		FlagWithOutput("--output=", indexCSV)
+	rule.Build(pctx, ctx, "merged-hiddenapi-index", "Merged Hidden API index")
+	h.indexCSVPath = indexCSV
 }
 
 var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
-	Command: `rm -rf $tmpDir && mkdir -p $tmpDir && mkdir $tmpDir/dex-input && mkdir $tmpDir/dex-output && ` +
-		`unzip -o -q $in 'classes*.dex' -d $tmpDir/dex-input && ` +
-		`for INPUT_DEX in $$(find $tmpDir/dex-input -maxdepth 1 -name 'classes*.dex' | sort); do ` +
-		`  echo "--input-dex=$${INPUT_DEX}"; ` +
-		`  echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})"; ` +
-		`done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags && ` +
-		`${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" && ` +
-		`${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" $out $tmpDir/dex.jar $in`,
+	Command: `rm -rf $tmpDir && mkdir -p $tmpDir && mkdir $tmpDir/dex-input && mkdir $tmpDir/dex-output &&
+		unzip -o -q $in 'classes*.dex' -d $tmpDir/dex-input &&
+		for INPUT_DEX in $$(find $tmpDir/dex-input -maxdepth 1 -name 'classes*.dex' | sort); do
+		  echo "--input-dex=$${INPUT_DEX}";
+		  echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})";
+		done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags &&
+		${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" &&
+		${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
 	CommandDeps: []string{
 		"${config.HiddenAPI}",
 		"${config.SoongZipCmd}",
@@ -159,9 +170,21 @@
 		tmpOutput = android.PathForModuleOut(ctx, "hiddenapi", "unaligned", "unaligned.jar")
 		tmpDir = android.PathForModuleOut(ctx, "hiddenapi", "unaligned")
 	}
+
+	enforceHiddenApiFlagsToAllMembers := true
 	// If frameworks/base doesn't exist we must be building with the 'master-art' manifest.
 	// Disable assertion that all methods/fields have hidden API flags assigned.
 	if !ctx.Config().FrameworksBaseDirExists(ctx) {
+		enforceHiddenApiFlagsToAllMembers = false
+	}
+	// b/149353192: when a module is instrumented, jacoco adds synthetic members
+	// $jacocoData and $jacocoInit. Since they don't exist when building the hidden API flags,
+	// don't complain when we don't find hidden API flags for the synthetic members.
+	if j, ok := ctx.Module().(*Library); ok && j.shouldInstrument(ctx) {
+		enforceHiddenApiFlagsToAllMembers = false
+	}
+
+	if !enforceHiddenApiFlagsToAllMembers {
 		hiddenapiFlags = "--no-force-assign-all"
 	}
 
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 3243e43..7e7e955 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -22,13 +22,15 @@
 
 func init() {
 	android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
 	android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
 }
 
 type hiddenAPISingletonPathsStruct struct {
-	stubFlags android.OutputPath
 	flags     android.OutputPath
+	index     android.OutputPath
 	metadata  android.OutputPath
+	stubFlags android.OutputPath
 }
 
 var hiddenAPISingletonPathsKey = android.NewOnceKey("hiddenAPISingletonPathsKey")
@@ -39,9 +41,10 @@
 func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
 	return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
 		return hiddenAPISingletonPathsStruct{
-			stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
 			flags:     android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
+			index:     android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"),
 			metadata:  android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"),
+			stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
 		}
 	}).(hiddenAPISingletonPathsStruct)
 }
@@ -294,9 +297,8 @@
 
 	rule.Command().
 		BuiltTool(ctx, "merge_csv").
-		Inputs(metadataCSV).
-		Text(">").
-		Output(outputPath)
+		FlagWithOutput("--output=", outputPath).
+		Inputs(metadataCSV)
 
 	rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
 
@@ -365,3 +367,45 @@
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	return module
 }
+
+func hiddenAPIIndexSingletonFactory() android.Singleton {
+	return &hiddenAPIIndexSingleton{}
+}
+
+type hiddenAPIIndexSingleton struct {
+	index android.Path
+}
+
+func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
+	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+		return
+	}
+
+	indexes := android.Paths{}
+	ctx.VisitAllModules(func(module android.Module) {
+		if h, ok := module.(hiddenAPIIntf); ok {
+			if h.indexCSV() != nil {
+				indexes = append(indexes, h.indexCSV())
+			}
+		}
+	})
+
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		BuiltTool(ctx, "merge_csv").
+		FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
+		FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
+		Inputs(indexes)
+	rule.Build(pctx, ctx, "singleton-merged-hiddenapi-index", "Singleton merged Hidden API index")
+
+	h.index = hiddenAPISingletonPaths(ctx).index
+}
+
+func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) {
+	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+		return
+	}
+
+	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String())
+}
diff --git a/java/java.go b/java/java.go
index ed3dca9..8d58a90 100644
--- a/java/java.go
+++ b/java/java.go
@@ -23,12 +23,14 @@
 	"path/filepath"
 	"strconv"
 	"strings"
+	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/dexpreopt"
 	"android/soong/java/config"
 	"android/soong/tradefed"
 )
@@ -37,14 +39,7 @@
 	RegisterJavaBuildComponents(android.InitRegistrationContext)
 
 	// Register sdk member types.
-	android.RegisterSdkMemberType(&headerLibrarySdkMemberType{
-		librarySdkMemberType{
-			android.SdkMemberTypeBase{
-				PropertyName: "java_header_libs",
-				SupportsSdk:  true,
-			},
-		},
-	})
+	android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
 
 	android.RegisterSdkMemberType(&implLibrarySdkMemberType{
 		librarySdkMemberType{
@@ -59,6 +54,8 @@
 			PropertyName: "java_tests",
 		},
 	})
+
+	android.PostDepsMutators(RegisterPostDepsMutators)
 }
 
 func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
@@ -79,10 +76,52 @@
 	ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
 	ctx.RegisterModuleType("dex_import", DexImportFactory)
 
+	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
+	})
+
 	ctx.RegisterSingletonType("logtags", LogtagsSingleton)
 	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.BottomUp("ordered_system_server_jars", systemServerJarsDepsMutator)
+}
+
+var (
+	dexpreoptedSystemServerJarsKey  = android.NewOnceKey("dexpreoptedSystemServerJars")
+	dexpreoptedSystemServerJarsLock sync.Mutex
+)
+
+func DexpreoptedSystemServerJars(config android.Config) *[]string {
+	return config.Once(dexpreoptedSystemServerJarsKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+// A PostDepsMutator pass that enforces total order on non-updatable system server jars. A total
+// order is neededed because such jars must be dexpreopted together (each jar on the list must have
+// all preceding jars in its class loader context). The total order must be compatible with the
+// partial order imposed by genuine dependencies between system server jars (which is not always
+// respected by the PRODUCT_SYSTEM_SERVER_JARS variable).
+//
+// An earlier mutator pass creates genuine dependencies, and this pass traverses the jars in that
+// order (which is partial and non-deterministic). This pass adds additional dependencies between
+// jars, making the order total and deterministic. It also constructs a global ordered list.
+func systemServerJarsDepsMutator(ctx android.BottomUpMutatorContext) {
+	jars := dexpreopt.NonUpdatableSystemServerJars(ctx, dexpreopt.GetGlobalConfig(ctx))
+	name := ctx.ModuleName()
+	if android.InList(name, jars) {
+		dexpreoptedSystemServerJarsLock.Lock()
+		defer dexpreoptedSystemServerJarsLock.Unlock()
+		jars := DexpreoptedSystemServerJars(ctx.Config())
+		for _, dep := range *jars {
+			ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerDepTag, dep)
+		}
+		*jars = append(*jars, name)
+	}
+}
+
 func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
 	if j.SocSpecific() || j.DeviceSpecific() ||
 		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
@@ -666,6 +705,11 @@
 	} else if j.shouldInstrumentStatic(ctx) {
 		ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
 	}
+
+	// services depend on com.android.location.provider, but dependency in not registered in a Blueprint file
+	if ctx.ModuleName() == "services" {
+		ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerForcedDepTag, "com.android.location.provider")
+	}
 }
 
 func hasSrcExt(srcs []string, ext string) bool {
@@ -757,9 +801,13 @@
 type linkType int
 
 const (
+	// TODO(jiyong) rename these for better readability. Make the allowed
+	// and disallowed link types explicit
 	javaCore linkType = iota
 	javaSdk
 	javaSystem
+	javaModule
+	javaSystemServer
 	javaPlatform
 )
 
@@ -789,6 +837,14 @@
 		return javaSdk, true
 	case ver.kind == sdkPublic:
 		return javaSdk, false
+	case name == "android_module_lib_stubs_current":
+		return javaModule, true
+	case ver.kind == sdkModule:
+		return javaModule, false
+	case name == "services-stubs":
+		return javaSystemServer, true
+	case ver.kind == sdkSystemServer:
+		return javaSystemServer, false
 	case ver.kind == sdkPrivate || ver.kind == sdkNone || ver.kind == sdkCorePlatform:
 		return javaPlatform, false
 	case !ver.valid():
@@ -824,11 +880,23 @@
 		}
 		break
 	case javaSystem:
-		if otherLinkType == javaPlatform {
+		if otherLinkType == javaPlatform || otherLinkType == javaModule || otherLinkType == javaSystemServer {
 			ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
 				ctx.OtherModuleName(to))
 		}
 		break
+	case javaModule:
+		if otherLinkType == javaPlatform || otherLinkType == javaSystemServer {
+			ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage,
+				ctx.OtherModuleName(to))
+		}
+		break
+	case javaSystemServer:
+		if otherLinkType == javaPlatform {
+			ctx.ModuleErrorf("compiles against system server API, but dependency %q is compiling against private API."+commonMessage,
+				ctx.OtherModuleName(to))
+		}
+		break
 	case javaPlatform:
 		// no restriction on link-type
 		break
@@ -963,18 +1031,16 @@
 			case bootClasspathTag:
 				// If a system modules dependency has been added to the bootclasspath
 				// then add its libs to the bootclasspath.
-				sm := module.(*SystemModules)
-				deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+				sm := module.(SystemModulesProvider)
+				deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
 
 			case systemModulesTag:
 				if deps.systemModules != nil {
 					panic("Found two system module dependencies")
 				}
-				sm := module.(*SystemModules)
-				if sm.outputDir == nil || len(sm.outputDeps) == 0 {
-					panic("Missing directory for system module dependency")
-				}
-				deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
+				sm := module.(SystemModulesProvider)
+				outputDir, outputDeps := sm.OutputDirAndDeps()
+				deps.systemModules = &systemModules{outputDir, outputDeps}
 			}
 		}
 	})
@@ -1257,6 +1323,7 @@
 	j.compiledSrcJars = srcJars
 
 	enable_sharding := false
+	var headerJarFileWithoutJarjar android.Path
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
 		if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
 			enable_sharding = true
@@ -1266,7 +1333,8 @@
 			// allow for the use of annotation processors that do function correctly
 			// with sharding enabled. See: b/77284273.
 		}
-		j.headerJarFile = j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
+		headerJarFileWithoutJarjar, j.headerJarFile =
+			j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
 		if ctx.Failed() {
 			return
 		}
@@ -1285,7 +1353,7 @@
 		}
 
 		if enable_sharding {
-			flags.classpath = append(flags.classpath, j.headerJarFile)
+			flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
 			shardSize := int(*(j.properties.Javac_shard_size))
 			var shardSrcs []android.Paths
 			if len(uniqueSrcFiles) > 0 {
@@ -1453,6 +1521,14 @@
 		j.headerJarFile = j.implementationJarFile
 	}
 
+	// Force enable the instrumentation for java code that is built for APEXes ...
+	// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
+	// doesn't make sense)
+	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
+	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+		j.properties.Instrument = true
+	}
+
 	if j.shouldInstrument(ctx) {
 		outputFile = j.instrument(ctx, flags, outputFile, jarName)
 	}
@@ -1469,6 +1545,16 @@
 
 	j.implementationAndResourcesJar = implementationAndResourcesJar
 
+	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
+	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() {
+		if j.deviceProperties.Compile_dex == nil {
+			j.deviceProperties.Compile_dex = proptools.BoolPtr(true)
+		}
+		if j.deviceProperties.Hostdex == nil {
+			j.deviceProperties.Hostdex = proptools.BoolPtr(true)
+		}
+	}
+
 	if ctx.Device() && j.hasCode(ctx) &&
 		(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
 		// Dex compilation
@@ -1566,7 +1652,8 @@
 }
 
 func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
-	deps deps, flags javaBuilderFlags, jarName string, extraJars android.Paths) android.Path {
+	deps deps, flags javaBuilderFlags, jarName string,
+	extraJars android.Paths) (headerJar, jarjarHeaderJar android.Path) {
 
 	var jars android.Paths
 	if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1574,7 +1661,7 @@
 		turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
 		TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
 		if ctx.Failed() {
-			return nil
+			return nil, nil
 		}
 		jars = append(jars, turbineJar)
 	}
@@ -1583,7 +1670,6 @@
 
 	// Combine any static header libraries into classes-header.jar. If there is only
 	// one input jar this step will be skipped.
-	var headerJar android.Path
 	jars = append(jars, deps.staticHeaderJars...)
 
 	// we cannot skip the combine step for now if there is only one jar
@@ -1592,18 +1678,19 @@
 	TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
 		false, nil, []string{"META-INF/TRANSITIVE"})
 	headerJar = combinedJar
+	jarjarHeaderJar = combinedJar
 
 	if j.expandJarjarRules != nil {
 		// Transform classes.jar into classes-jarjar.jar
 		jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
 		TransformJarJar(ctx, jarjarFile, headerJar, j.expandJarjarRules)
-		headerJar = jarjarFile
+		jarjarHeaderJar = jarjarFile
 		if ctx.Failed() {
-			return nil
+			return nil, nil
 		}
 	}
 
-	return headerJar
+	return headerJar, jarjarHeaderJar
 }
 
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1704,8 +1791,10 @@
 
 func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	depTag := ctx.OtherModuleDependencyTag(dep)
-	// dependencies other than the static linkage are all considered crossing APEX boundary
-	return depTag == staticLibTag
+	// Dependencies other than the static linkage are all considered crossing APEX boundary
+	// Also, a dependency to an sdk member is also considered as such. This is required because
+	// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
+	return depTag == staticLibTag || j.IsInAnySdk()
 }
 
 func (j *Module) Stem() string {
@@ -1716,6 +1805,10 @@
 	return j.jacocoReportClassesFile
 }
 
+func (j *Module) IsInstallable() bool {
+	return Bool(j.properties.Installable)
+}
+
 //
 // Java libraries (.jar file)
 //
@@ -1753,7 +1846,6 @@
 	j.checkSdkVersion(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
-	j.dexpreopter.isInstallable = Bool(j.properties.Installable)
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
 	j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
 	j.compile(ctx, nil)
@@ -1834,6 +1926,15 @@
 	module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
 }
 
+var javaHeaderLibsSdkMemberType android.SdkMemberType = &headerLibrarySdkMemberType{
+	librarySdkMemberType{
+		android.SdkMemberTypeBase{
+			PropertyName: "java_header_libs",
+			SupportsSdk:  true,
+		},
+	},
+}
+
 type headerLibrarySdkMemberType struct {
 	librarySdkMemberType
 }
@@ -2393,6 +2494,14 @@
 	return nil, nil
 }
 
+func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+	depTag := ctx.OtherModuleDependencyTag(dep)
+	// dependencies other than the static linkage are all considered crossing APEX boundary
+	// Also, a dependency to an sdk member is also considered as such. This is required because
+	// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
+	return depTag == staticLibTag || j.IsInAnySdk()
+}
+
 // Add compile time check for interface implementation
 var _ android.IDEInfo = (*Import)(nil)
 var _ android.IDECustomizedModuleName = (*Import)(nil)
@@ -2493,13 +2602,16 @@
 	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
 }
 
+func (j *DexImport) IsInstallable() bool {
+	return true
+}
+
 func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(j.properties.Jars) != 1 {
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
 	}
 
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
-	j.dexpreopter.isInstallable = true
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
 
 	inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars")
diff --git a/java/java_test.go b/java/java_test.go
index 8815c09..6d972be 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -57,7 +57,15 @@
 }
 
 func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
-	return TestConfig(buildDir, env, bp, fs)
+	bp += dexpreopt.BpToolModulesForTest()
+
+	config := TestConfig(buildDir, env, bp, fs)
+
+	// Set up the global Once cache used for dexpreopt.GlobalSoongConfig, so that
+	// it doesn't create a real one, which would fail.
+	_ = dexpreopt.GlobalSoongConfigForTests(config)
+
+	return config
 }
 
 func testContext() *android.TestContext {
@@ -84,7 +92,8 @@
 
 	// Register module types and mutators from cc needed for JNI testing
 	cc.RegisterRequiredBuildComponentsForTest(ctx)
-	ctx.RegisterModuleType("ndk_prebuilt_shared_stl", cc.NdkPrebuiltSharedStlFactory)
+
+	dexpreopt.RegisterToolModulesForTest(ctx)
 
 	return ctx
 }
@@ -93,7 +102,7 @@
 	t.Helper()
 
 	pathCtx := android.PathContextForTesting(config)
-	setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+	dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
 
 	ctx.Register(config)
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -112,7 +121,7 @@
 	ctx := testContext()
 
 	pathCtx := android.PathContextForTesting(config)
-	setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+	dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
 
 	ctx.Register(config)
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -972,6 +981,65 @@
 	}
 }
 
+func TestDroidstubsWithSystemModules(t *testing.T) {
+	ctx, _ := testJava(t, `
+		droidstubs {
+		    name: "stubs-source-system-modules",
+		    srcs: [
+		        "bar-doc/*.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "source-system-modules",
+		}
+
+		java_library {
+				name: "source-jar",
+		    srcs: [
+		        "a.java",
+		    ],
+		}
+
+		java_system_modules {
+				name: "source-system-modules",
+				libs: ["source-jar"],
+		}
+
+		droidstubs {
+		    name: "stubs-prebuilt-system-modules",
+		    srcs: [
+		        "bar-doc/*.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "prebuilt-system-modules",
+		}
+
+		java_import {
+				name: "prebuilt-jar",
+				jars: ["a.jar"],
+		}
+
+		java_system_modules_import {
+				name: "prebuilt-system-modules",
+				libs: ["prebuilt-jar"],
+		}
+		`)
+
+	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-source-system-modules", "source-jar.jar")
+
+	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar")
+}
+
+func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) {
+	metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava")
+	var systemJars []string
+	for _, i := range metalavaRule.Implicits {
+		systemJars = append(systemJars, i.Base())
+	}
+	if len(systemJars) != 1 || systemJars[0] != systemJar {
+		t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
+	}
+}
+
 func TestJarGenrules(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
@@ -1112,10 +1180,10 @@
 	ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkSystemApiSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkTestApiSuffix, "android_common")
-	ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
-	ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
-	ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkTestApiSuffix, "android_common")
-	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_arm64_armv8-a")
+	ctx.ModuleForTests("foo"+sdkStubsSourceSuffix, "android_common")
+	ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkSystemApiSuffix, "android_common")
+	ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkTestApiSuffix, "android_common")
+	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
 	ctx.ModuleForTests("foo.api.public.28", "")
 	ctx.ModuleForTests("foo.api.system.28", "")
 	ctx.ModuleForTests("foo.api.test.28", "")
@@ -1367,3 +1435,59 @@
 		}
 	}
 }
+
+func TestJavaLibraryWithSystemModules(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+		    name: "lib-with-source-system-modules",
+		    srcs: [
+		        "a.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "source-system-modules",
+		}
+
+		java_library {
+				name: "source-jar",
+		    srcs: [
+		        "a.java",
+		    ],
+		}
+
+		java_system_modules {
+				name: "source-system-modules",
+				libs: ["source-jar"],
+		}
+
+		java_library {
+		    name: "lib-with-prebuilt-system-modules",
+		    srcs: [
+		        "a.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "prebuilt-system-modules",
+		}
+
+		java_import {
+				name: "prebuilt-jar",
+				jars: ["a.jar"],
+		}
+
+		java_system_modules_import {
+				name: "prebuilt-system-modules",
+				libs: ["prebuilt-jar"],
+		}
+		`)
+
+	checkBootClasspathForSystemModule(t, ctx, "lib-with-source-system-modules", "/source-jar.jar")
+
+	checkBootClasspathForSystemModule(t, ctx, "lib-with-prebuilt-system-modules", "/prebuilt-jar.jar")
+}
+
+func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, moduleName string, expectedSuffix string) {
+	javacRule := ctx.ModuleForTests(moduleName, "android_common").Rule("javac")
+	bootClasspath := javacRule.Args["bootClasspath"]
+	if strings.HasPrefix(bootClasspath, "--system ") && strings.HasSuffix(bootClasspath, expectedSuffix) {
+		t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
+	}
+}
diff --git a/java/sdk.go b/java/sdk.go
index f388358..1e60d67 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -71,6 +71,8 @@
 	sdkPublic
 	sdkSystem
 	sdkTest
+	sdkModule
+	sdkSystemServer
 	sdkPrivate
 )
 
@@ -91,6 +93,10 @@
 		return "core"
 	case sdkCorePlatform:
 		return "core_platform"
+	case sdkModule:
+		return "module"
+	case sdkSystemServer:
+		return "system_server"
 	default:
 		return "invalid"
 	}
@@ -256,6 +262,10 @@
 			kind = sdkSystem
 		case "test":
 			kind = sdkTest
+		case "module":
+			kind = sdkModule
+		case "system_server":
+			kind = sdkSystemServer
 		default:
 			return sdkSpec{sdkInvalid, sdkVersionNone, str}
 		}
@@ -319,13 +329,13 @@
 		}
 	}
 
-	toModule := func(m, r string, aidl android.Path) sdkDep {
+	toModule := func(modules []string, res string, aidl android.Path) sdkDep {
 		return sdkDep{
 			useModule:          true,
-			bootclasspath:      []string{m, config.DefaultLambdaStubsLibrary},
+			bootclasspath:      append(modules, config.DefaultLambdaStubsLibrary),
 			systemModules:      "core-current-stubs-system-modules",
-			java9Classpath:     []string{m},
-			frameworkResModule: r,
+			java9Classpath:     modules,
+			frameworkResModule: res,
 			aidl:               android.OptionalPathForPath(aidl),
 		}
 	}
@@ -375,13 +385,19 @@
 			noFrameworksLibs:   true,
 		}
 	case sdkPublic:
-		return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
+		return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
 	case sdkSystem:
-		return toModule("android_system_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
+		return toModule([]string{"android_system_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
 	case sdkTest:
-		return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
+		return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
 	case sdkCore:
-		return toModule("core.current.stubs", "", nil)
+		return toModule([]string{"core.current.stubs"}, "", nil)
+	case sdkModule:
+		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
+		return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+	case sdkSystemServer:
+		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
+		return toModule([]string{"android_module_lib_stubs_current", "services-stubs"}, "framework-res", sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw))
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index fb8ae95..a8edf1d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -33,25 +33,25 @@
 	sdkStubsLibrarySuffix = ".stubs"
 	sdkSystemApiSuffix    = ".system"
 	sdkTestApiSuffix      = ".test"
-	sdkDocsSuffix         = ".docs"
+	sdkStubsSourceSuffix  = ".stubs.source"
 	sdkXmlFileSuffix      = ".xml"
-	permissionsTemplate   = `<?xml version="1.0" encoding="utf-8"?>\n` +
+	permissionsTemplate   = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
 		`<!-- Copyright (C) 2018 The Android Open Source Project\n` +
 		`\n` +
-		`    Licensed under the Apache License, Version 2.0 (the "License");\n` +
+		`    Licensed under the Apache License, Version 2.0 (the \"License\");\n` +
 		`    you may not use this file except in compliance with the License.\n` +
 		`    You may obtain a copy of the License at\n` +
 		`\n` +
 		`        http://www.apache.org/licenses/LICENSE-2.0\n` +
 		`\n` +
 		`    Unless required by applicable law or agreed to in writing, software\n` +
-		`    distributed under the License is distributed on an "AS IS" BASIS,\n` +
+		`    distributed under the License is distributed on an \"AS IS\" BASIS,\n` +
 		`    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` +
 		`    See the License for the specific language governing permissions and\n` +
 		`    limitations under the License.\n` +
 		`-->\n` +
 		`<permissions>\n` +
-		`    <library name="%s" file="%s"/>\n` +
+		`    <library name=\"%s\" file=\"%s\"/>\n` +
 		`</permissions>\n`
 )
 
@@ -108,7 +108,7 @@
 }
 
 func (scope *apiScope) docsModuleName(baseName string) string {
-	return baseName + sdkDocsSuffix + scope.moduleSuffix
+	return baseName + sdkStubsSourceSuffix + scope.moduleSuffix
 }
 
 type apiScopes []*apiScope
@@ -249,8 +249,6 @@
 	sdkLibraryProperties sdkLibraryProperties
 
 	commonToSdkLibraryAndImport
-
-	permissionsFile android.Path
 }
 
 var _ Dependency = (*SdkLibrary)(nil)
@@ -264,17 +262,29 @@
 	}
 }
 
+var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
+
+func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
+	if dt, ok := depTag.(dependencyTag); ok {
+		return dt == xmlPermissionsFileTag
+	}
+	return false
+}
+
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
-	useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks()
 	for _, apiScope := range module.getActiveApiScopes() {
 		// Add dependencies to the stubs library
-		if useBuiltStubs {
-			ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
-		}
+		ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
 
+		// And the api file
 		ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.docsName(apiScope))
 	}
 
+	if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
+		// Add dependency to the rule for generating the xml permissions file
+		ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
+	}
+
 	module.Library.deps(ctx)
 }
 
@@ -284,8 +294,6 @@
 		module.Library.GenerateAndroidBuildActions(ctx)
 	}
 
-	module.buildPermissionsFile(ctx)
-
 	// Record the paths to the header jars of the library (stubs and impl).
 	// When this java_sdk_library is depended upon from others via "libs" property,
 	// the recorded paths will be returned depending on the link type of the caller.
@@ -313,30 +321,6 @@
 	})
 }
 
-func (module *SdkLibrary) buildPermissionsFile(ctx android.ModuleContext) {
-	xmlContent := fmt.Sprintf(permissionsTemplate, module.BaseModuleName(), module.implPath())
-	permissionsFile := android.PathForModuleOut(ctx, module.xmlFileName())
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      permissionsFile,
-		Description: "Generating " + module.BaseModuleName() + " permissions",
-		Args: map[string]string{
-			"content": xmlContent,
-		},
-	})
-
-	module.permissionsFile = permissionsFile
-}
-
-func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
-	switch tag {
-	case ".xml":
-		return android.Paths{module.permissionsFile}, nil
-	}
-	return module.Library.OutputFiles(tag)
-}
-
 func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
 	if proptools.Bool(module.sdkLibraryProperties.Api_only) {
 		return nil
@@ -397,27 +381,6 @@
 	return module.BaseModuleName()
 }
 
-// File path to the runtime implementation library
-func (module *SdkLibrary) implPath() string {
-	if apexName := module.ApexName(); apexName != "" {
-		// TODO(b/146468504): ApexName() is only a soong module name, not apex name.
-		// In most cases, this works fine. But when apex_name is set or override_apex is used
-		// this can be wrong.
-		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, module.implName())
-	}
-	partition := "system"
-	if module.SocSpecific() {
-		partition = "vendor"
-	} else if module.DeviceSpecific() {
-		partition = "odm"
-	} else if module.ProductSpecific() {
-		partition = "product"
-	} else if module.SystemExtSpecific() {
-		partition = "system_ext"
-	}
-	return "/" + partition + "/framework/" + module.implName() + ".jar"
-}
-
 // Module name of the XML file for the lib
 func (module *SdkLibrary) xmlFileName() string {
 	return module.BaseModuleName() + sdkXmlFileSuffix
@@ -458,6 +421,7 @@
 		Installable         *bool
 		Sdk_version         *string
 		System_modules      *string
+		Patch_module        *string
 		Libs                []string
 		Soc_specific        *bool
 		Device_specific     *bool
@@ -466,9 +430,6 @@
 		Compile_dex         *bool
 		Java_version        *string
 		Product_variables   struct {
-			Unbundled_build struct {
-				Enabled *bool
-			}
 			Pdk struct {
 				Enabled *bool
 			}
@@ -485,12 +446,9 @@
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
 	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.System_modules = module.Library.Module.deviceProperties.System_modules
+	props.Patch_module = module.Library.Module.properties.Patch_module
 	props.Installable = proptools.BoolPtr(false)
 	props.Libs = module.sdkLibraryProperties.Stub_only_libs
-	// Unbundled apps will use the prebult one from /prebuilts/sdk
-	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
-		props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
-	}
 	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
 	props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs
 	props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags
@@ -625,33 +583,32 @@
 
 // Creates the xml file that publicizes the runtime library
 func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
-	// creates a prebuilt_etc module to actually place the xml file under
-	// <partition>/etc/permissions
-	etcProps := struct {
+	props := struct {
 		Name                *string
-		Src                 *string
-		Sub_dir             *string
+		Lib_name            *string
 		Soc_specific        *bool
 		Device_specific     *bool
 		Product_specific    *bool
 		System_ext_specific *bool
-	}{}
-	etcProps.Name = proptools.StringPtr(module.xmlFileName())
-	etcProps.Src = proptools.StringPtr(":" + module.BaseModuleName() + "{.xml}")
-	etcProps.Sub_dir = proptools.StringPtr("permissions")
-	if module.SocSpecific() {
-		etcProps.Soc_specific = proptools.BoolPtr(true)
-	} else if module.DeviceSpecific() {
-		etcProps.Device_specific = proptools.BoolPtr(true)
-	} else if module.ProductSpecific() {
-		etcProps.Product_specific = proptools.BoolPtr(true)
-	} else if module.SystemExtSpecific() {
-		etcProps.System_ext_specific = proptools.BoolPtr(true)
+	}{
+		Name:     proptools.StringPtr(module.xmlFileName()),
+		Lib_name: proptools.StringPtr(module.BaseModuleName()),
 	}
-	mctx.CreateModule(android.PrebuiltEtcFactory, &etcProps)
+
+	if module.SocSpecific() {
+		props.Soc_specific = proptools.BoolPtr(true)
+	} else if module.DeviceSpecific() {
+		props.Device_specific = proptools.BoolPtr(true)
+	} else if module.ProductSpecific() {
+		props.Product_specific = proptools.BoolPtr(true)
+	} else if module.SystemExtSpecific() {
+		props.System_ext_specific = proptools.BoolPtr(true)
+	}
+
+	mctx.CreateModule(sdkLibraryXmlFactory, &props)
 }
 
-func (module *SdkLibrary) PrebuiltJars(ctx android.BaseModuleContext, s sdkSpec) android.Paths {
+func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) android.Paths {
 	var ver sdkVersion
 	var kind sdkKind
 	if s.usePrebuilt(ctx) {
@@ -665,7 +622,7 @@
 	}
 
 	dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String())
-	jar := filepath.Join(dir, module.BaseModuleName()+".jar")
+	jar := filepath.Join(dir, baseName+".jar")
 	jarPath := android.ExistentPathForSource(ctx, jar)
 	if !jarPath.Valid() {
 		if ctx.Config().AllowMissingDependencies() {
@@ -683,10 +640,9 @@
 	sdkVersion sdkSpec,
 	headerJars bool) android.Paths {
 
-	// If a specific numeric version has been requested or the build is explicitly configured
-	// for it then use prebuilt versions of the sdk.
-	if sdkVersion.version.isNumbered() || ctx.Config().UnbundledBuildUsePrebuiltSdks() {
-		return module.PrebuiltJars(ctx, sdkVersion)
+	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
+	if sdkVersion.version.isNumbered() {
+		return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
 	} else {
 		if !sdkVersion.specified() {
 			if headerJars {
@@ -882,7 +838,7 @@
 
 	module.AddProperties(&module.properties)
 
-	android.InitPrebuiltModule(module, &[]string{})
+	android.InitPrebuiltModule(module, &[]string{""})
 	InitJavaModule(module, android.HostAndDeviceSupported)
 
 	android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
@@ -899,6 +855,11 @@
 
 func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookContext) {
 
+	// If the build is configured to use prebuilts then force this to be preferred.
+	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
+		module.prebuilt.ForcePrefer()
+	}
+
 	for apiScope, scopeProperties := range module.scopeProperties() {
 		if len(scopeProperties.Jars) == 0 {
 			continue
@@ -914,6 +875,7 @@
 			Sdk_version         *string
 			Libs                []string
 			Jars                []string
+			Prefer              *bool
 		}{}
 
 		props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
@@ -933,6 +895,12 @@
 			props.System_ext_specific = proptools.BoolPtr(true)
 		}
 
+		// If the build should use prebuilt sdks then set prefer to true on the stubs library.
+		// That will cause the prebuilt version of the stubs to override the source version.
+		if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
+			props.Prefer = proptools.BoolPtr(true)
+		}
+
 		mctx.CreateModule(ImportFactory, &props)
 	}
 
@@ -980,6 +948,11 @@
 	ctx android.BaseModuleContext,
 	sdkVersion sdkSpec) android.Paths {
 
+	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
+	if sdkVersion.version.isNumbered() {
+		return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
+	}
+
 	var apiScope *apiScope
 	switch sdkVersion.kind {
 	case sdkSystem:
@@ -1005,3 +978,111 @@
 	// This module is just a wrapper for the stubs.
 	return module.sdkJars(ctx, sdkVersion)
 }
+
+//
+// java_sdk_library_xml
+//
+type sdkLibraryXml struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	android.ApexModuleBase
+
+	properties sdkLibraryXmlProperties
+
+	outputFilePath android.OutputPath
+	installDirPath android.InstallPath
+}
+
+type sdkLibraryXmlProperties struct {
+	// canonical name of the lib
+	Lib_name *string
+}
+
+// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
+// Not to be used directly by users. java_sdk_library internally uses this.
+func sdkLibraryXmlFactory() android.Module {
+	module := &sdkLibraryXml{}
+
+	module.AddProperties(&module.properties)
+
+	android.InitApexModule(module)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+	return module
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) SubDir() string {
+	return "permissions"
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) OutputFile() android.OutputPath {
+	return module.outputFilePath
+}
+
+// from android.ApexModule
+func (module *sdkLibraryXml) AvailableFor(what string) bool {
+	return true
+}
+
+func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// do nothing
+}
+
+// File path to the runtime implementation library
+func (module *sdkLibraryXml) implPath() string {
+	implName := proptools.String(module.properties.Lib_name)
+	if apexName := module.ApexName(); apexName != "" {
+		// TODO(b/146468504): ApexName() is only a soong module name, not apex name.
+		// In most cases, this works fine. But when apex_name is set or override_apex is used
+		// this can be wrong.
+		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName)
+	}
+	partition := "system"
+	if module.SocSpecific() {
+		partition = "vendor"
+	} else if module.DeviceSpecific() {
+		partition = "odm"
+	} else if module.ProductSpecific() {
+		partition = "product"
+	} else if module.SystemExtSpecific() {
+		partition = "system_ext"
+	}
+	return "/" + partition + "/framework/" + implName + ".jar"
+}
+
+func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	libName := proptools.String(module.properties.Lib_name)
+	xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath())
+
+	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
+		Output(module.outputFilePath)
+
+	rule.Build(pctx, ctx, "java_sdk_xml", "Permission XML")
+
+	module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
+}
+
+func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
+	if !module.IsForPlatform() {
+		return []android.AndroidMkEntries{android.AndroidMkEntries{
+			Disabled: true,
+		}}
+	}
+
+	return []android.AndroidMkEntries{android.AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(module.outputFilePath),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_TAGS", "optional")
+				entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.ToMakePath().String())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
+			},
+		},
+	}}
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 9cabd77..ea6733d 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -211,6 +211,22 @@
 			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
+		{
+			name:           "module_current",
+			properties:     `sdk_version: "module_current",`,
+			bootclasspath:  []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_module_lib_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
+		},
+		{
+			name:           "system_server_current",
+			properties:     `sdk_version: "system_server_current",`,
+			bootclasspath:  []string{"android_module_lib_stubs_current", "services-stubs", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_module_lib_stubs_current", "services-stubs"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
+		},
 	}
 
 	for _, testcase := range classpathTestcases {
diff --git a/java/system_modules.go b/java/system_modules.go
index 92297c4..47de6e3 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -31,6 +31,15 @@
 	RegisterSystemModulesBuildComponents(android.InitRegistrationContext)
 
 	pctx.SourcePathVariable("moduleInfoJavaPath", "build/soong/scripts/jars-to-module-info-java.sh")
+
+	// Register sdk member types.
+	android.RegisterSdkMemberType(&systemModulesSdkMemberType{
+		android.SdkMemberTypeBase{
+			PropertyName:         "java_system_modules",
+			SupportsSdk:          true,
+			TransitiveSdkMembers: true,
+		},
+	})
 }
 
 func RegisterSystemModulesBuildComponents(ctx android.RegistrationContext) {
@@ -66,6 +75,10 @@
 		},
 	},
 		"classpath", "outDir", "workDir")
+
+	// Dependency tag that causes the added dependencies to be added as java_header_libs
+	// to the sdk/module_exports/snapshot.
+	systemModulesLibsTag = android.DependencyTagForSdkMemberType(javaHeaderLibsSdkMemberType)
 )
 
 func TransformJarsToSystemModules(ctx android.ModuleContext, jars android.Paths) (android.Path, android.Paths) {
@@ -104,9 +117,19 @@
 	return module
 }
 
+type SystemModulesProvider interface {
+	HeaderJars() android.Paths
+	OutputDirAndDeps() (android.Path, android.Paths)
+}
+
+var _ SystemModulesProvider = (*SystemModules)(nil)
+
+var _ SystemModulesProvider = (*systemModulesImport)(nil)
+
 type SystemModules struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.SdkBase
 
 	properties SystemModulesProperties
 
@@ -122,10 +145,21 @@
 	Libs []string
 }
 
+func (system *SystemModules) HeaderJars() android.Paths {
+	return system.headerJars
+}
+
+func (system *SystemModules) OutputDirAndDeps() (android.Path, android.Paths) {
+	if system.outputDir == nil || len(system.outputDeps) == 0 {
+		panic("Missing directory for system module dependency")
+	}
+	return system.outputDir, system.outputDeps
+}
+
 func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	var jars android.Paths
 
-	ctx.VisitDirectDepsWithTag(libTag, func(module android.Module) {
+	ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
 		dep, _ := module.(Dependency)
 		jars = append(jars, dep.HeaderJars()...)
 	})
@@ -136,7 +170,7 @@
 }
 
 func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) {
-	ctx.AddVariationDependencies(nil, libTag, system.properties.Libs...)
+	ctx.AddVariationDependencies(nil, systemModulesLibsTag, system.properties.Libs...)
 }
 
 func (system *SystemModules) AndroidMk() android.AndroidMkData {
@@ -173,6 +207,7 @@
 	android.InitPrebuiltModule(module, &module.properties.Libs)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
@@ -188,3 +223,37 @@
 func (system *systemModulesImport) Prebuilt() *android.Prebuilt {
 	return &system.prebuilt
 }
+
+type systemModulesSdkMemberType struct {
+	android.SdkMemberTypeBase
+}
+
+func (mt *systemModulesSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+	mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool {
+	if _, ok := module.(*SystemModules); ok {
+		// A prebuilt system module cannot be added as a member of an sdk because the source and
+		// snapshot instances would conflict.
+		_, ok := module.(*systemModulesImport)
+		return !ok
+	}
+	return false
+}
+
+func (mt *systemModulesSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+	variants := member.Variants()
+	if len(variants) != 1 {
+		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+		for _, variant := range variants {
+			sdkModuleContext.ModuleErrorf("    %q", variant)
+		}
+	}
+	variant := variants[0]
+	systemModule := variant.(*SystemModules)
+
+	pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
+	// Add the references to the libraries that form the system module.
+	pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag())
+}
diff --git a/java/testing.go b/java/testing.go
index c409a46..5b6a39b 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -18,6 +18,7 @@
 	"fmt"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config {
@@ -52,8 +53,6 @@
 		"assets_a/a":             nil,
 		"assets_b/b":             nil,
 
-		"prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so": nil,
-
 		"prebuilts/sdk/14/public/android.jar":         nil,
 		"prebuilts/sdk/14/public/framework.aidl":      nil,
 		"prebuilts/sdk/14/system/android.jar":         nil,
@@ -122,6 +121,8 @@
 		"stubs/sources/foo/Foo.java": nil,
 	}
 
+	cc.GatherRequiredFilesForTest(mockFS)
+
 	for k, v := range fs {
 		mockFS[k] = v
 	}
@@ -146,6 +147,8 @@
 		"android_stubs_current",
 		"android_system_stubs_current",
 		"android_test_stubs_current",
+		"android_module_lib_stubs_current",
+		"services-stubs",
 		"core.current.stubs",
 		"core.platform.api.stubs",
 		"kotlin-stdlib",
diff --git a/python/tests/py-cmd_test.py b/python/tests/py-cmd_test.py
new file mode 100644
index 0000000..acda2d7
--- /dev/null
+++ b/python/tests/py-cmd_test.py
@@ -0,0 +1,78 @@
+# Copyright 2020 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import site
+import sys
+
+# This file checks the visible python state against expected values when run
+# using a prebuilt python.
+
+failed = False
+def assert_equal(what, a, b):
+    global failed
+    if a != b:
+        print("Expected %s('%s') == '%s'" % (what, a, b))
+        failed = True
+
+assert_equal("__name__", __name__, "__main__")
+assert_equal("os.path.basename(__file__)", os.path.basename(__file__), "py-cmd_test.py")
+
+if os.getenv('ARGTEST', False):
+    assert_equal("len(sys.argv)", len(sys.argv), 3)
+    assert_equal("sys.argv[1]", sys.argv[1], "arg1")
+    assert_equal("sys.argv[2]", sys.argv[2], "arg2")
+elif os.getenv('ARGTEST2', False):
+    assert_equal("len(sys.argv)", len(sys.argv), 3)
+    assert_equal("sys.argv[1]", sys.argv[1], "--arg1")
+    assert_equal("sys.argv[2]", sys.argv[2], "arg2")
+else:
+    assert_equal("len(sys.argv)", len(sys.argv), 1)
+
+if os.getenv('ARGTEST_ONLY', False):
+    if failed:
+        sys.exit(1)
+    sys.exit(0)
+
+assert_equal("__package__", __package__, None)
+assert_equal("sys.argv[0]", sys.argv[0], 'py-cmd_test.py')
+if sys.version_info[0] == 2:
+    assert_equal("basename(sys.executable)", os.path.basename(sys.executable), 'py2-cmd')
+else:
+    assert_equal("basename(sys.executable)", os.path.basename(sys.executable), 'py3-cmd')
+assert_equal("sys.exec_prefix", sys.exec_prefix, sys.executable)
+assert_equal("sys.prefix", sys.prefix, sys.executable)
+assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
+
+if sys.version_info[0] == 2:
+    assert_equal("len(sys.path)", len(sys.path), 4)
+    assert_equal("sys.path[0]", sys.path[0], os.path.dirname(__file__))
+    assert_equal("sys.path[1]", sys.path[1], "/extra")
+    assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, "internal"))
+    assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, "internal", "stdlib"))
+else:
+    assert_equal("len(sys.path)", len(sys.path), 8)
+    assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
+    assert_equal("sys.path[1]", sys.path[1], "/extra")
+    assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip'))
+    assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), '..'))
+    assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])))
+    assert_equal("sys.path[5]", sys.path[5], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload'))
+    assert_equal("sys.path[6]", sys.path[6], os.path.join(sys.executable, "internal"))
+    assert_equal("sys.path[7]", sys.path[7], os.path.join(sys.executable, "internal", "stdlib"))
+
+if failed:
+    sys.exit(1)
+
+import testpkg.pycmd_test
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index 21187ed..35941dc 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -23,8 +23,11 @@
   exit 1
 fi
 
-if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) || ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ]]; then
-  echo "Run 'm par_test par_test3' first"
+if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
+      ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ||
+      ( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) ||
+      ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
+  echo "Run 'm par_test par_test3 py2-cmd py3-cmd' first"
   exit 1
 fi
 
@@ -44,4 +47,15 @@
 
 ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 --arg1 arg2
 
+cd $(dirname ${BASH_SOURCE[0]})
+
+PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
+PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py
+
+ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
+ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
+
+ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2
+ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2
+
 echo "Passed!"
diff --git a/python/tests/testpkg/__init__.py b/python/tests/testpkg/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/tests/testpkg/__init__.py
diff --git a/python/tests/testpkg/pycmd_test.py b/python/tests/testpkg/pycmd_test.py
new file mode 100644
index 0000000..6b8a263
--- /dev/null
+++ b/python/tests/testpkg/pycmd_test.py
@@ -0,0 +1,33 @@
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+# This file checks the visible python state against expected values when run
+# via the py*-cmd prebuilts
+
+failed = False
+def assert_equal(what, a, b):
+    global failed
+    if a != b:
+        print("Expected %s('%s') == '%s'" % (what, a, b))
+        failed = True
+
+assert_equal("__name__", __name__, "testpkg.pycmd_test")
+assert_equal("basename(__file__)", os.path.basename(__file__), "pycmd_test.py")
+assert_equal("__package__", __package__, "testpkg")
+
+if failed:
+    sys.exit(1)
diff --git a/rust/config/whitelist.go b/rust/config/whitelist.go
index 7dfb002..a339050 100644
--- a/rust/config/whitelist.go
+++ b/rust/config/whitelist.go
@@ -2,6 +2,7 @@
 
 var (
 	RustAllowedPaths = []string{
+		"external/minijail",
 		"external/rust",
 		"external/crosvm",
 		"external/adhd",
diff --git a/rust/rust.go b/rust/rust.go
index e2af6f0..de6512c 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -354,11 +354,6 @@
 	return nil
 }
 
-func (mod *Module) AllStaticDeps() []string {
-	// TODO(jiyong): do this for rust?
-	return nil
-}
-
 func (mod *Module) Module() android.Module {
 	return mod
 }
@@ -623,21 +618,24 @@
 			linkFile := ccDep.OutputFile()
 			linkPath := linkPathFromFilePath(linkFile.Path())
 			libName := libNameFromFilePath(linkFile.Path())
+			depFlag := "-l" + libName
+
 			if !linkFile.Valid() {
 				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
 			}
 
 			exportDep := false
-
 			switch depTag {
 			case cc.StaticDepTag:
+				depFlag = "-lstatic=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+				depPaths.depFlags = append(depPaths.depFlags, depFlag)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
 			case cc.SharedDepTag:
+				depFlag = "-ldylib=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+				depPaths.depFlags = append(depPaths.depFlags, depFlag)
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
@@ -650,10 +648,10 @@
 			// Make sure these dependencies are propagated
 			if lib, ok := mod.compiler.(*libraryDecorator); ok && exportDep {
 				lib.linkDirs = append(lib.linkDirs, linkPath)
-				lib.depFlags = append(lib.depFlags, "-l"+libName)
+				lib.depFlags = append(lib.depFlags, depFlag)
 			} else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
 				procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
-				procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
+				procMacro.depFlags = append(procMacro.depFlags, depFlag)
 			}
 
 		}
@@ -705,13 +703,15 @@
 func linkPathFromFilePath(filepath android.Path) string {
 	return strings.Split(filepath.String(), filepath.Base())[0]
 }
+
 func libNameFromFilePath(filepath android.Path) string {
-	libName := strings.Split(filepath.Base(), filepath.Ext())[0]
+	libName := strings.TrimSuffix(filepath.Base(), filepath.Ext())
 	if strings.HasPrefix(libName, "lib") {
 		libName = libName[3:]
 	}
 	return libName
 }
+
 func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
 	ctx := &depsContext{
 		BottomUpMutatorContext: actx,
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 3be9ee7..020581d 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -22,6 +22,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -61,6 +62,8 @@
 		"libz.so":    nil,
 	}
 
+	cc.GatherRequiredFilesForTest(fs)
+
 	return android.TestArchConfig(buildDir, nil, bp, fs)
 }
 
@@ -114,13 +117,13 @@
 
 // Test that we can extract the lib name from a lib path.
 func TestLibNameFromFilePath(t *testing.T) {
-	libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+	libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so")
 	libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
 
 	libBarName := libNameFromFilePath(libBarPath)
 	libLibName := libNameFromFilePath(libLibPath)
 
-	expectedResult := "bar"
+	expectedResult := "bar.so"
 	if libBarName != expectedResult {
 		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
 	}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 4aaff9a..e848b50 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -3,7 +3,6 @@
     main: "manifest_fixer.py",
     srcs: [
         "manifest_fixer.py",
-        "manifest.py",
     ],
     version: {
         py2: {
@@ -13,6 +12,9 @@
             enabled: false,
         },
     },
+    libs: [
+        "manifest_utils",
+    ],
 }
 
 python_test_host {
@@ -21,6 +23,24 @@
     srcs: [
         "manifest_fixer_test.py",
         "manifest_fixer.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+    libs: [
+        "manifest_utils",
+    ],
+    test_suites: ["general-tests"],
+}
+
+python_library_host {
+    name: "manifest_utils",
+    srcs: [
         "manifest.py",
     ],
     version: {
@@ -31,7 +51,6 @@
             enabled: false,
         },
     },
-    test_suites: ["general-tests"],
 }
 
 python_binary_host {
@@ -39,7 +58,6 @@
     main: "manifest_check.py",
     srcs: [
         "manifest_check.py",
-        "manifest.py",
     ],
     version: {
         py2: {
@@ -49,6 +67,9 @@
             enabled: false,
         },
     },
+    libs: [
+        "manifest_utils",
+    ],
 }
 
 python_test_host {
@@ -57,7 +78,6 @@
     srcs: [
         "manifest_check_test.py",
         "manifest_check.py",
-        "manifest.py",
     ],
     version: {
         py2: {
@@ -67,6 +87,9 @@
             enabled: false,
         },
     },
+    libs: [
+        "manifest_utils",
+    ],
     test_suites: ["general-tests"],
 }
 
@@ -91,7 +114,6 @@
     main: "test_config_fixer.py",
     srcs: [
         "test_config_fixer.py",
-        "manifest.py",
     ],
     version: {
         py2: {
@@ -101,6 +123,9 @@
             enabled: false,
         },
     },
+    libs: [
+        "manifest_utils",
+    ],
 }
 
 python_test_host {
@@ -109,7 +134,6 @@
     srcs: [
         "test_config_fixer_test.py",
         "test_config_fixer.py",
-        "manifest.py",
     ],
     version: {
         py2: {
@@ -119,5 +143,8 @@
             enabled: false,
         },
     },
+    libs: [
+        "manifest_utils",
+    ],
     test_suites: ["general-tests"],
-}
\ No newline at end of file
+}
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
index 4b2c3c2..ba1109e 100755
--- a/scripts/jsonmodify.py
+++ b/scripts/jsonmodify.py
@@ -112,9 +112,10 @@
 
   if args.out:
     with open(args.out, "w") as f:
-      json.dump(obj, f, indent=2)
+      json.dump(obj, f, indent=2, separators=(',', ': '))
+      f.write('\n')
   else:
-    print(json.dumps(obj, indent=2))
+    print(json.dumps(obj, indent=2, separators=(',', ': ')))
 
 
 if __name__ == '__main__':
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 945bc18..c59732b 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -51,6 +51,9 @@
                       help='specify additional <uses-library> tag to add. android:requred is set to false')
   parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true',
                       help='manifest is for a package built against the platform')
+  parser.add_argument('--logging-parent', dest='logging_parent', default='',
+                      help=('specify logging parent as an additional <meta-data> tag. '
+                            'This value is ignored if the logging_parent meta-data tag is present.'))
   parser.add_argument('--use-embedded-dex', dest='use_embedded_dex', action='store_true',
                       help=('specify if the app wants to use embedded dex and avoid extracted,'
                             'locally compiled code. Must not conflict if already declared '
@@ -124,6 +127,52 @@
     element.setAttributeNode(target_attr)
 
 
+def add_logging_parent(doc, logging_parent_value):
+  """Add logging parent as an additional <meta-data> tag.
+
+  Args:
+    doc: The XML document. May be modified by this function.
+    logging_parent_value: A string representing the logging
+      parent value.
+  Raises:
+    RuntimeError: Invalid manifest
+  """
+  manifest = parse_manifest(doc)
+
+  logging_parent_key = 'android.content.pm.LOGGING_PARENT'
+  elems = get_children_with_tag(manifest, 'application')
+  application = elems[0] if len(elems) == 1 else None
+  if len(elems) > 1:
+    raise RuntimeError('found multiple <application> tags')
+  elif not elems:
+    application = doc.createElement('application')
+    indent = get_indent(manifest.firstChild, 1)
+    first = manifest.firstChild
+    manifest.insertBefore(doc.createTextNode(indent), first)
+    manifest.insertBefore(application, first)
+
+  indent = get_indent(application.firstChild, 2)
+
+  last = application.lastChild
+  if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+    last = None
+
+  if not find_child_with_attribute(application, 'meta-data', android_ns,
+                                   'name', logging_parent_key):
+    ul = doc.createElement('meta-data')
+    ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
+    ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
+    application.insertBefore(doc.createTextNode(indent), last)
+    application.insertBefore(ul, last)
+    last = application.lastChild
+
+  # align the closing tag with the opening tag if it's not
+  # indented
+  if last and last.nodeType != minidom.Node.TEXT_NODE:
+    indent = get_indent(application.previousSibling, 1)
+    application.appendChild(doc.createTextNode(indent))
+
+
 def add_uses_libraries(doc, new_uses_libraries, required):
   """Add additional <uses-library> tags
 
@@ -291,6 +340,9 @@
     if args.uses_non_sdk_api:
       add_uses_non_sdk_api(doc)
 
+    if args.logging_parent:
+      add_logging_parent(doc, args.logging_parent)
+
     if args.use_embedded_dex:
       add_use_embedded_dex(doc)
 
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index ea8095e..d6e7f26 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -226,6 +226,47 @@
     self.assertEqual(output, expected)
 
 
+class AddLoggingParentTest(unittest.TestCase):
+  """Unit tests for add_logging_parent function."""
+
+  def add_logging_parent_test(self, input_manifest, logging_parent=None):
+    doc = minidom.parseString(input_manifest)
+    if logging_parent:
+      manifest_fixer.add_logging_parent(doc, logging_parent)
+    output = StringIO.StringIO()
+    manifest_fixer.write_xml(output, doc)
+    return output.getvalue()
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '%s'
+      '</manifest>\n')
+
+  def uses_logging_parent(self, logging_parent=None):
+    attrs = ''
+    if logging_parent:
+      meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" '
+                   'android:value="%s"/>\n') % (logging_parent)
+      attrs += '    <application>\n        %s    </application>\n' % (meta_text)
+
+    return attrs
+
+  def test_no_logging_parent(self):
+    """Tests manifest_fixer with no logging_parent."""
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.uses_logging_parent()
+    output = self.add_logging_parent_test(manifest_input)
+    self.assertEqual(output, expected)
+
+  def test_logging_parent(self):
+    """Tests manifest_fixer with no logging_parent."""
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
+    output = self.add_logging_parent_test(manifest_input, 'FOO')
+    self.assertEqual(output, expected)
+
+
 class AddUsesLibrariesTest(unittest.TestCase):
   """Unit tests for add_uses_libraries function."""
 
diff --git a/sdk/bp.go b/sdk/bp.go
index 6936daf..c2a75e4 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -48,8 +48,7 @@
 }
 
 func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
-	set := &bpPropertySet{}
-	set.init()
+	set := newPropertySet()
 	s.AddProperty(name, set)
 	return set
 }
@@ -62,7 +61,7 @@
 	return s.tags[name]
 }
 
-func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
+func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
 	var newOrder []string
 	for _, name := range s.order {
 		value := s.properties[name]
@@ -70,7 +69,13 @@
 		var newValue interface{}
 		var newTag android.BpPropertyTag
 		if propertySet, ok := value.(*bpPropertySet); ok {
-			newValue, newTag = transformer.transformPropertySet(name, propertySet, tag)
+			var newPropertySet *bpPropertySet
+			newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
+			if newPropertySet == nil {
+				newValue = nil
+			} else {
+				newValue = newPropertySet
+			}
 		} else {
 			newValue, newTag = transformer.transformProperty(name, value, tag)
 		}
@@ -88,6 +93,16 @@
 	s.order = newOrder
 }
 
+func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
+	if newPropertySet != nil {
+		newPropertySet.transformContents(transformer)
+
+		newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
+	}
+	return newPropertySet, newTag
+}
+
 func (s *bpPropertySet) setProperty(name string, value interface{}) {
 	if s.properties[name] == nil {
 		s.AddProperty(name, value)
@@ -136,7 +151,17 @@
 	// The name will be "" for the top level property set.
 	//
 	// Returning (nil, ...) will cause the property set to be removed.
-	transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+	transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+
+	// Transform the property set, returning the new property set/tag to insert back into the
+	// parent property set (or module if this is the top level property set).
+	//
+	// This will be called after transforming the properties in the supplied set.
+	//
+	// The name will be "" for the top level property set.
+	//
+	// Returning (nil, ...) will cause the property set to be removed.
+	transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
 
 	// Transform a property, return the new value/tag to insert back into the property set.
 	//
@@ -165,7 +190,11 @@
 	return module
 }
 
-func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+func (t identityTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	return propertySet, tag
+}
+
+func (t identityTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
 	return propertySet, tag
 }
 
@@ -180,12 +209,13 @@
 func (m *bpModule) transform(transformer bpTransformer) *bpModule {
 	transformedModule := transformer.transformModule(m)
 	// Copy the contents of the returned property set into the module and then transform that.
-	transformedModule.bpPropertySet, _ = transformer.transformPropertySet("", transformedModule.bpPropertySet, nil)
-	transformedModule.bpPropertySet.transform(transformer)
+	transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
 	return transformedModule
 }
 
-type deepCopyTransformation struct{}
+type deepCopyTransformation struct {
+	identityTransformation
+}
 
 func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
 	// Take a shallow copy of the module. Any mutable property values will be copied by the
@@ -194,7 +224,7 @@
 	return &moduleCopy
 }
 
-func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+func (t deepCopyTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
 	// Create a shallow copy of the properties map. Any mutable property values will be copied by the
 	// transformer.
 	propertiesCopy := make(map[string]interface{})
@@ -253,10 +283,19 @@
 }
 
 func (f *bpFile) newModule(moduleType string) *bpModule {
+	return newModule(moduleType)
+}
+
+func newModule(moduleType string) *bpModule {
 	module := &bpModule{
 		moduleType:    moduleType,
-		bpPropertySet: &bpPropertySet{},
+		bpPropertySet: newPropertySet(),
 	}
-	module.bpPropertySet.init()
 	return module
 }
+
+func newPropertySet() *bpPropertySet {
+	set := &bpPropertySet{}
+	set.init()
+	return set
+}
diff --git a/sdk/bp_test.go b/sdk/bp_test.go
new file mode 100644
index 0000000..f89f38c
--- /dev/null
+++ b/sdk/bp_test.go
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sdk
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+type removeFredTransformation struct {
+	identityTransformation
+}
+
+func (t removeFredTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+	if name == "fred" {
+		return nil, nil
+	}
+	return value, tag
+}
+
+func (t removeFredTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if name == "fred" {
+		return nil, nil
+	}
+	return propertySet, tag
+}
+
+func (t removeFredTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if len(propertySet.properties) == 0 {
+		return nil, nil
+	}
+	return propertySet, tag
+}
+
+func TestTransformRemoveProperty(t *testing.T) {
+
+	helper := &TestHelper{t}
+
+	set := newPropertySet()
+	set.AddProperty("name", "name")
+	set.AddProperty("fred", "12")
+
+	set.transformContents(removeFredTransformation{})
+
+	contents := &generatedContents{}
+	outputPropertySet(contents, set)
+	helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\\n", contents.content.String())
+}
+
+func TestTransformRemovePropertySet(t *testing.T) {
+
+	helper := &TestHelper{t}
+
+	set := newPropertySet()
+	set.AddProperty("name", "name")
+	set.AddPropertySet("fred")
+
+	set.transformContents(removeFredTransformation{})
+
+	contents := &generatedContents{}
+	outputPropertySet(contents, set)
+	helper.AssertTrimmedStringEquals("removing property set failed", "name: \"name\",\\n", contents.content.String())
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 9a75610..ecb1da0 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -75,6 +75,7 @@
 
 		cc_library_shared {
 			name: "sdkmember",
+			system_shared_libs: [],
 		}
 
 		sdk_snapshot {
@@ -337,6 +338,68 @@
 	)
 }
 
+func TestSnapshotWithCcBinary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "mymodule_exports",
+			native_binaries: ["mynativebinary"],
+		}
+
+		cc_binary {
+			name: "mynativebinary",
+			srcs: [
+				"Test.cpp",
+			],
+			compile_multilib: "both",
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mymodule_exports", "android_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+    name: "mymodule_exports_mynativebinary@current",
+    sdk_member_name: "mynativebinary",
+    compile_multilib: "both",
+    arch: {
+        arm64: {
+            srcs: ["arm64/bin/mynativebinary"],
+        },
+        arm: {
+            srcs: ["arm/bin/mynativebinary"],
+        },
+    },
+}
+
+cc_prebuilt_binary {
+    name: "mynativebinary",
+    prefer: false,
+    compile_multilib: "both",
+    arch: {
+        arm64: {
+            srcs: ["arm64/bin/mynativebinary"],
+        },
+        arm: {
+            srcs: ["arm/bin/mynativebinary"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "mymodule_exports@current",
+    native_binaries: ["mymodule_exports_mynativebinary@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativebinary/android_arm64_armv8-a/mynativebinary -> arm64/bin/mynativebinary
+.intermediates/mynativebinary/android_arm_armv7-a-neon/mynativebinary -> arm/bin/mynativebinary
+`),
+	)
+}
+
 func TestSnapshotWithCcSharedLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
@@ -686,3 +749,199 @@
 `),
 	)
 }
+
+func TestHostSnapshotWithMultiLib64(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "myexports",
+			device_supported: false,
+			host_supported: true,
+			target: {
+				host: {
+					compile_multilib: "64",
+				},
+			},
+			native_static_libs: ["mynativelib"],
+		}
+
+		cc_library_static {
+			name: "mynativelib",
+			device_supported: false,
+			host_supported: true,
+			srcs: [
+				"Test.cpp",
+				"aidl/foo/bar/Test.aidl",
+			],
+			export_include_dirs: ["include"],
+			aidl: {
+				export_aidl_headers: true,
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "linux_glibc_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_static {
+    name: "myexports_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/mynativelib.a"],
+            export_include_dirs: ["x86_64/include_gen/mynativelib"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_static {
+    name: "mynativelib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/mynativelib.a"],
+            export_include_dirs: ["x86_64/include_gen/mynativelib"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    device_supported: false,
+    host_supported: true,
+    target: {
+        host: {
+            compile_multilib: "64",
+        },
+    },
+    native_static_libs: ["myexports_mynativelib@current"],
+}`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/mynativelib.a -> x86_64/lib/mynativelib.a
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/Test.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/BnTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/BpTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+`),
+	)
+}
+
+func TestSnapshotWithCcHeadersLibrary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_header_libs: ["mynativeheaders"],
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			export_include_dirs: ["include"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "android_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+`),
+	)
+}
+
+func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			device_supported: false,
+			host_supported: true,
+			native_header_libs: ["mynativeheaders"],
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			device_supported: false,
+			host_supported: true,
+			export_include_dirs: ["include"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    device_supported: false,
+    host_supported: true,
+    native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+`),
+	)
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 692c205..0737e5e 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -34,7 +34,7 @@
 	result := testSdkWithJava(t, `
 		sdk {
 			name: "mysdk",
-			java_header_libs: ["myjavalib"],
+			java_header_libs: ["sdkmember"],
 		}
 
 		sdk_snapshot {
@@ -47,22 +47,36 @@
 			java_header_libs: ["sdkmember_mysdk_2"],
 		}
 
-		java_import {
+		java_library {
 			name: "sdkmember",
-			prefer: false,
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
 			host_supported: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 
 		java_import {
 			name: "sdkmember_mysdk_1",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 
 		java_import {
 			name: "sdkmember_mysdk_2",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 
 		java_library {
@@ -569,3 +583,170 @@
 		checkMergeZip(".intermediates/myexports/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
 	)
 }
+
+func TestSnapshotWithJavaSystemModules(t *testing.T) {
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			java_header_libs: ["exported-system-module"],
+			java_system_modules: ["my-system-modules"],
+		}
+
+		java_system_modules {
+			name: "my-system-modules",
+			libs: ["system-module", "exported-system-module"],
+		}
+
+		java_library {
+			name: "system-module",
+			srcs: ["Test.java"],
+			sdk_version: "none",
+			system_modules: "none",
+		}
+
+		java_library {
+			name: "exported-system-module",
+			srcs: ["Test.java"],
+			sdk_version: "none",
+			system_modules: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "android_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_exported-system-module@current",
+    sdk_member_name: "exported-system-module",
+    jars: ["java/exported-system-module.jar"],
+}
+
+java_import {
+    name: "exported-system-module",
+    prefer: false,
+    jars: ["java/exported-system-module.jar"],
+}
+
+java_import {
+    name: "mysdk_system-module@current",
+    sdk_member_name: "system-module",
+    visibility: ["//visibility:private"],
+    jars: ["java/system-module.jar"],
+}
+
+java_import {
+    name: "mysdk_system-module",
+    prefer: false,
+    visibility: ["//visibility:private"],
+    jars: ["java/system-module.jar"],
+}
+
+java_system_modules_import {
+    name: "mysdk_my-system-modules@current",
+    sdk_member_name: "my-system-modules",
+    libs: [
+        "mysdk_system-module@current",
+        "mysdk_exported-system-module@current",
+    ],
+}
+
+java_system_modules_import {
+    name: "my-system-modules",
+    prefer: false,
+    libs: [
+        "mysdk_system-module",
+        "exported-system-module",
+    ],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    java_header_libs: ["mysdk_exported-system-module@current"],
+    java_system_modules: ["mysdk_my-system-modules@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/exported-system-module/android_common/turbine-combined/exported-system-module.jar -> java/exported-system-module.jar
+.intermediates/system-module/android_common/turbine-combined/system-module.jar -> java/system-module.jar
+`),
+	)
+}
+
+func TestHostSnapshotWithJavaSystemModules(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			device_supported: false,
+			host_supported: true,
+			java_system_modules: ["my-system-modules"],
+		}
+
+		java_system_modules {
+			name: "my-system-modules",
+			device_supported: false,
+			host_supported: true,
+			libs: ["system-module"],
+		}
+
+		java_library {
+			name: "system-module",
+			device_supported: false,
+			host_supported: true,
+			srcs: ["Test.java"],
+			sdk_version: "none",
+			system_modules: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_system-module@current",
+    sdk_member_name: "system-module",
+    visibility: ["//visibility:private"],
+    device_supported: false,
+    host_supported: true,
+    jars: ["java/system-module.jar"],
+}
+
+java_import {
+    name: "mysdk_system-module",
+    prefer: false,
+    visibility: ["//visibility:private"],
+    device_supported: false,
+    host_supported: true,
+    jars: ["java/system-module.jar"],
+}
+
+java_system_modules_import {
+    name: "mysdk_my-system-modules@current",
+    sdk_member_name: "my-system-modules",
+    device_supported: false,
+    host_supported: true,
+    libs: ["mysdk_system-module@current"],
+}
+
+java_system_modules_import {
+    name: "my-system-modules",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    libs: ["mysdk_system-module"],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    device_supported: false,
+    host_supported: true,
+    java_system_modules: ["mysdk_my-system-modules@current"],
+}
+`),
+		checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
+	)
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index f22763c..c194ac1 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -50,6 +50,9 @@
 	// list properties, e.g. java_libs.
 	dynamicMemberTypeListProperties interface{}
 
+	// The set of exported members.
+	exportedMembers map[string]struct{}
+
 	properties sdkProperties
 
 	snapshotFile android.OptionalPath
@@ -217,6 +220,33 @@
 	return s
 }
 
+func (s *sdk) memberListProperties() []*sdkMemberListProperty {
+	return s.dynamicSdkMemberTypes.memberListProperties
+}
+
+func (s *sdk) getExportedMembers() map[string]struct{} {
+	if s.exportedMembers == nil {
+		// Collect all the exported members.
+		s.exportedMembers = make(map[string]struct{})
+
+		for _, memberListProperty := range s.memberListProperties() {
+			names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+
+			// Every member specified explicitly in the properties is exported by the sdk.
+			for _, name := range names {
+				s.exportedMembers[name] = struct{}{}
+			}
+		}
+	}
+
+	return s.exportedMembers
+}
+
+func (s *sdk) isInternalMember(memberName string) bool {
+	_, ok := s.getExportedMembers()[memberName]
+	return !ok
+}
+
 func (s *sdk) snapshot() bool {
 	return s.properties.Snapshot
 }
@@ -290,10 +320,14 @@
 // Step 1: create dependencies from an SDK module to its members.
 func memberMutator(mctx android.BottomUpMutatorContext) {
 	if s, ok := mctx.Module().(*sdk); ok {
-		for _, memberListProperty := range s.dynamicSdkMemberTypes.memberListProperties {
-			names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
-			tag := memberListProperty.dependencyTag
-			memberListProperty.memberType.AddDependencies(mctx, tag, names)
+		if s.Enabled() {
+			for _, memberListProperty := range s.memberListProperties() {
+				names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+				if len(names) > 0 {
+					tag := memberListProperty.dependencyTag
+					memberListProperty.memberType.AddDependencies(mctx, tag, names)
+				}
+			}
 		}
 	}
 }
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index d376e59..934bdae 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -111,8 +111,14 @@
 			sdk_version: "none",
 		}
 
+		java_defaults {
+			name: "java-defaults",
+			visibility: ["//other/bar"], 
+		}
+
 		java_library {
 			name: "mypublicjavalib",
+			defaults: ["java-defaults"],
       visibility: ["//visibility:public"],
 			srcs: ["Test.java"],
 			system_modules: "none",
diff --git a/sdk/testing.go b/sdk/testing.go
index c9cc30f..7352c74 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -53,12 +53,20 @@
 		"myapex.pk8":                                 nil,
 	}
 
+	cc.GatherRequiredFilesForTest(mockFS)
+
 	for k, v := range fs {
 		mockFS[k] = v
 	}
 
 	config := android.TestArchConfig(buildDir, nil, bp, mockFS)
 
+	// Add windows as a default disable OS to test behavior when some OS variants
+	// are disabled.
+	config.Targets[android.Windows] = []android.Target{
+		{android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
+	}
+
 	ctx := android.NewTestArchContext()
 
 	// from android package
@@ -72,6 +80,7 @@
 	java.RegisterJavaBuildComponents(ctx)
 	java.RegisterAppBuildComponents(ctx)
 	java.RegisterStubsBuildComponents(ctx)
+	java.RegisterSystemModulesBuildComponents(ctx)
 
 	// from cc package
 	cc.RegisterRequiredBuildComponentsForTest(ctx)
diff --git a/sdk/update.go b/sdk/update.go
index 97bafa1..d211e80 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -105,24 +105,28 @@
 // Collect all the members.
 //
 // The members are first grouped by type and then grouped by name. The order of
-// the types is the order they are referenced in android.SdkMemberTypes. The
-// names are in order in which the dependencies were added.
-func (s *sdk) collectMembers(ctx android.ModuleContext) []*sdkMember {
+// the types is the order they are referenced in android.SdkMemberTypesRegistry.
+// The names are in the order in which the dependencies were added.
+//
+// Returns the members as well as the multilib setting to use.
+func (s *sdk) collectMembers(ctx android.ModuleContext) ([]*sdkMember, string) {
 	byType := make(map[android.SdkMemberType][]*sdkMember)
 	byName := make(map[string]*sdkMember)
 
-	ctx.VisitDirectDeps(func(m android.Module) {
-		tag := ctx.OtherModuleDependencyTag(m)
+	lib32 := false // True if any of the members have 32 bit version.
+	lib64 := false // True if any of the members have 64 bit version.
+
+	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+		tag := ctx.OtherModuleDependencyTag(child)
 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
 			memberType := memberTag.SdkMemberType()
 
 			// Make sure that the resolved module is allowed in the member list property.
-			if !memberType.IsInstance(m) {
-				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(m), memberType.SdkPropertyName())
+			if !memberType.IsInstance(child) {
+				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
 			}
 
-			name := ctx.OtherModuleName(m)
-
+			name := ctx.OtherModuleName(child)
 			member := byName[name]
 			if member == nil {
 				member = &sdkMember{memberType: memberType, name: name}
@@ -130,17 +134,51 @@
 				byType[memberType] = append(byType[memberType], member)
 			}
 
-			member.variants = append(member.variants, m.(android.SdkAware))
+			multilib := child.Target().Arch.ArchType.Multilib
+			if multilib == "lib32" {
+				lib32 = true
+			} else if multilib == "lib64" {
+				lib64 = true
+			}
+
+			// Only append new variants to the list. This is needed because a member can be both
+			// exported by the sdk and also be a transitive sdk member.
+			member.variants = appendUniqueVariants(member.variants, child.(android.SdkAware))
+
+			// If the member type supports transitive sdk members then recurse down into
+			// its dependencies, otherwise exit traversal.
+			return memberType.HasTransitiveSdkMembers()
 		}
+
+		return false
 	})
 
 	var members []*sdkMember
-	for _, memberListProperty := range s.dynamicSdkMemberTypes.memberListProperties {
+	for _, memberListProperty := range s.memberListProperties() {
 		membersOfType := byType[memberListProperty.memberType]
 		members = append(members, membersOfType...)
 	}
 
-	return members
+	// Compute the setting of multilib.
+	var multilib string
+	if lib32 && lib64 {
+		multilib = "both"
+	} else if lib32 {
+		multilib = "32"
+	} else if lib64 {
+		multilib = "64"
+	}
+
+	return members, multilib
+}
+
+func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
+	for _, v := range variants {
+		if v == newVariant {
+			return variants
+		}
+	}
+	return append(variants, newVariant)
 }
 
 // SDK directory structure
@@ -190,24 +228,31 @@
 	}
 	s.builderForTests = builder
 
-	for _, member := range s.collectMembers(ctx) {
+	members, multilib := s.collectMembers(ctx)
+	for _, member := range members {
 		member.memberType.BuildSnapshot(ctx, builder, member)
 	}
 
 	// Create a transformer that will transform an unversioned module into a versioned module.
 	unversionedToVersionedTransformer := unversionedToVersionedTransformation{builder: builder}
 
+	// Create a transformer that will transform an unversioned module by replacing any references
+	// to internal members with a unique module name and setting prefer: false.
+	unversionedTransformer := unversionedTransformation{builder: builder}
+
 	for _, unversioned := range builder.prebuiltOrder {
+		// Prune any empty property sets.
+		unversioned = unversioned.transform(pruneEmptySetTransformer{})
+
 		// Copy the unversioned module so it can be modified to make it versioned.
 		versioned := unversioned.deepCopy()
 
 		// Transform the unversioned module into a versioned one.
 		versioned.transform(unversionedToVersionedTransformer)
-
 		bpFile.AddModule(versioned)
 
-		// Set prefer: false - this is not strictly required as that is the default.
-		unversioned.insertAfter("name", "prefer", false)
+		// Transform the unversioned module to make it suitable for use in the snapshot.
+		unversioned.transform(unversionedTransformer)
 		bpFile.AddModule(unversioned)
 	}
 
@@ -229,7 +274,17 @@
 	}
 
 	addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
-	for _, memberListProperty := range s.dynamicSdkMemberTypes.memberListProperties {
+
+	// Compile_multilib defaults to both and must always be set to both on the
+	// device and so only needs to be set when targeted at the host and is neither
+	// unspecified or both.
+	if s.HostSupported() && multilib != "" && multilib != "both" {
+		targetSet := snapshotModule.AddPropertySet("target")
+		hostSet := targetSet.AddPropertySet("host")
+		hostSet.AddProperty("compile_multilib", multilib)
+	}
+
+	for _, memberListProperty := range s.memberListProperties() {
 		names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
 		if len(names) > 0 {
 			snapshotModule.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names))
@@ -285,13 +340,17 @@
 	return outputZipFile
 }
 
+type propertyTag struct {
+	name string
+}
+
+var sdkMemberReferencePropertyTag = propertyTag{"sdkMemberReferencePropertyTag"}
+
 type unversionedToVersionedTransformation struct {
 	identityTransformation
 	builder *snapshotBuilder
 }
 
-var _ bpTransformer = (*unversionedToVersionedTransformation)(nil)
-
 func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
 	// Use a versioned name for the module but remember the original name for the
 	// snapshot.
@@ -301,6 +360,52 @@
 	return module
 }
 
+func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+	if tag == sdkMemberReferencePropertyTag {
+		return t.builder.versionedSdkMemberNames(value.([]string)), tag
+	} else {
+		return value, tag
+	}
+}
+
+type unversionedTransformation struct {
+	identityTransformation
+	builder *snapshotBuilder
+}
+
+func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
+	// If the module is an internal member then use a unique name for it.
+	name := module.getValue("name").(string)
+	module.setProperty("name", t.builder.unversionedSdkMemberName(name))
+
+	// Set prefer: false - this is not strictly required as that is the default.
+	module.insertAfter("name", "prefer", false)
+
+	return module
+}
+
+func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+	if tag == sdkMemberReferencePropertyTag {
+		return t.builder.unversionedSdkMemberNames(value.([]string)), tag
+	} else {
+		return value, tag
+	}
+}
+
+type pruneEmptySetTransformer struct {
+	identityTransformation
+}
+
+var _ bpTransformer = (*pruneEmptySetTransformer)(nil)
+
+func (t pruneEmptySetTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if len(propertySet.properties) == 0 {
+		return nil, nil
+	} else {
+		return propertySet, tag
+	}
+}
+
 func generateBpContents(contents *generatedContents, bpFile *bpFile) {
 	contents.Printfln("// This is auto-generated. DO NOT EDIT.")
 	for _, bpModule := range bpFile.order {
@@ -424,11 +529,17 @@
 	m := s.bpFile.newModule(moduleType)
 	m.AddProperty("name", name)
 
-	// Extract visibility information from a member variant. All variants have the same
-	// visibility so it doesn't matter which one is used.
-	visibility := android.EffectiveVisibilityRules(s.ctx, member.Variants()[0])
-	if len(visibility) != 0 {
-		m.AddProperty("visibility", visibility)
+	if s.sdk.isInternalMember(name) {
+		// An internal member is only referenced from the sdk snapshot which is in the
+		// same package so can be marked as private.
+		m.AddProperty("visibility", []string{"//visibility:private"})
+	} else {
+		// Extract visibility information from a member variant. All variants have the same
+		// visibility so it doesn't matter which one is used.
+		visibility := android.EffectiveVisibilityRules(s.ctx, member.Variants()[0])
+		if len(visibility) != 0 {
+			m.AddProperty("visibility", visibility)
+		}
 	}
 
 	addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
@@ -447,6 +558,10 @@
 	}
 }
 
+func (s *snapshotBuilder) SdkMemberReferencePropertyTag() android.BpPropertyTag {
+	return sdkMemberReferencePropertyTag
+}
+
 // Get a versioned name appropriate for the SDK snapshot version being taken.
 func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
 	return versionedSdkMemberName(s.ctx, unversionedName, s.version)
@@ -460,6 +575,23 @@
 	return references
 }
 
+// Get an internal name unique to the sdk.
+func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string) string {
+	if s.sdk.isInternalMember(unversionedName) {
+		return s.ctx.ModuleName() + "_" + unversionedName
+	} else {
+		return unversionedName
+	}
+}
+
+func (s *snapshotBuilder) unversionedSdkMemberNames(members []string) []string {
+	var references []string = nil
+	for _, m := range members {
+		references = append(references, s.unversionedSdkMemberName(m))
+	}
+	return references
+}
+
 var _ android.SdkMember = (*sdkMember)(nil)
 
 type sdkMember struct {
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index ce404f8..65dbb22 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -144,6 +144,9 @@
 	// list of .sysprop files which defines the properties.
 	Srcs []string `android:"path"`
 
+	// If set to true, build a variant of the module for the host.  Defaults to false.
+	Host_supported *bool
+
 	// Whether public stub exists or not.
 	Public_stub *bool `blueprint:"mutated"`
 }
@@ -306,12 +309,20 @@
 	Sysprop          struct {
 		Platform *bool
 	}
-	Header_libs        []string
-	Shared_libs        []string
+	Target struct {
+		Android struct {
+			Header_libs []string
+			Shared_libs []string
+		}
+		Host struct {
+			Static_libs []string
+		}
+	}
 	Required           []string
 	Recovery           *bool
 	Recovery_available *bool
 	Vendor_available   *bool
+	Host_supported     *bool
 }
 
 type javaLibraryProperties struct {
@@ -394,10 +405,12 @@
 	ccProps.Device_specific = proptools.BoolPtr(ctx.DeviceSpecific())
 	ccProps.Product_specific = proptools.BoolPtr(ctx.ProductSpecific())
 	ccProps.Sysprop.Platform = proptools.BoolPtr(isOwnerPlatform)
-	ccProps.Header_libs = []string{"libbase_headers"}
-	ccProps.Shared_libs = []string{"liblog"}
+	ccProps.Target.Android.Header_libs = []string{"libbase_headers"}
+	ccProps.Target.Android.Shared_libs = []string{"liblog"}
+	ccProps.Target.Host.Static_libs = []string{"libbase", "liblog"}
 	ccProps.Recovery_available = m.properties.Recovery_available
 	ccProps.Vendor_available = m.properties.Vendor_available
+	ccProps.Host_supported = m.properties.Host_supported
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
 	scope := "internal"
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 7cad3da..51da222 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -161,6 +161,7 @@
 			api_packages: ["android.sysprop"],
 			property_owner: "Platform",
 			vendor_available: true,
+			host_supported: true,
 		}
 
 		sysprop_library {
@@ -244,6 +245,11 @@
 			static_libs: ["sysprop-platform", "sysprop-vendor"],
 		}
 
+		cc_library {
+			name: "libbase",
+			host_supported: true,
+		}
+
 		cc_library_headers {
 			name: "libbase_headers",
 			vendor_available: true,
@@ -256,6 +262,12 @@
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
+			host_supported: true,
+		}
+
+		cc_binary_host {
+			name: "hostbin",
+			static_libs: ["sysprop-platform"],
 		}
 
 		llndk_library {
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index c35d8b9..a46dce9 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -44,17 +44,16 @@
 	CommandDeps: []string{"$template"},
 }, "name", "template", "extraConfigs")
 
-func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool) (path android.Path, autogenPath android.WritablePath) {
+func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
 	p := getTestConfig(ctx, prop)
 	if !Bool(autoGenConfig) && p != nil {
 		return p, nil
-	} else if !android.InList("cts", testSuites) && BoolDefault(autoGenConfig, true) {
+	} else if BoolDefault(autoGenConfig, true) && (!android.InList("cts", testSuites) || testConfigTemplateProp != nil) {
 		outputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".config")
 		return nil, outputFile
 	} else {
 		// CTS modules can be used for test data, so test config files must be
-		// explicitly created using AndroidTest.xml
-		// TODO(b/112602712): remove the path check
+		// explicitly created using AndroidTest.xml or test_config_template.
 		return nil, nil
 	}
 }
@@ -130,7 +129,7 @@
 
 func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
 	testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
-	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
@@ -149,7 +148,7 @@
 
 func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string,
 	testConfigTemplateProp *string, testSuites []string, configs []Config, autoGenConfig *bool) android.Path {
-	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
@@ -164,7 +163,7 @@
 
 func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
 	testSuites []string, autoGenConfig *bool) android.Path {
-	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
@@ -184,7 +183,7 @@
 func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp *string,
 	testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
 
-	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
@@ -199,7 +198,7 @@
 
 func AutoGenRustTestConfig(ctx android.ModuleContext, name string, testConfigProp *string,
 	testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
-	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePathString := "${RustHostTestConfigTemplate}"
 		if ctx.Device() {
@@ -226,7 +225,7 @@
 
 func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
 	testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool) android.Path {
-	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		template := "${InstrumentationTestConfigTemplate}"
 		moduleTemplate := getTestConfigTemplate(ctx, testConfigTemplateProp)
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 1c4f574..36d4f04 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -237,6 +237,7 @@
 			if fi.IsDir() {
 				if err := os.Remove(old); err == nil {
 					ctx.Println("Removed directory that is no longer installed: ", old)
+					cleanEmptyDirs(ctx, filepath.Dir(old))
 				} else {
 					ctx.Println("Failed to remove directory that is no longer installed (%q): %v", old, err)
 					ctx.Println("It's recommended to run `m installclean`")
@@ -244,6 +245,7 @@
 			} else {
 				if err := os.Remove(old); err == nil {
 					ctx.Println("Removed file that is no longer installed: ", old)
+					cleanEmptyDirs(ctx, filepath.Dir(old))
 				} else if !os.IsNotExist(err) {
 					ctx.Fatalf("Failed to remove file that is no longer installed (%q): %v", old, err)
 				}
@@ -254,3 +256,16 @@
 	// Use the new list as the base for the next build
 	os.Rename(file, oldFile)
 }
+
+func cleanEmptyDirs(ctx Context, dir string) {
+	files, err := ioutil.ReadDir(dir)
+	if err != nil || len(files) > 0 {
+		return
+	}
+	if err := os.Remove(dir); err == nil {
+		ctx.Println("Removed directory that is no longer installed: ", dir)
+	} else {
+		ctx.Fatalf("Failed to remove directory that is no longer installed (%q): %v", dir, err)
+	}
+	cleanEmptyDirs(ctx, filepath.Dir(dir))
+}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 22ec1f1..0749fe3 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -142,6 +142,7 @@
 			"CCACHE_SLOPPINESS",
 			"CCACHE_BASEDIR",
 			"CCACHE_CPP2",
+			"CCACHE_DIR",
 		}, config.BuildBrokenNinjaUsesEnvVars()...)...)
 	}
 
diff --git a/vnames.go.json b/vnames.go.json
index 5842097..7ce2d4b 100644
--- a/vnames.go.json
+++ b/vnames.go.json
@@ -3,7 +3,7 @@
         "pattern": "(.*)",
         "vname": {
             "corpus": "android.googlesource.com/platform/superproject",
-            "path": "build/soong/@1@"
+            "path": "@1@"
         }
     }
 ]