Merge "Add support for the remote execution of Abi links."
diff --git a/Android.bp b/Android.bp
index a9eceb2..342ca4c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -391,6 +391,7 @@
     srcs: [
         "rust/androidmk.go",
         "rust/compiler.go",
+        "rust/coverage.go",
         "rust/binary.go",
         "rust/builder.go",
         "rust/library.go",
@@ -403,6 +404,7 @@
     testSrcs: [
         "rust/binary_test.go",
         "rust/compiler_test.go",
+        "rust/coverage_test.go",
         "rust/library_test.go",
         "rust/rust_test.go",
         "rust/test_test.go",
diff --git a/android/defaults.go b/android/defaults.go
index 6a908ea..81e340e 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -35,6 +35,9 @@
 	defaultsProperties            defaultsProperties
 	defaultableProperties         []interface{}
 	defaultableVariableProperties interface{}
+
+	// The optional hook to call after any defaults have been applied.
+	hook DefaultableHook
 }
 
 func (d *DefaultableModuleBase) defaults() *defaultsProperties {
@@ -46,6 +49,16 @@
 	d.defaultableVariableProperties = variableProperties
 }
 
+func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
+	d.hook = hook
+}
+
+func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
+	if d.hook != nil {
+		d.hook(ctx)
+	}
+}
+
 // Interface that must be supported by any module to which defaults can be applied.
 type Defaultable interface {
 	// Get a pointer to the struct containing the Defaults property.
@@ -57,6 +70,15 @@
 	// Apply defaults from the supplied Defaults to the property structures supplied to
 	// setProperties(...).
 	applyDefaults(TopDownMutatorContext, []Defaults)
+
+	// Set the hook to be called after any defaults have been applied.
+	//
+	// Should be used in preference to a AddLoadHook when the behavior of the load
+	// hook is dependent on properties supplied in the Android.bp file.
+	SetDefaultableHook(hook DefaultableHook)
+
+	// Call the hook if specified.
+	callHookIfAvailable(context DefaultableHookContext)
 }
 
 type DefaultableModule interface {
@@ -75,6 +97,15 @@
 	module.AddProperties(module.defaults())
 }
 
+// A restricted subset of context methods, similar to LoadHookContext.
+type DefaultableHookContext interface {
+	EarlyModuleContext
+
+	CreateModule(ModuleFactory, ...interface{}) Module
+}
+
+type DefaultableHook func(ctx DefaultableHookContext)
+
 // The Defaults_visibility property.
 type DefaultsVisibilityProperties struct {
 
@@ -268,25 +299,29 @@
 }
 
 func defaultsMutator(ctx TopDownMutatorContext) {
-	if defaultable, ok := ctx.Module().(Defaultable); ok && len(defaultable.defaults().Defaults) > 0 {
-		var defaultsList []Defaults
-		seen := make(map[Defaults]bool)
+	if defaultable, ok := ctx.Module().(Defaultable); ok {
+		if len(defaultable.defaults().Defaults) > 0 {
+			var defaultsList []Defaults
+			seen := make(map[Defaults]bool)
 
-		ctx.WalkDeps(func(module, parent Module) bool {
-			if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
-				if defaults, ok := module.(Defaults); ok {
-					if !seen[defaults] {
-						seen[defaults] = true
-						defaultsList = append(defaultsList, defaults)
-						return len(defaults.defaults().Defaults) > 0
+			ctx.WalkDeps(func(module, parent Module) bool {
+				if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
+					if defaults, ok := module.(Defaults); ok {
+						if !seen[defaults] {
+							seen[defaults] = true
+							defaultsList = append(defaultsList, defaults)
+							return len(defaults.defaults().Defaults) > 0
+						}
+					} else {
+						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
+							ctx.OtherModuleName(module))
 					}
-				} else {
-					ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
-						ctx.OtherModuleName(module))
 				}
-			}
-			return false
-		})
-		defaultable.applyDefaults(ctx, defaultsList)
+				return false
+			})
+			defaultable.applyDefaults(ctx, defaultsList)
+		}
+
+		defaultable.callHookIfAvailable(ctx)
 	}
 }
diff --git a/android/hooks.go b/android/hooks.go
index 47f69d1..f43a007 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -39,6 +39,12 @@
 	moduleFactories() map[string]blueprint.ModuleFactory
 }
 
+// Add a hook that will be called once the module has been loaded, i.e. its
+// properties have been initialized from the Android.bp file.
+//
+// Consider using SetDefaultableHook to register a hook for any module that implements
+// DefaultableModule as the hook is called after any defaults have been applied to the
+// module which could reduce duplication and make it easier to use.
 func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
 	blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) {
 		actx := &loadHookContext{
diff --git a/android/module.go b/android/module.go
index f5cfe66..e431ada 100644
--- a/android/module.go
+++ b/android/module.go
@@ -19,6 +19,7 @@
 	"os"
 	"path"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"text/scanner"
 
@@ -135,6 +136,13 @@
 	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
 	GetTagPath() []blueprint.DependencyTag
 
+	// GetPathString is supposed to be called in visit function passed in WalkDeps()
+	// and returns a multi-line string showing the modules and dependency tags
+	// among them along the top-down dependency path from a start module to current child module.
+	// skipFirst when set to true, the output doesn't include the start module,
+	// which is already printed when this function is used along with ModuleErrorf().
+	GetPathString(skipFirst bool) string
+
 	AddMissingDependencies(missingDeps []string)
 
 	Target() Target
@@ -1734,6 +1742,41 @@
 	return b.tagPath
 }
 
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
+
+// PrettyPrintTag returns string representation of the tag, but prefers
+// custom String() method if available.
+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
+}
+
+func (b *baseModuleContext) GetPathString(skipFirst bool) string {
+	sb := strings.Builder{}
+	tagPath := b.GetTagPath()
+	walkPath := b.GetWalkPath()
+	if !skipFirst {
+		sb.WriteString(walkPath[0].String())
+	}
+	for i, m := range walkPath[1:] {
+		sb.WriteString("\n")
+		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i])))
+		sb.WriteString(fmt.Sprintf("    -> %s", m.String()))
+	}
+	return sb.String()
+}
+
 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 79a8506..77d5f43 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -82,10 +82,6 @@
 var preArch = []RegisterMutatorFunc{
 	RegisterNamespaceMutator,
 
-	// Create an association between prebuilt modules and their corresponding source
-	// modules (if any).
-	RegisterPrebuiltsPreArchMutators,
-
 	// Check the visibility rules are valid.
 	//
 	// This must run after the package renamer mutators so that any issues found during
@@ -114,8 +110,19 @@
 	RegisterVisibilityRuleChecker,
 
 	// Apply properties from defaults modules to the referencing modules.
+	//
+	// Any mutators that are added before this will not see any modules created by
+	// a DefaultableHook.
 	RegisterDefaultsPreArchMutators,
 
+	// Create an association between prebuilt modules and their corresponding source
+	// modules (if any).
+	//
+	// Must be run after defaults mutators to ensure that any modules created by
+	// a DefaultableHook can be either a prebuilt or a source module with a matching
+	// prebuilt.
+	RegisterPrebuiltsPreArchMutators,
+
 	// Gather the visibility rules for all modules for us during visibility enforcement.
 	//
 	// This must come after the defaults mutators to ensure that any visibility supplied
diff --git a/android/sdk.go b/android/sdk.go
index 6f62f55..e823106 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -331,13 +331,7 @@
 
 	// Add a prebuilt module that the sdk will populate.
 	//
-	// 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.
-	//
-	// 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:
+	// 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)
@@ -348,9 +342,24 @@
 	//
 	// * 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
+	//   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.
 	//
+	//   A field annotated with a tag of `android:"arch_variant"` will be allowed to have
+	//   values that differ by arch, fields not tagged as such must have common values across
+	//   all variants.
+	//
+	// * Additional field tags can be specified on a field that will ignore certain values
+	//   for the purpose of common value optimization. A value that is ignored must have the
+	//   default value for the property type. This is to ensure that significant value are not
+	//   ignored by accident. The purpose of this is to allow the snapshot generation to reflect
+	//   the behavior of the runtime. e.g. if a property is ignored on the host then a property
+	//   that is common for android can be treated as if it was common for android and host as
+	//   the setting for host is ignored anyway.
+	//   * `sdk:"ignored-on-host" - this indicates the property is ignored on the host variant.
+	//
 	// * 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.
diff --git a/android/util.go b/android/util.go
index e74b64e..8dbf214 100644
--- a/android/util.go
+++ b/android/util.go
@@ -141,6 +141,16 @@
 	return false
 }
 
+// Returns true if any string in the given list has the given suffix.
+func SuffixInList(list []string, suffix string) bool {
+	for _, s := range list {
+		if strings.HasSuffix(s, suffix) {
+			return true
+		}
+	}
+	return false
+}
+
 // IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element.
 func IndexListPred(pred func(s string) bool, list []string) int {
 	for i, l := range list {
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 8dd6a8f..4cf41a6 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -903,6 +903,69 @@
 				}`),
 		},
 	},
+	{
+		name: "ensure visibility properties are checked for correctness",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_parent {
+					name: "parent",
+					visibility: ["//top/nested"],
+					child: {
+						name: "libchild",
+						visibility: ["top/other"],
+					},
+				}`),
+		},
+		expectedErrors: []string{
+			`module "parent": child.visibility: invalid visibility pattern "top/other"`,
+		},
+	},
+	{
+		name: "invalid visibility added to child detected during gather phase",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_parent {
+					name: "parent",
+					visibility: ["//top/nested"],
+					child: {
+						name: "libchild",
+						invalid_visibility: ["top/other"],
+					},
+				}`),
+		},
+		expectedErrors: []string{
+			// That this error is reported against the child not the parent shows it was
+			// not being detected in the parent which is correct as invalid_visibility is
+			// purposely not added to the list of visibility properties to check, and was
+			// in fact detected in the child in the gather phase. Contrast this error message
+			// with the preceding one.
+			`module "libchild" \(created by module "parent"\): visibility: invalid visibility pattern "top/other"`,
+		},
+	},
+	{
+		name: "automatic visibility inheritance enabled",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_parent {
+					name: "parent",
+					visibility: ["//top/nested"],
+					child: {
+						name: "libchild",
+						visibility: ["//top/other"],
+					},
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libchild"],
+				}`),
+			"top/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libchild"],
+				}`),
+		},
+	},
 }
 
 func TestVisibility(t *testing.T) {
@@ -936,6 +999,7 @@
 
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("mock_library", newMockLibraryModule)
+	ctx.RegisterModuleType("mock_parent", newMockParentFactory)
 	ctx.RegisterModuleType("mock_defaults", defaultsFactory)
 
 	// Order of the following method calls is significant.
@@ -996,3 +1060,42 @@
 	InitDefaultsModule(m)
 	return m
 }
+
+type mockParentProperties struct {
+	Child struct {
+		Name *string
+
+		// Visibility to pass to the child module.
+		Visibility []string
+
+		// Purposely not validated visibility to pass to the child.
+		Invalid_visibility []string
+	}
+}
+
+type mockParent struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties mockParentProperties
+}
+
+func (p *mockParent) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+func newMockParentFactory() Module {
+	m := &mockParent{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitDefaultableModule(m)
+	AddVisibilityProperty(m, "child.visibility", &m.properties.Child.Visibility)
+
+	m.SetDefaultableHook(func(ctx DefaultableHookContext) {
+		visibility := m.properties.Child.Visibility
+		visibility = append(visibility, m.properties.Child.Invalid_visibility...)
+		ctx.CreateModule(newMockLibraryModule, &struct {
+			Name       *string
+			Visibility []string
+		}{m.properties.Child.Name, visibility})
+	})
+	return m
+}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index f863f8d..5a62324 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -111,6 +111,7 @@
 
 			"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
 			"LOCAL_TEST_CONFIG":                      "test_config",
+			"LOCAL_RRO_THEME":                        "theme",
 		})
 	addStandardProperties(bpparser.ListType,
 		map[string]string{
@@ -925,6 +926,7 @@
 	"BUILD_HOST_JAVA_LIBRARY":        "java_library_host",
 	"BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik",
 	"BUILD_PACKAGE":                  "android_app",
+	"BUILD_RRO_PACKAGE":              "runtime_resource_overlay",
 
 	"BUILD_CTS_EXECUTABLE":          "cc_binary",               // will be further massaged by bpfix depending on the output path
 	"BUILD_CTS_SUPPORT_PACKAGE":     "cts_support_package",     // will be rewritten to android_test by bpfix
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 3e1d486..d9bde94 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1360,6 +1360,29 @@
 }
 `,
 	},
+	{
+		desc: "runtime_resource_overlay",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := foo
+LOCAL_PRODUCT_MODULE := true
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SDK_VERSION := current
+LOCAL_RRO_THEME := FooTheme
+
+include $(BUILD_RRO_PACKAGE)
+`,
+		expected: `
+runtime_resource_overlay {
+	name: "foo",
+	product_specific: true,
+	resource_dirs: ["res"],
+	sdk_version: "current",
+	theme: "FooTheme",
+
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/apex/androidmk.go b/apex/androidmk.go
index db1048e..2c5407c 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -308,7 +308,7 @@
 				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 
 				if apexType == imageApex {
-					fmt.Fprintln(w, "ALL_MODULES.$(LOCAL_MODULE).BUNDLE :=", a.bundleModuleFile.String())
+					fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())
 				}
 
 				if a.installedFilesFile != nil {
diff --git a/apex/apex.go b/apex/apex.go
index d196e95..fa71ffa 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,7 +18,6 @@
 	"fmt"
 	"path"
 	"path/filepath"
-	"regexp"
 	"sort"
 	"strings"
 	"sync"
@@ -228,7 +227,6 @@
 		"netd_aidl_interface-unstable-java",
 		"netd_event_listener_interface-java",
 		"netlink-client",
-		"networkstack-aidl-interfaces-unstable-java",
 		"networkstack-client",
 		"sap-api-java-static",
 		"services.net",
@@ -680,7 +678,6 @@
 		"netd_aidl_interface-unstable-java",
 		"netd_event_listener_interface-java",
 		"netlink-client",
-		"networkstack-aidl-interfaces-unstable-java",
 		"networkstack-client",
 		"services.net",
 		"wifi-lite-protos",
@@ -1605,6 +1602,8 @@
 	return android.InList(sanitizerName, globalSanitizerNames)
 }
 
+var _ cc.Coverage = (*apexBundle)(nil)
+
 func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
 	return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
 }
