Merge "Support missing a shared library variant."
diff --git a/android/config.go b/android/config.go
index da4f8e2..d0ac4c3 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1028,8 +1028,12 @@
 	return c.config.productVariables.DeviceKernelHeaders
 }
 
+func (c *config) NativeLineCoverage() bool {
+	return Bool(c.productVariables.NativeLineCoverage)
+}
+
 func (c *deviceConfig) NativeCoverageEnabled() bool {
-	return Bool(c.config.productVariables.Native_coverage)
+	return Bool(c.config.productVariables.Native_coverage) || Bool(c.config.productVariables.NativeLineCoverage)
 }
 
 func (c *deviceConfig) ClangCoverageEnabled() bool {
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 3e55958..f54e774 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -54,7 +54,7 @@
 // For example, an Android.bp file could have:
 //
 //     soong_config_module_type_import {
-//         from: "device/acme/Android.bp.bp",
+//         from: "device/acme/Android.bp",
 //         module_types: ["acme_cc_defaults"],
 //     }
 //
@@ -139,9 +139,9 @@
 }
 
 // soong_config_module_type defines module types with conditionals on Soong config
-// variables from another Android.bp file.  The new module type will exist for all
-// modules after the definition in an Android.bp file, and can be imported into other
-// Android.bp files using soong_config_module_type_import.
+// variables.  The new module type will exist for all modules after the definition
+// in an Android.bp file, and can be imported into other Android.bp files using
+// soong_config_module_type_import.
 //
 // For example, an Android.bp file could have:
 //
@@ -186,8 +186,6 @@
 //         srcs: ["*.cpp"],
 //     }
 //
-// And device/acme/Android.bp could have:
-//
 // If an acme BoardConfig.mk file contained:
 //
 //     SOONG_CONFIG_NAMESPACES += acme
diff --git a/android/util.go b/android/util.go
index 81f481d..e985fc1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -121,8 +121,19 @@
 	return IndexList(s, list) != -1
 }
 
