Merge "Revert "Revert "Move libgcc to libcrt.builtins"""
diff --git a/Android.bp b/Android.bp
index aeabb13..eefa149 100644
--- a/Android.bp
+++ b/Android.bp
@@ -219,6 +219,7 @@
         "blueprint-pathtools",
         "soong",
         "soong-android",
+        "soong-cc",
         "soong-genrule",
         "soong-java-config",
         "soong-tradefed",
diff --git a/android/config.go b/android/config.go
index 4b10552..5da1e0b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -232,8 +232,8 @@
 
 	config.Targets = map[OsClass][]Target{
 		Device: []Target{
-			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true}},
-			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true}},
+			{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"}}},
 		},
 		Host: []Target{
 			{BuildOs, Arch{ArchType: X86_64}},
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 1d50980..10e5b0a 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -140,6 +140,7 @@
 			"LOCAL_DX_FLAGS":              "dxflags",
 			"LOCAL_JAVA_LIBRARIES":        "libs",
 			"LOCAL_STATIC_JAVA_LIBRARIES": "static_libs",
+			"LOCAL_JNI_SHARED_LIBRARIES":  "jni_libs",
 			"LOCAL_AAPT_FLAGS":            "aaptflags",
 			"LOCAL_PACKAGE_SPLITS":        "package_splits",
 			"LOCAL_COMPATIBILITY_SUITE":   "test_suites",
@@ -154,6 +155,7 @@
 			// java_library_static to android_library.
 			"LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs",
 			"LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs",
+			"LOCAL_ADDITIONAL_CERTIFICATES":  "additional_certificates",
 		})
 
 	addStandardProperties(bpparser.BoolType,
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 12e9114..cacd287 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -48,7 +48,7 @@
 
 	arm64Cppflags = []string{}
 
-	arm64CpuVariantCflags = map[string][]string{
+	arm64ClangCpuVariantCflags = map[string][]string{
 		"cortex-a53": []string{
 			"-mcpu=cortex-a53",
 		},
@@ -61,9 +61,7 @@
 			"-mcpu=cortex-a55",
 		},
 		"kryo": []string{
-			// Use the cortex-a57 cpu since some compilers
-			// don't support a Kryo specific target yet.
-			"-mcpu=cortex-a57",
+			"-mcpu=kryo",
 		},
 		"exynos-m1": []string{
 			"-mcpu=exynos-m1",
@@ -72,8 +70,6 @@
 			"-mcpu=exynos-m2",
 		},
 	}
-
-	arm64ClangCpuVariantCflags = copyVariantFlags(arm64CpuVariantCflags)
 )
 
 const (
@@ -94,18 +90,13 @@
 		"exynos-m2",
 		"denver64")
 
-	// Clang supports specific Kryo targeting
-	replaceFirst(arm64ClangCpuVariantCflags["kryo"], "-mcpu=cortex-a57", "-mcpu=kryo")
-
 	pctx.StaticVariable("arm64GccVersion", arm64GccVersion)
 
 	pctx.SourcePathVariable("Arm64GccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/aarch64/aarch64-linux-android-${arm64GccVersion}")
 
-	pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " "))
 	pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
 	pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
-	pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
 	pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64"))
 
 	pctx.StaticVariable("Arm64ClangCflags", strings.Join(ClangFilterUnknownCflags(arm64Cflags), " "))
@@ -116,45 +107,23 @@
 	pctx.StaticVariable("Arm64ClangArmv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
 	pctx.StaticVariable("Arm64ClangArmv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
 
-	pctx.StaticVariable("Arm64CortexA53Cflags",
-		strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
 	pctx.StaticVariable("Arm64ClangCortexA53Cflags",
 		strings.Join(arm64ClangCpuVariantCflags["cortex-a53"], " "))
 
-	pctx.StaticVariable("Arm64CortexA55Cflags",
-		strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
 	pctx.StaticVariable("Arm64ClangCortexA55Cflags",
 		strings.Join(arm64ClangCpuVariantCflags["cortex-a55"], " "))
 
-	pctx.StaticVariable("Arm64KryoCflags",
-		strings.Join(arm64CpuVariantCflags["kryo"], " "))
 	pctx.StaticVariable("Arm64ClangKryoCflags",
 		strings.Join(arm64ClangCpuVariantCflags["kryo"], " "))
 
-	pctx.StaticVariable("Arm64ExynosM1Cflags",
-		strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
 	pctx.StaticVariable("Arm64ClangExynosM1Cflags",
 		strings.Join(arm64ClangCpuVariantCflags["exynos-m1"], " "))
 
-	pctx.StaticVariable("Arm64ExynosM2Cflags",
-		strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
 	pctx.StaticVariable("Arm64ClangExynosM2Cflags",
 		strings.Join(arm64ClangCpuVariantCflags["exynos-m2"], " "))
 }
 
 var (
-	arm64CpuVariantCflagsVar = map[string]string{
-		"":           "",
-		"cortex-a53": "${config.Arm64CortexA53Cflags}",
-		"cortex-a55": "${config.Arm64CortexA55Cflags}",
-		"cortex-a72": "${config.Arm64CortexA53Cflags}",
-		"cortex-a73": "${config.Arm64CortexA53Cflags}",
-		"cortex-a75": "${config.Arm64CortexA55Cflags}",
-		"kryo":       "${config.Arm64KryoCflags}",
-		"exynos-m1":  "${config.Arm64ExynosM1Cflags}",
-		"exynos-m2":  "${config.Arm64ExynosM2Cflags}",
-	}
-
 	arm64ClangArchVariantCflagsVar = map[string]string{
 		"armv8-a":  "${config.Arm64ClangArmv8ACflags}",
 		"armv8-2a": "${config.Arm64ClangArmv82ACflags}",
@@ -177,7 +146,7 @@
 	toolchain64Bit
 
 	ldflags              string
-	toolchainCflags      string
+	lldflags             string
 	toolchainClangCflags string
 }
 
@@ -197,22 +166,6 @@
 	return arm64GccVersion
 }
 
-func (t *toolchainArm64) ToolchainCflags() string {
-	return t.toolchainCflags
-}
-
-func (t *toolchainArm64) Cflags() string {
-	return "${config.Arm64Cflags}"
-}
-
-func (t *toolchainArm64) Cppflags() string {
-	return "${config.Arm64Cppflags}"
-}
-
-func (t *toolchainArm64) Ldflags() string {
-	return t.ldflags
-}
-
 func (t *toolchainArm64) IncludeFlags() string {
 	return "${config.Arm64IncludeFlags}"
 }
@@ -234,7 +187,7 @@
 }
 
 func (t *toolchainArm64) ClangLldflags() string {
-	return "${config.Arm64Lldflags}"
+	return t.lldflags
 }
 
 func (t *toolchainArm64) ToolchainClangCflags() string {
@@ -272,7 +225,10 @@
 			"${config.Arm64Ldflags}",
 			extraLdflags,
 		}, " "),
-		toolchainCflags:      variantOrDefault(arm64CpuVariantCflagsVar, arch.CpuVariant),
+		lldflags: strings.Join([]string{
+			"${config.Arm64Lldflags}",
+			extraLdflags,
+		}, " "),
 		toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
 	}
 }
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 8dee2c8..95c9495 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -50,7 +50,7 @@
 		"-Os",
 	}
 
