Merge "Revert "Apex: add NeverAllowRule for updatable"" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 2a4653a..0621475 100644
--- a/Android.bp
+++ b/Android.bp
@@ -207,6 +207,7 @@
         "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 +233,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 +536,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/README.md b/README.md
index 3eac87b..8b028a8 100644
--- a/README.md
+++ b/README.md
@@ -421,6 +421,7 @@
     config_namespace: "acme",
     variables: ["board"],
     bool_variables: ["feature"],
+    value_variables: ["width"],
     properties: ["cflags", "srcs"],
 }
 
@@ -431,8 +432,9 @@
 ```
 
 This example describes a new `acme_cc_defaults` module type that extends the
-`cc_defaults` module type, with two additional conditionals based on variables
-`board` and `feature`, which can affect properties `cflags` and `srcs`.
+`cc_defaults` module type, with three additional conditionals based on
+variables `board`, `feature` and `width`, which can affect properties `cflags`
+and `srcs`.
 
 The values of the variables can be set from a product's `BoardConfig.mk` file:
 ```
@@ -443,6 +445,7 @@
 
 SOONG_CONFIG_acme_board := soc_a
 SOONG_CONFIG_acme_feature := true
+SOONG_CONFIG_acme_width := 200
 ```
 
 The `acme_cc_defaults` module type can be used anywhere after the definition in
@@ -471,6 +474,9 @@
         feature: {
             cflags: ["-DFEATURE"],
         },
+        width: {
+            cflags: ["-DWIDTH=%s"],
+        },
     },
 }
 
@@ -482,7 +488,7 @@
 ```
 
 With the `BoardConfig.mk` snippet above, libacme_foo would build with
-cflags "-DGENERIC -DSOC_A -DFEATURE".
+cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
 
 `soong_config_module_type` modules will work best when used to wrap defaults
 modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
diff --git a/android/androidmk.go b/android/androidmk.go
index dbf3aa8..c296a5b 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -29,7 +29,11 @@
 )
 
 func init() {
-	RegisterSingletonType("androidmk", AndroidMkSingleton)
+	RegisterAndroidMkBuildComponents(InitRegistrationContext)
+}
+
+func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
 }
 
 // Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
diff --git a/android/apex.go b/android/apex.go
index 2b5072b..9bf6fc7 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,8 @@
 	"sort"
 	"strconv"
 	"sync"
+
+	"github.com/google/blueprint"
 )
 
 const (
@@ -32,6 +34,14 @@
 	MinSdkVersion int
 }
 
+// Extracted from ApexModule to make it easier to define custom subsets of the
+// ApexModule interface and improve code navigation within the IDE.
+type DepIsInSameApex interface {
+	// DepIsInSameApex tests if the other module 'dep' is installed to the same
+	// APEX as this module
+	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+}
+
 // ApexModule is the interface that a module type is expected to implement if
 // the module has to be built differently depending on whether the module
 // is destined for an apex or not (installed to one of the regular partitions).
@@ -49,6 +59,8 @@
 // respectively.
 type ApexModule interface {
 	Module
+	DepIsInSameApex
+
 	apexModuleBase() *ApexModuleBase
 
 	// Marks that this module should be built for the specified APEXes.
@@ -88,10 +100,6 @@
 	// Tests if this module is available for the specified APEX or ":platform"
 	AvailableFor(what string) bool
 
-	// DepIsInSameApex tests if the other module 'dep' is installed to the same
-	// APEX as this module
-	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
-
 	// Returns the highest version which is <= maxSdkVersion.
 	// For example, with maxSdkVersion is 10 and versionList is [9,11]
 	// it returns 9 as string
@@ -111,6 +119,15 @@
 	Info ApexInfo `blueprint:"mutated"`
 }
 
+// Marker interface that identifies dependencies that are excluded from APEX
+// contents.
+type ExcludeFromApexContentsTag interface {
+	blueprint.DependencyTag
+
+	// Method that differentiates this interface from others.
+	ExcludeFromApexContents()
+}
+
 // Provides default implementation for the ApexModule interface. APEX-aware
 // modules are expected to include this struct and call InitApexModule().
 type ApexModuleBase struct {
@@ -126,6 +143,10 @@
 	return m
 }
 
+func (m *ApexModuleBase) ApexAvailable() []string {
+	return m.ApexProperties.Apex_available
+}
+
 func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
 	m.apexVariationsLock.Lock()
 	defer m.apexVariationsLock.Unlock()
@@ -163,7 +184,7 @@
 
 const (
 	AvailableToPlatform = "//apex_available:platform"
-	availableToAnyApex  = "//apex_available:anyapex"
+	AvailableToAnyApex  = "//apex_available:anyapex"
 )
 
 func CheckAvailableForApex(what string, apex_available []string) bool {
@@ -173,7 +194,7 @@
 		return what == AvailableToPlatform
 	}
 	return InList(what, apex_available) ||
-		(what != AvailableToPlatform && InList(availableToAnyApex, apex_available))
+		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
 }
 
 func (m *ApexModuleBase) AvailableFor(what string) bool {
@@ -199,7 +220,7 @@
 
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
 	for _, n := range m.ApexProperties.Apex_available {
-		if n == AvailableToPlatform || n == availableToAnyApex {
+		if n == AvailableToPlatform || n == AvailableToAnyApex {
 			continue
 		}
 		if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
diff --git a/android/api_levels.go b/android/api_levels.go
index 62a5fce..b6296d8 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -74,7 +74,7 @@
 			"P":     28,
 			"Q":     29,
 		}
-		for i, codename := range config.PlatformVersionCombinedCodenames() {
+		for i, codename := range config.PlatformVersionActiveCodenames() {
 			apiLevelsMap[codename] = baseApiLevel + i
 		}
 
diff --git a/android/arch.go b/android/arch.go
index 73a490d..e440486 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -596,7 +596,7 @@
 }()
 
 var (
-	osTypeList      []OsType
+	OsTypeList      []OsType
 	commonTargetMap = make(map[string]Target)
 
 	NoOsType    OsType
@@ -607,6 +607,10 @@
 	Android     = NewOsType("android", Device, false)
 	Fuchsia     = NewOsType("fuchsia", Device, false)
 
+	// A pseudo OSType for a common os variant, which is OSType agnostic and which
+	// has dependencies on all the OS variants.
+	CommonOS = NewOsType("common_os", Generic, false)
+
 	osArchTypeMap = map[OsType][]ArchType{
 		Linux:       []ArchType{X86, X86_64},
 		LinuxBionic: []ArchType{X86_64},
@@ -668,7 +672,7 @@
 
 		DefaultDisabled: defDisabled,
 	}
-	osTypeList = append(osTypeList, os)
+	OsTypeList = append(OsTypeList, os)
 
 	if _, found := commonTargetMap[name]; found {
 		panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@@ -680,7 +684,7 @@
 }
 
 func osByName(name string) OsType {
-	for _, os := range osTypeList {
+	for _, os := range OsTypeList {
 		if os.Name == name {
 			return os
 		}
@@ -746,7 +750,7 @@
 
 	var moduleOSList []OsType
 
-	for _, os := range osTypeList {
+	for _, os := range OsTypeList {
 		supportedClass := false
 		for _, osClass := range osClasses {
 			if os.Class == osClass {
@@ -775,12 +779,64 @@
 		osNames[i] = os.String()
 	}
 
-	modules := mctx.CreateVariations(osNames...)
-	for i, m := range modules {
-		m.(Module).base().commonProperties.CompileOS = moduleOSList[i]
-		m.(Module).base().setOSProperties(mctx)
+	createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+	if createCommonOSVariant {
+		// A CommonOS variant was requested so add it to the list of OS's variants to
+		// create. It needs to be added to the end because it needs to depend on the
+		// the other variants in the list returned by CreateVariations(...) and inter
+		// variant dependencies can only be created from a later variant in that list to
+		// an earlier one. That is because variants are always processed in the order in
+		// which they are returned from CreateVariations(...).
+		osNames = append(osNames, CommonOS.Name)
+		moduleOSList = append(moduleOSList, CommonOS)
 	}
 
+	modules := mctx.CreateVariations(osNames...)
+	for i, m := range modules {
+		m.base().commonProperties.CompileOS = moduleOSList[i]
+		m.base().setOSProperties(mctx)
+	}
+
+	if createCommonOSVariant {
+		// A CommonOS variant was requested so add dependencies from it (the last one in
+		// the list) to the OS type specific variants.
+		last := len(modules) - 1
+		commonOSVariant := modules[last]
+		commonOSVariant.base().commonProperties.CommonOSVariant = true
+		for _, module := range modules[0:last] {
+			// Ignore modules that are enabled. Note, this will only avoid adding
+			// dependencies on OsType variants that are explicitly disabled in their
+			// properties. The CommonOS variant will still depend on disabled variants
+			// if they are disabled afterwards, e.g. in archMutator if
+			if module.Enabled() {
+				mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
+			}
+		}
+	}
+}
+
+// Identifies the dependency from CommonOS variant to the os specific variants.
+type commonOSTag struct{ blueprint.BaseDependencyTag }
+
+var commonOsToOsSpecificVariantTag = commonOSTag{}
+
+// Get the OsType specific variants for the current CommonOS variant.
+//
+// The returned list will only contain enabled OsType specific variants of the
+// module referenced in the supplied context. An empty list is returned if there
+// are no enabled variants or the supplied context is not for an CommonOS
+// variant.
+func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
+	var variants []Module
+	mctx.VisitDirectDeps(func(m Module) {
+		if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
+			if m.Enabled() {
+				variants = append(variants, m)
+			}
+		}
+	})
+
+	return variants
 }
 
 // archMutator splits a module into a variant for each Target requested by the module.  Target selection
@@ -821,6 +877,15 @@
 	}
 
 	os := base.commonProperties.CompileOS
+	if os == CommonOS {
+		// Make sure that the target related properties are initialized for the
+		// CommonOS variant.
+		addTargetProperties(module, commonTargetMap[os.Name], nil, true)
+
+		// Do not create arch specific variants for the CommonOS variant.
+		return
+	}
+
 	osTargets := mctx.Config().Targets[os]
 	image := base.commonProperties.ImageVariation
 	// Filter NativeBridge targets unless they are explicitly supported
@@ -881,15 +946,17 @@
 
 	modules := mctx.CreateVariations(targetNames...)
 	for i, m := range modules {
-		m.(Module).base().commonProperties.CompileTarget = targets[i]
-		m.(Module).base().commonProperties.CompileMultiTargets = multiTargets
-		if i == 0 {
-			m.(Module).base().commonProperties.CompilePrimary = true
-		}
+		addTargetProperties(m, targets[i], multiTargets, i == 0)
 		m.(Module).base().setArchProperties(mctx)
 	}
 }
 
+func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
+	m.base().commonProperties.CompileTarget = target
+	m.base().commonProperties.CompileMultiTargets = multiTargets
+	m.base().commonProperties.CompilePrimary = primaryTarget
+}
+
 func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
 	switch class {
 	case Device:
@@ -1004,7 +1071,7 @@
 			"Arm_on_x86",
 			"Arm_on_x86_64",
 		}
-		for _, os := range osTypeList {
+		for _, os := range OsTypeList {
 			targets = append(targets, os.Field)
 
 			for _, archType := range osArchTypeMap[os] {
@@ -1711,6 +1778,8 @@
 	return ret
 }
 
+// Return the set of Os specific common architecture targets for each Os in a list of
+// targets.
 func getCommonTargets(targets []Target) []Target {
 	var ret []Target
 	set := make(map[string]bool)
diff --git a/android/config.go b/android/config.go
index c9d7dab..bf52c45 100644
--- a/android/config.go
+++ b/android/config.go
@@ -359,6 +359,9 @@
 		return Config{}, err
 	}
 
+	// Make the CommonOS OsType available for all products.
+	targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
+
 	var archConfig []archConfig
 	if Bool(config.Mega_device) {
 		archConfig = getMegaDeviceConfig()
@@ -570,8 +573,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
@@ -649,22 +652,6 @@
 	return c.productVariables.Platform_version_active_codenames
 }
 
-// Codenames that are available in the branch but not included in the current
-// lunch target.
-func (c *config) PlatformVersionFutureCodenames() []string {
-	return c.productVariables.Platform_version_future_codenames
-}
-
-// All possible codenames in the current branch. NB: Not named AllCodenames
-// because "all" has historically meant "active" in make, and still does in
-// build.prop.
-func (c *config) PlatformVersionCombinedCodenames() []string {
-	combined := []string{}
-	combined = append(combined, c.PlatformVersionActiveCodenames()...)
-	combined = append(combined, c.PlatformVersionFutureCodenames()...)
-	return combined
-}
-
 func (c *config) ProductAAPTConfig() []string {
 	return c.productVariables.AAPTConfig
 }
@@ -878,6 +865,13 @@
 
 func (c *config) EnforceRROForModule(name string) bool {
 	enforceList := c.productVariables.EnforceRROTargets
+	// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
+	exemptedList := c.productVariables.EnforceRROExemptedTargets
+	if exemptedList != nil {
+		if InList(name, exemptedList) {
+			return false
+		}
+	}
 	if enforceList != nil {
 		if InList("*", enforceList) {
 			return true
diff --git a/android/module.go b/android/module.go
index f668cc3..f300e05 100644
--- a/android/module.go
+++ b/android/module.go
@@ -128,10 +128,20 @@
 	// and returns a top-down dependency path from a start module to current child module.
 	GetWalkPath() []Module
 
+	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency tags path from a start module to current child module.
+	// It has one less entry than GetWalkPath() as it contains the dependency tags that
+	// exist between each adjacent pair of modules in the GetWalkPath().
+	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
+	GetTagPath() []blueprint.DependencyTag
+
 	AddMissingDependencies(missingDeps []string)
 
 	Target() Target
 	TargetPrimary() bool
+
+	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+	// responsible for creating.
 	MultiTargets() []Target
 	Arch() Arch
 	Os() OsType
@@ -215,6 +225,7 @@
 	InstallInRoot() bool
 	InstallBypassMake() bool
 	SkipInstall()
+	IsSkipInstall() bool
 	ExportedToMake() bool
 	InitRc() Paths
 	VintfFragments() Paths
@@ -360,6 +371,10 @@
 		}
 	}
 
+	// If set to true then the archMutator will create variants for each arch specific target
+	// (e.g. 32/64) that the module is required to produce. If set to false then it will only
+	// create a variant for the architecture and will list the additional arch specific targets
+	// that the variant needs to produce in the CompileMultiTargets property.
 	UseTargetVariants bool   `blueprint:"mutated"`
 	Default_multilib  string `blueprint:"mutated"`
 
@@ -438,16 +453,56 @@
 		Suffix *string `android:"arch_variant"`
 	} `android:"arch_variant"`
 
-	// Set by TargetMutator
-	CompileOS           OsType   `blueprint:"mutated"`
-	CompileTarget       Target   `blueprint:"mutated"`
+	// The OsType of artifacts that this module variant is responsible for creating.
+	//
+	// Set by osMutator
+	CompileOS OsType `blueprint:"mutated"`
+
+	// The Target of artifacts that this module variant is responsible for creating.
+	//
+	// Set by archMutator
+	CompileTarget Target `blueprint:"mutated"`
+
+	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+	// responsible for creating.
+	//
+	// By default this is nil as, where necessary, separate variants are created for the
+	// different multilib types supported and that information is encapsulated in the
+	// CompileTarget so the module variant simply needs to create artifacts for that.
+	//
+	// However, if UseTargetVariants is set to false (e.g. by
+	// InitAndroidMultiTargetsArchModule)  then no separate variants are created for the
+	// multilib targets. Instead a single variant is created for the architecture and
+	// this contains the multilib specific targets that this variant should create.
+	//
+	// Set by archMutator
 	CompileMultiTargets []Target `blueprint:"mutated"`
-	CompilePrimary      bool     `blueprint:"mutated"`
+
+	// True if the module variant's CompileTarget is the primary target
+	//
+	// Set by archMutator
+	CompilePrimary bool `blueprint:"mutated"`
 
 	// Set by InitAndroidModule
 	HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
 	ArchSpecific          bool                  `blueprint:"mutated"`
 
+	// If set to true then a CommonOS variant will be created which will have dependencies
+	// on all its OsType specific variants. Used by sdk/module_exports to create a snapshot
+	// that covers all os and architecture variants.
+	//
+	// The OsType specific variants can be retrieved by calling
+	// GetOsSpecificVariantsOfCommonOSVariant
+	//
+	// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
+	CreateCommonOSVariant bool `blueprint:"mutated"`
+
+	// If set to true then this variant is the CommonOS variant that has dependencies on its
+	// OsType specific variants.
+	//
+	// Set by osMutator.
+	CommonOSVariant bool `blueprint:"mutated"`
+
 	SkipInstall bool `blueprint:"mutated"`
 
 	NamespaceExportedToMake bool `blueprint:"mutated"`
@@ -580,6 +635,14 @@
 	m.base().commonProperties.UseTargetVariants = false
 }
 
+// As InitAndroidMultiTargetsArchModule except it creates an additional CommonOS variant that
+// has dependencies on all the OsType specific variants.
+func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
+	InitAndroidArchModule(m, hod, defaultMultilib)
+	m.base().commonProperties.UseTargetVariants = false
+	m.base().commonProperties.CreateCommonOSVariant = true
+}
+
 // A ModuleBase object contains the properties that are common to all Android
 // modules.  It should be included as an anonymous field in every module
 // struct definition.  InitAndroidModule should then be called from the module's
@@ -771,6 +834,11 @@
 	return m.commonProperties.ArchSpecific
 }
 
+// True if the current variant is a CommonOS variant, false otherwise.
+func (m *ModuleBase) IsCommonOSVariant() bool {
+	return m.commonProperties.CommonOSVariant
+}
+
 func (m *ModuleBase) OsClassSupported() []OsClass {
 	switch m.commonProperties.HostOrDeviceSupported {
 	case HostSupported:
@@ -844,7 +912,7 @@
 		// partition at "system/vendor/odm".
 		if config.OdmPath() == "odm" {
 			partition = "odm"
-		} else if strings.HasPrefix(config.OdmPath (), "vendor/") {
+		} else if strings.HasPrefix(config.OdmPath(), "vendor/") {
 			partition = "vendor"
 		}
 	} else if m.ProductSpecific() {
@@ -879,6 +947,10 @@
 	m.commonProperties.SkipInstall = true
 }
 
+func (m *ModuleBase) IsSkipInstall() bool {
+	return m.commonProperties.SkipInstall == true
+}
+
 func (m *ModuleBase) ExportedToMake() bool {
 	return m.commonProperties.NamespaceExportedToMake
 }
@@ -953,6 +1025,16 @@
 	}
 }
 
+func (m *ModuleBase) getVariationByMutatorName(mutator string) string {
+	for i, v := range m.commonProperties.DebugMutators {
+		if v == mutator {
+			return m.commonProperties.DebugVariations[i]
+		}
+	}
+
+	return ""
+}
+
 func (m *ModuleBase) InRamdisk() bool {
 	return m.base().commonProperties.ImageVariation == RamdiskVariation
 }
@@ -1131,8 +1213,11 @@
 	blueprintCtx.GetMissingDependencies()
 
 	// For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and
-	// are enabled.
-	ctx.baseModuleContext.strictVisitDeps = true
+	// are enabled. Unless the module is a CommonOS variant which may have dependencies on disabled variants
+	// (because the dependencies are added before the modules are disabled). The
+	// GetOsSpecificVariantsOfCommonOSVariant(...) method will ensure that the disabled variants are
+	// ignored.
+	ctx.baseModuleContext.strictVisitDeps = !m.IsCommonOSVariant()
 
 	if ctx.config.captureBuild {
 		ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
@@ -1308,20 +1393,25 @@
 	debug         bool
 
 	walkPath []Module
+	tagPath  []blueprint.DependencyTag
 
 	strictVisitDeps bool // If true, enforce that all dependencies are enabled
 }
 
-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) 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...)
 }
 func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
 	return b.bp.OtherModuleDependencyTag(m)
 }
-func (b *baseModuleContext) OtherModuleExists(name string) bool        { return b.bp.OtherModuleExists(name) }
-func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) }
+func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
+func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
+	return b.bp.OtherModuleType(m)
+}
 
 func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
 	return b.bp.GetDirectDepWithTag(name, tag)
@@ -1593,6 +1683,7 @@
 
 func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
 	b.walkPath = []Module{b.Module()}
+	b.tagPath = []blueprint.DependencyTag{}
 	b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
 		childAndroidModule, _ := child.(Module)
 		parentAndroidModule, _ := parent.(Module)
@@ -1600,8 +1691,10 @@
 			// record walkPath before visit
 			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
 				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+				b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
 			}
 			b.walkPath = append(b.walkPath, childAndroidModule)
+			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
 			return visit(childAndroidModule, parentAndroidModule)
 		} else {
 			return false
@@ -1613,6 +1706,10 @@
 	return b.walkPath
 }
 
+func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
+	return b.tagPath
+}
+
 func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
 	m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
 		visit(module.(Module))
diff --git a/android/mutator.go b/android/mutator.go
index a46d4be..10a815a 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -103,7 +103,7 @@
 	registerPathDepsMutator,
 	RegisterPrebuiltsPostDepsMutators,
 	RegisterVisibilityRuleEnforcer,
-	registerNeverallowMutator,
+	RegisterNeverallowMutator,
 	RegisterOverridePostDepsMutators,
 }
 
diff --git a/android/neverallow.go b/android/neverallow.go
index 8fcfb8a..4d3a16f 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -17,6 +17,7 @@
 import (
 	"path/filepath"
 	"reflect"
+	"regexp"
 	"strconv"
 	"strings"
 
@@ -41,7 +42,7 @@
 //     counts as a match
 // - it has none of the "Without" properties matched (same rules as above)
 
-func registerNeverallowMutator(ctx RegisterMutatorsContext) {
+func RegisterNeverallowMutator(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("neverallow", neverallowMutator).Parallel()
 }
 
@@ -146,7 +147,8 @@
 	rules := []Rule{
 		NeverAllow().
 			NotIn(coreLibraryProjects...).
-			With("sdk_version", "none"),
+			With("sdk_version", "none").
+			WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
 	}
 
 	return rules
@@ -213,7 +215,7 @@
 }
 
 type ValueMatcher interface {
-	test(string) bool
+	Test(string) bool
 	String() string
 }
 
@@ -221,7 +223,7 @@
 	expected string
 }
 