@@ -1621,6 +1620,8 @@
 	a.properties.IsCoverageVariant = coverage
 }
 
+func (a *apexBundle) EnableCoverageIfNeeded() {}
+
 // TODO(jiyong) move apexFileFor* close to the apexFile type definition
 func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile {
 	// Decide the APEX-local directory by the multilib of the library
@@ -1809,24 +1810,6 @@
 	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
@@ -1861,14 +1844,7 @@
 		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)
+		ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true))
 		// Visit this module's dependencies to check and report any issues with their availability.
 		return true
 	})
@@ -2099,8 +2075,8 @@
 							//
 							// Always include if we are a host-apex however since those won't have any
 							// system libraries.
-							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) {
-								a.requiredDeps = append(a.requiredDeps, cc.Name())
+							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.BaseModuleName(), a.requiredDeps) {
+								a.requiredDeps = append(a.requiredDeps, cc.BaseModuleName())
 							}
 							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
 							// Don't track further
@@ -2132,7 +2108,7 @@
 						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
 					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
-					ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
+					ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
 				}
 			}
 		}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ce39b39..dc69862 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4530,12 +4530,12 @@
 	ctx.RegisterModuleType("apex", BundleFactory)
 	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	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)
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 523ac26..05cdfcd 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -117,44 +117,7 @@
 	})
 
 	t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
-		ctx, _ := testApex(t, bp+`
-			cc_library {
-				name: "libprofile-extras",
-				vendor_available: true,
-				recovery_available: true,
-				native_coverage: false,
-				system_shared_libs: [],
-				stl: "none",
-				notice: "custom_notice",
-			}
-			cc_library {
-				name: "libprofile-clang-extras",
-				vendor_available: true,
-				recovery_available: true,
-				native_coverage: false,
-				system_shared_libs: [],
-				stl: "none",
-				notice: "custom_notice",
-			}
-			cc_library {
-				name: "libprofile-extras_ndk",
-				vendor_available: true,
-				native_coverage: false,
-				system_shared_libs: [],
-				stl: "none",
-				notice: "custom_notice",
-				sdk_version: "current",
-			}
-			cc_library {
-				name: "libprofile-clang-extras_ndk",
-				vendor_available: true,
-				native_coverage: false,
-				system_shared_libs: [],
-				stl: "none",
-				notice: "custom_notice",
-				sdk_version: "current",
-			}
-		`, func(fs map[string][]byte, config android.Config) {
+		ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
 			config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
 		})
 
diff --git a/cc/cc.go b/cc/cc.go
index 49605cc..02c4879 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -437,7 +437,6 @@
 	ndkLateStubDepTag     = DependencyTag{Name: "ndk late stub", Library: true}
 	vndkExtDepTag         = DependencyTag{Name: "vndk extends", Library: true}
 	runtimeDepTag         = DependencyTag{Name: "runtime lib"}
-	coverageDepTag        = DependencyTag{Name: "coverage"}
 	testPerSrcDepTag      = DependencyTag{Name: "test_per_src"}
 )
 
@@ -745,6 +744,15 @@
 	return c.outputFile
 }
 
+func (c *Module) CoverageFiles() android.Paths {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.objs().coverageFiles
+		}
+	}
+	panic(fmt.Errorf("CoverageFiles called on non-library module: %q", c.BaseModuleName()))
+}
+
 var _ LinkableInterface = (*Module)(nil)
 
 func (c *Module) UnstrippedOutputFile() android.Path {
@@ -2493,13 +2501,16 @@
 			// When combining coverage files for shared libraries and executables, coverage files
 			// in static libraries act as if they were whole static libraries. The same goes for
 			// source based Abi dump files.
-			// This should only be done for cc.Modules
 			if c, ok := ccDep.(*Module); ok {
 				staticLib := c.linker.(libraryInterface)
 				depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
 					staticLib.objs().coverageFiles...)
 				depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
 					staticLib.objs().sAbiDumpFiles...)
+			} else if c, ok := ccDep.(LinkableInterface); ok {
+				// Handle non-CC modules here
+				depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
+					c.CoverageFiles()...)
 			}
 		}
 
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 5575baa..9383463 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -92,7 +92,6 @@
 
 	pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
 	pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
-	pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64"))
 
 	pctx.StaticVariable("Arm64ClangCflags", strings.Join(ClangFilterUnknownCflags(arm64Cflags), " "))
 	pctx.StaticVariable("Arm64ClangLdflags", strings.Join(ClangFilterUnknownCflags(arm64Ldflags), " "))
@@ -164,7 +163,7 @@
 }
 
 func (t *toolchainArm64) IncludeFlags() string {
-	return "${config.Arm64IncludeFlags}"
+	return ""
 }
 
 func (t *toolchainArm64) ClangTriple() string {
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index d37e486..f01c638 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -175,7 +175,6 @@
 
 	pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
 	pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
-	pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm"))
 
 	// Clang cflags
 	pctx.StaticVariable("ArmToolchainClangCflags", strings.Join(ClangFilterUnknownCflags(armToolchainCflags), " "))
@@ -269,7 +268,7 @@
 }
 
 func (t *toolchainArm) IncludeFlags() string {
-	return "${config.ArmIncludeFlags}"
+	return ""
 }
 
 func (t *toolchainArm) ClangTriple() string {
diff --git a/cc/config/global.go b/cc/config/global.go
index 5e6457f..1dd8a2d 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -162,7 +162,7 @@
 
 		// http://b/131390872
 		// Automatically initialize any uninitialized stack variables.
-		// Prefer zero-init if both options are set.
+		// Prefer zero-init if multiple options are set.
 		if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") {
 			flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
 		} else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
@@ -170,8 +170,8 @@
 		} else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") {
 			flags = append(flags, "-ftrivial-auto-var-init=uninitialized")
 		} else {
-			// Default to pattern initialization.
-			flags = append(flags, "-ftrivial-auto-var-init=pattern")
+			// Default to zero initialization.
+			flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
 		}
 
 		return strings.Join(flags, " ")
@@ -266,16 +266,6 @@
 
 var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
 
-func bionicHeaders(kernelArch string) string {
-	return strings.Join([]string{
-		"-isystem bionic/libc/include",
-		"-isystem bionic/libc/kernel/uapi",
-		"-isystem bionic/libc/kernel/uapi/asm-" + kernelArch,
-		"-isystem bionic/libc/kernel/android/scsi",
-		"-isystem bionic/libc/kernel/android/uapi",
-	}, " ")
-}
-
 func envOverrideFunc(envVar, defaultVal string) func(ctx android.PackageVarContext) string {
 	return func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv(envVar); override != "" {
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index bcfae5d..1e25a3b 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -103,7 +103,6 @@
 
 	pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
 	pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Lldflags, " "))
-	pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
 	pctx.StaticVariable("X86_64ClangCflags", strings.Join(ClangFilterUnknownCflags(x86_64Cflags), " "))
@@ -145,7 +144,7 @@
 }
 
 func (t *toolchainX86_64) IncludeFlags() string {
-	return "${config.X86_64IncludeFlags}"
+	return ""
 }
 
 func (t *toolchainX86_64) ClangTriple() string {
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 64392dc..fe83098 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -114,7 +114,6 @@
 
 	pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
 	pctx.StaticVariable("X86Lldflags", strings.Join(x86Lldflags, " "))
-	pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
 	pctx.StaticVariable("X86ClangCflags", strings.Join(ClangFilterUnknownCflags(x86ClangCflags), " "))
@@ -156,7 +155,7 @@
 }
 
 func (t *toolchainX86) IncludeFlags() string {
-	return "${config.X86IncludeFlags}"
+	return ""
 }
 
 func (t *toolchainX86) ClangTriple() string {
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index fb1cdeb..fa625e3 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -70,8 +70,6 @@
 	pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " "))
 	pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLldflags, " "))
 
-	pctx.StaticVariable("LinuxBionicIncludeFlags", bionicHeaders("x86"))
-
 	// Use the device gcc toolchain for now
 	pctx.StaticVariable("LinuxBionicGccRoot", "${X86_64GccRoot}")
 }
@@ -97,7 +95,7 @@
 }
 
 func (t *toolchainLinuxBionic) IncludeFlags() string {
-	return "${config.LinuxBionicIncludeFlags}"
+	return ""
 }
 
 func (t *toolchainLinuxBionic) ClangTriple() string {
diff --git a/cc/coverage.go b/cc/coverage.go
index bde07fd..cc9a1ad 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -65,10 +65,10 @@
 	if cov.Properties.NeedCoverageVariant {
 		ctx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, coverageDepTag, getGcovProfileLibraryName(ctx))
+		}, CoverageDepTag, getGcovProfileLibraryName(ctx))
 		ctx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, coverageDepTag, getClangProfileLibraryName(ctx))
+		}, CoverageDepTag, getClangProfileLibraryName(ctx))
 	}
 	return deps
 }
@@ -134,14 +134,14 @@
 		if gcovCoverage {
 			flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
 
-			coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), coverageDepTag).(*Module)
+			coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module)
 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
 
 			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
 		} else if clangCoverage {
 			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate")
 
-			coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), coverageDepTag).(*Module)
+			coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
 		}
 	}
@@ -150,25 +150,30 @@
 }
 
 func (cov *coverage) begin(ctx BaseModuleContext) {
+	if ctx.Host() {
+		// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
+		// Just turn off for now.
+	} else {
+		cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion())
+	}
+}
+
+func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
+	useSdk bool, sdkVersion string) CoverageProperties {
 	// Coverage is disabled globally
 	if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
-		return
+		return properties
 	}
 
 	var needCoverageVariant bool
 	var needCoverageBuild bool
 
-	if ctx.Host() {
-		// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
-		// Just turn off for now.
-	} else if !ctx.nativeCoverage() {
-		// Native coverage is not supported for this module type.
-	} else {
+	if moduleTypeHasCoverage {
 		// Check if Native_coverage is set to false.  This property defaults to true.
-		needCoverageVariant = BoolDefault(cov.Properties.Native_coverage, true)
-		if sdk_version := ctx.sdkVersion(); ctx.useSdk() && sdk_version != "current" {
+		needCoverageVariant = BoolDefault(properties.Native_coverage, true)
+		if useSdk && sdkVersion != "current" {
 			// Native coverage is not supported for SDK versions < 23
-			if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
+			if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 {
 				needCoverageVariant = false
 			}
 		}
@@ -179,8 +184,10 @@
 		}
 	}
 
-	cov.Properties.NeedCoverageBuild = needCoverageBuild
-	cov.Properties.NeedCoverageVariant = needCoverageVariant
+	properties.NeedCoverageBuild = needCoverageBuild
+	properties.NeedCoverageVariant = needCoverageVariant
+
+	return properties
 }
 
 // Coverage is an interface for non-CC modules to implement to be mutated for coverage
@@ -190,6 +197,7 @@
 	PreventInstall()
 	HideFromMake()
 	MarkAsCoverageVariant(bool)
+	EnableCoverageIfNeeded()
 }
 
 func coverageMutator(mctx android.BottomUpMutatorContext) {
@@ -212,14 +220,17 @@
 			m[1].(*Module).coverage.Properties.IsCoverageVariant = true
 		}
 	} else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) {
-		// APEX modules fall here
+		// APEX and Rust modules fall here
 
 		// Note: variant "" is also created because an APEX can be depended on by another
 		// module which are split into "" and "cov" variants. e.g. when cc_test refers
 		// to an APEX via 'data' property.
 		m := mctx.CreateVariations("", "cov")
-		m[0].(Coverage).MarkAsCoverageVariant(true)
+		m[0].(Coverage).MarkAsCoverageVariant(false)
 		m[0].(Coverage).PreventInstall()
 		m[0].(Coverage).HideFromMake()
+
+		m[1].(Coverage).MarkAsCoverageVariant(true)
+		m[1].(Coverage).EnableCoverageIfNeeded()
 	}
 }
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 2c8e311..a7a1de2 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -307,7 +307,7 @@
 	// The list of possibly common exported include dirs.
 	//
 	// This field is exported as its contents may not be arch specific.
-	ExportedIncludeDirs android.Paths
+	ExportedIncludeDirs android.Paths `android:"arch_variant"`
 
 	// The list of arch specific exported generated include dirs.
 	//
@@ -322,27 +322,31 @@
 	// The list of possibly common exported system include dirs.
 	//
 	// This field is exported as its contents may not be arch specific.
-	ExportedSystemIncludeDirs android.Paths
+	ExportedSystemIncludeDirs android.Paths `android:"arch_variant"`
 
 	// The list of possibly common exported flags.
 	//
 	// This field is exported as its contents may not be arch specific.
-	ExportedFlags []string
+	ExportedFlags []string `android:"arch_variant"`
 
 	// The set of shared libraries
 	//
 	// This field is exported as its contents may not be arch specific.
-	SharedLibs []string
+	SharedLibs []string `android:"arch_variant"`
 
 	// The set of system shared libraries. Note nil and [] are semantically
 	// distinct - see BaseLinkerProperties.System_shared_libs.
 	//
 	// This field is exported as its contents may not be arch specific.
-	SystemSharedLibs []string
+	SystemSharedLibs []string `android:"arch_variant"`
 
 	// The specific stubs version for the lib variant, or empty string if stubs
 	// are not in use.
-	StubsVersion string
+	//
+	// Marked 'ignored-on-host' as the StubsVersion() from which this is initialized is
+	// not set on host and the stubs.versions property which this is written to is does
+	// not vary by arch so cannot be android specific.
+	StubsVersion string `sdk:"ignored-on-host"`
 
 	// outputFile is not exported as it is always arch specific.
 	outputFile android.Path
diff --git a/cc/linkable.go b/cc/linkable.go
index 4a70d48..de36f90 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -12,6 +12,7 @@
 	CcLibraryInterface() bool
 
 	OutputFile() android.OptionalPath
+	CoverageFiles() android.Paths
 
 	IncludeDirs() android.Paths
 	SetDepsInLinkOrder([]android.Path)
@@ -83,4 +84,5 @@
 
 	CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
 	CrtEndDepTag   = DependencyTag{Name: "crtend"}
+	CoverageDepTag = DependencyTag{Name: "coverage"}
 )
