Merge "Rename EXPERIMENTAL_USE_OPENJDK9 to EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9."
diff --git a/Android.bp b/Android.bp
index 1fdd44e..e2d606e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -276,6 +276,7 @@
         "java/plugin.go",
         "java/prebuilt_apis.go",
         "java/proto.go",
+        "java/robolectric.go",
         "java/sdk.go",
         "java/sdk_library.go",
         "java/support_libraries.go",
@@ -443,6 +444,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
 
     arch: {
         arm: {
@@ -465,6 +467,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
 
     arch: {
         arm: {
@@ -483,6 +486,118 @@
 }
 
 toolchain_library {
+    name: "libgcc_stripped",
+    defaults: ["linux_bionic_supported"],
+    vendor_available: true,
+    recovery_available: true,
+    native_bridge_supported: true,
+
+    arch: {
+        arm: {
+            src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
+            strip: {
+                keep_symbols_list: [
+                    // unwind-arm.o
+                    "_Unwind_Complete",
+                    "_Unwind_DeleteException",
+                    "_Unwind_GetCFA",
+                    "_Unwind_VRS_Get",
+                    "_Unwind_VRS_Pop",
+                    "_Unwind_VRS_Set",
+                    "__aeabi_unwind_cpp_pr0",
+                    "__aeabi_unwind_cpp_pr1",
+                    "__aeabi_unwind_cpp_pr2",
+                    "__gnu_Unwind_Backtrace",
+                    "__gnu_Unwind_ForcedUnwind",
+                    "__gnu_Unwind_RaiseException",
+                    "__gnu_Unwind_Resume",
+                    "__gnu_Unwind_Resume_or_Rethrow",
+
+                    // libunwind.o
+                    "_Unwind_Backtrace",
+                    "_Unwind_ForcedUnwind",
+                    "_Unwind_RaiseException",
+                    "_Unwind_Resume",
+                    "_Unwind_Resume_or_Rethrow",
+                    "___Unwind_Backtrace",
+                    "___Unwind_ForcedUnwind",
+                    "___Unwind_RaiseException",
+                    "___Unwind_Resume",
+                    "___Unwind_Resume_or_Rethrow",
+                    "__gnu_Unwind_Restore_VFP",
+                    "__gnu_Unwind_Restore_VFP_D",
+                    "__gnu_Unwind_Restore_VFP_D_16_to_31",
+                    "__gnu_Unwind_Restore_WMMXC",
+                    "__gnu_Unwind_Restore_WMMXD",
+                    "__gnu_Unwind_Save_VFP",
+                    "__gnu_Unwind_Save_VFP_D",
+                    "__gnu_Unwind_Save_VFP_D_16_to_31",
+                    "__gnu_Unwind_Save_WMMXC",
+                    "__gnu_Unwind_Save_WMMXD",
+                    "__restore_core_regs",
+                    "restore_core_regs",
+
+                    // pr-support.o
+                    "_Unwind_GetDataRelBase",
+                    "_Unwind_GetLanguageSpecificData",
+                    "_Unwind_GetRegionStart",
+                    "_Unwind_GetTextRelBase",
+                    "__gnu_unwind_execute",
+                    "__gnu_unwind_frame",
+                ],
+                use_gnu_strip: true,
+            },
+        },
+        arm64: {
+            src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
+        },
+        x86: {
+            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
+
+        },
+        x86_64: {
+            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
+        },
+    },
+    strip: {
+        keep_symbols_list: [
+            // unwind-dw2.o
+            "_Unwind_Backtrace",
+            "_Unwind_DeleteException",
+            "_Unwind_FindEnclosingFunction",
+            "_Unwind_ForcedUnwind",
+            "_Unwind_GetCFA",
+            "_Unwind_GetDataRelBase",
+            "_Unwind_GetGR",
+            "_Unwind_GetIP",
+            "_Unwind_GetIPInfo",
+            "_Unwind_GetLanguageSpecificData",
+            "_Unwind_GetRegionStart",
+            "_Unwind_GetTextRelBase",
+            "_Unwind_RaiseException",
+            "_Unwind_Resume",
+            "_Unwind_Resume_or_Rethrow",
+            "_Unwind_SetGR",
+            "_Unwind_SetIP",
+            "__frame_state_for",
+
+            // unwind-dw2-fde-dip.o
+            "_Unwind_Find_FDE",
+            "__deregister_frame",
+            "__deregister_frame_info",
+            "__deregister_frame_info_bases",
+            "__register_frame",
+            "__register_frame_info",
+            "__register_frame_info_bases",
+            "__register_frame_info_table",
+            "__register_frame_info_table_bases",
+            "__register_frame_table",
+        ],
+        use_gnu_strip: true,
+    },
+}
+
+toolchain_library {
     name: "libwinpthread",
     host_supported: true,
     enabled: false,
@@ -523,6 +638,7 @@
 kernel_headers {
     name: "device_kernel_headers",
     vendor: true,
+    recovery_available: true,
 }
 
 cc_genrule {
diff --git a/android/androidmk.go b/android/androidmk.go
index 2a3748e..2bbd452 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -28,6 +28,10 @@
 	"github.com/google/blueprint/bootstrap"
 )
 
+var (
+	NativeBridgeSuffix = ".native_bridge"
+)
+
 func init() {
 	RegisterSingletonType("androidmk", AndroidMkSingleton)
 }
@@ -161,6 +165,10 @@
 		}
 	}
 
+	if amod.Target().NativeBridge {
+		a.SubName += NativeBridgeSuffix
+	}
+
 	fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
 
 	// Collect make variable assignment entries.
@@ -190,7 +198,22 @@
 	case Device:
 		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
 		if archStr != "common" {
-			a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
+			if amod.Target().NativeBridge {
+				// TODO: Unhardcode these rules.
+				guestArchStr := archStr
+				hostArchStr := ""
+				if guestArchStr == "arm" {
+					hostArchStr = "x86"
+				} else if guestArchStr == "arm64" {
+					hostArchStr = "x86_64"
+				}
+
+				if hostArchStr != "" {
+					a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
+				}
+			} else {
+				a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
+			}
 		}
 
 		a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
diff --git a/android/arch.go b/android/arch.go
index 957a659..c68fe46 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -683,13 +683,25 @@
 	return NoOsType
 }
 
+type NativeBridgeSupport bool
+
+const (
+	NativeBridgeDisabled NativeBridgeSupport = false
+	NativeBridgeEnabled  NativeBridgeSupport = true
+)
+
 type Target struct {
-	Os   OsType
-	Arch Arch
+	Os           OsType
+	Arch         Arch
+	NativeBridge NativeBridgeSupport
 }
 
 func (target Target) String() string {
-	return target.Os.String() + "_" + target.Arch.String()
+	variant := ""
+	if target.NativeBridge {
+		variant = "native_bridge_"
+	}
+	return target.Os.String() + "_" + variant + target.Arch.String()
 }
 
 // archMutator splits a module into a variant for each Target requested by the module.  Target selection
@@ -750,6 +762,18 @@
 			continue
 		}
 
+		// Filter NativeBridge targets unless they are explicitly supported
+		if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
+			var targets []Target
+			for _, t := range osTargets {
+				if !t.NativeBridge {
+					targets = append(targets, t)
+				}
+			}
+
+			osTargets = targets
+		}
+
 		// only the primary arch in the recovery partition
 		if os == Android && module.InstallInRecovery() {
 			osTargets = []Target{osTargets[0]}
@@ -1378,7 +1402,8 @@
 	targets := make(map[OsType][]Target)
 	var targetErr error
 
-	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string) {
+	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string,
+		nativeBridgeEnabled NativeBridgeSupport) {
 		if targetErr != nil {
 			return
 		}
@@ -1391,8 +1416,9 @@
 
 		targets[os] = append(targets[os],
 			Target{
-				Os:   os,
-				Arch: arch,
+				Os:           os,
+				Arch:         arch,
+				NativeBridge: nativeBridgeEnabled,
 			})
 	}
 
@@ -1400,14 +1426,14 @@
 		return nil, fmt.Errorf("No host primary architecture set")
 	}
 
-	addTarget(BuildOs, *variables.HostArch, nil, nil, nil)
+	addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled)
 
 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
-		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil)
+		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
 	}
 
 	if Bool(config.Host_bionic) {
-		addTarget(LinuxBionic, "x86_64", nil, nil, nil)
+		addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled)
 	}
 
 	if String(variables.CrossHost) != "" {
@@ -1420,10 +1446,10 @@
 			return nil, fmt.Errorf("No cross-host primary architecture set")
 		}
 
-		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil)
+		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil, NativeBridgeDisabled)
 
 		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
-			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil)
+			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
 		}
 	}
 
@@ -1434,18 +1460,32 @@
 		}
 
 		addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
