Merge "Don't hide *.kotlin_module in turbine dependencies"
diff --git a/Android.bp b/Android.bp
index afac2b5..e2d606e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -638,6 +638,7 @@
 kernel_headers {
     name: "device_kernel_headers",
     vendor: true,
+    recovery_available: true,
 }
 
 cc_genrule {
diff --git a/android/config.go b/android/config.go
index b142042..15e2ad4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -369,14 +369,14 @@
 }
 
 func (c *config) fromEnv() error {
-	switch c.Getenv("EXPERIMENTAL_USE_OPENJDK9") {
-	case "", "1.8":
-		// Nothing, we always use OpenJDK9
+	switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
+	case "":
+		// Nothing, this is the default
 	case "true":
-		// Use OpenJDK9 and target 1.9
+		// Use -source 9 -target 9
 		c.targetOpenJDK9 = true
 	default:
-		return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "1.8", or "true"`)
+		return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "" or "true"`)
 	}
 
 	return nil
diff --git a/android/module.go b/android/module.go
index fb5c00a..3906fd7 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1299,6 +1299,10 @@
 	a.commonProperties.Product_services_specific = boolPtr(false)
 }
 
+func (a *ModuleBase) EnableNativeBridgeSupportByDefault() {
+	a.commonProperties.Native_bridge_supported = boolPtr(true)
+}
+
 func (a *androidModuleContext) InstallInData() bool {
 	return a.module.InstallInData()
 }
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 2556770..5087b18 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -50,6 +50,11 @@
 	return "prebuilt_" + name
 }
 
+// The below source-related functions and the srcs, src fields are based on an assumption that
+// prebuilt modules have a static source property at the moment. Currently there is only one
+// exception, android_app_import, which chooses a source file depending on the product's DPI
+// preference configs. We'll want to add native support for dynamic source cases if we end up having
+// more modules like this.
 func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
 	if p.srcs != nil {
 		if len(*p.srcs) == 0 {
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 34e673c..88c5304 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -879,7 +879,6 @@
 }
 `,
 	},
-
 	{
 		desc: "prebuilt_etc_PRODUCT_OUT/system/etc",
 		in: `
@@ -1065,6 +1064,80 @@
 `,
 	},
 	{
+		desc: "prebuilt_usr_share",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share {
+	name: "foo",
+
+	src: "foo.txt",
+}
+`,
+	},
+	{
+		desc: "prebuilt_usr_share subdir_bar",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share {
+	name: "foo",
+
+	src: "foo.txt",
+	sub_dir: "bar",
+}
+`,
+	},
+	{
+		desc: "prebuilt_usr_share_host",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share_host {
+	name: "foo",
+
+	src: "foo.txt",
+}
+`,
+	},
+	{
+		desc: "prebuilt_usr_share_host subdir_bar",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share_host {
+	name: "foo",
+
+	src: "foo.txt",
+	sub_dir: "bar",
+}
+`,
+	},
+	{
 		desc: "vts_config",
 		in: `
 include $(CLEAR_VARS)
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 706c0ec..f217da6 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -431,14 +431,6 @@
 	return ""
 }
 
-// Create sub_dir: attribute for the given path
-func makePrebuiltEtcDestination(mod *parser.Module, path string) {
-	mod.Properties = append(mod.Properties, &parser.Property{
-		Name:  "sub_dir",
-		Value: &parser.String{Value: path},
-	})
-}
-
 // Set the value of the given attribute to the error message
 func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error {
 	msg := fmt.Sprintf(format, a...)
@@ -464,16 +456,52 @@
 	return val
 }
 
