Merge "sdk_version: "module_current" is supported"
diff --git a/android/arch.go b/android/arch.go
index 65833a8..3657e6d 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1622,7 +1622,7 @@
 
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
-		{"arm", "armv7-a", "", []string{"armeabi"}},
+		{"arm", "armv7-a", "", []string{"armeabi-v7a"}},
 		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
 		{"x86", "", "", []string{"x86"}},
 		{"x86_64", "", "", []string{"x86_64"}},
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/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..22f0f6f 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)
@@ -3451,6 +3452,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/ccdeps.go b/cc/ccdeps.go
index 4e23a7b..225405c 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -17,7 +17,6 @@
 import (
 	"encoding/json"
 	"fmt"
-	"os"
 	"path"
 	"sort"
 	"strings"
@@ -106,7 +105,7 @@
 
 	moduleDeps.Modules = moduleInfos
 
-	ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName).String()
+	ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName)
 	err := createJsonFile(moduleDeps, ccfpath)
 	if err != nil {
 		ctx.Errorf(err.Error())
@@ -236,17 +235,14 @@
 	return m
 }
 
-func createJsonFile(moduleDeps ccDeps, ccfpath string) error {
-	file, err := os.Create(ccfpath)
-	if err != nil {
-		return fmt.Errorf("Failed to create file: %s, relative: %v", ccdepsJsonFileName, err)
-	}
-	defer file.Close()
-	moduleDeps.Modules = sortMap(moduleDeps.Modules)
+func createJsonFile(moduleDeps ccDeps, ccfpath android.WritablePath) error {
 	buf, err := json.MarshalIndent(moduleDeps, "", "\t")
 	if err != nil {
-		return fmt.Errorf("Write file failed: %s, relative: %v", ccdepsJsonFileName, err)
+		return fmt.Errorf("JSON marshal of cc deps failed: %s", err)
 	}
-	fmt.Fprintf(file, string(buf))
+	err = android.WriteFileToOutputDir(ccfpath, buf, 0666)
+	if err != nil {
+		return fmt.Errorf("Writing cc deps to %s failed: %s", ccfpath.String(), err)
+	}
 	return nil
 }
diff --git a/cc/config/global.go b/cc/config/global.go
index 44de4d5..333885f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -127,8 +127,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r370808"
-	ClangDefaultShortVersion = "10.0.1"
+	ClangDefaultVersion      = "clang-r370808b"
+	ClangDefaultShortVersion = "10.0.2"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
@@ -168,6 +168,9 @@
 			flags = append(flags, "-ftrivial-auto-var-init=pattern")
 		} else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") {
 			flags = append(flags, "-ftrivial-auto-var-init=uninitialized")
+		} else {
+			// Default to pattern initialization.
+			flags = append(flags, "-ftrivial-auto-var-init=pattern")
 		}
 
 		return strings.Join(flags, " ")