-func PrefixInList(s string, list []string) bool {
-	for _, prefix := range list {
+// Returns true if the given string s is prefixed with any string in the given prefix list.
+func PrefixInList(s string, prefixList []string) bool {
+	for _, prefix := range prefixList {
+		if strings.HasPrefix(s, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
+// Returns true if any string in the given list has the given prefix.
+func PrefixedStringInList(list []string, prefix string) bool {
+	for _, s := range list {
 		if strings.HasPrefix(s, prefix) {
 			return true
 		}
diff --git a/android/variable.go b/android/variable.go
index c277acc..9625a87 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -252,6 +252,7 @@
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
+	NativeLineCoverage   *bool    `json:",omitempty"`
 	Native_coverage      *bool    `json:",omitempty"`
 	ClangCoverage        *bool    `json:",omitempty"`
 	CoveragePaths        []string `json:",omitempty"`
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 8929910..714045f 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -42,7 +42,11 @@
 		}}
 }
 
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
+	// apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property.
+	// An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName>
+	// In many cases, the two names are the same, but could be different in general.
+
 	moduleNames := []string{}
 	apexType := a.properties.ApexType
 	// To avoid creating duplicate build rules, run this function only when primaryApexType is true
@@ -52,12 +56,21 @@
 		return moduleNames
 	}
 
+	// b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
+	// APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
+	// as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
+	// for the overriding VNDK APEXes.
+	symbolFilesNotNeeded := a.vndkApex && len(a.overridableProperties.Overrides) > 0
+	if symbolFilesNotNeeded && apexType != flattenedApex {
+		return moduleNames
+	}
+
 	var postInstallCommands []string
 	for _, fi := range a.filesInfo {
 		if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() {
 			// TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
 			linkTarget := filepath.Join("/system", fi.Path())
-			linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexName, fi.Path())
+			linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.Path())
 			mkdirCmd := "mkdir -p " + filepath.Dir(linkPath)
 			linkCmd := "ln -sfn " + linkTarget + " " + linkPath
 			postInstallCommands = append(postInstallCommands, mkdirCmd, linkCmd)
@@ -75,7 +88,7 @@
 		if linkToSystemLib {
 			moduleName = fi.moduleName
 		} else {
-			moduleName = fi.moduleName + "." + apexName + a.suffix
+			moduleName = fi.moduleName + "." + apexBundleName + a.suffix
 		}
 
 		if !android.InList(moduleName, moduleNames) {
@@ -99,8 +112,8 @@
 		if apexType == flattenedApex {
 			// /system/apex/<name>/{lib|framework|...}
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(),
-				apexName, fi.installDir))
-			if a.primaryApexType {
+				apexBundleName, fi.installDir))
+			if a.primaryApexType && !symbolFilesNotNeeded {
 				fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
 			}
 			if len(fi.symlinks) > 0 {
@@ -236,7 +249,7 @@
 			apexType := a.properties.ApexType
 			if a.installable() {
 				apexName := proptools.StringDefault(a.properties.Apex_name, name)
-				moduleNames = a.androidMkForFiles(w, apexName, moduleDir)
+				moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir)
 			}
 
 			if apexType == flattenedApex {
diff --git a/apex/apex.go b/apex/apex.go
index 48cdedf..53bdc12 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1194,6 +1194,12 @@
 	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
 }
 
+func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
+	dirInApex := filepath.Join("etc", config.SubDir())
+	fileToCopy := config.CompatConfig()
+	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, config)
+}
+
 func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface {
 	android.Module
 	Privileged() bool
@@ -1361,8 +1367,10 @@
 			case prebuiltTag:
 				if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
 					filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+				} else if prebuilt, ok := child.(java.PlatformCompatConfigIntf); ok {
+					filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, prebuilt, depName))
 				} else {
-					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc and not a platform_compat_config module", depName)
 				}
 			case testTag:
 				if ccTest, ok := child.(*cc.Module); ok {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c7ecbc9..faf7ae5 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -299,6 +299,7 @@
 	ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
 	ctx.RegisterModuleType("prebuilt_etc", android.PrebuiltEtcFactory)
+	ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
 	ctx.RegisterModuleType("sh_binary", android.ShBinaryFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	java.RegisterJavaBuildComponents(ctx)
@@ -2209,11 +2210,12 @@
 }
 
 func TestApexName(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx, config := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
 			apex_name: "com.android.myapex",
+			native_shared_libs: ["mylib"],
 		}
 
 		apex_key {
@@ -2221,6 +2223,17 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
 	`)
 
 	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
@@ -2228,6 +2241,16 @@
 	ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
 	apexRule := module.Rule("apexRule")
 	ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname")
+
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+	name := apexBundle.BaseModuleName()
+	prefix := "TARGET_"
+	var builder strings.Builder
+	data.Custom(&builder, name, prefix, "", data)
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
 }
 
 func TestNonTestApex(t *testing.T) {
@@ -3451,6 +3474,41 @@
 	ensureContains(t, xml.Args["content"], `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
 }
 
+func TestCompatConfig(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			prebuilts: ["myjar-platform-compat-config"],
+			java_libs: ["myjar"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		platform_compat_config {
+		    name: "myjar-platform-compat-config",
+		    src: ":myjar",
+		}
+
+		java_library {
+			name: "myjar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			compile_dex: true,
+			apex_available: [ "myapex" ],
+		}
+	`)
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"etc/compatconfig/myjar-platform-compat-config.xml",
+		"javalib/myjar.jar",
+	})
+}
+
 func TestRejectNonInstallableJavaLibrary(t *testing.T) {
 	testApexError(t, `"myjar" is not configured to be compiled into dex`, `
 		apex {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index fd5a4da..165901d 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -241,39 +241,43 @@
 
 func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
 
-	// a function for emitting include dirs
-	addExportedDirsForNativeLibs := func(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
-		includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
-		if len(includeDirs) == 0 {
-			return
-		}
-		var propertyName string
-		if !systemInclude {
-			propertyName = "export_include_dirs"
-		} else {
-			propertyName = "export_system_include_dirs"
-		}
-		properties.AddProperty(propertyName, includeDirs)
-	}
-
 	pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
 
-	addExportedDirsForNativeLibs(info.commonProperties, pbm, false /*systemInclude*/)
-	addExportedDirsForNativeLibs(info.commonProperties, pbm, true /*systemInclude*/)
+	addPossiblyArchSpecificProperties(info.commonProperties, pbm)
 
 	archProperties := pbm.AddPropertySet("arch")
 	for _, av := range info.archVariantProperties {
 		archTypeProperties := archProperties.AddPropertySet(av.archType)
+		// Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
 		archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})
 
-		// export_* properties are added inside the arch: {<arch>: {...}} block
-		addExportedDirsForNativeLibs(av, archTypeProperties, false /*systemInclude*/)
-		addExportedDirsForNativeLibs(av, archTypeProperties, true /*systemInclude*/)
+		addPossiblyArchSpecificProperties(av, archTypeProperties)
 	}
 	pbm.AddProperty("stl", "none")
 	pbm.AddProperty("system_shared_libs", []string{})
 }
 
+// Add properties that may, or may not, be arch specific.
+func addPossiblyArchSpecificProperties(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+	addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
+	addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
+}
+
+// a function for emitting include dirs
+func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
+	includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
+	if len(includeDirs) == 0 {
+		return
+	}
+	var propertyName string
+	if !systemInclude {
+		propertyName = "export_include_dirs"
+	} else {
+		propertyName = "export_system_include_dirs"
+	}
+	properties.AddProperty(propertyName, includeDirs)
+}
+
 const (
 	nativeIncludeDir          = "include"
 	nativeGeneratedIncludeDir = "include_gen"
diff --git a/java/aapt2.go b/java/aapt2.go
index cfe0dea..04e4de5 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -147,10 +147,16 @@
 		RspfileContent: "$in",
 	})
 