-func (m *equalMatcher) test(value string) bool {
+func (m *equalMatcher) Test(value string) bool {
 	return m.expected == value
 }
 
@@ -232,7 +234,7 @@
 type anyMatcher struct {
 }
 
-func (m *anyMatcher) test(value string) bool {
+func (m *anyMatcher) Test(value string) bool {
 	return true
 }
 
@@ -246,7 +248,7 @@
 	prefix string
 }
 
-func (m *startsWithMatcher) test(value string) bool {
+func (m *startsWithMatcher) Test(value string) bool {
 	return strings.HasPrefix(value, m.prefix)
 }
 
@@ -254,6 +256,18 @@
 	return ".starts-with(" + m.prefix + ")"
 }
 
+type regexMatcher struct {
+	re *regexp.Regexp
+}
+
+func (m *regexMatcher) Test(value string) bool {
+	return m.re.MatchString(value)
+}
+
+func (m *regexMatcher) String() string {
+	return ".regexp(" + m.re.String() + ")"
+}
+
 type ruleProperty struct {
 	fields  []string // e.x.: Vndk.Enabled
 	matcher ValueMatcher
@@ -457,6 +471,14 @@
 	return &startsWithMatcher{prefix}
 }
 
+func Regexp(re string) ValueMatcher {
+	r, err := regexp.Compile(re)
+	if err != nil {
+		panic(err)
+	}
+	return &regexMatcher{r}
+}
+
 // assorted utils
 
 func cleanPaths(paths []string) []string {
@@ -507,7 +529,7 @@
 		}
 
 		check := func(value string) bool {
-			return prop.matcher.test(value)
+			return prop.matcher.Test(value)
 		}
 
 		if matchValue(propertiesValue, check) {
@@ -564,6 +586,6 @@
 // Overrides the default neverallow rules for the supplied config.
 //
 // For testing only.
-func setTestNeverallowRules(config Config, testRules []Rule) {
+func SetTestNeverallowRules(config Config, testRules []Rule) {
 	config.Once(neverallowRulesKey, func() interface{} { return testRules })
 }
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 6f07a4a..83b2250 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -227,6 +227,16 @@
 		},
 	},
 	{
+		name: "sdk_version: \"none\" on android_*stubs_current stub",
+		fs: map[string][]byte{
+			"frameworks/base/Android.bp": []byte(`
+				java_library {
+					name: "android_stubs_current",
+					sdk_version: "none",
+				}`),
+		},
+	},
+	{
 		name: "sdk_version: \"none\" outside core libraries",
 		fs: map[string][]byte{
 			"Android.bp": []byte(`
@@ -259,7 +269,7 @@
 		t.Run(test.name, func(t *testing.T) {
 			// If the test has its own rules then use them instead of the default ones.
 			if test.rules != nil {
-				setTestNeverallowRules(config, test.rules)
+				SetTestNeverallowRules(config, test.rules)
 			}
 			_, errs := testNeverallow(config)
 			CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
@@ -273,7 +283,7 @@
 	ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
 	ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
 	ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
-	ctx.PostDepsMutators(registerNeverallowMutator)
+	ctx.PostDepsMutators(RegisterNeverallowMutator)
 	ctx.Register(config)
 
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
diff --git a/android/paths.go b/android/paths.go
index 66725c6..0edda38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1238,8 +1238,8 @@
 	return ret
 }
 
-func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
-	paths = append([]string{"ndk"}, paths...)
+func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
+	paths = append([]string{prefix}, paths...)
 	path, err := validatePath(paths...)
 	if err != nil {
 		reportPathError(ctx, err)
@@ -1247,6 +1247,14 @@
 	return InstallPath{basePath{path, ctx.Config(), ""}, ""}
 }
 
+func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
+	return pathForNdkOrSdkInstall(ctx, "ndk", paths)
+}
+
+func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
+	return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
+}
+
 func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
 	rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 2d16f65..82745a4 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -39,6 +39,12 @@
 // Mark this tag so dependencies that use it are excluded from visibility enforcement.
 func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {}
 
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t prebuiltDependencyTag) ExcludeFromApexContents() {}
+
+var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag
+var _ ExcludeFromApexContentsTag = PrebuiltDepTag
+
 type PrebuiltProperties struct {
 	// When prefer is set to true the prebuilt will be used instead of any source module with
 	// a matching name.
@@ -50,12 +56,9 @@
 
 type Prebuilt struct {
 	properties PrebuiltProperties
-	module     Module
-	srcs       *[]string
 
-	// Metadata for single source Prebuilt modules.
-	srcProps reflect.Value
-	srcField reflect.StructField
+	srcsSupplier     PrebuiltSrcsSupplier
+	srcsPropertyName string
 }
 
 func (p *Prebuilt) Name(name string) string {
@@ -72,31 +75,26 @@
 // preference configs. We'll want to add native support for dynamic source cases if we end up having
 // more modules like this.
 func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
-	if p.srcs != nil {
-		if len(*p.srcs) == 0 {
-			ctx.PropertyErrorf("srcs", "missing prebuilt source file")
+	if p.srcsSupplier != nil {
+		srcs := p.srcsSupplier()
+
+		if len(srcs) == 0 {
+			ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
 			return nil
 		}
 
-		if len(*p.srcs) > 1 {
-			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+		if len(srcs) > 1 {
+			ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
 			return nil
 		}
 
 		// Return the singleton source after expanding any filegroup in the
 		// sources.
-		return PathForModuleSrc(ctx, (*p.srcs)[0])
-	} else {
-		if !p.srcProps.IsValid() {
-			ctx.ModuleErrorf("prebuilt source was not set")
-		}
-		src := p.getSingleSourceFieldValue()
-		if src == "" {
-			ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
-				"missing prebuilt source file")
-			return nil
-		}
+		src := srcs[0]
 		return PathForModuleSrc(ctx, src)
+	} else {
+		ctx.ModuleErrorf("prebuilt source was not set")
+		return nil
 	}
 }
 
@@ -104,18 +102,80 @@
 	return p.properties.UsePrebuilt
 }
 
-func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+// Called to provide the srcs value for the prebuilt module.
+//
+// Return the src value or nil if it is not available.
+type PrebuiltSrcsSupplier func() []string
+
+// Initialize the module as a prebuilt module that uses the provided supplier to access the
+// prebuilt sources of the module.
+//
+// The supplier will be called multiple times and must return the same values each time it
+// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
+// as a replacement for a source module with the same name even if prefer = true.
+//
+// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
+// containing exactly one source file.
+//
+// The provided property name is used to provide helpful error messages in the event that
+// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
+func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
 	p := module.Prebuilt()
 	module.AddProperties(&p.properties)
-	p.srcs = srcs
+
+	if srcsSupplier == nil {
+		panic(fmt.Errorf("srcsSupplier must not be nil"))
+	}
+	if srcsPropertyName == "" {
+		panic(fmt.Errorf("srcsPropertyName must not be empty"))
+	}
+
+	p.srcsSupplier = srcsSupplier
+	p.srcsPropertyName = srcsPropertyName
+}
+
+func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+	if srcs == nil {
+		panic(fmt.Errorf("srcs must not be nil"))
+	}
+
+	srcsSupplier := func() []string {
+		return *srcs
+	}
+
+	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
 }
 
 func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
-	p := module.Prebuilt()
-	module.AddProperties(&p.properties)
-	p.srcProps = reflect.ValueOf(srcProps).Elem()
-	p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
-	p.checkSingleSourceProperties()
+	srcPropsValue := reflect.ValueOf(srcProps).Elem()
+	srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
+	if !srcPropsValue.IsValid() || srcStructField.Name == "" {
+		panic(fmt.Errorf("invalid single source prebuilt %+v", module))
+	}
+
+	if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
+		panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
+	}
+
+	srcFieldIndex := srcStructField.Index
+	srcPropertyName := proptools.PropertyNameForField(srcField)
+
+	srcsSupplier := func() []string {
+		value := srcPropsValue.FieldByIndex(srcFieldIndex)
+		if value.Kind() == reflect.Ptr {
+			value = value.Elem()
+		}
+		if value.Kind() != reflect.String {
+			panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
+		}
+		src := value.String()
+		if src == "" {
+			return nil
+		}
+		return []string{src}
+	}
+
+	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
 }
 
 type PrebuiltInterface interface {
@@ -152,7 +212,7 @@
 func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
-		if p.srcs == nil && !p.srcProps.IsValid() {
+		if p.srcsSupplier == nil {
 			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
 		}
 		if !p.properties.SourceExists {
@@ -191,11 +251,7 @@
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
 func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
-	if p.srcs != nil && len(*p.srcs) == 0 {
-		return false
-	}
-
-	if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
+	if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
 		return false
 	}
 
@@ -210,24 +266,3 @@
 func (p *Prebuilt) SourceExists() bool {
 	return p.properties.SourceExists
 }
-
-func (p *Prebuilt) checkSingleSourceProperties() {
-	if !p.srcProps.IsValid() || p.srcField.Name == "" {
-		panic(fmt.Errorf("invalid single source prebuilt %+v", p))
-	}
-
-	if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
-		panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
-	}
-}
-
-func (p *Prebuilt) getSingleSourceFieldValue() string {
-	value := p.srcProps.FieldByIndex(p.srcField.Index)
-	if value.Kind() == reflect.Ptr {
-		value = value.Elem()
-	}
-	if value.Kind() != reflect.String {
-		panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
-	}
-	return value.String()
-}
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 d13ad7d..2fdaf35 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -22,17 +22,30 @@
 	"github.com/google/blueprint/proptools"
 )
 
+// Extracted from SdkAware to make it easier to define custom subsets of the
+// SdkAware interface and improve code navigation within the IDE.
+//
+// In addition to its use in SdkAware this interface must also be implemented by
+// APEX to specify the SDKs required by that module and its contents. e.g. APEX
+// is expected to implement RequiredSdks() by reading its own properties like
+// `uses_sdks`.
+type RequiredSdks interface {
+	// The set of SDKs required by an APEX and its contents.
+	RequiredSdks() SdkRefs
+}
+
 // SdkAware is the interface that must be supported by any module to become a member of SDK or to be
 // built with SDK
 type SdkAware interface {
 	Module
+	RequiredSdks
+
 	sdkBase() *SdkBase
 	MakeMemberOf(sdk SdkRef)
 	IsInAnySdk() bool
 	ContainingSdk() SdkRef
 	MemberName() string
 	BuildWithSdks(sdks SdkRefs)
-	RequiredSdks() SdkRefs
 }
 
 // SdkRef refers to a version of an SDK
@@ -145,10 +158,6 @@
 	return s.properties.RequiredSdks
 }
 
-func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
-	sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
-}
-
 // InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
 // SdkBase.
 func InitSdkAwareModule(m SdkAware) {
@@ -186,9 +195,33 @@
 	// is correctly output for both versioned and unversioned prebuilts in the
 	// snapshot.
 	//
+	// "required: true" means that the property must only contain references
+	// to other members of the sdk. Passing a reference to a module that is not a
+	// member of the sdk will result in a build error.
+	//
+	// "required: false" means that the property can contain references to modules
+	// that are either members or not members of the sdk. If a reference is to a
+	// module that is a non member then the reference is left unchanged, i.e. it
+	// is not transformed as references to members are.
+	//
+	// The handling of the member names is dependent on whether it is an internal or
+	// exported member. An exported member is one whose name is specified in one of
+	// the member type specific properties. An internal member is one that is added
+	// due to being a part of an exported (or other internal) member and is not itself
+	// an exported member.
+	//
+	// Member names are handled as follows:
+	// * When creating the unversioned form of the module the name is left unchecked
+	//   unless the member is internal in which case it is transformed into an sdk
+	//   specific name, i.e. by prefixing with the sdk name.
+	//
+	// * When creating the versioned form of the module the name is transformed into
+	//   a versioned sdk specific name, i.e. by prefixing with the sdk name and
+	//   suffixing with the version.
+	//
 	// e.g.
-	// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag())
-	SdkMemberReferencePropertyTag() BpPropertyTag
+	// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
+	SdkMemberReferencePropertyTag(required bool) BpPropertyTag
 }
 
 type BpPropertyTag interface{}
@@ -295,14 +328,36 @@
 	// the module is not allowed in whichever sdk property it was added.
 	IsInstance(module Module) bool
 
-	// Build the snapshot for the SDK member
+	// Add a prebuilt module that the sdk will populate.
 	//
-	// The ModuleContext provided is for the SDK module, so information for
-	// variants in the supplied member can be accessed using the Other... methods.
+	// Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
+	// method to build the snapshot. That method is deprecated because it requires the SdkMemberType
+	// implementation to do all the word.
 	//
-	// The SdkMember is guaranteed to contain variants for which the
-	// IsInstance(Module) method returned true.
-	BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
+	// Otherwise, returning a non-nil value from this will cause the sdk module type to do the
+	// majority of the work to generate the snapshot. The sdk module code generates the snapshot
+	// as follows:
+	//
+	// * A properties struct of type SdkMemberProperties is created for each variant and
+	//   populated with information from the variant by calling PopulateFromVariant(SdkAware)
+	//   on the struct.
+	//
+	// * An additional properties struct is created into which the common properties will be
+	//   added.
+	//
+	// * The variant property structs are analysed to find exported (capitalized) fields which
+	//   have common values. Those fields are cleared and the common value added to the common
+	//   properties. A field annotated with a tag of `sdk:"keep"` will be treated as if it
+	//   was not capitalized, i.e. not optimized for common values.
+	//
+	// * The sdk module type populates the BpModule structure, creating the arch specific
+	//   structure and calls AddToPropertySet(...) on the properties struct to add the member
+	//   specific properties in the correct place in the structure.
+	//
+	AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
+
+	// Create a structure into which variant specific properties can be added.
+	CreateVariantPropertiesStruct() SdkMemberProperties
 }
 
 // Base type for SdkMemberType implementations.
@@ -389,3 +444,84 @@
 		SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
 	}
 }
+
+// Base structure for all implementations of SdkMemberProperties.
+//
+// Contains common properties that apply across many different member types. These
+// are not affected by the optimization to extract common values.
+type SdkMemberPropertiesBase struct {
+	// The number of unique os types supported by the member variants.
+	//
+	// If a member has a variant with more than one os type then it will need to differentiate
+	// the locations of any of their prebuilt files in the snapshot by os type to prevent them
+	// from colliding. See OsPrefix().
+	//
+	// This property is the same for all variants of a member and so would be optimized away
+	// if it was not explicitly kept.
+	Os_count int `sdk:"keep"`
+
+	// The os type for which these properties refer.
+	//
+	// Provided to allow a member to differentiate between os types in the locations of their
+	// prebuilt files when it supports more than one os type.
+	//
+	// This property is the same for all os type specific variants of a member and so would be
+	// optimized away if it was not explicitly kept.
+	Os OsType `sdk:"keep"`
+
+	// The setting to use for the compile_multilib property.
+	//
+	// This property is set after optimization so there is no point in trying to optimize it.
+	Compile_multilib string `sdk:"keep"`
+}
+
+// The os prefix to use for any file paths in the sdk.
+//
+// Is an empty string if the member only provides variants for a single os type, otherwise
+// is the OsType.Name.
+func (b *SdkMemberPropertiesBase) OsPrefix() string {
+	if b.Os_count == 1 {
+		return ""
+	} else {
+		return b.Os.Name
+	}
+}
+
+func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase {
+	return b
+}
+
+// Interface to be implemented on top of a structure that contains variant specific
+// information.
+//
+// Struct fields that are capitalized are examined for common values to extract. Fields
+// that are not capitalized are assumed to be arch specific.
+type SdkMemberProperties interface {
+	// Access the base structure.
+	Base() *SdkMemberPropertiesBase
+
+	// Populate this structure with information from the variant.
+	PopulateFromVariant(ctx SdkMemberContext, variant Module)
+
+	// Add the information from this structure to the property set.
+	AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
+}
+
+// Provides access to information common to a specific member.
+type SdkMemberContext interface {
+
+	// The module context of the sdk common os variant which is creating the snapshot.
+	SdkModuleContext() ModuleContext
+
+	// The builder of the snapshot.
+	SnapshotBuilder() SnapshotBuilder
+
+	// The type of the member.
+	MemberType() SdkMemberType
+
+	// The name of the member.
+	//
+	// Provided for use by sdk members to create a member specific location within the snapshot
+	// into which to copy the prebuilt files.
+	Name() string
+}
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index fa1e204..619cf86 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -73,6 +73,9 @@
 //             feature: {
 //                 cflags: ["-DFEATURE"],
 //             },
+//             width: {
+//                 cflags: ["-DWIDTH=%s"],
+//             },
 //         },
 //     }
 //
@@ -90,6 +93,7 @@
 //         config_namespace: "acme",
 //         variables: ["board"],
 //         bool_variables: ["feature"],
+//         value_variables: ["width"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -107,8 +111,9 @@
 //
 //     SOONG_CONFIG_acme_board := soc_a
 //     SOONG_CONFIG_acme_feature := true
+//     SOONG_CONFIG_acme_width := 200
 //
-// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
+// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
 func soongConfigModuleTypeImportFactory() Module {
 	module := &soongConfigModuleTypeImport{}
 
@@ -122,7 +127,10 @@
 }
 
 func (m *soongConfigModuleTypeImport) Name() string {
-	return "soong_config_module_type_import_" + soongconfig.CanonicalizeToProperty(m.properties.From)
+	// The generated name is non-deterministic, but it does not
+	// matter because this module does not emit any rules.
+	return soongconfig.CanonicalizeToProperty(m.properties.From) +
+		"soong_config_module_type_import_" + fmt.Sprintf("%p", m)
 }
 
 func (*soongConfigModuleTypeImport) Nameless()                                 {}
@@ -148,6 +156,7 @@
 //         config_namespace: "acme",
 //         variables: ["board"],
 //         bool_variables: ["feature"],
+//         value_variables: ["width"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -171,6 +180,9 @@
 //             feature: {
 //                 cflags: ["-DFEATURE"],
 //             },
+//             width: {
+//	               cflags: ["-DWIDTH=%s"],
+//             },
 //         },
 //     }
 //
@@ -189,6 +201,7 @@
 //
 //     SOONG_CONFIG_acme_board := soc_a
 //     SOONG_CONFIG_acme_feature := true
+//     SOONG_CONFIG_acme_width := 200
 //
 // Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
 func soongConfigModuleTypeFactory() Module {
@@ -349,7 +362,12 @@
 
 			AddLoadHook(module, func(ctx LoadHookContext) {
 				config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
-				for _, ps := range soongconfig.PropertiesToApply(moduleType, conditionalProps, config) {
+				newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
+				if err != nil {
+					ctx.ModuleErrorf("%s", err)
+					return
+				}
+				for _, ps := range newProps {
 					ctx.AppendProperties(ps)
 				}
 			})
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 1cf060d..f905b1a 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -45,6 +45,7 @@
 			config_namespace: "acme",
 			variables: ["board", "feature1", "FEATURE3"],
 			bool_variables: ["feature2"],
+			value_variables: ["size"],
 			properties: ["cflags", "srcs"],
 		}
 
@@ -82,6 +83,9 @@
 						cflags: ["-DSOC_B"],
 					},
 				},
+				size: {
+					cflags: ["-DSIZE=%s"],
+				},
 				feature1: {
 					cflags: ["-DFEATURE1"],
 				},
@@ -101,6 +105,7 @@
 		config.TestProductVariables.VendorVars = map[string]map[string]string{
 			"acme": map[string]string{
 				"board":    "soc_a",
+				"size":     "42",
 				"feature1": "true",
 				"feature2": "false",
 				// FEATURE3 unset
@@ -121,7 +126,7 @@
 		FailIfErrored(t, errs)
 
 		foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
-		if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
+		if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
 			t.Errorf("wanted foo cflags %q, got %q", w, g)
 		}
 	}
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 2d6063d..142a813 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -112,6 +112,10 @@
 	// the list of boolean SOONG_CONFIG variables that this module type will read
 	Bool_variables []string
 
+	// the list of SOONG_CONFIG variables that this module type will read. The value will be
+	// inserted into the properties with %s substitution.
+	Value_variables []string
+
 	// the list of properties that this module type will extend.
 	Properties []string
 }
@@ -161,6 +165,18 @@
 		})
 	}
 
+	for _, name := range props.Value_variables {
+		if name == "" {
+			return []error{fmt.Errorf("value_variables entry must not be blank")}
+		}
+
+		mt.Variables = append(mt.Variables, &valueVariable{
+			baseVariable: baseVariable{
+				variable: name,
+			},
+		})
+	}
+
 	return nil
 }
 
@@ -404,15 +420,17 @@
 
 // PropertiesToApply returns the applicable properties from a ModuleType that should be applied
 // based on SoongConfig values.
-func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) []interface{} {
+func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
 	var ret []interface{}
 	props = props.Elem().FieldByName(soongConfigProperty)
 	for i, c := range moduleType.Variables {
-		if ps := c.PropertiesToApply(config, props.Field(i)); ps != nil {
+		if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
+			return nil, err
+		} else if ps != nil {
 			ret = append(ret, ps)
 		}
 	}
-	return ret
+	return ret, nil
 }
 
 type ModuleType struct {
@@ -438,7 +456,7 @@
 
 	// PropertiesToApply should return one of the interface{} values set by initializeProperties to be applied
 	// to the module.
-	PropertiesToApply(config SoongConfig, values reflect.Value) interface{}
+	PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error)
 }
 
 type baseVariable struct {
@@ -473,14 +491,14 @@
 	}
 }
 
-func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) interface{} {
+func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
 	for j, v := range s.values {
 		if config.String(s.variable) == v {
-			return values.Field(j).Interface()
+			return values.Field(j).Interface(), nil
 		}
 	}
 
-	return nil
+	return nil, nil
 }
 
 type boolVariable struct {
@@ -495,11 +513,83 @@
 	v.Set(reflect.Zero(typ))
 }
 
-func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) interface{} {
+func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
 	if config.Bool(b.variable) {
-		return values.Interface()
+		return values.Interface(), nil
 	}
 
+	return nil, nil
+}
+
+type valueVariable struct {
+	baseVariable
+}
+
+func (s *valueVariable) variableValuesType() reflect.Type {
+	return emptyInterfaceType
+}
+
+func (s *valueVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
+	v.Set(reflect.Zero(typ))
+}
+
+func (s *valueVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
+	if !config.IsSet(s.variable) {
+		return nil, nil
+	}
+	configValue := config.String(s.variable)
+
+	propStruct := values.Elem().Elem()
+	for i := 0; i < propStruct.NumField(); i++ {
+		field := propStruct.Field(i)
+		kind := field.Kind()
+		if kind == reflect.Ptr {
+			if field.IsNil() {
+				continue
+			}
+			field = field.Elem()
+		}
+		switch kind {
+		case reflect.String:
+			err := printfIntoProperty(field, configValue)
+			if err != nil {
+				return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+			}
+		case reflect.Slice:
+			for j := 0; j < field.Len(); j++ {
+				err := printfIntoProperty(field.Index(j), configValue)
+				if err != nil {
+					return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+				}
+			}
+		case reflect.Bool:
+			// Nothing to do
+		default:
+			return nil, fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, propStruct.Type().Field(i).Name, kind)
+		}
+	}
+
+	return values.Interface(), nil
+}
+
+func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
+	s := propertyValue.String()
+
+	count := strings.Count(s, "%")
+	if count == 0 {
+		return nil
+	}
+
+	if count > 1 {
+		return fmt.Errorf("value variable properties only support a single '%%'")
+	}
+
+	if !strings.Contains(s, "%s") {
+		return fmt.Errorf("unsupported %% in value variable property")
+	}
+
+	propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, configValue)))
+
 	return nil
 }
 
diff --git a/android/testing.go b/android/testing.go
index 9aff039..90989ef 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -410,6 +410,10 @@
 
 }
 
+func SetInMakeForTests(config Config) {
+	config.inMake = true
+}
+
 func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) []AndroidMkEntries {
 	var p AndroidMkEntriesProvider
 	var ok bool
diff --git a/android/variable.go b/android/variable.go
index 06bd4ed..118e107 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -140,16 +140,14 @@
 	// 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"`
 	Platform_sdk_codename                     *string  `json:",omitempty"`
 	Platform_sdk_final                        *bool    `json:",omitempty"`
 	Platform_version_active_codenames         []string `json:",omitempty"`
-	Platform_version_future_codenames         []string `json:",omitempty"`
 	Platform_vndk_version                     *string  `json:",omitempty"`
 	Platform_systemsdk_versions               []string `json:",omitempty"`
 	Platform_security_patch                   *string  `json:",omitempty"`
@@ -189,9 +187,11 @@
 	CrossHostArch          *string `json:",omitempty"`
 	CrossHostSecondaryArch *string `json:",omitempty"`
 
-	DeviceResourceOverlays     []string `json:",omitempty"`
-	ProductResourceOverlays    []string `json:",omitempty"`
-	EnforceRROTargets          []string `json:",omitempty"`
+	DeviceResourceOverlays  []string `json:",omitempty"`
+	ProductResourceOverlays []string `json:",omitempty"`
+	EnforceRROTargets       []string `json:",omitempty"`
+	// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
+	EnforceRROExemptedTargets  []string `json:",omitempty"`
 	EnforceRROExcludedOverlays []string `json:",omitempty"`
 
 	AAPTCharacteristics *string  `json:",omitempty"`
@@ -251,7 +251,7 @@
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
-	SamplingPGO  *bool   `json:",omitempty"`
+	SamplingPGO *bool `json:",omitempty"`
 
 	NativeLineCoverage   *bool    `json:",omitempty"`
 	Native_coverage      *bool    `json:",omitempty"`
@@ -347,14 +347,13 @@
 
 func (v *productVariables) SetDefaultConfig() {
 	*v = productVariables{
-		BuildNumberFromFile: stringPtr("123456789"),
+		BuildNumberFile: stringPtr("build_number.txt"),
 
 		Platform_version_name:             stringPtr("Q"),
 		Platform_sdk_version:              intPtr(28),
 		Platform_sdk_codename:             stringPtr("Q"),
 		Platform_sdk_final:                boolPtr(false),
 		Platform_version_active_codenames: []string{"Q"},
-		Platform_version_future_codenames: []string{"Q"},
 		Platform_vndk_version:             stringPtr("Q"),
 
 		HostArch:                   stringPtr("x86_64"),
diff --git a/apex/apex.go b/apex/apex.go
index 8e3e562..82e2442 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"path"
 	"path/filepath"
+	"regexp"
 	"sort"
 	"strings"
 	"sync"
@@ -61,8 +62,26 @@
 	usesTag        = dependencyTag{name: "uses"}
 	androidAppTag  = dependencyTag{name: "androidApp", payload: true}
 	apexAvailWl    = makeApexAvailableWhitelist()
+
+	inverseApexAvailWl = invertApexWhiteList(apexAvailWl)
 )
 
+// Transform the map of apex -> modules to module -> apexes.
+func invertApexWhiteList(m map[string][]string) map[string][]string {
+	r := make(map[string][]string)
+	for apex, modules := range m {
+		for _, module := range modules {
+			r[module] = append(r[module], apex)
+		}
+	}
+	return r
+}
+
+// Retrieve the while list of apexes to which the supplied module belongs.
+func WhitelistedApexAvailable(moduleName string) []string {
+	return inverseApexAvailWl[normalizeModuleName(moduleName)]
+}
+
 // This is a map from apex to modules, which overrides the
 // apex_available setting for that particular module to make
 // it available for the apex regardless of its setting.
@@ -74,27 +93,9 @@
 	// Module separator
 	//
 	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",
@@ -105,18 +106,14 @@
 		"libpackagelistparser",
 		"libpcre2",
 		"libprocessgroup_headers",
-		"libqemu_pipe",
-		"libsystem_headers",
-		"libutils_headers",
 	}
 	//
 	// Module separator
 	//
-	m["com.android.art"] = []string{
+	artApexContents := []string{
 		"art_cmdlineparser_headers",
 		"art_disassembler_headers",
 		"art_libartbase_headers",
-		"bcm_object",
 		"bionic_libc_platform_headers",
 		"core-repackaged-icu4j",
 		"cpp-define-generator-asm-support",
@@ -125,12 +122,9 @@
 		"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",
@@ -140,15 +134,6 @@
 		"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",
@@ -161,7 +146,6 @@
 		"libicuuc_headers",
 		"libicuuc_stubdata",
 		"libjdwp_headers",
-		"liblog_headers",
 		"liblz4",
 		"liblzma",
 		"libmeminfo",
@@ -172,7 +156,6 @@
 		"libopenjdkjvmti_headers",
 		"libperfetto_client_experimental",
 		"libprocinfo",
-		"libprotobuf-cpp-lite",
 		"libunwind_llvm",
 		"libunwindstack",
 		"libv8",
@@ -187,6 +170,8 @@
 		"libziparchive",
 		"perfetto_trace_protos",
 	}
+	m["com.android.art.debug"] = artApexContents
+	m["com.android.art.release"] = artApexContents
 	//
 	// Module separator
 	//
@@ -207,13 +192,10 @@
 		"android.hidl.token@1.0-utils",
 		"avrcp-target-service",
 		"avrcp_headers",
-		"bcm_object",
 		"bluetooth-protos-lite",
 		"bluetooth.mapsapi",
 		"com.android.vcard",
 		"dnsresolver_aidl_interface-V2-java",
-		"fmtlib",
-		"guava",
 		"ipmemorystore-aidl-interfaces-V5-java",
 		"ipmemorystore-aidl-interfaces-java",
 		"internal_include_headers",
@@ -223,9 +205,6 @@
 		"libFraunhoferAAC",
 		"libaudio-a2dp-hw-utils",
 		"libaudio-hearing-aid-hw-utils",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbinder_headers",
 		"libbluetooth",
 		"libbluetooth-types",
@@ -247,38 +226,23 @@
 		"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",
 		"libudrv-uipc",
-		"libutils_headers",
 		"libz",
 		"media_plugin_headers",
 		"net-utils-services-common",
@@ -298,12 +262,8 @@
 	// Module separator
 	//
 	m["com.android.conscrypt"] = []string{
-		"bcm_object",
 		"boringssl_self_test",
-		"libc++",
-		"libcrypto",
 		"libnativehelper_header_only",
-		"libssl",
 		"unsupportedappusage",
 	}
 	//
@@ -343,44 +303,13 @@
 		"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
@@ -409,9 +338,7 @@
 		"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",
@@ -433,23 +360,14 @@
 		"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",
@@ -461,14 +379,7 @@
 		"libgui",
 		"libgui_headers",
 		"libhardware_headers",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidlmemory",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
 		"libinput",
-		"libjsoncpp",
-		"liblog_headers",
 		"liblzma",
 		"libmath",
 		"libmedia",
@@ -501,7 +412,6 @@
 		"libprocessgroup",
 		"libprocessgroup_headers",
 		"libprocinfo",
-		"libsonivox",
 		"libspeexresampler",
 		"libspeexresampler",
 		"libstagefright_esds",
@@ -516,11 +426,9 @@
 		"libstagefright_mpeg2extractor",
 		"libstagefright_mpeg2support",
 		"libsync",
-		"libsystem_headers",
 		"libui",
 		"libui_headers",
 		"libunwindstack",
-		"libutils_headers",
 		"libvibrator",
 		"libvorbisidec",
 		"libwavextractor",
@@ -562,7 +470,6 @@
 		"android.hidl.safe_union@1.0",
 		"android.hidl.token@1.0",
 		"android.hidl.token@1.0-utils",
-		"fmtlib",
 		"libEGL",
 		"libFLAC",
 		"libFLAC-config",
@@ -579,15 +486,10 @@
 		"libavcenc",
 		"libavservices_minijail",
 		"libavservices_minijail",
-		"libbacktrace",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbinder_headers",
 		"libbinderthreadstateutils",
 		"libbluetooth-types-header",
 		"libbufferhub_headers",
-		"libc++",
 		"libc_scudo",
 		"libcap",
 		"libcodec2",
@@ -627,8 +529,6 @@
 		"libcodec2_soft_vp9dec",
 		"libcodec2_soft_vp9enc",
 		"libcodec2_vndk",
-		"libcutils",
-		"libcutils_headers",
 		"libdexfile_support",
 		"libdvr_headers",
 		"libfmq",
@@ -644,15 +544,8 @@
 		"libhardware_headers",
 		"libhevcdec",
 		"libhevcenc",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidlmemory",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
 		"libion",
 		"libjpeg",
-		"libjsoncpp",
-		"liblog_headers",
 		"liblzma",
 		"libmath",
 		"libmedia_codecserviceregistrant",
@@ -691,11 +584,9 @@
 		"libstagefright_m4vh263enc",
 		"libstagefright_mp3dec",
 		"libsync",
-		"libsystem_headers",
 		"libui",
 		"libui_headers",
 		"libunwindstack",
-		"libutils_headers",
 		"libvorbisidec",
 		"libvpx",
 		"libyuv",
@@ -711,7 +602,6 @@
 		"MediaProvider",
 		"MediaProviderGoogle",
 		"fmtlib_ndk",
-		"guava",
 		"libbase_ndk",
 		"libfuse",
 		"libfuse_jni",
@@ -735,7 +625,6 @@
 		"kotlinx-coroutines-android-nodeps",
 		"kotlinx-coroutines-core",
 		"kotlinx-coroutines-core-nodeps",
-		"libprotobuf-java-lite",
 		"permissioncontroller-statsd",
 		"GooglePermissionController",
 		"PermissionController",
@@ -745,14 +634,9 @@
 	//
 	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",
@@ -766,7 +650,6 @@
 		"libc_freebsd",
 		"libc_freebsd_large_stack",
 		"libc_gdtoa",
-		"libc_headers",
 		"libc_init_dynamic",
 		"libc_init_static",
 		"libc_jemalloc_wrapper",
@@ -781,8 +664,6 @@
 		"libc_syscalls",
 		"libc_tzcode",
 		"libc_unwind_static",
-		"libcutils",
-		"libcutils_headers",
 		"libdebuggerd",
 		"libdebuggerd_common_headers",
 		"libdebuggerd_handler_core",
@@ -795,7 +676,6 @@
 		"libjemalloc5",
 		"liblinker_main",
 		"liblinker_malloc",
-		"liblog_headers",
 		"liblz4",
 		"liblzma",
 		"libprocessgroup_headers",
@@ -803,11 +683,9 @@
 		"libpropertyinfoparser",
 		"libscudo",
 		"libstdc++",
-		"libsystem_headers",
 		"libsystemproperties",
 		"libtombstoned_client_static",
 		"libunwindstack",
-		"libutils_headers",
 		"libz",
 		"libziparchive",
 	}
@@ -815,34 +693,19 @@
 	// 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",
@@ -851,28 +714,13 @@
 	// Module separator
 	//
 	m["com.android.tethering"] = []string{
-		"libbase",
-		"libc++",
 		"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",
 	}
@@ -908,20 +756,9 @@
 		"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",
@@ -949,34 +786,14 @@
 	// 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",
+	m[android.AvailableToAnyApex] = []string{
 		"libatomic",
-		"libc++_static",
-		"libc++abi",
-		"libc++demangle",
-		"libc_headers",
 		"libclang_rt",
 		"libgcc_stripped",
 		"libprofile-clang-extras",
@@ -984,22 +801,6 @@
 		"libprofile-extras",
 		"libprofile-extras_ndk",
 		"libunwind_llvm",
-		"ndk_crtbegin_dynamic.27",
-		"ndk_crtbegin_so.16",
-		"ndk_crtbegin_so.19",
-		"ndk_crtbegin_so.21",
-		"ndk_crtbegin_so.24",
-		"ndk_crtbegin_so.27",
-		"ndk_crtend_android.27",
-		"ndk_crtend_so.16",
-		"ndk_crtend_so.19",
-		"ndk_crtend_so.21",
-		"ndk_crtend_so.24",
-		"ndk_crtend_so.27",
-		"ndk_libandroid_support",
-		"ndk_libc++_static",
-		"ndk_libc++abi",
-		"ndk_libunwind",
 	}
 	return m
 }
@@ -1037,10 +838,13 @@
 // Mark the direct and transitive dependencies of apex bundles so that they
 // can be built for the apex bundles.
 func apexDepsMutator(mctx android.TopDownMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
 	var apexBundles []android.ApexInfo
 	var directDep bool
 	if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
-		apexBundles = []android.ApexInfo{android.ApexInfo{
+		apexBundles = []android.ApexInfo{{
 			ApexName:      mctx.ModuleName(),
 			MinSdkVersion: a.minSdkVersion(mctx),
 		}}
@@ -1054,22 +858,33 @@
 		return
 	}
 
-	cur := mctx.Module().(interface {
-		DepIsInSameApex(android.BaseModuleContext, android.Module) bool
-	})
+	cur := mctx.Module().(android.DepIsInSameApex)
 
 	mctx.VisitDirectDeps(func(child android.Module) {
 		depName := mctx.OtherModuleName(child)
 		if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
-			cur.DepIsInSameApex(mctx, child) {
+			(cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) {
 			android.UpdateApexDependency(apexBundles, depName, directDep)
 			am.BuildForApexes(apexBundles)
 		}
 	})
 }
 
+// If a module in an APEX depends on a module from an SDK then it needs an APEX
+// specific variant created for it. Refer to sdk.sdkDepsReplaceMutator.
+func inAnySdk(module android.Module) bool {
+	if sa, ok := module.(android.SdkAware); ok {
+		return sa.IsInAnySdk()
+	}
+
+	return false
+}
+
 // Create apex variations if a module is included in APEX(s).
 func apexMutator(mctx android.BottomUpMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
 	if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
 		am.CreateApexVariations(mctx)
 	} else if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
@@ -1107,6 +922,9 @@
 }
 
 func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
 	if ab, ok := mctx.Module().(*apexBundle); ok {
 		var variants []string
 		switch proptools.StringDefault(ab.properties.Payload_type, "image") {
@@ -1930,15 +1748,16 @@
 func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface {
 	android.Module
 	Privileged() bool
+	InstallApkName() string
 	OutputFile() android.Path
 	JacocoReportClassesFile() android.Path
 	Certificate() java.Certificate
-}, pkgName string) apexFile {
+}) apexFile {
 	appDir := "app"
 	if aapp.Privileged() {
 		appDir = "priv-app"
 	}
-	dirInApex := filepath.Join(appDir, pkgName)
+	dirInApex := filepath.Join(appDir, aapp.InstallApkName())
 	fileToCopy := aapp.OutputFile()
 	af := newApexFile(ctx, fileToCopy, aapp.Name(), dirInApex, app, aapp)
 	af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
@@ -1961,10 +1780,14 @@
 	return true
 }
 
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
+
 // Visit dependencies that contributes to the payload of this APEX
-func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
-	do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
-	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
+	ctx.WalkDeps(func(child, parent android.Module) bool {
 		am, ok := child.(android.ApexModule)
 		if !ok || !am.CanHaveApexVariants() {
 			return false
@@ -1973,22 +1796,18 @@
 		// Check for the direct dependencies that contribute to the payload
 		if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
 			if dt.payload {
-				do(ctx, parent, am, false /* externalDep */)
-				return true
+				return do(ctx, parent, am, false /* externalDep */)
 			}
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
 			return false
 		}
 
 		// Check for the indirect dependencies if it is considered as part of the APEX
 		if am.ApexName() != "" {
-			do(ctx, parent, am, false /* externalDep */)
-			return true
+			return do(ctx, parent, am, false /* externalDep */)
 		}
 
-		do(ctx, parent, am, true /* externalDep */)
-
-		// As soon as the dependency graph crosses the APEX boundary, don't go further.
-		return false
+		return do(ctx, parent, am, true /* externalDep */)
 	})
 }
 
@@ -2001,6 +1820,24 @@
 	return intVer
 }
 
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
+
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+	// Use tag's custom String() method if available.
+	if stringer, ok := tag.(fmt.Stringer); ok {
+		return stringer.String()
+	}
+
+	// Otherwise, get a default string representation of the tag's struct.
+	tagString := fmt.Sprintf("%#v", tag)
+
+	// Remove the boilerplate from BaseDependencyTag as it adds no value.
+	tagString = tagCleaner.ReplaceAllString(tagString, "")
+	return tagString
+}
+
 // Ensures that the dependencies are marked as available for this APEX
 func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
 	// Let's be practical. Availability for test, host, and the VNDK apex isn't important
@@ -2008,24 +1845,54 @@
 		return
 	}
 
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	// Coverage build adds additional dependencies for the coverage-only runtime libraries.
+	// Requiring them and their transitive depencies with apex_available is not right
+	// because they just add noise.
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || a.IsNativeCoverageNeeded(ctx) {
+		return
+	}
+
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+		if externalDep {
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
+		}
+
 		apexName := ctx.ModuleName()
 		fromName := ctx.OtherModuleName(from)
 		toName := ctx.OtherModuleName(to)
