Merge "Fix the logic for selecting ABI dump paths"
diff --git a/android/config.go b/android/config.go
index 7953170..558c828 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1032,6 +1032,10 @@
 	return c.config.productVariables.DeviceKernelHeaders
 }
 
+func (c *deviceConfig) SamplingPGO() bool {
+	return Bool(c.config.productVariables.SamplingPGO)
+}
+
 func (c *config) NativeLineCoverage() bool {
 	return Bool(c.productVariables.NativeLineCoverage)
 }
diff --git a/android/sdk.go b/android/sdk.go
index 731bdff..66094cd 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -145,10 +145,6 @@
 	return s.properties.RequiredSdks
 }
 
-func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
-	sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
-}
-
 // InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
 // SdkBase.
 func InitSdkAwareModule(m SdkAware) {
@@ -320,17 +316,6 @@
 	// the module is not allowed in whichever sdk property it was added.
 	IsInstance(module Module) bool
 
-	// Build the snapshot for the SDK member
-	//
-	// The ModuleContext provided is for the SDK module, so information for
-	// variants in the supplied member can be accessed using the Other... methods.
-	//
-	// The SdkMember is guaranteed to contain variants for which the
-	// IsInstance(Module) method returned true.
-	//
-	// deprecated Use AddPrebuiltModule() instead.
-	BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
-
 	// Add a prebuilt module that the sdk will populate.
 	//
 	// Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
@@ -357,7 +342,7 @@
 	//   structure and calls AddToPropertySet(...) on the properties struct to add the member
 	//   specific properties in the correct place in the structure.
 	//
-	AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule
+	AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
 
 	// Create a structure into which variant specific properties can be added.
 	CreateVariantPropertiesStruct() SdkMemberProperties
@@ -382,19 +367,6 @@
 	return b.TransitiveSdkMembers
 }
 
-func (b *SdkMemberTypeBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) {
-	panic("override AddPrebuiltModule")
-}
-
-func (b *SdkMemberTypeBase) AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule {
-	// Returning nil causes the legacy BuildSnapshot method to be used.
-	return nil
-}
-
-func (b *SdkMemberTypeBase) CreateVariantPropertiesStruct() SdkMemberProperties {
-	panic("override me")
-}
-
 // Encapsulates the information about registered SdkMemberTypes.
 type SdkMemberTypesRegistry struct {
 	// The list of types sorted by property name.
@@ -466,14 +438,29 @@
 // Contains common properties that apply across many different member types. These
 // are not affected by the optimization to extract common values.
 type SdkMemberPropertiesBase struct {
-	// The setting to use for the compile_multilib property.
-	Compile_multilib string `sdk:"keep"`
-
 	// The number of unique os types supported by the member variants.
+	//
+	// If a member has a variant with more than one os type then it will need to differentiate
+	// the locations of any of their prebuilt files in the snapshot by os type to prevent them
+	// from colliding. See OsPrefix().
+	//
+	// This property is the same for all variants of a member and so would be optimized away
+	// if it was not explicitly kept.
 	Os_count int `sdk:"keep"`
 
 	// The os type for which these properties refer.
+	//
+	// Provided to allow a member to differentiate between os types in the locations of their
+	// prebuilt files when it supports more than one os type.
+	//
+	// This property is the same for all os type specific variants of a member and so would be
+	// optimized away if it was not explicitly kept.
 	Os OsType `sdk:"keep"`
+
+	// The setting to use for the compile_multilib property.
+	//
+	// This property is set after optimization so there is no point in trying to optimize it.
+	Compile_multilib string `sdk:"keep"`
 }
 
 // The os prefix to use for any file paths in the sdk.
@@ -501,9 +488,28 @@
 	// Access the base structure.
 	Base() *SdkMemberPropertiesBase
 
-	// Populate the structure with information from the variant.
-	PopulateFromVariant(variant SdkAware)
+	// Populate this structure with information from the variant.
+	PopulateFromVariant(ctx SdkMemberContext, variant Module)
 
-	// Add the information from the structure to the property set.
-	AddToPropertySet(sdkModuleContext ModuleContext, builder SnapshotBuilder, propertySet BpPropertySet)
+	// Add the information from this structure to the property set.
+	AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
+}
+
+// Provides access to information common to a specific member.
+type SdkMemberContext interface {
+
+	// The module context of the sdk common os variant which is creating the snapshot.
+	SdkModuleContext() ModuleContext
+
+	// The builder of the snapshot.
+	SnapshotBuilder() SnapshotBuilder
+
+	// The type of the member.
+	MemberType() SdkMemberType
+
+	// The name of the member.
+	//
+	// Provided for use by sdk members to create a member specific location within the snapshot
+	// into which to copy the prebuilt files.
+	Name() string
 }
diff --git a/android/variable.go b/android/variable.go
index 91de956..8357d2f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -252,6 +252,8 @@
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
+	SamplingPGO  *bool   `json:",omitempty"`
+
 	NativeLineCoverage   *bool    `json:",omitempty"`
 	Native_coverage      *bool    `json:",omitempty"`
 	ClangCoverage        *bool    `json:",omitempty"`
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 5c15e8e..db1048e 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -22,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -181,6 +182,9 @@
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
 			// we will have foo.apk.apk
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".apk"))
+			if app, ok := fi.module.(*java.AndroidApp); ok && len(app.JniCoverageOutputs()) > 0 {
+				fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " "))
+			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk")
 		} else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest {
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
diff --git a/apex/apex.go b/apex/apex.go
index 46aaa8b..ebc5969 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2023,6 +2023,13 @@
 		return
 	}
 
+	// Coverage build adds additional dependencies for the coverage-only runtime libraries.
+	// Requiring them and their transitive depencies with apex_available is not right
+	// because they just add noise.
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || a.IsNativeCoverageNeeded(ctx) {
+		return
+	}
+
 	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
 		apexName := ctx.ModuleName()
 		fromName := ctx.OtherModuleName(from)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 5468c77..0bae124 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -874,58 +874,89 @@
 
 }
 
-func TestApexDependencyToLLNDK(t *testing.T) {
-	ctx, _ := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			use_vendor: true,
-			native_shared_libs: ["mylib"],
-		}
+func TestApexDependsOnLLNDKTransitively(t *testing.T) {
+	testcases := []struct {
+		name          string
+		minSdkVersion string
+		shouldLink    string
+		shouldNotLink []string
+	}{
+		{
+			name:          "should link to test latest",
+			minSdkVersion: "current",
+			shouldLink:    "30",
+			shouldNotLink: []string{"29"},
+		},
+		{
+			name:          "should link to llndk#29",
+			minSdkVersion: "29",
+			shouldLink:    "29",
+			shouldNotLink: []string{"30"},
+		},
+	}
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx, _ := testApex(t, `
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				use_vendor: true,
+				native_shared_libs: ["mylib"],
+				min_sdk_version: "`+tc.minSdkVersion+`",
+			}
 
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
+			apex_key {
+				name: "myapex.key",
+				public_key: "testkey.avbpubkey",
+				private_key: "testkey.pem",
+			}
 
-		cc_library {
-			name: "mylib",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			shared_libs: ["libbar"],
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "myapex" ],
-		}
+			cc_library {
+				name: "mylib",
+				srcs: ["mylib.cpp"],
+				vendor_available: true,
+				shared_libs: ["libbar"],
+				system_shared_libs: [],
+				stl: "none",
+				apex_available: [ "myapex" ],
+			}
 
-		cc_library {
-			name: "libbar",
-			srcs: ["mylib.cpp"],
-			system_shared_libs: [],
-			stl: "none",
-		}
+			cc_library {
+				name: "libbar",
+				srcs: ["mylib.cpp"],
+				system_shared_libs: [],
+				stl: "none",
+				stubs: { versions: ["29","30"] },
+			}
 
-		llndk_library {
-			name: "libbar",
-			symbol_file: "",
-		}
-	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorWhitelistForTest(config, []string{"myapex"})
-	})
+			llndk_library {
+				name: "libbar",
+				symbol_file: "",
+			}
+			`, func(fs map[string][]byte, config android.Config) {
+				setUseVendorWhitelistForTest(config, []string{"myapex"})
+			}, withUnbundledBuild)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
-	copyCmds := apexRule.Args["copy_commands"]
+			// Ensure that LLNDK dep is not included
+			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+				"lib64/mylib.so",
+			})
 
-	// Ensure that LLNDK dep is not included
-	ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
+			// Ensure that LLNDK dep is required
+			apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+			ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
+			ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
-	ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
+			mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+			ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
+			for _, ver := range tc.shouldNotLink {
+				ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
+			}
 
-	// Ensure that LLNDK dep is required
-	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
-
+			mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+			ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink)
+		})
+	}
 }
 
 func TestApexWithSystemLibsStubs(t *testing.T) {
@@ -1255,10 +1286,6 @@
 	// note that platform variant is not.
 	cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module)
 	ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
-
-	libFlags := ctx.ModuleForTests("libx", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
-	ensureContains(t, libFlags, "android_arm64_armv8-a_shared_myapex/libc++.so")
-	ensureContains(t, libFlags, "android_arm64_armv8-a_shared_29/libc.so") // min_sdk_version applied
 }
 
 func TestInvalidMinSdkVersion(t *testing.T) {
@@ -1797,6 +1824,7 @@
 				"myapex",
 				"otherapex",
 			],
