Merge "Add enable_profile_use property"
diff --git a/android/androidmk.go b/android/androidmk.go
index 5ce486d..759d328 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -43,6 +43,7 @@
 	OutputFile OptionalPath
 	Disabled   bool
 	Include    string
+	Required   []string
 
 	Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
 
@@ -168,6 +169,8 @@
 		data.Include = "$(BUILD_PREBUILT)"
 	}
 
+	data.Required = amod.commonProperties.Required
+
 	// Make does not understand LinuxBionic
 	if amod.Os() == LinuxBionic {
 		return nil
@@ -197,8 +200,8 @@
 	fmt.Fprintln(&data.preamble, "LOCAL_MODULE_CLASS :=", data.Class)
 	fmt.Fprintln(&data.preamble, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String())
 
-	if len(amod.commonProperties.Required) > 0 {
-		fmt.Fprintln(&data.preamble, "LOCAL_REQUIRED_MODULES := "+strings.Join(amod.commonProperties.Required, " "))
+	if len(data.Required) > 0 {
+		fmt.Fprintln(&data.preamble, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " "))
 	}
 
 	archStr := amod.Arch().ArchType.String()
diff --git a/android/config.go b/android/config.go
index a70fa76..5abda26 100644
--- a/android/config.go
+++ b/android/config.go
@@ -78,6 +78,7 @@
 	srcDir   string // the path of the root source directory
 	buildDir string // the path of the build output directory
 
+	env       map[string]string
 	envLock   sync.Mutex
 	envDeps   map[string]string
 	envFrozen bool
@@ -168,15 +169,15 @@
 }
 
 // TestConfig returns a Config object suitable for using for tests
-func TestConfig(buildDir string) Config {
+func TestConfig(buildDir string, env map[string]string) Config {
 	config := &config{
 		ProductVariables: productVariables{
 			DeviceName: stringPtr("test_device"),
 		},
 
-		buildDir:          buildDir,
-		captureBuild:      true,
-		ignoreEnvironment: true,
+		buildDir:     buildDir,
+		captureBuild: true,
+		env:          env,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
@@ -186,14 +187,14 @@
 }
 
 // TestConfig returns a Config object suitable for using for tests that need to run the arch mutator
-func TestArchConfig(buildDir string) Config {
-	testConfig := TestConfig(buildDir)
+func TestArchConfig(buildDir string, env map[string]string) Config {
+	testConfig := TestConfig(buildDir, env)
 	config := testConfig.config
 
 	config.Targets = map[OsClass][]Target{
 		Device: []Target{
-			{Android, Arch{ArchType: Arm64, Native: true}},
-			{Android, Arch{ArchType: Arm, Native: true}},
+			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true}},
+			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true}},
 		},
 		Host: []Target{
 			{BuildOs, Arch{ArchType: X86_64}},
@@ -212,6 +213,8 @@
 		ConfigFileName:           filepath.Join(buildDir, configFileName),
 		ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
 
+		env: originalEnv,
+
 		srcDir:   srcDir,
 		buildDir: buildDir,
 	}
@@ -335,9 +338,7 @@
 		if c.envFrozen {
 			panic("Cannot access new environment variables after envdeps are frozen")
 		}
-		if !c.ignoreEnvironment {
-			val, _ = originalEnv[key]
-		}
+		val, _ = c.env[key]
 		c.envDeps[key] = val
 	}
 	return val
diff --git a/android/paths_test.go b/android/paths_test.go
index 3986b71..248f4d4 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -209,7 +209,7 @@
 }
 
 func TestPathForModuleInstall(t *testing.T) {
-	testConfig := TestConfig("")
+	testConfig := TestConfig("", nil)
 
 	hostTarget := Target{Os: Linux}
 	deviceTarget := Target{Os: Android}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 9a1de9c..93f5805 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -118,7 +118,7 @@
 	}
 	defer os.RemoveAll(buildDir)
 