-		if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
-			return
+
+		// If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
+		// do any of its dependencies.
+		if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
 		}
-		ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", fromName, toName)
+
+		if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
+			return true
+		}
+		message := ""
+		tagPath := ctx.GetTagPath()
+		// Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf().
+		walkPath := ctx.GetWalkPath()[1:]
+		for i, m := range walkPath {
+			message = fmt.Sprintf("%s\n           via tag %s\n    -> %s", message, PrettyPrintTag(tagPath[i]), m.String())
+		}
+		ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
+		// Visit this module's dependencies to check and report any issues with their availability.
+		return true
 	})
 }
 
 // Collects the list of module names that directly or indirectly contributes to the payload of this APEX
 func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
 	a.depInfos = make(map[string]depInfo)
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if from.Name() == to.Name() {
 			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
-			return
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return !externalDep
 		}
 
 		if info, exists := a.depInfos[to.Name()]; exists {
@@ -2041,6 +1908,9 @@
 				isExternal: externalDep,
 			}
 		}
+
+		// As soon as the dependency graph crosses the APEX boundary, don't go further.
+		return !externalDep
 	})
 }
 
@@ -2117,6 +1987,9 @@
 	// TODO(jiyong) do this using walkPayloadDeps
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
 		depTag := ctx.OtherModuleDependencyTag(child)
+		if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+			return false
+		}
 		depName := ctx.OtherModuleName(child)
 		if _, isDirectDep := parent.(*apexBundle); isDirectDep {
 			switch depTag {
@@ -2165,14 +2038,13 @@
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
 				}
 			case androidAppTag:
-				pkgName := ctx.DeviceConfig().OverridePackageNameFor(depName)
 				if ap, ok := child.(*java.AndroidApp); ok {
-					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
 					return true // track transitive dependencies
 				} else if ap, ok := child.(*java.AndroidAppImport); ok {
-					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
 				} else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
-					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
 				} else {
 					ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 				}
@@ -2278,7 +2150,7 @@
 						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
 					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
-					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+					ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
 				}
 			}
 		}
@@ -2387,10 +2259,21 @@
 
 func whitelistedApexAvailable(apex, moduleName string) 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 = normalizeModuleName(moduleName)
 
+	if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+		return true
+	}
+
+	key = android.AvailableToAnyApex
+	if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+		return true
+	}
+
+	return false
+}
+
+func normalizeModuleName(moduleName string) string {
 	// 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_")
@@ -2399,17 +2282,7 @@
 		// 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
+	return moduleName
 }
 
 func newApexBundle() *apexBundle {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 80d8153..eed0d72 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -27,6 +27,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/dexpreopt"
 	"android/soong/java"
 )
 
@@ -140,6 +141,7 @@
 		"my_include":                                 nil,
 		"foo/bar/MyClass.java":                       nil,
 		"prebuilt.jar":                               nil,
+		"prebuilt.so":                                nil,
 		"vendor/foo/devkeys/test.x509.pem":           nil,
 		"vendor/foo/devkeys/test.pk8":                nil,
 		"testkey.x509.pem":                           nil,
@@ -341,7 +343,7 @@
 			apex_available: [ "myapex" ],
 		}
 
-		cc_library {
+		cc_library_shared {
 			name: "mylib2",
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
@@ -355,6 +357,16 @@
 			],
 		}
 
+		cc_prebuilt_library_shared {
+			name: "mylib2",
+			srcs: ["prebuilt.so"],
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+    }
+
 		cc_library_static {
 			name: "libstatic",
 			srcs: ["mylib.cpp"],
@@ -3401,6 +3413,7 @@
 			dex_preopt: {
 				enabled: false,
 			},
+			filename: "AwesomePrebuiltAppFooPriv.apk",
 		}
 	`)
 
@@ -3409,7 +3422,47 @@
 	copyCmds := apexRule.Args["copy_commands"]
 
 	ensureContains(t, copyCmds, "image.apex/app/AppFooPrebuilt/AppFooPrebuilt.apk")
-	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AppFooPrivPrebuilt.apk")
+	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AwesomePrebuiltAppFooPriv.apk")
+}
+
+func TestApexWithAppImportsPrefer(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			apps: [
+				"AppFoo",
+			],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		android_app {
+			name: "AppFoo",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		android_app_import {
+			name: "AppFoo",
+			apk: "AppFooPrebuilt.apk",
+			filename: "AppFooPrebuilt.apk",
+			presigned: true,
+			prefer: true,
+		}
+	`, withFiles(map[string][]byte{
+		"AppFooPrebuilt.apk": nil,
+	}))
+
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"app/AppFoo/AppFooPrebuilt.apk",
+	})
 }
 
 func TestApexWithTestHelperApp(t *testing.T) {
@@ -3477,7 +3530,7 @@
 	}`)
 }
 
-func TestApexAvailable(t *testing.T) {
+func TestApexAvailable_DirectDep(t *testing.T) {
 	// libfoo is not available to myapex, but only to otherapex
 	testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
 	apex {
@@ -3510,9 +3563,17 @@
 		system_shared_libs: [],
 		apex_available: ["otherapex"],
 	}`)
+}
 
+func TestApexAvailable_IndirectDep(t *testing.T) {
 	// libbbaz is an indirect dep
-	testApexError(t, "requires \"libbaz\" that is not available for the APEX", `
+	testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
+.*via tag apex\.dependencyTag.*"sharedLib".*
+.*-> libfoo.*link:shared.*
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbar.*link:shared.*
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbaz.*link:shared.*`, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3546,7 +3607,9 @@
 		stl: "none",
 		system_shared_libs: [],
 	}`)
+}
 
+func TestApexAvailable_InvalidApexName(t *testing.T) {
 	testApexError(t, "\"otherapex\" is not a valid module name", `
 	apex {
 		name: "myapex",
@@ -3567,7 +3630,7 @@
 		apex_available: ["otherapex"],
 	}`)
 
-	ctx, _ := testApex(t, `
+	testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3603,7 +3666,9 @@
 			versions: ["10", "20", "30"],
 		},
 	}`)
+}
 
+func TestApexAvailable_CreatedForPlatform(t *testing.T) {
 	// check that libfoo and libbar are created only for myapex, but not for the platform
 	// 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
@@ -3615,7 +3680,7 @@
 	//	ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
 	//	ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
 
-	ctx, _ = testApex(t, `
+	ctx, _ := testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3637,8 +3702,10 @@
 	// check that libfoo is created only for the platform
 	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
 	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+}
 