+			recovery_available: true,
 		}
 		cc_library {
 			name: "mylib2",
@@ -1814,7 +1842,7 @@
 	// non-APEX variant does not have __ANDROID_APEX__ defined
 	mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
-	ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
 
 	// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
@@ -1846,6 +1874,11 @@
 	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
 	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+
+	// recovery variant does not set __ANDROID_SDK_VERSION__
+	mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
 }
 
 func TestHeaderLibsDependency(t *testing.T) {
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 59d1502..4cdfb31 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -60,6 +60,10 @@
 func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	cflags := []string{
 		"-nostdlibinc",
+
+		// Make paths in deps files relative
+		"-no-canonical-prefixes",
+
 		"-O2",
 		"-isystem bionic/libc/include",
 		"-isystem bionic/libc/kernel/uapi",
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 2778ebd..1d9cc54 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -18,6 +18,7 @@
 	"path/filepath"
 
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 )
 
@@ -63,9 +64,8 @@
 	return false
 }
 
-func (mt *binarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
-	return pbm
+func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
 }
 
 func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -107,7 +107,7 @@
 	SystemSharedLibs []string
 }
 
-func (p *nativeBinaryInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	ccModule := variant.(*Module)
 
 	p.archType = ccModule.Target().Arch.ArchType.String()
@@ -122,11 +122,12 @@
 	}
 }
 
-func (p *nativeBinaryInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
 	if p.Compile_multilib != "" {
 		propertySet.AddProperty("compile_multilib", p.Compile_multilib)
 	}
 
+	builder := ctx.SnapshotBuilder()
 	if p.outputFile != nil {
 		propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
 
@@ -137,7 +138,9 @@
 		propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
 	}
 
-	if len(p.SystemSharedLibs) > 0 {
+	// SystemSharedLibs needs to be propagated if it's a list, even if it's empty,
+	// so check for non-nil instead of nonzero length.
+	if p.SystemSharedLibs != nil {
 		propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
 	}
 }
diff --git a/cc/cc.go b/cc/cc.go
index 037b99c..de07229 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -378,7 +378,7 @@
 
 type specifiedDeps struct {
 	sharedLibs       []string
-	systemSharedLibs []string
+	systemSharedLibs []string // Note nil and [] are semantically distinct.
 }
 
 type installer interface {
@@ -622,6 +622,10 @@
 			c.Properties.PreventInstall = true
 			return
 		}
+		if _, ok := c.linker.(*llndkStubDecorator); ok {
+			c.Properties.HideFromMake = true
+			return
+		}
 	}
 	panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName()))
 }
@@ -641,6 +645,10 @@
 			library.MutatedProperties.StubsVersion = version
 			return
 		}
+		if llndk, ok := c.linker.(*llndkStubDecorator); ok {
+			llndk.libraryDecorator.MutatedProperties.StubsVersion = version
+			return
+		}
 	}
 	panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
 }
@@ -650,6 +658,9 @@
 		if library, ok := c.linker.(*libraryDecorator); ok {
 			return library.MutatedProperties.StubsVersion
 		}
+		if llndk, ok := c.linker.(*llndkStubDecorator); ok {
+			return llndk.libraryDecorator.MutatedProperties.StubsVersion
+		}
 	}
 	panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName()))
 }
@@ -1851,7 +1862,7 @@
 	addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
 		var variations []blueprint.Variation
 		variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
-		versionVariantAvail := !ctx.useVndk() && !c.InRecovery() && !c.InRamdisk()
+		versionVariantAvail := !c.InRecovery() && !c.InRamdisk()
 		if version != "" && versionVariantAvail {
 			// Version is explicitly specified. i.e. libFoo#30
 			variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
@@ -2186,13 +2197,17 @@
 		if depTag == android.ProtoPluginDepTag {
 			return
 		}
+		if depTag == llndkImplDep {
+			return
+		}
 
 		if dep.Target().Os != ctx.Os() {
 			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
 			return
 		}
 		if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
-			ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+			ctx.ModuleErrorf("Arch mismatch between %q(%v) and %q(%v)",
+				ctx.ModuleName(), ctx.Arch().ArchType, depName, dep.Target().Arch.ArchType)
 			return
 		}
 
@@ -2287,6 +2302,27 @@
 					return // stop processing this dep
 				}
 			}
+			if c.UseVndk() {
+				if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK
+					// by default, use current version of LLNDK
+					versionToUse := ""
+					versions := stubsVersionsFor(ctx.Config())[depName]
+					if c.ApexName() != "" && len(versions) > 0 {
+						// if this is for use_vendor apex && dep has stubsVersions
+						// apply the same rule of apex sdk enforcement to choose right version
+						var err error
+						useLatest := c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild()
+						versionToUse, err = c.ChooseSdkVersion(versions, useLatest)
+						if err != nil {
+							ctx.OtherModuleErrorf(dep, err.Error())
+							return
+						}
+					}
+					if versionToUse != ccDep.StubsVersion() {
+						return
+					}
+				}
+			}
 
 			depPaths.IncludeDirs = append(depPaths.IncludeDirs, ccDep.IncludeDirs()...)
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 9a9678f..67eb248 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2398,6 +2398,34 @@
 	}
 }
 
+func TestLlndkLibrary(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library {
+		name: "libllndk",
+		stubs: { versions: ["1", "2"] },
+	}
+	llndk_library {
+		name: "libllndk",
+	}
+	`)
+	actual := ctx.ModuleVariantsForTests("libllndk.llndk")
+	expected := []string{
+		"android_vendor.VER_arm64_armv8-a_shared",
+		"android_vendor.VER_arm64_armv8-a_shared_1",
+		"android_vendor.VER_arm64_armv8-a_shared_2",
+		"android_vendor.VER_arm_armv7-a-neon_shared",
+		"android_vendor.VER_arm_armv7-a-neon_shared_1",
+		"android_vendor.VER_arm_armv7-a-neon_shared_2",
+	}
+	checkEquals(t, "variants for llndk stubs", expected, actual)
+
+	params := ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub")
+	checkEquals(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
+
+	params = ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub")
+	checkEquals(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
+}
+
 func TestLlndkHeaders(t *testing.T) {
 	ctx := testCc(t, `
 	llndk_headers {
diff --git a/cc/compiler.go b/cc/compiler.go
index fe81bd0..681b1ab 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -315,18 +315,6 @@
 			"-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
 	}
 
-	if ctx.canUseSdk() {
-		sdkVersion := ctx.sdkVersion()
-		if sdkVersion == "" || sdkVersion == "current" {
-			if ctx.isForPlatform() {
-				sdkVersion = strconv.Itoa(android.FutureApiLevel)
-			} else {
-				sdkVersion = strconv.Itoa(ctx.apexSdkVersion())
-			}
-		}
-		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+sdkVersion)
-	}
-
 	if ctx.useVndk() {
 		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VNDK__")
 	}
@@ -340,6 +328,9 @@
 		if Bool(compiler.Properties.Use_apex_name_macro) {
 			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__")
 		}
+		if ctx.Device() {
+			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion()))
+		}
 	}
 
 	instructionSet := String(compiler.Properties.Instruction_set)
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 6a9b709..b7173a3 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -198,6 +198,11 @@
 	return installLocation
 }
 
+// Get the device-only shared library symbols install directory.
+func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string {
+	return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base())
+}
+
 func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
 	fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
 		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -269,6 +274,12 @@
 		fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
 			sharedLibraryInstallLocation(
 				lib, ctx.Host(), ctx.Arch().ArchType.String()))
+
+		// Also add the dependency on the shared library symbols dir.
+		if !ctx.Host() {
+			fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+				sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String()))
+		}
 	}
 }
 
@@ -419,12 +430,24 @@
 				continue
 			}
 			sharedLibraryInstalled[installDestination] = true
+
 			// Escape all the variables, as the install destination here will be called
 			// via. $(eval) in Make.
 			installDestination = strings.ReplaceAll(
 				installDestination, "$", "$$")
 			s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
 				library.String()+":"+installDestination)
+
+			// Ensure that on device, the library is also reinstalled to the /symbols/
+			// dir. Symbolized DSO's are always installed to the device when fuzzing, but
+			// we want symbolization tools (like `stack`) to be able to find the symbols
+			// in $ANDROID_PRODUCT_OUT/symbols automagically.
+			if !ccModule.Host() {
+				symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
+				symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
+				s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
+					library.String()+":"+symbolsInstallDestination)
+			}
 		}
 
 		// The executable.
diff --git a/cc/library.go b/cc/library.go
index 776668b..b9f448b 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -749,10 +749,12 @@
 
 func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
 	if library.static() {
+		// Compare with nil because an empty list needs to be propagated.
 		if library.StaticProperties.Static.System_shared_libs != nil {
 			library.baseLinker.Properties.System_shared_libs = library.StaticProperties.Static.System_shared_libs
 		}
 	} else if library.shared() {
+		// Compare with nil because an empty list needs to be propagated.
 		if library.SharedProperties.Shared.System_shared_libs != nil {
 			library.baseLinker.Properties.System_shared_libs = library.SharedProperties.Shared.System_shared_libs
 		}
@@ -828,10 +830,21 @@
 	}
 
 	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
-	specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
+
+	// Must distinguish nil and [] in system_shared_libs - ensure that [] in
+	// either input list doesn't come out as nil.
+	if specifiedDeps.systemSharedLibs == nil {
+		specifiedDeps.systemSharedLibs = properties.System_shared_libs
+	} else {
+		specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
+	}
 
 	specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
-	specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
+	if len(specifiedDeps.systemSharedLibs) > 0 {
+		// Skip this if systemSharedLibs is either nil or [], to ensure they are
+		// retained.
+		specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
+	}
 	return specifiedDeps
 }
 
@@ -1372,6 +1385,8 @@
 			len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 &&
 			len(staticCompiler.StaticProperties.Static.Shared_libs) == 0 &&
 			len(sharedCompiler.SharedProperties.Shared.Shared_libs) == 0 &&
+			// Compare System_shared_libs properties with nil because empty lists are
+			// semantically significant for them.
 			staticCompiler.StaticProperties.Static.System_shared_libs == nil &&
 			sharedCompiler.SharedProperties.Shared.System_shared_libs == nil {
 
@@ -1488,6 +1503,19 @@
 	}
 }
 