-	armArchVariantCflags = map[string][]string{
+	armClangArchVariantCflags = map[string][]string{
 		"armv7-a": []string{
 			"-march=armv7-a",
 			"-mfloat-abi=softfp",
@@ -68,7 +68,7 @@
 		},
 	}
 
-	armCpuVariantCflags = map[string][]string{
+	armClangCpuVariantCflags = map[string][]string{
 		"cortex-a7": []string{
 			"-mcpu=cortex-a7",
 			"-mfpu=neon-vfpv4",
@@ -118,7 +118,7 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"krait": []string{
-			"-mcpu=cortex-a15",
+			"-mcpu=krait",
 			"-mfpu=neon-vfpv4",
 			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
 			// don't advertise.
@@ -138,9 +138,6 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 	}
-
-	armClangCpuVariantCflags  = copyVariantFlags(armCpuVariantCflags)
-	armClangArchVariantCflags = copyVariantFlags(armArchVariantCflags)
 )
 
 const (
@@ -174,49 +171,15 @@
 	android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon")
 	android.RegisterArchVariantFeatures(android.Arm, "armv8-a", "neon")
 
-	// Krait is not supported by GCC, but is supported by Clang, so
-	// override the definitions when building modules with Clang.
-	replaceFirst(armClangCpuVariantCflags["krait"], "-mcpu=cortex-a15", "-mcpu=krait")
-
-	// The reason we use "-march=armv8-a+crc", instead of "-march=armv8-a", for
-	// gcc is the latter would conflict with any specified/supported -mcpu!
-	// All armv8-a cores supported by gcc 4.9 support crc, so it's safe
-	// to add +crc. Besides, the use of gcc is only for legacy code.
-	replaceFirst(armArchVariantCflags["armv8-a"], "-march=armv8-a", "-march=armv8-a+crc")
-
 	pctx.StaticVariable("armGccVersion", armGccVersion)
 
 	pctx.SourcePathVariable("ArmGccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/arm/arm-linux-androideabi-${armGccVersion}")
 
-	pctx.StaticVariable("ArmToolchainCflags", strings.Join(armToolchainCflags, " "))
-	pctx.StaticVariable("ArmCflags", strings.Join(armCflags, " "))
 	pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
 	pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
-	pctx.StaticVariable("ArmCppflags", strings.Join(armCppflags, " "))
 	pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm"))
 
-	// Extended cflags
-
-	// ARM vs. Thumb instruction set flags
-	pctx.StaticVariable("ArmArmCflags", strings.Join(armArmCflags, " "))
-	pctx.StaticVariable("ArmThumbCflags", strings.Join(armThumbCflags, " "))
-
-	// Architecture variant cflags
-	pctx.StaticVariable("ArmArmv7ACflags", strings.Join(armArchVariantCflags["armv7-a"], " "))
-	pctx.StaticVariable("ArmArmv7ANeonCflags", strings.Join(armArchVariantCflags["armv7-a-neon"], " "))
-	pctx.StaticVariable("ArmArmv8ACflags", strings.Join(armArchVariantCflags["armv8-a"], " "))
-
-	// Cpu variant cflags
-	pctx.StaticVariable("ArmGenericCflags", strings.Join(armCpuVariantCflags[""], " "))
-	pctx.StaticVariable("ArmCortexA7Cflags", strings.Join(armCpuVariantCflags["cortex-a7"], " "))
-	pctx.StaticVariable("ArmCortexA8Cflags", strings.Join(armCpuVariantCflags["cortex-a8"], " "))
-	pctx.StaticVariable("ArmCortexA15Cflags", strings.Join(armCpuVariantCflags["cortex-a15"], " "))
-	pctx.StaticVariable("ArmCortexA53Cflags", strings.Join(armCpuVariantCflags["cortex-a53"], " "))
-	pctx.StaticVariable("ArmCortexA55Cflags", strings.Join(armCpuVariantCflags["cortex-a55"], " "))
-	pctx.StaticVariable("ArmKraitCflags", strings.Join(armCpuVariantCflags["krait"], " "))
-	pctx.StaticVariable("ArmKryoCflags", strings.Join(armCpuVariantCflags["kryo"], " "))
-
 	// Clang cflags
 	pctx.StaticVariable("ArmToolchainClangCflags", strings.Join(ClangFilterUnknownCflags(armToolchainCflags), " "))
 	pctx.StaticVariable("ArmClangCflags", strings.Join(ClangFilterUnknownCflags(armCflags), " "))
@@ -256,30 +219,6 @@
 }
 
 var (
-	armArchVariantCflagsVar = map[string]string{
-		"armv7-a":      "${config.ArmArmv7ACflags}",
-		"armv7-a-neon": "${config.ArmArmv7ANeonCflags}",
-		"armv8-a":      "${config.ArmArmv8ACflags}",
-	}
-
-	armCpuVariantCflagsVar = map[string]string{
-		"":               "${config.ArmGenericCflags}",
-		"cortex-a7":      "${config.ArmCortexA7Cflags}",
-		"cortex-a8":      "${config.ArmCortexA8Cflags}",
-		"cortex-a15":     "${config.ArmCortexA15Cflags}",
-		"cortex-a53":     "${config.ArmCortexA53Cflags}",
-		"cortex-a53.a57": "${config.ArmCortexA53Cflags}",
-		"cortex-a55":     "${config.ArmCortexA55Cflags}",
-		"cortex-a72":     "${config.ArmCortexA53Cflags}",
-		"cortex-a73":     "${config.ArmCortexA53Cflags}",
-		"cortex-a75":     "${config.ArmCortexA55Cflags}",
-		"krait":          "${config.ArmKraitCflags}",
-		"kryo":           "${config.ArmKryoCflags}",
-		"exynos-m1":      "${config.ArmCortexA53Cflags}",
-		"exynos-m2":      "${config.ArmCortexA53Cflags}",
-		"denver":         "${config.ArmCortexA15Cflags}",
-	}
-
 	armClangArchVariantCflagsVar = map[string]string{
 		"armv7-a":      "${config.ArmClangArmv7ACflags}",
 		"armv7-a-neon": "${config.ArmClangArmv7ANeonCflags}",
@@ -307,9 +246,9 @@
 
 type toolchainArm struct {
 	toolchain32Bit
-	ldflags                               string
-	lldflags                              string
-	toolchainCflags, toolchainClangCflags string
+	ldflags              string
+	lldflags             string
+	toolchainClangCflags string
 }
 
 func (t *toolchainArm) Name() string {
@@ -328,22 +267,6 @@
 	return armGccVersion
 }
 
-func (t *toolchainArm) ToolchainCflags() string {
-	return t.toolchainCflags
-}
-
-func (t *toolchainArm) Cflags() string {
-	return "${config.ArmCflags}"
-}
-
-func (t *toolchainArm) Cppflags() string {
-	return "${config.ArmCppflags}"
-}
-
-func (t *toolchainArm) Ldflags() string {
-	return t.ldflags
-}
-
 func (t *toolchainArm) IncludeFlags() string {
 	return "${config.ArmIncludeFlags}"
 }
@@ -395,16 +318,11 @@
 
 func armToolchainFactory(arch android.Arch) Toolchain {
 	var fixCortexA8 string
-	toolchainCflags := make([]string, 2, 3)
 	toolchainClangCflags := make([]string, 2, 3)
 
-	toolchainCflags[0] = "${config.ArmToolchainCflags}"
-	toolchainCflags[1] = armArchVariantCflagsVar[arch.ArchVariant]
 	toolchainClangCflags[0] = "${config.ArmToolchainClangCflags}"
 	toolchainClangCflags[1] = armClangArchVariantCflagsVar[arch.ArchVariant]
 
-	toolchainCflags = append(toolchainCflags,
-		variantOrDefault(armCpuVariantCflagsVar, arch.CpuVariant))
 	toolchainClangCflags = append(toolchainClangCflags,
 		variantOrDefault(armClangCpuVariantCflagsVar, arch.CpuVariant))
 
@@ -426,7 +344,6 @@
 	}
 
 	return &toolchainArm{
-		toolchainCflags: strings.Join(toolchainCflags, " "),
 		ldflags: strings.Join([]string{
 			"${config.ArmLdflags}",
 			fixCortexA8,
diff --git a/cc/config/global.go b/cc/config/global.go
index 8a3d545..29dca9f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -15,7 +15,6 @@
 package config
 
 import (
-	"fmt"
 	"runtime"
 	"strings"
 
@@ -250,10 +249,3 @@
 		"-isystem bionic/libc/kernel/android/uapi",
 	}, " ")
 }
-
-func replaceFirst(slice []string, from, to string) {
-	if slice[0] != from {
-		panic(fmt.Errorf("Expected %q, found %q", from, to))
-	}
-	slice[0] = to
-}
diff --git a/cc/config/mips64_device.go b/cc/config/mips64_device.go
index 0c4640b..561d8d6 100644
--- a/cc/config/mips64_device.go
+++ b/cc/config/mips64_device.go
@@ -69,9 +69,6 @@
 	pctx.SourcePathVariable("Mips64GccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mips64GccVersion}")
 
-	pctx.StaticVariable("Mips64Cflags", strings.Join(mips64Cflags, " "))
-	pctx.StaticVariable("Mips64Ldflags", strings.Join(mips64Ldflags, " "))
-	pctx.StaticVariable("Mips64Cppflags", strings.Join(mips64Cppflags, " "))
 	pctx.StaticVariable("Mips64IncludeFlags", bionicHeaders("mips"))
 
 	// Clang cflags
@@ -83,7 +80,6 @@
 
 	// Architecture variant cflags
 	for variant, cflags := range mips64ArchVariantCflags {
-		pctx.StaticVariable("Mips64"+variant+"VariantCflags", strings.Join(cflags, " "))
 		pctx.StaticVariable("Mips64"+variant+"VariantClangCflags",
 			strings.Join(ClangFilterUnknownCflags(cflags), " "))
 	}
@@ -91,8 +87,8 @@
 
 type toolchainMips64 struct {
 	toolchain64Bit
-	cflags, clangCflags                   string
-	toolchainCflags, toolchainClangCflags string
+	clangCflags          string
+	toolchainClangCflags string
 }
 
 func (t *toolchainMips64) Name() string {
@@ -111,22 +107,6 @@
 	return mips64GccVersion
 }
 
-func (t *toolchainMips64) ToolchainCflags() string {
-	return t.toolchainCflags
-}
-
-func (t *toolchainMips64) Cflags() string {
-	return t.cflags
-}
-
-func (t *toolchainMips64) Cppflags() string {
-	return "${config.Mips64Cppflags}"
-}
-
-func (t *toolchainMips64) Ldflags() string {
-	return "${config.Mips64Ldflags}"
-}
-
 func (t *toolchainMips64) IncludeFlags() string {
 	return "${config.Mips64IncludeFlags}"
 }
@@ -166,9 +146,7 @@
 
 func mips64ToolchainFactory(arch android.Arch) Toolchain {
 	return &toolchainMips64{
-		cflags:               "${config.Mips64Cflags}",
 		clangCflags:          "${config.Mips64ClangCflags}",
-		toolchainCflags:      "${config.Mips64" + arch.ArchVariant + "VariantCflags}",
 		toolchainClangCflags: "${config.Mips64" + arch.ArchVariant + "VariantClangCflags}",
 	}
 }
diff --git a/cc/config/mips_device.go b/cc/config/mips_device.go
index eb44fd5..8cd35b3 100644
--- a/cc/config/mips_device.go
+++ b/cc/config/mips_device.go
@@ -111,9 +111,6 @@
 		"prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mipsGccVersion}")
 
 	pctx.StaticVariable("MipsToolchainLdflags", strings.Join(mipsToolchainLdflags, " "))
-	pctx.StaticVariable("MipsCflags", strings.Join(mipsCflags, " "))
-	pctx.StaticVariable("MipsLdflags", strings.Join(mipsLdflags, " "))
-	pctx.StaticVariable("MipsCppflags", strings.Join(mipsCppflags, " "))
 	pctx.StaticVariable("MipsIncludeFlags", bionicHeaders("mips"))
 
 	// Clang cflags
@@ -125,7 +122,6 @@
 
 	// Architecture variant cflags
 	for variant, cflags := range mipsArchVariantCflags {
-		pctx.StaticVariable("Mips"+variant+"VariantCflags", strings.Join(cflags, " "))
 		pctx.StaticVariable("Mips"+variant+"VariantClangCflags",
 			strings.Join(ClangFilterUnknownCflags(cflags), " "))
 	}
@@ -133,8 +129,8 @@
 
 type toolchainMips struct {
 	toolchain32Bit
-	cflags, clangCflags                   string
-	toolchainCflags, toolchainClangCflags string
+	clangCflags          string
+	toolchainClangCflags string
 }
 
 func (t *toolchainMips) Name() string {
@@ -153,26 +149,6 @@
 	return mipsGccVersion
 }
 
-func (t *toolchainMips) ToolchainLdflags() string {
-	return "${config.MipsToolchainLdflags}"
-}
-
-func (t *toolchainMips) ToolchainCflags() string {
-	return t.toolchainCflags
-}
-
-func (t *toolchainMips) Cflags() string {
-	return t.cflags
-}
-
-func (t *toolchainMips) Cppflags() string {
-	return "${config.MipsCppflags}"
-}
-
-func (t *toolchainMips) Ldflags() string {
-	return "${config.MipsLdflags}"
-}
-
 func (t *toolchainMips) IncludeFlags() string {
 	return "${config.MipsIncludeFlags}"
 }
@@ -216,9 +192,7 @@
 
 func mipsToolchainFactory(arch android.Arch) Toolchain {
 	return &toolchainMips{
-		cflags:               "${config.MipsCflags}",
 		clangCflags:          "${config.MipsClangCflags}",
-		toolchainCflags:      "${config.Mips" + arch.ArchVariant + "VariantCflags}",
 		toolchainClangCflags: "${config.Mips" + arch.ArchVariant + "VariantClangCflags}",
 	}
 }
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 0b9f4ed..997bca6 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -162,18 +162,6 @@
 	return false
 }
 
-func copyVariantFlags(m map[string][]string) map[string][]string {
-	ret := make(map[string][]string, len(m))
-	for k, v := range m {
-		l := make([]string, len(m[k]))
-		for i := range m[k] {
-			l[i] = v[i]
-		}
-		ret[k] = l
-	}
-	return ret
-}
-
 func variantOrDefault(variants map[string]string, choice string) string {
 	if ret, ok := variants[choice]; ok {
 		return ret
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 5e2dc49..ff8a6da 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -125,10 +125,8 @@
 	pctx.StaticVariable("X86_64ToolchainCflags", "-m64")
 	pctx.StaticVariable("X86_64ToolchainLdflags", "-m64")
 
-	pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " "))
 	pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
 	pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Lldflags, " "))
-	pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
 	pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
@@ -144,7 +142,6 @@
 
 	// Architecture variant cflags
 	for variant, cflags := range x86_64ArchVariantCflags {
-		pctx.StaticVariable("X86_64"+variant+"VariantCflags", strings.Join(cflags, " "))
 		pctx.StaticVariable("X86_64"+variant+"VariantClangCflags",
 			strings.Join(ClangFilterUnknownCflags(cflags), " "))
 	}
@@ -152,7 +149,7 @@
 
 type toolchainX86_64 struct {
 	toolchain64Bit
-	toolchainCflags, toolchainClangCflags string
+	toolchainClangCflags string
 }
 
 func (t *toolchainX86_64) Name() string {
@@ -171,26 +168,6 @@
 	return x86_64GccVersion
 }
 
-func (t *toolchainX86_64) ToolchainLdflags() string {
-	return "${config.X86_64ToolchainLdflags}"
-}
-
-func (t *toolchainX86_64) ToolchainCflags() string {
-	return t.toolchainCflags
-}
-
-func (t *toolchainX86_64) Cflags() string {
-	return "${config.X86_64Cflags}"
-}
-
-func (t *toolchainX86_64) Cppflags() string {
-	return "${config.X86_64Cppflags}"
-}
-
-func (t *toolchainX86_64) Ldflags() string {
-	return "${config.X86_64Ldflags}"
-}
-
 func (t *toolchainX86_64) IncludeFlags() string {
 	return "${config.X86_64IncludeFlags}"
 }
@@ -232,23 +209,16 @@
 }
 
 func x86_64ToolchainFactory(arch android.Arch) Toolchain {
-	toolchainCflags := []string{
-		"${config.X86_64ToolchainCflags}",
-		"${config.X86_64" + arch.ArchVariant + "VariantCflags}",
-	}
-
 	toolchainClangCflags := []string{
 		"${config.X86_64ToolchainCflags}",
 		"${config.X86_64" + arch.ArchVariant + "VariantClangCflags}",
 	}
 
 	for _, feature := range arch.ArchFeatures {
-		toolchainCflags = append(toolchainCflags, x86_64ArchFeatureCflags[feature]...)
 		toolchainClangCflags = append(toolchainClangCflags, x86_64ArchFeatureCflags[feature]...)
 	}
 
 	return &toolchainX86_64{
-		toolchainCflags:      strings.Join(toolchainCflags, " "),
 		toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
 	}
 }
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 694137d..09632db 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -117,9 +117,6 @@
 
 	pctx.StaticVariable("DarwinGccTriple", "i686-apple-darwin11")
 
-	pctx.StaticVariable("DarwinCflags", strings.Join(darwinCflags, " "))
-	pctx.StaticVariable("DarwinLdflags", strings.Join(darwinLdflags, " "))
-
 	pctx.StaticVariable("DarwinClangCflags", strings.Join(darwinClangCflags, " "))
 	pctx.StaticVariable("DarwinClangLdflags", strings.Join(darwinClangLdflags, " "))
 	pctx.StaticVariable("DarwinClangLldflags", strings.Join(darwinClangLldflags, " "))
@@ -182,18 +179,6 @@
 	return darwinGccVersion
 }
 