+var mergeAssetsRule = pctx.AndroidStaticRule("mergeAssets",
+	blueprint.RuleParams{
+		Command:     `${config.MergeZipsCmd} ${out} ${in}`,
+		CommandDeps: []string{"${config.MergeZipsCmd}"},
+	})
+
 func aapt2Link(ctx android.ModuleContext,
 	packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath,
 	flags []string, deps android.Paths,
-	compiledRes, compiledOverlay android.Paths, splitPackages android.WritablePaths) {
+	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
 
 	genDir := android.PathForModuleGen(ctx, "aapt2", "R")
 
@@ -186,12 +192,25 @@
 	}
 
 	implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages)
+	linkOutput := packageRes
+
+	// AAPT2 ignores assets in overlays. Merge them after linking.
+	if len(assetPackages) > 0 {
+		linkOutput = android.PathForModuleOut(ctx, "aapt2", "package-res.apk")
+		inputZips := append(android.Paths{linkOutput}, assetPackages...)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        mergeAssetsRule,
+			Inputs:      inputZips,
+			Output:      packageRes,
+			Description: "merge assets from dependencies",
+		})
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            aapt2LinkRule,
 		Description:     "aapt2 link",
 		Implicits:       deps,
-		Output:          packageRes,
+		Output:          linkOutput,
 		ImplicitOutputs: implicitOutputs,
 		Args: map[string]string{
 			"flags":           strings.Join(flags, " "),
diff --git a/java/aar.go b/java/aar.go
index d707e36..24c5e7d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -32,6 +32,7 @@
 	ExportedRRODirs() []rroDir
 	ExportedStaticPackages() android.Paths
 	ExportedManifests() android.Paths
+	ExportedAssets() android.OptionalPath
 }
 
 func init() {
@@ -93,6 +94,7 @@
 	extraAaptPackagesFile   android.Path
 	mergedManifestFile      android.Path
 	noticeFile              android.OptionalPath
+	assetPackage            android.OptionalPath
 	isLibrary               bool
 	useEmbeddedNativeLibs   bool
 	useEmbeddedDex          bool
@@ -124,6 +126,10 @@
 	return a.transitiveManifestPaths
 }
 