-	ctx, _ = testApex(t, `
+func TestApexAvailable_CreatedForApex(t *testing.T) {
+	testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3728,7 +3795,7 @@
 	copyCmds := apexRule.Args["copy_commands"]
 
 	ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
-	ensureContains(t, copyCmds, "image.apex/app/app/override_app.apk")
+	ensureContains(t, copyCmds, "image.apex/app/override_app/override_app.apk")
 
 	apexBundle := module.Module().(*apexBundle)
 	name := apexBundle.Name()
@@ -4059,6 +4126,27 @@
 	ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
 }
 
+func TestApexMutatorsDontRunIfDisabled(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		delete(config.Targets, android.Android)
+		config.AndroidCommonTarget = android.Target{}
+	})
+
+	if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) {
+		t.Errorf("Expected variants: %v, but got: %v", expected, got)
+	}
+}
+
 func TestAppBundle(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -4089,6 +4177,175 @@
 	ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
 }
 
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+	t.Helper()
+
+	bp = bp + `
+		filegroup {
+			name: "some-updatable-apex-file_contexts",
+			srcs: [
+				"system/sepolicy/apex/some-updatable-apex-file_contexts",
+			],
+		}
+	`
+	bp += cc.GatherRequiredDepsForTest(android.Android)
+	bp += java.GatherRequiredDepsForTest()
+	bp += dexpreopt.BpToolModulesForTest()
+
+	fs := map[string][]byte{
+		"a.java":                             nil,
+		"a.jar":                              nil,
+		"build/make/target/product/security": nil,
+		"apex_manifest.json":                 nil,
+		"AndroidManifest.xml":                nil,
+		"system/sepolicy/apex/some-updatable-apex-file_contexts":       nil,
+		"system/sepolicy/apex/com.android.art.something-file_contexts": nil,
+		"framework/aidl/a.aidl": nil,
+	}
+	cc.GatherRequiredFilesForTest(fs)
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("apex", BundleFactory)
+	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	cc.RegisterRequiredBuildComponentsForTest(ctx)
+	java.RegisterJavaBuildComponents(ctx)
+	java.RegisterSystemModulesBuildComponents(ctx)
+	java.RegisterAppBuildComponents(ctx)
+	java.RegisterDexpreoptBootJarsComponents(ctx)
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+	ctx.PreDepsMutators(RegisterPreDepsMutators)
+	ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+	config := android.TestArchConfig(buildDir, nil, bp, fs)
+	ctx.Register(config)
+
+	_ = dexpreopt.GlobalSoongConfigForTests(config)
+	dexpreopt.RegisterToolModulesForTest(ctx)
+	pathCtx := android.PathContextForTesting(config)
+	dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+	transformDexpreoptConfig(dexpreoptConfig)
+	dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	android.FailIfErrored(t, errs)
+
+	_, errs = ctx.PrepareBuildActions(config)
+	if errmsg == "" {
+		android.FailIfErrored(t, errs)
+	} else if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, errmsg, errs)
+		return
+	} else {
+		t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
+	}
+}
+
+func TestNoUpdatableJarsInBootImage(t *testing.T) {
+	bp := `
+		java_library {
+			name: "some-updatable-apex-lib",
+			srcs: ["a.java"],
+			apex_available: [
+				"some-updatable-apex",
+			],
+		}
+
+		java_library {
+			name: "some-platform-lib",
+			srcs: ["a.java"],
+			installable: true,
+		}
+
+		java_library {
+			name: "some-art-lib",
+			srcs: ["a.java"],
+			apex_available: [
+				"com.android.art.something",
+			],
+			hostdex: true,
+		}
+
+		apex {
+			name: "some-updatable-apex",
+			key: "some-updatable-apex.key",
+			java_libs: ["some-updatable-apex-lib"],
+		}
+
+		apex_key {
+			name: "some-updatable-apex.key",
+		}
+
+		apex {
+			name: "com.android.art.something",
+			key: "com.android.art.something.key",
+			java_libs: ["some-art-lib"],
+		}
+
+		apex_key {
+			name: "com.android.art.something.key",
+		}
+	`
+
+	var error string
+	var transform func(*dexpreopt.GlobalConfig)
+
+	// updatable jar from ART apex in the ART boot image => ok
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"some-art-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, "", bp, transform)
+
+	// updatable jar from ART apex in the framework boot image => error
+	error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"some-art-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// updatable jar from some other apex in the ART boot image => error
+	error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"some-updatable-apex-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// updatable jar from some other apex in the framework boot image => error
+	error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"some-updatable-apex-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// nonexistent jar in the ART boot image => error
+	error = "failed to find a dex jar path for module 'nonexistent'"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"nonexistent"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// nonexistent jar in the framework boot image => error
+	error = "failed to find a dex jar path for module 'nonexistent'"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"nonexistent"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// platform jar in the ART boot image => error
+	error = "module 'some-platform-lib' is part of the platform and not allowed in the ART boot image"
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.ArtApexJars = []string{"some-platform-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+	// platform jar in the framework boot image => ok
+	transform = func(config *dexpreopt.GlobalConfig) {
+		config.BootJars = []string{"some-platform-lib"}
+	}
+	testNoUpdatableJarsInBootImage(t, "", bp, transform)
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 1fc2233..f84d426 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -219,14 +219,18 @@
 func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
 	var noticeFiles android.Paths
 
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if externalDep {
-			return
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
 		}
+
 		notice := to.NoticeFile()
 		if notice.Valid() {
 			noticeFiles = append(noticeFiles, notice.Path())
 		}
+
+		return true
 	})
 
 	if len(noticeFiles) == 0 {
diff --git a/apex/vndk.go b/apex/vndk.go
index 2a0d5b0..f948d76 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -121,10 +122,13 @@
 	// When all hard-coded references are fixed, remove symbolic links
 	// Note that  we should keep following symlinks for older VNDKs (<=29)
 	// Since prebuilt vndk libs still depend on system/lib/vndk path
-	if strings.HasPrefix(name, vndkApexName) {
-		vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
-		if strings.HasPrefix(name, vndkApexNamePrefix) {
-			vndkVersion = strings.TrimPrefix(name, vndkApexNamePrefix)
+	if strings.HasPrefix(name, vndkApexNamePrefix) {
+		vndkVersion := strings.TrimPrefix(name, vndkApexNamePrefix)
+		if numVer, err := strconv.Atoi(vndkVersion); err != nil {
+			ctx.ModuleErrorf("apex_vndk should be named as %v<ver:number>: %s", vndkApexNamePrefix, name)
+			return
+		} else if numVer > android.SdkVersion_Android10 {
+			return
 		}
 		// the name of vndk apex is formatted "com.android.vndk.v" + version
 		apexName := vndkApexNamePrefix + vndkVersion
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ef695b0..1c90aaf 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -248,6 +248,10 @@
 			entries.SubName = "." + library.stubsVersion()
 		}
 		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			// Note library.skipInstall() has a special case to get here for static
+			// libraries that otherwise would have skipped installation and hence not
+			// have executed AndroidMkEntries at all. The reason is to ensure they get
+			// a NOTICE file make target which other libraries might depend on.
 			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 			if library.buildStubs() {
 				entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 53bc065..9b3235c 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -63,49 +63,12 @@
 	return false
 }
 
-func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	info := mt.organizeVariants(member)
-	buildSharedNativeBinarySnapshot(info, builder, member)
+func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
 }
 
-// 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")
-	pbm.AddProperty("compile_multilib", "both")
-	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))
-	}
+func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &nativeBinaryInfoProperties{}
 }
 
 const (
@@ -114,7 +77,7 @@
 
 // path to the native binary. Relative to <sdk_root>/<api_dir>
 func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
-	return filepath.Join(lib.archType,
+	return filepath.Join(lib.OsPrefix(), lib.archType,
 		nativeBinaryDir, lib.outputFile.Base())
 }
 
@@ -123,8 +86,7 @@
 // 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
+	android.SdkMemberPropertiesBase
 
 	// archType is not exported as if set (to a non default value) it is always arch specific.
 	// This is "" for common properties.
@@ -132,12 +94,50 @@
 
 	// outputFile is not exported as it is always arch specific.
 	outputFile android.Path
+
+	// The set of shared libraries
+	//
+	// This field is exported as its contents may not be arch specific.
+	SharedLibs []string
+
+	// The set of system shared libraries
+	//
+	// This field is exported as its contents may not be arch specific.
+	SystemSharedLibs []string
 }
 
-// nativeBinaryInfo represents a collection of arch-specific modules having the same name
-type nativeBinaryInfo struct {
-	name                  string
-	memberType            *binarySdkMemberType
-	archVariantProperties []nativeBinaryInfoProperties
-	commonProperties      nativeBinaryInfoProperties
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	ccModule := variant.(*Module)
+
+	p.archType = ccModule.Target().Arch.ArchType.String()
+	p.outputFile = ccModule.OutputFile().Path()
+
+	if ccModule.linker != nil {
+		specifiedDeps := specifiedDeps{}
+		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+		p.SharedLibs = specifiedDeps.sharedLibs
+		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+	}
+}
+
+func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if p.Compile_multilib != "" {
+		propertySet.AddProperty("compile_multilib", p.Compile_multilib)
+	}
+
+	builder := ctx.SnapshotBuilder()
+	if p.outputFile != nil {
+		propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
+
+		builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
+	}
+
+	if len(p.SharedLibs) > 0 {
+		propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
+	}
+
+	if len(p.SystemSharedLibs) > 0 {
+		propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+	}
 }
diff --git a/cc/builder.go b/cc/builder.go
index 136263b..e09dc55 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -293,7 +293,7 @@
 	rsFlags       string
 	toolchain     config.Toolchain
 	tidy          bool
-	coverage      bool
+	gcovCoverage  bool
 	sAbiDump      bool
 	emitXrefs     bool
 
@@ -355,7 +355,7 @@
 		tidyFiles = make(android.Paths, 0, len(srcFiles))
 	}
 	var coverageFiles android.Paths
-	if flags.coverage {
+	if flags.gcovCoverage {
 		coverageFiles = make(android.Paths, 0, len(srcFiles))
 	}
 	var kytheFiles android.Paths
@@ -456,7 +456,7 @@
 
 		var ccCmd string
 		tidy := flags.tidy
-		coverage := flags.coverage
+		coverage := flags.gcovCoverage
 		dump := flags.sAbiDump
 		rule := cc
 		emitXref := flags.emitXrefs
diff --git a/cc/cc.go b/cc/cc.go
index 930c19c..9baeceb 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -181,11 +181,11 @@
 	// These must be after any module include flags, which will be in CommonFlags.
 	SystemIncludeFlags []string
 
-	Toolchain config.Toolchain
-	Tidy      bool
-	Coverage  bool
-	SAbiDump  bool
-	EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
+	Toolchain    config.Toolchain
+	Tidy         bool
+	GcovCoverage bool
+	SAbiDump     bool
+	EmitXrefs    bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
 
 	RequiredInstructionSet string
 	DynamicLinker          string
@@ -211,6 +211,9 @@
 	// Minimum sdk version supported when compiling against the ndk
 	Sdk_version *string
 
+	// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+	Min_sdk_version *string
+
 	AndroidMkSharedLibs       []string `blueprint:"mutated"`
 	AndroidMkStaticLibs       []string `blueprint:"mutated"`
 	AndroidMkRuntimeLibs      []string `blueprint:"mutated"`
@@ -250,6 +253,8 @@
 	// Used by vendor snapshot to record dependencies from snapshot modules.
 	SnapshotSharedLibs  []string `blueprint:"mutated"`
 	SnapshotRuntimeLibs []string `blueprint:"mutated"`
+
+	Installable *bool
 }
 
 type VendorProperties struct {
@@ -368,15 +373,26 @@
 
 	nativeCoverage() bool
 	coverageOutputFilePath() android.OptionalPath
+
+	// Get the deps that have been explicitly specified in the properties.
+	// Only updates the
+	linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+}
+
+type specifiedDeps struct {
+	sharedLibs       []string
+	systemSharedLibs []string
 }
 
 type installer interface {
 	installerProps() []interface{}
 	install(ctx ModuleContext, path android.Path)
+	everInstallable() bool
 	inData() bool
 	inSanitizerDir() bool
 	hostToolPath() android.OptionalPath
 	relativeInstallPath() string
+	skipInstall(mod *Module)
 }
 
 type xref interface {
@@ -1076,7 +1092,7 @@
 	if ctx.ctx.Device() {
 		if ctx.useVndk() {
 			vndkVer := ctx.mod.VndkVersion()
-			if inList(vndkVer, ctx.ctx.Config().PlatformVersionCombinedCodenames()) {
+			if inList(vndkVer, ctx.ctx.Config().PlatformVersionActiveCodenames()) {
 				return "current"
 			}
 			return vndkVer
@@ -1512,6 +1528,13 @@
 		if ctx.Failed() {
 			return
 		}
+	} else if !proptools.BoolDefault(c.Properties.Installable, true) {
+		// If the module has been specifically configure to not be installed then
+		// skip the installation as otherwise it will break when running inside make
+		// as the output path to install will not be specified. Not all uninstallable
+		// modules can skip installation as some are needed for resolving make side
+		// dependencies.
+		c.SkipInstall()
 	}
 }
 
@@ -1849,8 +1872,7 @@
 	addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
 		var variations []blueprint.Variation
 		variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
-		versionVariantAvail := !c.InRecovery() && !c.InRamdisk()
-		if version != "" && versionVariantAvail {
+		if version != "" && VersionVariantAvailable(c) {
 			// Version is explicitly specified. i.e. libFoo#30
 			variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
 			depTag.ExplicitlyVersioned = true
@@ -1860,7 +1882,7 @@
 		// If the version is not specified, add dependency to all stubs libraries.
 		// The stubs library will be used when the depending module is built for APEX and
 		// the dependent module is not in the same APEX.
-		if version == "" && versionVariantAvail {
+		if version == "" && VersionVariantAvailable(c) {
 			for _, ver := range stubsVersionsFor(actx.Config())[name] {
 				// Note that depTag.ExplicitlyVersioned is false in this case.
 				actx.AddVariationDependencies([]blueprint.Variation{
@@ -2258,7 +2280,7 @@
 			}
 			if ccDep.CcLibrary() && !depIsStatic {
 				depIsStubs := ccDep.BuildStubs()
-				depHasStubs := ccDep.HasStubsVariants()
+				depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants()
 				depInSameApex := android.DirectlyInApex(c.ApexName(), depName)
 				depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
 
@@ -2274,8 +2296,8 @@
 					// If not building for APEX, use stubs only when it is from
 					// an APEX (and not from platform)
 					useThisDep = (depInPlatform != depIsStubs)
-					if c.InRamdisk() || c.InRecovery() || c.bootstrap() {
-						// However, for ramdisk, recovery or bootstrap modules,
+					if c.bootstrap() {
+						// However, for host, ramdisk, recovery or bootstrap modules,
 						// always link to non-stub variant
 						useThisDep = !depIsStubs
 					}
@@ -2588,6 +2610,14 @@
 	return c.InRecovery()
 }
 
+func (c *Module) SkipInstall() {
+	if c.installer == nil {
+		c.ModuleBase.SkipInstall()
+		return
+	}
+	c.installer.skipInstall(c)
+}
+
 func (c *Module) HostToolPath() android.OptionalPath {
 	if c.installer == nil {
 		return android.OptionalPath{}
@@ -2697,8 +2727,18 @@
 	}
 }
 
+// Return true if the module is ever installable.
+func (c *Module) EverInstallable() bool {
+	return c.installer != nil &&
+		// Check to see whether the module is actually ever installable.
+		c.installer.everInstallable()
+}
+
 func (c *Module) installable() bool {
-	ret := c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid()
+	ret := c.EverInstallable() &&
+		// Check to see whether the module has been configured to not be installed.
+		proptools.BoolDefault(c.Properties.Installable, true) &&
+		!c.Properties.PreventInstall && c.outputFile.Valid()
 
 	// The platform variant doesn't need further condition. Apex variants however might not
 	// be installable because it will likely to be included in the APEX and won't appear
diff --git a/cc/config/global.go b/cc/config/global.go
index 29020ab..5611a96 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -127,8 +127,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r377782c"
-	ClangDefaultShortVersion = "10.0.5"
+	ClangDefaultVersion      = "clang-r377782d"
+	ClangDefaultShortVersion = "10.0.6"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 43e8c85..cd0a508 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -58,8 +58,11 @@
 		"-Wl,--dynamicbase",
 		"-Wl,--nxcompat",
 	}
+	windowsLldflags = []string{
+		"-Wl,--Xlink=-Brepro", // Enable deterministic build
+	}
 	windowsClangLdflags  = append(ClangFilterUnknownCflags(windowsLdflags), []string{}...)
-	windowsClangLldflags = ClangFilterUnknownLldflags(windowsClangLdflags)
+	windowsClangLldflags = append(ClangFilterUnknownLldflags(windowsClangLdflags), windowsLldflags...)
 
 	windowsX86Cflags = []string{
 		"-m32",
diff --git a/cc/coverage.go b/cc/coverage.go
index b94b628..bde07fd 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -82,10 +82,10 @@
 	}
 
 	if cov.Properties.CoverageEnabled {
-		flags.Coverage = true
 		cov.linkCoverage = true
 
 		if gcovCoverage {
+			flags.GcovCoverage = true
 			flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")
 
 			// Override -Wframe-larger-than and non-default optimization
diff --git a/cc/genrule.go b/cc/genrule.go
index 155e410..9331448 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -27,6 +27,7 @@
 	Vendor_available   *bool
 	Ramdisk_available  *bool
 	Recovery_available *bool
+	Sdk_version        *string
 }
 
 // cc_genrule is a genrule that can depend on other cc_* objects.
diff --git a/cc/installer.go b/cc/installer.go
index 2f55ac5..0b4a68c 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -86,6 +86,11 @@
 	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
 }
 
+func (installer *baseInstaller) everInstallable() bool {
+	// Most cc modules are installable.
+	return true
+}
+
 func (installer *baseInstaller) inData() bool {
 	return installer.location == InstallInData
 }
@@ -101,3 +106,7 @@
 func (installer *baseInstaller) relativeInstallPath() string {
 	return String(installer.Properties.Relative_install_path)
 }
+
+func (installer *baseInstaller) skipInstall(mod *Module) {
+	mod.ModuleBase.SkipInstall()
+}
diff --git a/cc/library.go b/cc/library.go
index c7488ee..c3b20b6 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
@@ -196,6 +195,7 @@
 	module.sdkMemberTypes = []android.SdkMemberType{
 		sharedLibrarySdkMemberType,
 		staticLibrarySdkMemberType,
+		staticAndSharedLibrarySdkMemberType,
 	}
 	return module.Init()
 }
@@ -233,16 +233,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
 
@@ -828,6 +818,23 @@
 	return deps
 }
 
+func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+	specifiedDeps = library.baseLinker.linkerSpecifiedDeps(specifiedDeps)
+	var properties StaticOrSharedProperties
+	if library.static() {
+		properties = library.StaticProperties.Static
+	} else if library.shared() {
+		properties = library.SharedProperties.Shared
+	}
+
+	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
+	specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
+
+	specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
+	specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
+	return specifiedDeps
+}
+
 func (library *libraryDecorator) linkStatic(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
@@ -1232,6 +1239,12 @@
 	}
 }
 
+func (library *libraryDecorator) everInstallable() bool {
+	// Only shared and static libraries are installed. Header libraries (which are
+	// neither static or shared) are not installed.
+	return library.shared() || library.static()
+}
+
 func (library *libraryDecorator) static() bool {
 	return library.MutatedProperties.VariantIsStatic
 }
@@ -1303,6 +1316,18 @@
 	return android.CheckAvailableForApex(what, list)
 }
 
+func (library *libraryDecorator) skipInstall(mod *Module) {
+	if library.static() && library.buildStatic() && !library.buildStubs() {
+		// If we're asked to skip installation of a static library (in particular
+		// when it's not //apex_available:platform) we still want an AndroidMk entry
+		// for it to ensure we get the relevant NOTICE file targets (cf.
+		// notice_files.mk) that other libraries might depend on. AndroidMkEntries
+		// always sets LOCAL_UNINSTALLABLE_MODULE for these entries.
+		return
+	}
+	mod.ModuleBase.SkipInstall()
+}
+
 var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
 
 func versioningMacroNamesList(config android.Config) *map[string]string {
@@ -1382,22 +1407,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.
@@ -1486,10 +1517,18 @@
 	}
 }
 
-// Version mutator splits a module into the mandatory non-stubs variant
+func VersionVariantAvailable(module interface {
+	Host() bool
+	InRamdisk() bool
+	InRecovery() bool
+}) bool {
+	return !module.Host() && !module.InRamdisk() && !module.InRecovery()
+}
+
+// VersionMutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func VersionMutator(mctx android.BottomUpMutatorContext) {
-	if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() {
+	if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
 		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
 			versions := library.StubsVersions()
 			normalizeVersions(mctx, versions)
@@ -1525,7 +1564,7 @@
 	}
 	if genrule, ok := mctx.Module().(*genrule.Module); ok {
 		if _, ok := genrule.Extra.(*GenruleExtraProperties); ok {
-			if !genrule.InRecovery() {
+			if VersionVariantAvailable(genrule) {
 				mctx.CreateVariations("")
 				return
 			}
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 dd097cf..566bdce 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -16,10 +16,10 @@
 
 import (
 	"path/filepath"
-	"reflect"
 
 	"android/soong/android"
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 // This file contains support for using cc library modules within an sdk.
@@ -42,10 +42,20 @@
 	linkTypes:          []string{"static"},
 }
 
+var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_libs",
+		SupportsSdk:  true,
+	},
+	prebuiltModuleType: "cc_prebuilt_library",
+	linkTypes:          []string{"static", "shared"},
+}
+
 func init() {
 	// Register sdk member types.
 	android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
 	android.RegisterSdkMemberType(staticLibrarySdkMemberType)
+	android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType)
 }
 
 type librarySdkMemberType struct {
@@ -65,12 +75,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)
+				}
 			}
 		}
 	}
@@ -89,48 +106,25 @@
 	return false
 }
 
-// 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)
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType)
+
+	ccModule := member.Variants()[0].(*Module)
+
+	sdkVersion := ccModule.SdkVersion()
+	if sdkVersion != "" {
+		pbm.AddProperty("sdk_version", sdkVersion)
+	}
+
+	stl := ccModule.stl.Properties.Stl
+	if stl != nil {
+		pbm.AddProperty("stl", proptools.String(stl))
+	}
+	return pbm
 }
 
-// Organize the variants by architecture.
-func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
-	memberName := member.Name()
-	info := &nativeLibInfo{
-		name:       memberName,
-		memberType: mt,
-	}
-
-	for _, variant := range member.Variants() {
-		ccModule := variant.(*Module)
-
-		// Separate out the generated include dirs (which are arch specific) from the
-		// include dirs (which may not be).
-		exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
-			ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
-
-		info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
-			name:                         memberName,
-			archType:                     ccModule.Target().Arch.ArchType.String(),
-			ExportedIncludeDirs:          exportedIncludeDirs,
-			exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
-			ExportedSystemIncludeDirs:    ccModule.ExportedSystemIncludeDirs(),
-			ExportedFlags:                ccModule.ExportedFlags(),
-			exportedGeneratedHeaders:     ccModule.ExportedGeneratedHeaders(),
-			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 (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &nativeLibInfoProperties{memberType: mt}
 }
 
 func isGeneratedHeaderDirectory(p android.Path) bool {
@@ -138,144 +132,137 @@
 	return gen
 }
 
-// Extract common properties from a slice of property structures of the same type.
-//
-// All the property structures must be of the same type.
-// commonProperties - must be a pointer to the structure into which common properties will be added.
-// inputPropertiesSlice - must be a slice of input properties structures.
-//
-// Iterates over each exported field (capitalized name) and checks to see whether they
-// have the same value (using DeepEquals) across all the input properties. If it does not then no
-// change is made. Otherwise, the common value is stored in the field in the commonProperties
-// and the field in each of the input properties structure is set to its default value.
-func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
-	commonStructValue := reflect.ValueOf(commonProperties).Elem()
-	propertiesStructType := commonStructValue.Type()
+type includeDirsProperty struct {
+	// Accessor to retrieve the paths
+	pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
 
-	// Create an empty structure from which default values for the field can be copied.
-	emptyStructValue := reflect.New(propertiesStructType).Elem()
+	// The name of the property in the prebuilt library, "" means there is no property.
+	propertyName string
 
-	for f := 0; f < propertiesStructType.NumField(); f++ {
-		// Check to see if all the structures have the same value for the field. The commonValue
-		// is nil on entry to the loop and if it is nil on exit then there is no common value,
-		// otherwise it points to the common value.
-		var commonValue *reflect.Value
-		sliceValue := reflect.ValueOf(inputPropertiesSlice)
+	// The directory within the snapshot directory into which items should be copied.
+	snapshotDir string
 
-		for i := 0; i < sliceValue.Len(); i++ {
-			structValue := sliceValue.Index(i)
-			fieldValue := structValue.Field(f)
-			if !fieldValue.CanInterface() {
-				// The field is not exported so ignore it.
-				continue
-			}
+	// True if the items on the path should be copied.
+	copy bool
 
-			if commonValue == nil {
-				// Use the first value as the commonProperties value.
-				commonValue = &fieldValue
-			} else {
-				// If the value does not match the current common value then there is
-				// no value in common so break out.
-				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
-					commonValue = nil
-					break
-				}
-			}
-		}
-
-		// If the fields all have a common value then store it in the common struct field
-		// and set the input struct's field to the empty value.
-		if commonValue != nil {
-			emptyValue := emptyStructValue.Field(f)
-			commonStructValue.Field(f).Set(*commonValue)
-			for i := 0; i < sliceValue.Len(); i++ {
-				structValue := sliceValue.Index(i)
-				fieldValue := structValue.Field(f)
-				fieldValue.Set(emptyValue)
-			}
-		}
-	}
+	// True if the paths represent directories, files if they represent files.
+	dirs bool
 }
 
-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)
-
-	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)
-	}
-	pbm.AddProperty("stl", "none")
-	pbm.AddProperty("system_shared_libs", []string{})
+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(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
-	addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
-	addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
-}
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
 
-// a function for emitting include dirs
-func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
-	includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
-	if len(includeDirs) == 0 {
-		return
+	// Copy the generated library to the snapshot and add a reference to it in the .bp module.
+	if libInfo.outputFile != nil {
+		nativeLibraryPath := nativeLibraryPathFor(libInfo)
+		builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
+		outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
 	}
-	var propertyName string
-	if !systemInclude {
-		propertyName = "export_include_dirs"
-	} else {
-		propertyName = "export_system_include_dirs"
+
+	if len(libInfo.SharedLibs) > 0 {
+		outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
 	}
-	properties.AddProperty(propertyName, includeDirs)
+
+	if len(libInfo.SystemSharedLibs) > 0 {
+		outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+	}
+
+	// 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)
+			}
+		}
+	}
+
+	// Add the collated include dir properties to the output.
+	for property, dirs := range includeDirs {
+		outputProperties.AddProperty(property, dirs)
+	}
 }
 
 const (
@@ -285,41 +272,20 @@
 )
 
 // path to the native library. Relative to <sdk_root>/<api_dir>
-func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
-	return filepath.Join(lib.archType,
+func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
+	return filepath.Join(lib.OsPrefix(), lib.archType,
 		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.
 // The unexported fields will be left untouched.
 type nativeLibInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	memberType *librarySdkMemberType
+
 	// The name of the library, is not exported as this must not be changed during optimization.
 	name string
 
@@ -352,14 +318,53 @@
 	// This field is exported as its contents may not be arch specific.
 	ExportedFlags []string
 
+	// The set of shared libraries
+	//
+	// This field is exported as its contents may not be arch specific.
+	SharedLibs []string
+
+	// The set of system shared libraries
+	//
+	// This field is exported as its contents may not be arch specific.
+	SystemSharedLibs []string
+
 	// outputFile is not exported as it is always arch specific.
 	outputFile android.Path
 }
 
-// nativeLibInfo represents a collection of arch-specific modules having the same name
-type nativeLibInfo struct {
-	name                  string
-	memberType            *librarySdkMemberType
-	archVariantProperties []nativeLibInfoProperties
-	commonProperties      nativeLibInfoProperties
+func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	ccModule := variant.(*Module)
+
+	// If the library has some link types then it produces an output binary file, otherwise it
+	// is header only.
+	if p.memberType.linkTypes != nil {
+		p.outputFile = ccModule.OutputFile().Path()
+	}
+
+	// Separate out the generated include dirs (which are arch specific) from the
+	// include dirs (which may not be).
+	exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
+		ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
+
+	p.name = variant.Name()
+	p.archType = ccModule.Target().Arch.ArchType.String()
+
+	// Make sure that the include directories are unique.
+	p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
+	p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
+	p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
+
+	p.ExportedFlags = ccModule.ExportedFlags()
+	if ccModule.linker != nil {
+		specifiedDeps := specifiedDeps{}
+		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+		p.SharedLibs = specifiedDeps.sharedLibs
+		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+	}
+	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+}
+
+func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet)
 }
diff --git a/cc/linkable.go b/cc/linkable.go
index 80cd6b8..9147681 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -39,6 +39,8 @@
 	Shared() bool
 	Toc() android.OptionalPath
 
+	Host() bool
+
 	InRamdisk() bool
 	OnlyInRamdisk() bool
 
diff --git a/cc/linker.go b/cc/linker.go
index af4cbf3..aa2d0ab 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -490,6 +490,12 @@
 	panic(fmt.Errorf("baseLinker doesn't know how to link"))
 }
 
+func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
+	specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
+	return specifiedDeps
+}
+
 // Injecting version symbols
 // Some host modules want a version number, but we don't want to rebuild it every time.  Optionally add a step
 // after linking that injects a constant placeholder with the current version number.
@@ -501,19 +507,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/llndk_library.go b/cc/llndk_library.go
index 09050aa..7ff20f4 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -83,7 +83,7 @@
 
 func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	vndkVer := ctx.Module().(*Module).VndkVersion()
-	if !inList(vndkVer, ctx.Config().PlatformVersionCombinedCodenames()) || vndkVer == "" {
+	if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
 		// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
 		vndkVer = "current"
 	}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index e849aee..3a630d2 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -90,6 +90,11 @@
 	return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, objectExtension, ctx.sdkVersion())
 }
 
+func (*ndkPrebuiltObjectLinker) availableFor(what string) bool {
+	// ndk prebuilt objects are available to everywhere
+	return true
+}
+
 type ndkPrebuiltStlLinker struct {
 	*libraryDecorator
 }
@@ -103,6 +108,11 @@
 	return deps
 }
 
+func (*ndkPrebuiltStlLinker) availableFor(what string) bool {
+	// ndk prebuilt objects are available to everywhere
+	return true
+}
+
 // ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
 // library (stl) library for linking operation. The soong's module name format
 // is ndk_<NAME>.so where the library is located under
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index b0cf489..3dbd3e3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -23,6 +23,7 @@
 }
 
 func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
@@ -87,18 +88,25 @@
 
 func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
-	// 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...)
 
+	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
+	srcs := p.prebuiltSrcs()
+	if len(srcs) > 0 {
 		builderFlags := flagsToBuilderFlags(flags)
 
-		in := p.Prebuilt.SingleSourcePath(ctx)
+		if len(srcs) > 1 {
+			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+			return nil
+		}
+
+		in := android.PathForModuleSrc(ctx, srcs[0])
 
 		if p.shared() {
 			p.unstrippedOutputFile = in
@@ -122,6 +130,18 @@
 	return nil
 }
 
+func (p *prebuiltLibraryLinker) prebuiltSrcs() []string {
+	srcs := p.properties.Srcs
+	if p.static() {
+		srcs = append(srcs, p.libraryDecorator.StaticProperties.Static.Srcs...)
+	}
+	if p.shared() {
+		srcs = append(srcs, p.libraryDecorator.SharedProperties.Shared.Srcs...)
+	}
+
+	return srcs
+}
+
 func (p *prebuiltLibraryLinker) shared() bool {
 	return p.libraryDecorator.shared()
 }
@@ -134,6 +154,10 @@
 	p.properties.Srcs = nil
 }
 
+func (p *prebuiltLibraryLinker) skipInstall(mod *Module) {
+	mod.ModuleBase.SkipInstall()
+}
+
 func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
 	module, library := NewLibrary(hod)
 	module.compiler = nil
@@ -142,16 +166,32 @@
 		libraryDecorator: library,
 	}
 	module.linker = prebuilt
+	module.installer = prebuilt
 
 	module.AddProperties(&prebuilt.properties)
 
-	android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+	srcsSupplier := func() []string {
+		return prebuilt.prebuiltSrcs()
+	}
+
+	android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
 
 	// Prebuilt libraries can be used in SDKs.
 	android.InitSdkAwareModule(module)
 	return module, library
 }
 
+// cc_prebuilt_library installs a precompiled shared library that are
+// listed in the srcs property in the device's directory.
+func PrebuiltLibraryFactory() android.Module {
+	module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+
+	// Prebuilt shared libraries can be included in APEXes
+	android.InitApexModule(module)
+
+	return module.Init()
+}
+
 // cc_prebuilt_library_shared installs a precompiled shared library that are
 // listed in the srcs property in the device's directory.
 func PrebuiltSharedLibraryFactory() android.Module {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 3d809fc..0eca97f 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -59,36 +59,38 @@
 			name: "libe",
 			srcs: ["libe.a"],
 		}
+
+		cc_library {
+			name: "libf",
+		}
+
+		cc_prebuilt_library {
+			name: "libf",
+			static: {
+				srcs: ["libf.a"],
+			},
+			shared: {
+				srcs: ["libf.so"],
+			},
+		}
 	`
 
-	fs := map[string][]byte{
-		"liba.so": nil,
-		"libb.a":  nil,
-		"libd.so": nil,
-		"libe.a":  nil,
-	}
-
-	config := TestConfig(buildDir, android.Android, nil, bp, fs)
-
-	ctx := CreateTestContext()
-
-	ctx.Register(config)
-
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
+	ctx := testPrebuilt(t, bp)
 
 	// Verify that all the modules exist and that their dependencies were connected correctly
 	liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
 	libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_static").Module()
 	libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_shared").Module()
 	libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_static").Module()
+	libfStatic := ctx.ModuleForTests("libf", "android_arm64_armv8-a_static").Module()
+	libfShared := ctx.ModuleForTests("libf", "android_arm64_armv8-a_shared").Module()
 
 	prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_shared").Module()
 	prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_static").Module()
 	prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_shared").Module()
 	prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_static").Module()
+	prebuiltLibfStatic := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_static").Module()
+	prebuiltLibfShared := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_shared").Module()
 
 	hasDep := func(m android.Module, wantDep android.Module) bool {
 		t.Helper()
@@ -116,4 +118,89 @@
 	if !hasDep(libe, prebuiltLibe) {
 		t.Errorf("libe missing dependency on prebuilt_libe")
 	}
+
+	if !hasDep(libfStatic, prebuiltLibfStatic) {
+		t.Errorf("libf static missing dependency on prebuilt_libf")
+	}
+
+	if !hasDep(libfShared, prebuiltLibfShared) {
+		t.Errorf("libf shared missing dependency on prebuilt_libf")
+	}
+}
+
+func testPrebuilt(t *testing.T, bp string) *android.TestContext {
+	fs := map[string][]byte{
+		"liba.so": nil,
+		"libb.a":  nil,
+		"libd.so": nil,
+		"libe.a":  nil,
+		"libf.a":  nil,
+		"libf.so": nil,
+	}
+	config := TestConfig(buildDir, android.Android, nil, bp, fs)
+	ctx := CreateTestContext()
+
+	// Enable androidmk support.
+	// * Register the singleton
+	// * Configure that we are inside make
+	// * Add CommonOS to ensure that androidmk processing works.
+	android.RegisterAndroidMkBuildComponents(ctx)
+	android.SetInMakeForTests(config)
+
+	ctx.Register(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+	return ctx
+}
+
+func TestPrebuiltLibraryShared(t *testing.T) {
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library_shared {
+		name: "libtest",
+		srcs: ["libf.so"],
+    strip: {
+        none: true,
+    },
+	}
+	`)
+
+	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+	assertString(t, shared.OutputFile().String(), "libf.so")
+}
+
+func TestPrebuiltLibraryStatic(t *testing.T) {
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library_static {
+		name: "libtest",
+		srcs: ["libf.a"],
+	}
+	`)
+
+	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+	assertString(t, static.OutputFile().String(), "libf.a")
+}
+
+func TestPrebuiltLibrary(t *testing.T) {
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library {
+		name: "libtest",
+		static: {
+			srcs: ["libf.a"],
+		},
+		shared: {
+			srcs: ["libf.so"],
+		},
+    strip: {
+        none: true,
+    },
+	}
+	`)
+
+	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+	assertString(t, shared.OutputFile().String(), "libf.so")
+
+	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+	assertString(t, static.OutputFile().String(), "libf.a")
 }
diff --git a/cc/testing.go b/cc/testing.go
index e5be7da..f85795b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -25,6 +25,7 @@
 	RegisterCCBuildComponents(ctx)
 	RegisterBinaryBuildComponents(ctx)
 	RegisterLibraryBuildComponents(ctx)
+	RegisterLibraryHeadersBuildComponents(ctx)
 
 	ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
 	ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
@@ -33,7 +34,7 @@
 	ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
 }
 
-func GatherRequiredDepsForTest(os android.OsType) string {
+func GatherRequiredDepsForTest(oses ...android.OsType) string {
 	ret := `
 		toolchain_library {
 			name: "libatomic",
@@ -227,6 +228,11 @@
 			stl: "none",
 			vendor_available: true,
 			recovery_available: true,
+			host_supported: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 		cc_library {
 			name: "libc++",
@@ -236,6 +242,7 @@
 			stl: "none",
 			vendor_available: true,
 			recovery_available: true,
+			host_supported: true,
 			vndk: {
 				enabled: true,
 				support_system_process: true,
@@ -254,6 +261,10 @@
 			host_supported: false,
 			vendor_available: true,
 			recovery_available: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 		cc_library {
 			name: "libunwind_llvm",
@@ -265,8 +276,21 @@
 			recovery_available: true,
 		}
 
+		cc_defaults {
+			name: "crt_defaults",
+			recovery_available: true,
+			vendor_available: true,
+			native_bridge_supported: true,
+			stl: "none",
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
+		}
+
 		cc_object {
 			name: "crtbegin_so",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -275,6 +299,7 @@
 
 		cc_object {
 			name: "crtbegin_dynamic",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -283,6 +308,7 @@
 
 		cc_object {
 			name: "crtbegin_static",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -291,6 +317,7 @@
 
 		cc_object {
 			name: "crtend_so",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -299,6 +326,7 @@
 
 		cc_object {
 			name: "crtend_android",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -352,8 +380,9 @@
 		}
 	`
 
-	if os == android.Fuchsia {
-		ret += `
+	for _, os := range oses {
+		if os == android.Fuchsia {
+			ret += `
 		cc_library {
 			name: "libbioniccompat",
 			stl: "none",
@@ -363,6 +392,22 @@
 			stl: "none",
 		}
 		`
+		}
+		if os == android.Windows {
+			ret += `
+		toolchain_library {
+			name: "libwinpthread",
+			host_supported: true,
+			enabled: false,
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+			src: "",
+		}
+		`
+		}
 	}
 	return ret
 }
diff --git a/cc/util.go b/cc/util.go
index 60070bb..af26268 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -82,7 +82,7 @@
 		tidyFlags:     strings.Join(in.TidyFlags, " "),
 		sAbiFlags:     strings.Join(in.SAbiFlags, " "),
 		toolchain:     in.Toolchain,
-		coverage:      in.Coverage,
+		gcovCoverage:  in.GcovCoverage,
 		tidy:          in.Tidy,
 		sAbiDump:      in.SAbiDump,
 		emitXrefs:     in.EmitXrefs,
diff --git a/cc/vndk.go b/cc/vndk.go
index 29af9a7..8eab8ba 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -309,6 +309,10 @@
 		panic(err)
 	}
 
+	if m.HasStubsVariants() {
+		mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
+	}
+
 	vndkLibrariesLock.Lock()
 	defer vndkLibrariesLock.Unlock()
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 136bb36..6f24f34 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -472,34 +472,6 @@
 				if ddoc.Javadoc.stubsSrcJar != nil {
 					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar)
 				}
-				apiFilePrefix := "INTERNAL_PLATFORM_"
-				if String(ddoc.properties.Api_tag_name) != "" {
-					apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_"
-				}
-				if ddoc.apiFile != nil {
-					entries.SetPath(apiFilePrefix+"API_FILE", ddoc.apiFile)
-				}
-				if ddoc.dexApiFile != nil {
-					entries.SetPath(apiFilePrefix+"DEX_API_FILE", ddoc.dexApiFile)
-				}
-				if ddoc.privateApiFile != nil {
-					entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", ddoc.privateApiFile)
-				}
-				if ddoc.privateDexApiFile != nil {
-					entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", ddoc.privateDexApiFile)
-				}
-				if ddoc.removedApiFile != nil {
-					entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", ddoc.removedApiFile)
-				}
-				if ddoc.removedDexApiFile != nil {
-					entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", ddoc.removedDexApiFile)
-				}
-				if ddoc.exactApiFile != nil {
-					entries.SetPath(apiFilePrefix+"EXACT_API_FILE", ddoc.exactApiFile)
-				}
-				if ddoc.proguardFile != nil {
-					entries.SetPath(apiFilePrefix+"PROGUARD_FILE", ddoc.proguardFile)
-				}
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -545,10 +517,21 @@
 }
 
 func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries {
+	// If the stubsSrcJar is not generated (because generate_stubs is false) then
+	// use the api file as the output file to ensure the relevant phony targets
+	// are created in make if only the api txt file is being generated. This is
+	// needed because an invalid output file would prevent the make entries from
+	// being written.
+	// TODO(b/146727827): Revert when we do not need to generate stubs and API separately.
+	distFile := android.OptionalPathForPath(dstubs.apiFile)
+	outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar)
+	if !outputFile.Valid() {
+		outputFile = distFile
+	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
-		DistFile:   android.OptionalPathForPath(dstubs.apiFile),
-		OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar),
+		DistFile:   distFile,
+		OutputFile: outputFile,
 		Include:    "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
@@ -567,35 +550,18 @@
 				if dstubs.metadataZip != nil {
 					entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.metadataZip)
 				}
-				apiFilePrefix := "INTERNAL_PLATFORM_"
-				if String(dstubs.properties.Api_tag_name) != "" {
-					apiFilePrefix += String(dstubs.properties.Api_tag_name) + "_"
-				}
-				if dstubs.apiFile != nil {
-					entries.SetPath(apiFilePrefix+"API_FILE", dstubs.apiFile)
-				}
-				if dstubs.dexApiFile != nil {
-					entries.SetPath(apiFilePrefix+"DEX_API_FILE", dstubs.dexApiFile)
-				}
-				if dstubs.privateApiFile != nil {
-					entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", dstubs.privateApiFile)
-				}
-				if dstubs.privateDexApiFile != nil {
-					entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", dstubs.privateDexApiFile)
-				}
-				if dstubs.removedApiFile != nil {
-					entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", dstubs.removedApiFile)
-				}
-				if dstubs.removedDexApiFile != nil {
-					entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", dstubs.removedDexApiFile)
-				}
-				if dstubs.exactApiFile != nil {
-					entries.SetPath(apiFilePrefix+"EXACT_API_FILE", dstubs.exactApiFile)
-				}
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
 			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+				if dstubs.apiFile != nil {
+					fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
+					fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.apiFile)
+				}
+				if dstubs.removedApiFile != nil {
+					fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
+					fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.removedApiFile)
+				}
 				if dstubs.checkCurrentApiTimestamp != nil {
 					fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-current-api")
 					fmt.Fprintln(w, dstubs.Name()+"-check-current-api:",
@@ -622,14 +588,12 @@
 					fmt.Fprintln(w, dstubs.Name()+"-check-last-released-api:",
 						dstubs.checkLastReleasedApiTimestamp.String())
 
-					if dstubs.Name() != "android.car-system-stubs-docs" {
-						fmt.Fprintln(w, ".PHONY: checkapi")
-						fmt.Fprintln(w, "checkapi:",
-							dstubs.checkLastReleasedApiTimestamp.String())
+					fmt.Fprintln(w, ".PHONY: checkapi")
+					fmt.Fprintln(w, "checkapi:",
+						dstubs.checkLastReleasedApiTimestamp.String())
 
-						fmt.Fprintln(w, ".PHONY: droidcore")
-						fmt.Fprintln(w, "droidcore: checkapi")
-					}
+					fmt.Fprintln(w, ".PHONY: droidcore")
+					fmt.Fprintln(w, "droidcore: checkapi")
 				}
 				if dstubs.apiLintTimestamp != nil {
 					fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-api-lint")
@@ -707,6 +671,7 @@
 			func(entries *android.AndroidMkEntries) {
 				entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
 				entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath())
+				entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...)
 			},
 		},
 	}}
diff --git a/java/app.go b/java/app.go
index f9992d8..0ec2502 100755
--- a/java/app.go
+++ b/java/app.go
@@ -110,6 +110,10 @@
 	PreventInstall    bool `blueprint:"mutated"`
 	HideFromMake      bool `blueprint:"mutated"`
 	IsCoverageVariant bool `blueprint:"mutated"`
+
+	// Whether this app is considered mainline updatable or not. When set to true, this will enforce
+	// additional rules for making sure that the APK is truly updatable. Default is false.
+	Updatable *bool
 }
 
 // android_app properties that can be overridden by override_android_app
@@ -242,11 +246,21 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.checkPlatformAPI(ctx)
-	a.checkSdkVersion(ctx)
+	a.checkAppSdkVersions(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
+func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
+	if Bool(a.appProperties.Updatable) {
+		if !a.sdkVersion().stable() {
+			ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion())
+		}
+	}
+
+	a.checkPlatformAPI(ctx)
+	a.checkSdkVersions(ctx)
+}
+
 // Returns true if the native libraries should be stored in the APK uncompressed and the
 // extractNativeLibs application flag should be set to false in the manifest.
 func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
@@ -385,7 +399,18 @@
 			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
 			for _, jni := range jniLibs {
 				if jni.coverageFile.Valid() {
-					a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+					// Only collect coverage for the first target arch if this is a multilib target.
+					// TODO(jungjw): Ideally, we want to collect both reports, but that would cause coverage
+					// data file path collisions since the current coverage file path format doesn't contain
+					// arch-related strings. This is fine for now though; the code coverage team doesn't use
+					// multi-arch targets such as test_suite_* for coverage collections yet.
+					//
+					// Work with the team to come up with a new format that handles multilib modules properly
+					// and change this.
+					if len(ctx.Config().Targets[android.Android]) == 1 ||
+						ctx.Config().Targets[android.Android][0].Arch.ArchType == jni.target.Arch.ArchType {
+						a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+					}
 				}
 			}
 		} else {
@@ -475,6 +500,10 @@
 	return certificates
 }
 
+func (a *AndroidApp) InstallApkName() string {
+	return a.installApkName
+}
+
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
 	var apkDeps android.Paths
 
@@ -1085,6 +1114,10 @@
 	a.generateAndroidBuildActions(ctx)
 }
 
+func (a *AndroidAppImport) InstallApkName() string {
+	return a.BaseModuleName()
+}
+
 func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
 	numCertPropsSet := 0
 	if String(a.properties.Certificate) != "" {
@@ -1142,6 +1175,8 @@
 		dexOutput = dexUncompressed
 	}
 
+	apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
+
 	// Sign or align the package
 	// TODO: Handle EXTERNAL
 	if !Bool(a.properties.Presigned) {
@@ -1152,11 +1187,11 @@
 			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
 		}
 		a.certificate = certificates[0]