-func (t *toolchainDarwin) Cflags() string {
-	return "${config.DarwinCflags}"
-}
-
-func (t *toolchainDarwin) Cppflags() string {
-	return ""
-}
-
-func (t *toolchainDarwin) Ldflags() string {
-	return "${config.DarwinLdflags}"
-}
-
 func (t *toolchainDarwin) IncludeFlags() string {
 	return ""
 }
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index ffdf8ea..fc0b1d8 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -149,10 +149,8 @@
 	pctx.StaticVariable("X86ToolchainCflags", "-m32")
 	pctx.StaticVariable("X86ToolchainLdflags", "-m32")
 
-	pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
 	pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
 	pctx.StaticVariable("X86Lldflags", strings.Join(x86Lldflags, " "))
-	pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
 	pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
@@ -168,7 +166,6 @@
 
 	// Architecture variant cflags
 	for variant, cflags := range x86ArchVariantCflags {
-		pctx.StaticVariable("X86"+variant+"VariantCflags", strings.Join(cflags, " "))
 		pctx.StaticVariable("X86"+variant+"VariantClangCflags",
 			strings.Join(ClangFilterUnknownCflags(cflags), " "))
 	}
@@ -176,7 +173,7 @@
 
 type toolchainX86 struct {
 	toolchain32Bit
-	toolchainCflags, toolchainClangCflags string
+	toolchainClangCflags string
 }
 
 func (t *toolchainX86) Name() string {
@@ -195,26 +192,6 @@
 	return x86GccVersion
 }
 