+func (a *aapt) ExportedAssets() android.OptionalPath {
+	return a.assetPackage
+}
+
 func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
 	manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
 	resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
@@ -219,9 +225,15 @@
 	}
 }
 
+var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
+	blueprint.RuleParams{
+		Command:     `${config.Zip2ZipCmd} -i ${in} -o ${out} "assets/**/*"`,
+		CommandDeps: []string{"${config.Zip2ZipCmd}"},
+	})
+
 func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
 
-	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries :=
 		aaptLibs(ctx, sdkContext)
 
 	// App manifest file
@@ -321,7 +333,20 @@
 	}
 
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
-		linkFlags, linkDeps, compiledRes, compiledOverlay, splitPackages)
+		linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages)
+
+	// Extract assets from the resource package output so that they can be used later in aapt2link
+	// for modules that depend on this one.
+	if android.PrefixedStringInList(linkFlags, "-A ") || len(assetPackages) > 0 {
+		assets := android.PathForModuleOut(ctx, "assets.zip")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        extractAssetsRule,
+			Input:       packageRes,
+			Output:      assets,
+			Description: "extract assets from built resource file",
+		})
+		a.assetPackage = android.OptionalPathForPath(assets)
+	}
 
 	a.aaptSrcJar = srcJar
 	a.exportPackage = packageRes
@@ -335,7 +360,7 @@
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
 func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
-	staticRRODirs []rroDir, deps android.Paths, flags []string, sdkLibraries []string) {
+	staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) {
 
 	var sharedLibs android.Paths
 
@@ -373,6 +398,9 @@
 				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
 				transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
 				sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
+				if aarDep.ExportedAssets().Valid() {
+					assets = append(assets, aarDep.ExportedAssets().Path())
+				}
 
 			outer:
 				for _, d := range aarDep.ExportedRRODirs() {
@@ -402,7 +430,7 @@
 	transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
 	sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
 
-	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags, sdkLibraries
+	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries
 }
 
 type AndroidLibrary struct {
@@ -572,6 +600,11 @@
 	return android.Paths{a.manifest}
 }
 
+// TODO(jungjw): Decide whether we want to implement this.
+func (a *AARImport) ExportedAssets() android.OptionalPath {
+	return android.OptionalPath{}
+}
+
 func (a *AARImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
@@ -660,7 +693,7 @@
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+	transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags, sdkLibraries :=
 		aaptLibs(ctx, sdkContext(a))
 
 	_ = staticLibManifests
@@ -673,7 +706,7 @@
 	overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
 
 	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
-		linkFlags, linkDeps, nil, overlayRes, nil)
+		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
 }
 
 var _ Dependency = (*AARImport)(nil)
diff --git a/java/app_test.go b/java/app_test.go
index c20a8e7..c86b038 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -323,6 +323,107 @@
 	}
 }
 