-		signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
+		signed := android.PathForModuleOut(ctx, "signed", apkFilename)
 		SignAppPackage(ctx, signed, dexOutput, certificates, nil)
 		a.outputFile = signed
 	} else {
-		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
 		TransformZipAlign(ctx, alignedApk, dexOutput)
 		a.outputFile = alignedApk
 		a.certificate = presignedCertificate
@@ -1164,8 +1199,7 @@
 
 	// TODO: Optionally compress the output apk.
 
-	a.installPath = ctx.InstallFile(installDir,
-		proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk"), a.outputFile)
+	a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
 
 	// TODO: androidmk converter jni libs
 }
@@ -1334,6 +1368,19 @@
 	// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
 	// Defaults to sdk_version if not set.
 	Min_sdk_version *string
+
+	// list of android_library modules whose resources are extracted and linked against statically
+	Static_libs []string
+
+	// list of android_app modules whose resources are extracted and linked against
+	Resource_libs []string
+
+	// Names of modules to be overridden. Listed modules can only be other overlays
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden overlays, but if both
+	// overlays would be installed by default (in PRODUCT_PACKAGES) the other overlay will be removed
+	// from PRODUCT_PACKAGES.
+	Overrides []string
 }
 
 func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1346,6 +1393,9 @@
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
+
+	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
 }
 
 func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/app_test.go b/java/app_test.go
index 10503e7..b1c8b63 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -264,6 +264,108 @@
 	`)
 }
 
+func TestUpdatableApps(t *testing.T) {
+	testCases := []struct {
+		name          string
+		bp            string
+		expectedError string
+	}{
+		{
+			name: "Stable public SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "29",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Stable system SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "system_29",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current public SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current system SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "system_current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current module SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "module_current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current core SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "core_current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "No Platform APIs",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					platform_apis: true,
+					updatable: true,
+				}`,
+			expectedError: "Updatable apps must use stable SDKs",
+		},
+		{
+			name: "No Core Platform APIs",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "core_platform",
+					updatable: true,
+				}`,
+			expectedError: "Updatable apps must use stable SDKs",
+		},
+		{
+			name: "No unspecified APIs",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					updatable: true,
+				}`,
+			expectedError: "Updatable apps must use stable SDK",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			if test.expectedError == "" {
+				testJava(t, test.bp)
+			} else {
+				testJavaError(t, test.expectedError, test.bp)
+			}
+		})
+	}
+}
+
 func TestResourceDirs(t *testing.T) {
 	testCases := []struct {
 		name      string
@@ -2342,11 +2444,17 @@
 }
 
 func TestRuntimeResourceOverlay(t *testing.T) {
-	ctx, config := testJava(t, `
+	fs := map[string][]byte{
+		"baz/res/res/values/strings.xml": nil,
+		"bar/res/res/values/strings.xml": nil,
+	}
+	bp := `
 		runtime_resource_overlay {
 			name: "foo",
 			certificate: "platform",
 			product_specific: true,
+			static_libs: ["bar"],
+			resource_libs: ["baz"],
 			aaptflags: ["--keep-raw-values"],
 		}
 
@@ -2355,8 +2463,23 @@
 			certificate: "platform",
 			product_specific: true,
 			theme: "faza",
+			overrides: ["foo"],
 		}
-		`)
+
+		android_library {
+			name: "bar",
+			resource_dirs: ["bar/res"],
+		}
+
+		android_app {
+			name: "baz",
+			sdk_version: "current",
+			resource_dirs: ["baz/res"],
+		}
+		`
+	config := testAppConfig(nil, bp, fs)
+	ctx := testContext()
+	run(t, ctx, config)
 
 	m := ctx.ModuleForTests("foo", "android_common")
 
@@ -2368,6 +2491,19 @@
 		t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
 	}
 
+	// Check overlay.list output for static_libs dependency.
+	overlayList := m.Output("aapt2/overlay.list").Inputs.Strings()
+	staticLibPackage := buildDir + "/.intermediates/bar/android_common/package-res.apk"
+	if !inList(staticLibPackage, overlayList) {
+		t.Errorf("Stactic lib res package %q missing in overlay list: %q", staticLibPackage, overlayList)
+	}
+
+	// Check AAPT2 link flags for resource_libs dependency.
+	resourceLibFlag := "-I " + buildDir + "/.intermediates/baz/android_common/package-res.apk"
+	if !strings.Contains(aapt2Flags, resourceLibFlag) {
+		t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags)
+	}
+
 	// Check cert signing flag.
 	signedApk := m.Output("signed/foo.apk")
 	signingFlag := signedApk.Args["certificates"]
@@ -2375,14 +2511,15 @@
 	if expected != signingFlag {
 		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
 	}
-	path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_CERTIFICATE"]
+	androidMkEntries := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0]
+	path := androidMkEntries.EntryMap["LOCAL_CERTIFICATE"]
 	expectedPath := []string{"build/make/target/product/security/platform.x509.pem"}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_CERTIFICATE value: %v, expected: %v", path, expectedPath)
 	}
 
 	// Check device location.
-	path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+	path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"]
 	expectedPath = []string{"/tmp/target/product/test_device/product/overlay"}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
@@ -2390,9 +2527,16 @@
 
 	// A themed module has a different device location
 	m = ctx.ModuleForTests("foo_themed", "android_common")
-	path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+	androidMkEntries = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0]
+	path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"]
 	expectedPath = []string{"/tmp/target/product/test_device/product/overlay/faza"}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
 	}
+
+	overrides := androidMkEntries.EntryMap["LOCAL_OVERRIDES_PACKAGES"]
+	expectedOverrides := []string{"foo"}
+	if !reflect.DeepEqual(overrides, expectedOverrides) {
+		t.Errorf("Unexpected LOCAL_OVERRIDES_PACKAGES value: %v, expected: %v", overrides, expectedOverrides)
+	}
 }
diff --git a/java/builder.go b/java/builder.go
index f9b5367..ad9afee 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -146,7 +146,12 @@
 
 	jarjar = pctx.AndroidStaticRule("jarjar",
 		blueprint.RuleParams{
-			Command:     "${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JarjarCmd} process $rulesFile $in $out",
+			Command: "${config.JavaCmd} ${config.JavaVmFlags}" +
+				// b/146418363 Enable Android specific jarjar transformer to drop compat annotations
+				// for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes
+				// avoids adding new hiddenapis after jarjar'ing.
+				" -DremoveAndroidCompatAnnotations=true" +
+				" -jar ${config.JarjarCmd} process $rulesFile $in $out",
 			CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
 		},
 		"rulesFile")
@@ -190,7 +195,7 @@
 	classpath      classpath
 	java9Classpath classpath
 	processorPath  classpath
-	processor      string
+	processors     []string
 	systemModules  *systemModules
 	aidlFlags      string
 	aidlDeps       android.Paths
@@ -264,8 +269,8 @@
 	deps = append(deps, flags.processorPath...)
 
 	processor := "-proc:none"
-	if flags.processor != "" {
-		processor = "-processor " + flags.processor
+	if len(flags.processors) > 0 {
+		processor = "-processor " + strings.Join(flags.processors, ",")
 	}
 
 	intermediatesDir := "xref"
@@ -379,8 +384,8 @@
 	deps = append(deps, flags.processorPath...)
 
 	processor := "-proc:none"
-	if flags.processor != "" {
-		processor = "-processor " + flags.processor
+	if len(flags.processors) > 0 {
+		processor = "-processor " + strings.Join(flags.processors, ",")
 	}
 
 	srcJarDir := "srcjars"
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 76b1d69..1b26667 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -26,7 +26,7 @@
 )
 
 func init() {
-	android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+	RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
 }
 
 // The image "location" is a symbolic path that with multiarchitecture
@@ -168,6 +168,10 @@
 	return &dexpreoptBootJars{}
 }
 
+func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
+	ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+}
+
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
 	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
 		return true
@@ -238,16 +242,66 @@
 	dumpOatRules(ctx, d.defaultBootImage)
 }
 
+// Inspect this module to see if it contains a bootclasspath dex jar.
+// Note that the same jar may occur in multiple modules.
+// This logic is tested in the apex package to avoid import cycle apex <-> java.
+func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
+	// All apex Java libraries have non-installable platform variants, skip them.
+	if module.IsSkipInstall() {
+		return -1, nil
+	}
+
+	jar, hasJar := module.(interface{ DexJar() android.Path })
+	if !hasJar {
+		return -1, nil
+	}
+
+	name := ctx.ModuleName(module)
+	index := android.IndexList(name, image.modules)
+	if index == -1 {
+		return -1, nil
+	}
+
+	// Check that this module satisfies constraints for a particular boot image.
+	apex, isApexModule := module.(android.ApexModule)
+	if image.name == artBootImageName {
+		if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") {
+			// ok, found the jar in the ART apex
+		} else if isApexModule && !apex.IsForPlatform() {
+			// this jar is part of an updatable apex other than ART, fail immediately
+			ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName())
+		} else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
+			// this is a special "hostdex" variant, skip it and resume search
+			return -1, nil
+		} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+			// this is Jacoco platform variant for a coverage build, skip it and resume search
+			return -1, nil
+		} else {
+			// this (installable) jar is part of the platform, fail immediately
+			ctx.Errorf("module '%s' is part of the platform and not allowed in the ART boot image", name)
+		}
+	} else if image.name == frameworkBootImageName {
+		if !isApexModule || apex.IsForPlatform() {
+			// ok, this jar is part of the platform
+		} else {
+			// this jar is part of an updatable apex, fail immediately
+			ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName())
+		}
+	} else {
+		panic("unknown boot image: " + image.name)
+	}
+
+	return index, jar.DexJar()
+}
+
 // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
 func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
+	// Collect dex jar paths for the boot image modules.
+	// This logic is tested in the apex package to avoid import cycle apex <-> java.
 	bootDexJars := make(android.Paths, len(image.modules))
 	ctx.VisitAllModules(func(module android.Module) {
-		// Collect dex jar paths for the modules listed above.
-		if j, ok := module.(interface{ DexJar() android.Path }); ok {
-			name := ctx.ModuleName(module)
-			if i := android.IndexList(name, image.modules); i != -1 {
-				bootDexJars[i] = j.DexJar()
-			}
+		if i, j := getBootImageJar(ctx, image, module); i != -1 {
+			bootDexJars[i] = j
 		}
 	})
 
@@ -259,7 +313,8 @@
 				missingDeps = append(missingDeps, image.modules[i])
 				bootDexJars[i] = android.PathForOutput(ctx, "missing")
 			} else {
-				ctx.Errorf("failed to find dex jar path for module %q",
+				ctx.Errorf("failed to find a dex jar path for module '%s'"+
+					", note that some jars may be filtered out by module constraints",
 					image.modules[i])
 			}
 		}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index c3b2133..e7b3c3b 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -53,7 +53,7 @@
 
 	ctx := testContext()
 
-	ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+	RegisterDexpreoptBootJarsComponents(ctx)
 
 	run(t, ctx, config)
 
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 70d997a..8f08f1f 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -177,37 +177,15 @@
 	// filegroup or genrule can be included within this property.
 	Knowntags []string `android:"path"`
 
-	// the tag name used to distinguish if the API files belong to public/system/test.
-	Api_tag_name *string
-
 	// the generated public API filename by Doclava.
 	Api_filename *string
 
-	// the generated public Dex API filename by Doclava.
-	Dex_api_filename *string
-
-	// the generated private API filename by Doclava.
-	Private_api_filename *string
-
-	// the generated private Dex API filename by Doclava.
-	Private_dex_api_filename *string
-
 	// the generated removed API filename by Doclava.
 	Removed_api_filename *string
 
 	// the generated removed Dex API filename by Doclava.
 	Removed_dex_api_filename *string
 
-	// mapping of dex signatures to source file and line number. This is a temporary property and
-	// will be deleted; you probably shouldn't be using it.
-	Dex_mapping_filename *string
-
-	// the generated exact API filename by Doclava.
-	Exact_api_filename *string
-
-	// the generated proguard filename by Doclava.
-	Proguard_filename *string
-
 	// if set to false, don't allow droiddoc to generate stubs source files. Defaults to true.
 	Create_stubs *bool
 
@@ -229,37 +207,15 @@
 }
 
 type DroidstubsProperties struct {
-	// the tag name used to distinguish if the API files belong to public/system/test.
-	Api_tag_name *string
-
 	// the generated public API filename by Metalava.
 	Api_filename *string
 
-	// the generated public Dex API filename by Metalava.
-	Dex_api_filename *string
-
-	// the generated private API filename by Metalava.
-	Private_api_filename *string
-
-	// the generated private Dex API filename by Metalava.
-	Private_dex_api_filename *string
-
 	// the generated removed API filename by Metalava.
 	Removed_api_filename *string
 
 	// the generated removed Dex API filename by Metalava.
 	Removed_dex_api_filename *string
 
-	// mapping of dex signatures to source file and line number. This is a temporary property and
-	// will be deleted; you probably shouldn't be using it.
-	Dex_mapping_filename *string
-
-	// the generated exact API filename by Metalava.
-	Exact_api_filename *string
-
-	// the generated proguard filename by Metalava.
-	Proguard_filename *string
-
 	Check_api struct {
 		Last_released ApiToCheck
 
@@ -301,6 +257,11 @@
 	// if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
 	Create_doc_stubs *bool
 
+	// if set to false then do not write out stubs. Defaults to true.
+	//
+	// TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
+	Generate_stubs *bool
+
 	// is set to true, Metalava will allow framework SDK to contain API levels annotations.
 	Api_levels_annotations_enabled *bool
 
@@ -718,14 +679,9 @@
 
 	properties        DroiddocProperties
 	apiFile           android.WritablePath
-	dexApiFile        android.WritablePath
 	privateApiFile    android.WritablePath
-	privateDexApiFile android.WritablePath
 	removedApiFile    android.WritablePath
 	removedDexApiFile android.WritablePath
-	exactApiFile      android.WritablePath
-	apiMappingFile    android.WritablePath
-	proguardFile      android.WritablePath
 
 	checkCurrentApiTimestamp      android.WritablePath
 	updateCurrentApiTimestamp     android.WritablePath
@@ -773,6 +729,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.
@@ -782,7 +739,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) == "" {
@@ -862,41 +819,11 @@
 		cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
 	}
 
-	if String(d.properties.Private_api_filename) != "" {
-		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
-		cmd.FlagWithOutput("-privateApi ", d.privateApiFile)
-	}
-
-	if String(d.properties.Dex_api_filename) != "" {
-		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
-		cmd.FlagWithOutput("-dexApi ", d.dexApiFile)
-	}
-
-	if String(d.properties.Private_dex_api_filename) != "" {
-		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
-		cmd.FlagWithOutput("-privateDexApi ", d.privateDexApiFile)
-	}
-
 	if String(d.properties.Removed_dex_api_filename) != "" {
 		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
 		cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
 	}
 
-	if String(d.properties.Exact_api_filename) != "" {
-		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
-		cmd.FlagWithOutput("-exactApi ", d.exactApiFile)
-	}
-
-	if String(d.properties.Dex_mapping_filename) != "" {
-		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
-		cmd.FlagWithOutput("-apiMapping ", d.apiMappingFile)
-	}
-
-	if String(d.properties.Proguard_filename) != "" {
-		d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
-		cmd.FlagWithOutput("-proguard ", d.proguardFile)
-	}
-
 	if BoolDefault(d.properties.Create_stubs, true) {
 		cmd.FlagWithArg("-stubs ", stubsDir.String())
 	}
@@ -1196,14 +1123,9 @@
 	apiFile                 android.WritablePath
 	apiXmlFile              android.WritablePath
 	lastReleasedApiXmlFile  android.WritablePath
-	dexApiFile              android.WritablePath
 	privateApiFile          android.WritablePath
-	privateDexApiFile       android.WritablePath
 	removedApiFile          android.WritablePath
 	removedDexApiFile       android.WritablePath
-	apiMappingFile          android.WritablePath
-	exactApiFile            android.WritablePath
-	proguardFile            android.WritablePath
 	nullabilityWarningsFile android.WritablePath
 
 	checkCurrentApiTimestamp      android.WritablePath
@@ -1284,7 +1206,7 @@
 	}
 }
 
-func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
+func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Api_filename) != "" {
@@ -1300,51 +1222,23 @@
 		cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
 	}
 
-	if String(d.properties.Private_api_filename) != "" {
-		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
-		cmd.FlagWithOutput("--private-api ", d.privateApiFile)
-	}
-
-	if String(d.properties.Dex_api_filename) != "" {
-		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
-		cmd.FlagWithOutput("--dex-api ", d.dexApiFile)
-	}
-
-	if String(d.properties.Private_dex_api_filename) != "" {
-		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
-		cmd.FlagWithOutput("--private-dex-api ", d.privateDexApiFile)
-	}
-
 	if String(d.properties.Removed_dex_api_filename) != "" {
 		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
 		cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile)
 	}
 
-	if String(d.properties.Exact_api_filename) != "" {
-		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
-		cmd.FlagWithOutput("--exact-api ", d.exactApiFile)
-	}
-
-	if String(d.properties.Dex_mapping_filename) != "" {
-		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
-		cmd.FlagWithOutput("--dex-api-mapping ", d.apiMappingFile)
-	}
-
-	if String(d.properties.Proguard_filename) != "" {
-		d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
-		cmd.FlagWithOutput("--proguard ", d.proguardFile)
-	}
-
 	if Bool(d.properties.Write_sdk_values) {
 		d.metadataDir = android.PathForModuleOut(ctx, "metadata")
 		cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
 	}
 
-	if Bool(d.properties.Create_doc_stubs) {
-		cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
-	} else {
-		cmd.FlagWithArg("--stubs ", stubsDir.String())
-		cmd.Flag("--exclude-documentation-from-stubs")
+	if stubsDir.Valid() {
+		if Bool(d.properties.Create_doc_stubs) {
+			cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
+		} else {
+			cmd.FlagWithArg("--stubs ", stubsDir.String())
+			cmd.Flag("--exclude-documentation-from-stubs")
+		}
 	}
 }
 
@@ -1501,15 +1395,18 @@
 
 	// Create rule for metalava
 
-	d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
 	srcJarDir := android.PathForModuleOut(ctx, "srcjars")
-	stubsDir := android.PathForModuleOut(ctx, "stubsDir")
 
 	rule := android.NewRuleBuilder()
 
-	rule.Command().Text("rm -rf").Text(stubsDir.String())
-	rule.Command().Text("mkdir -p").Text(stubsDir.String())
+	generateStubs := BoolDefault(d.properties.Generate_stubs, true)
+	var stubsDir android.OptionalPath
+	if generateStubs {
+		d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
+		stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "stubsDir"))
+		rule.Command().Text("rm -rf").Text(stubsDir.String())
+		rule.Command().Text("mkdir -p").Text(stubsDir.String())
+	}
 
 	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
 
@@ -1535,13 +1432,15 @@
 		cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
 	}
 
-	rule.Command().
-		BuiltTool(ctx, "soong_zip").
-		Flag("-write_if_changed").
-		Flag("-jar").
-		FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
-		FlagWithArg("-C ", stubsDir.String()).
-		FlagWithArg("-D ", stubsDir.String())
+	if generateStubs {
+		rule.Command().
+			BuiltTool(ctx, "soong_zip").
+			Flag("-write_if_changed").
+			Flag("-jar").
+			FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
+			FlagWithArg("-C ", stubsDir.String()).
+			FlagWithArg("-D ", stubsDir.String())
+	}
 
 	if Bool(d.properties.Write_sdk_values) {
 		d.metadataZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-metadata.zip")
@@ -2040,18 +1939,33 @@
 	return ok
 }
 
-func (mt *droidStubsSdkMemberType) 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())
+func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources")
+}
+
+func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &droidStubsInfoProperties{}
+}
+
+type droidStubsInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	StubsSrcJar android.Path
+}
+
+func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	droidstubs := variant.(*Droidstubs)
+	p.StubsSrcJar = droidstubs.stubsSrcJar
+}
+
+func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if p.StubsSrcJar != nil {
+		builder := ctx.SnapshotBuilder()
+
+		snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources")
+
+		builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir)
+
+		propertySet.AddProperty("srcs", []string{snapshotRelativeDir})
 	}
-	variant := variants[0]
-	d, _ := variant.(*Droidstubs)
-	stubsSrcJar := d.stubsSrcJar
-
-	snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
-	builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
-
-	pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
-	pbm.AddProperty("srcs", []string{snapshotRelativeDir})
 }
diff --git a/java/java.go b/java/java.go
index d67ff87..1c2e22a 100644
--- a/java/java.go
+++ b/java/java.go
@@ -39,11 +39,17 @@
 	// Register sdk member types.
 	android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
 
-	android.RegisterSdkMemberType(&implLibrarySdkMemberType{
-		librarySdkMemberType{
-			android.SdkMemberTypeBase{
-				PropertyName: "java_libs",
-			},
+	android.RegisterSdkMemberType(&librarySdkMemberType{
+		android.SdkMemberTypeBase{
+			PropertyName: "java_libs",
+		},
+		func(j *Library) android.Path {
+			implementationJars := j.ImplementationJars()
+			if len(implementationJars) != 1 {
+				panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+			}
+
+			return implementationJars[0]
 		},
 	})
 
@@ -80,7 +86,7 @@
 	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
-func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
+func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
 	if j.SocSpecific() || j.DeviceSpecific() ||
 		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
 		if sc, ok := ctx.Module().(sdkContext); ok {
@@ -90,6 +96,18 @@
 			}
 		}
 	}
+
+	ctx.VisitDirectDeps(func(module android.Module) {
+		tag := ctx.OtherModuleDependencyTag(module)
+		switch module.(type) {
+		// TODO(satayev): cover other types as well, e.g. imports
+		case *Library, *AndroidLibrary:
+			switch tag {
+			case bootClasspathTag, libTag, staticLibTag, java9LibTag:
+				checkLinkType(ctx, j, module.(linkTypeContext), tag.(dependencyTag))
+			}
+		}
+	})
 }
 
 func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
@@ -892,15 +910,7 @@
 			// Handled by AndroidApp.collectAppDeps
 			return
 		}
-		switch module.(type) {
-		case *Library, *AndroidLibrary:
-			if to, ok := module.(linkTypeContext); ok {
-				switch tag {
-				case bootClasspathTag, libTag, staticLibTag:
-					checkLinkType(ctx, j, to, tag.(dependencyTag))
-				}
-			}
-		}
+
 		switch dep := module.(type) {
 		case SdkLibraryDependency:
 			switch tag {
@@ -1124,7 +1134,8 @@
 	flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
 	flags.processorPath = append(flags.processorPath, deps.processorPath...)
 
-	flags.processor = strings.Join(deps.processorClasses, ",")
+	flags.processors = append(flags.processors, deps.processorClasses...)
+	flags.processors = android.FirstUniqueStrings(flags.processors)
 
 	if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() &&
 		decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() {
@@ -1259,7 +1270,7 @@
 			srcJars = append(srcJars, kaptSrcJar)
 			// Disable annotation processing in javac, it's already been handled by kapt
 			flags.processorPath = nil
-			flags.processor = ""
+			flags.processors = nil
 		}
 
 		kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
@@ -1754,11 +1765,6 @@
 	if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
 		return true
 	}
-	// Also, a dependency to an sdk member is also considered as such. This is required because
-	// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
-	if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
-		return true
-	}
 	return false
 }
 
@@ -1817,7 +1823,7 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.checkSdkVersion(ctx)
+	j.checkSdkVersions(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
@@ -1856,16 +1862,20 @@
 )
 
 // path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(member android.SdkMember) string {
-	return sdkSnapshotFilePathForMember(member, jarFileSuffix)
+func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+	return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
 }
 
-func sdkSnapshotFilePathForMember(member android.SdkMember, suffix string) string {
-	return filepath.Join(javaDir, member.Name()+suffix)
+func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string {
+	return filepath.Join(javaDir, osPrefix, name+suffix)
 }
 
 type librarySdkMemberType struct {
 	android.SdkMemberTypeBase
+
+	// Function to retrieve the appropriate output jar (implementation or header) from
+	// the library.
+	jarToExportGetter func(j *Library) android.Path
 }
 
 func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
@@ -1877,75 +1887,67 @@
 	return ok
 }
 
-func (mt *librarySdkMemberType) buildSnapshot(
-	sdkModuleContext android.ModuleContext,
-	builder android.SnapshotBuilder,
-	member android.SdkMember,
-	jarToExportGetter func(j *Library) android.Path) {
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import")
+}
 
-	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]
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &librarySdkMemberProperties{}
+}
+
+type librarySdkMemberProperties struct {
+	android.SdkMemberPropertiesBase
+
+	JarToExport     android.Path
+	AidlIncludeDirs android.Paths
+}
+
+func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	j := variant.(*Library)
 
-	exportedJar := jarToExportGetter(j)
-	snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
-	builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+	p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(j)
+	p.AidlIncludeDirs = j.AidlIncludeDirs()
+}
 
-	for _, dir := range j.AidlIncludeDirs() {
-		// TODO(jiyong): copy parcelable declarations only
-		aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
-		for _, file := range aidlFiles {
-			builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
-		}
+func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	builder := ctx.SnapshotBuilder()
+
+	exportedJar := p.JarToExport
+	if exportedJar != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
 	}
 
-	module := builder.AddPrebuiltModule(member, "java_import")
-	module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	aidlIncludeDirs := p.AidlIncludeDirs
+	if len(aidlIncludeDirs) != 0 {
+		sdkModuleContext := ctx.SdkModuleContext()
+		for _, dir := range aidlIncludeDirs {
+			// TODO(jiyong): copy parcelable declarations only
+			aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
+			for _, file := range aidlFiles {
+				builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+			}
+		}
+
+		// TODO(b/151933053) - add aidl include dirs property
+	}
 }
 
-var javaHeaderLibsSdkMemberType android.SdkMemberType = &headerLibrarySdkMemberType{
-	librarySdkMemberType{
-		android.SdkMemberTypeBase{
-			PropertyName: "java_header_libs",
-			SupportsSdk:  true,
-		},
+var javaHeaderLibsSdkMemberType android.SdkMemberType = &librarySdkMemberType{
+	android.SdkMemberTypeBase{
+		PropertyName: "java_header_libs",
+		SupportsSdk:  true,
 	},
-}
-
-type headerLibrarySdkMemberType struct {
-	librarySdkMemberType
-}
-
-func (mt *headerLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
+	func(j *Library) android.Path {
 		headerJars := j.HeaderJars()
 		if len(headerJars) != 1 {
 			panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
 		}
 
 		return headerJars[0]
-	})
-}
-
-type implLibrarySdkMemberType struct {
-	librarySdkMemberType
-}
-
-func (mt *implLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
-		implementationJars := j.ImplementationJars()
-		if len(implementationJars) != 1 {
-			panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
-		}
-
-		return implementationJars[0]
-	})
+	},
 }
 
 // java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
@@ -2096,31 +2098,50 @@
 	return ok
 }
 
-func (mt *testSdkMemberType) 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]
-	j := variant.(*Test)
+func (mt *testSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_test_import")
+}
 
-	implementationJars := j.ImplementationJars()
+func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &testSdkMemberProperties{}
+}
+
+type testSdkMemberProperties struct {
+	android.SdkMemberPropertiesBase
+
+	JarToExport android.Path
+	TestConfig  android.Path
+}
+
+func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	test := variant.(*Test)
+
+	implementationJars := test.ImplementationJars()
 	if len(implementationJars) != 1 {
-		panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+		panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
 	}
 
-	snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
-	builder.CopyToSnapshot(implementationJars[0], snapshotRelativeJavaLibPath)
+	p.JarToExport = implementationJars[0]
+	p.TestConfig = test.testConfig
+}
 
-	snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(member, testConfigSuffix)
-	builder.CopyToSnapshot(j.testConfig, snapshotRelativeTestConfigPath)
+func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	builder := ctx.SnapshotBuilder()
 
-	module := builder.AddPrebuiltModule(member, "java_test_import")
-	module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
-	module.AddProperty("test_config", snapshotRelativeTestConfigPath)
+	exportedJar := p.JarToExport
+	if exportedJar != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	}
+
+	testConfig := p.TestConfig
+	if testConfig != nil {
+		snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), ctx.Name(), testConfigSuffix)
+		builder.CopyToSnapshot(testConfig, snapshotRelativeTestConfigPath)
+		propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
+	}
 }
 
 // java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
@@ -2323,7 +2344,7 @@
 //
 
 type ImportProperties struct {
-	Jars []string `android:"path"`
+	Jars []string `android:"path,arch_variant"`
 
 	Sdk_version *string
 
@@ -2483,11 +2504,6 @@
 	if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
 		return true
 	}
-	// Also, a dependency to an sdk member is also considered as such. This is required because
-	// sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
-	if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
-		return true
-	}
 	return false
 }
 
diff --git a/java/kotlin.go b/java/kotlin.go
index cb7da20..9b160a0 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -136,8 +136,11 @@
 	kaptProcessorPath := flags.processorPath.FormRepeatedClassPath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
 
 	kaptProcessor := ""