-func (t *toolchainX86) ToolchainLdflags() string {
-	return "${config.X86ToolchainLdflags}"
-}
-
-func (t *toolchainX86) ToolchainCflags() string {
-	return t.toolchainCflags
-}
-
-func (t *toolchainX86) Cflags() string {
-	return "${config.X86Cflags}"
-}
-
-func (t *toolchainX86) Cppflags() string {
-	return "${config.X86Cppflags}"
-}
-
-func (t *toolchainX86) Ldflags() string {
-	return "${config.X86Ldflags}"
-}
-
 func (t *toolchainX86) IncludeFlags() string {
 	return "${config.X86IncludeFlags}"
 }
@@ -256,23 +233,16 @@
 }
 
 func x86ToolchainFactory(arch android.Arch) Toolchain {
-	toolchainCflags := []string{
-		"${config.X86ToolchainCflags}",
-		"${config.X86" + arch.ArchVariant + "VariantCflags}",
-	}
-
 	toolchainClangCflags := []string{
 		"${config.X86ToolchainCflags}",
 		"${config.X86" + arch.ArchVariant + "VariantClangCflags}",
 	}
 
 	for _, feature := range arch.ArchFeatures {
-		toolchainCflags = append(toolchainCflags, x86ArchFeatureCflags[feature]...)
 		toolchainClangCflags = append(toolchainClangCflags, x86ArchFeatureCflags[feature]...)
 	}
 
 	return &toolchainX86{
-		toolchainCflags:      strings.Join(toolchainCflags, " "),
 		toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
 	}
 }
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index a9fb1f6..8a12523 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -96,18 +96,6 @@
 	return "4.9"
 }
 
-func (t *toolchainLinuxBionic) Cflags() string {
-	return ""
-}
-
-func (t *toolchainLinuxBionic) Cppflags() string {
-	return ""
-}
-
-func (t *toolchainLinuxBionic) Ldflags() string {
-	return ""
-}
-
 func (t *toolchainLinuxBionic) IncludeFlags() string {
 	return "${config.LinuxBionicIncludeFlags}"
 }
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 3965cd7..8da21b3 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -122,19 +122,10 @@
 
 	pctx.StaticVariable("LinuxGccTriple", "x86_64-linux")
 
-	pctx.StaticVariable("LinuxCflags", strings.Join(linuxCflags, " "))
-	pctx.StaticVariable("LinuxLdflags", strings.Join(linuxLdflags, " "))
-
 	pctx.StaticVariable("LinuxClangCflags", strings.Join(linuxClangCflags, " "))
 	pctx.StaticVariable("LinuxClangLdflags", strings.Join(linuxClangLdflags, " "))
 	pctx.StaticVariable("LinuxClangLldflags", strings.Join(linuxClangLldflags, " "))
 
-	// Extended cflags
-	pctx.StaticVariable("LinuxX86Cflags", strings.Join(linuxX86Cflags, " "))
-	pctx.StaticVariable("LinuxX8664Cflags", strings.Join(linuxX8664Cflags, " "))
-	pctx.StaticVariable("LinuxX86Ldflags", strings.Join(linuxX86Ldflags, " "))
-	pctx.StaticVariable("LinuxX8664Ldflags", strings.Join(linuxX8664Ldflags, " "))
-
 	pctx.StaticVariable("LinuxX86ClangCflags",
 		strings.Join(ClangFilterUnknownCflags(linuxX86Cflags), " "))
 	pctx.StaticVariable("LinuxX8664ClangCflags",
@@ -182,26 +173,6 @@
 	return linuxGccVersion
 }
 
-func (t *toolchainLinuxX86) Cflags() string {
-	return "${config.LinuxCflags} ${config.LinuxX86Cflags}"
-}
-
-func (t *toolchainLinuxX8664) Cflags() string {
-	return "${config.LinuxCflags} ${config.LinuxX8664Cflags}"
-}
-
-func (t *toolchainLinux) Cppflags() string {
-	return ""
-}
-
-func (t *toolchainLinuxX86) Ldflags() string {
-	return "${config.LinuxLdflags} ${config.LinuxX86Ldflags}"
-}
-
-func (t *toolchainLinuxX8664) Ldflags() string {
-	return "${config.LinuxLdflags} ${config.LinuxX8664Ldflags}"
-}
-
 func (t *toolchainLinux) IncludeFlags() string {
 	return ""
 }
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 9573174..988ba03 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -137,19 +137,11 @@
 
 	pctx.StaticVariable("WindowsGccTriple", "x86_64-w64-mingw32")
 
-	pctx.StaticVariable("WindowsCflags", strings.Join(windowsCflags, " "))
-	pctx.StaticVariable("WindowsLdflags", strings.Join(windowsLdflags, " "))
-
 	pctx.StaticVariable("WindowsClangCflags", strings.Join(windowsClangCflags, " "))
 	pctx.StaticVariable("WindowsClangLdflags", strings.Join(windowsClangLdflags, " "))
 	pctx.StaticVariable("WindowsClangLldflags", strings.Join(windowsClangLldflags, " "))
 	pctx.StaticVariable("WindowsClangCppflags", strings.Join(windowsClangCppflags, " "))
 
-	pctx.StaticVariable("WindowsX86Cflags", strings.Join(windowsX86Cflags, " "))
-	pctx.StaticVariable("WindowsX8664Cflags", strings.Join(windowsX8664Cflags, " "))
-	pctx.StaticVariable("WindowsX86Ldflags", strings.Join(windowsX86Ldflags, " "))
-	pctx.StaticVariable("WindowsX8664Ldflags", strings.Join(windowsX8664Ldflags, " "))
-
 	pctx.StaticVariable("WindowsX86ClangCflags",
 		strings.Join(ClangFilterUnknownCflags(windowsX86Cflags), " "))
 	pctx.StaticVariable("WindowsX8664ClangCflags",
@@ -198,26 +190,6 @@
 	return windowsGccVersion
 }
 