diff --git a/cc/test.go b/cc/test.go
index f51cf01..b1f8eec 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -90,6 +90,10 @@
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
 	// explicitly.
 	Auto_gen_config *bool
+
+	// Add parameterized mainline modules to auto generated test config. The options will be
+	// handled by TradeFed to download and install the specified modules on the device.
+	Test_mainline_modules []string
 }
 
 func init() {
@@ -329,24 +333,27 @@
 	var api_level_prop string
 	var configs []tradefed.Config
 	var min_level string
+	for _, module := range test.Properties.Test_mainline_modules {
+		configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
+	}
 	if Bool(test.Properties.Require_root) {
 		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
 	} else {
 		var options []tradefed.Option
-		options = append(options, tradefed.Option{"force-root", "false"})
+		options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
 		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
 	}
 	if Bool(test.Properties.Disable_framework) {
 		var options []tradefed.Option
-		options = append(options, tradefed.Option{"run-command", "stop"})
-		options = append(options, tradefed.Option{"teardown-command", "start"})
+		options = append(options, tradefed.Option{Name: "run-command", Value: "stop"})
+		options = append(options, tradefed.Option{Name: "teardown-command", Value: "start"})
 		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RunCommandTargetPreparer", options})
 	}
 	if Bool(test.testDecorator.Properties.Isolated) {
-		configs = append(configs, tradefed.Option{"not-shardable", "true"})
+		configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"})
 	}
 	if test.Properties.Test_options.Run_test_as != nil {
-		configs = append(configs, tradefed.Option{"run-test-as", String(test.Properties.Test_options.Run_test_as)})
+		configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(test.Properties.Test_options.Run_test_as)})
 	}
 	if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil {
 		ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.")
@@ -359,8 +366,8 @@
 	}
 	if api_level_prop != "" {
 		var options []tradefed.Option
-		options = append(options, tradefed.Option{"min-api-level", min_level})
-		options = append(options, tradefed.Option{"api-level-prop", api_level_prop})
+		options = append(options, tradefed.Option{Name: "min-api-level", Value: min_level})
+		options = append(options, tradefed.Option{Name: "api-level-prop", Value: api_level_prop})
 		configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
 	}
 
diff --git a/cc/testing.go b/cc/testing.go
index 53f0995..be020c5 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -192,6 +192,45 @@
 			symbol_file: "",
 			sdk_version: "current",
 		}
+
+		// Coverage libraries
+		cc_library {
+			name: "libprofile-extras",
+			vendor_available: true,
+			recovery_available: true,
+			native_coverage: false,
+			system_shared_libs: [],
+			stl: "none",
+			notice: "custom_notice",
+		}
+		cc_library {
+			name: "libprofile-clang-extras",
+			vendor_available: true,
+			recovery_available: true,
+			native_coverage: false,
+			system_shared_libs: [],
+			stl: "none",
+			notice: "custom_notice",
+		}
+		cc_library {
+			name: "libprofile-extras_ndk",
+			vendor_available: true,
+			native_coverage: false,
+			system_shared_libs: [],
+			stl: "none",
+			notice: "custom_notice",
+			sdk_version: "current",
+		}
+		cc_library {
+			name: "libprofile-clang-extras_ndk",
+			vendor_available: true,
+			native_coverage: false,
+			system_shared_libs: [],
+			stl: "none",
+			notice: "custom_notice",
+			sdk_version: "current",
+		}
+
 		cc_library {
 			name: "libdl",
 			no_libcrt: true,
@@ -485,8 +524,8 @@
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
-	RegisterRequiredBuildComponentsForTest(ctx)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	RegisterRequiredBuildComponentsForTest(ctx)
 	ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 	ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
 
diff --git a/java/app.go b/java/app.go
index d25575c..f1af2ad 100755
--- a/java/app.go
+++ b/java/app.go
@@ -80,10 +80,14 @@
 	// list of native libraries that will be provided in or alongside the resulting jar
 	Jni_libs []string `android:"arch_variant"`
 
-	// if true, allow JNI libraries that link against platform APIs even if this module sets
+	// if true, use JNI libraries that link against platform APIs even if this module sets
 	// sdk_version.
 	Jni_uses_platform_apis *bool
 
+	// if true, use JNI libraries that link against SDK APIs even if this module does not set
+	// sdk_version.
+	Jni_uses_sdk_apis *bool
+
 	// STL library to use for JNI libraries.
 	Stl *string `android:"arch_variant"`
 
@@ -171,6 +175,8 @@
 	noticeOutputs android.NoticeOutputs
 
 	overriddenManifestPackageName string
+
+	android.ApexBundleDepsInfo
 }
 
 func (a *AndroidApp) IsInstallable() bool {
@@ -226,6 +232,16 @@
 		a.aapt.deps(ctx, sdkDep)
 	}
 
+	usesSDK := a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform
+
+	if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) {
+		ctx.PropertyErrorf("jni_uses_sdk_apis",
+			"can only be set for modules that do not set sdk_version")
+	} else if !usesSDK && Bool(a.appProperties.Jni_uses_platform_apis) {
+		ctx.PropertyErrorf("jni_uses_platform_apis",
+			"can only be set for modules that set sdk_version")
+	}
+
 	tag := &jniDependencyTag{}
 	for _, jniTarget := range ctx.MultiTargets() {
 		variation := append(jniTarget.Variations(),
@@ -233,8 +249,8 @@
 
 		// If the app builds against an Android SDK use the SDK variant of JNI dependencies
 		// unless jni_uses_platform_apis is set.
-		if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform &&
-			!Bool(a.appProperties.Jni_uses_platform_apis) {
+		if (usesSDK && !Bool(a.appProperties.Jni_uses_platform_apis)) ||
+			Bool(a.appProperties.Jni_uses_sdk_apis) {
 			variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
 		}
 		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
@@ -602,6 +618,8 @@
 			ctx.InstallFile(a.installDir, extra.Base(), extra)
 		}
 	}
+
+	a.buildAppDependencyInfo(ctx)
 }
 
 func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool,
@@ -670,6 +688,49 @@
 	return jniLibs, certificates
 }
 
+func (a *AndroidApp) walkPayloadDeps(ctx android.ModuleContext,
+	do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
+
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		isExternal := !a.DepIsInSameApex(ctx, child)
+		if am, ok := child.(android.ApexModule); ok {
+			do(ctx, parent, am, isExternal)
+		}
+		return !isExternal
+	})
+}
+
+func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) {
+	if ctx.Host() {
+		return
+	}
+
+	depsInfo := android.DepNameToDepInfoMap{}
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+		depName := to.Name()
+		if info, exist := depsInfo[depName]; exist {
+			info.From = append(info.From, from.Name())
+			info.IsExternal = info.IsExternal && externalDep
+			depsInfo[depName] = info
+		} else {
+			toMinSdkVersion := "(no version)"
+			if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+				if v := m.MinSdkVersion(); v != "" {
+					toMinSdkVersion = v
+				}
+			}
+			depsInfo[depName] = android.ApexModuleDepInfo{
+				To:            depName,
+				From:          []string{from.Name()},
+				IsExternal:    externalDep,
+				MinSdkVersion: toMinSdkVersion,
+			}
+		}
+	})
+
+	a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo)
+}
+
 func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
 	certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
 	if overridden {
@@ -714,6 +775,8 @@
 	a.appProperties.IsCoverageVariant = coverage
 }
 
+func (a *AndroidApp) EnableCoverageIfNeeded() {}
+
 var _ cc.Coverage = (*AndroidApp)(nil)
 
 // android_app compiles sources and Android resources into an Android application package `.apk` file.
@@ -1391,6 +1454,8 @@
 		module.processVariants(ctx)
 	})
 
+	module.dexpreopter.isTest = true
+
 	android.InitApexModule(module)
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
diff --git a/java/app_test.go b/java/app_test.go
index 998c76a..4bcfa5a 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1110,6 +1110,100 @@
 	}
 }
 
+func TestJNISDK(t *testing.T) {
+	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+		cc_library {
+			name: "libjni",
+			system_shared_libs: [],
+			stl: "none",
+			sdk_version: "current",
+		}
+
+		android_test {
+			name: "app_platform",
+			jni_libs: ["libjni"],
+			platform_apis: true,
+		}
+
+		android_test {
+			name: "app_sdk",
+			jni_libs: ["libjni"],
+			sdk_version: "current",
+		}
+
+		android_test {
+			name: "app_force_platform",
+			jni_libs: ["libjni"],
+			sdk_version: "current",
+			jni_uses_platform_apis: true,
+		}
+
+		android_test {
+			name: "app_force_sdk",
+			jni_libs: ["libjni"],
+			platform_apis: true,
+			jni_uses_sdk_apis: true,
+		}
+	`)
+
+	testCases := []struct {
+		name   string
+		sdkJNI bool
+	}{
+		{"app_platform", false},
+		{"app_sdk", true},
+		{"app_force_platform", false},
+		{"app_force_sdk", true},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			app := ctx.ModuleForTests(test.name, "android_common")
+			platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared").
+				Output("libjni.so").Output.String()
+			sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").
+				Output("libjni.so").Output.String()
+
+			jniLibZip := app.MaybeOutput("jnilibs.zip")
+			if len(jniLibZip.Implicits) != 1 {
+				t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings())
+			}
+			gotJNI := jniLibZip.Implicits[0].String()
+
+			if test.sdkJNI {
+				if gotJNI != sdkJNI {
+					t.Errorf("expected SDK JNI library %q, got %q", sdkJNI, gotJNI)
+				}
+			} else {
+				if gotJNI != platformJNI {
+					t.Errorf("expected platform JNI library %q, got %q", platformJNI, gotJNI)
+				}
+			}
+		})
+	}
+
+	t.Run("jni_uses_platform_apis_error", func(t *testing.T) {
+		testJavaError(t, `jni_uses_platform_apis: can only be set for modules that set sdk_version`, `
+			android_test {
+				name: "app_platform",
+				platform_apis: true,
+				jni_uses_platform_apis: true,
+			}
+		`)
+	})
+
+	t.Run("jni_uses_sdk_apis_error", func(t *testing.T) {
+		testJavaError(t, `jni_uses_sdk_apis: can only be set for modules that do not set sdk_version`, `
+			android_test {
+				name: "app_sdk",
+				sdk_version: "current",
+				jni_uses_sdk_apis: true,
+			}
+		`)
+	})
+
+}
+
 func TestCertificates(t *testing.T) {
 	testCases := []struct {
 		name                string
@@ -1141,7 +1235,7 @@
 
 				android_app_certificate {
 					name: "new_certificate",
-			    certificate: "cert/new_cert",
+					certificate: "cert/new_cert",
 				}
 			`,
 			certificateOverride: "",
@@ -1172,7 +1266,7 @@
 
 				android_app_certificate {
 					name: "new_certificate",
-			    certificate: "cert/new_cert",
+					certificate: "cert/new_cert",
 				}
 			`,
 			certificateOverride: "foo:new_certificate",
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 879353d..78ecb09 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1388,6 +1388,7 @@
 			pool = v
 		}
 		inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()}
+		inputs = append(inputs, sourcepaths.Strings()...)
 		if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
 			inputs = append(inputs, strings.Split(v, ",")...)
 		}
@@ -1521,9 +1522,9 @@
 			msg += fmt.Sprintf(``+
 				`2. You can update the baseline by executing the following\n`+
 				`   command:\n`+
-				`       cp \\ \n`+
-				`       "'"$PWD"$'/%s" \\ \n`+
-				`       "'"$PWD"$'/%s" \n`+
+				`       cp \\\n`+
+				`       "'"$PWD"$'/%s" \\\n`+
+				`       "'"$PWD"$'/%s"\n`+
 				`   To submit the revised baseline.txt to the main Android\n`+
 				`   repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
 		} else {
diff --git a/java/java.go b/java/java.go
index 472d3da..9d75c74 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1906,7 +1906,7 @@
 type librarySdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
-	JarToExport     android.Path
+	JarToExport     android.Path `android:"arch_variant"`
 	AidlIncludeDirs android.Paths
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index e8a1a7c..0033f31 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1229,6 +1229,24 @@
 	}
 }
 