-	if flags.processor != "" {
-		kaptProcessor = "-P plugin:org.jetbrains.kotlin.kapt3:processors=" + flags.processor
+	for i, p := range flags.processors {
+		if i > 0 {
+			kaptProcessor += " "
+		}
+		kaptProcessor += "-P plugin:org.jetbrains.kotlin.kapt3:processors=" + p
 	}
 
 	encodedJavacFlags := kaptEncodeFlags([][2]string{
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 5c6d45f..60ca1c4 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -88,7 +88,7 @@
 		java_library {
 			name: "foo",
 			srcs: ["a.java", "b.kt"],
-			plugins: ["bar"],
+			plugins: ["bar", "baz"],
 		}
 
 		java_plugin {
@@ -96,6 +96,12 @@
 			processor_class: "com.bar",
 			srcs: ["b.java"],
 		}
+
+		java_plugin {
+			name: "baz",
+			processor_class: "com.baz",
+			srcs: ["b.java"],
+		}
 		`)
 
 	buildOS := android.BuildOs.String()
@@ -105,6 +111,7 @@
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 
 	bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+	baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
 
 	// Test that the kotlin and java sources are passed to kapt and kotlinc
 	if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
@@ -136,11 +143,12 @@
 	}
 
 	// Test that the processors are passed to kapt
-	expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar
+	expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+		" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
 	if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
 		t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
 	}
-	expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar"
+	expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
 	if kapt.Args["kaptProcessor"] != expectedProcessor {
 		t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
 	}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index cb17fee..86eddb1 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -28,10 +28,6 @@
 
 func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("prebuilt_apis", PrebuiltApisFactory)
-
-	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
-	})
 }
 
 type prebuiltApisProperties struct {
@@ -48,7 +44,7 @@
 	// no need to implement
 }
 
-func parseJarPath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
+func parseJarPath(path string) (module string, apiver string, scope string) {
 	elements := strings.Split(path, "/")
 
 	apiver = elements[0]
@@ -58,7 +54,7 @@
 	return
 }
 
-func parseApiFilePath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
+func parseApiFilePath(ctx android.LoadHookContext, path string) (module string, apiver string, scope string) {
 	elements := strings.Split(path, "/")
 	apiver = elements[0]
 
@@ -73,7 +69,7 @@
 	return
 }
 
-func createImport(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
 	props := struct {
 		Name        *string
 		Jars        []string
@@ -89,7 +85,7 @@
 	mctx.CreateModule(ImportFactory, &props)
 }
 
-func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+func createFilegroup(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
 	fgName := module + ".api." + scope + "." + apiver
 	filegroupProps := struct {
 		Name *string
@@ -100,7 +96,7 @@
 	mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
 }
 
-func getPrebuiltFiles(mctx android.TopDownMutatorContext, name string) []string {
+func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string {
 	mydir := mctx.ModuleDir() + "/"
 	var files []string
 	for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
@@ -115,7 +111,7 @@
 	return files
 }
 
-func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
+func prebuiltSdkStubs(mctx android.LoadHookContext) {
 	mydir := mctx.ModuleDir() + "/"
 	// <apiver>/<scope>/<module>.jar
 	files := getPrebuiltFiles(mctx, "*.jar")
@@ -123,12 +119,12 @@
 	for _, f := range files {
 		// create a Import module for each jar file
 		localPath := strings.TrimPrefix(f, mydir)
-		module, apiver, scope := parseJarPath(mctx, localPath)
+		module, apiver, scope := parseJarPath(localPath)
 		createImport(mctx, module, scope, apiver, localPath)
 	}
 }
 
-func prebuiltApiFiles(mctx android.TopDownMutatorContext) {
+func prebuiltApiFiles(mctx android.LoadHookContext) {
 	mydir := mctx.ModuleDir() + "/"
 	// <apiver>/<scope>/api/<module>.txt
 	files := getPrebuiltFiles(mctx, "api/*.txt")
@@ -178,7 +174,7 @@
 	}
 }
 
-func PrebuiltApisMutator(mctx android.TopDownMutatorContext) {
+func createPrebuiltApiModules(mctx android.LoadHookContext) {
 	if _, ok := mctx.Module().(*prebuiltApis); ok {
 		prebuiltApiFiles(mctx)
 		prebuiltSdkStubs(mctx)
@@ -191,9 +187,15 @@
 // generates a filegroup module named <module>-api.<scope>.<ver>.
 //
 // It also creates <module>-api.<scope>.latest for the latest <ver>.
+//
+// Similarly, it generates a java_import for all API .jar files found under the
+// directory where the Android.bp is located. Specifically, an API file located
+// at ./<ver>/<scope>/api/<module>.jar generates a java_import module named
+// <prebuilt-api-module>.<scope>.<ver>.<module>.
 func PrebuiltApisFactory() android.Module {
 	module := &prebuiltApis{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
+	android.AddLoadHook(module, createPrebuiltApiModules)
 	return module
 }
diff --git a/java/sdk.go b/java/sdk.go
index 4c9ba2b..be5e512 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -35,6 +35,7 @@
 
 var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
 var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
+var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey")
 var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
 
 type sdkContext interface {
@@ -147,6 +148,10 @@
 	raw     string
 }
 
+func (s sdkSpec) String() string {
+	return fmt.Sprintf("%s_%s", s.kind, s.version)
+}
+
 // valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the
 // specified SDK actually exists.
 func (s sdkSpec) valid() bool {
@@ -158,6 +163,23 @@
 	return s.valid() && s.kind != sdkPrivate
 }
 
+// whether the API surface is managed and versioned, i.e. has .txt file that
+// get frozen on SDK freeze and changes get reviewed by API council.
+func (s sdkSpec) stable() bool {
+	if !s.specified() {
+		return false
+	}
+	switch s.kind {
+	case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer:
+		return true
+	case sdkNone, sdkCorePlatform, sdkTest, sdkPrivate:
+		return false
+	default:
+		panic(fmt.Errorf("unknown sdkKind=%v", s.kind))
+	}
+	return false
+}
+
 // prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK
 // that can be used for unbundled builds.
 func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool {
@@ -393,7 +415,7 @@
 		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))
+		return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx))
 	case sdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
 		return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
@@ -452,6 +474,7 @@
 	}
 
 	createSdkFrameworkAidl(ctx)
+	createNonUpdatableFrameworkAidl(ctx)
 	createAPIFingerprint(ctx)
 }
 
@@ -463,6 +486,31 @@
 		"android_system_stubs_current",
 	}
 
+	combinedAidl := sdkFrameworkAidlPath(ctx)
+	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
+
+	rule := createFrameworkAidl(stubsModules, tempPath, ctx)
+
+	commitChangeForRestat(rule, tempPath, combinedAidl)
+
+	rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
+}
+
+// Creates a version of framework.aidl for the non-updatable part of the platform.
+func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
+	stubsModules := []string{"android_module_lib_stubs_current"}
+
+	combinedAidl := nonUpdatableFrameworkAidlPath(ctx)
+	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
+
+	rule := createFrameworkAidl(stubsModules, tempPath, ctx)
+
+	commitChangeForRestat(rule, tempPath, combinedAidl)
+
+	rule.Build(pctx, ctx, "framework_non_updatable_aidl", "generate framework_non_updatable.aidl")
+}
+
+func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx android.SingletonContext) *android.RuleBuilder {
 	stubsJars := make([]android.Paths, len(stubsModules))
 
 	ctx.VisitAllModules(func(module android.Module) {
@@ -482,8 +530,7 @@
 			if ctx.Config().AllowMissingDependencies() {
 				missingDeps = append(missingDeps, stubsModules[i])
 			} else {
-				ctx.Errorf("failed to find dex jar path for module %q",
-					stubsModules[i])
+				ctx.Errorf("failed to find dex jar path for module %q", stubsModules[i])
 			}
 		}
 	}
@@ -507,20 +554,15 @@
 		}
 	}
 
-	combinedAidl := sdkFrameworkAidlPath(ctx)
-	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
-
 	rule.Command().
-		Text("rm -f").Output(tempPath)
+		Text("rm -f").Output(path)
 	rule.Command().
 		Text("cat").
 		Inputs(aidls).
 		Text("| sort -u >").
-		Output(tempPath)
+		Output(path)
 
-	commitChangeForRestat(rule, tempPath, combinedAidl)
-
-	rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
+	return rule
 }
 
 func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
@@ -529,6 +571,12 @@
 	}).(android.OutputPath)
 }
 
+func nonUpdatableFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
+	return ctx.Config().Once(nonUpdatableFrameworkAidlPathKey, func() interface{} {
+		return android.PathForOutput(ctx, "framework_non_updatable.aidl")
+	}).(android.OutputPath)
+}
+
 // Create api_fingerprint.txt
 func createAPIFingerprint(ctx android.SingletonContext) {
 	out := ApiFingerprintPath(ctx)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 52c9004..a478a7d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -15,17 +15,18 @@
 package java
 
 import (
-	"android/soong/android"
-
 	"fmt"
 	"path"
 	"path/filepath"
+	"reflect"
 	"sort"
 	"strings"
 	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
 )
 
 const (
@@ -66,6 +67,9 @@
 	// The name of the api scope, e.g. public, system, test
 	name string
 
+	// The name of the field in the dynamically created structure.
+	fieldName string
+
 	// The tag to use to depend on the stubs library module.
 	stubsTag scopeDependencyTag
 
@@ -86,11 +90,14 @@
 	// *current. Older stubs library built with a numbered SDK version is created from
 	// the prebuilt jar.
 	sdkVersion string
+
+	// Extra arguments to pass to droidstubs for this scope.
+	droidstubsArgs []string
 }
 
 // Initialize a scope, creating and adding appropriate dependency tags
 func initApiScope(scope *apiScope) *apiScope {
-	//apiScope := &scope
+	scope.fieldName = proptools.FieldNameForProperty(scope.name)
 	scope.stubsTag = scopeDependencyTag{
 		name:     scope.name + "-stubs",
 		apiScope: scope,
@@ -131,6 +138,7 @@
 		moduleSuffix:              sdkSystemApiSuffix,
 		apiFileMakeVariableSuffix: "_SYSTEM",
 		sdkVersion:                "system_current",
+		droidstubsArgs:            []string{"-showAnnotation android.annotation.SystemApi"},
 	})
 	apiScopeTest = initApiScope(&apiScope{
 		name:                      "test",
@@ -138,6 +146,7 @@
 		moduleSuffix:              sdkTestApiSuffix,
 		apiFileMakeVariableSuffix: "_TEST",
 		sdkVersion:                "test_current",
+		droidstubsArgs:            []string{"-showAnnotation android.annotation.TestApi"},
 	})
 	allApiScopes = apiScopes{
 		apiScopePublic,
@@ -162,6 +171,14 @@
 		sort.Strings(*javaSdkLibraries)
 		ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
 	})
+
+	// Register sdk member types.
+	android.RegisterSdkMemberType(&sdkLibrarySdkMemberType{
+		android.SdkMemberTypeBase{
+			PropertyName: "java_sdk_libs",
+			SupportsSdk:  true,
+		},
+	})
 }
 
 func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -373,13 +390,6 @@
 	}
 }
 
-// $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
-// api file for the current source
-// TODO: remove this when apicheck is done in soong
-func (module *SdkLibrary) apiTagName(apiScope *apiScope) string {
-	return strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1) + apiScope.apiFileMakeVariableSuffix
-}
-
 func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
 	return ":" + module.BaseModuleName() + ".api." + apiScope.name + ".latest"
 }
@@ -458,7 +468,7 @@
 	mctx.CreateModule(LibraryFactory, &props)
 }
 
-// Creates a droiddoc module that creates stubs source files from the given full source
+// Creates a droidstubs module that creates stubs source files from the given full source
 // files
 func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
 	props := struct {
@@ -470,9 +480,6 @@
 		Libs                             []string
 		Arg_files                        []string
 		Args                             *string
-		Api_tag_name                     *string
-		Api_filename                     *string
-		Removed_api_filename             *string
 		Java_version                     *string
 		Merge_annotations_dirs           []string
 		Merge_inclusion_annotations_dirs []string
@@ -516,15 +523,15 @@
 	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
 	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
 
-	droiddocArgs := []string{}
+	droidstubsArgs := []string{}
 	if len(module.sdkLibraryProperties.Api_packages) != 0 {
-		droiddocArgs = append(droiddocArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
+		droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
 	}
 	if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
-		droiddocArgs = append(droiddocArgs,
+		droidstubsArgs = append(droidstubsArgs,
 			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
 	}
-	droiddocArgs = append(droiddocArgs, module.sdkLibraryProperties.Droiddoc_options...)
+	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
 	disabledWarnings := []string{
 		"MissingPermission",
 		"BroadcastBehavior",
@@ -536,16 +543,12 @@
 		"Todo",
 		"Typo",
 	}
-	droiddocArgs = append(droiddocArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
+	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
 
-	switch apiScope {
-	case apiScopeSystem:
-		droiddocArgs = append(droiddocArgs, "-showAnnotation android.annotation.SystemApi")
-	case apiScopeTest:
-		droiddocArgs = append(droiddocArgs, " -showAnnotation android.annotation.TestApi")
-	}
+	// Add in scope specific arguments.
+	droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...)
 	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
-	props.Args = proptools.StringPtr(strings.Join(droiddocArgs, " "))
+	props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
 
 	// List of APIs identified from the provided source files are created. They are later
 	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
@@ -555,10 +558,6 @@
 	apiDir := module.getApiDir()
 	currentApiFileName = path.Join(apiDir, currentApiFileName)
 	removedApiFileName = path.Join(apiDir, removedApiFileName)
-	// TODO(jiyong): remove these three props
-	props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope))
-	props.Api_filename = proptools.StringPtr(currentApiFileName)
-	props.Removed_api_filename = proptools.StringPtr(removedApiFileName)
 
 	// check against the not-yet-release API
 	props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
@@ -819,36 +818,74 @@
 	// List of shared java libs, common to all scopes, that this module has
 	// dependencies to
 	Libs []string
-
-	// Properties associated with the public api scope.
-	Public sdkLibraryScopeProperties
-
-	// Properties associated with the system api scope.
-	System sdkLibraryScopeProperties
-
-	// Properties associated with the test api scope.
-	Test sdkLibraryScopeProperties
 }
 
 type sdkLibraryImport struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 	prebuilt android.Prebuilt
+	android.ApexModuleBase
+	android.SdkBase
 
 	properties sdkLibraryImportProperties
 
+	// Map from api scope to the scope specific property structure.
+	scopeProperties map[*apiScope]*sdkLibraryScopeProperties
+
 	commonToSdkLibraryAndImport
 }
 
 var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
 
+// The type of a structure that contains a field of type sdkLibraryScopeProperties
+// for each apiscope in allApiScopes, e.g. something like:
+// struct {
+//   Public sdkLibraryScopeProperties
+//   System sdkLibraryScopeProperties
+//   ...
+// }
+var allScopeStructType = createAllScopePropertiesStructType()
+
+// Dynamically create a structure type for each apiscope in allApiScopes.
+func createAllScopePropertiesStructType() reflect.Type {
+	var fields []reflect.StructField
+	for _, apiScope := range allApiScopes {
+		field := reflect.StructField{
+			Name: apiScope.fieldName,
+			Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
+		}
+		fields = append(fields, field)
+	}
+
+	return reflect.StructOf(fields)
+}
+
+// Create an instance of the scope specific structure type and return a map
+// from apiscope to a pointer to each scope specific field.
+func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) {
+	allScopePropertiesPtr := reflect.New(allScopeStructType)
+	allScopePropertiesStruct := allScopePropertiesPtr.Elem()
+	scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
+
+	for _, apiScope := range allApiScopes {
+		field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
+		scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
+	}
+
+	return allScopePropertiesPtr.Interface(), scopeProperties
+}
+
 // java_sdk_library_import imports a prebuilt java_sdk_library.
 func sdkLibraryImportFactory() android.Module {
 	module := &sdkLibraryImport{}
 
-	module.AddProperties(&module.properties)
+	allScopeProperties, scopeToProperties := createPropertiesInstance()
+	module.scopeProperties = scopeToProperties
+	module.AddProperties(&module.properties, allScopeProperties)
 
 	android.InitPrebuiltModule(module, &[]string{""})
+	android.InitApexModule(module)
+	android.InitSdkAwareModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 
 	android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
@@ -870,48 +907,12 @@
 		module.prebuilt.ForcePrefer()
 	}
 
-	for apiScope, scopeProperties := range module.scopeProperties() {
+	for apiScope, scopeProperties := range module.scopeProperties {
 		if len(scopeProperties.Jars) == 0 {
 			continue
 		}
 
-		// Creates a java import for the jar with ".stubs" suffix
-		props := struct {
-			Name                *string
-			Soc_specific        *bool
-			Device_specific     *bool
-			Product_specific    *bool
-			System_ext_specific *bool
-			Sdk_version         *string
-			Libs                []string
-			Jars                []string
-			Prefer              *bool
-		}{}
-
-		props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
-		props.Sdk_version = scopeProperties.Sdk_version
-		// Prepend any of the libs from the legacy public properties to the libs for each of the
-		// scopes to avoid having to duplicate them in each scope.
-		props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
-		props.Jars = scopeProperties.Jars
-
-		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)
-		}
-
-		// 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)
+		module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
 	}
 
 	javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -920,16 +921,44 @@
 	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
 }
 
-func (module *sdkLibraryImport) scopeProperties() map[*apiScope]*sdkLibraryScopeProperties {
-	p := make(map[*apiScope]*sdkLibraryScopeProperties)
-	p[apiScopePublic] = &module.properties.Public
-	p[apiScopeSystem] = &module.properties.System
-	p[apiScopeTest] = &module.properties.Test
-	return p
+func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.LoadHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+	// Creates a java import for the jar with ".stubs" suffix
+	props := struct {
+		Name                *string
+		Soc_specific        *bool
+		Device_specific     *bool
+		Product_specific    *bool
+		System_ext_specific *bool
+		Sdk_version         *string
+		Libs                []string
+		Jars                []string
+		Prefer              *bool
+	}{}
+	props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
+	props.Sdk_version = scopeProperties.Sdk_version
+	// Prepend any of the libs from the legacy public properties to the libs for each of the
+	// scopes to avoid having to duplicate them in each scope.
+	props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
+	props.Jars = scopeProperties.Jars
+	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)
+	}
+	// 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)
 }
 
 func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
-	for apiScope, scopeProperties := range module.scopeProperties() {
+	for apiScope, scopeProperties := range module.scopeProperties {
 		if len(scopeProperties.Jars) == 0 {
 			continue
 		}
@@ -1096,3 +1125,81 @@
 		},
 	}}
 }
+
+type sdkLibrarySdkMemberType struct {
+	android.SdkMemberTypeBase
+}
+
+func (s *sdkLibrarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+	mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
+	_, ok := module.(*SdkLibrary)
+	return ok
+}
+
+func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_sdk_library_import")
+}
+
+func (s *sdkLibrarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &sdkLibrarySdkMemberProperties{}
+}
+
+type sdkLibrarySdkMemberProperties struct {
+	android.SdkMemberPropertiesBase
+
+	// Scope to per scope properties.
+	Scopes map[*apiScope]scopeProperties
+
+	// Additional libraries that the exported stubs libraries depend upon.
+	Libs []string
+}
+
+type scopeProperties struct {
+	Jars       android.Paths
+	SdkVersion string
+}
+
+func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	sdk := variant.(*SdkLibrary)
+
+	s.Scopes = make(map[*apiScope]scopeProperties)
+	for _, apiScope := range allApiScopes {
+		paths := sdk.getScopePaths(apiScope)
+		jars := paths.stubsImplPath
+		if len(jars) > 0 {
+			properties := scopeProperties{}
+			properties.Jars = jars
+			properties.SdkVersion = apiScope.sdkVersion
+			s.Scopes[apiScope] = properties
+		}
+	}
+
+	s.Libs = sdk.properties.Libs
+}
+
+func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	for _, apiScope := range allApiScopes {
+		if properties, ok := s.Scopes[apiScope]; ok {
+			scopeSet := propertySet.AddPropertySet(apiScope.name)
+
+			var jars []string
+			for _, p := range properties.Jars {
+				dest := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name, ctx.Name()+"-stubs.jar")
+				ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
+				jars = append(jars, dest)
+			}
+			scopeSet.AddProperty("jars", jars)
+
+			if properties.SdkVersion != "" {
+				scopeSet.AddProperty("sdk_version", properties.SdkVersion)
+			}
+		}
+	}
+
+	if len(s.Libs) > 0 {
+		propertySet.AddPropertyWithTag("libs", s.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(false))
+	}
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 088db9e..8eb5ffb 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -217,7 +217,7 @@
 			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",
+			aidl:           "-p" + buildDir + "/framework_non_updatable.aidl",
 		},
 		{
 			name:           "system_server_current",
diff --git a/java/system_modules.go b/java/system_modules.go
index 47de6e3..7394fd5 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -242,18 +242,28 @@
 	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)
+func (mt *systemModulesSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_system_modules_import")
+}
 
-	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())
+type systemModulesInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	Libs []string
+}
+
+func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &systemModulesInfoProperties{}
+}
+
+func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	systemModule := variant.(*SystemModules)
+	p.Libs = systemModule.properties.Libs
+}
+
+func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if len(p.Libs) > 0 {
+		// Add the references to the libraries that form the system module.
+		propertySet.AddPropertyWithTag("libs", p.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
+	}
 }
diff --git a/python/androidmk.go b/python/androidmk.go
index 8e8e8ef..d293d52 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -100,5 +100,6 @@
 		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
 		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
 		fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(installer.androidMkSharedLibs, " "))
+		fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := false")
 	})
 }
diff --git a/rust/rust.go b/rust/rust.go
index f446ef0..17734f9 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -727,13 +727,14 @@
 
 	deps := mod.deps(ctx)
 	commonDepVariations := []blueprint.Variation{}
-	commonDepVariations = append(commonDepVariations,
-		blueprint.Variation{Mutator: "version", Variation: ""})
+	if cc.VersionVariantAvailable(mod) {
+		commonDepVariations = append(commonDepVariations,
+			blueprint.Variation{Mutator: "version", Variation: ""})
+	}
 	if !mod.Host() {
 		commonDepVariations = append(commonDepVariations,
 			blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
 	}
-
 	actx.AddVariationDependencies(
 		append(commonDepVariations, []blueprint.Variation{
 			{Mutator: "rust_libraries", Variation: "rlib"},
diff --git a/sdk/bp.go b/sdk/bp.go
index 6936daf..68fe7ab 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -35,7 +35,7 @@
 
 func (s *bpPropertySet) AddProperty(name string, value interface{}) {
 	if s.properties[name] != nil {
-		panic("Property %q already exists in property set")
+		panic(fmt.Sprintf("Property %q already exists in property set", name))
 	}
 
 	s.properties[name] = value
@@ -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 9c8e292..0a4e16d 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -17,6 +17,7 @@
 import (
 	"testing"
 
+	"android/soong/android"
 	"android/soong/cc"
 )
 
@@ -24,11 +25,13 @@
 	t.Helper()
 
 	fs := map[string][]byte{
-		"Test.cpp":                  nil,
-		"include/Test.h":            nil,
-		"arm64/include/Arm64Test.h": nil,
-		"libfoo.so":                 nil,
-		"aidl/foo/bar/Test.aidl":    nil,
+		"Test.cpp":                      nil,
+		"include/Test.h":                nil,
+		"include-android/AndroidTest.h": nil,
+		"include-host/HostTest.h":       nil,
+		"arm64/include/Arm64Test.h":     nil,
+		"libfoo.so":                     nil,
+		"aidl/foo/bar/Test.aidl":        nil,
 	}
 	return testSdkWithFs(t, bp, fs)
 }
@@ -54,7 +57,7 @@
 	arm64Output := result.Module("sdkmember", "android_arm64_armv8-a_shared").(*cc.Module).OutputFile()
 
 	var inputs []string
-	buildParams := result.Module("mysdk", "android_common").BuildParamsForTests()
+	buildParams := result.Module("mysdk", android.CommonOS.Name).BuildParamsForTests()
 	for _, bp := range buildParams {
 		if bp.Input != nil {
 			inputs = append(inputs, bp.Input.String())
@@ -250,7 +253,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "android_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAllCopyRules(`
 include/Test.h -> include/include/Test.h
 .intermediates/mynativelib1/android_arm64_armv8-a_shared/mynativelib1.so -> arm64/lib/mynativelib1.so
@@ -287,13 +290,15 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "android_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
 cc_prebuilt_library_shared {
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
+    installable: false,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -304,13 +309,12 @@
             srcs: ["arm/lib/mynativelib.so"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -321,8 +325,6 @@
             srcs: ["arm/lib/mynativelib.so"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 sdk_snapshot {
@@ -356,13 +358,14 @@
 		}
 	`)
 
-	result.CheckSnapshot("mymodule_exports", "android_common", "",
+	result.CheckSnapshot("mymodule_exports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
 cc_prebuilt_binary {
     name: "mymodule_exports_mynativebinary@current",
     sdk_member_name: "mynativebinary",
+    installable: false,
     compile_multilib: "both",
     arch: {
         arm64: {
@@ -400,6 +403,114 @@
 	)
 }
 
+func TestMultipleHostOsTypesSnapshotWithCcBinary(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,
+			native_binaries: ["mynativebinary"],
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+
+		cc_binary {
+			name: "mynativebinary",
+			device_supported: false,
+			host_supported: true,
+			srcs: [
+				"Test.cpp",
+			],
+			compile_multilib: "both",
+			system_shared_libs: [],
+			stl: "none",
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+    name: "myexports_mynativebinary@current",
+    sdk_member_name: "mynativebinary",
+    device_supported: false,
+    host_supported: true,
+    installable: false,
+    target: {
+        linux_glibc: {
+            compile_multilib: "both",
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/bin/mynativebinary"],
+        },
+        windows: {
+            compile_multilib: "64",
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+        },
+    },
+}
+
+cc_prebuilt_binary {
+    name: "mynativebinary",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    target: {
+        linux_glibc: {
+            compile_multilib: "both",
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/bin/mynativebinary"],
+        },
+        windows: {
+            compile_multilib: "64",
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    device_supported: false,
+    host_supported: true,
+    native_binaries: ["myexports_mynativebinary@current"],
+    target: {
+        windows: {
+            compile_multilib: "64",
+        },
+    },
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativebinary/linux_glibc_x86_64/mynativebinary -> linux_glibc/x86_64/bin/mynativebinary
+.intermediates/mynativebinary/linux_glibc_x86/mynativebinary -> linux_glibc/x86/bin/mynativebinary
+.intermediates/mynativebinary/windows_x86_64/mynativebinary.exe -> windows/x86_64/bin/mynativebinary.exe
+`),
+	)
+}
+
 func TestSnapshotWithCcSharedLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
@@ -413,6 +524,7 @@
 				"Test.cpp",
 				"aidl/foo/bar/Test.aidl",
 			],
+			apex_available: ["apex1", "apex2"],
 			export_include_dirs: ["include"],
 			aidl: {
 				export_aidl_headers: true,
@@ -422,13 +534,19 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "android_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
 cc_prebuilt_library_shared {
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
+    apex_available: [
+        "apex1",
+        "apex2",
+    ],
+    installable: false,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -440,13 +558,16 @@
             export_include_dirs: ["arm/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
+    apex_available: [
+        "apex1",
+        "apex2",
+    ],
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -458,8 +579,6 @@
             export_include_dirs: ["arm/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 sdk_snapshot {
@@ -481,6 +600,189 @@
 	)
 }
 
+func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: [
+				"mynativelib",
+				"myothernativelib",
+				"mysystemnativelib",
+			],
+		}
+
+		cc_library {
+			name: "mysystemnativelib",
+			srcs: [
+				"Test.cpp",
+			],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library_shared {
+			name: "myothernativelib",
+			srcs: [
+				"Test.cpp",
+			],
+			system_shared_libs: [
+				// A reference to a library that is not an sdk member. Uses libm as that
+				// is in the default set of modules available to this test and so is available
+				// both here and also when the generated Android.bp file is tested in
+				// CheckSnapshot(). This ensures that the system_shared_libs property correctly
+				// handles references to modules that are not sdk members.
+				"libm",
+			],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "mynativelib",
+			srcs: [
+				"Test.cpp",
+			],
+			shared_libs: [
+				// A reference to another sdk member.
+				"myothernativelib",
+			],
+			target: {
+				android: {
+					shared: {
+						shared_libs: [
+							// A reference to a library that is not an sdk member. The libc library
+							// is used here to check that the shared_libs property is handled correctly
+							// in a similar way to how libm is used to check system_shared_libs above.
+							"libc",
+						],
+					},
+				},
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    installable: false,
+    stl: "none",
+    shared_libs: [
+        "mysdk_myothernativelib@current",
+        "libc",
+    ],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/mynativelib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/mynativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mynativelib",
+    prefer: false,
+    stl: "none",
+    shared_libs: [
+        "myothernativelib",
+        "libc",
+    ],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/mynativelib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/mynativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mysdk_myothernativelib@current",
+    sdk_member_name: "myothernativelib",
+    installable: false,
+    stl: "none",
+    system_shared_libs: ["libm"],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/myothernativelib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/myothernativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "myothernativelib",
+    prefer: false,
+    stl: "none",
+    system_shared_libs: ["libm"],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/myothernativelib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/myothernativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mysdk_mysystemnativelib@current",
+    sdk_member_name: "mysystemnativelib",
+    installable: false,
+    stl: "none",
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/mysystemnativelib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/mysystemnativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mysystemnativelib",
+    prefer: false,
+    stl: "none",
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/mysystemnativelib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/mysystemnativelib.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_shared_libs: [
+        "mysdk_mynativelib@current",
+        "mysdk_myothernativelib@current",
+        "mysdk_mysystemnativelib@current",
+    ],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so
+.intermediates/myothernativelib/android_arm64_armv8-a_shared/myothernativelib.so -> arm64/lib/myothernativelib.so
+.intermediates/myothernativelib/android_arm_armv7-a-neon_shared/myothernativelib.so -> arm/lib/myothernativelib.so
+.intermediates/mysystemnativelib/android_arm64_armv8-a_shared/mysystemnativelib.so -> arm64/lib/mysystemnativelib.so
+.intermediates/mysystemnativelib/android_arm_armv7-a-neon_shared/mysystemnativelib.so -> arm/lib/mysystemnativelib.so
+`),
+	)
+}
+
 func TestHostSnapshotWithCcSharedLibrary(t *testing.T) {
 	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
 	SkipIfNotLinux(t)
@@ -507,10 +809,11 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
+			sdk_version: "minimum",
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -519,6 +822,9 @@
     sdk_member_name: "mynativelib",
     device_supported: false,
     host_supported: true,
+    installable: false,
+    sdk_version: "minimum",
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -530,8 +836,6 @@
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 cc_prebuilt_library_shared {
@@ -539,6 +843,8 @@
     prefer: false,
     device_supported: false,
     host_supported: true,
+    sdk_version: "minimum",
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -550,8 +856,6 @@
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 sdk_snapshot {
@@ -575,6 +879,103 @@
 	)
 }
 
+func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(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_shared_libs: ["mynativelib"],
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+
+		cc_library_shared {
+			name: "mynativelib",
+			device_supported: false,
+			host_supported: true,
+			srcs: [
+				"Test.cpp",
+			],
+			system_shared_libs: [],
+			stl: "none",
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    device_supported: false,
+    host_supported: true,
+    installable: false,
+    stl: "none",
+    target: {
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/lib/mynativelib.dll"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mynativelib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    target: {
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/lib/mynativelib.dll"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    device_supported: false,
+    host_supported: true,
+    native_shared_libs: ["mysdk_mynativelib@current"],
+    target: {
+        windows: {
+            compile_multilib: "64",
+        },
+    },
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
+.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
+.intermediates/mynativelib/windows_x86_64_shared/mynativelib.dll -> windows/x86_64/lib/mynativelib.dll
+`),
+	)
+}
+
 func TestSnapshotWithCcStaticLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		module_exports {
@@ -597,13 +998,15 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "android_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
 cc_prebuilt_library_static {
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
+    installable: false,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -615,13 +1018,12 @@
             export_include_dirs: ["arm/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -633,8 +1035,6 @@
             export_include_dirs: ["arm/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 module_exports_snapshot {
@@ -685,7 +1085,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "linux_glibc_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -694,6 +1094,8 @@
     sdk_member_name: "mynativelib",
     device_supported: false,
     host_supported: true,
+    installable: false,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -705,8 +1107,6 @@
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 cc_prebuilt_library_static {
@@ -714,6 +1114,7 @@
     prefer: false,
     device_supported: false,
     host_supported: true,
+    stl: "none",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -725,8 +1126,6 @@
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
     },
-    stl: "none",
-    system_shared_libs: [],
 }
 
 module_exports_snapshot {
@@ -749,3 +1148,359 @@
 `),
 	)
 }
+
+func TestSnapshotWithCcLibrary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "myexports",
+			native_libs: ["mynativelib"],
+		}
+
+		cc_library {
+			name: "mynativelib",
+			srcs: [
+				"Test.cpp",
+			],
+			export_include_dirs: ["include"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library {
+    name: "myexports_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    installable: false,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+    arch: {
+        arm64: {
+            static: {
+                srcs: ["arm64/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm64/lib/mynativelib.so"],
+            },
+        },
+        arm: {
+            static: {
+                srcs: ["arm/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm/lib/mynativelib.so"],
+            },
+        },
+    },
+}
+
+cc_prebuilt_library {
+    name: "mynativelib",
+    prefer: false,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+    arch: {
+        arm64: {
+            static: {
+                srcs: ["arm64/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm64/lib/mynativelib.so"],
+            },
+        },
+        arm: {
+            static: {
+                srcs: ["arm/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm/lib/mynativelib.so"],
+            },
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    native_libs: ["myexports_mynativelib@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/android_arm64_armv8-a_static/mynativelib.a -> arm64/lib/mynativelib.a
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_static/mynativelib.a -> arm/lib/mynativelib.a
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
+	)
+}
+
+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", "",
+		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,
+    installable: false,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/mynativelib.a"],
+            export_include_dirs: ["x86_64/include_gen/mynativelib"],
+        },
+    },
+}
+
+cc_prebuilt_library_static {
+    name: "mynativelib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/mynativelib.a"],
+            export_include_dirs: ["x86_64/include_gen/mynativelib"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    device_supported: false,
+    host_supported: true,
+    native_static_libs: ["myexports_mynativelib@current"],
+    target: {
+        linux_glibc: {
+            compile_multilib: "64",
+        },
+    },
+}`),
+		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", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    stl: "none",
+    export_include_dirs: ["include/include"],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+}
+
+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", "",
+		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,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+}
+
+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
+`),
+	)
+}
+
+func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			host_supported: true,
+			native_header_libs: ["mynativeheaders"],
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			host_supported: true,
+			system_shared_libs: [],
+			stl: "none",
+			export_system_include_dirs: ["include"],
+			target: {
+				android: {
+					export_include_dirs: ["include-android"],
+				},
+				host: {
+					export_include_dirs: ["include-host"],
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    host_supported: true,
+    stl: "none",
+    export_system_include_dirs: ["include/include"],
+    target: {
+        android: {
+            export_include_dirs: ["include/include-android"],
+        },
+        linux_glibc: {
+            export_include_dirs: ["include/include-host"],
+        },
+    },
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    host_supported: true,
+    stl: "none",
+    export_system_include_dirs: ["include/include"],
+    target: {
+        android: {
+            export_include_dirs: ["include/include-android"],
+        },
+        linux_glibc: {
+            export_include_dirs: ["include/include-host"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+include-android/AndroidTest.h -> include/include-android/AndroidTest.h
+include-host/HostTest.h -> include/include-host/HostTest.h
+`),
+	)
+}
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index b905d71..20e2521 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -42,7 +42,7 @@
 			"package/Android.bp": []byte(packageBp),
 		})
 