diff --git a/cc/library.go b/cc/library.go
index 6c8f5bf..0bddab5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1104,7 +1104,21 @@
 			if ctx.isVndkSp() {
 				library.baseInstaller.subDir = "vndk-sp"
 			} else if ctx.isVndk() {
-				if !ctx.mustUseVendorVariant() && !ctx.isVndkExt() {
+				mayUseCoreVariant := true
+
+				if ctx.mustUseVendorVariant() {
+					mayUseCoreVariant = false
+				}
+
+				if ctx.isVndkExt() {
+					mayUseCoreVariant = false
+				}
+
+				if ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 {
+					mayUseCoreVariant = false
+				}
+
+				if mayUseCoreVariant {
 					library.checkSameCoreVariant = true
 					if ctx.DeviceConfig().VndkUseCoreVariant() {
 						library.useCoreVariant = true
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/cc/pgo.go b/cc/pgo.go
index 6c39d83..8eb3400 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -43,7 +43,7 @@
 const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
 const profileSamplingFlag = "-gmlt -fdebug-info-for-profiling"
 const profileUseInstrumentFormat = "-fprofile-use=%s"
-const profileUseSamplingFormat = "-fprofile-sample-use=%s"
+const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
 
 func getPgoProfileProjects(config android.DeviceConfig) []string {
 	return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
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/androidmk.go b/java/androidmk.go
index 6d4d40b..d76e29b 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -341,7 +341,7 @@
 
 				entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", app.Privileged())
 
-				entries.SetPath("LOCAL_CERTIFICATE", app.certificate.Pem)
+				entries.SetString("LOCAL_CERTIFICATE", app.certificate.AndroidMkString())
 				entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", app.getOverriddenPackages()...)
 
 				for _, jniLib := range app.installJniLibs {
@@ -699,6 +699,7 @@
 		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
 				entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath())
 			},
 		},
diff --git a/java/app.go b/java/app.go
index a27996c..6e0ffeb 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1243,6 +1243,8 @@
 
 	properties RuntimeResourceOverlayProperties
 
+	certificate Certificate
+
 	outputFile android.Path
 	installDir android.InstallPath
 }
@@ -1288,6 +1290,7 @@
 	certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
 	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates)
+	r.certificate = certificates[0]
 
 	r.outputFile = signed
 	r.installDir = android.PathForModuleInstall(ctx, "overlay", String(r.properties.Theme))
diff --git a/java/app_test.go b/java/app_test.go
index 2682682..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
@@ -2242,10 +2343,15 @@
 	if expected != signingFlag {
 		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
 	}
+	path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_CERTIFICATE"]
+	expectedPath := []string{"build/make/target/product/security/platform.x509.pem"}
+	if !reflect.DeepEqual(path, expectedPath) {
+		t.Errorf("Unexpected LOCAL_CERTIFICATE value: %v, expected: %v", path, expectedPath)
+	}
 
 	// Check device location.
-	path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath := []string{"/tmp/target/product/test_device/product/overlay"}
+	path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+	expectedPath = []string{"/tmp/target/product/test_device/product/overlay"}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
 	}
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_test.go b/java/java_test.go
index a2788cb..8815c09 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -479,7 +479,9 @@
 
 		java_sdk_library_import {
 			name: "sdklib",
-			jars: ["b.jar"],
+			public: {
+				jars: ["c.jar"],
+			},
 		}
 
 		prebuilt_stubs_sources {
@@ -531,6 +533,54 @@
 	}
 }
 