-			variables.DeviceCpuVariant, variables.DeviceAbi)
+			variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled)
 
 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
 			addTarget(Android, *variables.DeviceSecondaryArch,
 				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
-				variables.DeviceSecondaryAbi)
+				variables.DeviceSecondaryAbi, NativeBridgeDisabled)
 
 			deviceArches := targets[Android]
 			if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
 				deviceArches[1].Arch.Native = false
 			}
 		}
+
+		if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
+			addTarget(Android, *variables.NativeBridgeArch,
+				variables.NativeBridgeArchVariant, variables.NativeBridgeCpuVariant,
+				variables.NativeBridgeAbi, NativeBridgeEnabled)
+		}
+
+		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
+			variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
+			addTarget(Android, *variables.NativeBridgeSecondaryArch,
+				variables.NativeBridgeSecondaryArchVariant,
+				variables.NativeBridgeSecondaryCpuVariant,
+				variables.NativeBridgeSecondaryAbi, NativeBridgeEnabled)
+		}
 	}
 
 	if targetErr != nil {
diff --git a/android/config.go b/android/config.go
index 5973b11..15e2ad4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -234,16 +234,36 @@
 	return Config{config}
 }
 
+func TestArchConfigNativeBridge(buildDir string, env map[string]string) Config {
+	testConfig := TestConfig(buildDir, env)
+	config := testConfig.config
+
+	config.Targets = map[OsType][]Target{
+		Android: []Target{
+			{Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
+			{Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
+			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled},
+			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled},
+		},
+		BuildOs: []Target{
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
+			{BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
+		},
+	}
+
+	return testConfig
+}
+
 func TestArchConfigFuchsia(buildDir string, env map[string]string) Config {
 	testConfig := TestConfig(buildDir, env)
 	config := testConfig.config
 
 	config.Targets = map[OsType][]Target{
 		Fuchsia: []Target{
-			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}},
+			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}, NativeBridgeDisabled},
 		},
 		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}},
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
 		},
 	}
 
@@ -257,12 +277,12 @@
 
 	config.Targets = map[OsType][]Target{
 		Android: []Target{
-			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}},
-			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}},
+			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
+			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
 		},
 		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}},
-			{BuildOs, Arch{ArchType: X86}},
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
+			{BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
 		},
 	}
 
diff --git a/android/module.go b/android/module.go
index 6743412..3906fd7 100644
--- a/android/module.go
+++ b/android/module.go
@@ -143,6 +143,7 @@
 	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 
+	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
 	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
 
@@ -289,6 +290,9 @@
 	// Whether this module is installed to recovery partition
 	Recovery *bool
 
+	// Whether this module is built for non-native architecures (also known as native bridge binary)
+	Native_bridge_supported *bool `android:"arch_variant"`
+
 	// init.rc files to be installed if this module is installed
 	Init_rc []string `android:"path"`
 
@@ -1093,6 +1097,18 @@
 	}
 }
 
+func (a *androidModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
+	var deps []Module
+	a.VisitDirectDepsBlueprint(func(m blueprint.Module) {
+		if aModule, _ := m.(Module); aModule != nil {
+			if a.ModuleContext.OtherModuleDependencyTag(aModule) == tag {
+				deps = append(deps, aModule)
+			}
+		}
+	})
+	return deps
+}
+
 func (a *androidModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
 	m, _ := a.getDirectDepInternal(name, tag)
 	return m
@@ -1283,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/neverallow.go b/android/neverallow.go
index fba43b3..9314483 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -97,32 +97,15 @@
 		"external/wycheproof",
 	}
 
-	var coreModules = []string{
-		"core-all",
-		"core-oj",
-		"core-libart",
-		"okhttp",
-		"bouncycastle",
-		"conscrypt",
-		"apache-xml",
-	}
-
-	// Core library constraints. Prevent targets adding dependencies on core
-	// library internals, which could lead to compatibility issues with the ART
-	// mainline module. They should use core.platform.api.stubs instead.
+	// Core library constraints. The no_standard_libs can only be used in core
+	// library projects. Access to core library targets is restricted using
+	// visibility rules.
 	rules := []*rule{
 		neverallow().
 			notIn(append(coreLibraryProjects, "development")...).
 			with("no_standard_libs", "true"),
 	}
 