+func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
+	testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java", "b.java"],
+			api_packages: ["foo"],
+			// Explicitly disable public to test the check that ensures the set of enabled
+			// scopes is consistent.
+			public: {
+				enabled: false,
+			},
+			system: {
+				enabled: true,
+			},
+		}
+		`)
+}
+
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
diff --git a/java/sdk_library.go b/java/sdk_library.go
index d70f632..2c85c8c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -60,6 +60,17 @@
 	blueprint.BaseDependencyTag
 	name     string
 	apiScope *apiScope
+
+	// Function for extracting appropriate path information from the dependency.
+	depInfoExtractor func(paths *scopePaths, dep android.Module) error
+}
+
+// Extract tag specific information from the dependency.
+func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) {
+	err := tag.depInfoExtractor(paths, dep)
+	if err != nil {
+		ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error())
+	}
 }
 
 // Provides information about an api scope, e.g. public, system, test.
@@ -67,14 +78,29 @@
 	// The name of the api scope, e.g. public, system, test
 	name string
 
+	// The api scope that this scope extends.
+	extends *apiScope
+
+	// The legacy enabled status for a specific scope can be dependent on other
+	// properties that have been specified on the library so it is provided by
+	// a function that can determine the status by examining those properties.
+	legacyEnabledStatus func(module *SdkLibrary) bool
+
+	// The default enabled status for non-legacy behavior, which is triggered by
+	// explicitly enabling at least one api scope.
+	defaultEnabledStatus bool
+
+	// Gets a pointer to the scope specific properties.
+	scopeSpecificProperties func(module *SdkLibrary) *ApiScopeProperties
+
 	// 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
 
-	// The tag to use to depend on the stubs
-	apiFileTag scopeDependencyTag
+	// The tag to use to depend on the stubs source and API module.
+	stubsSourceAndApiTag scopeDependencyTag
 
 	// The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
 	apiFilePrefix string
@@ -97,14 +123,17 @@
 
 // Initialize a scope, creating and adding appropriate dependency tags
 func initApiScope(scope *apiScope) *apiScope {
-	scope.fieldName = proptools.FieldNameForProperty(scope.name)
+	name := scope.name
+	scope.fieldName = proptools.FieldNameForProperty(name)
 	scope.stubsTag = scopeDependencyTag{
-		name:     scope.name + "-stubs",
-		apiScope: scope,
+		name:             name + "-stubs",
+		apiScope:         scope,
+		depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency,
 	}
-	scope.apiFileTag = scopeDependencyTag{
-		name:     scope.name + "-api",
-		apiScope: scope,
+	scope.stubsSourceAndApiTag = scopeDependencyTag{
+		name:             name + "-stubs-source-and-api",
+		apiScope:         scope,
+		depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
 	}
 	return scope
 }
@@ -113,10 +142,14 @@
 	return baseName + sdkStubsLibrarySuffix + scope.moduleSuffix
 }
 
-func (scope *apiScope) docsModuleName(baseName string) string {
+func (scope *apiScope) stubsSourceModuleName(baseName string) string {
 	return baseName + sdkStubsSourceSuffix + scope.moduleSuffix
 }
 
+func (scope *apiScope) String() string {
+	return scope.name
+}
+
 type apiScopes []*apiScope
 
 func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
@@ -129,28 +162,68 @@
 
 var (
 	apiScopePublic = initApiScope(&apiScope{
-		name:       "public",
+		name: "public",
+
+		// Public scope is enabled by default for both legacy and non-legacy modes.
+		legacyEnabledStatus: func(module *SdkLibrary) bool {
+			return true
+		},
+		defaultEnabledStatus: true,
+
+		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
+			return &module.sdkLibraryProperties.Public
+		},
 		sdkVersion: "current",
 	})
 	apiScopeSystem = initApiScope(&apiScope{
-		name:           "system",
+		name:                "system",
+		extends:             apiScopePublic,
+		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
+		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
+			return &module.sdkLibraryProperties.System
+		},
 		apiFilePrefix:  "system-",
 		moduleSuffix:   sdkSystemApiSuffix,
 		sdkVersion:     "system_current",
-		droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi"},
+		droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"},
 	})
 	apiScopeTest = initApiScope(&apiScope{
-		name:           "test",
+		name:                "test",
+		extends:             apiScopePublic,
+		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
+		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
+			return &module.sdkLibraryProperties.Test
+		},
 		apiFilePrefix:  "test-",
 		moduleSuffix:   sdkTestApiSuffix,
 		sdkVersion:     "test_current",
 		droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
 		unstable:       true,
 	})
+	apiScopeModuleLib = initApiScope(&apiScope{
+		name:    "module_lib",
+		extends: apiScopeSystem,
+		// Module_lib scope is disabled by default in legacy mode.
+		//
+		// Enabling this would break existing usages.
+		legacyEnabledStatus: func(module *SdkLibrary) bool {
+			return false
+		},
+		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
+			return &module.sdkLibraryProperties.Module_lib
+		},
+		apiFilePrefix: "module-lib-",
+		moduleSuffix:  ".module_lib",
+		sdkVersion:    "module_current",
+		droidstubsArgs: []string{
+			"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
+		},
+	})
 	allApiScopes = apiScopes{
 		apiScopePublic,
 		apiScopeSystem,
 		apiScopeTest,
+		apiScopeModuleLib,
 	}
 )
 
@@ -185,7 +258,27 @@
 	ctx.RegisterModuleType("java_sdk_library_import", sdkLibraryImportFactory)
 }
 
+// Properties associated with each api scope.
+type ApiScopeProperties struct {
+	// Indicates whether the api surface is generated.
+	//
+	// If this is set for any scope then all scopes must explicitly specify if they
+	// are enabled. This is to prevent new usages from depending on legacy behavior.
+	//
+	// Otherwise, if this is not set for any scope then the default  behavior is
+	// scope specific so please refer to the scope specific property documentation.
+	Enabled *bool
+}
+
 type sdkLibraryProperties struct {
+	// Visibility for stubs library modules. If not specified then defaults to the
+	// visibility property.
+	Stubs_library_visibility []string
+
+	// Visibility for stubs source modules. If not specified then defaults to the
+	// visibility property.
+	Stubs_source_visibility []string
+
 	// List of Java libraries that will be in the classpath when building stubs
 	Stub_only_libs []string `android:"arch_variant"`
 
@@ -227,8 +320,36 @@
 	// don't create dist rules.
 	No_dist *bool `blueprint:"mutated"`
 
-	// indicates whether system and test apis should be managed.
-	Has_system_and_test_apis bool `blueprint:"mutated"`
+	// indicates whether system and test apis should be generated.
+	Generate_system_and_test_apis bool `blueprint:"mutated"`
+
+	// The properties specific to the public api scope
+	//
+	// Unless explicitly specified by using public.enabled the public api scope is
+	// enabled by default in both legacy and non-legacy mode.
+	Public ApiScopeProperties
+
+	// The properties specific to the system api scope
+	//
+	// In legacy mode the system api scope is enabled by default when sdk_version
+	// is set to something other than "none".
+	//
+	// In non-legacy mode the system api scope is disabled by default.
+	System ApiScopeProperties
+
+	// The properties specific to the test api scope
+	//
+	// In legacy mode the test api scope is enabled by default when sdk_version
+	// is set to something other than "none".
+	//
+	// In non-legacy mode the test api scope is disabled by default.
+	Test ApiScopeProperties
+
+	// The properties specific to the module_lib api scope
+	//
+	// Unless explicitly specified by using test.enabled the module_lib api scope is
+	// disabled by default.
+	Module_lib ApiScopeProperties
 
 	// TODO: determines whether to create HTML doc or not
 	//Html_doc *bool
@@ -242,6 +363,27 @@
 	stubsSrcJar        android.Path
 }
 
+func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error {
+	if lib, ok := dep.(Dependency); ok {
+		paths.stubsHeaderPath = lib.HeaderJars()
+		paths.stubsImplPath = lib.ImplementationJars()
+		return nil
+	} else {
+		return fmt.Errorf("expected module that implements Dependency, e.g. java_library")
+	}
+}
+
+func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
+	if provider, ok := dep.(ApiStubsProvider); ok {
+		paths.currentApiFilePath = provider.ApiFilePath()
+		paths.removedApiFilePath = provider.RemovedApiFilePath()
+		paths.stubsSrcJar = provider.StubsSrcJar()
+		return nil
+	} else {
+		return fmt.Errorf("expected module that implements ApiStubsProvider, e.g. droidstubs")
+	}
+}
+
 // Common code between sdk library and sdk library import
 type commonToSdkLibraryAndImport struct {
 	scopePaths map[*apiScope]*scopePaths
@@ -265,18 +407,65 @@
 
 	sdkLibraryProperties sdkLibraryProperties
 
+	// Map from api scope to the scope specific property structure.
+	scopeToProperties map[*apiScope]*ApiScopeProperties
+
 	commonToSdkLibraryAndImport
 }
 
 var _ Dependency = (*SdkLibrary)(nil)
 var _ SdkLibraryDependency = (*SdkLibrary)(nil)
 
-func (module *SdkLibrary) getActiveApiScopes() apiScopes {
-	if module.sdkLibraryProperties.Has_system_and_test_apis {
-		return allApiScopes
-	} else {
-		return apiScopes{apiScopePublic}
+func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool {
+	return module.sdkLibraryProperties.Generate_system_and_test_apis
+}
+
+func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) apiScopes {
+	// Check to see if any scopes have been explicitly enabled. If any have then all
+	// must be.
+	anyScopesExplicitlyEnabled := false
+	for _, scope := range allApiScopes {
+		scopeProperties := module.scopeToProperties[scope]
+		if scopeProperties.Enabled != nil {
+			anyScopesExplicitlyEnabled = true
+			break
+		}
 	}
+
+	var generatedScopes apiScopes
+	enabledScopes := make(map[*apiScope]struct{})
+	for _, scope := range allApiScopes {
+		scopeProperties := module.scopeToProperties[scope]
+		// If any scopes are explicitly enabled then ignore the legacy enabled status.
+		// This is to ensure that any new usages of this module type do not rely on legacy
+		// behaviour.
+		defaultEnabledStatus := false
+		if anyScopesExplicitlyEnabled {
+			defaultEnabledStatus = scope.defaultEnabledStatus
+		} else {
+			defaultEnabledStatus = scope.legacyEnabledStatus(module)
+		}
+		enabled := proptools.BoolDefault(scopeProperties.Enabled, defaultEnabledStatus)
+		if enabled {
+			enabledScopes[scope] = struct{}{}
+			generatedScopes = append(generatedScopes, scope)
+		}
+	}
+
+	// Now check to make sure that any scope that is extended by an enabled scope is also
+	// enabled.
+	for _, scope := range allApiScopes {
+		if _, ok := enabledScopes[scope]; ok {
+			extends := scope.extends
+			if extends != nil {
+				if _, ok := enabledScopes[extends]; !ok {
+					ctx.ModuleErrorf("enabled api scope %q depends on disabled scope %q", scope, extends)
+				}
+			}
+		}
+	}
+
+	return generatedScopes
 }
 
 var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
@@ -289,12 +478,12 @@
 }
 
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
-	for _, apiScope := range module.getActiveApiScopes() {
+	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
 		// Add dependencies to the stubs library
 		ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
 
-		// And the api file
-		ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.docsName(apiScope))
+		// And the stubs source and api files
+		ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceName(apiScope))
 	}
 
 	if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
@@ -315,27 +504,16 @@
 	// When this java_sdk_library is depended upon from others via "libs" property,
 	// the recorded paths will be returned depending on the link type of the caller.
 	ctx.VisitDirectDeps(func(to android.Module) {
-		otherName := ctx.OtherModuleName(to)
 		tag := ctx.OtherModuleDependencyTag(to)
 
-		if lib, ok := to.(Dependency); ok {
-			if scopeTag, ok := tag.(scopeDependencyTag); ok {
-				apiScope := scopeTag.apiScope
-				scopePaths := module.getScopePaths(apiScope)
-				scopePaths.stubsHeaderPath = lib.HeaderJars()
-				scopePaths.stubsImplPath = lib.ImplementationJars()
-			}
-		}
-		if doc, ok := to.(ApiStubsProvider); ok {
-			if scopeTag, ok := tag.(scopeDependencyTag); ok {
-				apiScope := scopeTag.apiScope
-				scopePaths := module.getScopePaths(apiScope)
-				scopePaths.currentApiFilePath = doc.ApiFilePath()
-				scopePaths.removedApiFilePath = doc.RemovedApiFilePath()
-				scopePaths.stubsSrcJar = doc.StubsSrcJar()
-			} else {
-				ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
-			}
+		// Extract information from any of the scope specific dependencies.
+		if scopeTag, ok := tag.(scopeDependencyTag); ok {
+			apiScope := scopeTag.apiScope
+			scopePaths := module.getScopePaths(apiScope)
+
+			// Extract information from the dependency. The exact information extracted
+			// is determined by the nature of the dependency which is determined by the tag.
+			scopeTag.extractDepInfo(ctx, to, scopePaths)
 		}
 	})
 }
@@ -350,14 +528,15 @@
 	return entriesList
 }
 
-// Module name of the stubs library
+// Name of the java_library module that compiles the stubs source.
 func (module *SdkLibrary) stubsName(apiScope *apiScope) string {
 	return apiScope.stubsModuleName(module.BaseModuleName())
 }
 
-// Module name of the docs
-func (module *SdkLibrary) docsName(apiScope *apiScope) string {
-	return apiScope.docsModuleName(module.BaseModuleName())
+// // Name of the droidstubs module that generates the stubs source and
+// generates/checks the API.
+func (module *SdkLibrary) stubsSourceName(apiScope *apiScope) string {
+	return apiScope.stubsSourceModuleName(module.BaseModuleName())
 }
 
 // Module name of the runtime implementation library
@@ -382,7 +561,7 @@
 }
 
 // Get the sdk version for use when compiling the stubs library.
-func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
+func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) string {
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
 	if sdkDep.hasStandardLibs() {
 		// If building against a standard sdk then use the sdk version appropriate for the scope.
@@ -402,9 +581,10 @@
 }
 
 // Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
 	props := struct {
 		Name                *string
+		Visibility          []string
 		Srcs                []string
 		Installable         *bool
 		Sdk_version         *string
@@ -435,8 +615,14 @@
 	}{}
 
 	props.Name = proptools.StringPtr(module.stubsName(apiScope))
+
+	// If stubs_library_visibility is not set then the created module will use the
+	// visibility of this module.
+	visibility := module.sdkLibraryProperties.Stubs_library_visibility
+	props.Visibility = visibility
+
 	// sources are generated from the droiddoc
-	props.Srcs = []string{":" + module.docsName(apiScope)}
+	props.Srcs = []string{":" + module.stubsSourceName(apiScope)}
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
 	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.System_modules = module.Library.Module.deviceProperties.System_modules
@@ -472,10 +658,11 @@
 }
 
 // Creates a droidstubs module that creates stubs source files from the given full source
-// files
-func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
+// files and also updates and checks the API specification files.
+func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope) {
 	props := struct {
 		Name                             *string
+		Visibility                       []string
 		Srcs                             []string
 		Installable                      *bool
 		Sdk_version                      *string
@@ -508,7 +695,13 @@
 	// * system_modules
 	// * libs (static_libs/libs)
 
-	props.Name = proptools.StringPtr(module.docsName(apiScope))
+	props.Name = proptools.StringPtr(module.stubsSourceName(apiScope))
+
+	// If stubs_source_visibility is not set then the created module will use the
+	// visibility of this module.
+	visibility := module.sdkLibraryProperties.Stubs_source_visibility
+	props.Visibility = visibility
+
 	props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...)
 	props.Sdk_version = module.Library.Module.deviceProperties.Sdk_version
 	props.System_modules = module.Library.Module.deviceProperties.System_modules
@@ -592,7 +785,7 @@
 }
 
 // Creates the xml file that publicizes the runtime library
-func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
+func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
 	props := struct {
 		Name                *string
 		Lib_name            *string
@@ -713,7 +906,12 @@
 // For a java_sdk_library module, create internal modules for stubs, docs,
 // runtime libs and xml file. If requested, the stubs and docs are created twice
 // once for public API level and once for system API level
-func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) {
+func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) {
+	// If the module has been disabled then don't create any child modules.
+	if !module.Enabled() {
+		return
+	}
+
 	if len(module.Library.Module.properties.Srcs) == 0 {
 		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
 		return
@@ -724,15 +922,15 @@
 	// also assume it does not contribute to the dist build.
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
 	hasSystemAndTestApis := sdkDep.hasStandardLibs()
-	module.sdkLibraryProperties.Has_system_and_test_apis = hasSystemAndTestApis
+	module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis
 	module.sdkLibraryProperties.No_dist = proptools.BoolPtr(!hasSystemAndTestApis)
 
 	missing_current_api := false
 
-	activeScopes := module.getActiveApiScopes()
+	generatedScopes := module.getGeneratedApiScopes(mctx)
 
 	apiDir := module.getApiDir()
-	for _, scope := range activeScopes {
+	for _, scope := range generatedScopes {
 		for _, api := range []string{"current.txt", "removed.txt"} {
 			path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
 			p := android.ExistentPathForSource(mctx, path)
@@ -755,13 +953,13 @@
 			"You can update them by:\n"+
 			"%s %q %s && m update-api",
 			script, filepath.Join(mctx.ModuleDir(), apiDir),
-			strings.Join(activeScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "))
+			strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "))
 		return
 	}
 
-	for _, scope := range activeScopes {
+	for _, scope := range generatedScopes {
 		module.createStubsLibrary(mctx, scope)
-		module.createStubsSources(mctx, scope)
+		module.createStubsSourcesAndApi(mctx, scope)
 	}
 
 	if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
@@ -799,7 +997,19 @@
 	module.InitSdkLibraryProperties()
 	android.InitApexModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.CreateInternalModules(ctx) })
+
+	// Initialize the map from scope to scope specific properties.
+	scopeToProperties := make(map[*apiScope]*ApiScopeProperties)
+	for _, scope := range allApiScopes {
+		scopeToProperties[scope] = scope.scopeSpecificProperties(module)
+	}
+	module.scopeToProperties = scopeToProperties
+
+	// Add the properties containing visibility rules so that they are checked.
+	android.AddVisibilityProperty(module, "stubs_library_visibility", &module.sdkLibraryProperties.Stubs_library_visibility)
+	android.AddVisibilityProperty(module, "stubs_source_visibility", &module.sdkLibraryProperties.Stubs_source_visibility)
+
+	module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { module.CreateInternalModules(ctx) })
 	return module
 }
 
@@ -816,7 +1026,7 @@
 	// List of shared java libs that this module has dependencies to
 	Libs []string
 
-	// The stub sources.
+	// The stubs source.
 	Stub_srcs []string `android:"path"`
 
 	// The current.txt
@@ -900,7 +1110,7 @@
 	android.InitSdkAwareModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 
-	android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
+	module.SetDefaultableHook(func(mctx android.DefaultableHookContext) { module.createInternalModules(mctx) })
 	return module
 }
 
@@ -912,7 +1122,7 @@
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
-func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookContext) {
+func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
 
 	// If the build is configured to use prebuilts then force this to be preferred.
 	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
@@ -935,7 +1145,7 @@
 	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
 }
 
-func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.LoadHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	// Creates a java import for the jar with ".stubs" suffix
 	props := struct {
 		Name                *string
@@ -971,12 +1181,12 @@
 	mctx.CreateModule(ImportFactory, &props)
 }
 
-func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.LoadHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	props := struct {
 		Name *string
 		Srcs []string
 	}{}
-	props.Name = proptools.StringPtr(apiScope.docsModuleName(module.BaseModuleName()))
+	props.Name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
 	props.Srcs = scopeProperties.Stub_srcs
 	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
 }
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 0fba739..0e2bea3 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -46,6 +46,12 @@
 }
 
 func (mod *Module) AndroidMk() android.AndroidMkData {
+	if mod.Properties.HideFromMake {
+		return android.AndroidMkData{
+			Disabled: true,
+		}
+	}
+
 	ret := android.AndroidMkData{
 		OutputFile: mod.outputFile,
 		Include:    "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
@@ -84,6 +90,9 @@
 	ret.DistFile = binary.distFile
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+		if binary.coverageOutputZipFile.Valid() {
+			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+binary.coverageOutputZipFile.String())
+		}
 	})
 }
 
@@ -124,6 +133,10 @@
 		if !library.rlib() {
 			fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
 		}
+		if library.coverageOutputZipFile.Valid() {
+			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+library.coverageOutputZipFile.String())
+		}
+
 	})
 }
 
diff --git a/rust/binary.go b/rust/binary.go
index fda056e..c25ae09 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -35,9 +35,10 @@
 type binaryDecorator struct {
 	*baseCompiler
 
-	Properties           BinaryCompilerProperties
-	distFile             android.OptionalPath
-	unstrippedOutputFile android.Path
+	Properties            BinaryCompilerProperties
+	distFile              android.OptionalPath
+	coverageOutputZipFile android.OptionalPath
+	unstrippedOutputFile  android.Path
 }
 
 var _ compiler = (*binaryDecorator)(nil)
@@ -104,6 +105,10 @@
 		&binary.Properties)
 }
 
+func (binary *binaryDecorator) nativeCoverage() bool {
+	return true
+}
+
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
 
@@ -114,7 +119,21 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 
-	TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	binary.coverageFile = outputs.coverageFile
+
+	var coverageFiles android.Paths
+	if outputs.coverageFile != nil {
+		coverageFiles = append(coverageFiles, binary.coverageFile)
+	}
+	if len(deps.coverageFiles) > 0 {
+		coverageFiles = append(coverageFiles, deps.coverageFiles...)
+	}
+	binary.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, binary.getStem(ctx))
 
 	return outputFile
 }
+
+func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath {
+	return binary.coverageOutputZipFile
+}
diff --git a/rust/builder.go b/rust/builder.go
index 2d5e602..fbe0e53 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -18,6 +18,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
 )
@@ -36,44 +37,57 @@
 			Depfile: "$out.d",
 		},
 		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
+
+	zip = pctx.AndroidStaticRule("zip",
+		blueprint.RuleParams{
+			Command:        "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
+			CommandDeps:    []string{"${SoongZipCmd}"},
+			Rspfile:        "$out.rsp",
+			RspfileContent: "$in",
+		})
 )
 
-func init() {
+type buildOutput struct {
+	outputFile   android.Path
+	coverageFile android.Path
+}
 
+func init() {
+	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 }
 
 func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
-	outputFile android.WritablePath, includeDirs []string) {
+	outputFile android.WritablePath, includeDirs []string) buildOutput {
 	flags.RustFlags = append(flags.RustFlags, "-C lto")
 
-	transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
 }
 
 func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
-	outputFile android.WritablePath, includeDirs []string) {
-	transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
+	outputFile android.WritablePath, includeDirs []string) buildOutput {
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
 }
 
 func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
-	outputFile android.WritablePath, includeDirs []string) {
-	transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
+	outputFile android.WritablePath, includeDirs []string) buildOutput {
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
 }
 
 func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
-	outputFile android.WritablePath, includeDirs []string) {
+	outputFile android.WritablePath, includeDirs []string) buildOutput {
 	flags.RustFlags = append(flags.RustFlags, "-C lto")
-	transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
 }
 
 func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
-	outputFile android.WritablePath, includeDirs []string) {
+	outputFile android.WritablePath, includeDirs []string) buildOutput {
 	flags.RustFlags = append(flags.RustFlags, "-C lto")
-	transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
 }
 
 func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps,
-	flags Flags, outputFile android.WritablePath, includeDirs []string) {
-	transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
+	flags Flags, outputFile android.WritablePath, includeDirs []string) buildOutput {
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
 }
 
 func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -85,11 +99,15 @@
 }
 
 func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
-	outputFile android.WritablePath, crate_type string, includeDirs []string) {
+	outputFile android.WritablePath, crate_type string, includeDirs []string) buildOutput {
 
 	var inputs android.Paths
 	var implicits android.Paths
+	var output buildOutput
 	var libFlags, rustcFlags, linkFlags []string
+	var implicitOutputs android.WritablePaths
+
+	output.outputFile = outputFile
 	crate_name := ctx.(ModuleContext).CrateName()
 	targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
 
@@ -141,12 +159,26 @@
 		implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
 	}
 
+	if flags.Coverage {
+		var gcnoFile android.WritablePath
+
+		if outputFile.Ext() != "" {
+			gcnoFile = android.PathForModuleOut(ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcno"))
+		} else {
+			gcnoFile = android.PathForModuleOut(ctx, outputFile.Base()+".gcno")
+		}
+
+		implicitOutputs = append(implicitOutputs, gcnoFile)
+		output.coverageFile = gcnoFile
+	}
+
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        rustc,
-		Description: "rustc " + main.Rel(),
-		Output:      outputFile,
-		Inputs:      inputs,
-		Implicits:   implicits,
+		Rule:            rustc,
+		Description:     "rustc " + main.Rel(),
+		Output:          outputFile,
+		ImplicitOutputs: implicitOutputs,
+		Inputs:          inputs,
+		Implicits:       implicits,
 		Args: map[string]string{
 			"rustcFlags": strings.Join(rustcFlags, " "),
 			"linkFlags":  strings.Join(linkFlags, " "),
@@ -156,4 +188,23 @@
 		},
 	})
 
+	return output
+}
+
+func TransformCoverageFilesToZip(ctx android.ModuleContext,
+	covFiles android.Paths, baseName string) android.OptionalPath {
+	if len(covFiles) > 0 {
+
+		outputFile := android.PathForModuleOut(ctx, baseName+".zip")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        zip,
+			Description: "zip " + outputFile.Base(),
+			Inputs:      covFiles,
+			Output:      outputFile,
+		})
+
+		return android.OptionalPathForPath(outputFile)
+	}
+	return android.OptionalPath{}
 }
diff --git a/rust/compiler.go b/rust/compiler.go
index 7499776..5f098bc 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -110,6 +110,7 @@
 	linkDirs      []string
 	edition       string
 	src           android.Path //rustc takes a single src file
+	coverageFile  android.Path //rustc generates a single gcno file
 
 	// Install related
 	dir      string
@@ -120,6 +121,10 @@
 	location installLocation
 }
 
+func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
+	panic("baseCompiler does not implement coverageOutputZipPath()")
+}
+
 var _ compiler = (*baseCompiler)(nil)
 
 func (compiler *baseCompiler) inData() bool {
@@ -235,6 +240,10 @@
 		compiler.relativeInstallPath(), compiler.relative)
 }
 
+func (compiler *baseCompiler) nativeCoverage() bool {
+	return false
+}
+
 func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
 	compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
 }
diff --git a/rust/coverage.go b/rust/coverage.go
new file mode 100644
index 0000000..9be57dc
--- /dev/null
+++ b/rust/coverage.go
@@ -0,0 +1,72 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong/cc"
+)
+
+var CovLibraryName = "libprofile-extras"
+
+type coverage struct {
+	Properties cc.CoverageProperties
+
+	// Whether binaries containing this module need --coverage added to their ldflags
+	linkCoverage bool
+}
+
+func (cov *coverage) props() []interface{} {
+	return []interface{}{&cov.Properties}
+}
+
+func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
+	if cov.Properties.NeedCoverageVariant {
+		ctx.AddVariationDependencies([]blueprint.Variation{
+			{Mutator: "link", Variation: "static"},
+		}, cc.CoverageDepTag, CovLibraryName)
+	}
+
+	return deps
+}
+
+func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+
+	if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+		return flags, deps
+	}
+
+	if cov.Properties.CoverageEnabled {
+		flags.Coverage = true
+		coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
+		flags.RustFlags = append(flags.RustFlags,
+			"-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads")
+		flags.LinkFlags = append(flags.LinkFlags,
+			"--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv")
+		deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+	}
+
+	return flags, deps
+}
+
+func (cov *coverage) begin(ctx BaseModuleContext) {
+	if ctx.Host() {
+		// Host coverage not yet supported.
+	} else {
+		// Update useSdk and sdkVersion args if Rust modules become SDK aware.
+		cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), false, "")
+	}
+}
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
new file mode 100644
index 0000000..27acad3
--- /dev/null
+++ b/rust/coverage_test.go
@@ -0,0 +1,181 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+// Test that coverage flags are being correctly generated.
+func TestCoverageFlags(t *testing.T) {
+	ctx := testRustCov(t, `
+		rust_library {
+			name: "libfoo_cov",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}
+		rust_binary {
+			name: "fizz_cov",
+			srcs: ["foo.rs"],
+		}
+        rust_binary {
+			name: "buzzNoCov",
+			srcs: ["foo.rs"],
+			native_coverage: false,
+		}
+		rust_library {
+			name: "libbar_nocov",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			native_coverage: false,
+		}`)
+
+	// Make sure native_coverage: false isn't creating a coverage variant.
+	if android.InList("android_arm64_armv8-a_dylib_cov", ctx.ModuleVariantsForTests("libbar_nocov")) {
+		t.Fatalf("coverage variant created for module 'libbar_nocov' with native coverage disabled")
+	}
+
+	// Just test the dylib variants unless the library coverage logic changes to distinguish between the types.
+	libfooCov := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc")
+	libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
+	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
+	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
+
+	rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"}
+	for _, flag := range rustcCoverageFlags {
+		missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
+		containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
+
+		if !strings.Contains(fizzCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"])
+		}
+		if !strings.Contains(libfooCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"])
+		}
+		if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"])
+		}
+		if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"])
+		}
+	}
+
+	linkCoverageFlags := []string{"--coverage", " -g "}
+	for _, flag := range linkCoverageFlags {
+		missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
+		containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
+
+		if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
+		}
+		if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
+		}
+		if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
+		}
+		if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
+		}
+	}
+
+}
+
+// Test coverage files are included correctly
+func TestCoverageZip(t *testing.T) {
+	ctx := testRustCov(t, `
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			rlibs: ["librlib"],
+			crate_name: "foo",
+		}
+		rust_library_rlib {
+			name: "librlib",
+			srcs: ["foo.rs"],
+			crate_name: "rlib",
+		}
+		rust_binary {
+			name: "fizz",
+			rlibs: ["librlib"],
+			static_libs: ["libfoo"],
+			srcs: ["foo.rs"],
+		}
+		cc_binary {
+			name: "buzz",
+			static_libs: ["libfoo"],
+			srcs: ["foo.c"],
+		}
+		cc_library {
+			name: "libbar",
+			static_libs: ["libfoo"],
+			compile_multilib: "64",
+			srcs: ["foo.c"],
+		}`)
+
+	fizzZipInputs := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
+	libfooZipInputs := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib_cov").Rule("zip").Inputs.Strings()
+	buzzZipInputs := ctx.ModuleForTests("buzz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
+	libbarZipInputs := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared_cov").Rule("zip").Inputs.Strings()
+
+	// Make sure the expected number of input files are included.
+	if len(fizzZipInputs) != 3 {
+		t.Fatalf("expected only 3 coverage inputs for rust 'fizz' binary, got %#v: %#v", len(fizzZipInputs), fizzZipInputs)
+	}
+	if len(libfooZipInputs) != 2 {
+		t.Fatalf("expected only 2 coverage inputs for rust 'libfoo' library, got %#v: %#v", len(libfooZipInputs), libfooZipInputs)
+	}
+	if len(buzzZipInputs) != 2 {
+		t.Fatalf("expected only 2 coverage inputs for cc 'buzz' binary, got %#v: %#v", len(buzzZipInputs), buzzZipInputs)
+	}
+	if len(libbarZipInputs) != 2 {
+		t.Fatalf("expected only 2 coverage inputs for cc 'libbar' library, got %#v: %#v", len(libbarZipInputs), libbarZipInputs)
+	}
+
+	// Make sure the expected inputs are provided to the zip rule.
+	if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
+		!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") ||
+		!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
+		t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
+	}
+	if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
+		!android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_dylib_cov/libfoo.dylib.gcno") {
+		t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
+	}
+	if !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_cov/obj/foo.gcno") ||
+		!android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") {
+		t.Fatalf("missing expected coverage files for cc 'buzz' binary: %#v", buzzZipInputs)
+	}
+	if !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/obj/foo.gcno") ||
+		!android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") {
+		t.Fatalf("missing expected coverage files for cc 'libbar' library: %#v", libbarZipInputs)
+	}
+}
+
+func TestCoverageDeps(t *testing.T) {
+	ctx := testRustCov(t, `
+		rust_binary {
+			name: "fizz",
+			srcs: ["foo.rs"],
+		}`)
+
+	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
+	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-extras.a") {
+		t.Fatalf("missing expected coverage 'libprofile-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
+	}
+}
diff --git a/rust/library.go b/rust/library.go
index 87e816d..8aa033c 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -75,11 +75,12 @@
 type libraryDecorator struct {
 	*baseCompiler
 
-	Properties           LibraryCompilerProperties
-	MutatedProperties    LibraryMutatedProperties
-	distFile             android.OptionalPath
-	unstrippedOutputFile android.Path
-	includeDirs          android.Paths
+	Properties            LibraryCompilerProperties
+	MutatedProperties     LibraryMutatedProperties
+	distFile              android.OptionalPath
+	coverageOutputZipFile android.OptionalPath
+	unstrippedOutputFile  android.Path
+	includeDirs           android.Paths
 }
 
 type libraryInterface interface {
@@ -107,6 +108,10 @@
 	BuildOnlyShared()
 }
 
+func (library *libraryDecorator) nativeCoverage() bool {
+	return true
+}
+
 func (library *libraryDecorator) exportedDirs() []string {
 	return library.linkDirs
 }
@@ -351,24 +356,37 @@
 		fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		library.coverageFile = outputs.coverageFile
 	} else if library.dylib() {
 		fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		library.coverageFile = outputs.coverageFile
 	} else if library.static() {
 		fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		library.coverageFile = outputs.coverageFile
 	} else if library.shared() {
 		fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+		library.coverageFile = outputs.coverageFile
 	}
 
+	var coverageFiles android.Paths
+	if library.coverageFile != nil {
+		coverageFiles = append(coverageFiles, library.coverageFile)
+	}
+	if len(deps.coverageFiles) > 0 {
+		coverageFiles = append(coverageFiles, deps.coverageFiles...)
+	}
+	library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
+
 	if library.rlib() || library.dylib() {
 		library.reexportDirs(deps.linkDirs...)
 		library.reexportDepFlags(deps.depFlags...)
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 45bef9e..1d97650 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -69,3 +69,7 @@
 	deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
 	return deps
 }
+
+func (prebuilt *prebuiltLibraryDecorator) nativeCoverage() bool {
+	return false
+}
diff --git a/rust/rust.go b/rust/rust.go
index 5cc8845..8cf2e6d 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -40,6 +40,7 @@
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
 		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
+		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
 }
@@ -51,6 +52,7 @@
 	LinkFlags       []string      // Flags that apply to linker
 	RustFlagsDeps   android.Paths // Files depended on by compiler flags
 	Toolchain       config.Toolchain
+	Coverage        bool
 }
 
 type BaseProperties struct {
@@ -60,6 +62,8 @@
 	AndroidMkSharedLibs    []string
 	AndroidMkStaticLibs    []string
 	SubName                string `blueprint:"mutated"`
+	PreventInstall         bool
+	HideFromMake           bool
 }
 
 type Module struct {
@@ -72,6 +76,7 @@
 	multilib android.Multilib
 
 	compiler         compiler
+	coverage         *coverage
 	cachedToolchain  config.Toolchain
 	subAndroidMkOnce map[subAndroidMkProvider]bool
 	outputFile       android.OptionalPath
@@ -224,6 +229,8 @@
 	depFlags   []string
 	//ReexportedDeps android.Paths
 
+	coverageFiles android.Paths
+
 	CrtBegin android.OptionalPath
 	CrtEnd   android.OptionalPath
 }
@@ -245,6 +252,34 @@
 	inData() bool
 	install(ctx ModuleContext, path android.Path)
 	relativeInstallPath() string
+
+	nativeCoverage() bool
+}
+
+func (mod *Module) isCoverageVariant() bool {
+	return mod.coverage.Properties.IsCoverageVariant
+}
+
+var _ cc.Coverage = (*Module)(nil)
+
+func (mod *Module) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+	return mod.coverage != nil && mod.coverage.Properties.NeedCoverageVariant
+}
+
+func (mod *Module) PreventInstall() {
+	mod.Properties.PreventInstall = true
+}
+
+func (mod *Module) HideFromMake() {
+	mod.Properties.HideFromMake = true
+}
+
+func (mod *Module) MarkAsCoverageVariant(coverage bool) {
+	mod.coverage.Properties.IsCoverageVariant = coverage
+}
+
+func (mod *Module) EnableCoverageIfNeeded() {
+	mod.coverage.Properties.CoverageEnabled = mod.coverage.Properties.NeedCoverageBuild
 }
 
 func defaultsFactory() android.Module {
@@ -268,6 +303,7 @@
 		&ProcMacroCompilerProperties{},
 		&PrebuiltProperties{},
 		&TestProperties{},
+		&cc.CoverageProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -395,6 +431,18 @@
 	return false
 }
 
+func (mod *Module) CoverageFiles() android.Paths {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(*libraryDecorator); ok {
+			if library.coverageFile != nil {
+				return android.Paths{library.coverageFile}
+			}
+			return android.Paths{}
+		}
+	}
+	panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
+}
+
 var _ cc.LinkableInterface = (*Module)(nil)
 
 func (mod *Module) Init() android.Module {
@@ -403,6 +451,10 @@
 	if mod.compiler != nil {
 		mod.AddProperties(mod.compiler.compilerProps()...)
 	}
+	if mod.coverage != nil {
+		mod.AddProperties(mod.coverage.props()...)
+	}
+
 	android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
 
 	android.InitDefaultableModule(mod)
@@ -432,6 +484,7 @@
 }
 func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	module := newBaseModule(hod, multilib)
+	module.coverage = &coverage{}
 	return module
 }
 
@@ -454,6 +507,7 @@
 	toolchain() config.Toolchain
 	baseModuleName() string
 	CrateName() string
+	nativeCoverage() bool
 }
 
 type depsContext struct {
@@ -466,6 +520,14 @@
 	moduleContextImpl
 }
 
+func (ctx *moduleContextImpl) nativeCoverage() bool {
+	return ctx.mod.nativeCoverage()
+}
+
+func (mod *Module) nativeCoverage() bool {
+	return mod.compiler != nil && mod.compiler.nativeCoverage()
+}
+
 type moduleContextImpl struct {
 	mod *Module
 	ctx BaseModuleContext
@@ -508,9 +570,17 @@
 
 	if mod.compiler != nil {
 		flags = mod.compiler.compilerFlags(ctx, flags)
+	}
+	if mod.coverage != nil {
+		flags, deps = mod.coverage.flags(ctx, flags, deps)
+	}
+
+	if mod.compiler != nil {
 		outputFile := mod.compiler.compile(ctx, flags, deps)
 		mod.outputFile = android.OptionalPathForPath(outputFile)
-		mod.compiler.install(ctx, mod.outputFile.Path())
+		if !mod.Properties.PreventInstall {
+			mod.compiler.install(ctx, mod.outputFile.Path())
+		}
 	}
 }
 
@@ -521,6 +591,10 @@
 		deps = mod.compiler.compilerDeps(ctx, deps)
 	}
 
+	if mod.coverage != nil {
+		deps = mod.coverage.deps(ctx, deps)
+	}
+
 	deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
 	deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
 	deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
@@ -553,6 +627,12 @@
 	testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
 )
 
+func (mod *Module) begin(ctx BaseModuleContext) {
+	if mod.coverage != nil {
+		mod.coverage.begin(ctx)
+	}
+}
+
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
@@ -588,6 +668,7 @@
 					ctx.ModuleErrorf("mod %q not an rlib library", depName)
 					return
 				}
+				depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...)
 				directRlibDeps = append(directRlibDeps, rustDep)
 				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
 			case procMacroDepTag:
@@ -642,6 +723,7 @@
 				depFlag = "-lstatic=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, depFlag)
+				depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
 			case cc.SharedDepTag:
@@ -772,6 +854,29 @@
 	actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
 }
 
+func BeginMutator(ctx android.BottomUpMutatorContext) {
+	if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() {
+		mod.beginMutator(ctx)
+	}
+}
+
+type baseModuleContext struct {
+	android.BaseModuleContext
+	moduleContextImpl
+}
+
+func (mod *Module) beginMutator(actx android.BottomUpMutatorContext) {
+	ctx := &baseModuleContext{
+		BaseModuleContext: actx,
+		moduleContextImpl: moduleContextImpl{
+			mod: mod,
+		},
+	}
+	ctx.ctx = ctx
+
+	mod.begin(ctx)
+}
+
 func (mod *Module) Name() string {
 	name := mod.ModuleBase.Name()
 	if p, ok := mod.compiler.(interface {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 32eddc1..d658ee2 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -21,6 +21,8 @@
 	"strings"
 	"testing"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/cc"
 )
@@ -57,6 +59,7 @@
 
 	fs := map[string][]byte{
 		"foo.rs":     nil,
+		"foo.c":      nil,
 		"src/bar.rs": nil,
 		"liby.so":    nil,
 		"libz.so":    nil,
@@ -68,6 +71,14 @@
 }
 
 func testRust(t *testing.T, bp string) *android.TestContext {
+	return testRustContext(t, bp, false)
+}
+
+func testRustCov(t *testing.T, bp string) *android.TestContext {
+	return testRustContext(t, bp, true)
+}
+
+func testRustContext(t *testing.T, bp string, coverage bool) *android.TestContext {
 	// TODO (b/140435149)
 	if runtime.GOOS != "linux" {
 		t.Skip("Only the Linux toolchain is supported for Rust")
@@ -76,6 +87,11 @@
 	t.Helper()
 	config := testConfig(bp)
 
+	if coverage {
+		config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
+		config.TestProductVariables.CoveragePaths = []string{"*"}
+	}
+
 	t.Helper()
 	ctx := CreateTestContext()
 	ctx.Register(config)
diff --git a/rust/test.go b/rust/test.go
index 04f844c..94568c1 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -50,6 +50,10 @@
 	testConfig android.Path
 }
 
+func (test *testDecorator) nativeCoverage() bool {
+	return true
+}
+
 func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
 	module := newModule(hod, android.MultilibFirst)
 
diff --git a/rust/testing.go b/rust/testing.go
index aad4ffe..09008a8 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -98,6 +98,7 @@
 		// rust mutators
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
 		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
+		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 
 	return ctx
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index eef6149..c60eaa1 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -1,5 +1,15 @@
 #!/bin/bash -e
 
+# This is a wrapper around "m" that builds the given modules in multi-arch mode
+# for all architectures supported by Mainline modules. The make (kati) stage is
+# skipped, so the build targets in the arguments can only be Soong modules or
+# intermediate output files - make targets and normal installed paths are not
+# supported.
+#
+# This script is typically used with "sdk" or "module_export" modules, which
+# Soong will install in $OUT_DIR/soong/mainline-sdks (cf
+# PathForMainlineSdksInstall in android/paths.go).
+
 export OUT_DIR=${OUT_DIR:-out}
 
 if [ -e ${OUT_DIR}/soong/.soong.in_make ]; then
@@ -8,11 +18,16 @@
   # expected to be supplied by the .mk files, and that might cause errors in
   # "m --skip-make" below. We therefore default to a different out dir
   # location in that case.
-  AML_OUT_DIR=out-aml
+  AML_OUT_DIR=out/aml
   echo "Avoiding in-make OUT_DIR '${OUT_DIR}' - building in '${AML_OUT_DIR}' instead"
   OUT_DIR=${AML_OUT_DIR}
 fi
 
+if [ ! -e "build/envsetup.sh" ]; then
+  echo "$0 must be run from the top of the tree"
+  exit 1
+fi
+
 source build/envsetup.sh
 
 my_get_build_var() {
@@ -22,13 +37,13 @@
   OUT_DIR=${OUT_DIR}/get_build_var get_build_var "$@"
 }
 
-PLATFORM_SDK_VERSION=$(my_get_build_var PLATFORM_SDK_VERSION)
-PLATFORM_VERSION=$(my_get_build_var PLATFORM_VERSION)
-PLATFORM_VERSION_ALL_CODENAMES=$(my_get_build_var PLATFORM_VERSION_ALL_CODENAMES)
+readonly PLATFORM_SDK_VERSION="$(my_get_build_var PLATFORM_SDK_VERSION)"
+readonly PLATFORM_VERSION="$(my_get_build_var PLATFORM_VERSION)"
+PLATFORM_VERSION_ALL_CODENAMES="$(my_get_build_var PLATFORM_VERSION_ALL_CODENAMES)"
 
 # PLATFORM_VERSION_ALL_CODENAMES is a comma separated list like O,P. We need to
 # turn this into ["O","P"].
-PLATFORM_VERSION_ALL_CODENAMES=${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}
+PLATFORM_VERSION_ALL_CODENAMES="${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}"
 PLATFORM_VERSION_ALL_CODENAMES="[\"${PLATFORM_VERSION_ALL_CODENAMES}\"]"
 
 # Logic from build/make/core/goma.mk
@@ -46,11 +61,16 @@
   USE_GOMA=false
 fi
 
-SOONG_OUT=${OUT_DIR}/soong
+readonly SOONG_OUT=${OUT_DIR}/soong
 mkdir -p ${SOONG_OUT}
-SOONG_VARS=${SOONG_OUT}/soong.variables
+readonly SOONG_VARS=${SOONG_OUT}/soong.variables
 
-# We enable bionic linux builds as ART also needs prebuilts for it.
+# Aml_abis: true
+#   -  This flag configures Soong to compile for all architectures required for
+#      Mainline modules.
+# CrossHost: linux_bionic
+# CrossHostArch: x86_64
+#   -  Enable Bionic on host as ART needs prebuilts for it.
 cat > ${SOONG_VARS}.new << EOF
 {
     "Platform_sdk_version": ${PLATFORM_SDK_VERSION},
@@ -79,4 +99,6 @@
 # We use force building LLVM components flag (even though we actually don't
 # compile them) because we don't have bionic host prebuilts
 # for them.
-FORCE_BUILD_LLVM_COMPONENTS=true m --skip-make "$@"
+export FORCE_BUILD_LLVM_COMPONENTS=true
+
+m --skip-make "$@"
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index fc91c3d..770adc9 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -ex
+#!/bin/bash -e
 
 # Non exhaustive list of modules where we want prebuilts. More can be added as
 # needed.
@@ -23,42 +23,45 @@
 
 # We want to create apex modules for all supported architectures.
 PRODUCTS=(
-    aosp_arm
-    aosp_arm64
-    aosp_x86
-    aosp_x86_64
+  aosp_arm
+  aosp_arm64
+  aosp_x86
+  aosp_x86_64
 )
 
 if [ ! -e "build/make/core/Makefile" ]; then
-    echo "$0 must be run from the top of the tree"
-    exit 1
+  echo "$0 must be run from the top of the tree"
+  exit 1
 fi
 
+echo_and_run() {
+  echo "$*"
+  "$@"
+}
+
 OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
 DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
 
 for product in "${PRODUCTS[@]}"; do
-    build/soong/soong_ui.bash --make-mode $@ \
-        TARGET_PRODUCT=${product} \
-        ${MAINLINE_MODULES[@]}
+  echo_and_run build/soong/soong_ui.bash --make-mode $@ \
+    TARGET_PRODUCT=${product} \
+    ${MAINLINE_MODULES[@]}
 
-    PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
-    TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
-    rm -rf ${DIST_DIR}/${TARGET_ARCH}/
-    mkdir -p ${DIST_DIR}/${TARGET_ARCH}/
-    for module in "${MAINLINE_MODULES[@]}"; do
-      cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
-    done
+  PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
+  TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
+  rm -rf ${DIST_DIR}/${TARGET_ARCH}/
+  mkdir -p ${DIST_DIR}/${TARGET_ARCH}/
+  for module in "${MAINLINE_MODULES[@]}"; do
+    echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
+  done
 done
 
 
 # Create multi-archs SDKs in a different out directory. The multi-arch script
-# uses soong directly and therefore needs its own directory that doesn't clash
-# with make.
-export OUT_DIR=${OUT_DIR}/aml/
-for sdk in "${MODULES_SDK_AND_EXPORTS[@]}"; do
-    build/soong/scripts/build-aml-prebuilts.sh ${sdk}
-done
+# uses Soong in --skip-make mode which cannot use the same directory as normal
+# mode with make.
+export OUT_DIR=${OUT_DIR}/aml
+echo_and_run build/soong/scripts/build-aml-prebuilts.sh ${MODULES_SDK_AND_EXPORTS[@]}
 
 rm -rf ${DIST_DIR}/mainline-sdks
-cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
+echo_and_run cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
diff --git a/sdk/bp_test.go b/sdk/bp_test.go
index f89f38c..c630c25 100644
--- a/sdk/bp_test.go
+++ b/sdk/bp_test.go
@@ -57,7 +57,7 @@
 
 	contents := &generatedContents{}
 	outputPropertySet(contents, set)
-	helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\\n", contents.content.String())
+	helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\n", contents.content.String())
 }
 
 func TestTransformRemovePropertySet(t *testing.T) {
@@ -72,5 +72,5 @@
 
 	contents := &generatedContents{}
 	outputPropertySet(contents, set)
-	helper.AssertTrimmedStringEquals("removing property set failed", "name: \"name\",\\n", contents.content.String())
+	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 733f7ac..dded153 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -1805,3 +1805,89 @@
 }
 `))
 }