-	config := TestConfig(buildDir)
+	config := TestConfig(buildDir, nil)
 
 	for _, test := range prebuiltsTests {
 		t.Run(test.name, func(t *testing.T) {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index eb63065..2114031 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -89,7 +89,7 @@
 	}
 	c.subAndroidMk(&ret, c.installer)
 
-	if c.vndk() && Bool(c.VendorProperties.Vendor_available) {
+	if c.vndk() && c.hasVendorVariant() {
 		// .vendor suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
 		ret.SubName += vendorSuffix
diff --git a/cc/cc.go b/cc/cc.go
index 4f10a11..4c02e9e 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -34,9 +34,9 @@
 	android.RegisterModuleType("cc_defaults", defaultsFactory)
 
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("image", vendorMutator).Parallel()
 		ctx.BottomUp("link", linkageMutator).Parallel()
 		ctx.BottomUp("vndk", vndkMutator).Parallel()
-		ctx.BottomUp("image", vendorMutator).Parallel()
 		ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
 		ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
 		ctx.BottomUp("begin", beginMutator).Parallel()
@@ -168,16 +168,21 @@
 }
 
 type VendorProperties struct {
-	// whether this module should be allowed to install onto /vendor as
-	// well as /system. The two variants will be built separately, one
-	// like normal, and the other limited to the set of libraries and
-	// headers that are exposed to /vendor modules.
+	// whether this module should be allowed to be directly depended by other
+	// modules with `vendor: true`, `proprietary: true`, or `vendor_available:true`.
+	// If set to true, two variants will be built separately, one like
+	// normal, and the other limited to the set of libraries and headers
+	// that are exposed to /vendor modules.
 	//
 	// The vendor variant may be used with a different (newer) /system,
 	// so it shouldn't have any unversioned runtime dependencies, or
 	// make assumptions about the system that may not be true in the
 	// future.
 	//
+	// If set to false, this module becomes inaccessible from /vendor modules.
+	//
+	// Default value is true when vndk: {enabled: true} or vendor: true.
+	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
 }
@@ -388,6 +393,12 @@
 	return false
 }
 
+// Returns true only when this module is configured to have core and vendor
+// variants.
+func (c *Module) hasVendorVariant() bool {
+	return c.isVndk() || Bool(c.VendorProperties.Vendor_available)
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -1159,7 +1170,7 @@
 
 		// Export the shared libs to the make world. In doing so, .vendor suffix
 		// is added if the lib has both core and vendor variants and this module
-		// is building against vndk. This is because the vendor variant will be
+		// is building against vndk. This is because the vendor variant will
 		// have .vendor suffix in its name in the make world. However, if the
 		// lib is a vendor-only lib or this lib is not building against vndk,
 		// then the suffix is not added.
@@ -1168,7 +1179,7 @@
 			libName := strings.TrimSuffix(name, llndkLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
 			isLLndk := inList(libName, llndkLibraries)
-			if c.vndk() && (Bool(cc.VendorProperties.Vendor_available) || isLLndk) {
+			if c.vndk() && (cc.hasVendorVariant() || isLLndk) {
 				libName += vendorSuffix
 			}
 			// Note: the order of libs in this list is not important because
@@ -1286,6 +1297,16 @@
 	vendorMode = "vendor"
 )
 
+func squashVendorSrcs(m *Module) {
+	if lib, ok := m.compiler.(*libraryDecorator); ok {
+		lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs,
+			lib.baseCompiler.Properties.Target.Vendor.Srcs...)
+
+		lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs,
+			lib.baseCompiler.Properties.Target.Vendor.Exclude_srcs...)
+	}
+}
+
 func vendorMutator(mctx android.BottomUpMutatorContext) {
 	if mctx.Os() != android.Android {
 		return
@@ -1311,15 +1332,15 @@
 	}
 
 	// Sanity check
-	if Bool(m.VendorProperties.Vendor_available) && mctx.Vendor() {
+	if m.VendorProperties.Vendor_available != nil && mctx.Vendor() {
 		mctx.PropertyErrorf("vendor_available",
 			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
 		return
 	}
 	if vndk := m.vndkdep; vndk != nil {
-		if vndk.isVndk() && !Bool(m.VendorProperties.Vendor_available) {
+		if vndk.isVndk() && m.VendorProperties.Vendor_available == nil {
 			mctx.PropertyErrorf("vndk",
-				"has to define `vendor_available: true` to enable vndk")
+				"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
 			return
 		}
 		if !vndk.isVndk() && vndk.isVndkSp() {
@@ -1337,15 +1358,19 @@
 		// LL-NDK stubs only exist in the vendor variant, since the
 		// real libraries will be used in the core variant.
 		mctx.CreateVariations(vendorMode)
-	} else if Bool(m.VendorProperties.Vendor_available) {
+	} else if m.hasVendorVariant() {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
 		mod := mctx.CreateVariations(coreMode, vendorMode)
-		mod[1].(*Module).Properties.UseVndk = true
+		vendor := mod[1].(*Module)
+		vendor.Properties.UseVndk = true
+		squashVendorSrcs(vendor)
 	} else if mctx.Vendor() && m.Properties.Sdk_version == "" {
 		// This will be available in /vendor only
 		mod := mctx.CreateVariations(vendorMode)
-		mod[0].(*Module).Properties.UseVndk = true
+		vendor := mod[0].(*Module)
+		vendor.Properties.UseVndk = true
+		squashVendorSrcs(vendor)
 	} else {
 		// This is either in /system (or similar: /data), or is a
 		// modules built with the NDK. Modules built with the NDK
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 92120a5..94e3e66 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2,10 +2,136 @@
 
 import (
 	"android/soong/android"
+	"io/ioutil"
+	"os"
 	"reflect"
 	"testing"
+
+	"github.com/google/blueprint/proptools"
 )
 
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_cc_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testCc(t *testing.T, bp string) *android.TestContext {
+	config := android.TestArchConfig(buildDir, nil)
+	config.ProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(libraryFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
+	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("image", vendorMutator).Parallel()
+		ctx.BottomUp("link", linkageMutator).Parallel()
+		ctx.BottomUp("vndk", vndkMutator).Parallel()
+	})
+	ctx.Register()
+
+	ctx.MockFileSystem(map[string][]byte{
+		"Android.bp": []byte(bp),
+		"foo.c":      nil,
+		"bar.c":      nil,
+	})
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	fail(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	fail(t, errs)
+
+	return ctx
+}
+
+func TestVendorSrc(t *testing.T) {
+	ctx := testCc(t, `
+		cc_library {
+			name: "libTest",
+			srcs: ["foo.c"],
+			no_libgcc : true,
+			nocrt : true,
+			system_shared_libs : [],
+			vendor_available: true,
+			target: {
+				vendor: {
+					srcs: ["bar.c"],
+				},
+			},
+		}
+		toolchain_library {
+			name: "libatomic",
+			vendor_available: true,
+		}
+		toolchain_library {
+			name: "libcompiler_rt-extras",
+			vendor_available: true,
+		}
+		cc_library {
+			name: "libc",
+			no_libgcc : true,
+			nocrt : true,
+			system_shared_libs: [],
+		}
+		llndk_library {
+			name: "libc",
+			symbol_file: "",
+		}
+		cc_library {
+			name: "libm",
+			no_libgcc : true,
+			nocrt : true,
+			system_shared_libs: [],
+		}
+		llndk_library {
+			name: "libm",
+			symbol_file: "",
+		}
+		cc_library {
+			name: "libdl",
+			no_libgcc : true,
+			nocrt : true,
+			system_shared_libs: [],
+		}
+		llndk_library {
+			name: "libdl",
+			symbol_file: "",
+		}
+	`)
+
+	ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld")
+	var objs []string
+	for _, o := range ld.Inputs {
+		objs = append(objs, o.Base())
+	}
+	if len(objs) != 2 {
+		t.Errorf("inputs of libTest is expected to 2, but was %d.", len(objs))
+	}
+	if objs[0] != "foo.o" || objs[1] != "bar.o" {
+		t.Errorf("inputs of libTest must be []string{\"foo.o\", \"bar.o\"}, but was %#v.", objs)
+	}
+}
+
 var firstUniqueElementsTestCases = []struct {
 	in  []string
 	out []string
diff --git a/cc/compiler.go b/cc/compiler.go
index a65ddf8..3b3bbbb 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -490,14 +490,6 @@
 	pathDeps := deps.GeneratedHeaders
 	pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
 
-	if ctx.vndk() {
-		compiler.Properties.Srcs = append(compiler.Properties.Srcs,
-			compiler.Properties.Target.Vendor.Srcs...)
-
-		compiler.Properties.Exclude_srcs = append(compiler.Properties.Exclude_srcs,
-			compiler.Properties.Target.Vendor.Exclude_srcs...)
-	}
-
 	srcs := ctx.ExpandSources(compiler.Properties.Srcs, compiler.Properties.Exclude_srcs)
 	srcs = append(srcs, deps.GeneratedSources...)
 
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 0d22ed4..390936a 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -117,7 +117,7 @@
 	pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " "))
 	pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
 	pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
-	pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64", "arm64"))
+	pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64"))
 
 	pctx.StaticVariable("Arm64ClangCflags", strings.Join(ClangFilterUnknownCflags(arm64Cflags), " "))
 	pctx.StaticVariable("Arm64ClangLdflags", strings.Join(ClangFilterUnknownCflags(arm64Ldflags), " "))
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index f093563..7110ccb 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -216,7 +216,7 @@
 	pctx.StaticVariable("ArmCflags", strings.Join(armCflags, " "))
 	pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
 	pctx.StaticVariable("ArmCppflags", strings.Join(armCppflags, " "))
-	pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm", "arm"))
+	pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm"))
 
 	// Extended cflags
 
diff --git a/cc/config/global.go b/cc/config/global.go
index 82a44e6..e9f5473 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -180,9 +180,8 @@
 
 var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
 
-func bionicHeaders(bionicArch, kernelArch string) string {
+func bionicHeaders(kernelArch string) string {
 	return strings.Join([]string{
-		"-isystem bionic/libc/arch-" + bionicArch + "/include",
 		"-isystem bionic/libc/include",
 		"-isystem bionic/libc/kernel/uapi",
 		"-isystem bionic/libc/kernel/uapi/asm-" + kernelArch,
diff --git a/cc/config/mips64_device.go b/cc/config/mips64_device.go
index 3a49e7b..35fa551 100644
--- a/cc/config/mips64_device.go
+++ b/cc/config/mips64_device.go
@@ -108,7 +108,7 @@
 	pctx.StaticVariable("Mips64Cflags", strings.Join(mips64Cflags, " "))
 	pctx.StaticVariable("Mips64Ldflags", strings.Join(mips64Ldflags, " "))
 	pctx.StaticVariable("Mips64Cppflags", strings.Join(mips64Cppflags, " "))
-	pctx.StaticVariable("Mips64IncludeFlags", bionicHeaders("mips64", "mips"))
+	pctx.StaticVariable("Mips64IncludeFlags", bionicHeaders("mips"))
 
 	// Clang cflags
 	pctx.StaticVariable("Mips64ClangCflags", strings.Join(ClangFilterUnknownCflags(mips64ClangCflags), " "))
diff --git a/cc/config/mips_device.go b/cc/config/mips_device.go
index c135029..d154426 100644
--- a/cc/config/mips_device.go
+++ b/cc/config/mips_device.go
@@ -147,7 +147,7 @@
 	pctx.StaticVariable("MipsCflags", strings.Join(mipsCflags, " "))
 	pctx.StaticVariable("MipsLdflags", strings.Join(mipsLdflags, " "))
 	pctx.StaticVariable("MipsCppflags", strings.Join(mipsCppflags, " "))
-	pctx.StaticVariable("MipsIncludeFlags", bionicHeaders("mips", "mips"))
+	pctx.StaticVariable("MipsIncludeFlags", bionicHeaders("mips"))
 
 	// Clang cflags
 	pctx.StaticVariable("MipsClangCflags", strings.Join(ClangFilterUnknownCflags(mipsClangCflags), " "))
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 2a6fe2a..a98001e 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -159,7 +159,7 @@
 	pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " "))
 	pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
 	pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
-	pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86_64", "x86"))
+	pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
 	pctx.StaticVariable("X86_64ClangCflags", strings.Join(ClangFilterUnknownCflags(x86_64Cflags), " "))
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 23518b6..53d2265 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -181,7 +181,7 @@
 	pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
 	pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
 	pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
-	pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86", "x86"))
+	pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
 	pctx.StaticVariable("X86ClangCflags", strings.Join(ClangFilterUnknownCflags(x86ClangCflags), " "))
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 093876d..277361b 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -78,7 +78,7 @@
 	pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " "))
 	pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " "))
 
-	pctx.StaticVariable("LinuxBionicIncludeFlags", bionicHeaders("x86_64", "x86"))
+	pctx.StaticVariable("LinuxBionicIncludeFlags", bionicHeaders("x86"))
 
 	// Use the device gcc toolchain for now
 	pctx.StaticVariable("LinuxBionicGccRoot", "${X86_64GccRoot}")
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index c3d3462..30c4d4c 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -50,6 +50,11 @@
 
 	// Whether the system library uses symbol versions.
 	Unversioned bool
+
+	// whether this module can be directly depended upon by libs that are installed to /vendor.
+	// When set to false, this module can only be depended on by VNDK libraries, not vendor
+	// libraries. This effectively hides this module from vendors. Default value is true.
+	Vendor_available bool
 }
 
 type llndkStubDecorator struct {
@@ -149,6 +154,7 @@
 	stub := &llndkStubDecorator{
 		libraryDecorator: library,
 	}
+	stub.Properties.Vendor_available = true
 	module.compiler = stub
 	module.linker = stub
 	module.installer = nil
diff --git a/cc/makevars.go b/cc/makevars.go
index 2c6af70..295b4ac 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -62,6 +62,7 @@
 	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("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
diff --git a/cc/test_data_test.go b/cc/test_data_test.go
index 962bde5..434edcd 100644
--- a/cc/test_data_test.go
+++ b/cc/test_data_test.go
@@ -117,7 +117,7 @@
 	}
 	defer os.RemoveAll(buildDir)
 
-	config := android.TestConfig(buildDir)
+	config := android.TestConfig(buildDir, nil)
 
 	for _, test := range testDataTests {
 		t.Run(test.name, func(t *testing.T) {
diff --git a/cc/vndk.go b/cc/vndk.go
index 395069b..860678d 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -27,8 +27,8 @@
 		// declared as a VNDK or VNDK-SP module. The vendor variant
 		// will be installed in /system instead of /vendor partition.
 		//
-		// `vendor_available: true` must set to together for VNDK
-		// modules.
+		// `vendor_vailable` must be explicitly set to either true or
+		// false together with `vndk: {enabled: true}`.
 		Enabled *bool
 
 		// declared as a VNDK-SP module, which is a subset of VNDK.
@@ -81,6 +81,24 @@
 	if to.linker == nil {
 		return
 	}
+	if !vndk.isVndk() {
+		// Non-VNDK modules (those installed to /vendor) can't depend on modules marked with
+		// vendor_available: false.
+		violation := false
+		if lib, ok := to.linker.(*llndkStubDecorator); ok && !lib.Properties.Vendor_available {
+			violation = true
+		} else {
+			if _, ok := to.linker.(libraryInterface); ok && to.VendorProperties.Vendor_available != nil && !Bool(to.VendorProperties.Vendor_available) {
+				// Vendor_available == nil && !Bool(Vendor_available) should be okay since
+				// it means a vendor-only library which is a valid dependency for non-VNDK
+				// modules.
+				violation = true
+			}
+		}
+		if violation {
+			ctx.ModuleErrorf("Vendor module that is not VNDK should not link to %q which is marked as `vendor_available: false`", to.Name())
+		}
+	}
 	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
 		// Check only shared libraries.
 		// Other (static and LL-NDK) libraries are allowed to link.
@@ -102,16 +120,17 @@
 }
 
 var (
-	vndkCoreLibraries []string
-	vndkSpLibraries   []string
-	llndkLibraries    []string
-	vndkLibrariesLock sync.Mutex
+	vndkCoreLibraries    []string
+	vndkSpLibraries      []string
+	llndkLibraries       []string
+	vndkPrivateLibraries []string
+	vndkLibrariesLock    sync.Mutex
 )
 
 // gather list of vndk-core, vndk-sp, and ll-ndk libs
 func vndkMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok {
-		if _, ok := m.linker.(*llndkStubDecorator); ok {
+		if lib, ok := m.linker.(*llndkStubDecorator); ok {
 			vndkLibrariesLock.Lock()
 			defer vndkLibrariesLock.Unlock()
 			name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
@@ -119,22 +138,40 @@
 				llndkLibraries = append(llndkLibraries, name)
 				sort.Strings(llndkLibraries)
 			}
-		} else if lib, ok := m.linker.(*libraryDecorator); ok && lib.shared() {
-			if m.vndkdep.isVndk() {
-				vndkLibrariesLock.Lock()
-				defer vndkLibrariesLock.Unlock()
-				if m.vndkdep.isVndkSp() {
-					if !inList(m.Name(), vndkSpLibraries) {
-						vndkSpLibraries = append(vndkSpLibraries, m.Name())
-						sort.Strings(vndkSpLibraries)
+			if !lib.Properties.Vendor_available {
+				if !inList(name, vndkPrivateLibraries) {
+					vndkPrivateLibraries = append(vndkPrivateLibraries, name)
+					sort.Strings(vndkPrivateLibraries)
+				}
+			}
+		} else {
+			lib, is_lib := m.linker.(*libraryDecorator)
+			prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+			if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
+				name := strings.TrimPrefix(m.Name(), "prebuilt_")
+				if m.vndkdep.isVndk() {
+					vndkLibrariesLock.Lock()
+					defer vndkLibrariesLock.Unlock()
+					if m.vndkdep.isVndkSp() {
+						if !inList(name, vndkSpLibraries) {
+							vndkSpLibraries = append(vndkSpLibraries, name)
+							sort.Strings(vndkSpLibraries)
+						}
+					} else {
+						if !inList(name, vndkCoreLibraries) {
+							vndkCoreLibraries = append(vndkCoreLibraries, name)
+							sort.Strings(vndkCoreLibraries)
+						}
 					}
-				} else {
-					if !inList(m.Name(), vndkCoreLibraries) {
-						vndkCoreLibraries = append(vndkCoreLibraries, m.Name())
-						sort.Strings(vndkCoreLibraries)
+					if !Bool(m.VendorProperties.Vendor_available) {
+						if !inList(name, vndkPrivateLibraries) {
+							vndkPrivateLibraries = append(vndkPrivateLibraries, name)
+							sort.Strings(vndkPrivateLibraries)
+						}
 					}
 				}
 			}
 		}
+
 	}
 }
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 296000b..1c853d6 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -223,7 +223,7 @@
 		trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
 	}
 
-	vars, err := build.DumpMakeVars(buildCtx, config, nil, nil, []string{"all_named_products"})
+	vars, err := build.DumpMakeVars(buildCtx, config, nil, []string{"all_named_products"})
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/cmd/soong_zip/soong_zip.go b/cmd/soong_zip/soong_zip.go
index cb9df9a..2bcc9a5 100644
--- a/cmd/soong_zip/soong_zip.go
+++ b/cmd/soong_zip/soong_zip.go
@@ -62,12 +62,6 @@
 	io.Closer
 }
 
-type fileArg struct {
-	pathPrefixInZip, sourcePrefixToStrip string
-	sourceFiles                          []string
-	globDir                              string
-}
-
 type pathMapping struct {
 	dest, src string
 	zipMethod uint16
@@ -89,8 +83,6 @@
 	return nil
 }
 
-type fileArgs []fileArg
-
 type file struct{}
 
 type listFiles struct{}
@@ -106,10 +98,10 @@
 		return fmt.Errorf("must pass -C before -f")
 	}
 
-	fArgs = append(fArgs, fileArg{
-		pathPrefixInZip:     filepath.Clean(*rootPrefix),
-		sourcePrefixToStrip: filepath.Clean(*relativeRoot),
-		sourceFiles:         []string{s},
+	fArgs = append(fArgs, FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		SourceFiles:         []string{s},
 	})
 
 	return nil
@@ -129,10 +121,10 @@
 		return err
 	}
 
-	fArgs = append(fArgs, fileArg{
-		pathPrefixInZip:     filepath.Clean(*rootPrefix),
-		sourcePrefixToStrip: filepath.Clean(*relativeRoot),
-		sourceFiles:         strings.Split(string(list), "\n"),
+	fArgs = append(fArgs, FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		SourceFiles:         strings.Split(string(list), "\n"),
 	})
 
 	return nil
@@ -147,10 +139,10 @@
 		return fmt.Errorf("must pass -C before -D")
 	}
 
-	fArgs = append(fArgs, fileArg{
-		pathPrefixInZip:     filepath.Clean(*rootPrefix),
-		sourcePrefixToStrip: filepath.Clean(*relativeRoot),
-		globDir:             filepath.Clean(s),
+	fArgs = append(fArgs, FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		GlobDir:             filepath.Clean(s),
 	})
 
 	return nil
@@ -166,7 +158,7 @@
 	compLevel    = flag.Int("L", 5, "deflate compression level (0-9)")
 	emulateJar   = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
 
-	fArgs            fileArgs
+	fArgs            FileArgs
 	nonDeflatedFiles = make(uniqueSet)
 
 	cpuProfile = flag.String("cpuprofile", "", "write cpu profile to file")
@@ -186,7 +178,36 @@
 	os.Exit(2)
 }
 
-type zipWriter struct {
+func main() {
+	flag.Parse()
+
+	err := Run(ZipArgs{
+		FileArgs:                 fArgs,
+		OutputFilePath:           *out,
+		CpuProfileFilePath:       *cpuProfile,
+		TraceFilePath:            *traceFile,
+		EmulateJar:               *emulateJar,
+		AddDirectoryEntriesToZip: *directories,
+		CompressionLevel:         *compLevel,
+		ManifestSourcePath:       *manifest,
+		NumParallelJobs:          *parallelJobs,
+		NonDeflatedFiles:         nonDeflatedFiles,
+	})
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(1)
+	}
+}
+
+type FileArg struct {
+	PathPrefixInZip, SourcePrefixToStrip string
+	SourceFiles                          []string
+	GlobDir                              string
+}
+
+type FileArgs []FileArg
+
+type ZipWriter struct {
 	time         time.Time
 	createdFiles map[string]string
 	createdDirs  map[string]string
@@ -213,11 +234,22 @@
 	allocatedSize int64
 }
 
-func main() {
-	flag.Parse()
+type ZipArgs struct {
+	FileArgs                 FileArgs
+	OutputFilePath           string
+	CpuProfileFilePath       string
+	TraceFilePath            string
+	EmulateJar               bool
+	AddDirectoryEntriesToZip bool
+	CompressionLevel         int
+	ManifestSourcePath       string
+	NumParallelJobs          int
+	NonDeflatedFiles         map[string]bool
+}
 
-	if *cpuProfile != "" {
-		f, err := os.Create(*cpuProfile)
+func Run(args ZipArgs) (err error) {
+	if args.CpuProfileFilePath != "" {
+		f, err := os.Create(args.CpuProfileFilePath)
 		if err != nil {
 			fmt.Fprintln(os.Stderr, err.Error())
 			os.Exit(1)
@@ -227,8 +259,8 @@
 		defer pprof.StopCPUProfile()
 	}
 
-	if *traceFile != "" {
-		f, err := os.Create(*traceFile)
+	if args.TraceFilePath != "" {
+		f, err := os.Create(args.TraceFilePath)
 		if err != nil {
 			fmt.Fprintln(os.Stderr, err.Error())
 			os.Exit(1)
@@ -242,46 +274,41 @@
 		defer trace.Stop()
 	}
 
-	if *out == "" {
-		fmt.Fprintf(os.Stderr, "error: -o is required\n")
-		usage()
+	if args.OutputFilePath == "" {
+		return fmt.Errorf("output file path must be nonempty")
 	}
 
-	if *emulateJar {
-		*directories = true
+	if args.EmulateJar {
+		args.AddDirectoryEntriesToZip = true
 	}
 
-	w := &zipWriter{
+	w := &ZipWriter{
 		time:         jar.DefaultTime,
 		createdDirs:  make(map[string]string),
 		createdFiles: make(map[string]string),
-		directories:  *directories,
-		compLevel:    *compLevel,
+		directories:  args.AddDirectoryEntriesToZip,
+		compLevel:    args.CompressionLevel,
 	}
-
 	pathMappings := []pathMapping{}
 
-	for _, fa := range fArgs {
-		srcs := fa.sourceFiles
-		if fa.globDir != "" {
-			srcs = append(srcs, recursiveGlobFiles(fa.globDir)...)
+	for _, fa := range args.FileArgs {
+		srcs := fa.SourceFiles
+		if fa.GlobDir != "" {
+			srcs = append(srcs, recursiveGlobFiles(fa.GlobDir)...)
 		}
 		for _, src := range srcs {
-			if err := fillPathPairs(fa.pathPrefixInZip,
-				fa.sourcePrefixToStrip, src, &pathMappings); err != nil {
+			if err := fillPathPairs(fa.PathPrefixInZip,
+				fa.SourcePrefixToStrip, src, &pathMappings, args.NonDeflatedFiles); err != nil {
 				log.Fatal(err)
 			}
 		}
 	}
 
-	err := w.write(*out, pathMappings, *manifest)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Exit(1)
-	}
+	return w.write(args.OutputFilePath, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.NumParallelJobs)
+
 }
 
-func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping) error {
+func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping, nonDeflatedFiles map[string]bool) error {
 	src = strings.TrimSpace(src)
 	if src == "" {
 		return nil
@@ -317,7 +344,7 @@
 	io.Seeker
 }
 
-func (z *zipWriter) write(out string, pathMappings []pathMapping, manifest string) error {
+func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error {
 	f, err := os.Create(out)
 	if err != nil {
 		return err
@@ -346,18 +373,18 @@
 	// The RateLimit object will put the upper bounds on the number of
 	// parallel compressions and outstanding buffers.
 	z.writeOps = make(chan chan *zipEntry, 1000)
-	z.cpuRateLimiter = NewCPURateLimiter(int64(*parallelJobs))
+	z.cpuRateLimiter = NewCPURateLimiter(int64(parallelJobs))
 	z.memoryRateLimiter = NewMemoryRateLimiter(0)
 	defer func() {
 		z.cpuRateLimiter.Stop()
 		z.memoryRateLimiter.Stop()
 	}()
 
-	if manifest != "" && !*emulateJar {
+	if manifest != "" && !emulateJar {
 		return errors.New("must specify --jar when specifying a manifest via -m")
 	}
 
-	if *emulateJar {
+	if emulateJar {
 		// manifest may be empty, in which case addManifest will fill in a default
 		pathMappings = append(pathMappings, pathMapping{jar.ManifestFile, manifest, zip.Deflate})
 
@@ -369,10 +396,10 @@
 		defer close(z.writeOps)
 
 		for _, ele := range pathMappings {
-			if *emulateJar && ele.dest == jar.ManifestFile {
+			if emulateJar && ele.dest == jar.ManifestFile {
 				err = z.addManifest(ele.dest, ele.src, ele.zipMethod)
 			} else {
-				err = z.addFile(ele.dest, ele.src, ele.zipMethod)
+				err = z.addFile(ele.dest, ele.src, ele.zipMethod, emulateJar)
 			}
 			if err != nil {
 				z.errors <- err
@@ -470,7 +497,7 @@
 }
 
 // imports (possibly with compression) <src> into the zip at sub-path <dest>
-func (z *zipWriter) addFile(dest, src string, method uint16) error {
+func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar bool) error {
 	var fileSize int64
 	var executable bool
 
@@ -478,11 +505,11 @@
 		return err
 	} else if s.IsDir() {
 		if z.directories {
-			return z.writeDirectory(dest, src)
+			return z.writeDirectory(dest, src, emulateJar)
 		}
 		return nil
 	} else {
-		if err := z.writeDirectory(filepath.Dir(dest), src); err != nil {
+		if err := z.writeDirectory(filepath.Dir(dest), src, emulateJar); err != nil {
 			return err
 		}
 
@@ -523,7 +550,7 @@
 	return z.writeFileContents(header, r)
 }
 
-func (z *zipWriter) addManifest(dest string, src string, method uint16) error {
+func (z *ZipWriter) addManifest(dest string, src string, method uint16) error {
 	if prev, exists := z.createdDirs[dest]; exists {
 		return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
 	}
@@ -531,7 +558,7 @@
 		return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
 	}
 
-	if err := z.writeDirectory(filepath.Dir(dest), src); err != nil {
+	if err := z.writeDirectory(filepath.Dir(dest), src, true); err != nil {
 		return err
 	}
 
@@ -545,7 +572,7 @@
 	return z.writeFileContents(fh, reader)
 }
 
-func (z *zipWriter) writeFileContents(header *zip.FileHeader, r readerSeekerCloser) (err error) {
+func (z *ZipWriter) writeFileContents(header *zip.FileHeader, r readerSeekerCloser) (err error) {
 
 	header.SetModTime(z.time)
 
@@ -621,7 +648,7 @@
 	return nil
 }
 
-func (z *zipWriter) crcFile(r io.Reader, ze *zipEntry, resultChan chan *zipEntry, wg *sync.WaitGroup) {
+func (z *ZipWriter) crcFile(r io.Reader, ze *zipEntry, resultChan chan *zipEntry, wg *sync.WaitGroup) {
 	defer wg.Done()
 	defer z.cpuRateLimiter.Finish()
 
@@ -637,7 +664,7 @@
 	close(resultChan)
 }
 
-func (z *zipWriter) compressPartialFile(r io.Reader, dict []byte, last bool, resultChan chan io.Reader, wg *sync.WaitGroup) {
+func (z *ZipWriter) compressPartialFile(r io.Reader, dict []byte, last bool, resultChan chan io.Reader, wg *sync.WaitGroup) {
 	defer wg.Done()
 
 	result, err := z.compressBlock(r, dict, last)
@@ -651,7 +678,7 @@
 	resultChan <- result
 }
 
-func (z *zipWriter) compressBlock(r io.Reader, dict []byte, last bool) (*bytes.Buffer, error) {
+func (z *ZipWriter) compressBlock(r io.Reader, dict []byte, last bool) (*bytes.Buffer, error) {
 	buf := new(bytes.Buffer)
 	var fw *flate.Writer
 	var err error
@@ -685,7 +712,7 @@
 	return buf, nil
 }
 
-func (z *zipWriter) compressWholeFile(ze *zipEntry, r io.ReadSeeker, compressChan chan *zipEntry) {
+func (z *ZipWriter) compressWholeFile(ze *zipEntry, r io.ReadSeeker, compressChan chan *zipEntry) {
 
 	crc := crc32.NewIEEE()
 	_, err := io.Copy(crc, r)
@@ -758,7 +785,7 @@
 
 // writeDirectory annotates that dir is a directory created for the src file or directory, and adds
 // the directory entry to the zip file if directories are enabled.
-func (z *zipWriter) writeDirectory(dir, src string) error {
+func (z *ZipWriter) writeDirectory(dir string, src string, emulateJar bool) error {
 	// clean the input
 	dir = filepath.Clean(dir)
 
@@ -785,7 +812,7 @@
 		for _, cleanDir := range zipDirs {
 			var dirHeader *zip.FileHeader
 
-			if *emulateJar && cleanDir+"/" == jar.MetaDir {
+			if emulateJar && cleanDir+"/" == jar.MetaDir {
 				dirHeader = jar.MetaDirFileHeader()
 			} else {
 				dirHeader = &zip.FileHeader{
@@ -808,7 +835,7 @@
 	return nil
 }
 
-func (z *zipWriter) writeSymlink(rel, file string) error {
+func (z *ZipWriter) writeSymlink(rel, file string) error {
 	fileHeader := &zip.FileHeader{
 		Name: rel,
 	}
diff --git a/java/androidmk.go b/java/androidmk.go
index 89d7d51..e349de4 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -19,6 +19,8 @@
 	"io"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 )
 
@@ -38,6 +40,25 @@
 				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.deviceProperties.Sdk_version)
 			},
 		},
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			android.WriteAndroidMkData(w, data)
+
+			if proptools.Bool(library.deviceProperties.Hostdex) && !library.Host() {
+				fmt.Fprintln(w, "include $(CLEAR_VARS)")
+				fmt.Fprintln(w, "LOCAL_MODULE := "+name+"-hostdex")
+				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := JAVA_LIBRARIES")
+				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", library.classpathFile.String())
+				if library.properties.Installable != nil && *library.properties.Installable == false {
+					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+				}
+				if library.dexJarFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
+				}
+				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " "))
+				fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
+			}
+		},
 	}
 }
 
diff --git a/java/app.go b/java/app.go
index e40478a..490a03d 100644
--- a/java/app.go
+++ b/java/app.go
@@ -274,8 +274,6 @@
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
-	module.deviceProperties.Dex = true
-
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
diff --git a/java/builder.go b/java/builder.go
index ca0d2c5..118f239 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -137,36 +137,8 @@
 func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
 	flags javaBuilderFlags, deps android.Paths) android.ModuleOutPath {
 
-	classDir := android.PathForModuleOut(ctx, "classes")
-	annoDir := android.PathForModuleOut(ctx, "anno")
-	classJar := android.PathForModuleOut(ctx, "classes-compiled.jar")
-
-	javacFlags := flags.javacFlags
-	if len(srcFileLists) > 0 {
-		javacFlags += " " + android.JoinWithPrefix(srcFileLists.Strings(), "@")
-	}
-
-	deps = append(deps, srcFileLists...)
-	deps = append(deps, flags.bootClasspath...)
-	deps = append(deps, flags.classpath...)
-
-	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:        javac,
-		Description: "javac",
-		Output:      classJar,
-		Inputs:      srcFiles,
-		Implicits:   deps,
-		Args: map[string]string{
-			"javacFlags":    javacFlags,
-			"bootClasspath": flags.bootClasspath.JavaBootClasspath(ctx.Device()),
-			"classpath":     flags.classpath.JavaClasspath(),
-			"outDir":        classDir.String(),
-			"annoDir":       annoDir.String(),
-			"javaVersion":   flags.javaVersion,
-		},
-	})
-
-	return classJar
+	return transformJavaToClasses(ctx, srcFiles, srcFileLists, flags, deps,
+		"classes-compiled.jar", "", "javac", javac)
 }
 
 func RunErrorProne(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
@@ -177,38 +149,54 @@
 		return nil
 	}
 
-	classDir := android.PathForModuleOut(ctx, "classes-errorprone")
-	annoDir := android.PathForModuleOut(ctx, "anno-errorprone")
-	classFileList := android.PathForModuleOut(ctx, "classes-errorprone.list")
+	return transformJavaToClasses(ctx, srcFiles, srcFileLists, flags, nil,
+		"classes-errorprone.list", "-errorprone", "errorprone", errorprone)
+}
+
+// transformJavaToClasses takes source files and converts them to a jar containing .class files.
+// srcFiles is a list of paths to sources, srcFileLists is a list of paths to files that contain
+// paths to sources.  There is no dependency on the sources passed through srcFileLists, those
+// must be added through the deps argument, which contains a list of paths that should be added
+// as implicit dependencies.  flags contains various command line flags to be passed to the
+// compiler.
+//
+// This method may be used for different compilers, including javac and Error Prone.  The rule
+// argument specifies which command line to use and desc sets the description of the rule that will
+// be printed at build time.  The stem argument provides the file name of the output jar, and
+// suffix will be appended to various intermediate files and directories to avoid collisions when
+// this function is called twice in the same module directory.
+func transformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
+	flags javaBuilderFlags, deps android.Paths, stem, suffix, desc string,
+	rule blueprint.Rule) android.ModuleOutPath {
+
+	outputFile := android.PathForModuleOut(ctx, stem)
 
 	javacFlags := flags.javacFlags
 	if len(srcFileLists) > 0 {
 		javacFlags += " " + android.JoinWithPrefix(srcFileLists.Strings(), "@")
 	}
 
-	var deps android.Paths
-
 	deps = append(deps, srcFileLists...)
 	deps = append(deps, flags.bootClasspath...)
 	deps = append(deps, flags.classpath...)
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:        errorprone,
-		Description: "errorprone",
-		Output:      classFileList,
+		Rule:        rule,
+		Description: desc,
+		Output:      outputFile,
 		Inputs:      srcFiles,
 		Implicits:   deps,
 		Args: map[string]string{
 			"javacFlags":    javacFlags,
 			"bootClasspath": flags.bootClasspath.JavaBootClasspath(ctx.Device()),
 			"classpath":     flags.classpath.JavaClasspath(),
-			"outDir":        classDir.String(),
-			"annoDir":       annoDir.String(),
+			"outDir":        android.PathForModuleOut(ctx, "classes"+suffix).String(),
+			"annoDir":       android.PathForModuleOut(ctx, "anno"+suffix).String(),
 			"javaVersion":   flags.javaVersion,
 		},
 	})
 
-	return classFileList
+	return outputFile
 }
 
 func TransformResourcesToJar(ctx android.ModuleContext, jarArgs []string,
diff --git a/java/java.go b/java/java.go
index fde88e9..5393b06 100644
--- a/java/java.go
+++ b/java/java.go
@@ -125,16 +125,15 @@
 	// if not blank, set to the version of the sdk to compile against
 	Sdk_version string
 
-	// Set for device java libraries, and for host versions of device java libraries
-	// built for testing
-	Dex bool `blueprint:"mutated"`
-
 	// directories to pass to aidl tool
 	Aidl_includes []string
 
 	// directories that should be added as include directories
 	// for any aidl sources of modules that depend on this module
 	Export_aidl_include_dirs []string
+
+	// If true, export a copy of the module as a -hostdex module for host testing.
+	Hostdex *bool
 }
 
 // Module contains the properties and members used by all java module types
@@ -279,8 +278,6 @@
 			if sdkDep.useModule {
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
 			}
-		} else {
-			// TODO(ccross): add hostdex support
 		}
 	}
 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
@@ -508,7 +505,6 @@
 
 	j.classpathFile = outputFile
 
-	// TODO(ccross): handle hostdex
 	if ctx.Device() && j.installable() {
 		dxFlags := j.deviceProperties.Dxflags
 		if false /* emma enabled */ {
@@ -622,7 +618,6 @@
 		if !installable {
 			module.properties.Installable = proptools.BoolPtr(false)
 		}
-		module.deviceProperties.Dex = true
 
 		module.AddProperties(
 			&module.Module.properties,
@@ -680,8 +675,6 @@
 func BinaryFactory() android.Module {
 	module := &Binary{}
 
-	module.deviceProperties.Dex = true
-
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
diff --git a/java/java_test.go b/java/java_test.go
index 4034340..a86973d 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -52,7 +52,7 @@
 }
 
 func testJava(t *testing.T, bp string) *android.TestContext {
-	config := android.TestArchConfig(buildDir)
+	config := android.TestArchConfig(buildDir, nil)
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
diff --git a/python/python_test.go b/python/python_test.go
index 8737302..176c6ec 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -450,7 +450,7 @@
 		t.Fatal(err)
 	}
 
-	config = android.TestConfig(buildDir)
+	config = android.TestConfig(buildDir, nil)
 
 	return
 }
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 34c21f7..d1b4943 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -27,11 +27,11 @@
         "cleanbuild.go",
         "config.go",
         "context.go",
+        "dumpvars.go",
         "environment.go",
         "exec.go",
         "finder.go",
         "kati.go",
-        "make.go",
         "ninja.go",
         "proc_sync.go",
         "signal.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 45d18e0..0df22b3 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -104,7 +104,7 @@
 
 func help(ctx Context, config Config, what int) {
 	cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
-	cmd.Sandbox = makeSandbox
+	cmd.Sandbox = dumpvarsSandbox
 	cmd.Stdout = ctx.Stdout()
 	cmd.Stderr = ctx.Stderr()
 	cmd.RunOrFatal()
diff --git a/ui/build/config.go b/ui/build/config.go
index 2b0da4d..c8d7292 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -437,21 +437,13 @@
 	}
 }
 
-func (c *configImpl) HostAsan() bool {
+func (c *configImpl) PrebuiltBuildTool(name string) string {
 	if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
 		if sanitize := strings.Fields(v); inList("address", sanitize) {
-			return true
-		}
-	}
-	return false
-}
-
-func (c *configImpl) PrebuiltBuildTool(name string) string {
-	// (b/36182021) We're seeing rare ckati crashes, so always enable asan kati on the build servers.
-	if c.HostAsan() || (c.Dist() && name == "ckati") {
-		asan := filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "asan/bin", name)
-		if _, err := os.Stat(asan); err == nil {
-			return asan
+			asan := filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "asan/bin", name)
+			if _, err := os.Stat(asan); err == nil {
+				return asan
+			}
 		}
 	}
 	return filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "bin", name)
diff --git a/ui/build/make.go b/ui/build/dumpvars.go
similarity index 82%
rename from ui/build/make.go
rename to ui/build/dumpvars.go
index edf6d96..e6c3f56 100644
--- a/ui/build/make.go
+++ b/ui/build/dumpvars.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"path/filepath"
 	"strings"
 )
 
@@ -28,27 +27,29 @@
 // Make without actually building them. So all the variables based on
 // MAKECMDGOALS can be read.
 //
-// extra_targets adds real arguments to the make command, in case other targets
-// actually need to be run (like the Soong config generator).
-//
 // vars is the list of variables to read. The values will be put in the
 // returned map.
-func DumpMakeVars(ctx Context, config Config, goals, extra_targets, vars []string) (map[string]string, error) {
+func DumpMakeVars(ctx Context, config Config, goals, vars []string) (map[string]string, error) {
+	return dumpMakeVars(ctx, config, goals, vars, false)
+}
+
+func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool) (map[string]string, error) {
 	ctx.BeginTrace("dumpvars")
 	defer ctx.EndTrace()
 
-	cmd := Command(ctx, config, "make",
-		"make",
-		"--no-print-directory",
-		"-f", "build/core/config.mk",
+	cmd := Command(ctx, config, "dumpvars",
+		config.PrebuiltBuildTool("ckati"),
+		"-f", "build/make/core/config.mk",
+		"--color_warnings",
 		"dump-many-vars",
-		"CALLED_FROM_SETUP=true",
-		"BUILD_SYSTEM=build/core",
-		"MAKECMDGOALS="+strings.Join(goals, " "),
-		"DUMP_MANY_VARS="+strings.Join(vars, " "),
-		"OUT_DIR="+config.OutDir())
-	cmd.Args = append(cmd.Args, extra_targets...)
-	cmd.Sandbox = makeSandbox
+		"MAKECMDGOALS="+strings.Join(goals, " "))
+	cmd.Environment.Set("CALLED_FROM_SETUP", "true")
+	cmd.Environment.Set("BUILD_SYSTEM", "build/make/core")
+	if write_soong_vars {
+		cmd.Environment.Set("WRITE_SOONG_VARIABLES", "true")
+	}
+	cmd.Environment.Set("DUMP_MANY_VARS", strings.Join(vars, " "))
+	cmd.Sandbox = dumpvarsSandbox
 	// TODO: error out when Stderr contains any content
 	cmd.Stderr = ctx.Stderr()
 	output, err := cmd.Output()
@@ -136,9 +137,7 @@
 		"TARGET_DEVICE",
 	}, exportEnvVars...), bannerVars...)
 
-	make_vars, err := DumpMakeVars(ctx, config, config.Arguments(), []string{
-		filepath.Join(config.SoongOutDir(), "soong.variables"),
-	}, allVars)
+	make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true)
 	if err != nil {
 		ctx.Fatalln("Error dumping make vars:", err)
 	}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index cc02c76..7bb721d 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -77,7 +77,8 @@
 		"--color_warnings",
 		"--gen_all_targets",
 		"--werror_find_emulator",
-		"-f", "build/core/main.mk",
+		"--kati_stats",
+		"-f", "build/make/core/main.mk",
 	}
 
 	if !config.Environment().IsFalse("KATI_EMULATE_FIND") {
@@ -109,6 +110,7 @@
 }
 
 var katiIncludeRe = regexp.MustCompile(`^(\[\d+/\d+] )?including [^ ]+ ...$`)
+var katiLogRe = regexp.MustCompile(`^\*kati\*: `)
 
 func katiRewriteOutput(ctx Context, pipe io.ReadCloser) {
 	haveBlankLine := true
@@ -119,6 +121,12 @@
 		line := scanner.Text()
 		verbose := katiIncludeRe.MatchString(line)
 
+		// Only put kati debug/stat lines in our verbose log
+		if katiLogRe.MatchString(line) {
+			ctx.Verbose(line)
+			continue
+		}
+
 		// For verbose lines, write them on the current line without a newline,
 		// then overwrite them if the next thing we're printing is another
 		// verbose line.
diff --git a/ui/build/sandbox_darwin.go b/ui/build/sandbox_darwin.go
index 60407d4..2cf6e20 100644
--- a/ui/build/sandbox_darwin.go
+++ b/ui/build/sandbox_darwin.go
@@ -24,7 +24,7 @@
 const (
 	noSandbox            = ""
 	globalSandbox        = "build/soong/ui/build/sandbox/darwin/global.sb"
-	makeSandbox          = globalSandbox
+	dumpvarsSandbox      = globalSandbox
 	soongSandbox         = globalSandbox
 	katiSandbox          = globalSandbox
 	katiCleanSpecSandbox = globalSandbox
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 6615d37..f2bfac2 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -19,7 +19,7 @@
 const (
 	noSandbox            = false
 	globalSandbox        = false
-	makeSandbox          = false
+	dumpvarsSandbox      = false
 	soongSandbox         = false
 	katiSandbox          = false
 	katiCleanSpecSandbox = false