-// A prefix to strip before setting 'filename' attribute and an array of boolean attributes to set.
-type filenamePrefixToFlags struct {
+// etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as:
+//    * changing the module type from prebuilt_etc to a different one
+//    * stripping the prefix of the install path based on the module type
+//    * appending additional boolean properties to the prebuilt module
+type etcPrebuiltModuleUpdate struct {
+	// The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path
+	// before setting the 'filename' attribute.
 	prefix string
-	flags  []string
+
+	// There is only one prebuilt module type in makefiles. In Soong, there are multiple versions  of
+	// prebuilts based on local_module_path. By default, it is "prebuilt_etc" if modType is blank. An
+	// example is if the local_module_path contains $(TARGET_OUT)/usr/share, the module type is
+	// considered as prebuilt_usr_share.
+	modType string
+
+	// Additional boolean attributes to be added in the prebuilt module. Each added boolean attribute
+	// has a value of true.
+	flags []string
 }
 
-var localModulePathRewrite = map[string][]filenamePrefixToFlags{
-	"HOST_OUT":                        {{prefix: "/etc"}},
+func (f etcPrebuiltModuleUpdate) update(m *parser.Module, path string) bool {
+	updated := false
+	if path == f.prefix {
+		updated = true
+	} else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
+		m.Properties = append(m.Properties, &parser.Property{
+			Name:  "sub_dir",
+			Value: &parser.String{Value: trimmedPath},
+		})
+		updated = true
+	}
+	if updated {
+		for _, flag := range f.flags {
+			m.Properties = append(m.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
+		}
+		if f.modType != "" {
+			m.Type = f.modType
+		}
+	}
+	return updated
+}
+
+var localModuleUpdate = map[string][]etcPrebuiltModuleUpdate{
+	"HOST_OUT":                        {{prefix: "/etc", modType: "prebuilt_etc_host"}, {prefix: "/usr/share", modType: "prebuilt_usr_share_host"}},
 	"PRODUCT_OUT":                     {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
-	"TARGET_OUT":                      {{prefix: "/etc"}},
+	"TARGET_OUT":                      {{prefix: "/etc"}, {prefix: "/usr/share", modType: "prebuilt_usr_share"}},
 	"TARGET_OUT_ETC":                  {{prefix: ""}},
 	"TARGET_OUT_PRODUCT":              {{prefix: "/etc", flags: []string{"product_specific"}}},
 	"TARGET_OUT_PRODUCT_ETC":          {{prefix: "", flags: []string{"product_specific"}}},
@@ -526,37 +554,23 @@
 		if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
 			removeProperty(mod, local_module_path)
 			prefixVariableName := getStringProperty(prop_local_module_path, "var")
-			path := getStringProperty(prop_local_module_path, "fixed")
-			if prefixRewrites, ok := localModulePathRewrite[prefixVariableName]; ok {
-				rewritten := false
-				for _, prefixRewrite := range prefixRewrites {
-					if path == prefixRewrite.prefix {
-						rewritten = true
-					} else if trimmedPath := strings.TrimPrefix(path, prefixRewrite.prefix+"/"); trimmedPath != path {
-						makePrebuiltEtcDestination(mod, trimmedPath)
-						rewritten = true
-					}
-					if rewritten {
-						for _, flag := range prefixRewrite.flags {
-							mod.Properties = append(mod.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
-						}
-						break
-					}
+			if moduleUpdates, ok := localModuleUpdate[prefixVariableName]; ok {
+				path := getStringProperty(prop_local_module_path, "fixed")
+				updated := false
+				for i := 0; i < len(moduleUpdates) && !updated; i++ {
+					updated = moduleUpdates[i].update(mod, path)
 				}
-				if !rewritten {
+				if !updated {
 					expectedPrefices := ""
 					sep := ""
-					for _, prefixRewrite := range prefixRewrites {
+					for _, moduleUpdate := range moduleUpdates {
 						expectedPrefices += sep
 						sep = ", "
-						expectedPrefices += prefixRewrite.prefix
+						expectedPrefices += moduleUpdate.prefix
 					}
 					return indicateAttributeError(mod, "filename",
 						"LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices)
 				}
-				if prefixVariableName == "HOST_OUT" {
-					mod.Type = "prebuilt_etc_host"
-				}
 			} else {
 				return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName)
 			}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 79469ee..c7883e2 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -86,7 +86,7 @@
 				if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
 					fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
 				}
-				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.getMakeLinkType())
+				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
 				if c.useVndk() {
 					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
 				}
diff --git a/cc/cc.go b/cc/cc.go
index bb24942..eaf41d8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -246,14 +246,14 @@
 	sdkVersion() string
 	useVndk() bool
 	isNdk() bool
-	isLlndk() bool
-	isLlndkPublic() bool
-	isVndkPrivate() bool
+	isLlndk(config android.Config) bool
+	isLlndkPublic(config android.Config) bool
+	isVndkPrivate(config android.Config) bool
 	isVndk() bool
 	isVndkSp() bool
 	isVndkExt() bool
 	inRecovery() bool
-	shouldCreateVndkSourceAbiDump() bool
+	shouldCreateVndkSourceAbiDump(config android.Config) bool
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
@@ -408,6 +408,8 @@
 
 	// only non-nil when this is a shared library that reuses the objects of a static library
 	staticVariant *Module
+
+	makeLinkType string
 }
 
 func (c *Module) OutputFile() android.OptionalPath {
@@ -510,19 +512,19 @@
 	return inList(c.Name(), ndkMigratedLibs)
 }
 
-func (c *Module) isLlndk() bool {
+func (c *Module) isLlndk(config android.Config) bool {
 	// Returns true for both LLNDK (public) and LLNDK-private libs.
-	return inList(c.Name(), llndkLibraries)
+	return inList(c.Name(), *llndkLibraries(config))
 }
 
-func (c *Module) isLlndkPublic() bool {
+func (c *Module) isLlndkPublic(config android.Config) bool {
 	// Returns true only for LLNDK (public) libs.
-	return c.isLlndk() && !c.isVndkPrivate()
+	return c.isLlndk(config) && !c.isVndkPrivate(config)
 }
 
-func (c *Module) isVndkPrivate() bool {
+func (c *Module) isVndkPrivate(config android.Config) bool {
 	// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
-	return inList(c.Name(), vndkPrivateLibraries)
+	return inList(c.Name(), *vndkPrivateLibraries(config))
 }
 
 func (c *Module) isVndk() bool {
@@ -687,16 +689,16 @@
 	return ctx.mod.isNdk()
 }
 
-func (ctx *moduleContextImpl) isLlndk() bool {
-	return ctx.mod.isLlndk()
+func (ctx *moduleContextImpl) isLlndk(config android.Config) bool {
+	return ctx.mod.isLlndk(config)
 }
 
-func (ctx *moduleContextImpl) isLlndkPublic() bool {
-	return ctx.mod.isLlndkPublic()
+func (ctx *moduleContextImpl) isLlndkPublic(config android.Config) bool {
+	return ctx.mod.isLlndkPublic(config)
 }
 
-func (ctx *moduleContextImpl) isVndkPrivate() bool {
-	return ctx.mod.isVndkPrivate()
+func (ctx *moduleContextImpl) isVndkPrivate(config android.Config) bool {
+	return ctx.mod.isVndkPrivate(config)
 }
 
 func (ctx *moduleContextImpl) isVndk() bool {
@@ -728,7 +730,7 @@
 }
 
 // Check whether ABI dumps should be created for this module.
-func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump() bool {
+func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump(config android.Config) bool {
 	if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
 		return false
 	}
@@ -753,10 +755,10 @@
 	if ctx.isNdk() {
 		return true
 	}
-	if ctx.isLlndkPublic() {
+	if ctx.isLlndkPublic(config) {
 		return true
 	}
-	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate() {
+	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(config) {
 		// Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext and this is not
 		// VNDK-private.
 		return true
@@ -907,6 +909,8 @@
 }
 
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+	c.makeLinkType = c.getMakeLinkType(actx.Config())
+
 	ctx := &moduleContext{
 		ModuleContext: actx,
 		moduleContextImpl: moduleContextImpl{
@@ -1186,6 +1190,9 @@
 		//
 		// The caller can then know to add the variantLibs dependencies differently from the
 		// nonvariantLibs
+
+		llndkLibraries := llndkLibraries(actx.Config())
+		vendorPublicLibraries := vendorPublicLibraries(actx.Config())
 		rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
 			variantLibs = []string{}
 			nonvariantLibs = []string{}
@@ -1198,9 +1205,9 @@
 					} else {
 						variantLibs = append(variantLibs, name+ndkLibrarySuffix)
 					}
-				} else if ctx.useVndk() && inList(name, llndkLibraries) {
+				} else if ctx.useVndk() && inList(name, *llndkLibraries) {
 					nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
-				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, vendorPublicLibraries) {
+				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
 					vendorPublicLib := name + vendorPublicLibrarySuffix
 					if actx.OtherModuleExists(vendorPublicLib) {
 						nonvariantLibs = append(nonvariantLibs, vendorPublicLib)
@@ -1501,6 +1508,7 @@
 // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
 // or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
 func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
+	llndkLibraries := llndkLibraries(ctx.Config())
 	check := func(child, parent android.Module) bool {
 		to, ok := child.(*Module)
 		if !ok {
@@ -1517,7 +1525,7 @@
 			return true
 		}
 
-		if to.isVndkSp() || inList(child.Name(), llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
+		if to.isVndkSp() || inList(child.Name(), *llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
 			return false
 		}
 
@@ -1532,7 +1540,7 @@
 	}
 	if module, ok := ctx.Module().(*Module); ok {
 		if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
-			if inList(ctx.ModuleName(), llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
+			if inList(ctx.ModuleName(), *llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
 				ctx.WalkDeps(check)
 			}
 		}
@@ -1546,6 +1554,9 @@
 	directStaticDeps := []*Module{}
 	directSharedDeps := []*Module{}
 
+	llndkLibraries := llndkLibraries(ctx.Config())
+	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1788,8 +1799,8 @@
 			libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
 			libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
-			isLLndk := inList(libName, llndkLibraries)
-			isVendorPublicLib := inList(libName, vendorPublicLibraries)
+			isLLndk := inList(libName, *llndkLibraries)
+			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
 			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
 
 			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() {
@@ -1919,10 +1930,12 @@
 	return false
 }
 
-func (c *Module) getMakeLinkType() string {
+func (c *Module) getMakeLinkType(config android.Config) string {
 	if c.useVndk() {
-		if inList(c.Name(), vndkCoreLibraries) || inList(c.Name(), vndkSpLibraries) || inList(c.Name(), llndkLibraries) {
-			if inList(c.Name(), vndkPrivateLibraries) {
+		if inList(c.Name(), *vndkCoreLibraries(config)) ||
+			inList(c.Name(), *vndkSpLibraries(config)) ||
+			inList(c.Name(), *llndkLibraries(config)) {
+			if inList(c.Name(), *vndkPrivateLibraries(config)) {
 				return "native:vndk_private"
 			} else {
 				return "native:vndk"
@@ -1937,7 +1950,7 @@
 		// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
 		//family, link := getNdkStlFamilyAndLinkType(c)
 		//return fmt.Sprintf("native:ndk:%s:%s", family, link)
-	} else if inList(c.Name(), vndkUsingCoreVariantLibraries) {
+	} else if inList(c.Name(), *vndkUsingCoreVariantLibraries(config)) {
 		return "native:platform_vndk"
 	} else {
 		return "native:platform"
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 347bfab..94a8257 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -101,8 +101,9 @@
 		// not emit the table by default on Android since NDK still uses GNU binutils.
 		"-faddrsig",
 
-		// -Wimplicit-fallthrough is not enabled by -Wall.
+		// Make implicit fallthrough an error in the future.
 		"-Wimplicit-fallthrough",
+		"-Wno-error=implicit-fallthrough",
 
 		// Help catch common 32/64-bit errors.
 		"-Werror=int-conversion",
diff --git a/cc/library.go b/cc/library.go
index 1f79bec..c2ab098 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -429,7 +429,7 @@
 	if library.Properties.Header_abi_checker.Enabled != nil {
 		return Bool(library.Properties.Header_abi_checker.Enabled)
 	}
-	return ctx.shouldCreateVndkSourceAbiDump()
+	return ctx.shouldCreateVndkSourceAbiDump(ctx.Config())
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -783,7 +783,7 @@
 }
 
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
-	isLlndkOrNdk := inList(ctx.baseModuleName(), llndkLibraries) || inList(ctx.baseModuleName(), ndkMigratedLibs)
+	isLlndkOrNdk := inList(ctx.baseModuleName(), *llndkLibraries(ctx.Config())) || inList(ctx.baseModuleName(), ndkMigratedLibs)
 
 	refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), false)
 	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), true)
@@ -827,7 +827,7 @@
 		refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
 		if refAbiDumpFile != nil {
 			library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
-				refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(), ctx.isNdk(), ctx.isVndkExt())
+				refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(ctx.Config()), ctx.isNdk(), ctx.isVndkExt())
 		}
 	}
 }
diff --git a/cc/makevars.go b/cc/makevars.go
index dc91525..3c24f34 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -64,6 +64,8 @@
 }
 
 func makeVarsProvider(ctx android.MakeVarsContext) {
+	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
 	ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
 	ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
 	ctx.Strict("LLVM_PREBUILTS_BASE", "${config.ClangBase}")
@@ -92,18 +94,18 @@
 
 	ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
 
-	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(vndkCoreLibraries, " "))
-	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(vndkSpLibraries, " "))
-	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
-	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
-	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(vndkUsingCoreVariantLibraries, " "))
+	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(*vndkCoreLibraries(ctx.Config()), " "))
+	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(*vndkSpLibraries(ctx.Config()), " "))
+	ctx.Strict("LLNDK_LIBRARIES", strings.Join(*llndkLibraries(ctx.Config()), " "))
+	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " "))
+	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " "))
 
 	// Filter vendor_public_library that are exported to make
 	exportedVendorPublicLibraries := []string{}
 	ctx.VisitAllModules(func(module android.Module) {
 		if ccModule, ok := module.(*Module); ok {
 			baseName := ccModule.BaseModuleName()
-			if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
+			if inList(baseName, *vendorPublicLibraries) && module.ExportedToMake() {
 				if !inList(baseName, exportedVendorPublicLibraries) {
 					exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName)
 				}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c63b200..ff990b5 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -38,9 +38,12 @@
 	ndkLibrarySuffix = ".ndk"
 
 	ndkPrebuiltSharedLibs = []string{
+		"aaudio",
+		"amidi",
 		"android",
 		"binder_ndk",
 		"c",
+		"camera2ndk",
 		"dl",
 		"EGL",
 		"GLESv1_CM",
@@ -49,6 +52,7 @@
 		"jnigraphics",
 		"log",
 		"mediandk",
+		"nativewindow",
 		"m",
 		"OpenMAXAL",
 		"OpenSLES",
@@ -382,5 +386,6 @@
 func ndkLibraryFactory() android.Module {
 	module := newStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	module.ModuleBase.EnableNativeBridgeSupportByDefault()
 	return module
 }
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 8451295..026ff22 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -70,6 +70,7 @@
 // ./prebuilts/ndk/current/platforms/android-<sdk_version>/arch-$(HOST_ARCH)/usr/lib/<NAME>.o.
 func ndkPrebuiltObjectFactory() android.Module {
 	module := newBaseModule(android.DeviceSupported, android.MultilibBoth)
+	module.ModuleBase.EnableNativeBridgeSupportByDefault()
 	module.linker = &ndkPrebuiltObjectLinker{
 		objectLinker: objectLinker{
 			baseLinker: NewBaseLinker(nil),
@@ -134,6 +135,7 @@
 	}
 	module.installer = nil
 	module.Properties.HideFromMake = true
+	module.ModuleBase.EnableNativeBridgeSupportByDefault()
 	return module.Init()
 }
 
diff --git a/cc/sabi.go b/cc/sabi.go
index 4a86499..451176f 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -78,7 +78,7 @@
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		((c.isVndk() && c.useVndk()) || inList(c.Name(), llndkLibraries) ||
+		((c.isVndk() && c.useVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m android.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 2d80c22..acf2bef 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -817,7 +817,7 @@
 		}
 
 		if mctx.Device() && runtimeLibrary != "" {
-			if inList(runtimeLibrary, llndkLibraries) && !c.static() && c.useVndk() {
+			if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.useVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
 
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index 2072ad9..5738d25 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -24,10 +24,16 @@
 var (
 	vendorPublicLibrarySuffix = ".vendorpublic"
 
-	vendorPublicLibraries     = []string{}
+	vendorPublicLibrariesKey  = android.NewOnceKey("vendorPublicLibraries")
 	vendorPublicLibrariesLock sync.Mutex
 )
 
+func vendorPublicLibraries(config android.Config) *[]string {
+	return config.Once(vendorPublicLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
 // Creates a stub shared library for a vendor public library. Vendor public libraries
 // are vendor libraries (owned by them and installed to /vendor partition) that are
 // exposed to Android apps via JNI. The libraries are made public by being listed in
@@ -82,12 +88,13 @@
 
 	vendorPublicLibrariesLock.Lock()
 	defer vendorPublicLibrariesLock.Unlock()
-	for _, lib := range vendorPublicLibraries {
+	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+	for _, lib := range *vendorPublicLibraries {
 		if lib == name {
 			return
 		}
 	}
-	vendorPublicLibraries = append(vendorPublicLibraries, name)
+	*vendorPublicLibraries = append(*vendorPublicLibraries, name)
 }
 
 func (stub *vendorPublicLibraryStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
diff --git a/cc/vndk.go b/cc/vndk.go
index 44a83e7..7859fa2 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -192,29 +192,63 @@
 }
 
 var (
-	vndkCoreLibraries             []string
-	vndkSpLibraries               []string
-	llndkLibraries                []string
-	vndkPrivateLibraries          []string
-	vndkUsingCoreVariantLibraries []string
-	vndkLibrariesLock             sync.Mutex
+	vndkCoreLibrariesKey             = android.NewOnceKey("vndkCoreLibrarires")
+	vndkSpLibrariesKey               = android.NewOnceKey("vndkSpLibrarires")
+	llndkLibrariesKey                = android.NewOnceKey("llndkLibrarires")
+	vndkPrivateLibrariesKey          = android.NewOnceKey("vndkPrivateLibrarires")
+	vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
+	vndkLibrariesLock                sync.Mutex
 )
 
+func vndkCoreLibraries(config android.Config) *[]string {
+	return config.Once(vndkCoreLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func vndkSpLibraries(config android.Config) *[]string {
+	return config.Once(vndkSpLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func llndkLibraries(config android.Config) *[]string {
+	return config.Once(llndkLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func vndkPrivateLibraries(config android.Config) *[]string {
+	return config.Once(vndkPrivateLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func vndkUsingCoreVariantLibraries(config android.Config) *[]string {
+	return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
 // gather list of vndk-core, vndk-sp, and ll-ndk libs
 func VndkMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.Enabled() {
 		if lib, ok := m.linker.(*llndkStubDecorator); ok {
 			vndkLibrariesLock.Lock()
 			defer vndkLibrariesLock.Unlock()
+
+			llndkLibraries := llndkLibraries(mctx.Config())
+			vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+
 			name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
-			if !inList(name, llndkLibraries) {
-				llndkLibraries = append(llndkLibraries, name)
-				sort.Strings(llndkLibraries)
+			if !inList(name, *llndkLibraries) {
+				*llndkLibraries = append(*llndkLibraries, name)
+				sort.Strings(*llndkLibraries)
 			}
 			if !Bool(lib.Properties.Vendor_available) {
-				if !inList(name, vndkPrivateLibraries) {
-					vndkPrivateLibraries = append(vndkPrivateLibraries, name)
-					sort.Strings(vndkPrivateLibraries)
+				if !inList(name, *vndkPrivateLibraries) {
+					*vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+					sort.Strings(*vndkPrivateLibraries)
 				}
 			}
 		} else {
@@ -225,27 +259,33 @@
 				if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
 					vndkLibrariesLock.Lock()
 					defer vndkLibrariesLock.Unlock()
+
+					vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
+					vndkSpLibraries := vndkSpLibraries(mctx.Config())
+					vndkCoreLibraries := vndkCoreLibraries(mctx.Config())
+					vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+
 					if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
-						if !inList(name, vndkUsingCoreVariantLibraries) {
-							vndkUsingCoreVariantLibraries = append(vndkUsingCoreVariantLibraries, name)
-							sort.Strings(vndkUsingCoreVariantLibraries)
+						if !inList(name, *vndkUsingCoreVariantLibraries) {
+							*vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
+							sort.Strings(*vndkUsingCoreVariantLibraries)
 						}
 					}
 					if m.vndkdep.isVndkSp() {
-						if !inList(name, vndkSpLibraries) {
-							vndkSpLibraries = append(vndkSpLibraries, name)
-							sort.Strings(vndkSpLibraries)
+						if !inList(name, *vndkSpLibraries) {
+							*vndkSpLibraries = append(*vndkSpLibraries, name)
+							sort.Strings(*vndkSpLibraries)
 						}
 					} else {
-						if !inList(name, vndkCoreLibraries) {
-							vndkCoreLibraries = append(vndkCoreLibraries, name)
-							sort.Strings(vndkCoreLibraries)
+						if !inList(name, *vndkCoreLibraries) {
+							*vndkCoreLibraries = append(*vndkCoreLibraries, name)
+							sort.Strings(*vndkCoreLibraries)
 						}
 					}
 					if !Bool(m.VendorProperties.Vendor_available) {
-						if !inList(name, vndkPrivateLibraries) {
-							vndkPrivateLibraries = append(vndkPrivateLibraries, name)
-							sort.Strings(vndkPrivateLibraries)
+						if !inList(name, *vndkPrivateLibraries) {
+							*vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+							sort.Strings(*vndkPrivateLibraries)
 						}
 					}
 				}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3b77042..1e0f862 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -176,7 +176,7 @@
 
 // LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct.  It is used directly in Soong
 // and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make.
-func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, error) {
+func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byte, error) {
 	type GlobalJSONConfig struct {
 		GlobalConfig
 
@@ -199,9 +199,9 @@
 	}
 
 	config := GlobalJSONConfig{}
-	err := loadConfig(ctx, path, &config)
+	data, err := loadConfig(ctx, path, &config)
 	if err != nil {
-		return config.GlobalConfig, err
+		return config.GlobalConfig, nil, err
 	}
 
 	// Construct paths that require a PathContext.
@@ -217,7 +217,7 @@
 	config.GlobalConfig.Tools.VerifyUsesLibraries = constructPath(ctx, config.Tools.VerifyUsesLibraries)
 	config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext)
 
-	return config.GlobalConfig, nil
+	return config.GlobalConfig, data, nil
 }
 
 // LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct.  It is not used in Soong, which
@@ -241,7 +241,7 @@
 
 	config := ModuleJSONConfig{}
 
-	err := loadConfig(ctx, path, &config)
+	_, err := loadConfig(ctx, path, &config)
 	if err != nil {
 		return config.ModuleConfig, err
 	}
@@ -259,24 +259,24 @@
 	return config.ModuleConfig, nil
 }
 
-func loadConfig(ctx android.PathContext, path string, config interface{}) error {
+func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) {
 	r, err := ctx.Fs().Open(path)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	defer r.Close()
 
 	data, err := ioutil.ReadAll(r)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	err = json.Unmarshal(data, config)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	return nil
+	return data, nil
 }
 
 func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index c72f684..d54ddb1 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -78,7 +78,7 @@
 
 	ctx := &pathContext{android.TestConfig(*outDir, nil)}
 
-	globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
+	globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err)
 		os.Exit(2)
diff --git a/java/app.go b/java/app.go
index ec021fc..db9c5dd 100644
--- a/java/app.go
+++ b/java/app.go
@@ -17,17 +17,20 @@
 // This file contains the module types for compiling Android apps.
 
 import (
-	"path/filepath"
-	"strings"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+	"path/filepath"
+	"reflect"
+	"strings"
 
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/tradefed"
 )
 
+var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"}
+var dpiVariantsStruct reflect.Type
+
 func init() {
 	android.RegisterModuleType("android_app", AndroidAppFactory)
 	android.RegisterModuleType("android_test", AndroidTestFactory)
@@ -35,6 +38,22 @@
 	android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
 	android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
 	android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
+
+	// Dynamically construct a struct for the dpi_variants property in android_app_import.
+	perDpiStruct := reflect.StructOf([]reflect.StructField{
+		{
+			Name: "Apk",
+			Type: reflect.TypeOf((*string)(nil)),
+		},
+	})
+	dpiVariantsFields := make([]reflect.StructField, len(supportedDpis))
+	for i, dpi := range supportedDpis {
+		dpiVariantsFields[i] = reflect.StructField{
+			Name: string(dpi),
+			Type: perDpiStruct,
+		}
+	}
+	dpiVariantsStruct = reflect.StructOf(dpiVariantsFields)
 }
 
 // AndroidManifest.xml merging
@@ -635,6 +654,26 @@
 	// A prebuilt apk to import
 	Apk string
 
+	// Per-DPI settings. This property makes it possible to specify a different source apk path for
+	// each DPI.
+	//
+	// Example:
+	//
+	//     android_app_import {
+	//         name: "example_import",
+	//         apk: "prebuilts/example.apk",
+	//         dpi_variants: {
+	//             mdpi: {
+	//                 apk: "prebuilts/example_mdpi.apk",
+	//             },
+	//             xhdpi: {
+	//                 apk: "prebuilts/example_xhdpi.apk",
+	//             },
+	//         },
+	//         certificate: "PRESIGNED",
+	//     }
+	Dpi_variants interface{}
+
 	// The name of a certificate in the default certificate directory, blank to use the default
 	// product certificate, or an android_app_certificate module name in the form ":module".
 	Certificate *string
@@ -656,6 +695,41 @@
 	Overrides []string
 }
 
+func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string {
+	dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi))
+	if !dpiField.IsValid() {
+		return ""
+	}
+	apkValue := dpiField.FieldByName("Apk").Elem()
+	if apkValue.IsValid() {
+		return apkValue.String()
+	}
+	return ""
+}
+
+// Chooses a source APK path to use based on the module's per-DPI settings and the product config.
+func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string {
+	config := ctx.Config()
+	dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem()
+	if !dpiVariantsValue.IsValid() {
+		return a.properties.Apk
+	}
+	// Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI.
+	if config.ProductAAPTPreferredConfig() != "" {
+		if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" {
+			return apk
+		}
+	}
+	for _, dpi := range config.ProductAAPTPrebuiltDPI() {
+		if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" {
+			return apk
+		}
+	}
+
+	// No match. Use the generic one.
+	return a.properties.Apk
+}
+
 func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
 	cert := android.SrcIsModule(String(a.properties.Certificate))
 	if cert != "" {
@@ -690,6 +764,19 @@
 	return shouldUncompressDex(ctx, &a.dexpreopter)
 }
 
+func (a *AndroidAppImport) uncompressDex(
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		FlagWithInput("-i ", inputPath).
+		FlagWithOutput("-o ", outputPath).
+		FlagWithArg("-0 ", "'classes*.dex'").
+		Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+	rule.Build(pctx, ctx, "uncompress-dex", "Uncompress dex files")
+}
+
 func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
 		ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
@@ -701,10 +788,9 @@
 	_, certificates := collectAppDeps(ctx)
 
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
-	// TODO: LOCAL_DPI_VARIANTS
 	// TODO: LOCAL_PACKAGE_SPLITS
 
-	srcApk := a.prebuilt.SingleSourcePath(ctx)
+	srcApk := android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
 
 	// TODO: Install or embed JNI libraries
 
@@ -718,6 +804,11 @@
 	a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
 	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
 	dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+	if a.dexpreopter.uncompressedDex {
+		dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
+		a.uncompressDex(ctx, dexOutput, dexUncompressed.OutputPath)
+		dexOutput = dexUncompressed
+	}
 
 	// Sign or align the package
 	// TODO: Handle EXTERNAL
@@ -754,6 +845,7 @@
 // android_app_import imports a prebuilt apk with additional processing specified in the module.
 func AndroidAppImportFactory() android.Module {
 	module := &AndroidAppImport{}
+	module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface()
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.dexpreoptProperties)
 
diff --git a/java/app_test.go b/java/app_test.go
index e4c6afe..bc35e21 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -15,15 +15,18 @@
 package java
 
 import (
-	"android/soong/android"
-	"android/soong/cc"
-
 	"fmt"
 	"path/filepath"
 	"reflect"
+	"regexp"
 	"sort"
 	"strings"
 	"testing"
+
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -1052,3 +1055,81 @@
 		t.Errorf("can't find aligning rule")
 	}
 }
+
+func TestAndroidAppImport_DpiVariants(t *testing.T) {
+	bp := `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			dpi_variants: {
+				xhdpi: {
+					apk: "prebuilts/apk/app_xhdpi.apk",
+				},
+				xxhdpi: {
+					apk: "prebuilts/apk/app_xxhdpi.apk",
+				},
+			},
+			certificate: "PRESIGNED",
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`
+	testCases := []struct {
+		name                string
+		aaptPreferredConfig *string
+		aaptPrebuiltDPI     []string
+		expected            string
+	}{
+		{
+			name:                "no preferred",
+			aaptPreferredConfig: nil,
+			aaptPrebuiltDPI:     []string{},
+			expected:            "prebuilts/apk/app.apk",
+		},
+		{
+			name:                "AAPTPreferredConfig matches",
+			aaptPreferredConfig: proptools.StringPtr("xhdpi"),
+			aaptPrebuiltDPI:     []string{"xxhdpi", "lhdpi"},
+			expected:            "prebuilts/apk/app_xhdpi.apk",
+		},
+		{
+			name:                "AAPTPrebuiltDPI matches",
+			aaptPreferredConfig: proptools.StringPtr("mdpi"),
+			aaptPrebuiltDPI:     []string{"xxhdpi", "xhdpi"},
+			expected:            "prebuilts/apk/app_xxhdpi.apk",
+		},
+		{
+			name:                "non-first AAPTPrebuiltDPI matches",
+			aaptPreferredConfig: proptools.StringPtr("mdpi"),
+			aaptPrebuiltDPI:     []string{"ldpi", "xhdpi"},
+			expected:            "prebuilts/apk/app_xhdpi.apk",
+		},
+		{
+			name:                "no matches",
+			aaptPreferredConfig: proptools.StringPtr("mdpi"),
+			aaptPrebuiltDPI:     []string{"ldpi", "xxxhdpi"},
+			expected:            "prebuilts/apk/app.apk",
+		},
+	}
+
+	jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)")
+	for _, test := range testCases {
+		config := testConfig(nil)
+		config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig
+		config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
+		ctx := testAppContext(config, bp, nil)
+
+		run(t, ctx, config)
+
+		variant := ctx.ModuleForTests("foo", "android_common")
+		jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
+		matches := jniRuleRe.FindStringSubmatch(jniRuleCommand)
+		if len(matches) != 2 {
+			t.Errorf("failed to extract the src apk path from %q", jniRuleCommand)
+		}
+		if test.expected != matches[1] {
+			t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
+		}
+	}
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 092a133..2a1a901 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -56,6 +56,7 @@
 	dexPaths     android.WritablePaths
 	dir          android.OutputPath
 	symbolsDir   android.OutputPath
+	targets      []android.Target
 	images       map[android.ArchType]android.OutputPath
 	zip          android.WritablePath
 }
@@ -114,6 +115,8 @@
 type dexpreoptBootJars struct {
 	defaultBootImage *bootImage
 	otherImages      []*bootImage
+
+	dexpreoptConfigForMake android.WritablePath
 }
 
 // dexpreoptBoot singleton rules
@@ -122,6 +125,9 @@
 		return
 	}
 
+	d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
+	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
+
 	global := dexpreoptGlobalConfig(ctx)
 
 	// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
@@ -191,16 +197,9 @@
 	var allFiles android.Paths
 
 	if !global.DisablePreopt {
-		targets := ctx.Config().Targets[android.Android]
-		if ctx.Config().SecondArchIsTranslated() {
-			targets = targets[:1]
-		}
-
-		for _, target := range targets {
-			if target.NativeBridge == android.NativeBridgeDisabled {
-				files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
-				allFiles = append(allFiles, files.Paths()...)
-			}
+		for _, target := range image.targets {
+			files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+			allFiles = append(allFiles, files.Paths()...)
 		}
 	}
 
@@ -459,8 +458,24 @@
 
 }
 
+func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
+	data := dexpreoptGlobalConfigRaw(ctx).data
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.WriteFile,
+		Output: path,
+		Args: map[string]string{
+			"content": string(data),
+		},
+	})
+}
+
 // Export paths for default boot image to Make
 func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
+	if d.dexpreoptConfigForMake != nil {
+		ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String())
+	}
+
 	image := d.defaultBootImage
 	if image != nil {
 		ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index a0b1ea5..d903f45 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,40 +15,50 @@
 package java
 
 import (
-	"android/soong/android"
-	"android/soong/dexpreopt"
 	"path/filepath"
 	"strings"
+
+	"android/soong/android"
+	"android/soong/dexpreopt"
 )
 
 // dexpreoptGlobalConfig returns the global dexpreopt.config.  It is loaded once the first time it is called for any
 // ctx.Config(), and returns the same data for all future calls with the same ctx.Config().  A value can be inserted
 // for tests using setDexpreoptTestGlobalConfig.
 func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
+	return dexpreoptGlobalConfigRaw(ctx).global
+}
+
+type globalConfigAndRaw struct {
+	global dexpreopt.GlobalConfig
+	data   []byte
+}
+
+func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
 	return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
 		if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
 			ctx.AddNinjaFileDeps(f)
-			globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, f)
+			globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f)
 			if err != nil {
 				panic(err)
 			}
-			return globalConfig
+			return globalConfigAndRaw{globalConfig, data}
 		}
 
 		// No global config filename set, see if there is a test config set
 		return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} {
 			// Nope, return a config with preopting disabled
-			return dexpreopt.GlobalConfig{
+			return globalConfigAndRaw{dexpreopt.GlobalConfig{
 				DisablePreopt: true,
-			}
+			}, nil}
 		})
-	}).(dexpreopt.GlobalConfig)
+	}).(globalConfigAndRaw)
 }
 
 // setDexpreoptTestGlobalConfig sets a GlobalConfig that future calls to dexpreoptGlobalConfig will return.  It must
 // be called before the first call to dexpreoptGlobalConfig for the config.
 func setDexpreoptTestGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) {
-	config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfig })
+	config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
 }
 
 var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
@@ -72,6 +82,23 @@
 
 var systemServerClasspathKey = android.NewOnceKey("systemServerClasspath")
 
+// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
+// supported through native bridge.
+func dexpreoptTargets(ctx android.PathContext) []android.Target {
+	var targets []android.Target
+	for i, target := range ctx.Config().Targets[android.Android] {
+		if ctx.Config().SecondArchIsTranslated() && i > 0 {
+			break
+		}
+
+		if target.NativeBridge == android.NativeBridgeDisabled {
+			targets = append(targets, target)
+		}
+	}
+
+	return targets
+}
+
 // defaultBootImageConfig returns the bootImageConfig that will be used to dexpreopt modules.  It is computed once the
 // first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
 // ctx.Config().
@@ -113,7 +140,9 @@
 		images := make(map[android.ArchType]android.OutputPath)
 		zip := dir.Join(ctx, "boot.zip")
 
-		for _, target := range ctx.Config().Targets[android.Android] {
+		targets := dexpreoptTargets(ctx)
+
+		for _, target := range targets {
 			images[target.Arch.ArchType] = dir.Join(ctx,
 				"system/framework", target.Arch.ArchType.String()).Join(ctx, "boot.art")
 		}
@@ -126,6 +155,7 @@
 			dir:          dir,
 			symbolsDir:   symbolsDir,
 			images:       images,
+			targets:      targets,
 			zip:          zip,
 		}
 	}).(bootImageConfig)
@@ -168,7 +198,9 @@
 		symbolsDir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_apexjars_unstripped")
 		images := make(map[android.ArchType]android.OutputPath)
 
-		for _, target := range ctx.Config().Targets[android.Android] {
+		targets := dexpreoptTargets(ctx)
+
+		for _, target := range targets {
 			images[target.Arch.ArchType] = dir.Join(ctx,
 				"system/framework", target.Arch.ArchType.String(), "apex.art")
 		}
@@ -180,6 +212,7 @@
 			dexPaths:     bootDexPaths,
 			dir:          dir,
 			symbolsDir:   symbolsDir,
+			targets:      targets,
 			images:       images,
 		}
 	}).(bootImageConfig)
diff --git a/java/java.go b/java/java.go
index 4ca7838..866b33c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -639,7 +639,7 @@
 	switch {
 	case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
 		name == "stub-annotations" || name == "private-stub-annotations-jar" ||
-		name == "core-lambda-stubs":
+		name == "core-lambda-stubs" || name == "core-generated-annotation-stubs":
 		return javaCore, true
 	case ver == "core_current":
 		return javaCore, false
diff --git a/java/java_test.go b/java/java_test.go
index 53df6f4..370e796 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -164,7 +164,9 @@
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":   nil,
 		"prebuilts/sdk/Android.bp":                    []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
 
-		"prebuilts/apk/app.apk": nil,
+		"prebuilts/apk/app.apk":        nil,
+		"prebuilts/apk/app_xhdpi.apk":  nil,
+		"prebuilts/apk/app_xxhdpi.apk": nil,
 
 		// For framework-res, which is an implicit dependency for framework
 		"AndroidManifest.xml":                        nil,
@@ -1005,8 +1007,8 @@
 		}
 	`
 
-	t.Run("1.8", func(t *testing.T) {
-		// Test default javac 1.8
+	t.Run("Java language level 8", func(t *testing.T) {
+		// Test default javac -source 1.8 -target 1.8
 		ctx := testJava(t, bp)
 
 		checkPatchModuleFlag(t, ctx, "foo", "")
@@ -1014,9 +1016,9 @@
 		checkPatchModuleFlag(t, ctx, "baz", "")
 	})
 
-	t.Run("1.9", func(t *testing.T) {
-		// Test again with javac 1.9
-		config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+	t.Run("Java language level 9", func(t *testing.T) {
+		// Test again with javac -source 9 -target 9
+		config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
 		ctx := testContext(config, bp, nil)
 		run(t, ctx, config)
 
diff --git a/java/sdk_test.go b/java/sdk_test.go
index e446129..cc4da2e 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -272,8 +272,8 @@
 				}
 			}
 
-			t.Run("1.8", func(t *testing.T) {
-				// Test default javac 1.8
+			t.Run("Java language level 8", func(t *testing.T) {
+				// Test default javac -source 1.8 -target 1.8
 				config := testConfig(nil)
 				if testcase.unbundled {
 					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
@@ -299,9 +299,9 @@
 				}
 			})
 
-			// Test again with javac 1.9
-			t.Run("1.9", func(t *testing.T) {
-				config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+			// Test again with javac -source 9 -target 9
+			t.Run("Java language level 9", func(t *testing.T) {
+				config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
 				if testcase.unbundled {
 					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 				}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 483c273..c6e5ddc 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -224,7 +224,6 @@
 		"BUILD_BROKEN_USES_BUILD_HOST_NATIVE_TEST",
 		"BUILD_BROKEN_USES_BUILD_HOST_PREBUILT",
 		"BUILD_BROKEN_USES_BUILD_HOST_SHARED_LIBRARY",
-		"BUILD_BROKEN_USES_BUILD_HOST_SHARED_TEST_LIBRARY",
 		"BUILD_BROKEN_USES_BUILD_HOST_STATIC_LIBRARY",
 		"BUILD_BROKEN_USES_BUILD_HOST_STATIC_TEST_LIBRARY",
 		"BUILD_BROKEN_USES_BUILD_HOST_TEST_CONFIG",
@@ -238,7 +237,6 @@
 		"BUILD_BROKEN_USES_BUILD_PREBUILT",
 		"BUILD_BROKEN_USES_BUILD_RRO_PACKAGE",
 		"BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY",
-		"BUILD_BROKEN_USES_BUILD_SHARED_TEST_LIBRARY",
 		"BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY",
 		"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
 		"BUILD_BROKEN_USES_BUILD_STATIC_TEST_LIBRARY",
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 54006d2..4a30391 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -102,6 +102,7 @@
 	"python3":  Allowed,
 	"realpath": Allowed,
 	"rsync":    Allowed,
+	"sed":      Allowed,
 	"sh":       Allowed,
 	"tar":      Allowed,
 	"timeout":  Allowed,
@@ -155,7 +156,6 @@
 	"readlink":  LinuxOnlyPrebuilt,
 	"rm":        LinuxOnlyPrebuilt,
 	"rmdir":     LinuxOnlyPrebuilt,
-	"sed":       LinuxOnlyPrebuilt,
 	"seq":       LinuxOnlyPrebuilt,
 	"setsid":    LinuxOnlyPrebuilt,
 	"sha1sum":   LinuxOnlyPrebuilt,