+
+func TestDeviceAndHostSnapshotWithStubsLibrary(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_shared_libs: ["stubslib"],
+		}
+
+		cc_library {
+			name: "internaldep",
+			host_supported: true,
+		}
+
+		cc_library {
+			name: "stubslib",
+			host_supported: true,
+			shared_libs: ["internaldep"],
+			stubs: {
+				symbol_file: "some/where/stubslib.map.txt",
+				versions: ["1", "2", "3"],
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_stubslib@current",
+    sdk_member_name: "stubslib",
+    host_supported: true,
+    installable: false,
+    stubs: {
+        versions: ["3"],
+    },
+    target: {
+        android_arm64: {
+            srcs: ["android/arm64/lib/stubslib.so"],
+        },
+        android_arm: {
+            srcs: ["android/arm/lib/stubslib.so"],
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/stubslib.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/stubslib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "stubslib",
+    prefer: false,
+    host_supported: true,
+    stubs: {
+        versions: ["3"],
+    },
+    target: {
+        android_arm64: {
+            srcs: ["android/arm64/lib/stubslib.so"],
+        },
+        android_arm: {
+            srcs: ["android/arm/lib/stubslib.so"],
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/stubslib.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/stubslib.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    native_shared_libs: ["mysdk_stubslib@current"],
+}
+`))
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 788d016..560a6b8 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -32,6 +32,8 @@
 		"api/system-removed.txt":                            nil,
 		"api/test-current.txt":                              nil,
 		"api/test-removed.txt":                              nil,
+		"api/module-lib-current.txt":                        nil,
+		"api/module-lib-removed.txt":                        nil,
 		"build/soong/scripts/gen-java-current-api-files.sh": nil,
 	}
 
@@ -56,6 +58,9 @@
 	name: "android_test_stubs_current",
 }
 java_import {
+	name: "android_module_lib_stubs_current",
+}
+java_import {
 	name: "core-lambda-stubs", 
 	sdk_version: "none",
 }
@@ -984,6 +989,8 @@
 			apex_available: ["//apex_available:anyapex"],
 			srcs: ["Test.java"],
 			sdk_version: "current",
+			stubs_library_visibility: ["//other"],
+			stubs_source_visibility: ["//another"],
 		}
 	`)
 
@@ -1067,3 +1074,194 @@
 			".intermediates/mysdk/common_os/tmp/sdk_library/test/myjavalib_stub_sources.zip"),
 	)
 }
+
+func TestSnapshotWithJavaSdkLibrary_ApiSurfaces(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",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			},
+		}
+	`)
+
+	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"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+        current_api: "sdk_library/system/myjavalib.txt",
+        removed_api: "sdk_library/system/myjavalib-removed.txt",
+        sdk_version: "system_current",
+    },
+}
+
+java_sdk_library_import {
+    name: "myjavalib",
+    prefer: false,
+    apex_available: ["//apex_available:anyapex"],
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+        current_api: "sdk_library/system/myjavalib.txt",
+        removed_api: "sdk_library/system/myjavalib-removed.txt",
+        sdk_version: "system_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.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib-removed.txt
+`),
+		checkMergeZips(
+			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
+			".intermediates/mysdk/common_os/tmp/sdk_library/system/myjavalib_stub_sources.zip",
+		),
+	)
+}
+
+func TestSnapshotWithJavaSdkLibrary_ModuleLib(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",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+		}
+	`)
+
+	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"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+        current_api: "sdk_library/system/myjavalib.txt",
+        removed_api: "sdk_library/system/myjavalib-removed.txt",
+        sdk_version: "system_current",
+    },
+    module_lib: {
+        jars: ["sdk_library/module_lib/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/module_lib/myjavalib_stub_sources"],
+        current_api: "sdk_library/module_lib/myjavalib.txt",
+        removed_api: "sdk_library/module_lib/myjavalib-removed.txt",
+        sdk_version: "module_current",
+    },
+}
+
+java_sdk_library_import {
+    name: "myjavalib",
+    prefer: false,
+    apex_available: ["//apex_available:anyapex"],
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+        current_api: "sdk_library/system/myjavalib.txt",
+        removed_api: "sdk_library/system/myjavalib-removed.txt",
+        sdk_version: "system_current",
+    },
+    module_lib: {
+        jars: ["sdk_library/module_lib/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/module_lib/myjavalib_stub_sources"],
+        current_api: "sdk_library/module_lib/myjavalib.txt",
+        removed_api: "sdk_library/module_lib/myjavalib-removed.txt",
+        sdk_version: "module_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.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module_lib/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module_lib/myjavalib.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module_lib/myjavalib-removed.txt
+`),
+		checkMergeZips(
+			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
+			".intermediates/mysdk/common_os/tmp/sdk_library/system/myjavalib_stub_sources.zip",
+			".intermediates/mysdk/common_os/tmp/sdk_library/module_lib/myjavalib_stub_sources.zip",
+		),
+	)
+}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 2f125e2..ae1a492 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -226,19 +226,20 @@
 }
 
 type EmbeddedPropertiesStruct struct {
-	S_Embedded_Common    string
-	S_Embedded_Different string
+	S_Embedded_Common    string `android:"arch_variant"`
+	S_Embedded_Different string `android:"arch_variant"`
 }
 
 type testPropertiesStruct struct {
+	name        string
 	private     string
 	Public_Kept string `sdk:"keep"`
 	S_Common    string
-	S_Different string
+	S_Different string `android:"arch_variant"`
 	A_Common    []string
-	A_Different []string
+	A_Different []string `android:"arch_variant"`
 	F_Common    *bool
-	F_Different *bool
+	F_Different *bool `android:"arch_variant"`
 	EmbeddedPropertiesStruct
 }
 