+func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
+	// "" is for the non-stubs variant
+	versions = append([]string{""}, versions...)
+
+	modules := mctx.CreateVariations(versions...)
+	for i, m := range modules {
+		if versions[i] != "" {
+			m.(LinkableInterface).SetBuildStubs()
+			m.(LinkableInterface).SetStubsVersions(versions[i])
+		}
+	}
+}
+
 // Version mutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func VersionMutator(mctx android.BottomUpMutatorContext) {
@@ -1499,24 +1527,30 @@
 				return
 			}
 
-			// save the list of versions for later use
 			stubsVersionsLock.Lock()
 			defer stubsVersionsLock.Unlock()
+			// save the list of versions for later use
 			stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
 
-			// "" is for the non-stubs variant
-			versions = append([]string{""}, versions...)
-
-			modules := mctx.CreateVariations(versions...)
-			for i, m := range modules {
-				if versions[i] != "" {
-					m.(LinkableInterface).SetBuildStubs()
-					m.(LinkableInterface).SetStubsVersions(versions[i])
-				}
-			}
-		} else {
-			mctx.CreateVariations("")
+			createVersionVariations(mctx, versions)
+			return
 		}
+
+		if c, ok := library.(*Module); ok && c.IsStubs() {
+			stubsVersionsLock.Lock()
+			defer stubsVersionsLock.Unlock()
+			// For LLNDK llndk_library, we borrow vstubs.ersions from its implementation library.
+			// Since llndk_library has dependency to its implementation library,
+			// we can safely access stubsVersionsFor() with its baseModuleName.
+			versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()]
+			// save the list of versions for later use
+			stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
+
+			createVersionVariations(mctx, versions)
+			return
+		}
+
+		mctx.CreateVariations("")
 		return
 	}
 	if genrule, ok := mctx.Module().(*genrule.Module); ok {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index d010db1..0a11af1 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -110,8 +110,8 @@
 	return false
 }
 
-func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	pbm := builder.AddPrebuiltModule(member, mt.prebuiltModuleType)
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType)
 
 	ccModule := member.Variants()[0].(*Module)
 
@@ -212,7 +212,9 @@
 		outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
 	}
 
-	if len(libInfo.SystemSharedLibs) > 0 {
+	// SystemSharedLibs needs to be propagated if it's a list, even if it's empty,
+	// so check for non-nil instead of nonzero length.
+	if libInfo.SystemSharedLibs != nil {
 		outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
 	}
 
@@ -327,7 +329,8 @@
 	// This field is exported as its contents may not be arch specific.
 	SharedLibs []string
 
-	// The set of system shared libraries
+	// 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
@@ -336,7 +339,7 @@
 	outputFile android.Path
 }
 
-func (p *nativeLibInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	ccModule := variant.(*Module)
 
 	// If the library has some link types then it produces an output binary file, otherwise it
@@ -369,6 +372,6 @@
 	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
 }
 
-func (p *nativeLibInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
-	addPossiblyArchSpecificProperties(sdkModuleContext, builder, p, propertySet)
+func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet)
 }
diff --git a/cc/linker.go b/cc/linker.go
index ae5ee0a..f65d7c8 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -491,7 +491,15 @@
 
 func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
 	specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
-	specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
+
+	// Must distinguish nil and [] in system_shared_libs - ensure that [] in
+	// either input list doesn't come out as nil.
+	if specifiedDeps.systemSharedLibs == nil {
+		specifiedDeps.systemSharedLibs = linker.Properties.System_shared_libs
+	} else {
+		specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
+	}
+
 	return specifiedDeps
 }
 
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 3dee692..09050aa 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -19,8 +19,14 @@
 	"strings"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint"
 )
 
+var llndkImplDep = struct {
+	blueprint.DependencyTag
+}{}
+
 var (
 	llndkLibrarySuffix = ".llndk"
 	llndkHeadersSuffix = ".llndk"
@@ -81,6 +87,9 @@
 		// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
 		vndkVer = "current"
 	}
+	if stub.stubsVersion() != "" {
+		vndkVer = stub.stubsVersion()
+	}
 	objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), vndkVer, "--llndk")
 	stub.versionScriptPath = versionScript
 	return objs
@@ -154,6 +163,10 @@
 		stub.libraryDecorator.flagExporter.Properties.Export_include_dirs = []string{}
 	}
 
+	if stub.stubsVersion() != "" {
+		stub.reexportFlags("-D" + versioningMacroName(ctx.baseModuleName()) + "=" + stub.stubsVersion())
+	}
+
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
diff --git a/cc/pgo.go b/cc/pgo.go
index d5c4b87..88903bb 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -88,20 +88,21 @@
 	return []interface{}{&pgo.Properties}
 }
 
-func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
 
-	if props.isInstrumentation() {
-		flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
-		// The profile runtime is added below in deps().  Add the below
-		// flag, which is the only other link-time action performed by
-		// the Clang driver during link.
-		flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
-	}
-	if props.isSampling() {
-		flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
-	}
+	flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
+	// The profile runtime is added below in deps().  Add the below
+	// flag, which is the only other link-time action performed by
+	// the Clang driver during link.
+	flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
+	return flags
+}
+func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
+
+	flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
+	flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
 	return flags
 }
 
@@ -286,8 +287,12 @@
 	props := pgo.Properties
 
 	// Add flags to profile this module based on its profile_kind
-	if props.ShouldProfileModule {
-		return props.addProfileGatherFlags(ctx, flags)
+	if props.ShouldProfileModule && props.isInstrumentation() {
+		return props.addInstrumentationProfileGatherFlags(ctx, flags)
+	} else if props.ShouldProfileModule && props.isSampling() {
+		return props.addSamplingProfileGatherFlags(ctx, flags)
+	} else if ctx.DeviceConfig().SamplingPGO() {
+		return props.addSamplingProfileGatherFlags(ctx, flags)
 	}
 
 	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
diff --git a/cc/vndk.go b/cc/vndk.go
index e02e7b5..4888dcf 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -297,6 +297,9 @@
 	if !Bool(lib.Properties.Vendor_available) {
 		vndkPrivateLibraries(mctx.Config())[name] = filename
 	}
+	if mctx.OtherModuleExists(name) {
+		mctx.AddFarVariationDependencies(m.Target().Variations(), llndkImplDep, name)
+	}
 }
 
 func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
diff --git a/cuj/cuj.go b/cuj/cuj.go
index c7ff8ff..3333012 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -33,8 +33,9 @@
 )
 
 type Test struct {
-	name string
-	args []string
+	name   string
+	args   []string
+	before func() error
 
 	results TestResults
 }
@@ -119,6 +120,15 @@
 	t.results.metrics = met
 }
 
+// Touch the Intent.java file to cause a rebuild of the frameworks to monitor the
+// incremental build speed as mentioned b/152046247. Intent.java file was chosen
+// as it is a key component of the framework and is often modified.
+func touchIntentFile() error {
+	const intentFileName = "frameworks/base/core/java/android/content/Intent.java"
+	currentTime := time.Now().Local()
+	return os.Chtimes(intentFileName, currentTime, currentTime)
+}
+
 func main() {
 	outDir := os.Getenv("OUT_DIR")
 	if outDir == "" {
@@ -170,6 +180,36 @@
 			name: "framework_rebuild_twice",
 			args: []string{"framework"},
 		},
+		{
+			// Scenario major_inc_build (b/152046247): tracking build speed of major incremental build.
+			name: "major_inc_build_droid",
+			args: []string{"droid"},
+		},
+		{
+			name:   "major_inc_build_framework_minus_apex_after_droid_build",
+			args:   []string{"framework-minus-apex"},
+			before: touchIntentFile,
+		},
+		{
+			name:   "major_inc_build_framework_after_droid_build",
+			args:   []string{"framework"},
+			before: touchIntentFile,
+		},
+		{
+			name:   "major_inc_build_sync_after_droid_build",
+			args:   []string{"sync"},
+			before: touchIntentFile,
+		},
+		{
+			name:   "major_inc_build_droid_rebuild",
+			args:   []string{"droid"},
+			before: touchIntentFile,
+		},
+		{
+			name:   "major_inc_build_update_api_after_droid_rebuild",
+			args:   []string{"update-api"},
+			before: touchIntentFile,
+		},
 	}
 
 	cujMetrics := metrics.NewCriticalUserJourneysMetrics()
@@ -178,6 +218,12 @@
 	for i, t := range tests {
 		logsSubDir := fmt.Sprintf("%02d_%s", i, t.name)
 		logsDir := filepath.Join(cujDir, "logs", logsSubDir)
+		if t.before != nil {
+			if err := t.before(); err != nil {
+				fmt.Printf("error running before function on test %q: %v\n", t.name, err)
+				break
+			}
+		}
 		t.Run(logsDir)
 		if t.results.err != nil {
 			fmt.Printf("error running test %q: %s\n", t.name, t.results.err)
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 6cb9873..0e1bfc6 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -41,21 +41,12 @@
 
 	"android/soong/android"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 )
 
 const SystemPartition = "/system/"
 const SystemOtherPartition = "/system_other/"
 
-type dependencyTag struct {
-	blueprint.BaseDependencyTag
-	name string
-}
-
-var SystemServerDepTag = dependencyTag{name: "system-server-dep"}
-var SystemServerForcedDepTag = dependencyTag{name: "system-server-forced-dep"}
-
 // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
 // ModuleConfig.  The produced files and their install locations will be available through rule.Installs().
 func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConfig,
@@ -116,13 +107,6 @@
 		}
 	}
 