-	result.CheckSnapshot("myexports", "android_common", "package",
+	result.CheckSnapshot("myexports", "package",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 0737e5e..bce2ab3 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -24,7 +24,51 @@
 	fs := map[string][]byte{
 		"Test.java":              nil,
 		"aidl/foo/bar/Test.aidl": nil,
+
+		// For java_sdk_library
+		"api/current.txt":                                   nil,
+		"api/removed.txt":                                   nil,
+		"api/system-current.txt":                            nil,
+		"api/system-removed.txt":                            nil,
+		"api/test-current.txt":                              nil,
+		"api/test-removed.txt":                              nil,
+		"build/soong/scripts/gen-java-current-api-files.sh": nil,
 	}
+
+	// for java_sdk_library tests
+	bp = `
+java_system_modules_import {
+	name: "core-current-stubs-system-modules",
+}
+java_system_modules_import {
+	name: "core-platform-api-stubs-system-modules",
+}
+java_import {
+	name: "core.platform.api.stubs",
+}
+java_sdk_library_import {
+	name: "android_stubs_current",
+}
+java_sdk_library_import {
+	name: "android_system_stubs_current",
+}
+java_sdk_library_import {
+	name: "android_test_stubs_current",
+}
+java_import {
+	name: "core-lambda-stubs", 
+	sdk_version: "none",
+}
+java_import {
+	name: "ext", 
+	sdk_version: "none",
+}
+java_import {
+	name: "framework", 
+	sdk_version: "none",
+}
+` + bp
+
 	return testSdkWithFs(t, bp, fs)
 }
 
@@ -53,30 +97,18 @@
 			system_modules: "none",
 			sdk_version: "none",
 			host_supported: true,
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
 		}
 
 		java_import {
 			name: "sdkmember_mysdk_1",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
 		}
 
 		java_import {
 			name: "sdkmember_mysdk_2",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
 		}
 
 		java_library {
@@ -141,7 +173,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "android_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -196,7 +228,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -230,6 +262,72 @@
 	)
 }
 
+func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			host_supported: true,
+			java_header_libs: ["myjavalib"],
+		}
+
+		java_library {
+			name: "myjavalib",
+			host_supported: true,
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    host_supported: true,
+    target: {
+        android: {
+            jars: ["java/android/myjavalib.jar"],
+        },
+        linux_glibc: {
+            jars: ["java/linux_glibc/myjavalib.jar"],
+        },
+    },
+}
+
+java_import {
+    name: "myjavalib",
+    prefer: false,
+    host_supported: true,
+    target: {
+        android: {
+            jars: ["java/android/myjavalib.jar"],
+        },
+        linux_glibc: {
+            jars: ["java/linux_glibc/myjavalib.jar"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    java_header_libs: ["mysdk_myjavalib@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+	)
+}
+
 func TestSnapshotWithJavaImplLibrary(t *testing.T) {
 	result := testSdkWithJava(t, `
 		module_exports {
@@ -250,7 +348,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "android_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -305,7 +403,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "linux_glibc_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -356,7 +454,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "android_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -409,7 +507,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "linux_glibc_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -503,7 +601,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "android_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -526,7 +624,7 @@
 
 `),
 		checkAllCopyRules(""),
-		checkMergeZip(".intermediates/myexports/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+		checkMergeZip(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
 	)
 }
 
@@ -552,7 +650,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("myexports", "linux_glibc_common", "",
+	result.CheckSnapshot("myexports", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -580,7 +678,7 @@
 }
 `),
 		checkAllCopyRules(""),
-		checkMergeZip(".intermediates/myexports/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+		checkMergeZip(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
 	)
 }
 
@@ -612,7 +710,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "android_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -702,7 +800,7 @@
 		}
 	`)
 
-	result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+	result.CheckSnapshot("mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -750,3 +848,194 @@
 		checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
 	)
 }
+
+func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithJava(t, `
+		module_exports {
+			name: "myexports",
+			host_supported: true,
+			java_libs: ["myjavalib"],
+			target: {
+				android: {
+					java_header_libs: ["androidjavalib"],
+				},
+				host: {
+					java_header_libs: ["hostjavalib"],
+				},
+			},
+		}
+
+		java_library {
+			name: "myjavalib",
+			host_supported: true,
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+		}
+
+		java_library {
+			name: "androidjavalib",
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+		}
+
+		java_library_host {
+			name: "hostjavalib",
+			srcs: ["Test.java"],
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "myexports_hostjavalib@current",
+    sdk_member_name: "hostjavalib",
+    device_supported: false,
+    host_supported: true,
+    jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+    name: "hostjavalib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+    name: "myexports_androidjavalib@current",
+    sdk_member_name: "androidjavalib",
+    jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+    name: "androidjavalib",
+    prefer: false,
+    jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+    name: "myexports_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    host_supported: true,
+    target: {
+        android: {
+            jars: ["java/android/myjavalib.jar"],
+        },
+        linux_glibc: {
+            jars: ["java/linux_glibc/myjavalib.jar"],
+        },
+    },
+}
+
+java_import {
+    name: "myjavalib",
+    prefer: false,
+    host_supported: true,
+    target: {
+        android: {
+            jars: ["java/android/myjavalib.jar"],
+        },
+        linux_glibc: {
+            jars: ["java/linux_glibc/myjavalib.jar"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    host_supported: true,
+    java_libs: ["myexports_myjavalib@current"],
+    target: {
+        android: {
+            java_header_libs: ["myexports_androidjavalib@current"],
+        },
+        linux_glibc: {
+            java_header_libs: ["myexports_hostjavalib@current"],
+        },
+    },
+}
+`),
+		checkAllCopyRules(`
+.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
+.intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
+.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+	)
+}
+
+func TestSnapshotWithJavaSdkLibrary(t *testing.T) {
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			java_sdk_libs: ["myjavalib"],
+		}
+
+		java_sdk_library {
+			name: "myjavalib",
+			apex_available: ["//apex_available:anyapex"],
+			srcs: ["Test.java"],
+			sdk_version: "current",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    apex_available: ["//apex_available:anyapex"],
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        sdk_version: "system_current",
+    },
+    test: {
+        jars: ["sdk_library/test/myjavalib-stubs.jar"],
+        sdk_version: "test_current",
+    },
+}
+
+java_sdk_library_import {
+    name: "myjavalib",
+    prefer: false,
+    apex_available: ["//apex_available:anyapex"],
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        sdk_version: "system_current",
+    },
+    test: {
+        jars: ["sdk_library/test/myjavalib-stubs.jar"],
+        sdk_version: "test_current",
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    java_sdk_libs: ["mysdk_myjavalib@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.test/android_common/javac/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
+`),
+	)
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 4976dc0..cb5a605 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -50,8 +50,17 @@
 	// list properties, e.g. java_libs.
 	dynamicMemberTypeListProperties interface{}
 
-	// The set of exported members.
-	exportedMembers map[string]struct{}
+	// Information about the OsType specific member variants associated with this variant.
+	//
+	// Set by OsType specific variants in the collectMembers() method and used by the
+	// CommonOS variant when building the snapshot. That work is all done on separate
+	// calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be
+	// called for the OsType specific variants before the CommonOS variant (because
+	// the latter depends on the former).
+	memberRefs []sdkMemberRef
+
+	// The multilib variants that are used by this sdk variant.
+	multilibUsages multilibUsage
 
 	properties sdkProperties
 
@@ -143,6 +152,7 @@
 		fields = append(fields, reflect.StructField{
 			Name: proptools.FieldNameForProperty(p),
 			Type: reflect.TypeOf([]string{}),
+			Tag:  `android:"arch_variant"`,
 		})
 
 		// Copy the field index for use in the getter func as using the loop variable directly will
@@ -201,7 +211,7 @@
 	// properties for the member type specific list properties.
 	s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties()
 	s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties)
-	android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
+	android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(s)
 	android.AddLoadHook(s, func(ctx android.LoadHookContext) {
 		type props struct {
@@ -225,26 +235,19 @@
 }
 
 func (s *sdk) getExportedMembers() map[string]struct{} {
-	if s.exportedMembers == nil {
-		// Collect all the exported members.
-		s.exportedMembers = make(map[string]struct{})
+	// Collect all the exported members.
+	exportedMembers := make(map[string]struct{})
 
-		for _, memberListProperty := range s.memberListProperties() {
-			names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+	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{}{}
-			}
+		// Every member specified explicitly in the properties is exported by the sdk.
+		for _, name := range names {
+			exportedMembers[name] = struct{}{}
 		}
 	}
 
-	return s.exportedMembers
-}
-
-func (s *sdk) isInternalMember(memberName string) bool {
-	_, ok := s.getExportedMembers()[memberName]
-	return !ok
+	return exportedMembers
 }
 
 func (s *sdk) snapshot() bool {
@@ -252,10 +255,31 @@
 }
 
 func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if !s.snapshot() {
+	if s.snapshot() {
 		// We don't need to create a snapshot out of sdk_snapshot.
 		// That doesn't make sense. We need a snapshot to create sdk_snapshot.
-		s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx))
+		return
+	}
+
+	// This method is guaranteed to be called on OsType specific variants before it is called
+	// on their corresponding CommonOS variant.
+	if !s.IsCommonOSVariant() {
+		// Update the OsType specific sdk variant with information about its members.
+		s.collectMembers(ctx)
+	} else {
+		// Get the OsType specific variants on which the CommonOS depends.
+		osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx)
+		var sdkVariants []*sdk
+		for _, m := range osSpecificVariants {
+			if sdkVariant, ok := m.(*sdk); ok {
+				sdkVariants = append(sdkVariants, sdkVariant)
+			}
+		}
+
+		// Generate the snapshot from the member info.
+		p := s.buildSnapshot(ctx, sdkVariants)
+		s.snapshotFile = android.OptionalPathForPath(p)
+		ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), s.Name()+"-current.zip", p)
 	}
 }
 
@@ -288,7 +312,7 @@
 	ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
 }
 
-// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
+// RegisterPostDepsMutators registers post-deps mutators to support modules implementing SdkAware
 // interface and the sdk module type. This function has been made public to be called by tests
 // outside of the sdk package
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
@@ -320,11 +344,14 @@
 // Step 1: create dependencies from an SDK module to its members.
 func memberMutator(mctx android.BottomUpMutatorContext) {
 	if s, ok := mctx.Module().(*sdk); ok {
-		if s.Enabled() {
+		// Add dependencies from enabled and non CommonOS variants to the sdk member variants.
+		if s.Enabled() && !s.IsCommonOSVariant() {
 			for _, memberListProperty := range s.memberListProperties() {
 				names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
-				tag := memberListProperty.dependencyTag
-				memberListProperty.memberType.AddDependencies(mctx, tag, names)
+				if len(names) > 0 {
+					tag := memberListProperty.dependencyTag
+					memberListProperty.memberType.AddDependencies(mctx, tag, names)
+				}
 			}
 		}
 	}
@@ -404,23 +431,31 @@
 	}
 }
 