@@ -246,10 +247,17 @@
 	return p
 }
 
+func (p *testPropertiesStruct) String() string {
+	return p.name
+}
+
+var _ propertiesContainer = (*testPropertiesStruct)(nil)
+
 func TestCommonValueOptimization(t *testing.T) {
-	common := &testPropertiesStruct{}
+	common := &testPropertiesStruct{name: "common"}
 	structs := []propertiesContainer{
 		&testPropertiesStruct{
+			name:        "struct-0",
 			private:     "common",
 			Public_Kept: "common",
 			S_Common:    "common",
@@ -264,6 +272,7 @@
 			},
 		},
 		&testPropertiesStruct{
+			name:        "struct-1",
 			private:     "common",
 			Public_Kept: "common",
 			S_Common:    "common",
@@ -280,11 +289,15 @@
 	}
 
 	extractor := newCommonValueExtractor(common)
-	extractor.extractCommonProperties(common, structs)
 
 	h := TestHelper{t}
-	h.AssertDeepEquals("common properties not correct", common,
+
+	err := extractor.extractCommonProperties(common, structs)
+	h.AssertDeepEquals("unexpected error", nil, err)
+
+	h.AssertDeepEquals("common properties not correct",
 		&testPropertiesStruct{
+			name:        "common",
 			private:     "",
 			Public_Kept: "",
 			S_Common:    "common",
@@ -297,10 +310,12 @@
 				S_Embedded_Common:    "embedded_common",
 				S_Embedded_Different: "",
 			},
-		})
+		},
+		common)
 