-	// Don't preopt system server jars that are not Soong modules.
-	if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
-		if _, ok := ctx.(android.ModuleContext); !ok {
-			return true
-		}
-	}
-
 	// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
 	// Also preopt system server jars since selinux prevents system server from loading anything from
 	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
@@ -239,6 +223,8 @@
 
 	invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
 
+	systemServerJars := NonUpdatableSystemServerJars(ctx, global)
+
 	// The class loader context using paths in the build
 	var classLoaderContextHost android.Paths
 
@@ -253,8 +239,8 @@
 	var conditionalClassLoaderContextHost29 android.Paths
 	var conditionalClassLoaderContextTarget29 []string
 
-	var classLoaderContextHostString, classLoaderContextDeviceString string
-	var classLoaderDeps android.Paths
+	// A flag indicating if the '&' class loader context is used.
+	unknownClassLoaderContext := false
 
 	if module.EnforceUsesLibraries {
 		usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
@@ -298,49 +284,38 @@
 			pathForLibrary(module, hidlBase))
 		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
 			filepath.Join("/system/framework", hidlBase+".jar"))
-
-		classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":")
-	} else if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
-		// We expect that all dexpreopted system server jars are Soong modules.
-		mctx, isModule := ctx.(android.ModuleContext)
-		if !isModule {
-			panic("Cannot dexpreopt system server jar that is not a soong module.")
+	} else if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
+		// System server jars should be dexpreopted together: class loader context of each jar
+		// should include all preceding jars on the system server classpath.
+		for _, otherJar := range systemServerJars[:jarIndex] {
+			classLoaderContextHost = append(classLoaderContextHost, SystemServerDexJarHostPath(ctx, otherJar))
+			classLoaderContextTarget = append(classLoaderContextTarget, "/system/framework/"+otherJar+".jar")
 		}
 
-		// System server jars should be dexpreopted together: class loader context of each jar
-		// should include preceding jars (which can be found as dependencies of the current jar
-		// with a special tag).
-		var jarsOnHost android.Paths
-		var jarsOnDevice []string
-		mctx.VisitDirectDepsWithTag(SystemServerDepTag, func(dep android.Module) {
-			depName := mctx.OtherModuleName(dep)
-			if jar, ok := dep.(interface{ DexJar() android.Path }); ok {
-				jarsOnHost = append(jarsOnHost, jar.DexJar())
-				jarsOnDevice = append(jarsOnDevice, "/system/framework/"+depName+".jar")
-			} else {
-				mctx.ModuleErrorf("module \"%s\" is not a jar", depName)
-			}
-		})
-		classLoaderContextHostString = strings.Join(jarsOnHost.Strings(), ":")
-		classLoaderContextDeviceString = strings.Join(jarsOnDevice, ":")
-		classLoaderDeps = jarsOnHost
+		// Copy the system server jar to a predefined location where dex2oat will find it.
+		dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
+		rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
+		rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
 	} else {
 		// Pass special class loader context to skip the classpath and collision check.
 		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
 		// Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
 		// to the &.
-		classLoaderContextHostString = `\&`
+		unknownClassLoaderContext = true
 	}
 
 	rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
 	rule.Command().FlagWithOutput("rm -f ", odexPath)
 	// Set values in the environment of the rule.  These may be modified by construct_context.sh.
-	if classLoaderContextHostString == `\&` {
-		rule.Command().Text(`class_loader_context_arg=--class-loader-context=\&`)
-		rule.Command().Text(`stored_class_loader_context_arg=""`)
+	if unknownClassLoaderContext {
+		rule.Command().
+			Text(`class_loader_context_arg=--class-loader-context=\&`).
+			Text(`stored_class_loader_context_arg=""`)
 	} else {
-		rule.Command().Text("class_loader_context_arg=--class-loader-context=PCL[" + classLoaderContextHostString + "]")
-		rule.Command().Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + classLoaderContextDeviceString + "]")
+		rule.Command().
+			Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(classLoaderContextHost.Strings(), ":") + "]").
+			Implicits(classLoaderContextHost).
+			Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(classLoaderContextTarget, ":") + "]")
 	}
 
 	if module.EnforceUsesLibraries {
@@ -395,7 +370,7 @@
 		Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":").
 		Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
 		Flag("${class_loader_context_arg}").
-		Flag("${stored_class_loader_context_arg}").Implicits(classLoaderDeps).
+		Flag("${stored_class_loader_context_arg}").
 		FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
 		FlagWithInput("--dex-file=", module.DexPath).
 		FlagWithArg("--dex-location=", dexLocationArg).
@@ -609,6 +584,14 @@
 	}).([]string)
 }
 
+// A predefined location for the system server dex jars. This is needed in order to generate
+// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown
+// at that time (Soong processes the jars in dependency order, which may be different from the
+// the system server classpath order).
+func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath {
+	return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar")
+}
+
 func contains(l []string, s string) bool {
 	for _, e := range l {
 		if e == s {
diff --git a/java/androidmk.go b/java/androidmk.go
index d76e29b..ee2437a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -275,7 +275,7 @@
 }
 
 func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
-	if !app.IsForPlatform() {
+	if !app.IsForPlatform() || app.appProperties.HideFromMake {
 		return []android.AndroidMkEntries{android.AndroidMkEntries{
 			Disabled: true,
 		}}
@@ -288,6 +288,7 @@
 			func(entries *android.AndroidMkEntries) {
 				// App module names can be overridden.
 				entries.SetString("LOCAL_MODULE", app.installApkName)
+				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall)
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
 				if app.dexJarFile != nil {
 					entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile)
@@ -347,6 +348,9 @@
 				for _, jniLib := range app.installJniLibs {
 					entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name)
 				}
+				if len(app.jniCoverageOutputs) > 0 {
+					entries.AddStrings("LOCAL_PREBUILT_COVERAGE_ARCHIVE", app.jniCoverageOutputs.Strings()...)
+				}
 				if len(app.dexpreopter.builtInstalled) > 0 {
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled)
 				}
@@ -542,6 +546,7 @@
 func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries {
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
+		DistFile:   android.OptionalPathForPath(dstubs.apiFile),
 		OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar),
 		Include:    "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
diff --git a/java/app.go b/java/app.go
index fc3ce97..3f6c1d9 100755
--- a/java/app.go
+++ b/java/app.go
@@ -105,6 +105,11 @@
 	// If set, find and merge all NOTICE files that this module and its dependencies have and store
 	// it in the APK as an asset.
 	Embed_notices *bool
+
+	// cc.Coverage related properties
+	PreventInstall    bool `blueprint:"mutated"`
+	HideFromMake      bool `blueprint:"mutated"`
+	IsCoverageVariant bool `blueprint:"mutated"`
 }
 
 // android_app properties that can be overridden by override_android_app
@@ -133,7 +138,8 @@
 
 	overridableAppProperties overridableAppProperties
 
-	installJniLibs []jniLib
+	installJniLibs     []jniLib
+	jniCoverageOutputs android.Paths
 
 	bundleFile android.Path
 
@@ -171,6 +177,10 @@
 	return a.certificate
 }
 
+func (a *AndroidApp) JniCoverageOutputs() android.Paths {
+	return a.jniCoverageOutputs
+}
+
 var _ AndroidLibraryDependency = (*AndroidApp)(nil)
 
 type Certificate struct {
@@ -373,6 +383,11 @@
 		if a.shouldEmbedJnis(ctx) {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
 			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
+			for _, jni := range jniLibs {
+				if jni.coverageFile.Valid() {
+					a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+				}
+			}
 		} else {
 			a.installJniLibs = jniLibs
 		}
@@ -575,9 +590,10 @@
 
 				if lib.Valid() {
 					jniLibs = append(jniLibs, jniLib{
-						name:   ctx.OtherModuleName(module),
-						path:   path,
-						target: module.Target(),
+						name:         ctx.OtherModuleName(module),
+						path:         path,
+						target:       module.Target(),
+						coverageFile: dep.CoverageOutputFile(),
 					})
 				} else {
 					ctx.ModuleErrorf("dependency %q missing output file", otherName)
@@ -631,6 +647,24 @@
 	return Bool(a.appProperties.Privileged)
 }
 
+func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+	return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+}
+
+func (a *AndroidApp) PreventInstall() {
+	a.appProperties.PreventInstall = true
+}
+
+func (a *AndroidApp) HideFromMake() {
+	a.appProperties.HideFromMake = true
+}
+
+func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) {
+	a.appProperties.IsCoverageVariant = coverage
+}
+
+var _ cc.Coverage = (*AndroidApp)(nil)
+
 // android_app compiles sources and Android resources into an Android application package `.apk` file.
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 40cfe4f..bf64ae8 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -155,6 +155,8 @@
 		images = append(images, variant.images)
 		imagesDeps = append(imagesDeps, variant.imagesDeps)
 	}
+	// The locations for all Android targets are identical. Pick the first one.
+	imageLocations := bootImage.getVariant(targets[0]).imageLocations()
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
 
@@ -198,7 +200,7 @@
 		Archs:                   archs,
 		DexPreoptImages:         images,
 		DexPreoptImagesDeps:     imagesDeps,
-		DexPreoptImageLocations: bootImage.imageLocations,
+		DexPreoptImageLocations: imageLocations,
 
 		PreoptBootClassPathDexFiles:     dexFiles,
 		PreoptBootClassPathDexLocations: dexLocations,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index a3b264e..ae3cd06 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -28,28 +28,10 @@
 	android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
 }
 
