Merge "Add cc_*.target.recovery.static_libs"
diff --git a/Android.bp b/Android.bp
index 1b68adb..62b0fd4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -81,6 +81,7 @@
     ],
     testSrcs: [
         "android/android_test.go",
+        "android/androidmk_test.go",
         "android/arch_test.go",
         "android/config_test.go",
         "android/expand_test.go",
@@ -177,6 +178,7 @@
         "cc/linker.go",
 
         "cc/binary.go",
+        "cc/fuzz.go",
         "cc/library.go",
         "cc/object.go",
         "cc/test.go",
@@ -291,6 +293,7 @@
         "java/testing.go",
     ],
     testSrcs: [
+        "java/androidmk_test.go",
         "java/app_test.go",
         "java/device_host_converter_test.go",
         "java/dexpreopt_test.go",
diff --git a/README.md b/README.md
index 531ef4c..60d7d5a 100644
--- a/README.md
+++ b/README.md
@@ -236,6 +236,11 @@
 If no `default_visibility` property can be found then the module uses the
 global default of `//visibility:legacy_public`.
 
+The `visibility` property has no effect on a defaults module although it does
+apply to any non-defaults module that uses it. To set the visibility of a
+defaults module, use the `defaults_visibility` property on the defaults module;
+not to be confused with the `default_visibility` property on the package module.
+
 Once the build has been completely switched over to soong it is possible that a
 global refactoring will be done to change this to `//visibility:private` at
 which point all packages that do not currently specify a `default_visibility`
diff --git a/android/androidmk.go b/android/androidmk.go
index 7d0aa3b..1f1bd70 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -191,15 +191,7 @@
 		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
 		if archStr != "common" {
 			if amod.Target().NativeBridge {
-				// TODO: Unhardcode these rules.
-				guestArchStr := archStr
-				hostArchStr := ""
-				if guestArchStr == "arm" {
-					hostArchStr = "x86"
-				} else if guestArchStr == "arm64" {
-					hostArchStr = "x86_64"
-				}
-
+				hostArchStr := amod.Target().NativeBridgeHostArchName
 				if hostArchStr != "" {
 					a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
 				}
@@ -216,7 +208,10 @@
 		}
 		a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific))
 		a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific))
-		a.SetBoolIfTrue("LOCAL_PRODUCT_SERVICES_MODULE", Bool(amod.commonProperties.Product_services_specific))
+		// TODO(b/135957588) product_services_specific is matched to LOCAL_PRODUCT_MODULE
+		// as a workaround. Remove this after clearing all Android.bp
+		a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_services_specific))
+		a.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(amod.commonProperties.System_ext_specific))
 		if amod.commonProperties.Owner != nil {
 			a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner)
 		}
@@ -388,6 +383,31 @@
 	return nil
 }
 
+func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) {
+	// Get the preamble content through AndroidMkEntries logic.
+	entries := AndroidMkEntries{
+		Class:           data.Class,
+		SubName:         data.SubName,
+		DistFile:        data.DistFile,
+		OutputFile:      data.OutputFile,
+		Disabled:        data.Disabled,
+		Include:         data.Include,
+		Required:        data.Required,
+		Host_required:   data.Host_required,
+		Target_required: data.Target_required,
+	}
+	entries.fillInEntries(config, bpPath, mod)
+
+	// preamble doesn't need the footer content.
+	entries.footer = bytes.Buffer{}
+	entries.write(&data.preamble)
+
+	// copy entries back to data since it is used in Custom
+	data.Required = entries.Required
+	data.Host_required = entries.Host_required
+	data.Target_required = entries.Target_required
+}
+
 func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
 	provider AndroidMkDataProvider) error {
 
@@ -401,22 +421,7 @@
 		data.Include = "$(BUILD_PREBUILT)"
 	}
 
-	// Get the preamble content through AndroidMkEntries logic.
-	entries := AndroidMkEntries{
-		Class:           data.Class,
-		SubName:         data.SubName,
-		DistFile:        data.DistFile,
-		OutputFile:      data.OutputFile,
-		Disabled:        data.Disabled,
-		Include:         data.Include,
-		Required:        data.Required,
-		Host_required:   data.Host_required,
-		Target_required: data.Target_required,
-	}
-	entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
-	// preamble doesn't need the footer content.
-	entries.footer = bytes.Buffer{}
-	entries.write(&data.preamble)
+	data.fillInData(ctx.Config(), ctx.BlueprintFile(mod), mod)
 
 	prefix := ""
 	if amod.ArchSpecific() {
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
new file mode 100644
index 0000000..0bb455b
--- /dev/null
+++ b/android/androidmk_test.go
@@ -0,0 +1,82 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"io"
+	"reflect"
+	"testing"
+)
+
+type customModule struct {
+	ModuleBase
+	data AndroidMkData
+}
+
+func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *customModule) AndroidMk() AndroidMkData {
+	return AndroidMkData{
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
+			m.data = data
+		},
+	}
+}
+
+func customModuleFactory() Module {
+	module := &customModule{}
+	InitAndroidModule(module)
+	return module
+}
+
+func TestAndroidMkSingleton_PassesUpdatedAndroidMkDataToCustomCallback(t *testing.T) {
+	config := TestConfig(buildDir, nil)
+	config.inMake = true // Enable androidmk Singleton
+
+	ctx := NewTestContext()
+	ctx.RegisterSingletonType("androidmk", SingletonFactoryAdaptor(AndroidMkSingleton))
+	ctx.RegisterModuleType("custom", ModuleFactoryAdaptor(customModuleFactory))
+	ctx.Register()
+
+	bp := `
+	custom {
+		name: "foo",
+		required: ["bar"],
+		host_required: ["baz"],
+		target_required: ["qux"],
+	}
+	`
+
+	ctx.MockFileSystem(map[string][]byte{
+		"Android.bp": []byte(bp),
+	})
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	m := ctx.ModuleForTests("foo", "").Module().(*customModule)
+
+	assertEqual := func(expected interface{}, actual interface{}) {
+		if !reflect.DeepEqual(expected, actual) {
+			t.Errorf("%q expected, but got %q", expected, actual)
+		}
+	}
+	assertEqual([]string{"bar"}, m.data.Required)
+	assertEqual([]string{"baz"}, m.data.Host_required)
+	assertEqual([]string{"qux"}, m.data.Target_required)
+}
diff --git a/android/arch.go b/android/arch.go
index 46e582c..44c3f48 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -691,9 +691,11 @@
 )
 
 type Target struct {
-	Os           OsType
-	Arch         Arch
-	NativeBridge NativeBridgeSupport
+	Os                       OsType
+	Arch                     Arch
+	NativeBridge             NativeBridgeSupport
+	NativeBridgeHostArchName string
+	NativeBridgeRelativePath string
 }
 
 func (target Target) String() string {
@@ -1403,7 +1405,8 @@
 	var targetErr error
 
 	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string,
-		nativeBridgeEnabled NativeBridgeSupport) {
+		nativeBridgeEnabled NativeBridgeSupport, nativeBridgeHostArchName *string,
+		nativeBridgeRelativePath *string) {
 		if targetErr != nil {
 			return
 		}
@@ -1413,12 +1416,21 @@
 			targetErr = err
 			return
 		}
+		nativeBridgeRelativePathStr := String(nativeBridgeRelativePath)
+		nativeBridgeHostArchNameStr := String(nativeBridgeHostArchName)
+
+		// Use guest arch as relative install path by default
+		if nativeBridgeEnabled && nativeBridgeRelativePathStr == "" {
+			nativeBridgeRelativePathStr = arch.ArchType.String()
+		}
 
 		targets[os] = append(targets[os],
 			Target{
-				Os:           os,
-				Arch:         arch,
-				NativeBridge: nativeBridgeEnabled,
+				Os:                       os,
+				Arch:                     arch,
+				NativeBridge:             nativeBridgeEnabled,
+				NativeBridgeHostArchName: nativeBridgeHostArchNameStr,
+				NativeBridgeRelativePath: nativeBridgeRelativePathStr,
 			})
 	}
 
@@ -1426,14 +1438,14 @@
 		return nil, fmt.Errorf("No host primary architecture set")
 	}
 
-	addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled)
+	addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 
 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
-		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
+		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 	}
 
 	if Bool(config.Host_bionic) {
-		addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled)
+		addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled, nil, nil)
 	}
 
 	if String(variables.CrossHost) != "" {
@@ -1446,10 +1458,10 @@
 			return nil, fmt.Errorf("No cross-host primary architecture set")
 		}
 
-		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil, NativeBridgeDisabled)
+		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 
 		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
-			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
+			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 		}
 	}
 
@@ -1460,12 +1472,12 @@
 		}
 
 		addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
-			variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled)
+			variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled, nil, nil)
 
 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
 			addTarget(Android, *variables.DeviceSecondaryArch,
 				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
-				variables.DeviceSecondaryAbi, NativeBridgeDisabled)
+				variables.DeviceSecondaryAbi, NativeBridgeDisabled, nil, nil)
 
 			deviceArches := targets[Android]
 			if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
@@ -1476,7 +1488,8 @@
 		if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
 			addTarget(Android, *variables.NativeBridgeArch,
 				variables.NativeBridgeArchVariant, variables.NativeBridgeCpuVariant,
-				variables.NativeBridgeAbi, NativeBridgeEnabled)
+				variables.NativeBridgeAbi, NativeBridgeEnabled, variables.DeviceArch,
+				variables.NativeBridgeRelativePath)
 		}
 
 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
@@ -1484,7 +1497,10 @@
 			addTarget(Android, *variables.NativeBridgeSecondaryArch,
 				variables.NativeBridgeSecondaryArchVariant,
 				variables.NativeBridgeSecondaryCpuVariant,
-				variables.NativeBridgeSecondaryAbi, NativeBridgeEnabled)
+				variables.NativeBridgeSecondaryAbi,
+				NativeBridgeEnabled,
+				variables.DeviceSecondaryArch,
+				variables.NativeBridgeSecondaryRelativePath)
 		}
 	}
 
diff --git a/android/config.go b/android/config.go
index e4012fa..074dfc7 100644
--- a/android/config.go
+++ b/android/config.go
@@ -240,10 +240,10 @@
 	config := testConfig.config
 
 	config.Targets[Android] = []Target{
-		{Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
-		{Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
-		{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled},
-		{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled},
+		{Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
+		{Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""},
+		{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64"},
+		{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm"},
 	}
 
 	return testConfig
@@ -255,10 +255,10 @@
 
 	config.Targets = map[OsType][]Target{
 		Fuchsia: []Target{
-			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}, NativeBridgeDisabled},
+			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}, NativeBridgeDisabled, "", ""},
 		},
 		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
 		},
 	}
 
@@ -272,12 +272,12 @@
 
 	config.Targets = map[OsType][]Target{
 		Android: []Target{
-			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
-			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
+			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
+			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""},
 		},
 		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
-			{BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
+			{BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled, "", ""},
 		},
 	}
 
@@ -748,10 +748,22 @@
 	return Bool(c.productVariables.UseGoma)
 }
 
+func (c *config) UseRBE() bool {
+	return Bool(c.productVariables.UseRBE)
+}
+
 func (c *config) RunErrorProne() bool {
 	return c.IsEnvTrue("RUN_ERROR_PRONE")
 }
 
+func (c *config) XrefCorpusName() string {
+	return c.Getenv("XREF_CORPUS")
+}
+
+func (c *config) EmitXrefRules() bool {
+	return c.XrefCorpusName() != ""
+}
+
 // Returns true if -source 1.9 -target 1.9 is being passed to javac
 func (c *config) TargetOpenJDK9() bool {
 	return c.targetOpenJDK9
@@ -901,11 +913,11 @@
 	return "product"
 }
 
-func (c *deviceConfig) ProductServicesPath() string {
-	if c.config.productVariables.ProductServicesPath != nil {
-		return *c.config.productVariables.ProductServicesPath
+func (c *deviceConfig) SystemExtPath() string {
+	if c.config.productVariables.SystemExtPath != nil {
+		return *c.config.productVariables.SystemExtPath
 	}
-	return "product_services"
+	return "system_ext"
 }
 
 func (c *deviceConfig) BtConfigIncludeDir() string {
diff --git a/android/defaults.go b/android/defaults.go
index 844b4d4..f489c02 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -42,9 +42,16 @@
 	d.defaultableProperties = props
 }
 
+// Interface that must be supported by any module to which defaults can be applied.
 type Defaultable interface {
+	// Get a pointer to the struct containing the Defaults property.
 	defaults() *defaultsProperties
+
+	// Set the property structures into which defaults will be added.
 	setProperties([]interface{})
+
+	// Apply defaults from the supplied Defaults to the property structures supplied to
+	// setProperties(...).
 	applyDefaults(TopDownMutatorContext, []Defaults)
 }
 
@@ -56,45 +63,118 @@
 var _ Defaultable = (*DefaultableModuleBase)(nil)
 
 func InitDefaultableModule(module DefaultableModule) {
-	module.(Defaultable).setProperties(module.(Module).GetProperties())
+	module.setProperties(module.(Module).GetProperties())
 
 	module.AddProperties(module.defaults())
 }
 
-type DefaultsModuleBase struct {
-	DefaultableModuleBase
-	defaultProperties []interface{}
+// The Defaults_visibility property.
+type DefaultsVisibilityProperties struct {
+
+	// Controls the visibility of the defaults module itself.
+	Defaults_visibility []string
 }
 
+type DefaultsModuleBase struct {
+	DefaultableModuleBase
+
+	// Container for defaults of the common properties
+	commonProperties commonProperties
+
+	defaultsVisibilityProperties DefaultsVisibilityProperties
+}
+
+// The common pattern for defaults modules is to register separate instances of
+// the xxxProperties structs in the AddProperties calls, rather than reusing the
+// ones inherited from Module.
+//
+// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't
+// contain the values that have been set for the defaults module. Rather, to
+// retrieve the values it is necessary to iterate over properties(). E.g. to get
+// the commonProperties instance that have the real values:
+//
+//   d := myModule.(Defaults)
+//   for _, props := range d.properties() {
+//     if cp, ok := props.(*commonProperties); ok {
+//       ... access property values in cp ...
+//     }
+//   }
+//
+// The rationale is that the properties on a defaults module apply to the
+// defaultable modules using it, not to the defaults module itself. E.g. setting
+// the "enabled" property false makes inheriting modules disabled by default,
+// rather than disabling the defaults module itself.
 type Defaults interface {
 	Defaultable
+
+	// Although this function is unused it is actually needed to ensure that only modules that embed
+	// DefaultsModuleBase will type-assert to the Defaults interface.
 	isDefaults() bool
+
+	// Get the structures containing the properties for which defaults can be provided.
 	properties() []interface{}
+
+	// Return the defaults common properties.
+	common() *commonProperties
+
+	// Return the defaults visibility properties.
+	defaultsVisibility() *DefaultsVisibilityProperties
 }
 
 func (d *DefaultsModuleBase) isDefaults() bool {
 	return true
 }
 
+type DefaultsModule interface {
+	Module
+	Defaults
+}
+
 func (d *DefaultsModuleBase) properties() []interface{} {
 	return d.defaultableProperties
 }
 
+func (d *DefaultsModuleBase) common() *commonProperties {
+	return &d.commonProperties
+}
+
+func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties {
+	return &d.defaultsVisibilityProperties
+}
+
 func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
 }
 
-func InitDefaultsModule(module DefaultableModule) {
+func InitDefaultsModule(module DefaultsModule) {
+	commonProperties := module.common()
+
 	module.AddProperties(
 		&hostAndDeviceProperties{},
-		&commonProperties{},
+		commonProperties,
 		&variableProperties{})
 
 	InitArchModule(module)
 	InitDefaultableModule(module)
 
-	module.AddProperties(&module.base().nameProperties)
+	// Add properties that will not have defaults applied to them.
+	base := module.base()
+	defaultsVisibility := module.defaultsVisibility()
+	module.AddProperties(&base.nameProperties, defaultsVisibility)
 
-	module.base().module = module
+	// The defaults_visibility property controls the visibility of a defaults module.
+	base.primaryVisibilityProperty =
+		newVisibilityProperty("defaults_visibility", &defaultsVisibility.Defaults_visibility)
+
+	// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
+	// Instead it is stored in a separate instance of commonProperties created above so use that.
+	// The visibility property needs to be checked (but not parsed) by the visibility module during
+	// its checking phase and parsing phase.
+	base.visibilityPropertyInfo = []visibilityProperty{
+		base.primaryVisibilityProperty,
+		newVisibilityProperty("visibility", &commonProperties.Visibility),
+	}
+
+	base.module = module
 }
 
 var _ Defaults = (*DefaultsModuleBase)(nil)
diff --git a/android/expand.go b/android/expand.go
index 527c4ac..67fb4ee 100644
--- a/android/expand.go
+++ b/android/expand.go
@@ -18,12 +18,30 @@
 	"fmt"
 	"strings"
 	"unicode"
+
+	"github.com/google/blueprint/proptools"
 )
 
+// ExpandNinjaEscaped substitutes $() variables in a string
+// $(var) is passed to mapping(var), which should return the expanded value, a bool for whether the result should
+// be left unescaped when using in a ninja value (generally false, true if the expanded value is a ninja variable like
+// '${in}'), and an error.
+// $$ is converted to $, which is escaped back to $$.
+func ExpandNinjaEscaped(s string, mapping func(string) (string, bool, error)) (string, error) {
+	return expand(s, true, mapping)
+}
+
 // Expand substitutes $() variables in a string
-// $(var) is passed to Expander(var)
-// $$ is converted to $
+// $(var) is passed to mapping(var), which should return the expanded value and an error.
+// $$ is converted to $.
 func Expand(s string, mapping func(string) (string, error)) (string, error) {
+	return expand(s, false, func(s string) (string, bool, error) {
+		s, err := mapping(s)
+		return s, false, err
+	})
+}
+
+func expand(s string, ninjaEscape bool, mapping func(string) (string, bool, error)) (string, error) {
 	// based on os.Expand
 	buf := make([]byte, 0, 2*len(s))
 	i := 0
@@ -33,10 +51,13 @@
 				return "", fmt.Errorf("expected character after '$'")
 			}
 			buf = append(buf, s[i:j]...)
-			value, w, err := getMapping(s[j+1:], mapping)
+			value, ninjaVariable, w, err := getMapping(s[j+1:], mapping)
 			if err != nil {
 				return "", err
 			}
+			if !ninjaVariable && ninjaEscape {
+				value = proptools.NinjaEscape(value)
+			}
 			buf = append(buf, value...)
 			j += w
 			i = j + 1
@@ -45,26 +66,26 @@
 	return string(buf) + s[i:], nil
 }
 
-func getMapping(s string, mapping func(string) (string, error)) (string, int, error) {
+func getMapping(s string, mapping func(string) (string, bool, error)) (string, bool, int, error) {
 	switch s[0] {
 	case '(':
 		// Scan to closing brace
 		for i := 1; i < len(s); i++ {
 			if s[i] == ')' {
-				ret, err := mapping(strings.TrimSpace(s[1:i]))
-				return ret, i + 1, err
+				ret, ninjaVariable, err := mapping(strings.TrimSpace(s[1:i]))
+				return ret, ninjaVariable, i + 1, err
 			}
 		}
-		return "", len(s), fmt.Errorf("missing )")
+		return "", false, len(s), fmt.Errorf("missing )")
 	case '$':
-		return "$$", 1, nil
+		return "$", false, 1, nil
 	default:
 		i := strings.IndexFunc(s, unicode.IsSpace)
 		if i == 0 {
-			return "", 0, fmt.Errorf("unexpected character '%c' after '$'", s[0])
+			return "", false, 0, fmt.Errorf("unexpected character '%c' after '$'", s[0])
 		} else if i == -1 {
 			i = len(s)
 		}
-		return "", 0, fmt.Errorf("expected '(' after '$', did you mean $(%s)?", s[:i])
+		return "", false, 0, fmt.Errorf("expected '(' after '$', did you mean $(%s)?", s[:i])
 	}
 }
diff --git a/android/expand_test.go b/android/expand_test.go
index 128de8a..12179ed 100644
--- a/android/expand_test.go
+++ b/android/expand_test.go
@@ -20,88 +20,111 @@
 )
 
 var vars = map[string]string{
-	"var1": "abc",
-	"var2": "",
-	"var3": "def",
-	"💩":    "😃",
+	"var1":   "abc",
+	"var2":   "",
+	"var3":   "def",
+	"💩":      "😃",
+	"escape": "${in}",
 }
 
-func expander(s string) (string, error) {
+func expander(s string) (string, bool, error) {
 	if val, ok := vars[s]; ok {
-		return val, nil
+		return val, s == "escape", nil
 	} else {
-		return "", fmt.Errorf("unknown variable %q", s)
+		return "", false, fmt.Errorf("unknown variable %q", s)
 	}
 }
 
 var expandTestCases = []struct {
-	in  string
-	out string
-	err bool
+	in          string
+	out         string
+	out_escaped string
+	err         bool
 }{
 	{
-		in:  "$(var1)",
-		out: "abc",
+		in:          "$(var1)",
+		out:         "abc",
+		out_escaped: "abc",
 	},
 	{
-		in:  "$( var1 )",
-		out: "abc",
+		in:          "$( var1 )",
+		out:         "abc",
+		out_escaped: "abc",
 	},
 	{
-		in:  "def$(var1)",
-		out: "defabc",
+		in:          "def$(var1)",
+		out:         "defabc",
+		out_escaped: "defabc",
 	},
 	{
-		in:  "$(var1)def",
-		out: "abcdef",
+		in:          "$(var1)def",
+		out:         "abcdef",
+		out_escaped: "abcdef",
 	},
 	{
-		in:  "def$(var1)def",
-		out: "defabcdef",
+		in:          "def$(var1)def",
+		out:         "defabcdef",
+		out_escaped: "defabcdef",
 	},
 	{
-		in:  "$(var2)",
-		out: "",
+		in:          "$(var2)",
+		out:         "",
+		out_escaped: "",
 	},
 	{
-		in:  "def$(var2)",
-		out: "def",
+		in:          "def$(var2)",
+		out:         "def",
+		out_escaped: "def",
 	},
 	{
-		in:  "$(var2)def",
-		out: "def",
+		in:          "$(var2)def",
+		out:         "def",
+		out_escaped: "def",
 	},
 	{
-		in:  "def$(var2)def",
-		out: "defdef",
+		in:          "def$(var2)def",
+		out:         "defdef",
+		out_escaped: "defdef",
 	},
 	{
-		in:  "$(var1)$(var3)",
-		out: "abcdef",
+		in:          "$(var1)$(var3)",
+		out:         "abcdef",
+		out_escaped: "abcdef",
 	},
 	{
-		in:  "$(var1)g$(var3)",
-		out: "abcgdef",
+		in:          "$(var1)g$(var3)",
+		out:         "abcgdef",
+		out_escaped: "abcgdef",
 	},
 	{
-		in:  "$$",
-		out: "$$",
+		in:          "$$",
+		out:         "$",
+		out_escaped: "$$",
 	},
 	{
-		in:  "$$(var1)",
-		out: "$$(var1)",
+		in:          "$$(var1)",
+		out:         "$(var1)",
+		out_escaped: "$$(var1)",
 	},
 	{
-		in:  "$$$(var1)",
-		out: "$$abc",
+		in:          "$$$(var1)",
+		out:         "$abc",
+		out_escaped: "$$abc",
 	},
 	{
-		in:  "$(var1)$$",
-		out: "abc$$",
+		in:          "$(var1)$$",
+		out:         "abc$",
+		out_escaped: "abc$$",
 	},
 	{
-		in:  "$(💩)",
-		out: "😃",
+		in:          "$(💩)",
+		out:         "😃",
+		out_escaped: "😃",
+	},
+	{
+		in:          "$$a$(escape)$$b",
+		out:         "$a${in}$b",
+		out_escaped: "$$a${in}$$b",
 	},
 
 	// Errors
@@ -141,7 +164,10 @@
 
 func TestExpand(t *testing.T) {
 	for _, test := range expandTestCases {
-		got, err := Expand(test.in, expander)
+		got, err := Expand(test.in, func(s string) (string, error) {
+			s, _, err := expander(s)
+			return s, err
+		})
 		if err != nil && !test.err {
 			t.Errorf("%q: unexpected error %s", test.in, err.Error())
 		} else if err == nil && test.err {
@@ -151,3 +177,16 @@
 		}
 	}
 }
+
+func TestExpandNinjaEscaped(t *testing.T) {
+	for _, test := range expandTestCases {
+		got, err := ExpandNinjaEscaped(test.in, expander)
+		if err != nil && !test.err {
+			t.Errorf("%q: unexpected error %s", test.in, err.Error())
+		} else if err == nil && test.err {
+			t.Errorf("%q: expected error, got %q", test.in, got)
+		} else if !test.err && got != test.out_escaped {
+			t.Errorf("%q: expected %q, got %q", test.in, test.out, got)
+		}
+	}
+}
diff --git a/android/module.go b/android/module.go
index 2d4c1b5..138b9cd 100644
--- a/android/module.go
+++ b/android/module.go
@@ -126,7 +126,7 @@
 	DeviceSpecific() bool
 	SocSpecific() bool
 	ProductSpecific() bool
-	ProductServicesSpecific() bool
+	SystemExtSpecific() bool
 	AConfig() Config
 	DeviceConfig() DeviceConfig
 }
@@ -211,6 +211,9 @@
 
 	// Get information about the properties that can contain visibility rules.
 	visibilityProperties() []visibilityProperty
+
+	// Get the visibility rules that control the visibility of this module.
+	visibility() []string
 }
 
 // Qualified id for a module
@@ -302,6 +305,11 @@
 	// If no `default_visibility` property can be found then the module uses the
 	// global default of `//visibility:legacy_public`.
 	//
+	// The `visibility` property has no effect on a defaults module although it does
+	// apply to any non-defaults module that uses it. To set the visibility of a
+	// defaults module, use the `defaults_visibility` property on the defaults module;
+	// not to be confused with the `default_visibility` property on the package module.
+	//
 	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
 	// more details.
 	Visibility []string
@@ -350,11 +358,15 @@
 	// /system/product if product partition does not exist).
 	Product_specific *bool
 
-	// whether this module provides services owned by the OS provider to the core platform. When set
-	// to true, it is installed into  /product_services (or /system/product_services if
-	// product_services partition does not exist).
+	// TODO(b/135957588) Product_services_specific will be removed once we clear all Android.bp
+	// files that have 'product_services_specific: true'. This will be converted to
+	// Product_speicific as a workaround.
 	Product_services_specific *bool
 
+	// whether this module extends system. When set to true, it is installed into /system_ext
+	// (or /system/system_ext if system_ext partition does not exist).
+	System_ext_specific *bool
+
 	// Whether this module is installed to recovery partition
 	Recovery *bool
 
@@ -469,7 +481,7 @@
 	deviceSpecificModule
 	socSpecificModule
 	productSpecificModule
-	productServicesSpecificModule
+	systemExtSpecificModule
 )
 
 func (k moduleKind) String() string {
@@ -482,8 +494,8 @@
 		return "soc-specific"
 	case productSpecificModule:
 		return "product-specific"
-	case productServicesSpecificModule:
-		return "productservices-specific"
+	case systemExtSpecificModule:
+		return "systemext-specific"
 	default:
 		panic(fmt.Errorf("unknown module kind %d", k))
 	}
@@ -499,6 +511,12 @@
 		&base.variableProperties)
 	base.generalProperties = m.GetProperties()
 	base.customizableProperties = m.GetProperties()
+
+	// The default_visibility property needs to be checked and parsed by the visibility module during
+	// its checking and parsing phases.
+	base.primaryVisibilityProperty =
+		newVisibilityProperty("visibility", &base.commonProperties.Visibility)
+	base.visibilityPropertyInfo = []visibilityProperty{base.primaryVisibilityProperty}
 }
 
 func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
@@ -578,6 +596,13 @@
 	archProperties          [][]interface{}
 	customizableProperties  []interface{}
 
+	// Information about all the properties on the module that contains visibility rules that need
+	// checking.
+	visibilityPropertyInfo []visibilityProperty
+
+	// The primary visibility property, may be nil, that controls access to the module.
+	primaryVisibilityProperty visibilityProperty
+
 	noAddressSanitizer bool
 	installFiles       Paths
 	checkbuildFiles    Paths
@@ -664,10 +689,15 @@
 }
 
 func (m *ModuleBase) visibilityProperties() []visibilityProperty {
-	return []visibilityProperty{
-		newVisibilityProperty("visibility", func() []string {
-			return m.base().commonProperties.Visibility
-		}),
+	return m.visibilityPropertyInfo
+}
+
+func (m *ModuleBase) visibility() []string {
+	// The soong_namespace module does not initialize the primaryVisibilityProperty.
+	if m.primaryVisibilityProperty != nil {
+		return m.primaryVisibilityProperty.getStrings()
+	} else {
+		return nil
 	}
 }
 
@@ -738,7 +768,7 @@
 }
 
 func (m *ModuleBase) Platform() bool {
-	return !m.DeviceSpecific() && !m.SocSpecific() && !m.ProductSpecific() && !m.ProductServicesSpecific()
+	return !m.DeviceSpecific() && !m.SocSpecific() && !m.ProductSpecific() && !m.SystemExtSpecific()
 }
 
 func (m *ModuleBase) DeviceSpecific() bool {
@@ -753,8 +783,8 @@
 	return Bool(m.commonProperties.Product_specific)
 }
 
-func (m *ModuleBase) ProductServicesSpecific() bool {
-	return Bool(m.commonProperties.Product_services_specific)
+func (m *ModuleBase) SystemExtSpecific() bool {
+	return Bool(m.commonProperties.System_ext_specific)
 }
 
 func (m *ModuleBase) Enabled() bool {
@@ -875,7 +905,7 @@
 	var socSpecific = Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific)
 	var deviceSpecific = Bool(m.commonProperties.Device_specific)
 	var productSpecific = Bool(m.commonProperties.Product_specific)
-	var productServicesSpecific = Bool(m.commonProperties.Product_services_specific)
+	var systemExtSpecific = Bool(m.commonProperties.System_ext_specific)
 
 	msg := "conflicting value set here"
 	if socSpecific && deviceSpecific {
@@ -891,16 +921,16 @@
 		}
 	}
 
-	if productSpecific && productServicesSpecific {
-		ctx.PropertyErrorf("product_specific", "a module cannot be specific to product and product_services at the same time.")
-		ctx.PropertyErrorf("product_services_specific", msg)
+	if productSpecific && systemExtSpecific {
+		ctx.PropertyErrorf("product_specific", "a module cannot be specific to product and system_ext at the same time.")
+		ctx.PropertyErrorf("system_ext_specific", msg)
 	}
 
-	if (socSpecific || deviceSpecific) && (productSpecific || productServicesSpecific) {
+	if (socSpecific || deviceSpecific) && (productSpecific || systemExtSpecific) {
 		if productSpecific {
 			ctx.PropertyErrorf("product_specific", "a module cannot be specific to SoC or device and product at the same time.")
 		} else {
-			ctx.PropertyErrorf("product_services_specific", "a module cannot be specific to SoC or device and product_services at the same time.")
+			ctx.PropertyErrorf("system_ext_specific", "a module cannot be specific to SoC or device and system_ext at the same time.")
 		}
 		if deviceSpecific {
 			ctx.PropertyErrorf("device_specific", msg)
@@ -919,8 +949,8 @@
 
 	if productSpecific {
 		return productSpecificModule
-	} else if productServicesSpecific {
-		return productServicesSpecificModule
+	} else if systemExtSpecific {
+		return systemExtSpecificModule
 	} else if deviceSpecific {
 		return deviceSpecificModule
 	} else if socSpecific {
@@ -1433,18 +1463,18 @@
 	return b.kind == productSpecificModule
 }
 
-func (b *baseModuleContext) ProductServicesSpecific() bool {
-	return b.kind == productServicesSpecificModule
+func (b *baseModuleContext) SystemExtSpecific() bool {
+	return b.kind == systemExtSpecificModule
 }
 
 // Makes this module a platform module, i.e. not specific to soc, device,
-// product, or product_services.
+// product, or system_ext.
 func (m *ModuleBase) MakeAsPlatform() {
 	m.commonProperties.Vendor = boolPtr(false)
 	m.commonProperties.Proprietary = boolPtr(false)
 	m.commonProperties.Soc_specific = boolPtr(false)
 	m.commonProperties.Product_specific = boolPtr(false)
-	m.commonProperties.Product_services_specific = boolPtr(false)
+	m.commonProperties.System_ext_specific = boolPtr(false)
 }
 
 func (m *ModuleBase) EnableNativeBridgeSupportByDefault() {
diff --git a/android/mutator.go b/android/mutator.go
index b799432..82376e4 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -243,7 +243,8 @@
 }
 
 func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) {
-	t.bp.CreateModule(factory, props...)
+	common := []interface{}{&t.Module().base().commonProperties}
+	t.bp.CreateModule(factory, append(common, props...)...)
 }
 
 func (b *bottomUpMutatorContext) MutatorName() string {
diff --git a/android/neverallow.go b/android/neverallow.go
index 1893e8b..23b6454 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -48,6 +48,7 @@
 var neverallows = []Rule{}
 
 func init() {
+	AddNeverAllowRules(createIncludeDirsRules()...)
 	AddNeverAllowRules(createTrebleRules()...)
 	AddNeverAllowRules(createLibcoreRules()...)
 	AddNeverAllowRules(createJavaDeviceForHostRules()...)
@@ -58,6 +59,42 @@
 	neverallows = append(neverallows, rules...)
 }
 
+func createIncludeDirsRules() []Rule {
+	// The list of paths that cannot be referenced using include_dirs
+	paths := []string{
+		"art",
+		"libcore",
+		"libnativehelper",
+		"external/apache-harmony",
+		"external/apache-xml",
+		"external/boringssl",
+		"external/bouncycastle",
+		"external/conscrypt",
+		"external/icu",
+		"external/okhttp",
+		"external/vixl",
+		"external/wycheproof",
+		"system/core/libnativebridge",
+		"system/core/libnativehelper",
+	}
+
+	// Create a composite matcher that will match if the value starts with any of the restricted
+	// paths. A / is appended to the prefix to ensure that restricting path X does not affect paths
+	// XY.
+	rules := make([]Rule, 0, len(paths))
+	for _, path := range paths {
+		rule :=
+			NeverAllow().
+				WithMatcher("include_dirs", StartsWith(path+"/")).
+				Because("include_dirs is deprecated, all usages of '" + path + "' have been migrated" +
+					" to use alternate mechanisms and so can no longer be used.")
+
+		rules = append(rules, rule)
+	}
+
+	return rules
+}
+
 func createTrebleRules() []Rule {
 	return []Rule{
 		NeverAllow().
@@ -156,9 +193,51 @@
 	}
 }
 
+type ValueMatcher interface {
+	test(string) bool
+	String() string
+}
+
+type equalMatcher struct {
+	expected string
+}
+
+func (m *equalMatcher) test(value string) bool {
+	return m.expected == value
+}
+
+func (m *equalMatcher) String() string {
+	return "=" + m.expected
+}
+
+type anyMatcher struct {
+}
+
+func (m *anyMatcher) test(value string) bool {
+	return true
+}
+
+func (m *anyMatcher) String() string {
+	return "=*"
+}
+
+var anyMatcherInstance = &anyMatcher{}
+
+type startsWithMatcher struct {
+	prefix string
+}
+
+func (m *startsWithMatcher) test(value string) bool {
+	return strings.HasPrefix(value, m.prefix)
+}
+
+func (m *startsWithMatcher) String() string {
+	return ".starts-with(" + m.prefix + ")"
+}
+
 type ruleProperty struct {
-	fields []string // e.x.: Vndk.Enabled
-	value  string   // e.x.: true
+	fields  []string // e.x.: Vndk.Enabled
+	matcher ValueMatcher
 }
 
 // A NeverAllow rule.
@@ -173,8 +252,12 @@
 
 	With(properties, value string) Rule
 
+	WithMatcher(properties string, matcher ValueMatcher) Rule
+
 	Without(properties, value string) Rule
 
+	WithoutMatcher(properties string, matcher ValueMatcher) Rule
+
 	Because(reason string) Rule
 }
 
@@ -218,21 +301,36 @@
 }
 
 func (r *rule) With(properties, value string) Rule {
+	return r.WithMatcher(properties, selectMatcher(value))
+}
+
+func (r *rule) WithMatcher(properties string, matcher ValueMatcher) Rule {
 	r.props = append(r.props, ruleProperty{
-		fields: fieldNamesForProperties(properties),
-		value:  value,
+		fields:  fieldNamesForProperties(properties),
+		matcher: matcher,
 	})
 	return r
 }
 
 func (r *rule) Without(properties, value string) Rule {
+	return r.WithoutMatcher(properties, selectMatcher(value))
+}
+
+func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule {
 	r.unlessProps = append(r.unlessProps, ruleProperty{
-		fields: fieldNamesForProperties(properties),
-		value:  value,
+		fields:  fieldNamesForProperties(properties),
+		matcher: matcher,
 	})
 	return r
 }
 
+func selectMatcher(expected string) ValueMatcher {
+	if expected == "*" {
+		return anyMatcherInstance
+	}
+	return &equalMatcher{expected: expected}
+}
+
 func (r *rule) Because(reason string) Rule {
 	r.reason = reason
 	return r
@@ -253,10 +351,10 @@
 		s += " -type:" + v
 	}
 	for _, v := range r.props {
-		s += " " + strings.Join(v.fields, ".") + "=" + v.value
+		s += " " + strings.Join(v.fields, ".") + v.matcher.String()
 	}
 	for _, v := range r.unlessProps {
-		s += " -" + strings.Join(v.fields, ".") + "=" + v.value
+		s += " -" + strings.Join(v.fields, ".") + v.matcher.String()
 	}
 	if len(r.reason) != 0 {
 		s += " which is restricted because " + r.reason
@@ -280,6 +378,10 @@
 	return includeProps && !excludeProps
 }
 
+func StartsWith(prefix string) ValueMatcher {
+	return &startsWithMatcher{prefix}
+}
+
 // assorted utils
 
 func cleanPaths(paths []string) []string {
@@ -338,8 +440,8 @@
 			continue
 		}
 
-		check := func(v string) bool {
-			return prop.value == "*" || prop.value == v
+		check := func(value string) bool {
+			return prop.matcher.test(value)
 		}
 
 		if matchValue(propertiesValue, check) {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index ee3c94f..02b4362 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -23,6 +23,29 @@
 	fs            map[string][]byte
 	expectedError string
 }{
+	// include_dir rule tests
+	{
+		name: "include_dir not allowed to reference art",
+		fs: map[string][]byte{
+			"other/Blueprints": []byte(`
+				cc_library {
+					name: "libother",
+					include_dirs: ["art/libdexfile/include"],
+				}`),
+		},
+		expectedError: "all usages of 'art' have been migrated",
+	},
+	{
+		name: "include_dir can reference another location",
+		fs: map[string][]byte{
+			"other/Blueprints": []byte(`
+				cc_library {
+					name: "libother",
+					include_dirs: ["another/include"],
+				}`),
+		},
+	},
+	// Treble rule tests
 	{
 		name: "no vndk.enabled under vendor directory",
 		fs: map[string][]byte{
@@ -217,6 +240,7 @@
 }
 
 type mockCcLibraryProperties struct {
+	Include_dirs     []string
 	Vendor_available *bool
 
 	Vndk struct {
diff --git a/android/notices.go b/android/notices.go
index dbb88fc..7b61d65 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -27,6 +27,13 @@
 	pctx.HostBinToolVariable("minigzip", "minigzip")
 }
 
+type NoticeOutputs struct {
+	Merged       OptionalPath
+	TxtOutput    OptionalPath
+	HtmlOutput   OptionalPath
+	HtmlGzOutput OptionalPath
+}
+
 var (
 	mergeNoticesRule = pctx.AndroidStaticRule("mergeNoticesRule", blueprint.RuleParams{
 		Command:     `${merge_notices} --output $out $in`,
@@ -35,13 +42,13 @@
 	})
 
 	generateNoticeRule = pctx.AndroidStaticRule("generateNoticeRule", blueprint.RuleParams{
-		Command: `rm -rf $tmpDir $$(dirname $out) && ` +
-			`mkdir -p $tmpDir $$(dirname $out) && ` +
-			`${generate_notice} --text-output $tmpDir/NOTICE.txt --html-output $tmpDir/NOTICE.html -t "$title" -s $inputDir && ` +
-			`${minigzip} -c $tmpDir/NOTICE.html > $out`,
+		Command: `rm -rf $$(dirname $txtOut) $$(dirname $htmlOut) $$(dirname $out) && ` +
+			`mkdir -p $$(dirname $txtOut) $$(dirname $htmlOut)  $$(dirname $out) && ` +
+			`${generate_notice} --text-output $txtOut --html-output $htmlOut -t "$title" -s $inputDir && ` +
+			`${minigzip} -c $htmlOut > $out`,
 		CommandDeps: []string{"${generate_notice}", "${minigzip}"},
 		Description: "produce notice file $out",
-	}, "tmpDir", "title", "inputDir")
+	}, "txtOut", "htmlOut", "title", "inputDir")
 )
 
 func MergeNotices(ctx ModuleContext, mergedNotice WritablePath, noticePaths []Path) {
@@ -54,7 +61,7 @@
 }
 
 func BuildNoticeOutput(ctx ModuleContext, installPath OutputPath, installFilename string,
-	noticePaths []Path) ModuleOutPath {
+	noticePaths []Path) NoticeOutputs {
 	// Merge all NOTICE files into one.
 	// TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
 	//
@@ -68,20 +75,28 @@
 	MergeNotices(ctx, mergedNotice, noticePaths)
 
 	// Transform the merged NOTICE file into a gzipped HTML file.
-	noticeOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
-	tmpDir := PathForModuleOut(ctx, "NOTICE_tmp")
+	txtOuptut := PathForModuleOut(ctx, "NOTICE_txt", "NOTICE.txt")
+	htmlOutput := PathForModuleOut(ctx, "NOTICE_html", "NOTICE.html")
+	htmlGzOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
 	title := "Notices for " + ctx.ModuleName()
 	ctx.Build(pctx, BuildParams{
-		Rule:        generateNoticeRule,
-		Description: "generate notice output",
-		Input:       mergedNotice,
-		Output:      noticeOutput,
+		Rule:            generateNoticeRule,
+		Description:     "generate notice output",
+		Input:           mergedNotice,
+		Output:          htmlGzOutput,
+		ImplicitOutputs: WritablePaths{txtOuptut, htmlOutput},
 		Args: map[string]string{
-			"tmpDir":   tmpDir.String(),
+			"txtOut":   txtOuptut.String(),
+			"htmlOut":  htmlOutput.String(),
 			"title":    title,
 			"inputDir": PathForModuleOut(ctx, "NOTICE_FILES/src").String(),
 		},
 	})
 
-	return noticeOutput
+	return NoticeOutputs{
+		Merged:       OptionalPathForPath(mergedNotice),
+		TxtOutput:    OptionalPathForPath(txtOuptut),
+		HtmlOutput:   OptionalPathForPath(htmlOutput),
+		HtmlGzOutput: OptionalPathForPath(htmlGzOutput),
+	}
 }
diff --git a/android/onceper.go b/android/onceper.go
index ff865c2..481cdea 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -95,6 +95,16 @@
 	return s[0], s[1]
 }
 
+// OncePath is the same as Once, but returns the value cast to a Path
+func (once *OncePer) OncePath(key OnceKey, value func() Path) Path {
+	return once.Once(key, func() interface{} { return value() }).(Path)
+}
+
+// OncePath is the same as Once, but returns the value cast to a SourcePath
+func (once *OncePer) OnceSourcePath(key OnceKey, value func() SourcePath) SourcePath {
+	return once.Once(key, func() interface{} { return value() }).(SourcePath)
+}
+
 // OnceKey is an opaque type to be used as the key in calls to Once.
 type OnceKey struct {
 	key interface{}
diff --git a/android/package.go b/android/package.go
index 03f6a1e..880d6a9 100644
--- a/android/package.go
+++ b/android/package.go
@@ -64,16 +64,6 @@
 	return newPackageId(ctx.ModuleDir())
 }
 
-// Override to ensure that the default_visibility rules are checked by the visibility module during
-// its checking phase.
-func (p *packageModule) visibilityProperties() []visibilityProperty {
-	return []visibilityProperty{
-		newVisibilityProperty("default_visibility", func() []string {
-			return p.properties.Default_visibility
-		}),
-	}
-}
-
 func (p *packageModule) Name() string {
 	return p.properties.Name
 }
@@ -97,6 +87,13 @@
 	module.properties.Name = name
 
 	module.AddProperties(&module.properties)
+
+	// The default_visibility property needs to be checked and parsed by the visibility module during
+	// its checking and parsing phases.
+	module.primaryVisibilityProperty =
+		newVisibilityProperty("default_visibility", &module.properties.Default_visibility)
+	module.visibilityPropertyInfo = []visibilityProperty{module.primaryVisibilityProperty}
+
 	return module
 }
 
diff --git a/android/path_properties.go b/android/path_properties.go
index af7af59..6b1cdb3 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -35,16 +35,17 @@
 
 	props := m.base().generalProperties
 
+	var pathProperties []string
 	for _, ps := range props {
-		pathProperties := pathPropertiesForPropertyStruct(ctx, ps)
-		pathProperties = FirstUniqueStrings(pathProperties)
+		pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ctx, ps)...)
+	}
 
-		for _, s := range pathProperties {
-			if m, t := SrcIsModuleWithTag(s); m != "" {
-				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
-			}
+	pathProperties = FirstUniqueStrings(pathProperties)
+
+	for _, s := range pathProperties {
+		if m, t := SrcIsModuleWithTag(s); m != "" {
+			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
 		}
-
 	}
 }
 
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index e98c136..59bfa6c 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -28,12 +28,17 @@
 		Qux string
 	}
 
+	// A second property struct with a duplicate property name
+	props2 struct {
+		Foo string `android:"path"`
+	}
+
 	sourceDeps []string
 }
 
 func pathDepsMutatorTestModuleFactory() Module {
 	module := &pathDepsMutatorTestModule{}
-	module.AddProperties(&module.props)
+	module.AddProperties(&module.props, &module.props2)
 	InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
 	return module
 }
@@ -44,6 +49,13 @@
 			p.sourceDeps = append(p.sourceDeps, ctx.OtherModuleName(dep))
 		}
 	})
+
+	if p.props.Foo != "" {
+		// Make sure there is only one dependency on a module listed in a property present in multiple property structs
+		if ctx.GetDirectDepWithTag(SrcIsModule(p.props.Foo), sourceOrOutputDepTag("")) == nil {
+			ctx.ModuleErrorf("GetDirectDepWithTag failed")
+		}
+	}
 }
 
 func TestPathDepsMutator(t *testing.T) {
diff --git a/android/paths.go b/android/paths.go
index 20b8b82..e3f0544 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -230,7 +230,7 @@
 // references to OutputFileProducer modules using the ":name{.tag}" syntax.  Properties passed as the paths or excludes
 // argument must have been annotated with struct tag `android:"path"` so that dependencies on SourceFileProducer modules
 // will have already been handled by the path_properties mutator.  If ctx.Config().AllowMissingDependencies() is
-// truethen any missing SourceFileProducer or OutputFileProducer dependencies will cause the module to be marked as
+// true then any missing SourceFileProducer or OutputFileProducer dependencies will cause the module to be marked as
 // having missing dependencies.
 func PathsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) Paths {
 	ret, missingDeps := PathsAndMissingDepsForModuleSrcExcludes(ctx, paths, excludes)
@@ -1145,8 +1145,8 @@
 		partition = ctx.DeviceConfig().OdmPath()
 	} else if ctx.ProductSpecific() {
 		partition = ctx.DeviceConfig().ProductPath()
-	} else if ctx.ProductServicesSpecific() {
-		partition = ctx.DeviceConfig().ProductServicesPath()
+	} else if ctx.SystemExtSpecific() {
+		partition = ctx.DeviceConfig().SystemExtPath()
 	} else {
 		partition = "system"
 	}
diff --git a/android/paths_test.go b/android/paths_test.go
index 7bcfe41..8286e9a 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -294,15 +294,15 @@
 			out: "target/product/test_device/product/bin/my_test",
 		},
 		{
-			name: "product_services binary",
+			name: "system_ext binary",
 			ctx: &moduleInstallPathContextImpl{
 				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
-					kind:   productServicesSpecificModule,
+					kind:   systemExtSpecificModule,
 				},
 			},
 			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/product_services/bin/my_test",
+			out: "target/product/test_device/system_ext/bin/my_test",
 		},
 
 		{
@@ -354,11 +354,11 @@
 		},
 
 		{
-			name: "product_services native test binary",
+			name: "system_ext native test binary",
 			ctx: &moduleInstallPathContextImpl{
 				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
-					kind:   productServicesSpecificModule,
+					kind:   systemExtSpecificModule,
 				},
 				inData: true,
 			},
@@ -415,16 +415,16 @@
 		},
 
 		{
-			name: "sanitized product_services binary",
+			name: "sanitized system_ext binary",
 			ctx: &moduleInstallPathContextImpl{
 				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
-					kind:   productServicesSpecificModule,
+					kind:   systemExtSpecificModule,
 				},
 				inSanitizerDir: true,
 			},
 			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/data/asan/product_services/bin/my_test",
+			out: "target/product/test_device/data/asan/system_ext/bin/my_test",
 		},
 
 		{
@@ -479,11 +479,11 @@
 			out: "target/product/test_device/data/asan/data/nativetest/my_test",
 		},
 		{
-			name: "sanitized product_services native test binary",
+			name: "sanitized system_ext native test binary",
 			ctx: &moduleInstallPathContextImpl{
 				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
-					kind:   productServicesSpecificModule,
+					kind:   systemExtSpecificModule,
 				},
 				inData:         true,
 				inSanitizerDir: true,
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 5087b18..8559df9 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -28,7 +29,7 @@
 	blueprint.BaseDependencyTag
 }
 
-var prebuiltDepTag prebuiltDependencyTag
+var PrebuiltDepTag prebuiltDependencyTag
 
 type PrebuiltProperties struct {
 	// When prefer is set to true the prebuilt will be used instead of any source module with
@@ -43,7 +44,10 @@
 	properties PrebuiltProperties
 	module     Module
 	srcs       *[]string
-	src        *string
+
+	// Metadata for single source Prebuilt modules.
+	srcProps reflect.Value
+	srcField reflect.StructField
 }
 
 func (p *Prebuilt) Name(name string) string {
@@ -71,11 +75,16 @@
 		// sources.
 		return PathForModuleSrc(ctx, (*p.srcs)[0])
 	} else {
-		if proptools.String(p.src) == "" {
-			ctx.PropertyErrorf("src", "missing prebuilt source file")
+		if !p.srcProps.IsValid() {
+			ctx.ModuleErrorf("prebuilt source was not set")
+		}
+		src := p.getSingleSourceFieldValue()
+		if src == "" {
+			ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
+				"missing prebuilt source file")
 			return nil
 		}
-		return PathForModuleSrc(ctx, *p.src)
+		return PathForModuleSrc(ctx, src)
 	}
 }
 
@@ -89,10 +98,12 @@
 	p.srcs = srcs
 }
 
-func InitSingleSourcePrebuiltModule(module PrebuiltInterface, src *string) {
+func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
 	p := module.Prebuilt()
 	module.AddProperties(&p.properties)
-	p.src = src
+	p.srcProps = reflect.ValueOf(srcProps).Elem()
+	p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
+	p.checkSingleSourceProperties()
 }
 
 type PrebuiltInterface interface {
@@ -116,7 +127,7 @@
 		p := m.Prebuilt()
 		name := m.base().BaseModuleName()
 		if ctx.OtherModuleExists(name) {
-			ctx.AddReverseDependency(ctx.Module(), prebuiltDepTag, name)
+			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
 			p.properties.SourceExists = true
 		} else {
 			ctx.Rename(name)
@@ -129,14 +140,14 @@
 func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
-		if p.srcs == nil && p.src == nil {
+		if p.srcs == nil && !p.srcProps.IsValid() {
 			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
 		}
 		if !p.properties.SourceExists {
 			p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil)
 		}
 	} else if s, ok := ctx.Module().(Module); ok {
-		ctx.VisitDirectDepsWithTag(prebuiltDepTag, func(m Module) {
+		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(m Module) {
 			p := m.(PrebuiltInterface).Prebuilt()
 			if p.usePrebuilt(ctx, s) {
 				p.properties.UsePrebuilt = true
@@ -172,7 +183,7 @@
 		return false
 	}
 
-	if p.src != nil && *p.src == "" {
+	if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
 		return false
 	}
 
@@ -183,3 +194,28 @@
 
 	return source == nil || !source.Enabled()
 }
+
+func (p *Prebuilt) checkSingleSourceProperties() {
+	if !p.srcProps.IsValid() || p.srcField.Name == "" {
+		panic(fmt.Errorf("invalid single source prebuilt %+v", p))
+	}
+
+	if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
+		panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
+	}
+}
+
+func (p *Prebuilt) getSingleSourceFieldValue() string {
+	value := p.srcProps.FieldByIndex(p.srcField.Index)
+	if value.Kind() == reflect.Ptr {
+		value = value.Elem()
+	}
+	if value.Kind() != reflect.String {
+		panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
+	}
+	return value.String()
+}
+
+func (p *Prebuilt) SourceExists() bool {
+	return p.properties.SourceExists
+}
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 069e1f5..9722a25 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -91,6 +91,10 @@
 	return PathForModuleSrc(ctx, String(p.properties.Src))
 }
 
+func (p *PrebuiltEtc) InstallDirPath() OutputPath {
+	return p.installDirPath
+}
+
 // This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
 // additional steps (like validating the src) before the file is installed.
 func (p *PrebuiltEtc) SetAdditionalDependencies(paths Paths) {
@@ -165,15 +169,16 @@
 	}
 }
 
-func InitPrebuiltEtcModule(p *PrebuiltEtc) {
+func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
+	p.installDirBase = dirBase
 	p.AddProperties(&p.properties)
 }
 
 // prebuilt_etc is for a prebuilt artifact that is installed in
 // <partition>/etc/<sub_dir> directory.
 func PrebuiltEtcFactory() Module {
-	module := &PrebuiltEtc{installDirBase: "etc"}
-	InitPrebuiltEtcModule(module)
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "etc")
 	// This module is device-only
 	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
 	return module
@@ -182,8 +187,8 @@
 // prebuilt_etc_host is for a host prebuilt artifact that is installed in
 // $(HOST_OUT)/etc/<sub_dir> directory.
 func PrebuiltEtcHostFactory() Module {
-	module := &PrebuiltEtc{installDirBase: "etc"}
-	InitPrebuiltEtcModule(module)
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "etc")
 	// This module is host-only
 	InitAndroidArchModule(module, HostSupported, MultilibCommon)
 	return module
@@ -192,8 +197,8 @@
 // prebuilt_usr_share is for a prebuilt artifact that is installed in
 // <partition>/usr/share/<sub_dir> directory.
 func PrebuiltUserShareFactory() Module {
-	module := &PrebuiltEtc{installDirBase: "usr/share"}
-	InitPrebuiltEtcModule(module)
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "usr/share")
 	// This module is device-only
 	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
 	return module
@@ -202,8 +207,8 @@
 // prebuild_usr_share_host is for a host prebuilt artifact that is installed in
 // $(HOST_OUT)/usr/share/<sub_dir> directory.
 func PrebuiltUserShareHostFactory() Module {
-	module := &PrebuiltEtc{installDirBase: "usr/share"}
-	InitPrebuiltEtcModule(module)
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "usr/share")
 	// This module is host-only
 	InitAndroidArchModule(module, HostSupported, MultilibCommon)
 	return module
@@ -254,8 +259,8 @@
 
 // prebuilt_font installs a font in <partition>/fonts directory.
 func PrebuiltFontFactory() Module {
-	module := &PrebuiltEtc{installDirBase: "fonts"}
-	InitPrebuiltEtcModule(module)
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "fonts")
 	// This module is device-only
 	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
 	return module
@@ -265,8 +270,9 @@
 // If soc_specific property is set to true, the firmware file is installed to the vendor <partition>/firmware
 // directory for vendor image.
 func PrebuiltFirmwareFactory() Module {
-	module := &PrebuiltEtc{installDirBase: "etc/firmware", socInstallDirBase: "firmware"}
-	InitPrebuiltEtcModule(module)
+	module := &PrebuiltEtc{}
+	module.socInstallDirBase = "firmware"
+	InitPrebuiltEtcModule(module, "etc/firmware")
 	// This module is device-only
 	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
 	return module
diff --git a/android/proto.go b/android/proto.go
index 5247c68..c8ade45 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -135,7 +135,7 @@
 	}
 
 	rule.Command().
-		Tool(ctx.Config().HostToolPath(ctx, "aprotoc")).
+		BuiltTool(ctx, "aprotoc").
 		FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()).
 		FlagWithDepFile("--dependency_out=", depFile).
 		FlagWithArg("-I ", protoBase).
@@ -145,5 +145,5 @@
 		ImplicitOutputs(outputs)
 
 	rule.Command().
-		Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).Flag(depFile.String())
+		BuiltTool(ctx, "dep_fixer").Flag(depFile.String())
 }
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 8d7e74b..48d070e 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -263,11 +263,36 @@
 	return toolsList
 }
 
-// Commands returns a slice containing a the built command line for each call to RuleBuilder.Command.
+// RspFileInputs returns the list of paths that were passed to the RuleBuilderCommand.FlagWithRspFileInputList method.
+func (r *RuleBuilder) RspFileInputs() Paths {
+	var rspFileInputs Paths
+	for _, c := range r.commands {
+		if c.rspFileInputs != nil {
+			if rspFileInputs != nil {
+				panic("Multiple commands in a rule may not have rsp file inputs")
+			}
+			rspFileInputs = c.rspFileInputs
+		}
+	}
+
+	return rspFileInputs
+}
+
+// Commands returns a slice containing the built command line for each call to RuleBuilder.Command.
 func (r *RuleBuilder) Commands() []string {
 	var commands []string
 	for _, c := range r.commands {
-		commands = append(commands, string(c.buf))
+		commands = append(commands, c.String())
+	}
+	return commands
+}
+
+// NinjaEscapedCommands returns a slice containin the built command line after ninja escaping for each call to
+// RuleBuilder.Command.
+func (r *RuleBuilder) NinjaEscapedCommands() []string {
+	var commands []string
+	for _, c := range r.commands {
+		commands = append(commands, c.NinjaEscapedString())
 	}
 	return commands
 }
@@ -284,7 +309,7 @@
 
 func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
 	return r.Command().
-		Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).
+		BuiltTool(ctx, "dep_fixer").
 		Inputs(depFiles.Paths())
 }
 
@@ -324,7 +349,7 @@
 	}
 
 	tools := r.Tools()
-	commands := r.Commands()
+	commands := r.NinjaEscapedCommands()
 	outputs := r.Outputs()
 
 	if len(commands) == 0 {
@@ -334,7 +359,7 @@
 		panic("No outputs specified from any Commands")
 	}
 
-	commandString := strings.Join(proptools.NinjaEscapeList(commands), " && ")
+	commandString := strings.Join(commands, " && ")
 
 	if r.sbox {
 		sboxOutputs := make([]string, len(outputs))
@@ -352,28 +377,38 @@
 		}
 
 		sboxCmd := &RuleBuilderCommand{}
-		sboxCmd.Tool(ctx.Config().HostToolPath(ctx, "sbox")).
+		sboxCmd.BuiltTool(ctx, "sbox").
 			Flag("-c").Text(commandString).
 			Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())).
 			Flag("--output-root").Text(r.sboxOutDir.String()).
 			Flags(sboxOutputs)
 
-		commandString = string(sboxCmd.buf)
+		commandString = sboxCmd.buf.String()
 		tools = append(tools, sboxCmd.tools...)
 	}
 
 	// Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
-	// ImplicitOutputs.  RuleBuilder never uses "$out", so the distinction between Outputs and ImplicitOutputs
-	// doesn't matter.
+	// ImplicitOutputs.  RuleBuilder only uses "$out" for the rsp file location, so the distinction between Outputs and
+	// ImplicitOutputs doesn't matter.
 	output := outputs[0]
 	implicitOutputs := outputs[1:]
 
+	var rspFile, rspFileContent string
+	rspFileInputs := r.RspFileInputs()
+	if rspFileInputs != nil {
+		rspFile = "$out.rsp"
+		rspFileContent = "$in"
+	}
+
 	ctx.Build(pctx, BuildParams{
 		Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
-			Command:     commandString,
-			CommandDeps: tools.Strings(),
-			Restat:      r.restat,
+			Command:        commandString,
+			CommandDeps:    tools.Strings(),
+			Restat:         r.restat,
+			Rspfile:        rspFile,
+			RspfileContent: rspFileContent,
 		}),
+		Inputs:          rspFileInputs,
 		Implicits:       r.Inputs(),
 		Output:          output,
 		ImplicitOutputs: implicitOutputs,
@@ -388,11 +423,15 @@
 // RuleBuilderCommand, so they can be used chained or unchained.  All methods that add text implicitly add a single
 // space as a separator from the previous method.
 type RuleBuilderCommand struct {
-	buf      []byte
-	inputs   Paths
-	outputs  WritablePaths
-	depFiles WritablePaths
-	tools    Paths
+	buf           strings.Builder
+	inputs        Paths
+	outputs       WritablePaths
+	depFiles      WritablePaths
+	tools         Paths
+	rspFileInputs Paths
+
+	// spans [start,end) of the command that should not be ninja escaped
+	unescapedSpans [][2]int
 
 	sbox       bool
 	sboxOutDir WritablePath
@@ -420,10 +459,10 @@
 // Text adds the specified raw text to the command line.  The text should not contain input or output paths or the
 // rule will not have them listed in its dependencies or outputs.
 func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
-	if len(c.buf) > 0 {
-		c.buf = append(c.buf, ' ')
+	if c.buf.Len() > 0 {
+		c.buf.WriteByte(' ')
 	}
-	c.buf = append(c.buf, text...)
+	c.buf.WriteString(text)
 	return c
 }
 
@@ -439,6 +478,16 @@
 	return c.Text(flag)
 }
 
+// OptionalFlag adds the specified raw text to the command line if it is not nil.  The text should not contain input or
+// output paths or the rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) OptionalFlag(flag *string) *RuleBuilderCommand {
+	if flag != nil {
+		c.Text(*flag)
+	}
+
+	return c
+}
+
 // Flags adds the specified raw text to the command line.  The text should not contain input or output paths or the
 // rule will not have them listed in its dependencies or outputs.
 func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
@@ -478,6 +527,24 @@
 	return c.Text(path.String())
 }
 
+// BuiltTool adds the specified tool path that was built using a host Soong module to the command line.  The path will
+// be also added to the dependencies returned by RuleBuilder.Tools.
+//
+// It is equivalent to:
+//  cmd.Tool(ctx.Config().HostToolPath(ctx, tool))
+func (c *RuleBuilderCommand) BuiltTool(ctx PathContext, tool string) *RuleBuilderCommand {
+	return c.Tool(ctx.Config().HostToolPath(ctx, tool))
+}
+
+// PrebuiltBuildTool adds the specified tool path from prebuils/build-tools.  The path will be also added to the
+// dependencies returned by RuleBuilder.Tools.
+//
+// It is equivalent to:
+//  cmd.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
+func (c *RuleBuilderCommand) PrebuiltBuildTool(ctx PathContext, tool string) *RuleBuilderCommand {
+	return c.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
+}
+
 // Input adds the specified input path to the command line.  The path will also be added to the dependencies returned by
 // RuleBuilder.Inputs.
 func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand {
@@ -606,9 +673,54 @@
 	return c.Text(flag + c.outputStr(path))
 }
 
+// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with no separator
+// between them.  The paths will be written to the rspfile.
+func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, paths Paths) *RuleBuilderCommand {
+	if c.rspFileInputs != nil {
+		panic("FlagWithRspFileInputList cannot be called if rsp file inputs have already been provided")
+	}
+
+	// Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be
+	// generated.
+	if paths == nil {
+		paths = Paths{}
+	}
+
+	c.rspFileInputs = paths
+
+	rspFile := "$out.rsp"
+	c.FlagWithArg(flag, rspFile)
+	c.unescapedSpans = append(c.unescapedSpans, [2]int{c.buf.Len() - len(rspFile), c.buf.Len()})
+	return c
+}
+
 // String returns the command line.
 func (c *RuleBuilderCommand) String() string {
-	return string(c.buf)
+	return c.buf.String()
+}
+
+// String returns the command line.
+func (c *RuleBuilderCommand) NinjaEscapedString() string {
+	return ninjaEscapeExceptForSpans(c.String(), c.unescapedSpans)
+}
+
+func ninjaEscapeExceptForSpans(s string, spans [][2]int) string {
+	if len(spans) == 0 {
+		return proptools.NinjaEscape(s)
+	}
+
+	sb := strings.Builder{}
+	sb.Grow(len(s) * 11 / 10)
+
+	i := 0
+	for _, span := range spans {
+		sb.WriteString(proptools.NinjaEscape(s[i:span[0]]))
+		sb.WriteString(s[span[0]:span[1]])
+		i = span[1]
+	}
+	sb.WriteString(proptools.NinjaEscape(s[i:]))
+
+	return sb.String()
 }
 
 func ninjaNameEscape(s string) string {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index cfbc2ab..6eba4f1 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -38,6 +38,7 @@
 			"ls":      nil,
 			"turbine": nil,
 			"java":    nil,
+			"javac":   nil,
 		})
 }
 
@@ -235,6 +236,34 @@
 	// ls --sort=time,size
 }
 
+func ExampleRuleBuilderCommand_FlagWithRspFileInputList() {
+	ctx := pathContext()
+	fmt.Println(NewRuleBuilder().Command().
+		Tool(PathForSource(ctx, "javac")).
+		FlagWithRspFileInputList("@", PathsForTesting("a.java", "b.java")).
+		NinjaEscapedString())
+	// Output:
+	// javac @$out.rsp
+}
+
+func ExampleRuleBuilderCommand_String() {
+	fmt.Println(NewRuleBuilder().Command().
+		Text("FOO=foo").
+		Text("echo $FOO").
+		String())
+	// Output:
+	// FOO=foo echo $FOO
+}
+
+func ExampleRuleBuilderCommand_NinjaEscapedString() {
+	fmt.Println(NewRuleBuilder().Command().
+		Text("FOO=foo").
+		Text("echo $FOO").
+		NinjaEscapedString())
+	// Output:
+	// FOO=foo echo $$FOO
+}
+
 func TestRuleBuilder(t *testing.T) {
 	fs := map[string][]byte{
 		"dep_fixer": nil,
@@ -503,3 +532,77 @@
 			"cp bar "+outFile, outFile, outFile+".d", true, nil)
 	})
 }
+
+func Test_ninjaEscapeExceptForSpans(t *testing.T) {
+	type args struct {
+		s     string
+		spans [][2]int
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "empty",
+			args: args{
+				s: "",
+			},
+			want: "",
+		},
+		{
+			name: "unescape none",
+			args: args{
+				s: "$abc",
+			},
+			want: "$$abc",
+		},
+		{
+			name: "unescape all",
+			args: args{
+				s:     "$abc",
+				spans: [][2]int{{0, 4}},
+			},
+			want: "$abc",
+		},
+		{
+			name: "unescape first",
+			args: args{
+				s:     "$abc$",
+				spans: [][2]int{{0, 1}},
+			},
+			want: "$abc$$",
+		},
+		{
+			name: "unescape last",
+			args: args{
+				s:     "$abc$",
+				spans: [][2]int{{4, 5}},
+			},
+			want: "$$abc$",
+		},
+		{
+			name: "unescape middle",
+			args: args{
+				s:     "$a$b$c$",
+				spans: [][2]int{{2, 5}},
+			},
+			want: "$$a$b$c$$",
+		},
+		{
+			name: "unescape multiple",
+			args: args{
+				s:     "$a$b$c$",
+				spans: [][2]int{{2, 3}, {4, 5}},
+			},
+			want: "$$a$b$c$$",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := ninjaEscapeExceptForSpans(tt.args.s, tt.args.spans); got != tt.want {
+				t.Errorf("ninjaEscapeExceptForSpans() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/android/sh_binary.go b/android/sh_binary.go
index fb7446d..2855aa0 100644
--- a/android/sh_binary.go
+++ b/android/sh_binary.go
@@ -29,6 +29,7 @@
 	RegisterModuleType("sh_binary", ShBinaryFactory)
 	RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
 	RegisterModuleType("sh_test", ShTestFactory)
+	RegisterModuleType("sh_test_host", ShTestHostFactory)
 }
 
 type shBinaryProperties struct {
@@ -195,6 +196,7 @@
 	return module
 }
 
+// sh_test defines a shell script based test module.
 func ShTestFactory() Module {
 	module := &ShTest{}
 	InitShBinaryModule(&module.ShBinary)
@@ -203,3 +205,13 @@
 	InitAndroidArchModule(module, HostAndDeviceSupported, MultilibFirst)
 	return module
 }
+
+// sh_test_host defines a shell script based test module that runs on a host.
+func ShTestHostFactory() Module {
+	module := &ShTest{}
+	InitShBinaryModule(&module.ShBinary)
+	module.AddProperties(&module.testProperties)
+
+	InitAndroidArchModule(module, HostSupported, MultilibFirst)
+	return module
+}
diff --git a/android/sh_binary_test.go b/android/sh_binary_test.go
index c99e18c..9df769c 100644
--- a/android/sh_binary_test.go
+++ b/android/sh_binary_test.go
@@ -10,6 +10,7 @@
 
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("sh_test", ModuleFactoryAdaptor(ShTestFactory))
+	ctx.RegisterModuleType("sh_test_host", ModuleFactoryAdaptor(ShTestHostFactory))
 	ctx.Register()
 	mockFiles := map[string][]byte{
 		"Android.bp":         []byte(bp),
@@ -48,3 +49,23 @@
 		t.Errorf("Unexpected test data expected: %q, actual: %q", expected, actual)
 	}
 }
+
+func TestShTestHost(t *testing.T) {
+	ctx, _ := testShBinary(t, `
+		sh_test_host {
+			name: "foo",
+			src: "test.sh",
+			filename: "test.sh",
+			data: [
+				"testdata/data1",
+				"testdata/sub/data2",
+			],
+		}
+	`)
+
+	buildOS := BuildOs.String()
+	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
+	if !mod.Host() {
+		t.Errorf("host bit is not set for a sh_test_host module.")
+	}
+}
diff --git a/android/testing.go b/android/testing.go
index 44bee4b..b59f399 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -376,9 +376,20 @@
 	var p AndroidMkEntriesProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkEntriesProvider); !ok {
-		t.Errorf("module does not implmement AndroidMkEntriesProvider: " + mod.Name())
+		t.Errorf("module does not implement AndroidMkEntriesProvider: " + mod.Name())
 	}
 	entries := p.AndroidMkEntries()
 	entries.fillInEntries(config, bpPath, mod)
 	return entries
 }
+
+func AndroidMkDataForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkData {
+	var p AndroidMkDataProvider
+	var ok bool
+	if p, ok = mod.(AndroidMkDataProvider); !ok {
+		t.Errorf("module does not implement AndroidMkDataProvider: " + mod.Name())
+	}
+	data := p.AndroidMk()
+	data.fillInData(config, bpPath, mod)
+	return data
+}
diff --git a/android/util.go b/android/util.go
index 3b8bc78..e02cca1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -115,6 +115,17 @@
 	return false
 }
 
+// IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element.
+func IndexListPred(pred func(s string) bool, list []string) int {
+	for i, l := range list {
+		if pred(l) {
+			return i
+		}
+	}
+
+	return -1
+}
+
 func FilterList(list []string, filter []string) (remainder []string, filtered []string) {
 	for _, l := range list {
 		if InList(l, filter) {
@@ -188,6 +199,13 @@
 	return list[totalSkip:]
 }
 
+// SortedUniqueStrings returns what the name says
+func SortedUniqueStrings(list []string) []string {
+	unique := FirstUniqueStrings(list)
+	sort.Strings(unique)
+	return unique
+}
+
 // checkCalledFromInit panics if a Go package's init function is not on the
 // call stack.
 func checkCalledFromInit() {
diff --git a/android/variable.go b/android/variable.go
index b4f31c6..bfff81c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -59,17 +59,6 @@
 			Cflags []string
 		}
 
-		// Product_is_iot is true for Android Things devices.
-		Product_is_iot struct {
-			Cflags       []string
-			Enabled      bool
-			Exclude_srcs []string
-			Init_rc      []string
-			Shared_libs  []string
-			Srcs         []string
-			Static_libs  []string
-		}
-
 		// treble_linker_namespaces is true when the system/vendor linker namespace separation is
 		// enabled.
 		Treble_linker_namespaces struct {
@@ -165,15 +154,17 @@
 	DeviceSecondaryCpuVariant  *string  `json:",omitempty"`
 	DeviceSecondaryAbi         []string `json:",omitempty"`
 
-	NativeBridgeArch        *string  `json:",omitempty"`
-	NativeBridgeArchVariant *string  `json:",omitempty"`
-	NativeBridgeCpuVariant  *string  `json:",omitempty"`
-	NativeBridgeAbi         []string `json:",omitempty"`
+	NativeBridgeArch         *string  `json:",omitempty"`
+	NativeBridgeArchVariant  *string  `json:",omitempty"`
+	NativeBridgeCpuVariant   *string  `json:",omitempty"`
+	NativeBridgeAbi          []string `json:",omitempty"`
+	NativeBridgeRelativePath *string  `json:",omitempty"`
 
-	NativeBridgeSecondaryArch        *string  `json:",omitempty"`
-	NativeBridgeSecondaryArchVariant *string  `json:",omitempty"`
-	NativeBridgeSecondaryCpuVariant  *string  `json:",omitempty"`
-	NativeBridgeSecondaryAbi         []string `json:",omitempty"`
+	NativeBridgeSecondaryArch         *string  `json:",omitempty"`
+	NativeBridgeSecondaryArchVariant  *string  `json:",omitempty"`
+	NativeBridgeSecondaryCpuVariant   *string  `json:",omitempty"`
+	NativeBridgeSecondaryAbi          []string `json:",omitempty"`
+	NativeBridgeSecondaryRelativePath *string  `json:",omitempty"`
 
 	HostArch          *string `json:",omitempty"`
 	HostSecondaryArch *string `json:",omitempty"`
@@ -204,6 +195,7 @@
 	HostStaticBinaries               *bool `json:",omitempty"`
 	Binder32bit                      *bool `json:",omitempty"`
 	UseGoma                          *bool `json:",omitempty"`
+	UseRBE                           *bool `json:",omitempty"`
 	Debuggable                       *bool `json:",omitempty"`
 	Eng                              *bool `json:",omitempty"`
 	Treble_linker_namespaces         *bool `json:",omitempty"`
@@ -232,10 +224,10 @@
 	EnableXOM       *bool    `json:",omitempty"`
 	XOMExcludePaths []string `json:",omitempty"`
 
-	VendorPath          *string `json:",omitempty"`
-	OdmPath             *string `json:",omitempty"`
-	ProductPath         *string `json:",omitempty"`
-	ProductServicesPath *string `json:",omitempty"`
+	VendorPath    *string `json:",omitempty"`
+	OdmPath       *string `json:",omitempty"`
+	ProductPath   *string `json:",omitempty"`
+	SystemExtPath *string `json:",omitempty"`
 
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
@@ -259,8 +251,6 @@
 
 	Override_rs_driver *string `json:",omitempty"`
 
-	Product_is_iot *bool `json:",omitempty"`
-
 	Fuchsia *bool `json:",omitempty"`
 
 	DeviceKernelHeaders []string `json:",omitempty"`
diff --git a/android/visibility.go b/android/visibility.go
index 94af343..a7e718b 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -67,8 +67,8 @@
 
 // Describes the properties provided by a module that contain visibility rules.
 type visibilityPropertyImpl struct {
-	name          string
-	stringsGetter func() []string
+	name            string
+	stringsProperty *[]string
 }
 
 type visibilityProperty interface {
@@ -76,10 +76,10 @@
 	getStrings() []string
 }
 
-func newVisibilityProperty(name string, stringsGetter func() []string) visibilityProperty {
+func newVisibilityProperty(name string, stringsProperty *[]string) visibilityProperty {
 	return visibilityPropertyImpl{
-		name:          name,
-		stringsGetter: stringsGetter,
+		name:            name,
+		stringsProperty: stringsProperty,
 	}
 }
 
@@ -88,7 +88,7 @@
 }
 
 func (p visibilityPropertyImpl) getStrings() []string {
-	return p.stringsGetter()
+	return *p.stringsProperty
 }
 
 // A compositeRule is a visibility rule composed from a list of atomic visibility rules.
@@ -211,16 +211,7 @@
 // Checks the per-module visibility rule lists before defaults expansion.
 func visibilityRuleChecker(ctx BottomUpMutatorContext) {
 	qualified := createQualifiedModuleName(ctx)
-	if d, ok := ctx.Module().(Defaults); ok {
-		// Defaults modules don't store the payload properties in m.base().
-		for _, props := range d.properties() {
-			if cp, ok := props.(*commonProperties); ok {
-				if visibility := cp.Visibility; visibility != nil {
-					checkRules(ctx, qualified.pkg, "visibility", visibility)
-				}
-			}
-		}
-	} else if m, ok := ctx.Module().(Module); ok {
+	if m, ok := ctx.Module().(Module); ok {
 		visibilityProperties := m.visibilityProperties()
 		for _, p := range visibilityProperties {
 			if visibility := p.getStrings(); visibility != nil {
@@ -294,14 +285,12 @@
 	qualifiedModuleId := m.qualifiedModuleId(ctx)
 	currentPkg := qualifiedModuleId.pkg
 
-	// Parse all the properties into rules and store them.
-	visibilityProperties := m.visibilityProperties()
-	for _, p := range visibilityProperties {
-		if visibility := p.getStrings(); visibility != nil {
-			rule := parseRules(ctx, currentPkg, visibility)
-			if rule != nil {
-				moduleToVisibilityRuleMap(ctx).Store(qualifiedModuleId, rule)
-			}
+	// Parse the visibility rules that control access to the module and store them by id
+	// for use when enforcing the rules.
+	if visibility := m.visibility(); visibility != nil {
+		rule := parseRules(ctx, currentPkg, m.visibility())
+		if rule != nil {
+			moduleToVisibilityRuleMap(ctx).Store(qualifiedModuleId, rule)
 		}
 	}
 }
diff --git a/android/visibility_test.go b/android/visibility_test.go
index af6acf4..c44dc9e 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -658,6 +658,40 @@
 				` visible to this module`,
 		},
 	},
+
+	// Defaults module's defaults_visibility tests
+	{
+		name: "defaults_visibility invalid",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "top_defaults",
+					defaults_visibility: ["//visibility:invalid"],
+				}`),
+		},
+		expectedErrors: []string{
+			`defaults_visibility: unrecognized visibility rule "//visibility:invalid"`,
+		},
+	},
+	{
+		name: "defaults_visibility overrides package default",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}
+				mock_defaults {
+					name: "top_defaults",
+					defaults_visibility: ["//visibility:public"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					defaults: ["top_defaults"],
+				}`),
+		},
+	},
+
 	// Package default_visibility tests
 	{
 		name: "package default_visibility property is checked",
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index af81e43..2def179 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -192,7 +192,7 @@
 			"LOCAL_VENDOR_MODULE":              "vendor",
 			"LOCAL_ODM_MODULE":                 "device_specific",
 			"LOCAL_PRODUCT_MODULE":             "product_specific",
-			"LOCAL_PRODUCT_SERVICES_MODULE":    "product_services_specific",
+			"LOCAL_SYSTEM_EXT_MODULE":          "system_ext_specific",
 			"LOCAL_EXPORT_PACKAGE_RESOURCES":   "export_package_resources",
 			"LOCAL_PRIVILEGED_MODULE":          "privileged",
 			"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
@@ -602,8 +602,8 @@
 		return fmt.Errorf("Cannot handle appending to LOCAL_MODULE_PATH")
 	}
 	// Analyze value in order to set the correct values for the 'device_specific',
-	// 'product_specific', 'product_services_specific' 'vendor'/'soc_specific',
-	// 'product_services_specific' attribute. Two cases are allowed:
+	// 'product_specific', 'system_ext_specific' 'vendor'/'soc_specific',
+	// 'system_ext_specific' attribute. Two cases are allowed:
 	//   $(VAR)/<literal-value>
 	//   $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/<literal-value>
 	// The last case is equivalent to $(TARGET_OUT_VENDOR)/<literal-value>
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 4d5180e..dbb7fde 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -957,37 +957,37 @@
 `,
 	},
 	{
-		desc: "prebuilt_etc_TARGET_OUT_PRODUCT_SERVICES/etc",
+		desc: "prebuilt_etc_TARGET_OUT_SYSTEM_EXT/etc",
 		in: `
 include $(CLEAR_VARS)
 LOCAL_MODULE := etc.test1
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES)/etc/foo/bar
+LOCAL_MODULE_PATH := $(TARGET_OUT_SYSTEM_EXT)/etc/foo/bar
 include $(BUILD_PREBUILT)
 `,
 		expected: `
 prebuilt_etc {
 	name: "etc.test1",
 	sub_dir: "foo/bar",
-	product_services_specific: true,
+	system_ext_specific: true,
 
 }
 `,
 	},
 	{
-		desc: "prebuilt_etc_TARGET_OUT_PRODUCT_SERVICES_ETC",
+		desc: "prebuilt_etc_TARGET_OUT_SYSTEM_EXT_ETC",
 		in: `
 include $(CLEAR_VARS)
 LOCAL_MODULE := etc.test1
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES_ETC)/foo/bar
+LOCAL_MODULE_PATH := $(TARGET_OUT_SYSTEM_EXT_ETC)/foo/bar
 include $(BUILD_PREBUILT)
 `,
 		expected: `
 prebuilt_etc {
 	name: "etc.test1",
 	sub_dir: "foo/bar",
-	product_services_specific: true,
+	system_ext_specific: true,
 
 
 }
diff --git a/apex/apex.go b/apex/apex.go
index 5155e58..e4fad83 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -46,13 +46,21 @@
 		Description: "fs_config ${out}",
 	}, "ro_paths", "exec_paths")
 
+	injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
+		Command: `rm -f $out && ${jsonmodify} $in ` +
+			`-a provideNativeLibs ${provideNativeLibs} ` +
+			`-a requireNativeLibs ${requireNativeLibs} -o $out`,
+		CommandDeps: []string{"${jsonmodify}"},
+		Description: "Inject dependency into ${out}",
+	}, "provideNativeLibs", "requireNativeLibs")
+
 	// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
 	// against the binary policy using sefcontext_compiler -p <policy>.
 
 	// TODO(b/114327326): automate the generation of file_contexts
 	apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
-			`(${copy_commands}) && ` +
+			`(. ${out}.copy_commands) && ` +
 			`APEXER_TOOL_PATH=${tool_path} ` +
 			`${apexer} --force --manifest ${manifest} ` +
 			`--file_contexts ${file_contexts} ` +
@@ -62,18 +70,22 @@
 		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
 			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
 			"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
-		Description: "APEX ${image_dir} => ${out}",
+		Rspfile:        "${out}.copy_commands",
+		RspfileContent: "${copy_commands}",
+		Description:    "APEX ${image_dir} => ${out}",
 	}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key", "opt_flags")
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
-			`(${copy_commands}) && ` +
+			`(. ${out}.copy_commands) && ` +
 			`APEXER_TOOL_PATH=${tool_path} ` +
 			`${apexer} --force --manifest ${manifest} ` +
 			`--payload_type zip ` +
 			`${image_dir} ${out} `,
-		CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
-		Description: "ZipAPEX ${image_dir} => ${out}",
+		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
+		Rspfile:        "${out}.copy_commands",
+		RspfileContent: "${copy_commands}",
+		Description:    "ZipAPEX ${image_dir} => ${out}",
 	}, "tool_path", "image_dir", "copy_commands", "manifest")
 
 	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
@@ -111,6 +123,7 @@
 	testTag        = dependencyTag{name: "test"}
 	keyTag         = dependencyTag{name: "key"}
 	certificateTag = dependencyTag{name: "certificate"}
+	usesTag        = dependencyTag{name: "uses"}
 )
 
 func init() {
@@ -138,6 +151,7 @@
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
 	pctx.HostBinToolVariable("zip2zip", "zip2zip")
 	pctx.HostBinToolVariable("zipalign", "zipalign")
+	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 
 	android.RegisterModuleType("apex", apexBundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -147,6 +161,7 @@
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
 		ctx.BottomUp("apex", apexMutator).Parallel()
+		ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
 	})
 }
 
@@ -187,6 +202,11 @@
 		mctx.CreateVariations(apexBundleName)
 	}
 }
+func apexUsesMutator(mctx android.BottomUpMutatorContext) {
+	if ab, ok := mctx.Module().(*apexBundle); ok {
+		mctx.AddFarVariationDependencies(nil, usesTag, ab.properties.Uses...)
+	}
+}
 
 type apexNativeDependencies struct {
 	// List of native libraries
@@ -272,6 +292,12 @@
 
 	// List of sanitizer names that this APEX is enabled for
 	SanitizerNames []string `blueprint:"mutated"`
+
+	// Indicates this APEX provides C++ shared libaries to other APEXes. Default: false.
+	Provide_cpp_shared_libs *bool
+
+	// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
+	Uses []string
 }
 
 type apexTargetBundleProperties struct {
@@ -341,7 +367,7 @@
 	case both:
 		panic(fmt.Errorf("must be either zip or image"))
 	default:
-		panic(fmt.Errorf("unkonwn APEX type %d", a))
+		panic(fmt.Errorf("unknown APEX type %d", a))
 	}
 }
 
@@ -354,7 +380,7 @@
 	case both:
 		panic(fmt.Errorf("must be either zip or image"))
 	default:
-		panic(fmt.Errorf("unkonwn APEX type %d", a))
+		panic(fmt.Errorf("unknown APEX type %d", a))
 	}
 }
 
@@ -371,7 +397,7 @@
 	case nativeTest:
 		return "NATIVE_TESTS"
 	default:
-		panic(fmt.Errorf("unkonwn class %d", class))
+		panic(fmt.Errorf("unknown class %d", class))
 	}
 }
 
@@ -397,6 +423,8 @@
 	outputFiles      map[apexPackaging]android.WritablePath
 	installDir       android.OutputPath
 
+	prebuiltFileToDelete string
+
 	public_key_file  android.Path
 	private_key_file android.Path
 
@@ -412,6 +440,9 @@
 	flattened bool
 
 	testApex bool
+
+	// intermediate path for apex_manifest.json
+	manifestOut android.WritablePath
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -436,6 +467,7 @@
 	ctx.AddFarVariationDependencies([]blueprint.Variation{
 		{Mutator: "arch", Variation: arch},
 		{Mutator: "image", Variation: imageVariation},
+		{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
 	}, testTag, tests...)
 }
 
@@ -479,6 +511,7 @@
 		ctx.AddFarVariationDependencies([]blueprint.Variation{
 			{Mutator: "arch", Variation: target.String()},
 			{Mutator: "image", Variation: a.getImageVariation(config)},
+			{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
 		}, testTag, a.properties.Tests...)
 
 		// Add native modules targetting both ABIs
@@ -645,6 +678,8 @@
 	dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
 	if !cc.Arch().Native {
 		dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
+	} else if cc.Target().NativeBridge == android.NativeBridgeEnabled {
+		dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
 	}
 	if handleSpecialLibs {
 		switch cc.Name() {
@@ -668,6 +703,11 @@
 
 func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
 	dirInApex = filepath.Join("bin", cc.RelativeInstallPath())
+	if !cc.Arch().Native {
+		dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
+	} else if cc.Target().NativeBridge == android.NativeBridgeEnabled {
+		dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
+	}
 	fileToCopy = cc.OutputFile().Path()
 	return
 }
@@ -727,14 +767,45 @@
 
 	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
 
+	// native lib dependencies
+	var provideNativeLibs []string
+	var requireNativeLibs []string
+
+	// Check if "uses" requirements are met with dependent apexBundles
+	var providedNativeSharedLibs []string
+	useVendor := proptools.Bool(a.properties.Use_vendor)
+	ctx.VisitDirectDepsBlueprint(func(m blueprint.Module) {
+		if ctx.OtherModuleDependencyTag(m) != usesTag {
+			return
+		}
+		otherName := ctx.OtherModuleName(m)
+		other, ok := m.(*apexBundle)
+		if !ok {
+			ctx.PropertyErrorf("uses", "%q is not a provider", otherName)
+			return
+		}
+		if proptools.Bool(other.properties.Use_vendor) != useVendor {
+			ctx.PropertyErrorf("use_vendor", "%q has different value of use_vendor", otherName)
+			return
+		}
+		if !proptools.Bool(other.properties.Provide_cpp_shared_libs) {
+			ctx.PropertyErrorf("uses", "%q does not provide native_shared_libs", otherName)
+			return
+		}
+		providedNativeSharedLibs = append(providedNativeSharedLibs, other.properties.Native_shared_libs...)
+	})
+
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+		depTag := ctx.OtherModuleDependencyTag(child)
+		depName := ctx.OtherModuleName(child)
 		if _, ok := parent.(*apexBundle); ok {
 			// direct dependencies
-			depTag := ctx.OtherModuleDependencyTag(child)
-			depName := ctx.OtherModuleName(child)
 			switch depTag {
 			case sharedLibTag:
 				if cc, ok := child.(*cc.Module); ok {
+					if cc.HasStubsVariants() {
+						provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
+					}
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
 					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
 					return true
@@ -743,11 +814,6 @@
 				}
 			case executableTag:
 				if cc, ok := child.(*cc.Module); ok {
-					if !cc.Arch().Native {
-						// There is only one 'bin' directory so we shouldn't bother copying in
-						// native-bridge'd binaries and only use main ones.
-						return true
-					}
 					fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
 					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeExecutable, cc, cc.Symlinks()})
 					return true
@@ -787,9 +853,20 @@
 					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
 				}
 			case testTag:
-				if cc, ok := child.(*cc.Module); ok {
-					fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, cc, nil})
+				if ccTest, ok := child.(*cc.Module); ok {
+					if ccTest.IsTestPerSrcAllTestsVariation() {
+						// Multiple-output test module (where `test_per_src: true`).
+						//
+						// `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
+						// We do not add this variation to `filesInfo`, as it has no output;
+						// however, we do add the other variations of this module as indirect
+						// dependencies (see below).
+						return true
+					} else {
+						// Single-output test module (where `test_per_src: false`).
+						fileToCopy, dirInApex := getCopyManifestForExecutable(ccTest)
+						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, ccTest, nil})
+					}
 					return true
 				} else {
 					ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
@@ -810,29 +887,57 @@
 				} else {
 					ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
 				}
+			case android.PrebuiltDepTag:
+				// If the prebuilt is force disabled, remember to delete the prebuilt file
+				// that might have been installed in the previous builds
+				if prebuilt, ok := child.(*Prebuilt); ok && prebuilt.isForceDisabled() {
+					a.prebuiltFileToDelete = prebuilt.InstallFilename()
+				}
 			}
 		} else {
 			// indirect dependencies
 			if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
-				if cc, ok := child.(*cc.Module); ok {
-					if !a.Host() && (cc.IsStubs() || cc.HasStubsVariants()) {
-						// If the dependency is a stubs lib, don't include it in this APEX,
-						// but make sure that the lib is installed on the device.
-						// In case no APEX is having the lib, the lib is installed to the system
-						// partition.
-						//
-						// Always include if we are a host-apex however since those won't have any
-						// system libraries.
-						if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
-							a.externalDeps = append(a.externalDeps, cc.Name())
+				// We cannot use a switch statement on `depTag` here as the checked
+				// tags used below are private (e.g. `cc.sharedDepTag`).
+				if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
+					if cc, ok := child.(*cc.Module); ok {
+						if android.InList(cc.Name(), providedNativeSharedLibs) {
+							// If we're using a shared library which is provided from other APEX,
+							// don't include it in this APEX
+							return false
 						}
-						// Don't track further
-						return false
+						if !a.Host() && (cc.IsStubs() || cc.HasStubsVariants()) {
+							// If the dependency is a stubs lib, don't include it in this APEX,
+							// but make sure that the lib is installed on the device.
+							// In case no APEX is having the lib, the lib is installed to the system
+							// partition.
+							//
+							// Always include if we are a host-apex however since those won't have any
+							// system libraries.
+							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
+								a.externalDeps = append(a.externalDeps, cc.Name())
+							}
+							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
+							// Don't track further
+							return false
+						}
+						fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
+						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
+						return true
 					}
-					depName := ctx.OtherModuleName(child)
-					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
-					return true
+				} else if cc.IsTestPerSrcDepTag(depTag) {
+					if cc, ok := child.(*cc.Module); ok {
+						fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
+						// Handle modules created as `test_per_src` variations of a single test module:
+						// use the name of the generated test binary (`fileToCopy`) instead of the name
+						// of the original test module (`depName`, shared by all `test_per_src`
+						// variations of that module).
+						moduleName := filepath.Base(fileToCopy.String())
+						filesInfo = append(filesInfo, apexFile{fileToCopy, moduleName, dirInApex, nativeTest, cc, nil})
+						return true
+					}
+				} else {
+					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
 				}
 			}
 		}
@@ -873,12 +978,27 @@
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
+	a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
+	// put dependency({provide|require}NativeLibs) in apex_manifest.json
+	manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
+	provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
+	requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   injectApexDependency,
+		Input:  manifestSrc,
+		Output: a.manifestOut,
+		Args: map[string]string{
+			"provideNativeLibs": strings.Join(provideNativeLibs, " "),
+			"requireNativeLibs": strings.Join(requireNativeLibs, " "),
+		},
+	})
+
 	if a.apexTypes.zip() {
 		a.buildUnflattenedApex(ctx, zipApex)
 	}
 	if a.apexTypes.image() {
 		// Build rule for unflattened APEX is created even when ctx.Config().FlattenApex()
-		// is true. This is to support referencing APEX via ":<module_name" syntax
+		// is true. This is to support referencing APEX via ":<module_name>" syntax
 		// in other modules. It is in AndroidMk where the selection of flattened
 		// or unflattened APEX is made.
 		a.buildUnflattenedApex(ctx, imageApex)
@@ -905,8 +1025,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(
-		android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)))
+	return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)).HtmlGzOutput
 }
 
 func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType apexPackaging) {
@@ -921,8 +1040,6 @@
 		a.container_private_key_file = key
 	}
 
-	manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
 	var abis []string
 	for _, target := range ctx.MultiTargets() {
 		if len(target.Arch.Abi) > 0 {
@@ -952,7 +1069,7 @@
 		}
 	}
 	implicitInputs := append(android.Paths(nil), filesToCopy...)
-	implicitInputs = append(implicitInputs, manifest)
+	implicitInputs = append(implicitInputs, a.manifestOut)
 
 	outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -966,7 +1083,7 @@
 			if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
 				executablePaths = append(executablePaths, pathInApex)
 				for _, s := range f.symlinks {
-					executablePaths = append(executablePaths, filepath.Join("bin", s))
+					executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
 				}
 			} else {
 				readOnlyPaths = append(readOnlyPaths, pathInApex)
@@ -1047,7 +1164,7 @@
 				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 				"image_dir":        android.PathForModuleOut(ctx, "image"+suffix).String(),
 				"copy_commands":    strings.Join(copyCommands, " && "),
-				"manifest":         manifest.String(),
+				"manifest":         a.manifestOut.String(),
 				"file_contexts":    fileContexts.String(),
 				"canned_fs_config": cannedFsConfig.String(),
 				"key":              a.private_key_file.String(),
@@ -1085,7 +1202,7 @@
 				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 				"image_dir":     android.PathForModuleOut(ctx, "image"+suffix).String(),
 				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      manifest.String(),
+				"manifest":      a.manifestOut.String(),
 			},
 		})
 	}
@@ -1116,16 +1233,7 @@
 	if a.installable() {
 		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
-		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
-		// rename to apex_manifest.json
-		copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Input:  manifest,
-			Output: copiedManifest,
-		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
 
 		// rename to apex_pubkey
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -1290,6 +1398,10 @@
 				if len(a.externalDeps) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.externalDeps, " "))
 				}
+				if a.prebuiltFileToDelete != "" {
+					fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", "rm -rf "+
+						filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), a.prebuiltFileToDelete))
+				}
 				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 
 				if apexType == imageApex {
@@ -1364,7 +1476,8 @@
 
 type PrebuiltProperties struct {
 	// the path to the prebuilt .apex file to import.
-	Source string `blueprint:"mutated"`
+	Source       string `blueprint:"mutated"`
+	ForceDisable bool   `blueprint:"mutated"`
 
 	Src  *string
 	Arch struct {
@@ -1386,6 +1499,13 @@
 	// Optional name for the installed apex. If unspecified, name of the
 	// module is used as the file name
 	Filename *string
+
+	// Names of modules to be overridden. Listed modules can only be other binaries
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden binaries, but if both
+	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+	// from PRODUCT_PACKAGES.
+	Overrides []string
 }
 
 func (p *Prebuilt) installable() bool {
@@ -1393,6 +1513,27 @@
 }
 
 func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// If the device is configured to use flattened APEX, force disable the prebuilt because
+	// the prebuilt is a non-flattened one.
+	forceDisable := ctx.Config().FlattenApex()
+
+	// Force disable the prebuilts when we are doing unbundled build. We do unbundled build
+	// to build the prebuilts themselves.
+	forceDisable = forceDisable || ctx.Config().UnbundledBuild()
+
+	// Force disable the prebuilts when coverage is enabled.
+	forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled()
+	forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
+
+	// b/137216042 don't use prebuilts when address sanitizer is on
+	forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) ||
+		android.InList("hwaddress", ctx.Config().SanitizeDevice())
+
+	if forceDisable && p.prebuilt.SourceExists() {
+		p.properties.ForceDisable = true
+		return
+	}
+
 	// This is called before prebuilt_select and prebuilt_postdeps mutators
 	// The mutators requires that src to be set correctly for each arch so that
 	// arch variants are disabled when src is not provided for the arch.
@@ -1420,6 +1561,10 @@
 	p.properties.Source = src
 }
 
+func (p *Prebuilt) isForceDisabled() bool {
+	return p.properties.ForceDisable
+}
+
 func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
@@ -1434,6 +1579,10 @@
 }
 
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if p.properties.ForceDisable {
+		return
+	}
+
 	// TODO(jungjw): Check the key validity.
 	p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
@@ -1460,17 +1609,16 @@
 	return p.prebuilt.Name(p.ModuleBase.Name())
 }
 
-func (p *Prebuilt) AndroidMk() android.AndroidMkData {
-	return android.AndroidMkData{
+func (p *Prebuilt) AndroidMkEntries() android.AndroidMkEntries {
+	return android.AndroidMkEntries{
 		Class:      "ETC",
 		OutputFile: android.OptionalPathForPath(p.inputApex),
 		Include:    "$(BUILD_PREBUILT)",
-		Extra: []android.AndroidMkExtraFunc{
-			func(w io.Writer, outputFile android.Path) {
-				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
-				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", p.installFilename)
-				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !p.installable())
-			},
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			entries.SetString("LOCAL_MODULE_PATH", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
+			entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+			entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
+			entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...)
 		},
 	}
 }
@@ -1479,7 +1627,7 @@
 func PrebuiltFactory() android.Module {
 	module := &Prebuilt{}
 	module.AddProperties(&module.properties)
-	android.InitSingleSourcePrebuiltModule(module, &module.properties.Source)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties, "Source")
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b410425..38d2bf2 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -17,6 +17,7 @@
 import (
 	"io/ioutil"
 	"os"
+	"reflect"
 	"strings"
 	"testing"
 
@@ -29,7 +30,32 @@
 
 var buildDir string
 
-func testApex(t *testing.T, bp string) *android.TestContext {
+func testApexError(t *testing.T, pattern, bp string) {
+	ctx, config := testApexContext(t, bp)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+	_, errs = ctx.PrepareBuildActions(config)
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+func testApex(t *testing.T, bp string) (*android.TestContext, android.Config) {
+	ctx, config := testApexContext(t, bp)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+	return ctx, config
+}
+
+func testApexContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	config := android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
 	config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
@@ -48,6 +74,7 @@
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
 		ctx.BottomUp("apex", apexMutator)
+		ctx.BottomUp("apex_uses", apexUsesMutator)
 		ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
 		ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
 	})
@@ -64,6 +91,8 @@
 	ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory))
 	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
+
 	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
 	})
@@ -71,6 +100,7 @@
 		ctx.BottomUp("image", cc.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+		ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
 	})
@@ -168,10 +198,16 @@
 		"system/sepolicy/apex/myapex-file_contexts":         nil,
 		"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
 		"system/sepolicy/apex/otherapex-file_contexts":      nil,
+		"system/sepolicy/apex/commonapex-file_contexts":     nil,
 		"mylib.cpp":                            nil,
+		"mylib_common.cpp":                     nil,
 		"mytest.cpp":                           nil,
+		"mytest1.cpp":                          nil,
+		"mytest2.cpp":                          nil,
+		"mytest3.cpp":                          nil,
 		"myprebuilt":                           nil,
 		"my_include":                           nil,
+		"foo/bar/MyClass.java":                 nil,
 		"vendor/foo/devkeys/test.x509.pem":     nil,
 		"vendor/foo/devkeys/test.pk8":          nil,
 		"testkey.x509.pem":                     nil,
@@ -188,12 +224,8 @@
 		"myapex-arm.apex":                      nil,
 		"frameworks/base/api/current.txt":      nil,
 	})
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
 
-	return ctx
+	return ctx, config
 }
 
 func setUp() {
@@ -210,6 +242,7 @@
 
 // ensure that 'result' contains 'expected'
 func ensureContains(t *testing.T, result string, expected string) {
+	t.Helper()
 	if !strings.Contains(result, expected) {
 		t.Errorf("%q is not found in %q", expected, result)
 	}
@@ -217,26 +250,36 @@
 
 // ensures that 'result' does not contain 'notExpected'
 func ensureNotContains(t *testing.T, result string, notExpected string) {
+	t.Helper()
 	if strings.Contains(result, notExpected) {
 		t.Errorf("%q is found in %q", notExpected, result)
 	}
 }
 
 func ensureListContains(t *testing.T, result []string, expected string) {
+	t.Helper()
 	if !android.InList(expected, result) {
 		t.Errorf("%q is not found in %v", expected, result)
 	}
 }
 
 func ensureListNotContains(t *testing.T, result []string, notExpected string) {
+	t.Helper()
 	if android.InList(notExpected, result) {
 		t.Errorf("%q is found in %v", notExpected, result)
 	}
 }
 
+func ensureListEmpty(t *testing.T, result []string) {
+	t.Helper()
+	if len(result) > 0 {
+		t.Errorf("%q is expected to be empty", result)
+	}
+}
+
 // Minimal test
 func TestBasicApex(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex_defaults {
 			name: "myapex-defaults",
 			manifest: ":myapex.manifest",
@@ -247,7 +290,8 @@
 				both: {
 					binaries: ["foo",],
 				}
-			}
+			},
+			java_libs: ["myjar"],
 		}
 
 		apex {
@@ -305,6 +349,23 @@
 			stl: "none",
 			notice: "custom_notice",
 		}
+
+		java_library {
+			name: "myjar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			compile_dex: true,
+			static_libs: ["myotherjar"],
+		}
+
+		java_library {
+			name: "myotherjar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			compile_dex: true,
+		}
 	`)
 
 	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -321,17 +382,24 @@
 
 	// Ensure that apex variant is created for the direct dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared_myapex")
+	ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex")
 
 	// Ensure that apex variant is created for the indirect dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared_myapex")
+	ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_myapex")
 
 	// Ensure that both direct and indirect deps are copied into apex
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+	ensureContains(t, copyCmds, "image.apex/javalib/myjar.jar")
+	// .. but not for java libs
+	ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
 
-	// Ensure that the platform variant ends with _core_shared
+	// Ensure that the platform variant ends with _core_shared or _common
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared")
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared")
+	ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common")
+	ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common")
 
 	// Ensure that all symlinks are present.
 	found_foo_link_64 := false
@@ -360,7 +428,7 @@
 }
 
 func TestBasicZipApex(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -408,7 +476,7 @@
 }
 
 func TestApexWithStubs(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -492,7 +560,7 @@
 }
 
 func TestApexWithExplicitStubsDependency(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -559,7 +627,7 @@
 }
 
 func TestApexWithSystemLibsStubs(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -680,7 +748,7 @@
 }
 
 func TestFilesInSubDir(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -740,7 +808,7 @@
 }
 
 func TestUseVendor(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -789,8 +857,32 @@
 	ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib2.so")
 }
 
+func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) {
+	testApexError(t, `dependency "mylib" of "myapex" missing variant:\n.*image:vendor`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+			use_vendor: true,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+}
+
 func TestStaticLinking(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -830,7 +922,7 @@
 }
 
 func TestKeys(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex_keytest",
 			key: "myapex.key",
@@ -884,7 +976,7 @@
 }
 
 func TestMacro(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -928,7 +1020,7 @@
 }
 
 func TestHeaderLibsDependency(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -975,8 +1067,111 @@
 	ensureContains(t, cFlags, "-Imy_include")
 }
 
+func TestDependenciesInApexManifest(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex_nodep",
+			key: "myapex.key",
+			native_shared_libs: ["lib_nodep"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex {
+			name: "myapex_dep",
+			key: "myapex.key",
+			native_shared_libs: ["lib_dep"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex {
+			name: "myapex_provider",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex {
+			name: "myapex_selfcontained",
+			key: "myapex.key",
+			native_shared_libs: ["lib_dep", "libfoo"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "lib_nodep",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "lib_dep",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libfoo"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libfoo",
+			srcs: ["mytest.cpp"],
+			stubs: {
+				versions: ["1"],
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	names := func(s string) (ns []string) {
+		for _, n := range strings.Split(s, " ") {
+			if len(n) > 0 {
+				ns = append(ns, n)
+			}
+		}
+		return
+	}
+
+	var injectRule android.TestingBuildParams
+	var provideNativeLibs, requireNativeLibs []string
+
+	injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListEmpty(t, provideNativeLibs)
+	ensureListEmpty(t, requireNativeLibs)
+
+	injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListEmpty(t, provideNativeLibs)
+	ensureListContains(t, requireNativeLibs, "libfoo.so")
+
+	injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListContains(t, provideNativeLibs, "libfoo.so")
+	ensureListEmpty(t, requireNativeLibs)
+
+	injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListContains(t, provideNativeLibs, "libfoo.so")
+	ensureListEmpty(t, requireNativeLibs)
+}
+
 func TestNonTestApex(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1027,7 +1222,7 @@
 	if android.InAnyApex("mylib_common_test") {
 		t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!")
 	}
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex_test {
 			name: "myapex",
 			key: "myapex.key",
@@ -1075,7 +1270,7 @@
 }
 
 func TestApexWithTarget(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1155,7 +1350,7 @@
 }
 
 func TestApexWithShBinary(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1183,7 +1378,7 @@
 }
 
 func TestApexInProductPartition(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1215,7 +1410,7 @@
 }
 
 func TestApexKeyFromOtherModule(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		apex_key {
 			name: "myapex.key",
 			public_key: ":my.avbpubkey",
@@ -1248,7 +1443,7 @@
 }
 
 func TestPrebuilt(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -1271,7 +1466,7 @@
 }
 
 func TestPrebuiltFilenameOverride(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, _ := testApex(t, `
 		prebuilt_apex {
 			name: "myapex",
 			src: "myapex-arm.apex",
@@ -1287,13 +1482,34 @@
 	}
 }
 
+func TestPrebuiltOverrides(t *testing.T) {
+	ctx, config := testApex(t, `
+		prebuilt_apex {
+			name: "myapex.prebuilt",
+			src: "myapex-arm.apex",
+			overrides: [
+				"myapex",
+			],
+		}
+	`)
+
+	p := ctx.ModuleForTests("myapex.prebuilt", "android_common").Module().(*Prebuilt)
+
+	expected := []string{"myapex"}
+	actual := android.AndroidMkEntriesForTest(t, config, "", p).EntryMap["LOCAL_OVERRIDES_PACKAGES"]
+	if !reflect.DeepEqual(actual, expected) {
+		t.Errorf("Incorrect LOCAL_OVERRIDES_PACKAGES value '%s', expected '%s'", actual, expected)
+	}
+}
+
 func TestApexWithTests(t *testing.T) {
-	ctx := testApex(t, `
+	ctx, config := testApex(t, `
 		apex_test {
 			name: "myapex",
 			key: "myapex.key",
 			tests: [
 				"mytest",
+				"mytests",
 			],
 		}
 
@@ -1312,6 +1528,21 @@
 			static_executable: true,
 			stl: "none",
 		}
+
+		cc_test {
+			name: "mytests",
+			gtest: false,
+			srcs: [
+				"mytest1.cpp",
+				"mytest2.cpp",
+				"mytest3.cpp",
+			],
+			test_per_src: true,
+			relative_install_path: "test",
+			system_shared_libs: [],
+			static_executable: true,
+			stl: "none",
+		}
 	`)
 
 	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -1319,6 +1550,143 @@
 
 	// Ensure that test dep is copied into apex.
 	ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
+
+	// Ensure that test deps built with `test_per_src` are copied into apex.
+	ensureContains(t, copyCmds, "image.apex/bin/test/mytest1")
+	ensureContains(t, copyCmds, "image.apex/bin/test/mytest2")
+	ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
+
+	// Ensure the module is correctly translated.
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+	name := apexBundle.BaseModuleName()
+	prefix := "TARGET_"
+	var builder strings.Builder
+	data.Custom(&builder, name, prefix, "", data)
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest1\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest2\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest3\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_manifest.json\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_pubkey\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n")
+}
+
+func TestApexUsesOtherApex(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+			uses: ["commonapex"],
+		}
+
+		apex {
+			name: "commonapex",
+			key: "myapex.key",
+			native_shared_libs: ["libcommon"],
+			provide_cpp_shared_libs: true,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libcommon"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libcommon",
+			srcs: ["mylib_common.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	module1 := ctx.ModuleForTests("myapex", "android_common_myapex")
+	apexRule1 := module1.Rule("apexRule")
+	copyCmds1 := apexRule1.Args["copy_commands"]
+
+	module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex")
+	apexRule2 := module2.Rule("apexRule")
+	copyCmds2 := apexRule2.Args["copy_commands"]
+
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared_myapex")
+	ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_core_shared_commonapex")
+	ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so")
+	ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so")
+	ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so")
+}
+
+func TestApexUsesFailsIfNotProvided(t *testing.T) {
+	testApexError(t, `uses: "commonapex" does not provide native_shared_libs`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			uses: ["commonapex"],
+		}
+
+		apex {
+			name: "commonapex",
+			key: "myapex.key",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+	testApexError(t, `uses: "commonapex" is not a provider`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			uses: ["commonapex"],
+		}
+
+		cc_library {
+			name: "commonapex",
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+}
+
+func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) {
+	testApexError(t, `use_vendor: "commonapex" has different value of use_vendor`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			use_vendor: true,
+			uses: ["commonapex"],
+		}
+
+		apex {
+			name: "commonapex",
+			key: "myapex.key",
+			provide_cpp_shared_libs: true,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
 }
 
 func TestMain(m *testing.M) {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index cac4d9a..5f1cce8 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -508,15 +508,15 @@
 	"TARGET_OUT": {{prefix: "/usr/share", modType: "prebuilt_usr_share"}, {prefix: "/fonts", modType: "prebuilt_font"},
 		{prefix: "/etc/firmware", modType: "prebuilt_firmware"}, {prefix: "/vendor/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}},
 		{prefix: "/etc"}},
-	"TARGET_OUT_ETC":                  {{prefix: "/firmware", modType: "prebuilt_firmware"}, {prefix: ""}},
-	"TARGET_OUT_PRODUCT":              {{prefix: "/etc", flags: []string{"product_specific"}}, {prefix: "/fonts", modType: "prebuilt_font", flags: []string{"product_specific"}}},
-	"TARGET_OUT_PRODUCT_ETC":          {{prefix: "", flags: []string{"product_specific"}}},
-	"TARGET_OUT_ODM":                  {{prefix: "/etc", flags: []string{"device_specific"}}},
-	"TARGET_OUT_PRODUCT_SERVICES":     {{prefix: "/etc", flags: []string{"product_services_specific"}}},
-	"TARGET_OUT_PRODUCT_SERVICES_ETC": {{prefix: "", flags: []string{"product_services_specific"}}},
-	"TARGET_OUT_VENDOR":               {{prefix: "/etc", flags: []string{"proprietary"}}, {prefix: "/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}}},
-	"TARGET_OUT_VENDOR_ETC":           {{prefix: "", flags: []string{"proprietary"}}},
-	"TARGET_RECOVERY_ROOT_OUT":        {{prefix: "/system/etc", flags: []string{"recovery"}}},
+	"TARGET_OUT_ETC":            {{prefix: "/firmware", modType: "prebuilt_firmware"}, {prefix: ""}},
+	"TARGET_OUT_PRODUCT":        {{prefix: "/etc", flags: []string{"product_specific"}}, {prefix: "/fonts", modType: "prebuilt_font", flags: []string{"product_specific"}}},
+	"TARGET_OUT_PRODUCT_ETC":    {{prefix: "", flags: []string{"product_specific"}}},
+	"TARGET_OUT_ODM":            {{prefix: "/etc", flags: []string{"device_specific"}}},
+	"TARGET_OUT_SYSTEM_EXT":     {{prefix: "/etc", flags: []string{"system_ext_specific"}}},
+	"TARGET_OUT_SYSTEM_EXT_ETC": {{prefix: "", flags: []string{"system_ext_specific"}}},
+	"TARGET_OUT_VENDOR":         {{prefix: "/etc", flags: []string{"proprietary"}}, {prefix: "/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}}},
+	"TARGET_OUT_VENDOR_ETC":     {{prefix: "", flags: []string{"proprietary"}}},
+	"TARGET_RECOVERY_ROOT_OUT":  {{prefix: "/system/etc", flags: []string{"recovery"}}},
 }
 
 // rewriteAndroidPrebuiltEtc fixes prebuilt_etc rule
diff --git a/cc/binary.go b/cc/binary.go
index 1757f1c..149a92e 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -444,7 +444,8 @@
 	// Bionic binaries (e.g. linker) is installed to the bootstrap subdirectory.
 	// The original path becomes a symlink to the corresponding file in the
 	// runtime APEX.
-	if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
+	translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled || !ctx.Arch().Native
+	if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRecovery() {
 		if ctx.Device() && isBionic(ctx.baseModuleName()) {
 			binary.installSymlinkToRuntimeApex(ctx, file)
 		}
diff --git a/cc/builder.go b/cc/builder.go
index ee40736..2909d51 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -78,7 +78,7 @@
 		blueprint.RuleParams{
 			// Without -no-pie, clang 7.0 adds -pie to link Android files,
 			// but -r and -pie cannot be used together.
-			Command:     "$ldCmd -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}",
+			Command:     "$ldCmd -fuse-ld=lld -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}",
 			CommandDeps: []string{"$ldCmd"},
 		},
 		"ldCmd", "ldFlags")
@@ -221,6 +221,17 @@
 			Rspfile:        "$out.rsp",
 			RspfileContent: "$in",
 		})
+
+	_ = pctx.SourcePathVariable("cxxExtractor",
+		"prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/cxx_extractor")
+	_ = pctx.VariableFunc("kytheCorpus",
+		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
+	kytheExtract = pctx.StaticRule("kythe",
+		blueprint.RuleParams{
+			Command:     "rm -f $out && KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out $cxxExtractor $cFlags $in ",
+			CommandDeps: []string{"$cxxExtractor"},
+		},
+		"cFlags")
 )
 
 func init() {
@@ -257,6 +268,7 @@
 	tidy            bool
 	coverage        bool
 	sAbiDump        bool
+	emitXrefs       bool
 
 	systemIncludeFlags string
 
@@ -281,6 +293,7 @@
 	tidyFiles     android.Paths
 	coverageFiles android.Paths
 	sAbiDumpFiles android.Paths
+	kytheFiles    android.Paths
 }
 
 func (a Objects) Copy() Objects {
@@ -289,6 +302,7 @@
 		tidyFiles:     append(android.Paths{}, a.tidyFiles...),
 		coverageFiles: append(android.Paths{}, a.coverageFiles...),
 		sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...),
+		kytheFiles:    append(android.Paths{}, a.kytheFiles...),
 	}
 }
 
@@ -298,6 +312,7 @@
 		tidyFiles:     append(a.tidyFiles, b.tidyFiles...),
 		coverageFiles: append(a.coverageFiles, b.coverageFiles...),
 		sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...),
+		kytheFiles:    append(a.kytheFiles, b.kytheFiles...),
 	}
 }
 
@@ -314,6 +329,10 @@
 	if flags.coverage {
 		coverageFiles = make(android.Paths, 0, len(srcFiles))
 	}
+	var kytheFiles android.Paths
+	if flags.emitXrefs {
+		kytheFiles = make(android.Paths, 0, len(srcFiles))
+	}
 
 	commonFlags := strings.Join([]string{
 		flags.globalFlags,
@@ -401,6 +420,7 @@
 		coverage := flags.coverage
 		dump := flags.sAbiDump
 		rule := cc
+		emitXref := flags.emitXrefs
 
 		switch srcFile.Ext() {
 		case ".s":
@@ -412,6 +432,7 @@
 			tidy = false
 			coverage = false
 			dump = false
+			emitXref = false
 		case ".c":
 			ccCmd = "clang"
 			moduleCflags = cflags
@@ -450,6 +471,22 @@
 			},
 		})
 
+		if emitXref {
+			kytheFile := android.ObjPathWithExt(ctx, subdir, srcFile, "kzip")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        kytheExtract,
+				Description: "Xref C++ extractor " + srcFile.Rel(),
+				Output:      kytheFile,
+				Input:       srcFile,
+				Implicits:   cFlagsDeps,
+				OrderOnly:   pathDeps,
+				Args: map[string]string{
+					"cFlags": moduleCflags,
+				},
+			})
+			kytheFiles = append(kytheFiles, kytheFile)
+		}
+
 		if tidy {
 			tidyFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy")
 			tidyFiles = append(tidyFiles, tidyFile)
@@ -493,6 +530,7 @@
 		tidyFiles:     tidyFiles,
 		coverageFiles: coverageFiles,
 		sAbiDumpFiles: sAbiDumpFiles,
+		kytheFiles:    kytheFiles,
 	}
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index 6215067..2bde2d3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -40,7 +40,7 @@
 		ctx.BottomUp("link", LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", VndkMutator).Parallel()
 		ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
-		ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
+		ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version", VersionMutator).Parallel()
 		ctx.BottomUp("begin", BeginMutator).Parallel()
 		ctx.BottomUp("sysprop", SyspropMutator).Parallel()
@@ -77,6 +77,7 @@
 		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
 	})
 
+	android.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory)
 	pctx.Import("android/soong/cc/config")
 }
 
@@ -162,6 +163,7 @@
 	Tidy      bool
 	Coverage  bool
 	SAbiDump  bool
+	EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
 
 	RequiredInstructionSet string
 	DynamicLinker          string
@@ -179,6 +181,9 @@
 }
 
 type ObjectLinkerProperties struct {
+	// list of modules that should only provide headers for this module.
+	Header_libs []string `android:"arch_variant,variant_prepend"`
+
 	// names of other cc_object modules to link into this module using partial linking
 	Objs []string `android:"arch_variant"`
 
@@ -262,7 +267,7 @@
 	isVndkSp() bool
 	isVndkExt() bool
 	inRecovery() bool
-	shouldCreateVndkSourceAbiDump(config android.Config) bool
+	shouldCreateSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
@@ -337,17 +342,22 @@
 	blueprint.BaseDependencyTag
 	name    string
 	library bool
+	shared  bool
 
 	reexportFlags bool
 
 	explicitlyVersioned bool
 }
 
+type xref interface {
+	XrefCcFiles() android.Paths
+}
+
 var (
-	sharedDepTag          = dependencyTag{name: "shared", library: true}
-	sharedExportDepTag    = dependencyTag{name: "shared", library: true, reexportFlags: true}
-	earlySharedDepTag     = dependencyTag{name: "early_shared", library: true}
-	lateSharedDepTag      = dependencyTag{name: "late shared", library: true}
+	sharedDepTag          = dependencyTag{name: "shared", library: true, shared: true}
+	sharedExportDepTag    = dependencyTag{name: "shared", library: true, shared: true, reexportFlags: true}
+	earlySharedDepTag     = dependencyTag{name: "early_shared", library: true, shared: true}
+	lateSharedDepTag      = dependencyTag{name: "late shared", library: true, shared: true}
 	staticDepTag          = dependencyTag{name: "static", library: true}
 	staticExportDepTag    = dependencyTag{name: "static", library: true, reexportFlags: true}
 	lateStaticDepTag      = dependencyTag{name: "late static", library: true}
@@ -368,8 +378,25 @@
 	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
 	vndkExtDepTag         = dependencyTag{name: "vndk extends", library: true}
 	runtimeDepTag         = dependencyTag{name: "runtime lib"}
+	coverageDepTag        = dependencyTag{name: "coverage"}
+	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
 )
 
+func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
+	ccDepTag, ok := depTag.(dependencyTag)
+	return ok && ccDepTag.shared
+}
+
+func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
+	ccDepTag, ok := depTag.(dependencyTag)
+	return ok && ccDepTag == runtimeDepTag
+}
+
+func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {
+	ccDepTag, ok := depTag.(dependencyTag)
+	return ok && ccDepTag == testPerSrcDepTag
+}
+
 // Module contains the properties and members used by all C/C++ module types, and implements
 // the blueprint.Module interface.  It delegates to compiler, linker, and installer interfaces
 // to construct the output file.  Behavior can be customized with a Customizer interface
@@ -419,6 +446,8 @@
 	staticVariant *Module
 
 	makeLinkType string
+	// Kythe (source file indexer) paths for this compilation module
+	kytheFiles android.Paths
 }
 
 func (c *Module) OutputFile() android.OptionalPath {
@@ -645,6 +674,10 @@
 	return isBionic(name)
 }
 
+func (c *Module) XrefCcFiles() android.Paths {
+	return c.kytheFiles
+}
+
 type baseModuleContext struct {
 	android.BaseModuleContext
 	moduleContextImpl
@@ -756,7 +789,7 @@
 }
 
 // Check whether ABI dumps should be created for this module.
-func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump(config android.Config) bool {
+func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool {
 	if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
 		return false
 	}
@@ -782,18 +815,7 @@
 		// Stubs do not need ABI dumps.
 		return false
 	}
-	if ctx.isNdk() {
-		return true
-	}
-	if ctx.isLlndkPublic(config) {
-		return true
-	}
-	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(config) {
-		// Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext and this is not
-		// VNDK-private.
-		return true
-	}
-	return false
+	return true
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
@@ -938,7 +960,22 @@
 	return results
 }
 
+func (c *Module) IsTestPerSrcAllTestsVariation() bool {
+	test, ok := c.linker.(testPerSrc)
+	return ok && test.isAllTestsVariation()
+}
+
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+	// Handle the case of a test module split by `test_per_src` mutator.
+	//
+	// The `test_per_src` mutator adds an extra variation named "", depending on all the other
+	// `test_per_src` variations of the test module. Set `outputFile` to an empty path for this
+	// module and return early, as this module does not produce an output file per se.
+	if c.IsTestPerSrcAllTestsVariation() {
+		c.outputFile = android.OptionalPath{}
+		return
+	}
+
 	c.makeLinkType = c.getMakeLinkType(actx)
 
 	ctx := &moduleContext{
@@ -960,6 +997,7 @@
 
 	flags := Flags{
 		Toolchain: c.toolchain(ctx),
+		EmitXrefs: ctx.Config().EmitXrefRules(),
 	}
 	if c.compiler != nil {
 		flags = c.compiler.compilerFlags(ctx, flags, deps)
@@ -974,7 +1012,7 @@
 		flags = c.sanitize.flags(ctx, flags)
 	}
 	if c.coverage != nil {
-		flags = c.coverage.flags(ctx, flags)
+		flags, deps = c.coverage.flags(ctx, flags, deps)
 	}
 	if c.lto != nil {
 		flags = c.lto.flags(ctx, flags)
@@ -1025,6 +1063,7 @@
 		if ctx.Failed() {
 			return
 		}
+		c.kytheFiles = objs.kytheFiles
 	}
 
 	if c.linker != nil {
@@ -1848,7 +1887,7 @@
 			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
 			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
 
-			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() {
+			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() && !c.inRecovery() {
 				// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 				// core module instead.
 				return libName
@@ -2015,12 +2054,14 @@
 }
 
 // Overrides ApexModule.IsInstallabeToApex()
-// Only shared libraries are installable to APEX.
+// Only shared/runtime libraries and "test_per_src" tests are installable to APEX.
 func (c *Module) IsInstallableToApex() bool {
 	if shared, ok := c.linker.(interface {
 		shared() bool
 	}); ok {
 		return shared.shared()
+	} else if _, ok := c.linker.(testPerSrc); ok {
+		return true
 	}
 	return false
 }
@@ -2082,6 +2123,7 @@
 		&VendorProperties{},
 		&BaseCompilerProperties{},
 		&BaseLinkerProperties{},
+		&ObjectLinkerProperties{},
 		&LibraryProperties{},
 		&FlagExporterProperties{},
 		&BinaryLinkerProperties{},
@@ -2330,6 +2372,31 @@
 	return ctx.Config().PlatformSdkVersion()
 }
 
+func kytheExtractAllFactory() android.Singleton {
+	return &kytheExtractAllSingleton{}
+}
+
+type kytheExtractAllSingleton struct {
+}
+
+func (ks *kytheExtractAllSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var xrefTargets android.Paths
+	ctx.VisitAllModules(func(module android.Module) {
+		if ccModule, ok := module.(xref); ok {
+			xrefTargets = append(xrefTargets, ccModule.XrefCcFiles()...)
+		}
+	})
+	// TODO(asmundak): Perhaps emit a rule to output a warning if there were no xrefTargets
+	if len(xrefTargets) > 0 {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   blueprint.Phony,
+			Output: android.PathForPhony(ctx, "xref_cxx"),
+			Inputs: xrefTargets,
+			//Default: true,
+		})
+	}
+}
+
 var Bool = proptools.Bool
 var BoolDefault = proptools.BoolDefault
 var BoolPtr = proptools.BoolPtr
diff --git a/cc/cc_test.go b/cc/cc_test.go
index ca34185..c619b5a 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2264,6 +2264,22 @@
 	}
 }
 
+// Simple smoke test for the cc_fuzz target that ensures the rule compiles
+// correctly.
+func TestFuzzTarget(t *testing.T) {
+	ctx := testCc(t, `
+		cc_fuzz {
+			name: "fuzz_smoke_test",
+			srcs: ["foo.c"],
+		}`)
+
+	variant := "android_arm64_armv8-a_core"
+	ctx.ModuleForTests("fuzz_smoke_test", variant).Rule("cc")
+}
+
+func TestAidl(t *testing.T) {
+}
+
 func assertString(t *testing.T, got, expected string) {
 	t.Helper()
 	if got != expected {
diff --git a/cc/compiler.go b/cc/compiler.go
index fd6184b..ffb6ad2 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -308,27 +309,10 @@
 		flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
 			"-isystem "+getCurrentIncludePath(ctx).String(),
 			"-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
-
-		// TODO: Migrate to API suffixed triple?
-		// Traditionally this has come from android/api-level.h, but with the
-		// libc headers unified it must be set by the build system since we
-		// don't have per-API level copies of that header now.
-		version := ctx.sdkVersion()
-		if version == "current" {
-			version = "__ANDROID_API_FUTURE__"
-		}
-		flags.GlobalFlags = append(flags.GlobalFlags,
-			"-D__ANDROID_API__="+version)
 	}
 
 	if ctx.useVndk() {
-		// sdkVersion() returns VNDK version for vendor modules.
-		version := ctx.sdkVersion()
-		if version == "current" {
-			version = "__ANDROID_API_FUTURE__"
-		}
-		flags.GlobalFlags = append(flags.GlobalFlags,
-			"-D__ANDROID_API__="+version, "-D__ANDROID_VNDK__")
+		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_VNDK__")
 	}
 
 	if ctx.inRecovery() {
@@ -364,6 +348,15 @@
 	flags.LdFlags = config.ClangFilterUnknownCflags(flags.LdFlags)
 
 	target := "-target " + tc.ClangTriple()
+	if ctx.Os().Class == android.Device {
+		version := ctx.sdkVersion()
+		if version == "" || version == "current" {
+			target += strconv.Itoa(android.FutureApiLevel)
+		} else {
+			target += version
+		}
+	}
+
 	gccPrefix := "-B" + config.ToolPath(tc)
 
 	flags.CFlags = append(flags.CFlags, target, gccPrefix)
@@ -485,7 +478,7 @@
 			"-I"+android.PathForModuleGen(ctx, "aidl").String())
 	}
 
-	if compiler.hasSrcExt(".rs") || compiler.hasSrcExt(".fs") {
+	if compiler.hasSrcExt(".rscript") || compiler.hasSrcExt(".fs") {
 		flags = rsFlags(ctx, flags, &compiler.Properties)
 	}
 
diff --git a/cc/config/global.go b/cc/config/global.go
index a27246e..9ce6896 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -150,8 +150,22 @@
 	pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
 	pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
 
-	pctx.StaticVariable("CommonClangGlobalCflags",
-		strings.Join(append(ClangFilterUnknownCflags(commonGlobalCflags), "${ClangExtraCflags}"), " "))
+	pctx.VariableFunc("CommonClangGlobalCflags", func(ctx android.PackageVarContext) string {
+		flags := ClangFilterUnknownCflags(commonGlobalCflags)
+		flags = append(flags, "${ClangExtraCflags}")
+
+		// http://b/131390872
+		// Automatically initialize any uninitialized stack variables.
+		// Prefer zero-init if both options are set.
+		if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") {
+			flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
+		} else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
+			flags = append(flags, "-ftrivial-auto-var-init=pattern")
+		}
+
+		return strings.Join(flags, " ")
+	})
+
 	pctx.VariableFunc("DeviceClangGlobalCflags", func(ctx android.PackageVarContext) string {
 		if ctx.Config().Fuchsia() {
 			return strings.Join(ClangFilterUnknownCflags(deviceGlobalCflags), " ")
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index d5e9d01..db9092d 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -181,6 +181,9 @@
 	if arch == "" {
 		return ""
 	}
+	if !t.Bionic() {
+		return "libclang_rt." + library + "-" + arch
+	}
 	return "libclang_rt." + library + "-" + arch + "-android"
 }
 
@@ -224,6 +227,10 @@
 	return LibclangRuntimeLibrary(t, "scudo_minimal")
 }
 
+func LibFuzzerRuntimeLibrary(t Toolchain) string {
+	return LibclangRuntimeLibrary(t, "fuzzer")
+}
+
 func ToolPath(t Toolchain) string {
 	if p := t.ToolPath(); p != "" {
 		return p
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index d9c96df..bcfae5d 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -63,7 +63,7 @@
 	}
 
 	x86_64ArchFeatureCflags = map[string][]string{
-		"ssse3":  []string{"-DUSE_SSSE3", "-mssse3"},
+		"ssse3":  []string{"-mssse3"},
 		"sse4":   []string{"-msse4"},
 		"sse4_1": []string{"-msse4.1"},
 		"sse4_2": []string{"-msse4.2"},
diff --git a/cc/config/x86_64_fuchsia_device.go b/cc/config/x86_64_fuchsia_device.go
index 79af00c..0f2013b 100644
--- a/cc/config/x86_64_fuchsia_device.go
+++ b/cc/config/x86_64_fuchsia_device.go
@@ -92,7 +92,7 @@
 }
 
 func (t *toolchainFuchsiaX8664) ToolchainClangCflags() string {
-	return "-DUSE_SSSE3 -mssse3"
+	return "-mssse3"
 }
 
 var toolchainFuchsiaSingleton Toolchain = &toolchainFuchsiaX8664{}
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 6504758..64392dc 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -82,7 +82,7 @@
 	}
 
 	x86ArchFeatureCflags = map[string][]string{
-		"ssse3":  []string{"-DUSE_SSSE3", "-mssse3"},
+		"ssse3":  []string{"-mssse3"},
 		"sse4":   []string{"-msse4"},
 		"sse4_1": []string{"-msse4.1"},
 		"sse4_2": []string{"-msse4.2"},
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index f072f34..f08a379 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -233,6 +233,14 @@
 	return "${config.LinuxX8664YasmFlags}"
 }
 
+func (toolchainLinuxX86) LibclangRuntimeLibraryArch() string {
+	return "i686"
+}
+
+func (toolchainLinuxX8664) LibclangRuntimeLibraryArch() string {
+	return "x86_64"
+}
+
 func (t *toolchainLinux) AvailableLibraries() []string {
 	return linuxAvailableLibraries
 }
diff --git a/cc/coverage.go b/cc/coverage.go
index 9dc7f06..0de0c1c 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -17,6 +17,8 @@
 import (
 	"strconv"
 
+	"github.com/google/blueprint"
+
 	"android/soong/android"
 )
 
@@ -41,30 +43,28 @@
 	return []interface{}{&cov.Properties}
 }
 
-func (cov *coverage) deps(ctx BaseModuleContext, deps Deps) Deps {
-	if cov.Properties.NeedCoverageBuild {
-		// Link libprofile-extras/libprofile-extras_ndk when coverage
-		// variant is required.  This is a no-op unless coverage is
-		// actually enabled during linking, when
-		// '-uinit_profile_extras' is added (in flags()) to force the
-		// setup code in libprofile-extras be linked into the
-		// binary/library.
-		//
-		// We cannot narrow it further to only the 'cov' variant since
-		// the mutator hasn't run (and we don't have the 'cov' variant
-		// yet).
-		if !ctx.useSdk() {
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "libprofile-extras")
-		} else {
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "libprofile-extras_ndk")
-		}
+func getProfileLibraryName(ctx ModuleContextIntf) string {
+	// This function should only ever be called for a cc.Module, so the
+	// following statement should always succeed.
+	if ctx.useSdk() {
+		return "libprofile-extras_ndk"
+	} else {
+		return "libprofile-extras"
+	}
+}
+
+func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
+	if cov.Properties.NeedCoverageVariant {
+		ctx.AddVariationDependencies([]blueprint.Variation{
+			{Mutator: "link", Variation: "static"},
+		}, coverageDepTag, getProfileLibraryName(ctx))
 	}
 	return deps
 }
 
-func (cov *coverage) flags(ctx ModuleContext, flags Flags) Flags {
+func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
 	if !ctx.DeviceConfig().NativeCoverageEnabled() {
-		return flags
+		return flags, deps
 	}
 
 	if cov.Properties.CoverageEnabled {
@@ -114,11 +114,13 @@
 	if cov.linkCoverage {
 		flags.LdFlags = append(flags.LdFlags, "--coverage")
 
-		// Force linking of constructor/setup code in libprofile-extras
-		flags.LdFlags = append(flags.LdFlags, "-uinit_profile_extras")
+		coverage := ctx.GetDirectDepWithTag(getProfileLibraryName(ctx), coverageDepTag).(*Module)
+		deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+
+		flags.LdFlags = append(flags.LdFlags, "-Wl,--wrap,getenv")
 	}
 
-	return flags
+	return flags, deps
 }
 
 func (cov *coverage) begin(ctx BaseModuleContext) {
diff --git a/cc/fuzz.go b/cc/fuzz.go
new file mode 100644
index 0000000..c1754b2
--- /dev/null
+++ b/cc/fuzz.go
@@ -0,0 +1,124 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+	"android/soong/cc/config"
+)
+
+func init() {
+	android.RegisterModuleType("cc_fuzz", FuzzFactory)
+}
+
+// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
+// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
+// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
+func FuzzFactory() android.Module {
+	module := NewFuzz(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func NewFuzzInstaller() *baseInstaller {
+	return NewBaseInstaller("fuzz", "fuzz", InstallInData)
+}
+
+type fuzzBinary struct {
+	*binaryDecorator
+	*baseCompiler
+}
+
+func (fuzz *fuzzBinary) linkerProps() []interface{} {
+	props := fuzz.binaryDecorator.linkerProps()
+	return props
+}
+
+func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
+	// Add ../lib[64] to rpath so that out/host/linux-x86/fuzz/<fuzzer> can
+	// find out/host/linux-x86/lib[64]/library.so
+	runpaths := []string{"../lib"}
+	for _, runpath := range runpaths {
+		if ctx.toolchain().Is64Bit() {
+			runpath += "64"
+		}
+		fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
+			fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, runpath)
+	}
+
+	// add "" to rpath so that fuzzer binaries can find libraries in their own fuzz directory
+	fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
+		fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, "")
+
+	fuzz.binaryDecorator.linkerInit(ctx)
+}
+
+func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
+	deps.StaticLibs = append(deps.StaticLibs,
+		config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
+	deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
+	return deps
+}
+
+func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
+	return flags
+}
+
+func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
+	fuzz.binaryDecorator.baseInstaller.dir = "fuzz"
+	fuzz.binaryDecorator.baseInstaller.dir64 = "fuzz"
+	fuzz.binaryDecorator.baseInstaller.install(ctx, file)
+}
+
+func NewFuzz(hod android.HostOrDeviceSupported) *Module {
+	module, binary := NewBinary(hod)
+
+	// TODO(mitchp): The toolchain does not currently export the x86 (32-bit)
+	// variant of libFuzzer for host. There is no way to only disable the host
+	// 32-bit variant, so we specify cc_fuzz targets as 64-bit only. This doesn't
+	// hurt anyone, as cc_fuzz is mostly for experimental targets as of this
+	// moment.
+	module.multilib = "64"
+
+	binary.baseInstaller = NewFuzzInstaller()
+	module.sanitize.SetSanitizer(fuzzer, true)
+
+	fuzz := &fuzzBinary{
+		binaryDecorator: binary,
+		baseCompiler:    NewBaseCompiler(),
+	}
+	module.compiler = fuzz
+	module.linker = fuzz
+	module.installer = fuzz
+
+	// The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		disableDarwinAndLinuxBionic := struct {
+			Target struct {
+				Darwin struct {
+					Enabled *bool
+				}
+				Linux_bionic struct {
+					Enabled *bool
+				}
+			}
+		}{}
+		disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
+		disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
+		ctx.AppendProperties(&disableDarwinAndLinuxBionic)
+	})
+
+	return module
+}
diff --git a/cc/gen.go b/cc/gen.go
index 7516b28..42b0cbe 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -99,7 +99,7 @@
 
 	cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison").
 		FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")).
-		Tool(ctx.Config().PrebuiltBuildTool(ctx, "bison")).
+		PrebuiltBuildTool(ctx, "bison").
 		Flag("-d").
 		Flags(flags).
 		FlagWithOutput("--defines=", headerFile).
@@ -120,8 +120,13 @@
 	headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
 	headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
 
+	baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
+	if baseDir != "" {
+		aidlFlags += " -I" + baseDir
+	}
+
 	cmd := rule.Command()
-	cmd.Tool(ctx.Config().HostToolPath(ctx, "aidl-cpp")).
+	cmd.BuiltTool(ctx, "aidl-cpp").
 		FlagWithDepFile("-d", depFile).
 		Flag("--ninja").
 		Flag(aidlFlags).
@@ -238,7 +243,7 @@
 			depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
 			srcFiles[i] = cppFile
 			deps = append(deps, genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)...)
-		case ".rs", ".fs":
+		case ".rscript", ".fs":
 			cppFile := rsGeneratedCppFile(ctx, srcFile)
 			rsFiles = append(rsFiles, srcFiles[i])
 			srcFiles[i] = cppFile
diff --git a/cc/gen_test.go b/cc/gen_test.go
index e4219d9..da3b4e8 100644
--- a/cc/gen_test.go
+++ b/cc/gen_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"strings"
 	"testing"
 )
 
@@ -42,7 +43,8 @@
 		ctx := testCc(t, `
 		filegroup {
 			name: "fg",
-			srcs: ["b.aidl"],
+			srcs: ["sub/c.aidl"],
+			path: "sub",
 		}
 
 		cc_library_shared {
@@ -59,6 +61,12 @@
 		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.GlobalFlags) {
 			t.Errorf("missing aidl includes in global flags")
 		}
+
+		aidlCommand := aidl.RuleParams.Command
+		if !strings.Contains(aidlCommand, "-Isub") {
+			t.Errorf("aidl command for c.aidl should contain \"-Isub\", but was %q", aidlCommand)
+		}
+
 	})
 
 }
diff --git a/cc/installer.go b/cc/installer.go
index cb261b7..a52ccf1 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -66,9 +66,12 @@
 	if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
 		dir = installer.dir64
 	}
-	if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+	if !ctx.Host() && !ctx.Arch().Native {
 		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
+	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
+	}
 	if installer.location == InstallInData && ctx.useVndk() {
 		dir = filepath.Join(dir, "vendor")
 	}
diff --git a/cc/library.go b/cc/library.go
index 5fbb36e..b193ab7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -33,7 +33,7 @@
 
 type StaticSharedLibraryProperties struct {
 	Srcs   []string `android:"path,arch_variant"`
-	Cflags []string `android:"path,arch_variant"`
+	Cflags []string `android:"arch_variant"`
 
 	Enabled            *bool    `android:"arch_variant"`
 	Whole_static_libs  []string `android:"arch_variant"`
@@ -110,11 +110,12 @@
 		// Symbol tags that should be ignored from the symbol file
 		Exclude_symbol_tags []string
 	}
+
+	// Order symbols in .bss section by their sizes.  Only useful for shared libraries.
+	Sort_bss_symbols_by_size *bool
 }
 
 type LibraryMutatedProperties struct {
-	VariantName string `blueprint:"mutated"`
-
 	// Build a static variant
 	BuildStatic bool `blueprint:"mutated"`
 	// Build a shared variant
@@ -431,11 +432,25 @@
 	return flags
 }
 
-func (library *libraryDecorator) shouldCreateVndkSourceAbiDump(ctx ModuleContext) bool {
+func (library *libraryDecorator) shouldCreateSourceAbiDump(ctx ModuleContext) bool {
+	if !ctx.shouldCreateSourceAbiDump() {
+		return false
+	}
 	if library.Properties.Header_abi_checker.Enabled != nil {
 		return Bool(library.Properties.Header_abi_checker.Enabled)
 	}
-	return ctx.shouldCreateVndkSourceAbiDump(ctx.Config())
+	if ctx.isNdk() {
+		return true
+	}
+	if ctx.isLlndkPublic(ctx.Config()) {
+		return true
+	}
+	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) {
+		// Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext, and not
+		// VNDK-private.
+		return true
+	}
+	return false
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -457,7 +472,7 @@
 		}
 		return Objects{}
 	}
-	if library.shouldCreateVndkSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
+	if library.shouldCreateSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
@@ -528,7 +543,7 @@
 		}
 	}
 
-	return name + library.MutatedProperties.VariantName
+	return name
 }
 
 var versioningMacroNamesListMutex sync.Mutex
@@ -633,7 +648,7 @@
 	library.objects = deps.WholeStaticLibObjs.Copy()
 	library.objects = library.objects.Append(objs)
 
-	fileName := ctx.ModuleName() + library.MutatedProperties.VariantName + staticLibraryExtension
+	fileName := ctx.ModuleName() + staticLibraryExtension
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	builderFlags := flagsToBuilderFlags(flags)
 
@@ -651,8 +666,7 @@
 
 	TransformObjToStaticLib(ctx, library.objects.objFiles, builderFlags, outputFile, objs.tidyFiles)
 
-	library.coverageOutputFile = TransformCoverageFilesToZip(ctx, library.objects,
-		ctx.ModuleName()+library.MutatedProperties.VariantName)
+	library.coverageOutputFile = TransformCoverageFilesToZip(ctx, library.objects, ctx.ModuleName())
 
 	library.wholeStaticMissingDeps = ctx.GetMissingDependencies()
 
@@ -761,6 +775,18 @@
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
 	linkerDeps = append(linkerDeps, objs.tidyFiles...)
 
+	if Bool(library.Properties.Sort_bss_symbols_by_size) {
+		unsortedOutputFile := android.PathForModuleOut(ctx, "unsorted", fileName)
+		TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
+			deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
+			linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, unsortedOutputFile, implicitOutputs)
+
+		symbolOrderingFile := android.PathForModuleOut(ctx, "unsorted", fileName+".symbol_order")
+		symbolOrderingFlag := library.baseLinker.sortBssSymbolsBySize(ctx, unsortedOutputFile, symbolOrderingFile, builderFlags)
+		builderFlags.ldFlags += " " + symbolOrderingFlag
+		linkerDeps = append(linkerDeps, symbolOrderingFile)
+	}
+
 	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
 		deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
 		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
@@ -810,7 +836,7 @@
 }
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
-	if library.shouldCreateVndkSourceAbiDump(ctx) {
+	if library.shouldCreateSourceAbiDump(ctx) {
 		vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
 		if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
 			vndkVersion = ver
@@ -955,13 +981,18 @@
 			// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
 			// The original path becomes a symlink to the corresponding file in the
 			// runtime APEX.
-			if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
+			translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled || !ctx.Arch().Native
+			if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && !translatedArch && !ctx.inRecovery() {
 				if ctx.Device() && isBionic(ctx.baseModuleName()) {
 					library.installSymlinkToRuntimeApex(ctx, file)
 				}
 				library.baseInstaller.subDir = "bootstrap"
 			}
+		} else if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && ctx.isLlndk(ctx.Config()) && !isBionic(ctx.baseModuleName()) {
+			// Skip installing LLNDK (non-bionic) libraries moved to APEX.
+			ctx.Module().SkipInstall()
 		}
+
 		library.baseInstaller.install(ctx, file)
 	}
 
diff --git a/cc/linker.go b/cc/linker.go
index b5b500e..962fcce 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -151,9 +151,6 @@
 
 	// local file name to pass to the linker as --version_script
 	Version_script *string `android:"path,arch_variant"`
-
-	// Local file name to pass to the linker as --symbol-ordering-file
-	Symbol_ordering_file *string `android:"arch_variant"`
 }
 
 func NewBaseLinker(sanitize *sanitize) *baseLinker {
@@ -447,16 +444,6 @@
 		}
 	}
 
-	if !linker.dynamicProperties.BuildStubs {
-		symbolOrderingFile := ctx.ExpandOptionalSource(
-			linker.Properties.Symbol_ordering_file, "Symbol_ordering_file")
-		if symbolOrderingFile.Valid() {
-			flags.LdFlags = append(flags.LdFlags,
-				"-Wl,--symbol-ordering-file,"+symbolOrderingFile.String())
-			flags.LdFlagsDeps = append(flags.LdFlagsDeps, symbolOrderingFile.Path())
-		}
-	}
-
 	return flags
 }
 
@@ -488,7 +475,33 @@
 		Input:       in,
 		Output:      out,
 		Args: map[string]string{
-			"buildNumberFromFile": ctx.Config().BuildNumberFromFile(),
+			"buildNumberFromFile": proptools.NinjaEscape(ctx.Config().BuildNumberFromFile()),
 		},
 	})
 }
+
+// Rule to generate .bss symbol ordering file.
+
+var (
+	_                      = pctx.SourcePathVariable("genSortedBssSymbolsPath", "build/soong/scripts/gen_sorted_bss_symbols.sh")
+	gen_sorted_bss_symbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols",
+		blueprint.RuleParams{
+			Command:     "CROSS_COMPILE=$crossCompile $genSortedBssSymbolsPath ${in} ${out}",
+			CommandDeps: []string{"$genSortedBssSymbolsPath"},
+		},
+		"crossCompile")
+)
+
+func (linker *baseLinker) sortBssSymbolsBySize(ctx ModuleContext, in android.Path, symbolOrderingFile android.ModuleOutPath, flags builderFlags) string {
+	crossCompile := gccCmd(flags.toolchain, "")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        gen_sorted_bss_symbols,
+		Description: "generate bss symbol order " + symbolOrderingFile.Base(),
+		Output:      symbolOrderingFile,
+		Input:       in,
+		Args: map[string]string{
+			"crossCompile": crossCompile,
+		},
+	})
+	return "-Wl,--symbol-ordering-file," + symbolOrderingFile.String()
+}
diff --git a/cc/lto.go b/cc/lto.go
index 1084869..431d70d 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -80,6 +80,12 @@
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
+	// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
+	// LTO breaks fuzzer builds.
+	if inList("-fsanitize=fuzzer-no-link", flags.CFlags) {
+		return flags
+	}
+
 	if lto.LTO() {
 		var ltoFlag string
 		if Bool(lto.Properties.Lto.Thin) {
diff --git a/cc/makevars.go b/cc/makevars.go
index 78a32c8..f9c58b9 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -63,6 +63,13 @@
 	}
 }
 
+type notOnHostContext struct {
+}
+
+func (c *notOnHostContext) Host() bool {
+	return false
+}
+
 func makeVarsProvider(ctx android.MakeVarsContext) {
 	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
 
@@ -102,13 +109,23 @@
 	// Therefore, by removing the library here, we cause it to only be installed if libc
 	// depends on it.
 	installedLlndkLibraries := []string{}
+
+	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
+	// they been moved to an apex.
+	movedToApexLlndkLibraries := []string{}
 	for _, lib := range *llndkLibraries(ctx.Config()) {
 		if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
 			continue
 		}
 		installedLlndkLibraries = append(installedLlndkLibraries, lib)
+
+		// Skip bionic libs, they are handled in different manner
+		if android.DirectlyInAnyApex(&notOnHostContext{}, lib) && !isBionic(lib) {
+			movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib)
+		}
 	}
 	ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
+	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " "))
 
 	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " "))
 	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " "))
@@ -138,7 +155,6 @@
 
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
-	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", strings.Join(asanLibs, " "))
 
 	ctx.Strict("HWADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(hwasanCflags, " "))
 	ctx.Strict("HWADDRESS_SANITIZER_GLOBAL_OPTIONS", strings.Join(hwasanGlobalOptions, ","))
@@ -250,9 +266,9 @@
 	}
 
 	clangPrefix := secondPrefix + "CLANG_" + typePrefix
-	clangExtras := "-target " + toolchain.ClangTriple()
-	clangExtras += " -B" + config.ToolPath(toolchain)
+	clangExtras := "-B" + config.ToolPath(toolchain)
 
+	ctx.Strict(clangPrefix+"TRIPLE", toolchain.ClangTriple())
 	ctx.Strict(clangPrefix+"GLOBAL_CFLAGS", strings.Join([]string{
 		toolchain.ClangCflags(),
 		"${config.CommonClangGlobalCflags}",
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 969cb3f..3747b41 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -54,6 +54,7 @@
 		"mediandk",
 		"nativewindow",
 		"m",
+		"neuralnetworks",
 		"OpenMAXAL",
 		"OpenSLES",
 		"stdc++",
diff --git a/cc/object.go b/cc/object.go
index 50ecc38..9fa0ac9 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -66,6 +66,7 @@
 		deps.LateSharedLibs = append(deps.LateSharedLibs, "libc")
 	}
 
+	deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs...)
 	deps.ObjFiles = append(deps.ObjFiles, object.Properties.Objs...)
 	return deps
 }
diff --git a/cc/rs.go b/cc/rs.go
index fbc6bfb..5951edb 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -51,7 +51,7 @@
 		"depFiles", "outDir", "rsFlags", "stampFile")
 )
 
-// Takes a path to a .rs or .fs file, and returns a path to a generated ScriptC_*.cpp file
+// Takes a path to a .rscript or .fs file, and returns a path to a generated ScriptC_*.cpp file
 // This has to match the logic in llvm-rs-cc in DetermineOutputFile.
 func rsGeneratedCppFile(ctx android.ModuleContext, rsFile android.Path) android.WritablePath {
 	fileName := strings.TrimSuffix(rsFile.Base(), rsFile.Ext())
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 0eb9a74..261ca88 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -33,7 +33,6 @@
 
 	asanCflags  = []string{"-fno-omit-frame-pointer"}
 	asanLdflags = []string{"-Wl,-u,__asan_preinit"}
-	asanLibs    = []string{"libasan"}
 
 	// TODO(pcc): Stop passing -hwasan-allow-ifunc here once it has been made
 	// the default.
@@ -391,7 +390,6 @@
 
 	if ctx.Device() {
 		if Bool(sanitize.Properties.Sanitize.Address) {
-			deps.StaticLibs = append(deps.StaticLibs, asanLibs...)
 			// Compiling asan and having libc_scudo in the same
 			// executable will cause the executable to crash.
 			// Remove libc_scudo since it is only used to override
@@ -445,7 +443,6 @@
 			// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
 			flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed")
 		} else {
-			flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0")
 			if ctx.bootstrap() {
 				flags.DynamicLinker = "/system/bin/bootstrap/linker_asan"
 			} else {
@@ -467,7 +464,9 @@
 
 		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
 		_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
+		_, flags.CFlags = removeFromList("-flto", flags.CFlags)
 		flags.LdFlags = append(flags.LdFlags, "-fno-lto")
+		flags.CFlags = append(flags.CFlags, "-fno-lto")
 
 		// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
 		_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
diff --git a/cc/test.go b/cc/test.go
index c735fd9..aff8ba5 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -121,7 +121,9 @@
 type testPerSrc interface {
 	testPerSrc() bool
 	srcs() []string
+	isAllTestsVariation() bool
 	setSrc(string, string)
+	unsetSrc()
 }
 
 func (test *testBinary) testPerSrc() bool {
@@ -132,28 +134,55 @@
 	return test.baseCompiler.Properties.Srcs
 }
 
+func (test *testBinary) isAllTestsVariation() bool {
+	stem := test.binaryDecorator.Properties.Stem
+	return stem != nil && *stem == ""
+}
+
 func (test *testBinary) setSrc(name, src string) {
 	test.baseCompiler.Properties.Srcs = []string{src}
 	test.binaryDecorator.Properties.Stem = StringPtr(name)
 }
 
+func (test *testBinary) unsetSrc() {
+	test.baseCompiler.Properties.Srcs = nil
+	test.binaryDecorator.Properties.Stem = StringPtr("")
+}
+
 var _ testPerSrc = (*testBinary)(nil)
 
-func testPerSrcMutator(mctx android.BottomUpMutatorContext) {
+func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok {
 		if test, ok := m.linker.(testPerSrc); ok {
-			if test.testPerSrc() && len(test.srcs()) > 0 {
+			numTests := len(test.srcs())
+			if test.testPerSrc() && numTests > 0 {
 				if duplicate, found := checkDuplicate(test.srcs()); found {
 					mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
 					return
 				}
-				testNames := make([]string, len(test.srcs()))
+				testNames := make([]string, numTests)
 				for i, src := range test.srcs() {
 					testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
 				}
+				// In addition to creating one variation per test source file,
+				// create an additional "all tests" variation named "", and have it
+				// depends on all other test_per_src variations. This is useful to
+				// create subsequent dependencies of a given module on all
+				// test_per_src variations created above: by depending on
+				// variation "", that module will transitively depend on all the
+				// other test_per_src variations without the need to know their
+				// name or even their number.
+				testNames = append(testNames, "")
 				tests := mctx.CreateLocalVariations(testNames...)
+				all_tests := tests[numTests]
+				all_tests.(*Module).linker.(testPerSrc).unsetSrc()
+				// Prevent the "all tests" variation from being installable nor
+				// exporting to Make, as it won't create any output file.
+				all_tests.(*Module).Properties.PreventInstall = true
+				all_tests.(*Module).Properties.HideFromMake = true
 				for i, src := range test.srcs() {
 					tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src)
+					mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i])
 				}
 			}
 		}
@@ -210,6 +239,11 @@
 			deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_c++", "libgtest_ndk_c++")
 		} else if BoolDefault(test.Properties.Isolated, false) {
 			deps.StaticLibs = append(deps.StaticLibs, "libgtest_isolated_main")
+			// The isolated library requires liblog, but adding it
+			// as a static library means unit tests cannot override
+			// liblog functions. Instead make it a shared library
+			// dependency.
+			deps.SharedLibs = append(deps.SharedLibs, "liblog")
 		} else {
 			deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest")
 		}
diff --git a/cc/testing.go b/cc/testing.go
index df7cb78..f0ad33b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -63,6 +63,41 @@
 		}
 
 		toolchain_library {
+			name: "libclang_rt.fuzzer-arm-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.fuzzer-aarch64-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.fuzzer-i686-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.fuzzer-x86_64-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.fuzzer-x86_64",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
 			name: "libgcc",
 			vendor_available: true,
 			recovery_available: true,
@@ -196,6 +231,7 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
 	ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
+	ctx.RegisterModuleType("cc_fuzz", android.ModuleFactoryAdaptor(FuzzFactory))
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
 	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
@@ -229,6 +265,7 @@
 		"bar.c":       nil,
 		"a.proto":     nil,
 		"b.aidl":      nil,
+		"sub/c.aidl":  nil,
 		"my_include":  nil,
 		"foo.map.txt": nil,
 		"liba.so":     nil,
diff --git a/cc/util.go b/cc/util.go
index 2e1bb25..0d1b2f0 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -74,6 +74,7 @@
 		coverage:        in.Coverage,
 		tidy:            in.Tidy,
 		sAbiDump:        in.SAbiDump,
+		emitXrefs:       in.EmitXrefs,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
diff --git a/cc/vndk.go b/cc/vndk.go
index f9f3764..2c78047 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -31,7 +31,7 @@
 		// declared as a VNDK or VNDK-SP module. The vendor variant
 		// will be installed in /system instead of /vendor partition.
 		//
-		// `vendor_vailable` must be explicitly set to either true or
+		// `vendor_available` must be explicitly set to either true or
 		// false together with `vndk: {enabled: true}`.
 		Enabled *bool
 
diff --git a/cmd/diff_target_files/target_files.go b/cmd/diff_target_files/target_files.go
index 8705ca7..0fa04e8 100644
--- a/cmd/diff_target_files/target_files.go
+++ b/cmd/diff_target_files/target_files.go
@@ -28,7 +28,7 @@
 	"ODM/",
 	"OEM/",
 	"PRODUCT/",
-	"PRODUCT_SERVICES/",
+	"SYSTEM_EXT/",
 	"ROOT/",
 	"SYSTEM/",
 	"SYSTEM_OTHER/",
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index c858c40..191b919 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -124,6 +124,25 @@
 
 var hostModuleNames = HostModuleNames{}
 
+type HostAndDeviceModuleNames map[string]bool
+
+func (n HostAndDeviceModuleNames) IsHostAndDeviceModule(groupId string, artifactId string) bool {
+	_, found := n[groupId+":"+artifactId]
+
+	return found
+}
+
+func (n HostAndDeviceModuleNames) String() string {
+	return ""
+}
+
+func (n HostAndDeviceModuleNames) Set(v string) error {
+	n[v] = true
+	return nil
+}
+
+var hostAndDeviceModuleNames = HostAndDeviceModuleNames{}
+
 var sdkVersion string
 var useVersion string
 var staticDeps bool
@@ -190,10 +209,14 @@
 	return !p.IsHostModule()
 }
 
+func (p Pom) IsHostAndDeviceModule() bool {
+	return hostAndDeviceModuleNames.IsHostAndDeviceModule(p.GroupId, p.ArtifactId)
+}
+
 func (p Pom) ModuleType() string {
 	if p.IsAar() {
 		return "android_library"
-	} else if p.IsHostModule() {
+	} else if p.IsHostModule() && !p.IsHostAndDeviceModule() {
 		return "java_library_host"
 	} else {
 		return "java_library_static"
@@ -203,7 +226,7 @@
 func (p Pom) ImportModuleType() string {
 	if p.IsAar() {
 		return "android_library_import"
-	} else if p.IsHostModule() {
+	} else if p.IsHostModule() && !p.IsHostAndDeviceModule() {
 		return "java_import_host"
 	} else {
 		return "java_import"
@@ -340,6 +363,9 @@
     {{- if .Jetifier}}
     jetifier: true,
     {{- end}}
+    {{- if .IsHostAndDeviceModule}}
+    host_supported: true,
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     static_libs: [
@@ -372,6 +398,9 @@
     {{- if .Jetifier}}
     jetifier: true,
     {{- end}}
+    {{- if .IsHostAndDeviceModule}}
+    host_supported: true,
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     static_libs: [
@@ -399,6 +428,9 @@
     name: "{{.BpName}}",
     {{- if .IsDeviceModule}}
     sdk_version: "{{.SdkVersion}}",
+    {{- if .IsHostAndDeviceModule}}
+    host_supported: true,
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     manifest: "manifests/{{.BpName}}/AndroidManifest.xml",
@@ -564,6 +596,7 @@
 	flag.Var(&extraLibs, "extra-libs", "Extra runtime dependencies needed when depending on a module")
 	flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
 	flag.Var(&hostModuleNames, "host", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is a host module")
+	flag.Var(&hostAndDeviceModuleNames, "host-and-device", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is both a host and device module.")
 	flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
 	flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
 	flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 4d59a39..39303bf 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -331,36 +331,36 @@
 	}
 
 	buildActionFlags := []struct {
-		name              string
-		description       string
-		action            build.BuildAction
-		buildDependencies bool
-		set               bool
+		name        string
+		description string
+		action      build.BuildAction
+		set         bool
 	}{{
-		name:              "all-modules",
-		description:       "Build action: build from the top of the source tree.",
-		action:            build.BUILD_MODULES,
-		buildDependencies: true,
+		name:        "all-modules",
+		description: "Build action: build from the top of the source tree.",
+		action:      build.BUILD_MODULES,
 	}, {
-		name:              "modules-in-a-dir-no-deps",
-		description:       "Build action: builds all of the modules in the current directory without their dependencies.",
-		action:            build.BUILD_MODULES_IN_A_DIRECTORY,
-		buildDependencies: false,
+		// This is redirecting to mma build command behaviour. Once it has soaked for a
+		// while, the build command is deleted from here once it has been removed from the
+		// envsetup.sh.
+		name:        "modules-in-a-dir-no-deps",
+		description: "Build action: builds all of the modules in the current directory without their dependencies.",
+		action:      build.BUILD_MODULES_IN_A_DIRECTORY,
 	}, {
-		name:              "modules-in-dirs-no-deps",
-		description:       "Build action: builds all of the modules in the supplied directories without their dependencies.",
-		action:            build.BUILD_MODULES_IN_DIRECTORIES,
-		buildDependencies: false,
+		// This is redirecting to mmma build command behaviour. Once it has soaked for a
+		// while, the build command is deleted from here once it has been removed from the
+		// envsetup.sh.
+		name:        "modules-in-dirs-no-deps",
+		description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
+		action:      build.BUILD_MODULES_IN_DIRECTORIES,
 	}, {
-		name:              "modules-in-a-dir",
-		description:       "Build action: builds all of the modules in the current directory and their dependencies.",
-		action:            build.BUILD_MODULES_IN_A_DIRECTORY,
-		buildDependencies: true,
+		name:        "modules-in-a-dir",
+		description: "Build action: builds all of the modules in the current directory and their dependencies.",
+		action:      build.BUILD_MODULES_IN_A_DIRECTORY,
 	}, {
-		name:              "modules-in-dirs",
-		description:       "Build action: builds all of the modules in the supplied directories and their dependencies.",
-		action:            build.BUILD_MODULES_IN_DIRECTORIES,
-		buildDependencies: true,
+		name:        "modules-in-dirs",
+		description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
+		action:      build.BUILD_MODULES_IN_DIRECTORIES,
 	}}
 	for i, flag := range buildActionFlags {
 		flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
@@ -380,12 +380,10 @@
 	// is specified.
 	buildActionCount := 0
 	var buildAction build.BuildAction
-	buildDependency := false
 	for _, flag := range buildActionFlags {
 		if flag.set {
 			buildActionCount++
 			buildAction = flag.action
-			buildDependency = flag.buildDependencies
 		}
 	}
 	if buildActionCount != 1 {
@@ -397,7 +395,7 @@
 
 	// Remove the build action flags from the args as they are not recognized by the config.
 	args = args[numBuildActionFlags:]
-	return build.NewBuildActionConfig(buildAction, *dir, buildDependency, ctx, args...)
+	return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
 }
 
 func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
@@ -410,7 +408,22 @@
 		fmt.Fprintln(writer, "!")
 		fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
 		fmt.Fprintln(writer, "")
-		time.Sleep(5 * time.Second)
+		select {
+		case <-time.After(5 * time.Second):
+		case <-ctx.Done():
+			return
+		}
+	}
+
+	if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
+		writer := ctx.Writer
+		fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
+		fmt.Fprintln(writer, "!")
+		fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
+		fmt.Fprintln(writer, "!")
+		fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
+		fmt.Fprintln(writer, "")
+		ctx.Fatal("done")
 	}
 
 	toBuild := build.BuildAll
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3e32958..51f5519 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -113,6 +113,7 @@
 
 	ProfileClassListing  android.OptionalPath
 	ProfileIsTextListing bool
+	ProfileBootListing   android.OptionalPath
 
 	EnforceUsesLibraries         bool
 	PresentOptionalUsesLibraries []string
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index e02e60f..c378f09 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -108,11 +108,15 @@
 	rule = android.NewRuleBuilder()
 
 	generateProfile := module.ProfileClassListing.Valid() && !global.DisableGenerateProfile
+	generateBootProfile := module.ProfileBootListing.Valid() && !global.DisableGenerateProfile
 
 	var profile android.WritablePath
 	if generateProfile {
 		profile = profileCommand(ctx, global, module, rule)
 	}
+	if generateBootProfile {
+		bootProfileCommand(ctx, global, module, rule)
+	}
 
 	if !dexpreoptDisabled(global, module) {
 		// Don't preopt individual boot jars, they will be preopted together.
@@ -190,6 +194,38 @@
 	return profilePath
 }
 
+func bootProfileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig,
+	rule *android.RuleBuilder) android.WritablePath {
+
+	profilePath := module.BuildPath.InSameDir(ctx, "profile.bprof")
+	profileInstalledPath := module.DexLocation + ".bprof"
+
+	if !module.ProfileIsTextListing {
+		rule.Command().FlagWithOutput("touch ", profilePath)
+	}
+
+	cmd := rule.Command().
+		Text(`ANDROID_LOG_TAGS="*:e"`).
+		Tool(global.Tools.Profman)
+
+	// The profile is a test listing of methods.
+	// We need to generate the actual binary profile.
+	cmd.FlagWithInput("--create-profile-from=", module.ProfileBootListing.Path())
+
+	cmd.
+		Flag("--generate-boot-profile").
+		FlagWithInput("--apk=", module.DexPath).
+		Flag("--dex-location="+module.DexLocation).
+		FlagWithOutput("--reference-profile-file=", profilePath)
+
+	if !module.ProfileIsTextListing {
+		cmd.Text(fmt.Sprintf(`|| echo "Profile out of date for %s"`, module.DexPath))
+	}
+	rule.Install(profilePath, profileInstalledPath)
+
+	return profilePath
+}
+
 func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
 	arch android.ArchType, profile, bootImage android.Path, bootImageDeps android.Paths, appImage, generateDM bool) {
 
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b0657ff..411da05 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -284,12 +284,12 @@
 
 	referencedDepfile := false
 
-	rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
+	rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
 		// report the error directly without returning an error to android.Expand to catch multiple errors in a
 		// single run
-		reportError := func(fmt string, args ...interface{}) (string, error) {
+		reportError := func(fmt string, args ...interface{}) (string, bool, error) {
 			ctx.PropertyErrorf("cmd", fmt, args...)
-			return "SOONG_ERROR", nil
+			return "SOONG_ERROR", false, nil
 		}
 
 		switch name {
@@ -304,19 +304,19 @@
 				return reportError("default label %q has multiple files, use $(locations %s) to reference it",
 					firstLabel, firstLabel)
 			}
-			return locationLabels[firstLabel][0], nil
+			return locationLabels[firstLabel][0], false, nil
 		case "in":
-			return "${in}", nil
+			return "${in}", true, nil
 		case "out":
-			return "__SBOX_OUT_FILES__", nil
+			return "__SBOX_OUT_FILES__", false, nil
 		case "depfile":
 			referencedDepfile = true
 			if !Bool(g.properties.Depfile) {
 				return reportError("$(depfile) used without depfile property")
 			}
-			return "__SBOX_DEPFILE__", nil
+			return "__SBOX_DEPFILE__", false, nil
 		case "genDir":
-			return "__SBOX_OUT_DIR__", nil
+			return "__SBOX_OUT_DIR__", false, nil
 		default:
 			if strings.HasPrefix(name, "location ") {
 				label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
@@ -327,7 +327,7 @@
 						return reportError("label %q has multiple files, use $(locations %s) to reference it",
 							label, label)
 					}
-					return paths[0], nil
+					return paths[0], false, nil
 				} else {
 					return reportError("unknown location label %q", label)
 				}
@@ -337,7 +337,7 @@
 					if len(paths) == 0 {
 						return reportError("label %q has no files", label)
 					}
-					return strings.Join(paths, " "), nil
+					return strings.Join(paths, " "), false, nil
 				} else {
 					return reportError("unknown locations label %q", label)
 				}
diff --git a/java/androidmk.go b/java/androidmk.go
index 39c2d13..ad0e171 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -55,6 +55,11 @@
 }
 
 func (library *Library) AndroidMk() android.AndroidMkData {
+	if !library.IsForPlatform() {
+		return android.AndroidMkData{
+			Disabled: true,
+		}
+	}
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
 		OutputFile: android.OptionalPathForPath(library.outputFile),
@@ -141,6 +146,11 @@
 }
 
 func (prebuilt *Import) AndroidMk() android.AndroidMkData {
+	if !prebuilt.IsForPlatform() {
+		return android.AndroidMkData{
+			Disabled: true,
+		}
+	}
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
 		OutputFile: android.OptionalPathForPath(prebuilt.combinedClasspathFile),
@@ -157,6 +167,11 @@
 }
 
 func (prebuilt *DexImport) AndroidMk() android.AndroidMkData {
+	if !prebuilt.IsForPlatform() {
+		return android.AndroidMkData{
+			Disabled: true,
+		}
+	}
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
 		OutputFile: android.OptionalPathForPath(prebuilt.maybeStrippedDexJarFile),
@@ -327,6 +342,18 @@
 					install := "$(LOCAL_MODULE_PATH)/" + strings.TrimSuffix(app.installApkName, ".apk") + split.suffix + ".apk"
 					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED +=", split.path.String()+":"+install)
 				}
+				if app.noticeOutputs.Merged.Valid() {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+						app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE")
+				}
+				if app.noticeOutputs.TxtOutput.Valid() {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+						app.installApkName, app.noticeOutputs.TxtOutput.String(), app.installApkName+"_NOTICE.txt")
+				}
+				if app.noticeOutputs.HtmlOutput.Valid() {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+						app.installApkName, app.noticeOutputs.HtmlOutput.String(), app.installApkName+"_NOTICE.html")
+				}
 			},
 		},
 	}
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
new file mode 100644
index 0000000..fbf2baa
--- /dev/null
+++ b/java/androidmk_test.go
@@ -0,0 +1,178 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"bytes"
+	"io"
+	"io/ioutil"
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+type testAndroidMk struct {
+	*testing.T
+	body []byte
+}
+
+type testAndroidMkModule struct {
+	*testing.T
+	props map[string]string
+}
+
+func newTestAndroidMk(t *testing.T, r io.Reader) *testAndroidMk {
+	t.Helper()
+	buf, err := ioutil.ReadAll(r)
+	if err != nil {
+		t.Fatal("failed to open read Android.mk.", err)
+	}
+	return &testAndroidMk{
+		T:    t,
+		body: buf,
+	}
+}
+
+func parseAndroidMkProps(lines []string) map[string]string {
+	props := make(map[string]string)
+	for _, line := range lines {
+		line = strings.TrimLeft(line, " ")
+		if line == "" || strings.HasPrefix(line, "#") {
+			continue
+		}
+		tokens := strings.Split(line, " ")
+		if tokens[1] == "+=" {
+			props[tokens[0]] += " " + strings.Join(tokens[2:], " ")
+		} else {
+			props[tokens[0]] = strings.Join(tokens[2:], " ")
+		}
+	}
+	return props
+}
+
+func (t *testAndroidMk) moduleFor(moduleName string) *testAndroidMkModule {
+	t.Helper()
+	lines := strings.Split(string(t.body), "\n")
+	index := android.IndexList("LOCAL_MODULE := "+moduleName, lines)
+	if index == -1 {
+		t.Fatalf("%q is not found.", moduleName)
+	}
+	lines = lines[index:]
+	includeIndex := android.IndexListPred(func(line string) bool {
+		return strings.HasPrefix(line, "include")
+	}, lines)
+	if includeIndex == -1 {
+		t.Fatalf("%q is not properly defined. (\"include\" not found).", moduleName)
+	}
+	props := parseAndroidMkProps(lines[:includeIndex])
+	return &testAndroidMkModule{
+		T:     t.T,
+		props: props,
+	}
+}
+
+func (t *testAndroidMkModule) hasRequired(dep string) {
+	t.Helper()
+	required, ok := t.props["LOCAL_REQUIRED_MODULES"]
+	if !ok {
+		t.Error("LOCAL_REQUIRED_MODULES is not found.")
+		return
+	}
+	if !android.InList(dep, strings.Split(required, " ")) {
+		t.Errorf("%q is expected in LOCAL_REQUIRED_MODULES, but not found in %q.", dep, required)
+	}
+}
+
+func (t *testAndroidMkModule) hasNoRequired(dep string) {
+	t.Helper()
+	required, ok := t.props["LOCAL_REQUIRED_MODULES"]
+	if !ok {
+		return
+	}
+	if android.InList(dep, strings.Split(required, " ")) {
+		t.Errorf("%q is not expected in LOCAL_REQUIRED_MODULES, but found.", dep)
+	}
+}
+
+func getAndroidMk(t *testing.T, ctx *android.TestContext, config android.Config, name string) *testAndroidMk {
+	t.Helper()
+	lib, _ := ctx.ModuleForTests(name, "android_common").Module().(*Library)
+	data := android.AndroidMkDataForTest(t, config, "", lib)
+	w := &bytes.Buffer{}
+	data.Custom(w, name, "", "", data)
+	return newTestAndroidMk(t, w)
+}
+
+func TestRequired(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			required: ["libfoo"],
+		}
+	`)
+
+	mk := getAndroidMk(t, ctx, config, "foo")
+	mk.moduleFor("foo").hasRequired("libfoo")
+}
+
+func TestHostdex(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			hostdex: true,
+		}
+	`)
+
+	mk := getAndroidMk(t, ctx, config, "foo")
+	mk.moduleFor("foo")
+	mk.moduleFor("foo-hostdex")
+}
+
+func TestHostdexRequired(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			hostdex: true,
+			required: ["libfoo"],
+		}
+	`)
+
+	mk := getAndroidMk(t, ctx, config, "foo")
+	mk.moduleFor("foo").hasRequired("libfoo")
+	mk.moduleFor("foo-hostdex").hasRequired("libfoo")
+}
+
+func TestHostdexSpecificRequired(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			hostdex: true,
+			target: {
+				hostdex: {
+					required: ["libfoo"],
+				},
+			},
+		}
+	`)
+
+	mk := getAndroidMk(t, ctx, config, "foo")
+	mk.moduleFor("foo").hasNoRequired("libfoo")
+	mk.moduleFor("foo-hostdex").hasRequired("libfoo")
+}
diff --git a/java/app.go b/java/app.go
index f58b0f8..674e5ec 100644
--- a/java/app.go
+++ b/java/app.go
@@ -30,8 +30,7 @@
 	"android/soong/tradefed"
 )
 
-var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"}
-var dpiVariantsStruct reflect.Type
+var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
 
 func init() {
 	android.RegisterModuleType("android_app", AndroidAppFactory)
@@ -40,22 +39,6 @@
 	android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
 	android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
 	android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
-
-	// Dynamically construct a struct for the dpi_variants property in android_app_import.
-	perDpiStruct := reflect.StructOf([]reflect.StructField{
-		{
-			Name: "Apk",
-			Type: reflect.TypeOf((*string)(nil)),
-		},
-	})
-	dpiVariantsFields := make([]reflect.StructField, len(supportedDpis))
-	for i, dpi := range supportedDpis {
-		dpiVariantsFields[i] = reflect.StructField{
-			Name: string(dpi),
-			Type: perDpiStruct,
-		}
-	}
-	dpiVariantsStruct = reflect.StructOf(dpiVariantsFields)
 }
 
 // AndroidManifest.xml merging
@@ -141,6 +124,8 @@
 	installApkName string
 
 	additionalAaptFlags []string
+
+	noticeOutputs android.NoticeOutputs
 }
 
 func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
@@ -206,9 +191,12 @@
 	}
 }
 
+func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.generateAndroidBuildActions(ctx)
+}
+
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
-	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
+	a.checkPlatformAPI(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
@@ -357,11 +345,7 @@
 	return jniJarFile
 }
 
-func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) android.OptionalPath {
-	if !Bool(a.appProperties.Embed_notices) && !ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
-		return android.OptionalPath{}
-	}
-
+func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) {
 	// Collect NOTICE files from all dependencies.
 	seenModules := make(map[android.Module]bool)
 	noticePathSet := make(map[android.Path]bool)
@@ -391,7 +375,7 @@
 	}
 
 	if len(noticePathSet) == 0 {
-		return android.OptionalPath{}
+		return
 	}
 	var noticePaths []android.Path
 	for path := range noticePathSet {
@@ -400,9 +384,8 @@
 	sort.Slice(noticePaths, func(i, j int) bool {
 		return noticePaths[i].String() < noticePaths[j].String()
 	})
-	noticeFile := android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths)
 
-	return android.OptionalPathForPath(noticeFile)
+	a.noticeOutputs = android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths)
 }
 
 // Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
@@ -442,6 +425,9 @@
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
 	var apkDeps android.Paths
 
+	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
+	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
+
 	// Check if the install APK name needs to be overridden.
 	a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
 
@@ -455,7 +441,10 @@
 		installDir = android.PathForModuleInstall(ctx, "app", a.installApkName)
 	}
 
-	a.aapt.noticeFile = a.noticeBuildActions(ctx, installDir)
+	a.noticeBuildActions(ctx, installDir)
+	if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+		a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput
+	}
 
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
@@ -601,8 +590,6 @@
 			a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
 		}
 	}
-	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
-	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 
 	a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites)
@@ -744,7 +731,8 @@
 	android.DefaultableModuleBase
 	prebuilt android.Prebuilt
 
-	properties AndroidAppImportProperties
+	properties  AndroidAppImportProperties
+	dpiVariants interface{}
 
 	outputFile  android.Path
 	certificate *Certificate
@@ -756,27 +744,7 @@
 
 type AndroidAppImportProperties struct {
 	// A prebuilt apk to import
-	Apk string
-
-	// Per-DPI settings. This property makes it possible to specify a different source apk path for
-	// each DPI.
-	//
-	// Example:
-	//
-	//     android_app_import {
-	//         name: "example_import",
-	//         apk: "prebuilts/example.apk",
-	//         dpi_variants: {
-	//             mdpi: {
-	//                 apk: "prebuilts/example_mdpi.apk",
-	//             },
-	//             xhdpi: {
-	//                 apk: "prebuilts/example_xhdpi.apk",
-	//             },
-	//         },
-	//         certificate: "PRESIGNED",
-	//     }
-	Dpi_variants interface{}
+	Apk *string
 
 	// 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".
@@ -799,39 +767,43 @@
 	Overrides []string
 }
 
-func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string {
-	dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi))
-	if !dpiField.IsValid() {
-		return ""
+// Chooses a source APK path to use based on the module and product specs.
+func (a *AndroidAppImport) updateSrcApkPath(ctx android.LoadHookContext) {
+	config := ctx.Config()
+
+	dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants")
+	// Try DPI variant matches in the reverse-priority order so that the highest priority match
+	// overwrites everything else.
+	// TODO(jungjw): Can we optimize this by making it priority order?
+	for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- {
+		dpi := config.ProductAAPTPrebuiltDPI()[i]
+		if inList(dpi, supportedDpis) {
+			MergePropertiesFromVariant(ctx, &a.properties, dpiProps, dpi, "dpi_variants")
+		}
 	}
-	apkValue := dpiField.FieldByName("Apk").Elem()
-	if apkValue.IsValid() {
-		return apkValue.String()
+	if config.ProductAAPTPreferredConfig() != "" {
+		dpi := config.ProductAAPTPreferredConfig()
+		if inList(dpi, supportedDpis) {
+			MergePropertiesFromVariant(ctx, &a.properties, dpiProps, dpi, "dpi_variants")
+		}
 	}
-	return ""
 }
 
-// Chooses a source APK path to use based on the module's per-DPI settings and the product config.
-func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string {
-	config := ctx.Config()
-	dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem()
-	if !dpiVariantsValue.IsValid() {
-		return a.properties.Apk
-	}
-	// Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI.
-	if config.ProductAAPTPreferredConfig() != "" {
-		if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" {
-			return apk
-		}
-	}
-	for _, dpi := range config.ProductAAPTPrebuiltDPI() {
-		if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" {
-			return apk
-		}
+func MergePropertiesFromVariant(ctx android.BaseModuleContext,
+	dst interface{}, variantGroup reflect.Value, variant, variantGroupPath string) {
+	src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant))
+	if !src.IsValid() {
+		ctx.ModuleErrorf("field %q does not exist", variantGroupPath+"."+variant)
 	}
 
-	// No match. Use the generic one.
-	return a.properties.Apk
+	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, proptools.OrderAppend)
+	if err != nil {
+		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+		} else {
+			panic(err)
+		}
+	}
 }
 
 func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -848,7 +820,7 @@
 	rule := android.NewRuleBuilder()
 	rule.Command().
 		Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
-		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		BuiltTool(ctx, "zip2zip").
 		FlagWithInput("-i ", inputPath).
 		FlagWithOutput("-o ", outputPath).
 		FlagWithArg("-0 ", "'lib/**/*.so'").
@@ -875,7 +847,7 @@
 	rule := android.NewRuleBuilder()
 	rule.Command().
 		Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
-		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		BuiltTool(ctx, "zip2zip").
 		FlagWithInput("-i ", inputPath).
 		FlagWithOutput("-o ", outputPath).
 		FlagWithArg("-0 ", "'classes*.dex'").
@@ -896,8 +868,7 @@
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
 
-	var srcApk android.Path
-	srcApk = android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
+	srcApk := a.prebuilt.SingleSourcePath(ctx)
 
 	if a.usesLibrary.enforceUsesLibraries() {
 		srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
@@ -959,16 +930,56 @@
 	return a.prebuilt.Name(a.ModuleBase.Name())
 }
 
+// Populates dpi_variants property and its fields at creation time.
+func (a *AndroidAppImport) addDpiVariants() {
+	// TODO(jungjw): Do we want to do some filtering here?
+	props := reflect.ValueOf(&a.properties).Type()
+
+	dpiFields := make([]reflect.StructField, len(supportedDpis))
+	for i, dpi := range supportedDpis {
+		dpiFields[i] = reflect.StructField{
+			Name: proptools.FieldNameForProperty(dpi),
+			Type: props,
+		}
+	}
+	dpiStruct := reflect.StructOf(dpiFields)
+	a.dpiVariants = reflect.New(reflect.StructOf([]reflect.StructField{
+		{
+			Name: "Dpi_variants",
+			Type: dpiStruct,
+		},
+	})).Interface()
+	a.AddProperties(a.dpiVariants)
+}
+
 // android_app_import imports a prebuilt apk with additional processing specified in the module.
+// DPI-specific apk source files can be specified using dpi_variants. Example:
+//
+//     android_app_import {
+//         name: "example_import",
+//         apk: "prebuilts/example.apk",
+//         dpi_variants: {
+//             mdpi: {
+//                 apk: "prebuilts/example_mdpi.apk",
+//             },
+//             xhdpi: {
+//                 apk: "prebuilts/example_xhdpi.apk",
+//             },
+//         },
+//         certificate: "PRESIGNED",
+//     }
 func AndroidAppImportFactory() android.Module {
 	module := &AndroidAppImport{}
-	module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface()
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.dexpreoptProperties)
 	module.AddProperties(&module.usesLibrary.usesLibraryProperties)
+	module.addDpiVariants()
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		module.updateSrcApkPath(ctx)
+	})
 
 	InitJavaModule(module, android.DeviceSupported)
-	android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
 
 	return module
 }
@@ -1060,7 +1071,7 @@
 	outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
 
 	rule := android.NewRuleBuilder()
-	cmd := rule.Command().Tool(ctx.Config().HostToolPath(ctx, "manifest_check")).
+	cmd := rule.Command().BuiltTool(ctx, "manifest_check").
 		Flag("--enforce-uses-libraries").
 		Input(manifest).
 		FlagWithOutput("-o ", outputFile)
diff --git a/java/app_test.go b/java/app_test.go
index c7ea338..f6a307e 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -43,7 +43,7 @@
 	}
 )
 
-func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext {
+func testAppContext(bp string, fs map[string][]byte) *android.TestContext {
 	appFS := map[string][]byte{}
 	for k, v := range fs {
 		appFS[k] = v
@@ -53,13 +53,13 @@
 		appFS[file] = nil
 	}
 
-	return testContext(config, bp, appFS)
+	return testContext(bp, appFS)
 }
 
 func testApp(t *testing.T, bp string) *android.TestContext {
 	config := testConfig(nil)
 
-	ctx := testAppContext(config, bp, nil)
+	ctx := testAppContext(bp, nil)
 
 	run(t, ctx, config)
 
@@ -72,6 +72,7 @@
 			ctx := testApp(t, moduleType+` {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current"
 				}
 			`)
 
@@ -117,6 +118,7 @@
 					name: "foo",
 					srcs: ["a.java"],
 					package_splits: ["v4", "v7,hdpi"],
+					sdk_version: "current"
 				}`)
 
 	foo := ctx.ModuleForTests("foo", "android_common")
@@ -139,6 +141,40 @@
 	}
 }
 
+func TestPlatformAPIs(t *testing.T) {
+	testJava(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			platform_apis: true,
+		}
+	`)
+
+	testJava(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+	`)
+
+	testJavaError(t, "platform_apis must be true when sdk_version is empty.", `
+		android_app {
+			name: "bar",
+			srcs: ["b.java"],
+		}
+	`)
+
+	testJavaError(t, "platform_apis must be false when sdk_version is not empty.", `
+		android_app {
+			name: "bar",
+			srcs: ["b.java"],
+			sdk_version: "system_current",
+			platform_apis: true,
+		}
+	`)
+}
+
 func TestResourceDirs(t *testing.T) {
 	testCases := []struct {
 		name      string
@@ -169,6 +205,7 @@
 	bp := `
 			android_app {
 				name: "foo",
+				sdk_version: "current",
 				%s
 			}
 		`
@@ -176,7 +213,7 @@
 	for _, testCase := range testCases {
 		t.Run(testCase.name, func(t *testing.T) {
 			config := testConfig(nil)
-			ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
+			ctx := testContext(fmt.Sprintf(bp, testCase.prop), fs)
 			run(t, ctx, config)
 
 			module := ctx.ModuleForTests("foo", "android_common")
@@ -349,12 +386,14 @@
 	bp := `
 			android_app {
 				name: "foo",
+				sdk_version: "current",
 				resource_dirs: ["foo/res"],
 				static_libs: ["lib", "lib3"],
 			}
 
 			android_app {
 				name: "bar",
+				sdk_version: "current",
 				resource_dirs: ["bar/res"],
 			}
 
@@ -388,7 +427,7 @@
 				config.TestProductVariables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays
 			}
 
-			ctx := testAppContext(config, bp, fs)
+			ctx := testAppContext(bp, fs)
 			run(t, ctx, config)
 
 			resourceListToFiles := func(module android.TestingModule, list []string) (files []string) {
@@ -461,6 +500,7 @@
 		platformSdkCodename   string
 		platformSdkFinal      bool
 		expectedMinSdkVersion string
+		platformApis          bool
 	}{
 		{
 			name:                  "current final SDK",
@@ -481,6 +521,7 @@
 		{
 			name:                  "default final SDK",
 			sdkVersion:            "",
+			platformApis:          true,
 			platformSdkInt:        27,
 			platformSdkCodename:   "REL",
 			platformSdkFinal:      true,
@@ -489,6 +530,7 @@
 		{
 			name:                  "default non-final SDK",
 			sdkVersion:            "",
+			platformApis:          true,
 			platformSdkInt:        27,
 			platformSdkCodename:   "OMR1",
 			platformSdkFinal:      false,
@@ -504,18 +546,23 @@
 	for _, moduleType := range []string{"android_app", "android_library"} {
 		for _, test := range testCases {
 			t.Run(moduleType+" "+test.name, func(t *testing.T) {
+				platformApiProp := ""
+				if test.platformApis {
+					platformApiProp = "platform_apis: true,"
+				}
 				bp := fmt.Sprintf(`%s {
 					name: "foo",
 					srcs: ["a.java"],
 					sdk_version: "%s",
-				}`, moduleType, test.sdkVersion)
+					%s
+				}`, moduleType, test.sdkVersion, platformApiProp)
 
 				config := testConfig(nil)
 				config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
 				config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
 				config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
 
-				ctx := testAppContext(config, bp, nil)
+				ctx := testAppContext(bp, nil)
 
 				run(t, ctx, config)
 
@@ -547,7 +594,7 @@
 }
 
 func TestJNIABI(t *testing.T) {
-	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
 			name: "libjni",
 			system_shared_libs: [],
@@ -620,7 +667,7 @@
 }
 
 func TestJNIPackaging(t *testing.T) {
-	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
 			name: "libjni",
 			system_shared_libs: [],
@@ -630,18 +677,21 @@
 		android_app {
 			name: "app",
 			jni_libs: ["libjni"],
+			sdk_version: "current",
 		}
 
 		android_app {
 			name: "app_noembed",
 			jni_libs: ["libjni"],
 			use_embedded_native_libs: false,
+			sdk_version: "current",
 		}
 
 		android_app {
 			name: "app_embed",
 			jni_libs: ["libjni"],
 			use_embedded_native_libs: true,
+			sdk_version: "current",
 		}
 
 		android_test {
@@ -715,6 +765,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			certificateOverride: "",
@@ -726,7 +777,8 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
-					certificate: ":new_certificate"
+					certificate: ":new_certificate",
+					sdk_version: "current",
 				}
 
 				android_app_certificate {
@@ -743,7 +795,8 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
-					certificate: "expiredkey"
+					certificate: "expiredkey",
+					sdk_version: "current",
 				}
 			`,
 			certificateOverride: "",
@@ -755,7 +808,8 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
-					certificate: "expiredkey"
+					certificate: "expiredkey",
+					sdk_version: "current",
 				}
 
 				android_app_certificate {
@@ -774,7 +828,7 @@
 			if test.certificateOverride != "" {
 				config.TestProductVariables.CertificateOverrides = []string{test.certificateOverride}
 			}
-			ctx := testAppContext(config, test.bp, nil)
+			ctx := testAppContext(test.bp, nil)
 
 			run(t, ctx, config)
 			foo := ctx.ModuleForTests("foo", "android_common")
@@ -801,6 +855,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			packageNameOverride: "",
@@ -815,6 +870,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			packageNameOverride: "foo:bar",
@@ -832,7 +888,7 @@
 			if test.packageNameOverride != "" {
 				config.TestProductVariables.PackageNameOverrides = []string{test.packageNameOverride}
 			}
-			ctx := testAppContext(config, test.bp, nil)
+			ctx := testAppContext(test.bp, nil)
 
 			run(t, ctx, config)
 			foo := ctx.ModuleForTests("foo", "android_common")
@@ -856,16 +912,18 @@
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}
 
 		android_test {
 			name: "bar",
 			instrumentation_for: "foo",
+			sdk_version: "current",
 		}
 		`
 	config := testConfig(nil)
 	config.TestProductVariables.ManifestPackageNameOverrides = []string{"foo:org.dandroid.bp"}
-	ctx := testAppContext(config, bp, nil)
+	ctx := testAppContext(bp, nil)
 
 	run(t, ctx, config)
 
@@ -879,12 +937,13 @@
 }
 
 func TestOverrideAndroidApp(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
 			certificate: "expiredkey",
 			overrides: ["qux"],
+			sdk_version: "current",
 		}
 
 		override_android_app {
@@ -980,10 +1039,11 @@
 }
 
 func TestOverrideAndroidAppDependency(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}
 
 		override_android_app {
@@ -1021,7 +1081,7 @@
 }
 
 func TestAndroidAppImport(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		android_app_import {
 			name: "foo",
 			apk: "prebuilts/apk/app.apk",
@@ -1050,7 +1110,7 @@
 }
 
 func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		android_app_import {
 			name: "foo",
 			apk: "prebuilts/apk/app.apk",
@@ -1071,7 +1131,7 @@
 }
 
 func TestAndroidAppImport_Presigned(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		android_app_import {
 			name: "foo",
 			apk: "prebuilts/apk/app.apk",
@@ -1138,7 +1198,7 @@
 		{
 			name:                "AAPTPreferredConfig matches",
 			aaptPreferredConfig: proptools.StringPtr("xhdpi"),
-			aaptPrebuiltDPI:     []string{"xxhdpi", "lhdpi"},
+			aaptPrebuiltDPI:     []string{"xxhdpi", "ldpi"},
 			expected:            "prebuilts/apk/app_xhdpi.apk",
 		},
 		{
@@ -1166,7 +1226,7 @@
 		config := testConfig(nil)
 		config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig
 		config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
-		ctx := testAppContext(config, bp, nil)
+		ctx := testAppContext(bp, nil)
 
 		run(t, ctx, config)
 
@@ -1183,7 +1243,7 @@
 }
 
 func TestStl(t *testing.T) {
-	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
 			name: "libjni",
 		}
@@ -1253,18 +1313,21 @@
 			name: "foo",
 			srcs: ["a.java"],
 			api_packages: ["foo"],
+			sdk_version: "current",
 		}
 
 		java_sdk_library {
 			name: "bar",
 			srcs: ["a.java"],
 			api_packages: ["bar"],
+			sdk_version: "current",
 		}
 
 		android_app {
 			name: "app",
 			srcs: ["a.java"],
 			uses_libs: ["foo"],
+			sdk_version: "current",
 			optional_uses_libs: [
 				"bar",
 				"baz",
@@ -1286,7 +1349,7 @@
 	config := testConfig(nil)
 	config.TestProductVariables.MissingUsesLibraries = []string{"baz"}
 
-	ctx := testAppContext(config, bp, nil)
+	ctx := testAppContext(bp, nil)
 
 	run(t, ctx, config)
 
@@ -1339,6 +1402,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			noCode: false,
@@ -1348,6 +1412,7 @@
 			bp: `
 				android_app {
 					name: "foo",
+					sdk_version: "current",
 				}
 			`,
 			noCode: true,
@@ -1358,11 +1423,13 @@
 				android_app {
 					name: "foo",
 					static_libs: ["lib"],
+					sdk_version: "current",
 				}
 
 				java_library {
 					name: "lib",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			noCode: false,
@@ -1373,10 +1440,12 @@
 				android_app {
 					name: "foo",
 					static_libs: ["lib"],
+					sdk_version: "current",
 				}
 
 				java_library {
 					name: "lib",
+					sdk_version: "current",
 				}
 			`,
 			// TODO(jungjw): this should probably be true
@@ -1398,7 +1467,7 @@
 }
 
 func TestEmbedNotice(t *testing.T) {
-	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
@@ -1406,6 +1475,7 @@
 			jni_libs: ["libjni"],
 			notice: "APP_NOTICE",
 			embed_notices: true,
+			sdk_version: "current",
 		}
 
 		// No embed_notice flag
@@ -1414,6 +1484,7 @@
 			srcs: ["a.java"],
 			jni_libs: ["libjni"],
 			notice: "APP_NOTICE",
+			sdk_version: "current",
 		}
 
 		// No NOTICE files
@@ -1421,6 +1492,7 @@
 			name: "baz",
 			srcs: ["a.java"],
 			embed_notices: true,
+			sdk_version: "current",
 		}
 
 		cc_library {
@@ -1435,6 +1507,7 @@
 			srcs: [
 				":gen",
 			],
+			sdk_version: "current",
 		}
 
 		genrule {
@@ -1479,16 +1552,20 @@
 
 	// bar has NOTICE files to process, but embed_notices is not set.
 	bar := ctx.ModuleForTests("bar", "android_common")
-	mergeNotices = bar.MaybeRule("mergeNoticesRule")
-	if mergeNotices.Rule != nil {
-		t.Errorf("mergeNotices shouldn't have run for bar")
+	res = bar.Output("package-res.apk")
+	aapt2Flags = res.Args["flags"]
+	e = "-A " + buildDir + "/.intermediates/bar/android_common/NOTICE"
+	if strings.Contains(aapt2Flags, e) {
+		t.Errorf("bar shouldn't have the asset dir flag for NOTICE: %q", e)
 	}
 
 	// baz's embed_notice is true, but it doesn't have any NOTICE files.
 	baz := ctx.ModuleForTests("baz", "android_common")
-	mergeNotices = baz.MaybeRule("mergeNoticesRule")
-	if mergeNotices.Rule != nil {
-		t.Errorf("mergeNotices shouldn't have run for baz")
+	res = baz.Output("package-res.apk")
+	aapt2Flags = res.Args["flags"]
+	e = "-A " + buildDir + "/.intermediates/baz/android_common/NOTICE"
+	if strings.Contains(aapt2Flags, e) {
+		t.Errorf("baz shouldn't have the asset dir flag for NOTICE: %q", e)
 	}
 }
 
@@ -1506,6 +1583,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			uncompressedPlatform:  true,
@@ -1518,6 +1596,7 @@
 					name: "foo",
 					use_embedded_dex: true,
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			uncompressedPlatform:  true,
@@ -1530,6 +1609,7 @@
 					name: "foo",
 					privileged: true,
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			uncompressedPlatform:  true,
@@ -1545,7 +1625,7 @@
 			config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 		}
 
-		ctx := testAppContext(config, bp, nil)
+		ctx := testAppContext(bp, nil)
 
 		run(t, ctx, config)
 
diff --git a/java/builder.go b/java/builder.go
index a48e8b1..f174cf0 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -62,6 +62,37 @@
 		"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
 		"outDir", "annoDir", "javaVersion")
 
+	_ = pctx.VariableFunc("kytheCorpus",
+		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
+	// Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about
+	// "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
+	// to field java.nio.Buffer.address"
+	kytheExtract = pctx.AndroidStaticRule("kythe",
+		blueprint.RuleParams{
+			Command: `${config.ZipSyncCmd} -d $srcJarDir ` +
+				`-l $srcJarDir/list -f "*.java" $srcJars && ` +
+				`( [ ! -s $srcJarDir/list -a ! -s $out.rsp ] || ` +
+				`KYTHE_ROOT_DIRECTORY=. KYTHE_OUTPUT_FILE=$out ` +
+				`KYTHE_CORPUS=${kytheCorpus} ` +
+				`${config.SoongJavacWrapper} ${config.JavaCmd} ` +
+				`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
+				`-jar ${config.JavaKytheExtractorJar} ` +
+				`${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
+				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
+				`-source $javaVersion -target $javaVersion ` +
+				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list)`,
+			CommandDeps: []string{
+				"${config.JavaCmd}",
+				"${config.JavaKytheExtractorJar}",
+				"${config.ZipSyncCmd}",
+			},
+			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
+			Rspfile:          "$out.rsp",
+			RspfileContent:   "$in",
+		},
+		"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
+		"outDir", "annoDir", "javaVersion")
+
 	turbine = pctx.AndroidStaticRule("turbine",
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
@@ -148,16 +179,15 @@
 }
 
 type javaBuilderFlags struct {
-	javacFlags        string
-	bootClasspath     classpath
-	classpath         classpath
-	processorPath     classpath
-	processor         string
-	systemModules     classpath
-	systemModulesDeps android.Paths
-	aidlFlags         string
-	aidlDeps          android.Paths
-	javaVersion       string
+	javacFlags    string
+	bootClasspath classpath
+	classpath     classpath
+	processorPath classpath
+	processor     string
+	systemModules *systemModules
+	aidlFlags     string
+	aidlDeps      android.Paths
+	javaVersion   string
 
 	errorProneExtraJavacFlags string
 	errorProneProcessorPath   classpath
@@ -197,6 +227,61 @@
 		"errorprone", "errorprone")
 }
 
+// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
+// to compile with given set of builder flags, etc.
+func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath,
+	srcFiles, srcJars android.Paths,
+	flags javaBuilderFlags, deps android.Paths,
+	intermediatesDir string) {
+
+	deps = append(deps, srcJars...)
+
+	var bootClasspath string
+	if flags.javaVersion == "1.9" {
+		var systemModuleDeps android.Paths
+		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
+		deps = append(deps, systemModuleDeps...)
+	} else {
+		deps = append(deps, flags.bootClasspath...)
+		if len(flags.bootClasspath) == 0 && ctx.Device() {
+			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
+			// ensure java does not fall back to the default bootclasspath.
+			bootClasspath = `-bootclasspath ""`
+		} else {
+			bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath")
+		}
+	}
+
+	deps = append(deps, flags.classpath...)
+	deps = append(deps, flags.processorPath...)
+
+	processor := "-proc:none"
+	if flags.processor != "" {
+		processor = "-processor " + flags.processor
+	}
+
+	ctx.Build(pctx,
+		android.BuildParams{
+			Rule:        kytheExtract,
+			Description: "Xref Java extractor",
+			Output:      xrefFile,
+			Inputs:      srcFiles,
+			Implicits:   deps,
+			Args: map[string]string{
+				"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, "anno").String(),
+				"bootClasspath": bootClasspath,
+				"classpath":     flags.classpath.FormJavaClassPath("-classpath"),
+				"javacFlags":    flags.javacFlags,
+				"javaVersion":   flags.javaVersion,
+				"outDir":        android.PathForModuleOut(ctx, "javac", "classes.xref").String(),
+				"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
+				"processor":     processor,
+				"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, "srcjars.xref").String(),
+				"srcJars":       strings.Join(srcJars.Strings(), " "),
+			},
+		})
+}
+
 func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
 
@@ -249,8 +334,9 @@
 
 	var bootClasspath string
 	if flags.javaVersion == "1.9" {
-		deps = append(deps, flags.systemModulesDeps...)
-		bootClasspath = flags.systemModules.FormJavaSystemModulesPath("--system=", ctx.Device())
+		var systemModuleDeps android.Paths
+		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
+		deps = append(deps, systemModuleDeps...)
 	} else {
 		deps = append(deps, flags.bootClasspath...)
 		if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -411,7 +497,7 @@
 	})
 }
 
-type classpath []android.Path
+type classpath android.Paths
 
 func (x *classpath) FormJavaClassPath(optName string) string {
 	if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") {
@@ -424,21 +510,6 @@
 	}
 }
 
-// Returns a --system argument in the form javac expects with -source 1.9.  If forceEmpty is true,
-// returns --system=none if the list is empty to ensure javac does not fall back to the default
-// system modules.
-func (x *classpath) FormJavaSystemModulesPath(optName string, forceEmpty bool) string {
-	if len(*x) > 1 {
-		panic("more than one system module")
-	} else if len(*x) == 1 {
-		return optName + (*x)[0].String()
-	} else if forceEmpty {
-		return optName + "none"
-	} else {
-		return ""
-	}
-}
-
 func (x *classpath) FormTurbineClasspath(optName string) []string {
 	if x == nil || *x == nil {
 		return nil
@@ -466,3 +537,21 @@
 	}
 	return ret
 }
+
+type systemModules struct {
+	dir  android.Path
+	deps android.Paths
+}
+
+// Returns a --system argument in the form javac expects with -source 1.9.  If forceEmpty is true,
+// returns --system=none if the list is empty to ensure javac does not fall back to the default
+// system modules.
+func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) {
+	if x != nil {
+		return "--system=" + x.dir.String(), x.deps
+	} else if forceEmpty {
+		return "--system=none", nil
+	} else {
+		return "", nil
+	}
+}
diff --git a/java/config/config.go b/java/config/config.go
index 6ade649..cb13744 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -47,12 +47,17 @@
 	}
 )
 
+const (
+	JavaVmFlags  = `-XX:OnError="cat hs_err_pid%p.log" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads`
+	JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads`
+)
+
 func init() {
 	pctx.Import("github.com/google/blueprint/bootstrap")
 
 	pctx.StaticVariable("JavacHeapSize", "2048M")
 	pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
-	pctx.StaticVariable("DexFlags", "-JXX:+TieredCompilation -JXX:TieredStopAtLevel=1")
+	pctx.StaticVariable("DexFlags", "-JXX:OnError='cat hs_err_pid%p.log' -JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads")
 
 	pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
 		`-Xmaxerrs 9999999`,
@@ -69,8 +74,9 @@
 		// b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9
 		`-XDstringConcat=inline`,
 	}, " "))
-	pctx.StaticVariable("JavaVmFlags", "-XX:OnError=\"cat hs_err_pid%p.log\" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads")
-	pctx.StaticVariable("JavacVmFlags", "-J-XX:OnError=\"cat hs_err_pid%p.log\" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads")
+
+	pctx.StaticVariable("JavaVmFlags", JavaVmFlags)
+	pctx.StaticVariable("JavacVmFlags", JavacVmFlags)
 
 	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 
@@ -88,6 +94,7 @@
 	pctx.SourcePathVariable("JlinkCmd", "${JavaToolchain}/jlink")
 	pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
 	pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar")
+	pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
 	pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
 
 	pctx.SourcePathVariable("GenKotlinBuildFileCmd", "build/soong/scripts/gen-kotlin-build-file.sh")
@@ -154,3 +161,41 @@
 	pctx.HostBinToolVariable("Class2Greylist", "class2greylist")
 	pctx.HostBinToolVariable("HiddenAPI", "hiddenapi")
 }
+
+// JavaCmd returns a SourcePath object with the path to the java command.
+func JavaCmd(ctx android.PathContext) android.SourcePath {
+	return javaTool(ctx, "java")
+}
+
+// JavadocCmd returns a SourcePath object with the path to the java command.
+func JavadocCmd(ctx android.PathContext) android.SourcePath {
+	return javaTool(ctx, "javadoc")
+}
+
+func javaTool(ctx android.PathContext, tool string) android.SourcePath {
+	type javaToolKey string
+
+	key := android.NewCustomOnceKey(javaToolKey(tool))
+
+	return ctx.Config().OnceSourcePath(key, func() android.SourcePath {
+		return javaToolchain(ctx).Join(ctx, tool)
+	})
+
+}
+
+var javaToolchainKey = android.NewOnceKey("javaToolchain")
+
+func javaToolchain(ctx android.PathContext) android.SourcePath {
+	return ctx.Config().OnceSourcePath(javaToolchainKey, func() android.SourcePath {
+		return javaHome(ctx).Join(ctx, "bin")
+	})
+}
+
+var javaHomeKey = android.NewOnceKey("javaHome")
+
+func javaHome(ctx android.PathContext) android.SourcePath {
+	return ctx.Config().OnceSourcePath(javaHomeKey, func() android.SourcePath {
+		// This is set up and guaranteed by soong_ui
+		return android.PathForSource(ctx, ctx.Config().Getenv("ANDROID_JAVA_HOME"))
+	})
+}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 9b9d0d8..44aae9b 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -50,9 +50,7 @@
 		}
 	`
 
-	config := testConfig(nil)
-	ctx := testContext(config, bp, nil)
-	run(t, ctx, config)
+	ctx, config := testJava(t, bp)
 
 	deviceModule := ctx.ModuleForTests("device_module", "android_common")
 	deviceTurbineCombined := deviceModule.Output("turbine-combined/device_module.jar")
@@ -133,9 +131,7 @@
 		}
 	`
 
-	config := testConfig(nil)
-	ctx := testContext(config, bp, nil)
-	run(t, ctx, config)
+	ctx, config := testJava(t, bp)
 
 	hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
 	hostJavac := hostModule.Output("javac/host_module.jar")
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index ed12fe6..6214dac 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -143,6 +143,7 @@
 	strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base())
 
 	var profileClassListing android.OptionalPath
+	var profileBootListing android.OptionalPath
 	profileIsTextListing := false
 	if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) {
 		// If dex_preopt.profile_guided is not set, default it based on the existence of the
@@ -150,6 +151,8 @@
 		if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" {
 			profileClassListing = android.OptionalPathForPath(
 				android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile)))
+			profileBootListing = android.ExistentPathForSource(ctx,
+				ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
 			profileIsTextListing = true
 		} else {
 			profileClassListing = android.ExistentPathForSource(ctx,
@@ -169,6 +172,7 @@
 
 		ProfileClassListing:  profileClassListing,
 		ProfileIsTextListing: profileIsTextListing,
+		ProfileBootListing:   profileBootListing,
 
 		EnforceUsesLibraries:         d.enforceUsesLibs,
 		PresentOptionalUsesLibraries: d.optionalUsesLibs,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index fe468a9..2a142ba 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -216,6 +216,7 @@
 	}
 
 	profile := bootImageProfileRule(ctx, image, missingDeps)
+	bootFrameworkProfileRule(ctx, image, missingDeps)
 
 	var allFiles android.Paths
 
@@ -229,7 +230,7 @@
 	if image.zip != nil {
 		rule := android.NewRuleBuilder()
 		rule.Command().
-			Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+			BuiltTool(ctx, "soong_zip").
 			FlagWithOutput("-o ", image.zip).
 			FlagWithArg("-C ", image.dir.String()).
 			FlagWithInputList("-f ", allFiles, " -f ")
@@ -297,6 +298,7 @@
 		FlagForEachArg("--dex-location=", image.dexLocations).
 		Flag("--generate-debug-info").
 		Flag("--generate-build-id").
+		Flag("--image-format=lz4hc").
 		FlagWithOutput("--oat-symbols=", symbolsFile).
 		Flag("--strip").
 		FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat")).
@@ -424,6 +426,52 @@
 
 var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
 
+func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
+	global := dexpreoptGlobalConfig(ctx)
+
+	if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+		return nil
+	}
+	return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} {
+		tools := global.Tools
+
+		rule := android.NewRuleBuilder()
+		rule.MissingDeps(missingDeps)
+
+		// Some branches like master-art-host don't have frameworks/base, so manually
+		// handle the case that the default is missing.  Those branches won't attempt to build the profile rule,
+		// and if they do they'll get a missing deps error.
+		defaultProfile := "frameworks/base/config/boot-profile.txt"
+		path := android.ExistentPathForSource(ctx, defaultProfile)
+		var bootFrameworkProfile android.Path
+		if path.Valid() {
+			bootFrameworkProfile = path.Path()
+		} else {
+			missingDeps = append(missingDeps, defaultProfile)
+			bootFrameworkProfile = android.PathForOutput(ctx, "missing")
+		}
+
+		profile := image.dir.Join(ctx, "boot.bprof")
+
+		rule.Command().
+			Text(`ANDROID_LOG_TAGS="*:e"`).
+			Tool(tools.Profman).
+			Flag("--generate-boot-profile").
+			FlagWithInput("--create-profile-from=", bootFrameworkProfile).
+			FlagForEachInput("--apk=", image.dexPaths.Paths()).
+			FlagForEachArg("--dex-location=", image.dexLocations).
+			FlagWithOutput("--reference-profile-file=", profile)
+
+		rule.Install(profile, "/system/etc/boot-image.bprof")
+		rule.Build(pctx, ctx, "bootFrameworkProfile", "profile boot framework jars")
+		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+
+		return profile
+	}).(android.WritablePath)
+}
+
+var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
+
 func dumpOatRules(ctx android.SingletonContext, image *bootImage) {
 	var archs []android.ArchType
 	for arch := range image.images {
@@ -438,7 +486,7 @@
 		rule := android.NewRuleBuilder()
 		rule.Command().
 			// TODO: for now, use the debug version for better error reporting
-			Tool(ctx.Config().HostToolPath(ctx, "oatdumpd")).
+			BuiltTool(ctx, "oatdumpd").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPaths.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocations, ":").
 			FlagWithArg("--image=", dexpreopt.PathToLocation(image.images[arch], arch)).Implicit(image.images[arch]).
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index f91ff69..4c38399 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -51,7 +51,7 @@
 	dexpreoptConfig.RuntimeApexJars = []string{"foo", "bar", "baz"}
 	setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
 
-	ctx := testContext(config, bp, nil)
+	ctx := testContext(bp, nil)
 
 	ctx.RegisterSingletonType("dex_bootjars", android.SingletonFactoryAdaptor(dexpreoptBootJarsFactory))
 
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 7d0109f..5550a4c 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -30,6 +30,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: true,
 		},
@@ -57,6 +58,7 @@
 			bp: `
 				android_app {
 					name: "foo",
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -66,11 +68,13 @@
 				android_app {
 					name: "foo",
 					static_libs: ["lib"],
+					sdk_version: "current",
 				}
 
 				java_library {
 					name: "lib",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: true,
 		},
@@ -142,7 +146,7 @@
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			ctx := testJava(t, test.bp)
+			ctx, _ := testJava(t, test.bp)
 
 			dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeDescription("dexpreopt")
 			enabled := dexpreopt.Rule != nil
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 25101de..78bfa80 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -15,126 +15,15 @@
 package java
 
 import (
-	"android/soong/android"
-	"android/soong/java/config"
 	"fmt"
 	"path/filepath"
 	"runtime"
 	"strings"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
-)
 
-var (
-	javadoc = pctx.AndroidStaticRule("javadoc",
-		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
-				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.SoongJavacWrapper} ${config.JavadocCmd} -encoding UTF-8 @$out.rsp @$srcJarDir/list ` +
-				`$opts $bootclasspathArgs $classpathArgs $sourcepathArgs ` +
-				`-d $outDir -quiet  && ` +
-				`${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
-				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir $postDoclavaCmds && ` +
-				`rm -rf "$srcJarDir"`,
-
-			CommandDeps: []string{
-				"${config.ZipSyncCmd}",
-				"${config.JavadocCmd}",
-				"${config.SoongZipCmd}",
-			},
-			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
-			Rspfile:          "$out.rsp",
-			RspfileContent:   "$in",
-			Restat:           true,
-		},
-		"outDir", "srcJarDir", "stubsDir", "srcJars", "opts",
-		"bootclasspathArgs", "classpathArgs", "sourcepathArgs", "docZip", "postDoclavaCmds")
-
-	apiCheck = pctx.AndroidStaticRule("apiCheck",
-		blueprint.RuleParams{
-			Command: `( ${config.ApiCheckCmd} -JXmx1024m -J"classpath $classpath" $opts ` +
-				`$apiFile $apiFileToCheck $removedApiFile $removedApiFileToCheck ` +
-				`&& touch $out ) || (echo -e "$msg" ; exit 38)`,
-			CommandDeps: []string{
-				"${config.ApiCheckCmd}",
-			},
-		},
-		"classpath", "opts", "apiFile", "apiFileToCheck", "removedApiFile", "removedApiFileToCheck", "msg")
-
-	updateApi = pctx.AndroidStaticRule("updateApi",
-		blueprint.RuleParams{
-			Command: `( ( cp -f $srcApiFile $destApiFile && cp -f $srcRemovedApiFile $destRemovedApiFile ) ` +
-				`&& touch $out ) || (echo failed to update public API ; exit 38)`,
-		},
-		"srcApiFile", "destApiFile", "srcRemovedApiFile", "destRemovedApiFile")
-
-	metalava = pctx.AndroidStaticRule("metalava",
-		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
-				`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
-				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.JavaCmd}  ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
-				`$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
-				`$opts && ` +
-				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
-				`rm -rf "$srcJarDir"`,
-			CommandDeps: []string{
-				"${config.ZipSyncCmd}",
-				"${config.JavaCmd}",
-				"${config.MetalavaJar}",
-				"${config.SoongZipCmd}",
-			},
-			Rspfile:        "$out.rsp",
-			RspfileContent: "$in",
-			Restat:         true,
-		},
-		"outDir", "srcJarDir", "stubsDir", "srcJars", "javaVersion", "bootclasspathArgs",
-		"classpathArgs", "sourcepathArgs", "opts")
-
-	metalavaApiCheck = pctx.AndroidStaticRule("metalavaApiCheck",
-		blueprint.RuleParams{
-			Command: `( rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
-				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.JavaCmd}  ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
-				`$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
-				`$opts && touch $out && rm -rf "$srcJarDir") || ` +
-				`( echo -e "$msg" ; exit 38 )`,
-			CommandDeps: []string{
-				"${config.ZipSyncCmd}",
-				"${config.JavaCmd}",
-				"${config.MetalavaJar}",
-			},
-			Rspfile:        "$out.rsp",
-			RspfileContent: "$in",
-		},
-		"srcJarDir", "srcJars", "javaVersion", "bootclasspathArgs", "classpathArgs", "sourcepathArgs", "opts", "msg")
-
-	nullabilityWarningsCheck = pctx.AndroidStaticRule("nullabilityWarningsCheck",
-		blueprint.RuleParams{
-			Command: `( diff $expected $actual && touch $out ) || ( echo -e "$msg" ; exit 38 )`,
-		},
-		"expected", "actual", "msg")
-
-	dokka = pctx.AndroidStaticRule("dokka",
-		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
-				`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
-				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.DokkaJar} $srcJarDir ` +
-				`$classpathArgs -format dac -dacRoot /reference/kotlin -output $outDir $opts && ` +
-				`${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
-				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
-				`rm -rf "$srcJarDir"`,
-			CommandDeps: []string{
-				"${config.ZipSyncCmd}",
-				"${config.DokkaJar}",
-				"${config.MetalavaJar}",
-				"${config.SoongZipCmd}",
-			},
-			Restat: true,
-		},
-		"outDir", "srcJarDir", "stubsDir", "srcJars", "classpathArgs", "opts", "docZip")
+	"android/soong/android"
+	"android/soong/java/config"
 )
 
 func init() {
@@ -238,7 +127,7 @@
 
 	// proofread file contains all of the text content of the javadocs concatenated into one file,
 	// suitable for spell-checking and other goodness.
-	Proofread_file *string `android:"path"`
+	Proofread_file *string
 
 	// a todo file lists the program elements that are missing documentation.
 	// At some point, this might be improved to show more warnings.
@@ -404,14 +293,6 @@
 	doclavaStubsFlags string
 	doclavaDocsFlags  string
 	postDoclavaCmds   string
-
-	metalavaStubsFlags                string
-	metalavaAnnotationsFlags          string
-	metalavaMergeAnnoDirFlags         string
-	metalavaInclusionAnnotationsFlags string
-	metalavaApiLevelsAnnotationsFlags string
-
-	metalavaApiToXmlFlags string
 }
 
 func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -454,23 +335,6 @@
 	ApiFilePath() android.Path
 }
 
-func transformUpdateApi(ctx android.ModuleContext, destApiFile, destRemovedApiFile,
-	srcApiFile, srcRemovedApiFile android.Path, output android.WritablePath) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        updateApi,
-		Description: "Update API",
-		Output:      output,
-		Implicits: append(android.Paths{}, srcApiFile, srcRemovedApiFile,
-			destApiFile, destRemovedApiFile),
-		Args: map[string]string{
-			"destApiFile":        destApiFile.String(),
-			"srcApiFile":         srcApiFile.String(),
-			"destRemovedApiFile": destRemovedApiFile.String(),
-			"srcRemovedApiFile":  srcRemovedApiFile.String(),
-		},
-	})
-}
-
 //
 // Javadoc
 //
@@ -500,6 +364,7 @@
 	}
 }
 
+// javadoc converts .java source files to documentation using javadoc.
 func JavadocFactory() android.Module {
 	module := &Javadoc{}
 
@@ -509,6 +374,7 @@
 	return module
 }
 
+// javadoc_host converts .java source files to documentation using javadoc.
 func JavadocHostFactory() android.Module {
 	module := &Javadoc{}
 
@@ -653,6 +519,7 @@
 				deps.classpath = append(deps.classpath, dep.SdkImplementationJars(ctx, j.sdkVersion())...)
 			case Dependency:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
+				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 			case android.SourceFileProducer:
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
@@ -689,8 +556,7 @@
 			if sm.outputDir == nil && len(sm.outputDeps) == 0 {
 				panic("Missing directory for system module dependency")
 			}
-			deps.systemModules = sm.outputDir
-			deps.systemModulesDeps = sm.outputDeps
+			deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
 		}
 	})
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -706,9 +572,6 @@
 	j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
 	j.srcFiles = append(j.srcFiles, deps.srcs...)
 
-	j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
-	j.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
 	if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 {
 		j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
 	}
@@ -759,52 +622,43 @@
 func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	deps := j.collectDeps(ctx)
 
-	var implicits android.Paths
-	implicits = append(implicits, deps.bootClasspath...)
-	implicits = append(implicits, deps.classpath...)
+	j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
 
-	var bootClasspathArgs, classpathArgs, sourcepathArgs string
+	outDir := android.PathForModuleOut(ctx, "out")
+	srcJarDir := android.PathForModuleOut(ctx, "srcjars")
+
+	j.stubsSrcJar = nil
+
+	rule := android.NewRuleBuilder()
+
+	rule.Command().Text("rm -rf").Text(outDir.String())
+	rule.Command().Text("mkdir -p").Text(outDir.String())
+
+	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars)
 
 	javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
-	if len(deps.bootClasspath) > 0 {
-		var systemModules classpath
-		if deps.systemModules != nil {
-			systemModules = append(systemModules, deps.systemModules)
-		}
-		implicits = append(implicits, deps.systemModulesDeps...)
-		bootClasspathArgs = systemModules.FormJavaSystemModulesPath("--system ", ctx.Device())
-		bootClasspathArgs = bootClasspathArgs + " --patch-module java.base=."
-	}
-	if len(deps.classpath.Strings()) > 0 {
-		classpathArgs = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
-	}
 
-	implicits = append(implicits, j.srcJars...)
-	implicits = append(implicits, j.argFiles...)
+	cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList,
+		deps.systemModules, deps.classpath, j.sourcepaths)
 
-	opts := "-source " + javaVersion + " -J-Xmx1024m -XDignore.symbol.file -Xdoclint:none"
+	cmd.FlagWithArg("-source ", javaVersion).
+		Flag("-J-Xmx1024m").
+		Flag("-XDignore.symbol.file").
+		Flag("-Xdoclint:none")
 
-	sourcepathArgs = "-sourcepath " + strings.Join(j.sourcepaths.Strings(), ":")
+	rule.Command().
+		BuiltTool(ctx, "soong_zip").
+		Flag("-write_if_changed").
+		Flag("-d").
+		FlagWithOutput("-o ", j.docZip).
+		FlagWithArg("-C ", outDir.String()).
+		FlagWithArg("-D ", outDir.String())
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:           javadoc,
-		Description:    "Javadoc",
-		Output:         j.stubsSrcJar,
-		ImplicitOutput: j.docZip,
-		Inputs:         j.srcFiles,
-		Implicits:      implicits,
-		Args: map[string]string{
-			"outDir":            android.PathForModuleOut(ctx, "out").String(),
-			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
-			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
-			"srcJars":           strings.Join(j.srcJars.Strings(), " "),
-			"opts":              opts,
-			"bootclasspathArgs": bootClasspathArgs,
-			"classpathArgs":     classpathArgs,
-			"sourcepathArgs":    sourcepathArgs,
-			"docZip":            j.docZip.String(),
-		},
-	})
+	rule.Restat()
+
+	zipSyncCleanupCmd(rule, srcJarDir)
+
+	rule.Build(pctx, ctx, "javadoc", "javadoc")
 }
 
 //
@@ -831,6 +685,7 @@
 	apiFilePath android.Path
 }
 
+// droiddoc converts .java source files to documentation using doclava or dokka.
 func DroiddocFactory() android.Module {
 	module := &Droiddoc{}
 
@@ -841,6 +696,7 @@
 	return module
 }
 
+// droiddoc_host converts .java source files to documentation using doclava or dokka.
 func DroiddocHostFactory() android.Module {
 	module := &Droiddoc{}
 
@@ -867,58 +723,25 @@
 	}
 }
 
-func (d *Droiddoc) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
-	deps deps) (droiddocBuilderFlags, error) {
-	var flags droiddocBuilderFlags
-
-	*implicits = append(*implicits, deps.bootClasspath...)
-	*implicits = append(*implicits, deps.classpath...)
-
-	if len(deps.bootClasspath.Strings()) > 0 {
-		// For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
-		flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
-	}
-	flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
-	// Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka.
-	dokkaClasspath := classpath{}
-	dokkaClasspath = append(dokkaClasspath, deps.bootClasspath...)
-	dokkaClasspath = append(dokkaClasspath, deps.classpath...)
-	flags.dokkaClasspathArgs = dokkaClasspath.FormJavaClassPath("-classpath")
-
-	// TODO(nanzhang): Remove this if- statement once we finish migration for all Doclava
-	// based stubs generation.
-	// In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
-	// dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
-	// the correct package name base path.
-	if len(d.Javadoc.properties.Local_sourcepaths) > 0 {
-		flags.sourcepathArgs = "-sourcepath " + strings.Join(d.Javadoc.sourcepaths.Strings(), ":")
-	} else {
-		flags.sourcepathArgs = "-sourcepath " + android.PathForModuleOut(ctx, "srcjars").String()
-	}
-
-	return flags, nil
-}
-
-func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits *android.Paths,
-	jsilver, doclava android.Path) string {
-
-	*implicits = append(*implicits, jsilver)
-	*implicits = append(*implicits, doclava)
-
+func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) {
 	var date string
 	if runtime.GOOS == "darwin" {
 		date = `date -r`
 	} else {
-		date = `date -d`
+		date = `date -d @`
 	}
 
 	// Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources.  For modules with 1.9
 	// sources, droiddoc will get sources produced by metalava which will have already stripped out the
 	// 1.9 language features.
-	args := " -source 1.8 -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " +
-		"-doclet com.google.doclava.Doclava -docletpath " + jsilver.String() + ":" + doclava.String() + " " +
-		"-hdf page.build " + ctx.Config().BuildId() + "-" + ctx.Config().BuildNumberFromFile() + " " +
-		`-hdf page.now "$$(` + date + ` @$$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")" `
+	cmd.FlagWithArg("-source ", "1.8").
+		Flag("-J-Xmx1600m").
+		Flag("-J-XX:-OmitStackTraceInFastThrow").
+		Flag("-XDignore.symbol.file").
+		FlagWithArg("-doclet ", "com.google.doclava.Doclava").
+		FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
+		FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-"+ctx.Config().BuildNumberFromFile()).
+		FlagWithArg("-hdf page.now ", `"$(`+date+`$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
 
 	if String(d.properties.Custom_template) == "" {
 		// TODO: This is almost always droiddoc-templates-sdk
@@ -927,23 +750,22 @@
 
 	ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) {
 		if t, ok := m.(*ExportedDroiddocDir); ok {
-			*implicits = append(*implicits, t.deps...)
-			args = args + " -templatedir " + t.dir.String()
+			cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps)
 		} else {
 			ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m))
 		}
 	})
 
 	if len(d.properties.Html_dirs) > 0 {
-		htmlDir := d.properties.Html_dirs[0]
-		*implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})...)
-		args = args + " -htmldir " + htmlDir
+		htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0])
+		cmd.FlagWithArg("-htmldir ", htmlDir.String()).
+			Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")}))
 	}
 
 	if len(d.properties.Html_dirs) > 1 {
-		htmlDir2 := d.properties.Html_dirs[1]
-		*implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(htmlDir2, "**/*")})...)
-		args = args + " -htmldir2 " + htmlDir2
+		htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1])
+		cmd.FlagWithArg("-htmldir2 ", htmlDir2.String()).
+			Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[1], "**/*")}))
 	}
 
 	if len(d.properties.Html_dirs) > 2 {
@@ -951,51 +773,43 @@
 	}
 
 	knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags)
-	*implicits = append(*implicits, knownTags...)
+	cmd.FlagForEachInput("-knowntags ", knownTags)
 
-	for _, kt := range knownTags {
-		args = args + " -knowntags " + kt.String()
-	}
-
-	for _, hdf := range d.properties.Hdf {
-		args = args + " -hdf " + hdf
-	}
+	cmd.FlagForEachArg("-hdf ", d.properties.Hdf)
 
 	if String(d.properties.Proofread_file) != "" {
 		proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
-		args = args + " -proofread " + proofreadFile.String()
+		cmd.FlagWithOutput("-proofread ", proofreadFile)
 	}
 
 	if String(d.properties.Todo_file) != "" {
 		// tricky part:
 		// we should not compute full path for todo_file through PathForModuleOut().
 		// the non-standard doclet will get the full path relative to "-o".
-		args = args + " -todo " + String(d.properties.Todo_file)
+		cmd.FlagWithArg("-todo ", String(d.properties.Todo_file)).
+			ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file)))
 	}
 
 	if String(d.properties.Resourcesdir) != "" {
 		// TODO: should we add files under resourcesDir to the implicits? It seems that
 		// resourcesDir is one sub dir of htmlDir
 		resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir))
-		args = args + " -resourcesdir " + resourcesDir.String()
+		cmd.FlagWithArg("-resourcesdir ", resourcesDir.String())
 	}
 
 	if String(d.properties.Resourcesoutdir) != "" {
 		// TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere.
-		args = args + " -resourcesoutdir " + String(d.properties.Resourcesoutdir)
+		cmd.FlagWithArg("-resourcesoutdir ", String(d.properties.Resourcesoutdir))
 	}
-	return args
 }
 
-func (d *Droiddoc) collectStubsFlags(ctx android.ModuleContext,
-	implicitOutputs *android.WritablePaths) string {
-	var doclavaFlags string
+func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
 	if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Api_filename) != "" {
+
 		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
-		doclavaFlags += " -api " + d.apiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.apiFile)
+		cmd.FlagWithOutput("-api ", d.apiFile)
 		d.apiFilePath = d.apiFile
 	}
 
@@ -1003,223 +817,324 @@
 		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Removed_api_filename) != "" {
 		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
-		doclavaFlags += " -removedApi " + d.removedApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.removedApiFile)
+		cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
 	}
 
 	if String(d.properties.Private_api_filename) != "" {
 		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
-		doclavaFlags += " -privateApi " + d.privateApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.privateApiFile)
+		cmd.FlagWithOutput("-privateApi ", d.privateApiFile)
 	}
 
 	if String(d.properties.Dex_api_filename) != "" {
 		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
-		doclavaFlags += " -dexApi " + d.dexApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.dexApiFile)
+		cmd.FlagWithOutput("-dexApi ", d.dexApiFile)
 	}
 
 	if String(d.properties.Private_dex_api_filename) != "" {
 		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
-		doclavaFlags += " -privateDexApi " + d.privateDexApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
+		cmd.FlagWithOutput("-privateDexApi ", d.privateDexApiFile)
 	}
 
 	if String(d.properties.Removed_dex_api_filename) != "" {
 		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
-		doclavaFlags += " -removedDexApi " + d.removedDexApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
+		cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
 	}
 
 	if String(d.properties.Exact_api_filename) != "" {
 		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
-		doclavaFlags += " -exactApi " + d.exactApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.exactApiFile)
+		cmd.FlagWithOutput("-exactApi ", d.exactApiFile)
 	}
 
 	if String(d.properties.Dex_mapping_filename) != "" {
 		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
-		doclavaFlags += " -apiMapping " + d.apiMappingFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
+		cmd.FlagWithOutput("-apiMapping ", d.apiMappingFile)
 	}
 
 	if String(d.properties.Proguard_filename) != "" {
 		d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
-		doclavaFlags += " -proguard " + d.proguardFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.proguardFile)
+		cmd.FlagWithOutput("-proguard ", d.proguardFile)
 	}
 
 	if BoolDefault(d.properties.Create_stubs, true) {
-		doclavaFlags += " -stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
+		cmd.FlagWithArg("-stubs ", stubsDir.String())
 	}
 
 	if Bool(d.properties.Write_sdk_values) {
-		doclavaFlags += " -sdkvalues " + android.PathForModuleOut(ctx, "out").String()
+		cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String())
 	}
-
-	return doclavaFlags
 }
 
-func (d *Droiddoc) getPostDoclavaCmds(ctx android.ModuleContext, implicits *android.Paths) string {
-	var cmds string
+func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) {
 	if String(d.properties.Static_doc_index_redirect) != "" {
-		static_doc_index_redirect := ctx.ExpandSource(String(d.properties.Static_doc_index_redirect),
-			"static_doc_index_redirect")
-		*implicits = append(*implicits, static_doc_index_redirect)
-		cmds = cmds + " && cp " + static_doc_index_redirect.String() + " " +
-			android.PathForModuleOut(ctx, "out", "index.html").String()
+		staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect))
+		rule.Command().Text("cp").
+			Input(staticDocIndexRedirect).
+			Output(android.PathForModuleOut(ctx, "out", "index.html"))
 	}
 
 	if String(d.properties.Static_doc_properties) != "" {
-		static_doc_properties := ctx.ExpandSource(String(d.properties.Static_doc_properties),
-			"static_doc_properties")
-		*implicits = append(*implicits, static_doc_properties)
-		cmds = cmds + " && cp " + static_doc_properties.String() + " " +
-			android.PathForModuleOut(ctx, "out", "source.properties").String()
+		staticDocProperties := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_properties))
+		rule.Command().Text("cp").
+			Input(staticDocProperties).
+			Output(android.PathForModuleOut(ctx, "out", "source.properties"))
 	}
-	return cmds
 }
 
-func (d *Droiddoc) transformDoclava(ctx android.ModuleContext, implicits android.Paths,
-	implicitOutputs android.WritablePaths,
-	bootclasspathArgs, classpathArgs, sourcepathArgs, opts, postDoclavaCmds string) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:            javadoc,
-		Description:     "Doclava",
-		Output:          d.Javadoc.stubsSrcJar,
-		Inputs:          d.Javadoc.srcFiles,
-		Implicits:       implicits,
-		ImplicitOutputs: implicitOutputs,
-		Args: map[string]string{
-			"outDir":            android.PathForModuleOut(ctx, "out").String(),
-			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
-			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
-			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
-			"opts":              opts,
-			"bootclasspathArgs": bootclasspathArgs,
-			"classpathArgs":     classpathArgs,
-			"sourcepathArgs":    sourcepathArgs,
-			"docZip":            d.Javadoc.docZip.String(),
-			"postDoclavaCmds":   postDoclavaCmds,
-		},
-	})
+func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+	outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand {
+
+	cmd := rule.Command().
+		BuiltTool(ctx, "soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
+		Flag(config.JavacVmFlags).
+		FlagWithArg("-encoding ", "UTF-8").
+		FlagWithRspFileInputList("@", srcs).
+		FlagWithInput("@", srcJarList)
+
+	// TODO(ccross): Remove this if- statement once we finish migration for all Doclava
+	// based stubs generation.
+	// In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
+	// dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
+	// the correct package name base path.
+	if len(sourcepaths) > 0 {
+		cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":")
+	} else {
+		cmd.FlagWithArg("-sourcepath ", srcJarDir.String())
+	}
+
+	cmd.FlagWithArg("-d ", outDir.String()).
+		Flag("-quiet")
+
+	return cmd
 }
 
-func (d *Droiddoc) transformCheckApi(ctx android.ModuleContext, apiFile, removedApiFile android.Path,
-	checkApiClasspath classpath, msg, opts string, output android.WritablePath) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        apiCheck,
-		Description: "Doclava Check API",
-		Output:      output,
-		Inputs:      nil,
-		Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
-			checkApiClasspath...),
-		Args: map[string]string{
-			"msg":                   msg,
-			"classpath":             checkApiClasspath.FormJavaClassPath(""),
-			"opts":                  opts,
-			"apiFile":               apiFile.String(),
-			"apiFileToCheck":        d.apiFile.String(),
-			"removedApiFile":        removedApiFile.String(),
-			"removedApiFileToCheck": d.removedApiFile.String(),
-		},
-	})
+func javadocSystemModulesCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+	outDir, srcJarDir, srcJarList android.Path, systemModules *systemModules,
+	classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+
+	cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths)
+
+	flag, deps := systemModules.FormJavaSystemModulesPath(ctx.Device())
+	cmd.Flag(flag).Implicits(deps)
+
+	cmd.FlagWithArg("--patch-module ", "java.base=.")
+
+	if len(classpath) > 0 {
+		cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+	}
+
+	return cmd
 }
 
-func (d *Droiddoc) transformDokka(ctx android.ModuleContext, implicits android.Paths,
-	classpathArgs, opts string) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        dokka,
-		Description: "Dokka",
-		Output:      d.Javadoc.stubsSrcJar,
-		Inputs:      d.Javadoc.srcFiles,
-		Implicits:   implicits,
-		Args: map[string]string{
-			"outDir":        android.PathForModuleOut(ctx, "dokka-out").String(),
-			"srcJarDir":     android.PathForModuleOut(ctx, "dokka-srcjars").String(),
-			"stubsDir":      android.PathForModuleOut(ctx, "dokka-stubsDir").String(),
-			"srcJars":       strings.Join(d.Javadoc.srcJars.Strings(), " "),
-			"classpathArgs": classpathArgs,
-			"opts":          opts,
-			"docZip":        d.Javadoc.docZip.String(),
-		},
-	})
+func javadocBootclasspathCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+	outDir, srcJarDir, srcJarList android.Path, bootclasspath, classpath classpath,
+	sourcepaths android.Paths) *android.RuleBuilderCommand {
+
+	cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths)
+
+	if len(bootclasspath) == 0 && ctx.Device() {
+		// explicitly specify -bootclasspath "" if the bootclasspath is empty to
+		// ensure java does not fall back to the default bootclasspath.
+		cmd.FlagWithArg("-bootclasspath ", `""`)
+	} else if len(bootclasspath) > 0 {
+		cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
+	}
+
+	if len(classpath) > 0 {
+		cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+	}
+
+	return cmd
+}
+
+func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
+	outDir, srcJarDir android.Path, bootclasspath, classpath classpath) *android.RuleBuilderCommand {
+
+	// Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka.
+	dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...)
+
+	return rule.Command().
+		BuiltTool(ctx, "dokka").
+		Flag(config.JavacVmFlags).
+		Flag(srcJarDir.String()).
+		FlagWithInputList("-classpath ", dokkaClasspath, ":").
+		FlagWithArg("-format ", "dac").
+		FlagWithArg("-dacRoot ", "/reference/kotlin").
+		FlagWithArg("-output ", outDir.String())
 }
 
 func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	deps := d.Javadoc.collectDeps(ctx)
 
+	d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
+	d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
+
 	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
 	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
 	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
 	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
 
-	var implicits android.Paths
-	implicits = append(implicits, d.Javadoc.srcJars...)
-	implicits = append(implicits, d.Javadoc.argFiles...)
+	outDir := android.PathForModuleOut(ctx, "out")
+	srcJarDir := android.PathForModuleOut(ctx, "srcjars")
+	stubsDir := android.PathForModuleOut(ctx, "stubsDir")
 
-	var implicitOutputs android.WritablePaths
-	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
-	for _, o := range d.Javadoc.properties.Out {
-		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
-	}
+	rule := android.NewRuleBuilder()
 
-	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
-	if err != nil {
-		return
-	}
+	rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String())
+	rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String())
 
-	flags.doclavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
+	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+	var cmd *android.RuleBuilderCommand
 	if Bool(d.properties.Dokka_enabled) {
-		d.transformDokka(ctx, implicits, flags.classpathArgs, d.Javadoc.args)
+		cmd = dokkaCmd(ctx, rule, outDir, srcJarDir, deps.bootClasspath, deps.classpath)
 	} else {
-		flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, jsilver, doclava)
-		flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits)
-		d.transformDoclava(ctx, implicits, implicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
-			flags.sourcepathArgs, flags.doclavaDocsFlags+flags.doclavaStubsFlags+" "+d.Javadoc.args,
-			flags.postDoclavaCmds)
+		cmd = javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList,
+			deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
 	}
 
+	d.stubsFlags(ctx, cmd, stubsDir)
+
+	cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+
+	var desc string
+	if Bool(d.properties.Dokka_enabled) {
+		desc = "dokka"
+	} else {
+		d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava})
+
+		for _, o := range d.Javadoc.properties.Out {
+			cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
+		}
+
+		d.postDoclavaCmds(ctx, rule)
+		desc = "doclava"
+	}
+
+	rule.Command().
+		BuiltTool(ctx, "soong_zip").
+		Flag("-write_if_changed").
+		Flag("-d").
+		FlagWithOutput("-o ", d.docZip).
+		FlagWithArg("-C ", outDir.String()).
+		FlagWithArg("-D ", outDir.String())
+
+	rule.Command().
+		BuiltTool(ctx, "soong_zip").
+		Flag("-write_if_changed").
+		Flag("-jar").
+		FlagWithOutput("-o ", d.stubsSrcJar).
+		FlagWithArg("-C ", stubsDir.String()).
+		FlagWithArg("-D ", stubsDir.String())
+
+	rule.Restat()
+
+	zipSyncCleanupCmd(rule, srcJarDir)
+
+	rule.Build(pctx, ctx, "javadoc", desc)
+
 	if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
 		!ctx.Config().IsPdkBuild() {
-		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
-			"check_api.current.api_file")
-		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
-			"check_api.current_removed_api_file")
+
+		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
 
 		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
-		d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
-			fmt.Sprintf(`\n******************************\n`+
-				`You have tried to change the API from what has been previously approved.\n\n`+
-				`To make these errors go away, you have two choices:\n`+
-				`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
-				`      errors above.\n\n`+
-				`   2. You can update current.txt by executing the following command:\n`+
-				`         make %s-update-current-api\n\n`+
-				`      To submit the revised current.txt to the main Android repository,\n`+
-				`      you will need approval.\n`+
-				`******************************\n`, ctx.ModuleName()), String(d.properties.Check_api.Current.Args),
-			d.checkCurrentApiTimestamp)
+
+		rule := android.NewRuleBuilder()
+
+		rule.Command().Text("( true")
+
+		rule.Command().
+			BuiltTool(ctx, "apicheck").
+			Flag("-JXmx1024m").
+			FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
+			OptionalFlag(d.properties.Check_api.Current.Args).
+			Input(apiFile).
+			Input(d.apiFile).
+			Input(removedApiFile).
+			Input(d.removedApiFile)
+
+		msg := fmt.Sprintf(`\n******************************\n`+
+			`You have tried to change the API from what has been previously approved.\n\n`+
+			`To make these errors go away, you have two choices:\n`+
+			`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
+			`      errors above.\n\n`+
+			`   2. You can update current.txt by executing the following command:\n`+
+			`         make %s-update-current-api\n\n`+
+			`      To submit the revised current.txt to the main Android repository,\n`+
+			`      you will need approval.\n`+
+			`******************************\n`, ctx.ModuleName())
+
+		rule.Command().
+			Text("touch").Output(d.checkCurrentApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API")
 
 		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
-		transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile,
-			d.updateCurrentApiTimestamp)
+
+		// update API rule
+		rule = android.NewRuleBuilder()
+
+		rule.Command().Text("( true")
+
+		rule.Command().
+			Text("cp").Flag("-f").
+			Input(d.apiFile).Flag(apiFile.String())
+
+		rule.Command().
+			Text("cp").Flag("-f").
+			Input(d.removedApiFile).Flag(removedApiFile.String())
+
+		msg = "failed to update public API"
+
+		rule.Command().
+			Text("touch").Output(d.updateCurrentApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API")
 	}
 
 	if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
 		!ctx.Config().IsPdkBuild() {
-		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
-			"check_api.last_released.api_file")
-		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
-			"check_api.last_released.removed_api_file")
+
+		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
+		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
 
 		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
-		d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
-			`\n******************************\n`+
-				`You have tried to change the API from what has been previously released in\n`+
-				`an SDK.  Please fix the errors listed above.\n`+
-				`******************************\n`, String(d.properties.Check_api.Last_released.Args),
-			d.checkLastReleasedApiTimestamp)
+
+		rule := android.NewRuleBuilder()
+
+		rule.Command().
+			Text("(").
+			BuiltTool(ctx, "apicheck").
+			Flag("-JXmx1024m").
+			FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
+			OptionalFlag(d.properties.Check_api.Last_released.Args).
+			Input(apiFile).
+			Input(d.apiFile).
+			Input(removedApiFile).
+			Input(d.removedApiFile)
+
+		msg := `\n******************************\n` +
+			`You have tried to change the API from what has been previously released in\n` +
+			`an SDK.  Please fix the errors listed above.\n` +
+			`******************************\n`
+
+		rule.Command().
+			Text("touch").Output(d.checkLastReleasedApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API")
 	}
 }
 
@@ -1258,6 +1173,9 @@
 	jdiffStubsSrcJar android.WritablePath
 }
 
+// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
+// documented, filtering out hidden classes and methods.  The resulting .java files are intended to be passed to
+// a droiddoc module to generate documentation.
 func DroidstubsFactory() android.Module {
 	module := &Droidstubs{}
 
@@ -1268,6 +1186,10 @@
 	return module
 }
 
+// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
+// to be documented, filtering out hidden classes and methods.  The resulting .java files are intended to be
+// passed to a droiddoc_host module to generate documentation.  Use a droidstubs_host instead of a droidstubs
+// module when symbols needed by the source files are provided by java_library_host modules.
 func DroidstubsHostFactory() android.Module {
 	module := &Droidstubs{}
 
@@ -1308,34 +1230,12 @@
 	}
 }
 
-func (d *Droidstubs) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
-	deps deps) (droiddocBuilderFlags, error) {
-	var flags droiddocBuilderFlags
-
-	*implicits = append(*implicits, deps.bootClasspath...)
-	*implicits = append(*implicits, deps.classpath...)
-
-	// continue to use -bootclasspath even if Metalava under -source 1.9 is enabled
-	// since it doesn't support system modules yet.
-	if len(deps.bootClasspath.Strings()) > 0 {
-		// For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
-		flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
-	}
-	flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
-
-	flags.sourcepathArgs = "-sourcepath \"" + strings.Join(d.Javadoc.sourcepaths.Strings(), ":") + "\""
-	return flags, nil
-}
-
-func (d *Droidstubs) collectStubsFlags(ctx android.ModuleContext,
-	implicitOutputs *android.WritablePaths) string {
-	var metalavaFlags string
+func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
 	if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Api_filename) != "" {
 		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
-		metalavaFlags = metalavaFlags + " --api " + d.apiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.apiFile)
+		cmd.FlagWithOutput("--api ", d.apiFile)
 		d.apiFilePath = d.apiFile
 	}
 
@@ -1343,159 +1243,144 @@
 		apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Removed_api_filename) != "" {
 		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
-		metalavaFlags = metalavaFlags + " --removed-api " + d.removedApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.removedApiFile)
+		cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
 	}
 
 	if String(d.properties.Private_api_filename) != "" {
 		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
-		metalavaFlags = metalavaFlags + " --private-api " + d.privateApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.privateApiFile)
+		cmd.FlagWithOutput("--private-api ", d.privateApiFile)
 	}
 
 	if String(d.properties.Dex_api_filename) != "" {
 		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
-		metalavaFlags += " --dex-api " + d.dexApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.dexApiFile)
+		cmd.FlagWithOutput("--dex-api ", d.dexApiFile)
 	}
 
 	if String(d.properties.Private_dex_api_filename) != "" {
 		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
-		metalavaFlags = metalavaFlags + " --private-dex-api " + d.privateDexApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
+		cmd.FlagWithOutput("--private-dex-api ", d.privateDexApiFile)
 	}
 
 	if String(d.properties.Removed_dex_api_filename) != "" {
 		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
-		metalavaFlags = metalavaFlags + " --removed-dex-api " + d.removedDexApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
+		cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile)
 	}
 
 	if String(d.properties.Exact_api_filename) != "" {
 		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
-		metalavaFlags = metalavaFlags + " --exact-api " + d.exactApiFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.exactApiFile)
+		cmd.FlagWithOutput("--exact-api ", d.exactApiFile)
 	}
 
 	if String(d.properties.Dex_mapping_filename) != "" {
 		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
-		metalavaFlags = metalavaFlags + " --dex-api-mapping " + d.apiMappingFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
+		cmd.FlagWithOutput("--dex-api-mapping ", d.apiMappingFile)
 	}
 
 	if String(d.properties.Proguard_filename) != "" {
 		d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
-		metalavaFlags += " --proguard " + d.proguardFile.String()
-		*implicitOutputs = append(*implicitOutputs, d.proguardFile)
+		cmd.FlagWithOutput("--proguard ", d.proguardFile)
 	}
 
 	if Bool(d.properties.Write_sdk_values) {
-		metalavaFlags = metalavaFlags + " --sdk-values " + android.PathForModuleOut(ctx, "out").String()
+		cmd.FlagWithArg("--sdk-values ", android.PathForModuleOut(ctx, "out").String())
 	}
 
 	if Bool(d.properties.Create_doc_stubs) {
-		metalavaFlags += " --doc-stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
+		cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
 	} else {
-		metalavaFlags += " --stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
+		cmd.FlagWithArg("--stubs ", stubsDir.String())
 	}
-	return metalavaFlags
 }
 
-func (d *Droidstubs) collectAnnotationsFlags(ctx android.ModuleContext,
-	implicits *android.Paths, implicitOutputs *android.WritablePaths) (string, string) {
-	var flags, mergeAnnoDirFlags string
+func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 	if Bool(d.properties.Annotations_enabled) {
-		flags += " --include-annotations"
+		cmd.Flag("--include-annotations")
+
 		validatingNullability :=
 			strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") ||
 				String(d.properties.Validate_nullability_from_list) != ""
 		migratingNullability := String(d.properties.Previous_api) != ""
+
 		if !(migratingNullability || validatingNullability) {
 			ctx.PropertyErrorf("previous_api",
 				"has to be non-empty if annotations was enabled (unless validating nullability)")
 		}
+
 		if migratingNullability {
 			previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
-			*implicits = append(*implicits, previousApi)
-			flags += " --migrate-nullness " + previousApi.String()
+			cmd.FlagWithInput("--migrate-nullness ", previousApi)
 		}
+
 		if s := String(d.properties.Validate_nullability_from_list); s != "" {
-			flags += " --validate-nullability-from-list " + android.PathForModuleSrc(ctx, s).String()
+			cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
 		}
+
 		if validatingNullability {
 			d.nullabilityWarningsFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_nullability_warnings.txt")
-			*implicitOutputs = append(*implicitOutputs, d.nullabilityWarningsFile)
-			flags += " --nullability-warnings-txt " + d.nullabilityWarningsFile.String()
+			cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
 		}
 
 		d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip")
-		*implicitOutputs = append(*implicitOutputs, d.annotationsZip)
-
-		flags += " --extract-annotations " + d.annotationsZip.String()
+		cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
 
 		if len(d.properties.Merge_annotations_dirs) == 0 {
 			ctx.PropertyErrorf("merge_annotations_dirs",
 				"has to be non-empty if annotations was enabled!")
 		}
-		ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
-			if t, ok := m.(*ExportedDroiddocDir); ok {
-				*implicits = append(*implicits, t.deps...)
-				mergeAnnoDirFlags += " --merge-qualifier-annotations " + t.dir.String()
-			} else {
-				ctx.PropertyErrorf("merge_annotations_dirs",
-					"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
-			}
-		})
-		flags += mergeAnnoDirFlags
-		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
-		flags += " --hide HiddenTypedefConstant --hide SuperfluousPrefix --hide AnnotationExtraction"
-	}
 
-	return flags, mergeAnnoDirFlags
+		d.mergeAnnoDirFlags(ctx, cmd)
+
+		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
+		cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
+			FlagWithArg("--hide ", "SuperfluousPrefix").
+			FlagWithArg("--hide ", "AnnotationExtraction")
+	}
 }
 
-func (d *Droidstubs) collectInclusionAnnotationsFlags(ctx android.ModuleContext,
-	implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
-	var flags string
+func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
+	ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
+		if t, ok := m.(*ExportedDroiddocDir); ok {
+			cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
+		} else {
+			ctx.PropertyErrorf("merge_annotations_dirs",
+				"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
+		}
+	})
+}
+
+func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 	ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
 		if t, ok := m.(*ExportedDroiddocDir); ok {
-			*implicits = append(*implicits, t.deps...)
-			flags += " --merge-inclusion-annotations " + t.dir.String()
+			cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
 		} else {
 			ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
 				"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
 		}
 	})
-
-	return flags
 }
 
-func (d *Droidstubs) collectAPILevelsAnnotationsFlags(ctx android.ModuleContext,
-	implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
-	var flags string
+func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 	if Bool(d.properties.Api_levels_annotations_enabled) {
 		d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml")
-		*implicitOutputs = append(*implicitOutputs, d.apiVersionsXml)
 
 		if len(d.properties.Api_levels_annotations_dirs) == 0 {
 			ctx.PropertyErrorf("api_levels_annotations_dirs",
 				"has to be non-empty if api levels annotations was enabled!")
 		}
 
-		flags = " --generate-api-levels " + d.apiVersionsXml.String() + " --apply-api-levels " +
-			d.apiVersionsXml.String() + " --current-version " + ctx.Config().PlatformSdkVersion() +
-			" --current-codename " + ctx.Config().PlatformSdkCodename() + " "
+		cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
+		cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml)
+		cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion())
+		cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
 
 		ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
 			if t, ok := m.(*ExportedDroiddocDir); ok {
-				var androidJars android.Paths
 				for _, dep := range t.deps {
 					if strings.HasSuffix(dep.String(), "android.jar") {
-						androidJars = append(androidJars, dep)
+						cmd.Implicit(dep)
 					}
 				}
-				*implicits = append(*implicits, androidJars...)
-				flags += " --android-jar-pattern " + t.dir.String() + "/%/public/android.jar "
+				cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar")
 			} else {
 				ctx.PropertyErrorf("api_levels_annotations_dirs",
 					"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
@@ -1503,112 +1388,57 @@
 		})
 
 	}
-
-	return flags
 }
 
-func (d *Droidstubs) collectApiToXmlFlags(ctx android.ModuleContext, implicits *android.Paths,
-	implicitOutputs *android.WritablePaths) string {
-	var flags string
+func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 	if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
 		if d.apiFile.String() == "" {
 			ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
 		}
 
 		d.apiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.xml")
-		*implicitOutputs = append(*implicitOutputs, d.apiXmlFile)
-
-		flags = " --api-xml " + d.apiXmlFile.String()
+		cmd.FlagWithOutput("--api-xml ", d.apiXmlFile)
 
 		if String(d.properties.Check_api.Last_released.Api_file) == "" {
 			ctx.PropertyErrorf("check_api.last_released.api_file",
 				"has to be non-empty if jdiff was enabled!")
 		}
-		lastReleasedApi := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
-			"check_api.last_released.api_file")
-		*implicits = append(*implicits, lastReleasedApi)
 
+		lastReleasedApi := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
 		d.lastReleasedApiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_last_released_api.xml")
-		*implicitOutputs = append(*implicitOutputs, d.lastReleasedApiXmlFile)
+		cmd.FlagWithInput("--convert-to-jdiff ", lastReleasedApi).Output(d.lastReleasedApiXmlFile)
+	}
+}
 
-		flags += " --convert-to-jdiff " + lastReleasedApi.String() + " " +
-			d.lastReleasedApiXmlFile.String()
+func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion string, srcs android.Paths,
+	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+	cmd := rule.Command().BuiltTool(ctx, "metalava").
+		Flag(config.JavacVmFlags).
+		FlagWithArg("-encoding ", "UTF-8").
+		FlagWithArg("-source ", javaVersion).
+		FlagWithRspFileInputList("@", srcs).
+		FlagWithInput("@", srcJarList)
+
+	if len(bootclasspath) > 0 {
+		cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
 	}
 
-	return flags
-}
+	if len(classpath) > 0 {
+		cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+	}
 
-func (d *Droidstubs) transformMetalava(ctx android.ModuleContext, implicits android.Paths,
-	implicitOutputs android.WritablePaths, javaVersion,
-	bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
+	if len(sourcepaths) > 0 {
+		cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":")
+	} else {
+		cmd.FlagWithArg("-sourcepath ", `""`)
+	}
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:            metalava,
-		Description:     "Metalava",
-		Output:          d.Javadoc.stubsSrcJar,
-		Inputs:          d.Javadoc.srcFiles,
-		Implicits:       implicits,
-		ImplicitOutputs: implicitOutputs,
-		Args: map[string]string{
-			"outDir":            android.PathForModuleOut(ctx, "out").String(),
-			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
-			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
-			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
-			"javaVersion":       javaVersion,
-			"bootclasspathArgs": bootclasspathArgs,
-			"classpathArgs":     classpathArgs,
-			"sourcepathArgs":    sourcepathArgs,
-			"opts":              opts,
-		},
-	})
-}
+	cmd.Flag("--no-banner").
+		Flag("--color").
+		Flag("--quiet").
+		Flag("--format=v2")
 
-func (d *Droidstubs) transformCheckApi(ctx android.ModuleContext,
-	apiFile, removedApiFile android.Path, implicits android.Paths,
-	javaVersion, bootclasspathArgs, classpathArgs, sourcepathArgs, opts, subdir, msg string,
-	output android.WritablePath) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        metalavaApiCheck,
-		Description: "Metalava Check API",
-		Output:      output,
-		Inputs:      d.Javadoc.srcFiles,
-		Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
-			implicits...),
-		Args: map[string]string{
-			"srcJarDir":         android.PathForModuleOut(ctx, subdir, "srcjars").String(),
-			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
-			"javaVersion":       javaVersion,
-			"bootclasspathArgs": bootclasspathArgs,
-			"classpathArgs":     classpathArgs,
-			"sourcepathArgs":    sourcepathArgs,
-			"opts":              opts,
-			"msg":               msg,
-		},
-	})
-}
-
-func (d *Droidstubs) transformJdiff(ctx android.ModuleContext, implicits android.Paths,
-	implicitOutputs android.WritablePaths,
-	bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:            javadoc,
-		Description:     "Jdiff",
-		Output:          d.jdiffStubsSrcJar,
-		Inputs:          d.Javadoc.srcFiles,
-		Implicits:       implicits,
-		ImplicitOutputs: implicitOutputs,
-		Args: map[string]string{
-			"outDir":            android.PathForModuleOut(ctx, "jdiff-out").String(),
-			"srcJarDir":         android.PathForModuleOut(ctx, "jdiff-srcjars").String(),
-			"stubsDir":          android.PathForModuleOut(ctx, "jdiff-stubsDir").String(),
-			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
-			"opts":              opts,
-			"bootclasspathArgs": bootclasspathArgs,
-			"classpathArgs":     classpathArgs,
-			"sourcepathArgs":    sourcepathArgs,
-			"docZip":            d.jdiffDocZip.String(),
-		},
-	})
+	return cmd
 }
 
 func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1616,29 +1446,29 @@
 
 	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
 
-	var implicits android.Paths
-	implicits = append(implicits, d.Javadoc.srcJars...)
-	implicits = append(implicits, d.Javadoc.argFiles...)
+	// Create rule for metalava
 
-	var implicitOutputs android.WritablePaths
-	for _, o := range d.Javadoc.properties.Out {
-		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
-	}
+	d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
 
-	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
-	metalavaCheckApiImplicits := implicits
-	jdiffImplicits := implicits
+	srcJarDir := android.PathForModuleOut(ctx, "srcjars")
+	stubsDir := android.PathForModuleOut(ctx, "stubsDir")
 
-	if err != nil {
-		return
-	}
+	rule := android.NewRuleBuilder()
 
-	flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
-	flags.metalavaAnnotationsFlags, flags.metalavaMergeAnnoDirFlags =
-		d.collectAnnotationsFlags(ctx, &implicits, &implicitOutputs)
-	flags.metalavaInclusionAnnotationsFlags = d.collectInclusionAnnotationsFlags(ctx, &implicits, &implicitOutputs)
-	flags.metalavaApiLevelsAnnotationsFlags = d.collectAPILevelsAnnotationsFlags(ctx, &implicits, &implicitOutputs)
-	flags.metalavaApiToXmlFlags = d.collectApiToXmlFlags(ctx, &implicits, &implicitOutputs)
+	rule.Command().Text("rm -rf").Text(stubsDir.String())
+	rule.Command().Text("mkdir -p").Text(stubsDir.String())
+
+	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+	cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+	d.stubsFlags(ctx, cmd, stubsDir)
+
+	d.annotationsFlags(ctx, cmd)
+	d.inclusionAnnotationsFlags(ctx, cmd)
+	d.apiLevelsAnnotationsFlags(ctx, cmd)
+	d.apiToXmlFlags(ctx, cmd)
 
 	if strings.Contains(d.Javadoc.args, "--generate-documentation") {
 		// Currently Metalava have the ability to invoke Javadoc in a seperate process.
@@ -1646,61 +1476,150 @@
 		// "--generate-documentation" arg. This is not needed when Metalava removes this feature.
 		d.Javadoc.args = d.Javadoc.args + " -nodocs "
 	}
-	d.transformMetalava(ctx, implicits, implicitOutputs, javaVersion,
-		flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs,
-		flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+flags.metalavaInclusionAnnotationsFlags+
-			flags.metalavaApiLevelsAnnotationsFlags+flags.metalavaApiToXmlFlags+" "+d.Javadoc.args)
+
+	cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+	for _, o := range d.Javadoc.properties.Out {
+		cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
+	}
+
+	rule.Command().
+		BuiltTool(ctx, "soong_zip").
+		Flag("-write_if_changed").
+		Flag("-jar").
+		FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
+		FlagWithArg("-C ", stubsDir.String()).
+		FlagWithArg("-D ", stubsDir.String())
+	rule.Restat()
+
+	zipSyncCleanupCmd(rule, srcJarDir)
+
+	rule.Build(pctx, ctx, "metalava", "metalava")
+
+	// Create rule for apicheck
 
 	if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
 		!ctx.Config().IsPdkBuild() {
-		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
-			"check_api.current.api_file")
-		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
-			"check_api.current_removed_api_file")
+
+		if len(d.Javadoc.properties.Out) > 0 {
+			ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+		}
+
+		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
 
 		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
-		opts := " " + d.Javadoc.args + " --check-compatibility:api:current " + apiFile.String() +
-			" --check-compatibility:removed:current " + removedApiFile.String() +
-			flags.metalavaInclusionAnnotationsFlags + flags.metalavaMergeAnnoDirFlags + " "
 
-		d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits,
-			javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "current-apicheck",
-			fmt.Sprintf(`\n******************************\n`+
-				`You have tried to change the API from what has been previously approved.\n\n`+
-				`To make these errors go away, you have two choices:\n`+
-				`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
-				`      errors above.\n\n`+
-				`   2. You can update current.txt by executing the following command:\n`+
-				`         make %s-update-current-api\n\n`+
-				`      To submit the revised current.txt to the main Android repository,\n`+
-				`      you will need approval.\n`+
-				`******************************\n`, ctx.ModuleName()),
-			d.checkCurrentApiTimestamp)
+		rule := android.NewRuleBuilder()
+
+		rule.Command().Text("( true")
+
+		srcJarDir := android.PathForModuleOut(ctx, "current-apicheck", "srcjars")
+		srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+		cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+			deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+		cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles).
+			FlagWithInput("--check-compatibility:api:current ", apiFile).
+			FlagWithInput("--check-compatibility:removed:current ", removedApiFile)
+
+		d.inclusionAnnotationsFlags(ctx, cmd)
+		d.mergeAnnoDirFlags(ctx, cmd)
+
+		zipSyncCleanupCmd(rule, srcJarDir)
+
+		msg := fmt.Sprintf(`\n******************************\n`+
+			`You have tried to change the API from what has been previously approved.\n\n`+
+			`To make these errors go away, you have two choices:\n`+
+			`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
+			`      errors above.\n\n`+
+			`   2. You can update current.txt by executing the following command:\n`+
+			`         make %s-update-current-api\n\n`+
+			`      To submit the revised current.txt to the main Android repository,\n`+
+			`      you will need approval.\n`+
+			`******************************\n`, ctx.ModuleName())
+
+		rule.Command().
+			Text("touch").Output(d.checkCurrentApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "metalava check current API")
 
 		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
-		transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile,
-			d.updateCurrentApiTimestamp)
+
+		// update API rule
+		rule = android.NewRuleBuilder()
+
+		rule.Command().Text("( true")
+
+		rule.Command().
+			Text("cp").Flag("-f").
+			Input(d.apiFile).Flag(apiFile.String())
+
+		rule.Command().
+			Text("cp").Flag("-f").
+			Input(d.removedApiFile).Flag(removedApiFile.String())
+
+		msg = "failed to update public API"
+
+		rule.Command().
+			Text("touch").Output(d.updateCurrentApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "metalavaCurrentApiUpdate", "update current API")
 	}
 
 	if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
 		!ctx.Config().IsPdkBuild() {
-		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
-			"check_api.last_released.api_file")
-		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
-			"check_api.last_released.removed_api_file")
+
+		if len(d.Javadoc.properties.Out) > 0 {
+			ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+		}
+
+		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
+		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
 
 		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
-		opts := " " + d.Javadoc.args + " --check-compatibility:api:released " + apiFile.String() +
-			flags.metalavaInclusionAnnotationsFlags + " --check-compatibility:removed:released " +
-			removedApiFile.String() + flags.metalavaMergeAnnoDirFlags + " "
 
-		d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits,
-			javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "last-apicheck",
-			`\n******************************\n`+
-				`You have tried to change the API from what has been previously released in\n`+
-				`an SDK.  Please fix the errors listed above.\n`+
-				`******************************\n`,
-			d.checkLastReleasedApiTimestamp)
+		rule := android.NewRuleBuilder()
+
+		rule.Command().Text("( true")
+
+		srcJarDir := android.PathForModuleOut(ctx, "last-apicheck", "srcjars")
+		srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+		cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+			deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+		cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles).
+			FlagWithInput("--check-compatibility:api:released ", apiFile)
+
+		d.inclusionAnnotationsFlags(ctx, cmd)
+
+		cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
+
+		d.mergeAnnoDirFlags(ctx, cmd)
+
+		zipSyncCleanupCmd(rule, srcJarDir)
+
+		msg := `\n******************************\n` +
+			`You have tried to change the API from what has been previously released in\n` +
+			`an SDK.  Please fix the errors listed above.\n` +
+			`******************************\n`
+		rule.Command().
+			Text("touch").Output(d.checkLastReleasedApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "metalavaLastApiCheck", "metalava check last API")
 	}
 
 	if String(d.properties.Check_nullability_warnings) != "" {
@@ -1708,9 +1627,11 @@
 			ctx.PropertyErrorf("check_nullability_warnings",
 				"Cannot specify check_nullability_warnings unless validating nullability")
 		}
-		checkNullabilityWarnings := ctx.ExpandSource(String(d.properties.Check_nullability_warnings),
-			"check_nullability_warnings")
+
+		checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
+
 		d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "check_nullability_warnings.timestamp")
+
 		msg := fmt.Sprintf(`\n******************************\n`+
 			`The warnings encountered during nullability annotation validation did\n`+
 			`not match the checked in file of expected warnings. The diffs are shown\n`+
@@ -1720,20 +1641,32 @@
 			`         cp %s %s\n`+
 			`       and submitting the updated file as part of your change.`,
 			d.nullabilityWarningsFile, checkNullabilityWarnings)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        nullabilityWarningsCheck,
-			Description: "Nullability Warnings Check",
-			Output:      d.checkNullabilityWarningsTimestamp,
-			Implicits:   android.Paths{checkNullabilityWarnings, d.nullabilityWarningsFile},
-			Args: map[string]string{
-				"expected": checkNullabilityWarnings.String(),
-				"actual":   d.nullabilityWarningsFile.String(),
-				"msg":      msg,
-			},
-		})
+
+		rule := android.NewRuleBuilder()
+
+		rule.Command().
+			Text("(").
+			Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
+			Text("&&").
+			Text("touch").Output(d.checkNullabilityWarningsTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check")
 	}
 
 	if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
+		if len(d.Javadoc.properties.Out) > 0 {
+			ctx.PropertyErrorf("out", "out property may not be combined with jdiff")
+		}
+
+		outDir := android.PathForModuleOut(ctx, "jdiff-out")
+		srcJarDir := android.PathForModuleOut(ctx, "jdiff-srcjars")
+		stubsDir := android.PathForModuleOut(ctx, "jdiff-stubsDir")
+
+		rule := android.NewRuleBuilder()
 
 		// Please sync with android-api-council@ before making any changes for the name of jdiffDocZip below
 		// since there's cron job downstream that fetch this .zip file periodically.
@@ -1741,21 +1674,49 @@
 		d.jdiffDocZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-docs.zip")
 		d.jdiffStubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-stubs.srcjar")
 
-		var jdiffImplicitOutputs android.WritablePaths
-		jdiffImplicitOutputs = append(jdiffImplicitOutputs, d.jdiffDocZip)
-
 		jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar")
-		jdiffImplicits = append(jdiffImplicits, android.Paths{jdiff, d.apiXmlFile, d.lastReleasedApiXmlFile}...)
 
-		opts := " -source 1.8 -J-Xmx1600m -XDignore.symbol.file " +
-			"-doclet jdiff.JDiff -docletpath " + jdiff.String() + " -quiet " +
-			"-newapi " + strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext()) +
-			" -newapidir " + filepath.Dir(d.apiXmlFile.String()) +
-			" -oldapi " + strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext()) +
-			" -oldapidir " + filepath.Dir(d.lastReleasedApiXmlFile.String())
+		rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String())
+		rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String())
 
-		d.transformJdiff(ctx, jdiffImplicits, jdiffImplicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
-			flags.sourcepathArgs, opts)
+		srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+		cmd := javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList,
+			deps.bootClasspath, deps.classpath, d.sourcepaths)
+
+		cmd.Flag("-J-Xmx1600m").
+			Flag("-XDignore.symbol.file").
+			FlagWithArg("-doclet ", "jdiff.JDiff").
+			FlagWithInput("-docletpath ", jdiff).
+			Flag("-quiet").
+			FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
+			FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
+			Implicit(d.apiXmlFile).
+			FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
+			FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
+			Implicit(d.lastReleasedApiXmlFile)
+
+		rule.Command().
+			BuiltTool(ctx, "soong_zip").
+			Flag("-write_if_changed").
+			Flag("-d").
+			FlagWithOutput("-o ", d.jdiffDocZip).
+			FlagWithArg("-C ", outDir.String()).
+			FlagWithArg("-D ", outDir.String())
+
+		rule.Command().
+			BuiltTool(ctx, "soong_zip").
+			Flag("-write_if_changed").
+			Flag("-jar").
+			FlagWithOutput("-o ", d.jdiffStubsSrcJar).
+			FlagWithArg("-C ", stubsDir.String()).
+			FlagWithArg("-D ", stubsDir.String())
+
+		rule.Restat()
+
+		zipSyncCleanupCmd(rule, srcJarDir)
+
+		rule.Build(pctx, ctx, "jdiff", "jdiff")
 	}
 }
 
@@ -1781,6 +1742,7 @@
 	dir  android.Path
 }
 
+// droiddoc_exported_dir exports a directory of html templates or nullability annotations for use by doclava.
 func ExportedDroiddocDirFactory() android.Module {
 	module := &ExportedDroiddocDir{}
 	module.AddProperties(&module.properties)
@@ -1829,3 +1791,25 @@
 
 	return module
 }
+
+func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
+	srcJarDir android.ModuleOutPath, srcJars android.Paths) android.OutputPath {
+
+	rule.Command().Text("rm -rf").Text(srcJarDir.String())
+	rule.Command().Text("mkdir -p").Text(srcJarDir.String())
+	srcJarList := srcJarDir.Join(ctx, "list")
+
+	rule.Temporary(srcJarList)
+
+	rule.Command().BuiltTool(ctx, "zipsync").
+		FlagWithArg("-d ", srcJarDir.String()).
+		FlagWithOutput("-l ", srcJarList).
+		FlagWithArg("-f ", `"*.java"`).
+		Inputs(srcJars)
+
+	return srcJarList
+}
+
+func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) {
+	rule.Command().Text("rm -rf").Text(srcJarDir.String())
+}
diff --git a/java/gen.go b/java/gen.go
index b1c028d..69965ec 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -15,6 +15,8 @@
 package java
 
 import (
+	"strings"
+
 	"github.com/google/blueprint"
 
 	"android/soong/android"
@@ -63,6 +65,10 @@
 func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path {
 	javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java")
 	depFile := javaFile.String() + ".d"
+	baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
+	if baseDir != "" {
+		aidlFlags += " -I" + baseDir
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aidl,
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index cf9f492..8379f53 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -64,7 +64,7 @@
 	stubFlagsRule(ctx)
 
 	// These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
-	if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().UnbundledBuild() {
+	if ctx.Config().FrameworksBaseDirExists(ctx) {
 		h.flags = flagsRule(ctx)
 		h.metadata = metadataRule(ctx)
 	} else {
@@ -97,7 +97,7 @@
 	// Add the android.test.base to the set of stubs only if the android.test.base module is on
 	// the boot jars list as the runtime will only enforce hiddenapi access against modules on
 	// that list.
-	if inList("android.test.base", ctx.Config().BootJars()) {
+	if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		publicStubModules = append(publicStubModules, "android.test.base.stubs")
 	}
 
@@ -152,6 +152,14 @@
 		// Collect dex jar paths for modules that had hiddenapi encode called on them.
 		if h, ok := module.(hiddenAPIIntf); ok {
 			if jar := h.bootDexJar(); jar != nil {
+				// For a java lib included in an APEX, only take the one built for
+				// the platform variant, and skip the variants for APEXes.
+				// Otherwise, the hiddenapi tool will complain about duplicated classes
+				if a, ok := module.(android.ApexModule); ok {
+					if android.InAnyApex(module.Name()) && !a.IsForPlatform() {
+						return
+					}
+				}
 				bootDexJars = append(bootDexJars, jar)
 			}
 		}
diff --git a/java/java.go b/java/java.go
index 7c84e76..fea38b5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -50,6 +50,21 @@
 	android.RegisterModuleType("dex_import", DexImportFactory)
 
 	android.RegisterSingletonType("logtags", LogtagsSingleton)
+	android.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
+}
+
+func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
+	if sc, ok := ctx.Module().(sdkContext); ok {
+		usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
+		if usePlatformAPI != (sc.sdkVersion() == "") {
+			if usePlatformAPI {
+				ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+			} else {
+				ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
+			}
+		}
+
+	}
 }
 
 // TODO:
@@ -178,8 +193,8 @@
 	// list of module-specific flags that will be used for dex compiles
 	Dxflags []string `android:"arch_variant"`
 
-	// if not blank, set to the version of the sdk to compile against.  Defaults to compiling against the current
-	// sdk if platform_apis is not set.
+	// if not blank, set to the version of the sdk to compile against.
+	// Defaults to compiling against the current platform.
 	Sdk_version *string
 
 	// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
@@ -190,7 +205,8 @@
 	// Defaults to sdk_version if not set.
 	Target_sdk_version *string
 
-	// if true, compile against the platform APIs instead of an SDK.
+	// It must be true only if sdk_version is empty.
+	// This field works in only android_app, otherwise nothing happens.
 	Platform_apis *bool
 
 	Aidl struct {
@@ -267,6 +283,7 @@
 type Module struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.ApexModuleBase
 
 	properties       CompilerProperties
 	protoProperties  android.ProtoProperties
@@ -342,6 +359,9 @@
 
 	hiddenAPI
 	dexpreopter
+
+	// list of the xref extraction files
+	kytheFiles android.Paths
 }
 
 func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -382,6 +402,10 @@
 	CompiledSrcJars() android.Paths
 }
 
+type xref interface {
+	XrefJavaFiles() android.Paths
+}
+
 func (j *Module) CompiledSrcs() android.Paths {
 	return j.compiledJavaSrcs
 }
@@ -390,6 +414,10 @@
 	return j.compiledSrcJars
 }
 
+func (j *Module) XrefJavaFiles() android.Paths {
+	return j.kytheFiles
+}
+
 var _ SrcDependency = (*Module)(nil)
 
 func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -632,8 +660,7 @@
 	aidlIncludeDirs    android.Paths
 	srcs               android.Paths
 	srcJars            android.Paths
-	systemModules      android.Path
-	systemModulesDeps  android.Paths
+	systemModules      *systemModules
 	aidlPreprocess     android.OptionalPath
 	kotlinStdlib       android.Paths
 	kotlinAnnotations  android.Paths
@@ -844,8 +871,7 @@
 				if sm.outputDir == nil || len(sm.outputDeps) == 0 {
 					panic("Missing directory for system module dependency")
 				}
-				deps.systemModules = sm.outputDir
-				deps.systemModulesDeps = sm.outputDeps
+				deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
 			}
 		}
 	})
@@ -973,10 +999,7 @@
 	}
 
 	// systemModules
-	if deps.systemModules != nil {
-		flags.systemModules = append(flags.systemModules, deps.systemModules)
-		flags.systemModulesDeps = append(flags.systemModulesDeps, deps.systemModulesDeps...)
-	}
+	flags.systemModules = deps.systemModules
 
 	// aidl flags.
 	flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
@@ -1143,6 +1166,12 @@
 			TransformJavaToClasses(ctx, classes, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps)
 			jars = append(jars, classes)
 		}
+		if ctx.Config().EmitXrefRules() {
+			extractionFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".kzip")
+			emitXrefRule(ctx, extractionFile, uniqueSrcFiles, srcJars, flags, extraJarDeps, "xref")
+			j.kytheFiles = append(j.kytheFiles, extractionFile)
+
+		}
 		if ctx.Failed() {
 			return
 		}
@@ -1322,11 +1351,9 @@
 			return
 		}
 
-		if !ctx.Config().UnbundledBuild() {
-			// Hidden API CSV generation and dex encoding
-			dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
-				j.deviceProperties.UncompressDex)
-		}
+		// Hidden API CSV generation and dex encoding
+		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
+			j.deviceProperties.UncompressDex)
 
 		// merge dex jar with resources if necessary
 		if j.resourceJar != nil {
@@ -1557,7 +1584,8 @@
 	j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
 	j.compile(ctx, nil)
 
-	if (Bool(j.properties.Installable) || ctx.Host()) && !android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
+	exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform()
+	if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			ctx.ModuleName()+".jar", j.outputFile)
 	}
@@ -1588,6 +1616,7 @@
 		&module.Module.protoProperties)
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
+	android.InitApexModule(module)
 	return module
 }
 
@@ -1610,6 +1639,7 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	InitJavaModule(module, android.HostSupported)
+	android.InitApexModule(module)
 	return module
 }
 
@@ -1865,6 +1895,7 @@
 type Import struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.ApexModuleBase
 	prebuilt android.Prebuilt
 
 	properties ImportProperties
@@ -2021,6 +2052,7 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	InitJavaModule(module, android.HostAndDeviceSupported)
+	android.InitApexModule(module)
 	return module
 }
 
@@ -2036,18 +2068,20 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	InitJavaModule(module, android.HostSupported)
+	android.InitApexModule(module)
 	return module
 }
 
 // dex_import module
 
 type DexImportProperties struct {
-	Jars []string
+	Jars []string `android:"path"`
 }
 
 type DexImport struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.ApexModuleBase
 	prebuilt android.Prebuilt
 
 	properties DexImportProperties
@@ -2070,10 +2104,6 @@
 	return j.prebuilt.Name(j.ModuleBase.Name())
 }
 
-func (j *DexImport) DepsMutator(ctx android.BottomUpMutatorContext) {
-	android.ExtractSourcesDeps(ctx, j.properties.Jars)
-}
-
 func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(j.properties.Jars) != 1 {
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
@@ -2094,14 +2124,14 @@
 
 		// use zip2zip to uncompress classes*.dex files
 		rule.Command().
-			Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+			BuiltTool(ctx, "zip2zip").
 			FlagWithInput("-i ", inputJar).
 			FlagWithOutput("-o ", temporary).
 			FlagWithArg("-0 ", "'classes*.dex'")
 
 		// use zipalign to align uncompressed classes*.dex files
 		rule.Command().
-			Tool(ctx.Config().HostToolPath(ctx, "zipalign")).
+			BuiltTool(ctx, "zipalign").
 			Flag("-f").
 			Text("4").
 			Input(temporary).
@@ -2143,6 +2173,7 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	InitJavaModule(module, android.DeviceSupported)
+	android.InitApexModule(module)
 	return module
 }
 
@@ -2152,6 +2183,7 @@
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
+	android.ApexModuleBase
 }
 
 // java_defaults provides a set of properties that can be inherited by other java or android modules.
@@ -2210,10 +2242,34 @@
 	)
 
 	android.InitDefaultsModule(module)
-
+	android.InitApexModule(module)
 	return module
 }
 
+func kytheExtractJavaFactory() android.Singleton {
+	return &kytheExtractJavaSingleton{}
+}
+
+type kytheExtractJavaSingleton struct {
+}
+
+func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var xrefTargets android.Paths
+	ctx.VisitAllModules(func(module android.Module) {
+		if javaModule, ok := module.(xref); ok {
+			xrefTargets = append(xrefTargets, javaModule.XrefJavaFiles()...)
+		}
+	})
+	// TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets
+	if len(xrefTargets) > 0 {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   blueprint.Phony,
+			Output: android.PathForPhony(ctx, "xref_java"),
+			Inputs: xrefTargets,
+		})
+	}
+}
+
 var Bool = proptools.Bool
 var BoolDefault = proptools.BoolDefault
 var String = proptools.String
diff --git a/java/java_test.go b/java/java_test.go
index 677174d..81d1f2c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -57,8 +57,7 @@
 	return TestConfig(buildDir, env)
 }
 
-func testContext(config android.Config, bp string,
-	fs map[string][]byte) *android.TestContext {
+func testContext(bp string, fs map[string][]byte) *android.TestContext {
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
@@ -193,6 +192,7 @@
 		"bar-doc/a.java":                 nil,
 		"bar-doc/b.java":                 nil,
 		"bar-doc/IFoo.aidl":              nil,
+		"bar-doc/IBar.aidl":              nil,
 		"bar-doc/known_oj_tags.txt":      nil,
 		"external/doclava/templates-sdk": nil,
 
@@ -222,13 +222,36 @@
 	android.FailIfErrored(t, errs)
 }
 
-func testJava(t *testing.T, bp string) *android.TestContext {
+func testJavaError(t *testing.T, pattern string, bp string) {
 	t.Helper()
 	config := testConfig(nil)
-	ctx := testContext(config, bp, nil)
+	ctx := testContext(bp, nil)
+
+	pathCtx := android.PathContextForTesting(config, nil)
+	setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+
+	ctx.Register()
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+	_, errs = ctx.PrepareBuildActions(config)
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
+	t.Helper()
+	config := testConfig(nil)
+	ctx := testContext(bp, nil)
 	run(t, ctx, config)
 
-	return ctx
+	return ctx, config
 }
 
 func moduleToPath(name string) string {
@@ -243,7 +266,7 @@
 }
 
 func TestSimple(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -287,7 +310,7 @@
 }
 
 func TestSdkVersion(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -313,7 +336,7 @@
 }
 
 func TestArchSpecific(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -332,7 +355,7 @@
 }
 
 func TestBinary(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library_host {
 			name: "foo",
 			srcs: ["a.java"],
@@ -361,7 +384,7 @@
 }
 
 func TestPrebuilts(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -412,7 +435,7 @@
 }
 
 func TestDefaults(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_defaults {
 			name: "defaults",
 			srcs: ["a.java"],
@@ -558,7 +581,7 @@
 
 	for _, test := range table {
 		t.Run(test.name, func(t *testing.T) {
-			ctx := testJava(t, `
+			ctx, _ := testJava(t, `
 				java_library {
 					name: "foo",
 					srcs: [
@@ -587,7 +610,7 @@
 }
 
 func TestIncludeSrcs(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: [
@@ -650,7 +673,7 @@
 }
 
 func TestGeneratedSources(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: [
@@ -683,7 +706,7 @@
 }
 
 func TestTurbine(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -732,7 +755,7 @@
 }
 
 func TestSharding(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "bar",
 			srcs: ["a.java","b.java","c.java"],
@@ -750,16 +773,22 @@
 }
 
 func TestDroiddoc(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		droiddoc_template {
 		    name: "droiddoc-templates-sdk",
 		    path: ".",
 		}
+		filegroup {
+		    name: "bar-doc-aidl-srcs",
+		    srcs: ["bar-doc/IBar.aidl"],
+		    path: "bar-doc",
+		}
 		droiddoc {
 		    name: "bar-doc",
 		    srcs: [
 		        "bar-doc/*.java",
 		        "bar-doc/IFoo.aidl",
+		        ":bar-doc-aidl-srcs",
 		    ],
 		    exclude_srcs: [
 		        "bar-doc/b.java"
@@ -777,23 +806,24 @@
 		}
 		`)
 
-	stubsJar := filepath.Join(buildDir, ".intermediates", "bar-doc", "android_common", "bar-doc-stubs.srcjar")
-	barDoc := ctx.ModuleForTests("bar-doc", "android_common").Output("bar-doc-stubs.srcjar")
-	if stubsJar != barDoc.Output.String() {
-		t.Errorf("expected stubs Jar [%q], got %q", stubsJar, barDoc.Output.String())
-	}
 	inputs := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc").Inputs
 	var javaSrcs []string
 	for _, i := range inputs {
 		javaSrcs = append(javaSrcs, i.Base())
 	}
-	if len(javaSrcs) != 2 || javaSrcs[0] != "a.java" || javaSrcs[1] != "IFoo.java" {
-		t.Errorf("inputs of bar-doc must be []string{\"a.java\", \"IFoo.java\", but was %#v.", javaSrcs)
+	if len(javaSrcs) != 3 || javaSrcs[0] != "a.java" || javaSrcs[1] != "IFoo.java" || javaSrcs[2] != "IBar.java" {
+		t.Errorf("inputs of bar-doc must be []string{\"a.java\", \"IFoo.java\", \"IBar.java\", but was %#v.", javaSrcs)
+	}
+
+	aidlRule := ctx.ModuleForTests("bar-doc", "android_common").Output(inputs[2].String())
+	aidlFlags := aidlRule.Args["aidlFlags"]
+	if !strings.Contains(aidlFlags, "-Ibar-doc") {
+		t.Errorf("aidl flags for IBar.aidl should contain \"-Ibar-doc\", but was %q", aidlFlags)
 	}
 }
 
 func TestJarGenrules(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -847,7 +877,7 @@
 }
 
 func TestExcludeFileGroupInSrcs(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java", ":foo-srcs"],
@@ -874,7 +904,7 @@
 
 func TestJavaLibrary(t *testing.T) {
 	config := testConfig(nil)
-	ctx := testContext(config, "", map[string][]byte{
+	ctx := testContext("", map[string][]byte{
 		"libcore/Android.bp": []byte(`
 				java_library {
 						name: "core",
@@ -886,7 +916,7 @@
 }
 
 func TestJavaSdkLibrary(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		droiddoc_template {
 			name: "droiddoc-templates-sdk",
 			path: ".",
@@ -1057,7 +1087,7 @@
 
 	t.Run("Java language level 8", func(t *testing.T) {
 		// Test default javac -source 1.8 -target 1.8
-		ctx := testJava(t, bp)
+		ctx, _ := testJava(t, bp)
 
 		checkPatchModuleFlag(t, ctx, "foo", "")
 		checkPatchModuleFlag(t, ctx, "bar", "")
@@ -1067,7 +1097,7 @@
 	t.Run("Java language level 9", func(t *testing.T) {
 		// Test again with javac -source 9 -target 9
 		config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
-		ctx := testContext(config, bp, nil)
+		ctx := testContext(bp, nil)
 		run(t, ctx, config)
 
 		checkPatchModuleFlag(t, ctx, "foo", "")
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index e0eb0c0..5c6d45f 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -22,7 +22,7 @@
 )
 
 func TestKotlin(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java", "b.kt"],
@@ -84,7 +84,7 @@
 }
 
 func TestKapt(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java", "b.kt"],
diff --git a/java/plugin_test.go b/java/plugin_test.go
index d1aef2c..c7913d3 100644
--- a/java/plugin_test.go
+++ b/java/plugin_test.go
@@ -20,7 +20,7 @@
 )
 
 func TestNoPlugin(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -44,7 +44,7 @@
 }
 
 func TestPlugin(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -83,7 +83,7 @@
 }
 
 func TestPluginGeneratesApi(t *testing.T) {
-	ctx := testJava(t, `
+	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
diff --git a/java/proto.go b/java/proto.go
index 37de1d2..0ec6499 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -34,7 +34,7 @@
 	// Proto generated java files have an unknown package name in the path, so package the entire output directory
 	// into a srcjar.
 	rule.Command().
-		Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+		BuiltTool(ctx, "soong_zip").
 		Flag("-jar").
 		FlagWithOutput("-o ", srcJarFile).
 		FlagWithArg("-C ", outDir.String()).
diff --git a/java/sdk.go b/java/sdk.go
index 7b79a49..d1e2ae4 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -296,7 +296,7 @@
 			rule.Command().
 				Text("rm -f").Output(aidl)
 			rule.Command().
-				Tool(ctx.Config().HostToolPath(ctx, "sdkparcelables")).
+				BuiltTool(ctx, "sdkparcelables").
 				Input(jar).
 				Output(aidl)
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index b4a3f29..d38088d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -63,12 +63,6 @@
 	javaSdkLibrariesLock sync.Mutex
 )
 
-// java_sdk_library is to make a Java library that implements optional platform APIs to apps.
-// It is actually a wrapper of several modules: 1) stubs library that clients are linked against
-// to, 2) droiddoc module that internally generates API stubs source files, 3) the real runtime
-// shared library that implements the APIs, and 4) XML file for adding the runtime lib to the
-// classpath at runtime if requested via <uses-library>.
-//
 // TODO: these are big features that are currently missing
 // 1) disallowing linking to the runtime shared lib
 // 2) HTML generation
@@ -155,16 +149,21 @@
 var _ SdkLibraryDependency = (*SdkLibrary)(nil)
 
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+	useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks()
 	// Add dependencies to the stubs library
-	ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
+	if useBuiltStubs {
+		ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
+	}
 	ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
 
 	sdkDep := decodeSdkDep(ctx, sdkContext(&module.Library))
 	if sdkDep.hasStandardLibs() {
-		ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem))
+		if useBuiltStubs {
+			ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem))
+			ctx.AddVariationDependencies(nil, testApiStubsTag, module.stubsName(apiScopeTest))
+		}
 		ctx.AddVariationDependencies(nil, systemApiFileTag, module.docsName(apiScopeSystem))
 		ctx.AddVariationDependencies(nil, testApiFileTag, module.docsName(apiScopeTest))
-		ctx.AddVariationDependencies(nil, testApiStubsTag, module.stubsName(apiScopeTest))
 	}
 
 	module.Library.deps(ctx)
@@ -746,6 +745,11 @@
 	module.Library.Module.deviceProperties.IsSDKLibrary = true
 }
 
+// java_sdk_library is a special Java library that provides optional platform APIs to apps.
+// In practice, it can be viewed as a combination of several modules: 1) stubs library that clients
+// are linked against to, 2) droiddoc module that internally generates API stubs source files,
+// 3) the real runtime shared library that implements the APIs, and 4) XML file for adding
+// the runtime lib to the classpath at runtime if requested via <uses-library>.
 func SdkLibraryFactory() android.Module {
 	module := &SdkLibrary{}
 	module.InitSdkLibraryProperties()
@@ -787,6 +791,7 @@
 
 var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
 
+// java_sdk_library_import imports a prebuilt java_sdk_library.
 func sdkLibraryImportFactory() android.Module {
 	module := &sdkLibraryImport{}
 
diff --git a/java/sdk_test.go b/java/sdk_test.go
index f82a4fb..6be17eb 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -282,7 +282,7 @@
 				if testcase.pdk {
 					config.TestProductVariables.Pdk = proptools.BoolPtr(true)
 				}
-				ctx := testContext(config, bp, nil)
+				ctx := testContext(bp, nil)
 				run(t, ctx, config)
 
 				checkClasspath(t, ctx)
@@ -309,7 +309,7 @@
 				if testcase.pdk {
 					config.TestProductVariables.Pdk = proptools.BoolPtr(true)
 				}
-				ctx := testContext(config, bp, nil)
+				ctx := testContext(bp, nil)
 				run(t, ctx, config)
 
 				javac := ctx.ModuleForTests("foo", variant).Rule("javac")
@@ -335,7 +335,7 @@
 				if testcase.pdk {
 					config.TestProductVariables.Pdk = proptools.BoolPtr(true)
 				}
-				ctx := testContext(config, bp, nil)
+				ctx := testContext(bp, nil)
 				run(t, ctx, config)
 
 				checkClasspath(t, ctx)
diff --git a/java/support_libraries.go b/java/support_libraries.go
index 5a72f41..af7c3c2 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -52,8 +52,6 @@
 			supportAars = append(supportAars, name)
 		case *Library, *Import:
 			supportJars = append(supportJars, name)
-		default:
-			ctx.ModuleErrorf(module, "unknown module type %t", module)
 		}
 	})
 
diff --git a/python/proto.go b/python/proto.go
index 85ed1a5..b71e047 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -34,7 +34,7 @@
 	// Proto generated python files have an unknown package name in the path, so package the entire output directory
 	// into a srcszip.
 	zipCmd := rule.Command().
-		Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+		BuiltTool(ctx, "soong_zip").
 		FlagWithOutput("-o ", srcsZipFile)
 	if pkgPath != "" {
 		zipCmd.FlagWithArg("-P ", pkgPath)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 31f5922..8c59cbc 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -69,3 +69,19 @@
     },
     test_suites: ["general-tests"],
 }
+
+python_binary_host {
+    name: "jsonmodify",
+    main: "jsonmodify.py",
+    srcs: [
+        "jsonmodify.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    }
+}
diff --git a/scripts/gen_sorted_bss_symbols.sh b/scripts/gen_sorted_bss_symbols.sh
new file mode 100755
index 0000000..244ed0d
--- /dev/null
+++ b/scripts/gen_sorted_bss_symbols.sh
@@ -0,0 +1,28 @@
+#!/bin/bash -e
+
+# Copyright 2019 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Script to generate a symbol ordering file that sorts bss section symbols by
+# their sizes.
+# Inputs:
+#  Environment:
+#   CROSS_COMPILE: prefix added to nm tools
+#  Arguments:
+#   $1: Input ELF file
+#   $2: Output symbol ordering file
+
+set -o pipefail
+
+${CROSS_COMPILE}nm --size-sort $1 | awk '{if ($2 == "b" || $2 == "B") print $3}' > $2
diff --git a/scripts/jar-wrapper.sh b/scripts/jar-wrapper.sh
index 71c1d90..b468041 100644
--- a/scripts/jar-wrapper.sh
+++ b/scripts/jar-wrapper.sh
@@ -48,11 +48,11 @@
     exit 1
 fi
 
-javaOpts=""
+declare -a javaOpts=()
 while expr "x$1" : 'x-J' >/dev/null; do
-    opt=`expr "$1" : '-J\(.*\)'`
-    javaOpts="${javaOpts} -${opt}"
+    opt=`expr "$1" : '-J-\{0,1\}\(.*\)'`
+    javaOpts+=("-${opt}")
     shift
 done
 
-exec java ${javaOpts} -jar ${jardir}/${jarfile} "$@"
+exec java "${javaOpts[@]}" -jar ${jardir}/${jarfile} "$@"
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
new file mode 100755
index 0000000..4b2c3c2
--- /dev/null
+++ b/scripts/jsonmodify.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import argparse
+import collections
+import json
+import sys
+
+def follow_path(obj, path):
+  cur = obj
+  last_key = None
+  for key in path.split('.'):
+    if last_key:
+      if last_key not in cur:
+        return None,None
+      cur = cur[last_key]
+    last_key = key
+  if last_key not in cur:
+    return None,None
+  return cur, last_key
+
+
+def ensure_path(obj, path):
+  cur = obj
+  last_key = None
+  for key in path.split('.'):
+    if last_key:
+      if last_key not in cur:
+        cur[last_key] = dict()
+      cur = cur[last_key]
+    last_key = key
+  return cur, last_key
+
+
+class SetValue(str):
+  def apply(self, obj, val):
+    cur, key = ensure_path(obj, self)
+    cur[key] = val
+
+
+class Replace(str):
+  def apply(self, obj, val):
+    cur, key = follow_path(obj, self)
+    if cur:
+      cur[key] = val
+
+
+class Remove(str):
+  def apply(self, obj):
+    cur, key = follow_path(obj, self)
+    if cur:
+      del cur[key]
+
+
+class AppendList(str):
+  def apply(self, obj, *args):
+    cur, key = ensure_path(obj, self)
+    if key not in cur:
+      cur[key] = list()
+    if not isinstance(cur[key], list):
+      raise ValueError(self + " should be a array.")
+    cur[key].extend(args)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-o', '--out',
+                      help='write result to a file. If omitted, print to stdout',
+                      metavar='output',
+                      action='store')
+  parser.add_argument('input', nargs='?', help='JSON file')
+  parser.add_argument("-v", "--value", type=SetValue,
+                      help='set value of the key specified by path. If path doesn\'t exist, creates new one.',
+                      metavar=('path', 'value'),
+                      nargs=2, dest='patch', default=[], action='append')
+  parser.add_argument("-s", "--replace", type=Replace,
+                      help='replace value of the key specified by path. If path doesn\'t exist, no op.',
+                      metavar=('path', 'value'),
+                      nargs=2, dest='patch', action='append')
+  parser.add_argument("-r", "--remove", type=Remove,
+                      help='remove the key specified by path. If path doesn\'t exist, no op.',
+                      metavar='path',
+                      nargs=1, dest='patch', action='append')
+  parser.add_argument("-a", "--append_list", type=AppendList,
+                      help='append values to the list specified by path. If path doesn\'t exist, creates new list for it.',
+                      metavar=('path', 'value'),
+                      nargs='+', dest='patch', default=[], action='append')
+  args = parser.parse_args()
+
+  if args.input:
+    with open(args.input) as f:
+      obj = json.load(f, object_pairs_hook=collections.OrderedDict)
+  else:
+    obj = json.load(sys.stdin, object_pairs_hook=collections.OrderedDict)
+
+  for p in args.patch:
+    p[0].apply(obj, *p[1:])
+
+  if args.out:
+    with open(args.out, "w") as f:
+      json.dump(obj, f, indent=2)
+  else:
+    print(json.dumps(obj, indent=2))
+
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/strip.sh b/scripts/strip.sh
index bd62619..4a1ed3f 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -59,7 +59,7 @@
     # ${CROSS_COMPILE}strip --strip-all does not strip .ARM.attributes,
     # so we tell llvm-strip to keep it too.
     if [ -z "${use_gnu_strip}" ]; then
-        "${CLANG_BIN}/llvm-strip" --strip-all -keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
+        "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
     else
         "${CROSS_COMPILE}strip" --strip-all "${infile}" -o "${outfile}.tmp"
     fi
@@ -101,7 +101,7 @@
     rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
     local fail=
     if [ -z "${use_gnu_strip}" ]; then
-        "${CLANG_BIN}/llvm-strip" --strip-all -keep-section=.ARM.attributes -remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
+        "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
     else
         "${CROSS_COMPILE}strip" --strip-all -R .comment "${infile}" -o "${outfile}.tmp" || fail=true
     fi
diff --git a/scripts/system-clang-format b/scripts/system-clang-format
index 14abd93..a7614d2 100644
--- a/scripts/system-clang-format
+++ b/scripts/system-clang-format
@@ -1,4 +1,5 @@
 BasedOnStyle: Google
+Standard: Cpp11
 AccessModifierOffset: -2
 AllowShortFunctionsOnASingleLine: Inline
 ColumnLimit: 100
diff --git a/scripts/system-clang-format-2 b/scripts/system-clang-format-2
index e28b379..a4e23f8 100644
--- a/scripts/system-clang-format-2
+++ b/scripts/system-clang-format-2
@@ -1,4 +1,5 @@
 BasedOnStyle: Google
+Standard: Cpp11
 AllowShortFunctionsOnASingleLine: Inline
 ColumnLimit: 100
 CommentPragmas: NOLINT:.*
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 1ddaf68..6f81c17 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -52,6 +52,7 @@
         "ninja.go",
         "path.go",
         "proc_sync.go",
+        "rbe.go",
         "signal.go",
         "soong.go",
         "test_build.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 59d1474..6a19314 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -161,6 +161,11 @@
 		startGoma(ctx, config)
 	}
 
+	if config.StartRBE() {
+		// Ensure RBE proxy is started
+		startRBE(ctx, config)
+	}
+
 	if what&BuildProductConfig != 0 {
 		// Run make for product config
 		runMakeProductConfig(ctx, config)
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index c47f614..8e7f96a 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -111,7 +111,7 @@
 		productOut("system_other"),
 		productOut("vendor"),
 		productOut("product"),
-		productOut("product_services"),
+		productOut("system_ext"),
 		productOut("oem"),
 		productOut("obj/FAKE"),
 		productOut("breakpad"),
diff --git a/ui/build/config.go b/ui/build/config.go
index 4e19e9e..434047b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -61,6 +61,8 @@
 
 const srcDirFileCheck = "build/soong/root.bp"
 
+var buildFiles = []string{"Android.mk", "Android.bp"}
+
 type BuildAction uint
 
 const (
@@ -251,13 +253,13 @@
 
 // NewBuildActionConfig returns a build configuration based on the build action. The arguments are
 // processed based on the build action and extracts any arguments that belongs to the build action.
-func NewBuildActionConfig(action BuildAction, dir string, buildDependencies bool, ctx Context, args ...string) Config {
-	return NewConfig(ctx, getConfigArgs(action, dir, buildDependencies, ctx, args)...)
+func NewBuildActionConfig(action BuildAction, dir string, ctx Context, args ...string) Config {
+	return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...)
 }
 
 // getConfigArgs processes the command arguments based on the build action and creates a set of new
 // arguments to be accepted by Config.
-func getConfigArgs(action BuildAction, dir string, buildDependencies bool, ctx Context, args []string) []string {
+func getConfigArgs(action BuildAction, dir string, ctx Context, args []string) []string {
 	// The next block of code verifies that the current directory is the root directory of the source
 	// tree. It then finds the relative path of dir based on the root directory of the source tree
 	// and verify that dir is inside of the source tree.
@@ -293,7 +295,6 @@
 		configArgs = removeFromList("GET-INSTALL-PATH", configArgs)
 	}
 
-	var buildFiles []string
 	var targets []string
 
 	switch action {
@@ -305,27 +306,16 @@
 		if topDir == dir {
 			break
 		}
-		// Find the build file from the directory where the build action was triggered by traversing up
-		// the source tree. If a blank build filename is returned, simply use the directory where the build
-		// action was invoked.
+
 		buildFile := findBuildFile(ctx, relDir)
 		if buildFile == "" {
-			buildFile = filepath.Join(relDir, "Android.mk")
+			ctx.Fatalf("Build file not found for %s directory", relDir)
 		}
-		buildFiles = []string{buildFile}
 		targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
 	case BUILD_MODULES_IN_DIRECTORIES:
 		newConfigArgs, dirs := splitArgs(configArgs)
 		configArgs = newConfigArgs
-		targets, buildFiles = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
-	}
-
-	// This is to support building modules without building their dependencies. Soon, this will be
-	// deprecated.
-	if !buildDependencies && len(buildFiles) > 0 {
-		if err := os.Setenv("ONE_SHOT_MAKEFILE", strings.Join(buildFiles, " ")); err != nil {
-			ctx.Fatalf("Unable to set ONE_SHOT_MAKEFILE environment variable: %v", err)
-		}
+		targets = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
 	}
 
 	// Tidy only override all other specified targets.
@@ -344,26 +334,57 @@
 	return targetNamePrefix + strings.ReplaceAll(dir, "/", "-")
 }
 
-// findBuildFile finds a build file (makefile or blueprint file) by looking at dir first. If not
-// found, go up one level and repeat again until one is found and the path of that build file
-// relative to the root directory of the source tree is returned. The returned filename of build
-// file is "Android.mk". If one was not found, a blank string is returned.
+// hasBuildFile returns true if dir contains an Android build file.
+func hasBuildFile(ctx Context, dir string) bool {
+	for _, buildFile := range buildFiles {
+		_, err := os.Stat(filepath.Join(dir, buildFile))
+		if err == nil {
+			return true
+		}
+		if !os.IsNotExist(err) {
+			ctx.Fatalf("Error retrieving the build file stats: %v", err)
+		}
+	}
+	return false
+}
+
+// findBuildFile finds a build file (makefile or blueprint file) by looking if there is a build file
+// in the current and any sub directory of dir. If a build file is not found, traverse the path
+// up by one directory and repeat again until either a build file is found or reached to the root
+// source tree. The returned filename of build file is "Android.mk". If one was not found, a blank
+// string is returned.
 func findBuildFile(ctx Context, dir string) string {
-	// If the string is empty, assume it is top directory of the source tree.
-	if dir == "" {
+	// If the string is empty or ".", assume it is top directory of the source tree.
+	if dir == "" || dir == "." {
 		return ""
 	}
 
-	for ; dir != "."; dir = filepath.Dir(dir) {
-		for _, buildFile := range []string{"Android.bp", "Android.mk"} {
-			_, err := os.Stat(filepath.Join(dir, buildFile))
-			if err == nil {
-				// Returning the filename Android.mk as it might be used for ONE_SHOT_MAKEFILE variable.
-				return filepath.Join(dir, "Android.mk")
+	found := false
+	for buildDir := dir; buildDir != "."; buildDir = filepath.Dir(buildDir) {
+		err := filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error {
+			if err != nil {
+				return err
 			}
-			if !os.IsNotExist(err) {
-				ctx.Fatalf("Error retrieving the build file stats: %v", err)
+			if found {
+				return filepath.SkipDir
 			}
+			if info.IsDir() {
+				return nil
+			}
+			for _, buildFile := range buildFiles {
+				if info.Name() == buildFile {
+					found = true
+					return filepath.SkipDir
+				}
+			}
+			return nil
+		})
+		if err != nil {
+			ctx.Fatalf("Error finding Android build file: %v", err)
+		}
+
+		if found {
+			return filepath.Join(buildDir, "Android.mk")
 		}
 	}
 
@@ -404,7 +425,7 @@
 // directory from the dirs list does not exist, a fatal error is raised. relDir is related to the
 // source root tree where the build action command was invoked. Each directory is validated if the
 // build file can be found and follows the format "dir1:target1,target2,...". Target is optional.
-func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string, buildFiles []string) {
+func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string) {
 	for _, dir := range dirs {
 		// The directory may have specified specific modules to build. ":" is the separator to separate
 		// the directory and the list of modules.
@@ -428,28 +449,25 @@
 			}
 		}
 
-		buildFile := findBuildFile(ctx, dir)
-		if buildFile == "" {
-			ctx.Fatalf("Build file not found for %s directory", dir)
-		}
-		buildFileDir := filepath.Dir(buildFile)
-
-		// If there are specified targets, find the build file in the directory. If dir does not
-		// contain the build file, bail out as it is required for one shot build. If there are no
-		// target specified, build all the modules in dir (or the closest one in the dir path).
+		// If there are specified targets to build in dir, an android build file must exist for the one
+		// shot build. For the non-targets case, find the appropriate build file and build all the
+		// modules in dir (or the closest one in the dir path).
 		if len(newTargets) > 0 {
-			if buildFileDir != dir {
+			if !hasBuildFile(ctx, dir) {
 				ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
 			}
 		} else {
-			newTargets = []string{convertToTarget(buildFileDir, targetNamePrefix)}
+			buildFile := findBuildFile(ctx, dir)
+			if buildFile == "" {
+				ctx.Fatalf("Build file not found for %s directory", dir)
+			}
+			newTargets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
 		}
 
-		buildFiles = append(buildFiles, buildFile)
 		targets = append(targets, newTargets...)
 	}
 
-	return targets, buildFiles
+	return targets
 }
 
 func (c *configImpl) parseArgs(ctx Context, args []string) {
@@ -608,7 +626,7 @@
 
 func (c *configImpl) OutDir() string {
 	if outDir, ok := c.environ.Get("OUT_DIR"); ok {
-		return filepath.Clean(outDir)
+		return outDir
 	}
 	return "out"
 }
@@ -715,6 +733,30 @@
 	return true
 }
 
+func (c *configImpl) UseRBE() bool {
+	if v, ok := c.environ.Get("USE_RBE"); ok {
+		v = strings.TrimSpace(v)
+		if v != "" && v != "false" {
+			return true
+		}
+	}
+	return false
+}
+
+func (c *configImpl) StartRBE() bool {
+	if !c.UseRBE() {
+		return false
+	}
+
+	if v, ok := c.environ.Get("NOSTART_RBE"); ok {
+		v = strings.TrimSpace(v)
+		if v != "" && v != "false" {
+			return false
+		}
+	}
+	return true
+}
+
 // RemoteParallel controls how many remote jobs (i.e., commands which contain
 // gomacc) are run in parallel.  Note the parallelism of all other jobs is
 // still limited by Parallel()
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 7a1ee170..df618c4 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -363,19 +363,15 @@
 		// Expected targets from the function.
 		expectedTargets []string
 
-		// Expected build from the build system.
-		expectedBuildFiles []string
-
 		// Expecting error from running test case.
 		errStr string
 	}{{
-		description:        "one target dir specified",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3"},
-		curDir:             "0",
-		expectedTargets:    []string{"MODULES-IN-0-1-2-3"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3"},
+		curDir:          "0",
+		expectedTargets: []string{"MODULES-IN-0-1-2-3"},
 	}, {
 		description: "one target dir specified, build file does not exist",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -391,21 +387,19 @@
 		curDir:      "0",
 		errStr:      "1/2/3:t1:t2 not in proper directory:target1,target2,... format (\":\" was specified more than once)",
 	}, {
-		description:        "one target dir specified, no targets specified but has colon",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3:"},
-		curDir:             "0",
-		expectedTargets:    []string{"MODULES-IN-0-1-2-3"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified, no targets specified but has colon",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3:"},
+		curDir:          "0",
+		expectedTargets: []string{"MODULES-IN-0-1-2-3"},
 	}, {
-		description:        "one target dir specified, two targets specified",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3:t1,t2"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified, two targets specified",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3:t1,t2"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2"},
 	}, {
 		description: "one target dir specified, no targets and has a comma",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -428,20 +422,19 @@
 		curDir:      "0",
 		errStr:      "0/1/2/3 not in proper directory:target1,target2,... format",
 	}, {
-		description:        "one target dir specified, many targets specified",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified, many targets specified",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
 	}, {
 		description: "one target dir specified, one target specified, build file does not exist",
 		dirsInTrees: []string{"0/1/2/3"},
 		buildFiles:  []string{},
 		dirs:        []string{"1/2/3:t1"},
 		curDir:      "0",
-		errStr:      "Build file not found for 0/1/2/3 directory",
+		errStr:      "Couldn't locate a build file from 0/1/2/3 directory",
 	}, {
 		description: "one target dir specified, one target specified, build file not in target dir",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -450,29 +443,26 @@
 		curDir:      "0",
 		errStr:      "Couldn't locate a build file from 0/1/2/3 directory",
 	}, {
-		description:        "one target dir specified, build file not in target dir",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/Android.mk"},
-		dirs:               []string{"1/2/3"},
-		curDir:             "0",
-		expectedTargets:    []string{"MODULES-IN-0-1-2"},
-		expectedBuildFiles: []string{"0/1/2/Android.mk"},
+		description:     "one target dir specified, build file not in target dir",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/Android.mk"},
+		dirs:            []string{"1/2/3"},
+		curDir:          "0",
+		expectedTargets: []string{"MODULES-IN-0-1-2"},
 	}, {
-		description:        "multiple targets dir specified, targets specified",
-		dirsInTrees:        []string{"0/1/2/3", "0/3/4"},
-		buildFiles:         []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
-		dirs:               []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2", "t3", "t4", "t5"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+		description:     "multiple targets dir specified, targets specified",
+		dirsInTrees:     []string{"0/1/2/3", "0/3/4"},
+		buildFiles:      []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+		dirs:            []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
 	}, {
-		description:        "multiple targets dir specified, one directory has targets specified",
-		dirsInTrees:        []string{"0/1/2/3", "0/3/4"},
-		buildFiles:         []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
-		dirs:               []string{"1/2/3:t1,t2", "3/4"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2", "MODULES-IN-0-3-4"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+		description:     "multiple targets dir specified, one directory has targets specified",
+		dirsInTrees:     []string{"0/1/2/3", "0/3/4"},
+		buildFiles:      []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+		dirs:            []string{"1/2/3:t1,t2", "3/4"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
 	}, {
 		description: "two dirs specified, only one dir exist",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -481,13 +471,12 @@
 		curDir:      "0",
 		errStr:      "couldn't find directory 0/3/4",
 	}, {
-		description:        "multiple targets dirs specified at root source tree",
-		dirsInTrees:        []string{"0/1/2/3", "0/3/4"},
-		buildFiles:         []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
-		dirs:               []string{"0/1/2/3:t1,t2", "0/3/4"},
-		curDir:             ".",
-		expectedTargets:    []string{"t1", "t2", "MODULES-IN-0-3-4"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+		description:     "multiple targets dirs specified at root source tree",
+		dirsInTrees:     []string{"0/1/2/3", "0/3/4"},
+		buildFiles:      []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+		dirs:            []string{"0/1/2/3:t1,t2", "0/3/4"},
+		curDir:          ".",
+		expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
 	}, {
 		description: "no directories specified",
 		dirsInTrees: []string{"0/1/2/3", "0/3/4"},
@@ -518,13 +507,10 @@
 			r := setTop(t, topDir)
 			defer r()
 
-			targets, buildFiles := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
+			targets := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
 			if !reflect.DeepEqual(targets, tt.expectedTargets) {
 				t.Errorf("expected %v, got %v for targets", tt.expectedTargets, targets)
 			}
-			if !reflect.DeepEqual(buildFiles, tt.expectedBuildFiles) {
-				t.Errorf("expected %v, got %v for build files", tt.expectedBuildFiles, buildFiles)
-			}
 
 			// If the execution reached here and there was an expected error code, the unit test case failed.
 			if tt.errStr != "" {
@@ -545,8 +531,11 @@
 		// Array of build files to create in dir.
 		buildFiles []string
 
+		// Directories that exist in the source tree.
+		dirsInTrees []string
+
 		// ********* Action *********
-		// Directory to create, also the base directory is where findBuildFile is invoked.
+		// The base directory is where findBuildFile is invoked.
 		dir string
 
 		// ********* Validation *********
@@ -555,38 +544,63 @@
 	}{{
 		description:       "build file exists at leaf directory",
 		buildFiles:        []string{"1/2/3/Android.bp"},
+		dirsInTrees:       []string{"1/2/3"},
 		dir:               "1/2/3",
 		expectedBuildFile: "1/2/3/Android.mk",
 	}, {
 		description:       "build file exists in all directory paths",
 		buildFiles:        []string{"1/Android.mk", "1/2/Android.mk", "1/2/3/Android.mk"},
+		dirsInTrees:       []string{"1/2/3"},
 		dir:               "1/2/3",
 		expectedBuildFile: "1/2/3/Android.mk",
 	}, {
 		description:       "build file does not exist in all directory paths",
 		buildFiles:        []string{},
+		dirsInTrees:       []string{"1/2/3"},
 		dir:               "1/2/3",
 		expectedBuildFile: "",
 	}, {
 		description:       "build file exists only at top directory",
 		buildFiles:        []string{"Android.bp"},
+		dirsInTrees:       []string{"1/2/3"},
 		dir:               "1/2/3",
 		expectedBuildFile: "",
 	}, {
 		description:       "build file exist in a subdirectory",
 		buildFiles:        []string{"1/2/Android.bp"},
+		dirsInTrees:       []string{"1/2/3"},
 		dir:               "1/2/3",
 		expectedBuildFile: "1/2/Android.mk",
 	}, {
 		description:       "build file exists in a subdirectory",
 		buildFiles:        []string{"1/Android.mk"},
+		dirsInTrees:       []string{"1/2/3"},
 		dir:               "1/2/3",
 		expectedBuildFile: "1/Android.mk",
 	}, {
 		description:       "top directory",
 		buildFiles:        []string{"Android.bp"},
+		dirsInTrees:       []string{},
 		dir:               ".",
 		expectedBuildFile: "",
+	}, {
+		description:       "build file exists in subdirectory",
+		buildFiles:        []string{"1/2/3/Android.bp", "1/2/4/Android.bp"},
+		dirsInTrees:       []string{"1/2/3", "1/2/4"},
+		dir:               "1/2",
+		expectedBuildFile: "1/2/Android.mk",
+	}, {
+		description:       "build file exists in parent subdirectory",
+		buildFiles:        []string{"1/5/Android.bp"},
+		dirsInTrees:       []string{"1/2/3", "1/2/4", "1/5"},
+		dir:               "1/2",
+		expectedBuildFile: "1/Android.mk",
+	}, {
+		description:       "build file exists in deep parent's subdirectory.",
+		buildFiles:        []string{"1/5/6/Android.bp"},
+		dirsInTrees:       []string{"1/2/3", "1/2/4", "1/5/6", "1/5/7"},
+		dir:               "1/2",
+		expectedBuildFile: "1/Android.mk",
 	}}
 
 	for _, tt := range tests {
@@ -601,10 +615,7 @@
 			}
 			defer os.RemoveAll(topDir)
 
-			if tt.dir != "" {
-				createDirectories(t, topDir, []string{tt.dir})
-			}
-
+			createDirectories(t, topDir, tt.dirsInTrees)
 			createBuildFiles(t, topDir, tt.buildFiles)
 
 			curDir, err := os.Getwd()
@@ -707,16 +718,24 @@
 	// Expected arguments to be in Config instance.
 	expectedArgs []string
 
-	// Expected environment variables to be set.
-	expectedEnvVars []envVar
+	// Expecting error from running test case.
+	expectedErrStr string
 }
 
-func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) {
+func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction) {
 	ctx := testContext()
 
+	defer logger.Recover(func(err error) {
+		if tt.expectedErrStr == "" {
+			t.Fatalf("Got unexpected error: %v", err)
+		}
+		if tt.expectedErrStr != err.Error() {
+			t.Errorf("expected %s, got %s", tt.expectedErrStr, err.Error())
+		}
+	})
+
 	// Environment variables to set it to blank on every test case run.
 	resetEnvVars := []string{
-		"ONE_SHOT_MAKEFILE",
 		"WITH_TIDY_ONLY",
 	}
 
@@ -770,311 +789,156 @@
 		t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
 	}
 
-	args := getConfigArgs(action, tt.curDir, buildDependencies, ctx, tt.args)
+	args := getConfigArgs(action, tt.curDir, ctx, tt.args)
 	if !reflect.DeepEqual(tt.expectedArgs, args) {
 		t.Fatalf("expected %v, got %v for config arguments", tt.expectedArgs, args)
 	}
 
-	for _, env := range tt.expectedEnvVars {
-		if val := os.Getenv(env.name); val != env.value {
-			t.Errorf("expecting %s, got %s for environment variable %s", env.value, val, env.name)
-		}
+	// If the execution reached here and there was an expected error code, the unit test case failed.
+	if tt.expectedErrStr != "" {
+		t.Errorf("expecting error %s", tt.expectedErrStr)
 	}
 }
 
 func TestGetConfigArgsBuildModules(t *testing.T) {
 	tests := []buildActionTestCase{{
-		description:     "normal execution from the root source tree directory",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
-		args:            []string{"-j", "fake_module", "fake_module2"},
-		curDir:          ".",
-		tidyOnly:        "",
-		expectedArgs:    []string{"-j", "fake_module", "fake_module2"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution from the root source tree directory",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
+		args:         []string{"-j", "fake_module", "fake_module2"},
+		curDir:       ".",
+		tidyOnly:     "",
+		expectedArgs: []string{"-j", "fake_module", "fake_module2"},
 	}, {
-		description:     "normal execution in deep directory",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
-		args:            []string{"-j", "fake_module", "fake_module2", "-k"},
-		curDir:          "1/2/3/4/5/6/7/8/9",
-		tidyOnly:        "",
-		expectedArgs:    []string{"-j", "fake_module", "fake_module2", "-k"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in deep directory",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+		args:         []string{"-j", "fake_module", "fake_module2", "-k"},
+		curDir:       "1/2/3/4/5/6/7/8/9",
+		tidyOnly:     "",
+		expectedArgs: []string{"-j", "fake_module", "fake_module2", "-k"},
 	}, {
-		description:     "normal execution in deep directory, no targets",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
-		args:            []string{"-j", "-k"},
-		curDir:          "1/2/3/4/5/6/7/8/9",
-		tidyOnly:        "",
-		expectedArgs:    []string{"-j", "-k"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in deep directory, no targets",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+		args:         []string{"-j", "-k"},
+		curDir:       "1/2/3/4/5/6/7/8/9",
+		tidyOnly:     "",
+		expectedArgs: []string{"-j", "-k"},
 	}, {
-		description:     "normal execution in root source tree, no args",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp"},
-		args:            []string{},
-		curDir:          "0/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in root source tree, no args",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp"},
+		args:         []string{},
+		curDir:       "0/2",
+		tidyOnly:     "",
+		expectedArgs: []string{},
 	}, {
-		description:     "normal execution in symlink root source tree, no args",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp"},
-		rootSymlink:     true,
-		args:            []string{},
-		curDir:          "0/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in symlink root source tree, no args",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp"},
+		rootSymlink:  true,
+		args:         []string{},
+		curDir:       "0/2",
+		tidyOnly:     "",
+		expectedArgs: []string{},
 	}}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES with dependencies, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES, true)
-		})
-	}
-}
-
-// TODO: Remove this test case once mm shell build command has been deprecated.
-func TestGetConfigArgsBuildModulesInDirecotoryNoDeps(t *testing.T) {
-	tests := []buildActionTestCase{{
-		description:  "normal execution in a directory",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/2/Android.mk"},
-		args:         []string{"-j", "-k", "showcommands", "fake-module"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"-j", "-k", "showcommands", "fake-module", "MODULES-IN-0-1-2"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/Android.mk"}},
-	}, {
-		description:  "makefile in parent directory",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/Android.mk"}},
-	}, {
-		description:  "build file not found",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{},
-		args:         []string{},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1-2"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/Android.mk"}},
-	}, {
-		description:  "build action executed at root directory",
-		dirsInTrees:  []string{},
-		buildFiles:   []string{},
-		args:         []string{},
-		curDir:       ".",
-		tidyOnly:     "",
-		expectedArgs: []string{},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
-	}, {
-		description:  "GET-INSTALL-PATH specified,",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{"GET-INSTALL-PATH"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/Android.mk"}},
-	}, {
-		description:  "tidy only environment variable specified,",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{"GET-INSTALL-PATH"},
-		curDir:       "0/1/2",
-		tidyOnly:     "true",
-		expectedArgs: []string{"tidy_only"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/Android.mk"}},
-	}}
-	for _, tt := range tests {
-		t.Run("build action BUILD_MODULES_IN_DIR without their dependencies, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, false)
+			testGetConfigArgs(t, tt, BUILD_MODULES)
 		})
 	}
 }
 
 func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
 	tests := []buildActionTestCase{{
-		description:     "normal execution in a directory",
-		dirsInTrees:     []string{"0/1/2"},
-		buildFiles:      []string{"0/1/2/Android.mk"},
-		args:            []string{"fake-module"},
-		curDir:          "0/1/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{"fake-module", "MODULES-IN-0-1-2"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in a directory",
+		dirsInTrees:  []string{"0/1/2"},
+		buildFiles:   []string{"0/1/2/Android.mk"},
+		args:         []string{"fake-module"},
+		curDir:       "0/1/2",
+		tidyOnly:     "",
+		expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
 	}, {
-		description:     "build file in parent directory",
-		dirsInTrees:     []string{"0/1/2"},
-		buildFiles:      []string{"0/1/Android.mk"},
-		args:            []string{},
-		curDir:          "0/1/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{"MODULES-IN-0-1"},
-		expectedEnvVars: []envVar{},
+		description:  "build file in parent directory",
+		dirsInTrees:  []string{"0/1/2"},
+		buildFiles:   []string{"0/1/Android.mk"},
+		args:         []string{},
+		curDir:       "0/1/2",
+		tidyOnly:     "",
+		expectedArgs: []string{"MODULES-IN-0-1"},
 	},
 		{
-			description:     "build file in parent directory, multiple module names passed in",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/1/Android.mk"},
-			args:            []string{"fake-module1", "fake-module2", "fake-module3"},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
-			expectedEnvVars: []envVar{},
+			description:  "build file in parent directory, multiple module names passed in",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{"fake-module1", "fake-module2", "fake-module3"},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
 		}, {
-			description:     "build file in 2nd level parent directory",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/Android.bp"},
-			args:            []string{},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"MODULES-IN-0"},
-			expectedEnvVars: []envVar{},
+			description:  "build file in 2nd level parent directory",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/Android.bp"},
+			args:         []string{},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"MODULES-IN-0"},
 		}, {
-			description:     "build action executed at root directory",
-			dirsInTrees:     []string{},
-			buildFiles:      []string{},
-			rootSymlink:     false,
-			args:            []string{},
-			curDir:          ".",
-			tidyOnly:        "",
-			expectedArgs:    []string{},
-			expectedEnvVars: []envVar{},
+			description:  "build action executed at root directory",
+			dirsInTrees:  []string{},
+			buildFiles:   []string{},
+			rootSymlink:  false,
+			args:         []string{},
+			curDir:       ".",
+			tidyOnly:     "",
+			expectedArgs: []string{},
 		}, {
-			description:     "build action executed at root directory in symlink",
-			dirsInTrees:     []string{},
-			buildFiles:      []string{},
-			rootSymlink:     true,
-			args:            []string{},
-			curDir:          ".",
-			tidyOnly:        "",
-			expectedArgs:    []string{},
-			expectedEnvVars: []envVar{},
+			description:  "build action executed at root directory in symlink",
+			dirsInTrees:  []string{},
+			buildFiles:   []string{},
+			rootSymlink:  true,
+			args:         []string{},
+			curDir:       ".",
+			tidyOnly:     "",
+			expectedArgs: []string{},
 		}, {
-			description:     "build file not found - no error is expected to return",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{},
-			args:            []string{},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"MODULES-IN-0-1-2"},
-			expectedEnvVars: []envVar{},
+			description:    "build file not found",
+			dirsInTrees:    []string{"0/1/2"},
+			buildFiles:     []string{},
+			args:           []string{},
+			curDir:         "0/1/2",
+			tidyOnly:       "",
+			expectedArgs:   []string{"MODULES-IN-0-1-2"},
+			expectedErrStr: "Build file not found for 0/1/2 directory",
 		}, {
-			description:     "GET-INSTALL-PATH specified,",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/1/Android.mk"},
-			args:            []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
-			expectedEnvVars: []envVar{},
+			description:  "GET-INSTALL-PATH specified,",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
 		}, {
-			description:     "tidy only environment variable specified,",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/1/Android.mk"},
-			args:            []string{"GET-INSTALL-PATH"},
-			curDir:          "0/1/2",
-			tidyOnly:        "true",
-			expectedArgs:    []string{"tidy_only"},
-			expectedEnvVars: []envVar{},
+			description:  "tidy only environment variable specified,",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{"GET-INSTALL-PATH"},
+			curDir:       "0/1/2",
+			tidyOnly:     "true",
+			expectedArgs: []string{"tidy_only"},
 		}, {
-			description:     "normal execution in root directory with args",
-			dirsInTrees:     []string{},
-			buildFiles:      []string{},
-			args:            []string{"-j", "-k", "fake_module"},
-			curDir:          "",
-			tidyOnly:        "",
-			expectedArgs:    []string{"-j", "-k", "fake_module"},
-			expectedEnvVars: []envVar{},
+			description:  "normal execution in root directory with args",
+			dirsInTrees:  []string{},
+			buildFiles:   []string{},
+			args:         []string{"-j", "-k", "fake_module"},
+			curDir:       "",
+			tidyOnly:     "",
+			expectedArgs: []string{"-j", "-k", "fake_module"},
 		}}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, true)
-		})
-	}
-}
-
-// TODO: Remove this test case once mmm shell build command has been deprecated.
-func TestGetConfigArgsBuildModulesInDirectoriesNoDeps(t *testing.T) {
-	tests := []buildActionTestCase{{
-		description:  "normal execution in a directory",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"3.1/:t1,t2", "3.2/:t3,t4", "3.3/:t5,t6"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"t1", "t2", "t3", "t4", "t5", "t6"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}, {
-		description:  "GET-INSTALL-PATH specified",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "t6"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}, {
-		description:  "tidy only environment variable specified",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
-		curDir:       "0/1/2",
-		tidyOnly:     "1",
-		expectedArgs: []string{"tidy_only"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}, {
-		description:  "normal execution from top dir directory",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"0/1/2/3.1", "0/1/2/3.2/:t3,t4", "0/1/2/3.3/:t5,t6"},
-		curDir:       ".",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "t3", "t4", "t5", "t6"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}}
-	for _, tt := range tests {
-		t.Run("build action BUILD_MODULES_IN_DIRS_NO_DEPS, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, false)
+			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
 		})
 	}
 }
@@ -1088,10 +952,6 @@
 		curDir:       "0/1/2",
 		tidyOnly:     "",
 		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-2-3.3"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "GET-INSTALL-PATH specified",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3"},
@@ -1100,10 +960,6 @@
 		curDir:       "0/1",
 		tidyOnly:     "",
 		expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "GET-INSTALL-PATH-IN-0-1"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "tidy only environment variable specified",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
@@ -1112,10 +968,6 @@
 		curDir:       "0/1/2",
 		tidyOnly:     "1",
 		expectedArgs: []string{"tidy_only"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "normal execution from top dir directory",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
@@ -1125,10 +977,6 @@
 		curDir:       ".",
 		tidyOnly:     "",
 		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "normal execution from top dir directory in symlink",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
@@ -1138,14 +986,10 @@
 		curDir:       ".",
 		tidyOnly:     "",
 		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES_IN_DIRS, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, true)
+			testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES)
 		})
 	}
 }
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 266130f..6b9eac1 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -169,7 +169,7 @@
 	// Variables to export into the environment of Kati/Ninja
 	exportEnvVars := []string{
 		// So that we can use the correct TARGET_PRODUCT if it's been
-		// modified by PRODUCT-*/APP-* arguments
+		// modified by a buildspec.mk
 		"TARGET_PRODUCT",
 		"TARGET_BUILD_VARIANT",
 		"TARGET_BUILD_APPS",
diff --git a/ui/build/goma.go b/ui/build/goma.go
index ff0b40e..ae9b784 100644
--- a/ui/build/goma.go
+++ b/ui/build/goma.go
@@ -72,6 +72,7 @@
 	}
 
 	cmd := Command(ctx, config, "goma_ctl.py ensure_start", gomaCtl, "ensure_start")
+	cmd.Environment.Set("DIST_DIR", config.DistDir())
 
 	if output, err := cmd.CombinedOutput(); err != nil {
 		ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n%s\n", err, output)
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 5ad966a..9ddbbea 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -42,9 +42,6 @@
 	if args := config.KatiArgs(); len(args) > 0 {
 		katiSuffix += "-" + spaceSlashReplacer.Replace(strings.Join(args, "_"))
 	}
-	if oneShot, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
-		katiSuffix += "-" + spaceSlashReplacer.Replace(oneShot)
-	}
 
 	// If the suffix is too long, replace it with a md5 hash and write a
 	// file that contains the original suffix.
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index b41ac20..66750d6 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -43,7 +43,7 @@
 	args = append(args, config.NinjaArgs()...)
 
 	var parallel int
-	if config.UseGoma() {
+	if config.UseGoma() || config.UseRBE() {
 		parallel = config.RemoteParallel()
 	} else {
 		parallel = config.Parallel()
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index a4be2ac..100cc65 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,21 +74,16 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"bash": Allowed,
-	"bc":   Allowed,
-	// We need bzip2 here even though we provide a bzip2 binary because
-	// GNU tar seems to avoid calling ours.
-	"bzip2":    Allowed,
+	"bash":     Allowed,
+	"bc":       Allowed,
 	"dd":       Allowed,
 	"diff":     Allowed,
 	"dlv":      Allowed,
-	"egrep":    Allowed,
 	"expr":     Allowed,
 	"find":     Allowed,
 	"fuser":    Allowed,
 	"getopt":   Allowed,
 	"git":      Allowed,
-	"grep":     Allowed,
 	"gzcat":    Allowed,
 	"gzip":     Allowed,
 	"hexdump":  Allowed,
@@ -104,7 +99,6 @@
 	"realpath": Allowed,
 	"rsync":    Allowed,
 	"sh":       Allowed,
-	"tar":      Allowed,
 	"tr":       Allowed,
 	"unzip":    Allowed,
 	"zip":      Allowed,
@@ -136,9 +130,11 @@
 	"dirname":   LinuxOnlyPrebuilt,
 	"du":        LinuxOnlyPrebuilt,
 	"echo":      LinuxOnlyPrebuilt,
+	"egrep":     LinuxOnlyPrebuilt,
 	"env":       LinuxOnlyPrebuilt,
-	"head":      LinuxOnlyPrebuilt,
 	"getconf":   LinuxOnlyPrebuilt,
+	"grep":      LinuxOnlyPrebuilt,
+	"head":      LinuxOnlyPrebuilt,
 	"hostname":  LinuxOnlyPrebuilt,
 	"id":        LinuxOnlyPrebuilt,
 	"ln":        LinuxOnlyPrebuilt,
@@ -166,6 +162,7 @@
 	"sort":      LinuxOnlyPrebuilt,
 	"stat":      LinuxOnlyPrebuilt,
 	"tail":      LinuxOnlyPrebuilt,
+	"tar":       LinuxOnlyPrebuilt,
 	"tee":       LinuxOnlyPrebuilt,
 	"timeout":   LinuxOnlyPrebuilt,
 	"touch":     LinuxOnlyPrebuilt,
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
new file mode 100644
index 0000000..ceea4bf
--- /dev/null
+++ b/ui/build/rbe.go
@@ -0,0 +1,52 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build
+
+import (
+	"path/filepath"
+
+	"android/soong/ui/metrics"
+)
+
+const bootstrapCmd = "bootstrap"
+const rbeLeastNProcs = 2500
+const rbeLeastNFiles = 16000
+
+func startRBE(ctx Context, config Config) {
+	ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
+	defer ctx.EndTrace()
+
+	if u := ulimitOrFatal(ctx, config, "-u"); u < rbeLeastNProcs {
+		ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, rbeLeastNProcs)
+	}
+	if n := ulimitOrFatal(ctx, config, "-n"); n < rbeLeastNFiles {
+		ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, rbeLeastNFiles)
+	}
+
+	var rbeBootstrap string
+	if rbeDir, ok := config.Environment().Get("RBE_DIR"); ok {
+		rbeBootstrap = filepath.Join(rbeDir, bootstrapCmd)
+	} else if home, ok := config.Environment().Get("HOME"); ok {
+		rbeBootstrap = filepath.Join(home, "rbe", bootstrapCmd)
+	} else {
+		ctx.Fatalln("rbe bootstrap not found")
+	}
+
+	cmd := Command(ctx, config, "boostrap", rbeBootstrap)
+
+	if output, err := cmd.CombinedOutput(); err != nil {
+		ctx.Fatalf("rbe bootstrap failed with: %v\n%s\n", err, output)
+	}
+}
diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go
index 8659d4d..57f71ab 100644
--- a/ui/terminal/smart_status.go
+++ b/ui/terminal/smart_status.go
@@ -59,21 +59,24 @@
 // current build status similarly to Ninja's built-in terminal
 // output.
 func NewSmartStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
-	tableHeight, _ := strconv.Atoi(os.Getenv(tableHeightEnVar))
-
 	s := &smartStatusOutput{
 		writer:    w,
 		formatter: formatter,
 
 		haveBlankLine: true,
 
-		tableMode:            tableHeight > 0,
-		requestedTableHeight: tableHeight,
+		tableMode: true,
 
 		done:     make(chan bool),
 		sigwinch: make(chan os.Signal),
 	}
 
+	if env, ok := os.LookupEnv(tableHeightEnVar); ok {
+		h, _ := strconv.Atoi(env)
+		s.tableMode = h > 0
+		s.requestedTableHeight = h
+	}
+
 	s.updateTermSize()
 
 	if s.tableMode {
@@ -297,6 +300,14 @@
 
 		if s.tableMode {
 			tableHeight := s.requestedTableHeight
+			if tableHeight == 0 {
+				tableHeight = s.termHeight / 4
+				if tableHeight < 1 {
+					tableHeight = 1
+				} else if tableHeight > 10 {
+					tableHeight = 10
+				}
+			}
 			if tableHeight > s.termHeight-1 {
 				tableHeight = s.termHeight - 1
 			}
diff --git a/xml/xml.go b/xml/xml.go
index 7c670fb..3a680ec 100644
--- a/xml/xml.go
+++ b/xml/xml.go
@@ -71,10 +71,6 @@
 	return android.PathForModuleOut(ctx, p.PrebuiltEtc.SourceFilePath(ctx).Base()+"-timestamp")
 }
 
-func (p *prebuiltEtcXml) DepsMutator(ctx android.BottomUpMutatorContext) {
-	p.PrebuiltEtc.DepsMutator(ctx)
-}
-
 func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	p.PrebuiltEtc.GenerateAndroidBuildActions(ctx)
 
@@ -125,9 +121,8 @@
 func PrebuiltEtcXmlFactory() android.Module {
 	module := &prebuiltEtcXml{}
 	module.AddProperties(&module.properties)
-
-	android.InitPrebuiltEtcModule(&module.PrebuiltEtc)
+	android.InitPrebuiltEtcModule(&module.PrebuiltEtc, "etc")
 	// This module is device-only
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	return module
 }
diff --git a/xml/xml_test.go b/xml/xml_test.go
index e8fa49c..ae3e9fe 100644
--- a/xml/xml_test.go
+++ b/xml/xml_test.go
@@ -34,6 +34,7 @@
 		"foo.dtd":    nil,
 		"bar.xml":    nil,
 		"bar.xsd":    nil,
+		"baz.xml":    nil,
 	}
 	ctx.MockFileSystem(mockFiles)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
@@ -59,6 +60,13 @@
 	os.RemoveAll(buildDir)
 }
 
+func assertEqual(t *testing.T, name, expected, actual string) {
+	t.Helper()
+	if expected != actual {
+		t.Errorf(name+" expected %q != got %q", expected, actual)
+	}
+}
+
 // Minimal test
 func TestPrebuiltEtcXml(t *testing.T) {
 	ctx := testXml(t, `
@@ -72,15 +80,28 @@
 			src: "bar.xml",
 			schema: "bar.xsd",
 		}
+		prebuilt_etc_xml {
+			name: "baz.xml",
+			src: "baz.xml",
+		}
 	`)
 
-	xmllint := ctx.ModuleForTests("foo.xml", "android_common").Rule("xmllint")
-	input := xmllint.Input.String()
-	if input != "foo.xml" {
-		t.Errorf("input expected %q != got %q", "foo.xml", input)
+	for _, tc := range []struct {
+		rule, input, schemaType, schema string
+	}{
+		{rule: "xmllint-dtd", input: "foo.xml", schemaType: "dtd", schema: "foo.dtd"},
+		{rule: "xmllint-xsd", input: "bar.xml", schemaType: "xsd", schema: "bar.xsd"},
+		{rule: "xmllint-minimal", input: "baz.xml"},
+	} {
+		t.Run(tc.schemaType, func(t *testing.T) {
+			rule := ctx.ModuleForTests(tc.input, "android_arm64_armv8-a").Rule(tc.rule)
+			assertEqual(t, "input", tc.input, rule.Input.String())
+			if tc.schemaType != "" {
+				assertEqual(t, "schema", tc.schema, rule.Args[tc.schemaType])
+			}
+		})
 	}
-	schema := xmllint.Args["dtd"]
-	if schema != "foo.dtd" {
-		t.Errorf("dtd expected %q != got %q", "foo.dtdl", schema)
-	}
+
+	m := ctx.ModuleForTests("foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml)
+	assertEqual(t, "installDir", "target/product/test_device/system/etc", m.InstallDirPath().RelPathString())
 }