-	h.AssertDeepEquals("updated properties[0] not correct", structs[0],
+	h.AssertDeepEquals("updated properties[0] not correct",
 		&testPropertiesStruct{
+			name:        "struct-0",
 			private:     "common",
 			Public_Kept: "common",
 			S_Common:    "",
@@ -313,10 +328,12 @@
 				S_Embedded_Common:    "",
 				S_Embedded_Different: "embedded_upper",
 			},
-		})
+		},
+		structs[0])
 
-	h.AssertDeepEquals("updated properties[1] not correct", structs[1],
+	h.AssertDeepEquals("updated properties[1] not correct",
 		&testPropertiesStruct{
+			name:        "struct-1",
 			private:     "common",
 			Public_Kept: "common",
 			S_Common:    "",
@@ -329,5 +346,29 @@
 				S_Embedded_Common:    "",
 				S_Embedded_Different: "embedded_lower",
 			},
-		})
+		},
+		structs[1])
+}
+
+func TestCommonValueOptimization_InvalidArchSpecificVariants(t *testing.T) {
+	common := &testPropertiesStruct{name: "common"}
+	structs := []propertiesContainer{
+		&testPropertiesStruct{
+			name:     "struct-0",
+			S_Common: "should-be-but-is-not-common0",
+		},
+		&testPropertiesStruct{
+			name:     "struct-1",
+			S_Common: "should-be-but-is-not-common1",
+		},
+	}
+
+	extractor := newCommonValueExtractor(common)
+
+	h := TestHelper{t}
+
+	err := extractor.extractCommonProperties(common, structs)
+	h.AssertErrorMessageEquals("unexpected error", `field "S_Common" is not tagged as "arch_variant" but has arch specific properties:
+    "struct-0" has value "should-be-but-is-not-common0"
+    "struct-1" has value "should-be-but-is-not-common1"`, err)
 }
diff --git a/sdk/testing.go b/sdk/testing.go
index 9e27201..4361754 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -173,6 +173,15 @@
 	}
 }
 