-// The image "location" is a symbolic path that with multiarchitecture
-// support doesn't really exist on the device. Typically it is
-// /system/framework/boot.art and should be the same for all supported
-// architectures on the device. The concrete architecture specific
-// content actually ends up in a "filename" that contains an
-// architecture specific directory name such as arm, arm64, x86, x86_64.
-//
-// Here are some example values for an x86_64 / x86 configuration:
-//
-// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
-// will then reconstruct the real path, so the rules must have a dependency on the real path.
-
 // Target-independent description of pre-compiled boot image.
 type bootImageConfig struct {
-	// Whether this image is an extension.
-	extension bool
+	// If this image is an extension, the image that it extends.
+	extends *bootImageConfig
 
 	// Image name (used in directory names and ninja rule names).
 	name string
@@ -77,9 +59,6 @@
 	dexPaths     android.WritablePaths // for this image
 	dexPathsDeps android.WritablePaths // for the dependency images and in this image
 
-	// The "locations" of the dependency images and in this image.
-	imageLocations []string
-
 	// File path to a zip archive with all image files (or nil, if not needed).
 	zip android.WritablePath
 
@@ -125,7 +104,7 @@
 	// exists), and the rest are converted to 'name'-<jar>.art.
 	m := image.modules[idx]
 	name := image.stem
-	if idx != 0 || image.extension {
+	if idx != 0 || image.extends != nil {
 		name += "-" + stemOf(m)
 	}
 	return name
@@ -150,6 +129,24 @@
 	return ret
 }
 
+// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
+// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the
+// same for all supported architectures on the device. The concrete architecture specific files
+// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64.
+//
+// For example a physical file
+// "/apex/com.android.art/javalib/x86/boot.art" has "image location"
+// "/apex/com.android.art/javalib/boot.art" (which is not an actual file).
+//
+// The location is passed as an argument to the ART tools like dex2oat instead of the real path.
+// ART tools will then reconstruct the architecture-specific real path.
+func (image *bootImageVariant) imageLocations() (imageLocations []string) {
+	if image.extends != nil {
+		imageLocations = image.extends.getVariant(image.target).imageLocations()
+	}
+	return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType))
+}
+
 func concat(lists ...[]string) []string {
 	var size int
 	for _, l := range lists {
@@ -351,7 +348,7 @@
 		cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path())
 	}
 
-	if image.extension {
+	if image.extends != nil {
 		artImage := image.primaryImages
 		cmd.
 			Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
@@ -559,7 +556,7 @@
 			BuiltTool(ctx, "oatdumpd").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
-			FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()).
+			FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
 		rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
@@ -573,10 +570,7 @@
 			Text("echo").FlagWithArg("Output in ", output.String())
 		rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
 
-		// TODO: We need to make imageLocations per-variant to make oatdump work on host.
-		if image.target.Os == android.Android {
-			allPhonies = append(allPhonies, phony)
-		}
+		allPhonies = append(allPhonies, phony)
 	}
 
 	phony := android.PathForPhony(ctx, "dump-oat-boot")
@@ -617,20 +611,24 @@
 		var imageNames []string
 		for _, current := range append(d.otherImages, image) {
 			imageNames = append(imageNames, current.name)
-			for _, current := range current.variants {
+			imageLocations := []string{}
+			for _, variant := range current.variants {
 				suffix := ""
-				if current.target.Os.Class == android.Host {
+				if variant.target.Os.Class == android.Host {
 					suffix = "_host"
 				}
-				sfx := current.name + suffix + "_" + current.target.Arch.ArchType.String()
-				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls.String())
-				ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images.String())
-				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps.Strings(), " "))
-				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs.String())
-				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls.String())
+				sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String()
+				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String())
+				ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String())
+				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " "))
+				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
+				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
+				if variant.target.Os == android.Android {
+					// The locations for all Android targets are identical. Pick one.
+					imageLocations = variant.imageLocations()
+				}
 			}
-
-			ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":"))
+			ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":"))
 			ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
 		}
 		ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index d77d3e1..01a26ba 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -30,9 +30,9 @@
 	return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
 		global := dexpreopt.GetGlobalConfig(ctx)
 		var systemServerClasspathLocations []string
-		var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config())
-		// 1) The jars that are dexpreopted.
-		for _, m := range dexpreoptJars {
+		nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global)
+		// 1) Non-updatable jars.
+		for _, m := range nonUpdatable {
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				filepath.Join("/system/framework", m+".jar"))
 		}
@@ -41,13 +41,6 @@
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				dexpreopt.GetJarLocationFromApexJarPair(m))
 		}
-		// 3) The jars from make (which are not updatable, not preopted).
-		for _, m := range dexpreopt.NonUpdatableSystemServerJars(ctx, global) {
-			if !android.InList(m, dexpreoptJars) {
-				systemServerClasspathLocations = append(systemServerClasspathLocations,
-					filepath.Join("/system/framework", m+".jar"))
-			}
-		}
 		if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
 			panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
 				len(systemServerClasspathLocations),
@@ -122,7 +115,6 @@
 		// ART config for the primary boot image in the ART apex.
 		// It includes the Core Libraries.
 		artCfg := bootImageConfig{
-			extension:        false,
 			name:             artBootImageName,
 			stem:             "boot",
 			installSubdir:    artSubdir,
@@ -134,7 +126,7 @@
 		// Framework config for the boot image extension.
 		// It includes framework libraries and depends on the ART config.
 		frameworkCfg := bootImageConfig{
-			extension:        true,
+			extends:          &artCfg,
 			name:             frameworkBootImageName,
 			stem:             "boot",
 			installSubdir:    frameworkSubdir,
@@ -156,8 +148,6 @@
 			// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
 			imageName := c.firstModuleNameOrStem() + ".art"
 
-			c.imageLocations = []string{c.dir.Join(ctx, "android", c.installSubdir, imageName).String()}
-
 			// The path to bootclasspath dex files needs to be known at module
 			// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
 			// Set up known paths for them, the singleton rules will copy them there.
@@ -189,7 +179,6 @@
 		for i := range targets {
 			frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images
 		}
-		frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
 
 		return configs
 	}).(map[string]*bootImageConfig)
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 1ac7444..b0efaa5 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -2041,18 +2041,33 @@
 	return ok
 }
 
-func (mt *droidStubsSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	variants := member.Variants()
-	if len(variants) != 1 {
-		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources")
+}
+
+func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &droidStubsInfoProperties{}
+}
+
+type droidStubsInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	StubsSrcJar android.Path
+}
+
+func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	droidstubs := variant.(*Droidstubs)
+	p.StubsSrcJar = droidstubs.stubsSrcJar
+}
+
+func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if p.StubsSrcJar != nil {
+		builder := ctx.SnapshotBuilder()
+
+		snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources")
+
+		builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir)
+
+		propertySet.AddProperty("srcs", []string{snapshotRelativeDir})
 	}
-	variant := variants[0]
-	d, _ := variant.(*Droidstubs)
-	stubsSrcJar := d.stubsSrcJar
-
-	snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
-	builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
-
-	pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
-	pbm.AddProperty("srcs", []string{snapshotRelativeDir})
 }
diff --git a/java/java.go b/java/java.go
index 8c779f5..7645d85 100644
--- a/java/java.go
+++ b/java/java.go
@@ -23,14 +23,12 @@
 	"path/filepath"
 	"strconv"
 	"strings"
-	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/dexpreopt"
 	"android/soong/java/config"
 	"android/soong/tradefed"
 )
@@ -60,8 +58,6 @@
 			PropertyName: "java_tests",
 		},
 	})
-
-	android.PostDepsMutators(RegisterPostDepsMutators)
 }
 
 func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
@@ -90,44 +86,6 @@
 	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
-func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.BottomUp("ordered_system_server_jars", systemServerJarsDepsMutator)
-}
-
-var (
-	dexpreoptedSystemServerJarsKey  = android.NewOnceKey("dexpreoptedSystemServerJars")
-	dexpreoptedSystemServerJarsLock sync.Mutex
-)
-
-func DexpreoptedSystemServerJars(config android.Config) *[]string {
-	return config.Once(dexpreoptedSystemServerJarsKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-// A PostDepsMutator pass that enforces total order on non-updatable system server jars. A total
-// order is neededed because such jars must be dexpreopted together (each jar on the list must have
-// all preceding jars in its class loader context). The total order must be compatible with the
-// partial order imposed by genuine dependencies between system server jars (which is not always
-// respected by the PRODUCT_SYSTEM_SERVER_JARS variable).
-//
-// An earlier mutator pass creates genuine dependencies, and this pass traverses the jars in that
-// order (which is partial and non-deterministic). This pass adds additional dependencies between
-// jars, making the order total and deterministic. It also constructs a global ordered list.
-func systemServerJarsDepsMutator(ctx android.BottomUpMutatorContext) {
-	jars := dexpreopt.NonUpdatableSystemServerJars(ctx, dexpreopt.GetGlobalConfig(ctx))
-	name := ctx.ModuleName()
-	if android.InList(name, jars) {
-		dexpreoptedSystemServerJarsLock.Lock()
-		defer dexpreoptedSystemServerJarsLock.Unlock()
-		jars := DexpreoptedSystemServerJars(ctx.Config())
-		for _, dep := range *jars {
-			ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerDepTag, dep)
-		}
-		*jars = append(*jars, name)
-	}
-}
-
 func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
 	if j.SocSpecific() || j.DeviceSpecific() ||
 		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
@@ -582,9 +540,10 @@
 }
 
 type jniLib struct {
-	name   string
-	path   android.Path
-	target android.Target
+	name         string
+	path         android.Path
+	target       android.Target
+	coverageFile android.OptionalPath
 }
 
 func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
@@ -711,11 +670,6 @@
 	} else if j.shouldInstrumentStatic(ctx) {
 		ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
 	}
-
-	// services depend on com.android.location.provider, but dependency in not registered in a Blueprint file
-	if ctx.ModuleName() == "services" {
-		ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerForcedDepTag, "com.android.location.provider")
-	}
 }
 
 func hasSrcExt(srcs []string, ext string) bool {
@@ -847,7 +801,7 @@
 		return javaModule, true
 	case ver.kind == sdkModule:
 		return javaModule, false
-	case name == "services-stubs":
+	case name == "android_system_server_stubs_current":
 		return javaSystemServer, true
 	case ver.kind == sdkSystemServer:
 		return javaSystemServer, false
@@ -1909,37 +1863,43 @@
 	return ok
 }
 