-	for _, m := range coreModules {
-		r := neverallow().
-			notIn(coreLibraryProjects...).
-			with("libs", m).
-			because("Only core libraries projects can depend on " + m)
-		rules = append(rules, r)
-	}
 	return rules
 }
 
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index d55ca57..00c51ea 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -138,17 +138,6 @@
 		expectedError: "",
 	},
 	{
-		name: "dependency on core-libart",
-		fs: map[string][]byte{
-			"Blueprints": []byte(`
-				java_library {
-					name: "needs_core_libart",
-					libs: ["core-libart"],
-				}`),
-		},
-		expectedError: "Only core libraries projects can depend on core-libart",
-	},
-	{
 		name: "java_device_for_host",
 		fs: map[string][]byte{
 			"Blueprints": []byte(`
diff --git a/android/paths.go b/android/paths.go
index 0f20b84..da387a8 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -967,7 +967,7 @@
 // PathForVndkRefAbiDump returns an OptionalPath representing the path of the
 // reference abi dump for the given module. This is not guaranteed to be valid.
 func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string,
-	isLlndk, isGzip bool) OptionalPath {
+	isLlndkOrNdk, isVndk, isGzip bool) OptionalPath {
 
 	arches := ctx.DeviceConfig().Arches()
 	if len(arches) == 0 {
@@ -980,10 +980,12 @@
 	}
 
 	var dirName string
-	if isLlndk {
+	if isLlndkOrNdk {
 		dirName = "ndk"
-	} else {
+	} else if isVndk {
 		dirName = "vndk"
+	} else {
+		dirName = "platform" // opt-in libs
 	}
 
 	binderBitness := ctx.DeviceConfig().BinderBitness()
diff --git a/android/prebuilt.go b/android/prebuilt.go
index df25a89..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 {
@@ -74,6 +79,10 @@
 	}
 }
 
+func (p *Prebuilt) UsePrebuilt() bool {
+	return p.properties.UsePrebuilt
+}
+
 func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
 	p := module.Prebuilt()
 	module.AddProperties(&p.properties)
diff --git a/android/variable.go b/android/variable.go
index d29ba73..c500671 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -165,6 +165,16 @@
 	DeviceSecondaryCpuVariant  *string  `json:",omitempty"`
 	DeviceSecondaryAbi         []string `json:",omitempty"`
 
+	NativeBridgeArch        *string  `json:",omitempty"`
+	NativeBridgeArchVariant *string  `json:",omitempty"`
+	NativeBridgeCpuVariant  *string  `json:",omitempty"`
+	NativeBridgeAbi         []string `json:",omitempty"`
+
+	NativeBridgeSecondaryArch        *string  `json:",omitempty"`
+	NativeBridgeSecondaryArchVariant *string  `json:",omitempty"`
+	NativeBridgeSecondaryCpuVariant  *string  `json:",omitempty"`
+	NativeBridgeSecondaryAbi         []string `json:",omitempty"`
+
 	HostArch          *string `json:",omitempty"`
 	HostSecondaryArch *string `json:",omitempty"`
 
diff --git a/apex/apex.go b/apex/apex.go
index 509e0f2..68d0bc1 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1184,8 +1184,11 @@
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
 		} else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
-			if cc, ok := fi.module.(*cc.Module); ok && cc.UnstrippedOutputFile() != nil {
-				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+			if cc, ok := fi.module.(*cc.Module); ok {
+				if cc.UnstrippedOutputFile() != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+				}
+				cc.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
 		} else {
@@ -1373,11 +1376,15 @@
 	return android.Paths{p.outputApex}
 }
 
+func (p *Prebuilt) InstallFilename() string {
+	return proptools.StringDefault(p.properties.Filename, p.BaseModuleName()+imageApexSuffix)
+}
+
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// TODO(jungjw): Check the key validity.
 	p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
-	p.installFilename = proptools.StringDefault(p.properties.Filename, ctx.ModuleName()+imageApexSuffix)
+	p.installFilename = p.InstallFilename()
 	if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
 		ctx.ModuleErrorf("filename should end in %s for prebuilt_apex", imageApexSuffix)
 	}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b0cd4be..5276ce4 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -93,6 +93,13 @@
 		}
 
 		toolchain_library {
+			name: "libgcc_stripped",
+			src: "",
+			vendor_available: true,
+			recovery_available: true,
+		}
+
+		toolchain_library {
 			name: "libclang_rt.builtins-aarch64-android",
 			src: "",
 			vendor_available: true,
diff --git a/apex/key.go b/apex/key.go
index 229d593..08cd45e 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -105,12 +106,31 @@
 
 func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
 	s.output = android.PathForOutput(ctx, "apexkeys.txt")
-	var filecontent strings.Builder
+	apexModulesMap := make(map[string]android.Module)
 	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(android.Module); ok && !m.Enabled() {
-			return
+		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
+			apexModulesMap[m.Name()] = m
 		}
+	})
 
+	// Find prebuilts and let them override apexBundle if they are preferred
+	ctx.VisitAllModules(func(module android.Module) {
+		if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
+			m.Prebuilt().UsePrebuilt() {
+			apexModulesMap[m.BaseModuleName()] = m
+		}
+	})
+
+	// iterating over map does not give consistent ordering in golang
+	var moduleNames []string
+	for key, _ := range apexModulesMap {
+		moduleNames = append(moduleNames, key)
+	}
+	sort.Strings(moduleNames)
+
+	var filecontent strings.Builder
+	for _, key := range moduleNames {
+		module := apexModulesMap[key]
 		if m, ok := module.(*apexBundle); ok {
 			fmt.Fprintf(&filecontent,
 				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
@@ -119,8 +139,14 @@
 				m.private_key_file.String(),
 				m.container_certificate_file.String(),
 				m.container_private_key_file.String())
+		} else if m, ok := module.(*Prebuilt); ok {
+			fmt.Fprintf(&filecontent,
+				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+				m.InstallFilename(),
+				"PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED")
 		}
-	})
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        android.WriteFile,
 		Description: "apexkeys.txt",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 02806f9..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")
 				}
@@ -145,6 +145,16 @@
 	}
 }
 
+func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+	if library.sAbiOutputFile.Valid() {
+		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiOutputFile.String())
+		if library.sAbiDiff.Valid() && !library.static() {
+			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
+			fmt.Fprintln(w, "HEADER_ABI_DIFFS +=", library.sAbiDiff.String())
+		}
+	}
+}
+
 func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	if library.static() {
 		ret.Class = "STATIC_LIBRARIES"
@@ -169,14 +179,7 @@
 	ret.DistFile = library.distFile
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		library.androidMkWriteExportedFlags(w)
-		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := ")
-		if library.sAbiOutputFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiOutputFile.String())
-			if library.sAbiDiff.Valid() && !library.static() {
-				fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiDiff.String())
-				fmt.Fprintln(w, "HEADER_ABI_DIFFS += ", library.sAbiDiff.String())
-			}
-		}
+		library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
 
 		_, _, ext := splitFileExt(outputFile.Base())
 
diff --git a/cc/builder.go b/cc/builder.go
index 7b26d51..c99e461 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -255,6 +255,7 @@
 	groupStaticLibs bool
 
 	stripKeepSymbols       bool
+	stripKeepSymbolsList   string
 	stripKeepMiniDebugInfo bool
 	stripAddGnuDebuglink   bool
 	stripUseGnuStrip       bool
@@ -835,6 +836,9 @@
 	if flags.stripKeepSymbols {
 		args += " --keep-symbols"
 	}
+	if flags.stripKeepSymbolsList != "" {
+		args += " -k" + flags.stripKeepSymbolsList
+	}
 	if flags.stripUseGnuStrip {
 		args += " --use-gnu-strip"
 	}
diff --git a/cc/cc.go b/cc/cc.go
index bec39ca..eaf41d8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -19,6 +19,7 @@
 // is handled in builder.go
 
 import (
+	"io"
 	"strconv"
 	"strings"
 
@@ -245,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
@@ -407,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 {
@@ -509,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 {
@@ -686,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 {
@@ -727,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
 	}
@@ -752,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
@@ -906,6 +909,8 @@
 }
 
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+	c.makeLinkType = c.getMakeLinkType(actx.Config())
+
 	ctx := &moduleContext{
 		ModuleContext: actx,
 		moduleContextImpl: moduleContextImpl{
@@ -1185,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{}
@@ -1197,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)
@@ -1500,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 {
@@ -1516,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
 		}
 
@@ -1531,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)
 			}
 		}
@@ -1545,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)
@@ -1787,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() {
@@ -1803,6 +1815,8 @@
 				return libName + vendorPublicLibrarySuffix
 			} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
 				return libName + recoverySuffix
+			} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+				return libName + android.NativeBridgeSuffix
 			} else {
 				return libName
 			}
@@ -1916,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"
@@ -1934,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"
@@ -1966,6 +1982,14 @@
 	dpInfo.Srcs = append(dpInfo.Srcs, c.Srcs().Strings()...)
 }
 
+func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+		}
+	}
+}
+
 //
 // Defaults
 //
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 05d74b9..f3d5e60 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1833,13 +1833,13 @@
 	// Check the shared version of lib2.
 	variant := "android_arm64_armv8-a_core_shared"
 	module := ctx.ModuleForTests("lib2", variant).Module().(*Module)
-	checkStaticLibs(t, []string{"lib1", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc"}, module)
+	checkStaticLibs(t, []string{"lib1", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc_stripped"}, module)
 
 	// Check the static version of lib2.
 	variant = "android_arm64_armv8-a_core_static"
 	module = ctx.ModuleForTests("lib2", variant).Module().(*Module)
 	// libc++_static is linked additionally.
-	checkStaticLibs(t, []string{"lib1", "libc++_static", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc"}, module)
+	checkStaticLibs(t, []string{"lib1", "libc++_static", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc_stripped"}, module)
 }
 
 var compilerFlagsTestCases = []struct {
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/config/global.go b/cc/config/global.go
index 0a7d984..24075d9 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -84,6 +84,7 @@
 		"-Wl,--fatal-warnings",
 		"-Wl,--no-undefined-version",
 		"-Wl,--exclude-libs,libgcc.a",
+		"-Wl,--exclude-libs,libgcc_stripped.a",
 	}
 
 	deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
diff --git a/cc/installer.go b/cc/installer.go
index bd8f9e7..cb261b7 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -66,7 +66,7 @@
 	if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
 		dir = installer.dir64
 	}
-	if !ctx.Host() && !ctx.Arch().Native {
+	if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
 		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
 	if installer.location == InstallInData && ctx.useVndk() {
diff --git a/cc/library.go b/cc/library.go
index 13972cc..c2ab098 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"io"
 	"path/filepath"
 	"regexp"
 	"sort"
@@ -96,6 +97,9 @@
 
 	// Properties for ABI compatibility checker
 	Header_abi_checker struct {
+		// Enable ABI checks (even if this is not an LLNDK/VNDK lib)
+		Enabled *bool
+
 		// Path to a symbol file that specifies the symbols to be included in the generated
 		// ABI dump file
 		Symbol_file *string `android:"path"`
@@ -421,6 +425,13 @@
 	return exportedIncludes
 }
 
+func (library *libraryDecorator) shouldCreateVndkSourceAbiDump(ctx ModuleContext) bool {
+	if library.Properties.Header_abi_checker.Enabled != nil {
+		return Bool(library.Properties.Header_abi_checker.Enabled)
+	}
+	return ctx.shouldCreateVndkSourceAbiDump(ctx.Config())
+}
+
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if library.buildStubs() {
 		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
@@ -440,7 +451,7 @@
 		}
 		return Objects{}
 	}
-	if ctx.shouldCreateVndkSourceAbiDump() || library.sabi.Properties.CreateSAbiDumps {
+	if library.shouldCreateVndkSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
@@ -487,6 +498,9 @@
 	// Sets whether a specific variant is static or shared
 	setStatic()
 	setShared()
+
+	// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
+	androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
 }
 
 func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
@@ -769,10 +783,10 @@
 }
 
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
-	isLlndk := 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, isLlndk, false)
-	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndk, true)
+	refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), false)
+	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), true)
 
 	if refAbiDumpTextFile.Valid() {
 		if refAbiDumpGzipFile.Valid() {
@@ -790,7 +804,7 @@
 }
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
-	if len(objs.sAbiDumpFiles) > 0 && ctx.shouldCreateVndkSourceAbiDump() {
+	if len(objs.sAbiDumpFiles) > 0 && library.shouldCreateVndkSourceAbiDump(ctx) {
 		vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
 		if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
 			vndkVersion = ver
@@ -813,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/linker.go b/cc/linker.go
index e724df6..986a562 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -228,10 +228,10 @@
 		// libclang_rt.builtins, libgcc and libatomic have to be last on the command line
 		if !Bool(linker.Properties.No_libcrt) {
 			deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
-		}
-
-		deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
-		if !Bool(linker.Properties.No_libgcc) {
+			deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
+			deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc_stripped")
+		} else if !Bool(linker.Properties.No_libgcc) {
+			deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
 			deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc")
 		}
 
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..57fad7c 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -382,5 +382,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 2a7e657..026ff22 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -64,8 +64,13 @@
 	return deps
 }
 
+// ndk_prebuilt_object exports a precompiled ndk object file for linking
+// operations. Soong's module name format is ndk_<NAME>.o.<sdk_version> where
+// the object is located under
+// ./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),
@@ -98,6 +103,10 @@
 	return deps
 }
 
+// ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
+// library (stl) library for linking operation. The soong's module name format
+// is ndk_<NAME>.so where the library is located under
+// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.so.
 func ndkPrebuiltSharedStlFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyShared()
@@ -113,6 +122,10 @@
 	return module.Init()
 }
 
+// ndk_prebuilt_static_stl exports a precompiled ndk static standard template
+// library (stl) library for linking operation. The soong's module name format
+// is ndk_<NAME>.a where the library is located under
+// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.a.
 func ndkPrebuiltStaticStlFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyStatic()
@@ -122,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/strip.go b/cc/strip.go
index 02397f4..7122585 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -15,15 +15,19 @@
 package cc
 
 import (
+	"strings"
+
 	"android/soong/android"
 )
 
 type StripProperties struct {
 	Strip struct {
-		None         *bool
-		All          *bool
-		Keep_symbols *bool
-	}
+		None              *bool    `android:"arch_variant"`
+		All               *bool    `android:"arch_variant"`
+		Keep_symbols      *bool    `android:"arch_variant"`
+		Keep_symbols_list []string `android:"arch_variant"`
+		Use_gnu_strip     *bool    `android:"arch_variant"`
+	} `android:"arch_variant"`
 }
 
 type stripper struct {
@@ -42,9 +46,14 @@
 	} else {
 		if Bool(stripper.StripProperties.Strip.Keep_symbols) {
 			flags.stripKeepSymbols = true
+		} else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
+			flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
 		} else if !Bool(stripper.StripProperties.Strip.All) {
 			flags.stripKeepMiniDebugInfo = true
 		}
+		if Bool(stripper.StripProperties.Strip.Use_gnu_strip) {
+			flags.stripUseGnuStrip = true
+		}
 		if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo {
 			flags.stripAddGnuDebuglink = true
 		}
diff --git a/cc/testing.go b/cc/testing.go
index 2f41de1..8d76c2f 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -69,6 +69,13 @@
 			src: "",
 		}
 
+		toolchain_library {
+			name: "libgcc_stripped",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
 		cc_library {
 			name: "libc",
 			no_libgcc: true,
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 6494a26..b4c51ab 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -34,6 +34,8 @@
 type toolchainLibraryDecorator struct {
 	*libraryDecorator
 
+	stripper
+
 	Properties toolchainLibraryProperties
 }
 
@@ -45,7 +47,7 @@
 func (library *toolchainLibraryDecorator) linkerProps() []interface{} {
 	var props []interface{}
 	props = append(props, library.libraryDecorator.linkerProps()...)
-	return append(props, &library.Properties)
+	return append(props, &library.Properties, &library.stripper.StripProperties)
 }
 
 // toolchain_library is used internally by the build tool to link the specified
@@ -78,7 +80,17 @@
 		return android.PathForSource(ctx, "")
 	}
 
-	return android.PathForSource(ctx, *library.Properties.Src)
+	srcPath := android.PathForSource(ctx, *library.Properties.Src)
+
+	if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
+		fileName := ctx.ModuleName() + staticLibraryExtension
+		outputFile := android.PathForModuleOut(ctx, fileName)
+		buildFlags := flagsToBuilderFlags(flags)
+		library.stripper.strip(ctx, srcPath, outputFile, buildFlags)
+		return outputFile
+	}
+
+	return srcPath
 }
 
 func (library *toolchainLibraryDecorator) nativeCoverage() bool {
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/cmd/diff_target_files/known_nondeterminism.whitelist b/cmd/diff_target_files/known_nondeterminism.whitelist
index 6d71403..a8ade49 100644
--- a/cmd/diff_target_files/known_nondeterminism.whitelist
+++ b/cmd/diff_target_files/known_nondeterminism.whitelist
@@ -3,8 +3,6 @@
 [
   {
     "Paths": [
-       // b/120039850
-      "system/framework/oat/*/services.art"
     ]
   }
 ]
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index d6999c5..5f9bd01 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -32,42 +32,89 @@
 	"android/soong/ui/tracer"
 )
 
+// A command represents an operation to be executed in the soong build
+// system.
+type command struct {
+	// the flag name (must have double dashes)
+	flag string
+
+	// description for the flag (to display when running help)
+	description string
+
+	// Creates the build configuration based on the args and build context.
+	config func(ctx build.Context, args ...string) build.Config
+
+	// Returns what type of IO redirection this Command requires.
+	stdio func() terminal.StdioInterface
+
+	// run the command
+	run func(ctx build.Context, config build.Config, args []string, logsDir string)
+}
+
+const makeModeFlagName = "--make-mode"
+
+// list of supported commands (flags) supported by soong ui
+var commands []command = []command{
+	{
+		flag:        makeModeFlagName,
+		description: "build the modules by the target name (i.e. soong_docs)",
+		config: func(ctx build.Context, args ...string) build.Config {
+			return build.NewConfig(ctx, args...)
+		},
+		stdio: func() terminal.StdioInterface {
+			return terminal.StdioImpl{}
+		},
+		run: make,
+	}, {
+		flag:        "--dumpvar-mode",
+		description: "print the value of the legacy make variable VAR to stdout",
+		config:      dumpVarConfig,
+		stdio:       customStdio,
+		run:         dumpVar,
+	}, {
+		flag:        "--dumpvars-mode",
+		description: "dump the values of one or more legacy make variables, in shell syntax",
+		config:      dumpVarConfig,
+		stdio:       customStdio,
+		run:         dumpVars,
+	},
+}
+
+// indexList returns the index of first found s. -1 is return if s is not
+// found.
 func indexList(s string, list []string) int {
 	for i, l := range list {
 		if l == s {
 			return i
 		}
 	}
-
 	return -1
 }
 
+// inList returns true if one or more of s is in the list.
 func inList(s string, list []string) bool {
 	return indexList(s, list) != -1
 }
 
+// Main execution of soong_ui. The command format is as follows:
+//
+//    soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+//
+// Command is the type of soong_ui execution. Only one type of
+// execution is specified. The args are specific to the command.
 func main() {
-	var stdio terminal.StdioInterface
-	stdio = terminal.StdioImpl{}
-
-	// dumpvar uses stdout, everything else should be in stderr
-	if os.Args[1] == "--dumpvar-mode" || os.Args[1] == "--dumpvars-mode" {
-		stdio = terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+	c, args := getCommand(os.Args)
+	if c == nil {
+		fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
+		os.Exit(1)
 	}
 
-	writer := terminal.NewWriter(stdio)
+	writer := terminal.NewWriter(c.stdio())
 	defer writer.Finish()
 
 	log := logger.New(writer)
 	defer log.Cleanup()
 
-	if len(os.Args) < 2 || !(inList("--make-mode", os.Args) ||
-		os.Args[1] == "--dumpvars-mode" ||
-		os.Args[1] == "--dumpvar-mode") {
-
-		log.Fatalln("The `soong` native UI is not yet available.")
-	}
-
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 
@@ -96,12 +143,8 @@
 		Writer:  writer,
 		Status:  stat,
 	}}
-	var config build.Config
-	if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" {
-		config = build.NewConfig(buildCtx)
-	} else {
-		config = build.NewConfig(buildCtx, os.Args[1:]...)
-	}
+
+	config := c.config(buildCtx, args...)
 
 	build.SetupOutDir(buildCtx, config)
 
@@ -136,31 +179,10 @@
 	defer f.Shutdown()
 	build.FindSources(buildCtx, config, f)
 
-	if os.Args[1] == "--dumpvar-mode" {
-		dumpVar(buildCtx, config, os.Args[2:])
-	} else if os.Args[1] == "--dumpvars-mode" {
-		dumpVars(buildCtx, config, os.Args[2:])
-	} else {
-		if config.IsVerbose() {
-			writer.Print("! The argument `showcommands` is no longer supported.")
-			writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
-			writer.Print("!")
-			writer.Print(fmt.Sprintf("!   gzip -cd %s/verbose.log.gz | less -R", logsDir))
-			writer.Print("!")
-			writer.Print("! Older versions are saved in verbose.log.#.gz files")
-			writer.Print("")
-			time.Sleep(5 * time.Second)
-		}
-
-		toBuild := build.BuildAll
-		if config.Checkbuild() {
-			toBuild |= build.RunBuildTests
-		}
-		build.Build(buildCtx, config, toBuild)
-	}
+	c.run(buildCtx, config, args, logsDir)
 }
 
-func dumpVar(ctx build.Context, config build.Config, args []string) {
+func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
 	flags.Usage = func() {
 		fmt.Fprintf(os.Stderr, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
@@ -210,7 +232,7 @@
 	}
 }
 
-func dumpVars(ctx build.Context, config build.Config, args []string) {
+func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
 	flags.Usage = func() {
 		fmt.Fprintf(os.Stderr, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
@@ -277,3 +299,59 @@
 		fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
 	}
 }
+
+func customStdio() terminal.StdioInterface {
+	return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+}
+
+// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
+func dumpVarConfig(ctx build.Context, args ...string) build.Config {
+	return build.NewConfig(ctx)
+}
+
+func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
+	if config.IsVerbose() {
+		writer := ctx.Writer
+		writer.Print("! The argument `showcommands` is no longer supported.")
+		writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
+		writer.Print("!")
+		writer.Print(fmt.Sprintf("!   gzip -cd %s/verbose.log.gz | less -R", logsDir))
+		writer.Print("!")
+		writer.Print("! Older versions are saved in verbose.log.#.gz files")
+		writer.Print("")
+		time.Sleep(5 * time.Second)
+	}
+
+	toBuild := build.BuildAll
+	if config.Checkbuild() {
+		toBuild |= build.RunBuildTests
+	}
+	build.Build(ctx, config, toBuild)
+}
+
+// getCommand finds the appropriate command based on args[1] flag. args[0]
+// is the soong_ui filename.
+func getCommand(args []string) (*command, []string) {
+	if len(args) < 2 {
+		return nil, args
+	}
+
+	for _, c := range commands {
+		if c.flag == args[1] {
+			return &c, args[2:]
+		}
+
+		// special case for --make-mode: if soong_ui was called from
+		// build/make/core/main.mk, the makeparallel with --ninja
+		// option specified puts the -j<num> before --make-mode.
+		// TODO: Remove this hack once it has been fixed.
+		if c.flag == makeModeFlagName {
+			if inList(makeModeFlagName, args) {
+				return &c, args[1:]
+			}
+		}
+	}
+
+	// command not found
+	return nil, args
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index f1fa0ff..3b77042 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -59,6 +59,7 @@
 	NeverAllowStripping bool // whether stripping should not be done - used as build time check to make sure dex files are always available
 
 	NoDebugInfo                 bool // don't generate debug info by default
+	DontResolveStartupStrings   bool // don't resolve string literals loaded during application startup.
 	AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true)
 	NeverSystemServerDebugInfo  bool // never generate mini debug info for system server modules (overrides NoDebugInfo=false)
 	AlwaysOtherDebugInfo        bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
@@ -301,6 +302,7 @@
 		GenerateDMFiles:                    false,
 		NeverAllowStripping:                false,
 		NoDebugInfo:                        false,
+		DontResolveStartupStrings:          false,
 		AlwaysSystemServerDebugInfo:        false,
 		NeverSystemServerDebugInfo:         false,
 		AlwaysOtherDebugInfo:               false,
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 01ee15e..5b658d9 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -461,6 +461,9 @@
 		appImageInstallPath := pathtools.ReplaceExtension(odexInstallPath, "art")
 		cmd.FlagWithOutput("--app-image-file=", appImagePath).
 			FlagWithArg("--image-format=", "lz4")
+		if !global.DontResolveStartupStrings {
+			cmd.FlagWithArg("--resolve-startup-const-strings=", "true")
+		}
 		rule.Install(appImagePath, appImageInstallPath)
 	}
 
diff --git a/java/OWNERS b/java/OWNERS
index d68a5b0..16ef4d8 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1 @@
-per-file dexpreopt.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
diff --git a/java/aar.go b/java/aar.go
index 6d40a8a..7332e76 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -81,7 +81,7 @@
 	extraAaptPackagesFile   android.Path
 	mergedManifestFile      android.Path
 	isLibrary               bool
-	uncompressedJNI         bool
+	useEmbeddedNativeLibs   bool
 	useEmbeddedDex          bool
 	usesNonSdkApis          bool
 
@@ -201,7 +201,7 @@
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext,
-		a.isLibrary, a.uncompressedJNI, a.usesNonSdkApis, a.useEmbeddedDex)
+		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex)
 
 	a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
 
@@ -647,6 +647,10 @@
 	return nil
 }
 
+func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
+	return nil, nil
+}
+
 var _ android.PrebuiltInterface = (*Import)(nil)
 
 // android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/android_manifest.go b/java/android_manifest.go
index ea7c2dd..7b378cd 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -43,7 +43,7 @@
 
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
 func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
-	isLibrary, uncompressedJNI, usesNonSdkApis, useEmbeddedDex bool) android.Path {
+	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex bool) android.Path {
 
 	var args []string
 	if isLibrary {
@@ -54,8 +54,8 @@
 			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
 		}
 		if minSdkVersion >= 23 {
-			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !uncompressedJNI))
-		} else if uncompressedJNI {
+			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
+		} else if useEmbeddedNativeLibs {
 			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
 				minSdkVersion)
 		}
diff --git a/java/androidmk.go b/java/androidmk.go
index aa1a81b..5491b3e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -590,6 +590,32 @@
 	}
 }
 
+func (app *AndroidAppImport) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "APPS",
+		OutputFile: android.OptionalPathForPath(app.outputFile),
+		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				if Bool(app.properties.Privileged) {
+					fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
+				}
+				if app.certificate != nil {
+					fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
+				} else {
+					fmt.Fprintln(w, "LOCAL_CERTIFICATE := PRESIGNED")
+				}
+				if len(app.properties.Overrides) > 0 {
+					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(app.properties.Overrides, " "))
+				}
+				if len(app.dexpreopter.builtInstalled) > 0 {
+					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
+				}
+			},
+		},
+	}
+}
+
 func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
 	var testFiles []string
 	for _, d := range data {
diff --git a/java/app.go b/java/app.go
index da8024f..849af5b 100644
--- a/java/app.go
+++ b/java/app.go
@@ -17,23 +17,43 @@
 // 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)
 	android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory)
 	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
@@ -161,14 +181,14 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
+	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
 	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 }
 
-// shouldUncompressJNI returns true if the native libraries should be stored in the APK uncompressed and the
+// Returns true if the native libraries should be stored in the APK uncompressed and the
 // extractNativeLibs application flag should be set to false in the manifest.
-func (a *AndroidApp) shouldUncompressJNI(ctx android.ModuleContext) bool {
+func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
 	minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
@@ -187,19 +207,12 @@
 		return false
 	}
 
-	// Uncompress dex in APKs of privileged apps, and modules used by privileged apps.
-	if ctx.Config().UncompressPrivAppDex() &&
-		(Bool(a.appProperties.Privileged) ||
-			inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
+	// Uncompress dex in APKs of privileged apps
+	if ctx.Config().UncompressPrivAppDex() && Bool(a.appProperties.Privileged) {
 		return true
 	}
 
-	// Uncompress if the dex files is preopted on /system.
-	if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) {
-		return true
-	}
-
-	return false
+	return shouldUncompressDex(ctx, &a.dexpreopter)
 }
 
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
@@ -294,7 +307,7 @@
 			a.appProperties.AlwaysPackageNativeLibs
 		if embedJni {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
-			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
+			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
 		} else {
 			a.installJniLibs = jniLibs
 		}
@@ -302,37 +315,38 @@
 	return jniJarFile
 }
 
-func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx android.ModuleContext) []Certificate {
-	cert := a.getCertString(ctx)
-	certModule := android.SrcIsModule(cert)
-	if certModule != "" {
-		a.certificate = certificateDeps[0]
-		certificateDeps = certificateDeps[1:]
-	} else if cert != "" {
-		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		a.certificate = Certificate{
-			defaultDir.Join(ctx, cert+".x509.pem"),
-			defaultDir.Join(ctx, cert+".pk8"),
+// Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
+// isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
+func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
+	if android.SrcIsModule(certPropValue) == "" {
+		var mainCert Certificate
+		if certPropValue != "" {
+			defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+			mainCert = Certificate{
+				defaultDir.Join(ctx, certPropValue+".x509.pem"),
+				defaultDir.Join(ctx, certPropValue+".pk8"),
+			}
+		} else {
+			pem, key := ctx.Config().DefaultAppCertificate(ctx)
+			mainCert = Certificate{pem, key}
 		}
-	} else {
-		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		a.certificate = Certificate{pem, key}
+		certificates = append([]Certificate{mainCert}, certificates...)
 	}
 
-	if !a.Module.Platform() {
-		certPath := a.certificate.Pem.String()
+	if !m.Platform() {
+		certPath := certificates[0].Pem.String()
 		systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
 		if strings.HasPrefix(certPath, systemCertPath) {
 			enforceSystemCert := ctx.Config().EnforceSystemCertificate()
 			whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
 
-			if enforceSystemCert && !inList(a.Module.Name(), whitelist) {
+			if enforceSystemCert && !inList(m.Name(), whitelist) {
 				ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
 			}
 		}
 	}
 
-	return append([]Certificate{a.certificate}, certificateDeps...)
+	return certificates
 }
 
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
@@ -346,25 +360,26 @@
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, certificateDeps := a.collectAppDeps(ctx)
+	jniLibs, certificateDeps := collectAppDeps(ctx)
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
 
 	if ctx.Failed() {
 		return
 	}
 
-	certificates := a.certificateBuildActions(certificateDeps, ctx)
+	certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
+	a.certificate = certificates[0]
 
 	// Build a final signed app package.
 	// TODO(jungjw): Consider changing this to installApkName.
 	packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
-	CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
 	a.outputFile = packageFile
 
 	for _, split := range a.aapt.splits {
 		// Sign the split APKs
 		packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
-		CreateAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 	}
 
@@ -390,7 +405,7 @@
 	}
 }
 
-func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
 	var jniLibs []jniLib
 	var certificates []Certificate
 
@@ -412,7 +427,6 @@
 				}
 			} else {
 				ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
-
 			}
 		} else if tag == certificateTag {
 			if dep, ok := module.(*AndroidAppCertificate); ok {
@@ -487,6 +501,8 @@
 			a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
 		}
 	}
+	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
+	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 
 	a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites)
@@ -620,3 +636,203 @@
 	android.InitOverrideModule(m)
 	return m
 }
+
+type AndroidAppImport struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	prebuilt android.Prebuilt
+
+	properties AndroidAppImportProperties
+
+	outputFile  android.Path
+	certificate *Certificate
+
+	dexpreopter
+}
+
+type AndroidAppImportProperties struct {
+	// 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
+
+	// Set this flag to true if the prebuilt apk is already signed. The certificate property must not
+	// be set for presigned modules.
+	Presigned *bool
+
+	// Specifies that this app should be installed to the priv-app directory,
+	// where the system will grant it additional privileges not available to
+	// normal apps.
+	Privileged *bool
+
+	// Names of modules to be overridden. Listed modules can only be other binaries
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden binaries, but if both
+	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+	// from PRODUCT_PACKAGES.
+	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 != "" {
+		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+	}
+}
+
+func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		FlagWithInput("-i ", inputPath).
+		FlagWithOutput("-o ", outputPath).
+		FlagWithArg("-0 ", "'lib/**/*.so'").
+		Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+	rule.Build(pctx, ctx, "uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
+}
+
+// Returns whether this module should have the dex file stored uncompressed in the APK.
+func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
+	if ctx.Config().UnbundledBuild() {
+		return false
+	}
+
+	// Uncompress dex in APKs of privileged apps
+	if ctx.Config().UncompressPrivAppDex() && Bool(a.properties.Privileged) {
+		return true
+	}
+
+	return shouldUncompressDex(ctx, &a.dexpreopter)
+}
+
+func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
+		ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
+	}
+	if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
+		ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
+	}
+
+	_, certificates := collectAppDeps(ctx)
+
+	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
+	// TODO: LOCAL_PACKAGE_SPLITS
+
+	srcApk := android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
+
+	// TODO: Install or embed JNI libraries
+
+	// Uncompress JNI libraries in the apk
+	jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
+	a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
+
+	installDir := android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+	a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
+	a.dexpreopter.isInstallable = true
+	a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
+	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+	dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+
+	// Sign or align the package
+	// TODO: Handle EXTERNAL
+	if !Bool(a.properties.Presigned) {
+		certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
+		if len(certificates) != 1 {
+			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
+		}
+		a.certificate = &certificates[0]
+		signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
+		SignAppPackage(ctx, signed, dexOutput, certificates)
+		a.outputFile = signed
+	} else {
+		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+		TransformZipAlign(ctx, alignedApk, dexOutput)
+		a.outputFile = alignedApk
+	}
+
+	// TODO: Optionally compress the output apk.
+
+	ctx.InstallFile(installDir, a.BaseModuleName()+".apk", a.outputFile)
+
+	// TODO: androidmk converter jni libs
+}
+
+func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
+	return &a.prebuilt
+}
+
+func (a *AndroidAppImport) Name() string {
+	return a.prebuilt.Name(a.ModuleBase.Name())
+}
+
+// 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)
+
+	InitJavaModule(module, android.DeviceSupported)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
+
+	return module
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index 5bacb67..82a390f 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -62,7 +62,7 @@
 		CommandDeps: []string{"${config.MergeZipsCmd}"},
 	})
 
-func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
+func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
 	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
@@ -83,6 +83,11 @@
 		Output: unsignedApk,
 	})
 
+	SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+}
+
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+
 	var certificateArgs []string
 	var deps android.Paths
 	for _, c := range certificates {
@@ -93,7 +98,7 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        Signapk,
 		Description: "signapk",
-		Output:      outputFile,
+		Output:      signedApk,
 		Input:       unsignedApk,
 		Implicits:   deps,
 		Args: map[string]string{
diff --git a/java/app_test.go b/java/app_test.go
index a084c9c..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 (
@@ -968,3 +971,165 @@
 		}
 	}
 }
+
+func TestAndroidAppImport(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+
+	// Check cert signing flag.
+	signedApk := variant.Output("signed/foo.apk")
+	signingFlag := signedApk.Args["certificates"]
+	expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
+	if expected != signingFlag {
+		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+	}
+}
+
+func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			dex_preopt: {
+				enabled: false,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs. They shouldn't exist.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
+		t.Errorf("dexpreopt shouldn't have run.")
+	}
+}
+
+func TestAndroidAppImport_Presigned(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			presigned: true,
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+	// Make sure stripping wasn't done.
+	stripRule := variant.Output("dexpreopt/foo.apk")
+	if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
+		t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
+	}
+
+	// Make sure signing was skipped and aligning was done instead.
+	if variant.MaybeOutput("signed/foo.apk").Rule != nil {
+		t.Errorf("signing rule shouldn't be included.")
+	}
+	if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
+		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/device_host_converter.go b/java/device_host_converter.go
index 9c883e5..b92f4d7 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -34,6 +34,9 @@
 	implementationAndResourceJars android.Paths
 	resourceJars                  android.Paths
 
+	srcJarArgs []string
+	srcJarDeps android.Paths
+
 	combinedHeaderJar         android.Path
 	combinedImplementationJar android.Path
 }
@@ -100,6 +103,10 @@
 			d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
 			d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
 			d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+
+			srcJarArgs, srcJarDeps := dep.SrcJarArgs()
+			d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...)
+			d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...)
 		} else {
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
@@ -157,6 +164,10 @@
 	return nil
 }
 
+func (d *DeviceHostConverter) SrcJarArgs() ([]string, android.Paths) {
+	return d.srcJarArgs, d.srcJarDeps
+}
+
 func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index b502d07..08fd06e 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -22,11 +22,12 @@
 type dexpreopter struct {
 	dexpreoptProperties DexpreoptProperties
 
-	installPath     android.OutputPath
-	uncompressedDex bool
-	isSDKLibrary    bool
-	isTest          bool
-	isInstallable   bool
+	installPath         android.OutputPath
+	uncompressedDex     bool
+	isSDKLibrary        bool
+	isTest              bool
+	isInstallable       bool
+	isPresignedPrebuilt bool
 
 	builtInstalled string
 }
@@ -110,7 +111,9 @@
 	if len(archs) == 0 {
 		// assume this is a java library, dexpreopt for all arches for now
 		for _, target := range ctx.Config().Targets[android.Android] {
-			archs = append(archs, target.Arch.ArchType)
+			if target.NativeBridge == android.NativeBridgeDisabled {
+				archs = append(archs, target.Arch.ArchType)
+			}
 		}
 		if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary {
 			// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
@@ -177,6 +180,8 @@
 		NoCreateAppImage:    !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
 		ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
 
+		PresignedPrebuilt: d.isPresignedPrebuilt,
+
 		NoStripping:     Bool(d.dexpreoptProperties.Dex_preopt.No_stripping),
 		StripInputPath:  dexJarFile,
 		StripOutputPath: strippedDexJarFile.OutputPath,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index cb2ea9f..f48428f 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
 }
@@ -191,12 +192,7 @@
 	var allFiles android.Paths
 
 	if !global.DisablePreopt {
-		targets := ctx.Config().Targets[android.Android]
-		if ctx.Config().SecondArchIsTranslated() {
-			targets = targets[:1]
-		}
-
-		for _, target := range targets {
+		for _, target := range image.targets {
 			files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
 			allFiles = append(allFiles, files.Paths()...)
 		}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index b30bd00..270fcb4 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -72,6 +72,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 +130,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 +145,7 @@
 			dir:          dir,
 			symbolsDir:   symbolsDir,
 			images:       images,
+			targets:      targets,
 			zip:          zip,
 		}
 	}).(bootImageConfig)
@@ -138,21 +158,29 @@
 		global := dexpreoptGlobalConfig(ctx)
 
 		runtimeModules := global.RuntimeApexJars
+		nonFrameworkModules := concat(runtimeModules, global.ProductUpdatableBootModules)
+		frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
+		imageModules := concat(runtimeModules, frameworkModules)
 
-		var runtimeBootLocations []string
+		var bootLocations []string
 
 		for _, m := range runtimeModules {
-			runtimeBootLocations = append(runtimeBootLocations,
+			bootLocations = append(bootLocations,
 				filepath.Join("/apex/com.android.runtime/javalib", m+".jar"))
 		}
 
+		for _, m := range frameworkModules {
+			bootLocations = append(bootLocations,
+				filepath.Join("/system/framework", m+".jar"))
+		}
+
 		// The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
 		// the bootclasspath modules have been compiled.  Set up known paths for them, the singleton rules will copy
 		// them there.
 		// TODO: use module dependencies instead
-		var runtimeBootDexPaths android.WritablePaths
-		for _, m := range runtimeModules {
-			runtimeBootDexPaths = append(runtimeBootDexPaths,
+		var bootDexPaths android.WritablePaths
+		for _, m := range imageModules {
+			bootDexPaths = append(bootDexPaths,
 				android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_apexjars_input", m+".jar"))
 		}
 
@@ -160,18 +188,21 @@
 		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")
 		}
 
 		return bootImageConfig{
 			name:         "apex",
-			modules:      runtimeModules,
-			dexLocations: runtimeBootLocations,
-			dexPaths:     runtimeBootDexPaths,
+			modules:      imageModules,
+			dexLocations: bootLocations,
+			dexPaths:     bootDexPaths,
 			dir:          dir,
 			symbolsDir:   symbolsDir,
+			targets:      targets,
 			images:       images,
 		}
 	}).(bootImageConfig)
diff --git a/java/java.go b/java/java.go
index 6168b38..e764ec3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -290,6 +290,10 @@
 	// jar file containing only resources including from static library dependencies
 	resourceJar android.Path
 
+	// args and dependencies to package source files into a srcjar
+	srcJarArgs []string
+	srcJarDeps android.Paths
+
 	// jar file containing implementation classes and resources including static library
 	// dependencies
 	implementationAndResourcesJar android.Path
@@ -340,6 +344,9 @@
 	// list of additional targets for checkbuild
 	additionalCheckedModules android.Paths
 
+	// Extra files generated by the module type to be added as java resources.
+	extraResources android.Paths
+
 	hiddenAPI
 	dexpreopter
 }
@@ -362,6 +369,7 @@
 	DexJar() android.Path
 	AidlIncludeDirs() android.Paths
 	ExportedSdkLibs() []string
+	SrcJarArgs() ([]string, android.Paths)
 }
 
 type SdkLibraryDependency interface {
@@ -1110,9 +1118,18 @@
 		}
 	}
 
+	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
+
+	var includeSrcJar android.WritablePath
+	if Bool(j.properties.Include_srcs) {
+		includeSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+".srcjar")
+		TransformResourcesToJar(ctx, includeSrcJar, j.srcJarArgs, j.srcJarDeps)
+	}
+
 	dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
 		j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
 	fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
+	extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
 
 	var resArgs []string
 	var resDeps android.Paths
@@ -1123,11 +1140,8 @@
 	resArgs = append(resArgs, fileArgs...)
 	resDeps = append(resDeps, fileDeps...)
 
-	if Bool(j.properties.Include_srcs) {
-		srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
-		resArgs = append(resArgs, srcArgs...)
-		resDeps = append(resDeps, srcDeps...)
-	}
+	resArgs = append(resArgs, extraArgs...)
+	resDeps = append(resDeps, extraDeps...)
 
 	if len(resArgs) > 0 {
 		resourceJar := android.PathForModuleOut(ctx, "res", jarName)
@@ -1138,17 +1152,22 @@
 		}
 	}
 
-	if len(deps.staticResourceJars) > 0 {
-		var jars android.Paths
-		if j.resourceJar != nil {
-			jars = append(jars, j.resourceJar)
-		}
-		jars = append(jars, deps.staticResourceJars...)
+	var resourceJars android.Paths
+	if j.resourceJar != nil {
+		resourceJars = append(resourceJars, j.resourceJar)
+	}
+	if Bool(j.properties.Include_srcs) {
+		resourceJars = append(resourceJars, includeSrcJar)
+	}
+	resourceJars = append(resourceJars, deps.staticResourceJars...)
 
+	if len(resourceJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
 			false, nil, nil)
 		j.resourceJar = combinedJar
+	} else if len(resourceJars) == 1 {
+		j.resourceJar = resourceJars[0]
 	}
 
 	jars = append(jars, deps.staticJars...)
@@ -1253,9 +1272,9 @@
 	// merge implementation jar with resources if necessary
 	implementationAndResourcesJar := outputFile
 	if j.resourceJar != nil {
-		jars := android.Paths{implementationAndResourcesJar, j.resourceJar}
+		jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
 		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
 			false, nil, nil)
 		implementationAndResourcesJar = combinedJar
 	}
@@ -1436,6 +1455,10 @@
 	return j.exportedSdkLibs
 }
 
+func (j *Module) SrcJarArgs() ([]string, android.Paths) {
+	return j.srcJarArgs, j.srcJarDeps
+}
+
 var _ logtagsProducer = (*Module)(nil)
 
 func (j *Module) logtags() android.Paths {
@@ -1913,6 +1936,10 @@
 	return j.exportedSdkLibs
 }
 
+func (j *Import) SrcJarArgs() ([]string, android.Paths) {
+	return nil, nil
+}
+
 // Add compile time check for interface implementation
 var _ android.IDEInfo = (*Import)(nil)
 var _ android.IDECustomizedModuleName = (*Import)(nil)
diff --git a/java/java_resources.go b/java/java_resources.go
index 7161168..787d74a 100644
--- a/java/java_resources.go
+++ b/java/java_resources.go
@@ -85,19 +85,19 @@
 	return resourceFilesToJarArgs(ctx, res, exclude)
 }
 
-// Convert java_resources properties to arguments to soong_zip -jar, keeping files that should
-// normally not used as resources like *.java
-func SourceFilesToJarArgs(ctx android.ModuleContext,
-	res, exclude []string) (args []string, deps android.Paths) {
-
-	return resourceFilesToJarArgs(ctx, res, exclude)
-}
-
 func resourceFilesToJarArgs(ctx android.ModuleContext,
 	res, exclude []string) (args []string, deps android.Paths) {
 
 	files := android.PathsForModuleSrcExcludes(ctx, res, exclude)
 
+	args = resourcePathsToJarArgs(files)
+
+	return args, files
+}
+
+func resourcePathsToJarArgs(files android.Paths) []string {
+	var args []string
+
 	lastDir := ""
 	for i, f := range files {
 		rel := f.Rel()
@@ -113,5 +113,5 @@
 		lastDir = dir
 	}
 
-	return args, files
+	return args
 }
diff --git a/java/java_test.go b/java/java_test.go
index e4a7fbe..370e796 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -63,6 +63,7 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
 	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(AndroidAppCertificateFactory))
+	ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(AndroidAppImportFactory))
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
 	ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
@@ -163,6 +164,10 @@
 		"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_xhdpi.apk":  nil,
+		"prebuilts/apk/app_xxhdpi.apk": nil,
+
 		// For framework-res, which is an implicit dependency for framework
 		"AndroidManifest.xml":                        nil,
 		"build/make/target/product/security/testkey": nil,
@@ -479,12 +484,6 @@
 			args: "-C java-res -f java-res/a/a -f java-res/b/b",
 		},
 		{
-			// Test that a module with "include_srcs: true" includes its source files in the resources jar
-			name: "include sources",
-			prop: `include_srcs: true`,
-			args: "-C . -f a.java -f b.java -f c.java",
-		},
-		{
 			// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
 			name: "wildcard dirs",
 			prop: `java_resource_dirs: ["java-res/*"]`,
@@ -552,6 +551,69 @@
 	}
 }
 
+func TestIncludeSrcs(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			include_srcs: true,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			java_resource_dirs: ["java-res"],
+			include_srcs: true,
+		}
+	`)
+
+	// Test a library with include_srcs: true
+	foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
+	fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
+
+	if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("foo combined jars %v does not contain %q", w, g)
+	}
+
+	if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+		t.Errorf("foo source jar args %q is not %q", w, g)
+	}
+
+	// Test a library with include_srcs: true and resources
+	bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
+	barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
+	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
+	barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
+
+	if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+		t.Errorf("bar source jar args %q is not %q", w, g)
+	}
+
+	if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
+		t.Errorf("bar resource jar args %q is not %q", w, g)
+	}
+}
+
 func TestGeneratedSources(t *testing.T) {
 	ctx := testJava(t, `
 		java_library {
diff --git a/java/robolectric.go b/java/robolectric.go
new file mode 100644
index 0000000..26f1e9d
--- /dev/null
+++ b/java/robolectric.go
@@ -0,0 +1,110 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"fmt"
+	"io"
+	"strings"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+}
+
+var robolectricDefaultLibs = []string{
+	"robolectric_android-all-stub",
+	"Robolectric_all-target",
+	"mockito-robolectric-prebuilt",
+	"truth-prebuilt",
+}
+
+type robolectricProperties struct {
+	// The name of the android_app module that the tests will run against.
+	Instrumentation_for *string
+
+	Test_options struct {
+		// Timeout in seconds when running the tests.
+		Timeout *string
+	}
+}
+
+type robolectricTest struct {
+	Library
+
+	robolectricProperties robolectricProperties
+
+	libs []string
+}
+
+func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	r.Library.DepsMutator(ctx)
+
+	if r.robolectricProperties.Instrumentation_for != nil {
+		ctx.AddVariationDependencies(nil, instrumentationForTag, String(r.robolectricProperties.Instrumentation_for))
+	} else {
+		ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
+	}
+
+	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+}
+
+func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.Library.GenerateAndroidBuildActions(ctx)
+
+	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+		r.libs = append(r.libs, ctx.OtherModuleName(dep))
+	}
+}
+
+func (r *robolectricTest) AndroidMk() android.AndroidMkData {
+	data := r.Library.AndroidMk()
+
+	data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+		android.WriteAndroidMkData(w, data)
+
+		fmt.Fprintln(w, "")
+		fmt.Fprintln(w, "include $(CLEAR_VARS)")
+		fmt.Fprintln(w, "LOCAL_MODULE := Run"+name)
+		fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES :=", name)
+		fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES += ", strings.Join(r.libs, " "))
+		fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
+		if t := r.robolectricProperties.Test_options.Timeout; t != nil {
+			fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
+		}
+		fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+	}
+
+	return data
+}
+
+// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
+// instead of on a device.  It also generates a rule with the name of the module prefixed with "Run" that can be
+// used to run the tests.  Running the tests with build rule will eventually be deprecated and replaced with atest.
+func RobolectricTestFactory() android.Module {
+	module := &robolectricTest{}
+
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.protoProperties,
+		&module.robolectricProperties)
+
+	module.Module.dexpreopter.isTest = true
+
+	InitJavaModule(module, android.DeviceSupported)
+	return module
+}
diff --git a/scripts/strip.sh b/scripts/strip.sh
index d536907..0f77da8 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -24,6 +24,7 @@
 #   -i ${file}: input file (required)
 #   -o ${file}: output file (required)
 #   -d ${file}: deps file (required)
+#   -k symbols: Symbols to keep (optional)
 #   --add-gnu-debuglink
 #   --keep-mini-debug-info
 #   --keep-symbols
@@ -32,11 +33,11 @@
 
 set -o pipefail
 
-OPTSTRING=d:i:o:-:
+OPTSTRING=d:i:o:k:-:
 
 usage() {
     cat <<EOF
-Usage: strip.sh [options] -i in-file -o out-file -d deps-file
+Usage: strip.sh [options] -k symbols -i in-file -o out-file -d deps-file
 Options:
         --add-gnu-debuglink     Add a gnu-debuglink section to out-file
         --keep-mini-debug-info  Keep compressed debug info in out-file
@@ -71,6 +72,20 @@
     fi
 }
 
+do_strip_keep_symbol_list() {
+    if [ -z "${use_gnu_strip}" ]; then
+        echo "do_strip_keep_symbol_list does not work with llvm-objcopy"
+        echo "http://b/131631155"
+        usage
+    fi
+
+    echo "${symbols_to_keep}" | tr ',' '\n' > "${outfile}.symbolList"
+    KEEP_SYMBOLS="-w --strip-unneeded-symbol=* --keep-symbols="
+    KEEP_SYMBOLS+="${outfile}.symbolList"
+
+    "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
+}
+
 do_strip_keep_mini_debug_info() {
     rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
     local fail=
@@ -124,19 +139,21 @@
 
 while getopts $OPTSTRING opt; do
     case "$opt" in
-	d) depsfile="${OPTARG}" ;;
-	i) infile="${OPTARG}" ;;
-	o) outfile="${OPTARG}" ;;
-	-)
-	    case "${OPTARG}" in
-		add-gnu-debuglink) add_gnu_debuglink=true ;;
-		keep-mini-debug-info) keep_mini_debug_info=true ;;
-		keep-symbols) keep_symbols=true ;;
-		remove-build-id) remove_build_id=true ;;
-		*) echo "Unknown option --${OPTARG}"; usage ;;
-	    esac;;
-	?) usage ;;
-	*) echo "'${opt}' '${OPTARG}'"
+        d) depsfile="${OPTARG}" ;;
+        i) infile="${OPTARG}" ;;
+        o) outfile="${OPTARG}" ;;
+        k) symbols_to_keep="${OPTARG}" ;;
+        -)
+            case "${OPTARG}" in
+                add-gnu-debuglink) add_gnu_debuglink=true ;;
+                keep-mini-debug-info) keep_mini_debug_info=true ;;
+                keep-symbols) keep_symbols=true ;;
+                remove-build-id) remove_build_id=true ;;
+                use-gnu-strip) use_gnu_strip=true ;;
+                *) echo "Unknown option --${OPTARG}"; usage ;;
+            esac;;
+        ?) usage ;;
+        *) echo "'${opt}' '${OPTARG}'"
     esac
 done
 
@@ -160,6 +177,11 @@
     usage
 fi
 
+if [ ! -z "${symbols_to_keep}" -a ! -z "${keep_symbols}" ]; then
+    echo "--keep-symbols and -k cannot be used together"
+    usage
+fi
+
 if [ ! -z "${add_gnu_debuglink}" -a ! -z "${keep_mini_debug_info}" ]; then
     echo "--add-gnu-debuglink cannot be used with --keep-mini-debug-info"
     usage
@@ -169,6 +191,8 @@
 
 if [ ! -z "${keep_symbols}" ]; then
     do_strip_keep_symbols
+elif [ ! -z "${symbols_to_keep}" ]; then
+    do_strip_keep_symbol_list
 elif [ ! -z "${keep_mini_debug_info}" ]; then
     do_strip_keep_mini_debug_info
 else
diff --git a/ui/build/build.go b/ui/build/build.go
index 0ae06d6..59d1474 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -166,11 +166,13 @@
 		runMakeProductConfig(ctx, config)
 	}
 
-	if inList("installclean", config.Arguments()) {
+	if inList("installclean", config.Arguments()) ||
+		inList("install-clean", config.Arguments()) {
 		installClean(ctx, config, what)
 		ctx.Println("Deleted images and staging directories.")
 		return
-	} else if inList("dataclean", config.Arguments()) {
+	} else if inList("dataclean", config.Arguments()) ||
+		inList("data-clean", config.Arguments()) {
 		dataClean(ctx, config, what)
 		ctx.Println("Deleted data files.")
 		return
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 ed2d9ca..4a30391 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,13 +74,16 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"bash":     Allowed,
-	"bc":       Allowed,
+	"bash": Allowed,
+	"bc":   Allowed,
+	// We need bzip2 here even though we provide a bzip2 binary because
+	// GNU tar seems to avoid calling ours.
 	"bzip2":    Allowed,
 	"date":     Allowed,
 	"dd":       Allowed,
 	"diff":     Allowed,
 	"egrep":    Allowed,
+	"expr":     Allowed,
 	"find":     Allowed,
 	"fuser":    Allowed,
 	"getopt":   Allowed,
@@ -99,12 +102,12 @@
 	"python3":  Allowed,
 	"realpath": Allowed,
 	"rsync":    Allowed,
+	"sed":      Allowed,
 	"sh":       Allowed,
 	"tar":      Allowed,
 	"timeout":  Allowed,
 	"tr":       Allowed,
 	"unzip":    Allowed,
-	"xz":       Allowed,
 	"zip":      Allowed,
 	"zipinfo":  Allowed,
 
@@ -134,7 +137,6 @@
 	"du":        LinuxOnlyPrebuilt,
 	"echo":      LinuxOnlyPrebuilt,
 	"env":       LinuxOnlyPrebuilt,
-	"expr":      LinuxOnlyPrebuilt,
 	"head":      LinuxOnlyPrebuilt,
 	"getconf":   LinuxOnlyPrebuilt,
 	"hostname":  LinuxOnlyPrebuilt,
@@ -154,7 +156,6 @@
 	"readlink":  LinuxOnlyPrebuilt,
 	"rm":        LinuxOnlyPrebuilt,
 	"rmdir":     LinuxOnlyPrebuilt,
-	"sed":       LinuxOnlyPrebuilt,
 	"seq":       LinuxOnlyPrebuilt,
 	"setsid":    LinuxOnlyPrebuilt,
 	"sha1sum":   LinuxOnlyPrebuilt,