+func (h *TestHelper) AssertErrorMessageEquals(message string, expected string, actual error) {
+	h.t.Helper()
+	if actual == nil {
+		h.t.Errorf("Expected error but was nil")
+	} else if actual.Error() != expected {
+		h.t.Errorf("%s: expected %s, actual %s", message, expected, actual.Error())
+	}
+}
+
 func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string, actual string) {
 	h.t.Helper()
 	h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
@@ -198,7 +207,7 @@
 // e.g. find the src/dest pairs from each cp command, the various zip files
 // generated, etc.
 func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo {
-	androidBpContents := strings.NewReplacer("\\n", "\n").Replace(sdk.GetAndroidBpContentsForTests())
+	androidBpContents := sdk.GetAndroidBpContentsForTests()
 
 	info := &snapshotBuildInfo{
 		r:                 r,
diff --git a/sdk/update.go b/sdk/update.go
index 75da2dd..476a4a5 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -87,18 +87,23 @@
 }
 
 func (gc *generatedContents) Printfln(format string, args ...interface{}) {
-	// ninja consumes newline characters in rspfile_content. Prevent it by
-	// escaping the backslash in the newline character. The extra backslash
-	// is removed when the rspfile is written to the actual script file
-	fmt.Fprintf(&(gc.content), strings.Repeat("    ", gc.indentLevel)+format+"\\n", args...)
+	fmt.Fprintf(&(gc.content), strings.Repeat("    ", gc.indentLevel)+format+"\n", args...)
 }
 
 func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
 	rb := android.NewRuleBuilder()
-	// convert \\n to \n
+
+	content := gf.content.String()
+
+	// ninja consumes newline characters in rspfile_content. Prevent it by
+	// escaping the backslash in the newline character. The extra backslash
+	// is removed when the rspfile is written to the actual script file
+	content = strings.ReplaceAll(content, "\n", "\\n")
+
 	rb.Command().
 		Implicits(implicits).
-		Text("echo").Text(proptools.ShellEscape(gf.content.String())).
+		Text("echo").Text(proptools.ShellEscape(content)).
+		// convert \\n to \n
 		Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
 	rb.Command().
 		Text("chmod a+x").Output(gf.path)
@@ -306,13 +311,13 @@
 	for _, sdkVariant := range sdkVariants {
 		properties := sdkVariant.dynamicMemberTypeListProperties
 		osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant
-		dynamicMemberPropertiesContainers = append(dynamicMemberPropertiesContainers, &dynamicMemberPropertiesContainer{properties})
+		dynamicMemberPropertiesContainers = append(dynamicMemberPropertiesContainers, &dynamicMemberPropertiesContainer{sdkVariant, properties})
 	}
 
 	// Extract the common lists of members into a separate struct.
 	commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
 	extractor := newCommonValueExtractor(commonDynamicMemberProperties)
-	extractor.extractCommonProperties(commonDynamicMemberProperties, dynamicMemberPropertiesContainers)
+	extractCommonProperties(ctx, extractor, commonDynamicMemberProperties, dynamicMemberPropertiesContainers)
 
 	// Add properties common to all os types.
 	s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
@@ -389,6 +394,13 @@
 	return outputZipFile
 }
 
+func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) {
+	err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice)
+	if err != nil {
+		ctx.ModuleErrorf("error extracting common properties: %s", err)
+	}
+}
+
 func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) {
 	for _, memberListProperty := range s.memberListProperties() {
 		names := memberListProperty.getter(dynamicMemberTypeListProperties)
@@ -829,6 +841,8 @@
 	archInfos []*archTypeSpecificInfo
 }
 
+var _ propertiesContainer = (*osTypeSpecificInfo)(nil)
+
 type variantPropertiesFactoryFunc func() android.SdkMemberProperties
 
 // Create a new osTypeSpecificInfo for the specified os type and its properties
@@ -886,7 +900,7 @@
 
 // Optimize the properties by extracting common properties from arch type specific
 // properties into os type specific properties.
-func (osInfo *osTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
 	// Nothing to do if there is only a single common architecture.
 	if len(osInfo.archInfos) == 0 {
 		return
@@ -897,10 +911,10 @@
 		multilib = multilib.addArchType(archInfo.archType)
 
 		// Optimize the arch properties first.
-		archInfo.optimizeProperties(commonValueExtractor)
+		archInfo.optimizeProperties(ctx, commonValueExtractor)
 	}
 
-	commonValueExtractor.extractCommonProperties(osInfo.Properties, osInfo.archInfos)
+	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, osInfo.Properties, osInfo.archInfos)
 
 	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
 	osInfo.Properties.Base().Compile_multilib = multilib.String()
@@ -973,6 +987,17 @@
 	}
 }
 
+func (osInfo *osTypeSpecificInfo) isHostVariant() bool {
+	osClass := osInfo.osType.Class
+	return osClass == android.Host || osClass == android.HostCross
+}
+
+var _ isHostVariant = (*osTypeSpecificInfo)(nil)
+
+func (osInfo *osTypeSpecificInfo) String() string {
+	return fmt.Sprintf("OsType{%s}", osInfo.osType)
+}
+
 type archTypeSpecificInfo struct {
 	baseInfo
 
@@ -981,6 +1006,8 @@
 	linkInfos []*linkTypeSpecificInfo
 }
 
+var _ propertiesContainer = (*archTypeSpecificInfo)(nil)
+
 // 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 {
@@ -1038,12 +1065,12 @@
 
 // Optimize the properties by extracting common properties from link type specific
 // properties into arch type specific properties.
-func (archInfo *archTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
 	if len(archInfo.linkInfos) == 0 {
 		return
 	}
 
-	commonValueExtractor.extractCommonProperties(archInfo.Properties, archInfo.linkInfos)
+	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.linkInfos)
 }
 
 // Add the properties for an arch type to a property set.
@@ -1058,12 +1085,18 @@
 	}
 }
 
+func (archInfo *archTypeSpecificInfo) String() string {
+	return fmt.Sprintf("ArchType{%s}", archInfo.archType)
+}
+
 type linkTypeSpecificInfo struct {
 	baseInfo
 
 	linkType string
 }
 
+var _ propertiesContainer = (*linkTypeSpecificInfo)(nil)
+
 // 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 {
@@ -1079,6 +1112,10 @@
 	return linkInfo
 }
 
+func (l *linkTypeSpecificInfo) String() string {
+	return fmt.Sprintf("LinkType{%s}", l.linkType)
+}
+
 type memberContext struct {
 	sdkMemberContext android.ModuleContext
 	builder          *snapshotBuilder
@@ -1143,11 +1180,11 @@
 		osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo)
 
 		// Optimize the properties across all the variants for a specific os type.
-		osInfo.optimizeProperties(commonValueExtractor)
+		osInfo.optimizeProperties(ctx, commonValueExtractor)
 	}
 
 	// Extract properties which are common across all architectures and os types.
-	commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesContainers)
+	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
 
 	// Add the common properties to the module.
 	commonProperties.AddToPropertySet(ctx, bpModule)
@@ -1186,15 +1223,49 @@
 	return osTypes
 }
 
-// Given a struct value, access a field within that struct (or one of its embedded
-// structs).
+// Given a set of properties (struct value), return the value of the field within that
+// struct (or one of its embedded structs).
 type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
 
+// Checks the metadata to determine whether the property should be ignored for the
+// purposes of common value extraction or not.
+type extractorMetadataPredicate func(metadata propertiesContainer) bool
+
+// Indicates whether optimizable properties are provided by a host variant or
+// not.
+type isHostVariant interface {
+	isHostVariant() bool
+}
+
+// A property that can be optimized by the commonValueExtractor.
+type extractorProperty struct {
+	// The name of the field for this property.
+	name string
+
+	// Filter that can use metadata associated with the properties being optimized
+	// to determine whether the field should be ignored during common value
+	// optimization.
+	filter extractorMetadataPredicate
+
+	// Retrieves the value on which common value optimization will be performed.
+	getter fieldAccessorFunc
+
+	// The empty value for the field.
+	emptyValue reflect.Value
+
+	// True if the property can support arch variants false otherwise.
+	archVariant bool
+}
+
+func (p extractorProperty) String() string {
+	return p.name
+}
+
 // 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
+	// The properties that the extractor can optimize.
+	properties []extractorProperty
 }
 
 // Create a new common value extractor for the structure type for the supplied
@@ -1229,8 +1300,25 @@
 			continue
 		}
 
+		var filter extractorMetadataPredicate
+
+		// Add a filter
+		if proptools.HasTag(field, "sdk", "ignored-on-host") {
+			filter = func(metadata propertiesContainer) bool {
+				if m, ok := metadata.(isHostVariant); ok {
+					if m.isHostVariant() {
+						return false
+					}
+				}
+				return true
+			}
+		}
+
 		// Save a copy of the field index for use in the function.
 		fieldIndex := f
+
+		name := field.Name
+
 		fieldGetter := func(value reflect.Value) reflect.Value {
 			if containingStructAccessor != nil {
 				// This is an embedded structure so first access the field for the embedded
@@ -1241,6 +1329,12 @@
 			// Skip through interface and pointer values to find the structure.
 			value = getStructValue(value)
 
+			defer func() {
+				if r := recover(); r != nil {
+					panic(fmt.Errorf("%s for fieldIndex %d of field %s of value %#v", r, fieldIndex, name, value.Interface()))
+				}
+			}()
+
 			// Return the field.
 			return value.Field(fieldIndex)
 		}
@@ -1249,7 +1343,14 @@
 			// Gather fields from the embedded structure.
 			e.gatherFields(field.Type, fieldGetter)
 		} else {
-			e.fieldGetters = append(e.fieldGetters, fieldGetter)
+			property := extractorProperty{
+				name,
+				filter,
+				fieldGetter,
+				reflect.Zero(field.Type),
+				proptools.HasTag(field, "android", "arch_variant"),
+			}
+			e.properties = append(e.properties, property)
 		}
 	}
 }
@@ -1275,12 +1376,15 @@
 // Allows additional information to be associated with the properties, e.g. for
 // filtering.
 type propertiesContainer interface {
+	fmt.Stringer
+
 	// Get the properties that need optimizing.
 	optimizableProperties() interface{}
 }
 
 // A wrapper for dynamic member properties to allow them to be optimized.
 type dynamicMemberPropertiesContainer struct {
+	sdkVariant              *sdk
 	dynamicMemberProperties interface{}
 }
 
@@ -1288,6 +1392,10 @@
 	return c.dynamicMemberProperties
 }
 
+func (c dynamicMemberPropertiesContainer) String() string {
+	return c.sdkVariant.String()
+}
+
 // Extract common properties from a slice of property structures of the same type.
 //
 // All the property structures must be of the same type.
@@ -1298,23 +1406,46 @@
 // 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{}) {
+func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) error {
 	commonPropertiesValue := reflect.ValueOf(commonProperties)
 	commonStructValue := commonPropertiesValue.Elem()
 
 	sliceValue := reflect.ValueOf(inputPropertiesSlice)
 
-	for _, fieldGetter := range e.fieldGetters {
+	for _, property := range e.properties {
+		fieldGetter := property.getter
+		filter := property.filter
+		if filter == nil {
+			filter = func(metadata propertiesContainer) bool {
+				return true
+			}
+		}
+
 		// 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.
+		// is nil on entry to the loop and if it is nil on exit then there is no common value or
+		// all the values have been filtered out, otherwise it points to the common value.
 		var commonValue *reflect.Value
 
+		// Assume that all the values will be the same.
+		//
+		// While similar to this is not quite the same as commonValue == nil. If all the values
+		// have been filtered out then this will be false but commonValue == nil will be true.
+		valuesDiffer := false
+
 		for i := 0; i < sliceValue.Len(); i++ {
 			container := sliceValue.Index(i).Interface().(propertiesContainer)
 			itemValue := reflect.ValueOf(container.optimizableProperties())
 			fieldValue := fieldGetter(itemValue)
 
+			if !filter(container) {
+				expectedValue := property.emptyValue.Interface()
+				actualValue := fieldValue.Interface()
+				if !reflect.DeepEqual(expectedValue, actualValue) {
+					return fmt.Errorf("field %q is supposed to be ignored for %q but is set to %#v instead of %#v", property, container, actualValue, expectedValue)
+				}
+				continue
+			}
+
 			if commonValue == nil {
 				// Use the first value as the commonProperties value.
 				commonValue = &fieldValue
@@ -1323,15 +1454,16 @@
 				// no value in common so break out.
 				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
 					commonValue = nil
+					valuesDiffer = true
 					break
 				}
 			}
 		}
 
-		// If the fields all have a common value then store it in the common struct field
+		// If the fields all have 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())
+			emptyValue := property.emptyValue
 			fieldGetter(commonStructValue).Set(*commonValue)
 			for i := 0; i < sliceValue.Len(); i++ {
 				container := sliceValue.Index(i).Interface().(propertiesContainer)
@@ -1340,5 +1472,22 @@
 				fieldValue.Set(emptyValue)
 			}
 		}
+
+		if valuesDiffer && !property.archVariant {
+			// The values differ but the property does not support arch variants so it
+			// is an error.
+			var details strings.Builder
+			for i := 0; i < sliceValue.Len(); i++ {
+				container := sliceValue.Index(i).Interface().(propertiesContainer)
+				itemValue := reflect.ValueOf(container.optimizableProperties())
+				fieldValue := fieldGetter(itemValue)
+
+				_, _ = fmt.Fprintf(&details, "\n    %q has value %q", container.String(), fieldValue.Interface())
+			}
+
+			return fmt.Errorf("field %q is not tagged as \"arch_variant\" but has arch specific properties:%s", property.String(), details.String())
+		}
 	}
+
+	return nil
 }
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index a46dce9..596284b 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -64,12 +64,16 @@
 
 type Option struct {
 	Name  string
+	Key   string
 	Value string
 }
 
 var _ Config = Option{}
 
 func (o Option) Config() string {
+	if o.Key != "" {
+		return fmt.Sprintf(`<option name="%s" key="%s" value="%s" />`, o.Name, o.Key, o.Value)
+	}
 	return fmt.Sprintf(`<option name="%s" value="%s" />`, o.Name, o.Value)
 }
 
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 0bcdccb..e1123e0 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -104,6 +104,7 @@
 		productOut("*.img"),
 		productOut("*.zip"),
 		productOut("android-info.txt"),
+		productOut("misc_info.txt"),
 		productOut("apex"),
 		productOut("kernel"),
 		productOut("data"),