-func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	return builder.AddPrebuiltModule(member, "java_import")
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import")
 }
 
 func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
-	return &librarySdkMemberProperties{memberType: mt}
+	return &librarySdkMemberProperties{}
 }
 
 type librarySdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
-	memberType *librarySdkMemberType
-
-	library     *Library
-	jarToExport android.Path
+	JarToExport     android.Path
+	AidlIncludeDirs android.Paths
 }
 
-func (p *librarySdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	j := variant.(*Library)
 
-	p.library = j
-	p.jarToExport = p.memberType.jarToExportGetter(j)
+	p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(j)
+	p.AidlIncludeDirs = j.AidlIncludeDirs()
 }
 
-func (p *librarySdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
-	if p.jarToExport != nil {
-		exportedJar := p.jarToExport
-		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.library.Name())
+func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	builder := ctx.SnapshotBuilder()
+
+	exportedJar := p.JarToExport
+	if exportedJar != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
 		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
 
-		for _, dir := range p.library.AidlIncludeDirs() {
+		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	}
+
+	aidlIncludeDirs := p.AidlIncludeDirs
+	if len(aidlIncludeDirs) != 0 {
+		sdkModuleContext := ctx.SdkModuleContext()
+		for _, dir := range aidlIncludeDirs {
 			// TODO(jiyong): copy parcelable declarations only
 			aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
 			for _, file := range aidlFiles {
@@ -1947,7 +1907,7 @@
 			}
 		}
 
-		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+		// TODO(b/151933053) - add aidl include dirs property
 	}
 }
 
@@ -2113,8 +2073,8 @@
 	return ok
 }
 
-func (mt *testSdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	return builder.AddPrebuiltModule(member, "java_test_import")
+func (mt *testSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_test_import")
 }
 
 func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -2124,11 +2084,11 @@
 type testSdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
-	test        *Test
-	jarToExport android.Path
+	JarToExport android.Path
+	TestConfig  android.Path
 }
 
-func (p *testSdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	test := variant.(*Test)
 
 	implementationJars := test.ImplementationJars()
@@ -2136,19 +2096,25 @@
 		panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
 	}
 
-	p.test = test
-	p.jarToExport = implementationJars[0]
+	p.JarToExport = implementationJars[0]
+	p.TestConfig = test.testConfig
 }
 
-func (p *testSdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
-	if p.jarToExport != nil {
-		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.test.Name())
-		builder.CopyToSnapshot(p.jarToExport, snapshotRelativeJavaLibPath)
+func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	builder := ctx.SnapshotBuilder()
 
-		snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), p.test.Name(), testConfigSuffix)
-		builder.CopyToSnapshot(p.test.testConfig, snapshotRelativeTestConfigPath)
+	exportedJar := p.JarToExport
+	if exportedJar != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
 
 		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	}
+
+	testConfig := p.TestConfig
+	if testConfig != nil {
+		snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), ctx.Name(), testConfigSuffix)
+		builder.CopyToSnapshot(testConfig, snapshotRelativeTestConfigPath)
 		propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
 	}
 }
@@ -2373,6 +2339,12 @@
 
 	// set the name of the output
 	Stem *string
+
+	Aidl struct {
+		// directories that should be added as include directories for any aidl sources of modules
+		// that depend on this module, as well as to aidl for this module.
+		Export_include_dirs []string
+	}
 }
 
 type Import struct {
@@ -2386,6 +2358,7 @@
 
 	combinedClasspathFile android.Path
 	exportedSdkLibs       []string
+	exportAidlIncludeDirs android.Paths
 }
 
 func (j *Import) sdkVersion() sdkSpec {
@@ -2459,6 +2432,8 @@
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			jarName, outputFile)
 	}
+
+	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
 }
 
 var _ Dependency = (*Import)(nil)
@@ -2493,7 +2468,7 @@
 }
 
 func (j *Import) AidlIncludeDirs() android.Paths {
-	return nil
+	return j.exportAidlIncludeDirs
 }
 
 func (j *Import) ExportedSdkLibs() []string {
diff --git a/java/java_test.go b/java/java_test.go
index 6d972be..e8a1a7c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1491,3 +1491,27 @@
 		t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
 	}
 }
+
+func TestAidlExportIncludeDirsFromImports(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["aidl/foo/IFoo.aidl"],
+			libs: ["bar"],
+		}
+
+		java_import {
+			name: "bar",
+			jars: ["a.jar"],
+			aidl: {
+				export_include_dirs: ["aidl/bar"],
+			},
+		}
+	`)
+
+	aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+	expectedAidlFlag := "-Iaidl/bar"
+	if !strings.Contains(aidlCommand, expectedAidlFlag) {
+		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+	}
+}
diff --git a/java/sdk.go b/java/sdk.go
index ded2a06..0e132d3 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -406,7 +406,7 @@
 		return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
 	case sdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule([]string{"android_module_lib_stubs_current", "services-stubs"}, "framework-res", sdkFrameworkAidlPath(ctx))
+		return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw))
 	}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index ea6733d..088db9e 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -222,9 +222,9 @@
 		{
 			name:           "system_server_current",
 			properties:     `sdk_version: "system_server_current",`,
-			bootclasspath:  []string{"android_module_lib_stubs_current", "services-stubs", "core-lambda-stubs"},
+			bootclasspath:  []string{"android_system_server_stubs_current", "core-lambda-stubs"},
 			system:         "core-current-stubs-system-modules",
-			java9classpath: []string{"android_module_lib_stubs_current", "services-stubs"},
+			java9classpath: []string{"android_system_server_stubs_current"},
 			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 	}
diff --git a/java/system_modules.go b/java/system_modules.go
index 40031cb..7394fd5 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -242,18 +242,28 @@
 	return false
 }
 
-func (mt *systemModulesSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	variants := member.Variants()
-	if len(variants) != 1 {
-		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
-		for _, variant := range variants {
-			sdkModuleContext.ModuleErrorf("    %q", variant)
-		}
-	}
-	variant := variants[0]
-	systemModule := variant.(*SystemModules)
+func (mt *systemModulesSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_system_modules_import")
+}
 
-	pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
-	// Add the references to the libraries that form the system module.
-	pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag(true))
+type systemModulesInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	Libs []string
+}
+
+func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &systemModulesInfoProperties{}
+}
+
+func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	systemModule := variant.(*SystemModules)
+	p.Libs = systemModule.properties.Libs
+}
+
+func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if len(p.Libs) > 0 {
+		// Add the references to the libraries that form the system module.
+		propertySet.AddPropertyWithTag("libs", p.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
+	}
 }
diff --git a/java/testing.go b/java/testing.go
index 5b6a39b..6929bb7 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -50,6 +50,8 @@
 		"api/test-current.txt":   nil,
 		"api/test-removed.txt":   nil,
 		"framework/aidl/a.aidl":  nil,
+		"aidl/foo/IFoo.aidl":     nil,
+		"aidl/bar/IBar.aidl":     nil,
 		"assets_a/a":             nil,
 		"assets_b/b":             nil,
 
@@ -148,7 +150,7 @@
 		"android_system_stubs_current",
 		"android_test_stubs_current",
 		"android_module_lib_stubs_current",
-		"services-stubs",
+		"android_system_server_stubs_current",
 		"core.current.stubs",
 		"core.platform.api.stubs",
 		"kotlin-stdlib",
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
index 23121c6..c6f8b76 100755
--- a/scripts/transitive-deps.sh
+++ b/scripts/transitive-deps.sh
@@ -469,7 +469,9 @@
     fi
     readonly hashedNotice="${tmpFiles}/hashednotices"
     ( # md5sum outputs checksum space indicator(space or *) filename newline
+        set +e
         sort -u "${allNotice}" | tr '\n' '\0' | xargs -0 -r md5sum 2>/dev/null
+        set -e
       # use sed to replace space and indicator with separator
     ) > "${hashedNotice}"
     if ${showProgress}; then
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 27a9518..eb64bcc 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -48,7 +48,6 @@
 		cc_library_shared {
 			name: "sdkmember",
 			srcs: ["Test.cpp"],
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -178,13 +177,11 @@
 
 		cc_library_host_shared {
 			name: "sdkshared",
-			system_shared_libs: [],
 			stl: "none",
 		}
 
 		cc_library_host_static {
 			name: "sdkstatic",
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -201,25 +198,21 @@
 
 		cc_library_shared {
 			name: "sdkshared",
-			system_shared_libs: [],
 			stl: "none",
 		}
 
 		cc_library_static {
 			name: "sdkstatic",
-			system_shared_libs: [],
 			stl: "none",
 		}
 
 		cc_library {
 			name: "sdkboth1",
-			system_shared_libs: [],
 			stl: "none",
 		}
 
 		cc_library {
 			name: "sdkboth2",
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -295,7 +288,6 @@
 				"Test.cpp",
 			],
 			export_include_dirs: ["include"],
-			system_shared_libs: [],
 			stl: "none",
 		}
 
@@ -305,7 +297,6 @@
 				"Test.cpp",
 			],
 			export_include_dirs: ["include"],
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -342,7 +333,6 @@
 					export_system_include_dirs: ["arm64/include"],
 				},
 			},
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -410,7 +400,6 @@
 				"Test.cpp",
 			],
 			compile_multilib: "both",
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -485,7 +474,6 @@
 				"Test.cpp",
 			],
 			compile_multilib: "both",
-			system_shared_libs: [],
 			stl: "none",
 			target: {
 				windows: {
@@ -553,6 +541,11 @@
     device_supported: false,
     host_supported: true,
     native_binaries: ["myexports_mynativebinary@current"],
+    target: {
+        windows: {
+            compile_multilib: "64",
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -581,7 +574,6 @@
 			aidl: {
 				export_aidl_headers: true,
 			},
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -668,7 +660,6 @@
 			srcs: [
 				"Test.cpp",
 			],
-			system_shared_libs: [],
 			stl: "none",
 		}
 
@@ -709,7 +700,6 @@
 					},
 				},
 			},
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -859,7 +849,6 @@
 			aidl: {
 				export_aidl_headers: true,
 			},
-			system_shared_libs: [],
 			stl: "none",
 			sdk_version: "minimum",
 		}
@@ -955,7 +944,6 @@
 			srcs: [
 				"Test.cpp",
 			],
-			system_shared_libs: [],
 			stl: "none",
 			target: {
 				windows: {
@@ -1013,6 +1001,11 @@
     device_supported: false,
     host_supported: true,
     native_shared_libs: ["mysdk_mynativelib@current"],
+    target: {
+        windows: {
+            compile_multilib: "64",
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1040,7 +1033,6 @@
 			aidl: {
 				export_aidl_headers: true,
 			},
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -1127,7 +1119,6 @@
 			aidl: {
 				export_aidl_headers: true,
 			},
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -1209,7 +1200,6 @@
 				"Test.cpp",
 			],
 			export_include_dirs: ["include"],
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -1312,7 +1302,6 @@
 			aidl: {
 				export_aidl_headers: true,
 			},
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -1358,7 +1347,7 @@
     host_supported: true,
     native_static_libs: ["myexports_mynativelib@current"],
     target: {
-        host: {
+        linux_glibc: {
             compile_multilib: "64",
         },
     },
@@ -1383,7 +1372,6 @@
 		cc_library_headers {
 			name: "mynativeheaders",
 			export_include_dirs: ["include"],
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -1434,7 +1422,6 @@
 			device_supported: false,
 			host_supported: true,
 			export_include_dirs: ["include"],
-			system_shared_libs: [],
 			stl: "none",
 		}
 	`)