+func TestJavaSdkLibraryImport(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			libs: ["sdklib"],
+			sdk_version: "current",
+		}
+
+		java_library {
+			name: "foo.system",
+			srcs: ["a.java"],
+			libs: ["sdklib"],
+			sdk_version: "system_current",
+		}
+
+		java_library {
+			name: "foo.test",
+			srcs: ["a.java"],
+			libs: ["sdklib"],
+			sdk_version: "test_current",
+		}
+
+		java_sdk_library_import {
+			name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+			},
+			system: {
+				jars: ["b.jar"],
+			},
+			test: {
+				jars: ["c.jar"],
+			},
+		}
+		`)
+
+	for _, scope := range []string{"", ".system", ".test"} {
+		fooModule := ctx.ModuleForTests("foo"+scope, "android_common")
+		javac := fooModule.Rule("javac")
+
+		sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+		if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
+			t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
+		}
+	}
+}
+
 func TestDefaults(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_defaults {
@@ -1043,6 +1093,18 @@
 		    libs: ["baz"],
 		    sdk_version: "system_current",
 		}
+		java_library {
+			name: "baz-test",
+			srcs: ["c.java"],
+			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
@@ -1075,6 +1137,20 @@
 			"foo.stubs.jar")
 	}
 
+	bazTestJavac := ctx.ModuleForTests("baz-test", "android_common").Rule("javac")
+	// tests if baz-test is actually linked to the test stubs lib
+	if !strings.Contains(bazTestJavac.Args["classpath"], "foo.stubs.test.jar") {
+		t.Errorf("baz-test javac classpath %v does not contain %q", bazTestJavac.Args["classpath"],
+			"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_library.go b/java/sdk_library.go
index 0ef0f23..fb8ae95 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -225,12 +225,30 @@
 	apiFilePath     android.Path
 }
 
+// Common code between sdk library and sdk library import
+type commonToSdkLibraryAndImport struct {
+	scopePaths map[*apiScope]*scopePaths
+}
+
+func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths {
+	if c.scopePaths == nil {
+		c.scopePaths = make(map[*apiScope]*scopePaths)
+	}
+	paths := c.scopePaths[scope]
+	if paths == nil {
+		paths = &scopePaths{}
+		c.scopePaths[scope] = paths
+	}
+
+	return paths
+}
+
 type SdkLibrary struct {
 	Library
 
 	sdkLibraryProperties sdkLibraryProperties
 
-	scopePaths map[*apiScope]*scopePaths
+	commonToSdkLibraryAndImport
 
 	permissionsFile android.Path
 }
@@ -246,19 +264,6 @@
 	}
 }
 
-func (module *SdkLibrary) getScopePaths(scope *apiScope) *scopePaths {
-	if module.scopePaths == nil {
-		module.scopePaths = make(map[*apiScope]*scopePaths)
-	}
-	paths := module.scopePaths[scope]
-	if paths == nil {
-		paths = &scopePaths{}
-		module.scopePaths[scope] = paths
-	}
-
-	return paths
-}
-
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks()
 	for _, apiScope := range module.getActiveApiScopes() {
@@ -678,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() {
@@ -689,16 +695,19 @@
 				return module.Library.ImplementationJars()
 			}
 		}
-		var paths *scopePaths
+		var apiScope *apiScope
 		switch sdkVersion.kind {
 		case sdkSystem:
-			paths = module.getScopePaths(apiScopeSystem)
+			apiScope = apiScopeSystem
+		case sdkTest:
+			apiScope = apiScopeTest
 		case sdkPrivate:
 			return module.Library.HeaderJars()
 		default:
-			paths = module.getScopePaths(apiScopePublic)
+			apiScope = apiScopePublic
 		}
 
+		paths := module.getScopePaths(apiScope)
 		if headerJars {
 			return paths.stubsHeaderPath
 		} else {
@@ -830,7 +839,8 @@
 // SDK library prebuilts
 //
 
-type sdkLibraryImportProperties struct {
+// Properties associated with each api scope.
+type sdkLibraryScopeProperties struct {
 	Jars []string `android:"path"`
 
 	Sdk_version *string
@@ -839,6 +849,21 @@
 	Libs []string
 }
 
+type sdkLibraryImportProperties struct {
+	// List of shared java libs, common to all scopes, that this module has
+	// dependencies to
+	Libs []string
+
+	// Properties associated with the public api scope.
+	Public sdkLibraryScopeProperties
+
+	// Properties associated with the system api scope.
+	System sdkLibraryScopeProperties
+
+	// Properties associated with the test api scope.
+	Test sdkLibraryScopeProperties
+}
+
 type sdkLibraryImport struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -846,7 +871,7 @@
 
 	properties sdkLibraryImportProperties
 
-	stubsPath android.Paths
+	commonToSdkLibraryAndImport
 }
 
 var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
@@ -857,7 +882,7 @@
 
 	module.AddProperties(&module.properties)
 
-	android.InitPrebuiltModule(module, &module.properties.Jars)
+	android.InitPrebuiltModule(module, &[]string{})
 	InitJavaModule(module, android.HostAndDeviceSupported)
 
 	android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
@@ -873,38 +898,67 @@
 }
 
 func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookContext) {
-	// Creates a java import for the jar with ".stubs" suffix
-	props := struct {
-		Name                *string
-		Soc_specific        *bool
-		Device_specific     *bool
-		Product_specific    *bool
-		System_ext_specific *bool
-	}{}
 
-	props.Name = proptools.StringPtr(module.BaseModuleName() + sdkStubsLibrarySuffix)
+	for apiScope, scopeProperties := range module.scopeProperties() {
+		if len(scopeProperties.Jars) == 0 {
+			continue
+		}
 
-	if module.SocSpecific() {
-		props.Soc_specific = proptools.BoolPtr(true)
-	} else if module.DeviceSpecific() {
-		props.Device_specific = proptools.BoolPtr(true)
-	} else if module.ProductSpecific() {
-		props.Product_specific = proptools.BoolPtr(true)
-	} else if module.SystemExtSpecific() {
-		props.System_ext_specific = proptools.BoolPtr(true)
+		// Creates a java import for the jar with ".stubs" suffix
+		props := struct {
+			Name                *string
+			Soc_specific        *bool
+			Device_specific     *bool
+			Product_specific    *bool
+			System_ext_specific *bool
+			Sdk_version         *string
+			Libs                []string
+			Jars                []string
+		}{}
+
+		props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
+		props.Sdk_version = scopeProperties.Sdk_version
+		// Prepend any of the libs from the legacy public properties to the libs for each of the
+		// scopes to avoid having to duplicate them in each scope.
+		props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
+		props.Jars = scopeProperties.Jars
+
+		if module.SocSpecific() {
+			props.Soc_specific = proptools.BoolPtr(true)
+		} else if module.DeviceSpecific() {
+			props.Device_specific = proptools.BoolPtr(true)
+		} else if module.ProductSpecific() {
+			props.Product_specific = proptools.BoolPtr(true)
+		} else if module.SystemExtSpecific() {
+			props.System_ext_specific = proptools.BoolPtr(true)
+		}
+
+		mctx.CreateModule(ImportFactory, &props)
 	}
 
-	mctx.CreateModule(ImportFactory, &props, &module.properties)
-
 	javaSdkLibraries := javaSdkLibraries(mctx.Config())
 	javaSdkLibrariesLock.Lock()
 	defer javaSdkLibrariesLock.Unlock()
 	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
 }
 
+func (module *sdkLibraryImport) scopeProperties() map[*apiScope]*sdkLibraryScopeProperties {
+	p := make(map[*apiScope]*sdkLibraryScopeProperties)
+	p[apiScopePublic] = &module.properties.Public
+	p[apiScopeSystem] = &module.properties.System
+	p[apiScopeTest] = &module.properties.Test
+	return p
+}
+
 func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
-	// Add dependencies to the prebuilt stubs library
-	ctx.AddVariationDependencies(nil, apiScopePublic.stubsTag, module.BaseModuleName()+sdkStubsLibrarySuffix)
+	for apiScope, scopeProperties := range module.scopeProperties() {
+		if len(scopeProperties.Jars) == 0 {
+			continue
+		}
+
+		// Add dependencies to the prebuilt stubs library
+		ctx.AddVariationDependencies(nil, apiScope.stubsTag, apiScope.stubsModuleName(module.BaseModuleName()))
+	}
 }
 
 func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -912,21 +966,42 @@
 	ctx.VisitDirectDeps(func(to android.Module) {
 		tag := ctx.OtherModuleDependencyTag(to)
 
-		switch tag {
-		case apiScopePublic.stubsTag:
-			module.stubsPath = to.(Dependency).HeaderJars()
+		if lib, ok := to.(Dependency); ok {
+			if scopeTag, ok := tag.(scopeDependencyTag); ok {
+				apiScope := scopeTag.apiScope
+				scopePaths := module.getScopePaths(apiScope)
+				scopePaths.stubsHeaderPath = lib.HeaderJars()
+			}
 		}
 	})
 }
 
+func (module *sdkLibraryImport) sdkJars(
+	ctx android.BaseModuleContext,
+	sdkVersion sdkSpec) android.Paths {
+
+	var apiScope *apiScope
+	switch sdkVersion.kind {
+	case sdkSystem:
+		apiScope = apiScopeSystem
+	case sdkTest:
+		apiScope = apiScopeTest
+	default:
+		apiScope = apiScopePublic
+	}
+
+	paths := module.getScopePaths(apiScope)
+	return paths.stubsHeaderPath
+}
+
 // to satisfy SdkLibraryDependency interface
 func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
 	// This module is just a wrapper for the prebuilt stubs.
-	return module.stubsPath
+	return module.sdkJars(ctx, sdkVersion)
 }
 
 // to satisfy SdkLibraryDependency interface
 func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
 	// This module is just a wrapper for the stubs.
-	return module.stubsPath
+	return module.sdkJars(ctx, sdkVersion)
 }
diff --git a/java/testing.go b/java/testing.go
index 3e5de7d..8f979c7 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -30,6 +30,7 @@
 		"b.kt":                   nil,
 		"a.jar":                  nil,
 		"b.jar":                  nil,
+		"c.jar":                  nil,
 		"APP_NOTICE":             nil,
 		"GENRULE_NOTICE":         nil,
 		"LIB_NOTICE":             nil,
@@ -48,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,
 
@@ -60,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,
diff --git a/scripts/setup-android-build.sh b/scripts/setup-android-build.sh
new file mode 100755
index 0000000..dbb66c3
--- /dev/null
+++ b/scripts/setup-android-build.sh
@@ -0,0 +1,93 @@
+#! /bin/bash
+#
+# Sets the current directory as Android build output directory for a
+# given target by writing the "prefix script" to it. Commands prefixed
+# by this script are executed in the Android build environment. E.g.,
+# running
+#   ./run <command>
+# runs <command> as if we issued
+#   cd <source>
+#   mount --bind <build dir> out
+#   . build/envsetup.sh
+#   lunch <config>
+#   <command>
+#   exit
+#
+# This arrangement eliminates the need to issue envsetup/lunch commands
+# manually, and allows to run multiple builds from the same shell.
+# Thus, if your source tree is in ~/aosp and you are building for
+# 'blueline' and 'cuttlefish', issuing
+#   cd /sdx/blueline && \
+#      ~/aosp/build/soong/scripts/setup-android-build.sh aosp_blueline-userdebug
+#   cd /sdx/cuttlefish && \
+#      ~/aosp/build/soong/scripts/setup-android-build.sh aosp_cf_arm64_phone-userdebug
+# sets up build directories in /sdx/blueline and /sdx/cuttlefish respectively.
+# After that, issue
+#   /sdx/blueline/run m
+# to build blueline image, and issue
+#   /sdx/cuttlefish atest CtsSecurityBulletinHostTestCases
+# to run CTS tests. Notice there is no need to change to a specific directory for that.
+#
+# Argument:
+# * configuration (one of those shown by `lunch` command).
+#
+set -e
+function die() { printf "$@"; exit 1; }
+
+# Find out where the source tree using the fact that we are in its
+# build/ subdirectory.
+[[ "$(uname)" == Linux ]] || die "This setup runs only on Linux\n"
+declare -r mydir="${0%/*}"
+declare -r source="${mydir%/build/soong/scripts}"
+[[ "/${mydir}/" =~ '/build/soong/scripts/' ]] || \
+  die "$0 should be in build/soong/scripts/ subdirectory of the source tree\n"
+[[ ! -e .repo && ! -e .git ]] || \
+  die "Current directory looks like source. You should be in the _target_ directory.\n"
+# Do not override old run script.
+if [[ -x ./run ]]; then
+  # Set variables from config=xxx and source=xxx comments in the existing script.
+  . <(sed -nr 's/^# *source=(.*)/oldsource=\1/p;s/^# *config=(.*)/oldconfig=\1/p' run)
+  die "This directory has been already set up to build Android for %s from %s.\n\
+Remove 'run' file if you want to set it up afresh\n" "$oldconfig" "$oldsource"
+fi
+
+(($#<2)) || die "usage: %s [<config>]\n" $0
+
+if (($#==1)); then
+  # Configuration is provided, emit run script.
+  declare -r config="$1"
+  declare -r target="$PWD"
+  cat >./run <<EOF
+#! /bin/bash
+# source=$source
+# config=$config
+declare -r cmd=\$(printf ' %q' "\$@")
+"$source/prebuilts/build-tools/linux-x86/bin/nsjail"\
+ -Mo -q -e -t 0\
+ -EANDROID_QUIET_BUILD=true \
+ -B / -B "$target:$source/out"\
+ --cwd "$source"\
+ --skip_setsid \
+ --keep_caps\
+ --disable_clone_newcgroup\
+ --disable_clone_newnet\
+ --rlimit_as soft\
+ --rlimit_core soft\
+ --rlimit_cpu soft\
+ --rlimit_fsize soft\
+ --rlimit_nofile soft\
+ --proc_rw\
+ --hostname $(hostname) \
+ --\
+ /bin/bash -i -c ". build/envsetup.sh && lunch "$config" &&\$cmd"
+EOF
+  chmod +x ./run
+else
+  # No configuration, show available ones.
+  printf "Please specify build target. Common values:\n"
+  (cd "$source"
+   . build/envsetup.sh
+   get_build_var COMMON_LUNCH_CHOICES | tr ' ' '\n' | pr -c4 -tT -W"$(tput cols)"
+  )
+  exit 1
+fi