-func (t *toolchainWindowsX86) Cflags() string {
-	return "${config.WindowsCflags} ${config.WindowsX86Cflags}"
-}
-
-func (t *toolchainWindowsX8664) Cflags() string {
-	return "${config.WindowsCflags} ${config.WindowsX8664Cflags}"
-}
-
-func (t *toolchainWindows) Cppflags() string {
-	return ""
-}
-
-func (t *toolchainWindowsX86) Ldflags() string {
-	return "${config.WindowsLdflags} ${config.WindowsX86Ldflags}"
-}
-
-func (t *toolchainWindowsX8664) Ldflags() string {
-	return "${config.WindowsLdflags} ${config.WindowsX8664Ldflags}"
-}
-
 func (t *toolchainWindows) IncludeFlags() string {
 	return "${config.WindowsIncludeFlags}"
 }
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index d3b349c..c4fb3d6 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -41,11 +41,13 @@
 	staticTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
 
 	excludes   multiFlag
+	includes   multiFlag
 	uncompress multiFlag
 )
 
 func init() {
 	flag.Var(&excludes, "x", "exclude a filespec from the output")
+	flag.Var(&includes, "X", "include a filespec in the output that was previously excluded")
 	flag.Var(&uncompress, "0", "convert a filespec to uncompressed in the output")
 }
 
@@ -96,7 +98,7 @@
 	}()
 
 	if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime,
-		flag.Args(), excludes, uncompress); err != nil {
+		flag.Args(), excludes, includes, uncompress); err != nil {
 
 		log.Fatal(err)
 	}
@@ -109,7 +111,7 @@
 }
 
 func zip2zip(reader *zip.Reader, writer *zip.Writer, sortOutput, sortJava, setTime bool,
-	includes, excludes, uncompresses []string) error {
+	args []string, excludes, includes multiFlag, uncompresses []string) error {
 
 	matches := []pair{}
 
@@ -125,14 +127,14 @@
 		}
 	}
 