-// Step 6: ensure that the dependencies from outside of the APEX are all from the required SDKs
+// Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs
 func sdkRequirementsMutator(mctx android.TopDownMutatorContext) {
 	if m, ok := mctx.Module().(interface {
-		DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool
-		RequiredSdks() android.SdkRefs
+		android.DepIsInSameApex
+		android.RequiredSdks
 	}); ok {
 		requiredSdks := m.RequiredSdks()
 		if len(requiredSdks) == 0 {
 			return
 		}
 		mctx.VisitDirectDeps(func(dep android.Module) {
-			if mctx.OtherModuleDependencyTag(dep) == android.DefaultsDepTag {
+			tag := mctx.OtherModuleDependencyTag(dep)
+			if tag == android.DefaultsDepTag {
 				// dependency to defaults is always okay
 				return
 			}
 
-			// If the dep is from outside of the APEX, but is not in any of the
+			// Ignore the dependency from the unversioned member to any versioned members as an
+			// apex that depends on the unversioned member will not also be depending on a versioned
+			// member.
+			if _, ok := tag.(sdkMemberVersionedDepTag); ok {
+				return
+			}
+
+			// If the dep is outside of the APEX, but is not in any of the
 			// required SDKs, we know that the dep is a violation.
 			if sa, ok := dep.(android.SdkAware); ok {
 				if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 53c2971..fde9230 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -16,6 +16,8 @@
 
 import (
 	"testing"
+
+	"github.com/google/blueprint/proptools"
 )
 
 // Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
@@ -146,7 +148,7 @@
 			"package/Android.bp": []byte(packageBp),
 		})
 
-	result.CheckSnapshot("mysdk", "android_common", "package",
+	result.CheckSnapshot("mysdk", "package",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -206,3 +208,122 @@
 }
 `))
 }
+
+func TestSDkInstall(t *testing.T) {
+	sdk := `
+		sdk {
+			name: "mysdk",
+		}
+	`
+	result := testSdkWithFs(t, ``,
+		map[string][]byte{
+			"Android.bp": []byte(sdk),
+		})
+
+	result.CheckSnapshot("mysdk", "",
+		checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
+	)
+}
+
+type EmbeddedPropertiesStruct struct {
+	S_Embedded_Common    string
+	S_Embedded_Different string
+}
+
+type testPropertiesStruct struct {
+	private     string
+	Public_Kept string `sdk:"keep"`
+	S_Common    string
+	S_Different string
+	A_Common    []string
+	A_Different []string
+	F_Common    *bool
+	F_Different *bool
+	EmbeddedPropertiesStruct
+}
+
+func TestCommonValueOptimization(t *testing.T) {
+	common := &testPropertiesStruct{}
+	structs := []*testPropertiesStruct{
+		&testPropertiesStruct{
+			private:     "common",
+			Public_Kept: "common",
+			S_Common:    "common",
+			S_Different: "upper",
+			A_Common:    []string{"first", "second"},
+			A_Different: []string{"alpha", "beta"},
+			F_Common:    proptools.BoolPtr(false),
+			F_Different: proptools.BoolPtr(false),
+			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+				S_Embedded_Common:    "embedded_common",
+				S_Embedded_Different: "embedded_upper",
+			},
+		},
+		&testPropertiesStruct{
+			private:     "common",
+			Public_Kept: "common",
+			S_Common:    "common",
+			S_Different: "lower",
+			A_Common:    []string{"first", "second"},
+			A_Different: []string{"alpha", "delta"},
+			F_Common:    proptools.BoolPtr(false),
+			F_Different: proptools.BoolPtr(true),
+			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+				S_Embedded_Common:    "embedded_common",
+				S_Embedded_Different: "embedded_lower",
+			},
+		},
+	}
+
+	extractor := newCommonValueExtractor(common)
+	extractor.extractCommonProperties(common, structs)
+
+	h := TestHelper{t}
+	h.AssertDeepEquals("common properties not correct", common,
+		&testPropertiesStruct{
+			private:     "",
+			Public_Kept: "",
+			S_Common:    "common",
+			S_Different: "",
+			A_Common:    []string{"first", "second"},
+			A_Different: []string(nil),
+			F_Common:    proptools.BoolPtr(false),
+			F_Different: nil,
+			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+				S_Embedded_Common:    "embedded_common",
+				S_Embedded_Different: "",
+			},
+		})
+
+	h.AssertDeepEquals("updated properties[0] not correct", structs[0],
+		&testPropertiesStruct{
+			private:     "common",
+			Public_Kept: "common",
+			S_Common:    "",
+			S_Different: "upper",
+			A_Common:    nil,
+			A_Different: []string{"alpha", "beta"},
+			F_Common:    nil,
+			F_Different: proptools.BoolPtr(false),
+			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+				S_Embedded_Common:    "",
+				S_Embedded_Different: "embedded_upper",
+			},
+		})
+
+	h.AssertDeepEquals("updated properties[1] not correct", structs[1],
+		&testPropertiesStruct{
+			private:     "common",
+			Public_Kept: "common",
+			S_Common:    "",
+			S_Different: "lower",
+			A_Common:    nil,
+			A_Different: []string{"alpha", "delta"},
+			F_Common:    nil,
+			F_Different: proptools.BoolPtr(true),
+			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+				S_Embedded_Common:    "",
+				S_Embedded_Different: "embedded_lower",
+			},
+		})
+}
diff --git a/sdk/testing.go b/sdk/testing.go
index ae0620d..570ea0f 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -19,6 +19,7 @@
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"reflect"
 	"strings"
 	"testing"
 
@@ -40,7 +41,7 @@
 			name: "myapex.cert",
 			certificate: "myapex",
 		}
-	` + cc.GatherRequiredDepsForTest(android.Android)
+	` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
 
 	mockFS := map[string][]byte{
 		"build/make/target/product/security":         nil,
@@ -61,8 +62,24 @@
 
 	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()
 
+	// Enable androidmk support.
+	// * Register the singleton
+	// * Configure that we are inside make
+	// * Add CommonOS to ensure that androidmk processing works.
+	android.RegisterAndroidMkBuildComponents(ctx)
+	android.SetInMakeForTests(config)
+	config.Targets[android.CommonOS] = []android.Target{
+		{android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", ""},
+	}
+
 	// from android package
 	android.RegisterPackageBuildComponents(ctx)
 	ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
@@ -73,6 +90,7 @@
 	// from java package
 	java.RegisterJavaBuildComponents(ctx)
 	java.RegisterAppBuildComponents(ctx)
+	java.RegisterSdkLibraryBuildComponents(ctx)
 	java.RegisterStubsBuildComponents(ctx)
 	java.RegisterSystemModulesBuildComponents(ctx)
 
@@ -160,6 +178,13 @@
 	h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
 }
 
+func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
+	h.t.Helper()
+	if !reflect.DeepEqual(actual, expected) {
+		h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual)
+	}
+}
+
 // Encapsulates result of processing an SDK definition. Provides support for
 // checking the state of the build structures.
 type testSdkResult struct {
@@ -182,15 +207,23 @@
 
 	buildParams := sdk.BuildParamsForTests()
 	copyRules := &strings.Builder{}
+	otherCopyRules := &strings.Builder{}
+	snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"
 	for _, bp := range buildParams {
 		switch bp.Rule.String() {
 		case android.Cp.String():
-			// Get source relative to build directory.
-			src := android.NormalizePathForTesting(bp.Input)
+			output := bp.Output
 			// Get destination relative to the snapshot root
-			dest := bp.Output.Rel()
-			_, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
-			info.snapshotContents = append(info.snapshotContents, dest)
+			dest := output.Rel()
+			src := android.NormalizePathForTesting(bp.Input)
+			// We differentiate between copy rules for the snapshot, and copy rules for the install file.
+			if strings.HasPrefix(output.String(), snapshotDirPrefix) {
+				// Get source relative to build directory.
+				_, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
+				info.snapshotContents = append(info.snapshotContents, dest)
+			} else {
+				_, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
+			}
 
 		case repackageZip.String():
 			// Add the destdir to the snapshot contents as that is effectively where
@@ -223,6 +256,7 @@
 	}
 
 	info.copyRules = copyRules.String()
+	info.otherCopyRules = otherCopyRules.String()
 
 	return info
 }
@@ -240,9 +274,12 @@
 // Takes a list of functions which check different facets of the snapshot build rules.
 // Allows each test to customize what is checked without duplicating lots of code
 // or proliferating check methods of different flavors.
-func (r *testSdkResult) CheckSnapshot(name string, variant string, dir string, checkers ...snapshotBuildInfoChecker) {
+func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snapshotBuildInfoChecker) {
 	r.t.Helper()
 
+	// The sdk CommonOS variant is always responsible for generating the snapshot.
+	variant := android.CommonOS.Name
+
 	sdk := r.Module(name, variant).(*sdk)
 
 	snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk)
@@ -295,6 +332,13 @@
 	}
 }
 
+func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
+	return func(info *snapshotBuildInfo) {
+		info.r.t.Helper()
+		info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
+	}
+}
+
 // Check that the specified path is in the list of zips to merge with the intermediate zip.
 func checkMergeZip(expected string) snapshotBuildInfoChecker {
 	return func(info *snapshotBuildInfo) {
@@ -321,10 +365,14 @@
 	// snapshot.
 	snapshotContents []string
 
-	// A formatted representation of the src/dest pairs, one pair per line, of the format
-	// src -> dest
+	// A formatted representation of the src/dest pairs for a snapshot, one pair per line,
+	// of the format src -> dest
 	copyRules string
 
+	// A formatted representation of the src/dest pairs for files not in a snapshot, one pair
+	// per line, of the format src -> dest
+	otherCopyRules string
+
 	// The path to the intermediate zip, which is a zip created from the source files copied
 	// into the snapshot directory and which will be merged with other zips to form the final output.
 	// Is am empty string if there is no intermediate zip because there are no zips to merge in.
diff --git a/sdk/update.go b/sdk/update.go
index ff567be..e14347f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -17,8 +17,11 @@
 import (
 	"fmt"
 	"reflect"
+	"sort"
 	"strings"
 
+	"android/soong/apex"
+	"android/soong/cc"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -104,13 +107,10 @@
 
 // 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.SdkMemberTypesRegistry.
-// The names are in the order in which the dependencies were added.
-func (s *sdk) collectMembers(ctx android.ModuleContext) []*sdkMember {
-	byType := make(map[android.SdkMemberType][]*sdkMember)
-	byName := make(map[string]*sdkMember)
-
+// Returns a list containing type (extracted from the dependency tag) and the variant
+// plus the multilib usages.
+func (s *sdk) collectMembers(ctx android.ModuleContext) {
+	s.multilibUsages = multilibNone
 	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
@@ -121,18 +121,10 @@
 				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
 			}
 
-			name := ctx.OtherModuleName(child)
+			// Keep track of which multilib variants are used by the sdk.
+			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
 
-			member := byName[name]
-			if member == nil {
-				member = &sdkMember{memberType: memberType, name: name}
-				byName[name] = member
-				byType[memberType] = append(byType[memberType], member)
-			}
-
-			// 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))
+			s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
 
 			// If the member type supports transitive sdk members then recurse down into
 			// its dependencies, otherwise exit traversal.
@@ -141,6 +133,35 @@
 
 		return false
 	})
+}
+
+// Organize 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.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) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember {
+	byType := make(map[android.SdkMemberType][]*sdkMember)
+	byName := make(map[string]*sdkMember)
+
+	for _, memberRef := range memberRefs {
+		memberType := memberRef.memberType
+		variant := memberRef.variant
+
+		name := ctx.OtherModuleName(variant)
+		member := byName[name]
+		if member == nil {
+			member = &sdkMember{memberType: memberType, name: name}
+			byName[name] = member
+			byType[memberType] = append(byType[memberType], member)
+		}
+
+		// 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, variant)
+	}
 
 	var members []*sdkMember
 	for _, memberListProperty := range s.memberListProperties() {
@@ -186,7 +207,26 @@
 
 // buildSnapshot is the main function in this source file. It creates rules to copy
 // the contents (header files, stub libraries, etc) into the zip file.
-func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
+func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
+
+	allMembersByName := make(map[string]struct{})
+	exportedMembersByName := make(map[string]struct{})
+	var memberRefs []sdkMemberRef
+	for _, sdkVariant := range sdkVariants {
+		memberRefs = append(memberRefs, sdkVariant.memberRefs...)
+
+		// Record the names of all the members, both explicitly specified and implicitly
+		// included.
+		for _, memberRef := range sdkVariant.memberRefs {
+			allMembersByName[memberRef.variant.Name()] = struct{}{}
+		}
+
+		// Merge the exported member sets from all sdk variants.
+		for key, _ := range sdkVariant.getExportedMembers() {
+			exportedMembersByName[key] = struct{}{}
+		}
+	}
+
 	snapshotDir := android.PathForModuleOut(ctx, "snapshot")
 
 	bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
@@ -196,19 +236,27 @@
 	}
 
 	builder := &snapshotBuilder{
-		ctx:             ctx,
-		sdk:             s,
-		version:         "current",
-		snapshotDir:     snapshotDir.OutputPath,
-		copies:          make(map[string]string),
-		filesToZip:      []android.Path{bp.path},
-		bpFile:          bpFile,
-		prebuiltModules: make(map[string]*bpModule),
+		ctx:                   ctx,
+		sdk:                   s,
+		version:               "current",
+		snapshotDir:           snapshotDir.OutputPath,
+		copies:                make(map[string]string),
+		filesToZip:            []android.Path{bp.path},
+		bpFile:                bpFile,
+		prebuiltModules:       make(map[string]*bpModule),
+		allMembersByName:      allMembersByName,
+		exportedMembersByName: exportedMembersByName,
 	}
 	s.builderForTests = builder
 
-	for _, member := range s.collectMembers(ctx) {
-		member.memberType.BuildSnapshot(ctx, builder, member)
+	members := s.organizeMembers(ctx, memberRefs)
+	for _, member := range members {
+		memberType := member.memberType
+
+		memberCtx := &memberContext{ctx, builder, memberType, member.name}
+
+		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
+		s.createMemberSnapshot(memberCtx, member, prebuiltModule)
 	}
 
 	// Create a transformer that will transform an unversioned module into a versioned module.
@@ -219,6 +267,9 @@
 	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()
 
@@ -248,13 +299,46 @@
 		snapshotModule.AddProperty("visibility", visibility)
 	}
 
-	addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
-	for _, memberListProperty := range s.memberListProperties() {
-		names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
-		if len(names) > 0 {
-			snapshotModule.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names))
+	addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
+
+	var dynamicMemberPropertiesList []interface{}
+	osTypeToMemberProperties := make(map[android.OsType]*sdk)
+	for _, sdkVariant := range sdkVariants {
+		properties := sdkVariant.dynamicMemberTypeListProperties
+		osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant
+		dynamicMemberPropertiesList = append(dynamicMemberPropertiesList, properties)
+	}
+
+	// Extract the common lists of members into a separate struct.
+	commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
+	extractor := newCommonValueExtractor(commonDynamicMemberProperties)
+	extractor.extractCommonProperties(commonDynamicMemberProperties, dynamicMemberPropertiesList)
+
+	// Add properties common to all os types.
+	s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
+
+	// Iterate over the os types in a fixed order.
+	targetPropertySet := snapshotModule.AddPropertySet("target")
+	for _, osType := range s.getPossibleOsTypes() {
+		if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
+			osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
+
+			// 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.
+			multilib := sdkVariant.multilibUsages
+			if (osType.Class == android.Host || osType.Class == android.HostCross) &&
+				multilib != multilibNone && multilib != multilibBoth {
+				osPropertySet.AddProperty("compile_multilib", multilib.String())
+			}
+
+			s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
 		}
 	}
+
+	// Prune any empty property sets.
+	snapshotModule.transform(pruneEmptySetTransformer{})
+
 	bpFile.AddModule(snapshotModule)
 
 	// generate Android.bp
@@ -305,11 +389,32 @@
 	return outputZipFile
 }
 
+func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) {
+	for _, memberListProperty := range s.memberListProperties() {
+		names := memberListProperty.getter(dynamicMemberTypeListProperties)
+		if len(names) > 0 {
+			propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
+		}
+	}
+}
+
 type propertyTag struct {
 	name string
 }
 
-var sdkMemberReferencePropertyTag = propertyTag{"sdkMemberReferencePropertyTag"}
+// A BpPropertyTag to add to a property that contains references to other sdk members.
+//
+// This will cause the references to be rewritten to a versioned reference in the version
+// specific instance of a snapshot module.
+var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
+var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
+
+// A BpPropertyTag that indicates the property should only be present in the versioned
+// module.
+//
+// This will cause the property to be removed from the unversioned instance of a
+// snapshot module.
+var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"}
 
 type unversionedToVersionedTransformation struct {
 	identityTransformation
@@ -320,14 +425,15 @@
 	// Use a versioned name for the module but remember the original name for the
 	// snapshot.
 	name := module.getValue("name").(string)
-	module.setProperty("name", t.builder.versionedSdkMemberName(name))
+	module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
 	module.insertAfter("name", "sdk_member_name", name)
 	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
+	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+		required := tag == requiredSdkMemberReferencePropertyTag
+		return t.builder.versionedSdkMemberNames(value.([]string), required), tag
 	} else {
 		return value, tag
 	}
@@ -341,7 +447,7 @@
 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))
+	module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
 
 	// Set prefer: false - this is not strictly required as that is the default.
 	module.insertAfter("name", "prefer", false)
@@ -350,13 +456,31 @@
 }
 
 func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
-	if tag == sdkMemberReferencePropertyTag {
-		return t.builder.unversionedSdkMemberNames(value.([]string)), tag
+	if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+		required := tag == requiredSdkMemberReferencePropertyTag
+		return t.builder.unversionedSdkMemberNames(value.([]string), required), tag
+	} else if tag == sdkVersionedOnlyPropertyTag {
+		// The property is not allowed in the unversioned module so remove it.
+		return nil, nil
 	} 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 {
@@ -369,41 +493,53 @@
 
 func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
 	contents.Indent()
+
+	// Output the properties first, followed by the nested sets. This ensures a
+	// consistent output irrespective of whether property sets are created before
+	// or after the properties. This simplifies the creation of the module.
 	for _, name := range set.order {
 		value := set.getValue(name)
 
-		reflectedValue := reflect.ValueOf(value)
-		t := reflectedValue.Type()
-
-		kind := t.Kind()
-		switch kind {
-		case reflect.Slice:
-			length := reflectedValue.Len()
+		switch v := value.(type) {
+		case []string:
+			length := len(v)
 			if length > 1 {
 				contents.Printfln("%s: [", name)
 				contents.Indent()
 				for i := 0; i < length; i = i + 1 {
-					contents.Printfln("%q,", reflectedValue.Index(i).Interface())
+					contents.Printfln("%q,", v[i])
 				}
 				contents.Dedent()
 				contents.Printfln("],")
 			} else if length == 0 {
 				contents.Printfln("%s: [],", name)
 			} else {
-				contents.Printfln("%s: [%q],", name, reflectedValue.Index(0).Interface())
+				contents.Printfln("%s: [%q],", name, v[0])
 			}
-		case reflect.Bool:
-			contents.Printfln("%s: %t,", name, reflectedValue.Bool())
 
-		case reflect.Ptr:
-			contents.Printfln("%s: {", name)
-			outputPropertySet(contents, reflectedValue.Interface().(*bpPropertySet))
-			contents.Printfln("},")
+		case bool:
+			contents.Printfln("%s: %t,", name, v)
+
+		case *bpPropertySet:
+			// Do not write property sets in the properties phase.
 
 		default:
 			contents.Printfln("%s: %q,", name, value)
 		}
 	}
+
+	for _, name := range set.order {
+		value := set.getValue(name)
+
+		// Only write property sets in the sets phase.
+		switch v := value.(type) {
+		case *bpPropertySet:
+			contents.Printfln("%s: {", name)
+			outputPropertySet(contents, v)
+			contents.Printfln("},")
+		}
+	}
+
 	contents.Dedent()
 }
 
@@ -429,6 +565,12 @@
 
 	prebuiltModules map[string]*bpModule
 	prebuiltOrder   []*bpModule
+
+	// The set of all members by name.
+	allMembersByName map[string]struct{}
+
+	// The set of exported members by name.
+	exportedMembersByName map[string]struct{}
 }
 
 func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -480,69 +622,137 @@
 	m := s.bpFile.newModule(moduleType)
 	m.AddProperty("name", name)
 
-	if s.sdk.isInternalMember(name) {
+	variant := member.Variants()[0]
+
+	if s.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])
+		visibility := android.EffectiveVisibilityRules(s.ctx, variant)
 		if len(visibility) != 0 {
 			m.AddProperty("visibility", visibility)
 		}
 	}
 
-	addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
+	deviceSupported := false
+	hostSupported := false
+
+	for _, variant := range member.Variants() {
+		osClass := variant.Target().Os.Class
+		if osClass == android.Host || osClass == android.HostCross {
+			hostSupported = true
+		} else if osClass == android.Device {
+			deviceSupported = true
+		}
+	}
+
+	addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
+
+	// Where available copy apex_available properties from the member.
+	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
+		apexAvailable := apexAware.ApexAvailable()
+
+		// Add in any white listed apex available settings.
+		apexAvailable = append(apexAvailable, apex.WhitelistedApexAvailable(member.Name())...)
+
+		if len(apexAvailable) > 0 {
+			// Remove duplicates and sort.
+			apexAvailable = android.FirstUniqueStrings(apexAvailable)
+			sort.Strings(apexAvailable)
+
+			m.AddProperty("apex_available", apexAvailable)
+		}
+	}
+
+	// Disable installation in the versioned module of those modules that are ever installable.
+	if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
+		if installable.EverInstallable() {
+			m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag)
+		}
+	}
 
 	s.prebuiltModules[name] = m
 	s.prebuiltOrder = append(s.prebuiltOrder, m)
 	return m
 }
 
-func addHostDeviceSupportedProperties(module *android.ModuleBase, bpModule *bpModule) {
-	if !module.DeviceSupported() {
+func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
+	if !deviceSupported {
 		bpModule.AddProperty("device_supported", false)
 	}
-	if module.HostSupported() {
+	if hostSupported {
 		bpModule.AddProperty("host_supported", true)
 	}
 }
 
-func (s *snapshotBuilder) SdkMemberReferencePropertyTag() android.BpPropertyTag {
-	return sdkMemberReferencePropertyTag
+func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
+	if required {
+		return requiredSdkMemberReferencePropertyTag
+	} else {
+		return optionalSdkMemberReferencePropertyTag
+	}
+}
+
+func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
+	return optionalSdkMemberReferencePropertyTag
 }
 
 // Get a versioned name appropriate for the SDK snapshot version being taken.
-func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
+func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string {
+	if _, ok := s.allMembersByName[unversionedName]; !ok {
+		if required {
+			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+		}
+		return unversionedName
+	}
 	return versionedSdkMemberName(s.ctx, unversionedName, s.version)
 }
 
-func (s *snapshotBuilder) versionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string {
 	var references []string = nil
 	for _, m := range members {
-		references = append(references, s.versionedSdkMemberName(m))
+		references = append(references, s.versionedSdkMemberName(m, required))
 	}
 	return references
 }
 
 // Get an internal name unique to the sdk.
-func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string) string {
-	if s.sdk.isInternalMember(unversionedName) {
+func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string {
+	if _, ok := s.allMembersByName[unversionedName]; !ok {
+		if required {
+			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+		}
+		return unversionedName
+	}
+
+	if s.isInternalMember(unversionedName) {
 		return s.ctx.ModuleName() + "_" + unversionedName
 	} else {
 		return unversionedName
 	}
 }
 
-func (s *snapshotBuilder) unversionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string {
 	var references []string = nil
 	for _, m := range members {
-		references = append(references, s.unversionedSdkMemberName(m))
+		references = append(references, s.unversionedSdkMemberName(m, required))
 	}
 	return references
 }
 
+func (s *snapshotBuilder) isInternalMember(memberName string) bool {
+	_, ok := s.exportedMembersByName[memberName]
+	return !ok
+}
+
+type sdkMemberRef struct {
+	memberType android.SdkMemberType
+	variant    android.SdkAware
+}
+
 var _ android.SdkMember = (*sdkMember)(nil)
 
 type sdkMember struct {
@@ -558,3 +768,556 @@
 func (m *sdkMember) Variants() []android.SdkAware {
 	return m.variants
 }
+
+// Track usages of multilib variants.
+type multilibUsage int
+
+const (
+	multilibNone multilibUsage = 0
+	multilib32   multilibUsage = 1
+	multilib64   multilibUsage = 2
+	multilibBoth               = multilib32 | multilib64
+)
+
+// Add the multilib that is used in the arch type.
+func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
+	multilib := archType.Multilib
+	switch multilib {
+	case "":
+		return m
+	case "lib32":
+		return m | multilib32
+	case "lib64":
+		return m | multilib64
+	default:
+		panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
+	}
+}
+
+func (m multilibUsage) String() string {
+	switch m {
+	case multilibNone:
+		return ""
+	case multilib32:
+		return "32"
+	case multilib64:
+		return "64"
+	case multilibBoth:
+		return "both"
+	default:
+		panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
+			m, multilibNone, multilib32, multilib64, multilibBoth))
+	}
+}
+
+type baseInfo struct {
+	Properties android.SdkMemberProperties
+}
+
+type osTypeSpecificInfo struct {
+	baseInfo
+
+	osType android.OsType
+
+	// The list of arch type specific info for this os type.
+	//
+	// Nil if there is one variant whose arch type is common
+	archInfos []*archTypeSpecificInfo
+}
+
+type variantPropertiesFactoryFunc func() android.SdkMemberProperties
+
+// Create a new osTypeSpecificInfo for the specified os type and its properties
+// structures populated with information from the variants.
+func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
+	osInfo := &osTypeSpecificInfo{
+		osType: osType,
+	}
+
+	osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
+		properties := variantPropertiesFactory()
+		properties.Base().Os = osType
+		return properties
+	}
+
+	// Create a structure into which properties common across the architectures in
+	// this os type will be stored.
+	osInfo.Properties = osSpecificVariantPropertiesFactory()
+
+	// Group the variants by arch type.
+	var variantsByArchName = make(map[string][]android.Module)
+	var archTypes []android.ArchType
+	for _, variant := range osTypeVariants {
+		archType := variant.Target().Arch.ArchType
+		archTypeName := archType.Name
+		if _, ok := variantsByArchName[archTypeName]; !ok {
+			archTypes = append(archTypes, archType)
+		}
+
+		variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
+	}
+
+	if commonVariants, ok := variantsByArchName["common"]; ok {
+		if len(osTypeVariants) != 1 {
+			panic("Expected to only have 1 variant when arch type is common but found " + string(len(osTypeVariants)))
+		}
+
+		// A common arch type only has one variant and its properties should be treated
+		// as common to the os type.
+		osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
+	} else {
+		// Create an arch specific info for each supported architecture type.
+		for _, archType := range archTypes {
+			archTypeName := archType.Name
+
+			archVariants := variantsByArchName[archTypeName]
+			archInfo := newArchSpecificInfo(ctx, archType, osSpecificVariantPropertiesFactory, archVariants)
+
+			osInfo.archInfos = append(osInfo.archInfos, archInfo)
+		}
+	}
+
+	return osInfo
+}
+
+// Optimize the properties by extracting common properties from arch type specific
+// properties into os type specific properties.
+func (osInfo *osTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+	// Nothing to do if there is only a single common architecture.
+	if len(osInfo.archInfos) == 0 {
+		return
+	}
+
+	multilib := multilibNone
+	var archPropertiesList []android.SdkMemberProperties
+	for _, archInfo := range osInfo.archInfos {
+		multilib = multilib.addArchType(archInfo.archType)
+
+		// Optimize the arch properties first.
+		archInfo.optimizeProperties(commonValueExtractor)
+
+		archPropertiesList = append(archPropertiesList, archInfo.Properties)
+	}
+
+	commonValueExtractor.extractCommonProperties(osInfo.Properties, archPropertiesList)
+
+	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+	osInfo.Properties.Base().Compile_multilib = multilib.String()
+}
+
+// Add the properties for an os to a property set.
+//
+// Maps the properties related to the os variants through to an appropriate
+// module structure that will produce equivalent set of variants when it is
+// processed in a build.
+func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
+
+	var osPropertySet android.BpPropertySet
+	var archPropertySet android.BpPropertySet
+	var archOsPrefix string
+	if osInfo.Properties.Base().Os_count == 1 {
+		// There is only one os type present in the variants so don't bother
+		// with adding target specific properties.
+
+		// Create a structure that looks like:
+		// module_type {
+		//   name: "...",
+		//   ...
+		//   <common properties>
+		//   ...
+		//   <single os type specific properties>
+		//
+		//   arch: {
+		//     <arch specific sections>
+		//   }
+		//
+		osPropertySet = bpModule
+		archPropertySet = osPropertySet.AddPropertySet("arch")
+
+		// Arch specific properties need to be added to an arch specific section
+		// within arch.
+		archOsPrefix = ""
+	} else {
+		// Create a structure that looks like:
+		// module_type {
+		//   name: "...",
+		//   ...
+		//   <common properties>
+		//   ...
+		//   target: {
+		//     <arch independent os specific sections, e.g. android>
+		//     ...
+		//     <arch and os specific sections, e.g. android_x86>
+		//   }
+		//
+		osType := osInfo.osType
+		osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
+		archPropertySet = targetPropertySet
+
+		// Arch specific properties need to be added to an os and arch specific
+		// section prefixed with <os>_.
+		archOsPrefix = osType.Name + "_"
+	}
+
+	// Add the os specific but arch independent properties to the module.
+	osInfo.Properties.AddToPropertySet(ctx, osPropertySet)
+
+	// Add arch (and possibly os) specific sections for each set of arch (and possibly
+	// os) specific properties.
+	//
+	// The archInfos list will be empty if the os contains variants for the common
+	// architecture.
+	for _, archInfo := range osInfo.archInfos {
+		archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
+	}
+}
+
+type archTypeSpecificInfo struct {
+	baseInfo
+
+	archType android.ArchType
+
+	linkInfos []*linkTypeSpecificInfo
+}
+
+// Create a new archTypeSpecificInfo for the specified arch type and its properties
+// structures populated with information from the variants.
+func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
+
+	// Create an arch specific info into which the variant properties can be copied.
+	archInfo := &archTypeSpecificInfo{archType: archType}
+
+	// Create the properties into which the arch type specific properties will be
+	// added.
+	archInfo.Properties = variantPropertiesFactory()
+
+	if len(archVariants) == 1 {
+		archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
+	} else {
+		// There is more than one variant for this arch type which must be differentiated
+		// by link type.
+		for _, linkVariant := range archVariants {
+			linkType := getLinkType(linkVariant)
+			if linkType == "" {
+				panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
+			} else {
+				linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
+
+				archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
+			}
+		}
+	}
+
+	return archInfo
+}
+
+// Get the link type of the variant
+//
+// If the variant is not differentiated by link type then it returns "",
+// otherwise it returns one of "static" or "shared".
+func getLinkType(variant android.Module) string {
+	linkType := ""
+	if linkable, ok := variant.(cc.LinkableInterface); ok {
+		if linkable.Shared() && linkable.Static() {
+			panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
+		} else if linkable.Shared() {
+			linkType = "shared"
+		} else if linkable.Static() {
+			linkType = "static"
+		} else {
+			panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
+		}
+	}
+	return linkType
+}
+
+// Optimize the properties by extracting common properties from link type specific
+// properties into arch type specific properties.
+func (archInfo *archTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+	if len(archInfo.linkInfos) == 0 {
+		return
+	}
+
+	var propertiesList []android.SdkMemberProperties
+	for _, linkInfo := range archInfo.linkInfos {
+		propertiesList = append(propertiesList, linkInfo.Properties)
+	}
+
+	commonValueExtractor.extractCommonProperties(archInfo.Properties, propertiesList)
+}
+
+// Add the properties for an arch type to a property set.
+func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
+	archTypeName := archInfo.archType.Name
+	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
+	archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
+
+	for _, linkInfo := range archInfo.linkInfos {
+		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
+		linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet)
+	}
+}
+
+type linkTypeSpecificInfo struct {
+	baseInfo
+
+	linkType string
+}
+
+// Create a new linkTypeSpecificInfo for the specified link type and its properties
+// structures populated with information from the variant.
+func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
+	linkInfo := &linkTypeSpecificInfo{
+		baseInfo: baseInfo{
+			// Create the properties into which the link type specific properties will be
+			// added.
+			Properties: variantPropertiesFactory(),
+		},
+		linkType: linkType,
+	}
+	linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
+	return linkInfo
+}
+
+type memberContext struct {
+	sdkMemberContext android.ModuleContext
+	builder          *snapshotBuilder
+	memberType       android.SdkMemberType
+	name             string
+}
+
+func (m *memberContext) SdkModuleContext() android.ModuleContext {
+	return m.sdkMemberContext
+}
+
+func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
+	return m.builder
+}
+
+func (m *memberContext) MemberType() android.SdkMemberType {
+	return m.memberType
+}
+
+func (m *memberContext) Name() string {
+	return m.name
+}
+
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
+
+	memberType := member.memberType
+
+	// Group the variants by os type.
+	variantsByOsType := make(map[android.OsType][]android.Module)
+	variants := member.Variants()
+	for _, variant := range variants {
+		osType := variant.Target().Os
+		variantsByOsType[osType] = append(variantsByOsType[osType], variant)
+	}
+
+	osCount := len(variantsByOsType)
+	variantPropertiesFactory := func() android.SdkMemberProperties {
+		properties := memberType.CreateVariantPropertiesStruct()
+		base := properties.Base()
+		base.Os_count = osCount
+		return properties
+	}
+
+	osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
+
+	// The set of properties that are common across all architectures and os types.
+	commonProperties := variantPropertiesFactory()
+	commonProperties.Base().Os = android.CommonOS
+
+	// Create common value extractor that can be used to optimize the properties.
+	commonValueExtractor := newCommonValueExtractor(commonProperties)
+
+	// The list of property structures which are os type specific but common across
+	// architectures within that os type.
+	var osSpecificPropertiesList []android.SdkMemberProperties
+
+	for osType, osTypeVariants := range variantsByOsType {
+		osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
+		osTypeToInfo[osType] = osInfo
+		// Add the os specific properties to a list of os type specific yet architecture
+		// independent properties structs.
+		osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
+
+		// Optimize the properties across all the variants for a specific os type.
+		osInfo.optimizeProperties(commonValueExtractor)
+	}
+
+	// Extract properties which are common across all architectures and os types.
+	commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesList)
+
+	// Add the common properties to the module.
+	commonProperties.AddToPropertySet(ctx, bpModule)
+
+	// Create a target property set into which target specific properties can be
+	// added.
+	targetPropertySet := bpModule.AddPropertySet("target")
+
+	// Iterate over the os types in a fixed order.
+	for _, osType := range s.getPossibleOsTypes() {
+		osInfo := osTypeToInfo[osType]
+		if osInfo == nil {
+			continue
+		}
+
+		osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
+	}
+}
+
+// Compute the list of possible os types that this sdk could support.
+func (s *sdk) getPossibleOsTypes() []android.OsType {
+	var osTypes []android.OsType
+	for _, osType := range android.OsTypeList {
+		if s.DeviceSupported() {
+			if osType.Class == android.Device && osType != android.Fuchsia {
+				osTypes = append(osTypes, osType)
+			}
+		}
+		if s.HostSupported() {
+			if osType.Class == android.Host || osType.Class == android.HostCross {
+				osTypes = append(osTypes, osType)
+			}
+		}
+	}
+	sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
+	return osTypes
+}
+
+// Given a struct value, access a field within that struct (or one of its embedded
+// structs).
+type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
+
+// Supports extracting common values from a number of instances of a properties
+// structure into a separate common set of properties.
+type commonValueExtractor struct {
+	// The getters for every field from which common values can be extracted.
+	fieldGetters []fieldAccessorFunc
+}
+
+// Create a new common value extractor for the structure type for the supplied
+// properties struct.
+//
+// The returned extractor can be used on any properties structure of the same type
+// as the supplied set of properties.
+func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
+	structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
+	extractor := &commonValueExtractor{}
+	extractor.gatherFields(structType, nil)
+	return extractor
+}
+
+// Gather the fields from the supplied structure type from which common values will
+// be extracted.
+//
+// This is recursive function. If it encounters an embedded field (no field name)
+// that is a struct then it will recurse into that struct passing in the accessor
+// for the field. That will then be used in the accessors for the fields in the
+// embedded struct.
+func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc) {
+	for f := 0; f < structType.NumField(); f++ {
+		field := structType.Field(f)
+		if field.PkgPath != "" {
+			// Ignore unexported fields.
+			continue
+		}
+
+		// Ignore fields whose value should be kept.
+		if proptools.HasTag(field, "sdk", "keep") {
+			continue
+		}
+
+		// Save a copy of the field index for use in the function.
+		fieldIndex := f
+		fieldGetter := func(value reflect.Value) reflect.Value {
+			if containingStructAccessor != nil {
+				// This is an embedded structure so first access the field for the embedded
+				// structure.
+				value = containingStructAccessor(value)
+			}
+
+			// Skip through interface and pointer values to find the structure.
+			value = getStructValue(value)
+
+			// Return the field.
+			return value.Field(fieldIndex)
+		}
+
+		if field.Type.Kind() == reflect.Struct && field.Anonymous {
+			// Gather fields from the embedded structure.
+			e.gatherFields(field.Type, fieldGetter)
+		} else {
+			e.fieldGetters = append(e.fieldGetters, fieldGetter)
+		}
+	}
+}
+
+func getStructValue(value reflect.Value) reflect.Value {
+foundStruct:
+	for {
+		kind := value.Kind()
+		switch kind {
+		case reflect.Interface, reflect.Ptr:
+			value = value.Elem()
+		case reflect.Struct:
+			break foundStruct
+		default:
+			panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
+		}
+	}
+	return value
+}
+
+// Extract common properties from a slice of property structures of the same type.
+//
+// All the property structures must be of the same type.
+// commonProperties - must be a pointer to the structure into which common properties will be added.
+// inputPropertiesSlice - must be a slice of input properties structures.
+//
+// Iterates over each exported field (capitalized name) and checks to see whether they
+// have the same value (using DeepEquals) across all the input properties. If it does not then no
+// change is made. Otherwise, the common value is stored in the field in the commonProperties
+// and the field in each of the input properties structure is set to its default value.
+func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
+	commonPropertiesValue := reflect.ValueOf(commonProperties)
+	commonStructValue := commonPropertiesValue.Elem()
+
+	for _, fieldGetter := range e.fieldGetters {
+		// Check to see if all the structures have the same value for the field. The commonValue
+		// is nil on entry to the loop and if it is nil on exit then there is no common value,
+		// otherwise it points to the common value.
+		var commonValue *reflect.Value
+		sliceValue := reflect.ValueOf(inputPropertiesSlice)
+
+		for i := 0; i < sliceValue.Len(); i++ {
+			itemValue := sliceValue.Index(i)
+			fieldValue := fieldGetter(itemValue)
+
+			if commonValue == nil {
+				// Use the first value as the commonProperties value.
+				commonValue = &fieldValue
+			} else {
+				// If the value does not match the current common value then there is
+				// no value in common so break out.
+				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
+					commonValue = nil
+					break
+				}
+			}
+		}
+
+		// If the fields all have a common value then store it in the common struct field
+		// and set the input struct's field to the empty value.
+		if commonValue != nil {
+			emptyValue := reflect.Zero(commonValue.Type())
+			fieldGetter(commonStructValue).Set(*commonValue)
+			for i := 0; i < sliceValue.Len(); i++ {
+				itemValue := sliceValue.Index(i)
+				fieldValue := fieldGetter(itemValue)
+				fieldValue.Set(emptyValue)
+			}
+		}
+	}
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index ce404f8..14fab68 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -115,6 +115,7 @@
 
 type syspropLibrary struct {
 	android.ModuleBase
+	android.ApexModuleBase
 
 	properties syspropLibraryProperties
 
@@ -144,8 +145,17 @@
 	// 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"`
+
+	Cpp struct {
+		// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+		// Forwarded to cc_library.min_sdk_version
+		Min_sdk_version *string
+	}
 }
 
 var (
@@ -293,6 +303,7 @@
 		&m.properties,
 	)
 	android.InitAndroidModule(m)
+	android.InitApexModule(m)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
 	return m
 }
@@ -306,12 +317,22 @@
 	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
+	Apex_available     []string
+	Min_sdk_version    *string
 }
 
 type javaLibraryProperties struct {
@@ -394,10 +415,14 @@
 	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
+	ccProps.Apex_available = m.ApexProperties.Apex_available
+	ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
 	scope := "internal"
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 7cad3da..8503386 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -15,6 +15,8 @@
 package sysprop
 
 import (
+	"reflect"
+
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/java"
@@ -157,10 +159,12 @@
 	ctx := test(t, `
 		sysprop_library {
 			name: "sysprop-platform",
+			apex_available: ["//apex_available:platform"],
 			srcs: ["android/sysprop/PlatformProperties.sysprop"],
 			api_packages: ["android.sysprop"],
 			property_owner: "Platform",
 			vendor_available: true,
+			host_supported: true,
 		}
 
 		sysprop_library {
@@ -244,6 +248,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 +265,12 @@
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
+			host_supported: true,
+		}
+
+		cc_binary_host {
+			name: "hostbin",
+			static_libs: ["sysprop-platform"],
 		}
 
 		llndk_library {
@@ -293,7 +308,12 @@
 		"android_arm64_armv8-a_shared",
 		"android_arm64_armv8-a_static",
 	} {
-		ctx.ModuleForTests("libsysprop-platform", variant)
+		library := ctx.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
+		expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
+		if !reflect.DeepEqual(library.ApexProperties.Apex_available, expectedApexAvailableOnLibrary) {
+			t.Errorf("apex available property on libsysprop-platform must be %#v, but was %#v.",
+				expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
+		}
 
 		// core variant of vendor-owned sysprop_library is for product
 		ctx.ModuleForTests("libsysprop-vendor", variant)