@@ -1488,7 +1475,6 @@
 		cc_library_headers {
 			name: "mynativeheaders",
 			host_supported: true,
-			system_shared_libs: [],
 			stl: "none",
 			export_system_include_dirs: ["include"],
 			target: {
@@ -1551,3 +1537,205 @@
 `),
 	)
 }
+
+func TestSystemSharedLibPropagation(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: ["sslnil", "sslempty", "sslnonempty"],
+		}
+
+		cc_library {
+			name: "sslnil",
+			host_supported: true,
+		}
+
+		cc_library {
+			name: "sslempty",
+			system_shared_libs: [],
+		}
+
+		cc_library {
+			name: "sslnonempty",
+			system_shared_libs: ["sslnil"],
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_sslnil@current",
+    sdk_member_name: "sslnil",
+    installable: false,
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/sslnil.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/sslnil.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "sslnil",
+    prefer: false,
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/sslnil.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/sslnil.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mysdk_sslempty@current",
+    sdk_member_name: "sslempty",
+    installable: false,
+    system_shared_libs: [],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/sslempty.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/sslempty.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "sslempty",
+    prefer: false,
+    system_shared_libs: [],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/sslempty.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/sslempty.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mysdk_sslnonempty@current",
+    sdk_member_name: "sslnonempty",
+    installable: false,
+    system_shared_libs: ["mysdk_sslnil@current"],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/sslnonempty.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/sslnonempty.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "sslnonempty",
+    prefer: false,
+    system_shared_libs: ["sslnil"],
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/sslnonempty.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/sslnonempty.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_shared_libs: [
+        "mysdk_sslnil@current",
+        "mysdk_sslempty@current",
+        "mysdk_sslnonempty@current",
+    ],
+}
+`))
+
+	result = testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			host_supported: true,
+			native_shared_libs: ["sslvariants"],
+		}
+
+		cc_library {
+			name: "sslvariants",
+			host_supported: true,
+			target: {
+				android: {
+					system_shared_libs: [],
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_sslvariants@current",
+    sdk_member_name: "sslvariants",
+    host_supported: true,
+    installable: false,
+    target: {
+        android: {
+            system_shared_libs: [],
+        },
+        android_arm64: {
+            srcs: ["android/arm64/lib/sslvariants.so"],
+        },
+        android_arm: {
+            srcs: ["android/arm/lib/sslvariants.so"],
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/sslvariants.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "sslvariants",
+    prefer: false,
+    host_supported: true,
+    target: {
+        android: {
+            system_shared_libs: [],
+        },
+        android_arm64: {
+            srcs: ["android/arm64/lib/sslvariants.so"],
+        },
+        android_arm: {
+            srcs: ["android/arm/lib/sslvariants.so"],
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/sslvariants.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    native_shared_libs: ["mysdk_sslvariants@current"],
+}
+`))
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 984ed7a..dabdf85 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -52,11 +52,16 @@
 
 	// Information about the OsType specific member variants associated with this variant.
 	//
-	// Set by OsType specific variants when their GenerateAndroidBuildActions is invoked
-	// and used by the CommonOS variant when its GenerateAndroidBuildActions is invoked, which
-	// is guaranteed to occur afterwards.
+	// Set by OsType specific variants in the collectMembers() method and used by the
+	// CommonOS variant when building the snapshot. That work is all done on separate
+	// calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be
+	// called for the OsType specific variants before the CommonOS variant (because
+	// the latter depends on the former).
 	memberRefs []sdkMemberRef
 
+	// The multilib variants that are used by this sdk variant.
+	multilibUsages multilibUsage
+
 	properties sdkProperties
 
 	snapshotFile android.OptionalPath
@@ -259,8 +264,8 @@
 	// This method is guaranteed to be called on OsType specific variants before it is called
 	// on their corresponding CommonOS variant.
 	if !s.IsCommonOSVariant() {
-		// Collect the OsType specific members are add them to the OsType specific variant.
-		s.memberRefs = s.collectMembers(ctx)
+		// Update the OsType specific sdk variant with information about its members.
+		s.collectMembers(ctx)
 	} else {
 		// Get the OsType specific variants on which the CommonOS depends.
 		osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx)
diff --git a/sdk/update.go b/sdk/update.go
index c706d1c..e14347f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -107,9 +107,10 @@
 
 // Collect all the members.
 //
-// Returns a list containing type (extracted from the dependency tag) and the variant.
-func (s *sdk) collectMembers(ctx android.ModuleContext) []sdkMemberRef {
-	var memberRefs []sdkMemberRef
+// Returns a list containing type (extracted from the dependency tag) and the variant
+// plus the multilib usages.
+func (s *sdk) collectMembers(ctx android.ModuleContext) {
+	s.multilibUsages = multilibNone
 	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
@@ -120,7 +121,10 @@
 				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
 			}
 
-			memberRefs = append(memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
+			// Keep track of which multilib variants are used by the sdk.
+			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
+
+			s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
 
 			// If the member type supports transitive sdk members then recurse down into
 			// its dependencies, otherwise exit traversal.
@@ -129,8 +133,6 @@
 
 		return false
 	})
-
-	return memberRefs
 }
 
 // Organize the members.
@@ -140,12 +142,10 @@
 // The names are in the order in which the dependencies were added.
 //
 // Returns the members as well as the multilib setting to use.
-func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) ([]*sdkMember, string) {
+func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember {
 	byType := make(map[android.SdkMemberType][]*sdkMember)
 	byName := make(map[string]*sdkMember)
 
-	multilib := multilibNone
-
 	for _, memberRef := range memberRefs {
 		memberType := memberRef.memberType
 		variant := memberRef.variant
@@ -158,8 +158,6 @@
 			byType[memberType] = append(byType[memberType], member)
 		}
 
-		multilib = multilib.addArchType(variant.Target().Arch.ArchType)
-
 		// Only append new variants to the list. This is needed because a member can be both
 		// exported by the sdk and also be a transitive sdk member.
 		member.variants = appendUniqueVariants(member.variants, variant)
@@ -171,7 +169,7 @@
 		members = append(members, membersOfType...)
 	}
 
-	return members, multilib.String()
+	return members
 }
 
 func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
@@ -251,16 +249,14 @@
 	}
 	s.builderForTests = builder
 
-	members, multilib := s.organizeMembers(ctx, memberRefs)
+	members := s.organizeMembers(ctx, memberRefs)
 	for _, member := range members {
 		memberType := member.memberType
-		prebuiltModule := memberType.AddPrebuiltModule(ctx, builder, member)
-		if prebuiltModule == nil {
-			// Fall back to legacy method of building a snapshot
-			memberType.BuildSnapshot(ctx, builder, member)
-		} else {
-			s.createMemberSnapshot(ctx, builder, member, prebuiltModule)
-		}
+
+		memberCtx := &memberContext{ctx, builder, memberType, member.name}
+
+		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
+		s.createMemberSnapshot(memberCtx, member, prebuiltModule)
 	}
 
 	// Create a transformer that will transform an unversioned module into a versioned module.
@@ -305,15 +301,6 @@
 
 	addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
 
-	// Compile_multilib defaults to both and must always be set to both on the
-	// device and so only needs to be set when targeted at the host and is neither
-	// unspecified or both.
-	targetPropertySet := snapshotModule.AddPropertySet("target")
-	if s.HostSupported() && multilib != "" && multilib != "both" {
-		hostSet := targetPropertySet.AddPropertySet("host")
-		hostSet.AddProperty("compile_multilib", multilib)
-	}
-
 	var dynamicMemberPropertiesList []interface{}
 	osTypeToMemberProperties := make(map[android.OsType]*sdk)
 	for _, sdkVariant := range sdkVariants {
@@ -331,9 +318,20 @@
 	s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
 
 	// Iterate over the os types in a fixed order.
+	targetPropertySet := snapshotModule.AddPropertySet("target")
 	for _, osType := range s.getPossibleOsTypes() {
 		if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
 			osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
+
+			// Compile_multilib defaults to both and must always be set to both on the
+			// device and so only needs to be set when targeted at the host and is neither
+			// unspecified or both.
+			multilib := sdkVariant.multilibUsages
+			if (osType.Class == android.Host || osType.Class == android.HostCross) &&
+				multilib != multilibNone && multilib != multilibBoth {
+				osPropertySet.AddProperty("compile_multilib", multilib.String())
+			}
+
 			s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
 		}
 	}
@@ -831,7 +829,7 @@
 
 // Create a new osTypeSpecificInfo for the specified os type and its properties
 // structures populated with information from the variants.
-func newOsTypeSpecificInfo(osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.SdkAware) *osTypeSpecificInfo {
+func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
 	osInfo := &osTypeSpecificInfo{
 		osType: osType,
 	}
@@ -847,7 +845,7 @@
 	osInfo.Properties = osSpecificVariantPropertiesFactory()
 
 	// Group the variants by arch type.
-	var variantsByArchName = make(map[string][]android.SdkAware)
+	var variantsByArchName = make(map[string][]android.Module)
 	var archTypes []android.ArchType
 	for _, variant := range osTypeVariants {
 		archType := variant.Target().Arch.ArchType
@@ -866,14 +864,14 @@
 
 		// A common arch type only has one variant and its properties should be treated
 		// as common to the os type.
-		osInfo.Properties.PopulateFromVariant(commonVariants[0])
+		osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
 	} else {
 		// Create an arch specific info for each supported architecture type.
 		for _, archType := range archTypes {
 			archTypeName := archType.Name
 
 			archVariants := variantsByArchName[archTypeName]
-			archInfo := newArchSpecificInfo(archType, osSpecificVariantPropertiesFactory, archVariants)
+			archInfo := newArchSpecificInfo(ctx, archType, osSpecificVariantPropertiesFactory, archVariants)
 
 			osInfo.archInfos = append(osInfo.archInfos, archInfo)
 		}
@@ -912,10 +910,7 @@
 // Maps the properties related to the os variants through to an appropriate
 // module structure that will produce equivalent set of variants when it is
 // processed in a build.
-func (osInfo *osTypeSpecificInfo) addToPropertySet(
-	builder *snapshotBuilder,
-	bpModule android.BpModule,
-	targetPropertySet android.BpPropertySet) {
+func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
 
 	var osPropertySet android.BpPropertySet
 	var archPropertySet android.BpPropertySet
@@ -965,7 +960,7 @@
 	}
 
 	// Add the os specific but arch independent properties to the module.
-	osInfo.Properties.AddToPropertySet(builder.ctx, builder, osPropertySet)
+	osInfo.Properties.AddToPropertySet(ctx, osPropertySet)
 
 	// Add arch (and possibly os) specific sections for each set of arch (and possibly
 	// os) specific properties.
@@ -973,7 +968,7 @@
 	// The archInfos list will be empty if the os contains variants for the common
 	// architecture.
 	for _, archInfo := range osInfo.archInfos {
-		archInfo.addToPropertySet(builder, archPropertySet, archOsPrefix)
+		archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
 	}
 }
 
@@ -987,7 +982,7 @@
 
 // Create a new archTypeSpecificInfo for the specified arch type and its properties
 // structures populated with information from the variants.
-func newArchSpecificInfo(archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.SdkAware) *archTypeSpecificInfo {
+func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
 
 	// Create an arch specific info into which the variant properties can be copied.
 	archInfo := &archTypeSpecificInfo{archType: archType}
@@ -997,7 +992,7 @@
 	archInfo.Properties = variantPropertiesFactory()
 
 	if len(archVariants) == 1 {
-		archInfo.Properties.PopulateFromVariant(archVariants[0])
+		archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
 	} else {
 		// There is more than one variant for this arch type which must be differentiated
 		// by link type.
@@ -1006,7 +1001,7 @@
 			if linkType == "" {
 				panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
 			} else {
-				linkInfo := newLinkSpecificInfo(linkType, variantPropertiesFactory, linkVariant)
+				linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
 
 				archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
 			}
@@ -1052,14 +1047,14 @@
 }
 
 // Add the properties for an arch type to a property set.
-func (archInfo *archTypeSpecificInfo) addToPropertySet(builder *snapshotBuilder, archPropertySet android.BpPropertySet, archOsPrefix string) {
+func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
 	archTypeName := archInfo.archType.Name
 	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
-	archInfo.Properties.AddToPropertySet(builder.ctx, builder, archTypePropertySet)
+	archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
 
 	for _, linkInfo := range archInfo.linkInfos {
 		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
-		linkInfo.Properties.AddToPropertySet(builder.ctx, builder, linkPropertySet)
+		linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet)
 	}
 }
 
@@ -1071,7 +1066,7 @@
 
 // Create a new linkTypeSpecificInfo for the specified link type and its properties
 // structures populated with information from the variant.
-func newLinkSpecificInfo(linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.SdkAware) *linkTypeSpecificInfo {
+func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
 	linkInfo := &linkTypeSpecificInfo{
 		baseInfo: baseInfo{
 			// Create the properties into which the link type specific properties will be
@@ -1080,16 +1075,39 @@
 		},
 		linkType: linkType,
 	}
-	linkInfo.Properties.PopulateFromVariant(linkVariant)
+	linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
 	return linkInfo
 }
 
-func (s *sdk) createMemberSnapshot(sdkModuleContext android.ModuleContext, builder *snapshotBuilder, member *sdkMember, bpModule android.BpModule) {
+type memberContext struct {
+	sdkMemberContext android.ModuleContext
+	builder          *snapshotBuilder
+	memberType       android.SdkMemberType
+	name             string
+}
+
+func (m *memberContext) SdkModuleContext() android.ModuleContext {
+	return m.sdkMemberContext
+}
+
+func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
+	return m.builder
+}
+
+func (m *memberContext) MemberType() android.SdkMemberType {
+	return m.memberType
+}
+
+func (m *memberContext) Name() string {
+	return m.name
+}
+
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
 
 	memberType := member.memberType
 
 	// Group the variants by os type.
-	variantsByOsType := make(map[android.OsType][]android.SdkAware)
+	variantsByOsType := make(map[android.OsType][]android.Module)
 	variants := member.Variants()
 	for _, variant := range variants {
 		osType := variant.Target().Os
@@ -1118,7 +1136,7 @@
 	var osSpecificPropertiesList []android.SdkMemberProperties
 
 	for osType, osTypeVariants := range variantsByOsType {
-		osInfo := newOsTypeSpecificInfo(osType, variantPropertiesFactory, osTypeVariants)
+		osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
 		osTypeToInfo[osType] = osInfo
 		// Add the os specific properties to a list of os type specific yet architecture
 		// independent properties structs.
@@ -1132,7 +1150,7 @@
 	commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesList)
 
 	// Add the common properties to the module.
-	commonProperties.AddToPropertySet(sdkModuleContext, builder, bpModule)
+	commonProperties.AddToPropertySet(ctx, bpModule)
 
 	// Create a target property set into which target specific properties can be
 	// added.
@@ -1145,7 +1163,7 @@
 			continue
 		}
 
-		osInfo.addToPropertySet(builder, bpModule, targetPropertySet)
+		osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
 	}
 }
 
@@ -1265,10 +1283,6 @@
 func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
 	commonPropertiesValue := reflect.ValueOf(commonProperties)
 	commonStructValue := commonPropertiesValue.Elem()
-	propertiesStructType := commonStructValue.Type()
-
-	// Create an empty structure from which default values for the field can be copied.
-	emptyStructValue := reflect.New(propertiesStructType).Elem()
 
 	for _, fieldGetter := range e.fieldGetters {
 		// Check to see if all the structures have the same value for the field. The commonValue
@@ -1297,7 +1311,7 @@
 		// If the fields all have a common value then store it in the common struct field
 		// and set the input struct's field to the empty value.
 		if commonValue != nil {
-			emptyValue := fieldGetter(emptyStructValue)
+			emptyValue := reflect.Zero(commonValue.Type())
 			fieldGetter(commonStructValue).Set(*commonValue)
 			for i := 0; i < sliceValue.Len(); i++ {
 				itemValue := sliceValue.Index(i)
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 65dbb22..30cbd6b 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"io"
 	"path"
+	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -154,8 +155,21 @@
 var (
 	pctx         = android.NewPackageContext("android/soong/sysprop")
 	syspropCcTag = dependencyTag{name: "syspropCc"}
+
+	syspropLibrariesKey  = android.NewOnceKey("syspropLibraries")
+	syspropLibrariesLock sync.Mutex
 )
 
+func syspropLibraries(config android.Config) *[]string {
+	return config.Once(syspropLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func SyspropLibraries(config android.Config) []string {
+	return append([]string{}, *syspropLibraries(config)...)
+}
+
 func init() {
 	android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
 }
@@ -195,6 +209,10 @@
 	return proptools.Bool(m.properties.Public_stub)
 }
 
+func (m *syspropLibrary) CurrentSyspropApiFile() android.Path {
+	return m.currentApiFile
+}
+
 func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	baseModuleName := m.BaseModuleName()
 
@@ -463,6 +481,12 @@
 			Stem:        proptools.StringPtr(m.BaseModuleName()),
 		})
 	}
+
+	syspropLibrariesLock.Lock()
+	defer syspropLibrariesLock.Unlock()
+
+	libraries := syspropLibraries(ctx.Config())
+	*libraries = append(*libraries, ctx.ModuleName())
 }
 
 func syspropDepsMutator(ctx android.BottomUpMutatorContext) {