-	for _, include := range includes {
+	for _, arg := range args {
 		// Reserve escaping for future implementation, so make sure no
 		// one is using \ and expecting a certain behavior.
-		if strings.Contains(include, "\\") {
+		if strings.Contains(arg, "\\") {
 			return fmt.Errorf("\\ characters are not currently supported")
 		}
 
-		input, output := includeSplit(include)
+		input, output := includeSplit(arg)
 
 		var includeMatches []pair
 
@@ -161,7 +163,7 @@
 		matches = append(matches, includeMatches...)
 	}
 
-	if len(includes) == 0 {
+	if len(args) == 0 {
 		// implicitly match everything
 		for _, file := range reader.File {
 			matches = append(matches, pair{file, file.Name, false})
@@ -173,21 +175,18 @@
 	seen := make(map[string]*zip.File)
 
 	for _, match := range matches {
-		// Filter out matches whose original file name matches an exclude filter
-		excluded := false
-		for _, exclude := range excludes {
-			if excludeMatch, err := pathtools.Match(exclude, match.File.Name); err != nil {
+		// Filter out matches whose original file name matches an exclude filter, unless it also matches an
+		// include filter
+		if exclude, err := excludes.Match(match.File.Name); err != nil {
+			return err
+		} else if exclude {
+			if include, err := includes.Match(match.File.Name); err != nil {
 				return err
-			} else if excludeMatch {
-				excluded = true
-				break
+			} else if !include {
+				continue
 			}
 		}
 
-		if excluded {
-			continue
-		}
-
 		// Check for duplicate output names, ignoring ones that come from the same input zip entry.
 		if prev, exists := seen[match.newName]; exists {
 			if prev != match.File {
@@ -256,11 +255,25 @@
 
 type multiFlag []string
 
-func (e *multiFlag) String() string {
-	return strings.Join(*e, " ")
+func (m *multiFlag) String() string {
+	return strings.Join(*m, " ")
 }
 
-func (e *multiFlag) Set(s string) error {
-	*e = append(*e, s)
+func (m *multiFlag) Set(s string) error {
+	*m = append(*m, s)
 	return nil
 }
+
+func (m *multiFlag) Match(s string) (bool, error) {
+	if m == nil {
+		return false, nil
+	}
+	for _, f := range *m {
+		if match, err := pathtools.Match(f, s); err != nil {
+			return false, err
+		} else if match {
+			return true, nil
+		}
+	}
+	return false, nil
+}
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index e032fe6..ae16494 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -31,6 +31,7 @@
 	sortJava     bool
 	args         []string
 	excludes     []string
+	includes     []string
 	uncompresses []string
 
 	outputFiles []string
@@ -228,7 +229,7 @@
 		},
 	},
 	{
-		name: "excludes with include",
+		name: "excludes with args",
 
 		inputFiles: []string{
 			"a/a",
@@ -242,6 +243,31 @@
 		},
 	},
 	{
+		name: "excludes over args",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     []string{"a/a"},
+		excludes: []string{"a/*"},
+
+		outputFiles: nil,
+	},
+	{
+		name: "excludes with includes",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     nil,
+		excludes: []string{"a/*"},
+		includes: []string{"a/b"},
+
+		outputFiles: []string{"a/b"},
+	},
+	{
 		name: "excludes with glob",
 
 		inputFiles: []string{
@@ -358,7 +384,7 @@
 
 			outputWriter := zip.NewWriter(outputBuf)
 			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false,
-				testCase.args, testCase.excludes, testCase.uncompresses)
+				testCase.args, testCase.excludes, testCase.includes, testCase.uncompresses)
 			if errorString(testCase.err) != errorString(err) {
 				t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
 			}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f19e2aa..2824e49 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -52,10 +52,9 @@
 
 type hostToolDependencyTag struct {
 	blueprint.BaseDependencyTag
+	label string
 }
 
-var hostToolDepTag hostToolDependencyTag
-
 type generatorProperties struct {
 	// The command to run on one or more input files. Cmd supports substitution of a few variables
 	// (the actual substitution is implemented in GenerateAndroidBuildActions below)
@@ -63,7 +62,7 @@
 	// Available variables for substitution:
 	//
 	//  $(location): the path to the first entry in tools or tool_files
-	//  $(location <label>): the path to the tool or tool_file with name <label>
+	//  $(location <label>): the path to the tool, tool_file, input or output with name <label>
 	//  $(in): one or more input files
 	//  $(out): a single output file
 	//  $(depfile): a file to which dependencies will be written, if the depfile property is set to true
@@ -141,10 +140,14 @@
 	android.ExtractSourcesDeps(ctx, g.properties.Srcs)
 	android.ExtractSourcesDeps(ctx, g.properties.Tool_files)
 	if g, ok := ctx.Module().(*Module); ok {
-		if len(g.properties.Tools) > 0 {
+		for _, tool := range g.properties.Tools {
+			tag := hostToolDependencyTag{label: tool}
+			if m := android.SrcIsModule(tool); m != "" {
+				tool = m
+			}
 			ctx.AddFarVariationDependencies([]blueprint.Variation{
 				{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
-			}, hostToolDepTag, g.properties.Tools...)
+			}, tag, tool)
 		}
 	}
 }
@@ -159,12 +162,25 @@
 		g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, ""))
 	}
 
-	tools := map[string]android.Path{}
+	locationLabels := map[string][]string{}
+	firstLabel := ""
+
+	addLocationLabel := func(label string, paths []string) {
+		if firstLabel == "" {
+			firstLabel = label
+		}
+		if _, exists := locationLabels[label]; !exists {
+			locationLabels[label] = paths
+		} else {
+			ctx.ModuleErrorf("multiple labels for %q, %q and %q",
+				label, strings.Join(locationLabels[label], " "), strings.Join(paths, " "))
+		}
+	}
 
 	if len(g.properties.Tools) > 0 {
 		ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-			switch ctx.OtherModuleDependencyTag(module) {
-			case hostToolDepTag:
+			switch tag := ctx.OtherModuleDependencyTag(module).(type) {
+			case hostToolDependencyTag:
 				tool := ctx.OtherModuleName(module)
 				var path android.OptionalPath
 
@@ -192,11 +208,7 @@
 
 				if path.Valid() {
 					g.deps = append(g.deps, path.Path())
-					if _, exists := tools[tool]; !exists {
-						tools[tool] = path.Path()
-					} else {
-						ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], path.Path().String())
-					}
+					addLocationLabel(tag.label, []string{path.Path().String()})
 				} else {
 					ctx.ModuleErrorf("host tool %q missing output file", tool)
 				}
@@ -208,21 +220,27 @@
 		return
 	}
 
-	toolFiles := ctx.ExpandSources(g.properties.Tool_files, nil)
-	for _, tool := range toolFiles {
-		g.deps = append(g.deps, tool)
-		if _, exists := tools[tool.Rel()]; !exists {
-			tools[tool.Rel()] = tool
-		} else {
-			ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool.Rel()], tool.Rel())
-		}
+	for _, toolFile := range g.properties.Tool_files {
+		paths := ctx.ExpandSources([]string{toolFile}, nil)
+		g.deps = append(g.deps, paths...)
+		addLocationLabel(toolFile, paths.Strings())
+	}
+
+	var srcFiles android.Paths
+	for _, in := range g.properties.Srcs {
+		paths := ctx.ExpandSources([]string{in}, nil)
+		srcFiles = append(srcFiles, paths...)
+		addLocationLabel(in, paths.Strings())
+	}
+
+	task := g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles)
+
+	for _, out := range task.out {
+		addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
 	}
 
 	referencedDepfile := false
 
-	srcFiles := ctx.ExpandSources(g.properties.Srcs, nil)
-	task := g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles)
-
 	rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
 		// report the error directly without returning an error to android.Expand to catch multiple errors in a
 		// single run
@@ -233,13 +251,17 @@
 
 		switch name {
 		case "location":
-			if len(g.properties.Tools) == 0 && len(toolFiles) == 0 {
+			if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
 				return reportError("at least one `tools` or `tool_files` is required if $(location) is used")
-			} else if len(g.properties.Tools) > 0 {
-				return tools[g.properties.Tools[0]].String(), nil
-			} else {
-				return tools[toolFiles[0].Rel()].String(), nil
 			}
+			paths := locationLabels[firstLabel]
+			if len(paths) == 0 {
+				return reportError("default label %q has no files", firstLabel)
+			} else if len(paths) > 1 {
+				return reportError("default label %q has multiple files, use $(locations %s) to reference it",
+					firstLabel, firstLabel)
+			}
+			return locationLabels[firstLabel][0], nil
 		case "in":
 			return "${in}", nil
 		case "out":
@@ -255,13 +277,30 @@
 		default:
 			if strings.HasPrefix(name, "location ") {
 				label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
-				if tool, ok := tools[label]; ok {
-					return tool.String(), nil
+				if paths, ok := locationLabels[label]; ok {
+					if len(paths) == 0 {
+						return reportError("label %q has no files", label)
+					} else if len(paths) > 1 {
+						return reportError("label %q has multiple files, use $(locations %s) to reference it",
+							label, label)
+					}
+					return paths[0], nil
 				} else {
 					return reportError("unknown location label %q", label)
 				}
+			} else if strings.HasPrefix(name, "locations ") {
+				label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
+				if paths, ok := locationLabels[label]; ok {
+					if len(paths) == 0 {
+						return reportError("label %q has no files", label)
+					}
+					return strings.Join(paths, " "), nil
+				} else {
+					return reportError("unknown locations label %q", label)
+				}
+			} else {
+				return reportError("unknown variable '$(%s)'", name)
 			}
-			return reportError("unknown variable '$(%s)'", name)
 		}
 	})
 
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 0d690d4..7e16ce1 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -133,6 +133,15 @@
 			expect: "out/tool > __SBOX_OUT_FILES__",
 		},
 		{
+			name: "empty location tool2",
+			prop: `
+				tools: [":tool"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			expect: "out/tool > __SBOX_OUT_FILES__",
+		},
+		{
 			name: "empty location tool file",
 			prop: `
 				tool_files: ["tool_file1"],
@@ -170,6 +179,15 @@
 			expect: "out/tool > __SBOX_OUT_FILES__",
 		},
 		{
+			name: "tool2",
+			prop: `
+				tools: [":tool"],
+				out: ["out"],
+				cmd: "$(location :tool) > $(out)",
+			`,
+			expect: "out/tool > __SBOX_OUT_FILES__",
+		},
+		{
 			name: "tool file",
 			prop: `
 				tool_files: ["tool_file1"],
@@ -183,7 +201,7 @@
 			prop: `
 				tool_files: [":1tool_file"],
 				out: ["out"],
-				cmd: "$(location tool_file1) > $(out)",
+				cmd: "$(location :1tool_file) > $(out)",
 			`,
 			expect: "tool_file1 > __SBOX_OUT_FILES__",
 		},
@@ -192,7 +210,7 @@
 			prop: `
 				tool_files: [":tool_files"],
 				out: ["out"],
-				cmd: "$(location tool_file1) $(location tool_file2) > $(out)",
+				cmd: "$(locations :tool_files) > $(out)",
 			`,
 			expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
 		},
@@ -233,6 +251,42 @@
 			expect: "cat ${in} > __SBOX_OUT_FILES__",
 		},
 		{
+			name: "location in1",
+			prop: `
+				srcs: ["in1"],
+				out: ["out"],
+				cmd: "cat $(location in1) > $(out)",
+			`,
+			expect: "cat in1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "location in1 fg",
+			prop: `
+				srcs: [":1in"],
+				out: ["out"],
+				cmd: "cat $(location :1in) > $(out)",
+			`,
+			expect: "cat in1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "location ins",
+			prop: `
+				srcs: ["in1", "in2"],
+				out: ["out"],
+				cmd: "cat $(location in1) > $(out)",
+			`,
+			expect: "cat in1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "location ins fg",
+			prop: `
+				srcs: [":ins"],
+				out: ["out"],
+				cmd: "cat $(locations :ins) > $(out)",
+			`,
+			expect: "cat in1 in2 > __SBOX_OUT_FILES__",
+		},
+		{
 			name: "outs",
 			prop: `
 				out: ["out", "out2"],
@@ -241,6 +295,14 @@
 			expect: "echo foo > __SBOX_OUT_FILES__",
 		},
 		{
+			name: "location out",
+			prop: `
+				out: ["out", "out2"],
+				cmd: "echo foo > $(location out2)",
+			`,
+			expect: "echo foo > __SBOX_OUT_DIR__/out2",
+		},
+		{
 			name: "depfile",
 			prop: `
 				out: ["out"],
@@ -267,6 +329,24 @@
 			err: "at least one `tools` or `tool_files` is required if $(location) is used",
 		},
 		{
+			name: "error empty location no files",
+			prop: `
+				tool_files: [":empty"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			err: `default label ":empty" has no files`,
+		},
+		{
+			name: "error empty location multiple files",
+			prop: `
+				tool_files: [":tool_files"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			err: `default label ":tool_files" has multiple files`,
+		},
+		{
 			name: "error location",
 			prop: `
 				out: ["out"],
@@ -275,6 +355,41 @@
 			err: `unknown location label "missing"`,
 		},
 		{
+			name: "error locations",
+			prop: `
+					out: ["out"],
+					cmd: "echo foo > $(locations missing)",
+			`,
+			err: `unknown locations label "missing"`,
+		},
+		{
+			name: "error location no files",
+			prop: `
+					out: ["out"],
+					srcs: [":empty"],
+					cmd: "echo $(location :empty) > $(out)",
+			`,
+			err: `label ":empty" has no files`,
+		},
+		{
+			name: "error locations no files",
+			prop: `
+					out: ["out"],
+					srcs: [":empty"],
+					cmd: "echo $(locations :empty) > $(out)",
+			`,
+			err: `label ":empty" has no files`,
+		},
+		{
+			name: "error location multiple files",
+			prop: `
+					out: ["out"],
+					srcs: [":ins"],
+					cmd: "echo $(location :ins) > $(out)",
+			`,
+			err: `label ":ins" has multiple files`,
+		},
+		{
 			name: "error variable",
 			prop: `
 					out: ["out"],
diff --git a/java/androidmk.go b/java/androidmk.go
index 313a144..359594c 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -243,6 +243,10 @@
 				if len(app.appProperties.Overrides) > 0 {
 					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES := "+strings.Join(app.appProperties.Overrides, " "))
 				}
+
+				for _, jniLib := range app.installJniLibs {
+					fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), "+=", jniLib.name)
+				}
 			},
 		},
 	}
@@ -267,6 +271,21 @@
 	return data
 }
 
+func (a *AndroidTestHelperApp) AndroidMk() android.AndroidMkData {
+	data := a.AndroidApp.AndroidMk()
+	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
+		fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
+		if len(a.appTestHelperAppProperties.Test_suites) > 0 {
+			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+				strings.Join(a.appTestHelperAppProperties.Test_suites, " "))
+		} else {
+			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
+		}
+	})
+
+	return data
+}
+
 func (a *AndroidLibrary) AndroidMk() android.AndroidMkData {
 	data := a.Library.AndroidMk()
 
diff --git a/java/app.go b/java/app.go
index dc5296d..d21b62a 100644
--- a/java/app.go
+++ b/java/app.go
@@ -19,26 +19,30 @@
 import (
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/tradefed"
 )
 
 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)
 }
 
 // AndroidManifest.xml merging
 // package splits
 
 type appProperties struct {
-	// path to a certificate, or the name of a certificate in the default
-	// certificate directory, or blank to use the default product certificate
+	// 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
 
-	// paths to extra certificates to sign the apk with
+	// Names of extra android_app_certificate modules to sign the apk with in the form ":module".
 	Additional_certificates []string
 
 	// If set, create package-export.apk, which other packages can
@@ -59,6 +63,11 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
+
+	// list of native libraries that will be provided in or alongside the resulting jar
+	Jni_libs []string `android:"arch_variant"`
+
+	EmbedJNI bool `blueprint:"mutated"`
 }
 
 type AndroidApp struct {
@@ -70,6 +79,8 @@
 	appProperties appProperties
 
 	extraLinkFlags []string
+
+	installJniLibs []jniLib
 }
 
 func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
@@ -92,9 +103,36 @@
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
+
 	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
 		a.aapt.deps(ctx, sdkContext(a))
 	}
+
+	for _, jniTarget := range ctx.MultiTargets() {
+		variation := []blueprint.Variation{
+			{Mutator: "arch", Variation: jniTarget.String()},
+			{Mutator: "link", Variation: "shared"},
+		}
+		tag := &jniDependencyTag{
+			target: jniTarget,
+		}
+		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+	}
+
+	cert := android.SrcIsModule(String(a.appProperties.Certificate))
+	if cert != "" {
+		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+	}
+
+	for _, cert := range a.appProperties.Additional_certificates {
+		cert = android.SrcIsModule(cert)
+		if cert != "" {
+			ctx.AddDependency(ctx.Module(), certificateTag, cert)
+		} else {
+			ctx.PropertyErrorf("additional_certificates",
+				`must be names of android_app_certificate modules in the form ":module"`)
+		}
+	}
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -150,35 +188,45 @@
 		a.Module.compile(ctx, a.aaptSrcJar)
 	}
 
-	c := String(a.appProperties.Certificate)
-	switch {
-	case c == "":
-		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		a.certificate = certificate{pem, key}
-	case strings.ContainsRune(c, '/'):
-		a.certificate = certificate{
-			android.PathForSource(ctx, c+".x509.pem"),
-			android.PathForSource(ctx, c+".pk8"),
-		}
-	default:
-		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		a.certificate = certificate{
-			defaultDir.Join(ctx, c+".x509.pem"),
-			defaultDir.Join(ctx, c+".pk8"),
-		}
-	}
-
-	certificates := []certificate{a.certificate}
-	for _, c := range a.appProperties.Additional_certificates {
-		certificates = append(certificates, certificate{
-			android.PathForSource(ctx, c+".x509.pem"),
-			android.PathForSource(ctx, c+".pk8"),
-		})
-	}
-
 	packageFile := android.PathForModuleOut(ctx, "package.apk")
 
-	CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
+	var certificates []certificate
+
+	var jniJarFile android.WritablePath
+	jniLibs, certificateDeps := a.collectAppDeps(ctx)
+	if len(jniLibs) > 0 {
+		embedJni := ctx.Config().UnbundledBuild() || a.appProperties.EmbedJNI
+		if embedJni {
+			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
+			TransformJniLibsToJar(ctx, jniJarFile, jniLibs)
+		} else {
+			a.installJniLibs = jniLibs
+		}
+	}
+
+	if ctx.Failed() {
+		return
+	}
+
+	cert := String(a.appProperties.Certificate)
+	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"),
+		}
+	} else {
+		pem, key := ctx.Config().DefaultAppCertificate(ctx)
+		a.certificate = certificate{pem, key}
+	}
+
+	certificates = append([]certificate{a.certificate}, certificateDeps...)
+
+	CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, a.outputFile, certificates)
 
 	a.outputFile = packageFile
 
@@ -192,6 +240,42 @@
 	}
 }
 
+func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []certificate) {
+	var jniLibs []jniLib
+	var certificates []certificate
+
+	ctx.VisitDirectDeps(func(module android.Module) {
+		otherName := ctx.OtherModuleName(module)
+		tag := ctx.OtherModuleDependencyTag(module)
+
+		if jniTag, ok := tag.(*jniDependencyTag); ok {
+			if dep, ok := module.(*cc.Module); ok {
+				lib := dep.OutputFile()
+				if lib.Valid() {
+					jniLibs = append(jniLibs, jniLib{
+						name:   ctx.OtherModuleName(module),
+						path:   lib.Path(),
+						target: jniTag.target,
+					})
+				} else {
+					ctx.ModuleErrorf("dependency %q missing output file", otherName)
+				}
+			} else {
+				ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
+
+			}
+		} else if tag == certificateTag {
+			if dep, ok := module.(*AndroidAppCertificate); ok {
+				certificates = append(certificates, dep.certificate)
+			} else {
+				ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
+			}
+		}
+	})
+
+	return jniLibs, certificates
+}
+
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
@@ -212,7 +296,9 @@
 		return class == android.Device && ctx.Config().DevicePrefer32BitApps()
 	})
 
-	InitJavaModule(module, android.DeviceSupported)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+
 	return module
 }
 
@@ -258,6 +344,7 @@
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
+	module.appProperties.EmbedJNI = true
 
 	module.AddProperties(
 		&module.Module.properties,
@@ -268,6 +355,69 @@
 		&module.appTestProperties,
 		&module.testProperties)
 
-	InitJavaModule(module, android.DeviceSupported)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
 	return module
 }
+
+type appTestHelperAppProperties struct {
+	// list of compatibility suites (for example "cts", "vts") that the module should be
+	// installed into.
+	Test_suites []string `android:"arch_variant"`
+}
+
+type AndroidTestHelperApp struct {
+	AndroidApp
+
+	appTestHelperAppProperties appTestHelperAppProperties
+}
+
+func AndroidTestHelperAppFactory() android.Module {
+	module := &AndroidTestHelperApp{}
+
+	module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
+
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+	module.appProperties.EmbedJNI = true
+
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.deviceProperties,
+		&module.Module.protoProperties,
+		&module.aaptProperties,
+		&module.appProperties,
+		&module.appTestHelperAppProperties)
+
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
+type AndroidAppCertificate struct {
+	android.ModuleBase
+	properties  AndroidAppCertificateProperties
+	certificate certificate
+}
+
+type AndroidAppCertificateProperties struct {
+	// Name of the certificate files.  Extensions .x509.pem and .pk8 will be added to the name.
+	Certificate *string
+}
+
+func AndroidAppCertificateFactory() android.Module {
+	module := &AndroidAppCertificate{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidModule(module)
+	return module
+}
+
+func (c *AndroidAppCertificate) DepsMutator(ctx android.BottomUpMutatorContext) {
+}
+
+func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	cert := String(c.properties.Certificate)
+	c.certificate = certificate{
+		android.PathForModuleSrc(ctx, cert+".x509.pem"),
+		android.PathForModuleSrc(ctx, cert+".pk8"),
+	}
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index e27b1b7..b9b5f43 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -19,9 +19,11 @@
 // functions.
 
 import (
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -61,16 +63,18 @@
 	})
 
 func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	resJarFile, dexJarFile android.Path, certificates []certificate) {
-
-	// TODO(ccross): JNI libs
+	resJarFile, jniJarFile, dexJarFile android.Path, certificates []certificate) {
 
 	unsignedApk := android.PathForModuleOut(ctx, "unsigned.apk")
 
-	inputs := android.Paths{resJarFile}
+	var inputs android.Paths
 	if dexJarFile != nil {
 		inputs = append(inputs, dexJarFile)
 	}
+	inputs = append(inputs, resJarFile)
+	if jniJarFile != nil {
+		inputs = append(inputs, jniJarFile)
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   combineApk,
@@ -132,3 +136,37 @@
 		},
 	})
 }
+
+func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
+	jniLibs []jniLib) {
+
+	var deps android.Paths
+	jarArgs := []string{
+		"-j", // junk paths, they will be added back with -P arguments
+	}
+
+	if !ctx.Config().UnbundledBuild() {
+		jarArgs = append(jarArgs, "-L 0")
+	}
+
+	for _, j := range jniLibs {
+		deps = append(deps, j.path)
+		jarArgs = append(jarArgs,
+			"-P "+targetToJniDir(j.target),
+			"-f "+j.path.String())
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        zip,
+		Description: "zip jni libs",
+		Output:      outputFile,
+		Implicits:   deps,
+		Args: map[string]string{
+			"jarArgs": strings.Join(proptools.NinjaAndShellEscape(jarArgs), " "),
+		},
+	})
+}
+
+func targetToJniDir(target android.Target) string {
+	return filepath.Join("lib", target.Arch.Abi[0])
+}
diff --git a/java/app_test.go b/java/app_test.go
index c7c94ec..f6476dc 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"fmt"
+	"path/filepath"
 	"reflect"
 	"sort"
 	"strings"
@@ -338,3 +339,118 @@
 		}
 	}
 }
+
+func TestJNI(t *testing.T) {
+	ctx := testJava(t, `
+		toolchain_library {
+			name: "libcompiler_rt-extras",
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libatomic",
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libgcc",
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.builtins-aarch64-android",
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.builtins-arm-android",
+			src: "",
+		}
+
+		cc_object {
+			name: "crtbegin_so",
+			stl: "none",
+		}
+
+		cc_object {
+			name: "crtend_so",
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libjni",
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		android_test {
+			name: "test",
+			no_framework_libs: true,
+			jni_libs: ["libjni"],
+		}
+
+		android_test {
+			name: "test_first",
+			no_framework_libs: true,
+			compile_multilib: "first",
+			jni_libs: ["libjni"],
+		}
+
+		android_test {
+			name: "test_both",
+			no_framework_libs: true,
+			compile_multilib: "both",
+			jni_libs: ["libjni"],
+		}
+
+		android_test {
+			name: "test_32",
+			no_framework_libs: true,
+			compile_multilib: "32",
+			jni_libs: ["libjni"],
+		}
+
+		android_test {
+			name: "test_64",
+			no_framework_libs: true,
+			compile_multilib: "64",
+			jni_libs: ["libjni"],
+		}
+		`)
+
+	// check the existence of the internal modules
+	ctx.ModuleForTests("test", "android_common")
+	ctx.ModuleForTests("test_first", "android_common")
+	ctx.ModuleForTests("test_both", "android_common")
+	ctx.ModuleForTests("test_32", "android_common")
+	ctx.ModuleForTests("test_64", "android_common")
+
+	testCases := []struct {
+		name string
+		abis []string
+	}{
+		{"test", []string{"arm64-v8a"}},
+		{"test_first", []string{"arm64-v8a"}},
+		{"test_both", []string{"arm64-v8a", "armeabi-v7a"}},
+		{"test_32", []string{"armeabi-v7a"}},
+		{"test_64", []string{"arm64-v8a"}},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			app := ctx.ModuleForTests(test.name, "android_common")
+			jniLibZip := app.Output("jnilibs.zip")
+			var abis []string
+			args := strings.Fields(jniLibZip.Args["jarArgs"])
+			for i := 0; i < len(args); i++ {
+				if args[i] == "-P" {
+					abis = append(abis, filepath.Base(args[i+1]))
+					i++
+				}
+			}
+			if !reflect.DeepEqual(abis, test.abis) {
+				t.Errorf("want abis %v, got %v", test.abis, abis)
+			}
+		})
+	}
+}
diff --git a/java/builder.go b/java/builder.go
index 07af8eb..f55a7c7 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -109,6 +109,15 @@
 		},
 		"jarArgs")
 
+	zip = pctx.AndroidStaticRule("zip",
+		blueprint.RuleParams{
+			Command:        `${config.SoongZipCmd} -o $out @$out.rsp`,
+			CommandDeps:    []string{"${config.SoongZipCmd}"},
+			Rspfile:        "$out.rsp",
+			RspfileContent: "$jarArgs",
+		},
+		"jarArgs")
+
 	combineJar = pctx.AndroidStaticRule("combineJar",
 		blueprint.RuleParams{
 			Command:     `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out $in`,
diff --git a/java/java.go b/java/java.go
index b4b8feb..c5414f4 100644
--- a/java/java.go
+++ b/java/java.go
@@ -95,9 +95,6 @@
 	// list of java libraries that will be compiled into the resulting jar
 	Static_libs []string `android:"arch_variant"`
 
-	// list of native libraries that will be provided in or alongside the resulting jar
-	Jni_libs []string `android:"arch_variant"`
-
 	// manifest file to be included in resulting jar
 	Manifest *string
 
@@ -365,6 +362,11 @@
 	name string
 }
 
+type jniDependencyTag struct {
+	blueprint.BaseDependencyTag
+	target android.Target
+}
+
 var (
 	staticLibTag     = dependencyTag{name: "staticlib"}
 	libTag           = dependencyTag{name: "javalib"}
@@ -375,6 +377,7 @@
 	frameworkApkTag  = dependencyTag{name: "framework-apk"}
 	kotlinStdlibTag  = dependencyTag{name: "kotlin-stdlib"}
 	proguardRaiseTag = dependencyTag{name: "proguard-raise"}
+	certificateTag   = dependencyTag{name: "certificate"}
 )
 
 type sdkDep struct {
@@ -389,6 +392,12 @@
 	aidl android.Path
 }
 
+type jniLib struct {
+	name   string
+	path   android.Path
+	target android.Target
+}
+
 func (j *Module) shouldInstrument(ctx android.BaseContext) bool {
 	return j.properties.Instrument && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
 }
@@ -597,6 +606,7 @@
 	ctx.AddFarVariationDependencies([]blueprint.Variation{
 		{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
 	}, annoTag, j.properties.Annotation_processors...)
+
 	android.ExtractSourcesDeps(ctx, j.properties.Srcs)
 	android.ExtractSourcesDeps(ctx, j.properties.Exclude_srcs)
 	android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
@@ -787,6 +797,15 @@
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
 
+		if _, ok := tag.(*jniDependencyTag); ok {
+			// Handled by AndroidApp.collectAppDeps
+			return
+		}
+		if tag == certificateTag {
+			// Handled by AndroidApp.collectAppDeps
+			return
+		}
+
 		if to, ok := module.(*Library); ok {
 			switch tag {
 			case bootClasspathTag, libTag, staticLibTag:
diff --git a/java/java_test.go b/java/java_test.go
index 82accd5..1bfd24b 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -15,8 +15,6 @@
 package java
 
 import (
-	"android/soong/android"
-	"android/soong/genrule"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -27,6 +25,10 @@
 	"testing"
 
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/genrule"
 )
 
 var buildDir string
@@ -73,6 +75,7 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
+	ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
 	ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
@@ -95,6 +98,16 @@
 		ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
 	})
 	ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
+
+	// Register module types and mutators from cc needed for JNI testing
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+	})
+
 	ctx.Register()
 
 	extraModules := []string{
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 8c51641..6851e8c 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -101,7 +101,7 @@
 	"ls":        Allowed,
 	"lsof":      Allowed,
 	"m4":        Allowed,
-	"make":      Allowed,
+	"make":      Log,
 	"md5sum":    Allowed,
 	"mkdir":     Allowed,
 	"mktemp":    Allowed,
@@ -149,7 +149,7 @@
 	"which":     Allowed,
 	"whoami":    Allowed,
 	"xargs":     Allowed,
-	"xmllint":   Allowed,
+	"xmllint":   Log,
 	"xxd":       Allowed,
 	"xz":        Allowed,
 	"zip":       Allowed,