+func TestLibraryAssets(t *testing.T) {
+	bp := `
+			android_app {
+				name: "foo",
+				sdk_version: "current",
+				static_libs: ["lib1", "lib2", "lib3"],
+			}
+
+			android_library {
+				name: "lib1",
+				sdk_version: "current",
+				asset_dirs: ["assets_a"],
+			}
+
+			android_library {
+				name: "lib2",
+				sdk_version: "current",
+			}
+
+			android_library {
+				name: "lib3",
+				sdk_version: "current",
+				static_libs: ["lib4"],
+			}
+
+			android_library {
+				name: "lib4",
+				sdk_version: "current",
+				asset_dirs: ["assets_b"],
+			}
+		`
+
+	testCases := []struct {
+		name          string
+		assetFlag     string
+		assetPackages []string
+	}{
+		{
+			name: "foo",
+			// lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively.
+			assetPackages: []string{
+				buildDir + "/.intermediates/foo/android_common/aapt2/package-res.apk",
+				buildDir + "/.intermediates/lib1/android_common/assets.zip",
+				buildDir + "/.intermediates/lib3/android_common/assets.zip",
+			},
+		},
+		{
+			name:      "lib1",
+			assetFlag: "-A assets_a",
+		},
+		{
+			name: "lib2",
+		},
+		{
+			name: "lib3",
+			assetPackages: []string{
+				buildDir + "/.intermediates/lib3/android_common/aapt2/package-res.apk",
+				buildDir + "/.intermediates/lib4/android_common/assets.zip",
+			},
+		},
+		{
+			name:      "lib4",
+			assetFlag: "-A assets_b",
+		},
+	}
+	ctx := testApp(t, bp)
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			m := ctx.ModuleForTests(test.name, "android_common")
+
+			// Check asset flag in aapt2 link flags
+			var aapt2link android.TestingBuildParams
+			if len(test.assetPackages) > 0 {
+				aapt2link = m.Output("aapt2/package-res.apk")
+			} else {
+				aapt2link = m.Output("package-res.apk")
+			}
+			aapt2Flags := aapt2link.Args["flags"]
+			if test.assetFlag != "" {
+				if !strings.Contains(aapt2Flags, test.assetFlag) {
+					t.Errorf("Can't find asset flag %q in aapt2 link flags %q", test.assetFlag, aapt2Flags)
+				}
+			} else {
+				if strings.Contains(aapt2Flags, " -A ") {
+					t.Errorf("aapt2 link flags %q contain unexpected asset flag", aapt2Flags)
+				}
+			}
+
+			// Check asset merge rule.
+			if len(test.assetPackages) > 0 {
+				mergeAssets := m.Output("package-res.apk")
+				if !reflect.DeepEqual(test.assetPackages, mergeAssets.Inputs.Strings()) {
+					t.Errorf("Unexpected mergeAssets inputs: %v, expected: %v",
+						mergeAssets.Inputs.Strings(), test.assetPackages)
+				}
+			}
+		})
+	}
+}
+
 func TestAndroidResources(t *testing.T) {
 	testCases := []struct {
 		name                       string
diff --git a/java/droiddoc.go b/java/droiddoc.go
index abdceba..098400b 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -223,6 +223,9 @@
 
 	// if set to true, generate docs through Dokka instead of Doclava.
 	Dokka_enabled *bool
+
+	// Compat config XML. Generates compat change documentation if set.
+	Compat_config *string `android:"path"`
 }
 
 type DroidstubsProperties struct {
@@ -1037,6 +1040,11 @@
 
 	cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
 
+	if d.properties.Compat_config != nil {
+		compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config))
+		cmd.FlagWithInput("-compatconfig ", compatConfig)
+	}
+
 	var desc string
 	if Bool(d.properties.Dokka_enabled) {
 		desc = "dokka"
diff --git a/java/java.go b/java/java.go
index ed3dca9..a4e91ab 100644
--- a/java/java.go
+++ b/java/java.go
@@ -757,9 +757,12 @@
 type linkType int
 
 const (
+	// TODO(jiyong) rename these for better readability. Make the allowed
+	// and disallowed link types explicit
 	javaCore linkType = iota
 	javaSdk
 	javaSystem
+	javaModule
 	javaPlatform
 )
 
@@ -789,6 +792,10 @@
 		return javaSdk, true
 	case ver.kind == sdkPublic:
 		return javaSdk, false
+	case name == "android_module_lib_stubs_current":
+		return javaModule, true
+	case ver.kind == sdkModule:
+		return javaModule, false
 	case ver.kind == sdkPrivate || ver.kind == sdkNone || ver.kind == sdkCorePlatform:
 		return javaPlatform, false
 	case !ver.valid():
@@ -824,11 +831,17 @@
 		}
 		break
 	case javaSystem:
-		if otherLinkType == javaPlatform {
+		if otherLinkType == javaPlatform || otherLinkType == javaModule {
 			ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
 				ctx.OtherModuleName(to))
 		}
 		break
+	case javaModule:
+		if otherLinkType == javaPlatform {
+			ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage,
+				ctx.OtherModuleName(to))
+		}
+		break
 	case javaPlatform:
 		// no restriction on link-type
 		break
diff --git a/java/java_test.go b/java/java_test.go
index 0e987a6..8815c09 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1099,6 +1099,12 @@
 			libs: ["foo"],
 			sdk_version: "test_current",
 		}
+		java_library {
+			name: "baz-29",
+			srcs: ["c.java"],
+			libs: ["foo"],
+			sdk_version: "system_29",
+		}
 		`)
 
 	// check the existence of the internal modules
@@ -1138,6 +1144,13 @@
 			"foo.stubs.test.jar")
 	}
 
+	baz29Javac := ctx.ModuleForTests("baz-29", "android_common").Rule("javac")
+	// tests if baz-29 is actually linked to the system 29 stubs lib
+	if !strings.Contains(baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") {
+		t.Errorf("baz-29 javac classpath %v does not contain %q", baz29Javac.Args["classpath"],
+			"prebuilts/sdk/29/system/foo.jar")
+	}
+
 	// test if baz has exported SDK lib names foo and bar to qux
 	qux := ctx.ModuleForTests("qux", "android_common")
 	if quxLib, ok := qux.Module().(*Library); ok {
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index d5c7579..cb8e684 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -16,11 +16,17 @@
 
 import (
 	"android/soong/android"
+	"fmt"
 )
 
 func init() {
 	android.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
-	android.RegisterModuleType("platform_compat_config", platformCompatConfigFactory)
+	android.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
+	android.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
+}
+
+func platformCompatConfigPath(ctx android.PathContext) android.OutputPath {
+	return android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml")
 }
 
 type platformCompatConfigSingleton struct {
@@ -44,11 +50,24 @@
 	return p.metadataFile
 }
 
-type platformCompatConfigIntf interface {
-	compatConfigMetadata() android.OutputPath
+func (p *platformCompatConfig) CompatConfig() android.OutputPath {
+	return p.configFile
 }
 
-var _ platformCompatConfigIntf = (*platformCompatConfig)(nil)
+func (p *platformCompatConfig) SubDir() string {
+	return "compatconfig"
+}
+
+type PlatformCompatConfigIntf interface {
+	android.Module
+
+	compatConfigMetadata() android.OutputPath
+	CompatConfig() android.OutputPath
+	// Sub dir under etc dir.
+	SubDir() string
+}
+
+var _ PlatformCompatConfigIntf = (*platformCompatConfig)(nil)
 
 // compat singleton rules
 func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -56,7 +75,7 @@
 	var compatConfigMetadata android.Paths
 
 	ctx.VisitAllModules(func(module android.Module) {
-		if c, ok := module.(platformCompatConfigIntf); ok {
+		if c, ok := module.(PlatformCompatConfigIntf); ok {
 			metadata := c.compatConfigMetadata()
 			compatConfigMetadata = append(compatConfigMetadata, metadata)
 		}
@@ -68,7 +87,7 @@
 	}
 
 	rule := android.NewRuleBuilder()
-	outputPath := android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml")
+	outputPath := platformCompatConfigPath(ctx)
 
 	rule.Command().
 		BuiltTool(ctx, "process-compat-config").
@@ -124,9 +143,55 @@
 	return &platformCompatConfigSingleton{}
 }
 
-func platformCompatConfigFactory() android.Module {
+func PlatformCompatConfigFactory() android.Module {
 	module := &platformCompatConfig{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	return module
 }
+
+//============== merged_compat_config =================
+type globalCompatConfigProperties struct {
+	// name of the file into which the metadata will be copied.
+	Filename *string
+}
+
+type globalCompatConfig struct {
+	android.ModuleBase
+
+	properties globalCompatConfigProperties
+
+	outputFilePath android.OutputPath
+}
+
+func (c *globalCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	filename := String(c.properties.Filename)
+
+	inputPath := platformCompatConfigPath(ctx)
+	c.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Output: c.outputFilePath,
+		Input:  inputPath,
+	})
+}
+
+func (h *globalCompatConfig) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{h.outputFilePath}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
+// global_compat_config provides access to the merged compat config xml file generated by the build.
+func globalCompatConfigFactory() android.Module {
+	module := &globalCompatConfig{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	return module
+}
diff --git a/java/sdk.go b/java/sdk.go
index f388358..1c047a3 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -71,6 +71,7 @@
 	sdkPublic
 	sdkSystem
 	sdkTest
+	sdkModule
 	sdkPrivate
 )
 
@@ -91,6 +92,8 @@
 		return "core"
 	case sdkCorePlatform:
 		return "core_platform"
+	case sdkModule:
+		return "module"
 	default:
 		return "invalid"
 	}
@@ -256,6 +259,8 @@
 			kind = sdkSystem
 		case "test":
 			kind = sdkTest
+		case "module":
+			kind = sdkModule
 		default:
 			return sdkSpec{sdkInvalid, sdkVersionNone, str}
 		}
@@ -382,6 +387,9 @@
 		return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
 	case sdkCore:
 		return toModule("core.current.stubs", "", nil)
+	case sdkModule:
+		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
+		return toModule("android_module_lib_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw))
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index cd22e6e..fb8ae95 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -683,8 +683,9 @@
 	sdkVersion sdkSpec,
 	headerJars bool) android.Paths {
 
-	// This module is just a wrapper for the stubs.
-	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+	// If a specific numeric version has been requested or the build is explicitly configured
+	// for it then use prebuilt versions of the sdk.
+	if sdkVersion.version.isNumbered() || ctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
 	} else {
 		if !sdkVersion.specified() {
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 9cabd77..c815fe3 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -211,6 +211,15 @@
 			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
+		{
+
+			name:           "module_current",
+			properties:     `sdk_version: "module_current",`,
+			bootclasspath:  []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_module_lib_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
+		},
 	}
 
 	for _, testcase := range classpathTestcases {
diff --git a/java/testing.go b/java/testing.go
index e746e2d..8f979c7 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -49,6 +49,8 @@
 		"api/test-current.txt":   nil,
 		"api/test-removed.txt":   nil,
 		"framework/aidl/a.aidl":  nil,
+		"assets_a/a":             nil,
+		"assets_b/b":             nil,
 
 		"prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so": nil,
 
@@ -61,6 +63,7 @@
 		"prebuilts/sdk/29/public/android.jar":         nil,
 		"prebuilts/sdk/29/public/framework.aidl":      nil,
 		"prebuilts/sdk/29/system/android.jar":         nil,
+		"prebuilts/sdk/29/system/foo.jar":             nil,
 		"prebuilts/sdk/current/core/android.jar":      nil,
 		"prebuilts/sdk/current/public/android.jar":    nil,
 		"prebuilts/sdk/current/public/framework.aidl": nil,
@@ -143,6 +146,7 @@
 		"android_stubs_current",
 		"android_system_stubs_current",
 		"android_test_stubs_current",
+		"android_module_lib_stubs_current",
 		"core.current.stubs",
 		"core.platform.api.stubs",
 		"kotlin-stdlib",