Don't use prebuilt_apex when TARGET_FLATTEN_APEX is set to true
am: 0a573d798f

Change-Id: I67d532961fc4584bc0d7bf3616edb3236fb1acc9
diff --git a/Android.bp b/Android.bp
index 1d65dff..1b68adb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -37,6 +37,7 @@
         "blueprint-bootstrap",
         "soong",
         "soong-env",
+        "soong-shared",
     ],
     srcs: [
         "android/androidmk.go",
@@ -57,6 +58,7 @@
         "android/notices.go",
         "android/onceper.go",
         "android/override_module.go",
+        "android/package.go",
         "android/package_ctx.go",
         "android/path_properties.go",
         "android/paths.go",
@@ -70,6 +72,7 @@
         "android/testing.go",
         "android/util.go",
         "android/variable.go",
+        "android/visibility.go",
         "android/vts_config.go",
         "android/writedocs.go",
 
@@ -77,12 +80,16 @@
         "android/env.go",
     ],
     testSrcs: [
+        "android/android_test.go",
         "android/arch_test.go",
         "android/config_test.go",
         "android/expand_test.go",
+        "android/module_test.go",
+        "android/mutator_test.go",
         "android/namespace_test.go",
         "android/neverallow_test.go",
         "android/onceper_test.go",
+        "android/package_test.go",
         "android/path_properties_test.go",
         "android/paths_test.go",
         "android/prebuilt_test.go",
@@ -90,6 +97,7 @@
         "android/rule_builder_test.go",
         "android/util_test.go",
         "android/variable_test.go",
+        "android/visibility_test.go",
         "android/vts_config_test.go",
     ],
 }
@@ -275,6 +283,7 @@
         "java/plugin.go",
         "java/prebuilt_apis.go",
         "java/proto.go",
+        "java/robolectric.go",
         "java/sdk.go",
         "java/sdk_library.go",
         "java/support_libraries.go",
@@ -290,6 +299,7 @@
         "java/jdeps_test.go",
         "java/kotlin_test.go",
         "java/plugin_test.go",
+        "java/robolectric_test.go",
         "java/sdk_test.go",
     ],
     pluginFor: ["soong_build"],
@@ -442,6 +452,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
 
     arch: {
         arm: {
@@ -464,6 +475,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
 
     arch: {
         arm: {
@@ -486,6 +498,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
 
     arch: {
         arm: {
diff --git a/OWNERS b/OWNERS
index 85c70df..4ae045d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,5 @@
-per-file * = asmundak@google.com,ccross@android.com,dwillemsen@google.com,jungjw@google.com
+per-file * = asmundak@google.com,ccross@android.com,dwillemsen@google.com,jungjw@google.com,paulduffin@google.com
+
 per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com
 per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
 per-file tidy.go = srhines@google.com, chh@google.com
diff --git a/README.md b/README.md
index 2957940..531ef4c 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,8 @@
 Maps may values of any type, including nested maps.  Lists and maps may have
 trailing commas after the last value.
 
+Strings can contain double quotes using `\"`, for example `"cat \"a b\""`.
+
 ### Operators
 
 Strings, lists of strings, and maps can be appended using the `+` operator.
@@ -107,6 +109,49 @@
 }
 ```
 
+### Packages
+
+The build is organized into packages where each package is a collection of related files and a
+specification of the dependencies among them in the form of modules.
+
+A package is defined as a directory containing a file named `Android.bp`, residing beneath the
+top-level directory in the build and its name is its path relative to the top-level directory. A
+package includes all files in its directory, plus all subdirectories beneath it, except those which
+themselves contain an `Android.bp` file.
+
+The modules in a package's `Android.bp` and included files are part of the module.
+
+For example, in the following directory tree (where `.../android/` is the top-level Android
+directory) there are two packages, `my/app`, and the subpackage `my/app/tests`. Note that
+`my/app/data` is not a package, but a directory belonging to package `my/app`.
+
+    .../android/my/app/Android.bp
+    .../android/my/app/app.cc
+    .../android/my/app/data/input.txt
+    .../android/my/app/tests/Android.bp
+    .../android/my/app/tests/test.cc
+
+This is based on the Bazel package concept.
+
+The `package` module type allows information to be specified about a package. Only a single
+`package` module can be specified per package and in the case where there are multiple `.bp` files
+in the same package directory it is highly recommended that the `package` module (if required) is
+specified in the `Android.bp` file.
+
+Unlike most module type `package` does not have a `name` property. Instead the name is set to the
+name of the package, e.g. if the package is in `top/intermediate/package` then the package name is
+`//top/intermediate/package`.
+
+E.g. The following will set the default visibility for all the modules defined in the package and
+any subpackages that do not set their own default visibility (irrespective of whether they are in
+the same `.bp` file as the `package` module) to be visible to all the subpackages by default.
+
+```
+package {
+    default_visibility: [":__subpackages"]
+}
+```
+
 ### Name resolution
 
 Soong provides the ability for modules in different directories to specify
@@ -139,6 +184,65 @@
 built by the `m` command. After we have fully converted from Make to Soong, the
 details of enabling namespaces could potentially change.
 
+### Visibility
+
+The `visibility` property on a module controls whether the module can be
+used by other packages. Modules are always visible to other modules declared
+in the same package. This is based on the Bazel visibility mechanism.
+
+If specified the `visibility` property must contain at least one rule.
+
+Each rule in the property must be in one of the following forms:
+* `["//visibility:public"]`: Anyone can use this module.
+* `["//visibility:private"]`: Only rules in the module's package (not its
+subpackages) can use this module.
+* `["//some/package:__pkg__", "//other/package:__pkg__"]`: Only modules in
+`some/package` and `other/package` (defined in `some/package/*.bp` and
+`other/package/*.bp`) have access to this module. Note that sub-packages do not
+have access to the rule; for example, `//some/package/foo:bar` or
+`//other/package/testing:bla` wouldn't have access. `__pkg__` is a special
+module and must be used verbatim. It represents all of the modules in the
+package.
+* `["//project:__subpackages__", "//other:__subpackages__"]`: Only modules in
+packages `project` or `other` or in one of their sub-packages have access to
+this module. For example, `//project:rule`, `//project/library:lib` or
+`//other/testing/internal:munge` are allowed to depend on this rule (but not
+`//independent:evil`)
+* `["//project"]`: This is shorthand for `["//project:__pkg__"]`
+* `[":__subpackages__"]`: This is shorthand for `["//project:__subpackages__"]`
+where `//project` is the module's package, e.g. using `[":__subpackages__"]` in
+`packages/apps/Settings/Android.bp` is equivalent to
+`//packages/apps/Settings:__subpackages__`.
+* `["//visibility:legacy_public"]`: The default visibility, behaves as
+`//visibility:public` for now. It is an error if it is used in a module.
+
+The visibility rules of `//visibility:public` and `//visibility:private` cannot
+be combined with any other visibility specifications, except
+`//visibility:public` is allowed to override visibility specifications imported
+through the `defaults` property.
+
+Packages outside `vendor/` cannot make themselves visible to specific packages
+in `vendor/`, e.g. a module in `libcore` cannot declare that it is visible to
+say `vendor/google`, instead it must make itself visible to all packages within
+`vendor/` using `//vendor:__subpackages__`.
+
+If a module does not specify the `visibility` property then it uses the
+`default_visibility` property of the `package` module in the module's package.
+
+If the `default_visibility` property is not set for the module's package then
+it will use the `default_visibility` of its closest ancestor package for which
+a `default_visibility` property is specified.
+
+If no `default_visibility` property can be found then the module uses the
+global default of `//visibility:legacy_public`.
+
+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`
+property will be updated to have
+`default_visibility = [//visibility:legacy_public]` added. It will then be the
+owner's responsibility to replace that with a more appropriate visibility.
+
 ### Formatter
 
 Soong includes a canonical formatter for blueprint files, similar to
@@ -233,6 +337,19 @@
 This will bind mount the Soong source directories into the directory in the layout expected by
 the IDE.
 
+### Running Soong in a debugger
+
+To run the soong_build process in a debugger, install `dlv` and then start the build with
+`SOONG_DELVE=<listen addr>` in the environment.
+For examle:
+```bash
+SOONG_DELVE=:1234 m nothing
+```
+and then in another terminal:
+```
+dlv connect :1234
+```
+
 ## Contact
 
 Email android-building@googlegroups.com (external) for any questions, or see
diff --git a/android/android_test.go b/android/android_test.go
new file mode 100644
index 0000000..46b7054
--- /dev/null
+++ b/android/android_test.go
@@ -0,0 +1,46 @@
+// 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/ioutil"
+	"os"
+	"testing"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_android_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
diff --git a/android/androidmk.go b/android/androidmk.go
index bd49e4c..9bc2692 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -32,19 +32,23 @@
 	RegisterSingletonType("androidmk", AndroidMkSingleton)
 }
 
+// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
+// use the Custom function.
 type AndroidMkDataProvider interface {
 	AndroidMk() AndroidMkData
 	BaseModuleName() string
 }
 
 type AndroidMkData struct {
-	Class      string
-	SubName    string
-	DistFile   OptionalPath
-	OutputFile OptionalPath
-	Disabled   bool
-	Include    string
-	Required   []string
+	Class           string
+	SubName         string
+	DistFile        OptionalPath
+	OutputFile      OptionalPath
+	Disabled        bool
+	Include         string
+	Required        []string
+	Host_required   []string
+	Target_required []string
 
 	Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
 
@@ -55,6 +59,218 @@
 
 type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
 
+// Allows modules to customize their Android*.mk output.
+type AndroidMkEntriesProvider interface {
+	AndroidMkEntries() AndroidMkEntries
+	BaseModuleName() string
+}
+
+type AndroidMkEntries struct {
+	Class           string
+	SubName         string
+	DistFile        OptionalPath
+	OutputFile      OptionalPath
+	Disabled        bool
+	Include         string
+	Required        []string
+	Host_required   []string
+	Target_required []string
+
+	header bytes.Buffer
+	footer bytes.Buffer
+
+	AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries)
+
+	EntryMap   map[string][]string
+	entryOrder []string
+}
+
+func (a *AndroidMkEntries) SetString(name, value string) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.entryOrder = append(a.entryOrder, name)
+	}
+	a.EntryMap[name] = []string{value}
+}
+
+func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
+	if flag {
+		if _, ok := a.EntryMap[name]; !ok {
+			a.entryOrder = append(a.entryOrder, name)
+		}
+		a.EntryMap[name] = []string{"true"}
+	}
+}
+
+func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
+	if len(value) == 0 {
+		return
+	}
+	if _, ok := a.EntryMap[name]; !ok {
+		a.entryOrder = append(a.entryOrder, name)
+	}
+	a.EntryMap[name] = append(a.EntryMap[name], value...)
+}
+
+func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
+	a.EntryMap = make(map[string][]string)
+	amod := mod.(Module).base()
+	name := amod.BaseModuleName()
+
+	if a.Include == "" {
+		a.Include = "$(BUILD_PREBUILT)"
+	}
+	a.Required = append(a.Required, amod.commonProperties.Required...)
+	a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...)
+	a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...)
+
+	// Fill in the header part.
+	if len(amod.commonProperties.Dist.Targets) > 0 {
+		distFile := a.DistFile
+		if !distFile.Valid() {
+			distFile = a.OutputFile
+		}
+		if distFile.Valid() {
+			dest := filepath.Base(distFile.String())
+
+			if amod.commonProperties.Dist.Dest != nil {
+				var err error
+				if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			if amod.commonProperties.Dist.Suffix != nil {
+				ext := filepath.Ext(dest)
+				suffix := *amod.commonProperties.Dist.Suffix
+				dest = strings.TrimSuffix(dest, ext) + suffix + ext
+			}
+
+			if amod.commonProperties.Dist.Dir != nil {
+				var err error
+				if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
+			fmt.Fprintln(&a.header, ".PHONY:", goals)
+			fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
+				goals, distFile.String(), dest)
+		}
+	}
+
+	fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
+
+	// Collect make variable assignment entries.
+	a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
+	a.SetString("LOCAL_MODULE", name+a.SubName)
+	a.SetString("LOCAL_MODULE_CLASS", a.Class)
+	a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
+	a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
+	a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
+	a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
+
+	archStr := amod.Arch().ArchType.String()
+	host := false
+	switch amod.Os().Class {
+	case Host:
+		// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
+		if archStr != "common" {
+			a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
+		}
+		host = true
+	case HostCross:
+		// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
+		if archStr != "common" {
+			a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
+		}
+		host = true
+	case Device:
+		// 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"
+				}
+
+				if hostArchStr != "" {
+					a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
+				}
+			} else {
+				a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
+			}
+		}
+
+		a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
+		a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
+		a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
+		if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
+			a.SetString("LOCAL_VENDOR_MODULE", "true")
+		}
+		a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific))
+		a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_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)
+		}
+	}
+
+	if amod.noticeFile.Valid() {
+		a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
+	}
+
+	if host {
+		makeOs := amod.Os().String()
+		if amod.Os() == Linux || amod.Os() == LinuxBionic {
+			makeOs = "linux"
+		}
+		a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
+		a.SetString("LOCAL_IS_HOST_MODULE", "true")
+	}
+
+	prefix := ""
+	if amod.ArchSpecific() {
+		switch amod.Os().Class {
+		case Host:
+			prefix = "HOST_"
+		case HostCross:
+			prefix = "HOST_CROSS_"
+		case Device:
+			prefix = "TARGET_"
+
+		}
+
+		if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType {
+			prefix = "2ND_" + prefix
+		}
+	}
+	blueprintDir := filepath.Dir(bpPath)
+	if a.AddCustomEntries != nil {
+		a.AddCustomEntries(name, prefix, blueprintDir, a)
+	}
+
+	// Write to footer.
+	fmt.Fprintln(&a.footer, "include "+a.Include)
+}
+
+func (a *AndroidMkEntries) write(w io.Writer) {
+	w.Write(a.header.Bytes())
+	for _, name := range a.entryOrder {
+		fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " "))
+	}
+	w.Write(a.footer.Bytes())
+}
+
 func AndroidMkSingleton() Singleton {
 	return &androidMkSingleton{}
 }
@@ -157,6 +373,8 @@
 		return translateAndroidModule(ctx, w, mod, x)
 	case bootstrap.GoBinaryTool:
 		return translateGoBinaryModule(ctx, w, mod, x)
+	case AndroidMkEntriesProvider:
+		return translateAndroidMkEntriesModule(ctx, w, mod, x)
 	default:
 		return nil
 	}
@@ -176,35 +394,32 @@
 func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
 	provider AndroidMkDataProvider) error {
 
-	name := provider.BaseModuleName()
 	amod := mod.(Module).base()
-
-	if !amod.Enabled() {
-		return nil
-	}
-
-	if amod.commonProperties.SkipInstall {
-		return nil
-	}
-
-	if !amod.commonProperties.NamespaceExportedToMake {
-		// TODO(jeffrygaston) do we want to validate that there are no modules being
-		// exported to Kati that depend on this module?
+	if shouldSkipAndroidMkProcessing(amod) {
 		return nil
 	}
 
 	data := provider.AndroidMk()
-
 	if data.Include == "" {
 		data.Include = "$(BUILD_PREBUILT)"
 	}
 
-	data.Required = append(data.Required, amod.commonProperties.Required...)
-
-	// Make does not understand LinuxBionic
-	if amod.Os() == LinuxBionic {
-		return nil
+	// 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)
 
 	prefix := ""
 	if amod.ArchSpecific() {
@@ -223,115 +438,7 @@
 		}
 	}
 
-	if len(amod.commonProperties.Dist.Targets) > 0 {
-		distFile := data.DistFile
-		if !distFile.Valid() {
-			distFile = data.OutputFile
-		}
-		if distFile.Valid() {
-			dest := filepath.Base(distFile.String())
-
-			if amod.commonProperties.Dist.Dest != nil {
-				var err error
-				dest, err = validateSafePath(*amod.commonProperties.Dist.Dest)
-				if err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			if amod.commonProperties.Dist.Suffix != nil {
-				ext := filepath.Ext(dest)
-				suffix := *amod.commonProperties.Dist.Suffix
-				dest = strings.TrimSuffix(dest, ext) + suffix + ext
-			}
-
-			if amod.commonProperties.Dist.Dir != nil {
-				var err error
-				dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest)
-				if err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
-			fmt.Fprintln(&data.preamble, ".PHONY:", goals)
-			fmt.Fprintf(&data.preamble, "$(call dist-for-goals,%s,%s:%s)\n",
-				goals, distFile.String(), dest)
-		}
-	}
-
-	fmt.Fprintln(&data.preamble, "\ninclude $(CLEAR_VARS)")
-	fmt.Fprintln(&data.preamble, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod)))
-	fmt.Fprintln(&data.preamble, "LOCAL_MODULE :=", name+data.SubName)
-	fmt.Fprintln(&data.preamble, "LOCAL_MODULE_CLASS :=", data.Class)
-	fmt.Fprintln(&data.preamble, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String())
-
-	if len(data.Required) > 0 {
-		fmt.Fprintln(&data.preamble, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " "))
-	}
-
-	archStr := amod.Arch().ArchType.String()
-	host := false
-	switch amod.Os().Class {
-	case Host:
-		// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
-		if archStr != "common" {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_ARCH :=", archStr)
-		}
-		host = true
-	case HostCross:
-		// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
-		if archStr != "common" {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
-		}
-		host = true
-	case Device:
-		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
-		if archStr != "common" {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
-		}
-
-		if len(amod.commonProperties.Init_rc) > 0 {
-			fmt.Fprintln(&data.preamble, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " "))
-		}
-		if len(amod.commonProperties.Vintf_fragments) > 0 {
-			fmt.Fprintln(&data.preamble, "LOCAL_VINTF_FRAGMENTS := ", strings.Join(amod.commonProperties.Vintf_fragments, " "))
-		}
-		if Bool(amod.commonProperties.Proprietary) {
-			fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_VENDOR_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Device_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_ODM_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Product_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Product_services_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_SERVICES_MODULE := true")
-		}
-		if amod.commonProperties.Owner != nil {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
-		}
-	}
-
-	if amod.noticeFile.Valid() {
-		fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", amod.noticeFile.String())
-	}
-
-	if host {
-		makeOs := amod.Os().String()
-		if amod.Os() == Linux || amod.Os() == LinuxBionic {
-			makeOs = "linux"
-		}
-		fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_OS :=", makeOs)
-		fmt.Fprintln(&data.preamble, "LOCAL_IS_HOST_MODULE := true")
-	}
-
+	name := provider.BaseModuleName()
 	blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
 
 	if data.Custom != nil {
@@ -360,3 +467,30 @@
 
 	fmt.Fprintln(w, "include "+data.Include)
 }
+
+func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
+	provider AndroidMkEntriesProvider) error {
+	if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
+		return nil
+	}
+
+	entries := provider.AndroidMkEntries()
+	entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
+
+	entries.write(w)
+
+	return nil
+}
+
+func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
+	if !module.commonProperties.NamespaceExportedToMake {
+		// TODO(jeffrygaston) do we want to validate that there are no modules being
+		// exported to Kati that depend on this module?
+		return true
+	}
+
+	return !module.Enabled() ||
+		module.commonProperties.SkipInstall ||
+		// Make does not understand LinuxBionic
+		module.Os() == LinuxBionic
+}
diff --git a/android/api_levels.go b/android/api_levels.go
index 2f70f62..4f6efee 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -86,7 +86,7 @@
 // * Numeric API levels are simply converted.
 // * "minimum" and "current" are not currently handled since the former is
 //   NDK specific and the latter has inconsistent meaning.
-func ApiStrToNum(ctx BaseContext, apiLevel string) (int, error) {
+func ApiStrToNum(ctx BaseModuleContext, apiLevel string) (int, error) {
 	num, ok := getApiLevelsMap(ctx.Config())[apiLevel]
 	if ok {
 		return num, nil
diff --git a/android/arch.go b/android/arch.go
index 957a659..46e582c 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -683,13 +683,25 @@
 	return NoOsType
 }
 
+type NativeBridgeSupport bool
+
+const (
+	NativeBridgeDisabled NativeBridgeSupport = false
+	NativeBridgeEnabled  NativeBridgeSupport = true
+)
+
 type Target struct {
-	Os   OsType
-	Arch Arch
+	Os           OsType
+	Arch         Arch
+	NativeBridge NativeBridgeSupport
 }
 
 func (target Target) String() string {
-	return target.Os.String() + "_" + target.Arch.String()
+	variant := ""
+	if target.NativeBridge {
+		variant = "native_bridge_"
+	}
+	return target.Os.String() + "_" + variant + target.Arch.String()
 }
 
 // archMutator splits a module into a variant for each Target requested by the module.  Target selection
@@ -698,10 +710,10 @@
 //    - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
 //      whether the module type can compile for host, device or both.
 //    - The host_supported and device_supported properties on the module.
-// If host is supported for the module, the Host and HostCross OsClasses are  are selected.  If device is supported
+// If host is supported for the module, the Host and HostCross OsClasses are selected.  If device is supported
 // for the module, the Device OsClass is selected.
 // Within each selected OsClass, the multilib selection is determined by:
-//    - The compile_multilib property if it set (which may be overriden by target.android.compile_multlib or
+//    - The compile_multilib property if it set (which may be overridden by target.android.compile_multilib or
 //      target.host.compile_multilib).
 //    - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
 // Valid multilib values include:
@@ -750,6 +762,18 @@
 			continue
 		}
 
+		// Filter NativeBridge targets unless they are explicitly supported
+		if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
+			var targets []Target
+			for _, t := range osTargets {
+				if !t.NativeBridge {
+					targets = append(targets, t)
+				}
+			}
+
+			osTargets = targets
+		}
+
 		// only the primary arch in the recovery partition
 		if os == Android && module.InstallInRecovery() {
 			osTargets = []Target{osTargets[0]}
@@ -1105,7 +1129,7 @@
 
 var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
 
-func (a *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
+func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
 	dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
 
 	src = src.FieldByName(field)
@@ -1143,16 +1167,16 @@
 }
 
 // Rewrite the module's properties structs to contain arch-specific values.
-func (a *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
-	arch := a.Arch()
-	os := a.Os()
+func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
+	arch := m.Arch()
+	os := m.Os()
 
-	for i := range a.generalProperties {
-		genProps := a.generalProperties[i]
-		if a.archProperties[i] == nil {
+	for i := range m.generalProperties {
+		genProps := m.generalProperties[i]
+		if m.archProperties[i] == nil {
 			continue
 		}
-		for _, archProperties := range a.archProperties[i] {
+		for _, archProperties := range m.archProperties[i] {
 			archPropValues := reflect.ValueOf(archProperties).Elem()
 
 			archProp := archPropValues.FieldByName("Arch")
@@ -1173,7 +1197,7 @@
 			if arch.ArchType != Common {
 				field := proptools.FieldNameForProperty(t.Name)
 				prefix := "arch." + t.Name
-				archStruct := a.appendProperties(ctx, genProps, archProp, field, prefix)
+				archStruct := m.appendProperties(ctx, genProps, archProp, field, prefix)
 
 				// Handle arch-variant-specific properties in the form:
 				// arch: {
@@ -1185,7 +1209,7 @@
 				if v != "" {
 					field := proptools.FieldNameForProperty(v)
 					prefix := "arch." + t.Name + "." + v
-					a.appendProperties(ctx, genProps, archStruct, field, prefix)
+					m.appendProperties(ctx, genProps, archStruct, field, prefix)
 				}
 
 				// Handle cpu-variant-specific properties in the form:
@@ -1199,7 +1223,7 @@
 					if c != "" {
 						field := proptools.FieldNameForProperty(c)
 						prefix := "arch." + t.Name + "." + c
-						a.appendProperties(ctx, genProps, archStruct, field, prefix)
+						m.appendProperties(ctx, genProps, archStruct, field, prefix)
 					}
 				}
 
@@ -1212,7 +1236,7 @@
 				for _, feature := range arch.ArchFeatures {
 					field := proptools.FieldNameForProperty(feature)
 					prefix := "arch." + t.Name + "." + feature
-					a.appendProperties(ctx, genProps, archStruct, field, prefix)
+					m.appendProperties(ctx, genProps, archStruct, field, prefix)
 				}
 
 				// Handle multilib-specific properties in the form:
@@ -1223,7 +1247,7 @@
 				// },
 				field = proptools.FieldNameForProperty(t.Multilib)
 				prefix = "multilib." + t.Multilib
-				a.appendProperties(ctx, genProps, multilibProp, field, prefix)
+				m.appendProperties(ctx, genProps, multilibProp, field, prefix)
 			}
 
 			// Handle host-specific properties in the form:
@@ -1235,7 +1259,7 @@
 			if os.Class == Host || os.Class == HostCross {
 				field = "Host"
 				prefix = "target.host"
-				a.appendProperties(ctx, genProps, targetProp, field, prefix)
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
 			}
 
 			// Handle target OS generalities of the form:
@@ -1250,24 +1274,24 @@
 			if os.Linux() {
 				field = "Linux"
 				prefix = "target.linux"
-				a.appendProperties(ctx, genProps, targetProp, field, prefix)
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
 
 				if arch.ArchType != Common {
 					field = "Linux_" + arch.ArchType.Name
 					prefix = "target.linux_" + arch.ArchType.Name
-					a.appendProperties(ctx, genProps, targetProp, field, prefix)
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
 			}
 
 			if os.Bionic() {
 				field = "Bionic"
 				prefix = "target.bionic"
-				a.appendProperties(ctx, genProps, targetProp, field, prefix)
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
 
 				if arch.ArchType != Common {
 					field = "Bionic_" + t.Name
 					prefix = "target.bionic_" + t.Name
-					a.appendProperties(ctx, genProps, targetProp, field, prefix)
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
 			}
 
@@ -1297,18 +1321,18 @@
 			// },
 			field = os.Field
 			prefix = "target." + os.Name
-			a.appendProperties(ctx, genProps, targetProp, field, prefix)
+			m.appendProperties(ctx, genProps, targetProp, field, prefix)
 
 			if arch.ArchType != Common {
 				field = os.Field + "_" + t.Name
 				prefix = "target." + os.Name + "_" + t.Name
-				a.appendProperties(ctx, genProps, targetProp, field, prefix)
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
 			}
 
 			if (os.Class == Host || os.Class == HostCross) && os != Windows {
 				field := "Not_windows"
 				prefix := "target.not_windows"
-				a.appendProperties(ctx, genProps, targetProp, field, prefix)
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
 			}
 
 			// Handle 64-bit device properties in the form:
@@ -1328,11 +1352,11 @@
 				if ctx.Config().Android64() {
 					field := "Android64"
 					prefix := "target.android64"
-					a.appendProperties(ctx, genProps, targetProp, field, prefix)
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				} else {
 					field := "Android32"
 					prefix := "target.android32"
-					a.appendProperties(ctx, genProps, targetProp, field, prefix)
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
 
 				if (arch.ArchType == X86 && (hasArmAbi(arch) ||
@@ -1341,7 +1365,7 @@
 						hasX86AndroidArch(ctx.Config().Targets[Android])) {
 					field := "Arm_on_x86"
 					prefix := "target.arm_on_x86"
-					a.appendProperties(ctx, genProps, targetProp, field, prefix)
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
 				if (arch.ArchType == X86_64 && (hasArmAbi(arch) ||
 					hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
@@ -1349,7 +1373,7 @@
 						hasX8664AndroidArch(ctx.Config().Targets[Android])) {
 					field := "Arm_on_x86_64"
 					prefix := "target.arm_on_x86_64"
-					a.appendProperties(ctx, genProps, targetProp, field, prefix)
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
 			}
 		}
@@ -1378,7 +1402,8 @@
 	targets := make(map[OsType][]Target)
 	var targetErr error
 
-	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string) {
+	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string,
+		nativeBridgeEnabled NativeBridgeSupport) {
 		if targetErr != nil {
 			return
 		}
@@ -1391,8 +1416,9 @@
 
 		targets[os] = append(targets[os],
 			Target{
-				Os:   os,
-				Arch: arch,
+				Os:           os,
+				Arch:         arch,
+				NativeBridge: nativeBridgeEnabled,
 			})
 	}
 
@@ -1400,14 +1426,14 @@
 		return nil, fmt.Errorf("No host primary architecture set")
 	}
 
-	addTarget(BuildOs, *variables.HostArch, nil, nil, nil)
+	addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled)
 
 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
-		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil)
+		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
 	}
 
 	if Bool(config.Host_bionic) {
-		addTarget(LinuxBionic, "x86_64", nil, nil, nil)
+		addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled)
 	}
 
 	if String(variables.CrossHost) != "" {
@@ -1420,10 +1446,10 @@
 			return nil, fmt.Errorf("No cross-host primary architecture set")
 		}
 
-		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil)
+		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil, NativeBridgeDisabled)
 
 		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
-			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil)
+			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
 		}
 	}
 
@@ -1434,18 +1460,32 @@
 		}
 
 		addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
-			variables.DeviceCpuVariant, variables.DeviceAbi)
+			variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled)
 
 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
 			addTarget(Android, *variables.DeviceSecondaryArch,
 				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
-				variables.DeviceSecondaryAbi)
+				variables.DeviceSecondaryAbi, NativeBridgeDisabled)
 
 			deviceArches := targets[Android]
 			if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
 				deviceArches[1].Arch.Native = false
 			}
 		}
+
+		if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
+			addTarget(Android, *variables.NativeBridgeArch,
+				variables.NativeBridgeArchVariant, variables.NativeBridgeCpuVariant,
+				variables.NativeBridgeAbi, NativeBridgeEnabled)
+		}
+
+		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
+			variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
+			addTarget(Android, *variables.NativeBridgeSecondaryArch,
+				variables.NativeBridgeSecondaryArchVariant,
+				variables.NativeBridgeSecondaryCpuVariant,
+				variables.NativeBridgeSecondaryAbi, NativeBridgeEnabled)
+		}
 	}
 
 	if targetErr != nil {
@@ -1465,10 +1505,10 @@
 	return false
 }
 
-// hasArmArch returns true if targets has at least arm Android arch
+// hasArmArch returns true if targets has at least non-native_bridge arm Android arch
 func hasArmAndroidArch(targets []Target) bool {
 	for _, target := range targets {
-		if target.Os == Android && target.Arch.ArchType == Arm {
+		if target.Os == Android && target.Arch.ArchType == Arm && target.NativeBridge == NativeBridgeDisabled {
 			return true
 		}
 	}
diff --git a/android/config.go b/android/config.go
index d1db87b..c0ed50f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -198,6 +198,14 @@
 
 // TestConfig returns a Config object suitable for using for tests
 func TestConfig(buildDir string, env map[string]string) Config {
+	envCopy := make(map[string]string)
+	for k, v := range env {
+		envCopy[k] = v
+	}
+
+	// Copy the real PATH value to the test environment, it's needed by HostSystemTool() used in x86_darwin_host.go
+	envCopy["PATH"] = originalEnv["PATH"]
+
 	config := &config{
 		productVariables: productVariables{
 			DeviceName:                  stringPtr("test_device"),
@@ -213,7 +221,7 @@
 
 		buildDir:     buildDir,
 		captureBuild: true,
-		env:          env,
+		env:          envCopy,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
@@ -227,16 +235,30 @@
 	return Config{config}
 }
 
+func TestArchConfigNativeBridge(buildDir string, env map[string]string) Config {
+	testConfig := TestArchConfig(buildDir, env)
+	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},
+	}
+
+	return testConfig
+}
+
 func TestArchConfigFuchsia(buildDir string, env map[string]string) Config {
 	testConfig := TestConfig(buildDir, env)
 	config := testConfig.config
 
 	config.Targets = map[OsType][]Target{
 		Fuchsia: []Target{
-			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}},
+			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}, NativeBridgeDisabled},
 		},
 		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}},
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
 		},
 	}
 
@@ -250,17 +272,25 @@
 
 	config.Targets = map[OsType][]Target{
 		Android: []Target{
-			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}},
-			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}},
+			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
+			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
 		},
 		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}},
-			{BuildOs, Arch{ArchType: X86}},
+			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
+			{BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
 		},
 	}
 
+	if runtime.GOOS == "darwin" {
+		config.Targets[BuildOs] = config.Targets[BuildOs][:1]
+	}
+
 	config.BuildOsVariant = config.Targets[BuildOs][0].String()
 	config.BuildOsCommonVariant = getCommonTargets(config.Targets[BuildOs])[0].String()
+	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
+	config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
+	config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
+	config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
 
 	return testConfig
 }
@@ -342,14 +372,14 @@
 }
 
 func (c *config) fromEnv() error {
-	switch c.Getenv("EXPERIMENTAL_USE_OPENJDK9") {
-	case "", "1.8":
-		// Nothing, we always use OpenJDK9
+	switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
+	case "":
+		// Nothing, this is the default
 	case "true":
-		// Use OpenJDK9 and target 1.9
+		// Use -source 9 -target 9
 		c.targetOpenJDK9 = true
 	default:
-		return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "1.8", or "true"`)
+		return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "" or "true"`)
 	}
 
 	return nil
@@ -406,6 +436,10 @@
 	return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
 }
 
+func (c *config) PrebuiltBuildTool(ctx PathContext, tool string) Path {
+	return PathForSource(ctx, "prebuilts/build-tools", c.PrebuiltOS(), "bin", tool)
+}
+
 func (c *config) CpPreserveSymlinksFlags() string {
 	switch runtime.GOOS {
 	case "darwin":
@@ -584,7 +618,7 @@
 	if defaultCert != "" {
 		return PathForSource(ctx, filepath.Dir(defaultCert))
 	} else {
-		return PathForSource(ctx, "build/target/product/security")
+		return PathForSource(ctx, "build/make/target/product/security")
 	}
 }
 
@@ -601,7 +635,7 @@
 func (c *config) ApexKeyDir(ctx ModuleContext) SourcePath {
 	// TODO(b/121224311): define another variable such as TARGET_APEX_KEY_OVERRIDE
 	defaultCert := String(c.productVariables.DefaultAppCertificate)
-	if defaultCert == "" || filepath.Dir(defaultCert) == "build/target/product/security" {
+	if defaultCert == "" || filepath.Dir(defaultCert) == "build/make/target/product/security" {
 		// When defaultCert is unset or is set to the testkeys path, use the APEX keys
 		// that is under the module dir
 		return pathForModuleSrc(ctx)
@@ -867,11 +901,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 {
@@ -921,6 +955,10 @@
 	return c.config.productVariables.BoardPlatPrivateSepolicyDirs
 }
 
+func (c *deviceConfig) SepolicyM4Defs() []string {
+	return c.config.productVariables.BoardSepolicyM4Defs
+}
+
 func (c *deviceConfig) OverrideManifestPackageNameFor(name string) (manifestName string, overridden bool) {
 	return findOverrideValue(c.config.productVariables.ManifestPackageNameOverrides, name,
 		"invalid override rule %q in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES should be <module_name>:<manifest_name>")
@@ -1053,3 +1091,39 @@
 func (c *deviceConfig) TargetFSConfigGen() []string {
 	return c.config.productVariables.TargetFSConfigGen
 }
+
+func (c *config) ProductPublicSepolicyDirs() []string {
+	return c.productVariables.ProductPublicSepolicyDirs
+}
+
+func (c *config) ProductPrivateSepolicyDirs() []string {
+	return c.productVariables.ProductPrivateSepolicyDirs
+}
+
+func (c *config) ProductCompatibleProperty() bool {
+	return Bool(c.productVariables.ProductCompatibleProperty)
+}
+
+func (c *config) MissingUsesLibraries() []string {
+	return c.productVariables.MissingUsesLibraries
+}
+
+func (c *deviceConfig) BoardVndkRuntimeDisable() bool {
+	return Bool(c.config.productVariables.BoardVndkRuntimeDisable)
+}
+
+func (c *deviceConfig) DeviceArch() string {
+	return String(c.config.productVariables.DeviceArch)
+}
+
+func (c *deviceConfig) DeviceArchVariant() string {
+	return String(c.config.productVariables.DeviceArchVariant)
+}
+
+func (c *deviceConfig) DeviceSecondaryArch() string {
+	return String(c.config.productVariables.DeviceSecondaryArch)
+}
+
+func (c *deviceConfig) DeviceSecondaryArchVariant() string {
+	return String(c.config.productVariables.DeviceSecondaryArchVariant)
+}
diff --git a/android/defaults.go b/android/defaults.go
index d4fbf48..ae2c820 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -63,9 +63,28 @@
 
 type DefaultsModuleBase struct {
 	DefaultableModuleBase
-	defaultProperties []interface{}
 }
 
+// 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
 	isDefaults() bool
@@ -80,6 +99,9 @@
 	return d.defaultableProperties
 }
 
+func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
 func InitDefaultsModule(module DefaultableModule) {
 	module.AddProperties(
 		&hostAndDeviceProperties{},
diff --git a/android/defaults_test.go b/android/defaults_test.go
new file mode 100644
index 0000000..fa26595
--- /dev/null
+++ b/android/defaults_test.go
@@ -0,0 +1,116 @@
+// 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 (
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+type defaultsTestProperties struct {
+	Foo []string
+}
+
+type defaultsTestModule struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties defaultsTestProperties
+}
+
+func (d *defaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	ctx.Build(pctx, BuildParams{
+		Rule:   Touch,
+		Output: PathForModuleOut(ctx, "out"),
+	})
+}
+
+func defaultsTestModuleFactory() Module {
+	module := &defaultsTestModule{}
+	module.AddProperties(&module.properties)
+	InitDefaultableModule(module)
+	InitAndroidModule(module)
+	return module
+}
+
+type defaultsTestDefaults struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func defaultsTestDefaultsFactory() Module {
+	defaults := &defaultsTestDefaults{}
+	defaults.AddProperties(&defaultsTestProperties{})
+	InitDefaultsModule(defaults)
+	return defaults
+}
+
+func TestDefaultsAllowMissingDependencies(t *testing.T) {
+	config := TestConfig(buildDir, nil)
+	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
+
+	ctx := NewTestContext()
+	ctx.SetAllowMissingDependencies(true)
+
+	ctx.RegisterModuleType("test", ModuleFactoryAdaptor(defaultsTestModuleFactory))
+	ctx.RegisterModuleType("defaults", ModuleFactoryAdaptor(defaultsTestDefaultsFactory))
+
+	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+
+	ctx.Register()
+
+	bp := `
+		defaults {
+			name: "defaults",
+			defaults: ["missing"],
+			foo: ["defaults"],
+		}
+
+		test {
+			name: "missing_defaults",
+			defaults: ["missing"],
+			foo: ["module"],
+		}
+
+		test {
+			name: "missing_transitive_defaults",
+			defaults: ["defaults"],
+			foo: ["module"],
+		}
+	`
+
+	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)
+
+	missingDefaults := ctx.ModuleForTests("missing_defaults", "").Output("out")
+	missingTransitiveDefaults := ctx.ModuleForTests("missing_transitive_defaults", "").Output("out")
+
+	if missingDefaults.Rule != ErrorRule {
+		t.Errorf("expected missing_defaults rule to be ErrorRule, got %#v", missingDefaults.Rule)
+	}
+
+	if g, w := missingDefaults.Args["error"], "module missing_defaults missing dependencies: missing\n"; g != w {
+		t.Errorf("want error %q, got %q", w, g)
+	}
+
+	// TODO: missing transitive defaults is currently not handled
+	_ = missingTransitiveDefaults
+}
diff --git a/android/env.go b/android/env.go
index 469dfff..d9f2db2 100644
--- a/android/env.go
+++ b/android/env.go
@@ -16,6 +16,7 @@
 
 import (
 	"os"
+	"os/exec"
 	"strings"
 
 	"android/soong/env"
@@ -29,8 +30,16 @@
 // a manifest regeneration.
 
 var originalEnv map[string]string
+var SoongDelveListen string
+var SoongDelvePath string
 
 func init() {
+	// Delve support needs to read this environment variable very early, before NewConfig has created a way to
+	// access originalEnv with dependencies.  Store the value where soong_build can find it, it will manually
+	// ensure the dependencies are created.
+	SoongDelveListen = os.Getenv("SOONG_DELVE")
+	SoongDelvePath, _ = exec.LookPath("dlv")
+
 	originalEnv = make(map[string]string)
 	for _, env := range os.Environ() {
 		idx := strings.IndexRune(env, '=')
@@ -38,6 +47,8 @@
 			originalEnv[env[:idx]] = env[idx+1:]
 		}
 	}
+	// Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment
+	// variable values.  The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc.
 	os.Clearenv()
 }
 
diff --git a/android/hooks.go b/android/hooks.go
index 6b2468d..5810996 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -27,7 +27,7 @@
 // been applied.
 type LoadHookContext interface {
 	// TODO: a new context that includes Config() but not Target(), etc.?
-	BaseContext
+	BaseModuleContext
 	AppendProperties(...interface{})
 	PrependProperties(...interface{})
 	CreateModule(blueprint.ModuleFactory, ...interface{})
@@ -36,7 +36,7 @@
 // Arch hooks are run after the module has been split into architecture variants, and can be used
 // to add architecture-specific properties.
 type ArchHookContext interface {
-	BaseContext
+	BaseModuleContext
 	AppendProperties(...interface{})
 	PrependProperties(...interface{})
 }
@@ -123,20 +123,26 @@
 	install []func(InstallHookContext)
 }
 
+func registerLoadHookMutator(ctx RegisterMutatorsContext) {
+	ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
+}
+
 func LoadHookMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(Module); ok {
-		// Cast through *androidTopDownMutatorContext because AppendProperties is implemented
-		// on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext
-		var loadHookCtx LoadHookContext = ctx.(*androidTopDownMutatorContext)
+		m.base().commonProperties.DebugName = ctx.ModuleName()
+
+		// Cast through *topDownMutatorContext because AppendProperties is implemented
+		// on *topDownMutatorContext but not exposed through TopDownMutatorContext
+		var loadHookCtx LoadHookContext = ctx.(*topDownMutatorContext)
 		m.base().hooks.runLoadHooks(loadHookCtx, m.base())
 	}
 }
 
 func archHookMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(Module); ok {
-		// Cast through *androidTopDownMutatorContext because AppendProperties is implemented
-		// on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext
-		var archHookCtx ArchHookContext = ctx.(*androidTopDownMutatorContext)
+		// Cast through *topDownMutatorContext because AppendProperties is implemented
+		// on *topDownMutatorContext but not exposed through TopDownMutatorContext
+		var archHookCtx ArchHookContext = ctx.(*topDownMutatorContext)
 		m.base().hooks.runArchHooks(archHookCtx, m.base())
 	}
 }
diff --git a/android/module.go b/android/module.go
index 6a79622..adb9454 100644
--- a/android/module.go
+++ b/android/module.go
@@ -18,7 +18,6 @@
 	"fmt"
 	"path"
 	"path/filepath"
-	"sort"
 	"strings"
 	"text/scanner"
 
@@ -56,7 +55,61 @@
 
 type ModuleBuildParams BuildParams
 
-type androidBaseContext interface {
+// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
+// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module
+// instead of a blueprint.Module, plus some extra methods that return Android-specific information
+// about the current module.
+type BaseModuleContext interface {
+	Module() Module
+	ModuleName() string
+	ModuleDir() string
+	ModuleType() string
+	Config() Config
+
+	OtherModuleName(m blueprint.Module) string
+	OtherModuleDir(m blueprint.Module) string
+	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
+	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+	OtherModuleExists(name string) bool
+
+	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
+	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+
+	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+	VisitDirectDeps(visit func(Module))
+	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
+	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
+	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
+	VisitDepsDepthFirst(visit func(Module))
+	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
+	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
+	WalkDeps(visit func(Module, Module) bool)
+	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
+	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency path from a start module to current child module.
+	GetWalkPath() []Module
+
+	ContainsProperty(name string) bool
+	Errorf(pos scanner.Position, fmt string, args ...interface{})
+	ModuleErrorf(fmt string, args ...interface{})
+	PropertyErrorf(property, fmt string, args ...interface{})
+	Failed() bool
+
+	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
+	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
+	// builder whenever a file matching the pattern as added or removed, without rerunning if a
+	// file that does not match the pattern is added to a searched directory.
+	GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+	Glob(globPattern string, excludes []string) Paths
+	GlobFiles(globPattern string, excludes []string) Paths
+
+	Fs() pathtools.FileSystem
+	AddNinjaFileDeps(deps ...string)
+
+	AddMissingDependencies(missingDeps []string)
+
 	Target() Target
 	TargetPrimary() bool
 	MultiTargets() []Target
@@ -73,42 +126,17 @@
 	DeviceSpecific() bool
 	SocSpecific() bool
 	ProductSpecific() bool
-	ProductServicesSpecific() bool
+	SystemExtSpecific() bool
 	AConfig() Config
 	DeviceConfig() DeviceConfig
 }
 
+// Deprecated: use BaseModuleContext instead
 type BaseContext interface {
 	BaseModuleContext
-	androidBaseContext
-}
-
-// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
-// a Config instead of an interface{}.
-type BaseModuleContext interface {
-	ModuleName() string
-	ModuleDir() string
-	ModuleType() string
-	Config() Config
-
-	ContainsProperty(name string) bool
-	Errorf(pos scanner.Position, fmt string, args ...interface{})
-	ModuleErrorf(fmt string, args ...interface{})
-	PropertyErrorf(property, fmt string, args ...interface{})
-	Failed() bool
-
-	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
-	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
-	// builder whenever a file matching the pattern as added or removed, without rerunning if a
-	// file that does not match the pattern is added to a searched directory.
-	GlobWithDeps(pattern string, excludes []string) ([]string, error)
-
-	Fs() pathtools.FileSystem
-	AddNinjaFileDeps(deps ...string)
 }
 
 type ModuleContext interface {
-	androidBaseContext
 	BaseModuleContext
 
 	// Deprecated: use ModuleContext.Build instead.
@@ -117,8 +145,6 @@
 	ExpandSources(srcFiles, excludes []string) Paths
 	ExpandSource(srcFile, prop string) Path
 	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
-	Glob(globPattern string, excludes []string) Paths
-	GlobFiles(globPattern string, excludes []string) Paths
 
 	InstallExecutable(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
 	InstallFile(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
@@ -126,37 +152,16 @@
 	InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath
 	CheckbuildFile(srcPath Path)
 
-	AddMissingDependencies(deps []string)
-
 	InstallInData() bool
 	InstallInSanitizerDir() bool
 	InstallInRecovery() bool
 
 	RequiredModuleNames() []string
-
-	// android.ModuleContext methods
-	// These are duplicated instead of embedded so that can eventually be wrapped to take an
-	// android.Module instead of a blueprint.Module
-	OtherModuleName(m blueprint.Module) string
-	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
-	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
-
-	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
-	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+	HostRequiredModuleNames() []string
+	TargetRequiredModuleNames() []string
 
 	ModuleSubDir() string
 
-	VisitDirectDepsBlueprint(visit func(blueprint.Module))
-	VisitDirectDeps(visit func(Module))
-	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
-	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
-	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
-	VisitDepsDepthFirst(visit func(Module))
-	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
-	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
-	WalkDeps(visit func(Module, Module) bool)
-	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
-
 	Variable(pctx PackageContext, name, value string)
 	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
 	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
@@ -197,6 +202,58 @@
 	BuildParamsForTests() []BuildParams
 	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
 	VariablesForTests() map[string]string
+
+	// String returns a string that includes the module name and variants for printing during debugging.
+	String() string
+
+	// Get the qualified module id for this module.
+	qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName
+
+	// Get information about the properties that can contain visibility rules.
+	visibilityProperties() []visibilityProperty
+}
+
+// Qualified id for a module
+type qualifiedModuleName struct {
+	// The package (i.e. directory) in which the module is defined, without trailing /
+	pkg string
+
+	// The name of the module, empty string if package.
+	name string
+}
+
+func (q qualifiedModuleName) String() string {
+	if q.name == "" {
+		return "//" + q.pkg
+	}
+	return "//" + q.pkg + ":" + q.name
+}
+
+func (q qualifiedModuleName) isRootPackage() bool {
+	return q.pkg == "" && q.name == ""
+}
+
+// Get the id for the package containing this module.
+func (q qualifiedModuleName) getContainingPackageId() qualifiedModuleName {
+	pkg := q.pkg
+	if q.name == "" {
+		if pkg == "" {
+			panic(fmt.Errorf("Cannot get containing package id of root package"))
+		}
+
+		index := strings.LastIndex(pkg, "/")
+		if index == -1 {
+			pkg = ""
+		} else {
+			pkg = pkg[:index]
+		}
+	}
+	return newPackageId(pkg)
+}
+
+func newPackageId(pkg string) qualifiedModuleName {
+	// A qualified id for a package module has no name.
+	return qualifiedModuleName{pkg: pkg, name: ""}
 }
 
 type nameProperties struct {
@@ -208,6 +265,47 @@
 	// emit build rules for this module
 	Enabled *bool `android:"arch_variant"`
 
+	// Controls the visibility of this module to other modules. Allowable values are one or more of
+	// these formats:
+	//
+	//  ["//visibility:public"]: Anyone can use this module.
+	//  ["//visibility:private"]: Only rules in the module's package (not its subpackages) can use
+	//      this module.
+	//  ["//some/package:__pkg__", "//other/package:__pkg__"]: Only modules in some/package and
+	//      other/package (defined in some/package/*.bp and other/package/*.bp) have access to
+	//      this module. Note that sub-packages do not have access to the rule; for example,
+	//      //some/package/foo:bar or //other/package/testing:bla wouldn't have access. __pkg__
+	//      is a special module and must be used verbatim. It represents all of the modules in the
+	//      package.
+	//  ["//project:__subpackages__", "//other:__subpackages__"]: Only modules in packages project
+	//      or other or in one of their sub-packages have access to this module. For example,
+	//      //project:rule, //project/library:lib or //other/testing/internal:munge are allowed
+	//      to depend on this rule (but not //independent:evil)
+	//  ["//project"]: This is shorthand for ["//project:__pkg__"]
+	//  [":__subpackages__"]: This is shorthand for ["//project:__subpackages__"] where
+	//      //project is the module's package. e.g. using [":__subpackages__"] in
+	//      packages/apps/Settings/Android.bp is equivalent to
+	//      //packages/apps/Settings:__subpackages__.
+	//  ["//visibility:legacy_public"]: The default visibility, behaves as //visibility:public
+	//      for now. It is an error if it is used in a module.
+	//
+	// If a module does not specify the `visibility` property then it uses the
+	// `default_visibility` property of the `package` module in the module's package.
+	//
+	// If a module does not specify the `visibility` property then it uses the
+	// `default_visibility` property of the `package` module in the module's package.
+	//
+	// If the `default_visibility` property is not set for the module's package then
+	// it will use the `default_visibility` of its closest ancestor package for which
+	// a `default_visibility` property is specified.
+	//
+	// If no `default_visibility` property can be found then the module uses the
+	// global default of `//visibility:legacy_public`.
+	//
+	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
+	// more details.
+	Visibility []string
+
 	// control whether this module compiles for 32-bit, 64-bit, or both.  Possible values
 	// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
 	// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
@@ -252,14 +350,21 @@
 	// /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
 
+	// Whether this module is built for non-native architecures (also known as native bridge binary)
+	Native_bridge_supported *bool `android:"arch_variant"`
+
 	// init.rc files to be installed if this module is installed
 	Init_rc []string `android:"path"`
 
@@ -269,6 +374,12 @@
 	// names of other modules to install if this module is installed
 	Required []string `android:"arch_variant"`
 
+	// names of other modules to install on host if this module is installed
+	Host_required []string `android:"arch_variant"`
+
+	// names of other modules to install on target if this module is installed
+	Target_required []string `android:"arch_variant"`
+
 	// relative path to a file to include in the list of notices for the device
 	Notice *string `android:"path"`
 
@@ -302,6 +413,13 @@
 	SkipInstall bool `blueprint:"mutated"`
 
 	NamespaceExportedToMake bool `blueprint:"mutated"`
+
+	MissingDeps []string `blueprint:"mutated"`
+
+	// Name and variant strings stored by mutators to enable Module.String()
+	DebugName       string   `blueprint:"mutated"`
+	DebugMutators   []string `blueprint:"mutated"`
+	DebugVariations []string `blueprint:"mutated"`
 }
 
 type hostAndDeviceProperties struct {
@@ -355,7 +473,7 @@
 	deviceSpecificModule
 	socSpecificModule
 	productSpecificModule
-	productServicesSpecificModule
+	systemExtSpecificModule
 )
 
 func (k moduleKind) String() string {
@@ -368,8 +486,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))
 	}
@@ -418,9 +536,9 @@
 // The ModuleBase type is responsible for implementing the GenerateBuildActions
 // method to support the blueprint.Module interface. This method will then call
 // the module's GenerateAndroidBuildActions method once for each build variant
-// that is to be built. GenerateAndroidBuildActions is passed a
-// AndroidModuleContext rather than the usual blueprint.ModuleContext.
-// AndroidModuleContext exposes extra functionality specific to the Android build
+// that is to be built. GenerateAndroidBuildActions is passed a ModuleContext
+// rather than the usual blueprint.ModuleContext.
+// ModuleContext exposes extra functionality specific to the Android build
 // system including details about the particular build variant that is to be
 // generated.
 //
@@ -487,83 +605,112 @@
 	prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
 }
 
-func (a *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
+func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
 
-func (a *ModuleBase) AddProperties(props ...interface{}) {
-	a.registerProps = append(a.registerProps, props...)
+func (m *ModuleBase) AddProperties(props ...interface{}) {
+	m.registerProps = append(m.registerProps, props...)
 }
 
-func (a *ModuleBase) GetProperties() []interface{} {
-	return a.registerProps
+func (m *ModuleBase) GetProperties() []interface{} {
+	return m.registerProps
 }
 
-func (a *ModuleBase) BuildParamsForTests() []BuildParams {
-	return a.buildParams
+func (m *ModuleBase) BuildParamsForTests() []BuildParams {
+	return m.buildParams
 }
 
-func (a *ModuleBase) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
-	return a.ruleParams
+func (m *ModuleBase) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
+	return m.ruleParams
 }
 
-func (a *ModuleBase) VariablesForTests() map[string]string {
-	return a.variables
+func (m *ModuleBase) VariablesForTests() map[string]string {
+	return m.variables
 }
 
-func (a *ModuleBase) Prefer32(prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool) {
-	a.prefer32 = prefer32
+func (m *ModuleBase) Prefer32(prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool) {
+	m.prefer32 = prefer32
 }
 
 // Name returns the name of the module.  It may be overridden by individual module types, for
 // example prebuilts will prepend prebuilt_ to the name.
-func (a *ModuleBase) Name() string {
-	return String(a.nameProperties.Name)
+func (m *ModuleBase) Name() string {
+	return String(m.nameProperties.Name)
+}
+
+// String returns a string that includes the module name and variants for printing during debugging.
+func (m *ModuleBase) String() string {
+	sb := strings.Builder{}
+	sb.WriteString(m.commonProperties.DebugName)
+	sb.WriteString("{")
+	for i := range m.commonProperties.DebugMutators {
+		if i != 0 {
+			sb.WriteString(",")
+		}
+		sb.WriteString(m.commonProperties.DebugMutators[i])
+		sb.WriteString(":")
+		sb.WriteString(m.commonProperties.DebugVariations[i])
+	}
+	sb.WriteString("}")
+	return sb.String()
 }
 
 // BaseModuleName returns the name of the module as specified in the blueprints file.
-func (a *ModuleBase) BaseModuleName() string {
-	return String(a.nameProperties.Name)
+func (m *ModuleBase) BaseModuleName() string {
+	return String(m.nameProperties.Name)
 }
 
-func (a *ModuleBase) base() *ModuleBase {
-	return a
+func (m *ModuleBase) base() *ModuleBase {
+	return m
 }
 
-func (a *ModuleBase) SetTarget(target Target, multiTargets []Target, primary bool) {
-	a.commonProperties.CompileTarget = target
-	a.commonProperties.CompileMultiTargets = multiTargets
-	a.commonProperties.CompilePrimary = primary
+func (m *ModuleBase) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
+	return qualifiedModuleName{pkg: ctx.ModuleDir(), name: ctx.ModuleName()}
 }
 
-func (a *ModuleBase) Target() Target {
-	return a.commonProperties.CompileTarget
+func (m *ModuleBase) visibilityProperties() []visibilityProperty {
+	return []visibilityProperty{
+		newVisibilityProperty("visibility", func() []string {
+			return m.base().commonProperties.Visibility
+		}),
+	}
 }
 
-func (a *ModuleBase) TargetPrimary() bool {
-	return a.commonProperties.CompilePrimary
+func (m *ModuleBase) SetTarget(target Target, multiTargets []Target, primary bool) {
+	m.commonProperties.CompileTarget = target
+	m.commonProperties.CompileMultiTargets = multiTargets
+	m.commonProperties.CompilePrimary = primary
 }
 
-func (a *ModuleBase) MultiTargets() []Target {
-	return a.commonProperties.CompileMultiTargets
+func (m *ModuleBase) Target() Target {
+	return m.commonProperties.CompileTarget
 }
 
-func (a *ModuleBase) Os() OsType {
-	return a.Target().Os
+func (m *ModuleBase) TargetPrimary() bool {
+	return m.commonProperties.CompilePrimary
 }
 
-func (a *ModuleBase) Host() bool {
-	return a.Os().Class == Host || a.Os().Class == HostCross
+func (m *ModuleBase) MultiTargets() []Target {
+	return m.commonProperties.CompileMultiTargets
 }
 
-func (a *ModuleBase) Arch() Arch {
-	return a.Target().Arch
+func (m *ModuleBase) Os() OsType {
+	return m.Target().Os
 }
 
-func (a *ModuleBase) ArchSpecific() bool {
-	return a.commonProperties.ArchSpecific
+func (m *ModuleBase) Host() bool {
+	return m.Os().Class == Host || m.Os().Class == HostCross
 }
 
-func (a *ModuleBase) OsClassSupported() []OsClass {
-	switch a.commonProperties.HostOrDeviceSupported {
+func (m *ModuleBase) Arch() Arch {
+	return m.Target().Arch
+}
+
+func (m *ModuleBase) ArchSpecific() bool {
+	return m.commonProperties.ArchSpecific
+}
+
+func (m *ModuleBase) OsClassSupported() []OsClass {
+	switch m.commonProperties.HostOrDeviceSupported {
 	case HostSupported:
 		return []OsClass{Host, HostCross}
 	case HostSupportedNoCross:
@@ -572,13 +719,13 @@
 		return []OsClass{Device}
 	case HostAndDeviceSupported, HostAndDeviceDefault:
 		var supported []OsClass
-		if Bool(a.hostAndDeviceProperties.Host_supported) ||
-			(a.commonProperties.HostOrDeviceSupported == HostAndDeviceDefault &&
-				a.hostAndDeviceProperties.Host_supported == nil) {
+		if Bool(m.hostAndDeviceProperties.Host_supported) ||
+			(m.commonProperties.HostOrDeviceSupported == HostAndDeviceDefault &&
+				m.hostAndDeviceProperties.Host_supported == nil) {
 			supported = append(supported, Host, HostCross)
 		}
-		if a.hostAndDeviceProperties.Device_supported == nil ||
-			*a.hostAndDeviceProperties.Device_supported {
+		if m.hostAndDeviceProperties.Device_supported == nil ||
+			*m.hostAndDeviceProperties.Device_supported {
 			supported = append(supported, Device)
 		}
 		return supported
@@ -587,49 +734,49 @@
 	}
 }
 
-func (a *ModuleBase) DeviceSupported() bool {
-	return a.commonProperties.HostOrDeviceSupported == DeviceSupported ||
-		a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
-			(a.hostAndDeviceProperties.Device_supported == nil ||
-				*a.hostAndDeviceProperties.Device_supported)
+func (m *ModuleBase) DeviceSupported() bool {
+	return m.commonProperties.HostOrDeviceSupported == DeviceSupported ||
+		m.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
+			(m.hostAndDeviceProperties.Device_supported == nil ||
+				*m.hostAndDeviceProperties.Device_supported)
 }
 
-func (a *ModuleBase) Platform() bool {
-	return !a.DeviceSpecific() && !a.SocSpecific() && !a.ProductSpecific() && !a.ProductServicesSpecific()
+func (m *ModuleBase) Platform() bool {
+	return !m.DeviceSpecific() && !m.SocSpecific() && !m.ProductSpecific() && !m.SystemExtSpecific()
 }
 
-func (a *ModuleBase) DeviceSpecific() bool {
-	return Bool(a.commonProperties.Device_specific)
+func (m *ModuleBase) DeviceSpecific() bool {
+	return Bool(m.commonProperties.Device_specific)
 }
 
-func (a *ModuleBase) SocSpecific() bool {
-	return Bool(a.commonProperties.Vendor) || Bool(a.commonProperties.Proprietary) || Bool(a.commonProperties.Soc_specific)
+func (m *ModuleBase) SocSpecific() bool {
+	return Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific)
 }
 
-func (a *ModuleBase) ProductSpecific() bool {
-	return Bool(a.commonProperties.Product_specific)
+func (m *ModuleBase) ProductSpecific() bool {
+	return Bool(m.commonProperties.Product_specific)
 }
 
-func (a *ModuleBase) ProductServicesSpecific() bool {
-	return Bool(a.commonProperties.Product_services_specific)
+func (m *ModuleBase) SystemExtSpecific() bool {
+	return Bool(m.commonProperties.System_ext_specific)
 }
 
-func (a *ModuleBase) Enabled() bool {
-	if a.commonProperties.Enabled == nil {
-		return !a.Os().DefaultDisabled
+func (m *ModuleBase) Enabled() bool {
+	if m.commonProperties.Enabled == nil {
+		return !m.Os().DefaultDisabled
 	}
-	return *a.commonProperties.Enabled
+	return *m.commonProperties.Enabled
 }
 
-func (a *ModuleBase) SkipInstall() {
-	a.commonProperties.SkipInstall = true
+func (m *ModuleBase) SkipInstall() {
+	m.commonProperties.SkipInstall = true
 }
 
-func (a *ModuleBase) ExportedToMake() bool {
-	return a.commonProperties.NamespaceExportedToMake
+func (m *ModuleBase) ExportedToMake() bool {
+	return m.commonProperties.NamespaceExportedToMake
 }
 
-func (a *ModuleBase) computeInstallDeps(
+func (m *ModuleBase) computeInstallDeps(
 	ctx blueprint.ModuleContext) Paths {
 
 	result := Paths{}
@@ -644,35 +791,35 @@
 	return result
 }
 
-func (a *ModuleBase) filesToInstall() Paths {
-	return a.installFiles
+func (m *ModuleBase) filesToInstall() Paths {
+	return m.installFiles
 }
 
-func (p *ModuleBase) NoAddressSanitizer() bool {
-	return p.noAddressSanitizer
+func (m *ModuleBase) NoAddressSanitizer() bool {
+	return m.noAddressSanitizer
 }
 
-func (p *ModuleBase) InstallInData() bool {
+func (m *ModuleBase) InstallInData() bool {
 	return false
 }
 
-func (p *ModuleBase) InstallInSanitizerDir() bool {
+func (m *ModuleBase) InstallInSanitizerDir() bool {
 	return false
 }
 
-func (p *ModuleBase) InstallInRecovery() bool {
-	return Bool(p.commonProperties.Recovery)
+func (m *ModuleBase) InstallInRecovery() bool {
+	return Bool(m.commonProperties.Recovery)
 }
 
-func (a *ModuleBase) Owner() string {
-	return String(a.commonProperties.Owner)
+func (m *ModuleBase) Owner() string {
+	return String(m.commonProperties.Owner)
 }
 
-func (a *ModuleBase) NoticeFile() OptionalPath {
-	return a.noticeFile
+func (m *ModuleBase) NoticeFile() OptionalPath {
+	return m.noticeFile
 }
 
-func (a *ModuleBase) generateModuleTarget(ctx ModuleContext) {
+func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
 	allInstalledFiles := Paths{}
 	allCheckbuildFiles := Paths{}
 	ctx.VisitAllModuleVariants(func(module Module) {
@@ -697,7 +844,7 @@
 			Default:   !ctx.Config().EmbeddedInMake(),
 		})
 		deps = append(deps, name)
-		a.installTarget = name
+		m.installTarget = name
 	}
 
 	if len(allCheckbuildFiles) > 0 {
@@ -708,7 +855,7 @@
 			Implicits: allCheckbuildFiles,
 		})
 		deps = append(deps, name)
-		a.checkbuildTarget = name
+		m.checkbuildTarget = name
 	}
 
 	if len(deps) > 0 {
@@ -724,51 +871,51 @@
 			Implicits: deps,
 		})
 
-		a.blueprintDir = ctx.ModuleDir()
+		m.blueprintDir = ctx.ModuleDir()
 	}
 }
 
-func determineModuleKind(a *ModuleBase, ctx blueprint.BaseModuleContext) moduleKind {
-	var socSpecific = Bool(a.commonProperties.Vendor) || Bool(a.commonProperties.Proprietary) || Bool(a.commonProperties.Soc_specific)
-	var deviceSpecific = Bool(a.commonProperties.Device_specific)
-	var productSpecific = Bool(a.commonProperties.Product_specific)
-	var productServicesSpecific = Bool(a.commonProperties.Product_services_specific)
+func determineModuleKind(m *ModuleBase, ctx blueprint.BaseModuleContext) moduleKind {
+	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 systemExtSpecific = Bool(m.commonProperties.System_ext_specific)
 
 	msg := "conflicting value set here"
 	if socSpecific && deviceSpecific {
 		ctx.PropertyErrorf("device_specific", "a module cannot be specific to SoC and device at the same time.")
-		if Bool(a.commonProperties.Vendor) {
+		if Bool(m.commonProperties.Vendor) {
 			ctx.PropertyErrorf("vendor", msg)
 		}
-		if Bool(a.commonProperties.Proprietary) {
+		if Bool(m.commonProperties.Proprietary) {
 			ctx.PropertyErrorf("proprietary", msg)
 		}
-		if Bool(a.commonProperties.Soc_specific) {
+		if Bool(m.commonProperties.Soc_specific) {
 			ctx.PropertyErrorf("soc_specific", msg)
 		}
 	}
 
-	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)
 		} else {
-			if Bool(a.commonProperties.Vendor) {
+			if Bool(m.commonProperties.Vendor) {
 				ctx.PropertyErrorf("vendor", msg)
 			}
-			if Bool(a.commonProperties.Proprietary) {
+			if Bool(m.commonProperties.Proprietary) {
 				ctx.PropertyErrorf("proprietary", msg)
 			}
-			if Bool(a.commonProperties.Soc_specific) {
+			if Bool(m.commonProperties.Soc_specific) {
 				ctx.PropertyErrorf("soc_specific", msg)
 			}
 		}
@@ -776,8 +923,8 @@
 
 	if productSpecific {
 		return productSpecificModule
-	} else if productServicesSpecific {
-		return productServicesSpecificModule
+	} else if systemExtSpecific {
+		return systemExtSpecificModule
 	} else if deviceSpecific {
 		return deviceSpecificModule
 	} else if socSpecific {
@@ -787,27 +934,36 @@
 	}
 }
 
-func (a *ModuleBase) androidBaseContextFactory(ctx blueprint.BaseModuleContext) androidBaseContextImpl {
-	return androidBaseContextImpl{
-		target:        a.commonProperties.CompileTarget,
-		targetPrimary: a.commonProperties.CompilePrimary,
-		multiTargets:  a.commonProperties.CompileMultiTargets,
-		kind:          determineModuleKind(a, ctx),
-		config:        ctx.Config().(Config),
+func (m *ModuleBase) baseModuleContextFactory(ctx blueprint.BaseModuleContext) baseModuleContext {
+	return baseModuleContext{
+		BaseModuleContext: ctx,
+		target:            m.commonProperties.CompileTarget,
+		targetPrimary:     m.commonProperties.CompilePrimary,
+		multiTargets:      m.commonProperties.CompileMultiTargets,
+		kind:              determineModuleKind(m, ctx),
+		config:            ctx.Config().(Config),
 	}
 }
 
-func (a *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
-	ctx := &androidModuleContext{
-		module:                 a.module,
-		ModuleContext:          blueprintCtx,
-		androidBaseContextImpl: a.androidBaseContextFactory(blueprintCtx),
-		installDeps:            a.computeInstallDeps(blueprintCtx),
-		installFiles:           a.installFiles,
-		missingDeps:            blueprintCtx.GetMissingDependencies(),
-		variables:              make(map[string]string),
+func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
+	ctx := &moduleContext{
+		module:            m.module,
+		bp:                blueprintCtx,
+		baseModuleContext: m.baseModuleContextFactory(blueprintCtx),
+		installDeps:       m.computeInstallDeps(blueprintCtx),
+		installFiles:      m.installFiles,
+		variables:         make(map[string]string),
 	}
 
+	// Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never
+	// reporting missing dependency errors in Blueprint when AllowMissingDependencies == true.
+	// TODO: This will be removed once defaults modules handle missing dependency errors
+	blueprintCtx.GetMissingDependencies()
+
+	// For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and
+	// are enabled.
+	ctx.baseModuleContext.strictVisitDeps = true
+
 	if ctx.config.captureBuild {
 		ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
 	}
@@ -830,70 +986,80 @@
 	ctx.Variable(pctx, "moduleDescSuffix", s)
 
 	// Some common property checks for properties that will be used later in androidmk.go
-	if a.commonProperties.Dist.Dest != nil {
-		_, err := validateSafePath(*a.commonProperties.Dist.Dest)
+	if m.commonProperties.Dist.Dest != nil {
+		_, err := validateSafePath(*m.commonProperties.Dist.Dest)
 		if err != nil {
 			ctx.PropertyErrorf("dist.dest", "%s", err.Error())
 		}
 	}
-	if a.commonProperties.Dist.Dir != nil {
-		_, err := validateSafePath(*a.commonProperties.Dist.Dir)
+	if m.commonProperties.Dist.Dir != nil {
+		_, err := validateSafePath(*m.commonProperties.Dist.Dir)
 		if err != nil {
 			ctx.PropertyErrorf("dist.dir", "%s", err.Error())
 		}
 	}
-	if a.commonProperties.Dist.Suffix != nil {
-		if strings.Contains(*a.commonProperties.Dist.Suffix, "/") {
+	if m.commonProperties.Dist.Suffix != nil {
+		if strings.Contains(*m.commonProperties.Dist.Suffix, "/") {
 			ctx.PropertyErrorf("dist.suffix", "Suffix may not contain a '/' character.")
 		}
 	}
 
-	if a.Enabled() {
-		notice := proptools.StringDefault(a.commonProperties.Notice, "NOTICE")
-		if m := SrcIsModule(notice); m != "" {
-			a.noticeFile = ctx.ExpandOptionalSource(&notice, "notice")
+	if m.Enabled() {
+		notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
+		if module := SrcIsModule(notice); module != "" {
+			m.noticeFile = ctx.ExpandOptionalSource(&notice, "notice")
 		} else {
 			noticePath := filepath.Join(ctx.ModuleDir(), notice)
-			a.noticeFile = ExistentPathForSource(ctx, noticePath)
+			m.noticeFile = ExistentPathForSource(ctx, noticePath)
 		}
 
-		a.module.GenerateAndroidBuildActions(ctx)
+		m.module.GenerateAndroidBuildActions(ctx)
 		if ctx.Failed() {
 			return
 		}
 
-		a.installFiles = append(a.installFiles, ctx.installFiles...)
-		a.checkbuildFiles = append(a.checkbuildFiles, ctx.checkbuildFiles...)
+		m.installFiles = append(m.installFiles, ctx.installFiles...)
+		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
+	} else if ctx.Config().AllowMissingDependencies() {
+		// If the module is not enabled it will not create any build rules, nothing will call
+		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
+		// and report them as an error even when AllowMissingDependencies = true.  Call
+		// ctx.GetMissingDependencies() here to tell blueprint not to handle them.
+		ctx.GetMissingDependencies()
 	}
 
-	if a == ctx.FinalModule().(Module).base() {
-		a.generateModuleTarget(ctx)
+	if m == ctx.FinalModule().(Module).base() {
+		m.generateModuleTarget(ctx)
 		if ctx.Failed() {
 			return
 		}
 	}
 
-	a.buildParams = ctx.buildParams
-	a.ruleParams = ctx.ruleParams
-	a.variables = ctx.variables
+	m.buildParams = ctx.buildParams
+	m.ruleParams = ctx.ruleParams
+	m.variables = ctx.variables
 }
 
-type androidBaseContextImpl struct {
+type baseModuleContext struct {
+	blueprint.BaseModuleContext
 	target        Target
 	multiTargets  []Target
 	targetPrimary bool
 	debug         bool
 	kind          moduleKind
 	config        Config
+
+	walkPath []Module
+
+	strictVisitDeps bool // If true, enforce that all dependencies are enabled
 }
 
-type androidModuleContext struct {
-	blueprint.ModuleContext
-	androidBaseContextImpl
+type moduleContext struct {
+	bp blueprint.ModuleContext
+	baseModuleContext
 	installDeps     Paths
 	installFiles    Paths
 	checkbuildFiles Paths
-	missingDeps     []string
 	module          Module
 
 	// For tests
@@ -902,25 +1068,22 @@
 	variables   map[string]string
 }
 
-func (a *androidModuleContext) ninjaError(desc string, outputs []string, err error) {
-	a.ModuleContext.Build(pctx.PackageContext, blueprint.BuildParams{
-		Rule:        ErrorRule,
-		Description: desc,
-		Outputs:     outputs,
-		Optional:    true,
+func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
+	return pctx, BuildParams{
+		Rule:            ErrorRule,
+		Description:     params.Description,
+		Output:          params.Output,
+		Outputs:         params.Outputs,
+		ImplicitOutput:  params.ImplicitOutput,
+		ImplicitOutputs: params.ImplicitOutputs,
 		Args: map[string]string{
 			"error": err.Error(),
 		},
-	})
-	return
+	}
 }
 
-func (a *androidModuleContext) Config() Config {
-	return a.ModuleContext.Config().(Config)
-}
-
-func (a *androidModuleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
-	a.Build(pctx, BuildParams(params))
+func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
+	m.Build(pctx, BuildParams(params))
 }
 
 func convertBuildParams(params BuildParams) blueprint.BuildParams {
@@ -963,86 +1126,100 @@
 	return bparams
 }
 
-func (a *androidModuleContext) Variable(pctx PackageContext, name, value string) {
-	if a.config.captureBuild {
-		a.variables[name] = value
+func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
+	if m.config.captureBuild {
+		m.variables[name] = value
 	}
 
-	a.ModuleContext.Variable(pctx.PackageContext, name, value)
+	m.bp.Variable(pctx.PackageContext, name, value)
 }
 
-func (a *androidModuleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
+func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
 
-	rule := a.ModuleContext.Rule(pctx.PackageContext, name, params, argNames...)
+	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
 
-	if a.config.captureBuild {
-		a.ruleParams[rule] = params
+	if m.config.captureBuild {
+		m.ruleParams[rule] = params
 	}
 
 	return rule
 }
 
-func (a *androidModuleContext) Build(pctx PackageContext, params BuildParams) {
-	if a.config.captureBuild {
-		a.buildParams = append(a.buildParams, params)
+func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
+	if params.Description != "" {
+		params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
 	}
 
-	bparams := convertBuildParams(params)
-
-	if bparams.Description != "" {
-		bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
+	if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
+		pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
+			m.ModuleName(), strings.Join(missingDeps, ", ")))
 	}
 
-	if a.missingDeps != nil {
-		a.ninjaError(bparams.Description, bparams.Outputs,
-			fmt.Errorf("module %s missing dependencies: %s\n",
-				a.ModuleName(), strings.Join(a.missingDeps, ", ")))
-		return
+	if m.config.captureBuild {
+		m.buildParams = append(m.buildParams, params)
 	}
 
-	a.ModuleContext.Build(pctx.PackageContext, bparams)
+	m.bp.Build(pctx.PackageContext, convertBuildParams(params))
 }
 
-func (a *androidModuleContext) GetMissingDependencies() []string {
-	return a.missingDeps
+func (b *baseModuleContext) Module() Module {
+	module, _ := b.BaseModuleContext.Module().(Module)
+	return module
 }
 
-func (a *androidModuleContext) AddMissingDependencies(deps []string) {
+func (b *baseModuleContext) Config() Config {
+	return b.BaseModuleContext.Config().(Config)
+}
+
+func (m *moduleContext) GetMissingDependencies() []string {
+	var missingDeps []string
+	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
+	missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
+	missingDeps = FirstUniqueStrings(missingDeps)
+	return missingDeps
+}
+
+func (b *baseModuleContext) AddMissingDependencies(deps []string) {
 	if deps != nil {
-		a.missingDeps = append(a.missingDeps, deps...)
-		a.missingDeps = FirstUniqueStrings(a.missingDeps)
+		missingDeps := &b.Module().base().commonProperties.MissingDeps
+		*missingDeps = append(*missingDeps, deps...)
+		*missingDeps = FirstUniqueStrings(*missingDeps)
 	}
 }
 
-func (a *androidModuleContext) validateAndroidModule(module blueprint.Module) Module {
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, strict bool) Module {
 	aModule, _ := module.(Module)
+
+	if !strict {
+		return aModule
+	}
+
 	if aModule == nil {
-		a.ModuleErrorf("module %q not an android module", a.OtherModuleName(aModule))
+		b.ModuleErrorf("module %q not an android module", b.OtherModuleName(module))
 		return nil
 	}
 
 	if !aModule.Enabled() {
-		if a.Config().AllowMissingDependencies() {
-			a.AddMissingDependencies([]string{a.OtherModuleName(aModule)})
+		if b.Config().AllowMissingDependencies() {
+			b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
 		} else {
-			a.ModuleErrorf("depends on disabled module %q", a.OtherModuleName(aModule))
+			b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
 		}
 		return nil
 	}
-
 	return aModule
 }
 
-func (a *androidModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
+func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
 	type dep struct {
 		mod blueprint.Module
 		tag blueprint.DependencyTag
 	}
 	var deps []dep
-	a.VisitDirectDepsBlueprint(func(m blueprint.Module) {
-		if aModule, _ := m.(Module); aModule != nil && aModule.base().BaseModuleName() == name {
-			returnedTag := a.ModuleContext.OtherModuleDependencyTag(aModule)
+	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		if aModule, _ := module.(Module); aModule != nil && aModule.base().BaseModuleName() == name {
+			returnedTag := b.BaseModuleContext.OtherModuleDependencyTag(aModule)
 			if tag == nil || returnedTag == tag {
 				deps = append(deps, dep{aModule, returnedTag})
 			}
@@ -1052,48 +1229,60 @@
 		return deps[0].mod, deps[0].tag
 	} else if len(deps) >= 2 {
 		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
-			name, a.ModuleName()))
+			name, b.ModuleName()))
 	} else {
 		return nil, nil
 	}
 }
 
-func (a *androidModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
-	m, _ := a.getDirectDepInternal(name, tag)
-	return m
+func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
+	var deps []Module
+	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		if aModule, _ := module.(Module); aModule != nil {
+			if b.BaseModuleContext.OtherModuleDependencyTag(aModule) == tag {
+				deps = append(deps, aModule)
+			}
+		}
+	})
+	return deps
 }
 
-func (a *androidModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
-	return a.getDirectDepInternal(name, nil)
+func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
+	module, _ := m.getDirectDepInternal(name, tag)
+	return module
 }
 
-func (a *androidModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
-	a.ModuleContext.VisitDirectDeps(visit)
+func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
+	return b.getDirectDepInternal(name, nil)
 }
 
-func (a *androidModuleContext) VisitDirectDeps(visit func(Module)) {
-	a.ModuleContext.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := a.validateAndroidModule(module); aModule != nil {
+func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
+	b.BaseModuleContext.VisitDirectDeps(visit)
+}
+
+func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
+	b.BaseModuleContext.VisitDirectDeps(func(module blueprint.Module) {
+		if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
 			visit(aModule)
 		}
 	})
 }
 
-func (a *androidModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
-	a.ModuleContext.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := a.validateAndroidModule(module); aModule != nil {
-			if a.ModuleContext.OtherModuleDependencyTag(aModule) == tag {
+func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
+	b.BaseModuleContext.VisitDirectDeps(func(module blueprint.Module) {
+		if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+			if b.BaseModuleContext.OtherModuleDependencyTag(aModule) == tag {
 				visit(aModule)
 			}
 		}
 	})
 }
 
-func (a *androidModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
-	a.ModuleContext.VisitDirectDepsIf(
+func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
+	b.BaseModuleContext.VisitDirectDepsIf(
 		// pred
 		func(module blueprint.Module) bool {
-			if aModule := a.validateAndroidModule(module); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
 				return pred(aModule)
 			} else {
 				return false
@@ -1105,19 +1294,19 @@
 		})
 }
 
-func (a *androidModuleContext) VisitDepsDepthFirst(visit func(Module)) {
-	a.ModuleContext.VisitDepsDepthFirst(func(module blueprint.Module) {
-		if aModule := a.validateAndroidModule(module); aModule != nil {
+func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
+	b.BaseModuleContext.VisitDepsDepthFirst(func(module blueprint.Module) {
+		if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
 			visit(aModule)
 		}
 	})
 }
 
-func (a *androidModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
-	a.ModuleContext.VisitDepsDepthFirstIf(
+func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
+	b.BaseModuleContext.VisitDepsDepthFirstIf(
 		// pred
 		func(module blueprint.Module) bool {
-			if aModule := a.validateAndroidModule(module); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
 				return pred(aModule)
 			} else {
 				return false
@@ -1129,15 +1318,21 @@
 		})
 }
 
-func (a *androidModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
-	a.ModuleContext.WalkDeps(visit)
+func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
+	b.BaseModuleContext.WalkDeps(visit)
 }
 
-func (a *androidModuleContext) WalkDeps(visit func(Module, Module) bool) {
-	a.ModuleContext.WalkDeps(func(child, parent blueprint.Module) bool {
-		childAndroidModule := a.validateAndroidModule(child)
-		parentAndroidModule := a.validateAndroidModule(parent)
+func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
+	b.walkPath = []Module{b.Module()}
+	b.BaseModuleContext.WalkDeps(func(child, parent blueprint.Module) bool {
+		childAndroidModule, _ := child.(Module)
+		parentAndroidModule, _ := parent.(Module)
 		if childAndroidModule != nil && parentAndroidModule != nil {
+			// record walkPath before visit
+			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
+				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+			}
+			b.walkPath = append(b.walkPath, childAndroidModule)
 			return visit(childAndroidModule, parentAndroidModule)
 		} else {
 			return false
@@ -1145,139 +1340,151 @@
 	})
 }
 
-func (a *androidModuleContext) VisitAllModuleVariants(visit func(Module)) {
-	a.ModuleContext.VisitAllModuleVariants(func(module blueprint.Module) {
+func (b *baseModuleContext) GetWalkPath() []Module {
+	return b.walkPath
+}
+
+func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
+	m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
 		visit(module.(Module))
 	})
 }
 
-func (a *androidModuleContext) PrimaryModule() Module {
-	return a.ModuleContext.PrimaryModule().(Module)
+func (m *moduleContext) PrimaryModule() Module {
+	return m.bp.PrimaryModule().(Module)
 }
 
-func (a *androidModuleContext) FinalModule() Module {
-	return a.ModuleContext.FinalModule().(Module)
+func (m *moduleContext) FinalModule() Module {
+	return m.bp.FinalModule().(Module)
 }
 
-func (a *androidBaseContextImpl) Target() Target {
-	return a.target
+func (m *moduleContext) ModuleSubDir() string {
+	return m.bp.ModuleSubDir()
 }
 
-func (a *androidBaseContextImpl) TargetPrimary() bool {
-	return a.targetPrimary
+func (b *baseModuleContext) Target() Target {
+	return b.target
 }
 
-func (a *androidBaseContextImpl) MultiTargets() []Target {
-	return a.multiTargets
+func (b *baseModuleContext) TargetPrimary() bool {
+	return b.targetPrimary
 }
 
-func (a *androidBaseContextImpl) Arch() Arch {
-	return a.target.Arch
+func (b *baseModuleContext) MultiTargets() []Target {
+	return b.multiTargets
 }
 
-func (a *androidBaseContextImpl) Os() OsType {
-	return a.target.Os
+func (b *baseModuleContext) Arch() Arch {
+	return b.target.Arch
 }
 
-func (a *androidBaseContextImpl) Host() bool {
-	return a.target.Os.Class == Host || a.target.Os.Class == HostCross
+func (b *baseModuleContext) Os() OsType {
+	return b.target.Os
 }
 
-func (a *androidBaseContextImpl) Device() bool {
-	return a.target.Os.Class == Device
+func (b *baseModuleContext) Host() bool {
+	return b.target.Os.Class == Host || b.target.Os.Class == HostCross
 }
 
-func (a *androidBaseContextImpl) Darwin() bool {
-	return a.target.Os == Darwin
+func (b *baseModuleContext) Device() bool {
+	return b.target.Os.Class == Device
 }
 
-func (a *androidBaseContextImpl) Fuchsia() bool {
-	return a.target.Os == Fuchsia
+func (b *baseModuleContext) Darwin() bool {
+	return b.target.Os == Darwin
 }
 
-func (a *androidBaseContextImpl) Windows() bool {
-	return a.target.Os == Windows
+func (b *baseModuleContext) Fuchsia() bool {
+	return b.target.Os == Fuchsia
 }
 
-func (a *androidBaseContextImpl) Debug() bool {
-	return a.debug
+func (b *baseModuleContext) Windows() bool {
+	return b.target.Os == Windows
 }
 
-func (a *androidBaseContextImpl) PrimaryArch() bool {
-	if len(a.config.Targets[a.target.Os]) <= 1 {
+func (b *baseModuleContext) Debug() bool {
+	return b.debug
+}
+
+func (b *baseModuleContext) PrimaryArch() bool {
+	if len(b.config.Targets[b.target.Os]) <= 1 {
 		return true
 	}
-	return a.target.Arch.ArchType == a.config.Targets[a.target.Os][0].Arch.ArchType
+	return b.target.Arch.ArchType == b.config.Targets[b.target.Os][0].Arch.ArchType
 }
 
-func (a *androidBaseContextImpl) AConfig() Config {
-	return a.config
+func (b *baseModuleContext) AConfig() Config {
+	return b.config
 }
 
-func (a *androidBaseContextImpl) DeviceConfig() DeviceConfig {
-	return DeviceConfig{a.config.deviceConfig}
+func (b *baseModuleContext) DeviceConfig() DeviceConfig {
+	return DeviceConfig{b.config.deviceConfig}
 }
 
-func (a *androidBaseContextImpl) Platform() bool {
-	return a.kind == platformModule
+func (b *baseModuleContext) Platform() bool {
+	return b.kind == platformModule
 }
 
-func (a *androidBaseContextImpl) DeviceSpecific() bool {
-	return a.kind == deviceSpecificModule
+func (b *baseModuleContext) DeviceSpecific() bool {
+	return b.kind == deviceSpecificModule
 }
 
-func (a *androidBaseContextImpl) SocSpecific() bool {
-	return a.kind == socSpecificModule
+func (b *baseModuleContext) SocSpecific() bool {
+	return b.kind == socSpecificModule
 }
 
-func (a *androidBaseContextImpl) ProductSpecific() bool {
-	return a.kind == productSpecificModule
+func (b *baseModuleContext) ProductSpecific() bool {
+	return b.kind == productSpecificModule
 }
 
-func (a *androidBaseContextImpl) ProductServicesSpecific() bool {
-	return a.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.
-func (a *ModuleBase) MakeAsPlatform() {
-	a.commonProperties.Vendor = boolPtr(false)
-	a.commonProperties.Proprietary = boolPtr(false)
-	a.commonProperties.Soc_specific = boolPtr(false)
-	a.commonProperties.Product_specific = boolPtr(false)
-	a.commonProperties.Product_services_specific = boolPtr(false)
+// 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.System_ext_specific = boolPtr(false)
 }
 
-func (a *androidModuleContext) InstallInData() bool {
-	return a.module.InstallInData()
+func (m *ModuleBase) EnableNativeBridgeSupportByDefault() {
+	m.commonProperties.Native_bridge_supported = boolPtr(true)
 }
 
-func (a *androidModuleContext) InstallInSanitizerDir() bool {
-	return a.module.InstallInSanitizerDir()
+func (m *moduleContext) InstallInData() bool {
+	return m.module.InstallInData()
 }
 
-func (a *androidModuleContext) InstallInRecovery() bool {
-	return a.module.InstallInRecovery()
+func (m *moduleContext) InstallInSanitizerDir() bool {
+	return m.module.InstallInSanitizerDir()
 }
 
-func (a *androidModuleContext) skipInstall(fullInstallPath OutputPath) bool {
-	if a.module.base().commonProperties.SkipInstall {
+func (m *moduleContext) InstallInRecovery() bool {
+	return m.module.InstallInRecovery()
+}
+
+func (m *moduleContext) skipInstall(fullInstallPath OutputPath) bool {
+	if m.module.base().commonProperties.SkipInstall {
 		return true
 	}
 
 	// We'll need a solution for choosing which of modules with the same name in different
 	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the
 	// list of namespaces to install in a Soong-only build.
-	if !a.module.base().commonProperties.NamespaceExportedToMake {
+	if !m.module.base().commonProperties.NamespaceExportedToMake {
 		return true
 	}
 
-	if a.Device() {
-		if a.Config().SkipDeviceInstall() {
+	if m.Device() {
+		if m.Config().SkipDeviceInstall() {
 			return true
 		}
 
-		if a.Config().SkipMegaDeviceInstall(fullInstallPath.String()) {
+		if m.Config().SkipMegaDeviceInstall(fullInstallPath.String()) {
 			return true
 		}
 	}
@@ -1285,29 +1492,29 @@
 	return false
 }
 
-func (a *androidModuleContext) InstallFile(installPath OutputPath, name string, srcPath Path,
+func (m *moduleContext) InstallFile(installPath OutputPath, name string, srcPath Path,
 	deps ...Path) OutputPath {
-	return a.installFile(installPath, name, srcPath, Cp, deps)
+	return m.installFile(installPath, name, srcPath, Cp, deps)
 }
 
-func (a *androidModuleContext) InstallExecutable(installPath OutputPath, name string, srcPath Path,
+func (m *moduleContext) InstallExecutable(installPath OutputPath, name string, srcPath Path,
 	deps ...Path) OutputPath {
-	return a.installFile(installPath, name, srcPath, CpExecutable, deps)
+	return m.installFile(installPath, name, srcPath, CpExecutable, deps)
 }
 
-func (a *androidModuleContext) installFile(installPath OutputPath, name string, srcPath Path,
+func (m *moduleContext) installFile(installPath OutputPath, name string, srcPath Path,
 	rule blueprint.Rule, deps []Path) OutputPath {
 
-	fullInstallPath := installPath.Join(a, name)
-	a.module.base().hooks.runInstallHooks(a, fullInstallPath, false)
+	fullInstallPath := installPath.Join(m, name)
+	m.module.base().hooks.runInstallHooks(m, fullInstallPath, false)
 
-	if !a.skipInstall(fullInstallPath) {
+	if !m.skipInstall(fullInstallPath) {
 
-		deps = append(deps, a.installDeps...)
+		deps = append(deps, m.installDeps...)
 
 		var implicitDeps, orderOnlyDeps Paths
 
-		if a.Host() {
+		if m.Host() {
 			// Installed host modules might be used during the build, depend directly on their
 			// dependencies so their timestamp is updated whenever their dependency is updated
 			implicitDeps = deps
@@ -1315,73 +1522,73 @@
 			orderOnlyDeps = deps
 		}
 
-		a.Build(pctx, BuildParams{
+		m.Build(pctx, BuildParams{
 			Rule:        rule,
 			Description: "install " + fullInstallPath.Base(),
 			Output:      fullInstallPath,
 			Input:       srcPath,
 			Implicits:   implicitDeps,
 			OrderOnly:   orderOnlyDeps,
-			Default:     !a.Config().EmbeddedInMake(),
+			Default:     !m.Config().EmbeddedInMake(),
 		})
 
-		a.installFiles = append(a.installFiles, fullInstallPath)
+		m.installFiles = append(m.installFiles, fullInstallPath)
 	}
-	a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
+	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	return fullInstallPath
 }
 
-func (a *androidModuleContext) InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath {
-	fullInstallPath := installPath.Join(a, name)
-	a.module.base().hooks.runInstallHooks(a, fullInstallPath, true)
+func (m *moduleContext) InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath {
+	fullInstallPath := installPath.Join(m, name)
+	m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
 
-	if !a.skipInstall(fullInstallPath) {
+	if !m.skipInstall(fullInstallPath) {
 
 		relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
 		if err != nil {
 			panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
 		}
-		a.Build(pctx, BuildParams{
+		m.Build(pctx, BuildParams{
 			Rule:        Symlink,
 			Description: "install symlink " + fullInstallPath.Base(),
 			Output:      fullInstallPath,
 			OrderOnly:   Paths{srcPath},
-			Default:     !a.Config().EmbeddedInMake(),
+			Default:     !m.Config().EmbeddedInMake(),
 			Args: map[string]string{
 				"fromPath": relPath,
 			},
 		})
 
-		a.installFiles = append(a.installFiles, fullInstallPath)
-		a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
+		m.installFiles = append(m.installFiles, fullInstallPath)
+		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	}
 	return fullInstallPath
 }
 
 // installPath/name -> absPath where absPath might be a path that is available only at runtime
 // (e.g. /apex/...)
-func (a *androidModuleContext) InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath {
-	fullInstallPath := installPath.Join(a, name)
-	a.module.base().hooks.runInstallHooks(a, fullInstallPath, true)
+func (m *moduleContext) InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath {
+	fullInstallPath := installPath.Join(m, name)
+	m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
 
-	if !a.skipInstall(fullInstallPath) {
-		a.Build(pctx, BuildParams{
+	if !m.skipInstall(fullInstallPath) {
+		m.Build(pctx, BuildParams{
 			Rule:        Symlink,
 			Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
 			Output:      fullInstallPath,
-			Default:     !a.Config().EmbeddedInMake(),
+			Default:     !m.Config().EmbeddedInMake(),
 			Args: map[string]string{
 				"fromPath": absPath,
 			},
 		})
 
-		a.installFiles = append(a.installFiles, fullInstallPath)
+		m.installFiles = append(m.installFiles, fullInstallPath)
 	}
 	return fullInstallPath
 }
 
-func (a *androidModuleContext) CheckbuildFile(srcPath Path) {
-	a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
+func (m *moduleContext) CheckbuildFile(srcPath Path) {
+	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 }
 
 type fileInstaller interface {
@@ -1407,39 +1614,60 @@
 	return -1
 }
 
-func SrcIsModule(s string) string {
+// SrcIsModule decodes module references in the format ":name" into the module name, or empty string if the input
+// was not a module reference.
+func SrcIsModule(s string) (module string) {
 	if len(s) > 1 && s[0] == ':' {
 		return s[1:]
 	}
 	return ""
 }
 
-type sourceDependencyTag struct {
-	blueprint.BaseDependencyTag
+// SrcIsModule decodes module references in the format ":name{.tag}" into the module name and tag, ":name" into the
+// module name and an empty string for the tag, or empty strings if the input was not a module reference.
+func SrcIsModuleWithTag(s string) (module, tag string) {
+	if len(s) > 1 && s[0] == ':' {
+		module = s[1:]
+		if tagStart := strings.IndexByte(module, '{'); tagStart > 0 {
+			if module[len(module)-1] == '}' {
+				tag = module[tagStart+1 : len(module)-1]
+				module = module[:tagStart]
+				return module, tag
+			}
+		}
+		return module, ""
+	}
+	return "", ""
 }
 
-var SourceDepTag sourceDependencyTag
+type sourceOrOutputDependencyTag struct {
+	blueprint.BaseDependencyTag
+	tag string
+}
+
+func sourceOrOutputDepTag(tag string) blueprint.DependencyTag {
+	return sourceOrOutputDependencyTag{tag: tag}
+}
+
+var SourceDepTag = sourceOrOutputDepTag("")
 
 // Adds necessary dependencies to satisfy filegroup or generated sources modules listed in srcFiles
 // using ":module" syntax, if any.
 //
 // Deprecated: tag the property with `android:"path"` instead.
 func ExtractSourcesDeps(ctx BottomUpMutatorContext, srcFiles []string) {
-	var deps []string
 	set := make(map[string]bool)
 
 	for _, s := range srcFiles {
-		if m := SrcIsModule(s); m != "" {
-			if _, found := set[m]; found {
-				ctx.ModuleErrorf("found source dependency duplicate: %q!", m)
+		if m, t := SrcIsModuleWithTag(s); m != "" {
+			if _, found := set[s]; found {
+				ctx.ModuleErrorf("found source dependency duplicate: %q!", s)
 			} else {
-				set[m] = true
-				deps = append(deps, m)
+				set[s] = true
+				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
 			}
 		}
 	}
-
-	ctx.AddDependency(ctx.Module(), SourceDepTag, deps...)
 }
 
 // Adds necessary dependencies to satisfy filegroup or generated sources modules specified in s
@@ -1448,16 +1676,25 @@
 // Deprecated: tag the property with `android:"path"` instead.
 func ExtractSourceDeps(ctx BottomUpMutatorContext, s *string) {
 	if s != nil {
-		if m := SrcIsModule(*s); m != "" {
-			ctx.AddDependency(ctx.Module(), SourceDepTag, m)
+		if m, t := SrcIsModuleWithTag(*s); m != "" {
+			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
 		}
 	}
 }
 
+// A module that implements SourceFileProducer can be referenced from any property that is tagged with `android:"path"`
+// using the ":module" syntax and provides a list of paths to be used as if they were listed in the property.
 type SourceFileProducer interface {
 	Srcs() Paths
 }
 
+// A module that implements OutputFileProducer can be referenced from any property that is tagged with `android:"path"`
+// using the ":module" syntax or ":module{.tag}" syntax and provides a list of otuput files to be used as if they were
+// listed in the property.
+type OutputFileProducer interface {
+	OutputFiles(tag string) (Paths, error)
+}
+
 type HostToolProvider interface {
 	HostToolPath() OptionalPath
 }
@@ -1466,46 +1703,54 @@
 // be tagged with `android:"path" to support automatic source module dependency resolution.
 //
 // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
-func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Paths {
-	return PathsForModuleSrcExcludes(ctx, srcFiles, excludes)
+func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
+	return PathsForModuleSrcExcludes(m, srcFiles, excludes)
 }
 
 // Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
 // be tagged with `android:"path" to support automatic source module dependency resolution.
 //
 // Deprecated: use PathForModuleSrc instead.
-func (ctx *androidModuleContext) ExpandSource(srcFile, prop string) Path {
-	return PathForModuleSrc(ctx, srcFile)
+func (m *moduleContext) ExpandSource(srcFile, prop string) Path {
+	return PathForModuleSrc(m, srcFile)
 }
 
 // Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
 // the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module
 // dependency resolution.
-func (ctx *androidModuleContext) ExpandOptionalSource(srcFile *string, prop string) OptionalPath {
+func (m *moduleContext) ExpandOptionalSource(srcFile *string, prop string) OptionalPath {
 	if srcFile != nil {
-		return OptionalPathForPath(PathForModuleSrc(ctx, *srcFile))
+		return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
 	}
 	return OptionalPath{}
 }
 
-func (ctx *androidModuleContext) RequiredModuleNames() []string {
-	return ctx.module.base().commonProperties.Required
+func (m *moduleContext) RequiredModuleNames() []string {
+	return m.module.base().commonProperties.Required
 }
 
-func (ctx *androidModuleContext) Glob(globPattern string, excludes []string) Paths {
-	ret, err := ctx.GlobWithDeps(globPattern, excludes)
-	if err != nil {
-		ctx.ModuleErrorf("glob: %s", err.Error())
-	}
-	return pathsForModuleSrcFromFullPath(ctx, ret, true)
+func (m *moduleContext) HostRequiredModuleNames() []string {
+	return m.module.base().commonProperties.Host_required
 }
 
-func (ctx *androidModuleContext) GlobFiles(globPattern string, excludes []string) Paths {
-	ret, err := ctx.GlobWithDeps(globPattern, excludes)
+func (m *moduleContext) TargetRequiredModuleNames() []string {
+	return m.module.base().commonProperties.Target_required
+}
+
+func (b *baseModuleContext) Glob(globPattern string, excludes []string) Paths {
+	ret, err := b.GlobWithDeps(globPattern, excludes)
 	if err != nil {
-		ctx.ModuleErrorf("glob: %s", err.Error())
+		b.ModuleErrorf("glob: %s", err.Error())
 	}
-	return pathsForModuleSrcFromFullPath(ctx, ret, false)
+	return pathsForModuleSrcFromFullPath(b, ret, true)
+}
+
+func (b *baseModuleContext) GlobFiles(globPattern string, excludes []string) Paths {
+	ret, err := b.GlobWithDeps(globPattern, excludes)
+	if err != nil {
+		b.ModuleErrorf("glob: %s", err.Error())
+	}
+	return pathsForModuleSrcFromFullPath(b, ret, false)
 }
 
 func init() {
@@ -1565,17 +1810,8 @@
 		return
 	}
 
-	sortedKeys := func(m map[string]Paths) []string {
-		s := make([]string, 0, len(m))
-		for k := range m {
-			s = append(s, k)
-		}
-		sort.Strings(s)
-		return s
-	}
-
 	// Ensure ancestor directories are in modulesInDir
-	dirs := sortedKeys(modulesInDir)
+	dirs := SortedStringKeys(modulesInDir)
 	for _, dir := range dirs {
 		dir := parentDir(dir)
 		for dir != "." && dir != "/" {
@@ -1588,7 +1824,6 @@
 	}
 
 	// Make directories build their direct subdirectories
-	dirs = sortedKeys(modulesInDir)
 	for _, dir := range dirs {
 		p := parentDir(dir)
 		if p != "." && p != "/" {
@@ -1645,8 +1880,7 @@
 	}
 
 	// Wrap those into host|host-cross|target phony rules
-	osClasses := sortedKeys(osClass)
-	for _, class := range osClasses {
+	for _, class := range SortedStringKeys(osClass) {
 		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
 			Output:    PathForPhony(ctx, class),
@@ -1677,4 +1911,5 @@
 	Jars              []string `json:"jars,omitempty"`
 	Classes           []string `json:"class,omitempty"`
 	Installed_paths   []string `json:"installed,omitempty"`
+	SrcJars           []string `json:"srcjars,omitempty"`
 }
diff --git a/android/module_test.go b/android/module_test.go
new file mode 100644
index 0000000..c790a68
--- /dev/null
+++ b/android/module_test.go
@@ -0,0 +1,141 @@
+// Copyright 2015 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 "testing"
+
+func TestSrcIsModule(t *testing.T) {
+	type args struct {
+		s string
+	}
+	tests := []struct {
+		name       string
+		args       args
+		wantModule string
+	}{
+		{
+			name: "file",
+			args: args{
+				s: "foo",
+			},
+			wantModule: "",
+		},
+		{
+			name: "module",
+			args: args{
+				s: ":foo",
+			},
+			wantModule: "foo",
+		},
+		{
+			name: "tag",
+			args: args{
+				s: ":foo{.bar}",
+			},
+			wantModule: "foo{.bar}",
+		},
+		{
+			name: "extra colon",
+			args: args{
+				s: ":foo:bar",
+			},
+			wantModule: "foo:bar",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if gotModule := SrcIsModule(tt.args.s); gotModule != tt.wantModule {
+				t.Errorf("SrcIsModule() = %v, want %v", gotModule, tt.wantModule)
+			}
+		})
+	}
+}
+
+func TestSrcIsModuleWithTag(t *testing.T) {
+	type args struct {
+		s string
+	}
+	tests := []struct {
+		name       string
+		args       args
+		wantModule string
+		wantTag    string
+	}{
+		{
+			name: "file",
+			args: args{
+				s: "foo",
+			},
+			wantModule: "",
+			wantTag:    "",
+		},
+		{
+			name: "module",
+			args: args{
+				s: ":foo",
+			},
+			wantModule: "foo",
+			wantTag:    "",
+		},
+		{
+			name: "tag",
+			args: args{
+				s: ":foo{.bar}",
+			},
+			wantModule: "foo",
+			wantTag:    ".bar",
+		},
+		{
+			name: "empty tag",
+			args: args{
+				s: ":foo{}",
+			},
+			wantModule: "foo",
+			wantTag:    "",
+		},
+		{
+			name: "extra colon",
+			args: args{
+				s: ":foo:bar",
+			},
+			wantModule: "foo:bar",
+		},
+		{
+			name: "invalid tag",
+			args: args{
+				s: ":foo{.bar",
+			},
+			wantModule: "foo{.bar",
+		},
+		{
+			name: "invalid tag 2",
+			args: args{
+				s: ":foo.bar}",
+			},
+			wantModule: "foo.bar}",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			gotModule, gotTag := SrcIsModuleWithTag(tt.args.s)
+			if gotModule != tt.wantModule {
+				t.Errorf("SrcIsModuleWithTag() gotModule = %v, want %v", gotModule, tt.wantModule)
+			}
+			if gotTag != tt.wantTag {
+				t.Errorf("SrcIsModuleWithTag() gotTag = %v, want %v", gotTag, tt.wantTag)
+			}
+		})
+	}
+}
diff --git a/android/mutator.go b/android/mutator.go
index 71237a1..b799432 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -66,20 +66,21 @@
 }
 
 type RegisterMutatorsContext interface {
-	TopDown(name string, m AndroidTopDownMutator) MutatorHandle
-	BottomUp(name string, m AndroidBottomUpMutator) MutatorHandle
+	TopDown(name string, m TopDownMutator) MutatorHandle
+	BottomUp(name string, m BottomUpMutator) MutatorHandle
 }
 
 type RegisterMutatorFunc func(RegisterMutatorsContext)
 
 var preArch = []RegisterMutatorFunc{
-	func(ctx RegisterMutatorsContext) {
-		ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
-	},
+	registerLoadHookMutator,
 	RegisterNamespaceMutator,
+	// Rename package module types.
+	registerPackageRenamer,
 	RegisterPrebuiltsPreArchMutators,
+	registerVisibilityRuleChecker,
 	RegisterDefaultsPreArchMutators,
-	RegisterOverridePreArchMutators,
+	registerVisibilityRuleGatherer,
 }
 
 func registerArchMutator(ctx RegisterMutatorsContext) {
@@ -94,7 +95,9 @@
 var postDeps = []RegisterMutatorFunc{
 	registerPathDepsMutator,
 	RegisterPrebuiltsPostDepsMutators,
+	registerVisibilityRuleEnforcer,
 	registerNeverallowMutator,
+	RegisterOverridePostDepsMutators,
 }
 
 func PreArchMutators(f RegisterMutatorFunc) {
@@ -109,51 +112,31 @@
 	postDeps = append(postDeps, f)
 }
 
-type AndroidTopDownMutator func(TopDownMutatorContext)
+type TopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
 	BaseModuleContext
-	androidBaseContext
 
-	OtherModuleExists(name string) bool
+	MutatorName() string
+
 	Rename(name string)
-	Module() Module
-
-	OtherModuleName(m blueprint.Module) string
-	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
-	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 
 	CreateModule(blueprint.ModuleFactory, ...interface{})
-
-	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
-	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
-
-	VisitDirectDeps(visit func(Module))
-	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
-	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
-	VisitDepsDepthFirst(visit func(Module))
-	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
-	WalkDeps(visit func(Module, Module) bool)
-	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
-	// and returns a top-down dependency path from a start module to current child module.
-	GetWalkPath() []Module
 }
 
-type androidTopDownMutatorContext struct {
-	blueprint.TopDownMutatorContext
-	androidBaseContextImpl
-	walkPath []Module
+type topDownMutatorContext struct {
+	bp blueprint.TopDownMutatorContext
+	baseModuleContext
 }
 
-type AndroidBottomUpMutator func(BottomUpMutatorContext)
+type BottomUpMutator func(BottomUpMutatorContext)
 
 type BottomUpMutatorContext interface {
 	BaseModuleContext
-	androidBaseContext
 
-	OtherModuleExists(name string) bool
+	MutatorName() string
+
 	Rename(name string)
-	Module() blueprint.Module
 
 	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
 	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
@@ -166,17 +149,17 @@
 	ReplaceDependencies(string)
 }
 
-type androidBottomUpMutatorContext struct {
-	blueprint.BottomUpMutatorContext
-	androidBaseContextImpl
+type bottomUpMutatorContext struct {
+	bp blueprint.BottomUpMutatorContext
+	baseModuleContext
 }
 
-func (x *registerMutatorsContext) BottomUp(name string, m AndroidBottomUpMutator) MutatorHandle {
+func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			actx := &androidBottomUpMutatorContext{
-				BottomUpMutatorContext: ctx,
-				androidBaseContextImpl: a.base().androidBaseContextFactory(ctx),
+			actx := &bottomUpMutatorContext{
+				bp:                ctx,
+				baseModuleContext: a.base().baseModuleContextFactory(ctx),
 			}
 			m(actx)
 		}
@@ -186,12 +169,12 @@
 	return mutator
 }
 
-func (x *registerMutatorsContext) TopDown(name string, m AndroidTopDownMutator) MutatorHandle {
+func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle {
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			actx := &androidTopDownMutatorContext{
-				TopDownMutatorContext:  ctx,
-				androidBaseContextImpl: a.base().androidBaseContextFactory(ctx),
+			actx := &topDownMutatorContext{
+				bp:                ctx,
+				baseModuleContext: a.base().baseModuleContextFactory(ctx),
 			}
 			m(actx)
 		}
@@ -216,106 +199,13 @@
 	}
 }
 
-func (a *androidTopDownMutatorContext) Config() Config {
-	return a.config
-}
-
-func (a *androidBottomUpMutatorContext) Config() Config {
-	return a.config
-}
-
-func (a *androidTopDownMutatorContext) Module() Module {
-	module, _ := a.TopDownMutatorContext.Module().(Module)
-	return module
-}
-
-func (a *androidTopDownMutatorContext) VisitDirectDeps(visit func(Module)) {
-	a.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			visit(aModule)
-		}
-	})
-}
-
-func (a *androidTopDownMutatorContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
-	a.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			if a.TopDownMutatorContext.OtherModuleDependencyTag(aModule) == tag {
-				visit(aModule)
-			}
-		}
-	})
-}
-
-func (a *androidTopDownMutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
-	a.TopDownMutatorContext.VisitDirectDepsIf(
-		// pred
-		func(module blueprint.Module) bool {
-			if aModule, _ := module.(Module); aModule != nil {
-				return pred(aModule)
-			} else {
-				return false
-			}
-		},
-		// visit
-		func(module blueprint.Module) {
-			visit(module.(Module))
-		})
-}
-
-func (a *androidTopDownMutatorContext) VisitDepsDepthFirst(visit func(Module)) {
-	a.TopDownMutatorContext.VisitDepsDepthFirst(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			visit(aModule)
-		}
-	})
-}
-
-func (a *androidTopDownMutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
-	a.TopDownMutatorContext.VisitDepsDepthFirstIf(
-		// pred
-		func(module blueprint.Module) bool {
-			if aModule, _ := module.(Module); aModule != nil {
-				return pred(aModule)
-			} else {
-				return false
-			}
-		},
-		// visit
-		func(module blueprint.Module) {
-			visit(module.(Module))
-		})
-}
-
-func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) {
-	a.walkPath = []Module{a.Module()}
-	a.TopDownMutatorContext.WalkDeps(func(child, parent blueprint.Module) bool {
-		childAndroidModule, _ := child.(Module)
-		parentAndroidModule, _ := parent.(Module)
-		if childAndroidModule != nil && parentAndroidModule != nil {
-			// record walkPath before visit
-			for a.walkPath[len(a.walkPath)-1] != parentAndroidModule {
-				a.walkPath = a.walkPath[0 : len(a.walkPath)-1]
-			}
-			a.walkPath = append(a.walkPath, childAndroidModule)
-			return visit(childAndroidModule, parentAndroidModule)
-		} else {
-			return false
-		}
-	})
-}
-
-func (a *androidTopDownMutatorContext) GetWalkPath() []Module {
-	return a.walkPath
-}
-
-func (a *androidTopDownMutatorContext) AppendProperties(props ...interface{}) {
+func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {
 	for _, p := range props {
-		err := proptools.AppendMatchingProperties(a.Module().base().customizableProperties,
+		err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties,
 			p, nil)
 		if err != nil {
 			if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
-				a.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+				t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
 			} else {
 				panic(err)
 			}
@@ -323,16 +213,100 @@
 	}
 }
 
-func (a *androidTopDownMutatorContext) PrependProperties(props ...interface{}) {
+func (t *topDownMutatorContext) PrependProperties(props ...interface{}) {
 	for _, p := range props {
-		err := proptools.PrependMatchingProperties(a.Module().base().customizableProperties,
+		err := proptools.PrependMatchingProperties(t.Module().base().customizableProperties,
 			p, nil)
 		if err != nil {
 			if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
-				a.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+				t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
 			} else {
 				panic(err)
 			}
 		}
 	}
 }
+
+// android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that
+// has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid
+// ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every
+// non-overridden method has to be forwarded.  There are fewer non-overridden methods, so use the latter.  The following
+// methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext.
+
+func (t *topDownMutatorContext) MutatorName() string {
+	return t.bp.MutatorName()
+}
+
+func (t *topDownMutatorContext) Rename(name string) {
+	t.bp.Rename(name)
+	t.Module().base().commonProperties.DebugName = name
+}
+
+func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) {
+	t.bp.CreateModule(factory, props...)
+}
+
+func (b *bottomUpMutatorContext) MutatorName() string {
+	return b.bp.MutatorName()
+}
+
+func (b *bottomUpMutatorContext) Rename(name string) {
+	b.bp.Rename(name)
+	b.Module().base().commonProperties.DebugName = name
+}
+
+func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) {
+	b.bp.AddDependency(module, tag, name...)
+}
+
+func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) {
+	b.bp.AddReverseDependency(module, tag, name)
+}
+
+func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []blueprint.Module {
+	modules := b.bp.CreateVariations(variations...)
+
+	for i := range variations {
+		base := modules[i].(Module).base()
+		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
+		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
+	}
+
+	return modules
+}
+
+func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []blueprint.Module {
+	modules := b.bp.CreateLocalVariations(variations...)
+
+	for i := range variations {
+		base := modules[i].(Module).base()
+		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
+		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
+	}
+
+	return modules
+}
+
+func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) {
+	b.bp.SetDependencyVariation(variation)
+}
+
+func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
+	names ...string) {
+
+	b.bp.AddVariationDependencies(variations, tag, names...)
+}
+
+func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation,
+	tag blueprint.DependencyTag, names ...string) {
+
+	b.bp.AddFarVariationDependencies(variations, tag, names...)
+}
+
+func (b *bottomUpMutatorContext) AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) {
+	b.bp.AddInterVariantDependency(tag, from, to)
+}
+
+func (b *bottomUpMutatorContext) ReplaceDependencies(name string) {
+	b.bp.ReplaceDependencies(name)
+}
diff --git a/android/mutator_test.go b/android/mutator_test.go
new file mode 100644
index 0000000..0b23434
--- /dev/null
+++ b/android/mutator_test.go
@@ -0,0 +1,199 @@
+// Copyright 2015 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 (
+	"reflect"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+type mutatorTestModule struct {
+	ModuleBase
+	props struct {
+		Deps_missing_deps    []string
+		Mutator_missing_deps []string
+	}
+
+	missingDeps []string
+}
+
+func mutatorTestModuleFactory() Module {
+	module := &mutatorTestModule{}
+	module.AddProperties(&module.props)
+	InitAndroidModule(module)
+	return module
+}
+
+func (m *mutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	ctx.Build(pctx, BuildParams{
+		Rule:   Touch,
+		Output: PathForModuleOut(ctx, "output"),
+	})
+
+	m.missingDeps = ctx.GetMissingDependencies()
+}
+
+func (m *mutatorTestModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), nil, m.props.Deps_missing_deps...)
+}
+
+func addMissingDependenciesMutator(ctx TopDownMutatorContext) {
+	ctx.AddMissingDependencies(ctx.Module().(*mutatorTestModule).props.Mutator_missing_deps)
+}
+
+func TestMutatorAddMissingDependencies(t *testing.T) {
+	config := TestConfig(buildDir, nil)
+	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
+
+	ctx := NewTestContext()
+	ctx.SetAllowMissingDependencies(true)
+
+	ctx.RegisterModuleType("test", ModuleFactoryAdaptor(mutatorTestModuleFactory))
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.TopDown("add_missing_dependencies", addMissingDependenciesMutator)
+	})
+
+	bp := `
+		test {
+			name: "foo",
+			deps_missing_deps: ["regular_missing_dep"],
+			mutator_missing_deps: ["added_missing_dep"],
+		}
+	`
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	ctx.Register()
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	foo := ctx.ModuleForTests("foo", "").Module().(*mutatorTestModule)
+
+	if g, w := foo.missingDeps, []string{"added_missing_dep", "regular_missing_dep"}; !reflect.DeepEqual(g, w) {
+		t.Errorf("want foo missing deps %q, got %q", w, g)
+	}
+}
+
+func TestModuleString(t *testing.T) {
+	ctx := NewTestContext()
+
+	var moduleStrings []string
+
+	ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("pre_arch", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.CreateVariations("a", "b")
+		})
+		ctx.TopDown("rename_top_down", func(ctx TopDownMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.Rename(ctx.Module().base().Name() + "_renamed1")
+		})
+	})
+
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.CreateVariations("c", "d")
+		})
+	})
+
+	ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("post_deps", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.CreateLocalVariations("e", "f")
+		})
+		ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.Rename(ctx.Module().base().Name() + "_renamed2")
+		})
+		ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+		})
+	})
+
+	ctx.RegisterModuleType("test", ModuleFactoryAdaptor(mutatorTestModuleFactory))
+
+	bp := `
+		test {
+			name: "foo",
+		}
+	`
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	ctx.Register()
+
+	config := TestConfig(buildDir, nil)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	want := []string{
+		// Initial name.
+		"foo{}",
+
+		// After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
+		"foo{pre_arch:b}",
+		"foo{pre_arch:a}",
+
+		// After rename_top_down.
+		"foo_renamed1{pre_arch:a}",
+		"foo_renamed1{pre_arch:b}",
+
+		// After pre_deps.
+		"foo_renamed1{pre_arch:a,pre_deps:c}",
+		"foo_renamed1{pre_arch:a,pre_deps:d}",
+		"foo_renamed1{pre_arch:b,pre_deps:c}",
+		"foo_renamed1{pre_arch:b,pre_deps:d}",
+
+		// After post_deps.
+		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
+		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
+		"foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
+		"foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
+		"foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
+		"foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
+		"foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
+		"foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
+
+		// After rename_bottom_up.
+		"foo_renamed2{pre_arch:a,pre_deps:c,post_deps:e}",
+		"foo_renamed2{pre_arch:a,pre_deps:c,post_deps:f}",
+		"foo_renamed2{pre_arch:a,pre_deps:d,post_deps:e}",
+		"foo_renamed2{pre_arch:a,pre_deps:d,post_deps:f}",
+		"foo_renamed2{pre_arch:b,pre_deps:c,post_deps:e}",
+		"foo_renamed2{pre_arch:b,pre_deps:c,post_deps:f}",
+		"foo_renamed2{pre_arch:b,pre_deps:d,post_deps:e}",
+		"foo_renamed2{pre_arch:b,pre_deps:d,post_deps:f}",
+	}
+
+	if !reflect.DeepEqual(moduleStrings, want) {
+		t.Errorf("want module String() values:\n%q\ngot:\n%q", want, moduleStrings)
+	}
+}
diff --git a/android/namespace.go b/android/namespace.go
index 50bdcba..27ec163 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -26,12 +26,6 @@
 	"github.com/google/blueprint"
 )
 
-// This file implements namespaces
-const (
-	namespacePrefix = "//"
-	modulePrefix    = ":"
-)
-
 func init() {
 	RegisterModuleType("soong_namespace", NamespaceFactory)
 }
@@ -215,11 +209,11 @@
 // parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
 // module name
 func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
-	if !strings.HasPrefix(name, namespacePrefix) {
+	if !strings.HasPrefix(name, "//") {
 		return "", "", false
 	}
-	name = strings.TrimPrefix(name, namespacePrefix)
-	components := strings.Split(name, modulePrefix)
+	name = strings.TrimPrefix(name, "//")
+	components := strings.Split(name, ":")
 	if len(components) != 2 {
 		return "", "", false
 	}
@@ -228,6 +222,11 @@
 }
 
 func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace *Namespace) (searchOrder []*Namespace) {
+	if sourceNamespace.visibleNamespaces == nil {
+		// When handling dependencies before namespaceMutator, assume they are non-Soong Blueprint modules and give
+		// access to all namespaces.
+		return r.sortedNamespaces.sortedItems()
+	}
 	return sourceNamespace.visibleNamespaces
 }
 
diff --git a/android/namespace_test.go b/android/namespace_test.go
index 9a791a5..20241fe 100644
--- a/android/namespace_test.go
+++ b/android/namespace_test.go
@@ -16,8 +16,6 @@
 
 import (
 	"errors"
-	"io/ioutil"
-	"os"
 	"path/filepath"
 	"reflect"
 	"testing"
@@ -93,6 +91,28 @@
 	// setupTest will report any errors
 }
 
+func TestDependingOnBlueprintModuleInRootNamespace(t *testing.T) {
+	_ = setupTest(t,
+		map[string]string{
+			".": `
+			blueprint_test_module {
+				name: "a",
+			}
+			`,
+			"dir1": `
+			soong_namespace {
+			}
+			blueprint_test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	// setupTest will report any errors
+}
+
 func TestDependingOnModuleInImportedNamespace(t *testing.T) {
 	ctx := setupTest(t,
 		map[string]string{
@@ -613,18 +633,13 @@
 }
 
 func setupTestFromFiles(bps map[string][]byte) (ctx *TestContext, errs []error) {
-	buildDir, err := ioutil.TempDir("", "soong_namespace_test")
-	if err != nil {
-		return nil, []error{err}
-	}
-	defer os.RemoveAll(buildDir)
-
 	config := TestConfig(buildDir, nil)
 
 	ctx = NewTestContext()
 	ctx.MockFileSystem(bps)
 	ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
 	ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
+	ctx.RegisterModuleType("blueprint_test_module", newBlueprintTestModule)
 	ctx.PreArchMutators(RegisterNamespaceMutator)
 	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
 		ctx.BottomUp("rename", renameMutator)
@@ -649,6 +664,7 @@
 }
 
 func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) {
+	t.Helper()
 	ctx, errs := setupTestExpectErrs(bps)
 	FailIfErrored(t, errs)
 	return ctx
@@ -726,3 +742,22 @@
 	InitAndroidModule(m)
 	return m
 }
+
+type blueprintTestModule struct {
+	blueprint.SimpleName
+	properties struct {
+		Deps []string
+	}
+}
+
+func (b *blueprintTestModule) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
+	return b.properties.Deps
+}
+
+func (b *blueprintTestModule) GenerateBuildActions(blueprint.ModuleContext) {
+}
+
+func newBlueprintTestModule() (blueprint.Module, []interface{}) {
+	m := &blueprintTestModule{}
+	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index b90fe43..af91676 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -31,62 +31,65 @@
 // work regardless of these restrictions.
 //
 // A module is disallowed if all of the following are true:
-// - it is in one of the "in" paths
-// - it is not in one of the "notIn" paths
-// - it has all "with" properties matched
+// - it is in one of the "In" paths
+// - it is not in one of the "NotIn" paths
+// - it has all "With" properties matched
 // - - values are matched in their entirety
 // - - nil is interpreted as an empty string
 // - - nested properties are separated with a '.'
 // - - if the property is a list, any of the values in the list being matches
 //     counts as a match
-// - it has none of the "without" properties matched (same rules as above)
+// - it has none of the "Without" properties matched (same rules as above)
 
 func registerNeverallowMutator(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("neverallow", neverallowMutator).Parallel()
 }
 
-var neverallows = createNeverAllows()
+var neverallows = []Rule{}
 
-func createNeverAllows() []*rule {
-	rules := []*rule{}
-	rules = append(rules, createTrebleRules()...)
-	rules = append(rules, createLibcoreRules()...)
-	rules = append(rules, createMediaRules()...)
-	rules = append(rules, createJavaDeviceForHostRules()...)
-	return rules
+func init() {
+	AddNeverAllowRules(createTrebleRules()...)
+	AddNeverAllowRules(createLibcoreRules()...)
+	AddNeverAllowRules(createMediaRules()...)
+	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 }
 
-func createTrebleRules() []*rule {
-	return []*rule{
-		neverallow().
-			in("vendor", "device").
-			with("vndk.enabled", "true").
-			without("vendor", "true").
-			because("the VNDK can never contain a library that is device dependent."),
-		neverallow().
-			with("vndk.enabled", "true").
-			without("vendor", "true").
-			without("owner", "").
-			because("a VNDK module can never have an owner."),
+// Add a NeverAllow rule to the set of rules to apply.
+func AddNeverAllowRules(rules ...Rule) {
+	neverallows = append(neverallows, rules...)
+}
+
+func createTrebleRules() []Rule {
+	return []Rule{
+		NeverAllow().
+			In("vendor", "device").
+			With("vndk.enabled", "true").
+			Without("vendor", "true").
+			Because("the VNDK can never contain a library that is device dependent."),
+		NeverAllow().
+			With("vndk.enabled", "true").
+			Without("vendor", "true").
+			Without("owner", "").
+			Because("a VNDK module can never have an owner."),
 
 		// TODO(b/67974785): always enforce the manifest
-		neverallow().
-			without("name", "libhidltransport-impl-internal").
-			with("product_variables.enforce_vintf_manifest.cflags", "*").
-			because("manifest enforcement should be independent of ."),
+		NeverAllow().
+			Without("name", "libhidltransport-impl-internal").
+			With("product_variables.enforce_vintf_manifest.cflags", "*").
+			Because("manifest enforcement should be independent of ."),
 
 		// TODO(b/67975799): vendor code should always use /vendor/bin/sh
-		neverallow().
-			without("name", "libc_bionic_ndk").
-			with("product_variables.treble_linker_namespaces.cflags", "*").
-			because("nothing should care if linker namespaces are enabled or not"),
+		NeverAllow().
+			Without("name", "libc_bionic_ndk").
+			With("product_variables.treble_linker_namespaces.cflags", "*").
+			Because("nothing should care if linker namespaces are enabled or not"),
 
 		// Example:
-		// *neverallow().with("Srcs", "main.cpp"))
+		// *NeverAllow().with("Srcs", "main.cpp"))
 	}
 }
 
-func createLibcoreRules() []*rule {
+func createLibcoreRules() []Rule {
 	var coreLibraryProjects = []string{
 		"libcore",
 		"external/apache-harmony",
@@ -96,56 +99,42 @@
 		"external/icu",
 		"external/okhttp",
 		"external/wycheproof",
+
+		// Not really a core library but still needs access to same capabilities.
+		"development",
 	}
 
-	var coreModules = []string{
-		"core-all",
-		"core-oj",
-		"core-libart",
-		"okhttp",
-		"bouncycastle",
-		"conscrypt",
-		"apache-xml",
+	// Core library constraints. The sdk_version: "none" can only be used in core library projects.
+	// Access to core library targets is restricted using visibility rules.
+	rules := []Rule{
+		NeverAllow().
+			NotIn(coreLibraryProjects...).
+			With("sdk_version", "none"),
 	}
 
-	// Core library constraints. Prevent targets adding dependencies on core
-	// library internals, which could lead to compatibility issues with the ART
-	// mainline module. They should use core.platform.api.stubs instead.
-	rules := []*rule{
-		neverallow().
-			notIn(append(coreLibraryProjects, "development")...).
-			with("no_standard_libs", "true"),
-	}
-
-	for _, m := range coreModules {
-		r := neverallow().
-			notIn(coreLibraryProjects...).
-			with("libs", m).
-			because("Only core libraries projects can depend on " + m)
-		rules = append(rules, r)
-	}
 	return rules
 }
 
-func createMediaRules() []*rule {
-	return []*rule{
-		neverallow().
-			with("libs", "updatable-media").
-			because("updatable-media includes private APIs. Use updatable_media_stubs instead."),
+func createMediaRules() []Rule {
+	return []Rule{
+		NeverAllow().
+			With("libs", "updatable-media").
+			Because("updatable-media includes private APIs. Use updatable_media_stubs instead."),
 	}
 }
 
-func createJavaDeviceForHostRules() []*rule {
+func createJavaDeviceForHostRules() []Rule {
 	javaDeviceForHostProjectsWhitelist := []string{
+		"external/guava",
 		"external/robolectric-shadows",
 		"framework/layoutlib",
 	}
 
-	return []*rule{
-		neverallow().
-			notIn(javaDeviceForHostProjectsWhitelist...).
-			moduleType("java_device_for_host", "java_host_for_device").
-			because("java_device_for_host can only be used in whitelisted projects"),
+	return []Rule{
+		NeverAllow().
+			NotIn(javaDeviceForHostProjectsWhitelist...).
+			ModuleType("java_device_for_host", "java_host_for_device").
+			Because("java_device_for_host can only be used in whitelisted projects"),
 	}
 }
 
@@ -158,7 +147,8 @@
 	dir := ctx.ModuleDir() + "/"
 	properties := m.GetProperties()
 
-	for _, n := range neverallows {
+	for _, r := range neverallows {
+		n := r.(*rule)
 		if !n.appliesToPath(dir) {
 			continue
 		}
@@ -180,6 +170,23 @@
 	value  string   // e.x.: true
 }
 
+// A NeverAllow rule.
+type Rule interface {
+	In(path ...string) Rule
+
+	NotIn(path ...string) Rule
+
+	ModuleType(types ...string) Rule
+
+	NotModuleType(types ...string) Rule
+
+	With(properties, value string) Rule
+
+	Without(properties, value string) Rule
+
+	Because(reason string) Rule
+}
+
 type rule struct {
 	// User string for why this is a thing.
 	reason string
@@ -194,31 +201,32 @@
 	unlessProps []ruleProperty
 }
 
-func neverallow() *rule {
+// Create a new NeverAllow rule.
+func NeverAllow() Rule {
 	return &rule{}
 }
 
-func (r *rule) in(path ...string) *rule {
+func (r *rule) In(path ...string) Rule {
 	r.paths = append(r.paths, cleanPaths(path)...)
 	return r
 }
 
-func (r *rule) notIn(path ...string) *rule {
+func (r *rule) NotIn(path ...string) Rule {
 	r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...)
 	return r
 }
 
-func (r *rule) moduleType(types ...string) *rule {
+func (r *rule) ModuleType(types ...string) Rule {
 	r.moduleTypes = append(r.moduleTypes, types...)
 	return r
 }
 
-func (r *rule) notModuleType(types ...string) *rule {
+func (r *rule) NotModuleType(types ...string) Rule {
 	r.unlessModuleTypes = append(r.unlessModuleTypes, types...)
 	return r
 }
 
-func (r *rule) with(properties, value string) *rule {
+func (r *rule) With(properties, value string) Rule {
 	r.props = append(r.props, ruleProperty{
 		fields: fieldNamesForProperties(properties),
 		value:  value,
@@ -226,7 +234,7 @@
 	return r
 }
 
-func (r *rule) without(properties, value string) *rule {
+func (r *rule) Without(properties, value string) Rule {
 	r.unlessProps = append(r.unlessProps, ruleProperty{
 		fields: fieldNamesForProperties(properties),
 		value:  value,
@@ -234,7 +242,7 @@
 	return r
 }
 
-func (r *rule) because(reason string) *rule {
+func (r *rule) Because(reason string) Rule {
 	r.reason = reason
 	return r
 }
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 6fd2cd7..17e40f0 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
 	"testing"
 )
 
@@ -123,17 +121,6 @@
 		expectedError: "",
 	},
 	{
-		name: "dependency on core-libart",
-		fs: map[string][]byte{
-			"Blueprints": []byte(`
-				java_library {
-					name: "needs_core_libart",
-					libs: ["core-libart"],
-				}`),
-		},
-		expectedError: "Only core libraries projects can depend on core-libart",
-	},
-	{
 		name: "dependency on updatable-media",
 		fs: map[string][]byte{
 			"Blueprints": []byte(`
@@ -155,15 +142,41 @@
 		},
 		expectedError: "java_device_for_host can only be used in whitelisted projects",
 	},
+	// Libcore rule tests
+	{
+		name: "sdk_version: \"none\" inside core libraries",
+		fs: map[string][]byte{
+			"libcore/Blueprints": []byte(`
+				java_library {
+					name: "inside_core_libraries",
+					sdk_version: "none",
+				}`),
+		},
+	},
+	{
+		name: "sdk_version: \"none\" outside core libraries",
+		fs: map[string][]byte{
+			"Blueprints": []byte(`
+				java_library {
+					name: "outside_core_libraries",
+					sdk_version: "none",
+				}`),
+		},
+		expectedError: "module \"outside_core_libraries\": violates neverallow",
+	},
+	{
+		name: "sdk_version: \"current\"",
+		fs: map[string][]byte{
+			"Blueprints": []byte(`
+				java_library {
+					name: "outside_core_libraries",
+					sdk_version: "current",
+				}`),
+		},
+	},
 }
 
 func TestNeverallow(t *testing.T) {
-	buildDir, err := ioutil.TempDir("", "soong_neverallow_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	config := TestConfig(buildDir, nil)
 
 	for _, test := range neverallowTests {
@@ -183,6 +196,7 @@
 	ctx := NewTestContext()
 	ctx.RegisterModuleType("cc_library", ModuleFactoryAdaptor(newMockCcLibraryModule))
 	ctx.RegisterModuleType("java_library", ModuleFactoryAdaptor(newMockJavaLibraryModule))
+	ctx.RegisterModuleType("java_library_host", ModuleFactoryAdaptor(newMockJavaLibraryModule))
 	ctx.RegisterModuleType("java_device_for_host", ModuleFactoryAdaptor(newMockJavaLibraryModule))
 	ctx.PostDepsMutators(registerNeverallowMutator)
 	ctx.Register()
@@ -234,7 +248,8 @@
 }
 
 type mockJavaLibraryProperties struct {
-	Libs []string
+	Libs        []string
+	Sdk_version *string
 }
 
 type mockJavaLibraryModule struct {
diff --git a/android/notices.go b/android/notices.go
index dbb88fc..8503593 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 5ad17fa..ff865c2 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -40,7 +40,8 @@
 }
 
 // Once computes a value the first time it is called with a given key per OncePer, and returns the
-// value without recomputing when called with the same key.  key must be hashable.
+// value without recomputing when called with the same key.  key must be hashable.  If value panics
+// the panic will be propagated but the next call to Once with the same key will return nil.
 func (once *OncePer) Once(key OnceKey, value func() interface{}) interface{} {
 	// Fast path: check if the key is already in the map
 	if v, ok := once.values.Load(key); ok {
@@ -54,10 +55,15 @@
 		return once.maybeWaitFor(key, v)
 	}
 
-	// The waiter is inserted, call the value constructor, store it, and signal the waiter
-	v := value()
-	once.values.Store(key, v)
-	close(waiter)
+	// The waiter is inserted, call the value constructor, store it, and signal the waiter.  Use defer in case
+	// the function panics.
+	var v interface{}
+	defer func() {
+		once.values.Store(key, v)
+		close(waiter)
+	}()
+
+	v = value()
 
 	return v
 }
diff --git a/android/onceper_test.go b/android/onceper_test.go
index 95303ba..1a55ff4 100644
--- a/android/onceper_test.go
+++ b/android/onceper_test.go
@@ -175,3 +175,43 @@
 		t.Errorf(`reentrant Once should return "a": %q`, a)
 	}
 }
+
+// Test that a recovered panic in a Once function doesn't deadlock
+func TestOncePerPanic(t *testing.T) {
+	once := OncePer{}
+	key := NewOnceKey("key")
+
+	ch := make(chan interface{})
+
+	var a interface{}
+
+	go func() {
+		defer func() {
+			ch <- recover()
+		}()
+
+		a = once.Once(key, func() interface{} {
+			panic("foo")
+		})
+	}()
+
+	p := <-ch
+
+	if p.(string) != "foo" {
+		t.Errorf(`expected panic with "foo", got %#v`, p)
+	}
+
+	if a != nil {
+		t.Errorf(`expected a to be nil, got %#v`, a)
+	}
+
+	// If the call to Once that panicked leaves the key in a bad state this will deadlock
+	b := once.Once(key, func() interface{} {
+		return "bar"
+	})
+
+	// The second call to Once should return nil inserted by the first call that panicked.
+	if b != nil {
+		t.Errorf(`expected b to be nil, got %#v`, b)
+	}
+}
diff --git a/android/override_module.go b/android/override_module.go
index ba66182..22fb7de 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -84,8 +84,13 @@
 	getOverrides() []OverrideModule
 
 	override(ctx BaseModuleContext, o OverrideModule)
+	getOverriddenBy() string
 
 	setOverridesProperty(overridesProperties *[]string)
+
+	// Due to complications with incoming dependencies, overrides are processed after DepsMutator.
+	// So, overridable properties need to be handled in a separate, dedicated deps mutator.
+	OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext)
 }
 
 // Base module struct for overridable module types
@@ -104,6 +109,8 @@
 	// set this to a pointer to the property through the InitOverridableModule function, so that
 	// override information is propagated and aggregated correctly.
 	overridesProperty *[]string
+
+	overriddenBy string
 }
 
 func InitOverridableModule(m OverridableModule, overridesProperty *[]string) {
@@ -151,14 +158,23 @@
 			}
 		}
 	}
+	b.overriddenBy = o.Name()
+}
+
+func (b *OverridableModuleBase) getOverriddenBy() string {
+	return b.overriddenBy
+}
+
+func (b *OverridableModuleBase) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
 }
 
 // Mutators for override/overridable modules. All the fun happens in these functions. It is critical
 // to keep them in this order and not put any order mutators between them.
-func RegisterOverridePreArchMutators(ctx RegisterMutatorsContext) {
+func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel()
 	ctx.TopDown("register_override", registerOverrideMutator).Parallel()
 	ctx.BottomUp("perform_override", performOverrideMutator).Parallel()
+	ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel()
 }
 
 type overrideBaseDependencyTag struct {
@@ -205,5 +221,22 @@
 		for i, o := range overrides {
 			mods[i+1].(OverridableModule).override(ctx, o)
 		}
+	} else if o, ok := ctx.Module().(OverrideModule); ok {
+		// Create a variant of the overriding module with its own name. This matches the above local
+		// variant name rule for overridden modules, and thus allows ReplaceDependencies to match the
+		// two.
+		ctx.CreateLocalVariations(o.Name())
+	}
+}
+
+func overridableModuleDepsMutator(ctx BottomUpMutatorContext) {
+	if b, ok := ctx.Module().(OverridableModule); ok {
+		if o := b.getOverriddenBy(); o != "" {
+			// Redirect dependencies on the overriding module to this overridden module. Overriding
+			// modules are basically pseudo modules, and all build actions are associated to overridden
+			// modules. Therefore, dependencies on overriding modules need to be forwarded there as well.
+			ctx.ReplaceDependencies(o)
+		}
+		b.OverridablePropertiesDepsMutator(ctx)
 	}
 }
diff --git a/android/package.go b/android/package.go
new file mode 100644
index 0000000..03f6a1e
--- /dev/null
+++ b/android/package.go
@@ -0,0 +1,194 @@
+// 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 (
+	"fmt"
+	"sync/atomic"
+
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterModuleType("package", PackageFactory)
+}
+
+// The information maintained about each package.
+type packageInfo struct {
+	// The module from which this information was populated. If `duplicated` = true then this is the
+	// module that has been renamed and must be used to report errors.
+	module *packageModule
+
+	// If true this indicates that there are two package statements in the same package which is not
+	// allowed and will cause the build to fail. This flag is set by packageRenamer and checked in
+	// packageErrorReporter
+	duplicated bool
+}
+
+type packageProperties struct {
+	Name string `blueprint:"mutated"`
+
+	// Specifies the default visibility for all modules defined in this package.
+	Default_visibility []string
+}
+
+type packageModule struct {
+	ModuleBase
+
+	properties  packageProperties
+	packageInfo *packageInfo
+}
+
+func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
+	// Nothing to do.
+}
+
+func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
+	// Nothing to do.
+}
+
+func (p *packageModule) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
+	// Override to create a package id.
+	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
+}
+
+func (p *packageModule) setName(name string) {
+	p.properties.Name = name
+}
+
+// Counter to ensure package modules are created with a unique name within whatever namespace they
+// belong.
+var packageCount uint32 = 0
+
+func PackageFactory() Module {
+	module := &packageModule{}
+
+	// Get a unique if for the package. Has to be done atomically as the creation of the modules are
+	// done in parallel.
+	id := atomic.AddUint32(&packageCount, 1)
+	name := fmt.Sprintf("soong_package_%d", id)
+
+	module.properties.Name = name
+
+	module.AddProperties(&module.properties)
+	return module
+}
+
+// Registers the function that renames the packages.
+func registerPackageRenamer(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("packageRenamer", packageRenamer).Parallel()
+	ctx.BottomUp("packageErrorReporter", packageErrorReporter).Parallel()
+}
+
+// Renames the package to match the package directory.
+//
+// This also creates a PackageInfo object for each package and uses that to detect and remember
+// duplicates for later error reporting.
+func packageRenamer(ctx BottomUpMutatorContext) {
+	m, ok := ctx.Module().(*packageModule)
+	if !ok {
+		return
+	}
+
+	packageName := "//" + ctx.ModuleDir()
+
+	pi := newPackageInfo(ctx, packageName, m)
+	if pi.module != m {
+		// Remember that the package was duplicated but do not rename as that will cause an error to
+		// be logged with the generated name. Similarly, reporting the error here will use the generated
+		// name as renames are only processed after this phase.
+		pi.duplicated = true
+	} else {
+		// This is the first package module in this package so rename it to match the package name.
+		m.setName(packageName)
+		ctx.Rename(packageName)
+
+		// Store a package info reference in the module.
+		m.packageInfo = pi
+	}
+}
+
+// Logs any deferred errors.
+func packageErrorReporter(ctx BottomUpMutatorContext) {
+	m, ok := ctx.Module().(*packageModule)
+	if !ok {
+		return
+	}
+
+	packageDir := ctx.ModuleDir()
+	packageName := "//" + packageDir
+
+	// Get the PackageInfo for the package. Should have been populated in the packageRenamer phase.
+	pi := findPackageInfo(ctx, packageName)
+	if pi == nil {
+		ctx.ModuleErrorf("internal error, expected package info to be present for package '%s'",
+			packageName)
+		return
+	}
+
+	if pi.module != m {
+		// The package module has been duplicated but this is not the module that has been renamed so
+		// ignore it. An error will be logged for the renamed module which will ensure that the error
+		// message uses the correct name.
+		return
+	}
+
+	// Check to see whether there are duplicate package modules in the package.
+	if pi.duplicated {
+		ctx.ModuleErrorf("package {...} specified multiple times")
+		return
+	}
+}
+
+type defaultPackageInfoKey string
+
+func newPackageInfo(
+	ctx BaseModuleContext, packageName string, module *packageModule) *packageInfo {
+	key := NewCustomOnceKey(defaultPackageInfoKey(packageName))
+
+	return ctx.Config().Once(key, func() interface{} {
+		return &packageInfo{module: module}
+	}).(*packageInfo)
+}
+
+// Get the PackageInfo for the package name (starts with //, no trailing /), is nil if no package
+// module type was specified.
+func findPackageInfo(ctx BaseModuleContext, packageName string) *packageInfo {
+	key := NewCustomOnceKey(defaultPackageInfoKey(packageName))
+
+	pi := ctx.Config().Once(key, func() interface{} {
+		return nil
+	})
+
+	if pi == nil {
+		return nil
+	} else {
+		return pi.(*packageInfo)
+	}
+}
diff --git a/android/package_test.go b/android/package_test.go
new file mode 100644
index 0000000..e5b0556
--- /dev/null
+++ b/android/package_test.go
@@ -0,0 +1,103 @@
+package android
+
+import (
+	"testing"
+)
+
+var packageTests = []struct {
+	name           string
+	fs             map[string][]byte
+	expectedErrors []string
+}{
+	// Package default_visibility handling is tested in visibility_test.go
+	{
+		name: "package must not accept visibility and name properties",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					name: "package",
+					visibility: ["//visibility:private"],
+				}`),
+		},
+		expectedErrors: []string{
+			`top/Blueprints:3:10: mutated field name cannot be set in a Blueprint file`,
+			`top/Blueprints:4:16: unrecognized property "visibility"`,
+		},
+	},
+	{
+		name: "multiple packages in separate directories",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+				}`),
+			"other/Blueprints": []byte(`
+				package {
+				}`),
+			"other/nested/Blueprints": []byte(`
+				package {
+				}`),
+		},
+	},
+	{
+		name: "package must not be specified more than once per package",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}
+
+        package {
+				}`),
+		},
+		expectedErrors: []string{
+			`module "//top": package {...} specified multiple times`,
+		},
+	},
+}
+
+func TestPackage(t *testing.T) {
+	for _, test := range packageTests {
+		t.Run(test.name, func(t *testing.T) {
+			_, errs := testPackage(test.fs)
+
+			expectedErrors := test.expectedErrors
+			if expectedErrors == nil {
+				FailIfErrored(t, errs)
+			} else {
+				for _, expectedError := range expectedErrors {
+					FailIfNoMatchingErrors(t, expectedError, errs)
+				}
+				if len(errs) > len(expectedErrors) {
+					t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
+					for i, expectedError := range expectedErrors {
+						t.Errorf("expectedErrors[%d] = %s", i, expectedError)
+					}
+					for i, err := range errs {
+						t.Errorf("errs[%d] = %s", i, err)
+					}
+				}
+			}
+		})
+	}
+}
+
+func testPackage(fs map[string][]byte) (*TestContext, []error) {
+
+	// Create a new config per test as visibility information is stored in the config.
+	config := TestArchConfig(buildDir, nil)
+
+	ctx := NewTestArchContext()
+	ctx.RegisterModuleType("package", ModuleFactoryAdaptor(PackageFactory))
+	ctx.PreArchMutators(registerPackageRenamer)
+	ctx.Register()
+
+	ctx.MockFileSystem(fs)
+
+	_, errs := ctx.ParseBlueprintsFiles(".")
+	if len(errs) > 0 {
+		return ctx, errs
+	}
+
+	_, errs = ctx.PrepareBuildActions(config)
+	return ctx, errs
+}
diff --git a/android/path_properties.go b/android/path_properties.go
index 1a12290..af7af59 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -39,14 +39,12 @@
 		pathProperties := pathPropertiesForPropertyStruct(ctx, ps)
 		pathProperties = FirstUniqueStrings(pathProperties)
 
-		var deps []string
 		for _, s := range pathProperties {
-			if m := SrcIsModule(s); m != "" {
-				deps = append(deps, m)
+			if m, t := SrcIsModuleWithTag(s); m != "" {
+				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
 			}
 		}
 
-		ctx.AddDependency(ctx.Module(), SourceDepTag, deps...)
 	}
 }
 
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index ecc2d21..e98c136 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
 	"reflect"
 	"testing"
 )
@@ -41,8 +39,10 @@
 }
 
 func (p *pathDepsMutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
-	ctx.VisitDirectDepsWithTag(SourceDepTag, func(dep Module) {
-		p.sourceDeps = append(p.sourceDeps, ctx.OtherModuleName(dep))
+	ctx.VisitDirectDeps(func(dep Module) {
+		if _, ok := ctx.OtherModuleDependencyTag(dep).(sourceOrOutputDependencyTag); ok {
+			p.sourceDeps = append(p.sourceDeps, ctx.OtherModuleName(dep))
+		}
 	})
 }
 
@@ -59,7 +59,7 @@
 				name: "foo",
 				foo: ":a",
 				bar: [":b"],
-				baz: ":c",
+				baz: ":c{.bar}",
 				qux: ":d",
 			}`,
 			deps: []string{"a", "b", "c"},
@@ -83,12 +83,6 @@
 		},
 	}
 
-	buildDir, err := ioutil.TempDir("", "soong_path_properties_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			config := TestArchConfig(buildDir, nil)
diff --git a/android/paths.go b/android/paths.go
index 8cc7057..0ea4447 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -41,9 +41,7 @@
 var _ PathContext = ModuleContext(nil)
 
 type ModuleInstallPathContext interface {
-	PathContext
-
-	androidBaseContext
+	BaseModuleContext
 
 	InstallInData() bool
 	InstallInSanitizerDir() bool
@@ -217,21 +215,23 @@
 	return ret
 }
 
-// PathsForModuleSrc returns Paths rooted from the module's local source directory.  It expands globs and references
-// to SourceFileProducer modules using the ":name" syntax.  Properties passed as the paths 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 true, then any missing
-// SourceFileProducer dependencies will cause the module to be marked as having missing dependencies.
+// PathsForModuleSrc returns Paths rooted from the module's local source directory.  It expands globs, references to
+// SourceFileProducer modules using the ":name" syntax, and references to OutputFileProducer modules using the
+// ":name{.tag}" syntax.  Properties passed as the paths 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 true then any missing SourceFileProducer or
+// OutputFileProducer dependencies will cause the module to be marked as having missing dependencies.
 func PathsForModuleSrc(ctx ModuleContext, paths []string) Paths {
 	return PathsForModuleSrcExcludes(ctx, paths, nil)
 }
 
 // PathsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding paths listed in
-// the excludes arguments.  It expands globs and references to SourceFileProducer modules in both paths and excludes
-// using the ":name" 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 true, then any missing SourceFileProducer
-// dependencies will cause the module to be marked as having missing dependencies.
+// the excludes arguments.  It expands globs, references to SourceFileProducer modules using the ":name" syntax, and
+// 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
+// having missing dependencies.
 func PathsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) Paths {
 	ret, missingDeps := PathsAndMissingDepsForModuleSrcExcludes(ctx, paths, excludes)
 	if ctx.Config().AllowMissingDependencies() {
@@ -245,12 +245,13 @@
 }
 
 // PathsAndMissingDepsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding
-// paths listed in the excludes arguments, and a list of missing dependencies.  It expands globs and references to
-// SourceFileProducer modules in both paths and excludes using the ":name" 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 true, then any missing SourceFileProducer dependencies will be returned,
-// and they will NOT cause the module to be marked as having missing dependencies.
+// paths listed in the excludes arguments, and a list of missing dependencies.  It expands globs, references to
+// SourceFileProducer modules using the ":name" syntax, and 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 true then any missing SourceFileProducer or
+// OutputFileProducer dependencies will be returned, and they will NOT cause the module to be marked as having missing
+// dependencies.
 func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) (Paths, []string) {
 	prefix := pathForModuleSrc(ctx).String()
 
@@ -262,16 +263,24 @@
 	var missingExcludeDeps []string
 
 	for _, e := range excludes {
-		if m := SrcIsModule(e); m != "" {
-			module := ctx.GetDirectDepWithTag(m, SourceDepTag)
+		if m, t := SrcIsModuleWithTag(e); m != "" {
+			module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
 			if module == nil {
 				missingExcludeDeps = append(missingExcludeDeps, m)
 				continue
 			}
-			if srcProducer, ok := module.(SourceFileProducer); ok {
+			if outProducer, ok := module.(OutputFileProducer); ok {
+				outputFiles, err := outProducer.OutputFiles(t)
+				if err != nil {
+					ctx.ModuleErrorf("path dependency %q: %s", e, err)
+				}
+				expandedExcludes = append(expandedExcludes, outputFiles.Strings()...)
+			} else if t != "" {
+				ctx.ModuleErrorf("path dependency %q is not an output file producing module", e)
+			} else if srcProducer, ok := module.(SourceFileProducer); ok {
 				expandedExcludes = append(expandedExcludes, srcProducer.Srcs().Strings()...)
 			} else {
-				ctx.ModuleErrorf("srcs dependency %q is not a source file producing module", m)
+				ctx.ModuleErrorf("path dependency %q is not a source file producing module", e)
 			}
 		} else {
 			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
@@ -307,12 +316,20 @@
 }
 
 func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (Paths, error) {
-	if m := SrcIsModule(s); m != "" {
-		module := ctx.GetDirectDepWithTag(m, SourceDepTag)
+	if m, t := SrcIsModuleWithTag(s); m != "" {
+		module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
 		if module == nil {
 			return nil, missingDependencyError{[]string{m}}
 		}
-		if srcProducer, ok := module.(SourceFileProducer); ok {
+		if outProducer, ok := module.(OutputFileProducer); ok {
+			outputFiles, err := outProducer.OutputFiles(t)
+			if err != nil {
+				return nil, fmt.Errorf("path dependency %q: %s", s, err)
+			}
+			return outputFiles, nil
+		} else if t != "" {
+			return nil, fmt.Errorf("path dependency %q is not an output file producing module", s)
+		} else if srcProducer, ok := module.(SourceFileProducer); ok {
 			moduleSrcs := srcProducer.Srcs()
 			for _, e := range expandedExcludes {
 				for j := 0; j < len(moduleSrcs); j++ {
@@ -324,7 +341,7 @@
 			}
 			return moduleSrcs, nil
 		} else {
-			return nil, fmt.Errorf("path dependency %q is not a source file producing module", m)
+			return nil, fmt.Errorf("path dependency %q is not a source file producing module", s)
 		}
 	} else if pathtools.IsGlob(s) {
 		paths := ctx.GlobFiles(pathForModuleSrc(ctx, s).String(), expandedExcludes)
@@ -350,7 +367,7 @@
 // each string. If incDirs is false, strip paths with a trailing '/' from the list.
 // It intended for use in globs that only list files that exist, so it allows '$' in
 // filenames.
-func pathsForModuleSrcFromFullPath(ctx ModuleContext, paths []string, incDirs bool) Paths {
+func pathsForModuleSrcFromFullPath(ctx BaseModuleContext, paths []string, incDirs bool) Paths {
 	prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
 	if prefix == "./" {
 		prefix = ""
@@ -967,7 +984,7 @@
 // PathForVndkRefAbiDump returns an OptionalPath representing the path of the
 // reference abi dump for the given module. This is not guaranteed to be valid.
 func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string,
-	isLlndk, isGzip bool) OptionalPath {
+	isLlndkOrNdk, isVndk, isGzip bool) OptionalPath {
 
 	arches := ctx.DeviceConfig().Arches()
 	if len(arches) == 0 {
@@ -980,10 +997,12 @@
 	}
 
 	var dirName string
-	if isLlndk {
+	if isLlndkOrNdk {
 		dirName = "ndk"
-	} else {
+	} else if isVndk {
 		dirName = "vndk"
+	} else {
+		dirName = "platform" // opt-in libs
 	}
 
 	binderBitness := ctx.DeviceConfig().BinderBitness()
@@ -1126,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"
 	}
@@ -1267,16 +1286,23 @@
 // MaybeRel performs the same function as filepath.Rel, but reports errors to a PathContext, and returns false if
 // targetPath is not inside basePath.
 func MaybeRel(ctx PathContext, basePath string, targetPath string) (string, bool) {
+	rel, isRel, err := maybeRelErr(basePath, targetPath)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+	return rel, isRel
+}
+
+func maybeRelErr(basePath string, targetPath string) (string, bool, error) {
 	// filepath.Rel returns an error if one path is absolute and the other is not, handle that case first.
 	if filepath.IsAbs(basePath) != filepath.IsAbs(targetPath) {
-		return "", false
+		return "", false, nil
 	}
 	rel, err := filepath.Rel(basePath, targetPath)
 	if err != nil {
-		reportPathError(ctx, err)
-		return "", false
+		return "", false, err
 	} else if rel == ".." || strings.HasPrefix(rel, "../") || strings.HasPrefix(rel, "/") {
-		return "", false
+		return "", false, nil
 	}
-	return rel, true
+	return rel, true, nil
 }
diff --git a/android/paths_test.go b/android/paths_test.go
index b52d713..8286e9a 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -17,8 +17,6 @@
 import (
 	"errors"
 	"fmt"
-	"io/ioutil"
-	"os"
 	"reflect"
 	"strings"
 	"testing"
@@ -200,7 +198,7 @@
 }
 
 type moduleInstallPathContextImpl struct {
-	androidBaseContextImpl
+	baseModuleContext
 
 	inData         bool
 	inSanitizerDir bool
@@ -212,7 +210,7 @@
 }
 
 func (m moduleInstallPathContextImpl) Config() Config {
-	return m.androidBaseContextImpl.config
+	return m.baseModuleContext.config
 }
 
 func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
@@ -244,7 +242,7 @@
 		{
 			name: "host binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: hostTarget,
 				},
 			},
@@ -255,7 +253,7 @@
 		{
 			name: "system binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 				},
 			},
@@ -265,7 +263,7 @@
 		{
 			name: "vendor binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   socSpecificModule,
 				},
@@ -276,7 +274,7 @@
 		{
 			name: "odm binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   deviceSpecificModule,
 				},
@@ -287,7 +285,7 @@
 		{
 			name: "product binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   productSpecificModule,
 				},
@@ -296,21 +294,21 @@
 			out: "target/product/test_device/product/bin/my_test",
 		},
 		{
-			name: "product_services binary",
+			name: "system_ext binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				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",
 		},
 
 		{
 			name: "system native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 				},
 				inData: true,
@@ -321,7 +319,7 @@
 		{
 			name: "vendor native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   socSpecificModule,
 				},
@@ -333,7 +331,7 @@
 		{
 			name: "odm native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   deviceSpecificModule,
 				},
@@ -345,7 +343,7 @@
 		{
 			name: "product native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   productSpecificModule,
 				},
@@ -356,11 +354,11 @@
 		},
 
 		{
-			name: "product_services native test binary",
+			name: "system_ext native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
-					kind:   productServicesSpecificModule,
+					kind:   systemExtSpecificModule,
 				},
 				inData: true,
 			},
@@ -371,7 +369,7 @@
 		{
 			name: "sanitized system binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 				},
 				inSanitizerDir: true,
@@ -382,7 +380,7 @@
 		{
 			name: "sanitized vendor binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   socSpecificModule,
 				},
@@ -394,7 +392,7 @@
 		{
 			name: "sanitized odm binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   deviceSpecificModule,
 				},
@@ -406,7 +404,7 @@
 		{
 			name: "sanitized product binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   productSpecificModule,
 				},
@@ -417,22 +415,22 @@
 		},
 
 		{
-			name: "sanitized product_services binary",
+			name: "sanitized system_ext binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				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",
 		},
 
 		{
 			name: "sanitized system native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 				},
 				inData:         true,
@@ -444,7 +442,7 @@
 		{
 			name: "sanitized vendor native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   socSpecificModule,
 				},
@@ -457,7 +455,7 @@
 		{
 			name: "sanitized odm native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   deviceSpecificModule,
 				},
@@ -470,7 +468,7 @@
 		{
 			name: "sanitized product native test binary",
 			ctx: &moduleInstallPathContextImpl{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
 					kind:   productSpecificModule,
 				},
@@ -481,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{
-				androidBaseContextImpl: androidBaseContextImpl{
+				baseModuleContext: baseModuleContext{
 					target: deviceTarget,
-					kind:   productServicesSpecificModule,
+					kind:   systemExtSpecificModule,
 				},
 				inData:         true,
 				inSanitizerDir: true,
@@ -497,7 +495,7 @@
 
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			tc.ctx.androidBaseContextImpl.config = testConfig
+			tc.ctx.baseModuleContext.config = testConfig
 			output := PathForModuleInstall(tc.ctx, tc.in...)
 			if output.basePath.path != tc.out {
 				t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
@@ -758,6 +756,50 @@
 	if !p.props.Module_handles_missing_deps {
 		p.missingDeps = ctx.GetMissingDependencies()
 	}
+
+	ctx.Build(pctx, BuildParams{
+		Rule:   Touch,
+		Output: PathForModuleOut(ctx, "output"),
+	})
+}
+
+type pathForModuleSrcOutputFileProviderModule struct {
+	ModuleBase
+	props struct {
+		Outs   []string
+		Tagged []string
+	}
+
+	outs   Paths
+	tagged Paths
+}
+
+func pathForModuleSrcOutputFileProviderModuleFactory() Module {
+	module := &pathForModuleSrcOutputFileProviderModule{}
+	module.AddProperties(&module.props)
+	InitAndroidModule(module)
+	return module
+}
+
+func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	for _, out := range p.props.Outs {
+		p.outs = append(p.outs, PathForModuleOut(ctx, out))
+	}
+
+	for _, tagged := range p.props.Tagged {
+		p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
+	}
+}
+
+func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
+	switch tag {
+	case "":
+		return p.outs, nil
+	case ".tagged":
+		return p.tagged, nil
+	default:
+		return nil, fmt.Errorf("unsupported tag %q", tag)
+	}
 }
 
 type pathForModuleSrcTestCase struct {
@@ -776,6 +818,7 @@
 			ctx := NewTestContext()
 
 			ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
+			ctx.RegisterModuleType("output_file_provider", ModuleFactoryAdaptor(pathForModuleSrcOutputFileProviderModuleFactory))
 			ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
 
 			fgBp := `
@@ -785,9 +828,18 @@
 				}
 			`
 
+			ofpBp := `
+				output_file_provider {
+					name: "b",
+					outs: ["gen/b"],
+					tagged: ["gen/c"],
+				}
+			`
+
 			mockFS := map[string][]byte{
 				"fg/Android.bp":     []byte(fgBp),
 				"foo/Android.bp":    []byte(test.bp),
+				"ofp/Android.bp":    []byte(ofpBp),
 				"fg/src/a":          nil,
 				"foo/src/b":         nil,
 				"foo/src/c":         nil,
@@ -799,7 +851,7 @@
 			ctx.MockFileSystem(mockFS)
 
 			ctx.Register()
-			_, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"})
+			_, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp", "ofp/Android.bp"})
 			FailIfErrored(t, errs)
 			_, errs = ctx.PrepareBuildActions(config)
 			FailIfErrored(t, errs)
@@ -871,6 +923,26 @@
 			rels: []string{"src/a"},
 		},
 		{
+			name: "output file provider",
+			bp: `
+			test {
+				name: "foo",
+				srcs: [":b"],
+			}`,
+			srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
+			rels: []string{"gen/b"},
+		},
+		{
+			name: "output file provider tagged",
+			bp: `
+			test {
+				name: "foo",
+				srcs: [":b{.tagged}"],
+			}`,
+			srcs: []string{buildDir + "/.intermediates/ofp/b/gen/c"},
+			rels: []string{"gen/c"},
+		},
+		{
 			name: "special characters glob",
 			bp: `
 			test {
@@ -882,12 +954,6 @@
 		},
 	}
 
-	buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	testPathForModuleSrc(t, buildDir, tests)
 }
 
@@ -924,6 +990,26 @@
 			rel: "src/a",
 		},
 		{
+			name: "output file provider",
+			bp: `
+			test {
+				name: "foo",
+				src: ":b",
+			}`,
+			src: buildDir + "/.intermediates/ofp/b/gen/b",
+			rel: "gen/b",
+		},
+		{
+			name: "output file provider tagged",
+			bp: `
+			test {
+				name: "foo",
+				src: ":b{.tagged}",
+			}`,
+			src: buildDir + "/.intermediates/ofp/b/gen/c",
+			rel: "gen/c",
+		},
+		{
 			name: "special characters glob",
 			bp: `
 			test {
@@ -935,22 +1021,10 @@
 		},
 	}
 
-	buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	testPathForModuleSrc(t, buildDir, tests)
 }
 
 func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
-	buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	config := TestConfig(buildDir, nil)
 	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 3be10f7..3d9804c 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -50,6 +50,11 @@
 	return "prebuilt_" + name
 }
 
+// The below source-related functions and the srcs, src fields are based on an assumption that
+// prebuilt modules have a static source property at the moment. Currently there is only one
+// exception, android_app_import, which chooses a source file depending on the product's DPI
+// preference configs. We'll want to add native support for dynamic source cases if we end up having
+// more modules like this.
 func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
 	if p.srcs != nil {
 		if len(*p.srcs) == 0 {
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 8f23d78..069e1f5 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -14,11 +14,7 @@
 
 package android
 
-import (
-	"fmt"
-	"io"
-	"strings"
-)
+import "strconv"
 
 // TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
 
@@ -27,6 +23,8 @@
 	RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
 	RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
 	RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+	RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
+	RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
 
 	PreDepsMutators(func(ctx RegisterMutatorsContext) {
 		ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
@@ -64,7 +62,9 @@
 	sourceFilePath Path
 	outputFilePath OutputPath
 	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
-	installDirBase         string
+	installDirBase string
+	// The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware.
+	socInstallDirBase      string
 	installDirPath         OutputPath
 	additionalDependencies *Paths
 }
@@ -124,7 +124,14 @@
 		return
 	}
 	p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-	p.installDirPath = PathForModuleInstall(ctx, p.installDirBase, String(p.properties.Sub_dir))
+
+	// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
+	// socInstallDirBase.
+	installBaseDir := p.installDirBase
+	if ctx.SocSpecific() && p.socInstallDirBase != "" {
+		installBaseDir = p.socInstallDirBase
+	}
+	p.installDirPath = PathForModuleInstall(ctx, installBaseDir, String(p.properties.Sub_dir))
 
 	// This ensures that outputFilePath has the correct name for others to
 	// use, as the source file may have a different name.
@@ -135,38 +142,25 @@
 	})
 }
 
-func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
-	return AndroidMkData{
-		Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
-			nameSuffix := ""
-			if p.inRecovery() && !p.onlyInRecovery() {
-				nameSuffix = ".recovery"
-			}
-			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
-			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-			fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
-			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
-			if p.commonProperties.Owner != nil {
-				fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", *p.commonProperties.Owner)
-			}
-			fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
-			if p.Host() {
-				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
-			}
-			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.outputFilePath.String())
-			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
-			fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", p.outputFilePath.Base())
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !p.Installable())
-			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
-			fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", p.Arch().ArchType.String())
+func (p *PrebuiltEtc) AndroidMkEntries() AndroidMkEntries {
+	nameSuffix := ""
+	if p.inRecovery() && !p.onlyInRecovery() {
+		nameSuffix = ".recovery"
+	}
+	return AndroidMkEntries{
+		Class:      "ETC",
+		SubName:    nameSuffix,
+		OutputFile: OptionalPathForPath(p.outputFilePath),
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			entries.SetString("LOCAL_MODULE_TAGS", "optional")
+			entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+			entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+			entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
 			if p.additionalDependencies != nil {
-				fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=")
 				for _, path := range *p.additionalDependencies {
-					fmt.Fprint(w, " "+path.String())
+					entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
 				}
-				fmt.Fprintln(w, "")
 			}
-			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 		},
 	}
 }
@@ -257,3 +251,23 @@
 		}
 	}
 }
+
+// prebuilt_font installs a font in <partition>/fonts directory.
+func PrebuiltFontFactory() Module {
+	module := &PrebuiltEtc{installDirBase: "fonts"}
+	InitPrebuiltEtcModule(module)
+	// This module is device-only
+	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+	return module
+}
+
+// prebuilt_firmware installs a firmware file to <partition>/etc/firmware directory for system image.
+// 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)
+	// This module is device-only
+	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+	return module
+}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index e0ade7e..0a2c7a4 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -15,23 +15,20 @@
 package android
 
 import (
-	"bufio"
-	"bytes"
-	"io/ioutil"
-	"os"
 	"path/filepath"
-	"strings"
+	"reflect"
 	"testing"
 )
 
 func testPrebuiltEtc(t *testing.T, bp string) (*TestContext, Config) {
-	config, buildDir := setUp(t)
-	defer tearDown(buildDir)
+	config := TestArchConfig(buildDir, nil)
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("prebuilt_etc", ModuleFactoryAdaptor(PrebuiltEtcFactory))
 	ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(PrebuiltEtcHostFactory))
 	ctx.RegisterModuleType("prebuilt_usr_share", ModuleFactoryAdaptor(PrebuiltUserShareFactory))
 	ctx.RegisterModuleType("prebuilt_usr_share_host", ModuleFactoryAdaptor(PrebuiltUserShareHostFactory))
+	ctx.RegisterModuleType("prebuilt_font", ModuleFactoryAdaptor(PrebuiltFontFactory))
+	ctx.RegisterModuleType("prebuilt_firmware", ModuleFactoryAdaptor(PrebuiltFirmwareFactory))
 	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
 		ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
 	})
@@ -51,20 +48,6 @@
 	return ctx, config
 }
 
-func setUp(t *testing.T) (config Config, buildDir string) {
-	buildDir, err := ioutil.TempDir("", "soong_prebuilt_etc_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	config = TestArchConfig(buildDir, nil)
-	return
-}
-
-func tearDown(buildDir string) {
-	os.RemoveAll(buildDir)
-}
-
 func TestPrebuiltEtcVariants(t *testing.T) {
 	ctx, _ := testPrebuiltEtc(t, `
 		prebuilt_etc {
@@ -139,45 +122,37 @@
 }
 
 func TestPrebuiltEtcAndroidMk(t *testing.T) {
-	ctx, _ := testPrebuiltEtc(t, `
+	ctx, config := testPrebuiltEtc(t, `
 		prebuilt_etc {
 			name: "foo",
 			src: "foo.conf",
 			owner: "abc",
 			filename_from_src: true,
+			required: ["modA", "moduleB"],
+			host_required: ["hostModA", "hostModB"],
+			target_required: ["targetModA"],
 		}
 	`)
 
-	data := AndroidMkData{}
-	data.Required = append(data.Required, "modA", "moduleB")
-
-	expected := map[string]string{
-		"LOCAL_MODULE":                "foo",
-		"LOCAL_MODULE_CLASS":          "ETC",
-		"LOCAL_MODULE_OWNER":          "abc",
-		"LOCAL_INSTALLED_MODULE_STEM": "foo.conf",
-		"LOCAL_REQUIRED_MODULES":      "modA moduleB",
+	expected := map[string][]string{
+		"LOCAL_MODULE":                  {"foo"},
+		"LOCAL_MODULE_CLASS":            {"ETC"},
+		"LOCAL_MODULE_OWNER":            {"abc"},
+		"LOCAL_INSTALLED_MODULE_STEM":   {"foo.conf"},
+		"LOCAL_REQUIRED_MODULES":        {"modA", "moduleB"},
+		"LOCAL_HOST_REQUIRED_MODULES":   {"hostModA", "hostModB"},
+		"LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"},
 	}
 
 	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
-	buf := &bytes.Buffer{}
-	mod.AndroidMk().Custom(buf, "foo", "", "", data)
-	for k, expected := range expected {
-		found := false
-		scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
-		for scanner.Scan() {
-			line := scanner.Text()
-			tok := strings.Split(line, " := ")
-			if tok[0] == k {
-				found = true
-				if tok[1] != expected {
-					t.Errorf("Incorrect %s '%s', expected '%s'", k, tok[1], expected)
-				}
+	entries := AndroidMkEntriesForTest(t, config, "", mod)
+	for k, expectedValue := range expected {
+		if value, ok := entries.EntryMap[k]; ok {
+			if !reflect.DeepEqual(value, expectedValue) {
+				t.Errorf("Incorrect %s '%s', expected '%s'", k, value, expectedValue)
 			}
-		}
-
-		if !found {
-			t.Errorf("No %s defined, saw %s", k, buf.String())
+		} else {
+			t.Errorf("No %s defined, saw %q", k, entries.EntryMap)
 		}
 	}
 }
@@ -229,3 +204,54 @@
 		t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
 	}
 }
+
+func TestPrebuiltFontInstallDirPath(t *testing.T) {
+	ctx, _ := testPrebuiltEtc(t, `
+		prebuilt_font {
+			name: "foo.conf",
+			src: "foo.conf",
+		}
+	`)
+
+	p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
+	expected := "target/product/test_device/system/fonts"
+	if p.installDirPath.RelPathString() != expected {
+		t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+	}
+}
+
+func TestPrebuiltFirmwareDirPath(t *testing.T) {
+	targetPath := "target/product/test_device"
+	tests := []struct {
+		description  string
+		config       string
+		expectedPath string
+	}{{
+		description: "prebuilt: system firmware",
+		config: `
+			prebuilt_firmware {
+				name: "foo.conf",
+				src: "foo.conf",
+			}`,
+		expectedPath: filepath.Join(targetPath, "system/etc/firmware"),
+	}, {
+		description: "prebuilt: vendor firmware",
+		config: `
+			prebuilt_firmware {
+				name: "foo.conf",
+				src: "foo.conf",
+				soc_specific: true,
+				sub_dir: "sub_dir",
+			}`,
+		expectedPath: filepath.Join(targetPath, "vendor/firmware/sub_dir"),
+	}}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			ctx, _ := testPrebuiltEtc(t, tt.config)
+			p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
+			if p.installDirPath.RelPathString() != tt.expectedPath {
+				t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath)
+			}
+		})
+	}
+}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index e182641..0a18e2c 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -15,8 +15,7 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
+	"fmt"
 	"testing"
 
 	"github.com/google/blueprint"
@@ -126,12 +125,6 @@
 }
 
 func TestPrebuilts(t *testing.T) {
-	buildDir, err := ioutil.TempDir("", "soong_prebuilt_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	config := TestConfig(buildDir, nil)
 
 	for _, test := range prebuiltsTests {
@@ -250,8 +243,13 @@
 	return &p.prebuilt
 }
 
-func (p *prebuiltModule) Srcs() Paths {
-	return Paths{p.src}
+func (p *prebuiltModule) OutputFiles(tag string) (Paths, error) {
+	switch tag {
+	case "":
+		return Paths{p.src}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 type sourceModule struct {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 2d0fac1..e53eb0d 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -21,6 +21,8 @@
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/shared"
 )
 
 // RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
@@ -30,6 +32,8 @@
 	installs       RuleBuilderInstalls
 	temporariesSet map[WritablePath]bool
 	restat         bool
+	sbox           bool
+	sboxOutDir     WritablePath
 	missingDeps    []string
 }
 
@@ -73,11 +77,36 @@
 }
 
 // Restat marks the rule as a restat rule, which will be passed to ModuleContext.Rule in BuildParams.Restat.
+//
+// Restat is not compatible with Sbox()
 func (r *RuleBuilder) Restat() *RuleBuilder {
+	if r.sbox {
+		panic("Restat() is not compatible with Sbox()")
+	}
 	r.restat = true
 	return r
 }
 
+// Sbox marks the rule as needing to be wrapped by sbox. The WritablePath should point to the output
+// directory that sbox will wipe. It should not be written to by any other rule. sbox will ensure
+// that all outputs have been written, and will discard any output files that were not specified.
+//
+// Sbox is not compatible with Restat()
+func (r *RuleBuilder) Sbox(outputDir WritablePath) *RuleBuilder {
+	if r.sbox {
+		panic("Sbox() may not be called more than once")
+	}
+	if len(r.commands) > 0 {
+		panic("Sbox() may not be called after Command()")
+	}
+	if r.restat {
+		panic("Sbox() is not compatible with Restat()")
+	}
+	r.sbox = true
+	r.sboxOutDir = outputDir
+	return r
+}
+
 // Install associates an output of the rule with an install location, which can be retrieved later using
 // RuleBuilder.Installs.
 func (r *RuleBuilder) Install(from Path, to string) {
@@ -88,7 +117,10 @@
 // created by this method.  That can be mutated through their methods in any order, as long as the mutations do not
 // race with any call to Build.
 func (r *RuleBuilder) Command() *RuleBuilderCommand {
-	command := &RuleBuilderCommand{}
+	command := &RuleBuilderCommand{
+		sbox:       r.sbox,
+		sboxOutDir: r.sboxOutDir,
+	}
 	r.commands = append(r.commands, command)
 	return command
 }
@@ -120,12 +152,16 @@
 // that are also outputs of another command in the same RuleBuilder are filtered out.
 func (r *RuleBuilder) Inputs() Paths {
 	outputs := r.outputSet()
+	depFiles := r.depFileSet()
 
 	inputs := make(map[string]Path)
 	for _, c := range r.commands {
 		for _, input := range c.inputs {
-			if _, isOutput := outputs[input.String()]; !isOutput {
-				inputs[input.String()] = input
+			inputStr := input.String()
+			if _, isOutput := outputs[inputStr]; !isOutput {
+				if _, isDepFile := depFiles[inputStr]; !isDepFile {
+					inputs[input.String()] = input
+				}
 			}
 		}
 	}
@@ -171,6 +207,16 @@
 	return outputList
 }
 
+func (r *RuleBuilder) depFileSet() map[string]WritablePath {
+	depFiles := make(map[string]WritablePath)
+	for _, c := range r.commands {
+		for _, depFile := range c.depFiles {
+			depFiles[depFile.String()] = depFile
+		}
+	}
+	return depFiles
+}
+
 // DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
 // as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
 func (r *RuleBuilder) DepFiles() WritablePaths {
@@ -221,7 +267,7 @@
 func (r *RuleBuilder) Commands() []string {
 	var commands []string
 	for _, c := range r.commands {
-		commands = append(commands, string(c.buf))
+		commands = append(commands, c.buf.String())
 	}
 	return commands
 }
@@ -237,9 +283,9 @@
 var _ BuilderContext = SingletonContext(nil)
 
 func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
-	return (&RuleBuilderCommand{}).
+	return r.Command().
 		Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).
-		Flags(depFiles.Strings())
+		Inputs(depFiles.Paths())
 }
 
 // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
@@ -259,9 +305,6 @@
 		return
 	}
 
-	tools := r.Tools()
-	commands := r.Commands()
-
 	var depFile WritablePath
 	var depFormat blueprint.Deps
 	if depFiles := r.DepFiles(); len(depFiles) > 0 {
@@ -269,37 +312,75 @@
 		depFormat = blueprint.DepsGCC
 		if len(depFiles) > 1 {
 			// Add a command locally that merges all depfiles together into the first depfile.
-			cmd := r.depFileMergerCmd(ctx, depFiles)
-			commands = append(commands, string(cmd.buf))
-			tools = append(tools, cmd.tools...)
+			r.depFileMergerCmd(ctx, depFiles)
+
+			if r.sbox {
+				// Check for Rel() errors, as all depfiles should be in the output dir
+				for _, path := range depFiles[1:] {
+					Rel(ctx, r.sboxOutDir.String(), path.String())
+				}
+			}
 		}
 	}
 
+	tools := r.Tools()
+	commands := r.Commands()
+	outputs := r.Outputs()
+
+	if len(commands) == 0 {
+		return
+	}
+	if len(outputs) == 0 {
+		panic("No outputs specified from any Commands")
+	}
+
+	commandString := strings.Join(proptools.NinjaEscapeList(commands), " && ")
+
+	if r.sbox {
+		sboxOutputs := make([]string, len(outputs))
+		for i, output := range outputs {
+			sboxOutputs[i] = "__SBOX_OUT_DIR__/" + Rel(ctx, r.sboxOutDir.String(), output.String())
+		}
+
+		if depFile != nil {
+			sboxOutputs = append(sboxOutputs, "__SBOX_OUT_DIR__/"+Rel(ctx, r.sboxOutDir.String(), depFile.String()))
+		}
+
+		commandString = proptools.ShellEscape(commandString)
+		if !strings.HasPrefix(commandString, `'`) {
+			commandString = `'` + commandString + `'`
+		}
+
+		sboxCmd := &RuleBuilderCommand{}
+		sboxCmd.Tool(ctx.Config().HostToolPath(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 = 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.
-	var output WritablePath
-	var implicitOutputs WritablePaths
-	if outputs := r.Outputs(); len(outputs) > 0 {
-		output = outputs[0]
-		implicitOutputs = outputs[1:]
-	}
+	output := outputs[0]
+	implicitOutputs := outputs[1:]
 
-	if len(commands) > 0 {
-		ctx.Build(pctx, BuildParams{
-			Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
-				Command:     strings.Join(proptools.NinjaEscapeList(commands), " && "),
-				CommandDeps: tools.Strings(),
-				Restat:      r.restat,
-			}),
-			Implicits:       r.Inputs(),
-			Output:          output,
-			ImplicitOutputs: implicitOutputs,
-			Depfile:         depFile,
-			Deps:            depFormat,
-			Description:     desc,
-		})
-	}
+	ctx.Build(pctx, BuildParams{
+		Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
+			Command:     commandString,
+			CommandDeps: tools.Strings(),
+			Restat:      r.restat,
+		}),
+		Implicits:       r.Inputs(),
+		Output:          output,
+		ImplicitOutputs: implicitOutputs,
+		Depfile:         depFile,
+		Deps:            depFormat,
+		Description:     desc,
+	})
 }
 
 // RuleBuilderCommand is a builder for a command in a command line.  It can be mutated by its methods to add to the
@@ -307,20 +388,42 @@
 // 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
+	buf      strings.Builder
 	inputs   Paths
 	outputs  WritablePaths
 	depFiles WritablePaths
 	tools    Paths
+
+	sbox       bool
+	sboxOutDir WritablePath
+}
+
+func (c *RuleBuilderCommand) addInput(path Path) string {
+	if c.sbox {
+		if rel, isRel, _ := maybeRelErr(c.sboxOutDir.String(), path.String()); isRel {
+			return "__SBOX_OUT_DIR__/" + rel
+		}
+	}
+	c.inputs = append(c.inputs, path)
+	return path.String()
+}
+
+func (c *RuleBuilderCommand) outputStr(path Path) string {
+	if c.sbox {
+		// Errors will be handled in RuleBuilder.Build where we have a context to report them
+		rel, _, _ := maybeRelErr(c.sboxOutDir.String(), path.String())
+		return "__SBOX_OUT_DIR__/" + rel
+	}
+	return path.String()
 }
 
 // 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
 }
 
@@ -378,8 +481,7 @@
 // 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 {
-	c.inputs = append(c.inputs, path)
-	return c.Text(path.String())
+	return c.Text(c.addInput(path))
 }
 
 // Inputs adds the specified input paths to the command line, separated by spaces.  The paths will also be added to the
@@ -394,14 +496,16 @@
 // Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
 // command line.
 func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
-	c.inputs = append(c.inputs, path)
+	c.addInput(path)
 	return c
 }
 
 // Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the
 // command line.
 func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
-	c.inputs = append(c.inputs, paths...)
+	for _, path := range paths {
+		c.addInput(path)
+	}
 	return c
 }
 
@@ -409,7 +513,7 @@
 // RuleBuilder.Outputs.
 func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
 	c.outputs = append(c.outputs, path)
-	return c.Text(path.String())
+	return c.Text(c.outputStr(path))
 }
 
 // Outputs adds the specified output paths to the command line, separated by spaces.  The paths will also be added to
@@ -421,12 +525,21 @@
 	return c
 }
 
+// OutputDir adds the output directory to the command line. This is only available when used with RuleBuilder.Sbox,
+// and will be the temporary output directory managed by sbox, not the final one.
+func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
+	if !c.sbox {
+		panic("OutputDir only valid with Sbox")
+	}
+	return c.Text("__SBOX_OUT_DIR__")
+}
+
 // DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
 // line, and causes RuleBuilder.Build file to set the depfile flag for ninja.  If multiple depfiles are added to
 // commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
 func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
 	c.depFiles = append(c.depFiles, path)
-	return c.Text(path.String())
+	return c.Text(c.outputStr(path))
 }
 
 // ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
@@ -455,16 +568,18 @@
 // FlagWithInput adds the specified flag and input path to the command line, with no separator between them.  The path
 // will also be added to the dependencies returned by RuleBuilder.Inputs.
 func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
-	c.inputs = append(c.inputs, path)
-	return c.Text(flag + path.String())
+	return c.Text(flag + c.addInput(path))
 }
 
 // FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep
 // and no separator between the flag and inputs.  The input paths will also be added to the dependencies returned by
 // RuleBuilder.Inputs.
 func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand {
-	c.inputs = append(c.inputs, paths...)
-	return c.FlagWithList(flag, paths.Strings(), sep)
+	strs := make([]string, len(paths))
+	for i, path := range paths {
+		strs[i] = c.addInput(path)
+	}
+	return c.FlagWithList(flag, strs, sep)
 }
 
 // FlagForEachInput adds the specified flag joined with each input path to the command line.  The input paths will also
@@ -481,19 +596,19 @@
 // will also be added to the outputs returned by RuleBuilder.Outputs.
 func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand {
 	c.outputs = append(c.outputs, path)
-	return c.Text(flag + path.String())
+	return c.Text(flag + c.outputStr(path))
 }
 
 // FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them.  The path
 // will also be added to the outputs returned by RuleBuilder.Outputs.
 func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
 	c.depFiles = append(c.depFiles, path)
-	return c.Text(flag + path.String())
+	return c.Text(flag + c.outputStr(path))
 }
 
 // String returns the command line.
 func (c *RuleBuilderCommand) String() string {
-	return string(c.buf)
+	return c.buf.String()
 }
 
 func ninjaNameEscape(s string) string {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 7bad025..cfbc2ab 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -16,12 +16,14 @@
 
 import (
 	"fmt"
-	"io/ioutil"
-	"os"
 	"path/filepath"
 	"reflect"
 	"strings"
 	"testing"
+
+	"github.com/google/blueprint"
+
+	"android/soong/shared"
 )
 
 func pathContext() PathContext {
@@ -234,8 +236,6 @@
 }
 
 func TestRuleBuilder(t *testing.T) {
-	rule := NewRuleBuilder()
-
 	fs := map[string][]byte{
 		"dep_fixer": nil,
 		"input":     nil,
@@ -249,73 +249,114 @@
 
 	ctx := PathContextForTesting(TestConfig("out", nil), fs)
 
-	cmd := rule.Command().
-		DepFile(PathForOutput(ctx, "DepFile")).
-		Flag("Flag").
-		FlagWithArg("FlagWithArg=", "arg").
-		FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
-		FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
-		FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
-		Implicit(PathForSource(ctx, "Implicit")).
-		ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
-		ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
-		Input(PathForSource(ctx, "Input")).
-		Output(PathForOutput(ctx, "Output")).
-		Text("Text").
-		Tool(PathForSource(ctx, "Tool"))
+	addCommands := func(rule *RuleBuilder) {
+		cmd := rule.Command().
+			DepFile(PathForOutput(ctx, "DepFile")).
+			Flag("Flag").
+			FlagWithArg("FlagWithArg=", "arg").
+			FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
+			FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
+			FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
+			Implicit(PathForSource(ctx, "Implicit")).
+			ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
+			ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
+			Input(PathForSource(ctx, "Input")).
+			Output(PathForOutput(ctx, "Output")).
+			Text("Text").
+			Tool(PathForSource(ctx, "Tool"))
 
-	rule.Command().
-		Text("command2").
-		DepFile(PathForOutput(ctx, "depfile2")).
-		Input(PathForSource(ctx, "input2")).
-		Output(PathForOutput(ctx, "output2")).
-		Tool(PathForSource(ctx, "tool2"))
+		rule.Command().
+			Text("command2").
+			DepFile(PathForOutput(ctx, "depfile2")).
+			Input(PathForSource(ctx, "input2")).
+			Output(PathForOutput(ctx, "output2")).
+			Tool(PathForSource(ctx, "tool2"))
 
-	// Test updates to the first command after the second command has been started
-	cmd.Text("after command2")
-	// Test updating a command when the previous update did not replace the cmd variable
-	cmd.Text("old cmd")
+		// Test updates to the first command after the second command has been started
+		cmd.Text("after command2")
+		// Test updating a command when the previous update did not replace the cmd variable
+		cmd.Text("old cmd")
 
-	// Test a command that uses the output of a previous command as an input
-	rule.Command().
-		Text("command3").
-		Input(PathForSource(ctx, "input3")).
-		Input(PathForOutput(ctx, "output2")).
-		Output(PathForOutput(ctx, "output3"))
-
-	wantCommands := []string{
-		"out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
-		"command2 out/depfile2 input2 out/output2 tool2",
-		"command3 input3 out/output2 out/output3",
+		// Test a command that uses the output of a previous command as an input
+		rule.Command().
+			Text("command3").
+			Input(PathForSource(ctx, "input3")).
+			Input(PathForOutput(ctx, "output2")).
+			Output(PathForOutput(ctx, "output3"))
 	}
 
-	wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
-
 	wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
 	wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
 	wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
 	wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
 
-	if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
-		t.Errorf("\nwant rule.Commands() = %#v\n                   got %#v", w, g)
-	}
+	t.Run("normal", func(t *testing.T) {
+		rule := NewRuleBuilder()
+		addCommands(rule)
 
-	if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
-		t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
-	}
+		wantCommands := []string{
+			"out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
+			"command2 out/depfile2 input2 out/output2 tool2",
+			"command3 input3 out/output2 out/output3",
+		}
 
-	if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
-		t.Errorf("\nwant rule.Inputs() = %#v\n                 got %#v", w, g)
-	}
-	if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
-		t.Errorf("\nwant rule.Outputs() = %#v\n                  got %#v", w, g)
-	}
-	if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
-		t.Errorf("\nwant rule.DepFiles() = %#v\n                  got %#v", w, g)
-	}
-	if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
-		t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
-	}
+		wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
+
+		if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+			t.Errorf("\nwant rule.Commands() = %#v\n                   got %#v", w, g)
+		}
+
+		if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Inputs() = %#v\n                 got %#v", w, g)
+		}
+		if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Outputs() = %#v\n                  got %#v", w, g)
+		}
+		if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.DepFiles() = %#v\n                  got %#v", w, g)
+		}
+		if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
+		}
+
+		if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+			t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
+		}
+	})
+
+	t.Run("sbox", func(t *testing.T) {
+		rule := NewRuleBuilder().Sbox(PathForOutput(ctx))
+		addCommands(rule)
+
+		wantCommands := []string{
+			"__SBOX_OUT_DIR__/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_OUT_DIR__/depfile FlagWithInput=input FlagWithOutput=__SBOX_OUT_DIR__/output Input __SBOX_OUT_DIR__/Output Text Tool after command2 old cmd",
+			"command2 __SBOX_OUT_DIR__/depfile2 input2 __SBOX_OUT_DIR__/output2 tool2",
+			"command3 input3 __SBOX_OUT_DIR__/output2 __SBOX_OUT_DIR__/output3",
+		}
+
+		wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_OUT_DIR__/DepFile __SBOX_OUT_DIR__/depfile __SBOX_OUT_DIR__/ImplicitDepFile __SBOX_OUT_DIR__/depfile2"
+
+		if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+			t.Errorf("\nwant rule.Commands() = %#v\n                   got %#v", w, g)
+		}
+
+		if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Inputs() = %#v\n                 got %#v", w, g)
+		}
+		if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Outputs() = %#v\n                  got %#v", w, g)
+		}
+		if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.DepFiles() = %#v\n                  got %#v", w, g)
+		}
+		if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
+		}
+
+		if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+			t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
+		}
+	})
 }
 
 func testRuleBuilderFactory() Module {
@@ -329,14 +370,19 @@
 	ModuleBase
 	properties struct {
 		Src string
+
+		Restat bool
+		Sbox   bool
 	}
 }
 
 func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 	in := PathForSource(ctx, t.properties.Src)
 	out := PathForModuleOut(ctx, ctx.ModuleName())
+	outDep := PathForModuleOut(ctx, ctx.ModuleName()+".d")
+	outDir := PathForModuleOut(ctx)
 
-	testRuleBuilder_Build(ctx, in, out)
+	testRuleBuilder_Build(ctx, in, out, outDep, outDir, t.properties.Restat, t.properties.Sbox)
 }
 
 type testRuleBuilderSingleton struct{}
@@ -348,30 +394,38 @@
 func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
 	in := PathForSource(ctx, "bar")
 	out := PathForOutput(ctx, "baz")
-	testRuleBuilder_Build(ctx, in, out)
+	outDep := PathForOutput(ctx, "baz.d")
+	outDir := PathForOutput(ctx)
+	testRuleBuilder_Build(ctx, in, out, outDep, outDir, true, false)
 }
 
-func testRuleBuilder_Build(ctx BuilderContext, in Path, out WritablePath) {
+func testRuleBuilder_Build(ctx BuilderContext, in Path, out, outDep, outDir WritablePath, restat, sbox bool) {
 	rule := NewRuleBuilder()
 
-	rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out)
+	if sbox {
+		rule.Sbox(outDir)
+	}
 
-	rule.Restat()
+	rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out).ImplicitDepFile(outDep)
+
+	if restat {
+		rule.Restat()
+	}
 
 	rule.Build(pctx, ctx, "rule", "desc")
 }
 
 func TestRuleBuilder_Build(t *testing.T) {
-	buildDir, err := ioutil.TempDir("", "soong_test_rule_builder")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	bp := `
 		rule_builder_test {
 			name: "foo",
 			src: "bar",
+			restat: true,
+		}
+		rule_builder_test {
+			name: "foo_sbox",
+			src: "bar",
+			sbox: true,
 		}
 	`
 
@@ -391,9 +445,18 @@
 	_, errs = ctx.PrepareBuildActions(config)
 	FailIfErrored(t, errs)
 
-	check := func(t *testing.T, params TestingBuildParams, wantOutput string) {
-		if len(params.RuleParams.CommandDeps) != 1 || params.RuleParams.CommandDeps[0] != "cp" {
-			t.Errorf("want RuleParams.CommandDeps = [%q], got %q", "cp", params.RuleParams.CommandDeps)
+	check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) {
+		if params.RuleParams.Command != wantCommand {
+			t.Errorf("\nwant RuleParams.Command = %q\n                      got %q", wantCommand, params.RuleParams.Command)
+		}
+
+		wantDeps := append([]string{"cp"}, extraCmdDeps...)
+		if !reflect.DeepEqual(params.RuleParams.CommandDeps, wantDeps) {
+			t.Errorf("\nwant RuleParams.CommandDeps = %q\n                          got %q", wantDeps, params.RuleParams.CommandDeps)
+		}
+
+		if params.RuleParams.Restat != wantRestat {
+			t.Errorf("want RuleParams.Restat = %v, got %v", wantRestat, params.RuleParams.Restat)
 		}
 
 		if len(params.Implicits) != 1 || params.Implicits[0].String() != "bar" {
@@ -404,17 +467,39 @@
 			t.Errorf("want Output = %q, got %q", wantOutput, params.Output)
 		}
 
-		if !params.RuleParams.Restat {
-			t.Errorf("want RuleParams.Restat = true, got %v", params.RuleParams.Restat)
+		if len(params.ImplicitOutputs) != 0 {
+			t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
+		}
+
+		if params.Depfile.String() != wantDepfile {
+			t.Errorf("want Depfile = %q, got %q", wantDepfile, params.Depfile)
+		}
+
+		if params.Deps != blueprint.DepsGCC {
+			t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
 		}
 	}
 
 	t.Run("module", func(t *testing.T) {
+		outFile := filepath.Join(buildDir, ".intermediates", "foo", "foo")
 		check(t, ctx.ModuleForTests("foo", "").Rule("rule"),
-			filepath.Join(buildDir, ".intermediates", "foo", "foo"))
+			"cp bar "+outFile,
+			outFile, outFile+".d", true, nil)
+	})
+	t.Run("sbox", func(t *testing.T) {
+		outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
+		outFile := filepath.Join(outDir, "foo_sbox")
+		sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox")
+		sandboxPath := shared.TempDirForOutDir(buildDir)
+
+		cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " __SBOX_OUT_DIR__/foo_sbox __SBOX_OUT_DIR__/foo_sbox.d"
+
+		check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"),
+			cmd, outFile, outFile+".d", false, []string{sbox})
 	})
 	t.Run("singleton", func(t *testing.T) {
+		outFile := filepath.Join(buildDir, "baz")
 		check(t, ctx.SingletonForTests("rule_builder_test").Rule("rule"),
-			filepath.Join(buildDir, "baz"))
+			"cp bar "+outFile, outFile, outFile+".d", true, nil)
 	})
 }
diff --git a/android/sh_binary.go b/android/sh_binary.go
index cf415c5..2855aa0 100644
--- a/android/sh_binary.go
+++ b/android/sh_binary.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"io"
 	"strings"
 )
 
@@ -30,6 +29,7 @@
 	RegisterModuleType("sh_binary", ShBinaryFactory)
 	RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
 	RegisterModuleType("sh_test", ShTestFactory)
+	RegisterModuleType("sh_test_host", ShTestHostFactory)
 }
 
 type shBinaryProperties struct {
@@ -58,6 +58,10 @@
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
 	Test_config *string `android:"arch_variant"`
+
+	// list of files or filegroup modules that provide data that should be installed alongside
+	// the test.
+	Data []string `android:"path,arch_variant"`
 }
 
 type ShBinary struct {
@@ -73,6 +77,8 @@
 	ShBinary
 
 	testProperties TestProperties
+
+	data Paths
 }
 
 func (s *ShBinary) DepsMutator(ctx BottomUpMutatorContext) {
@@ -122,30 +128,50 @@
 	})
 }
 
-func (s *ShBinary) AndroidMk() AndroidMkData {
-	return AndroidMkData{
+func (s *ShBinary) AndroidMkEntries() AndroidMkEntries {
+	return AndroidMkEntries{
 		Class:      "EXECUTABLES",
 		OutputFile: OptionalPathForPath(s.outputFilePath),
 		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
-		Extra: []AndroidMkExtraFunc{
-			func(w io.Writer, outputFile Path) {
-				fmt.Fprintln(w, "LOCAL_MODULE_RELATIVE_PATH :=", String(s.properties.Sub_dir))
-				fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX :=")
-				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", s.outputFilePath.Rel())
-			},
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			s.customAndroidMkEntries(entries)
 		},
 	}
 }
 
-func (s *ShTest) AndroidMk() AndroidMkData {
-	data := s.ShBinary.AndroidMk()
-	data.Class = "NATIVE_TESTS"
-	data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
-		fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-			strings.Join(s.testProperties.Test_suites, " "))
-		fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=", String(s.testProperties.Test_config))
-	})
-	return data
+func (s *ShBinary) customAndroidMkEntries(entries *AndroidMkEntries) {
+	entries.SetString("LOCAL_MODULE_RELATIVE_PATH", String(s.properties.Sub_dir))
+	entries.SetString("LOCAL_MODULE_SUFFIX", "")
+	entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
+}
+
+func (s *ShTest) GenerateAndroidBuildActions(ctx ModuleContext) {
+	s.ShBinary.GenerateAndroidBuildActions(ctx)
+
+	s.data = PathsForModuleSrc(ctx, s.testProperties.Data)
+}
+
+func (s *ShTest) AndroidMkEntries() AndroidMkEntries {
+	return AndroidMkEntries{
+		Class:      "NATIVE_TESTS",
+		OutputFile: OptionalPathForPath(s.outputFilePath),
+		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			s.customAndroidMkEntries(entries)
+
+			entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
+			entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
+			for _, d := range s.data {
+				rel := d.Rel()
+				path := d.String()
+				if !strings.HasSuffix(path, rel) {
+					panic(fmt.Errorf("path %q does not end with %q", path, rel))
+				}
+				path = strings.TrimSuffix(path, rel)
+				entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
+			}
+		},
+	}
 }
 
 func InitShBinaryModule(s *ShBinary) {
@@ -170,6 +196,7 @@
 	return module
 }
 
+// sh_test defines a shell script based test module.
 func ShTestFactory() Module {
 	module := &ShTest{}
 	InitShBinaryModule(&module.ShBinary)
@@ -178,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
new file mode 100644
index 0000000..9df769c
--- /dev/null
+++ b/android/sh_binary_test.go
@@ -0,0 +1,71 @@
+package android
+
+import (
+	"reflect"
+	"testing"
+)
+
+func testShBinary(t *testing.T, bp string) (*TestContext, Config) {
+	config := TestArchConfig(buildDir, nil)
+
+	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),
+		"test.sh":            nil,
+		"testdata/data1":     nil,
+		"testdata/sub/data2": nil,
+	}
+	ctx.MockFileSystem(mockFiles)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	return ctx, config
+}
+
+func TestShTestTestData(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test {
+			name: "foo",
+			src: "test.sh",
+			filename: "test.sh",
+			data: [
+				"testdata/data1",
+				"testdata/sub/data2",
+			],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+
+	entries := AndroidMkEntriesForTest(t, config, "", mod)
+	expected := []string{":testdata/data1", ":testdata/sub/data2"}
+	actual := entries.EntryMap["LOCAL_TEST_DATA"]
+	if !reflect.DeepEqual(expected, actual) {
+		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 0ec5af5..44bee4b 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -37,6 +37,8 @@
 
 	ctx.SetNameInterface(nameResolver)
 
+	ctx.preArch = append(ctx.preArch, registerLoadHookMutator)
+
 	ctx.postDeps = append(ctx.postDeps, registerPathDepsMutator)
 
 	return ctx
@@ -177,7 +179,7 @@
 
 func maybeBuildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
 	for _, p := range provider.BuildParamsForTests() {
-		if p.Description == desc {
+		if strings.Contains(p.Description, desc) {
 			return newTestingBuildParams(provider, p)
 		}
 	}
@@ -369,3 +371,14 @@
 		}
 	}
 }
+
+func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkEntries {
+	var p AndroidMkEntriesProvider
+	var ok bool
+	if p, ok = mod.(AndroidMkEntriesProvider); !ok {
+		t.Errorf("module does not implmement AndroidMkEntriesProvider: " + mod.Name())
+	}
+	entries := p.AndroidMkEntries()
+	entries.fillInEntries(config, bpPath, mod)
+	return entries
+}
diff --git a/android/util.go b/android/util.go
index f9dce6f..3b8bc78 100644
--- a/android/util.go
+++ b/android/util.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"regexp"
 	"runtime"
 	"sort"
@@ -52,10 +53,40 @@
 	return string(ret)
 }
 
-func sortedKeys(m map[string][]string) []string {
-	s := make([]string, 0, len(m))
-	for k := range m {
-		s = append(s, k)
+func JoinWithSuffix(strs []string, suffix string, separator string) string {
+	if len(strs) == 0 {
+		return ""
+	}
+
+	if len(strs) == 1 {
+		return strs[0] + suffix
+	}
+
+	n := len(" ") * (len(strs) - 1)
+	for _, s := range strs {
+		n += len(suffix) + len(s)
+	}
+
+	ret := make([]byte, 0, n)
+	for i, s := range strs {
+		if i != 0 {
+			ret = append(ret, separator...)
+		}
+		ret = append(ret, s...)
+		ret = append(ret, suffix...)
+	}
+	return string(ret)
+}
+
+func SortedStringKeys(m interface{}) []string {
+	v := reflect.ValueOf(m)
+	if v.Kind() != reflect.Map {
+		panic(fmt.Sprintf("%#v is not a map", m))
+	}
+	keys := v.MapKeys()
+	s := make([]string, 0, len(keys))
+	for _, key := range keys {
+		s = append(s, key.String())
 	}
 	sort.Strings(s)
 	return s
diff --git a/android/variable.go b/android/variable.go
index e643c0e..fcd92d4 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -85,10 +85,12 @@
 		// are used for dogfooding and performance testing, and should be as similar to user builds
 		// as possible.
 		Debuggable struct {
-			Cflags   []string
-			Cppflags []string
-			Init_rc  []string
-			Required []string
+			Cflags          []string
+			Cppflags        []string
+			Init_rc         []string
+			Required        []string
+			Host_required   []string
+			Target_required []string
 		}
 
 		// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
@@ -163,6 +165,16 @@
 	DeviceSecondaryCpuVariant  *string  `json:",omitempty"`
 	DeviceSecondaryAbi         []string `json:",omitempty"`
 
+	NativeBridgeArch        *string  `json:",omitempty"`
+	NativeBridgeArchVariant *string  `json:",omitempty"`
+	NativeBridgeCpuVariant  *string  `json:",omitempty"`
+	NativeBridgeAbi         []string `json:",omitempty"`
+
+	NativeBridgeSecondaryArch        *string  `json:",omitempty"`
+	NativeBridgeSecondaryArchVariant *string  `json:",omitempty"`
+	NativeBridgeSecondaryCpuVariant  *string  `json:",omitempty"`
+	NativeBridgeSecondaryAbi         []string `json:",omitempty"`
+
 	HostArch          *string `json:",omitempty"`
 	HostSecondaryArch *string `json:",omitempty"`
 
@@ -220,10 +232,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"`
@@ -265,6 +277,9 @@
 	BoardOdmSepolicyDirs         []string `json:",omitempty"`
 	BoardPlatPublicSepolicyDirs  []string `json:",omitempty"`
 	BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
+	BoardSepolicyM4Defs          []string `json:",omitempty"`
+
+	BoardVndkRuntimeDisable *bool `json:",omitempty"`
 
 	VendorVars map[string]map[string]string `json:",omitempty"`
 
@@ -286,7 +301,13 @@
 	ProductHiddenAPIStubsSystem []string `json:",omitempty"`
 	ProductHiddenAPIStubsTest   []string `json:",omitempty"`
 
+	ProductPublicSepolicyDirs  []string `json:",omitempty"`
+	ProductPrivateSepolicyDirs []string `json:",omitempty"`
+	ProductCompatibleProperty  *bool    `json:",omitempty"`
+
 	TargetFSConfigGen []string `json:",omitempty"`
+
+	MissingUsesLibraries []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -303,9 +324,15 @@
 
 func (v *productVariables) SetDefaultConfig() {
 	*v = productVariables{
-		Platform_sdk_version:              intPtr(26),
-		Platform_version_active_codenames: []string{"P"},
-		Platform_version_future_codenames: []string{"P"},
+		BuildNumberFromFile: stringPtr("123456789"),
+
+		Platform_version_name:             stringPtr("Q"),
+		Platform_sdk_version:              intPtr(28),
+		Platform_sdk_codename:             stringPtr("Q"),
+		Platform_sdk_final:                boolPtr(false),
+		Platform_version_active_codenames: []string{"Q"},
+		Platform_version_future_codenames: []string{"Q"},
+		Platform_vndk_version:             stringPtr("Q"),
 
 		HostArch:                   stringPtr("x86_64"),
 		HostSecondaryArch:          stringPtr("x86"),
@@ -375,12 +402,12 @@
 	}
 }
 
-func (a *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext,
+func (m *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext,
 	prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) {
 
 	printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue)
 
-	err := proptools.AppendMatchingProperties(a.generalProperties,
+	err := proptools.AppendMatchingProperties(m.generalProperties,
 		productVariablePropertyValue.Addr().Interface(), nil)
 	if err != nil {
 		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
diff --git a/android/visibility.go b/android/visibility.go
new file mode 100644
index 0000000..94af343
--- /dev/null
+++ b/android/visibility.go
@@ -0,0 +1,446 @@
+// 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 (
+	"fmt"
+	"regexp"
+	"strings"
+	"sync"
+)
+
+// Enforces visibility rules between modules.
+//
+// Multi stage process:
+// * First stage works bottom up, before defaults expansion, to check the syntax of the visibility
+//   rules that have been specified.
+//
+// * Second stage works bottom up to extract the package info for each package and store them in a
+//   map by package name. See package.go for functionality for this.
+//
+// * Third stage works bottom up to extract visibility information from the modules, parse it,
+//   create visibilityRule structures and store them in a map keyed by the module's
+//   qualifiedModuleName instance, i.e. //<pkg>:<name>. The map is stored in the context rather
+//   than a global variable for testing. Each test has its own Config so they do not share a map
+//   and so can be run in parallel. If a module has no visibility specified then it uses the
+//   default package visibility if specified.
+//
+// * Fourth stage works top down and iterates over all the deps for each module. If the dep is in
+//   the same package then it is automatically visible. Otherwise, for each dep it first extracts
+//   its visibilityRule from the config map. If one could not be found then it assumes that it is
+//   publicly visible. Otherwise, it calls the visibility rule to check that the module can see
+//   the dependency. If it cannot then an error is reported.
+//
+// TODO(b/130631145) - Make visibility work properly with prebuilts.
+// TODO(b/130796911) - Make visibility work properly with defaults.
+
+// Patterns for the values that can be specified in visibility property.
+const (
+	packagePattern        = `//([^/:]+(?:/[^/:]+)*)`
+	namePattern           = `:([^/:]+)`
+	visibilityRulePattern = `^(?:` + packagePattern + `)?(?:` + namePattern + `)?$`
+)
+
+var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
+
+// A visibility rule is associated with a module and determines which other modules it is visible
+// to, i.e. which other modules can depend on the rule's module.
+type visibilityRule interface {
+	// Check to see whether this rules matches m.
+	// Returns true if it does, false otherwise.
+	matches(m qualifiedModuleName) bool
+
+	String() string
+}
+
+// Describes the properties provided by a module that contain visibility rules.
+type visibilityPropertyImpl struct {
+	name          string
+	stringsGetter func() []string
+}
+
+type visibilityProperty interface {
+	getName() string
+	getStrings() []string
+}
+
+func newVisibilityProperty(name string, stringsGetter func() []string) visibilityProperty {
+	return visibilityPropertyImpl{
+		name:          name,
+		stringsGetter: stringsGetter,
+	}
+}
+
+func (p visibilityPropertyImpl) getName() string {
+	return p.name
+}
+
+func (p visibilityPropertyImpl) getStrings() []string {
+	return p.stringsGetter()
+}
+
+// A compositeRule is a visibility rule composed from a list of atomic visibility rules.
+//
+// The list corresponds to the list of strings in the visibility property after defaults expansion.
+// Even though //visibility:public is not allowed together with other rules in the visibility list
+// of a single module, it is allowed here to permit a module to override an inherited visibility
+// spec with public visibility.
+//
+// //visibility:private is not allowed in the same way, since we'd need to check for it during the
+// defaults expansion to make that work. No non-private visibility rules are allowed in a
+// compositeRule containing a privateRule.
+//
+// This array will only be [] if all the rules are invalid and will behave as if visibility was
+// ["//visibility:private"].
+type compositeRule []visibilityRule
+
+// A compositeRule matches if and only if any of its rules matches.
+func (c compositeRule) matches(m qualifiedModuleName) bool {
+	for _, r := range c {
+		if r.matches(m) {
+			return true
+		}
+	}
+	return false
+}
+
+func (c compositeRule) String() string {
+	s := make([]string, 0, len(c))
+	for _, r := range c {
+		s = append(s, r.String())
+	}
+
+	return "[" + strings.Join(s, ", ") + "]"
+}
+
+// A packageRule is a visibility rule that matches modules in a specific package (i.e. directory).
+type packageRule struct {
+	pkg string
+}
+
+func (r packageRule) matches(m qualifiedModuleName) bool {
+	return m.pkg == r.pkg
+}
+
+func (r packageRule) String() string {
+	return fmt.Sprintf("//%s:__pkg__", r.pkg)
+}
+
+// A subpackagesRule is a visibility rule that matches modules in a specific package (i.e.
+// directory) or any of its subpackages (i.e. subdirectories).
+type subpackagesRule struct {
+	pkgPrefix string
+}
+
+func (r subpackagesRule) matches(m qualifiedModuleName) bool {
+	return isAncestor(r.pkgPrefix, m.pkg)
+}
+
+func isAncestor(p1 string, p2 string) bool {
+	return strings.HasPrefix(p2+"/", p1+"/")
+}
+
+func (r subpackagesRule) String() string {
+	return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
+}
+
+// visibilityRule for //visibility:public
+type publicRule struct{}
+
+func (r publicRule) matches(_ qualifiedModuleName) bool {
+	return true
+}
+
+func (r publicRule) String() string {
+	return "//visibility:public"
+}
+
+// visibilityRule for //visibility:private
+type privateRule struct{}
+
+func (r privateRule) matches(_ qualifiedModuleName) bool {
+	return false
+}
+
+func (r privateRule) String() string {
+	return "//visibility:private"
+}
+
+var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
+
+// The map from qualifiedModuleName to visibilityRule.
+func moduleToVisibilityRuleMap(ctx BaseModuleContext) *sync.Map {
+	return ctx.Config().Once(visibilityRuleMap, func() interface{} {
+		return &sync.Map{}
+	}).(*sync.Map)
+}
+
+// The rule checker needs to be registered before defaults expansion to correctly check that
+// //visibility:xxx isn't combined with other packages in the same list in any one module.
+func registerVisibilityRuleChecker(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
+}
+
+// Registers the function that gathers the visibility rules for each module.
+//
+// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
+// having to process multiple variants for each module. This goes after defaults expansion to gather
+// the complete visibility lists from flat lists and after the package info is gathered to ensure
+// that default_visibility is available.
+func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
+}
+
+// This must be registered after the deps have been resolved.
+func registerVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
+	ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
+}
+
+// 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 {
+		visibilityProperties := m.visibilityProperties()
+		for _, p := range visibilityProperties {
+			if visibility := p.getStrings(); visibility != nil {
+				checkRules(ctx, qualified.pkg, p.getName(), visibility)
+			}
+		}
+	}
+}
+
+func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) {
+	ruleCount := len(visibility)
+	if ruleCount == 0 {
+		// This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
+		// it could mean public visibility. Requiring at least one rule makes the owner's intent
+		// clearer.
+		ctx.PropertyErrorf(property, "must contain at least one visibility rule")
+		return
+	}
+
+	for _, v := range visibility {
+		ok, pkg, name := splitRule(v, currentPkg)
+		if !ok {
+			// Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
+			// ensure all the rules on this module are checked.
+			ctx.PropertyErrorf(property,
+				"invalid visibility pattern %q must match"+
+					" //<package>:<module>, //<package> or :<module>",
+				v)
+			continue
+		}
+
+		if pkg == "visibility" {
+			switch name {
+			case "private", "public":
+			case "legacy_public":
+				ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
+				continue
+			default:
+				ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
+				continue
+			}
+			if ruleCount != 1 {
+				ctx.PropertyErrorf(property, "cannot mix %q with any other visibility rules", v)
+				continue
+			}
+		}
+
+		// If the current directory is not in the vendor tree then there are some additional
+		// restrictions on the rules.
+		if !isAncestor("vendor", currentPkg) {
+			if !isAllowedFromOutsideVendor(pkg, name) {
+				ctx.PropertyErrorf(property,
+					"%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
+						" targets within //vendor, they can only use //vendor:__subpackages__.", v)
+				continue
+			}
+		}
+	}
+}
+
+// Gathers the flattened visibility rules after defaults expansion, parses the visibility
+// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement.
+//
+// See ../README.md#Visibility for information on the format of the visibility rules.
+func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
+	m, ok := ctx.Module().(Module)
+	if !ok {
+		return
+	}
+
+	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)
+			}
+		}
+	}
+}
+
+func parseRules(ctx BaseModuleContext, currentPkg string, visibility []string) compositeRule {
+	rules := make(compositeRule, 0, len(visibility))
+	hasPrivateRule := false
+	hasNonPrivateRule := false
+	for _, v := range visibility {
+		ok, pkg, name := splitRule(v, currentPkg)
+		if !ok {
+			continue
+		}
+
+		var r visibilityRule
+		isPrivateRule := false
+		if pkg == "visibility" {
+			switch name {
+			case "private":
+				r = privateRule{}
+				isPrivateRule = true
+			case "public":
+				r = publicRule{}
+			}
+		} else {
+			switch name {
+			case "__pkg__":
+				r = packageRule{pkg}
+			case "__subpackages__":
+				r = subpackagesRule{pkg}
+			default:
+				continue
+			}
+		}
+
+		if isPrivateRule {
+			hasPrivateRule = true
+		} else {
+			hasNonPrivateRule = true
+		}
+
+		rules = append(rules, r)
+	}
+
+	if hasPrivateRule && hasNonPrivateRule {
+		ctx.PropertyErrorf("visibility",
+			"cannot mix \"//visibility:private\" with any other visibility rules")
+		return compositeRule{privateRule{}}
+	}
+
+	return rules
+}
+
+func isAllowedFromOutsideVendor(pkg string, name string) bool {
+	if pkg == "vendor" {
+		if name == "__subpackages__" {
+			return true
+		}
+		return false
+	}
+
+	return !isAncestor("vendor", pkg)
+}
+
+func splitRule(ruleExpression string, currentPkg string) (bool, string, string) {
+	// Make sure that the rule is of the correct format.
+	matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression)
+	if ruleExpression == "" || matches == nil {
+		return false, "", ""
+	}
+
+	// Extract the package and name.
+	pkg := matches[1]
+	name := matches[2]
+
+	// Normalize the short hands
+	if pkg == "" {
+		pkg = currentPkg
+	}
+	if name == "" {
+		name = "__pkg__"
+	}
+
+	return true, pkg, name
+}
+
+func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
+	if _, ok := ctx.Module().(Module); !ok {
+		return
+	}
+
+	qualified := createQualifiedModuleName(ctx)
+
+	moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+
+	// Visit all the dependencies making sure that this module has access to them all.
+	ctx.VisitDirectDeps(func(dep Module) {
+		depName := ctx.OtherModuleName(dep)
+		depDir := ctx.OtherModuleDir(dep)
+		depQualified := qualifiedModuleName{depDir, depName}
+
+		// Targets are always visible to other targets in their own package.
+		if depQualified.pkg == qualified.pkg {
+			return
+		}
+
+		value, ok := moduleToVisibilityRule.Load(depQualified)
+		var rule compositeRule
+		if ok {
+			rule = value.(compositeRule)
+		} else {
+			rule = packageDefaultVisibility(ctx, depQualified)
+		}
+		if rule != nil && !rule.matches(qualified) {
+			ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
+		}
+	})
+}
+
+func createQualifiedModuleName(ctx BaseModuleContext) qualifiedModuleName {
+	moduleName := ctx.ModuleName()
+	dir := ctx.ModuleDir()
+	qualified := qualifiedModuleName{dir, moduleName}
+	return qualified
+}
+
+func packageDefaultVisibility(ctx BaseModuleContext, moduleId qualifiedModuleName) compositeRule {
+	moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+	packageQualifiedId := moduleId.getContainingPackageId()
+	for {
+		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
+		if ok {
+			return value.(compositeRule)
+		}
+
+		if packageQualifiedId.isRootPackage() {
+			return nil
+		}
+
+		packageQualifiedId = packageQualifiedId.getContainingPackageId()
+	}
+}
diff --git a/android/visibility_test.go b/android/visibility_test.go
new file mode 100644
index 0000000..af6acf4
--- /dev/null
+++ b/android/visibility_test.go
@@ -0,0 +1,916 @@
+package android
+
+import (
+	"testing"
+
+	"github.com/google/blueprint"
+)
+
+var visibilityTests = []struct {
+	name           string
+	fs             map[string][]byte
+	expectedErrors []string
+}{
+	{
+		name: "invalid visibility: empty list",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: [],
+				}`),
+		},
+		expectedErrors: []string{`visibility: must contain at least one visibility rule`},
+	},
+	{
+		name: "invalid visibility: empty rule",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: [""],
+				}`),
+		},
+		expectedErrors: []string{`visibility: invalid visibility pattern ""`},
+	},
+	{
+		name: "invalid visibility: unqualified",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["target"],
+				}`),
+		},
+		expectedErrors: []string{`visibility: invalid visibility pattern "target"`},
+	},
+	{
+		name: "invalid visibility: empty namespace",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//"],
+				}`),
+		},
+		expectedErrors: []string{`visibility: invalid visibility pattern "//"`},
+	},
+	{
+		name: "invalid visibility: empty module",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: [":"],
+				}`),
+		},
+		expectedErrors: []string{`visibility: invalid visibility pattern ":"`},
+	},
+	{
+		name: "invalid visibility: empty namespace and module",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//:"],
+				}`),
+		},
+		expectedErrors: []string{`visibility: invalid visibility pattern "//:"`},
+	},
+	{
+		name: "//visibility:unknown",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:unknown"],
+				}`),
+		},
+		expectedErrors: []string{`unrecognized visibility rule "//visibility:unknown"`},
+	},
+	{
+		name: "//visibility:xxx mixed",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:public", "//namespace"],
+				}
+
+				mock_library {
+					name: "libother",
+					visibility: ["//visibility:private", "//namespace"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libother": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+			`module "libexample": visibility: cannot mix "//visibility:public"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:legacy_public",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:legacy_public"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample": visibility: //visibility:legacy_public must` +
+				` not be used`,
+		},
+	},
+	{
+		// Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
+		// the current directory, a nested directory and a directory in a separate tree.
+		name: "//visibility:public",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:public"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		// Verify that //visibility:private allows the module to be referenced from the current
+		// directory only.
+		name: "//visibility:private",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:private"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		// Verify that :__pkg__ allows the module to be referenced from the current directory only.
+		name: ":__pkg__",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: [":__pkg__"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		// Verify that //top/nested allows the module to be referenced from the current directory and
+		// the top/nested directory only, not a subdirectory of top/nested and not peak directory.
+		name: "//top/nested",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//top/nested"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"top/nested/again/Blueprints": []byte(`
+				mock_library {
+					name: "libnestedagain",
+					deps: ["libexample"],
+				}`),
+			"peak/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+			`module "libnestedagain" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		// Verify that :__subpackages__ allows the module to be referenced from the current directory
+		// and sub directories but nowhere else.
+		name: ":__subpackages__",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: [":__subpackages__"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"peak/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		// Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
+		// directory and sub directories but nowhere else.
+		name: "//top/nested:__subpackages__",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//top/nested:__subpackages__", "//other"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"top/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		// Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
+		// the current directory, top/nested and peak and all its subpackages.
+		name: `["//top/nested", "//peak:__subpackages__"]`,
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//top/nested", "//peak:__subpackages__"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"peak/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		// Verify that //vendor... cannot be used outside vendor apart from //vendor:__subpackages__
+		name: `//vendor`,
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_library {
+					name: "libexample",
+					visibility: ["//vendor:__subpackages__"],
+				}
+	
+				mock_library {
+					name: "libsamepackage",
+					visibility: ["//vendor/apps/AcmeSettings"],
+				}`),
+			"vendor/Blueprints": []byte(`
+				mock_library {
+					name: "libvendorexample",
+					deps: ["libexample"],
+					visibility: ["//vendor/nested"],
+				}`),
+			"vendor/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libvendornested",
+					deps: ["libexample", "libvendorexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libsamepackage": visibility: "//vendor/apps/AcmeSettings"` +
+				` is not allowed. Packages outside //vendor cannot make themselves visible to specific` +
+				` targets within //vendor, they can only use //vendor:__subpackages__.`,
+		},
+	},
+
+	// Defaults propagation tests
+	{
+		// Check that visibility is the union of the defaults modules.
+		name: "defaults union, basic",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//other"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//top/nested"],
+					defaults: ["libexample_defaults"],
+				}
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "defaults union, multiple defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//other"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//top/nested"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "//visibility:public mixed with other in defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:public", "//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample_defaults": visibility: cannot mix "//visibility:public"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:public overriding defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:public"],
+					defaults: ["libexample_defaults"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "//visibility:public mixed with other from different defaults 1",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//namespace"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//visibility:public"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "//visibility:public mixed with other from different defaults 2",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//visibility:public"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "//visibility:private in defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:private"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults"],
+				}
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "//visibility:private mixed with other in defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:private", "//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample_defaults": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:private overriding defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:private"],
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:private in defaults overridden",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:private"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//namespace"],
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:private mixed with itself",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//visibility:private"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//visibility:private"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:private"],
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	// Package default_visibility tests
+	{
+		name: "package default_visibility property is checked",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:invalid"],
+				}`),
+		},
+		expectedErrors: []string{`default_visibility: unrecognized visibility rule "//visibility:invalid"`},
+	},
+	{
+		// This test relies on the default visibility being legacy_public.
+		name: "package default_visibility property used when no visibility specified",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}
+
+				mock_library {
+					name: "libexample",
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "package default_visibility public does not override visibility private",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:public"],
+				}
+
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:private"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "package default_visibility private does not override visibility public",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}
+
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:public"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "package default_visibility :__subpackages__",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: [":__subpackages__"],
+				}
+
+				mock_library {
+					name: "libexample",
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "package default_visibility inherited to subpackages",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//outsider"],
+				}
+
+				mock_library {
+					name: "libexample",
+          visibility: [":__subpackages__"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample", "libnested"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "package default_visibility inherited to subpackages",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				package {
+					default_visibility: ["//outsider"],
+				}
+
+				mock_library {
+					name: "libnested",
+				}`),
+			"top/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libother", "libnested"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top/other:libother which is` +
+				` not visible to this module`,
+		},
+	},
+}
+
+func TestVisibility(t *testing.T) {
+	for _, test := range visibilityTests {
+		t.Run(test.name, func(t *testing.T) {
+			_, errs := testVisibility(buildDir, test.fs)
+
+			expectedErrors := test.expectedErrors
+			if expectedErrors == nil {
+				FailIfErrored(t, errs)
+			} else {
+				for _, expectedError := range expectedErrors {
+					FailIfNoMatchingErrors(t, expectedError, errs)
+				}
+				if len(errs) > len(expectedErrors) {
+					t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
+					for i, expectedError := range expectedErrors {
+						t.Errorf("expectedErrors[%d] = %s", i, expectedError)
+					}
+					for i, err := range errs {
+						t.Errorf("errs[%d] = %s", i, err)
+					}
+				}
+			}
+		})
+	}
+}
+
+func testVisibility(buildDir string, fs map[string][]byte) (*TestContext, []error) {
+
+	// Create a new config per test as visibility information is stored in the config.
+	config := TestArchConfig(buildDir, nil)
+
+	ctx := NewTestArchContext()
+	ctx.RegisterModuleType("package", ModuleFactoryAdaptor(PackageFactory))
+	ctx.RegisterModuleType("mock_library", ModuleFactoryAdaptor(newMockLibraryModule))
+	ctx.RegisterModuleType("mock_defaults", ModuleFactoryAdaptor(defaultsFactory))
+	ctx.PreArchMutators(registerPackageRenamer)
+	ctx.PreArchMutators(registerVisibilityRuleChecker)
+	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+	ctx.PreArchMutators(registerVisibilityRuleGatherer)
+	ctx.PostDepsMutators(registerVisibilityRuleEnforcer)
+	ctx.Register()
+
+	ctx.MockFileSystem(fs)
+
+	_, errs := ctx.ParseBlueprintsFiles(".")
+	if len(errs) > 0 {
+		return ctx, errs
+	}
+
+	_, errs = ctx.PrepareBuildActions(config)
+	return ctx, errs
+}
+
+type mockLibraryProperties struct {
+	Deps []string
+}
+
+type mockLibraryModule struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties mockLibraryProperties
+}
+
+func newMockLibraryModule() Module {
+	m := &mockLibraryModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitDefaultableModule(m)
+	return m
+}
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+func (j *mockLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
+}
+
+func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+type mockDefaults struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func defaultsFactory() Module {
+	m := &mockDefaults{}
+	InitDefaultsModule(m)
+	return m
+}
diff --git a/android/vts_config_test.go b/android/vts_config_test.go
index 7d4c9b1..142b2f5 100644
--- a/android/vts_config_test.go
+++ b/android/vts_config_test.go
@@ -15,19 +15,11 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
 	"testing"
 )
 
 func testVtsConfig(test *testing.T, bpFileContents string) *TestContext {
-	buildDir, err := ioutil.TempDir("", "soong_vts_config_test")
-	if err != nil {
-		test.Fatal(err)
-	}
-
 	config := TestArchConfig(buildDir, nil)
-	defer func() { os.RemoveAll(buildDir) }()
 
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("vts_config", ModuleFactoryAdaptor(VtsConfigFactory))
diff --git a/androidmk/Android.bp b/androidmk/Android.bp
index 1d939b0..79fe530 100644
--- a/androidmk/Android.bp
+++ b/androidmk/Android.bp
@@ -30,6 +30,7 @@
         "androidmk-parser",
         "blueprint-parser",
         "bpfix-lib",
+        "soong-android",
     ],
 }
 
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 52bcf9c..2def179 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -15,9 +15,9 @@
 package main
 
 import (
+	"android/soong/android"
 	mkparser "android/soong/androidmk/parser"
 	"fmt"
-	"sort"
 	"strings"
 
 	bpparser "github.com/google/blueprint/parser"
@@ -123,13 +123,16 @@
 			"LOCAL_SYSTEM_SHARED_LIBRARIES":       "system_shared_libs",
 			"LOCAL_ASFLAGS":                       "asflags",
 			"LOCAL_CLANG_ASFLAGS":                 "clang_asflags",
+			"LOCAL_COMPATIBILITY_SUPPORT_FILES":   "data",
 			"LOCAL_CONLYFLAGS":                    "conlyflags",
 			"LOCAL_CPPFLAGS":                      "cppflags",
 			"LOCAL_REQUIRED_MODULES":              "required",
+			"LOCAL_HOST_REQUIRED_MODULES":         "host_required",
+			"LOCAL_TARGET_REQUIRED_MODULES":       "target_required",
 			"LOCAL_OVERRIDES_MODULES":             "overrides",
 			"LOCAL_LDLIBS":                        "host_ldlibs",
 			"LOCAL_CLANG_CFLAGS":                  "clang_cflags",
-			"LOCAL_YACCFLAGS":                     "yaccflags",
+			"LOCAL_YACCFLAGS":                     "yacc.flags",
 			"LOCAL_SANITIZE_RECOVER":              "sanitize.recover",
 			"LOCAL_LOGTAGS_FILES":                 "logtags",
 			"LOCAL_EXPORT_HEADER_LIBRARY_HEADERS": "export_header_lib_headers",
@@ -144,6 +147,7 @@
 			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
 
 			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
+			"LOCAL_JAVA_RESOURCE_FILES":   "java_resources",
 			"LOCAL_JAVACFLAGS":            "javacflags",
 			"LOCAL_ERROR_PRONE_FLAGS":     "errorprone.javacflags",
 			"LOCAL_DX_FLAGS":              "dxflags",
@@ -181,7 +185,6 @@
 			"LOCAL_NO_CRT":                     "nocrt",
 			"LOCAL_ALLOW_UNDEFINED_SYMBOLS":    "allow_undefined_symbols",
 			"LOCAL_RTTI_FLAG":                  "rtti",
-			"LOCAL_NO_STANDARD_LIBRARIES":      "no_standard_libs",
 			"LOCAL_PACK_MODULE_RELOCATIONS":    "pack_relocations",
 			"LOCAL_TIDY":                       "tidy",
 			"LOCAL_USE_CLANG_LLD":              "use_clang_lld",
@@ -189,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",
@@ -331,15 +334,6 @@
 	}
 }
 
-func sortedMapKeys(inputMap map[string]string) (sortedKeys []string) {
-	keys := make([]string, 0, len(inputMap))
-	for key := range inputMap {
-		keys = append(keys, key)
-	}
-	sort.Strings(keys)
-	return keys
-}
-
 // splitAndAssign splits a Make list into components and then
 // creates the corresponding variable assignments.
 func splitAndAssign(ctx variableAssignmentContext, splitFunc listSplitFunc, namesByClassification map[string]string) error {
@@ -353,7 +347,7 @@
 		return err
 	}
 
-	for _, nameClassification := range sortedMapKeys(namesByClassification) {
+	for _, nameClassification := range android.SortedStringKeys(namesByClassification) {
 		name := namesByClassification[nameClassification]
 		if component, ok := lists[nameClassification]; ok && !emptyList(component) {
 			err = setVariable(ctx.file, ctx.append, ctx.prefix, name, component, true)
@@ -525,7 +519,7 @@
 				ctx.file.errorf(ctx.mkvalue, "unsupported sanitize expression")
 			case *bpparser.String:
 				switch v.Value {
-				case "never", "address", "coverage", "thread", "undefined", "cfi":
+				case "never", "address", "fuzzer", "thread", "undefined", "cfi":
 					bpTrue := &bpparser.Bool{
 						Value: true,
 					}
@@ -608,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>
@@ -933,6 +927,7 @@
 	"STATIC_LIBRARIES": "cc_prebuilt_library_static",
 	"EXECUTABLES":      "cc_prebuilt_binary",
 	"JAVA_LIBRARIES":   "java_import",
+	"APPS":             "android_app_import",
 	"ETC":              "prebuilt_etc",
 }
 
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index f2dc6ff..dbb7fde 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -577,6 +577,10 @@
 			include $(CLEAR_VARS)
 			LOCAL_SRC_FILES := $(call all-java-files-under, src gen)
 			include $(BUILD_STATIC_JAVA_LIBRARY)
+
+			include $(CLEAR_VARS)
+			LOCAL_JAVA_RESOURCE_FILES := foo bar
+			include $(BUILD_STATIC_JAVA_LIBRARY)
 		`,
 		expected: `
 			java_library {
@@ -604,6 +608,13 @@
 					"gen/**/*.java",
 				],
 			}
+
+			java_library {
+				java_resources: [
+					"foo",
+					"bar",
+				],
+			}
 		`,
 	},
 	{
@@ -798,6 +809,7 @@
 LOCAL_PACKAGE_NAME := FooTest
 LOCAL_COMPATIBILITY_SUITE := cts
 LOCAL_CTS_TEST_PACKAGE := foo.bar
+LOCAL_COMPATIBILITY_SUPPORT_FILES := file1
 include $(BUILD_CTS_PACKAGE)
 `,
 		expected: `
@@ -806,6 +818,7 @@
     defaults: ["cts_defaults"],
     test_suites: ["cts"],
 
+    data: ["file1"],
 }
 `,
 	},
@@ -868,7 +881,6 @@
 }
 `,
 	},
-
 	{
 		desc: "prebuilt_etc_PRODUCT_OUT/system/etc",
 		in: `
@@ -945,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,
 
 
 }
@@ -1054,6 +1066,197 @@
 `,
 	},
 	{
+		desc: "prebuilt_usr_share",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share {
+	name: "foo",
+
+	src: "foo.txt",
+}
+`,
+	},
+	{
+		desc: "prebuilt_usr_share subdir_bar",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share {
+	name: "foo",
+
+	src: "foo.txt",
+	sub_dir: "bar",
+}
+`,
+	},
+	{
+		desc: "prebuilt_usr_share_host",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share_host {
+	name: "foo",
+
+	src: "foo.txt",
+}
+`,
+	},
+	{
+		desc: "prebuilt_font",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := font.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_font {
+	name: "font.ttf",
+	src: "font.ttf",
+
+}
+`,
+	},
+	{
+		desc: "prebuilt_font",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := font.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/fonts
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_font {
+	name: "font.ttf",
+	src: "font.ttf",
+	product_specific: true,
+
+}
+`,
+	},
+	{
+		desc: "prebuilt_usr_share_host subdir_bar",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_usr_share_host {
+	name: "foo",
+
+	src: "foo.txt",
+	sub_dir: "bar",
+}
+`,
+	},
+	{
+		desc: "prebuilt_firmware subdir_bar in $(TARGET_OUT_ETC)",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/firmware/bar
+LOCAL_SRC_FILES := foo.fw
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_firmware {
+	name: "foo",
+
+	src: "foo.fw",
+	sub_dir: "bar",
+}
+`,
+	},
+	{
+		desc: "prebuilt_firmware subdir_bar in $(TARGET_OUT)",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/firmware/bar
+LOCAL_SRC_FILES := foo.fw
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_firmware {
+	name: "foo",
+
+	src: "foo.fw",
+	sub_dir: "bar",
+}
+`,
+	},
+	{
+		desc: "prebuilt_firmware subdir_bar in $(TARGET_OUT_VENDOR)",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/firmware/bar
+LOCAL_SRC_FILES := foo.fw
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_firmware {
+	name: "foo",
+
+	src: "foo.fw",
+	sub_dir: "bar",
+	proprietary: true,
+}
+`,
+	},
+	{
+		desc: "prebuilt_firmware subdir_bar in $(TARGET_OUT)/vendor",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/firmware/bar
+LOCAL_SRC_FILES := foo.fw
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+prebuilt_firmware {
+	name: "foo",
+
+	src: "foo.fw",
+	sub_dir: "bar",
+	proprietary: true,
+}
+`,
+	},
+	{
 		desc: "vts_config",
 		in: `
 include $(CLEAR_VARS)
@@ -1112,6 +1315,32 @@
 }
 		`,
 	},
+	{
+		desc: "android_app_import",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_SRC_FILES := foo.apk
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MODULE_CLASS := APPS
+LOCAL_MODULE_TAGS := optional
+LOCAL_DEX_PREOPT := false
+include $(BUILD_PREBUILT)
+`,
+		expected: `
+android_app_import {
+	name: "foo",
+
+	privileged: true,
+
+	dex_preopt: {
+		enabled: false,
+	},
+	apk: "foo.apk",
+
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index 3726684..b77e12f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -61,7 +61,7 @@
 			`--key ${key} ${opt_flags} ${image_dir} ${out} `,
 		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
 			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
-			"${soong_zip}", "${zipalign}", "${aapt2}"},
+			"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
 		Description: "APEX ${image_dir} => ${out}",
 	}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key", "opt_flags")
 
@@ -108,8 +108,10 @@
 	executableTag  = dependencyTag{name: "executable"}
 	javaLibTag     = dependencyTag{name: "javaLib"}
 	prebuiltTag    = dependencyTag{name: "prebuilt"}
+	testTag        = dependencyTag{name: "test"}
 	keyTag         = dependencyTag{name: "key"}
 	certificateTag = dependencyTag{name: "certificate"}
+	usesTag        = dependencyTag{name: "uses"}
 )
 
 func init() {
@@ -145,7 +147,8 @@
 
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
-		ctx.BottomUp("apex", apexMutator)
+		ctx.BottomUp("apex", apexMutator).Parallel()
+		ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
 	})
 }
 
@@ -186,12 +189,19 @@
 		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
 	Native_shared_libs []string
 	// List of native executables
 	Binaries []string
+	// List of native tests
+	Tests []string
 }
 type apexMultilibProperties struct {
 	// Native dependencies whose compile_multilib is "first"
@@ -232,7 +242,7 @@
 	// List of native shared libs that are embedded inside this APEX bundle
 	Native_shared_libs []string
 
-	// List of native executables that are embedded inside this APEX bundle
+	// List of executables that are embedded inside this APEX bundle
 	Binaries []string
 
 	// List of java libraries that are embedded inside this APEX bundle
@@ -241,6 +251,9 @@
 	// List of prebuilt files that are embedded inside this APEX bundle
 	Prebuilts []string
 
+	// List of tests that are embedded inside this APEX bundle
+	Tests []string
+
 	// Name of the apex_key module that provides the private key to sign APEX
 	Key *string
 
@@ -266,6 +279,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 {
@@ -299,6 +318,7 @@
 	pyBinary
 	goBinary
 	javaSharedLib
+	nativeTest
 )
 
 type apexPackaging int
@@ -361,6 +381,8 @@
 		return "EXECUTABLES"
 	case javaSharedLib:
 		return "JAVA_LIBRARIES"
+	case nativeTest:
+		return "NATIVE_TESTS"
 	default:
 		panic(fmt.Errorf("unkonwn class %d", class))
 	}
@@ -406,7 +428,8 @@
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
-	native_shared_libs []string, binaries []string, arch string, imageVariation string) {
+	native_shared_libs []string, binaries []string, tests []string,
+	arch string, imageVariation string) {
 	// Use *FarVariation* to be able to depend on modules having
 	// conflicting variations with this module. This is required since
 	// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
@@ -422,6 +445,11 @@
 		{Mutator: "arch", Variation: arch},
 		{Mutator: "image", Variation: imageVariation},
 	}, executableTag, binaries...)
+
+	ctx.AddFarVariationDependencies([]blueprint.Variation{
+		{Mutator: "arch", Variation: arch},
+		{Mutator: "image", Variation: imageVariation},
+	}, testTag, tests...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -459,10 +487,19 @@
 			{Mutator: "link", Variation: "shared"},
 		}, sharedLibTag, a.properties.Native_shared_libs...)
 
+		// When multilib.* is omitted for tests, it implies
+		// multilib.both.
+		ctx.AddFarVariationDependencies([]blueprint.Variation{
+			{Mutator: "arch", Variation: target.String()},
+			{Mutator: "image", Variation: a.getImageVariation(config)},
+		}, testTag, a.properties.Tests...)
+
 		// Add native modules targetting both ABIs
 		addDependenciesForNativeModules(ctx,
 			a.properties.Multilib.Both.Native_shared_libs,
-			a.properties.Multilib.Both.Binaries, target.String(),
+			a.properties.Multilib.Both.Binaries,
+			a.properties.Multilib.Both.Tests,
+			target.String(),
 			a.getImageVariation(config))
 
 		isPrimaryAbi := i == 0
@@ -477,7 +514,9 @@
 			// Add native modules targetting the first ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.First.Native_shared_libs,
-				a.properties.Multilib.First.Binaries, target.String(),
+				a.properties.Multilib.First.Binaries,
+				a.properties.Multilib.First.Tests,
+				target.String(),
 				a.getImageVariation(config))
 
 			// When multilib.* is omitted for prebuilts, it implies multilib.first.
@@ -491,26 +530,45 @@
 			// Add native modules targetting 32-bit ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Lib32.Native_shared_libs,
-				a.properties.Multilib.Lib32.Binaries, target.String(),
+				a.properties.Multilib.Lib32.Binaries,
+				a.properties.Multilib.Lib32.Tests,
+				target.String(),
 				a.getImageVariation(config))
 
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Prefer32.Native_shared_libs,
-				a.properties.Multilib.Prefer32.Binaries, target.String(),
+				a.properties.Multilib.Prefer32.Binaries,
+				a.properties.Multilib.Prefer32.Tests,
+				target.String(),
 				a.getImageVariation(config))
 		case "lib64":
 			// Add native modules targetting 64-bit ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Lib64.Native_shared_libs,
-				a.properties.Multilib.Lib64.Binaries, target.String(),
+				a.properties.Multilib.Lib64.Binaries,
+				a.properties.Multilib.Lib64.Tests,
+				target.String(),
 				a.getImageVariation(config))
 
 			if !has32BitTarget {
 				addDependenciesForNativeModules(ctx,
 					a.properties.Multilib.Prefer32.Native_shared_libs,
-					a.properties.Multilib.Prefer32.Binaries, target.String(),
+					a.properties.Multilib.Prefer32.Binaries,
+					a.properties.Multilib.Prefer32.Tests,
+					target.String(),
 					a.getImageVariation(config))
 			}
+
+			if strings.HasPrefix(ctx.ModuleName(), "com.android.runtime") && target.Os.Class == android.Device {
+				for _, sanitizer := range ctx.Config().SanitizeDevice() {
+					if sanitizer == "hwaddress" {
+						addDependenciesForNativeModules(ctx,
+							[]string{"libclang_rt.hwasan-aarch64-android"},
+							nil, nil, target.String(), a.getImageVariation(config))
+						break
+					}
+				}
+			}
 		}
 
 	}
@@ -531,7 +589,7 @@
 	}
 }
 
-func (a *apexBundle) getCertString(ctx android.BaseContext) string {
+func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
 	certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
 	if overridden {
 		return ":" + certificate
@@ -539,11 +597,16 @@
 	return String(a.properties.Certificate)
 }
 
-func (a *apexBundle) Srcs() android.Paths {
-	if file, ok := a.outputFiles[imageApex]; ok {
-		return android.Paths{file}
-	} else {
-		return nil
+func (a *apexBundle) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		if file, ok := a.outputFiles[imageApex]; ok {
+			return android.Paths{file}, nil
+		} else {
+			return nil, nil
+		}
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
 }
 
@@ -670,8 +733,37 @@
 		return
 	}
 
+	if len(a.properties.Tests) > 0 && !a.testApex {
+		ctx.PropertyErrorf("tests", "property not allowed in apex module type")
+		return
+	}
+
 	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
 
+	// 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 {
 		if _, ok := parent.(*apexBundle); ok {
 			// direct dependencies
@@ -731,6 +823,14 @@
 				} else {
 					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})
+					return true
+				} else {
+					ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
+				}
 			case keyTag:
 				if key, ok := child.(*apexKey); ok {
 					a.private_key_file = key.private_key_file
@@ -752,6 +852,11 @@
 			// indirect dependencies
 			if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
 				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
+					}
 					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.
@@ -842,8 +947,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) {
@@ -900,7 +1004,7 @@
 		var executablePaths []string // this also includes dirs
 		for _, f := range a.filesInfo {
 			pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
-			if f.installDir == "bin" {
+			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))
@@ -1033,6 +1137,10 @@
 		Description: "signapk",
 		Output:      a.outputFiles[apexType],
 		Input:       unsignedOutputFile,
+		Implicits: []android.Path{
+			a.container_certificate_file,
+			a.container_private_key_file,
+		},
 		Args: map[string]string{
 			"certificates": a.container_certificate_file.String() + " " + a.container_private_key_file.String(),
 			"flags":        "-a 4096", //alignment
@@ -1171,8 +1279,11 @@
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
 		} else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
-			if cc, ok := fi.module.(*cc.Module); ok && cc.UnstrippedOutputFile() != nil {
-				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+			if cc, ok := fi.module.(*cc.Module); ok {
+				if cc.UnstrippedOutputFile() != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+				}
+				cc.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
 		} else {
@@ -1230,11 +1341,11 @@
 }
 
 func testApexBundleFactory() android.Module {
-	return ApexBundleFactory( /*testApex*/ true)
+	return ApexBundleFactory(true /*testApex*/)
 }
 
 func apexBundleFactory() android.Module {
-	return ApexBundleFactory( /*testApex*/ false)
+	return ApexBundleFactory(false /*testApex*/)
 }
 
 func ApexBundleFactory(testApex bool) android.Module {
@@ -1260,9 +1371,6 @@
 	android.DefaultsModuleBase
 }
 
-func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-}
-
 func defaultsFactory() android.Module {
 	return DefaultsFactory()
 }
@@ -1362,8 +1470,13 @@
 	p.properties.Source = src
 }
 
-func (p *Prebuilt) Srcs() android.Paths {
-	return android.Paths{p.outputApex}
+func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{p.outputApex}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 func (p *Prebuilt) InstallFilename() string {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c671e7c..94cf19d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -29,10 +29,38 @@
 
 var buildDir string
 
+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 {
-	var config android.Config
-	config, buildDir = setup(t)
-	defer teardown(buildDir)
+	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
+}
+
+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")
+	config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
+	config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
+	config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
@@ -45,6 +73,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()
 	})
@@ -54,6 +83,7 @@
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(cc.BinaryFactory))
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+	ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc.TestFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
@@ -158,13 +188,16 @@
 
 	ctx.MockFileSystem(map[string][]byte{
 		"Android.bp":                                        []byte(bp),
-		"build/target/product/security":                     nil,
+		"build/make/target/product/security":                nil,
 		"apex_manifest.json":                                nil,
 		"AndroidManifest.xml":                               nil,
 		"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,
+		"mytest.cpp":                           nil,
+		"mylib_common.cpp":                     nil,
 		"myprebuilt":                           nil,
 		"my_include":                           nil,
 		"vendor/foo/devkeys/test.x509.pem":     nil,
@@ -183,35 +216,25 @@
 		"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(t *testing.T) (config android.Config, buildDir string) {
-	buildDir, err := ioutil.TempDir("", "soong_apex_test")
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_apex_test")
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
-
-	config = android.TestArchConfig(buildDir, nil)
-	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
-	config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
-	config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
-	config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
-	config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
-	return
 }
 
-func teardown(buildDir string) {
+func tearDown() {
 	os.RemoveAll(buildDir)
 }
 
 // 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)
 	}
@@ -219,18 +242,21 @@
 
 // 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)
 	}
@@ -590,7 +616,7 @@
 
 		cc_library {
 			name: "libc",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			stl: "none",
@@ -601,7 +627,7 @@
 
 		cc_library {
 			name: "libm",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			stl: "none",
@@ -612,7 +638,7 @@
 
 		cc_library {
 			name: "libdl",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			stl: "none",
@@ -791,6 +817,30 @@
 	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, `
 		apex {
@@ -1288,3 +1338,164 @@
 		t.Errorf("installFilename invalid. expected: %q, actual: %q", expected, p.installFilename)
 	}
 }
+
+func TestApexWithTests(t *testing.T) {
+	ctx := testApex(t, `
+		apex_test {
+			name: "myapex",
+			key: "myapex.key",
+			tests: [
+				"mytest",
+			],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_test {
+			name: "mytest",
+			gtest: false,
+			srcs: ["mytest.cpp"],
+			relative_install_path: "test",
+			system_shared_libs: [],
+			static_executable: true,
+			stl: "none",
+		}
+	`)
+
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	// Ensure that test dep is copied into apex.
+	ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
+}
+
+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) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
diff --git a/apex/key.go b/apex/key.go
index 6ee3dca..08cd45e 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -56,8 +56,7 @@
 func apexKeyFactory() android.Module {
 	module := &apexKey{}
 	module.AddProperties(&module.properties)
-	// This module is device-only
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
 	return module
 }
 
diff --git a/bpf/Android.bp b/bpf/Android.bp
index 7bd4d44..882cd8a 100644
--- a/bpf/Android.bp
+++ b/bpf/Android.bp
@@ -21,10 +21,14 @@
         "blueprint",
         "blueprint-proptools",
         "soong-android",
+        "soong-cc",
         "soong-cc-config",
     ],
     srcs: [
         "bpf.go",
     ],
+    testSrcs: [
+        "bpf_test.go",
+    ],
     pluginFor: ["soong_build"],
 }
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 13468c7..90ec963 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -33,7 +33,7 @@
 var (
 	pctx = android.NewPackageContext("android/soong/bpf")
 
-	cc = pctx.AndroidGomaStaticRule("cc",
+	ccRule = pctx.AndroidGomaStaticRule("ccRule",
 		blueprint.RuleParams{
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
@@ -82,7 +82,7 @@
 		obj := android.ObjPathWithExt(ctx, "", src, "o")
 
 		ctx.Build(pctx, android.BuildParams{
-			Rule:   cc,
+			Rule:   ccRule,
 			Input:  src,
 			Output: obj,
 			Args: map[string]string{
@@ -122,13 +122,18 @@
 	}
 }
 
-// Implements SourceFileProducer interface so that the obj output can be used in the data property
+// Implements OutputFileFileProducer interface so that the obj output can be used in the data property
 // of other modules.
-func (bpf *bpf) Srcs() android.Paths {
-	return bpf.objs
+func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return bpf.objs, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
-var _ android.SourceFileProducer = (*bpf)(nil)
+var _ android.OutputFileProducer = (*bpf)(nil)
 
 func bpfFactory() android.Module {
 	module := &bpf{}
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index 1d53e41..cbb251f 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -20,7 +20,7 @@
 	"testing"
 
 	"android/soong/android"
-	cc2 "android/soong/cc"
+	"android/soong/cc"
 )
 
 var buildDir string
@@ -49,115 +49,14 @@
 }
 
 func testContext(bp string) *android.TestContext {
-	ctx := android.NewTestArchContext()
-	ctx.RegisterModuleType("bpf", android.ModuleFactoryAdaptor(bpfFactory))
-	ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc2.TestFactory))
-	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc2.LibraryFactory))
-	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(cc2.LibraryStaticFactory))
-	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc2.ObjectFactory))
-	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc2.ToolchainLibraryFactory))
-	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("link", cc2.LinkageMutator).Parallel()
-	})
-	ctx.Register()
-
-	// Add some modules that are required by the compiler and/or linker
-	bp = bp + `
-		toolchain_library {
-			name: "libatomic",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-arm-android",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-aarch64-android",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libgcc",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		cc_library {
-			name: "libc",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-		}
-
-		cc_library {
-			name: "libm",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-		}
-
-		cc_library {
-			name: "libdl",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-		}
-
-		cc_library {
-			name: "libgtest",
-			host_supported: true,
-			vendor_available: true,
-		}
-
-		cc_library {
-			name: "libgtest_main",
-			host_supported: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtbegin_dynamic",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtend_android",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtbegin_so",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtend_so",
-			recovery_available: true,
-			vendor_available: true,
-		}
-	`
 	mockFS := map[string][]byte{
-		"Android.bp":  []byte(bp),
 		"bpf.c":       nil,
 		"BpfTest.cpp": nil,
 	}
 
-	ctx.MockFileSystem(mockFS)
+	ctx := cc.CreateTestContext(bp, mockFS, android.Android)
+	ctx.RegisterModuleType("bpf", android.ModuleFactoryAdaptor(bpfFactory))
+	ctx.Register()
 
 	return ctx
 }
@@ -174,6 +73,7 @@
 			name: "vts_test_binary_bpf_module",
 			srcs: ["BpfTest.cpp"],
 			data: [":bpf.o"],
+			gtest: false,
 		}
 	`
 
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 706c0ec..5f1cce8 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -102,6 +102,10 @@
 		name: "rewriteAndroidTest",
 		fix:  rewriteAndroidTest,
 	},
+	{
+		name: "rewriteAndroidAppImport",
+		fix:  rewriteAndroidAppImport,
+	},
 }
 
 func NewFixRequest() FixRequest {
@@ -431,14 +435,6 @@
 	return ""
 }
 
-// Create sub_dir: attribute for the given path
-func makePrebuiltEtcDestination(mod *parser.Module, path string) {
-	mod.Properties = append(mod.Properties, &parser.Property{
-		Name:  "sub_dir",
-		Value: &parser.String{Value: path},
-	})
-}
-
 // Set the value of the given attribute to the error message
 func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error {
 	msg := fmt.Sprintf(format, a...)
@@ -464,25 +460,63 @@
 	return val
 }
 
-// A prefix to strip before setting 'filename' attribute and an array of boolean attributes to set.
-type filenamePrefixToFlags struct {
+// etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as:
+//    * changing the module type from prebuilt_etc to a different one
+//    * stripping the prefix of the install path based on the module type
+//    * appending additional boolean properties to the prebuilt module
+type etcPrebuiltModuleUpdate struct {
+	// The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path
+	// before setting the 'filename' attribute.
 	prefix string
-	flags  []string
+
+	// There is only one prebuilt module type in makefiles. In Soong, there are multiple versions  of
+	// prebuilts based on local_module_path. By default, it is "prebuilt_etc" if modType is blank. An
+	// example is if the local_module_path contains $(TARGET_OUT)/usr/share, the module type is
+	// considered as prebuilt_usr_share.
+	modType string
+
+	// Additional boolean attributes to be added in the prebuilt module. Each added boolean attribute
+	// has a value of true.
+	flags []string
 }
 
-var localModulePathRewrite = map[string][]filenamePrefixToFlags{
-	"HOST_OUT":                        {{prefix: "/etc"}},
-	"PRODUCT_OUT":                     {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
-	"TARGET_OUT":                      {{prefix: "/etc"}},
-	"TARGET_OUT_ETC":                  {{prefix: ""}},
-	"TARGET_OUT_PRODUCT":              {{prefix: "/etc", 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"}}},
-	"TARGET_OUT_VENDOR_ETC":           {{prefix: "", flags: []string{"proprietary"}}},
-	"TARGET_RECOVERY_ROOT_OUT":        {{prefix: "/system/etc", flags: []string{"recovery"}}},
+func (f etcPrebuiltModuleUpdate) update(m *parser.Module, path string) bool {
+	updated := false
+	if path == f.prefix {
+		updated = true
+	} else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
+		m.Properties = append(m.Properties, &parser.Property{
+			Name:  "sub_dir",
+			Value: &parser.String{Value: trimmedPath},
+		})
+		updated = true
+	}
+	if updated {
+		for _, flag := range f.flags {
+			m.Properties = append(m.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
+		}
+		if f.modType != "" {
+			m.Type = f.modType
+		}
+	}
+	return updated
+}
+
+var localModuleUpdate = map[string][]etcPrebuiltModuleUpdate{
+	"HOST_OUT":    {{prefix: "/etc", modType: "prebuilt_etc_host"}, {prefix: "/usr/share", modType: "prebuilt_usr_share_host"}},
+	"PRODUCT_OUT": {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
+	"TARGET_OUT": {{prefix: "/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_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
@@ -497,27 +531,8 @@
 			continue
 		}
 
-		// The rewriter converts LOCAL_SRC_FILES to `srcs` attribute. Convert
-		// it to 'src' attribute (which is where the file is installed). If the
-		// value 'srcs' is a list, we can convert it only if it contains a single
-		// element.
-		if srcs, ok := mod.GetProperty("srcs"); ok {
-			if srcList, ok := srcs.Value.(*parser.List); ok {
-				removeProperty(mod, "srcs")
-				if len(srcList.Values) == 1 {
-					mod.Properties = append(mod.Properties,
-						&parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcList.Values[0])})
-				} else if len(srcList.Values) > 1 {
-					indicateAttributeError(mod, "src", "LOCAL_SRC_FILES should contain at most one item")
-				}
-			} else if _, ok = srcs.Value.(*parser.Variable); ok {
-				removeProperty(mod, "srcs")
-				mod.Properties = append(mod.Properties,
-					&parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcs.Value)})
-			} else {
-				renameProperty(mod, "srcs", "src")
-			}
-		}
+		// 'srcs' --> 'src' conversion
+		convertToSingleSource(mod, "src")
 
 		// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
 		// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
@@ -526,37 +541,23 @@
 		if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
 			removeProperty(mod, local_module_path)
 			prefixVariableName := getStringProperty(prop_local_module_path, "var")
-			path := getStringProperty(prop_local_module_path, "fixed")
-			if prefixRewrites, ok := localModulePathRewrite[prefixVariableName]; ok {
-				rewritten := false
-				for _, prefixRewrite := range prefixRewrites {
-					if path == prefixRewrite.prefix {
-						rewritten = true
-					} else if trimmedPath := strings.TrimPrefix(path, prefixRewrite.prefix+"/"); trimmedPath != path {
-						makePrebuiltEtcDestination(mod, trimmedPath)
-						rewritten = true
-					}
-					if rewritten {
-						for _, flag := range prefixRewrite.flags {
-							mod.Properties = append(mod.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
-						}
-						break
-					}
+			if moduleUpdates, ok := localModuleUpdate[prefixVariableName]; ok {
+				path := getStringProperty(prop_local_module_path, "fixed")
+				updated := false
+				for i := 0; i < len(moduleUpdates) && !updated; i++ {
+					updated = moduleUpdates[i].update(mod, path)
 				}
-				if !rewritten {
+				if !updated {
 					expectedPrefices := ""
 					sep := ""
-					for _, prefixRewrite := range prefixRewrites {
+					for _, moduleUpdate := range moduleUpdates {
 						expectedPrefices += sep
 						sep = ", "
-						expectedPrefices += prefixRewrite.prefix
+						expectedPrefices += moduleUpdate.prefix
 					}
 					return indicateAttributeError(mod, "filename",
 						"LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices)
 				}
-				if prefixVariableName == "HOST_OUT" {
-					mod.Type = "prebuilt_etc_host"
-				}
 			} else {
 				return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName)
 			}
@@ -589,6 +590,62 @@
 	return nil
 }
 
+func rewriteAndroidAppImport(f *Fixer) error {
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !(ok && mod.Type == "android_app_import") {
+			continue
+		}
+		// 'srcs' --> 'apk' conversion
+		convertToSingleSource(mod, "apk")
+		// Handle special certificate value, "PRESIGNED".
+		if cert, ok := mod.GetProperty("certificate"); ok {
+			if certStr, ok := cert.Value.(*parser.String); ok {
+				if certStr.Value == "PRESIGNED" {
+					removeProperty(mod, "certificate")
+					prop := &parser.Property{
+						Name: "presigned",
+						Value: &parser.Bool{
+							Value: true,
+						},
+					}
+					mod.Properties = append(mod.Properties, prop)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// Converts the default source list property, 'srcs', to a single source property with a given name.
+// "LOCAL_MODULE" reference is also resolved during the conversion process.
+func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
+	if srcs, ok := mod.GetProperty("srcs"); ok {
+		if srcList, ok := srcs.Value.(*parser.List); ok {
+			removeProperty(mod, "srcs")
+			if len(srcList.Values) == 1 {
+				mod.Properties = append(mod.Properties,
+					&parser.Property{
+						Name:     srcPropertyName,
+						NamePos:  srcs.NamePos,
+						ColonPos: srcs.ColonPos,
+						Value:    resolveLocalModule(mod, srcList.Values[0])})
+			} else if len(srcList.Values) > 1 {
+				indicateAttributeError(mod, srcPropertyName, "LOCAL_SRC_FILES should contain at most one item")
+			}
+		} else if _, ok = srcs.Value.(*parser.Variable); ok {
+			removeProperty(mod, "srcs")
+			mod.Properties = append(mod.Properties,
+				&parser.Property{Name: srcPropertyName,
+					NamePos:  srcs.NamePos,
+					ColonPos: srcs.ColonPos,
+					Value:    resolveLocalModule(mod, srcs.Value)})
+		} else {
+			renameProperty(mod, "srcs", "apk")
+		}
+	}
+}
+
 func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
 	return func(f *Fixer) error {
 		// Make sure all the offsets are accurate
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 459cd36..5e0b817 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -784,3 +784,52 @@
 		})
 	}
 }
+
+func TestRewriteAndroidAppImport(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "android_app_import apk",
+			in: `
+				android_app_import {
+					name: "foo",
+					srcs: ["package.apk"],
+				}
+			`,
+			out: `
+				android_app_import {
+					name: "foo",
+					apk: "package.apk",
+				}
+			`,
+		},
+		{
+			name: "android_app_import presigned",
+			in: `
+				android_app_import {
+					name: "foo",
+					apk: "package.apk",
+					certificate: "PRESIGNED",
+				}
+			`,
+			out: `
+				android_app_import {
+					name: "foo",
+					apk: "package.apk",
+					presigned: true,
+
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return rewriteAndroidAppImport(fixer)
+			})
+		})
+	}
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 02806f9..272d3d4 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -24,8 +24,9 @@
 )
 
 var (
-	vendorSuffix   = ".vendor"
-	recoverySuffix = ".recovery"
+	nativeBridgeSuffix = ".native_bridge"
+	vendorSuffix       = ".vendor"
+	recoverySuffix     = ".recovery"
 )
 
 type AndroidMkContext interface {
@@ -86,9 +87,12 @@
 				if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
 					fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
 				}
-				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.getMakeLinkType())
+				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
 				if c.useVndk() {
 					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+					if c.isVndk() && !c.static() {
+						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
+					}
 				}
 			},
 		},
@@ -105,6 +109,10 @@
 	}
 	c.subAndroidMk(&ret, c.installer)
 
+	if c.Target().NativeBridge == android.NativeBridgeEnabled {
+		ret.SubName += nativeBridgeSuffix
+	}
+
 	if c.useVndk() && c.hasVendorVariant() {
 		// .vendor suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
@@ -134,14 +142,42 @@
 	}
 }
 
+func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string {
+	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		var result []string
+		for _, override := range overrides {
+			result = append(result, override+nativeBridgeSuffix)
+		}
+		return result
+	}
+
+	return overrides
+}
+
 func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
 	exportedFlags := library.exportedFlags()
+	for _, dir := range library.exportedDirs() {
+		exportedFlags = append(exportedFlags, "-I"+dir)
+	}
+	for _, dir := range library.exportedSystemDirs() {
+		exportedFlags = append(exportedFlags, "-isystem "+dir)
+	}
 	if len(exportedFlags) > 0 {
 		fmt.Fprintln(w, "LOCAL_EXPORT_CFLAGS :=", strings.Join(exportedFlags, " "))
 	}
-	exportedFlagsDeps := library.exportedFlagsDeps()
-	if len(exportedFlagsDeps) > 0 {
-		fmt.Fprintln(w, "LOCAL_EXPORT_C_INCLUDE_DEPS :=", strings.Join(exportedFlagsDeps.Strings(), " "))
+	exportedDeps := library.exportedDeps()
+	if len(exportedDeps) > 0 {
+		fmt.Fprintln(w, "LOCAL_EXPORT_C_INCLUDE_DEPS :=", strings.Join(exportedDeps.Strings(), " "))
+	}
+}
+
+func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+	if library.sAbiOutputFile.Valid() {
+		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiOutputFile.String())
+		if library.sAbiDiff.Valid() && !library.static() {
+			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
+			fmt.Fprintln(w, "HEADER_ABI_DIFFS +=", library.sAbiDiff.String())
+		}
 	}
 }
 
@@ -156,7 +192,7 @@
 				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
 			}
 			if len(library.Properties.Overrides) > 0 {
-				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(library.Properties.Overrides, " "))
+				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
 			}
 			if len(library.post_install_cmds) > 0 {
 				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
@@ -169,14 +205,7 @@
 	ret.DistFile = library.distFile
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		library.androidMkWriteExportedFlags(w)
-		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := ")
-		if library.sAbiOutputFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiOutputFile.String())
-			if library.sAbiDiff.Valid() && !library.static() {
-				fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiDiff.String())
-				fmt.Fprintln(w, "HEADER_ABI_DIFFS += ", library.sAbiDiff.String())
-			}
-		}
+		library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
 
 		_, _, ext := splitFileExt(outputFile.Base())
 
@@ -238,7 +267,7 @@
 		}
 
 		if len(binary.Properties.Overrides) > 0 {
-			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(binary.Properties.Overrides, " "))
+			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
 		}
 		if len(binary.post_install_cmds) > 0 {
 			fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
diff --git a/cc/binary.go b/cc/binary.go
index 666e884..1757f1c 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -106,13 +106,17 @@
 
 }
 
-func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string {
+func (binary *binaryDecorator) getStemWithoutSuffix(ctx BaseModuleContext) string {
 	stem := ctx.baseModuleName()
 	if String(binary.Properties.Stem) != "" {
 		stem = String(binary.Properties.Stem)
 	}
 
-	return stem + String(binary.Properties.Suffix)
+	return stem
+}
+
+func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string {
+	return binary.getStemWithoutSuffix(ctx) + String(binary.Properties.Suffix)
 }
 
 func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
@@ -326,7 +330,7 @@
 		}
 		strippedOutputFile := outputFile
 		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
-		binary.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
+		binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
 	}
 
 	binary.unstrippedOutputFile = outputFile
@@ -350,7 +354,7 @@
 			if binary.stripper.needsStrip(ctx) {
 				out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
 				binary.distFile = android.OptionalPathForPath(out)
-				binary.stripper.strip(ctx, versionedOutputFile, out, builderFlags)
+				binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
 			}
 
 			binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -384,11 +388,11 @@
 
 	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
 		deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
-		builderFlags, outputFile)
+		builderFlags, outputFile, nil)
 
 	objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
-	binary.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, binary.getStem(ctx))
+	binary.coverageOutputFile = TransformCoverageFilesToZip(ctx, objs, binary.getStem(ctx))
 
 	// Need to determine symlinks early since some targets (ie APEX) need this
 	// information but will not call 'install'
@@ -398,11 +402,11 @@
 	}
 
 	if Bool(binary.Properties.Symlink_preferred_arch) {
-		if String(binary.Properties.Stem) == "" && String(binary.Properties.Suffix) == "" {
-			ctx.PropertyErrorf("symlink_preferred_arch", "must also specify stem or suffix")
+		if String(binary.Properties.Suffix) == "" {
+			ctx.PropertyErrorf("symlink_preferred_arch", "must also specify suffix")
 		}
 		if ctx.TargetPrimary() {
-			binary.symlinks = append(binary.symlinks, ctx.baseModuleName())
+			binary.symlinks = append(binary.symlinks, binary.getStemWithoutSuffix(ctx))
 		}
 	}
 
@@ -440,8 +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 isBionic(ctx.baseModuleName()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
-		if ctx.Device() {
+	if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
+		if ctx.Device() && isBionic(ctx.baseModuleName()) {
 			binary.installSymlinkToRuntimeApex(ctx, file)
 		}
 		binary.baseInstaller.subDir = "bootstrap"
diff --git a/cc/builder.go b/cc/builder.go
index fc5400c..ee40736 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -22,10 +22,10 @@
 	"fmt"
 	"path/filepath"
 	"runtime"
-	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
 	"android/soong/cc/config"
@@ -92,20 +92,6 @@
 		},
 		"arCmd", "arFlags")
 
-	darwinAr = pctx.AndroidStaticRule("darwinAr",
-		blueprint.RuleParams{
-			Command:     "rm -f ${out} && ${config.MacArPath} $arFlags $out $in",
-			CommandDeps: []string{"${config.MacArPath}"},
-		},
-		"arFlags")
-
-	darwinAppendAr = pctx.AndroidStaticRule("darwinAppendAr",
-		blueprint.RuleParams{
-			Command:     "cp -f ${inAr} ${out}.tmp && ${config.MacArPath} $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
-			CommandDeps: []string{"${config.MacArPath}", "${inAr}"},
-		},
-		"arFlags", "inAr")
-
 	darwinStrip = pctx.AndroidStaticRule("darwinStrip",
 		blueprint.RuleParams{
 			Command:     "${config.MacStripPath} -u -r -o $out $in",
@@ -163,8 +149,8 @@
 
 	clangTidy = pctx.AndroidStaticRule("clangTidy",
 		blueprint.RuleParams{
-			Command:     "rm -f $out && CLANG_TIDY=${config.ClangBin}/clang-tidy ${config.ClangTidyShellPath} $tidyFlags $in -- $cFlags && touch $out",
-			CommandDeps: []string{"${config.ClangBin}/clang-tidy", "${config.ClangTidyShellPath}"},
+			Command:     "rm -f $out && ${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
+			CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
 		},
 		"cFlags", "tidyFlags")
 
@@ -227,6 +213,14 @@
 		blueprint.RuleParams{
 			Command: "gunzip -c $in > $out",
 		})
+
+	zip = pctx.AndroidStaticRule("zip",
+		blueprint.RuleParams{
+			Command:        "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
+			CommandDeps:    []string{"${SoongZipCmd}"},
+			Rspfile:        "$out.rsp",
+			RspfileContent: "$in",
+		})
 )
 
 func init() {
@@ -239,6 +233,8 @@
 		// Darwin doesn't have /proc
 		pctx.StaticVariable("relPwd", "")
 	}
+
+	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 }
 
 type builderFlags struct {
@@ -252,7 +248,6 @@
 	cppFlags        string
 	ldFlags         string
 	libFlags        string
-	yaccFlags       string
 	tidyFlags       string
 	sAbiFlags       string
 	yasmFlags       string
@@ -267,15 +262,18 @@
 
 	groupStaticLibs bool
 
-	stripKeepSymbols       bool
-	stripKeepSymbolsList   string
-	stripKeepMiniDebugInfo bool
-	stripAddGnuDebuglink   bool
-	stripUseGnuStrip       bool
+	stripKeepSymbols              bool
+	stripKeepSymbolsList          string
+	stripKeepSymbolsAndDebugFrame bool
+	stripKeepMiniDebugInfo        bool
+	stripAddGnuDebuglink          bool
+	stripUseGnuStrip              bool
 
 	proto            android.ProtoFlags
 	protoC           bool
 	protoOptionsFile bool
+
+	yacc *YaccProperties
 }
 
 type Objects struct {
@@ -418,7 +416,7 @@
 			ccCmd = "clang"
 			moduleCflags = cflags
 			moduleToolingCflags = toolingCflags
-		case ".cpp", ".cc", ".mm":
+		case ".cpp", ".cc", ".cxx", ".mm":
 			ccCmd = "clang++"
 			moduleCflags = cppflags
 			moduleToolingCflags = toolingCppflags
@@ -502,11 +500,6 @@
 func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
 	flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
 
-	if ctx.Darwin() {
-		transformDarwinObjToStaticLib(ctx, objFiles, flags, outputFile, deps)
-		return
-	}
-
 	arCmd := "${config.ClangBin}/llvm-ar"
 	arFlags := "crsD"
 	if !ctx.Darwin() {
@@ -529,87 +522,11 @@
 	})
 }
 
-// Generate a rule for compiling multiple .o files to a static library (.a) on
-// darwin.  The darwin ar tool doesn't support @file for list files, and has a
-// very small command line length limit, so we have to split the ar into multiple
-// steps, each appending to the previous one.
-func transformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
-	flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
-
-	arFlags := "cqs"
-
-	if len(objFiles) == 0 {
-		dummy := android.PathForModuleOut(ctx, "dummy"+objectExtension)
-		dummyAr := android.PathForModuleOut(ctx, "dummy"+staticLibraryExtension)
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        emptyFile,
-			Description: "empty object file",
-			Output:      dummy,
-			Implicits:   deps,
-		})
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        darwinAr,
-			Description: "empty static archive",
-			Output:      dummyAr,
-			Input:       dummy,
-			Args: map[string]string{
-				"arFlags": arFlags,
-			},
-		})
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        darwinAppendAr,
-			Description: "static link " + outputFile.Base(),
-			Output:      outputFile,
-			Input:       dummy,
-			Args: map[string]string{
-				"arFlags": "d",
-				"inAr":    dummyAr.String(),
-			},
-		})
-
-		return
-	}
-
-	// ARG_MAX on darwin is 262144, use half that to be safe
-	objFilesLists, err := splitListForSize(objFiles, 131072)
-	if err != nil {
-		ctx.ModuleErrorf("%s", err.Error())
-	}
-
-	var in, out android.WritablePath
-	for i, l := range objFilesLists {
-		in = out
-		out = outputFile
-		if i != len(objFilesLists)-1 {
-			out = android.PathForModuleOut(ctx, outputFile.Base()+strconv.Itoa(i))
-		}
-
-		build := android.BuildParams{
-			Rule:        darwinAr,
-			Description: "static link " + out.Base(),
-			Output:      out,
-			Inputs:      l,
-			Implicits:   deps,
-			Args: map[string]string{
-				"arFlags": arFlags,
-			},
-		}
-		if i != 0 {
-			build.Rule = darwinAppendAr
-			build.Args["inAr"] = in.String()
-		}
-		ctx.Build(pctx, build)
-	}
-}
-
 // Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
 // and shared libraries, to a shared library (.so) or dynamic executable
 func TransformObjToDynamicBinary(ctx android.ModuleContext,
 	objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths,
-	crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath) {
+	crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath, implicitOutputs android.WritablePaths) {
 
 	ldCmd := "${config.ClangBin}/clang++"
 
@@ -646,7 +563,11 @@
 	}
 
 	for _, lib := range sharedLibs {
-		libFlagsList = append(libFlagsList, lib.String())
+		libFile := lib.String()
+		if ctx.Windows() {
+			libFile = pathtools.ReplaceExtension(libFile, "lib")
+		}
+		libFlagsList = append(libFlagsList, libFile)
 	}
 
 	deps = append(deps, staticLibs...)
@@ -657,11 +578,12 @@
 	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        ld,
-		Description: "link " + outputFile.Base(),
-		Output:      outputFile,
-		Inputs:      objFiles,
-		Implicits:   deps,
+		Rule:            ld,
+		Description:     "link " + outputFile.Base(),
+		Output:          outputFile,
+		ImplicitOutputs: implicitOutputs,
+		Inputs:          objFiles,
+		Implicits:       deps,
 		Args: map[string]string{
 			"ldCmd":    ldCmd,
 			"crtBegin": crtBegin.String(),
@@ -723,7 +645,7 @@
 }
 
 func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
-	baseName, exportedHeaderFlags string, isLlndk, isVndkExt bool) android.OptionalPath {
+	baseName, exportedHeaderFlags string, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
 
 	outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
@@ -733,9 +655,14 @@
 	if exportedHeaderFlags == "" {
 		localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only")
 	}
-	if isLlndk {
-		localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-consider-opaque-types-different")
+	if isLlndk || isNdk {
 		createReferenceDumpFlags = "--llndk"
+		if isLlndk {
+			// TODO(b/130324828): "-consider-opaque-types-different" should apply to
+			// both LLNDK and NDK shared libs. However, a known issue in header-abi-diff
+			// breaks libaaudio. Remove the if-guard after the issue is fixed.
+			localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-consider-opaque-types-different")
+		}
 	}
 	if isVndkExt {
 		localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions")
@@ -840,6 +767,9 @@
 	if flags.stripKeepSymbolsList != "" {
 		args += " -k" + flags.stripKeepSymbolsList
 	}
+	if flags.stripKeepSymbolsAndDebugFrame {
+		args += " --keep-symbols-and-debug-frame"
+	}
 	if flags.stripUseGnuStrip {
 		args += " --use-gnu-strip"
 	}
@@ -867,13 +797,18 @@
 	})
 }
 
-func TransformCoverageFilesToLib(ctx android.ModuleContext,
-	inputs Objects, flags builderFlags, baseName string) android.OptionalPath {
+func TransformCoverageFilesToZip(ctx android.ModuleContext,
+	inputs Objects, baseName string) android.OptionalPath {
 
 	if len(inputs.coverageFiles) > 0 {
-		outputFile := android.PathForModuleOut(ctx, baseName+".gcnodir")
+		outputFile := android.PathForModuleOut(ctx, baseName+".zip")
 
-		TransformObjToStaticLib(ctx, inputs.coverageFiles, flags, outputFile, nil)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        zip,
+			Description: "zip " + outputFile.Base(),
+			Inputs:      inputs.coverageFiles,
+			Output:      outputFile,
+		})
 
 		return android.OptionalPathForPath(outputFile)
 	}
diff --git a/cc/cc.go b/cc/cc.go
index 0668fd9..a0ab255 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -19,6 +19,8 @@
 // is handled in builder.go
 
 import (
+	"fmt"
+	"io"
 	"strconv"
 	"strings"
 
@@ -51,6 +53,9 @@
 		ctx.TopDown("hwasan_deps", sanitizerDepsMutator(hwasan))
 		ctx.BottomUp("hwasan", sanitizerMutator(hwasan)).Parallel()
 
+		ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(fuzzer))
+		ctx.BottomUp("fuzzer", sanitizerMutator(fuzzer)).Parallel()
+
 		ctx.TopDown("cfi_deps", sanitizerDepsMutator(cfi))
 		ctx.BottomUp("cfi", sanitizerMutator(cfi)).Parallel()
 
@@ -60,7 +65,7 @@
 		ctx.TopDown("tsan_deps", sanitizerDepsMutator(tsan))
 		ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
 
-		ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator)
+		ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
 		ctx.BottomUp("coverage", coverageMutator).Parallel()
@@ -114,8 +119,13 @@
 	GeneratedSources android.Paths
 	GeneratedHeaders android.Paths
 
-	Flags, ReexportedFlags []string
-	ReexportedFlagsDeps    android.Paths
+	Flags                []string
+	IncludeDirs          []string
+	SystemIncludeDirs    []string
+	ReexportedDirs       []string
+	ReexportedSystemDirs []string
+	ReexportedFlags      []string
+	ReexportedDeps       android.Paths
 
 	// Paths to crt*.o files
 	CrtBegin, CrtEnd android.OptionalPath
@@ -136,7 +146,6 @@
 	ConlyFlags      []string // Flags that apply to C source files
 	CppFlags        []string // Flags that apply to C++ source files
 	ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
-	YaccFlags       []string // Flags that apply to Yacc source files
 	aidlFlags       []string // Flags that apply to aidl source files
 	rsFlags         []string // Flags that apply to renderscript source files
 	LdFlags         []string // Flags that apply to linker command lines
@@ -165,6 +174,8 @@
 	proto            android.ProtoFlags
 	protoC           bool // Whether to use C instead of C++
 	protoOptionsFile bool // Whether to look for a .options file next to the .proto
+
+	Yacc *YaccProperties
 }
 
 type ObjectLinkerProperties struct {
@@ -244,14 +255,14 @@
 	sdkVersion() string
 	useVndk() bool
 	isNdk() bool
-	isLlndk() bool
-	isLlndkPublic() bool
-	isVndkPrivate() bool
+	isLlndk(config android.Config) bool
+	isLlndkPublic(config android.Config) bool
+	isVndkPrivate(config android.Config) bool
 	isVndk() bool
 	isVndkSp() bool
 	isVndkExt() bool
 	inRecovery() bool
-	shouldCreateVndkSourceAbiDump() bool
+	shouldCreateVndkSourceAbiDump(config android.Config) bool
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
@@ -272,7 +283,7 @@
 }
 
 type BaseModuleContext interface {
-	android.BaseContext
+	android.BaseModuleContext
 	ModuleContextIntf
 }
 
@@ -357,6 +368,7 @@
 	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
 	vndkExtDepTag         = dependencyTag{name: "vndk extends", library: true}
 	runtimeDepTag         = dependencyTag{name: "runtime lib"}
+	coverageDepTag        = dependencyTag{name: "coverage"}
 )
 
 // Module contains the properties and members used by all C/C++ module types, and implements
@@ -406,6 +418,8 @@
 
 	// only non-nil when this is a shared library that reuses the objects of a static library
 	staticVariant *Module
+
+	makeLinkType string
 }
 
 func (c *Module) OutputFile() android.OptionalPath {
@@ -508,19 +522,19 @@
 	return inList(c.Name(), ndkMigratedLibs)
 }
 
-func (c *Module) isLlndk() bool {
+func (c *Module) isLlndk(config android.Config) bool {
 	// Returns true for both LLNDK (public) and LLNDK-private libs.
-	return inList(c.Name(), llndkLibraries)
+	return inList(c.Name(), *llndkLibraries(config))
 }
 
-func (c *Module) isLlndkPublic() bool {
+func (c *Module) isLlndkPublic(config android.Config) bool {
 	// Returns true only for LLNDK (public) libs.
-	return c.isLlndk() && !c.isVndkPrivate()
+	return c.isLlndk(config) && !c.isVndkPrivate(config)
 }
 
-func (c *Module) isVndkPrivate() bool {
+func (c *Module) isVndkPrivate(config android.Config) bool {
 	// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
-	return inList(c.Name(), vndkPrivateLibraries)
+	return inList(c.Name(), *vndkPrivateLibraries(config))
 }
 
 func (c *Module) isVndk() bool {
@@ -530,6 +544,13 @@
 	return false
 }
 
+func (c *Module) vndkVersion() string {
+	if vndkdep := c.vndkdep; vndkdep != nil {
+		return vndkdep.Properties.Vndk.Version
+	}
+	return ""
+}
+
 func (c *Module) isPgoCompile() bool {
 	if pgo := c.pgo; pgo != nil {
 		return pgo.Properties.PgoCompile
@@ -596,6 +617,9 @@
 	if library, ok := c.linker.(*libraryDecorator); ok {
 		return len(library.Properties.Stubs.Versions) > 0
 	}
+	if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+		return len(library.Properties.Stubs.Versions) > 0
+	}
 	return false
 }
 
@@ -615,8 +639,15 @@
 	return false
 }
 
+func installToBootstrap(name string, config android.Config) bool {
+	if name == "libclang_rt.hwasan-aarch64-android" {
+		return inList("hwaddress", config.SanitizeDevice())
+	}
+	return isBionic(name)
+}
+
 type baseModuleContext struct {
-	android.BaseContext
+	android.BaseModuleContext
 	moduleContextImpl
 }
 
@@ -685,16 +716,16 @@
 	return ctx.mod.isNdk()
 }
 
-func (ctx *moduleContextImpl) isLlndk() bool {
-	return ctx.mod.isLlndk()
+func (ctx *moduleContextImpl) isLlndk(config android.Config) bool {
+	return ctx.mod.isLlndk(config)
 }
 
-func (ctx *moduleContextImpl) isLlndkPublic() bool {
-	return ctx.mod.isLlndkPublic()
+func (ctx *moduleContextImpl) isLlndkPublic(config android.Config) bool {
+	return ctx.mod.isLlndkPublic(config)
 }
 
-func (ctx *moduleContextImpl) isVndkPrivate() bool {
-	return ctx.mod.isVndkPrivate()
+func (ctx *moduleContextImpl) isVndkPrivate(config android.Config) bool {
+	return ctx.mod.isVndkPrivate(config)
 }
 
 func (ctx *moduleContextImpl) isVndk() bool {
@@ -726,7 +757,7 @@
 }
 
 // Check whether ABI dumps should be created for this module.
-func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump() bool {
+func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump(config android.Config) bool {
 	if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
 		return false
 	}
@@ -748,13 +779,17 @@
 		// APEX variants do not need ABI dumps.
 		return false
 	}
+	if ctx.isStubs() {
+		// Stubs do not need ABI dumps.
+		return false
+	}
 	if ctx.isNdk() {
 		return true
 	}
-	if ctx.isLlndkPublic() {
+	if ctx.isLlndkPublic(config) {
 		return true
 	}
-	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate() {
+	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(config) {
 		// Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext and this is not
 		// VNDK-private.
 		return true
@@ -905,6 +940,8 @@
 }
 
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+	c.makeLinkType = c.getMakeLinkType(actx)
+
 	ctx := &moduleContext{
 		ModuleContext: actx,
 		moduleContextImpl: moduleContextImpl{
@@ -938,7 +975,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)
@@ -961,6 +998,14 @@
 	flags.ConlyFlags, _ = filterList(flags.ConlyFlags, config.IllegalFlags)
 
 	flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
+
+	for _, dir := range deps.IncludeDirs {
+		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+dir)
+	}
+	for _, dir := range deps.SystemIncludeDirs {
+		flags.GlobalFlags = append(flags.GlobalFlags, "-isystem "+dir)
+	}
+
 	c.flags = flags
 	// We need access to all the flags seen by a source file.
 	if c.sabi != nil {
@@ -1005,7 +1050,7 @@
 		}
 	}
 
-	if c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid() {
+	if c.installable() {
 		c.installer.install(ctx, c.outputFile.Path())
 		if ctx.Failed() {
 			return
@@ -1013,7 +1058,7 @@
 	}
 }
 
-func (c *Module) toolchain(ctx android.BaseContext) config.Toolchain {
+func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
 	if c.cachedToolchain == nil {
 		c.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
 	}
@@ -1134,7 +1179,7 @@
 
 func (c *Module) beginMutator(actx android.BottomUpMutatorContext) {
 	ctx := &baseModuleContext{
-		BaseContext: actx,
+		BaseModuleContext: actx,
 		moduleContextImpl: moduleContextImpl{
 			mod: c,
 		},
@@ -1184,6 +1229,9 @@
 		//
 		// The caller can then know to add the variantLibs dependencies differently from the
 		// nonvariantLibs
+
+		llndkLibraries := llndkLibraries(actx.Config())
+		vendorPublicLibraries := vendorPublicLibraries(actx.Config())
 		rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
 			variantLibs = []string{}
 			nonvariantLibs = []string{}
@@ -1196,9 +1244,9 @@
 					} else {
 						variantLibs = append(variantLibs, name+ndkLibrarySuffix)
 					}
-				} else if ctx.useVndk() && inList(name, llndkLibraries) {
+				} else if ctx.useVndk() && inList(name, *llndkLibraries) {
 					nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
-				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, vendorPublicLibraries) {
+				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
 					vendorPublicLib := name + vendorPublicLibrarySuffix
 					if actx.OtherModuleExists(vendorPublicLib) {
 						nonvariantLibs = append(nonvariantLibs, vendorPublicLib)
@@ -1499,6 +1547,7 @@
 // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
 // or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
 func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
+	llndkLibraries := llndkLibraries(ctx.Config())
 	check := func(child, parent android.Module) bool {
 		to, ok := child.(*Module)
 		if !ok {
@@ -1515,7 +1564,7 @@
 			return true
 		}
 
-		if to.isVndkSp() || inList(child.Name(), llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
+		if to.isVndkSp() || inList(child.Name(), *llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
 			return false
 		}
 
@@ -1530,7 +1579,7 @@
 	}
 	if module, ok := ctx.Module().(*Module); ok {
 		if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
-			if inList(ctx.ModuleName(), llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
+			if inList(ctx.ModuleName(), *llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
 				ctx.WalkDeps(check)
 			}
 		}
@@ -1544,6 +1593,16 @@
 	directStaticDeps := []*Module{}
 	directSharedDeps := []*Module{}
 
+	llndkLibraries := llndkLibraries(ctx.Config())
+	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
+	reexportExporter := func(exporter exportedFlagsProducer) {
+		depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, exporter.exportedDirs()...)
+		depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.exportedSystemDirs()...)
+		depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, exporter.exportedFlags()...)
+		depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, exporter.exportedDeps()...)
+	}
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1565,14 +1624,13 @@
 				if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
 					depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders,
 						genRule.GeneratedDeps()...)
-					flags := includeDirsToFlags(genRule.GeneratedHeaderDirs())
-					depPaths.Flags = append(depPaths.Flags, flags)
+					dirs := genRule.GeneratedHeaderDirs().Strings()
+					depPaths.IncludeDirs = append(depPaths.IncludeDirs, dirs...)
 					if depTag == genHeaderExportDepTag {
-						depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags)
-						depPaths.ReexportedFlagsDeps = append(depPaths.ReexportedFlagsDeps,
-							genRule.GeneratedDeps()...)
+						depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, dirs...)
+						depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps()...)
 						// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
-						c.sabi.Properties.ReexportedIncludeFlags = append(c.sabi.Properties.ReexportedIncludeFlags, flags)
+						c.sabi.Properties.ReexportedIncludes = append(c.sabi.Properties.ReexportedIncludes, dirs...)
 
 					}
 				} else {
@@ -1610,10 +1668,9 @@
 		if depTag == reuseObjTag {
 			if l, ok := ccDep.compiler.(libraryInterface); ok {
 				c.staticVariant = ccDep
-				objs, flags, deps := l.reuseObjs()
+				objs, exporter := l.reuseObjs()
 				depPaths.Objs = depPaths.Objs.Append(objs)
-				depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
-				depPaths.ReexportedFlagsDeps = append(depPaths.ReexportedFlagsDeps, deps...)
+				reexportExporter(exporter)
 				return
 			}
 		}
@@ -1676,18 +1733,20 @@
 			}
 
 			if i, ok := ccDep.linker.(exportedFlagsProducer); ok {
-				flags := i.exportedFlags()
-				deps := i.exportedFlagsDeps()
-				depPaths.Flags = append(depPaths.Flags, flags...)
-				depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, deps...)
+				depPaths.IncludeDirs = append(depPaths.IncludeDirs, i.exportedDirs()...)
+				depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
+				depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedDeps()...)
+				depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
 
 				if t.reexportFlags {
-					depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
-					depPaths.ReexportedFlagsDeps = append(depPaths.ReexportedFlagsDeps, deps...)
+					reexportExporter(i)
 					// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
 					// Re-exported shared library headers must be included as well since they can help us with type information
 					// about template instantiations (instantiated from their headers).
-					c.sabi.Properties.ReexportedIncludeFlags = append(c.sabi.Properties.ReexportedIncludeFlags, flags...)
+					// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
+					// scripts.
+					c.sabi.Properties.ReexportedIncludes = append(
+						c.sabi.Properties.ReexportedIncludes, i.exportedDirs()...)
 				}
 			}
 
@@ -1786,8 +1845,8 @@
 			libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
 			libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
-			isLLndk := inList(libName, llndkLibraries)
-			isVendorPublicLib := inList(libName, vendorPublicLibraries)
+			isLLndk := inList(libName, *llndkLibraries)
+			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
 			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
 
 			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() {
@@ -1802,6 +1861,8 @@
 				return libName + vendorPublicLibrarySuffix
 			} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
 				return libName + recoverySuffix
+			} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+				return libName + nativeBridgeSuffix
 			} else {
 				return libName
 			}
@@ -1847,12 +1908,16 @@
 
 	// Dedup exported flags from dependencies
 	depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
+	depPaths.IncludeDirs = android.FirstUniqueStrings(depPaths.IncludeDirs)
+	depPaths.SystemIncludeDirs = android.FirstUniqueStrings(depPaths.SystemIncludeDirs)
 	depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
+	depPaths.ReexportedDirs = android.FirstUniqueStrings(depPaths.ReexportedDirs)
+	depPaths.ReexportedSystemDirs = android.FirstUniqueStrings(depPaths.ReexportedSystemDirs)
 	depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
-	depPaths.ReexportedFlagsDeps = android.FirstUniquePaths(depPaths.ReexportedFlagsDeps)
+	depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
 
 	if c.sabi != nil {
-		c.sabi.Properties.ReexportedIncludeFlags = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludeFlags)
+		c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
 	}
 
 	return depPaths
@@ -1890,11 +1955,16 @@
 	return c.outputFile
 }
 
-func (c *Module) Srcs() android.Paths {
-	if c.outputFile.Valid() {
-		return android.Paths{c.outputFile.Path()}
+func (c *Module) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		if c.outputFile.Valid() {
+			return android.Paths{c.outputFile.Path()}, nil
+		}
+		return android.Paths{}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
-	return android.Paths{}
 }
 
 func (c *Module) static() bool {
@@ -1915,17 +1985,22 @@
 	return false
 }
 
-func (c *Module) getMakeLinkType() string {
+func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
+	name := actx.ModuleName()
 	if c.useVndk() {
-		if inList(c.Name(), vndkCoreLibraries) || inList(c.Name(), vndkSpLibraries) || inList(c.Name(), llndkLibraries) {
-			if inList(c.Name(), vndkPrivateLibraries) {
-				return "native:vndk_private"
-			} else {
+		if lib, ok := c.linker.(*llndkStubDecorator); ok {
+			if Bool(lib.Properties.Vendor_available) {
 				return "native:vndk"
 			}
-		} else {
-			return "native:vendor"
+			return "native:vndk_private"
 		}
+		if c.isVndk() && !c.isVndkExt() {
+			if Bool(c.VendorProperties.Vendor_available) {
+				return "native:vndk"
+			}
+			return "native:vndk_private"
+		}
+		return "native:vendor"
 	} else if c.inRecovery() {
 		return "native:recovery"
 	} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
@@ -1933,7 +2008,7 @@
 		// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
 		//family, link := getNdkStlFamilyAndLinkType(c)
 		//return fmt.Sprintf("native:ndk:%s:%s", family, link)
-	} else if inList(c.Name(), vndkUsingCoreVariantLibraries) {
+	} else if inList(name, *vndkUsingCoreVariantLibraries(actx.Config())) {
 		return "native:platform_vndk"
 	} else {
 		return "native:platform"
@@ -1951,6 +2026,10 @@
 	return false
 }
 
+func (c *Module) installable() bool {
+	return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
+}
+
 func (c *Module) imageVariation() string {
 	variation := "core"
 	if c.useVndk() {
@@ -1962,7 +2041,19 @@
 }
 
 func (c *Module) IDEInfo(dpInfo *android.IdeInfo) {
-	dpInfo.Srcs = append(dpInfo.Srcs, c.Srcs().Strings()...)
+	outputFiles, err := c.OutputFiles("")
+	if err != nil {
+		panic(err)
+	}
+	dpInfo.Srcs = append(dpInfo.Srcs, outputFiles.Strings()...)
+}
+
+func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+		}
+	}
 }
 
 //
@@ -1974,9 +2065,6 @@
 	android.ApexModuleBase
 }
 
-func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-}
-
 // cc_defaults provides a set of properties that can be inherited by other cc
 // modules. A module can use the properties from a cc_defaults using
 // `defaults: ["<:default_module_name>"]`. Properties of both modules are
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 678f90d..ca34185 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
 	"fmt"
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"reflect"
 	"sort"
 	"strings"
@@ -51,63 +52,13 @@
 	os.Exit(run())
 }
 
-func createTestContext(t *testing.T, config android.Config, bp string, fs map[string][]byte,
-	os android.OsType) *android.TestContext {
-
-	ctx := android.NewTestArchContext()
-	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
-	ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
-	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
-	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
-	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
-	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
-	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
-	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
-	ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
-	ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
-	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
-	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
-	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", ImageMutator).Parallel()
-		ctx.BottomUp("link", LinkageMutator).Parallel()
-		ctx.BottomUp("vndk", VndkMutator).Parallel()
-		ctx.BottomUp("version", VersionMutator).Parallel()
-		ctx.BottomUp("begin", BeginMutator).Parallel()
-	})
-	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
-	})
-
-	// add some modules that are required by the compiler and/or linker
-	bp = bp + GatherRequiredDepsForTest(os)
-
-	mockFS := map[string][]byte{
-		"Android.bp":  []byte(bp),
-		"foo.c":       nil,
-		"bar.c":       nil,
-		"a.proto":     nil,
-		"b.aidl":      nil,
-		"my_include":  nil,
-		"foo.map.txt": nil,
-		"liba.so":     nil,
-	}
-
-	for k, v := range fs {
-		mockFS[k] = v
-	}
-
-	ctx.MockFileSystem(mockFS)
-
-	return ctx
-}
-
 func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext {
 	return testCcWithConfigForOs(t, bp, config, android.Android)
 }
 
 func testCcWithConfigForOs(t *testing.T, bp string, config android.Config, os android.OsType) *android.TestContext {
 	t.Helper()
-	ctx := createTestContext(t, config, bp, nil, os)
+	ctx := CreateTestContext(bp, nil, os)
 	ctx.Register()
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
@@ -141,7 +92,7 @@
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
 
-	ctx := createTestContext(t, config, bp, nil, android.Android)
+	ctx := CreateTestContext(bp, nil, android.Android)
 	ctx.Register()
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
@@ -233,7 +184,7 @@
 		cc_library {
 			name: "libTest",
 			srcs: ["foo.c"],
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			vendor_available: true,
@@ -296,8 +247,28 @@
 	}
 }
 
+func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, name, subDir, variant string) {
+	vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+
+	snapshotPath := filepath.Join(subDir, name+".so")
+	mod := ctx.ModuleForTests(name, variant).Module().(*Module)
+	if !mod.outputFile.Valid() {
+		t.Errorf("%q must have output\n", name)
+		return
+	}
+
+	out := vndkSnapshot.Output(snapshotPath)
+	if out.Input != mod.outputFile.Path() {
+		t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), mod.outputFile.String())
+	}
+}
+
 func TestVndk(t *testing.T) {
-	ctx := testCc(t, `
+	config := android.TestArchConfig(buildDir, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+
+	ctx := testCcWithConfig(t, `
 		cc_library {
 			name: "libvndk",
 			vendor_available: true,
@@ -335,12 +306,35 @@
 			},
 			nocrt: true,
 		}
-	`)
+	`, config)
 
 	checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
 	checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "")
 	checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
 	checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "")
+
+	// Check VNDK snapshot output.
+
+	snapshotDir := "vndk-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+
+	vndkLibPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
+		"arm64", "armv8-a"))
+	vndkLib2ndPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
+		"arm", "armv7-a-neon"))
+
+	vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
+	vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
+	vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
+	vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
+
+	variant := "android_arm64_armv8-a_vendor_shared"
+	variant2nd := "android_arm_armv7-a-neon_vendor_shared"
+
+	checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLibPath, variant)
+	checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd)
+	checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLibPath, variant)
+	checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLib2ndPath, variant2nd)
 }
 
 func TestVndkDepError(t *testing.T) {
@@ -653,7 +647,7 @@
 	testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
 		cc_library {
 			name: "libllndk",
-			no_libgcc: true,
+			no_libcrt: true,
 			shared_libs: ["libnondoubleloadable"],
 		}
 
@@ -1269,6 +1263,110 @@
 	`)
 }
 
+func TestMakeLinkType(t *testing.T) {
+	config := android.TestArchConfig(buildDir, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	// native:vndk
+	ctx := testCcWithConfig(t, `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+	}
+	cc_library {
+		name: "libvndksp",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+			support_system_process: true,
+		},
+	}
+	cc_library {
+		name: "libvndkprivate",
+		vendor_available: false,
+		vndk: {
+			enabled: true,
+		},
+	}
+	cc_library {
+		name: "libvendor",
+		vendor: true,
+	}
+	cc_library {
+		name: "libvndkext",
+		vendor: true,
+		vndk: {
+			enabled: true,
+			extends: "libvndk",
+		},
+	}
+	vndk_prebuilt_shared {
+		name: "prevndk",
+		version: "27",
+		target_arch: "arm",
+		binder32bit: true,
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+		arch: {
+			arm: {
+				srcs: ["liba.so"],
+			},
+		},
+	}
+	cc_library {
+		name: "libllndk",
+	}
+	llndk_library {
+		name: "libllndk",
+		symbol_file: "",
+	}
+	cc_library {
+		name: "libllndkprivate",
+	}
+	llndk_library {
+		name: "libllndkprivate",
+		vendor_available: false,
+		symbol_file: "",
+	}`, config)
+
+	assertArrayString(t, *vndkCoreLibraries(config),
+		[]string{"libvndk", "libvndkprivate"})
+	assertArrayString(t, *vndkSpLibraries(config),
+		[]string{"libc++", "libvndksp"})
+	assertArrayString(t, *llndkLibraries(config),
+		[]string{"libc", "libdl", "libllndk", "libllndkprivate", "libm"})
+	assertArrayString(t, *vndkPrivateLibraries(config),
+		[]string{"libllndkprivate", "libvndkprivate"})
+
+	tests := []struct {
+		variant  string
+		name     string
+		expected string
+	}{
+		{vendorVariant, "libvndk", "native:vndk"},
+		{vendorVariant, "libvndksp", "native:vndk"},
+		{vendorVariant, "libvndkprivate", "native:vndk_private"},
+		{vendorVariant, "libvendor", "native:vendor"},
+		{vendorVariant, "libvndkext", "native:vendor"},
+		{vendorVariant, "prevndk.vndk.27.arm.binder32", "native:vndk"},
+		{vendorVariant, "libllndk.llndk", "native:vndk"},
+		{coreVariant, "libvndk", "native:platform"},
+		{coreVariant, "libvndkprivate", "native:platform"},
+		{coreVariant, "libllndk", "native:platform"},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			module := ctx.ModuleForTests(test.name, test.variant).Module().(*Module)
+			assertString(t, module.makeLinkType, test.expected)
+		})
+	}
+}
+
 var (
 	str11 = "01234567891"
 	str10 = str11[:10]
@@ -1688,7 +1786,7 @@
 		shared_libs: ["libllndk"],
 		vendor: true,
 		srcs: ["foo.c"],
-		no_libgcc: true,
+		no_libcrt: true,
 		nocrt: true,
 	}
 	`)
@@ -1717,7 +1815,7 @@
 	cc_library {
 		name: "libvendor_available1",
 		vendor_available: true,
-		no_libgcc : true,
+		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
 	}
@@ -1725,7 +1823,7 @@
 		name: "libvendor_available2",
 		vendor_available: true,
 		runtime_libs: ["libvendor_available1"],
-		no_libgcc : true,
+		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
 	}
@@ -1738,21 +1836,21 @@
 				exclude_runtime_libs: ["libvendor_available1"],
 			}
 		},
-		no_libgcc : true,
+		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
 	}
 	cc_library {
 		name: "libcore",
 		runtime_libs: ["libvendor_available1"],
-		no_libgcc : true,
+		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
 	}
 	cc_library {
 		name: "libvendor1",
 		vendor: true,
-		no_libgcc : true,
+		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
 	}
@@ -1760,7 +1858,7 @@
 		name: "libvendor2",
 		vendor: true,
 		runtime_libs: ["libvendor_available1", "libvendor1"],
-		no_libgcc : true,
+		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
 	}
@@ -1952,7 +2050,7 @@
 		name: "libvendorpublic",
 		srcs: ["foo.c"],
 		vendor: true,
-		no_libgcc: true,
+		no_libcrt: true,
 		nocrt: true,
 	}
 
@@ -1961,7 +2059,7 @@
 		shared_libs: ["libvendorpublic"],
 		vendor: false,
 		srcs: ["foo.c"],
-		no_libgcc: true,
+		no_libcrt: true,
 		nocrt: true,
 	}
 	cc_library {
@@ -1969,7 +2067,7 @@
 		shared_libs: ["libvendorpublic"],
 		vendor: true,
 		srcs: ["foo.c"],
-		no_libgcc: true,
+		no_libcrt: true,
 		nocrt: true,
 	}
 	`)
@@ -2165,3 +2263,25 @@
 		)
 	}
 }
+
+func assertString(t *testing.T, got, expected string) {
+	t.Helper()
+	if got != expected {
+		t.Errorf("expected %q got %q", expected, got)
+	}
+}
+
+func assertArrayString(t *testing.T, got, expected []string) {
+	t.Helper()
+	if len(got) != len(expected) {
+		t.Errorf("expected %d (%q) got (%d) %q", len(expected), expected, len(got), got)
+		return
+	}
+	for i := range got {
+		if got[i] != expected[i] {
+			t.Errorf("expected %d-th %q (%q) got %q (%q)",
+				i, expected[i], expected, got[i], got)
+			return
+		}
+	}
+}
diff --git a/cc/compdb.go b/cc/compdb.go
index 1102651..ecc67b8 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -141,7 +141,7 @@
 		isAsm = false
 		isCpp = false
 		clangPath = ccPath
-	case ".cpp", ".cc", ".mm":
+	case ".cpp", ".cc", ".cxx", ".mm":
 		isAsm = false
 		isCpp = true
 		clangPath = cxxPath
diff --git a/cc/compiler.go b/cc/compiler.go
index f9af4d8..fd6184b 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -57,9 +57,6 @@
 	// compiling with clang
 	Clang_asflags []string `android:"arch_variant"`
 
-	// list of module-specific flags that will be used for .y and .yy compiles
-	Yaccflags []string
-
 	// the instruction set architecture to use to compile the C/C++
 	// module.
 	Instruction_set *string `android:"arch_variant"`
@@ -103,6 +100,8 @@
 	// if set to false, use -std=c++* instead of -std=gnu++*
 	Gnu_extensions *bool
 
+	Yacc *YaccProperties
+
 	Aidl struct {
 		// list of directories that will be added to the aidl include paths.
 		Include_dirs []string
@@ -226,11 +225,6 @@
 		deps = protoDeps(ctx, deps, &compiler.Proto, Bool(compiler.Properties.Proto.Static))
 	}
 
-	if compiler.hasSrcExt(".sysprop") {
-		deps.HeaderLibs = append(deps.HeaderLibs, "libbase_headers")
-		deps.SharedLibs = append(deps.SharedLibs, "liblog")
-	}
-
 	if Bool(compiler.Properties.Openmp) {
 		deps.StaticLibs = append(deps.StaticLibs, "libomp")
 	}
@@ -275,7 +269,8 @@
 	flags.ConlyFlags = append(flags.ConlyFlags, esc(compiler.Properties.Conlyflags)...)
 	flags.AsFlags = append(flags.AsFlags, esc(compiler.Properties.Asflags)...)
 	flags.YasmFlags = append(flags.YasmFlags, esc(compiler.Properties.Asflags)...)
-	flags.YaccFlags = append(flags.YaccFlags, esc(compiler.Properties.Yaccflags)...)
+
+	flags.Yacc = compiler.Properties.Yacc
 
 	// Include dir cflags
 	localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
diff --git a/cc/config/clang.go b/cc/config/clang.go
index a87d569..59c78a6 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -107,6 +107,9 @@
 		// Help catch common 32/64-bit errors.
 		"-Werror=int-conversion",
 
+		// Enable the new pass manager.
+		"-fexperimental-new-pass-manager",
+
 		// Disable overly aggressive warning for macros defined with a leading underscore
 		// This happens in AndroidConfig.h, which is included nearly everywhere.
 		// TODO: can we remove this now?
diff --git a/cc/config/global.go b/cc/config/global.go
index 815c31d..a27246e 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -122,8 +122,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r353983c"
-	ClangDefaultShortVersion = "9.0.3"
+	ClangDefaultVersion      = "clang-r353983d"
+	ClangDefaultShortVersion = "9.0.4"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
@@ -202,7 +202,6 @@
 	})
 	pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
 	pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
-	pctx.StaticVariable("ClangTidyShellPath", "build/soong/scripts/clang-tidy.sh")
 
 	pctx.VariableFunc("ClangShortVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_RELEASE_VERSION"); override != "" {
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 542f737..e754ad5 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -65,6 +65,7 @@
 	"android.hardware.neuralnetworks@1.0",
 	"android.hardware.neuralnetworks@1.1",
 	"android.hardware.neuralnetworks@1.2",
+	"android.hardware.nfc@1.0",
 	"android.hardware.nfc@1.1",
 	"android.hardware.nfc@1.2",
 	"android.hardware.oemlock@1.0",
@@ -110,8 +111,11 @@
 	"libdumpstateutil",
 	"libexpat",
 	"libfmq",
+	"libgatekeeper",
 	"libgui",
 	"libhidlcache",
+	"libkeymaster_messages",
+	"libkeymaster_portable",
 	"libmedia_helper",
 	"libmedia_omx",
 	"libmemtrack",
@@ -122,7 +126,9 @@
 	"libsoftkeymasterdevice",
 	"libsqlite",
 	"libssl",
+	"libstagefright_amrnb_common",
 	"libstagefright_bufferqueue_helper",
+	"libstagefright_enc_common",
 	"libstagefright_flacdec",
 	"libstagefright_foundation",
 	"libstagefright_omx",
@@ -150,8 +156,10 @@
 	"libstagefright_soft_vpxenc",
 	"libstagefright_xmlparser",
 	"libsysutils",
+	"libtinyxml2",
 	"libui",
 	"libvorbisidec",
 	"libxml2",
+	"libyuv",
 	"libziparchive",
 }
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 0f0420f..d9c96df 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -67,10 +67,16 @@
 		"sse4":   []string{"-msse4"},
 		"sse4_1": []string{"-msse4.1"},
 		"sse4_2": []string{"-msse4.2"},
+
+		// Not all cases there is performance gain by enabling -mavx -mavx2
+		// flags so these flags are not enabled by default.
+		// if there is performance gain in individual library components,
+		// the compiler flags can be set in corresponding bp files.
+		// "avx":    []string{"-mavx"},
+		// "avx2":   []string{"-mavx2"},
+		// "avx512": []string{"-mavx512"}
+
 		"popcnt": []string{"-mpopcnt"},
-		"avx":    []string{"-mavx"},
-		"avx2":   []string{"-mavx2"},
-		"avx512": []string{"-mavx512"},
 		"aes_ni": []string{"-maes"},
 	}
 )
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 500014e..6504758 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -86,8 +86,15 @@
 		"sse4":   []string{"-msse4"},
 		"sse4_1": []string{"-msse4.1"},
 		"sse4_2": []string{"-msse4.2"},
-		"avx":    []string{"-mavx"},
-		"avx2":   []string{"-mavx2"},
+
+		// Not all cases there is performance gain by enabling -mavx -mavx2
+		// flags so these flags are not enabled by default.
+		// if there is performance gain in individual library components,
+		// the compiler flags can be set in corresponding bp files.
+		// "avx":    []string{"-mavx"},
+		// "avx2":   []string{"-mavx2"},
+		// "avx512": []string{"-mavx512"}
+
 		"aes_ni": []string{"-maes"},
 	}
 )
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/gen.go b/cc/gen.go
index 0c3d089..7516b28 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"strings"
 
 	"github.com/google/blueprint"
 
@@ -24,43 +25,26 @@
 
 func init() {
 	pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex")
-	pctx.SourcePathVariable("yaccCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/bison")
-	pctx.SourcePathVariable("yaccDataDir", "prebuilts/build-tools/common/bison")
+	pctx.SourcePathVariable("m4Cmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/m4")
 
 	pctx.HostBinToolVariable("aidlCmd", "aidl-cpp")
 	pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp")
 }
 
 var (
-	yacc = pctx.AndroidStaticRule("yacc",
-		blueprint.RuleParams{
-			Command:     "BISON_PKGDATADIR=$yaccDataDir $yaccCmd -d $yaccFlags --defines=$hFile -o $out $in",
-			CommandDeps: []string{"$yaccCmd"},
-		},
-		"yaccFlags", "hFile")
-
 	lex = pctx.AndroidStaticRule("lex",
 		blueprint.RuleParams{
-			Command:     "$lexCmd -o$out $in",
-			CommandDeps: []string{"$lexCmd"},
+			Command:     "M4=$m4Cmd $lexCmd -o$out $in",
+			CommandDeps: []string{"$lexCmd", "$m4Cmd"},
 		})
 
-	aidl = pctx.AndroidStaticRule("aidl",
-		blueprint.RuleParams{
-			Command:     "$aidlCmd -d${out}.d --ninja $aidlFlags $in $outDir $out",
-			CommandDeps: []string{"$aidlCmd"},
-			Depfile:     "${out}.d",
-			Deps:        blueprint.DepsGCC,
-		},
-		"aidlFlags", "outDir")
-
 	sysprop = pctx.AndroidStaticRule("sysprop",
 		blueprint.RuleParams{
-			Command: "$syspropCmd --header-dir=$headerOutDir --system-header-dir=$systemOutDir " +
+			Command: "$syspropCmd --header-dir=$headerOutDir --public-header-dir=$publicOutDir " +
 				"--source-dir=$srcOutDir --include-name=$includeName $in",
 			CommandDeps: []string{"$syspropCmd"},
 		},
-		"headerOutDir", "systemOutDir", "srcOutDir", "includeName")
+		"headerOutDir", "publicOutDir", "srcOutDir", "includeName")
 
 	windmc = pctx.AndroidStaticRule("windmc",
 		blueprint.RuleParams{
@@ -70,38 +54,91 @@
 		"windmcCmd")
 )
 
-func genYacc(ctx android.ModuleContext, yaccFile android.Path, outFile android.ModuleGenPath, yaccFlags string) (headerFile android.ModuleGenPath) {
-	headerFile = android.GenPathWithExt(ctx, "yacc", yaccFile, "h")
+type YaccProperties struct {
+	// list of module-specific flags that will be used for .y and .yy compiles
+	Flags []string
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:           yacc,
-		Description:    "yacc " + yaccFile.Rel(),
-		Output:         outFile,
-		ImplicitOutput: headerFile,
-		Input:          yaccFile,
-		Args: map[string]string{
-			"yaccFlags": yaccFlags,
-			"hFile":     headerFile.String(),
-		},
-	})
+	// whether the yacc files will produce a location.hh file
+	Gen_location_hh *bool
 
-	return headerFile
+	// whether the yacc files will product a position.hh file
+	Gen_position_hh *bool
 }
 
-func genAidl(ctx android.ModuleContext, aidlFile android.Path, outFile android.ModuleGenPath, aidlFlags string) android.Paths {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        aidl,
-		Description: "aidl " + aidlFile.Rel(),
-		Output:      outFile,
-		Input:       aidlFile,
-		Args: map[string]string{
-			"aidlFlags": aidlFlags,
-			"outDir":    android.PathForModuleGen(ctx, "aidl").String(),
-		},
-	})
+func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile android.Path,
+	outFile android.ModuleGenPath, props *YaccProperties) (headerFiles android.Paths) {
 
-	// TODO: This should return the generated headers, not the source file.
-	return android.Paths{outFile}
+	outDir := android.PathForModuleGen(ctx, "yacc")
+	headerFile := android.GenPathWithExt(ctx, "yacc", yaccFile, "h")
+	ret := android.Paths{headerFile}
+
+	cmd := rule.Command()
+
+	// Fix up #line markers to not use the sbox temporary directory
+	sedCmd := "sed -i.bak 's#__SBOX_OUT_DIR__#" + outDir.String() + "#'"
+	rule.Command().Text(sedCmd).Input(outFile)
+	rule.Command().Text(sedCmd).Input(headerFile)
+
+	var flags []string
+	if props != nil {
+		flags = props.Flags
+
+		if Bool(props.Gen_location_hh) {
+			locationHeader := outFile.InSameDir(ctx, "location.hh")
+			ret = append(ret, locationHeader)
+			cmd.ImplicitOutput(locationHeader)
+			rule.Command().Text(sedCmd).Input(locationHeader)
+		}
+		if Bool(props.Gen_position_hh) {
+			positionHeader := outFile.InSameDir(ctx, "position.hh")
+			ret = append(ret, positionHeader)
+			cmd.ImplicitOutput(positionHeader)
+			rule.Command().Text(sedCmd).Input(positionHeader)
+		}
+	}
+
+	cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison").
+		FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")).
+		Tool(ctx.Config().PrebuiltBuildTool(ctx, "bison")).
+		Flag("-d").
+		Flags(flags).
+		FlagWithOutput("--defines=", headerFile).
+		Flag("-o").Output(outFile).Input(yaccFile)
+
+	return ret
+}
+
+func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path,
+	outFile, depFile android.ModuleGenPath, aidlFlags string) android.Paths {
+
+	aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
+	baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
+	shortName := strings.TrimPrefix(baseName, "I")
+
+	outDir := android.PathForModuleGen(ctx, "aidl")
+	headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
+	headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
+	headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
+
+	cmd := rule.Command()
+	cmd.Tool(ctx.Config().HostToolPath(ctx, "aidl-cpp")).
+		FlagWithDepFile("-d", depFile).
+		Flag("--ninja").
+		Flag(aidlFlags).
+		Input(aidlFile).
+		OutputDir().
+		Output(outFile).
+		ImplicitOutputs(android.WritablePaths{
+			headerI,
+			headerBn,
+			headerBp,
+		})
+
+	return android.Paths{
+		headerI,
+		headerBn,
+		headerBp,
+	}
 }
 
 func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) {
@@ -115,7 +152,7 @@
 
 func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
 	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
-	systemHeaderFile := android.PathForModuleGen(ctx, "sysprop/system", "include", syspropFile.Rel()+".h")
+	publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
 	cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
 
 	ctx.Build(pctx, android.BuildParams{
@@ -126,7 +163,7 @@
 		Input:          syspropFile,
 		Args: map[string]string{
 			"headerOutDir": filepath.Dir(headerFile.String()),
-			"systemOutDir": filepath.Dir(systemHeaderFile.String()),
+			"publicOutDir": filepath.Dir(publicHeaderFile.String()),
 			"srcOutDir":    filepath.Dir(cppFile.String()),
 			"includeName":  syspropFile.Rel() + ".h",
 		},
@@ -159,19 +196,28 @@
 	buildFlags builderFlags) (android.Paths, android.Paths) {
 
 	var deps android.Paths
-
 	var rsFiles android.Paths
 
+	var aidlRule *android.RuleBuilder
+
+	var yaccRule_ *android.RuleBuilder
+	yaccRule := func() *android.RuleBuilder {
+		if yaccRule_ == nil {
+			yaccRule_ = android.NewRuleBuilder().Sbox(android.PathForModuleGen(ctx, "yacc"))
+		}
+		return yaccRule_
+	}
+
 	for i, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".y":
 			cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c")
 			srcFiles[i] = cFile
-			deps = append(deps, genYacc(ctx, srcFile, cFile, buildFlags.yaccFlags))
+			deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...)
 		case ".yy":
 			cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp")
 			srcFiles[i] = cppFile
-			deps = append(deps, genYacc(ctx, srcFile, cppFile, buildFlags.yaccFlags))
+			deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...)
 		case ".l":
 			cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
 			srcFiles[i] = cFile
@@ -185,9 +231,13 @@
 			srcFiles[i] = ccFile
 			deps = append(deps, headerFile)
 		case ".aidl":
+			if aidlRule == nil {
+				aidlRule = android.NewRuleBuilder().Sbox(android.PathForModuleGen(ctx, "aidl"))
+			}
 			cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
+			depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
 			srcFiles[i] = cppFile
-			deps = append(deps, genAidl(ctx, srcFile, cppFile, buildFlags.aidlFlags)...)
+			deps = append(deps, genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)...)
 		case ".rs", ".fs":
 			cppFile := rsGeneratedCppFile(ctx, srcFile)
 			rsFiles = append(rsFiles, srcFiles[i])
@@ -203,6 +253,14 @@
 		}
 	}
 
+	if aidlRule != nil {
+		aidlRule.Build(pctx, ctx, "aidl", "gen aidl")
+	}
+
+	if yaccRule_ != nil {
+		yaccRule_.Build(pctx, ctx, "yacc", "gen yacc")
+	}
+
 	if len(rsFiles) > 0 {
 		deps = append(deps, rsGenerateCpp(ctx, rsFiles, buildFlags.rsFlags)...)
 	}
diff --git a/cc/gen_test.go b/cc/gen_test.go
index a0f7308..e4219d9 100644
--- a/cc/gen_test.go
+++ b/cc/gen_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"path/filepath"
 	"testing"
 )
 
@@ -32,7 +33,7 @@
 		aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Rule("aidl")
 		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Module().(*Module)
 
-		if !inList("-I"+aidl.Args["outDir"], libfoo.flags.GlobalFlags) {
+		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.GlobalFlags) {
 			t.Errorf("missing aidl includes in global flags")
 		}
 	})
@@ -55,7 +56,7 @@
 		aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Rule("aidl")
 		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Module().(*Module)
 
-		if !inList("-I"+aidl.Args["outDir"], libfoo.flags.GlobalFlags) {
+		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.GlobalFlags) {
 			t.Errorf("missing aidl includes in global flags")
 		}
 	})
diff --git a/cc/genrule.go b/cc/genrule.go
index decf6ea..e594f4b 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -42,5 +42,7 @@
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth)
 
+	android.InitApexModule(module)
+
 	return module
 }
diff --git a/cc/installer.go b/cc/installer.go
index bd8f9e7..cb261b7 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -66,7 +66,7 @@
 	if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
 		dir = installer.dir64
 	}
-	if !ctx.Host() && !ctx.Arch().Native {
+	if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
 		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
 	if installer.location == InstallInData && ctx.useVndk() {
diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go
index 82a779c..fff419e 100644
--- a/cc/kernel_headers.go
+++ b/cc/kernel_headers.go
@@ -25,13 +25,16 @@
 func (stub *kernelHeadersDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
 	if ctx.Device() {
 		f := &stub.libraryDecorator.flagExporter
-		for _, dir := range ctx.DeviceConfig().DeviceKernelHeaderDirs() {
-			f.flags = append(f.flags, "-isystem "+dir)
-		}
+		f.reexportSystemDirs(ctx.DeviceConfig().DeviceKernelHeaderDirs()...)
 	}
 	return stub.libraryDecorator.linkStatic(ctx, flags, deps, objs)
 }
 
+// kernel_headers retrieves the list of kernel headers directories from
+// TARGET_BOARD_KERNEL_HEADERS and TARGET_PRODUCT_KERNEL_HEADERS variables in
+// a makefile for compilation. See
+// https://android.googlesource.com/platform/build/+/master/core/config.mk
+// for more details on them.
 func kernelHeadersFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.HeaderOnly()
diff --git a/cc/library.go b/cc/library.go
index ca1c1be..6ac0c39 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -15,6 +15,8 @@
 package cc
 
 import (
+	"fmt"
+	"io"
 	"path/filepath"
 	"regexp"
 	"sort"
@@ -95,6 +97,9 @@
 
 	// Properties for ABI compatibility checker
 	Header_abi_checker struct {
+		// Enable ABI checks (even if this is not an LLNDK/VNDK lib)
+		Enabled *bool
+
 		// Path to a symbol file that specifies the symbols to be included in the generated
 		// ABI dump file
 		Symbol_file *string `android:"path"`
@@ -108,8 +113,6 @@
 }
 
 type LibraryMutatedProperties struct {
-	VariantName string `blueprint:"mutated"`
-
 	// Build a static variant
 	BuildStatic bool `blueprint:"mutated"`
 	// Build a shared variant
@@ -203,8 +206,10 @@
 type flagExporter struct {
 	Properties FlagExporterProperties
 
-	flags     []string
-	flagsDeps android.Paths
+	dirs       []string
+	systemDirs []string
+	flags      []string
+	deps       android.Paths
 }
 
 func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
@@ -215,32 +220,57 @@
 	}
 }
 
-func (f *flagExporter) exportIncludes(ctx ModuleContext, inc string) {
-	includeDirs := f.exportedIncludes(ctx)
-	for _, dir := range includeDirs.Strings() {
-		f.flags = append(f.flags, inc+dir)
-	}
+func (f *flagExporter) exportIncludes(ctx ModuleContext) {
+	f.dirs = append(f.dirs, f.exportedIncludes(ctx).Strings()...)
 }
 
-func (f *flagExporter) reexportFlags(flags []string) {
+func (f *flagExporter) exportIncludesAsSystem(ctx ModuleContext) {
+	f.systemDirs = append(f.systemDirs, f.exportedIncludes(ctx).Strings()...)
+}
+
+func (f *flagExporter) reexportDirs(dirs ...string) {
+	f.dirs = append(f.dirs, dirs...)
+}
+
+func (f *flagExporter) reexportSystemDirs(dirs ...string) {
+	f.systemDirs = append(f.systemDirs, dirs...)
+}
+
+func (f *flagExporter) reexportFlags(flags ...string) {
+	for _, flag := range flags {
+		if strings.HasPrefix(flag, "-I") || strings.HasPrefix(flag, "-isystem") {
+			panic(fmt.Errorf("Exporting invalid flag %q: "+
+				"use reexportDirs or reexportSystemDirs to export directories", flag))
+		}
+	}
 	f.flags = append(f.flags, flags...)
 }
 
-func (f *flagExporter) reexportDeps(deps android.Paths) {
-	f.flagsDeps = append(f.flagsDeps, deps...)
+func (f *flagExporter) reexportDeps(deps ...android.Path) {
+	f.deps = append(f.deps, deps...)
+}
+
+func (f *flagExporter) exportedDirs() []string {
+	return f.dirs
+}
+
+func (f *flagExporter) exportedSystemDirs() []string {
+	return f.systemDirs
 }
 
 func (f *flagExporter) exportedFlags() []string {
 	return f.flags
 }
 
-func (f *flagExporter) exportedFlagsDeps() android.Paths {
-	return f.flagsDeps
+func (f *flagExporter) exportedDeps() android.Paths {
+	return f.deps
 }
 
 type exportedFlagsProducer interface {
+	exportedDirs() []string
+	exportedSystemDirs() []string
 	exportedFlags() []string
-	exportedFlagsDeps() android.Paths
+	exportedDeps() android.Paths
 }
 
 var _ exportedFlagsProducer = (*flagExporter)(nil)
@@ -252,9 +282,7 @@
 	MutatedProperties LibraryMutatedProperties
 
 	// For reusing static library objects for shared library
-	reuseObjects       Objects
-	reuseExportedFlags []string
-	reuseExportedDeps  android.Paths
+	reuseObjects Objects
 
 	// table-of-contents file to optimize out relinking when possible
 	tocFile android.OptionalPath
@@ -356,9 +384,10 @@
 				)
 			}
 		} else {
-			f = append(f,
-				"-shared",
-				"-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
+			f = append(f, "-shared")
+			if !ctx.Windows() {
+				f = append(f, "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
+			}
 		}
 
 		flags.LdFlags = append(f, flags.LdFlags...)
@@ -400,23 +429,11 @@
 	return flags
 }
 
-func extractExportIncludesFromFlags(flags []string) []string {
-	// This method is used in the  generation of rules which produce
-	// abi-dumps for source files. Exported headers are needed to infer the
-	// abi exported by a library and filter out the rest of the abi dumped
-	// from a source. We extract the include flags exported by a library.
-	// This includes the flags exported which are re-exported from static
-	// library dependencies, exported header library dependencies and
-	// generated header dependencies. -isystem headers are not included
-	// since for bionic libraries, abi-filtering is taken care of by version
-	// scripts.
-	var exportedIncludes []string
-	for _, flag := range flags {
-		if strings.HasPrefix(flag, "-I") {
-			exportedIncludes = append(exportedIncludes, flag)
-		}
+func (library *libraryDecorator) shouldCreateVndkSourceAbiDump(ctx ModuleContext) bool {
+	if library.Properties.Header_abi_checker.Enabled != nil {
+		return Bool(library.Properties.Header_abi_checker.Enabled)
 	}
-	return exportedIncludes
+	return ctx.shouldCreateVndkSourceAbiDump(ctx.Config())
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -438,14 +455,14 @@
 		}
 		return Objects{}
 	}
-	if ctx.shouldCreateVndkSourceAbiDump() || library.sabi.Properties.CreateSAbiDumps {
+	if library.shouldCreateVndkSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
 			SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
 		}
-		for _, reexportedInclude := range extractExportIncludesFromFlags(library.sabi.Properties.ReexportedIncludeFlags) {
-			SourceAbiFlags = append(SourceAbiFlags, reexportedInclude)
+		for _, reexportedInclude := range library.sabi.Properties.ReexportedIncludes {
+			SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude)
 		}
 		flags.SAbiFlags = SourceAbiFlags
 		total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.Properties.Shared.Srcs) +
@@ -475,7 +492,7 @@
 	getWholeStaticMissingDeps() []string
 	static() bool
 	objs() Objects
-	reuseObjs() (Objects, []string, android.Paths)
+	reuseObjs() (Objects, exportedFlagsProducer)
 	toc() android.OptionalPath
 
 	// Returns true if the build options for the module have selected a static or shared build
@@ -485,6 +502,9 @@
 	// Sets whether a specific variant is static or shared
 	setStatic()
 	setShared()
+
+	// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
+	androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
 }
 
 func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
@@ -506,7 +526,7 @@
 		}
 	}
 
-	return name + library.MutatedProperties.VariantName
+	return name
 }
 
 var versioningMacroNamesListMutex sync.Mutex
@@ -611,7 +631,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)
 
@@ -629,8 +649,7 @@
 
 	TransformObjToStaticLib(ctx, library.objects.objFiles, builderFlags, outputFile, objs.tidyFiles)
 
-	library.coverageOutputFile = TransformCoverageFilesToLib(ctx, library.objects, builderFlags,
-		ctx.ModuleName()+library.MutatedProperties.VariantName)
+	library.coverageOutputFile = TransformCoverageFilesToZip(ctx, library.objects, ctx.ModuleName())
 
 	library.wholeStaticMissingDeps = ctx.GetMissingDependencies()
 
@@ -682,6 +701,14 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := outputFile
 
+	var implicitOutputs android.WritablePaths
+	if ctx.Windows() {
+		importLibraryPath := android.PathForModuleOut(ctx, pathtools.ReplaceExtension(fileName, "lib"))
+
+		flags.LdFlags = append(flags.LdFlags, "-Wl,--out-implib="+importLibraryPath.String())
+		implicitOutputs = append(implicitOutputs, importLibraryPath)
+	}
+
 	builderFlags := flagsToBuilderFlags(flags)
 
 	// Optimize out relinking against shared libraries whose interface hasn't changed by
@@ -698,7 +725,7 @@
 		}
 		strippedOutputFile := outputFile
 		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
-		library.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
+		library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
 	}
 
 	library.unstrippedOutputFile = outputFile
@@ -715,7 +742,7 @@
 			if library.stripper.needsStrip(ctx) {
 				out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
 				library.distFile = android.OptionalPathForPath(out)
-				library.stripper.strip(ctx, versionedOutputFile, out, builderFlags)
+				library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
 			}
 
 			library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -733,7 +760,7 @@
 
 	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
 		deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
-		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
+		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
 
 	objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -741,7 +768,7 @@
 	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.StaticLibObjs.sAbiDumpFiles...)
 	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
 
-	library.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, library.getLibName(ctx))
+	library.coverageOutputFile = TransformCoverageFilesToZip(ctx, objs, library.getLibName(ctx))
 	library.linkSAbiDumpFiles(ctx, objs, fileName, ret)
 
 	return ret
@@ -759,10 +786,10 @@
 }
 
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
-	isLlndk := inList(ctx.baseModuleName(), llndkLibraries) || inList(ctx.baseModuleName(), ndkMigratedLibs)
+	isLlndkOrNdk := inList(ctx.baseModuleName(), *llndkLibraries(ctx.Config())) || inList(ctx.baseModuleName(), ndkMigratedLibs)
 
-	refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndk, false)
-	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndk, true)
+	refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), false)
+	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), true)
 
 	if refAbiDumpTextFile.Valid() {
 		if refAbiDumpGzipFile.Valid() {
@@ -780,7 +807,7 @@
 }
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
-	if len(objs.sAbiDumpFiles) > 0 && ctx.shouldCreateVndkSourceAbiDump() {
+	if library.shouldCreateVndkSourceAbiDump(ctx) {
 		vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
 		if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
 			vndkVersion = ver
@@ -791,8 +818,8 @@
 		for _, dir := range exportIncludeDirs.Strings() {
 			SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
 		}
-		for _, reexportedInclude := range extractExportIncludesFromFlags(library.sabi.Properties.ReexportedIncludeFlags) {
-			SourceAbiFlags = append(SourceAbiFlags, reexportedInclude)
+		for _, reexportedInclude := range library.sabi.Properties.ReexportedIncludes {
+			SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude)
 		}
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
 		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
@@ -803,7 +830,7 @@
 		refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
 		if refAbiDumpFile != nil {
 			library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
-				refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(), ctx.isVndkExt())
+				refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(ctx.Config()), ctx.isNdk(), ctx.isVndkExt())
 		}
 	}
 }
@@ -819,19 +846,17 @@
 		out = library.linkShared(ctx, flags, deps, objs)
 	}
 
-	library.exportIncludes(ctx, "-I")
-	library.reexportFlags(deps.ReexportedFlags)
-	library.reexportDeps(deps.ReexportedFlagsDeps)
+	library.exportIncludes(ctx)
+	library.reexportDirs(deps.ReexportedDirs...)
+	library.reexportSystemDirs(deps.ReexportedSystemDirs...)
+	library.reexportFlags(deps.ReexportedFlags...)
+	library.reexportDeps(deps.ReexportedDeps...)
 
 	if Bool(library.Properties.Aidl.Export_aidl_headers) {
 		if library.baseCompiler.hasSrcExt(".aidl") {
-			flags := []string{
-				"-I" + android.PathForModuleGen(ctx, "aidl").String(),
-			}
-			library.reexportFlags(flags)
-			library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
-			library.reexportDeps(library.baseCompiler.pathDeps) // TODO: restrict to aidl deps
-			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.pathDeps...)
+			dir := android.PathForModuleGen(ctx, "aidl").String()
+			library.reexportDirs(dir)
+			library.reexportDeps(library.baseCompiler.pathDeps...) // TODO: restrict to aidl deps
 		}
 	}
 
@@ -839,45 +864,34 @@
 		if library.baseCompiler.hasSrcExt(".proto") {
 			includes := []string{}
 			if flags.proto.CanonicalPathFromRoot {
-				includes = append(includes, "-I"+flags.proto.SubDir.String())
+				includes = append(includes, flags.proto.SubDir.String())
 			}
-			includes = append(includes, "-I"+flags.proto.Dir.String())
-			library.reexportFlags(includes)
-			library.reuseExportedFlags = append(library.reuseExportedFlags, includes...)
-			library.reexportDeps(library.baseCompiler.pathDeps) // TODO: restrict to proto deps
-			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.pathDeps...)
+			includes = append(includes, flags.proto.Dir.String())
+			library.reexportDirs(includes...)
+			library.reexportDeps(library.baseCompiler.pathDeps...) // TODO: restrict to proto deps
 		}
 	}
 
 	if library.baseCompiler.hasSrcExt(".sysprop") {
-		internalFlags := []string{
-			"-I" + android.PathForModuleGen(ctx, "sysprop", "include").String(),
-		}
-		systemFlags := []string{
-			"-I" + android.PathForModuleGen(ctx, "sysprop/system", "include").String(),
-		}
-
-		flags := internalFlags
-
+		dir := android.PathForModuleGen(ctx, "sysprop", "include").String()
 		if library.Properties.Sysprop.Platform != nil {
 			isProduct := ctx.ProductSpecific() && !ctx.useVndk()
 			isVendor := ctx.useVndk()
 			isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
 
-			useSystem := isProduct || (isOwnerPlatform == isVendor)
+			usePublic := isProduct || (isOwnerPlatform == isVendor)
 
-			if useSystem {
-				flags = systemFlags
+			if usePublic {
+				dir = android.PathForModuleGen(ctx, "sysprop/public", "include").String()
 			}
 		}
 
-		library.reexportFlags(flags)
-		library.reexportDeps(library.baseCompiler.pathDeps)
-		library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
+		library.reexportDirs(dir)
+		library.reexportDeps(library.baseCompiler.pathDeps...)
 	}
 
 	if library.buildStubs() {
-		library.reexportFlags([]string{"-D" + versioningMacroName(ctx.ModuleName()) + "=" + library.stubsVersion()})
+		library.reexportFlags("-D" + versioningMacroName(ctx.ModuleName()) + "=" + library.stubsVersion())
 	}
 
 	return out
@@ -899,8 +913,8 @@
 	return library.objects
 }
 
-func (library *libraryDecorator) reuseObjs() (Objects, []string, android.Paths) {
-	return library.reuseObjects, library.reuseExportedFlags, library.reuseExportedDeps
+func (library *libraryDecorator) reuseObjs() (Objects, exportedFlagsProducer) {
+	return library.reuseObjects, &library.flagExporter
 }
 
 func (library *libraryDecorator) toc() android.OptionalPath {
@@ -938,8 +952,8 @@
 			// 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 isBionic(ctx.baseModuleName()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
-				if ctx.Device() {
+			if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
+				if ctx.Device() && isBionic(ctx.baseModuleName()) {
 					library.installSymlinkToRuntimeApex(ctx, file)
 				}
 				library.baseInstaller.subDir = "bootstrap"
diff --git a/cc/linker.go b/cc/linker.go
index e063e44..dda2fcb 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -57,9 +57,6 @@
 	// This flag should only be necessary for compiling low-level libraries like libc.
 	Allow_undefined_symbols *bool `android:"arch_variant"`
 
-	// don't link in libgcc.a
-	No_libgcc *bool
-
 	// don't link in libclang_rt.builtins-*.a
 	No_libcrt *bool `android:"arch_variant"`
 
@@ -230,9 +227,6 @@
 			deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
 			deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
 			deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc_stripped")
-		} else if !Bool(linker.Properties.No_libgcc) {
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc")
 		}
 
 		systemSharedLibs := linker.Properties.System_shared_libs
@@ -301,10 +295,6 @@
 	if ctx.Darwin() {
 		return false
 	}
-	// http://b/110800681 - lld cannot link Android's Windows modules yet.
-	if ctx.Windows() {
-		return false
-	}
 	if linker.Properties.Use_clang_lld != nil {
 		return Bool(linker.Properties.Use_clang_lld)
 	}
@@ -358,7 +348,7 @@
 			// darwin defaults to treating undefined symbols as errors
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-undefined,dynamic_lookup")
 		}
-	} else if !ctx.Darwin() {
+	} else if !ctx.Darwin() && !ctx.Windows() {
 		flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
 	}
 
@@ -395,7 +385,7 @@
 
 	flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
 
-	if ctx.Host() {
+	if ctx.Host() && !ctx.Windows() {
 		rpath_prefix := `\$$ORIGIN/`
 		if ctx.Darwin() {
 			rpath_prefix = "@loader_path/"
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 56ef2b6..8290103 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -134,6 +134,7 @@
 	if !Bool(stub.Properties.Unversioned) {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
 		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 
 	if len(stub.Properties.Export_preprocessed_headers) > 0 {
@@ -144,17 +145,17 @@
 			timestampFiles = append(timestampFiles, stub.processHeaders(ctx, dir, genHeaderOutDir))
 		}
 
-		includePrefix := "-I"
 		if Bool(stub.Properties.Export_headers_as_system) {
-			includePrefix = "-isystem "
+			stub.reexportSystemDirs(genHeaderOutDir.String())
+		} else {
+			stub.reexportDirs(genHeaderOutDir.String())
 		}
 
-		stub.reexportFlags([]string{includePrefix + genHeaderOutDir.String()})
-		stub.reexportDeps(timestampFiles)
+		stub.reexportDeps(timestampFiles...)
 	}
 
 	if Bool(stub.Properties.Export_headers_as_system) {
-		stub.exportIncludes(ctx, "-isystem ")
+		stub.exportIncludesAsSystem(ctx)
 		stub.libraryDecorator.flagExporter.Properties.Export_include_dirs = []string{}
 	}
 
@@ -190,6 +191,14 @@
 	return module
 }
 
+// llndk_library creates a stub llndk shared library based on the provided
+// version file. Example:
+//
+//    llndk_library {
+//        name: "libfoo",
+//        symbol_file: "libfoo.map.txt",
+//        export_include_dirs: ["include_vndk"],
+//    }
 func LlndkLibraryFactory() android.Module {
 	module := NewLLndkStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
@@ -204,6 +213,8 @@
 	return name + llndkHeadersSuffix
 }
 
+// llndk_headers contains a set of c/c++ llndk headers files which are imported
+// by other soongs cc modules.
 func llndkHeadersFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.HeaderOnly()
diff --git a/cc/makevars.go b/cc/makevars.go
index aa6fdea..78a32c8 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -64,6 +64,8 @@
 }
 
 func makeVarsProvider(ctx android.MakeVarsContext) {
+	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
 	ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
 	ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
 	ctx.Strict("LLVM_PREBUILTS_BASE", "${config.ClangBase}")
@@ -75,7 +77,6 @@
 	ctx.Strict("LLVM_OBJCOPY", "${config.ClangBin}/llvm-objcopy")
 	ctx.Strict("LLVM_STRIP", "${config.ClangBin}/llvm-strip")
 	ctx.Strict("PATH_TO_CLANG_TIDY", "${config.ClangBin}/clang-tidy")
-	ctx.Strict("PATH_TO_CLANG_TIDY_SHELL", "${config.ClangTidyShellPath}")
 	ctx.StrictSorted("CLANG_CONFIG_UNKNOWN_CFLAGS", strings.Join(config.ClangUnknownCflags, " "))
 
 	ctx.Strict("RS_LLVM_PREBUILTS_VERSION", "${config.RSClangVersion}")
@@ -93,18 +94,31 @@
 
 	ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
 
-	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(vndkCoreLibraries, " "))
-	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(vndkSpLibraries, " "))
-	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
-	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
-	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(vndkUsingCoreVariantLibraries, " "))
+	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(*vndkCoreLibraries(ctx.Config()), " "))
+	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(*vndkSpLibraries(ctx.Config()), " "))
+
+	// Make uses LLNDK_LIBRARIES to determine which libraries to install.
+	// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+	// Therefore, by removing the library here, we cause it to only be installed if libc
+	// depends on it.
+	installedLlndkLibraries := []string{}
+	for _, lib := range *llndkLibraries(ctx.Config()) {
+		if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
+			continue
+		}
+		installedLlndkLibraries = append(installedLlndkLibraries, lib)
+	}
+	ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
+
+	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " "))
+	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " "))
 
 	// Filter vendor_public_library that are exported to make
 	exportedVendorPublicLibraries := []string{}
 	ctx.VisitAllModules(func(module android.Module) {
 		if ccModule, ok := module.(*Module); ok {
 			baseName := ccModule.BaseModuleName()
-			if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
+			if inList(baseName, *vendorPublicLibraries) && module.ExportedToMake() {
 				if !inList(baseName, exportedVendorPublicLibraries) {
 					exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName)
 				}
@@ -147,6 +161,8 @@
 
 	ctx.Strict("AIDL_CPP", "${aidlCmd}")
 
+	ctx.Strict("M4", "${m4Cmd}")
+
 	ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}")
 
 	ctx.Strict("SOONG_STRIP_PATH", "${stripPath}")
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5e45c1a..4065128 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -159,6 +159,16 @@
 	}
 }
 
+// ndk_headers installs the sets of ndk headers defined in the srcs property
+// to the sysroot base + "usr/include" + to directory + directory component.
+// ndk_headers requires the license file to be specified. Example:
+//
+//    Given:
+//    sysroot base = "ndk/sysroot"
+//    from = "include/foo"
+//    to = "bar"
+//    header = "include/foo/woodly/doodly.h"
+//    output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
 func ndkHeadersFactory() android.Module {
 	module := &headerModule{}
 	module.AddProperties(&module.properties)
@@ -278,6 +288,11 @@
 	return timestampFile
 }
 
+// versioned_ndk_headers preprocesses the headers with the bionic versioner:
+// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
+// Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
+// directory level specified in `from` property. This is only used to process
+// the bionic/libc/include directory.
 func versionedNdkHeadersFactory() android.Module {
 	module := &versionedHeaderModule{}
 
@@ -360,6 +375,8 @@
 	}
 }
 
+// preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
+// property by executing the command defined in the preprocessor property.
 func preprocessedNdkHeadersFactory() android.Module {
 	module := &preprocessedHeadersModule{}
 
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 7199467..969cb3f 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -38,9 +38,12 @@
 	ndkLibrarySuffix = ".ndk"
 
 	ndkPrebuiltSharedLibs = []string{
+		"aaudio",
+		"amidi",
 		"android",
 		"binder_ndk",
 		"c",
+		"camera2ndk",
 		"dl",
 		"EGL",
 		"GLESv1_CM",
@@ -49,6 +52,7 @@
 		"jnigraphics",
 		"log",
 		"mediandk",
+		"nativewindow",
 		"m",
 		"OpenMAXAL",
 		"OpenSLES",
@@ -117,7 +121,7 @@
 	}
 }
 
-func normalizeNdkApiLevel(ctx android.BaseContext, apiLevel string,
+func normalizeNdkApiLevel(ctx android.BaseModuleContext, apiLevel string,
 	arch android.Arch) (string, error) {
 
 	if apiLevel == "current" {
@@ -163,7 +167,7 @@
 	return strconv.Atoi(firstSupportedVersion)
 }
 
-func shouldUseVersionScript(ctx android.BaseContext, stub *stubDecorator) (bool, error) {
+func shouldUseVersionScript(ctx android.BaseModuleContext, stub *stubDecorator) (bool, error) {
 	// unversioned_until is normally empty, in which case we should use the version script.
 	if String(stub.properties.Unversioned_until) == "" {
 		return true, nil
@@ -333,6 +337,7 @@
 	if useVersionScript {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
 		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
@@ -377,8 +382,11 @@
 	return module
 }
 
+// ndk_library creates a stub library that exposes dummy implementation
+// of functions and variables for use at build time only.
 func ndkLibraryFactory() android.Module {
 	module := newStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	module.ModuleBase.EnableNativeBridgeSupportByDefault()
 	return module
 }
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 2a7e657..4356732 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -25,7 +25,7 @@
 func init() {
 	android.RegisterModuleType("ndk_prebuilt_object", ndkPrebuiltObjectFactory)
 	android.RegisterModuleType("ndk_prebuilt_static_stl", ndkPrebuiltStaticStlFactory)
-	android.RegisterModuleType("ndk_prebuilt_shared_stl", ndkPrebuiltSharedStlFactory)
+	android.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
 }
 
 // NDK prebuilt libraries.
@@ -64,8 +64,13 @@
 	return deps
 }
 
+// ndk_prebuilt_object exports a precompiled ndk object file for linking
+// operations. Soong's module name format is ndk_<NAME>.o.<sdk_version> where
+// the object is located under
+// ./prebuilts/ndk/current/platforms/android-<sdk_version>/arch-$(HOST_ARCH)/usr/lib/<NAME>.o.
 func ndkPrebuiltObjectFactory() android.Module {
 	module := newBaseModule(android.DeviceSupported, android.MultilibBoth)
+	module.ModuleBase.EnableNativeBridgeSupportByDefault()
 	module.linker = &ndkPrebuiltObjectLinker{
 		objectLinker: objectLinker{
 			baseLinker: NewBaseLinker(nil),
@@ -98,7 +103,11 @@
 	return deps
 }
 
-func ndkPrebuiltSharedStlFactory() android.Module {
+// ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
+// library (stl) library for linking operation. The soong's module name format
+// is ndk_<NAME>.so where the library is located under
+// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.so.
+func NdkPrebuiltSharedStlFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyShared()
 	module.compiler = nil
@@ -113,6 +122,10 @@
 	return module.Init()
 }
 
+// ndk_prebuilt_static_stl exports a precompiled ndk static standard template
+// library (stl) library for linking operation. The soong's module name format
+// is ndk_<NAME>.a where the library is located under
+// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.a.
 func ndkPrebuiltStaticStlFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyStatic()
@@ -122,6 +135,7 @@
 	}
 	module.installer = nil
 	module.Properties.HideFromMake = true
+	module.ModuleBase.EnableNativeBridgeSupportByDefault()
 	return module.Init()
 }
 
@@ -137,7 +151,7 @@
 		ctx.ModuleErrorf("NDK prebuilt libraries must have an ndk_lib prefixed name")
 	}
 
-	ndk.exportIncludes(ctx, "-isystem ")
+	ndk.exportIncludesAsSystem(ctx)
 
 	libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
 	libExt := flags.Toolchain.ShlibSuffix()
diff --git a/cc/pgo.go b/cc/pgo.go
index 7334ea2..4e915ff 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -27,10 +27,9 @@
 
 var (
 	// Add flags to ignore warnings that profiles are old or missing for
-	// some functions, and turn on the experimental new pass manager.
+	// some functions.
 	profileUseOtherFlags = []string{
 		"-Wno-backend-plugin",
-		"-fexperimental-new-pass-manager",
 	}
 
 	globalPgoProfileProjects = []string{
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 48e4667..dc6c43a 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -85,9 +85,11 @@
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 	// TODO(ccross): verify shared library dependencies
 	if len(p.properties.Srcs) > 0 {
-		p.libraryDecorator.exportIncludes(ctx, "-I")
-		p.libraryDecorator.reexportFlags(deps.ReexportedFlags)
-		p.libraryDecorator.reexportDeps(deps.ReexportedFlagsDeps)
+		p.libraryDecorator.exportIncludes(ctx)
+		p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+		p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+		p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+		p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
 
 		builderFlags := flagsToBuilderFlags(flags)
 
@@ -98,7 +100,7 @@
 			libName := ctx.baseModuleName() + flags.Toolchain.ShlibSuffix()
 			if p.needsStrip(ctx) {
 				stripped := android.PathForModuleOut(ctx, "stripped", libName)
-				p.strip(ctx, in, stripped, builderFlags)
+				p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
 				in = stripped
 			}
 
@@ -197,7 +199,7 @@
 
 		if p.needsStrip(ctx) {
 			stripped := android.PathForModuleOut(ctx, "stripped", fileName)
-			p.strip(ctx, in, stripped, builderFlags)
+			p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
 			in = stripped
 		}
 
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 7cc2651..98d78e8 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -70,7 +70,7 @@
 
 	config := android.TestArchConfig(buildDir, nil)
 
-	ctx := createTestContext(t, config, bp, fs, android.Android)
+	ctx := CreateTestContext(bp, fs, android.Android)
 
 	ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(prebuiltSharedLibraryFactory))
 	ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(prebuiltStaticLibraryFactory))
diff --git a/cc/proto_test.go b/cc/proto_test.go
index a7fcef9..4f0de78 100644
--- a/cc/proto_test.go
+++ b/cc/proto_test.go
@@ -15,7 +15,6 @@
 package cc
 
 import (
-	"runtime"
 	"strings"
 	"testing"
 
@@ -38,9 +37,6 @@
 	})
 
 	t.Run("plugin", func(t *testing.T) {
-		if runtime.GOOS != "linux" {
-			t.Skip("TODO(b/129763458): cc_binary_host tests fail on mac when trying to exec xcrun")
-		}
 		ctx := testCc(t, `
 		cc_binary_host {
 			name: "protoc-gen-foobar",
diff --git a/cc/rs.go b/cc/rs.go
index 5421b92..fbc6bfb 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -72,11 +72,12 @@
 	stampFile := android.PathForModuleGen(ctx, "rs", "rs.stamp")
 	depFiles := make(android.WritablePaths, 0, len(rsFiles))
 	genFiles := make(android.WritablePaths, 0, 2*len(rsFiles))
+	headers := make(android.Paths, 0, len(rsFiles))
 	for _, rsFile := range rsFiles {
 		depFiles = append(depFiles, rsGeneratedDepFile(ctx, rsFile))
-		genFiles = append(genFiles,
-			rsGeneratedCppFile(ctx, rsFile),
-			rsGeneratedHFile(ctx, rsFile))
+		headerFile := rsGeneratedHFile(ctx, rsFile)
+		genFiles = append(genFiles, rsGeneratedCppFile(ctx, rsFile), headerFile)
+		headers = append(headers, headerFile)
 	}
 
 	ctx.Build(pctx, android.BuildParams{
@@ -92,7 +93,7 @@
 		},
 	})
 
-	return android.Paths{stampFile}
+	return headers
 }
 
 func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags {
diff --git a/cc/sabi.go b/cc/sabi.go
index 4a86499..ae7b31d 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -28,8 +28,8 @@
 )
 
 type SAbiProperties struct {
-	CreateSAbiDumps        bool `blueprint:"mutated"`
-	ReexportedIncludeFlags []string
+	CreateSAbiDumps    bool     `blueprint:"mutated"`
+	ReexportedIncludes []string `blueprint:"mutated"`
 }
 
 type sabi struct {
@@ -78,7 +78,7 @@
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		((c.isVndk() && c.useVndk()) || inList(c.Name(), llndkLibraries) ||
+		((c.isVndk() && c.useVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m android.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b7a36a6..44bf9a3 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -40,7 +40,8 @@
 	hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=",
 		"-mllvm", "-hwasan-create-frame-descriptions=0",
 		"-mllvm", "-hwasan-allow-ifunc",
-		"-fsanitize-hwaddress-abi=platform"}
+		"-fsanitize-hwaddress-abi=platform",
+		"-fno-experimental-new-pass-manager"}
 
 	cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
 		"-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"}
@@ -78,6 +79,7 @@
 	intOverflow
 	cfi
 	scs
+	fuzzer
 )
 
 // Name of the sanitizer variation for this sanitizer type
@@ -95,6 +97,8 @@
 		return "cfi"
 	case scs:
 		return "scs"
+	case fuzzer:
+		return "fuzzer"
 	default:
 		panic(fmt.Errorf("unknown sanitizerType %d", t))
 	}
@@ -115,6 +119,8 @@
 		return "cfi"
 	case scs:
 		return "shadow-call-stack"
+	case fuzzer:
+		return "fuzzer"
 	default:
 		panic(fmt.Errorf("unknown sanitizerType %d", t))
 	}
@@ -134,7 +140,7 @@
 		Undefined        *bool    `android:"arch_variant"`
 		All_undefined    *bool    `android:"arch_variant"`
 		Misc_undefined   []string `android:"arch_variant"`
-		Coverage         *bool    `android:"arch_variant"`
+		Fuzzer           *bool    `android:"arch_variant"`
 		Safestack        *bool    `android:"arch_variant"`
 		Cfi              *bool    `android:"arch_variant"`
 		Integer_overflow *bool    `android:"arch_variant"`
@@ -224,22 +230,16 @@
 			s.Undefined = boolPtr(true)
 		}
 
-		if found, globalSanitizers = removeFromList("address", globalSanitizers); found {
-			if s.Address == nil {
-				s.Address = boolPtr(true)
-			} else if *s.Address == false {
-				// Coverage w/o address is an error. If globalSanitizers includes both, and the module
-				// disables address, then disable coverage as well.
-				_, globalSanitizers = removeFromList("coverage", globalSanitizers)
-			}
+		if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil {
+			s.Address = boolPtr(true)
 		}
 
 		if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil {
 			s.Thread = boolPtr(true)
 		}
 
-		if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found && s.Coverage == nil {
-			s.Coverage = boolPtr(true)
+		if found, globalSanitizers = removeFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
+			s.Fuzzer = boolPtr(true)
 		}
 
 		if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil {
@@ -347,7 +347,7 @@
 
 	if ctx.staticBinary() {
 		s.Address = nil
-		s.Coverage = nil
+		s.Fuzzer = nil
 		s.Thread = nil
 	}
 
@@ -363,7 +363,7 @@
 	}
 
 	if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
-		Bool(s.Coverage) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
+		Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
 		Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs)) {
 		sanitize.Properties.SanitizerEnabled = true
 	}
@@ -378,10 +378,10 @@
 		s.Thread = nil
 	}
 
-	if Bool(s.Coverage) {
-		if !Bool(s.Address) {
-			ctx.ModuleErrorf(`Use of "coverage" also requires "address"`)
-		}
+	// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
+	// mutually incompatible.
+	if Bool(s.Fuzzer) {
+		s.Cfi = nil
 	}
 }
 
@@ -462,8 +462,17 @@
 		flags.CFlags = append(flags.CFlags, hwasanCflags...)
 	}
 
-	if Bool(sanitize.Properties.Sanitize.Coverage) {
-		flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp")
+	if Bool(sanitize.Properties.Sanitize.Fuzzer) {
+		flags.CFlags = append(flags.CFlags, "-fsanitize=fuzzer-no-link")
+		flags.LdFlags = append(flags.LdFlags, "-fsanitize=fuzzer-no-link")
+
+		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
+		_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
+		flags.LdFlags = append(flags.LdFlags, "-fno-lto")
+
+		// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
+		_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
+		flags.CFlags = append(flags.CFlags, "-fno-experimental-new-pass-manager")
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Cfi) {
@@ -498,20 +507,26 @@
 		flags.CFlags = append(flags.CFlags, sanitizeArg)
 		flags.AsFlags = append(flags.AsFlags, sanitizeArg)
 		if ctx.Host() {
-			flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
-			flags.LdFlags = append(flags.LdFlags, sanitizeArg)
 			// Host sanitizers only link symbols in the final executable, so
 			// there will always be undefined symbols in intermediate libraries.
 			_, flags.LdFlags = removeFromList("-Wl,--no-undefined", flags.LdFlags)
+			flags.LdFlags = append(flags.LdFlags, sanitizeArg)
 		} else {
-			flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
-
 			if enableMinimalRuntime(sanitize) {
 				flags.CFlags = append(flags.CFlags, strings.Join(minimalRuntimeFlags, " "))
 				flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
 				flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
 			}
 		}
+
+		if Bool(sanitize.Properties.Sanitize.Fuzzer) {
+			// When fuzzing, we wish to crash with diagnostics on any bug.
+			flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
+		} else if ctx.Host() {
+			flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
+		} else {
+			flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
+		}
 		// http://b/119329758, Android core does not boot up with this sanitizer yet.
 		if toDisableImplicitIntegerChange(flags.CFlags) {
 			flags.CFlags = append(flags.CFlags, "-fno-sanitize=implicit-integer-sign-change")
@@ -574,6 +589,8 @@
 		return sanitize.Properties.Sanitize.Cfi
 	case scs:
 		return sanitize.Properties.Sanitize.Scs
+	case fuzzer:
+		return sanitize.Properties.Sanitize.Fuzzer
 	default:
 		panic(fmt.Errorf("unknown sanitizerType %d", t))
 	}
@@ -584,22 +601,21 @@
 		!sanitize.isSanitizerEnabled(hwasan) &&
 		!sanitize.isSanitizerEnabled(tsan) &&
 		!sanitize.isSanitizerEnabled(cfi) &&
-		!sanitize.isSanitizerEnabled(scs)
+		!sanitize.isSanitizerEnabled(scs) &&
+		!sanitize.isSanitizerEnabled(fuzzer)
 }
 
 func (sanitize *sanitize) isVariantOnProductionDevice() bool {
 	return !sanitize.isSanitizerEnabled(asan) &&
 		!sanitize.isSanitizerEnabled(hwasan) &&
-		!sanitize.isSanitizerEnabled(tsan)
+		!sanitize.isSanitizerEnabled(tsan) &&
+		!sanitize.isSanitizerEnabled(fuzzer)
 }
 
 func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
 	switch t {
 	case asan:
 		sanitize.Properties.Sanitize.Address = boolPtr(b)
-		if !b {
-			sanitize.Properties.Sanitize.Coverage = nil
-		}
 	case hwasan:
 		sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
 	case tsan:
@@ -610,6 +626,8 @@
 		sanitize.Properties.Sanitize.Cfi = boolPtr(b)
 	case scs:
 		sanitize.Properties.Sanitize.Scs = boolPtr(b)
+	case fuzzer:
+		sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
 	default:
 		panic(fmt.Errorf("unknown sanitizerType %d", t))
 	}
@@ -688,8 +706,8 @@
 			if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
 				return false
 			}
-			if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil {
 
+			if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil {
 				if enableMinimalRuntime(d.sanitize) {
 					// If a static dependency is built with the minimal runtime,
 					// make sure we include the ubsan minimal runtime.
@@ -700,8 +718,17 @@
 					// make sure we include the ubsan runtime.
 					c.sanitize.Properties.UbsanRuntimeDep = true
 				}
+
+				if c.sanitize.Properties.MinimalRuntimeDep &&
+					c.sanitize.Properties.UbsanRuntimeDep {
+					// both flags that this mutator might set are true, so don't bother recursing
+					return false
+				}
+
+				return true
+			} else {
+				return false
 			}
-			return true
 		})
 	}
 }
@@ -794,6 +821,10 @@
 			sanitizers = append(sanitizers, "shadow-call-stack")
 		}
 
+		if Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
+			sanitizers = append(sanitizers, "fuzzer-no-link")
+		}
+
 		// Save the list of sanitizers. These will be used again when generating
 		// the build rules (for Cflags, etc.)
 		c.sanitize.Properties.Sanitizers = sanitizers
@@ -823,7 +854,7 @@
 		}
 
 		if mctx.Device() && runtimeLibrary != "" {
-			if inList(runtimeLibrary, llndkLibraries) && !c.static() && c.useVndk() {
+			if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.useVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
 
@@ -932,6 +963,19 @@
 							modules[1].(*Module).Properties.HideFromMake = true
 						}
 					}
+				} else if t == fuzzer {
+					// TODO(b/131771163): CFI and fuzzer support are mutually incompatible
+					// as CFI pulls in LTO.
+					if mctx.Device() {
+						modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
+					}
+					if isSanitizerEnabled {
+						modules[0].(*Module).Properties.PreventInstall = true
+						modules[0].(*Module).Properties.HideFromMake = true
+					} else {
+						modules[1].(*Module).Properties.PreventInstall = true
+						modules[1].(*Module).Properties.HideFromMake = true
+					}
 				} else if t == hwasan {
 					if mctx.Device() {
 						// CFI and HWASAN are currently mutually exclusive so disable
@@ -997,6 +1041,7 @@
 func enableMinimalRuntime(sanitize *sanitize) bool {
 	if !Bool(sanitize.Properties.Sanitize.Address) &&
 		!Bool(sanitize.Properties.Sanitize.Hwaddress) &&
+		!Bool(sanitize.Properties.Sanitize.Fuzzer) &&
 		(Bool(sanitize.Properties.Sanitize.Integer_overflow) ||
 			len(sanitize.Properties.Sanitize.Misc_undefined) > 0) &&
 		!(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
diff --git a/cc/strip.go b/cc/strip.go
index 7122585..f3e3374 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -22,11 +22,12 @@
 
 type StripProperties struct {
 	Strip struct {
-		None              *bool    `android:"arch_variant"`
-		All               *bool    `android:"arch_variant"`
-		Keep_symbols      *bool    `android:"arch_variant"`
-		Keep_symbols_list []string `android:"arch_variant"`
-		Use_gnu_strip     *bool    `android:"arch_variant"`
+		None                         *bool    `android:"arch_variant"`
+		All                          *bool    `android:"arch_variant"`
+		Keep_symbols                 *bool    `android:"arch_variant"`
+		Keep_symbols_list            []string `android:"arch_variant"`
+		Keep_symbols_and_debug_frame *bool    `android:"arch_variant"`
+		Use_gnu_strip                *bool    `android:"arch_variant"`
 	} `android:"arch_variant"`
 }
 
@@ -40,12 +41,14 @@
 }
 
 func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
-	flags builderFlags) {
+	flags builderFlags, isStaticLib bool) {
 	if ctx.Darwin() {
 		TransformDarwinStrip(ctx, in, out)
 	} else {
 		if Bool(stripper.StripProperties.Strip.Keep_symbols) {
 			flags.stripKeepSymbols = true
+		} else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) {
+			flags.stripKeepSymbolsAndDebugFrame = true
 		} else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
 			flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
 		} else if !Bool(stripper.StripProperties.Strip.All) {
@@ -54,9 +57,19 @@
 		if Bool(stripper.StripProperties.Strip.Use_gnu_strip) {
 			flags.stripUseGnuStrip = true
 		}
-		if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo {
+		if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib {
 			flags.stripAddGnuDebuglink = true
 		}
 		TransformStrip(ctx, in, out, flags)
 	}
 }
+
+func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path,
+	out android.ModuleOutPath, flags builderFlags) {
+	stripper.strip(ctx, in, out, flags, false)
+}
+
+func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
+	flags builderFlags) {
+	stripper.strip(ctx, in, out, flags, true)
+}
diff --git a/cc/test.go b/cc/test.go
index dae2a37..c735fd9 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -64,6 +64,10 @@
 
 	// Test options.
 	Test_options TestOptions
+
+	// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
+	// with root permission.
+	Require_root *bool
 }
 
 func init() {
@@ -273,18 +277,19 @@
 
 func (test *testBinary) install(ctx ModuleContext, file android.Path) {
 	test.data = android.PathsForModuleSrc(ctx, test.Properties.Data)
-	optionsMap := map[string]string{}
-	if Bool(test.testDecorator.Properties.Isolated) {
-		optionsMap["not-shardable"] = "true"
+	var configs []tradefed.Config
+	if Bool(test.Properties.Require_root) {
+		configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RootTargetPreparer"})
 	}
-
+	if Bool(test.testDecorator.Properties.Isolated) {
+		configs = append(configs, tradefed.Option{"not-shardable", "true"})
+	}
 	if test.Properties.Test_options.Run_test_as != nil {
-		optionsMap["run-test-as"] = String(test.Properties.Test_options.Run_test_as)
+		configs = append(configs, tradefed.Option{"run-test-as", String(test.Properties.Test_options.Run_test_as)})
 	}
 
 	test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
-		test.Properties.Test_config_template,
-		test.Properties.Test_suites, optionsMap)
+		test.Properties.Test_config_template, test.Properties.Test_suites, configs)
 
 	test.binaryDecorator.baseInstaller.dir = "nativetest"
 	test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
@@ -371,6 +376,10 @@
 	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
 	// should be installed with the module.
 	Test_config_template *string `android:"path,arch_variant"`
+
+	// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
+	// with root permission.
+	Require_root *bool
 }
 
 type benchmarkDecorator struct {
@@ -403,8 +412,12 @@
 
 func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) {
 	benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data)
+	var configs []tradefed.Config
+	if Bool(benchmark.Properties.Require_root) {
+		configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RootTargetPreparer"})
+	}
 	benchmark.testConfig = tradefed.AutoGenNativeBenchmarkTestConfig(ctx, benchmark.Properties.Test_config,
-		benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites)
+		benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs)
 
 	benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
diff --git a/cc/testing.go b/cc/testing.go
index 8d76c2f..df7cb78 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -78,7 +78,7 @@
 
 		cc_library {
 			name: "libc",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
@@ -89,7 +89,7 @@
 		}
 		cc_library {
 			name: "libm",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
@@ -100,7 +100,7 @@
 		}
 		cc_library {
 			name: "libdl",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
@@ -111,7 +111,7 @@
 		}
 		cc_library {
 			name: "libc++_static",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			stl: "none",
@@ -120,7 +120,7 @@
 		}
 		cc_library {
 			name: "libc++",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			stl: "none",
@@ -133,7 +133,7 @@
 		}
 		cc_library {
 			name: "libunwind_llvm",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			stl: "none",
@@ -148,6 +148,12 @@
 		}
 
 		cc_object {
+			name: "crtbegin_dynamic",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
+		cc_object {
 			name: "crtbegin_static",
 			recovery_available: true,
 			vendor_available: true,
@@ -183,3 +189,56 @@
 	}
 	return ret
 }
+
+func CreateTestContext(bp string, fs map[string][]byte,
+	os android.OsType) *android.TestContext {
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
+	ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
+	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
+	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
+	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
+	ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(TestFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
+	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
+	ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
+	ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
+	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
+	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
+	ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(vndkPrebuiltSharedFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("image", ImageMutator).Parallel()
+		ctx.BottomUp("link", LinkageMutator).Parallel()
+		ctx.BottomUp("vndk", VndkMutator).Parallel()
+		ctx.BottomUp("version", VersionMutator).Parallel()
+		ctx.BottomUp("begin", BeginMutator).Parallel()
+	})
+	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+	})
+	ctx.RegisterSingletonType("vndk-snapshot", android.SingletonFactoryAdaptor(VndkSnapshotSingleton))
+
+	// add some modules that are required by the compiler and/or linker
+	bp = bp + GatherRequiredDepsForTest(os)
+
+	mockFS := map[string][]byte{
+		"Android.bp":  []byte(bp),
+		"foo.c":       nil,
+		"bar.c":       nil,
+		"a.proto":     nil,
+		"b.aidl":      nil,
+		"my_include":  nil,
+		"foo.map.txt": nil,
+		"liba.so":     nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 8ab8bc9..fef4508 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -50,6 +50,9 @@
 	return append(props, &library.Properties, &library.stripper.StripProperties)
 }
 
+// toolchain_library is used internally by the build tool to link the specified
+// static library in src property to the device libraries that are shipped with
+// gcc.
 func ToolchainLibraryFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyStatic()
@@ -83,7 +86,7 @@
 		fileName := ctx.ModuleName() + staticLibraryExtension
 		outputFile := android.PathForModuleOut(ctx, fileName)
 		buildFlags := flagsToBuilderFlags(flags)
-		library.stripper.strip(ctx, srcPath, outputFile, buildFlags)
+		library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags)
 		return outputFile
 	}
 
diff --git a/cc/util.go b/cc/util.go
index 5dcbaef..2e1bb25 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -29,10 +29,6 @@
 	return android.JoinWithPrefix(dirs.Strings(), "-I")
 }
 
-func includeFilesToFlags(files android.Paths) string {
-	return android.JoinWithPrefix(files.Strings(), "-include ")
-}
-
 func ldDirsToFlags(dirs []string) string {
 	return android.JoinWithPrefix(dirs, "-L")
 }
@@ -67,7 +63,6 @@
 		toolingCppFlags: strings.Join(in.ToolingCppFlags, " "),
 		conlyFlags:      strings.Join(in.ConlyFlags, " "),
 		cppFlags:        strings.Join(in.CppFlags, " "),
-		yaccFlags:       strings.Join(in.YaccFlags, " "),
 		aidlFlags:       strings.Join(in.aidlFlags, " "),
 		rsFlags:         strings.Join(in.rsFlags, " "),
 		ldFlags:         strings.Join(in.LdFlags, " "),
@@ -87,6 +82,8 @@
 		proto:            in.proto,
 		protoC:           in.protoC,
 		protoOptionsFile: in.protoOptionsFile,
+
+		yacc: in.Yacc,
 	}
 }
 
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index da41cbc..f0de267 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -24,10 +24,16 @@
 var (
 	vendorPublicLibrarySuffix = ".vendorpublic"
 
-	vendorPublicLibraries     = []string{}
+	vendorPublicLibrariesKey  = android.NewOnceKey("vendorPublicLibraries")
 	vendorPublicLibrariesLock sync.Mutex
 )
 
+func vendorPublicLibraries(config android.Config) *[]string {
+	return config.Once(vendorPublicLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
 // Creates a stub shared library for a vendor public library. Vendor public libraries
 // are vendor libraries (owned by them and installed to /vendor partition) that are
 // exposed to Android apps via JNI. The libraries are made public by being listed in
@@ -82,12 +88,13 @@
 
 	vendorPublicLibrariesLock.Lock()
 	defer vendorPublicLibrariesLock.Unlock()
-	for _, lib := range vendorPublicLibraries {
+	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+	for _, lib := range *vendorPublicLibraries {
 		if lib == name {
 			return
 		}
 	}
-	vendorPublicLibraries = append(vendorPublicLibraries, name)
+	*vendorPublicLibraries = append(*vendorPublicLibraries, name)
 }
 
 func (stub *vendorPublicLibraryStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -118,10 +125,20 @@
 	if !Bool(stub.Properties.Unversioned) {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
 		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
+// vendor_public_library creates a stub shared library for a vendor public
+// library. This stub library is a build-time only artifact that provides
+// symbols that are exposed from a vendor public library. Example:
+//
+//    vendor_public_library {
+//        name: "libfoo",
+//        symbol_file: "libfoo.map.txt",
+//        export_public_headers: ["libfoo_headers"],
+//    }
 func vendorPublicLibraryFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyShared()
diff --git a/cc/vndk.go b/cc/vndk.go
index 44a83e7..f9f3764 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -16,6 +16,8 @@
 
 import (
 	"errors"
+	"fmt"
+	"path/filepath"
 	"sort"
 	"strings"
 	"sync"
@@ -47,6 +49,10 @@
 
 		// Extending another module
 		Extends *string
+
+		// for vndk_prebuilt_shared, this is set by "version" property.
+		// Otherwise, this is set as PLATFORM_VNDK_VERSION.
+		Version string `blueprint:"mutated"`
 	}
 }
 
@@ -192,64 +198,364 @@
 }
 
 var (
-	vndkCoreLibraries             []string
-	vndkSpLibraries               []string
-	llndkLibraries                []string
-	vndkPrivateLibraries          []string
-	vndkUsingCoreVariantLibraries []string
-	vndkLibrariesLock             sync.Mutex
+	vndkCoreLibrariesKey             = android.NewOnceKey("vndkCoreLibrarires")
+	vndkSpLibrariesKey               = android.NewOnceKey("vndkSpLibrarires")
+	llndkLibrariesKey                = android.NewOnceKey("llndkLibrarires")
+	vndkPrivateLibrariesKey          = android.NewOnceKey("vndkPrivateLibrarires")
+	vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
+	modulePathsKey                   = android.NewOnceKey("modulePaths")
+	vndkSnapshotOutputsKey           = android.NewOnceKey("vndkSnapshotOutputs")
+	vndkLibrariesLock                sync.Mutex
 )
 
+type vndkSnapshotOutputPaths struct {
+	configs         android.Paths
+	notices         android.Paths
+	vndkCoreLibs    android.Paths
+	vndkCoreLibs2nd android.Paths
+	vndkSpLibs      android.Paths
+	vndkSpLibs2nd   android.Paths
+}
+
+func vndkCoreLibraries(config android.Config) *[]string {
+	return config.Once(vndkCoreLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func vndkSpLibraries(config android.Config) *[]string {
+	return config.Once(vndkSpLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func llndkLibraries(config android.Config) *[]string {
+	return config.Once(llndkLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func vndkPrivateLibraries(config android.Config) *[]string {
+	return config.Once(vndkPrivateLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func vndkUsingCoreVariantLibraries(config android.Config) *[]string {
+	return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func modulePaths(config android.Config) map[string]string {
+	return config.Once(modulePathsKey, func() interface{} {
+		return make(map[string]string)
+	}).(map[string]string)
+}
+
+func vndkSnapshotOutputs(config android.Config) *vndkSnapshotOutputPaths {
+	return config.Once(vndkSnapshotOutputsKey, func() interface{} {
+		return &vndkSnapshotOutputPaths{}
+	}).(*vndkSnapshotOutputPaths)
+}
+
+func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
+	lib := m.linker.(*llndkStubDecorator)
+	name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
+
+	vndkLibrariesLock.Lock()
+	defer vndkLibrariesLock.Unlock()
+
+	llndkLibraries := llndkLibraries(mctx.Config())
+	if !inList(name, *llndkLibraries) {
+		*llndkLibraries = append(*llndkLibraries, name)
+		sort.Strings(*llndkLibraries)
+	}
+	if !Bool(lib.Properties.Vendor_available) {
+		vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+		if !inList(name, *vndkPrivateLibraries) {
+			*vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+			sort.Strings(*vndkPrivateLibraries)
+		}
+	}
+}
+
+func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
+	name := strings.TrimPrefix(m.Name(), "prebuilt_")
+
+	vndkLibrariesLock.Lock()
+	defer vndkLibrariesLock.Unlock()
+
+	modulePaths := modulePaths(mctx.Config())
+	if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
+		vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
+		if !inList(name, *vndkUsingCoreVariantLibraries) {
+			*vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
+			sort.Strings(*vndkUsingCoreVariantLibraries)
+		}
+	}
+	if m.vndkdep.isVndkSp() {
+		vndkSpLibraries := vndkSpLibraries(mctx.Config())
+		if !inList(name, *vndkSpLibraries) {
+			*vndkSpLibraries = append(*vndkSpLibraries, name)
+			sort.Strings(*vndkSpLibraries)
+			modulePaths[name] = mctx.ModuleDir()
+		}
+	} else {
+		vndkCoreLibraries := vndkCoreLibraries(mctx.Config())
+		if !inList(name, *vndkCoreLibraries) {
+			*vndkCoreLibraries = append(*vndkCoreLibraries, name)
+			sort.Strings(*vndkCoreLibraries)
+			modulePaths[name] = mctx.ModuleDir()
+		}
+	}
+	if !Bool(m.VendorProperties.Vendor_available) {
+		vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+		if !inList(name, *vndkPrivateLibraries) {
+			*vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+			sort.Strings(*vndkPrivateLibraries)
+		}
+	}
+}
+
 // gather list of vndk-core, vndk-sp, and ll-ndk libs
 func VndkMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && m.Enabled() {
-		if lib, ok := m.linker.(*llndkStubDecorator); ok {
-			vndkLibrariesLock.Lock()
-			defer vndkLibrariesLock.Unlock()
-			name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
-			if !inList(name, llndkLibraries) {
-				llndkLibraries = append(llndkLibraries, name)
-				sort.Strings(llndkLibraries)
-			}
-			if !Bool(lib.Properties.Vendor_available) {
-				if !inList(name, vndkPrivateLibraries) {
-					vndkPrivateLibraries = append(vndkPrivateLibraries, name)
-					sort.Strings(vndkPrivateLibraries)
-				}
-			}
+	m, ok := mctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	if !m.Enabled() {
+		return
+	}
+
+	if m.isVndk() {
+		if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+			m.vndkdep.Properties.Vndk.Version = lib.version()
 		} else {
-			lib, is_lib := m.linker.(*libraryDecorator)
-			prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
-			if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
-				name := strings.TrimPrefix(m.Name(), "prebuilt_")
-				if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
-					vndkLibrariesLock.Lock()
-					defer vndkLibrariesLock.Unlock()
-					if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
-						if !inList(name, vndkUsingCoreVariantLibraries) {
-							vndkUsingCoreVariantLibraries = append(vndkUsingCoreVariantLibraries, name)
-							sort.Strings(vndkUsingCoreVariantLibraries)
-						}
-					}
-					if m.vndkdep.isVndkSp() {
-						if !inList(name, vndkSpLibraries) {
-							vndkSpLibraries = append(vndkSpLibraries, name)
-							sort.Strings(vndkSpLibraries)
-						}
-					} else {
-						if !inList(name, vndkCoreLibraries) {
-							vndkCoreLibraries = append(vndkCoreLibraries, name)
-							sort.Strings(vndkCoreLibraries)
-						}
-					}
-					if !Bool(m.VendorProperties.Vendor_available) {
-						if !inList(name, vndkPrivateLibraries) {
-							vndkPrivateLibraries = append(vndkPrivateLibraries, name)
-							sort.Strings(vndkPrivateLibraries)
-						}
-					}
-				}
-			}
+			m.vndkdep.Properties.Vndk.Version = mctx.DeviceConfig().PlatformVndkVersion()
 		}
 	}
+
+	if _, ok := m.linker.(*llndkStubDecorator); ok {
+		processLlndkLibrary(mctx, m)
+		return
+	}
+
+	lib, is_lib := m.linker.(*libraryDecorator)
+	prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+
+	if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
+		if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
+			processVndkLibrary(mctx, m)
+			return
+		}
+	}
+}
+
+func init() {
+	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
+		outputs := vndkSnapshotOutputs(ctx.Config())
+
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_CONFIGS", strings.Join(outputs.configs.Strings(), " "))
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_NOTICES", strings.Join(outputs.notices.Strings(), " "))
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS", strings.Join(outputs.vndkCoreLibs.Strings(), " "))
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS", strings.Join(outputs.vndkSpLibs.Strings(), " "))
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS_2ND", strings.Join(outputs.vndkCoreLibs2nd.Strings(), " "))
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS_2ND", strings.Join(outputs.vndkSpLibs2nd.Strings(), " "))
+	})
+}
+
+func VndkSnapshotSingleton() android.Singleton {
+	return &vndkSnapshotSingleton{}
+}
+
+type vndkSnapshotSingleton struct{}
+
+func installVndkSnapshotLib(ctx android.SingletonContext, name string, module *Module, dir string) android.Path {
+	if !module.outputFile.Valid() {
+		panic(fmt.Errorf("module %s has no outputFile\n", name))
+	}
+
+	out := android.PathForOutput(ctx, dir, name+".so")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cp,
+		Input:       module.outputFile.Path(),
+		Output:      out,
+		Description: "vndk snapshot " + dir + "/" + name + ".so",
+		Args: map[string]string{
+			"cpFlags": "-f -L",
+		},
+	})
+
+	return out
+}
+
+func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
+	if ctx.DeviceConfig().VndkVersion() != "current" {
+		return
+	}
+
+	if ctx.DeviceConfig().PlatformVndkVersion() == "" {
+		return
+	}
+
+	if ctx.DeviceConfig().BoardVndkRuntimeDisable() {
+		return
+	}
+
+	outputs := vndkSnapshotOutputs(ctx.Config())
+
+	snapshotDir := "vndk-snapshot"
+
+	var vndkLibPath, vndkLib2ndPath string
+
+	snapshotVariantPath := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+	if ctx.DeviceConfig().BinderBitness() == "32" {
+		vndkLibPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
+			"arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
+		vndkLib2ndPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
+			"arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+	} else {
+		vndkLibPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
+			"arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
+		vndkLib2ndPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
+			"arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+	}
+
+	vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
+	vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
+	vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
+	vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
+	noticePath := filepath.Join(snapshotVariantPath, "NOTICE_FILES")
+	noticeBuilt := make(map[string]bool)
+
+	tryBuildNotice := func(m *Module) {
+		name := ctx.ModuleName(m)
+
+		if _, ok := noticeBuilt[name]; ok {
+			return
+		}
+
+		noticeBuilt[name] = true
+
+		if m.NoticeFile().Valid() {
+			out := android.PathForOutput(ctx, noticePath, name+".so.txt")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        android.Cp,
+				Input:       m.NoticeFile().Path(),
+				Output:      out,
+				Description: "vndk snapshot notice " + name + ".so.txt",
+				Args: map[string]string{
+					"cpFlags": "-f -L",
+				},
+			})
+			outputs.notices = append(outputs.notices, out)
+		}
+	}
+
+	vndkCoreLibraries := vndkCoreLibraries(ctx.Config())
+	vndkSpLibraries := vndkSpLibraries(ctx.Config())
+	vndkPrivateLibraries := vndkPrivateLibraries(ctx.Config())
+
+	ctx.VisitAllModules(func(module android.Module) {
+		m, ok := module.(*Module)
+		if !ok || !m.Enabled() || !m.useVndk() || !m.installable() {
+			return
+		}
+
+		if m.Target().NativeBridge == android.NativeBridgeEnabled {
+			return
+		}
+
+		lib, is_lib := m.linker.(*libraryDecorator)
+		prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+
+		if !(is_lib && lib.shared()) && !(is_prebuilt_lib && prebuilt_lib.shared()) {
+			return
+		}
+
+		is_2nd := m.Target().Arch.ArchType != ctx.Config().DevicePrimaryArchType()
+
+		name := ctx.ModuleName(module)
+
+		if inList(name, *vndkCoreLibraries) {
+			if is_2nd {
+				out := installVndkSnapshotLib(ctx, name, m, vndkCoreLib2ndPath)
+				outputs.vndkCoreLibs2nd = append(outputs.vndkCoreLibs2nd, out)
+			} else {
+				out := installVndkSnapshotLib(ctx, name, m, vndkCoreLibPath)
+				outputs.vndkCoreLibs = append(outputs.vndkCoreLibs, out)
+			}
+			tryBuildNotice(m)
+		} else if inList(name, *vndkSpLibraries) {
+			if is_2nd {
+				out := installVndkSnapshotLib(ctx, name, m, vndkSpLib2ndPath)
+				outputs.vndkSpLibs2nd = append(outputs.vndkSpLibs2nd, out)
+			} else {
+				out := installVndkSnapshotLib(ctx, name, m, vndkSpLibPath)
+				outputs.vndkSpLibs = append(outputs.vndkSpLibs, out)
+			}
+			tryBuildNotice(m)
+		}
+	})
+
+	configsPath := filepath.Join(snapshotVariantPath, "configs")
+	vndkCoreTxt := android.PathForOutput(ctx, configsPath, "vndkcore.libraries.txt")
+	vndkPrivateTxt := android.PathForOutput(ctx, configsPath, "vndkprivate.libraries.txt")
+	modulePathTxt := android.PathForOutput(ctx, configsPath, "module_paths.txt")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      vndkCoreTxt,
+		Description: "vndk snapshot vndkcore.libraries.txt",
+		Args: map[string]string{
+			"content": android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"),
+		},
+	})
+	outputs.configs = append(outputs.configs, vndkCoreTxt)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      vndkPrivateTxt,
+		Description: "vndk snapshot vndkprivate.libraries.txt",
+		Args: map[string]string{
+			"content": android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"),
+		},
+	})
+	outputs.configs = append(outputs.configs, vndkPrivateTxt)
+
+	var modulePathTxtBuilder strings.Builder
+
+	modulePaths := modulePaths(ctx.Config())
+	var libs []string
+	for lib := range modulePaths {
+		libs = append(libs, lib)
+	}
+	sort.Strings(libs)
+
+	first := true
+	for _, lib := range libs {
+		if first {
+			first = false
+		} else {
+			modulePathTxtBuilder.WriteString("\\n")
+		}
+		modulePathTxtBuilder.WriteString(lib)
+		modulePathTxtBuilder.WriteString(".so ")
+		modulePathTxtBuilder.WriteString(modulePaths[lib])
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      modulePathTxt,
+		Description: "vndk snapshot module_paths.txt",
+		Args: map[string]string{
+			"content": modulePathTxtBuilder.String(),
+		},
+	})
+	outputs.configs = append(outputs.configs, modulePathTxt)
 }
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 74f7f27..0ecf566 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -172,6 +172,26 @@
 	return module
 }
 
+// vndk_prebuilt_shared installs Vendor Native Development kit (VNDK) snapshot
+// shared libraries for system build. Example:
+//
+//    vndk_prebuilt_shared {
+//        name: "libfoo",
+//        version: "27.1.0",
+//        vendor_available: true,
+//        vndk: {
+//            enabled: true,
+//        },
+//        export_include_dirs: ["include/external/libfoo/vndk_include"],
+//        arch: {
+//            arm64: {
+//                srcs: ["arm/lib64/libfoo.so"],
+//            },
+//            arm: {
+//                srcs: ["arm/lib/libfoo.so"],
+//            },
+//        },
+//    }
 func vndkPrebuiltSharedFactory() android.Module {
 	module := vndkPrebuiltSharedLibrary()
 	return module.Init()
diff --git a/cmd/diff_target_files/known_nondeterminism.whitelist b/cmd/diff_target_files/known_nondeterminism.whitelist
index 6d71403..a8ade49 100644
--- a/cmd/diff_target_files/known_nondeterminism.whitelist
+++ b/cmd/diff_target_files/known_nondeterminism.whitelist
@@ -3,8 +3,6 @@
 [
   {
     "Paths": [
-       // b/120039850
-      "system/framework/oat/*/services.art"
     ]
   }
 ]
diff --git a/cmd/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/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 330c5dd..1171a65 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -156,10 +156,12 @@
 }
 
 func main() {
-	writer := terminal.NewWriter(terminal.StdioImpl{})
-	defer writer.Finish()
+	stdio := terminal.StdioImpl{}
 
-	log := logger.New(writer)
+	output := terminal.NewStatusOutput(stdio.Stdout(), "",
+		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
+
+	log := logger.New(output)
 	defer log.Cleanup()
 
 	flag.Parse()
@@ -172,8 +174,7 @@
 
 	stat := &status.Status{}
 	defer stat.Finish()
-	stat.AddOutput(terminal.NewStatusOutput(writer, "",
-		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
+	stat.AddOutput(output)
 
 	var failures failureCount
 	stat.AddOutput(&failures)
@@ -188,7 +189,7 @@
 		Context: ctx,
 		Logger:  log,
 		Tracer:  trace,
-		Writer:  writer,
+		Writer:  output,
 		Status:  stat,
 	}}
 
@@ -341,7 +342,7 @@
 	} else if failures > 1 {
 		log.Fatalf("%d failures", failures)
 	} else {
-		writer.Print("Success")
+		fmt.Fprintln(output, "Success")
 	}
 }
 
@@ -386,7 +387,7 @@
 		Context: mpctx.Context,
 		Logger:  log,
 		Tracer:  mpctx.Tracer,
-		Writer:  terminal.NewWriter(terminal.NewCustomStdio(nil, f, f)),
+		Writer:  f,
 		Thread:  mpctx.Tracer.NewThread(product),
 		Status:  &status.Status{},
 	}}
@@ -466,3 +467,8 @@
 }
 
 func (f *failureCount) Flush() {}
+
+func (f *failureCount) Write(p []byte) (int, error) {
+	// discard writes
+	return len(p), nil
+}
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index a399b28..c858c40 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -89,7 +89,9 @@
 	return nil
 }
 
-var extraDeps = make(ExtraDeps)
+var extraStaticLibs = make(ExtraDeps)
+
+var extraLibs = make(ExtraDeps)
 
 type Exclude map[string]bool
 
@@ -124,6 +126,8 @@
 
 var sdkVersion string
 var useVersion string
+var staticDeps bool
+var jetifier bool
 
 func InList(s string, list []string) bool {
 	for _, l := range list {
@@ -229,8 +233,12 @@
 	return p.BpDeps("aar", []string{"compile", "runtime"})
 }
 
-func (p Pom) BpExtraDeps() []string {
-	return extraDeps[p.BpName()]
+func (p Pom) BpExtraStaticLibs() []string {
+	return extraStaticLibs[p.BpName()]
+}
+
+func (p Pom) BpExtraLibs() []string {
+	return extraLibs[p.BpName()]
 }
 
 // BpDeps obtains dependencies filtered by type and scope. The results of this
@@ -251,6 +259,10 @@
 	return sdkVersion
 }
 
+func (p Pom) Jetifier() bool {
+	return jetifier
+}
+
 func (p *Pom) FixDeps(modules map[string]*Pom) {
 	for _, d := range p.Dependencies {
 		if d.Type == "" {
@@ -322,19 +334,64 @@
 
 var bpTemplate = template.Must(template.New("bp").Parse(`
 {{.ImportModuleType}} {
-    name: "{{.BpName}}-nodeps",
+    name: "{{.BpName}}",
     {{.ImportProperty}}: ["{{.ArtifactFile}}"],
     sdk_version: "{{.SdkVersion}}",
+    {{- if .Jetifier}}
+    jetifier: true,
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     static_libs: [
+        {{- range .BpJarDeps}}
+        "{{.}}",
+        {{- end}}
         {{- range .BpAarDeps}}
         "{{.}}",
         {{- end}}
-        {{- range .BpExtraDeps}}
+        {{- range .BpExtraStaticLibs}}
         "{{.}}",
         {{- end}}
     ],
+    {{- if .BpExtraLibs}}
+    libs: [
+        {{- range .BpExtraLibs}}
+        "{{.}}",
+        {{- end}}
+    ],
+    {{- end}}
+    {{- end}}
+}
+`))
+
+var bpDepsTemplate = template.Must(template.New("bp").Parse(`
+{{.ImportModuleType}} {
+    name: "{{.BpName}}-nodeps",
+    {{.ImportProperty}}: ["{{.ArtifactFile}}"],
+    sdk_version: "{{.SdkVersion}}",
+    {{- if .Jetifier}}
+    jetifier: true,
+    {{- end}}
+    {{- if .IsAar}}
+    min_sdk_version: "{{.MinSdkVersion}}",
+    static_libs: [
+        {{- range .BpJarDeps}}
+        "{{.}}",
+        {{- end}}
+        {{- range .BpAarDeps}}
+        "{{.}}",
+        {{- end}}
+        {{- range .BpExtraStaticLibs}}
+        "{{.}}",
+        {{- end}}
+    ],
+    {{- if .BpExtraLibs}}
+    libs: [
+        {{- range .BpExtraLibs}}
+        "{{.}}",
+        {{- end}}
+    ],
+    {{- end}}
     {{- end}}
 }
 
@@ -349,16 +406,23 @@
     {{- end}}
     static_libs: [
         "{{.BpName}}-nodeps",
-         {{- range .BpJarDeps}}
+        {{- range .BpJarDeps}}
         "{{.}}",
         {{- end}}
         {{- range .BpAarDeps}}
         "{{.}}",
         {{- end}}
-        {{- range .BpExtraDeps}}
+        {{- range .BpExtraStaticLibs}}
         "{{.}}",
         {{- end}}
     ],
+    {{- if .BpExtraLibs}}
+    libs: [
+        {{- range .BpExtraLibs}}
+        "{{.}}",
+        {{- end}}
+    ],
+    {{- end}}
     java_version: "1.7",
 }
 `))
@@ -458,7 +522,7 @@
 The tool will extract the necessary information from *.pom files to create an Android.bp whose
 aar libraries can be linked against when using AAPT2.
 
-Usage: %s [--rewrite <regex>=<replace>] [-exclude <module>] [--extra-deps <module>=<module>[,<module>]] [<dir>] [-regen <file>]
+Usage: %s [--rewrite <regex>=<replace>] [-exclude <module>] [--extra-static-libs <module>=<module>[,<module>]] [--extra-libs <module>=<module>[,<module>]] [<dir>] [-regen <file>]
 
   -rewrite <regex>=<replace>
      rewrite can be used to specify mappings between Maven projects and Android.bp modules. The -rewrite
@@ -468,15 +532,21 @@
      the Android.bp module name using <replace>. If no matches are found, <artifactId> is used.
   -exclude <module>
      Don't put the specified module in the Android.bp file.
-  -extra-deps <module>=<module>[,<module>]
-     Some Android.bp modules have transitive dependencies that must be specified when they are
-     depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
+  -extra-static-libs <module>=<module>[,<module>]
+     Some Android.bp modules have transitive static dependencies that must be specified when they
+     are depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
+     This may be specified multiple times to declare these dependencies.
+  -extra-libs <module>=<module>[,<module>]
+     Some Android.bp modules have transitive runtime dependencies that must be specified when they
+     are depended upon (like androidx.test.rules requires android.test.base).
      This may be specified multiple times to declare these dependencies.
   -sdk-version <version>
-     Sets LOCAL_SDK_VERSION := <version> for all modules.
+     Sets sdk_version: "<version>" for all modules.
   -use-version <version>
      If the maven directory contains multiple versions of artifacts and their pom files,
      -use-version can be used to only write Android.bp files for a specific version of those artifacts.
+  -jetifier
+     Sets jetifier: true for all modules.
   <dir>
      The directory to search for *.pom files under.
      The contents are written to stdout, to be put in the current directory (often as Android.bp)
@@ -490,12 +560,14 @@
 	var regen string
 
 	flag.Var(&excludes, "exclude", "Exclude module")
-	flag.Var(&extraDeps, "extra-deps", "Extra dependencies needed when depending on a module")
+	flag.Var(&extraStaticLibs, "extra-static-libs", "Extra static dependencies needed when depending on a module")
+	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.StringVar(&sdkVersion, "sdk-version", "", "What to write to LOCAL_SDK_VERSION")
+	flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
 	flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
-	flag.Bool("static-deps", false, "Ignored")
+	flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
+	flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
 	flag.StringVar(&regen, "regen", "", "Rewrite specified file")
 	flag.Parse()
 
@@ -609,7 +681,11 @@
 
 	for _, pom := range poms {
 		var err error
-		err = bpTemplate.Execute(buf, pom)
+		if staticDeps {
+			err = bpDepsTemplate.Execute(buf, pom)
+		} else {
+			err = bpTemplate.Execute(buf, pom)
+		}
 		if err != nil {
 			fmt.Fprintln(os.Stderr, "Error writing", pom.PomFile, pom.BpName(), err)
 			os.Exit(1)
diff --git a/cmd/pom2mk/pom2mk.go b/cmd/pom2mk/pom2mk.go
index 94e5619..b347155 100644
--- a/cmd/pom2mk/pom2mk.go
+++ b/cmd/pom2mk/pom2mk.go
@@ -104,6 +104,7 @@
 var sdkVersion string
 var useVersion string
 var staticDeps bool
+var jetifier bool
 
 func InList(s string, list []string) bool {
 	for _, l := range list {
@@ -195,6 +196,10 @@
 	return sdkVersion
 }
 
+func (p Pom) Jetifier() bool {
+	return jetifier
+}
+
 func (p *Pom) FixDeps(modules map[string]*Pom) {
 	for _, d := range p.Dependencies {
 		if d.Type == "" {
@@ -229,6 +234,7 @@
   {{.}}{{end}}
 LOCAL_STATIC_ANDROID_LIBRARIES :={{range .MkAarDeps}} \
   {{.}}{{end}}
+LOCAL_JETIFIER_ENABLED := {{if .Jetifier}}true{{end}}
 include $(BUILD_PREBUILT)
 `))
 
@@ -367,6 +373,8 @@
      -use-version can be used to only write makefiles for a specific version of those artifacts.
   -static-deps
      Whether to statically include direct dependencies.
+  -jetifier
+     Enable jetifier in order to use androidx
   <dir>
      The directory to search for *.pom files under.
      The makefile is written to stdout, to be put in the current directory (often as Android.mk)
@@ -383,6 +391,7 @@
 	flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to LOCAL_SDK_VERSION")
 	flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
 	flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
+	flag.BoolVar(&jetifier, "jetifier", false, "Enable jetifier in order to use androidx")
 	flag.StringVar(&regen, "regen", "", "Rewrite specified file")
 	flag.Parse()
 
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 4167edb..4ac9295 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -56,7 +56,7 @@
 	}
 
 	fmt.Fprintf(os.Stderr,
-		"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> --overwrite [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
+		"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
 			"\n"+
 			"Deletes <outputRoot>,"+
 			"runs <commandToRun>,"+
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 41c7d46..30381e0 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -18,7 +18,12 @@
 	"flag"
 	"fmt"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
 
 	"github.com/google/blueprint/bootstrap"
 
@@ -50,6 +55,42 @@
 }
 
 func main() {
+	if android.SoongDelveListen != "" {
+		if android.SoongDelvePath == "" {
+			fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
+			os.Exit(1)
+		}
+		pid := strconv.Itoa(os.Getpid())
+		cmd := []string{android.SoongDelvePath,
+			"attach", pid,
+			"--headless",
+			"-l", android.SoongDelveListen,
+			"--api-version=2",
+			"--accept-multiclient",
+			"--log",
+		}
+
+		fmt.Println("Starting", strings.Join(cmd, " "))
+		dlv := exec.Command(cmd[0], cmd[1:]...)
+		dlv.Stdout = os.Stdout
+		dlv.Stderr = os.Stderr
+		dlv.Stdin = nil
+
+		// Put dlv into its own process group so we can kill it and the child process it starts.
+		dlv.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+
+		err := dlv.Start()
+		if err != nil {
+			// Print the error starting dlv and continue.
+			fmt.Println(err)
+		} else {
+			// Kill the process group for dlv when soong_build exits.
+			defer syscall.Kill(-dlv.Process.Pid, syscall.SIGKILL)
+			// Wait to give dlv a chance to connect and pause the process.
+			time.Sleep(time.Second)
+		}
+	}
+
 	flag.Parse()
 
 	// The top-level Blueprints file is passed as the first argument.
@@ -72,7 +113,17 @@
 
 	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
 
-	bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
+	extraNinjaDeps := []string{configuration.ConfigFileName, configuration.ProductVariablesFileName}
+
+	// Read the SOONG_DELVE again through configuration so that there is a dependency on the environment variable
+	// and soong_build will rerun when it is set for the first time.
+	if listen := configuration.Getenv("SOONG_DELVE"); listen != "" {
+		// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
+		// enabled even if it completed successfully.
+		extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
+	}
+
+	bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
 
 	if docFile != "" {
 		if err := writeDocs(ctx, docFile); err != nil {
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 9f40e33..f13dafa 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -32,42 +32,93 @@
 	"android/soong/ui/tracer"
 )
 
+// A command represents an operation to be executed in the soong build
+// system.
+type command struct {
+	// the flag name (must have double dashes)
+	flag string
+
+	// description for the flag (to display when running help)
+	description string
+
+	// Creates the build configuration based on the args and build context.
+	config func(ctx build.Context, args ...string) build.Config
+
+	// Returns what type of IO redirection this Command requires.
+	stdio func() terminal.StdioInterface
+
+	// run the command
+	run func(ctx build.Context, config build.Config, args []string, logsDir string)
+}
+
+const makeModeFlagName = "--make-mode"
+
+// list of supported commands (flags) supported by soong ui
+var commands []command = []command{
+	{
+		flag:        makeModeFlagName,
+		description: "build the modules by the target name (i.e. soong_docs)",
+		config: func(ctx build.Context, args ...string) build.Config {
+			return build.NewConfig(ctx, args...)
+		},
+		stdio: stdio,
+		run:   make,
+	}, {
+		flag:        "--dumpvar-mode",
+		description: "print the value of the legacy make variable VAR to stdout",
+		config:      dumpVarConfig,
+		stdio:       customStdio,
+		run:         dumpVar,
+	}, {
+		flag:        "--dumpvars-mode",
+		description: "dump the values of one or more legacy make variables, in shell syntax",
+		config:      dumpVarConfig,
+		stdio:       customStdio,
+		run:         dumpVars,
+	}, {
+		flag:        "--build-mode",
+		description: "build modules based on the specified build action",
+		config:      buildActionConfig,
+		stdio:       stdio,
+		run:         make,
+	},
+}
+
+// indexList returns the index of first found s. -1 is return if s is not
+// found.
 func indexList(s string, list []string) int {
 	for i, l := range list {
 		if l == s {
 			return i
 		}
 	}
-
 	return -1
 }
 
+// inList returns true if one or more of s is in the list.
 func inList(s string, list []string) bool {
 	return indexList(s, list) != -1
 }
 
+// Main execution of soong_ui. The command format is as follows:
+//
+//    soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+//
+// Command is the type of soong_ui execution. Only one type of
+// execution is specified. The args are specific to the command.
 func main() {
-	var stdio terminal.StdioInterface
-	stdio = terminal.StdioImpl{}
-
-	// dumpvar uses stdout, everything else should be in stderr
-	if os.Args[1] == "--dumpvar-mode" || os.Args[1] == "--dumpvars-mode" {
-		stdio = terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+	c, args := getCommand(os.Args)
+	if c == nil {
+		fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
+		os.Exit(1)
 	}
 
-	writer := terminal.NewWriter(stdio)
-	defer writer.Finish()
+	output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"),
+		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
 
-	log := logger.New(writer)
+	log := logger.New(output)
 	defer log.Cleanup()
 
-	if len(os.Args) < 2 || !(inList("--make-mode", os.Args) ||
-		os.Args[1] == "--dumpvars-mode" ||
-		os.Args[1] == "--dumpvar-mode") {
-
-		log.Fatalln("The `soong` native UI is not yet available.")
-	}
-
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 
@@ -78,8 +129,7 @@
 
 	stat := &status.Status{}
 	defer stat.Finish()
-	stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS"),
-		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
+	stat.AddOutput(output)
 	stat.AddOutput(trace.StatusTracer())
 
 	build.SetupSignals(log, cancel, func() {
@@ -93,15 +143,11 @@
 		Logger:  log,
 		Metrics: met,
 		Tracer:  trace,
-		Writer:  writer,
+		Writer:  output,
 		Status:  stat,
 	}}
-	var config build.Config
-	if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" {
-		config = build.NewConfig(buildCtx)
-	} else {
-		config = build.NewConfig(buildCtx, os.Args[1:]...)
-	}
+
+	config := c.config(buildCtx, args...)
 
 	build.SetupOutDir(buildCtx, config)
 
@@ -115,8 +161,10 @@
 	trace.SetOutput(filepath.Join(logsDir, "build.trace"))
 	stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log")))
 	stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log")))
+	stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error")))
+	stat.AddOutput(status.NewCriticalPath(log))
 
-	defer met.Dump(filepath.Join(logsDir, "build_metrics"))
+	defer met.Dump(filepath.Join(logsDir, "soong_metrics"))
 
 	if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
 		if !strings.HasSuffix(start, "N") {
@@ -141,28 +189,7 @@
 	defer f.Shutdown()
 	build.FindSources(buildCtx, config, f)
 
-	if os.Args[1] == "--dumpvar-mode" {
-		dumpVar(buildCtx, config, os.Args[2:])
-	} else if os.Args[1] == "--dumpvars-mode" {
-		dumpVars(buildCtx, config, os.Args[2:])
-	} else {
-		if config.IsVerbose() {
-			writer.Print("! The argument `showcommands` is no longer supported.")
-			writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
-			writer.Print("!")
-			writer.Print(fmt.Sprintf("!   gzip -cd %s/verbose.log.gz | less -R", logsDir))
-			writer.Print("!")
-			writer.Print("! Older versions are saved in verbose.log.#.gz files")
-			writer.Print("")
-			time.Sleep(5 * time.Second)
-		}
-
-		toBuild := build.BuildAll
-		if config.Checkbuild() {
-			toBuild |= build.RunBuildTests
-		}
-		build.Build(buildCtx, config, toBuild)
-	}
+	c.run(buildCtx, config, args, logsDir)
 }
 
 func fixBadDanglingLink(ctx build.Context, name string) {
@@ -179,16 +206,16 @@
 	}
 }
 
-func dumpVar(ctx build.Context, config build.Config, args []string) {
+func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
 	flags.Usage = func() {
-		fmt.Fprintf(os.Stderr, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
-		fmt.Fprintln(os.Stderr, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
-		fmt.Fprintln(os.Stderr, "")
+		fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
+		fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
+		fmt.Fprintln(ctx.Writer, "")
 
-		fmt.Fprintln(os.Stderr, "'report_config' is a special case that prints the human-readable config banner")
-		fmt.Fprintln(os.Stderr, "from the beginning of the build.")
-		fmt.Fprintln(os.Stderr, "")
+		fmt.Fprintln(ctx.Writer, "'report_config' is a special case that prints the human-readable config banner")
+		fmt.Fprintln(ctx.Writer, "from the beginning of the build.")
+		fmt.Fprintln(ctx.Writer, "")
 		flags.PrintDefaults()
 	}
 	abs := flags.Bool("abs", false, "Print the absolute path of the value")
@@ -229,18 +256,18 @@
 	}
 }
 
-func dumpVars(ctx build.Context, config build.Config, args []string) {
+func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
 	flags.Usage = func() {
-		fmt.Fprintf(os.Stderr, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
-		fmt.Fprintln(os.Stderr, "In dumpvars mode, dump the values of one or more legacy make variables, in")
-		fmt.Fprintln(os.Stderr, "shell syntax. The resulting output may be sourced directly into a shell to")
-		fmt.Fprintln(os.Stderr, "set corresponding shell variables.")
-		fmt.Fprintln(os.Stderr, "")
+		fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
+		fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
+		fmt.Fprintln(ctx.Writer, "shell syntax. The resulting output may be sourced directly into a shell to")
+		fmt.Fprintln(ctx.Writer, "set corresponding shell variables.")
+		fmt.Fprintln(ctx.Writer, "")
 
-		fmt.Fprintln(os.Stderr, "'report_config' is a special case that dumps a variable containing the")
-		fmt.Fprintln(os.Stderr, "human-readable config banner from the beginning of the build.")
-		fmt.Fprintln(os.Stderr, "")
+		fmt.Fprintln(ctx.Writer, "'report_config' is a special case that dumps a variable containing the")
+		fmt.Fprintln(ctx.Writer, "human-readable config banner from the beginning of the build.")
+		fmt.Fprintln(ctx.Writer, "")
 		flags.PrintDefaults()
 	}
 
@@ -296,3 +323,145 @@
 		fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
 	}
 }
+
+func stdio() terminal.StdioInterface {
+	return terminal.StdioImpl{}
+}
+
+func customStdio() terminal.StdioInterface {
+	return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+}
+
+// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
+func dumpVarConfig(ctx build.Context, args ...string) build.Config {
+	return build.NewConfig(ctx)
+}
+
+func buildActionConfig(ctx build.Context, args ...string) build.Config {
+	flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
+	flags.Usage = func() {
+		fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
+		fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
+		fmt.Fprintln(ctx.Writer, "action. The --dir flag is required to determine what is needed to")
+		fmt.Fprintln(ctx.Writer, "build in the source tree based on the build action. See below for")
+		fmt.Fprintln(ctx.Writer, "the list of acceptable build action flags.")
+		fmt.Fprintln(ctx.Writer, "")
+		flags.PrintDefaults()
+	}
+
+	buildActionFlags := []struct {
+		name              string
+		description       string
+		action            build.BuildAction
+		buildDependencies bool
+		set               bool
+	}{{
+		name:              "all-modules",
+		description:       "Build action: build from the top of the source tree.",
+		action:            build.BUILD_MODULES,
+		buildDependencies: true,
+	}, {
+		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,
+	}, {
+		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,
+	}, {
+		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-dirs",
+		description:       "Build action: builds all of the modules in the supplied directories and their dependencies.",
+		action:            build.BUILD_MODULES_IN_DIRECTORIES,
+		buildDependencies: true,
+	}}
+	for i, flag := range buildActionFlags {
+		flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
+	}
+	dir := flags.String("dir", "", "Directory of the executed build command.")
+
+	// Only interested in the first two args which defines the build action and the directory.
+	// The remaining arguments are passed down to the config.
+	const numBuildActionFlags = 2
+	if len(args) < numBuildActionFlags {
+		flags.Usage()
+		ctx.Fatalln("Improper build action arguments.")
+	}
+	flags.Parse(args[0:numBuildActionFlags])
+
+	// The next block of code is to validate that exactly one build action is set and the dir flag
+	// 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 {
+		ctx.Fatalln("Build action not defined.")
+	}
+	if *dir == "" {
+		ctx.Fatalln("-dir not specified.")
+	}
+
+	// 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...)
+}
+
+func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
+	if config.IsVerbose() {
+		writer := ctx.Writer
+		fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
+		fmt.Fprintln(writer, "! Instead, the verbose log is always written to a compressed file in the output dir:")
+		fmt.Fprintln(writer, "!")
+		fmt.Fprintf(writer, "!   gzip -cd %s/verbose.log.gz | less -R\n", logsDir)
+		fmt.Fprintln(writer, "!")
+		fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
+		fmt.Fprintln(writer, "")
+		time.Sleep(5 * time.Second)
+	}
+
+	toBuild := build.BuildAll
+	if config.Checkbuild() {
+		toBuild |= build.RunBuildTests
+	}
+	build.Build(ctx, config, toBuild)
+}
+
+// getCommand finds the appropriate command based on args[1] flag. args[0]
+// is the soong_ui filename.
+func getCommand(args []string) (*command, []string) {
+	if len(args) < 2 {
+		return nil, args
+	}
+
+	for _, c := range commands {
+		if c.flag == args[1] {
+			return &c, args[2:]
+		}
+
+		// special case for --make-mode: if soong_ui was called from
+		// build/make/core/main.mk, the makeparallel with --ninja
+		// option specified puts the -j<num> before --make-mode.
+		// TODO: Remove this hack once it has been fixed.
+		if c.flag == makeModeFlagName {
+			if inList(makeModeFlagName, args) {
+				return &c, args[1:]
+			}
+		}
+	}
+
+	// command not found
+	return nil, args
+}
diff --git a/cmd/zipsync/zipsync.go b/cmd/zipsync/zipsync.go
index ea755f5..a6023d3 100644
--- a/cmd/zipsync/zipsync.go
+++ b/cmd/zipsync/zipsync.go
@@ -30,6 +30,7 @@
 	outputDir  = flag.String("d", "", "output dir")
 	outputFile = flag.String("l", "", "output list file")
 	filter     = flag.String("f", "", "optional filter pattern")
+	zipPrefix  = flag.String("zip-prefix", "", "optional prefix within the zip file to extract, stripping the prefix")
 )
 
 func must(err error) {
@@ -77,6 +78,10 @@
 	var files []string
 	seen := make(map[string]string)
 
+	if *zipPrefix != "" {
+		*zipPrefix = filepath.Clean(*zipPrefix) + "/"
+	}
+
 	for _, input := range inputs {
 		reader, err := zip.OpenReader(input)
 		if err != nil {
@@ -85,23 +90,30 @@
 		defer reader.Close()
 
 		for _, f := range reader.File {
+			name := f.Name
+			if *zipPrefix != "" {
+				if !strings.HasPrefix(name, *zipPrefix) {
+					continue
+				}
+				name = strings.TrimPrefix(name, *zipPrefix)
+			}
 			if *filter != "" {
-				if match, err := filepath.Match(*filter, filepath.Base(f.Name)); err != nil {
+				if match, err := filepath.Match(*filter, filepath.Base(name)); err != nil {
 					log.Fatal(err)
 				} else if !match {
 					continue
 				}
 			}
-			if filepath.IsAbs(f.Name) {
-				log.Fatalf("%q in %q is an absolute path", f.Name, input)
+			if filepath.IsAbs(name) {
+				log.Fatalf("%q in %q is an absolute path", name, input)
 			}
 
-			if prev, exists := seen[f.Name]; exists {
-				log.Fatalf("%q found in both %q and %q", f.Name, prev, input)
+			if prev, exists := seen[name]; exists {
+				log.Fatalf("%q found in both %q and %q", name, prev, input)
 			}
-			seen[f.Name] = input
+			seen[name] = input
 
-			filename := filepath.Join(*outputDir, f.Name)
+			filename := filepath.Join(*outputDir, name)
 			if f.FileInfo().IsDir() {
 				must(os.MkdirAll(filename, f.FileInfo().Mode()))
 			} else {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3b77042..3e32958 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -65,8 +65,6 @@
 	AlwaysOtherDebugInfo        bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
 	NeverOtherDebugInfo         bool // never generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
 
-	MissingUsesLibraries []string // libraries that may be listed in OptionalUsesLibraries but will not be installed by the product
-
 	IsEng        bool // build is a eng variant
 	SanitizeLite bool // build is the second phase of a SANITIZE_LITE build
 
@@ -81,13 +79,11 @@
 	InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture
 
 	// Only used for boot image
-	DirtyImageObjects      android.OptionalPath // path to a dirty-image-objects file
-	PreloadedClasses       android.OptionalPath // path to a preloaded-classes file
-	BootImageProfiles      android.Paths        // path to a boot-image-profile.txt file
-	UseProfileForBootImage bool                 // whether a profile should be used to compile the boot image
-	BootFlags              string               // extra flags to pass to dex2oat for the boot image
-	Dex2oatImageXmx        string               // max heap size for dex2oat for the boot image
-	Dex2oatImageXms        string               // initial heap size for dex2oat for the boot image
+	DirtyImageObjects android.OptionalPath // path to a dirty-image-objects file
+	BootImageProfiles android.Paths        // path to a boot-image-profile.txt file
+	BootFlags         string               // extra flags to pass to dex2oat for the boot image
+	Dex2oatImageXmx   string               // max heap size for dex2oat for the boot image
+	Dex2oatImageXms   string               // initial heap size for dex2oat for the boot image
 
 	Tools Tools // paths to tools possibly used by the generated commands
 }
@@ -95,14 +91,14 @@
 // Tools contains paths to tools possibly used by the generated commands.  If you add a new tool here you MUST add it
 // to the order-only dependency list in DEXPREOPT_GEN_DEPS.
 type Tools struct {
-	Profman  android.Path
-	Dex2oat  android.Path
-	Aapt     android.Path
-	SoongZip android.Path
-	Zip2zip  android.Path
+	Profman       android.Path
+	Dex2oat       android.Path
+	Aapt          android.Path
+	SoongZip      android.Path
+	Zip2zip       android.Path
+	ManifestCheck android.Path
 
-	VerifyUsesLibraries android.Path
-	ConstructContext    android.Path
+	ConstructContext android.Path
 }
 
 type ModuleConfig struct {
@@ -110,6 +106,7 @@
 	DexLocation     string // dex location on device
 	BuildPath       android.OutputPath
 	DexPath         android.Path
+	ManifestPath    android.Path
 	UncompressedDex bool
 	HasApkLibraries bool
 	PreoptFlags     []string
@@ -117,13 +114,14 @@
 	ProfileClassListing  android.OptionalPath
 	ProfileIsTextListing bool
 
-	EnforceUsesLibraries  bool
-	OptionalUsesLibraries []string
-	UsesLibraries         []string
-	LibraryPaths          map[string]android.Path
+	EnforceUsesLibraries         bool
+	PresentOptionalUsesLibraries []string
+	UsesLibraries                []string
+	LibraryPaths                 map[string]android.Path
 
-	Archs           []android.ArchType
-	DexPreoptImages []android.Path
+	Archs               []android.ArchType
+	DexPreoptImages     []android.Path
+	DexPreoptImagesDeps []android.Paths
 
 	PreoptBootClassPathDexFiles     android.Paths // file paths of boot class path files
 	PreoptBootClassPathDexLocations []string      // virtual locations of boot class path files
@@ -176,37 +174,35 @@
 
 // LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct.  It is used directly in Soong
 // and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make.
-func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, error) {
+func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byte, error) {
 	type GlobalJSONConfig struct {
 		GlobalConfig
 
 		// Copies of entries in GlobalConfig that are not constructable without extra parameters.  They will be
 		// used to construct the real value manually below.
 		DirtyImageObjects string
-		PreloadedClasses  string
 		BootImageProfiles []string
 
 		Tools struct {
-			Profman  string
-			Dex2oat  string
-			Aapt     string
-			SoongZip string
-			Zip2zip  string
+			Profman       string
+			Dex2oat       string
+			Aapt          string
+			SoongZip      string
+			Zip2zip       string
+			ManifestCheck string
 
-			VerifyUsesLibraries string
-			ConstructContext    string
+			ConstructContext string
 		}
 	}
 
 	config := GlobalJSONConfig{}
-	err := loadConfig(ctx, path, &config)
+	data, err := loadConfig(ctx, path, &config)
 	if err != nil {
-		return config.GlobalConfig, err
+		return config.GlobalConfig, nil, err
 	}
 
 	// Construct paths that require a PathContext.
 	config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects))
-	config.GlobalConfig.PreloadedClasses = android.OptionalPathForPath(constructPath(ctx, config.PreloadedClasses))
 	config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles)
 
 	config.GlobalConfig.Tools.Profman = constructPath(ctx, config.Tools.Profman)
@@ -214,10 +210,10 @@
 	config.GlobalConfig.Tools.Aapt = constructPath(ctx, config.Tools.Aapt)
 	config.GlobalConfig.Tools.SoongZip = constructPath(ctx, config.Tools.SoongZip)
 	config.GlobalConfig.Tools.Zip2zip = constructPath(ctx, config.Tools.Zip2zip)
-	config.GlobalConfig.Tools.VerifyUsesLibraries = constructPath(ctx, config.Tools.VerifyUsesLibraries)
+	config.GlobalConfig.Tools.ManifestCheck = constructPath(ctx, config.Tools.ManifestCheck)
 	config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext)
 
-	return config.GlobalConfig, nil
+	return config.GlobalConfig, data, nil
 }
 
 // LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct.  It is not used in Soong, which
@@ -231,6 +227,7 @@
 		// used to construct the real value manually below.
 		BuildPath                   string
 		DexPath                     string
+		ManifestPath                string
 		ProfileClassListing         string
 		LibraryPaths                map[string]string
 		DexPreoptImages             []string
@@ -241,7 +238,7 @@
 
 	config := ModuleJSONConfig{}
 
-	err := loadConfig(ctx, path, &config)
+	_, err := loadConfig(ctx, path, &config)
 	if err != nil {
 		return config.ModuleConfig, err
 	}
@@ -249,6 +246,7 @@
 	// Construct paths that require a PathContext.
 	config.ModuleConfig.BuildPath = constructPath(ctx, config.BuildPath).(android.OutputPath)
 	config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath)
+	config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath)
 	config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
 	config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths)
 	config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
@@ -256,27 +254,30 @@
 	config.ModuleConfig.StripInputPath = constructPath(ctx, config.StripInputPath)
 	config.ModuleConfig.StripOutputPath = constructWritablePath(ctx, config.StripOutputPath)
 
+	// This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON.
+	config.ModuleConfig.DexPreoptImagesDeps = make([]android.Paths, len(config.ModuleConfig.DexPreoptImages))
+
 	return config.ModuleConfig, nil
 }
 
-func loadConfig(ctx android.PathContext, path string, config interface{}) error {
+func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) {
 	r, err := ctx.Fs().Open(path)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	defer r.Close()
 
 	data, err := ioutil.ReadAll(r)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	err = json.Unmarshal(data, config)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	return nil
+	return data, nil
 }
 
 func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
@@ -307,7 +308,6 @@
 		NeverSystemServerDebugInfo:         false,
 		AlwaysOtherDebugInfo:               false,
 		NeverOtherDebugInfo:                false,
-		MissingUsesLibraries:               nil,
 		IsEng:                              false,
 		SanitizeLite:                       false,
 		DefaultAppImages:                   false,
@@ -317,20 +317,18 @@
 		CpuVariant:                         nil,
 		InstructionSetFeatures:             nil,
 		DirtyImageObjects:                  android.OptionalPath{},
-		PreloadedClasses:                   android.OptionalPath{},
 		BootImageProfiles:                  nil,
-		UseProfileForBootImage:             false,
 		BootFlags:                          "",
 		Dex2oatImageXmx:                    "",
 		Dex2oatImageXms:                    "",
 		Tools: Tools{
-			Profman:             android.PathForTesting("profman"),
-			Dex2oat:             android.PathForTesting("dex2oat"),
-			Aapt:                android.PathForTesting("aapt"),
-			SoongZip:            android.PathForTesting("soong_zip"),
-			Zip2zip:             android.PathForTesting("zip2zip"),
-			VerifyUsesLibraries: android.PathForTesting("verify_uses_libraries.sh"),
-			ConstructContext:    android.PathForTesting("construct_context.sh"),
+			Profman:          android.PathForTesting("profman"),
+			Dex2oat:          android.PathForTesting("dex2oat"),
+			Aapt:             android.PathForTesting("aapt"),
+			SoongZip:         android.PathForTesting("soong_zip"),
+			Zip2zip:          android.PathForTesting("zip2zip"),
+			ManifestCheck:    android.PathForTesting("manifest_check"),
+			ConstructContext: android.PathForTesting("construct_context.sh"),
 		},
 	}
 }
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 5b658d9..e02e60f 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -125,7 +125,8 @@
 
 			for i, arch := range module.Archs {
 				image := module.DexPreoptImages[i]
-				dexpreoptCommand(ctx, global, module, rule, arch, profile, image, appImage, generateDM)
+				imageDeps := module.DexPreoptImagesDeps[i]
+				dexpreoptCommand(ctx, global, module, rule, arch, profile, image, imageDeps, appImage, generateDM)
 			}
 		}
 	}
@@ -190,7 +191,7 @@
 }
 
 func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
-	arch android.ArchType, profile, bootImage android.Path, appImage, generateDM bool) {
+	arch android.ArchType, profile, bootImage android.Path, bootImageDeps android.Paths, appImage, generateDM bool) {
 
 	// HACK: make soname in Soong-generated .odex files match Make.
 	base := filepath.Base(module.DexLocation)
@@ -226,15 +227,6 @@
 		bootImageLocation = PathToLocation(bootImage, arch)
 	}
 
-	// Lists of used and optional libraries from the build config to be verified against the manifest in the APK
-	var verifyUsesLibs []string
-	var verifyOptionalUsesLibs []string
-
-	// Lists of used and optional libraries from the build config, with optional libraries that are known to not
-	// be present in the current product removed.
-	var filteredUsesLibs []string
-	var filteredOptionalUsesLibs []string
-
 	// The class loader context using paths in the build
 	var classLoaderContextHost android.Paths
 
@@ -252,14 +244,10 @@
 	var classLoaderContextHostString string
 
 	if module.EnforceUsesLibraries {
-		verifyUsesLibs = copyOf(module.UsesLibraries)
-		verifyOptionalUsesLibs = copyOf(module.OptionalUsesLibraries)
-
-		filteredOptionalUsesLibs = filterOut(global.MissingUsesLibraries, module.OptionalUsesLibraries)
-		filteredUsesLibs = append(copyOf(module.UsesLibraries), filteredOptionalUsesLibs...)
+		usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
 
 		// Create class loader context for dex2oat from uses libraries and filtered optional libraries
-		for _, l := range filteredUsesLibs {
+		for _, l := range usesLibs {
 
 			classLoaderContextHost = append(classLoaderContextHost,
 				pathForLibrary(module, l))
@@ -270,11 +258,13 @@
 		const httpLegacy = "org.apache.http.legacy"
 		const httpLegacyImpl = "org.apache.http.legacy.impl"
 
-		// Fix up org.apache.http.legacy.impl since it should be org.apache.http.legacy in the manifest.
-		replace(verifyUsesLibs, httpLegacyImpl, httpLegacy)
-		replace(verifyOptionalUsesLibs, httpLegacyImpl, httpLegacy)
+		// org.apache.http.legacy contains classes that were in the default classpath until API 28.  If the
+		// targetSdkVersion in the manifest or APK is < 28, and the module does not explicitly depend on
+		// org.apache.http.legacy, then implicitly add the classes to the classpath for dexpreopt.  One the
+		// device the classes will be in a file called org.apache.http.legacy.impl.jar.
+		module.LibraryPaths[httpLegacyImpl] = module.LibraryPaths[httpLegacy]
 
-		if !contains(verifyUsesLibs, httpLegacy) && !contains(verifyOptionalUsesLibs, httpLegacy) {
+		if !contains(module.UsesLibraries, httpLegacy) && !contains(module.PresentOptionalUsesLibraries, httpLegacy) {
 			conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
 				pathForLibrary(module, httpLegacyImpl))
 			conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
@@ -284,6 +274,9 @@
 		const hidlBase = "android.hidl.base-V1.0-java"
 		const hidlManager = "android.hidl.manager-V1.0-java"
 
+		// android.hidl.base-V1.0-java and android.hidl.manager-V1.0 contain classes that were in the default
+		// classpath until API 29.  If the targetSdkVersion in the manifest or APK is < 29 then implicitly add
+		// the classes to the classpath for dexpreopt.
 		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
 			pathForLibrary(module, hidlManager))
 		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
@@ -309,9 +302,21 @@
 	rule.Command().Text(`stored_class_loader_context_arg=""`)
 
 	if module.EnforceUsesLibraries {
-		rule.Command().Textf(`uses_library_names="%s"`, strings.Join(verifyUsesLibs, " "))
-		rule.Command().Textf(`optional_uses_library_names="%s"`, strings.Join(verifyOptionalUsesLibs, " "))
-		rule.Command().Textf(`aapt_binary="%s"`, global.Tools.Aapt)
+		if module.ManifestPath != nil {
+			rule.Command().Text(`target_sdk_version="$(`).
+				Tool(global.Tools.ManifestCheck).
+				Flag("--extract-target-sdk-version").
+				Input(module.ManifestPath).
+				Text(`)"`)
+		} else {
+			// No manifest to extract targetSdkVersion from, hope that DexJar is an APK
+			rule.Command().Text(`target_sdk_version="$(`).
+				Tool(global.Tools.Aapt).
+				Flag("dump badging").
+				Input(module.DexPath).
+				Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
+				Text(`)"`)
+		}
 		rule.Command().Textf(`dex_preopt_host_libraries="%s"`,
 			strings.Join(classLoaderContextHost.Strings(), " ")).
 			Implicits(classLoaderContextHost)
@@ -327,8 +332,7 @@
 			Implicits(conditionalClassLoaderContextHost29)
 		rule.Command().Textf(`conditional_target_libs_29="%s"`,
 			strings.Join(conditionalClassLoaderContextTarget29, " "))
-		rule.Command().Text("source").Tool(global.Tools.VerifyUsesLibraries).Input(module.DexPath)
-		rule.Command().Text("source").Tool(global.Tools.ConstructContext)
+		rule.Command().Text("source").Tool(global.Tools.ConstructContext).Input(module.DexPath)
 	}
 
 	// Devices that do not have a product partition use a symlink from /product to /system/product.
@@ -350,7 +354,7 @@
 		Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
 		Flag("${class_loader_context_arg}").
 		Flag("${stored_class_loader_context_arg}").
-		FlagWithArg("--boot-image=", bootImageLocation).Implicit(bootImage).
+		FlagWithArg("--boot-image=", bootImageLocation).Implicits(bootImageDeps).
 		FlagWithInput("--dex-file=", module.DexPath).
 		FlagWithArg("--dex-location=", dexLocationArg).
 		FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath).
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index c72f684..d54ddb1 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -78,7 +78,7 @@
 
 	ctx := &pathContext{android.TestConfig(*outDir, nil)}
 
-	globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
+	globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err)
 		os.Exit(2)
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 6dfa9d2..7f1fe42 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -33,11 +33,12 @@
 		ProfileClassListing:             android.OptionalPath{},
 		ProfileIsTextListing:            false,
 		EnforceUsesLibraries:            false,
-		OptionalUsesLibraries:           nil,
+		PresentOptionalUsesLibraries:    nil,
 		UsesLibraries:                   nil,
 		LibraryPaths:                    nil,
 		Archs:                           []android.ArchType{android.Arm},
 		DexPreoptImages:                 android.Paths{android.PathForTesting("system/framework/arm/boot.art")},
+		DexPreoptImagesDeps:             []android.Paths{android.Paths{}},
 		PreoptBootClassPathDexFiles:     nil,
 		PreoptBootClassPathDexLocations: nil,
 		PreoptExtractedApk:              false,
diff --git a/finder/finder_test.go b/finder/finder_test.go
index 29711fc..f6d0aa9 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -891,8 +891,8 @@
 			IncludeFiles: []string{"findme.txt"},
 		},
 	)
-	foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
 	finder.Shutdown()
 	// check the response of the first finder
 	assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
@@ -1522,8 +1522,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	// check results
 	assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
@@ -1583,8 +1583,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
 	// check results
@@ -1629,8 +1629,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	// check results
 	assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
@@ -1650,8 +1650,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	// check results
 	assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 87e6747..b0657ff 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -101,6 +101,7 @@
 type Module struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.ApexModuleBase
 
 	// For other packages to make their own genrules with extra
 	// properties
@@ -582,9 +583,6 @@
 	android.DefaultsModuleBase
 }
 
-func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-}
-
 func defaultsFactory() android.Module {
 	return DefaultsFactory()
 }
diff --git a/jar/Android.bp b/jar/Android.bp
index 6c2e60e..2563474 100644
--- a/jar/Android.bp
+++ b/jar/Android.bp
@@ -18,8 +18,10 @@
     srcs: [
         "jar.go",
     ],
+    testSrcs: [
+        "jar_test.go",
+    ],
     deps: [
         "android-archive-zip",
     ],
 }
-
diff --git a/jar/jar.go b/jar/jar.go
index fa0e693..a8f06a4 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -17,9 +17,12 @@
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"os"
 	"strings"
+	"text/scanner"
 	"time"
+	"unicode"
 
 	"android/soong/third_party/zip"
 )
@@ -112,3 +115,111 @@
 
 	return finalBytes, nil
 }
+
+var javaIgnorableIdentifier = &unicode.RangeTable{
+	R16: []unicode.Range16{
+		{0x00, 0x08, 1},
+		{0x0e, 0x1b, 1},
+		{0x7f, 0x9f, 1},
+	},
+	LatinOffset: 3,
+}
+
+func javaIdentRune(ch rune, i int) bool {
+	if unicode.IsLetter(ch) {
+		return true
+	}
+	if unicode.IsDigit(ch) && i > 0 {
+		return true
+	}
+
+	if unicode.In(ch,
+		unicode.Nl, // letter number
+		unicode.Sc, // currency symbol
+		unicode.Pc, // connecting punctuation
+	) {
+		return true
+	}
+
+	if unicode.In(ch,
+		unicode.Cf, // format
+		unicode.Mc, // combining mark
+		unicode.Mn, // non-spacing mark
+		javaIgnorableIdentifier,
+	) && i > 0 {
+		return true
+	}
+
+	return false
+}
+
+// JavaPackage parses the package out of a java source file by looking for the package statement, or the first valid
+// non-package statement, in which case it returns an empty string for the package.
+func JavaPackage(r io.Reader, src string) (string, error) {
+	var s scanner.Scanner
+	var sErr error
+
+	s.Init(r)
+	s.Filename = src
+	s.Error = func(s *scanner.Scanner, msg string) {
+		sErr = fmt.Errorf("error parsing %q: %s", src, msg)
+	}
+	s.IsIdentRune = javaIdentRune
+
+	tok := s.Scan()
+	if sErr != nil {
+		return "", sErr
+	}
+	if tok == scanner.Ident {
+		switch s.TokenText() {
+		case "package":
+		// Nothing
+		case "import":
+			// File has no package statement, first keyword is an import
+			return "", nil
+		case "class", "enum", "interface":
+			// File has no package statement, first keyword is a type declaration
+			return "", nil
+		case "public", "protected", "private", "abstract", "static", "final", "strictfp":
+			// File has no package statement, first keyword is a modifier
+			return "", nil
+		case "module", "open":
+			// File has no package statement, first keyword is a module declaration
+			return "", nil
+		default:
+			return "", fmt.Errorf(`expected first token of java file to be "package", got %q`, s.TokenText())
+		}
+	} else if tok == '@' {
+		// File has no package statement, first token is an annotation
+		return "", nil
+	} else if tok == scanner.EOF {
+		// File no package statement, it has no non-whitespace non-comment tokens
+		return "", nil
+	} else {
+		return "", fmt.Errorf(`expected first token of java file to be "package", got %q`, s.TokenText())
+	}
+
+	var pkg string
+	for {
+		tok = s.Scan()
+		if sErr != nil {
+			return "", sErr
+		}
+		if tok != scanner.Ident {
+			return "", fmt.Errorf(`expected "package <package>;", got "package %s%s"`, pkg, s.TokenText())
+		}
+		pkg += s.TokenText()
+
+		tok = s.Scan()
+		if sErr != nil {
+			return "", sErr
+		}
+		if tok == ';' {
+			return pkg, nil
+		} else if tok == '.' {
+			pkg += "."
+		} else {
+			return "", fmt.Errorf(`expected "package <package>;", got "package %s%s"`, pkg, s.TokenText())
+		}
+	}
+}
diff --git a/jar/jar_test.go b/jar/jar_test.go
new file mode 100644
index 0000000..c92011e
--- /dev/null
+++ b/jar/jar_test.go
@@ -0,0 +1,182 @@
+// Copyright 2017 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 jar
+
+import (
+	"bytes"
+	"io"
+	"testing"
+)
+
+func TestGetJavaPackage(t *testing.T) {
+	type args struct {
+		r   io.Reader
+		src string
+	}
+	tests := []struct {
+		name    string
+		in      string
+		want    string
+		wantErr bool
+	}{
+		{
+			name: "simple",
+			in:   "package foo.bar;",
+			want: "foo.bar",
+		},
+		{
+			name: "comment",
+			in:   "/* test */\npackage foo.bar;",
+			want: "foo.bar",
+		},
+		{
+			name: "no package",
+			in:   "import foo.bar;",
+			want: "",
+		},
+		{
+			name:    "missing semicolon error",
+			in:      "package foo.bar",
+			wantErr: true,
+		},
+		{
+			name:    "parser error",
+			in:      "/*",
+			wantErr: true,
+		},
+		{
+			name:    "parser ident error",
+			in:      "package 0foo.bar;",
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			buf := bytes.NewBufferString(tt.in)
+			got, err := JavaPackage(buf, "<test>")
+			if (err != nil) != tt.wantErr {
+				t.Errorf("JavaPackage() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if got != tt.want {
+				t.Errorf("JavaPackage() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_javaIdentRune(t *testing.T) {
+	// runes that should be valid anywhere in an identifier
+	validAnywhere := []rune{
+		// letters, $, _
+		'a',
+		'A',
+		'$',
+		'_',
+
+		// assorted unicode
+		'𐐀',
+		'𐐨',
+		'Dž',
+		'ῼ',
+		'ʰ',
+		'゚',
+		'ƻ',
+		'㡢',
+		'₩',
+		'_',
+		'Ⅰ',
+		'𐍊',
+	}
+
+	// runes that should be invalid as the first rune in an identifier, but valid anywhere else
+	validAfterFirst := []rune{
+		// digits
+		'0',
+
+		// assorted unicode
+		'᥍',
+		'𝟎',
+		'ྂ',
+		'𝆀',
+
+		// control characters
+		'\x00',
+		'\b',
+		'\u000e',
+		'\u001b',
+		'\u007f',
+		'\u009f',
+		'\u00ad',
+		0xE007F,
+
+		// zero width space
+		'\u200b',
+	}
+
+	// runes that should never be valid in an identifier
+	invalid := []rune{
+		';',
+		0x110000,
+	}
+
+	validFirst := validAnywhere
+	invalidFirst := append(validAfterFirst, invalid...)
+	validPart := append(validAnywhere, validAfterFirst...)
+	invalidPart := invalid
+
+	check := func(t *testing.T, ch rune, i int, want bool) {
+		t.Helper()
+		if got := javaIdentRune(ch, i); got != want {
+			t.Errorf("javaIdentRune() = %v, want %v", got, want)
+		}
+	}
+
+	t.Run("first", func(t *testing.T) {
+		t.Run("valid", func(t *testing.T) {
+			for _, ch := range validFirst {
+				t.Run(string(ch), func(t *testing.T) {
+					check(t, ch, 0, true)
+				})
+			}
+		})
+
+		t.Run("invalid", func(t *testing.T) {
+			for _, ch := range invalidFirst {
+				t.Run(string(ch), func(t *testing.T) {
+					check(t, ch, 0, false)
+				})
+			}
+		})
+	})
+
+	t.Run("part", func(t *testing.T) {
+		t.Run("valid", func(t *testing.T) {
+			for _, ch := range validPart {
+				t.Run(string(ch), func(t *testing.T) {
+					check(t, ch, 1, true)
+				})
+			}
+		})
+
+		t.Run("invalid", func(t *testing.T) {
+			for _, ch := range invalidPart {
+				t.Run(string(ch), func(t *testing.T) {
+					check(t, ch, 1, false)
+				})
+			}
+		})
+	})
+}
diff --git a/java/OWNERS b/java/OWNERS
index d68a5b0..16ef4d8 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1 @@
-per-file dexpreopt.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
diff --git a/java/aapt2.go b/java/aapt2.go
index bcc8e97..f0eb99c 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -55,12 +55,14 @@
 
 var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
 	blueprint.RuleParams{
-		Command:     `${config.Aapt2Cmd} compile -o $outDir $cFlags --legacy $in`,
+		Command:     `${config.Aapt2Cmd} compile -o $outDir $cFlags $in`,
 		CommandDeps: []string{"${config.Aapt2Cmd}"},
 	},
 	"outDir", "cFlags")
 
-func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths) android.WritablePaths {
+func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
+	flags []string) android.WritablePaths {
+
 	shards := shardPaths(paths, AAPT2_SHARD_SIZE)
 
 	ret := make(android.WritablePaths, 0, len(paths))
@@ -81,9 +83,7 @@
 			Outputs:     outPaths,
 			Args: map[string]string{
 				"outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(),
-				// Always set --pseudo-localize, it will be stripped out later for release
-				// builds that don't want it.
-				"cFlags": "--pseudo-localize",
+				"cFlags": strings.Join(flags, " "),
 			},
 		})
 	}
@@ -94,42 +94,31 @@
 	return ret
 }
 
-func aapt2CompileDirs(ctx android.ModuleContext, flata android.WritablePath, dirs android.Paths, deps android.Paths) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        aapt2CompileRule,
-		Description: "aapt2 compile dirs",
-		Implicits:   deps,
-		Output:      flata,
-		Args: map[string]string{
-			"outDir": flata.String(),
-			// Always set --pseudo-localize, it will be stripped out later for release
-			// builds that don't want it.
-			"cFlags": "--pseudo-localize " + android.JoinWithPrefix(dirs.Strings(), "--dir "),
-		},
-	})
-}
-
 var aapt2CompileZipRule = pctx.AndroidStaticRule("aapt2CompileZip",
 	blueprint.RuleParams{
-		Command: `${config.ZipSyncCmd} -d $resZipDir $in && ` +
-			`${config.Aapt2Cmd} compile -o $out $cFlags --legacy --dir $resZipDir`,
+		Command: `${config.ZipSyncCmd} -d $resZipDir $zipSyncFlags $in && ` +
+			`${config.Aapt2Cmd} compile -o $out $cFlags --dir $resZipDir`,
 		CommandDeps: []string{
 			"${config.Aapt2Cmd}",
 			"${config.ZipSyncCmd}",
 		},
-	}, "cFlags", "resZipDir")
+	}, "cFlags", "resZipDir", "zipSyncFlags")
 
-func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path) {
+func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path, zipPrefix string,
+	flags []string) {
+
+	if zipPrefix != "" {
+		zipPrefix = "--zip-prefix " + zipPrefix
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aapt2CompileZipRule,
 		Description: "aapt2 compile zip",
 		Input:       zip,
 		Output:      flata,
 		Args: map[string]string{
-			// Always set --pseudo-localize, it will be stripped out later for release
-			// builds that don't want it.
-			"cFlags":    "--pseudo-localize",
-			"resZipDir": android.PathForModuleOut(ctx, "aapt2", "reszip", flata.Base()).String(),
+			"cFlags":       strings.Join(flags, " "),
+			"resZipDir":    android.PathForModuleOut(ctx, "aapt2", "reszip", flata.Base()).String(),
+			"zipSyncFlags": zipPrefix,
 		},
 	})
 }
diff --git a/java/aar.go b/java/aar.go
index 6273a9b..ce3d126 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -30,7 +30,7 @@
 	ExportedProguardFlagFiles() android.Paths
 	ExportedRRODirs() []rroDir
 	ExportedStaticPackages() android.Paths
-	ExportedManifest() android.Path
+	ExportedManifests() android.Paths
 }
 
 func init() {
@@ -72,18 +72,22 @@
 }
 
 type aapt struct {
-	aaptSrcJar            android.Path
-	exportPackage         android.Path
-	manifestPath          android.Path
-	proguardOptionsFile   android.Path
-	rroDirs               []rroDir
-	rTxt                  android.Path
-	extraAaptPackagesFile android.Path
-	noticeFile            android.OptionalPath
-	isLibrary             bool
-	uncompressedJNI       bool
-	useEmbeddedDex        bool
-	usesNonSdkApis        bool
+	aaptSrcJar              android.Path
+	exportPackage           android.Path
+	manifestPath            android.Path
+	transitiveManifestPaths android.Paths
+	proguardOptionsFile     android.Path
+	rroDirs                 []rroDir
+	rTxt                    android.Path
+	extraAaptPackagesFile   android.Path
+	mergedManifestFile      android.Path
+	noticeFile              android.OptionalPath
+	isLibrary               bool
+	useEmbeddedNativeLibs   bool
+	useEmbeddedDex          bool
+	usesNonSdkApis          bool
+	sdkLibraries            []string
+	hasNoCode               bool
 
 	splitNames []string
 	splits     []split
@@ -105,12 +109,13 @@
 	return a.rroDirs
 }
 
-func (a *aapt) ExportedManifest() android.Path {
-	return a.manifestPath
+func (a *aapt) ExportedManifests() android.Paths {
+	return a.transitiveManifestPaths
 }
 
-func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, manifestPath android.Path) (flags []string,
-	deps android.Paths, resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
+func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
+	manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
+	resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
 
 	hasVersionCode := false
 	hasVersionName := false
@@ -122,8 +127,6 @@
 		}
 	}
 
-	var linkFlags []string
-
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
 
@@ -134,8 +137,6 @@
 	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
 	resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips)
 
-	var linkDeps android.Paths
-
 	// Glob directories into lists of paths
 	for _, dir := range resourceDirs {
 		resDirs = append(resDirs, globbedResourceDir{
@@ -189,27 +190,48 @@
 		linkFlags = append(linkFlags, "--version-name ", versionName)
 	}
 
-	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips
+	linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"})
+
+	// Always set --pseudo-localize, it will be stripped out later for release
+	// builds that don't want it.
+	compileFlags = append(compileFlags, "--pseudo-localize")
+
+	return compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips
 }
 
-func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkContext sdkContext) {
-	sdkDep := decodeSdkDep(ctx, sdkContext)
+func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkDep sdkDep) {
 	if sdkDep.frameworkResModule != "" {
 		ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule)
 	}
 }
 
 func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
-	transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
+
+	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+		aaptLibs(ctx, sdkContext)
 
 	// App manifest file
 	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
-	manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary,
-		a.uncompressedJNI, a.useEmbeddedDex, a.usesNonSdkApis)
+	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
+		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode)
 
-	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
+	a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
+
+	if len(transitiveStaticLibManifests) > 0 {
+		a.mergedManifestFile = manifestMerger(ctx, manifestPath, transitiveStaticLibManifests, a.isLibrary)
+		if !a.isLibrary {
+			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
+			// will be propagated to the final application and merged there.  The merged manifest for libraries is
+			// only passed to Make, which can't handle transitive dependencies.
+			manifestPath = a.mergedManifestFile
+		}
+	} else {
+		a.mergedManifestFile = manifestPath
+	}
+
+	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
 
 	rroDirs = append(rroDirs, staticRRODirs...)
 	linkFlags = append(linkFlags, libFlags...)
@@ -228,12 +250,12 @@
 
 	var compiledResDirs []android.Paths
 	for _, dir := range resDirs {
-		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files).Paths())
+		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
 	}
 
 	for i, zip := range resZips {
 		flata := android.PathForModuleOut(ctx, fmt.Sprintf("reszip.%d.flata", i))
-		aapt2CompileZip(ctx, flata, zip)
+		aapt2CompileZip(ctx, flata, zip, "", compileFlags)
 		compiledResDirs = append(compiledResDirs, android.Paths{flata})
 	}
 
@@ -262,7 +284,7 @@
 	}
 
 	for _, dir := range overlayDirs {
-		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()...)
 	}
 
 	var splitPackages android.WritablePaths
@@ -294,8 +316,8 @@
 }
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
-func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, staticLibManifests android.Paths,
-	staticRRODirs []rroDir, deps android.Paths, flags []string) {
+func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
+	staticRRODirs []rroDir, deps android.Paths, flags []string, sdkLibraries []string) {
 
 	var sharedLibs android.Paths
 
@@ -314,7 +336,16 @@
 		switch ctx.OtherModuleDependencyTag(module) {
 		case instrumentationForTag:
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
-		case libTag, frameworkResTag:
+		case libTag:
+			if exportPackage != nil {
+				sharedLibs = append(sharedLibs, exportPackage)
+			}
+
+			if _, ok := module.(SdkLibraryDependency); ok {
+				sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module))
+			}
+
+		case frameworkResTag:
 			if exportPackage != nil {
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
@@ -322,7 +353,8 @@
 			if exportPackage != nil {
 				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
 				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
-				staticLibManifests = append(staticLibManifests, aarDep.ExportedManifest())
+				transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
+				sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
 
 			outer:
 				for _, d := range aarDep.ExportedRRODirs() {
@@ -349,8 +381,10 @@
 	}
 
 	transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
+	transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
+	sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
 
-	return transitiveStaticLibs, staticLibManifests, staticRRODirs, deps, flags
+	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags, sdkLibraries
 }
 
 type AndroidLibrary struct {
@@ -377,13 +411,15 @@
 
 func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
-	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
-		a.aapt.deps(ctx, sdkContext(a))
+	sdkDep := decodeSdkDep(ctx, sdkContext(a))
+	if sdkDep.hasFrameworkLibs() {
+		a.aapt.deps(ctx, sdkDep)
 	}
 }
 
 func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.aapt.isLibrary = true
+	a.aapt.sdkLibraries = a.exportedSdkLibs
 	a.aapt.buildActions(ctx, sdkContext(a))
 
 	ctx.CheckbuildFile(a.proguardOptionsFile)
@@ -474,7 +510,7 @@
 }
 
 func (a *AARImport) sdkVersion() string {
-	return String(a.properties.Sdk_version)
+	return proptools.StringDefault(a.properties.Sdk_version, defaultSdkVersion(a))
 }
 
 func (a *AARImport) minSdkVersion() string {
@@ -506,8 +542,8 @@
 	return a.exportedStaticPackages
 }
 
-func (a *AARImport) ExportedManifest() android.Path {
-	return a.manifest
+func (a *AARImport) ExportedManifests() android.Paths {
+	return android.Paths{a.manifest}
 }
 
 func (a *AARImport) Prebuilt() *android.Prebuilt {
@@ -531,13 +567,13 @@
 }
 
 // Unzip an AAR into its constituent files and directories.  Any files in Outputs that don't exist in the AAR will be
-// touched to create an empty file, and any directories in $expectedDirs will be created.
+// touched to create an empty file. The res directory is not extracted, as it will be extracted in its own rule.
 var unzipAAR = pctx.AndroidStaticRule("unzipAAR",
 	blueprint.RuleParams{
-		Command: `rm -rf $outDir && mkdir -p $outDir $expectedDirs && ` +
-			`unzip -qo -d $outDir $in && touch $out`,
+		Command: `rm -rf $outDir && mkdir -p $outDir && ` +
+			`unzip -qo -d $outDir $in && rm -rf $outDir/res && touch $out`,
 	},
-	"expectedDirs", "outDir")
+	"outDir")
 
 func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(a.properties.Aars) != 1 {
@@ -555,7 +591,6 @@
 	}
 
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
-	extractedResDir := extractedAARDir.Join(ctx, "res")
 	a.classpathFile = extractedAARDir.Join(ctx, "classes.jar")
 	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
 	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
@@ -566,16 +601,16 @@
 		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest},
 		Description: "unzip AAR",
 		Args: map[string]string{
-			"expectedDirs": extractedResDir.String(),
-			"outDir":       extractedAARDir.String(),
+			"outDir": extractedAARDir.String(),
 		},
 	})
 
+	// Always set --pseudo-localize, it will be stripped out later for release
+	// builds that don't want it.
+	compileFlags := []string{"--pseudo-localize"}
 	compiledResDir := android.PathForModuleOut(ctx, "flat-res")
-	aaptCompileDeps := android.Paths{a.classpathFile}
-	aaptCompileDirs := android.Paths{extractedResDir}
 	flata := compiledResDir.Join(ctx, "gen_res.flata")
-	aapt2CompileDirs(ctx, flata, aaptCompileDirs, aaptCompileDeps)
+	aapt2CompileZip(ctx, flata, aar, "res", compileFlags)
 
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
 	srcJar := android.PathForModuleGen(ctx, "R.jar")
@@ -594,10 +629,12 @@
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
+	transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+		aaptLibs(ctx, sdkContext(a))
 
 	_ = staticLibManifests
 	_ = staticRRODirs
+	_ = sdkLibraries
 
 	linkDeps = append(linkDeps, libDeps...)
 	linkFlags = append(linkFlags, libFlags...)
@@ -638,6 +675,10 @@
 	return nil
 }
 
+func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
+	return nil, nil
+}
+
 var _ android.PrebuiltInterface = (*Import)(nil)
 
 // android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 8dc3b47..021883e 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -36,13 +36,24 @@
 
 var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
 	blueprint.RuleParams{
-		Command:     `${config.ManifestMergerCmd} --main $in $libs --out $out`,
+		Command:     `${config.ManifestMergerCmd} $args --main $in $libs --out $out`,
 		CommandDeps: []string{"${config.ManifestMergerCmd}"},
 	},
-	"libs")
+	"args", "libs")
 
-func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
-	staticLibManifests android.Paths, isLibrary, uncompressedJNI, useEmbeddedDex, usesNonSdkApis bool) android.Path {
+// These two libs are added as optional dependencies (<uses-library> with
+// android:required set to false). This is because they haven't existed in pre-P
+// devices, but classes in them were in bootclasspath jars, etc. So making them
+// hard dependencies (android:required=true) would prevent apps from being
+// installed to such legacy devices.
+var optionalUsesLibs = []string{
+	"android.test.base",
+	"android.test.mock",
+}
+
+// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
+func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
+	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool) android.Path {
 
 	var args []string
 	if isLibrary {
@@ -53,8 +64,8 @@
 			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
 		}
 		if minSdkVersion >= 23 {
-			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !uncompressedJNI))
-		} else if uncompressedJNI {
+			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
+		} else if useEmbeddedNativeLibs {
 			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
 				minSdkVersion)
 		}
@@ -65,7 +76,19 @@
 	}
 
 	if useEmbeddedDex {
-		args = append(args, "--use-embedded-dex=true")
+		args = append(args, "--use-embedded-dex")
+	}
+
+	for _, usesLib := range sdkLibraries {
+		if inList(usesLib, optionalUsesLibs) {
+			args = append(args, "--optional-uses-library", usesLib)
+		} else {
+			args = append(args, "--uses-library", usesLib)
+		}
+	}
+
+	if hasNoCode {
+		args = append(args, "--has-no-code")
 	}
 
 	var deps android.Paths
@@ -79,35 +102,44 @@
 		deps = append(deps, apiFingerprint)
 	}
 
-	// Inject minSdkVersion into the manifest
 	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
 	ctx.Build(pctx, android.BuildParams{
-		Rule:      manifestFixerRule,
-		Input:     manifest,
-		Implicits: deps,
-		Output:    fixedManifest,
+		Rule:        manifestFixerRule,
+		Description: "fix manifest",
+		Input:       manifest,
+		Implicits:   deps,
+		Output:      fixedManifest,
 		Args: map[string]string{
 			"minSdkVersion":    sdkVersionOrDefault(ctx, sdkContext.minSdkVersion()),
 			"targetSdkVersion": targetSdkVersion,
 			"args":             strings.Join(args, " "),
 		},
 	})
-	manifest = fixedManifest
 
-	// Merge static aar dependency manifests if necessary
-	if len(staticLibManifests) > 0 {
-		mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:      manifestMergerRule,
-			Input:     manifest,
-			Implicits: staticLibManifests,
-			Output:    mergedManifest,
-			Args: map[string]string{
-				"libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
-			},
-		})
-		manifest = mergedManifest
+	return fixedManifest
+}
+
+func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
+	isLibrary bool) android.Path {
+
+	var args string
+	if !isLibrary {
+		// Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
+		args = "--remove-tools-declarations"
 	}
 
-	return manifest
+	mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        manifestMergerRule,
+		Description: "merge manifest",
+		Input:       manifest,
+		Implicits:   staticLibManifests,
+		Output:      mergedManifest,
+		Args: map[string]string{
+			"libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
+			"args": args,
+		},
+	})
+
+	return mergedManifest
 }
diff --git a/java/androidmk.go b/java/androidmk.go
index 7a939e8..90fdd0f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -38,7 +38,15 @@
 		}
 		fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
 		fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
-		fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " "))
+		if len(data.Required) > 0 {
+			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
+		}
+		if len(data.Host_required) > 0 {
+			fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " "))
+		}
+		if len(data.Target_required) > 0 {
+			fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " "))
+		}
 		if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 {
 			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " "))
 		}
@@ -86,12 +94,8 @@
 					fmt.Fprintln(w, "LOCAL_ADDITIONAL_CHECKED_MODULE +=", strings.Join(library.additionalCheckedModules.Strings(), " "))
 				}
 
-				// Temporary hack: export sources used to compile framework.jar to Make
-				// to be used for droiddoc
-				// TODO(ccross): remove this once droiddoc is in soong
-				if (library.Name() == "framework") || (library.Name() == "framework-annotation-proc") {
-					fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCS :=", strings.Join(library.compiledJavaSrcs.Strings(), " "))
-					fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCJARS :=", strings.Join(library.compiledSrcJars.Strings(), " "))
+				if library.proguardDictionary != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", library.proguardDictionary.String())
 				}
 			},
 		},
@@ -323,6 +327,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")
+				}
 			},
 		},
 	}
@@ -368,9 +384,6 @@
 		if a.aarFile != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_AAR :=", a.aarFile.String())
 		}
-		if a.proguardDictionary != nil {
-			fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", a.proguardDictionary.String())
-		}
 
 		if a.Name() == "framework-res" {
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
@@ -381,7 +394,7 @@
 
 		fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", a.exportPackage.String())
 		fmt.Fprintln(w, "LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=", a.extraAaptPackagesFile.String())
-		fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.manifestPath.String())
+		fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.mergedManifestFile.String())
 		fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=",
 			strings.Join(a.exportedProguardFlagFiles.Strings(), " "))
 		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
@@ -581,6 +594,32 @@
 	}
 }
 
+func (app *AndroidAppImport) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "APPS",
+		OutputFile: android.OptionalPathForPath(app.outputFile),
+		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				if Bool(app.properties.Privileged) {
+					fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
+				}
+				if app.certificate != nil {
+					fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
+				} else {
+					fmt.Fprintln(w, "LOCAL_CERTIFICATE := PRESIGNED")
+				}
+				if len(app.properties.Overrides) > 0 {
+					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(app.properties.Overrides, " "))
+				}
+				if len(app.dexpreopter.builtInstalled) > 0 {
+					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
+				}
+			},
+		},
+	}
+}
+
 func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
 	var testFiles []string
 	for _, d := range data {
diff --git a/java/app.go b/java/app.go
index ad672ea..e12b56c 100644
--- a/java/app.go
+++ b/java/app.go
@@ -18,6 +18,7 @@
 
 import (
 	"path/filepath"
+	"reflect"
 	"sort"
 	"strings"
 
@@ -29,12 +30,32 @@
 	"android/soong/tradefed"
 )
 
+var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"}
+var dpiVariantsStruct reflect.Type
+
 func init() {
 	android.RegisterModuleType("android_app", AndroidAppFactory)
 	android.RegisterModuleType("android_test", AndroidTestFactory)
 	android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory)
 	android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
 	android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
+	android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
+
+	// Dynamically construct a struct for the dpi_variants property in android_app_import.
+	perDpiStruct := reflect.StructOf([]reflect.StructField{
+		{
+			Name: "Apk",
+			Type: reflect.TypeOf((*string)(nil)),
+		},
+	})
+	dpiVariantsFields := make([]reflect.StructField, len(supportedDpis))
+	for i, dpi := range supportedDpis {
+		dpiVariantsFields[i] = reflect.StructField{
+			Name: string(dpi),
+			Type: perDpiStruct,
+		}
+	}
+	dpiVariantsStruct = reflect.StructOf(dpiVariantsFields)
 }
 
 // AndroidManifest.xml merging
@@ -66,6 +87,9 @@
 	// list of native libraries that will be provided in or alongside the resulting jar
 	Jni_libs []string `android:"arch_variant"`
 
+	// STL library to use for JNI libraries.
+	Stl *string `android:"arch_variant"`
+
 	// Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
 	// flag so that they are used from inside the APK at runtime.  Defaults to true for android_test modules unless
 	// sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
@@ -101,6 +125,8 @@
 	aapt
 	android.OverridableModuleBase
 
+	usesLibrary usesLibrary
+
 	certificate Certificate
 
 	appProperties appProperties
@@ -115,6 +141,8 @@
 	installApkName string
 
 	additionalAaptFlags []string
+
+	noticeOutputs android.NoticeOutputs
 }
 
 func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
@@ -134,10 +162,16 @@
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
 
-	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
-		a.aapt.deps(ctx, sdkContext(a))
+	if String(a.appProperties.Stl) == "c++_shared" && a.sdkVersion() == "" {
+		ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
 	}
 
+	sdkDep := decodeSdkDep(ctx, sdkContext(a))
+	if sdkDep.hasFrameworkLibs() {
+		a.aapt.deps(ctx, sdkDep)
+	}
+
+	embedJni := a.shouldEmbedJnis(ctx)
 	for _, jniTarget := range ctx.MultiTargets() {
 		variation := []blueprint.Variation{
 			{Mutator: "arch", Variation: jniTarget.String()},
@@ -147,8 +181,17 @@
 			target: jniTarget,
 		}
 		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+		if String(a.appProperties.Stl) == "c++_shared" {
+			if embedJni {
+				ctx.AddFarVariationDependencies(variation, tag, "ndk_libc++_shared")
+			}
+		}
 	}
 
+	a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
+}
+
+func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
 	cert := android.SrcIsModule(a.getCertString(ctx))
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
@@ -166,14 +209,14 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
+	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
 	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 }
 
-// shouldUncompressJNI returns true if the native libraries should be stored in the APK uncompressed and the
+// Returns true if the native libraries should be stored in the APK uncompressed and the
 // extractNativeLibs application flag should be set to false in the manifest.
-func (a *AndroidApp) shouldUncompressJNI(ctx android.ModuleContext) bool {
+func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
 	minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
@@ -188,11 +231,9 @@
 		return true
 	}
 
-	// Uncompress dex in APKs of privileged apps, and modules used by privileged apps
-	// (even for unbundled builds, they may be preinstalled as prebuilts).
-	if ctx.Config().UncompressPrivAppDex() &&
-		(Bool(a.appProperties.Privileged) ||
-			inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
+	// Uncompress dex in APKs of privileged apps (even for unbundled builds, they may
+	// be preinstalled as prebuilts).
+	if ctx.Config().UncompressPrivAppDex() && Bool(a.appProperties.Privileged) {
 		return true
 	}
 
@@ -200,17 +241,20 @@
 		return false
 	}
 
-	// Uncompress if the dex files is preopted on /system.
-	if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) {
-		return true
-	}
+	return shouldUncompressDex(ctx, &a.dexpreopter)
+}
 
-	return false
+func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
+	return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
+		a.appProperties.AlwaysPackageNativeLibs
 }
 
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
 	a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
 
+	// Ask manifest_fixer to add or update the application element indicating this app has no code.
+	a.aapt.hasNoCode = !a.hasCode(ctx)
+
 	aaptLinkFlags := []string{}
 
 	// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
@@ -249,6 +293,7 @@
 	aaptLinkFlags = append(aaptLinkFlags, a.additionalAaptFlags...)
 
 	a.aapt.splitNames = a.appProperties.Package_splits
+	a.aapt.sdkLibraries = a.exportedSdkLibs
 
 	a.aapt.buildActions(ctx, sdkContext(a), aaptLinkFlags...)
 
@@ -281,9 +326,17 @@
 	} else {
 		installDir = filepath.Join("app", a.installApkName)
 	}
+
 	a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
 	a.dexpreopter.isInstallable = Bool(a.properties.Installable)
 	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+
+	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+	a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
+	a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
+	a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+	a.dexpreopter.manifestFile = a.mergedManifestFile
+
 	a.deviceProperties.UncompressDex = a.dexpreopter.uncompressedDex
 
 	if ctx.ModuleName() != "framework-res" {
@@ -296,11 +349,9 @@
 func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
 	var jniJarFile android.WritablePath
 	if len(jniLibs) > 0 {
-		embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
-			a.appProperties.AlwaysPackageNativeLibs
-		if embedJni {
+		if a.shouldEmbedJnis(ctx) {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
-			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
+			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
 		} else {
 			a.installJniLibs = jniLibs
 		}
@@ -308,65 +359,24 @@
 	return jniJarFile
 }
 
-func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx android.ModuleContext) []Certificate {
-	cert := a.getCertString(ctx)
-	certModule := android.SrcIsModule(cert)
-	if certModule != "" {
-		a.certificate = certificateDeps[0]
-		certificateDeps = certificateDeps[1:]
-	} else if cert != "" {
-		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		a.certificate = Certificate{
-			defaultDir.Join(ctx, cert+".x509.pem"),
-			defaultDir.Join(ctx, cert+".pk8"),
-		}
-	} else {
-		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		a.certificate = Certificate{pem, key}
-	}
-
-	if !a.Module.Platform() {
-		certPath := a.certificate.Pem.String()
-		systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
-		if strings.HasPrefix(certPath, systemCertPath) {
-			enforceSystemCert := ctx.Config().EnforceSystemCertificate()
-			whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
-
-			if enforceSystemCert && !inList(a.Module.Name(), whitelist) {
-				ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
-			}
-		}
-	}
-
-	return append([]Certificate{a.certificate}, certificateDeps...)
-}
-
-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)
 
-	ctx.WalkDepsBlueprint(func(child blueprint.Module, parent blueprint.Module) bool {
-		if _, ok := child.(android.Module); !ok {
-			return false
-		}
-		module := child.(android.Module)
+	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 		// Have we already seen this?
-		if _, ok := seenModules[module]; ok {
+		if _, ok := seenModules[child]; ok {
 			return false
 		}
-		seenModules[module] = true
+		seenModules[child] = true
 
 		// Skip host modules.
-		if module.Target().Os.Class == android.Host || module.Target().Os.Class == android.HostCross {
+		if child.Target().Os.Class == android.Host || child.Target().Os.Class == android.HostCross {
 			return false
 		}
 
-		path := module.NoticeFile()
+		path := child.(android.Module).NoticeFile()
 		if path.Valid() {
 			noticePathSet[path.Path()] = true
 		}
@@ -379,7 +389,7 @@
 	}
 
 	if len(noticePathSet) == 0 {
-		return android.OptionalPath{}
+		return
 	}
 	var noticePaths []android.Path
 	for path := range noticePathSet {
@@ -388,12 +398,47 @@
 	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
+// isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
+func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
+	if android.SrcIsModule(certPropValue) == "" {
+		var mainCert Certificate
+		if certPropValue != "" {
+			defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+			mainCert = Certificate{
+				defaultDir.Join(ctx, certPropValue+".x509.pem"),
+				defaultDir.Join(ctx, certPropValue+".pk8"),
+			}
+		} else {
+			pem, key := ctx.Config().DefaultAppCertificate(ctx)
+			mainCert = Certificate{pem, key}
+		}
+		certificates = append([]Certificate{mainCert}, certificates...)
+	}
+
+	if !m.Platform() {
+		certPath := certificates[0].Pem.String()
+		systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
+		if strings.HasPrefix(certPath, systemCertPath) {
+			enforceSystemCert := ctx.Config().EnforceSystemCertificate()
+			whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
+
+			if enforceSystemCert && !inList(m.Name(), whitelist) {
+				ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
+			}
+		}
+	}
+
+	return certificates
 }
 
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
+	var apkDeps android.Paths
+
 	// Check if the install APK name needs to be overridden.
 	a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
 
@@ -407,34 +452,43 @@
 		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)
 
+	if a.usesLibrary.enforceUsesLibraries() {
+		manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile)
+		apkDeps = append(apkDeps, manifestCheckFile)
+	}
+
 	a.proguardBuildActions(ctx)
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, certificateDeps := a.collectAppDeps(ctx)
+	jniLibs, certificateDeps := collectAppDeps(ctx)
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
 
 	if ctx.Failed() {
 		return
 	}
 
-	certificates := a.certificateBuildActions(certificateDeps, ctx)
+	certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
+	a.certificate = certificates[0]
 
 	// Build a final signed app package.
 	// TODO(jungjw): Consider changing this to installApkName.
 	packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
-	CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps)
 	a.outputFile = packageFile
 
 	for _, split := range a.aapt.splits {
 		// Sign the split APKs
 		packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
-		CreateAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 	}
 
@@ -450,7 +504,7 @@
 	}
 }
 
-func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
 	var jniLibs []jniLib
 	var certificates []Certificate
 
@@ -472,7 +526,6 @@
 				}
 			} else {
 				ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
-
 			}
 		} else if tag == certificateTag {
 			if dep, ok := module.(*AndroidAppCertificate); ok {
@@ -486,7 +539,7 @@
 	return jniLibs, certificates
 }
 
-func (a *AndroidApp) getCertString(ctx android.BaseContext) string {
+func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
 	certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
 	if overridden {
 		return ":" + certificate
@@ -511,7 +564,8 @@
 		&module.Module.protoProperties,
 		&module.aaptProperties,
 		&module.appProperties,
-		&module.overridableAppProperties)
+		&module.overridableAppProperties,
+		&module.usesLibrary.usesLibraryProperties)
 
 	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
 		return class == android.Device && ctx.Config().DevicePrefer32BitApps()
@@ -547,6 +601,8 @@
 			a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
 		}
 	}
+	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
+	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 
 	a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites)
@@ -585,6 +641,7 @@
 		&module.appProperties,
 		&module.appTestProperties,
 		&module.overridableAppProperties,
+		&module.usesLibrary.usesLibraryProperties,
 		&module.testProperties)
 
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -625,7 +682,8 @@
 		&module.aaptProperties,
 		&module.appProperties,
 		&module.appTestHelperAppProperties,
-		&module.overridableAppProperties)
+		&module.overridableAppProperties,
+		&module.usesLibrary.usesLibraryProperties)
 
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
@@ -676,7 +734,365 @@
 	m := &OverrideAndroidApp{}
 	m.AddProperties(&overridableAppProperties{})
 
-	android.InitAndroidModule(m)
+	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	android.InitOverrideModule(m)
 	return m
 }
+
+type AndroidAppImport struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	prebuilt android.Prebuilt
+
+	properties AndroidAppImportProperties
+
+	outputFile  android.Path
+	certificate *Certificate
+
+	dexpreopter
+
+	usesLibrary usesLibrary
+}
+
+type AndroidAppImportProperties struct {
+	// A prebuilt apk to import
+	Apk string
+
+	// Per-DPI settings. This property makes it possible to specify a different source apk path for
+	// each DPI.
+	//
+	// Example:
+	//
+	//     android_app_import {
+	//         name: "example_import",
+	//         apk: "prebuilts/example.apk",
+	//         dpi_variants: {
+	//             mdpi: {
+	//                 apk: "prebuilts/example_mdpi.apk",
+	//             },
+	//             xhdpi: {
+	//                 apk: "prebuilts/example_xhdpi.apk",
+	//             },
+	//         },
+	//         certificate: "PRESIGNED",
+	//     }
+	Dpi_variants interface{}
+
+	// The name of a certificate in the default certificate directory, blank to use the default
+	// product certificate, or an android_app_certificate module name in the form ":module".
+	Certificate *string
+
+	// Set this flag to true if the prebuilt apk is already signed. The certificate property must not
+	// be set for presigned modules.
+	Presigned *bool
+
+	// Specifies that this app should be installed to the priv-app directory,
+	// where the system will grant it additional privileges not available to
+	// normal apps.
+	Privileged *bool
+
+	// Names of modules to be overridden. Listed modules can only be other binaries
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden binaries, but if both
+	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+	// from PRODUCT_PACKAGES.
+	Overrides []string
+}
+
+func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string {
+	dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi))
+	if !dpiField.IsValid() {
+		return ""
+	}
+	apkValue := dpiField.FieldByName("Apk").Elem()
+	if apkValue.IsValid() {
+		return apkValue.String()
+	}
+	return ""
+}
+
+// Chooses a source APK path to use based on the module's per-DPI settings and the product config.
+func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string {
+	config := ctx.Config()
+	dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem()
+	if !dpiVariantsValue.IsValid() {
+		return a.properties.Apk
+	}
+	// Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI.
+	if config.ProductAAPTPreferredConfig() != "" {
+		if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" {
+			return apk
+		}
+	}
+	for _, dpi := range config.ProductAAPTPrebuiltDPI() {
+		if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" {
+			return apk
+		}
+	}
+
+	// No match. Use the generic one.
+	return a.properties.Apk
+}
+
+func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+	cert := android.SrcIsModule(String(a.properties.Certificate))
+	if cert != "" {
+		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+	}
+
+	a.usesLibrary.deps(ctx, true)
+}
+
+func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		FlagWithInput("-i ", inputPath).
+		FlagWithOutput("-o ", outputPath).
+		FlagWithArg("-0 ", "'lib/**/*.so'").
+		Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+	rule.Build(pctx, ctx, "uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
+}
+
+// Returns whether this module should have the dex file stored uncompressed in the APK.
+func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
+	if ctx.Config().UnbundledBuild() {
+		return false
+	}
+
+	// Uncompress dex in APKs of privileged apps
+	if ctx.Config().UncompressPrivAppDex() && Bool(a.properties.Privileged) {
+		return true
+	}
+
+	return shouldUncompressDex(ctx, &a.dexpreopter)
+}
+
+func (a *AndroidAppImport) uncompressDex(
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+		Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+		FlagWithInput("-i ", inputPath).
+		FlagWithOutput("-o ", outputPath).
+		FlagWithArg("-0 ", "'classes*.dex'").
+		Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+	rule.Build(pctx, ctx, "uncompress-dex", "Uncompress dex files")
+}
+
+func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
+		ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
+	}
+	if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
+		ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
+	}
+
+	_, certificates := collectAppDeps(ctx)
+
+	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
+	// TODO: LOCAL_PACKAGE_SPLITS
+
+	var srcApk android.Path
+	srcApk = android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
+
+	if a.usesLibrary.enforceUsesLibraries() {
+		srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+	}
+
+	// TODO: Install or embed JNI libraries
+
+	// Uncompress JNI libraries in the apk
+	jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
+	a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
+
+	installDir := android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+	a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
+	a.dexpreopter.isInstallable = true
+	a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
+	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+
+	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+	a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
+	a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
+	a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+
+	dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+	if a.dexpreopter.uncompressedDex {
+		dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
+		a.uncompressDex(ctx, dexOutput, dexUncompressed.OutputPath)
+		dexOutput = dexUncompressed
+	}
+
+	// Sign or align the package
+	// TODO: Handle EXTERNAL
+	if !Bool(a.properties.Presigned) {
+		certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
+		if len(certificates) != 1 {
+			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
+		}
+		a.certificate = &certificates[0]
+		signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
+		SignAppPackage(ctx, signed, dexOutput, certificates)
+		a.outputFile = signed
+	} else {
+		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+		TransformZipAlign(ctx, alignedApk, dexOutput)
+		a.outputFile = alignedApk
+	}
+
+	// TODO: Optionally compress the output apk.
+
+	ctx.InstallFile(installDir, a.BaseModuleName()+".apk", a.outputFile)
+
+	// TODO: androidmk converter jni libs
+}
+
+func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
+	return &a.prebuilt
+}
+
+func (a *AndroidAppImport) Name() string {
+	return a.prebuilt.Name(a.ModuleBase.Name())
+}
+
+// android_app_import imports a prebuilt apk with additional processing specified in the module.
+func AndroidAppImportFactory() android.Module {
+	module := &AndroidAppImport{}
+	module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface()
+	module.AddProperties(&module.properties)
+	module.AddProperties(&module.dexpreoptProperties)
+	module.AddProperties(&module.usesLibrary.usesLibraryProperties)
+
+	InitJavaModule(module, android.DeviceSupported)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
+
+	return module
+}
+
+type UsesLibraryProperties struct {
+	// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file.
+	Uses_libs []string
+
+	// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file with
+	// required=false.
+	Optional_uses_libs []string
+
+	// If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file.  Defaults
+	// to true if either uses_libs or optional_uses_libs is set.  Will unconditionally default to true in the future.
+	Enforce_uses_libs *bool
+}
+
+// usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
+// <uses-library> tags that end up in the manifest of an APK match the ones known to the build system through the
+// uses_libs and optional_uses_libs properties.  The build system's values are used by dexpreopt to preopt apps
+// with knowledge of their shared libraries.
+type usesLibrary struct {
+	usesLibraryProperties UsesLibraryProperties
+}
+
+func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
+	if !ctx.Config().UnbundledBuild() {
+		ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
+		ctx.AddVariationDependencies(nil, usesLibTag, u.presentOptionalUsesLibs(ctx)...)
+		// Only add these extra dependencies if the module depends on framework libs. This avoids
+		// creating a cyclic dependency:
+		//     e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res.
+		if hasFrameworkLibs {
+			// dexpreopt/dexpreopt.go needs the paths to the dex jars of these libraries in case construct_context.sh needs
+			// to pass them to dex2oat.  Add them as a dependency so we can determine the path to the dex jar of each
+			// library to dexpreopt.
+			ctx.AddVariationDependencies(nil, usesLibTag,
+				"org.apache.http.legacy",
+				"android.hidl.base-V1.0-java",
+				"android.hidl.manager-V1.0-java")
+		}
+	}
+}
+
+// presentOptionalUsesLibs returns optional_uses_libs after filtering out MissingUsesLibraries, which don't exist in the
+// build.
+func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string {
+	optionalUsesLibs, _ := android.FilterList(u.usesLibraryProperties.Optional_uses_libs, ctx.Config().MissingUsesLibraries())
+	return optionalUsesLibs
+}
+
+// usesLibraryPaths returns a map of module names of shared library dependencies to the paths to their dex jars.
+func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) map[string]android.Path {
+	usesLibPaths := make(map[string]android.Path)
+
+	if !ctx.Config().UnbundledBuild() {
+		ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
+			if lib, ok := m.(Dependency); ok {
+				if dexJar := lib.DexJar(); dexJar != nil {
+					usesLibPaths[ctx.OtherModuleName(m)] = dexJar
+				} else {
+					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must produce a dex jar, does it have installable: true?",
+						ctx.OtherModuleName(m))
+				}
+			} else if ctx.Config().AllowMissingDependencies() {
+				ctx.AddMissingDependencies([]string{ctx.OtherModuleName(m)})
+			} else {
+				ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library",
+					ctx.OtherModuleName(m))
+			}
+		})
+	}
+
+	return usesLibPaths
+}
+
+// enforceUsesLibraries returns true of <uses-library> tags should be checked against uses_libs and optional_uses_libs
+// properties.  Defaults to true if either of uses_libs or optional_uses_libs is specified.  Will default to true
+// unconditionally in the future.
+func (u *usesLibrary) enforceUsesLibraries() bool {
+	defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs) > 0 ||
+		len(u.usesLibraryProperties.Optional_uses_libs) > 0
+	return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs)
+}
+
+// verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified
+// in the uses_libs and optional_uses_libs properties.  It returns the path to a copy of the manifest.
+func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
+	outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
+
+	rule := android.NewRuleBuilder()
+	cmd := rule.Command().Tool(ctx.Config().HostToolPath(ctx, "manifest_check")).
+		Flag("--enforce-uses-libraries").
+		Input(manifest).
+		FlagWithOutput("-o ", outputFile)
+
+	for _, lib := range u.usesLibraryProperties.Uses_libs {
+		cmd.FlagWithArg("--uses-library ", lib)
+	}
+
+	for _, lib := range u.usesLibraryProperties.Optional_uses_libs {
+		cmd.FlagWithArg("--optional-uses-library ", lib)
+	}
+
+	rule.Build(pctx, ctx, "verify_uses_libraries", "verify <uses-library>")
+
+	return outputFile
+}
+
+// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the ones specified
+// in the uses_libs and optional_uses_libs properties.  It returns the path to a copy of the APK.
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+	outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
+
+	rule := android.NewRuleBuilder()
+	aapt := ctx.Config().HostToolPath(ctx, "aapt")
+	rule.Command().
+		Textf("aapt_binary=%s", aapt.String()).Implicit(aapt).
+		Textf(`uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Uses_libs, " ")).
+		Textf(`optional_uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Optional_uses_libs, " ")).
+		Tool(android.PathForSource(ctx, "build/make/core/verify_uses_libraries.sh")).Input(apk)
+	rule.Command().Text("cp -f").Input(apk).Output(outputFile)
+
+	rule.Build(pctx, ctx, "verify_uses_libraries", "verify <uses-library>")
+
+	return outputFile
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index 5bacb67..348c8b4 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -31,7 +31,7 @@
 var (
 	Signapk = pctx.AndroidStaticRule("signapk",
 		blueprint.RuleParams{
-			Command: `${config.JavaCmd} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
+			Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
 				`-jar $signapkCmd $flags $certificates $in $out`,
 			CommandDeps: []string{"$signapkCmd", "$signapkJniLibrary"},
 		},
@@ -62,8 +62,8 @@
 		CommandDeps: []string{"${config.MergeZipsCmd}"},
 	})
 
-func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
+func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
+	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
 	unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -78,11 +78,17 @@
 	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:   combineApk,
-		Inputs: inputs,
-		Output: unsignedApk,
+		Rule:      combineApk,
+		Inputs:    inputs,
+		Output:    unsignedApk,
+		Implicits: deps,
 	})
 
+	SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+}
+
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+
 	var certificateArgs []string
 	var deps android.Paths
 	for _, c := range certificates {
@@ -93,7 +99,7 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        Signapk,
 		Description: "signapk",
-		Output:      outputFile,
+		Output:      signedApk,
 		Input:       unsignedApk,
 		Implicits:   deps,
 		Args: map[string]string{
diff --git a/java/app_test.go b/java/app_test.go
index 2bd44ad..721dd4d 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -15,17 +15,18 @@
 package java
 
 import (
-	"android/soong/android"
-	"android/soong/cc"
-
 	"fmt"
 	"path/filepath"
 	"reflect"
+	"regexp"
 	"sort"
 	"strings"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -129,8 +130,12 @@
 		foo.Output(expectedOutput)
 	}
 
-	if g, w := foo.Module().(*AndroidApp).Srcs().Strings(), expectedOutputs; !reflect.DeepEqual(g, w) {
-		t.Errorf("want Srcs() = %q, got %q", w, g)
+	outputFiles, err := foo.Module().(*AndroidApp).OutputFiles("")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, w := outputFiles.Strings(), expectedOutputs; !reflect.DeepEqual(g, w) {
+		t.Errorf(`want OutputFiles("") = %q, got %q`, w, g)
 	}
 }
 
@@ -551,34 +556,34 @@
 
 		android_test {
 			name: "test",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			jni_libs: ["libjni"],
 		}
 
 		android_test {
 			name: "test_first",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			compile_multilib: "first",
 			jni_libs: ["libjni"],
 		}
 
 		android_test {
 			name: "test_both",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			compile_multilib: "both",
 			jni_libs: ["libjni"],
 		}
 
 		android_test {
 			name: "test_32",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			compile_multilib: "32",
 			jni_libs: ["libjni"],
 		}
 
 		android_test {
 			name: "test_64",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			compile_multilib: "64",
 			jni_libs: ["libjni"],
 		}
@@ -641,26 +646,26 @@
 
 		android_test {
 			name: "test",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			jni_libs: ["libjni"],
 		}
 
 		android_test {
 			name: "test_noembed",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			jni_libs: ["libjni"],
 			use_embedded_native_libs: false,
 		}
 
 		android_test_helper_app {
 			name: "test_helper",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			jni_libs: ["libjni"],
 		}
 
 		android_test_helper_app {
 			name: "test_helper_noembed",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			jni_libs: ["libjni"],
 			use_embedded_native_libs: false,
 		}
@@ -695,7 +700,6 @@
 			}
 		})
 	}
-
 }
 
 func TestCertificates(t *testing.T) {
@@ -714,7 +718,7 @@
 				}
 			`,
 			certificateOverride: "",
-			expected:            "build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8",
+			expected:            "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
 		},
 		{
 			name: "module certificate property",
@@ -743,7 +747,7 @@
 				}
 			`,
 			certificateOverride: "",
-			expected:            "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
+			expected:            "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
 		},
 		{
 			name: "certificate overrides",
@@ -880,7 +884,7 @@
 			name: "foo",
 			srcs: ["a.java"],
 			certificate: "expiredkey",
-			overrides: ["baz"],
+			overrides: ["qux"],
 		}
 
 		override_android_app {
@@ -902,6 +906,7 @@
 		`)
 
 	expectedVariants := []struct {
+		moduleName  string
 		variantName string
 		apkName     string
 		apkPath     string
@@ -910,24 +915,27 @@
 		aaptFlag    string
 	}{
 		{
+			moduleName:  "foo",
 			variantName: "android_common",
 			apkPath:     "/target/product/test_device/system/app/foo/foo.apk",
-			signFlag:    "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
-			overrides:   []string{"baz"},
+			signFlag:    "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			overrides:   []string{"qux"},
 			aaptFlag:    "",
 		},
 		{
-			variantName: "bar_android_common",
+			moduleName:  "bar",
+			variantName: "android_common_bar",
 			apkPath:     "/target/product/test_device/system/app/bar/bar.apk",
 			signFlag:    "cert/new_cert.x509.pem cert/new_cert.pk8",
-			overrides:   []string{"baz", "foo"},
+			overrides:   []string{"qux", "foo"},
 			aaptFlag:    "",
 		},
 		{
-			variantName: "baz_android_common",
+			moduleName:  "baz",
+			variantName: "android_common_baz",
 			apkPath:     "/target/product/test_device/system/app/baz/baz.apk",
-			signFlag:    "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
-			overrides:   []string{"baz", "foo"},
+			signFlag:    "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			overrides:   []string{"qux", "foo"},
 			aaptFlag:    "--rename-manifest-package org.dandroid.bp",
 		},
 	}
@@ -971,6 +979,424 @@
 	}
 }
 
+func TestOverrideAndroidAppDependency(t *testing.T) {
+	ctx := testJava(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+
+		override_android_app {
+			name: "bar",
+			base: "foo",
+			package_name: "org.dandroid.bp",
+		}
+
+		android_test {
+			name: "baz",
+			srcs: ["b.java"],
+			instrumentation_for: "foo",
+		}
+
+		android_test {
+			name: "qux",
+			srcs: ["b.java"],
+			instrumentation_for: "bar",
+		}
+		`)
+
+	// Verify baz, which depends on the overridden module foo, has the correct classpath javac arg.
+	javac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+	fooTurbine := filepath.Join(buildDir, ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar")
+	if !strings.Contains(javac.Args["classpath"], fooTurbine) {
+		t.Errorf("baz classpath %v does not contain %q", javac.Args["classpath"], fooTurbine)
+	}
+
+	// Verify qux, which depends on the overriding module bar, has the correct classpath javac arg.
+	javac = ctx.ModuleForTests("qux", "android_common").Rule("javac")
+	barTurbine := filepath.Join(buildDir, ".intermediates", "foo", "android_common_bar", "turbine-combined", "foo.jar")
+	if !strings.Contains(javac.Args["classpath"], barTurbine) {
+		t.Errorf("qux classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
+	}
+}
+
+func TestAndroidAppImport(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+
+	// Check cert signing flag.
+	signedApk := variant.Output("signed/foo.apk")
+	signingFlag := signedApk.Args["certificates"]
+	expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
+	if expected != signingFlag {
+		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+	}
+}
+
+func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			dex_preopt: {
+				enabled: false,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs. They shouldn't exist.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
+		t.Errorf("dexpreopt shouldn't have run.")
+	}
+}
+
+func TestAndroidAppImport_Presigned(t *testing.T) {
+	ctx := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			presigned: true,
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+	// Make sure stripping wasn't done.
+	stripRule := variant.Output("dexpreopt/foo.apk")
+	if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
+		t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
+	}
+
+	// Make sure signing was skipped and aligning was done instead.
+	if variant.MaybeOutput("signed/foo.apk").Rule != nil {
+		t.Errorf("signing rule shouldn't be included.")
+	}
+	if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
+		t.Errorf("can't find aligning rule")
+	}
+}
+
+func TestAndroidAppImport_DpiVariants(t *testing.T) {
+	bp := `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			dpi_variants: {
+				xhdpi: {
+					apk: "prebuilts/apk/app_xhdpi.apk",
+				},
+				xxhdpi: {
+					apk: "prebuilts/apk/app_xxhdpi.apk",
+				},
+			},
+			certificate: "PRESIGNED",
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`
+	testCases := []struct {
+		name                string
+		aaptPreferredConfig *string
+		aaptPrebuiltDPI     []string
+		expected            string
+	}{
+		{
+			name:                "no preferred",
+			aaptPreferredConfig: nil,
+			aaptPrebuiltDPI:     []string{},
+			expected:            "prebuilts/apk/app.apk",
+		},
+		{
+			name:                "AAPTPreferredConfig matches",
+			aaptPreferredConfig: proptools.StringPtr("xhdpi"),
+			aaptPrebuiltDPI:     []string{"xxhdpi", "lhdpi"},
+			expected:            "prebuilts/apk/app_xhdpi.apk",
+		},
+		{
+			name:                "AAPTPrebuiltDPI matches",
+			aaptPreferredConfig: proptools.StringPtr("mdpi"),
+			aaptPrebuiltDPI:     []string{"xxhdpi", "xhdpi"},
+			expected:            "prebuilts/apk/app_xxhdpi.apk",
+		},
+		{
+			name:                "non-first AAPTPrebuiltDPI matches",
+			aaptPreferredConfig: proptools.StringPtr("mdpi"),
+			aaptPrebuiltDPI:     []string{"ldpi", "xhdpi"},
+			expected:            "prebuilts/apk/app_xhdpi.apk",
+		},
+		{
+			name:                "no matches",
+			aaptPreferredConfig: proptools.StringPtr("mdpi"),
+			aaptPrebuiltDPI:     []string{"ldpi", "xxxhdpi"},
+			expected:            "prebuilts/apk/app.apk",
+		},
+	}
+
+	jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)")
+	for _, test := range testCases {
+		config := testConfig(nil)
+		config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig
+		config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
+		ctx := testAppContext(config, bp, nil)
+
+		run(t, ctx, config)
+
+		variant := ctx.ModuleForTests("foo", "android_common")
+		jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
+		matches := jniRuleRe.FindStringSubmatch(jniRuleCommand)
+		if len(matches) != 2 {
+			t.Errorf("failed to extract the src apk path from %q", jniRuleCommand)
+		}
+		if test.expected != matches[1] {
+			t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
+		}
+	}
+}
+
+func TestStl(t *testing.T) {
+	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+		cc_library {
+			name: "libjni",
+		}
+
+		android_test {
+			name: "stl",
+			jni_libs: ["libjni"],
+			compile_multilib: "both",
+			sdk_version: "current",
+			stl: "c++_shared",
+		}
+
+		android_test {
+			name: "system",
+			jni_libs: ["libjni"],
+			compile_multilib: "both",
+			sdk_version: "current",
+		}
+
+		ndk_prebuilt_shared_stl {
+			name: "ndk_libc++_shared",
+		}
+		`)
+
+	testCases := []struct {
+		name string
+		jnis []string
+	}{
+		{"stl",
+			[]string{
+				"libjni.so",
+				"libc++_shared.so",
+			},
+		},
+		{"system",
+			[]string{
+				"libjni.so",
+			},
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			app := ctx.ModuleForTests(test.name, "android_common")
+			jniLibZip := app.Output("jnilibs.zip")
+			var jnis []string
+			args := strings.Fields(jniLibZip.Args["jarArgs"])
+			for i := 0; i < len(args); i++ {
+				if args[i] == "-f" {
+					jnis = append(jnis, args[i+1])
+					i += 1
+				}
+			}
+			jnisJoined := strings.Join(jnis, " ")
+			for _, jni := range test.jnis {
+				if !strings.Contains(jnisJoined, jni) {
+					t.Errorf("missing jni %q in %q", jni, jnis)
+				}
+			}
+		})
+	}
+}
+
+func TestUsesLibraries(t *testing.T) {
+	bp := `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			api_packages: ["foo"],
+		}
+
+		java_sdk_library {
+			name: "bar",
+			srcs: ["a.java"],
+			api_packages: ["bar"],
+		}
+
+		android_app {
+			name: "app",
+			srcs: ["a.java"],
+			uses_libs: ["foo"],
+			optional_uses_libs: [
+				"bar",
+				"baz",
+			],
+		}
+
+		android_app_import {
+			name: "prebuilt",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			uses_libs: ["foo"],
+			optional_uses_libs: [
+				"bar",
+				"baz",
+			],
+		}
+	`
+
+	config := testConfig(nil)
+	config.TestProductVariables.MissingUsesLibraries = []string{"baz"}
+
+	ctx := testAppContext(config, bp, nil)
+
+	run(t, ctx, config)
+
+	app := ctx.ModuleForTests("app", "android_common")
+	prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
+
+	// Test that all libraries are verified
+	cmd := app.Rule("verify_uses_libraries").RuleParams.Command
+	if w := "--uses-library foo"; !strings.Contains(cmd, w) {
+		t.Errorf("wanted %q in %q", w, cmd)
+	}
+
+	if w := "--optional-uses-library bar --optional-uses-library baz"; !strings.Contains(cmd, w) {
+		t.Errorf("wanted %q in %q", w, cmd)
+	}
+
+	cmd = prebuilt.Rule("verify_uses_libraries").RuleParams.Command
+
+	if w := `uses_library_names="foo"`; !strings.Contains(cmd, w) {
+		t.Errorf("wanted %q in %q", w, cmd)
+	}
+
+	if w := `optional_uses_library_names="bar baz"`; !strings.Contains(cmd, w) {
+		t.Errorf("wanted %q in %q", w, cmd)
+	}
+
+	// Test that only present libraries are preopted
+	cmd = app.Rule("dexpreopt").RuleParams.Command
+
+	if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) {
+		t.Errorf("wanted %q in %q", w, cmd)
+	}
+
+	cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
+
+	if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) {
+		t.Errorf("wanted %q in %q", w, cmd)
+	}
+}
+
+func TestCodelessApp(t *testing.T) {
+	testCases := []struct {
+		name   string
+		bp     string
+		noCode bool
+	}{
+		{
+			name: "normal",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+				}
+			`,
+			noCode: false,
+		},
+		{
+			name: "app without sources",
+			bp: `
+				android_app {
+					name: "foo",
+				}
+			`,
+			noCode: true,
+		},
+		{
+			name: "app with libraries",
+			bp: `
+				android_app {
+					name: "foo",
+					static_libs: ["lib"],
+				}
+
+				java_library {
+					name: "lib",
+					srcs: ["a.java"],
+				}
+			`,
+			noCode: false,
+		},
+		{
+			name: "app with sourceless libraries",
+			bp: `
+				android_app {
+					name: "foo",
+					static_libs: ["lib"],
+				}
+
+				java_library {
+					name: "lib",
+				}
+			`,
+			// TODO(jungjw): this should probably be true
+			noCode: false,
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			ctx := testApp(t, test.bp)
+
+			foo := ctx.ModuleForTests("foo", "android_common")
+			manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+			if strings.Contains(manifestFixerArgs, "--has-no-code") != test.noCode {
+				t.Errorf("unexpected manifest_fixer args: %q", manifestFixerArgs)
+			}
+		})
+	}
+}
+
 func TestEmbedNotice(t *testing.T) {
 	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		android_app {
@@ -1053,16 +1479,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)
 	}
 }
 
diff --git a/java/builder.go b/java/builder.go
index d257d1d..a48e8b1 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -43,7 +43,8 @@
 			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
 				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
-				`${config.SoongJavacWrapper} ${config.JavacWrapper}${config.JavacCmd} ${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
+				`${config.SoongJavacWrapper} ${config.JavacWrapper}${config.JavacCmd} ` +
+				`${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
 				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
 				`-source $javaVersion -target $javaVersion ` +
 				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
@@ -64,7 +65,7 @@
 	turbine = pctx.AndroidStaticRule("turbine",
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-				`${config.JavaCmd} -jar ${config.TurbineJar} --output $out.tmp ` +
+				`${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` +
 				`--temp_dir "$outDir" --sources @$out.rsp  --source_jars $srcJars ` +
 				`--javacopts ${config.CommonJdkFlags} ` +
 				`$javacFlags -source $javaVersion -target $javaVersion -- $bootClasspath $classpath && ` +
@@ -108,7 +109,7 @@
 
 	jarjar = pctx.AndroidStaticRule("jarjar",
 		blueprint.RuleParams{
-			Command:     "${config.JavaCmd} -jar ${config.JarjarCmd} process $rulesFile $in $out",
+			Command:     "${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JarjarCmd} process $rulesFile $in $out",
 			CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
 		},
 		"rulesFile")
@@ -124,7 +125,7 @@
 
 	jetifier = pctx.AndroidStaticRule("jetifier",
 		blueprint.RuleParams{
-			Command:     "${config.JavaCmd} -jar ${config.JetifierJar} -l error -o $out -i $in",
+			Command:     "${config.JavaCmd}  ${config.JavaVmFlags} -jar ${config.JetifierJar} -l error -o $out -i $in",
 			CommandDeps: []string{"${config.JavaCmd}", "${config.JetifierJar}"},
 		},
 	)
@@ -147,15 +148,16 @@
 }
 
 type javaBuilderFlags struct {
-	javacFlags    string
-	bootClasspath classpath
-	classpath     classpath
-	processorPath classpath
-	processor     string
-	systemModules classpath
-	aidlFlags     string
-	aidlDeps      android.Paths
-	javaVersion   string
+	javacFlags        string
+	bootClasspath     classpath
+	classpath         classpath
+	processorPath     classpath
+	processor         string
+	systemModules     classpath
+	systemModulesDeps android.Paths
+	aidlFlags         string
+	aidlDeps          android.Paths
+	javaVersion       string
 
 	errorProneExtraJavacFlags string
 	errorProneProcessorPath   classpath
@@ -247,7 +249,7 @@
 
 	var bootClasspath string
 	if flags.javaVersion == "1.9" {
-		deps = append(deps, flags.systemModules...)
+		deps = append(deps, flags.systemModulesDeps...)
 		bootClasspath = flags.systemModules.FormJavaSystemModulesPath("--system=", ctx.Device())
 	} else {
 		deps = append(deps, flags.bootClasspath...)
@@ -429,7 +431,7 @@
 	if len(*x) > 1 {
 		panic("more than one system module")
 	} else if len(*x) == 1 {
-		return optName + strings.TrimSuffix((*x)[0].String(), "lib/modules")
+		return optName + (*x)[0].String()
 	} else if forceEmpty {
 		return optName + "none"
 	} else {
diff --git a/java/config/config.go b/java/config/config.go
index 7f968bc..b72e89d 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -70,6 +70,8 @@
 		// 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.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 
@@ -143,7 +145,8 @@
 
 	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
 
-	pctx.SourcePathVariable("ManifestFixerCmd", "build/soong/scripts/manifest_fixer.py")
+	pctx.HostBinToolVariable("ManifestCheckCmd", "manifest_check")
+	pctx.HostBinToolVariable("ManifestFixerCmd", "manifest_fixer")
 
 	pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
 
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index 2af7b3c..fd8e3db 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -27,7 +27,12 @@
 func init() {
 	pctx.SourcePathVariable("KotlincCmd", "external/kotlinc/bin/kotlinc")
 	pctx.SourcePathVariable("KotlinCompilerJar", "external/kotlinc/lib/kotlin-compiler.jar")
+	pctx.SourcePathVariable("KotlinPreloaderJar", "external/kotlinc/lib/kotlin-preloader.jar")
+	pctx.SourcePathVariable("KotlinReflectJar", "external/kotlinc/lib/kotlin-reflect.jar")
+	pctx.SourcePathVariable("KotlinScriptRuntimeJar", "external/kotlinc/lib/kotlin-script-runtime.jar")
+	pctx.SourcePathVariable("KotlinTrove4jJar", "external/kotlinc/lib/trove4j.jar")
 	pctx.SourcePathVariable("KotlinKaptJar", "external/kotlinc/lib/kotlin-annotation-processing.jar")
+	pctx.SourcePathVariable("KotlinAnnotationJar", "external/kotlinc/lib/annotations-13.0.jar")
 	pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar)
 
 	// These flags silence "Illegal reflective access" warnings when running kotlinc in OpenJDK9
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 6881caf..ead298a 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -39,8 +39,8 @@
 	ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
 	ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
 	ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
-	ctx.Strict("JAVA", "${JavaCmd}")
-	ctx.Strict("JAVAC", "${JavacCmd}")
+	ctx.Strict("JAVA", "${JavaCmd} ${JavaVmFlags}")
+	ctx.Strict("JAVAC", "${JavacCmd} ${JavacVmFlags}")
 	ctx.Strict("JAR", "${JarCmd}")
 	ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
 	ctx.Strict("JAVADOC", "${JavadocCmd}")
@@ -58,8 +58,8 @@
 		ctx.Strict("ERROR_PRONE_CHECKS", "${ErrorProneChecks}")
 	}
 
-	ctx.Strict("TARGET_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
-	ctx.Strict("HOST_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
+	ctx.Strict("TARGET_JAVAC", "${JavacCmd}  ${JavacVmFlags} ${CommonJdkFlags}")
+	ctx.Strict("HOST_JAVAC", "${JavacCmd}  ${JavacVmFlags} ${CommonJdkFlags}")
 
 	ctx.Strict("JLINK", "${JlinkCmd}")
 	ctx.Strict("JMOD", "${JmodCmd}")
@@ -73,6 +73,7 @@
 
 	ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
 
+	ctx.Strict("MANIFEST_CHECK", "${ManifestCheckCmd}")
 	ctx.Strict("MANIFEST_FIXER", "${ManifestFixerCmd}")
 
 	ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}")
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9f40a6c..030b010 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -15,9 +15,12 @@
 package java
 
 import (
-	"android/soong/android"
+	"fmt"
+	"io"
 
 	"github.com/google/blueprint"
+
+	"android/soong/android"
 )
 
 type DeviceHostConverter struct {
@@ -30,6 +33,12 @@
 	implementationJars            android.Paths
 	implementationAndResourceJars android.Paths
 	resourceJars                  android.Paths
+
+	srcJarArgs []string
+	srcJarDeps android.Paths
+
+	combinedHeaderJar         android.Path
+	combinedImplementationJar android.Path
 }
 
 type DeviceHostConverterProperties struct {
@@ -44,7 +53,7 @@
 // java_device_for_host makes the classes.jar output of a device java_library module available to host
 // java_library modules.
 //
-// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
 func DeviceForHostFactory() android.Module {
 	module := &DeviceForHost{}
 
@@ -61,7 +70,7 @@
 // java_host_for_device makes the classes.jar output of a host java_library module available to device
 // java_library modules.
 //
-// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
 func HostForDeviceFactory() android.Module {
 	module := &HostForDevice{}
 
@@ -94,10 +103,35 @@
 			d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
 			d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
 			d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+
+			srcJarArgs, srcJarDeps := dep.SrcJarArgs()
+			d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...)
+			d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...)
 		} else {
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
 	})
+
+	jarName := ctx.ModuleName() + ".jar"
+
+	if len(d.implementationAndResourceJars) > 1 {
+		outputFile := android.PathForModuleOut(ctx, "combined", jarName)
+		TransformJarsToJar(ctx, outputFile, "combine", d.implementationAndResourceJars,
+			android.OptionalPath{}, false, nil, nil)
+		d.combinedImplementationJar = outputFile
+	} else {
+		d.combinedImplementationJar = d.implementationAndResourceJars[0]
+	}
+
+	if len(d.headerJars) > 1 {
+		outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		TransformJarsToJar(ctx, outputFile, "turbine combine", d.headerJars,
+			android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"})
+		d.combinedHeaderJar = outputFile
+	} else {
+		d.combinedHeaderJar = d.headerJars[0]
+	}
+
 }
 
 var _ Dependency = (*DeviceHostConverter)(nil)
@@ -129,3 +163,22 @@
 func (d *DeviceHostConverter) ExportedSdkLibs() []string {
 	return nil
 }
+
+func (d *DeviceHostConverter) SrcJarArgs() ([]string, android.Paths) {
+	return d.srcJarArgs, d.srcJarDeps
+}
+
+func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "JAVA_LIBRARIES",
+		OutputFile: android.OptionalPathForPath(d.combinedImplementationJar),
+		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", d.combinedHeaderJar.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", d.combinedImplementationJar.String())
+			},
+		},
+	}
+}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 146bf6f..9b9d0d8 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -126,7 +126,7 @@
 
 		java_library {
 			name: "device_module",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			srcs: ["b.java"],
 			java_resources: ["java-res/b/b"],
 			static_libs: ["host_for_device_module"],
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 9141f9e..ed12fe6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -22,11 +22,18 @@
 type dexpreopter struct {
 	dexpreoptProperties DexpreoptProperties
 
-	installPath     android.OutputPath
-	uncompressedDex bool
-	isSDKLibrary    bool
-	isTest          bool
-	isInstallable   bool
+	installPath         android.OutputPath
+	uncompressedDex     bool
+	isSDKLibrary        bool
+	isTest              bool
+	isInstallable       bool
+	isPresignedPrebuilt bool
+
+	manifestFile     android.Path
+	usesLibs         []string
+	optionalUsesLibs []string
+	enforceUsesLibs  bool
+	libraryPaths     map[string]android.Path
 
 	builtInstalled string
 }
@@ -51,7 +58,7 @@
 		// If set, provides the path to profile relative to the Android.bp file.  If not set,
 		// defaults to searching for a file that matches the name of this module in the default
 		// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
-		Profile *string
+		Profile *string `android:"path"`
 	}
 }
 
@@ -110,7 +117,9 @@
 	if len(archs) == 0 {
 		// assume this is a java library, dexpreopt for all arches for now
 		for _, target := range ctx.Config().Targets[android.Android] {
-			archs = append(archs, target.Arch.ArchType)
+			if target.NativeBridge == android.NativeBridgeDisabled {
+				archs = append(archs, target.Arch.ArchType)
+			}
 		}
 		if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary {
 			// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
@@ -123,8 +132,10 @@
 	}
 
 	var images android.Paths
+	var imagesDeps []android.Paths
 	for _, arch := range archs {
 		images = append(images, bootImage.images[arch])
+		imagesDeps = append(imagesDeps, bootImage.imagesDeps[arch])
 	}
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
@@ -151,6 +162,7 @@
 		DexLocation:     dexLocation,
 		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
 		DexPath:         dexJarFile,
+		ManifestPath:    d.manifestFile,
 		UncompressedDex: d.uncompressedDex,
 		HasApkLibraries: false,
 		PreoptFlags:     nil,
@@ -158,13 +170,14 @@
 		ProfileClassListing:  profileClassListing,
 		ProfileIsTextListing: profileIsTextListing,
 
-		EnforceUsesLibraries:  false,
-		OptionalUsesLibraries: nil,
-		UsesLibraries:         nil,
-		LibraryPaths:          nil,
+		EnforceUsesLibraries:         d.enforceUsesLibs,
+		PresentOptionalUsesLibraries: d.optionalUsesLibs,
+		UsesLibraries:                d.usesLibs,
+		LibraryPaths:                 d.libraryPaths,
 
-		Archs:           archs,
-		DexPreoptImages: images,
+		Archs:               archs,
+		DexPreoptImages:     images,
+		DexPreoptImagesDeps: imagesDeps,
 
 		// We use the dex paths and dex locations of the default boot image, as it
 		// contains the full dexpreopt boot classpath. Other images may just contain a subset of
@@ -177,6 +190,8 @@
 		NoCreateAppImage:    !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
 		ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
 
+		PresignedPrebuilt: d.isPresignedPrebuilt,
+
 		NoStripping:     Bool(d.dexpreoptProperties.Dex_preopt.No_stripping),
 		StripInputPath:  dexJarFile,
 		StripOutputPath: strippedDexJarFile.OutputPath,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 4d87b2f..fe468a9 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -56,7 +56,32 @@
 	dexPaths     android.WritablePaths
 	dir          android.OutputPath
 	symbolsDir   android.OutputPath
+	targets      []android.Target
 	images       map[android.ArchType]android.OutputPath
+	imagesDeps   map[android.ArchType]android.Paths
+	zip          android.WritablePath
+}
+
+func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) []android.OutputPath {
+	ret := make([]android.OutputPath, 0, len(image.modules)*len(exts))
+
+	// dex preopt on the bootclasspath produces multiple files.  The first dex file
+	// is converted into to 'name'.art (to match the legacy assumption that 'name'.art
+	// exists), and the rest are converted to 'name'-<jar>.art.
+	// In addition, each .art file has an associated .oat and .vdex file, and an
+	// unstripped .oat file
+	for i, m := range image.modules {
+		name := image.name
+		if i != 0 {
+			name += "-" + m
+		}
+
+		for _, ext := range exts {
+			ret = append(ret, dir.Join(ctx, name+ext))
+		}
+	}
+
+	return ret
 }
 
 type bootImage struct {
@@ -113,6 +138,8 @@
 type dexpreoptBootJars struct {
 	defaultBootImage *bootImage
 	otherImages      []*bootImage
+
+	dexpreoptConfigForMake android.WritablePath
 }
 
 // dexpreoptBoot singleton rules
@@ -121,6 +148,9 @@
 		return
 	}
 
+	d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
+	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
+
 	global := dexpreoptGlobalConfig(ctx)
 
 	// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
@@ -187,22 +217,31 @@
 
 	profile := bootImageProfileRule(ctx, image, missingDeps)
 
-	if !global.DisablePreopt {
-		targets := ctx.Config().Targets[android.Android]
-		if ctx.Config().SecondArchIsTranslated() {
-			targets = targets[:1]
-		}
+	var allFiles android.Paths
 
-		for _, target := range targets {
-			buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+	if !global.DisablePreopt {
+		for _, target := range image.targets {
+			files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+			allFiles = append(allFiles, files.Paths()...)
 		}
 	}
 
+	if image.zip != nil {
+		rule := android.NewRuleBuilder()
+		rule.Command().
+			Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+			FlagWithOutput("-o ", image.zip).
+			FlagWithArg("-C ", image.dir.String()).
+			FlagWithInputList("-f ", allFiles, " -f ")
+
+		rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image")
+	}
+
 	return image
 }
 
 func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage,
-	arch android.ArchType, profile android.Path, missingDeps []string) {
+	arch android.ArchType, profile android.Path, missingDeps []string) android.WritablePaths {
 
 	global := dexpreoptGlobalConfig(ctx)
 
@@ -247,8 +286,6 @@
 	if profile != nil {
 		cmd.FlagWithArg("--compiler-filter=", "speed-profile")
 		cmd.FlagWithInput("--profile-file=", profile)
-	} else if global.PreloadedClasses.Valid() {
-		cmd.FlagWithInput("--image-classes=", global.PreloadedClasses.Path())
 	}
 
 	if global.DirtyImageObjects.Valid() {
@@ -286,51 +323,46 @@
 	installDir := filepath.Join("/system/framework", arch.String())
 	vdexInstallDir := filepath.Join("/system/framework")
 
-	var extraFiles android.WritablePaths
 	var vdexInstalls android.RuleBuilderInstalls
 	var unstrippedInstalls android.RuleBuilderInstalls
 
-	// dex preopt on the bootclasspath produces multiple files.  The first dex file
-	// is converted into to 'name'.art (to match the legacy assumption that 'name'.art
-	// exists), and the rest are converted to 'name'-<jar>.art.
-	// In addition, each .art file has an associated .oat and .vdex file, and an
-	// unstripped .oat file
-	for i, m := range image.modules {
-		name := image.name
-		if i != 0 {
-			name += "-" + m
-		}
+	var zipFiles android.WritablePaths
 
-		art := outputDir.Join(ctx, name+".art")
-		oat := outputDir.Join(ctx, name+".oat")
-		vdex := outputDir.Join(ctx, name+".vdex")
-		unstrippedOat := symbolsDir.Join(ctx, name+".oat")
+	for _, artOrOat := range image.moduleFiles(ctx, outputDir, ".art", ".oat") {
+		cmd.ImplicitOutput(artOrOat)
+		zipFiles = append(zipFiles, artOrOat)
 
-		extraFiles = append(extraFiles, art, oat, vdex, unstrippedOat)
+		// Install the .oat and .art files
+		rule.Install(artOrOat, filepath.Join(installDir, artOrOat.Base()))
+	}
 
-		// Install the .oat and .art files.
-		rule.Install(art, filepath.Join(installDir, art.Base()))
-		rule.Install(oat, filepath.Join(installDir, oat.Base()))
+	for _, vdex := range image.moduleFiles(ctx, outputDir, ".vdex") {
+		cmd.ImplicitOutput(vdex)
+		zipFiles = append(zipFiles, vdex)
 
 		// The vdex files are identical between architectures, install them to a shared location.  The Make rules will
 		// only use the install rules for one architecture, and will create symlinks into the architecture-specific
 		// directories.
 		vdexInstalls = append(vdexInstalls,
 			android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())})
+	}
+
+	for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") {
+		cmd.ImplicitOutput(unstrippedOat)
 
 		// Install the unstripped oat files.  The Make rules will put these in $(TARGET_OUT_UNSTRIPPED)
 		unstrippedInstalls = append(unstrippedInstalls,
 			android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
 	}
 
-	cmd.ImplicitOutputs(extraFiles)
-
 	rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+arch.String(), "dexpreopt "+image.name+" jars "+arch.String())
 
 	// save output and installed files for makevars
 	image.installs[arch] = rule.Installs()
 	image.vdexInstalls[arch] = vdexInstalls
 	image.unstrippedInstalls[arch] = unstrippedInstalls
+
+	return zipFiles
 }
 
 const failureMessage = `ERROR: Dex2oat failed to compile a boot image.
@@ -340,7 +372,7 @@
 func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
 	global := dexpreoptGlobalConfig(ctx)
 
-	if !global.UseProfileForBootImage || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+	if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
 		return nil
 	}
 	return ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
@@ -436,13 +468,30 @@
 
 }
 
+func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
+	data := dexpreoptGlobalConfigRaw(ctx).data
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.WriteFile,
+		Output: path,
+		Args: map[string]string{
+			"content": string(data),
+		},
+	})
+}
+
 // Export paths for default boot image to Make
 func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
+	if d.dexpreoptConfigForMake != nil {
+		ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String())
+	}
+
 	image := d.defaultBootImage
 	if image != nil {
 		ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
 		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPaths.Strings(), " "))
 		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocations, " "))
+		ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+image.name, image.zip.String())
 
 		var imageNames []string
 		for _, current := range append(d.otherImages, image) {
@@ -457,8 +506,11 @@
 			for _, arch := range arches {
 				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.vdexInstalls[arch].String())
 				ctx.Strict("DEXPREOPT_IMAGE_"+current.name+"_"+arch.String(), current.images[arch].String())
+				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+current.name+"_"+arch.String(), strings.Join(current.imagesDeps[arch].Strings(), " "))
 				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.installs[arch].String())
 				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.unstrippedInstalls[arch].String())
+				if current.zip != nil {
+				}
 			}
 		}
 		ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index cbb52f1..f91ff69 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -62,6 +62,7 @@
 	bootArt := dexpreoptBootJars.Output("boot.art")
 
 	expectedInputs := []string{
+		"dex_bootjars/boot.prof",
 		"dex_bootjars_input/foo.jar",
 		"dex_bootjars_input/bar.jar",
 		"dex_bootjars_input/baz.jar",
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index abc5fa1..4a4d6d5 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,40 +15,51 @@
 package java
 
 import (
-	"android/soong/android"
-	"android/soong/dexpreopt"
 	"path/filepath"
 	"strings"
+
+	"android/soong/android"
+	"android/soong/dexpreopt"
 )
 
 // dexpreoptGlobalConfig returns the global dexpreopt.config.  It is loaded once the first time it is called for any
 // ctx.Config(), and returns the same data for all future calls with the same ctx.Config().  A value can be inserted
 // for tests using setDexpreoptTestGlobalConfig.
 func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
+	return dexpreoptGlobalConfigRaw(ctx).global
+}
+
+type globalConfigAndRaw struct {
+	global dexpreopt.GlobalConfig
+	data   []byte
+}
+
+func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
 	return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
 		if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
 			ctx.AddNinjaFileDeps(f)
-			globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, f)
+			globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f)
 			if err != nil {
 				panic(err)
 			}
-			return globalConfig
+			return globalConfigAndRaw{globalConfig, data}
 		}
 
 		// No global config filename set, see if there is a test config set
 		return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} {
 			// Nope, return a config with preopting disabled
-			return dexpreopt.GlobalConfig{
-				DisablePreopt: true,
-			}
+			return globalConfigAndRaw{dexpreopt.GlobalConfig{
+				DisablePreopt:          true,
+				DisableGenerateProfile: true,
+			}, nil}
 		})
-	}).(dexpreopt.GlobalConfig)
+	}).(globalConfigAndRaw)
 }
 
 // setDexpreoptTestGlobalConfig sets a GlobalConfig that future calls to dexpreoptGlobalConfig will return.  It must
 // be called before the first call to dexpreoptGlobalConfig for the config.
 func setDexpreoptTestGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) {
-	config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfig })
+	config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
 }
 
 var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
@@ -72,6 +83,23 @@
 
 var systemServerClasspathKey = android.NewOnceKey("systemServerClasspath")
 
+// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
+// supported through native bridge.
+func dexpreoptTargets(ctx android.PathContext) []android.Target {
+	var targets []android.Target
+	for i, target := range ctx.Config().Targets[android.Android] {
+		if ctx.Config().SecondArchIsTranslated() && i > 0 {
+			break
+		}
+
+		if target.NativeBridge == android.NativeBridgeDisabled {
+			targets = append(targets, target)
+		}
+	}
+
+	return targets
+}
+
 // defaultBootImageConfig returns the bootImageConfig that will be used to dexpreopt modules.  It is computed once the
 // first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
 // ctx.Config().
@@ -110,22 +138,35 @@
 
 		dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars")
 		symbolsDir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars_unstripped")
-		images := make(map[android.ArchType]android.OutputPath)
+		zip := dir.Join(ctx, "boot.zip")
 
-		for _, target := range ctx.Config().Targets[android.Android] {
-			images[target.Arch.ArchType] = dir.Join(ctx,
-				"system/framework", target.Arch.ArchType.String()).Join(ctx, "boot.art")
-		}
+		targets := dexpreoptTargets(ctx)
 
-		return bootImageConfig{
+		imageConfig := bootImageConfig{
 			name:         "boot",
 			modules:      nonUpdatableBootModules,
 			dexLocations: nonUpdatableBootLocations,
 			dexPaths:     nonUpdatableBootDexPaths,
 			dir:          dir,
 			symbolsDir:   symbolsDir,
-			images:       images,
+			images:       make(map[android.ArchType]android.OutputPath),
+			imagesDeps:   make(map[android.ArchType]android.Paths),
+			targets:      targets,
+			zip:          zip,
 		}
+
+		for _, target := range targets {
+			imageDir := dir.Join(ctx, "system/framework", target.Arch.ArchType.String())
+			imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, "boot.art")
+
+			imagesDeps := make([]android.Path, 0, len(imageConfig.modules)*3)
+			for _, dep := range imageConfig.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex") {
+				imagesDeps = append(imagesDeps, dep)
+			}
+			imageConfig.imagesDeps[target.Arch.ArchType] = imagesDeps
+		}
+
+		return imageConfig
 	}).(bootImageConfig)
 }
 
@@ -164,22 +205,33 @@
 
 		dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_apexjars")
 		symbolsDir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_apexjars_unstripped")
-		images := make(map[android.ArchType]android.OutputPath)
 
-		for _, target := range ctx.Config().Targets[android.Android] {
-			images[target.Arch.ArchType] = dir.Join(ctx,
-				"system/framework", target.Arch.ArchType.String(), "apex.art")
-		}
+		targets := dexpreoptTargets(ctx)
 
-		return bootImageConfig{
+		imageConfig := bootImageConfig{
 			name:         "apex",
 			modules:      imageModules,
 			dexLocations: bootLocations,
 			dexPaths:     bootDexPaths,
 			dir:          dir,
 			symbolsDir:   symbolsDir,
-			images:       images,
+			targets:      targets,
+			images:       make(map[android.ArchType]android.OutputPath),
+			imagesDeps:   make(map[android.ArchType]android.Paths),
 		}
+
+		for _, target := range targets {
+			imageDir := dir.Join(ctx, "system/framework", target.Arch.ArchType.String())
+			imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, "apex.art")
+
+			imagesDeps := make([]android.Path, 0, len(imageConfig.modules)*3)
+			for _, dep := range imageConfig.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex") {
+				imagesDeps = append(imagesDeps, dep)
+			}
+			imageConfig.imagesDeps[target.Arch.ArchType] = imagesDeps
+		}
+
+		return imageConfig
 	}).(bootImageConfig)
 }
 
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 4af2f5c..7d0109f 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -52,14 +52,26 @@
 				}`,
 			enabled: true,
 		},
-
 		{
 			name: "app without sources",
 			bp: `
 				android_app {
 					name: "foo",
 				}`,
-			// TODO(ccross): this should probably be false
+			enabled: false,
+		},
+		{
+			name: "app with libraries",
+			bp: `
+				android_app {
+					name: "foo",
+					static_libs: ["lib"],
+				}
+
+				java_library {
+					name: "lib",
+					srcs: ["a.java"],
+				}`,
 			enabled: true,
 		},
 		{
@@ -69,10 +81,8 @@
 					name: "foo",
 					installable: true,
 				}`,
-			// TODO(ccross): this should probably be false
-			enabled: true,
+			enabled: false,
 		},
-
 		{
 			name: "static java library",
 			bp: `
diff --git a/java/droiddoc.go b/java/droiddoc.go
index fd7e2a4..25101de 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -23,6 +23,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 var (
@@ -73,7 +74,7 @@
 			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
 				`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.JavaCmd} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
+				`${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 && ` +
@@ -95,7 +96,7 @@
 		blueprint.RuleParams{
 			Command: `( rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.JavaCmd} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
+				`${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 )`,
@@ -120,7 +121,7 @@
 			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
 				`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-				`${config.JavaCmd} -jar ${config.DokkaJar} $srcJarDir ` +
+				`${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 && ` +
@@ -171,13 +172,6 @@
 	// list of java libraries that will be in the classpath.
 	Libs []string `android:"arch_variant"`
 
-	// don't build against the default libraries (bootclasspath, ext, and framework for device
-	// targets)
-	No_standard_libs *bool
-
-	// don't build against the framework libraries (ext, and framework for device targets)
-	No_framework_libs *bool
-
 	// the java library (in classpath) for documentation that provides java srcs and srcjars.
 	Srcs_lib *string
 
@@ -211,6 +205,7 @@
 	// Available variables for substitution:
 	//
 	//  $(location <label>): the path to the arg_files with name <label>
+	//  $$: a literal $
 	Args *string
 
 	// names of the output files used in args that will be generated
@@ -496,8 +491,13 @@
 	stubsSrcJar android.WritablePath
 }
 
-func (j *Javadoc) Srcs() android.Paths {
-	return android.Paths{j.stubsSrcJar}
+func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{j.stubsSrcJar}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 func JavadocFactory() android.Module {
@@ -518,10 +518,10 @@
 	return module
 }
 
-var _ android.SourceFileProducer = (*Javadoc)(nil)
+var _ android.OutputFileProducer = (*Javadoc)(nil)
 
 func (j *Javadoc) sdkVersion() string {
-	return String(j.properties.Sdk_version)
+	return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
 }
 
 func (j *Javadoc) minSdkVersion() string {
@@ -534,14 +534,14 @@
 
 func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
-		if !Bool(j.properties.No_standard_libs) {
-			sdkDep := decodeSdkDep(ctx, sdkContext(j))
+		sdkDep := decodeSdkDep(ctx, sdkContext(j))
+		if sdkDep.hasStandardLibs() {
 			if sdkDep.useDefaultLibs {
 				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
 				if ctx.Config().TargetOpenJDK9() {
 					ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
 				}
-				if !Bool(j.properties.No_framework_libs) {
+				if sdkDep.hasFrameworkLibs() {
 					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
 				}
 			} else if sdkDep.useModule {
@@ -686,10 +686,11 @@
 				panic("Found two system module dependencies")
 			}
 			sm := module.(*SystemModules)
-			if sm.outputFile == nil {
+			if sm.outputDir == nil && len(sm.outputDeps) == 0 {
 				panic("Missing directory for system module dependency")
 			}
-			deps.systemModules = sm.outputFile
+			deps.systemModules = sm.outputDir
+			deps.systemModulesDeps = sm.outputDeps
 		}
 	})
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -770,6 +771,7 @@
 		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=."
 	}
@@ -1745,7 +1747,7 @@
 		jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar")
 		jdiffImplicits = append(jdiffImplicits, android.Paths{jdiff, d.apiXmlFile, d.lastReleasedApiXmlFile}...)
 
-		opts := " -encoding UTF-8 -source 1.8 -J-Xmx1600m -XDignore.symbol.file " +
+		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()) +
@@ -1802,9 +1804,6 @@
 	android.DefaultsModuleBase
 }
 
-func (*DocDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-}
-
 func DocDefaultsFactory() android.Module {
 	module := &DocDefaults{}
 
diff --git a/java/gen.go b/java/gen.go
index 0977628..b1c028d 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -23,8 +23,9 @@
 func init() {
 	pctx.HostBinToolVariable("aidlCmd", "aidl")
 	pctx.HostBinToolVariable("syspropCmd", "sysprop_java")
-	pctx.SourcePathVariable("logtagsCmd", "build/tools/java-event-log-tags.py")
-	pctx.SourcePathVariable("mergeLogtagsCmd", "build/tools/merge-event-log-tags.py")
+	pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py")
+	pctx.SourcePathVariable("mergeLogtagsCmd", "build/make/tools/merge-event-log-tags.py")
+	pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py")
 }
 
 var (
@@ -38,13 +39,13 @@
 	logtags = pctx.AndroidStaticRule("logtags",
 		blueprint.RuleParams{
 			Command:     "$logtagsCmd -o $out $in",
-			CommandDeps: []string{"$logtagsCmd"},
+			CommandDeps: []string{"$logtagsCmd", "$logtagsLib"},
 		})
 
 	mergeLogtags = pctx.AndroidStaticRule("mergeLogtags",
 		blueprint.RuleParams{
 			Command:     "$mergeLogtagsCmd -o $out $in",
-			CommandDeps: []string{"$mergeLogtagsCmd"},
+			CommandDeps: []string{"$mergeLogtagsCmd", "$logtagsLib"},
 		})
 
 	sysprop = pctx.AndroidStaticRule("sysprop",
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index b1ddab4..cf9f492 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -15,11 +15,14 @@
 package java
 
 import (
+	"fmt"
+
 	"android/soong/android"
 )
 
 func init() {
 	android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
 }
 
 type hiddenAPISingletonPathsStruct struct {
@@ -307,3 +310,48 @@
 		Text("fi").
 		Text(")")
 }
+
+type hiddenAPIFlagsProperties struct {
+	// name of the file into which the flags will be copied.
+	Filename *string
+}
+
+type hiddenAPIFlags struct {
+	android.ModuleBase
+
+	properties hiddenAPIFlagsProperties
+
+	outputFilePath android.OutputPath
+}
+
+func (h *hiddenAPIFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	filename := String(h.properties.Filename)
+
+	inputPath := hiddenAPISingletonPaths(ctx).flags
+	h.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Output: h.outputFilePath,
+		Input:  inputPath,
+	})
+}
+
+func (h *hiddenAPIFlags) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{h.outputFilePath}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
+// hiddenapi-flags provides access to the hiddenapi-flags.csv file generated during the build.
+func hiddenAPIFlagsFactory() android.Module {
+	module := &hiddenAPIFlags{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	return module
+}
diff --git a/java/jacoco.go b/java/jacoco.go
index 8b6d4ac..bce9822 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -31,7 +31,7 @@
 	jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{
 		Command: `rm -rf $tmpDir && mkdir -p $tmpDir && ` +
 			`${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
-			`${config.JavaCmd} -jar ${config.JacocoCLIJar} ` +
+			`${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JacocoCLIJar} ` +
 			`  instrument --quiet --dest $tmpDir $strippedJar && ` +
 			`${config.Ziptime} $tmpJar && ` +
 			`${config.MergeZipsCmd} --ignore-duplicates -j $out $tmpJar $in`,
diff --git a/java/java.go b/java/java.go
index ff6bbac..7c84e76 100644
--- a/java/java.go
+++ b/java/java.go
@@ -82,13 +82,6 @@
 	// list of files that should be excluded from java_resources and java_resource_dirs
 	Exclude_java_resources []string `android:"path,arch_variant"`
 
-	// don't build against the default libraries (bootclasspath, ext, and framework for device
-	// targets)
-	No_standard_libs *bool
-
-	// don't build against the framework libraries (ext, and framework for device targets)
-	No_framework_libs *bool
-
 	// list of module-specific flags that will be used for javac compiles
 	Javacflags []string `android:"arch_variant"`
 
@@ -290,6 +283,10 @@
 	// jar file containing only resources including from static library dependencies
 	resourceJar android.Path
 
+	// args and dependencies to package source files into a srcjar
+	srcJarArgs []string
+	srcJarDeps android.Paths
+
 	// jar file containing implementation classes and resources including static library
 	// dependencies
 	implementationAndResourcesJar android.Path
@@ -340,19 +337,29 @@
 	// list of additional targets for checkbuild
 	additionalCheckedModules android.Paths
 
+	// Extra files generated by the module type to be added as java resources.
+	extraResources android.Paths
+
 	hiddenAPI
 	dexpreopter
 }
 
-func (j *Module) Srcs() android.Paths {
-	return append(android.Paths{j.outputFile}, j.extraOutputFiles...)
+func (j *Module) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return append(android.Paths{j.outputFile}, j.extraOutputFiles...), nil
+	case ".jar":
+		return android.Paths{j.implementationAndResourcesJar}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 func (j *Module) DexJarFile() android.Path {
 	return j.dexJarFile
 }
 
-var _ android.SourceFileProducer = (*Module)(nil)
+var _ android.OutputFileProducer = (*Module)(nil)
 
 type Dependency interface {
 	HeaderJars() android.Paths
@@ -362,11 +369,12 @@
 	DexJar() android.Path
 	AidlIncludeDirs() android.Paths
 	ExportedSdkLibs() []string
+	SrcJarArgs() ([]string, android.Paths)
 }
 
 type SdkLibraryDependency interface {
-	SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths
-	SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths
+	SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths
+	SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths
 }
 
 type SrcDependency interface {
@@ -412,8 +420,21 @@
 	proguardRaiseTag      = dependencyTag{name: "proguard-raise"}
 	certificateTag        = dependencyTag{name: "certificate"}
 	instrumentationForTag = dependencyTag{name: "instrumentation_for"}
+	usesLibTag            = dependencyTag{name: "uses-library"}
 )
 
+func defaultSdkVersion(ctx checkVendorModuleContext) string {
+	if ctx.SocSpecific() || ctx.DeviceSpecific() {
+		return "system_current"
+	}
+	return ""
+}
+
+type checkVendorModuleContext interface {
+	SocSpecific() bool
+	DeviceSpecific() bool
+}
+
 type sdkDep struct {
 	useModule, useFiles, useDefaultLibs, invalidVersion bool
 
@@ -424,6 +445,16 @@
 
 	jars android.Paths
 	aidl android.OptionalPath
+
+	noStandardLibs, noFrameworksLibs bool
+}
+
+func (s sdkDep) hasStandardLibs() bool {
+	return !s.noStandardLibs
+}
+
+func (s sdkDep) hasFrameworkLibs() bool {
+	return !s.noStandardLibs && !s.noFrameworksLibs
 }
 
 type jniLib struct {
@@ -432,18 +463,18 @@
 	target android.Target
 }
 
-func (j *Module) shouldInstrument(ctx android.BaseContext) bool {
+func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
 	return j.properties.Instrument && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
 }
 
-func (j *Module) shouldInstrumentStatic(ctx android.BaseContext) bool {
+func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
 	return j.shouldInstrument(ctx) &&
 		(ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_STATIC") ||
 			ctx.Config().UnbundledBuild())
 }
 
 func (j *Module) sdkVersion() string {
-	return String(j.deviceProperties.Sdk_version)
+	return proptools.StringDefault(j.deviceProperties.Sdk_version, defaultSdkVersion(j))
 }
 
 func (j *Module) minSdkVersion() string {
@@ -462,12 +493,12 @@
 
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
-		if !Bool(j.properties.No_standard_libs) {
-			sdkDep := decodeSdkDep(ctx, sdkContext(j))
+		sdkDep := decodeSdkDep(ctx, sdkContext(j))
+		if sdkDep.hasStandardLibs() {
 			if sdkDep.useDefaultLibs {
 				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
 				ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
-				if !Bool(j.properties.No_framework_libs) {
+				if sdkDep.hasFrameworkLibs() {
 					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
 				}
 			} else if sdkDep.useModule {
@@ -479,8 +510,8 @@
 				}
 			}
 		} else if j.deviceProperties.System_modules == nil {
-			ctx.PropertyErrorf("no_standard_libs",
-				"system_modules is required to be set when no_standard_libs is true, did you mean no_framework_libs?")
+			ctx.PropertyErrorf("sdk_version",
+				`system_modules is required to be set when sdk_version is "none", did you mean "core_platform"`)
 		} else if *j.deviceProperties.System_modules != "none" {
 			ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules)
 		}
@@ -509,7 +540,8 @@
 	if j.hasSrcExt(".kt") {
 		// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
 		// Kotlin files
-		ctx.AddVariationDependencies(nil, kotlinStdlibTag, "kotlin-stdlib")
+		ctx.AddVariationDependencies(nil, kotlinStdlibTag,
+			"kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
 		if len(j.properties.Plugins) > 0 {
 			ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
 		}
@@ -601,6 +633,7 @@
 	srcs               android.Paths
 	srcJars            android.Paths
 	systemModules      android.Path
+	systemModulesDeps  android.Paths
 	aidlPreprocess     android.OptionalPath
 	kotlinStdlib       android.Paths
 	kotlinAnnotations  android.Paths
@@ -631,7 +664,7 @@
 	switch {
 	case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
 		name == "stub-annotations" || name == "private-stub-annotations-jar" ||
-		name == "core-lambda-stubs":
+		name == "core-lambda-stubs" || name == "core-generated-annotation-stubs":
 		return javaCore, true
 	case ver == "core_current":
 		return javaCore, false
@@ -647,7 +680,7 @@
 		return javaSdk, true
 	case ver == "current":
 		return javaSdk, false
-	case ver == "":
+	case ver == "" || ver == "none" || ver == "core_platform":
 		return javaPlatform, false
 	default:
 		if _, err := strconv.Atoi(ver); err != nil {
@@ -736,7 +769,7 @@
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 				// names of sdk libs that are directly depended are exported
 				j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
-			default:
+			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
 			}
 		case Dependency:
@@ -785,7 +818,7 @@
 					deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage)
 				}
 			case kotlinStdlibTag:
-				deps.kotlinStdlib = dep.HeaderJars()
+				deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...)
 			case kotlinAnnotationsTag:
 				deps.kotlinAnnotations = dep.HeaderJars()
 			}
@@ -803,19 +836,16 @@
 			}
 		default:
 			switch tag {
-			case android.DefaultsDepTag, android.SourceDepTag:
-				// Nothing to do
 			case systemModulesTag:
 				if deps.systemModules != nil {
 					panic("Found two system module dependencies")
 				}
 				sm := module.(*SystemModules)
-				if sm.outputFile == nil {
+				if sm.outputDir == nil || len(sm.outputDeps) == 0 {
 					panic("Missing directory for system module dependency")
 				}
-				deps.systemModules = sm.outputFile
-			default:
-				ctx.ModuleErrorf("depends on non-java module %q", otherName)
+				deps.systemModules = sm.outputDir
+				deps.systemModulesDeps = sm.outputDeps
 			}
 		}
 	})
@@ -829,7 +859,8 @@
 	var ret string
 	v := sdkContext.sdkVersion()
 	// For PDK builds, use the latest SDK version instead of "current"
-	if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
+	if ctx.Config().IsPdkBuild() &&
+		(v == "" || v == "none" || v == "core_platform" || v == "current") {
 		sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
 		latestSdkVersion := 0
 		if len(sdkVersions) > 0 {
@@ -846,9 +877,13 @@
 		ret = javaVersion
 	} else if ctx.Device() && sdk <= 23 {
 		ret = "1.7"
-	} else if ctx.Device() && sdk <= 28 || !ctx.Config().TargetOpenJDK9() {
+	} else if ctx.Device() && sdk <= 29 || !ctx.Config().TargetOpenJDK9() {
 		ret = "1.8"
-	} else if ctx.Device() && sdkContext.sdkVersion() != "" && sdk == android.FutureApiLevel {
+	} else if ctx.Device() &&
+		sdkContext.sdkVersion() != "" &&
+		sdkContext.sdkVersion() != "none" &&
+		sdkContext.sdkVersion() != "core_platform" &&
+		sdk == android.FutureApiLevel {
 		// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
 		ret = "1.8"
 	} else {
@@ -900,7 +935,7 @@
 	flags.processor = strings.Join(deps.processorClasses, ",")
 
 	if len(flags.bootClasspath) == 0 && ctx.Host() && flags.javaVersion != "1.9" &&
-		!Bool(j.properties.No_standard_libs) &&
+		decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() &&
 		inList(flags.javaVersion, []string{"1.6", "1.7", "1.8"}) {
 		// Give host-side tools a version of OpenJDK's standard libraries
 		// close to what they're targeting. As of Dec 2017, AOSP is only
@@ -940,6 +975,7 @@
 	// systemModules
 	if deps.systemModules != nil {
 		flags.systemModules = append(flags.systemModules, deps.systemModules)
+		flags.systemModulesDeps = append(flags.systemModulesDeps, deps.systemModulesDeps...)
 	}
 
 	// aidl flags.
@@ -954,7 +990,7 @@
 	return flags
 }
 
-func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path) {
+func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
@@ -973,7 +1009,9 @@
 
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
-	srcJars = append(srcJars, extraSrcJars...)
+	if aaptSrcJar != nil {
+		srcJars = append(srcJars, aaptSrcJar)
+	}
 
 	// Collect source files from compiledJavaSrcs, compiledSrcJars and filter out Exclude_srcs
 	// that IDEInfo struct will use
@@ -1110,9 +1148,18 @@
 		}
 	}
 
+	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
+
+	var includeSrcJar android.WritablePath
+	if Bool(j.properties.Include_srcs) {
+		includeSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+".srcjar")
+		TransformResourcesToJar(ctx, includeSrcJar, j.srcJarArgs, j.srcJarDeps)
+	}
+
 	dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
 		j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
 	fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
+	extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
 
 	var resArgs []string
 	var resDeps android.Paths
@@ -1123,11 +1170,8 @@
 	resArgs = append(resArgs, fileArgs...)
 	resDeps = append(resDeps, fileDeps...)
 
-	if Bool(j.properties.Include_srcs) {
-		srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
-		resArgs = append(resArgs, srcArgs...)
-		resDeps = append(resDeps, srcDeps...)
-	}
+	resArgs = append(resArgs, extraArgs...)
+	resDeps = append(resDeps, extraDeps...)
 
 	if len(resArgs) > 0 {
 		resourceJar := android.PathForModuleOut(ctx, "res", jarName)
@@ -1138,20 +1182,27 @@
 		}
 	}
 
-	if len(deps.staticResourceJars) > 0 {
-		var jars android.Paths
-		if j.resourceJar != nil {
-			jars = append(jars, j.resourceJar)
-		}
-		jars = append(jars, deps.staticResourceJars...)
+	var resourceJars android.Paths
+	if j.resourceJar != nil {
+		resourceJars = append(resourceJars, j.resourceJar)
+	}
+	if Bool(j.properties.Include_srcs) {
+		resourceJars = append(resourceJars, includeSrcJar)
+	}
+	resourceJars = append(resourceJars, deps.staticResourceJars...)
 
+	if len(resourceJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
 			false, nil, nil)
 		j.resourceJar = combinedJar
+	} else if len(resourceJars) == 1 {
+		j.resourceJar = resourceJars[0]
 	}
 
-	jars = append(jars, deps.staticJars...)
+	if len(deps.staticJars) > 0 {
+		jars = append(jars, deps.staticJars...)
+	}
 
 	manifest := j.overrideManifest
 	if !manifest.Valid() && j.properties.Manifest != nil {
@@ -1253,16 +1304,17 @@
 	// merge implementation jar with resources if necessary
 	implementationAndResourcesJar := outputFile
 	if j.resourceJar != nil {
-		jars := android.Paths{implementationAndResourcesJar, j.resourceJar}
+		jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
 		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
 			false, nil, nil)
 		implementationAndResourcesJar = combinedJar
 	}
 
 	j.implementationAndResourcesJar = implementationAndResourcesJar
 
-	if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
+	if ctx.Device() && j.hasCode(ctx) &&
+		(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
 		// Dex compilation
 		var dexOutputFile android.ModuleOutPath
 		dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
@@ -1363,7 +1415,7 @@
 	// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
 	combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
 	TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
-		false, nil, []string{"META-INF"})
+		false, nil, []string{"META-INF/TRANSITIVE"})
 	headerJar = combinedJar
 
 	if j.expandJarjarRules != nil {
@@ -1438,6 +1490,10 @@
 	return j.exportedSdkLibs
 }
 
+func (j *Module) SrcJarArgs() ([]string, android.Paths) {
+	return j.srcJarArgs, j.srcJarDeps
+}
+
 var _ logtagsProducer = (*Module)(nil)
 
 func (j *Module) logtags() android.Paths {
@@ -1448,6 +1504,7 @@
 func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, j.CompilerDeps()...)
 	dpInfo.Srcs = append(dpInfo.Srcs, j.expandIDEInfoCompiledSrcs...)
+	dpInfo.SrcJars = append(dpInfo.SrcJars, j.compiledSrcJars.Strings()...)
 	dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
 	if j.expandJarjarRules != nil {
 		dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
@@ -1461,6 +1518,11 @@
 	return jdeps
 }
 
+func (j *Module) hasCode(ctx android.ModuleContext) bool {
+	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+	return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0
+}
+
 //
 // Java libraries (.jar file)
 //
@@ -1493,7 +1555,7 @@
 	j.dexpreopter.isInstallable = Bool(j.properties.Installable)
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
 	j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
-	j.compile(ctx)
+	j.compile(ctx, nil)
 
 	if (Bool(j.properties.Installable) || ctx.Host()) && !android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
@@ -1641,6 +1703,9 @@
 		&module.Module.protoProperties,
 		&module.testHelperLibraryProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+	module.Module.dexpreopter.isTest = true
+
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -1809,7 +1874,7 @@
 }
 
 func (j *Import) sdkVersion() string {
-	return String(j.properties.Sdk_version)
+	return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
 }
 
 func (j *Import) minSdkVersion() string {
@@ -1912,6 +1977,10 @@
 	return j.exportedSdkLibs
 }
 
+func (j *Import) SrcJarArgs() ([]string, android.Paths) {
+	return nil, nil
+}
+
 // Add compile time check for interface implementation
 var _ android.IDEInfo = (*Import)(nil)
 var _ android.IDECustomizedModuleName = (*Import)(nil)
@@ -2085,9 +2154,6 @@
 	android.DefaultsModuleBase
 }
 
-func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-}
-
 // java_defaults provides a set of properties that can be inherited by other java or android modules.
 //
 // A module can use the properties from a java_defaults module using `defaults: ["defaults_module_name"]`.  Each
diff --git a/java/java_resources.go b/java/java_resources.go
index 7161168..787d74a 100644
--- a/java/java_resources.go
+++ b/java/java_resources.go
@@ -85,19 +85,19 @@
 	return resourceFilesToJarArgs(ctx, res, exclude)
 }
 
-// Convert java_resources properties to arguments to soong_zip -jar, keeping files that should
-// normally not used as resources like *.java
-func SourceFilesToJarArgs(ctx android.ModuleContext,
-	res, exclude []string) (args []string, deps android.Paths) {
-
-	return resourceFilesToJarArgs(ctx, res, exclude)
-}
-
 func resourceFilesToJarArgs(ctx android.ModuleContext,
 	res, exclude []string) (args []string, deps android.Paths) {
 
 	files := android.PathsForModuleSrcExcludes(ctx, res, exclude)
 
+	args = resourcePathsToJarArgs(files)
+
+	return args, files
+}
+
+func resourcePathsToJarArgs(files android.Paths) []string {
+	var args []string
+
 	lastDir := ""
 	for i, f := range files {
 		rel := f.Rel()
@@ -113,5 +113,5 @@
 		lastDir = dir
 	}
 
-	return args, files
+	return args
 }
diff --git a/java/java_test.go b/java/java_test.go
index 31b23e7..96ecdb6 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -63,6 +63,7 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
 	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(AndroidAppCertificateFactory))
+	ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(AndroidAppImportFactory))
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
 	ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
@@ -86,16 +87,16 @@
 	ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
 	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory))
 	ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory))
+	ctx.RegisterModuleType("java_sdk_library_import", android.ModuleFactoryAdaptor(sdkLibraryImportFactory))
 	ctx.RegisterModuleType("override_android_app", android.ModuleFactoryAdaptor(OverrideAndroidAppModuleFactory))
 	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory))
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
 	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
-	ctx.PreArchMutators(android.RegisterOverridePreArchMutators)
 	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
-		ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
 	})
+	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
 	ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
 	ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
 
@@ -104,6 +105,7 @@
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+	ctx.RegisterModuleType("ndk_prebuilt_shared_stl", android.ModuleFactoryAdaptor(cc.NdkPrebuiltSharedStlFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
@@ -137,6 +139,8 @@
 		"api/test-removed.txt":   nil,
 		"framework/aidl/a.aidl":  nil,
 
+		"prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so": nil,
+
 		"prebuilts/sdk/14/public/android.jar":         nil,
 		"prebuilts/sdk/14/public/framework.aidl":      nil,
 		"prebuilts/sdk/14/system/android.jar":         nil,
@@ -167,12 +171,18 @@
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":   nil,
 		"prebuilts/sdk/Android.bp":                    []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
 
+		"prebuilts/apk/app.apk":        nil,
+		"prebuilts/apk/app_xhdpi.apk":  nil,
+		"prebuilts/apk/app_xxhdpi.apk": nil,
+
 		// For framework-res, which is an implicit dependency for framework
-		"AndroidManifest.xml":                   nil,
-		"build/target/product/security/testkey": nil,
+		"AndroidManifest.xml":                        nil,
+		"build/make/target/product/security/testkey": nil,
 
 		"build/soong/scripts/jar-wrapper.sh": nil,
 
+		"build/make/core/verify_uses_libraries.sh": nil,
+
 		"build/make/core/proguard.flags":             nil,
 		"build/make/core/proguard_basic_keeps.flags": nil,
 
@@ -206,7 +216,7 @@
 	setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
 
 	ctx.Register()
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
 	android.FailIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
 	android.FailIfErrored(t, errs)
@@ -276,6 +286,32 @@
 	}
 }
 
+func TestSdkVersion(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			vendor: true,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common").Module().(*Library)
+	bar := ctx.ModuleForTests("bar", "android_common").Module().(*Library)
+
+	if foo.sdkVersion() != "system_current" {
+		t.Errorf("If sdk version of vendor module is empty, it must change to system_current.")
+	}
+
+	if bar.sdkVersion() != "" {
+		t.Errorf("If sdk version of non-vendor module is empty, it keeps empty.")
+	}
+}
+
 func TestArchSpecific(t *testing.T) {
 	ctx := testJava(t, `
 		java_library {
@@ -329,7 +365,7 @@
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
-			libs: ["bar"],
+			libs: ["bar", "sdklib"],
 			static_libs: ["baz"],
 		}
 
@@ -347,17 +383,27 @@
 			name: "qux",
 			jars: ["b.jar"],
 		}
+
+		java_sdk_library_import {
+			name: "sdklib",
+			jars: ["b.jar"],
+		}
 		`)
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
 	barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output
 	bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output
+	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
 
 	if !strings.Contains(javac.Args["classpath"], barJar.String()) {
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
 	}
 
+	if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
+	}
+
 	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != bazJar.String() {
 		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
 	}
@@ -473,12 +519,6 @@
 			args: "-C java-res -f java-res/a/a -f java-res/b/b",
 		},
 		{
-			// Test that a module with "include_srcs: true" includes its source files in the resources jar
-			name: "include sources",
-			prop: `include_srcs: true`,
-			args: "-C . -f a.java -f b.java -f c.java",
-		},
-		{
 			// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
 			name: "wildcard dirs",
 			prop: `java_resource_dirs: ["java-res/*"]`,
@@ -546,6 +586,69 @@
 	}
 }
 
+func TestIncludeSrcs(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			include_srcs: true,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			java_resource_dirs: ["java-res"],
+			include_srcs: true,
+		}
+	`)
+
+	// Test a library with include_srcs: true
+	foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
+	fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
+
+	if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("foo combined jars %v does not contain %q", w, g)
+	}
+
+	if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+		t.Errorf("foo source jar args %q is not %q", w, g)
+	}
+
+	// Test a library with include_srcs: true and resources
+	bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
+	barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
+	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
+	barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
+
+	if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+		t.Errorf("bar source jar args %q is not %q", w, g)
+	}
+
+	if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
+		t.Errorf("bar resource jar args %q is not %q", w, g)
+	}
+}
+
 func TestGeneratedSources(t *testing.T) {
 	ctx := testJava(t, `
 		java_library {
@@ -769,6 +872,19 @@
 	}
 }
 
+func TestJavaLibrary(t *testing.T) {
+	config := testConfig(nil)
+	ctx := testContext(config, "", map[string][]byte{
+		"libcore/Android.bp": []byte(`
+				java_library {
+						name: "core",
+						sdk_version: "none",
+						system_modules: "none",
+				}`),
+	})
+	run(t, ctx, config)
+}
+
 func TestJavaSdkLibrary(t *testing.T) {
 	ctx := testJava(t, `
 		droiddoc_template {
@@ -927,7 +1043,7 @@
 		java_library {
 			name: "bar",
 			srcs: ["b.java"],
-			no_standard_libs: true,
+			sdk_version: "none",
 			system_modules: "none",
 			patch_module: "java.base",
 		}
@@ -939,8 +1055,8 @@
 		}
 	`
 
-	t.Run("1.8", func(t *testing.T) {
-		// Test default javac 1.8
+	t.Run("Java language level 8", func(t *testing.T) {
+		// Test default javac -source 1.8 -target 1.8
 		ctx := testJava(t, bp)
 
 		checkPatchModuleFlag(t, ctx, "foo", "")
@@ -948,9 +1064,9 @@
 		checkPatchModuleFlag(t, ctx, "baz", "")
 	})
 
-	t.Run("1.9", func(t *testing.T) {
-		// Test again with javac 1.9
-		config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+	t.Run("Java language level 9", func(t *testing.T) {
+		// Test again with javac -source 9 -target 9
+		config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
 		ctx := testContext(config, bp, nil)
 		run(t, ctx, config)
 
diff --git a/java/jdeps.go b/java/jdeps.go
index 18498be..fccc40f 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -72,6 +72,7 @@
 		dpInfo.Aidl_include_dirs = android.FirstUniqueStrings(dpInfo.Aidl_include_dirs)
 		dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
 		dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
+		dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
 		moduleInfos[name] = dpInfo
 
 		mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/kotlin.go b/java/kotlin.go
index 81b89f9..8306907 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -18,6 +18,7 @@
 	"bytes"
 	"encoding/base64"
 	"encoding/binary"
+	"path/filepath"
 	"strings"
 
 	"android/soong/android"
@@ -27,16 +28,23 @@
 
 var kotlinc = pctx.AndroidGomaStaticRule("kotlinc",
 	blueprint.RuleParams{
-		Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" && mkdir -p "$classesDir" "$srcJarDir" && ` +
+		Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
+			`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
 			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-			`${config.GenKotlinBuildFileCmd} $classpath $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+			`${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
 			`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
-			`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile && ` +
+			`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
 			`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
 			`rm -rf "$srcJarDir"`,
 		CommandDeps: []string{
 			"${config.KotlincCmd}",
 			"${config.KotlinCompilerJar}",
+			"${config.KotlinPreloaderJar}",
+			"${config.KotlinReflectJar}",
+			"${config.KotlinScriptRuntimeJar}",
+			"${config.KotlinStdlibJar}",
+			"${config.KotlinTrove4jJar}",
+			"${config.KotlinAnnotationJar}",
 			"${config.GenKotlinBuildFileCmd}",
 			"${config.SoongZipCmd}",
 			"${config.ZipSyncCmd}",
@@ -44,7 +52,8 @@
 		Rspfile:        "$out.rsp",
 		RspfileContent: `$in`,
 	},
-	"kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile")
+	"kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile",
+	"emptyDir", "name")
 
 // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
 func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -55,6 +64,9 @@
 	deps = append(deps, flags.kotlincClasspath...)
 	deps = append(deps, srcJars...)
 
+	kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
+	kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        kotlinc,
 		Description: "kotlinc",
@@ -68,8 +80,10 @@
 			"classesDir":      android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
 			"srcJarDir":       android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(),
 			"kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(),
+			"emptyDir":        android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
 			// http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8
 			"kotlinJvmTarget": "1.8",
+			"name":            kotlinName,
 		},
 	})
 }
@@ -78,7 +92,7 @@
 	blueprint.RuleParams{
 		Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && mkdir -p "$srcJarDir" "$kaptDir" && ` +
 			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
-			`${config.GenKotlinBuildFileCmd} $classpath "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+			`${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
 			`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
 			`-Xplugin=${config.KotlinKaptJar} ` +
 			`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@@ -104,7 +118,7 @@
 		RspfileContent: `$in`,
 	},
 	"kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
-	"classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile")
+	"classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name")
 
 // kotlinKapt performs Kotlin-compatible annotation processing.  It takes .kt and .java sources and srcjars, and runs
 // annotation processors over all of them, producing a srcjar of generated code in outputFile.  The srcjar should be
@@ -131,6 +145,9 @@
 		{"-target", flags.javaVersion},
 	})
 
+	kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
+	kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        kapt,
 		Description: "kapt",
@@ -147,6 +164,7 @@
 			"kaptProcessor":     kaptProcessor,
 			"kaptDir":           android.PathForModuleOut(ctx, "kapt/gen").String(),
 			"encodedJavacFlags": encodedJavacFlags,
+			"name":              kotlinName,
 		},
 	})
 }
diff --git a/java/robolectric.go b/java/robolectric.go
new file mode 100644
index 0000000..cbe3557
--- /dev/null
+++ b/java/robolectric.go
@@ -0,0 +1,243 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+}
+
+var robolectricDefaultLibs = []string{
+	"robolectric_android-all-stub",
+	"Robolectric_all-target",
+	"mockito-robolectric-prebuilt",
+	"truth-prebuilt",
+}
+
+var (
+	roboCoverageLibsTag = dependencyTag{name: "roboSrcs"}
+)
+
+type robolectricProperties struct {
+	// The name of the android_app module that the tests will run against.
+	Instrumentation_for *string
+
+	// Additional libraries for which coverage data should be generated
+	Coverage_libs []string
+
+	Test_options struct {
+		// Timeout in seconds when running the tests.
+		Timeout *int64
+
+		// Number of shards to use when running the tests.
+		Shards *int64
+	}
+}
+
+type robolectricTest struct {
+	Library
+
+	robolectricProperties robolectricProperties
+
+	libs  []string
+	tests []string
+
+	roboSrcJar android.Path
+}
+
+func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	r.Library.DepsMutator(ctx)
+
+	if r.robolectricProperties.Instrumentation_for != nil {
+		ctx.AddVariationDependencies(nil, instrumentationForTag, String(r.robolectricProperties.Instrumentation_for))
+	} else {
+		ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
+	}
+
+	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+
+	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
+}
+
+func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
+		Join(ctx, "com/android/tools/test_config.properties")
+
+	// TODO: this inserts paths to built files into the test, it should really be inserting the contents.
+	instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag)
+
+	if len(instrumented) != 1 {
+		panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
+	}
+
+	instrumentedApp, ok := instrumented[0].(*AndroidApp)
+	if !ok {
+		ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
+	}
+
+	generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
+	r.extraResources = android.Paths{roboTestConfig}
+
+	r.Library.GenerateAndroidBuildActions(ctx)
+
+	roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
+	r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
+	r.roboSrcJar = roboSrcJar
+
+	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+		r.libs = append(r.libs, ctx.OtherModuleName(dep))
+	}
+
+	// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
+	// annotated as a test and run it.
+	for _, src := range r.compiledJavaSrcs {
+		s := src.Rel()
+		if !strings.HasSuffix(s, "Test.java") {
+			continue
+		} else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
+			continue
+		} else if strings.HasPrefix(s, "src/") {
+			s = strings.TrimPrefix(s, "src/")
+		}
+		r.tests = append(r.tests, s)
+	}
+}
+
+func shardTests(paths []string, shards int) [][]string {
+	if shards > len(paths) {
+		shards = len(paths)
+	}
+	if shards == 0 {
+		return nil
+	}
+	ret := make([][]string, 0, shards)
+	shardSize := (len(paths) + shards - 1) / shards
+	for len(paths) > shardSize {
+		ret = append(ret, paths[0:shardSize])
+		paths = paths[shardSize:]
+	}
+	if len(paths) > 0 {
+		ret = append(ret, paths)
+	}
+	return ret
+}
+
+func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) {
+	manifest := instrumentedApp.mergedManifestFile
+	resourceApk := instrumentedApp.outputFile
+
+	rule := android.NewRuleBuilder()
+
+	rule.Command().Text("rm -f").Output(outputFile)
+	rule.Command().
+		Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
+		Textf(`echo "android_resource_apk=%s" >>`, resourceApk.String()).Output(outputFile).
+		// Make it depend on the files to which it points so the test file's timestamp is updated whenever the
+		// contents change
+		Implicit(manifest).
+		Implicit(resourceApk)
+
+	rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties")
+}
+
+func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
+	instrumentedApp *AndroidApp) {
+
+	srcJarArgs := copyOf(instrumentedApp.srcJarArgs)
+	srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
+
+	for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
+		if dep, ok := m.(Dependency); ok {
+			depSrcJarArgs, depSrcJarDeps := dep.SrcJarArgs()
+			srcJarArgs = append(srcJarArgs, depSrcJarArgs...)
+			srcJarDeps = append(srcJarDeps, depSrcJarDeps...)
+		}
+	}
+
+	TransformResourcesToJar(ctx, outputFile, srcJarArgs, srcJarDeps)
+}
+
+func (r *robolectricTest) AndroidMk() android.AndroidMkData {
+	data := r.Library.AndroidMk()
+
+	data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+		android.WriteAndroidMkData(w, data)
+
+		if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
+			shards := shardTests(r.tests, int(*s))
+			for i, shard := range shards {
+				r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard)
+			}
+
+			// TODO: add rules to dist the outputs of the individual tests, or combine them together?
+			fmt.Fprintln(w, "")
+			fmt.Fprintln(w, ".PHONY:", "Run"+name)
+			fmt.Fprintln(w, "Run"+name, ": \\")
+			for i := range shards {
+				fmt.Fprintln(w, "   ", "Run"+name+strconv.Itoa(i), "\\")
+			}
+			fmt.Fprintln(w, "")
+		} else {
+			r.writeTestRunner(w, name, "Run"+name, r.tests)
+		}
+	}
+
+	return data
+}
+
+func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, tests []string) {
+	fmt.Fprintln(w, "")
+	fmt.Fprintln(w, "include $(CLEAR_VARS)")
+	fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+	fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES :=", module)
+	fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES += ", strings.Join(r.libs, " "))
+	fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
+	fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
+	fmt.Fprintln(w, "LOCAL_ROBOTEST_FILES :=", strings.Join(tests, " "))
+	if t := r.robolectricProperties.Test_options.Timeout; t != nil {
+		fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
+	}
+	fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+
+}
+
+// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
+// instead of on a device.  It also generates a rule with the name of the module prefixed with "Run" that can be
+// used to run the tests.  Running the tests with build rule will eventually be deprecated and replaced with atest.
+//
+// The test runner considers any file listed in srcs whose name ends with Test.java to be a test class, unless
+// it is named BaseRobolectricTest.java.  The path to the each source file must exactly match the package
+// name, or match the package name when the prefix "src/" is removed.
+func RobolectricTestFactory() android.Module {
+	module := &robolectricTest{}
+
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.protoProperties,
+		&module.robolectricProperties)
+
+	module.Module.dexpreopter.isTest = true
+
+	InitJavaModule(module, android.DeviceSupported)
+	return module
+}
diff --git a/java/robolectric_test.go b/java/robolectric_test.go
new file mode 100644
index 0000000..e89c6e7
--- /dev/null
+++ b/java/robolectric_test.go
@@ -0,0 +1,88 @@
+// 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 (
+	"reflect"
+	"testing"
+)
+
+func Test_shardTests(t *testing.T) {
+	type args struct {
+		paths  []string
+		shards int
+	}
+	tests := []struct {
+		name string
+		args args
+		want [][]string
+	}{
+		{
+			name: "empty",
+			args: args{
+				paths:  nil,
+				shards: 1,
+			},
+			want: [][]string(nil),
+		},
+		{
+			name: "too many shards",
+			args: args{
+				paths:  []string{"a", "b"},
+				shards: 3,
+			},
+			want: [][]string{{"a"}, {"b"}},
+		},
+		{
+			name: "single shard",
+			args: args{
+				paths:  []string{"a", "b"},
+				shards: 1,
+			},
+			want: [][]string{{"a", "b"}},
+		},
+		{
+			name: "shard per input",
+			args: args{
+				paths:  []string{"a", "b", "c"},
+				shards: 3,
+			},
+			want: [][]string{{"a"}, {"b"}, {"c"}},
+		},
+		{
+			name: "balanced shards",
+			args: args{
+				paths:  []string{"a", "b", "c", "d"},
+				shards: 2,
+			},
+			want: [][]string{{"a", "b"}, {"c", "d"}},
+		},
+		{
+			name: "unbalanced shards",
+			args: args{
+				paths:  []string{"a", "b", "c"},
+				shards: 2,
+			},
+			want: [][]string{{"a", "b"}, {"c"}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := shardTests(tt.args.paths, tt.args.shards); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("shardTests() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/java/sdk.go b/java/sdk.go
index e93f8fb..7b79a49 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -38,7 +38,7 @@
 var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
 
 type sdkContext interface {
-	// sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set.
+	// sdkVersion returns the sdk_version property of the current module, or an empty string if it is not set.
 	sdkVersion() string
 	// minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set.
 	minSdkVersion() string
@@ -46,9 +46,9 @@
 	targetSdkVersion() string
 }
 
-func sdkVersionOrDefault(ctx android.BaseContext, v string) string {
+func sdkVersionOrDefault(ctx android.BaseModuleContext, v string) string {
 	switch v {
-	case "", "current", "system_current", "test_current", "core_current":
+	case "", "none", "current", "test_current", "system_current", "core_current", "core_platform":
 		return ctx.Config().DefaultAppTargetSdk()
 	default:
 		return v
@@ -57,9 +57,9 @@
 
 // Returns a sdk version as a number.  For modules targeting an unreleased SDK (meaning it does not yet have a number)
 // it returns android.FutureApiLevel (10000).
-func sdkVersionToNumber(ctx android.BaseContext, v string) (int, error) {
+func sdkVersionToNumber(ctx android.BaseModuleContext, v string) (int, error) {
 	switch v {
-	case "", "current", "test_current", "system_current", "core_current":
+	case "", "none", "current", "test_current", "system_current", "core_current", "core_platform":
 		return ctx.Config().DefaultAppTargetSdkInt(), nil
 	default:
 		n := android.GetNumericSdkVersion(v)
@@ -71,7 +71,7 @@
 	}
 }
 
-func sdkVersionToNumberAsString(ctx android.BaseContext, v string) (string, error) {
+func sdkVersionToNumberAsString(ctx android.BaseModuleContext, v string) (string, error) {
 	n, err := sdkVersionToNumber(ctx, v)
 	if err != nil {
 		return "", err
@@ -79,8 +79,9 @@
 	return strconv.Itoa(n), nil
 }
 
-func decodeSdkDep(ctx android.BaseContext, sdkContext sdkContext) sdkDep {
+func decodeSdkDep(ctx android.BaseModuleContext, sdkContext sdkContext) sdkDep {
 	v := sdkContext.sdkVersion()
+
 	// For PDK builds, use the latest SDK version instead of "current"
 	if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
 		sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
@@ -151,9 +152,9 @@
 		}
 
 		if m == "core.current.stubs" {
-			ret.systemModules = "core-system-modules"
-		} else if m == "core.platform.api.stubs" {
-			ret.systemModules = "core-platform-api-stubs-system-modules"
+			ret.systemModules = "core-current-stubs-system-modules"
+			// core_current does not include framework classes.
+			ret.noFrameworksLibs = true
 		}
 		return ret
 	}
@@ -173,7 +174,8 @@
 		}
 	}
 
-	if ctx.Config().UnbundledBuildUsePrebuiltSdks() && v != "" {
+	if ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
+		v != "" && v != "none" && v != "core_platform" {
 		return toPrebuilt(v)
 	}
 
@@ -183,6 +185,16 @@
 			useDefaultLibs:     true,
 			frameworkResModule: "framework-res",
 		}
+	case "none":
+		return sdkDep{
+			noStandardLibs: true,
+		}
+	case "core_platform":
+		return sdkDep{
+			useDefaultLibs:     true,
+			frameworkResModule: "framework-res",
+			noFrameworksLibs:   true,
+		}
 	case "current":
 		return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
 	case "system_current":
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 974131c..b4a3f29 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -42,10 +42,6 @@
 	name string
 }
 
-type syspropLibraryInterface interface {
-	SyspropJavaModule() *SdkLibrary
-}
-
 var (
 	publicApiStubsTag = dependencyTag{name: "public"}
 	systemApiStubsTag = dependencyTag{name: "system"}
@@ -79,10 +75,7 @@
 
 func init() {
 	android.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
-
-	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
-	})
+	android.RegisterModuleType("java_sdk_library_import", sdkLibraryImportFactory)
 
 	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
 		javaSdkLibraries := javaSdkLibraries(ctx.Config())
@@ -166,7 +159,8 @@
 	ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
 	ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
 
-	if !Bool(module.properties.No_standard_libs) {
+	sdkDep := decodeSdkDep(ctx, sdkContext(&module.Library))
+	if sdkDep.hasStandardLibs() {
 		ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem))
 		ctx.AddVariationDependencies(nil, systemApiFileTag, module.docsName(apiScopeSystem))
 		ctx.AddVariationDependencies(nil, testApiFileTag, module.docsName(apiScopeTest))
@@ -381,7 +375,7 @@
 }
 
 // Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) {
 	props := struct {
 		Name              *string
 		Srcs              []string
@@ -391,7 +385,6 @@
 		Device_specific   *bool
 		Product_specific  *bool
 		Compile_dex       *bool
-		No_standard_libs  *bool
 		System_modules    *string
 		Java_version      *string
 		Product_variables struct {
@@ -408,17 +401,22 @@
 		}
 	}{}
 
+	sdkVersion := module.sdkVersion(apiScope)
+	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
+	if !sdkDep.hasStandardLibs() {
+		sdkVersion = "none"
+	}
+
 	props.Name = proptools.StringPtr(module.stubsName(apiScope))
 	// sources are generated from the droiddoc
 	props.Srcs = []string{":" + module.docsName(apiScope)}
-	props.Sdk_version = proptools.StringPtr(module.sdkVersion(apiScope))
+	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.Libs = module.sdkLibraryProperties.Stub_only_libs
 	// Unbundled apps will use the prebult one from /prebuilts/sdk
 	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
 	}
 	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
-	props.No_standard_libs = module.Library.Module.properties.No_standard_libs
 	props.System_modules = module.Library.Module.deviceProperties.System_modules
 	props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs
 	props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags
@@ -440,7 +438,7 @@
 
 // Creates a droiddoc module that creates stubs source files from the given full source
 // files
-func (module *SdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createDocs(mctx android.LoadHookContext, apiScope apiScope) {
 	props := struct {
 		Name                             *string
 		Srcs                             []string
@@ -448,13 +446,13 @@
 		Srcs_lib                         *string
 		Srcs_lib_whitelist_dirs          []string
 		Srcs_lib_whitelist_pkgs          []string
+		Sdk_version                      *string
 		Libs                             []string
 		Arg_files                        []string
 		Args                             *string
 		Api_tag_name                     *string
 		Api_filename                     *string
 		Removed_api_filename             *string
-		No_standard_libs                 *bool
 		Java_version                     *string
 		Merge_annotations_dirs           []string
 		Merge_inclusion_annotations_dirs []string
@@ -469,9 +467,16 @@
 		}
 	}{}
 
+	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
+	sdkVersion := ""
+	if !sdkDep.hasStandardLibs() {
+		sdkVersion = "none"
+	}
+
 	props.Name = proptools.StringPtr(module.docsName(apiScope))
 	props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...)
 	props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
+	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.Installable = proptools.BoolPtr(false)
 	// A droiddoc module has only one Libs property and doesn't distinguish between
 	// shared libs and static libs. So we need to add both of these libs to Libs property.
@@ -479,7 +484,6 @@
 	props.Libs = append(props.Libs, module.Library.Module.properties.Static_libs...)
 	props.Aidl.Include_dirs = module.Library.Module.deviceProperties.Aidl.Include_dirs
 	props.Aidl.Local_include_dirs = module.Library.Module.deviceProperties.Aidl.Local_include_dirs
-	props.No_standard_libs = module.Library.Module.properties.No_standard_libs
 	props.Java_version = module.Library.Module.properties.Java_version
 
 	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
@@ -539,7 +543,7 @@
 }
 
 // Creates the xml file that publicizes the runtime library
-func (module *SdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
+func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
 	template := `
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2018 The Android Open Source Project
@@ -598,9 +602,9 @@
 	mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps)
 }
 
-func (module *SdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) PrebuiltJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
 	var api, v string
-	if sdkVersion == "" {
+	if sdkVersion == "" || sdkVersion == "none" {
 		api = "system"
 		v = "current"
 	} else if strings.Contains(sdkVersion, "_") {
@@ -622,7 +626,7 @@
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
@@ -638,7 +642,7 @@
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
@@ -668,15 +672,7 @@
 // For a java_sdk_library module, create internal modules for stubs, docs,
 // runtime libs and xml file. If requested, the stubs and docs are created twice
 // once for public API level and once for system API level
-func SdkLibraryMutator(mctx android.TopDownMutatorContext) {
-	if module, ok := mctx.Module().(*SdkLibrary); ok {
-		module.createInternalModules(mctx)
-	} else if module, ok := mctx.Module().(syspropLibraryInterface); ok {
-		module.SyspropJavaModule().createInternalModules(mctx)
-	}
-}
-
-func (module *SdkLibrary) createInternalModules(mctx android.TopDownMutatorContext) {
+func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) {
 	if len(module.Library.Module.properties.Srcs) == 0 {
 		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
 	}
@@ -716,7 +712,8 @@
 	module.createStubsLibrary(mctx, apiScopePublic)
 	module.createDocs(mctx, apiScopePublic)
 
-	if !Bool(module.properties.No_standard_libs) {
+	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
+	if sdkDep.hasStandardLibs() {
 		// for system API stubs
 		module.createStubsLibrary(mctx, apiScopeSystem)
 		module.createDocs(mctx, apiScopeSystem)
@@ -753,5 +750,115 @@
 	module := &SdkLibrary{}
 	module.InitSdkLibraryProperties()
 	InitJavaModule(module, android.HostAndDeviceSupported)
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.CreateInternalModules(ctx) })
 	return module
 }
+
+//
+// SDK library prebuilts
+//
+
+type sdkLibraryImportProperties struct {
+	Jars []string `android:"path"`
+
+	Sdk_version *string
+
+	Installable *bool
+
+	// List of shared java libs that this module has dependencies to
+	Libs []string
+
+	// List of files to remove from the jar file(s)
+	Exclude_files []string
+
+	// List of directories to remove from the jar file(s)
+	Exclude_dirs []string
+}
+
+type sdkLibraryImport struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	prebuilt android.Prebuilt
+
+	properties sdkLibraryImportProperties
+
+	stubsPath android.Paths
+}
+
+var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
+
+func sdkLibraryImportFactory() android.Module {
+	module := &sdkLibraryImport{}
+
+	module.AddProperties(&module.properties)
+
+	android.InitPrebuiltModule(module, &module.properties.Jars)
+	InitJavaModule(module, android.HostAndDeviceSupported)
+
+	android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
+	return module
+}
+
+func (module *sdkLibraryImport) Prebuilt() *android.Prebuilt {
+	return &module.prebuilt
+}
+
+func (module *sdkLibraryImport) Name() string {
+	return module.prebuilt.Name(module.ModuleBase.Name())
+}
+
+func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookContext) {
+	// Creates a java import for the jar with ".stubs" suffix
+	props := struct {
+		Name             *string
+		Soc_specific     *bool
+		Device_specific  *bool
+		Product_specific *bool
+	}{}
+
+	props.Name = proptools.StringPtr(module.BaseModuleName() + sdkStubsLibrarySuffix)
+
+	if module.SocSpecific() {
+		props.Soc_specific = proptools.BoolPtr(true)
+	} else if module.DeviceSpecific() {
+		props.Device_specific = proptools.BoolPtr(true)
+	} else if module.ProductSpecific() {
+		props.Product_specific = proptools.BoolPtr(true)
+	}
+
+	mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props, &module.properties)
+
+	javaSdkLibraries := javaSdkLibraries(mctx.Config())
+	javaSdkLibrariesLock.Lock()
+	defer javaSdkLibrariesLock.Unlock()
+	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
+}
+
+func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Add dependencies to the prebuilt stubs library
+	ctx.AddVariationDependencies(nil, publicApiStubsTag, module.BaseModuleName()+sdkStubsLibrarySuffix)
+}
+
+func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Record the paths to the prebuilt stubs library.
+	ctx.VisitDirectDeps(func(to android.Module) {
+		tag := ctx.OtherModuleDependencyTag(to)
+
+		switch tag {
+		case publicApiStubsTag:
+			module.stubsPath = to.(Dependency).HeaderJars()
+		}
+	})
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
+	// This module is just a wrapper for the prebuilt stubs.
+	return module.stubsPath
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
+	// This module is just a wrapper for the stubs.
+	return module.stubsPath
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index e446129..f82a4fb 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -47,6 +47,14 @@
 			aidl:          "-Iframework/aidl",
 		},
 		{
+			name:          `sdk_version:"core_platform"`,
+			properties:    `sdk_version:"core_platform"`,
+			bootclasspath: config.DefaultBootclasspathLibraries,
+			system:        config.DefaultSystemModules,
+			classpath:     []string{},
+			aidl:          "",
+		},
+		{
 			name:          "blank sdk version",
 			properties:    `sdk_version: "",`,
 			bootclasspath: config.DefaultBootclasspathLibraries,
@@ -106,7 +114,7 @@
 		{
 
 			name:          "nostdlib",
-			properties:    `no_standard_libs: true, system_modules: "none"`,
+			properties:    `sdk_version: "none", system_modules: "none"`,
 			system:        "none",
 			bootclasspath: []string{`""`},
 			classpath:     []string{},
@@ -114,7 +122,7 @@
 		{
 
 			name:          "nostdlib system_modules",
-			properties:    `no_standard_libs: true, system_modules: "core-platform-api-stubs-system-modules"`,
+			properties:    `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
 			system:        "core-platform-api-stubs-system-modules",
 			bootclasspath: []string{`""`},
 			classpath:     []string{},
@@ -129,13 +137,6 @@
 			classpath:     []string{},
 		},
 		{
-			name:       "host nostdlib",
-			moduleType: "java_library_host",
-			host:       android.Host,
-			properties: `no_standard_libs: true`,
-			classpath:  []string{},
-		},
-		{
 
 			name:          "host supported default",
 			host:          android.Host,
@@ -146,7 +147,7 @@
 		{
 			name:       "host supported nostdlib",
 			host:       android.Host,
-			properties: `host_supported: true, no_standard_libs: true, system_modules: "none"`,
+			properties: `host_supported: true, sdk_version: "none", system_modules: "none"`,
 			classpath:  []string{},
 		},
 		{
@@ -245,7 +246,7 @@
 			if testcase.system == "none" {
 				system = "--system=none"
 			} else if testcase.system != "" {
-				system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system") + "/"
+				system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system")
 			}
 
 			checkClasspath := func(t *testing.T, ctx *android.TestContext) {
@@ -272,8 +273,8 @@
 				}
 			}
 
-			t.Run("1.8", func(t *testing.T) {
-				// Test default javac 1.8
+			t.Run("Java language level 8", func(t *testing.T) {
+				// Test default javac -source 1.8 -target 1.8
 				config := testConfig(nil)
 				if testcase.unbundled {
 					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
@@ -299,9 +300,9 @@
 				}
 			})
 
-			// Test again with javac 1.9
-			t.Run("1.9", func(t *testing.T) {
-				config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+			// Test again with javac -source 9 -target 9
+			t.Run("Java language level 9", func(t *testing.T) {
+				config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
 				if testcase.unbundled {
 					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 				}
diff --git a/java/system_modules.go b/java/system_modules.go
index 9ee0307..c616249 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -42,7 +42,11 @@
 			`${config.MergeZipsCmd} -j ${workDir}/module.jar ${workDir}/classes.jar $in && ` +
 			`${config.JmodCmd} create --module-version 9 --target-platform android ` +
 			`  --class-path ${workDir}/module.jar ${workDir}/jmod/${moduleName}.jmod && ` +
-			`${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules ${moduleName} --output ${outDir} && ` +
+			`${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules ${moduleName} --output ${outDir} ` +
+			// Note: The system-modules jlink plugin is disabled because (a) it is not
+			// useful on Android, and (b) it causes errors with later versions of jlink
+			// when the jdk.internal.module is absent from java.base (as it is here).
+			`  --disable-plugin system-modules && ` +
 			`cp ${config.JrtFsJar} ${outDir}/lib/`,
 		CommandDeps: []string{
 			"${moduleInfoJavaPath}",
@@ -57,7 +61,7 @@
 		"moduleName", "classpath", "outDir", "workDir")
 )
 
-func TransformJarsToSystemModules(ctx android.ModuleContext, moduleName string, jars android.Paths) android.WritablePath {
+func TransformJarsToSystemModules(ctx android.ModuleContext, moduleName string, jars android.Paths) (android.Path, android.Paths) {
 	outDir := android.PathForModuleOut(ctx, "system")
 	workDir := android.PathForModuleOut(ctx, "modules")
 	outputFile := android.PathForModuleOut(ctx, "system/lib/modules")
@@ -80,33 +84,30 @@
 		},
 	})
 
-	return outputFile
+	return outDir, outputs.Paths()
 }
 
 func SystemModulesFactory() android.Module {
 	module := &SystemModules{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
 	return module
 }
 
 type SystemModules struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
 	properties SystemModulesProperties
 
-	outputFile android.Path
+	outputDir  android.Path
+	outputDeps android.Paths
 }
 
 type SystemModulesProperties struct {
 	// List of java library modules that should be included in the system modules
 	Libs []string
-
-	// List of prebuilt jars that should be included in the system modules
-	Jars []string
-
-	// Sdk version that should be included in the system modules
-	Sdk_version *string
 }
 
 func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -117,9 +118,7 @@
 		jars = append(jars, dep.HeaderJars()...)
 	})
 
-	jars = append(jars, android.PathsForModuleSrc(ctx, system.properties.Jars)...)
-
-	system.outputFile = TransformJarsToSystemModules(ctx, "java.base", jars)
+	system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, "java.base", jars)
 }
 
 func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -129,16 +128,22 @@
 func (system *SystemModules) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-			makevar := "SOONG_SYSTEM_MODULES_" + name
 			fmt.Fprintln(w)
-			fmt.Fprintln(w, makevar, ":=", system.outputFile.String())
-			fmt.Fprintln(w, ".KATI_READONLY", ":=", makevar)
+
+			makevar := "SOONG_SYSTEM_MODULES_" + name
+			fmt.Fprintln(w, makevar, ":=$=", system.outputDir.String())
+			fmt.Fprintln(w)
+
+			makevar = "SOONG_SYSTEM_MODULES_LIBS_" + name
+			fmt.Fprintln(w, makevar, ":=$=", strings.Join(system.properties.Libs, " "))
+			fmt.Fprintln(w)
+
+			makevar = "SOONG_SYSTEM_MODULES_DEPS_" + name
+			fmt.Fprintln(w, makevar, ":=$=", strings.Join(system.outputDeps.Strings(), " "))
+			fmt.Fprintln(w)
+
 			fmt.Fprintln(w, name+":", "$("+makevar+")")
 			fmt.Fprintln(w, ".PHONY:", name)
-			fmt.Fprintln(w)
-			makevar = "SOONG_SYSTEM_MODULES_LIBS_" + name
-			fmt.Fprintln(w, makevar, ":=", strings.Join(system.properties.Libs, " "))
-			fmt.Fprintln(w, ".KATI_READONLY :=", makevar)
 		},
 	}
 }
diff --git a/java/testing.go b/java/testing.go
index 6b35bd0..a37c0a9 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -45,6 +45,8 @@
 		"core.current.stubs",
 		"core.platform.api.stubs",
 		"kotlin-stdlib",
+		"kotlin-stdlib-jdk7",
+		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 	}
 
@@ -53,8 +55,7 @@
 			java_library {
 				name: "%s",
 				srcs: ["a.java"],
-				no_standard_libs: true,
-				sdk_version: "core_current",
+				sdk_version: "none",
 				system_modules: "core-platform-api-stubs-system-modules",
 			}
 		`, extra)
@@ -64,8 +65,7 @@
 		java_library {
 			name: "framework",
 			srcs: ["a.java"],
-			no_standard_libs: true,
-			sdk_version: "core_current",
+			sdk_version: "none",
 			system_modules: "core-platform-api-stubs-system-modules",
 			aidl: {
 				export_include_dirs: ["framework/aidl"],
@@ -74,12 +74,37 @@
 
 		android_app {
 			name: "framework-res",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
+		}
+
+		java_library {
+			name: "android.hidl.base-V1.0-java",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "core-platform-api-stubs-system-modules",
+			installable: true,
+		}
+
+		java_library {
+			name: "android.hidl.manager-V1.0-java",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "core-platform-api-stubs-system-modules",
+			installable: true,
+		}
+
+		java_library {
+			name: "org.apache.http.legacy",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "core-platform-api-stubs-system-modules",
+			installable: true,
 		}
 	`
 
 	systemModules := []string{
 		"core-system-modules",
+		"core-current-stubs-system-modules",
 		"core-platform-api-stubs-system-modules",
 		"android_stubs_current_system_modules",
 		"android_system_stubs_current_system_modules",
diff --git a/phony/phony.go b/phony/phony.go
index ed6a2fe..305a434 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -28,7 +28,9 @@
 
 type phony struct {
 	android.ModuleBase
-	requiredModuleNames []string
+	requiredModuleNames       []string
+	hostRequiredModuleNames   []string
+	targetRequiredModuleNames []string
 }
 
 func PhonyFactory() android.Module {
@@ -40,8 +42,12 @@
 
 func (p *phony) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	p.requiredModuleNames = ctx.RequiredModuleNames()
-	if len(p.requiredModuleNames) == 0 {
-		ctx.PropertyErrorf("required", "phony must not have empty required dependencies in order to be useful(and therefore permitted).")
+	p.hostRequiredModuleNames = ctx.HostRequiredModuleNames()
+	p.targetRequiredModuleNames = ctx.TargetRequiredModuleNames()
+	if len(p.requiredModuleNames) == 0 &&
+		len(p.hostRequiredModuleNames) == 0 && len(p.targetRequiredModuleNames) == 0 {
+		ctx.PropertyErrorf("required", "phony must not have empty required dependencies "+
+			"in order to be useful(and therefore permitted).")
 	}
 }
 
@@ -54,7 +60,18 @@
 			if p.Host() {
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 			}
-			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(p.requiredModuleNames, " "))
+			if len(p.requiredModuleNames) > 0 {
+				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=",
+					strings.Join(p.requiredModuleNames, " "))
+			}
+			if len(p.hostRequiredModuleNames) > 0 {
+				fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=",
+					strings.Join(p.hostRequiredModuleNames, " "))
+			}
+			if len(p.targetRequiredModuleNames) > 0 {
+				fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=",
+					strings.Join(p.targetRequiredModuleNames, " "))
+			}
 			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 		},
 	}
diff --git a/scripts/Android.bp b/scripts/Android.bp
new file mode 100644
index 0000000..31f5922
--- /dev/null
+++ b/scripts/Android.bp
@@ -0,0 +1,71 @@
+python_binary_host {
+    name: "manifest_fixer",
+    main: "manifest_fixer.py",
+    srcs: [
+        "manifest_fixer.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+python_test_host {
+    name: "manifest_fixer_test",
+    main: "manifest_fixer_test.py",
+    srcs: [
+        "manifest_fixer_test.py",
+        "manifest_fixer.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+    test_suites: ["general-tests"],
+}
+
+python_binary_host {
+    name: "manifest_check",
+    main: "manifest_check.py",
+    srcs: [
+        "manifest_check.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+python_test_host {
+    name: "manifest_check_test",
+    main: "manifest_check_test.py",
+    srcs: [
+        "manifest_check_test.py",
+        "manifest_check.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+    test_suites: ["general-tests"],
+}
diff --git a/scripts/TEST_MAPPING b/scripts/TEST_MAPPING
new file mode 100644
index 0000000..1b0a229
--- /dev/null
+++ b/scripts/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit" : [
+    {
+      "name": "manifest_check_test",
+      "host": true
+    },
+    {
+      "name": "manifest_fixer_test",
+      "host": true
+    }    
+  ]
+}
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index f081f26..8021e55 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -60,37 +60,11 @@
 	warnings []string
 }{
 	{
-		name:     "BUILD_BROKEN_DUP_COPY_HEADERS",
-		behavior: DefaultDeprecated,
-		warnings: []string{"Duplicate header copy:"},
-	},
-	{
 		name:     "BUILD_BROKEN_DUP_RULES",
 		behavior: DefaultFalse,
 		warnings: []string{"overriding commands for target"},
 	},
 	{
-		name:     "BUILD_BROKEN_ANDROIDMK_EXPORTS",
-		behavior: DefaultFalse,
-		warnings: []string{"export_keyword"},
-	},
-	{
-		name:     "BUILD_BROKEN_PHONY_TARGETS",
-		behavior: DefaultFalse,
-		warnings: []string{
-			"depends on PHONY target",
-			"looks like a real file",
-			"writing to readonly directory",
-		},
-	},
-	{
-		name:     "BUILD_BROKEN_ENG_DEBUG_TAGS",
-		behavior: DefaultTrue,
-		warnings: []string{
-			"Changes.md#LOCAL_MODULE_TAGS",
-		},
-	},
-	{
 		name:     "BUILD_BROKEN_USES_NETWORK",
 		behavior: DefaultDeprecated,
 	},
diff --git a/scripts/clang-tidy.sh b/scripts/clang-tidy.sh
deleted file mode 100755
index 04d0bdd..0000000
--- a/scripts/clang-tidy.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2018 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.
-
-# Wrapper script to remove clang compiler flags rejected by clang-tidy.
-# Inputs:
-#  Environment:
-#   CLANG_TIDY: path to the real clang-tidy program
-
-# clang-tidy doesn't recognize every flag that clang compiler does.
-# It gives clang-diagnostic-unused-command-line-argument warnings
-# to -Wa,* flags.
-# The -flto flags caused clang-tidy to ignore the -I flags,
-# see https://bugs.llvm.org/show_bug.cgi?id=38332.
-# -fsanitize and -fwhole-program-vtables need -flto.
-args=("${@}")
-n=${#args[@]}
-for ((i=0; i<$n; ++i)); do
-  case ${args[i]} in
-    -Wa,*|-flto|-flto=*|-fsanitize=*|-fsanitize-*|-fwhole-program-vtables)
-      unset args[i]
-      ;;
-  esac
-done
-${CLANG_TIDY} "${args[@]}"
diff --git a/scripts/gen-kotlin-build-file.sh b/scripts/gen-kotlin-build-file.sh
index 1e03f72..177ca1b 100755
--- a/scripts/gen-kotlin-build-file.sh
+++ b/scripts/gen-kotlin-build-file.sh
@@ -17,7 +17,7 @@
 # Generates kotlinc module xml file to standard output based on rsp files
 
 if [[ -z "$1" ]]; then
-  echo "usage: $0 <classpath> <outDir> <rspFiles>..." >&2
+  echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
   exit 1
 fi
 
@@ -27,8 +27,9 @@
 fi;
 
 classpath=$1
-out_dir=$2
-shift 2
+name=$2
+out_dir=$3
+shift 3
 
 # Path in the build file may be relative to the build file, we need to make them
 # absolute
@@ -44,7 +45,7 @@
 }
 
 # Print preamble
-echo "<modules><module name=\"name\" type=\"java-production\" outputDir=\"${out_dir}\">"
+echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
 
 # Print classpath entries
 for file in $(echo "$classpath" | tr ":" "\n"); do
diff --git a/scripts/manifest.py b/scripts/manifest.py
new file mode 100755
index 0000000..4c75f8b
--- /dev/null
+++ b/scripts/manifest.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+"""A tool for inserting values from the build system into a manifest."""
+
+from __future__ import print_function
+from xml.dom import minidom
+
+
+android_ns = 'http://schemas.android.com/apk/res/android'
+
+
+def get_children_with_tag(parent, tag_name):
+  children = []
+  for child in  parent.childNodes:
+    if child.nodeType == minidom.Node.ELEMENT_NODE and \
+       child.tagName == tag_name:
+      children.append(child)
+  return children
+
+
+def find_child_with_attribute(element, tag_name, namespace_uri,
+                              attr_name, value):
+  for child in get_children_with_tag(element, tag_name):
+    attr = child.getAttributeNodeNS(namespace_uri, attr_name)
+    if attr is not None and attr.value == value:
+      return child
+  return None
+
+
+def parse_manifest(doc):
+  """Get the manifest element."""
+
+  manifest = doc.documentElement
+  if manifest.tagName != 'manifest':
+    raise RuntimeError('expected manifest tag at root')
+  return manifest
+
+
+def ensure_manifest_android_ns(doc):
+  """Make sure the manifest tag defines the android namespace."""
+
+  manifest = parse_manifest(doc)
+
+  ns = manifest.getAttributeNodeNS(minidom.XMLNS_NAMESPACE, 'android')
+  if ns is None:
+    attr = doc.createAttributeNS(minidom.XMLNS_NAMESPACE, 'xmlns:android')
+    attr.value = android_ns
+    manifest.setAttributeNode(attr)
+  elif ns.value != android_ns:
+    raise RuntimeError('manifest tag has incorrect android namespace ' +
+                       ns.value)
+
+
+def as_int(s):
+  try:
+    i = int(s)
+  except ValueError:
+    return s, False
+  return i, True
+
+
+def compare_version_gt(a, b):
+  """Compare two SDK versions.
+
+  Compares a and b, treating codenames like 'Q' as higher
+  than numerical versions like '28'.
+
+  Returns True if a > b
+
+  Args:
+    a: value to compare
+    b: value to compare
+  Returns:
+    True if a is a higher version than b
+  """
+
+  a, a_is_int = as_int(a.upper())
+  b, b_is_int = as_int(b.upper())
+
+  if a_is_int == b_is_int:
+    # Both are codenames or both are versions, compare directly
+    return a > b
+  else:
+    # One is a codename, the other is not.  Return true if
+    # b is an integer version
+    return b_is_int
+
+
+def get_indent(element, default_level):
+  indent = ''
+  if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
+    text = element.nodeValue
+    indent = text[:len(text)-len(text.lstrip())]
+  if not indent or indent == '\n':
+    # 1 indent = 4 space
+    indent = '\n' + (' ' * default_level * 4)
+  return indent
+
+
+def write_xml(f, doc):
+  f.write('<?xml version="1.0" encoding="utf-8"?>\n')
+  for node in doc.childNodes:
+    f.write(node.toxml(encoding='utf-8') + '\n')
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
new file mode 100755
index 0000000..9122da1
--- /dev/null
+++ b/scripts/manifest_check.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+"""A tool for checking that a manifest agrees with the build system."""
+
+from __future__ import print_function
+
+import argparse
+import sys
+from xml.dom import minidom
+
+
+from manifest import android_ns
+from manifest import get_children_with_tag
+from manifest import parse_manifest
+from manifest import write_xml
+
+
+class ManifestMismatchError(Exception):
+  pass
+
+
+def parse_args():
+  """Parse commandline arguments."""
+
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--uses-library', dest='uses_libraries',
+                      action='append',
+                      help='specify uses-library entries known to the build system')
+  parser.add_argument('--optional-uses-library',
+                      dest='optional_uses_libraries',
+                      action='append',
+                      help='specify uses-library entries known to the build system with required:false')
+  parser.add_argument('--enforce-uses-libraries',
+                      dest='enforce_uses_libraries',
+                      action='store_true',
+                      help='check the uses-library entries known to the build system against the manifest')
+  parser.add_argument('--extract-target-sdk-version',
+                      dest='extract_target_sdk_version',
+                      action='store_true',
+                      help='print the targetSdkVersion from the manifest')
+  parser.add_argument('--output', '-o', dest='output', help='output AndroidManifest.xml file')
+  parser.add_argument('input', help='input AndroidManifest.xml file')
+  return parser.parse_args()
+
+
+def enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries):
+  """Verify that the <uses-library> tags in the manifest match those provided by the build system.
+
+  Args:
+    doc: The XML document.
+    uses_libraries: The names of <uses-library> tags known to the build system
+    optional_uses_libraries: The names of <uses-library> tags with required:fals
+      known to the build system
+  Raises:
+    RuntimeError: Invalid manifest
+    ManifestMismatchError: Manifest does not match
+  """
+
+  manifest = parse_manifest(doc)
+  elems = get_children_with_tag(manifest, 'application')
+  application = elems[0] if len(elems) == 1 else None
+  if len(elems) > 1:
+    raise RuntimeError('found multiple <application> tags')
+  elif not elems:
+    if uses_libraries or optional_uses_libraries:
+      raise ManifestMismatchError('no <application> tag found')
+    return
+
+  verify_uses_library(application, uses_libraries, optional_uses_libraries)
+
+
+def verify_uses_library(application, uses_libraries, optional_uses_libraries):
+  """Verify that the uses-library values known to the build system match the manifest.
+
+  Args:
+    application: the <application> tag in the manifest.
+    uses_libraries: the names of expected <uses-library> tags.
+    optional_uses_libraries: the names of expected <uses-library> tags with required="false".
+  Raises:
+    ManifestMismatchError: Manifest does not match
+  """
+
+  if uses_libraries is None:
+    uses_libraries = []
+
+  if optional_uses_libraries is None:
+    optional_uses_libraries = []
+
+  manifest_uses_libraries, manifest_optional_uses_libraries = parse_uses_library(application)
+
+  err = []
+  if manifest_uses_libraries != uses_libraries:
+    err.append('Expected required <uses-library> tags "%s", got "%s"' %
+               (', '.join(uses_libraries), ', '.join(manifest_uses_libraries)))
+
+  if manifest_optional_uses_libraries != optional_uses_libraries:
+    err.append('Expected optional <uses-library> tags "%s", got "%s"' %
+               (', '.join(optional_uses_libraries), ', '.join(manifest_optional_uses_libraries)))
+
+  if err:
+    raise ManifestMismatchError('\n'.join(err))
+
+
+def parse_uses_library(application):
+  """Extract uses-library tags from the manifest.
+
+  Args:
+    application: the <application> tag in the manifest.
+  """
+
+  libs = get_children_with_tag(application, 'uses-library')
+
+  uses_libraries = [uses_library_name(x) for x in libs if uses_library_required(x)]
+  optional_uses_libraries = [uses_library_name(x) for x in libs if not uses_library_required(x)]
+
+  return first_unique_elements(uses_libraries), first_unique_elements(optional_uses_libraries)
+
+
+def first_unique_elements(l):
+  result = []
+  [result.append(x) for x in l if x not in result]
+  return result
+
+
+def uses_library_name(lib):
+  """Extract the name attribute of a uses-library tag.
+
+  Args:
+    lib: a <uses-library> tag.
+  """
+  name = lib.getAttributeNodeNS(android_ns, 'name')
+  return name.value if name is not None else ""
+
+
+def uses_library_required(lib):
+  """Extract the required attribute of a uses-library tag.
+
+  Args:
+    lib: a <uses-library> tag.
+  """
+  required = lib.getAttributeNodeNS(android_ns, 'required')
+  return (required.value == 'true') if required is not None else True
+
+
+def extract_target_sdk_version(doc):
+  """Returns the targetSdkVersion from the manifest.
+
+  Args:
+    doc: The XML document.
+  Raises:
+    RuntimeError: invalid manifest
+  """
+
+  manifest = parse_manifest(doc)
+
+  # Get or insert the uses-sdk element
+  uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
+  if len(uses_sdk) > 1:
+    raise RuntimeError('found multiple uses-sdk elements')
+  elif len(uses_sdk) == 0:
+    raise RuntimeError('missing uses-sdk element')
+
+  uses_sdk = uses_sdk[0]
+
+  min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion')
+  if min_attr is None:
+    raise RuntimeError('minSdkVersion is not specified')
+
+  target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion')
+  if target_attr is None:
+    target_attr = min_attr
+
+  return target_attr.value
+
+
+def main():
+  """Program entry point."""
+  try:
+    args = parse_args()
+
+    doc = minidom.parse(args.input)
+
+    if args.enforce_uses_libraries:
+      enforce_uses_libraries(doc,
+                             args.uses_libraries,
+                             args.optional_uses_libraries)
+
+    if args.extract_target_sdk_version:
+      print(extract_target_sdk_version(doc))
+
+    if args.output:
+      with open(args.output, 'wb') as f:
+        write_xml(f, doc)
+
+  # pylint: disable=broad-except
+  except Exception as err:
+    print('error: ' + str(err), file=sys.stderr)
+    sys.exit(-1)
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
new file mode 100755
index 0000000..7baad5d
--- /dev/null
+++ b/scripts/manifest_check_test.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+"""Unit tests for manifest_fixer.py."""
+
+import sys
+import unittest
+from xml.dom import minidom
+
+import manifest_check
+
+sys.dont_write_bytecode = True
+
+
+def uses_library(name, attr=''):
+  return '<uses-library android:name="%s"%s />' % (name, attr)
+
+
+def required(value):
+  return ' android:required="%s"' % ('true' if value else 'false')
+
+
+class EnforceUsesLibrariesTest(unittest.TestCase):
+  """Unit tests for add_extract_native_libs function."""
+
+  def run_test(self, input_manifest, uses_libraries=None, optional_uses_libraries=None):
+    doc = minidom.parseString(input_manifest)
+    try:
+      manifest_check.enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries)
+      return True
+    except manifest_check.ManifestMismatchError:
+      return False
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <application>\n'
+      '    %s\n'
+      '    </application>\n'
+      '</manifest>\n')
+
+  def test_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo'))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_uses_library_required(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(True)))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_expected_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_expected_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo'))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_missing_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('')
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_missing_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('')
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_extra_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo'))
+    matches = self.run_test(manifest_input)
+    self.assertFalse(matches)
+
+  def test_extra_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+    matches = self.run_test(manifest_input)
+    self.assertFalse(matches)
+
+  def test_multiple_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('bar')]))
+    matches = self.run_test(manifest_input, uses_libraries=['foo', 'bar'])
+    self.assertTrue(matches)
+
+  def test_multiple_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+                                                      uses_library('bar', required(False))]))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo', 'bar'])
+    self.assertTrue(matches)
+
+  def test_order_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('bar')]))
+    matches = self.run_test(manifest_input, uses_libraries=['bar', 'foo'])
+    self.assertFalse(matches)
+
+  def test_order_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+                                                      uses_library('bar', required(False))]))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['bar', 'foo'])
+    self.assertFalse(matches)
+
+  def test_duplicate_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('foo')]))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_duplicate_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+                                                      uses_library('foo', required(False))]))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_mixed(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('bar', required(False))]))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'],
+                            optional_uses_libraries=['bar'])
+    self.assertTrue(matches)
+
+
+class ExtractTargetSdkVersionTest(unittest.TestCase):
+  def test_target_sdk_version(self):
+    manifest = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" />\n'
+      '</manifest>\n')
+    doc = minidom.parseString(manifest)
+    target_sdk_version = manifest_check.extract_target_sdk_version(doc)
+    self.assertEqual(target_sdk_version, '29')
+
+  def test_min_sdk_version(self):
+    manifest = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <uses-sdk android:minSdkVersion="28" />\n'
+      '</manifest>\n')
+    doc = minidom.parseString(manifest)
+    target_sdk_version = manifest_check.extract_target_sdk_version(doc)
+    self.assertEqual(target_sdk_version, '28')
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 83868e6..945bc18 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -17,30 +17,20 @@
 """A tool for inserting values from the build system into a manifest."""
 
 from __future__ import print_function
+
 import argparse
 import sys
 from xml.dom import minidom
 
 
-android_ns = 'http://schemas.android.com/apk/res/android'
-
-
-def get_children_with_tag(parent, tag_name):
-  children = []
-  for child in  parent.childNodes:
-    if child.nodeType == minidom.Node.ELEMENT_NODE and \
-       child.tagName == tag_name:
-      children.append(child)
-  return children
-
-
-def find_child_with_attribute(element, tag_name, namespace_uri,
-                              attr_name, value):
-  for child in get_children_with_tag(element, tag_name):
-    attr = child.getAttributeNodeNS(namespace_uri, attr_name)
-    if attr is not None and attr.value == value:
-      return child
-  return None
+from manifest import android_ns
+from manifest import compare_version_gt
+from manifest import ensure_manifest_android_ns
+from manifest import find_child_with_attribute
+from manifest import get_children_with_tag
+from manifest import get_indent
+from manifest import parse_manifest
+from manifest import write_xml
 
 
 def parse_args():
@@ -69,81 +59,14 @@
                       default=None, type=lambda x: (str(x).lower() == 'true'),
                       help=('specify if the app wants to use embedded native libraries. Must not conflict '
                             'if already declared in the manifest.'))
+  parser.add_argument('--has-no-code', dest='has_no_code', action='store_true',
+                      help=('adds hasCode="false" attribute to application. Ignored if application elem '
+                            'already has a hasCode attribute.'))
   parser.add_argument('input', help='input AndroidManifest.xml file')
   parser.add_argument('output', help='output AndroidManifest.xml file')
   return parser.parse_args()
 
 
-def parse_manifest(doc):
-  """Get the manifest element."""
-
-  manifest = doc.documentElement
-  if manifest.tagName != 'manifest':
-    raise RuntimeError('expected manifest tag at root')
-  return manifest
-
-
-def ensure_manifest_android_ns(doc):
-  """Make sure the manifest tag defines the android namespace."""
-
-  manifest = parse_manifest(doc)
-
-  ns = manifest.getAttributeNodeNS(minidom.XMLNS_NAMESPACE, 'android')
-  if ns is None:
-    attr = doc.createAttributeNS(minidom.XMLNS_NAMESPACE, 'xmlns:android')
-    attr.value = android_ns
-    manifest.setAttributeNode(attr)
-  elif ns.value != android_ns:
-    raise RuntimeError('manifest tag has incorrect android namespace ' +
-                       ns.value)
-
-
-def as_int(s):
-  try:
-    i = int(s)
-  except ValueError:
-    return s, False
-  return i, True
-
-
-def compare_version_gt(a, b):
-  """Compare two SDK versions.
-
-  Compares a and b, treating codenames like 'Q' as higher
-  than numerical versions like '28'.
-
-  Returns True if a > b
-
-  Args:
-    a: value to compare
-    b: value to compare
-  Returns:
-    True if a is a higher version than b
-  """
-
-  a, a_is_int = as_int(a.upper())
-  b, b_is_int = as_int(b.upper())
-
-  if a_is_int == b_is_int:
-    # Both are codenames or both are versions, compare directly
-    return a > b
-  else:
-    # One is a codename, the other is not.  Return true if
-    # b is an integer version
-    return b_is_int
-
-
-def get_indent(element, default_level):
-  indent = ''
-  if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
-    text = element.nodeValue
-    indent = text[:len(text)-len(text.lstrip())]
-  if not indent or indent == '\n':
-    # 1 indent = 4 space
-    indent = '\n' + (' ' * default_level * 4)
-  return indent
-
-
 def raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library):
   """Ensure the manifest contains a <uses-sdk> tag with a minSdkVersion.
 
@@ -151,6 +74,7 @@
     doc: The XML document.  May be modified by this function.
     min_sdk_version: The requested minSdkVersion attribute.
     target_sdk_version: The requested targetSdkVersion attribute.
+    library: True if the manifest is for a library.
   Raises:
     RuntimeError: invalid manifest
   """
@@ -249,6 +173,7 @@
     indent = get_indent(application.previousSibling, 1)
     application.appendChild(doc.createTextNode(indent))
 
+
 def add_uses_non_sdk_api(doc):
   """Add android:usesNonSdkApi=true attribute to <application>.
 
@@ -323,10 +248,26 @@
                        (attr.value, value))
 
 
-def write_xml(f, doc):
-  f.write('<?xml version="1.0" encoding="utf-8"?>\n')
-  for node in doc.childNodes:
-    f.write(node.toxml(encoding='utf-8') + '\n')
+def set_has_code_to_false(doc):
+  manifest = parse_manifest(doc)
+  elems = get_children_with_tag(manifest, 'application')
+  application = elems[0] if len(elems) == 1 else None
+  if len(elems) > 1:
+    raise RuntimeError('found multiple <application> tags')
+  elif not elems:
+    application = doc.createElement('application')
+    indent = get_indent(manifest.firstChild, 1)
+    first = manifest.firstChild
+    manifest.insertBefore(doc.createTextNode(indent), first)
+    manifest.insertBefore(application, first)
+
+  attr = application.getAttributeNodeNS(android_ns, 'hasCode')
+  if attr is not None:
+    # Do nothing if the application already has a hasCode attribute.
+    return
+  attr = doc.createAttributeNS(android_ns, 'android:hasCode')
+  attr.value = 'false'
+  application.setAttributeNode(attr)
 
 
 def main():
@@ -353,6 +294,9 @@
     if args.use_embedded_dex:
       add_use_embedded_dex(doc)
 
+    if args.has_no_code:
+      set_has_code_to_false(doc)
+
     if args.extract_native_libs is not None:
       add_extract_native_libs(doc, args.extract_native_libs)
 
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 4ad9afa..ea8095e 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-"""Unit tests for manifest_fixer_test.py."""
+"""Unit tests for manifest_fixer.py."""
 
 import StringIO
 import sys
@@ -231,7 +231,7 @@
 
   def run_test(self, input_manifest, new_uses_libraries):
     doc = minidom.parseString(input_manifest)
-    manifest_fixer.add_uses_libraries(doc, new_uses_libraries)
+    manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
     output = StringIO.StringIO()
     manifest_fixer.write_xml(output, doc)
     return output.getvalue()
@@ -393,10 +393,10 @@
     return output.getvalue()
 
   manifest_tmpl = (
-    '<?xml version="1.0" encoding="utf-8"?>\n'
-    '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
-    '    <application%s/>\n'
-    '</manifest>\n')
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <application%s/>\n'
+      '</manifest>\n')
 
   def extract_native_libs(self, value):
     return ' android:extractNativeLibs="%s"' % value
@@ -424,5 +424,47 @@
     self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
 
 
+class AddNoCodeApplicationTest(unittest.TestCase):
+  """Unit tests for set_has_code_to_false function."""
+
+  def run_test(self, input_manifest):
+    doc = minidom.parseString(input_manifest)
+    manifest_fixer.set_has_code_to_false(doc)
+    output = StringIO.StringIO()
+    manifest_fixer.write_xml(output, doc)
+    return output.getvalue()
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '%s'
+      '</manifest>\n')
+
+  def test_no_application(self):
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
+    output = self.run_test(manifest_input)
+    self.assertEqual(output, expected)
+
+  def test_has_application_no_has_code(self):
+    manifest_input = self.manifest_tmpl % '    <application/>\n'
+    expected = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
+    output = self.run_test(manifest_input)
+    self.assertEqual(output, expected)
+
+  def test_has_application_has_code_false(self):
+    """ Do nothing if there's already an application elemeent. """
+    manifest_input = self.manifest_tmpl % '    <application android:hasCode="false"/>\n'
+    output = self.run_test(manifest_input)
+    self.assertEqual(output, manifest_input)
+
+  def test_has_application_has_code_true(self):
+    """ Do nothing if there's already an application elemeent even if its
+     hasCode attribute is true. """
+    manifest_input = self.manifest_tmpl % '    <application android:hasCode="true"/>\n'
+    output = self.run_test(manifest_input)
+    self.assertEqual(output, manifest_input)
+
+
 if __name__ == '__main__':
-  unittest.main()
+  unittest.main(verbosity=2)
diff --git a/scripts/setup_go_workspace_for_soong.sh b/scripts/setup_go_workspace_for_soong.sh
index 6374aae..479d09c 100755
--- a/scripts/setup_go_workspace_for_soong.sh
+++ b/scripts/setup_go_workspace_for_soong.sh
@@ -349,6 +349,7 @@
   "${ANDROID_PATH}/external/golang-protobuf|${OUTPUT_PATH}/src/github.com/golang/protobuf"
   "${ANDROID_PATH}/external/llvm/soong|${OUTPUT_PATH}/src/android/soong/llvm"
   "${ANDROID_PATH}/external/clang/soong|${OUTPUT_PATH}/src/android/soong/clang"
+  "${ANDROID_PATH}/external/robolectric-shadows/soong|${OUTPUT_PATH}/src/android/soong/robolectric"
 )
 
 main "$@"
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 0f77da8..bd62619 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -28,6 +28,7 @@
 #   --add-gnu-debuglink
 #   --keep-mini-debug-info
 #   --keep-symbols
+#   --keep-symbols-and-debug-frame
 #   --use-gnu-strip
 #   --remove-build-id
 
@@ -39,11 +40,12 @@
     cat <<EOF
 Usage: strip.sh [options] -k symbols -i in-file -o out-file -d deps-file
 Options:
-        --add-gnu-debuglink     Add a gnu-debuglink section to out-file
-        --keep-mini-debug-info  Keep compressed debug info in out-file
-        --keep-symbols          Keep symbols in out-file
-        --use-gnu-strip         Use strip/objcopy instead of llvm-{strip,objcopy}
-        --remove-build-id       Remove the gnu build-id section in out-file
+        --add-gnu-debuglink             Add a gnu-debuglink section to out-file
+        --keep-mini-debug-info          Keep compressed debug info in out-file
+        --keep-symbols                  Keep symbols in out-file
+        --keep-symbols-and-debug-frame  Keep symbols and .debug_frame in out-file
+        --use-gnu-strip                 Use strip/objcopy instead of llvm-{strip,objcopy}
+        --remove-build-id               Remove the gnu build-id section in out-file
 EOF
     exit 1
 }
@@ -63,6 +65,15 @@
     fi
 }
 
+do_strip_keep_symbols_and_debug_frame() {
+    REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {if ($2 != ".debug_frame") {print "--remove-section " $2}}' | xargs`
+    if [ -z "${use_gnu_strip}" ]; then
+        "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
+    else
+        "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
+    fi
+}
+
 do_strip_keep_symbols() {
     REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {print "--remove-section " $2}' | xargs`
     if [ -z "${use_gnu_strip}" ]; then
@@ -148,6 +159,7 @@
                 add-gnu-debuglink) add_gnu_debuglink=true ;;
                 keep-mini-debug-info) keep_mini_debug_info=true ;;
                 keep-symbols) keep_symbols=true ;;
+                keep-symbols-and-debug-frame) keep_symbols_and_debug_frame=true ;;
                 remove-build-id) remove_build_id=true ;;
                 use-gnu-strip) use_gnu_strip=true ;;
                 *) echo "Unknown option --${OPTARG}"; usage ;;
@@ -177,6 +189,16 @@
     usage
 fi
 
+if [ ! -z "${keep_symbols}" -a ! -z "${keep_symbols_and_debug_frame}" ]; then
+    echo "--keep-symbols and --keep-symbols-and-debug-frame cannot be used together"
+    usage
+fi
+
+if [ ! -z "${keep_mini_debug_info}" -a ! -z "${keep_symbols_and_debug_frame}" ]; then
+    echo "--keep-symbols-mini-debug-info and --keep-symbols-and-debug-frame cannot be used together"
+    usage
+fi
+
 if [ ! -z "${symbols_to_keep}" -a ! -z "${keep_symbols}" ]; then
     echo "--keep-symbols and -k cannot be used together"
     usage
@@ -195,6 +217,8 @@
     do_strip_keep_symbol_list
 elif [ ! -z "${keep_mini_debug_info}" ]; then
     do_strip_keep_mini_debug_info
+elif [ ! -z "${keep_symbols_and_debug_frame}" ]; then
+    do_strip_keep_symbols_and_debug_frame
 else
     do_strip
 fi
diff --git a/scripts/system-clang-format b/scripts/system-clang-format
index 55773a2..14abd93 100644
--- a/scripts/system-clang-format
+++ b/scripts/system-clang-format
@@ -4,6 +4,7 @@
 ColumnLimit: 100
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
+IncludeBlocks: Preserve
 IndentWidth: 4
 ContinuationIndentWidth: 8
 PointerAlignment: Left
diff --git a/scripts/system-clang-format-2 b/scripts/system-clang-format-2
index ede5d7e..e28b379 100644
--- a/scripts/system-clang-format-2
+++ b/scripts/system-clang-format-2
@@ -3,6 +3,7 @@
 ColumnLimit: 100
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
+IncludeBlocks: Preserve
 IndentWidth: 2
 PointerAlignment: Left
 TabWidth: 2
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 08845b7..86061c6 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -18,6 +18,7 @@
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/java"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -63,10 +64,6 @@
 	return "lib" + m.Name()
 }
 
-func (m *syspropLibrary) SyspropJavaModule() *java.SdkLibrary {
-	return &m.SdkLibrary
-}
-
 func syspropLibraryFactory() android.Module {
 	m := &syspropLibrary{}
 
@@ -78,7 +75,7 @@
 	m.SetNoDist()
 	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
-
+	android.AddLoadHook(m, func(ctx android.LoadHookContext) { m.SdkLibrary.CreateInternalModules(ctx) })
 	return m
 }
 
@@ -126,6 +123,8 @@
 		Sysprop          struct {
 			Platform *bool
 		}
+		Header_libs []string
+		Shared_libs []string
 	}{}
 
 	ccProps.Name = proptools.StringPtr(m.CcModuleName())
@@ -133,6 +132,8 @@
 	ccProps.Device_specific = proptools.BoolPtr(deviceSpecific)
 	ccProps.Product_specific = proptools.BoolPtr(productSpecific)
 	ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
+	ccProps.Header_libs = []string{"libbase_headers"}
+	ccProps.Shared_libs = []string{"liblog"}
 
 	ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &m.commonProperties, &ccProps)
 }
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 07406b3..0566036 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -61,15 +61,11 @@
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
 	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
 	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
-	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("load_hooks", android.LoadHookMutator).Parallel()
-	})
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
 	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
-		ctx.TopDown("java_sdk_library", java.SdkLibraryMutator).Parallel()
 	})
 
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
@@ -136,8 +132,8 @@
 		"prebuilts/sdk/Android.bp":                                            []byte(`prebuilt_apis { name: "sdk", api_dirs: ["28", "current"],}`),
 
 		// For framework-res, which is an implicit dependency for framework
-		"AndroidManifest.xml":                   nil,
-		"build/target/product/security/testkey": nil,
+		"AndroidManifest.xml":                        nil,
+		"build/make/target/product/security/testkey": nil,
 
 		"build/soong/scripts/jar-wrapper.sh": nil,
 
@@ -282,7 +278,7 @@
 
 		cc_library {
 			name: "liblog",
-			no_libgcc: true,
+			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
@@ -317,13 +313,13 @@
 	vendorVariant := "android_arm64_armv8-a_vendor_static"
 
 	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/include"
-	platformSystemCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
-	platformSystemVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/system/include"
+	platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/public/include"
+	platformPublicVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/public/include"
 
-	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/public/include"
 
 	vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor_static/gen/sysprop/include"
-	vendorSystemPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+	vendorPublicPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/public/include"
 
 	platformClient := ctx.ModuleForTests("cc-client-platform", coreVariant)
 	platformFlags := platformClient.Rule("cc").Args["cFlags"]
@@ -346,20 +342,20 @@
 	productClient := ctx.ModuleForTests("cc-client-product", coreVariant)
 	productFlags := productClient.Rule("cc").Args["cFlags"]
 
-	// Product should use platform's and vendor's system headers
+	// Product should use platform's and vendor's public headers
 	if !strings.Contains(productFlags, platformOnProductPath) ||
-		!strings.Contains(productFlags, vendorSystemPath) {
+		!strings.Contains(productFlags, vendorPublicPath) {
 		t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
-			platformSystemCorePath, vendorSystemPath, productFlags)
+			platformPublicCorePath, vendorPublicPath, productFlags)
 	}
 
 	vendorClient := ctx.ModuleForTests("cc-client-vendor", vendorVariant)
 	vendorFlags := vendorClient.Rule("cc").Args["cFlags"]
 
-	// Vendor should use platform's system header and vendor's internal header
-	if !strings.Contains(vendorFlags, platformSystemVendorPath) ||
+	// Vendor should use platform's public header and vendor's internal header
+	if !strings.Contains(vendorFlags, platformPublicVendorPath) ||
 		!strings.Contains(vendorFlags, vendorInternalPath) {
 		t.Errorf("flags for vendor must contain %#v and %#v, but was %#v.",
-			platformSystemVendorPath, vendorInternalPath, vendorFlags)
+			platformPublicVendorPath, vendorInternalPath, vendorFlags)
 	}
 }
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index da5dabe..952b022 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"sort"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -39,9 +38,9 @@
 }
 
 var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
-	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_OPTIONS}&'${extraOptions}'&g' $template > $out",
+	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g' $template > $out",
 	CommandDeps: []string{"$template"},
-}, "name", "template", "extraOptions")
+}, "name", "template", "extraConfigs")
 
 func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string) (path android.Path, autogenPath android.WritablePath) {
 	if p := getTestConfig(ctx, prop); p != nil {
@@ -57,17 +56,38 @@
 	}
 }
 
-func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, optionsMap map[string]string) {
-	// If no test option found, delete {EXTRA_OPTIONS} line.
-	var options []string
-	for optionName, value := range optionsMap {
-		if value != "" {
-			options = append(options, fmt.Sprintf(`<option name="%s" value="%s" />`, optionName, value))
-		}
+type Config interface {
+	Config() string
+}
+
+type Option struct {
+	Name  string
+	Value string
+}
+
+var _ Config = Option{}
+
+func (o Option) Config() string {
+	return fmt.Sprintf(`<option name="%s" value="%s" />`, o.Name, o.Value)
+}
+
+type Preparer struct {
+	Class string
+}
+
+var _ Config = Preparer{}
+
+func (p Preparer) Config() string {
+	return fmt.Sprintf(`<target_preparer class="%s" />`, p.Class)
+}
+
+func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) {
+	var configStrings []string
+	for _, config := range configs {
+		configStrings = append(configStrings, config.Config())
 	}
-	sort.Strings(options)
-	extraOptions := strings.Join(options, "\n        ")
-	extraOptions = proptools.NinjaAndShellEscape(extraOptions)
+	extraConfigs := strings.Join(configStrings, "\n        ")
+	extraConfigs = proptools.NinjaAndShellEscape(extraConfigs)
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        autogenTestConfig,
@@ -76,26 +96,23 @@
 		Args: map[string]string{
 			"name":         ctx.ModuleName(),
 			"template":     template,
-			"extraOptions": extraOptions,
+			"extraConfigs": extraConfigs,
 		},
 	})
 }
 
 func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
-	testConfigTemplateProp *string, testSuites []string,
-	optionsMap map[string]string) android.Path {
+	testConfigTemplateProp *string, testSuites []string, config []Config) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), optionsMap)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), config)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}",
-					optionsMap)
+				autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config)
 			} else {
-				autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}",
-					optionsMap)
+				autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config)
 			}
 		}
 		return autogenPath
@@ -104,14 +121,14 @@
 }
 
 func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string,
-	testConfigTemplateProp *string, testSuites []string) android.Path {
+	testConfigTemplateProp *string, testSuites []string, configs []Config) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+			autogenTemplate(ctx, autogenPath, templatePath.String(), configs)
 		} else {
-			autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", nil)
+			autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs)
 		}
 		return autogenPath
 	}
diff --git a/ui/build/build.go b/ui/build/build.go
index 0ae06d6..59d1474 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -166,11 +166,13 @@
 		runMakeProductConfig(ctx, config)
 	}
 
-	if inList("installclean", config.Arguments()) {
+	if inList("installclean", config.Arguments()) ||
+		inList("install-clean", config.Arguments()) {
 		installClean(ctx, config, what)
 		ctx.Println("Deleted images and staging directories.")
 		return
-	} else if inList("dataclean", config.Arguments()) {
+	} else if inList("dataclean", config.Arguments()) ||
+		inList("data-clean", config.Arguments()) {
 		dataClean(ctx, config, what)
 		ctx.Println("Deleted data files.")
 		return
diff --git a/ui/build/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 7eb3a72..4e19e9e 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -53,15 +53,39 @@
 
 	pdkBuild bool
 
-	brokenDupRules     bool
-	brokenPhonyTargets bool
-	brokenUsesNetwork  bool
+	brokenDupRules    bool
+	brokenUsesNetwork bool
 
 	pathReplaced bool
 }
 
 const srcDirFileCheck = "build/soong/root.bp"
 
+type BuildAction uint
+
+const (
+	// Builds all of the modules and their dependencies of a specified directory, relative to the root
+	// directory of the source tree.
+	BUILD_MODULES_IN_A_DIRECTORY BuildAction = iota
+
+	// Builds all of the modules and their dependencies of a list of specified directories. All specified
+	// directories are relative to the root directory of the source tree.
+	BUILD_MODULES_IN_DIRECTORIES
+
+	// Build a list of specified modules. If none was specified, simply build the whole source tree.
+	BUILD_MODULES
+)
+
+// checkTopDir validates that the current directory is at the root directory of the source tree.
+func checkTopDir(ctx Context) {
+	if _, err := os.Stat(srcDirFileCheck); err != nil {
+		if os.IsNotExist(err) {
+			ctx.Fatalf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
+		}
+		ctx.Fatalln("Error verifying tree state:", err)
+	}
+}
+
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
 		environ: OsEnvironment(),
@@ -155,12 +179,7 @@
 	ret.environ.Set("TMPDIR", absPath(ctx, ret.TempDir()))
 
 	// Precondition: the current directory is the top of the source tree
-	if _, err := os.Stat(srcDirFileCheck); err != nil {
-		if os.IsNotExist(err) {
-			log.Fatalf("Current working directory must be the source tree. %q not found", srcDirFileCheck)
-		}
-		log.Fatalln("Error verifying tree state:", err)
-	}
+	checkTopDir(ctx)
 
 	if srcDir := absPath(ctx, "."); strings.ContainsRune(srcDir, ' ') {
 		log.Println("You are building in a directory whose absolute path contains a space character:")
@@ -230,6 +249,209 @@
 	return Config{ret}
 }
 
+// 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)...)
+}
+
+// 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 {
+	// 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.
+	checkTopDir(ctx)
+	topDir, err := os.Getwd()
+	if err != nil {
+		ctx.Fatalf("Error retrieving top directory: %v", err)
+	}
+	dir, err = filepath.EvalSymlinks(dir)
+	if err != nil {
+		ctx.Fatalf("Unable to evaluate symlink of %s: %v", dir, err)
+	}
+	dir, err = filepath.Abs(dir)
+	if err != nil {
+		ctx.Fatalf("Unable to find absolute path %s: %v", dir, err)
+	}
+	relDir, err := filepath.Rel(topDir, dir)
+	if err != nil {
+		ctx.Fatalf("Unable to find relative path %s of %s: %v", relDir, topDir, err)
+	}
+	// If there are ".." in the path, it's not in the source tree.
+	if strings.Contains(relDir, "..") {
+		ctx.Fatalf("Directory %s is not under the source tree %s", dir, topDir)
+	}
+
+	configArgs := args[:]
+
+	// If the arguments contains GET-INSTALL-PATH, change the target name prefix from MODULES-IN- to
+	// GET-INSTALL-PATH-IN- to extract the installation path instead of building the modules.
+	targetNamePrefix := "MODULES-IN-"
+	if inList("GET-INSTALL-PATH", configArgs) {
+		targetNamePrefix = "GET-INSTALL-PATH-IN-"
+		configArgs = removeFromList("GET-INSTALL-PATH", configArgs)
+	}
+
+	var buildFiles []string
+	var targets []string
+
+	switch action {
+	case BUILD_MODULES:
+		// No additional processing is required when building a list of specific modules or all modules.
+	case BUILD_MODULES_IN_A_DIRECTORY:
+		// If dir is the root source tree, all the modules are built of the source tree are built so
+		// no need to find the build file.
+		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")
+		}
+		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)
+		}
+	}
+
+	// Tidy only override all other specified targets.
+	tidyOnly := os.Getenv("WITH_TIDY_ONLY")
+	if tidyOnly == "true" || tidyOnly == "1" {
+		configArgs = append(configArgs, "tidy_only")
+	} else {
+		configArgs = append(configArgs, targets...)
+	}
+
+	return configArgs
+}
+
+// convertToTarget replaces "/" to "-" in dir and pre-append the targetNamePrefix to the target name.
+func convertToTarget(dir string, targetNamePrefix string) string {
+	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.
+func findBuildFile(ctx Context, dir string) string {
+	// If the string is empty, assume it is top directory of the source tree.
+	if 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")
+			}
+			if !os.IsNotExist(err) {
+				ctx.Fatalf("Error retrieving the build file stats: %v", err)
+			}
+		}
+	}
+
+	return ""
+}
+
+// splitArgs iterates over the arguments list and splits into two lists: arguments and directories.
+func splitArgs(args []string) (newArgs []string, dirs []string) {
+	specialArgs := map[string]bool{
+		"showcommands": true,
+		"snod":         true,
+		"dist":         true,
+		"checkbuild":   true,
+	}
+
+	newArgs = []string{}
+	dirs = []string{}
+
+	for _, arg := range args {
+		// It's a dash argument if it starts with "-" or it's a key=value pair, it's not a directory.
+		if strings.IndexRune(arg, '-') == 0 || strings.IndexRune(arg, '=') != -1 {
+			newArgs = append(newArgs, arg)
+			continue
+		}
+
+		if _, ok := specialArgs[arg]; ok {
+			newArgs = append(newArgs, arg)
+			continue
+		}
+
+		dirs = append(dirs, arg)
+	}
+
+	return newArgs, dirs
+}
+
+// getTargetsFromDirs iterates over the dirs list and creates a list of targets to build. If a
+// 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) {
+	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.
+		s := strings.Split(dir, ":")
+		l := len(s)
+		if l > 2 { // more than one ":" was specified.
+			ctx.Fatalf("%s not in proper directory:target1,target2,... format (\":\" was specified more than once)", dir)
+		}
+
+		dir = filepath.Join(relDir, s[0])
+		if _, err := os.Stat(dir); err != nil {
+			ctx.Fatalf("couldn't find directory %s", dir)
+		}
+
+		// Verify that if there are any targets specified after ":". Each target is separated by ",".
+		var newTargets []string
+		if l == 2 && s[1] != "" {
+			newTargets = strings.Split(s[1], ",")
+			if inList("", newTargets) {
+				ctx.Fatalf("%s not in proper directory:target1,target2,... format", dir)
+			}
+		}
+
+		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 len(newTargets) > 0 {
+			if buildFileDir != dir {
+				ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
+			}
+		} else {
+			newTargets = []string{convertToTarget(buildFileDir, targetNamePrefix)}
+		}
+
+		buildFiles = append(buildFiles, buildFile)
+		targets = append(targets, newTargets...)
+	}
+
+	return targets, buildFiles
+}
+
 func (c *configImpl) parseArgs(ctx Context, args []string) {
 	for i := 0; i < len(args); i++ {
 		arg := strings.TrimSpace(args[i])
@@ -615,14 +837,6 @@
 	return c.brokenDupRules
 }
 
-func (c *configImpl) SetBuildBrokenPhonyTargets(val bool) {
-	c.brokenPhonyTargets = val
-}
-
-func (c *configImpl) BuildBrokenPhonyTargets() bool {
-	return c.brokenPhonyTargets
-}
-
 func (c *configImpl) SetBuildBrokenUsesNetwork(val bool) {
 	c.brokenUsesNetwork = val
 }
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 242e3af..7a1ee17 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -17,19 +17,22 @@
 import (
 	"bytes"
 	"context"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
 	"reflect"
 	"strings"
 	"testing"
 
 	"android/soong/ui/logger"
-	"android/soong/ui/terminal"
 )
 
 func testContext() Context {
 	return Context{&ContextImpl{
 		Context: context.Background(),
 		Logger:  logger.New(&bytes.Buffer{}),
-		Writer:  terminal.NewWriter(terminal.NewCustomStdio(&bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{})),
+		Writer:  &bytes.Buffer{},
 	}}
 }
 
@@ -173,3 +176,976 @@
 		})
 	}
 }
+
+func TestConfigCheckTopDir(t *testing.T) {
+	ctx := testContext()
+	buildRootDir := filepath.Dir(srcDirFileCheck)
+	expectedErrStr := fmt.Sprintf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
+
+	tests := []struct {
+		// ********* Setup *********
+		// Test description.
+		description string
+
+		// ********* Action *********
+		// If set to true, the build root file is created.
+		rootBuildFile bool
+
+		// The current path where Soong is being executed.
+		path string
+
+		// ********* Validation *********
+		// Expecting error and validate the error string against expectedErrStr.
+		wantErr bool
+	}{{
+		description:   "current directory is the root source tree",
+		rootBuildFile: true,
+		path:          ".",
+		wantErr:       false,
+	}, {
+		description:   "one level deep in the source tree",
+		rootBuildFile: true,
+		path:          "1",
+		wantErr:       true,
+	}, {
+		description:   "very deep in the source tree",
+		rootBuildFile: true,
+		path:          "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7",
+		wantErr:       true,
+	}, {
+		description:   "outside of source tree",
+		rootBuildFile: false,
+		path:          "1/2/3/4/5",
+		wantErr:       true,
+	}}
+
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				if !tt.wantErr {
+					t.Fatalf("Got unexpected error: %v", err)
+				}
+				if expectedErrStr != err.Error() {
+					t.Fatalf("expected %s, got %s", expectedErrStr, err.Error())
+				}
+			})
+
+			// Create the root source tree.
+			rootDir, err := ioutil.TempDir("", "")
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer os.RemoveAll(rootDir)
+
+			// Create the build root file. This is to test if topDir returns an error if the build root
+			// file does not exist.
+			if tt.rootBuildFile {
+				dir := filepath.Join(rootDir, buildRootDir)
+				if err := os.MkdirAll(dir, 0755); err != nil {
+					t.Errorf("failed to create %s directory: %v", dir, err)
+				}
+				f := filepath.Join(rootDir, srcDirFileCheck)
+				if err := ioutil.WriteFile(f, []byte{}, 0644); err != nil {
+					t.Errorf("failed to create file %s: %v", f, err)
+				}
+			}
+
+			// Next block of code is to set the current directory.
+			dir := rootDir
+			if tt.path != "" {
+				dir = filepath.Join(dir, tt.path)
+				if err := os.MkdirAll(dir, 0755); err != nil {
+					t.Errorf("failed to create %s directory: %v", dir, err)
+				}
+			}
+			curDir, err := os.Getwd()
+			if err != nil {
+				t.Fatalf("failed to get the current directory: %v", err)
+			}
+			defer func() { os.Chdir(curDir) }()
+
+			if err := os.Chdir(dir); err != nil {
+				t.Fatalf("failed to change directory to %s: %v", dir, err)
+			}
+
+			checkTopDir(ctx)
+		})
+	}
+}
+
+func TestConfigConvertToTarget(t *testing.T) {
+	tests := []struct {
+		// ********* Setup *********
+		// Test description.
+		description string
+
+		// ********* Action *********
+		// The current directory where Soong is being executed.
+		dir string
+
+		// The current prefix string to be pre-appended to the target.
+		prefix string
+
+		// ********* Validation *********
+		// The expected target to be invoked in ninja.
+		expectedTarget string
+	}{{
+		description:    "one level directory in source tree",
+		dir:            "test1",
+		prefix:         "MODULES-IN-",
+		expectedTarget: "MODULES-IN-test1",
+	}, {
+		description:    "multiple level directories in source tree",
+		dir:            "test1/test2/test3/test4",
+		prefix:         "GET-INSTALL-PATH-IN-",
+		expectedTarget: "GET-INSTALL-PATH-IN-test1-test2-test3-test4",
+	}}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			target := convertToTarget(tt.dir, tt.prefix)
+			if target != tt.expectedTarget {
+				t.Errorf("expected %s, got %s for target", tt.expectedTarget, target)
+			}
+		})
+	}
+}
+
+func setTop(t *testing.T, dir string) func() {
+	curDir, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("failed to get current directory: %v", err)
+	}
+	if err := os.Chdir(dir); err != nil {
+		t.Fatalf("failed to change directory to top dir %s: %v", dir, err)
+	}
+	return func() { os.Chdir(curDir) }
+}
+
+func createBuildFiles(t *testing.T, topDir string, buildFiles []string) {
+	for _, buildFile := range buildFiles {
+		buildFile = filepath.Join(topDir, buildFile)
+		if err := ioutil.WriteFile(buildFile, []byte{}, 0644); err != nil {
+			t.Errorf("failed to create file %s: %v", buildFile, err)
+		}
+	}
+}
+
+func createDirectories(t *testing.T, topDir string, dirs []string) {
+	for _, dir := range dirs {
+		dir = filepath.Join(topDir, dir)
+		if err := os.MkdirAll(dir, 0755); err != nil {
+			t.Errorf("failed to create %s directory: %v", dir, err)
+		}
+	}
+}
+
+func TestConfigGetTargets(t *testing.T) {
+	ctx := testContext()
+	tests := []struct {
+		// ********* Setup *********
+		// Test description.
+		description string
+
+		// Directories that exist in the source tree.
+		dirsInTrees []string
+
+		// Build files that exists in the source tree.
+		buildFiles []string
+
+		// ********* Action *********
+		// Directories passed in to soong_ui.
+		dirs []string
+
+		// Current directory that the user executed the build action command.
+		curDir string
+
+		// ********* Validation *********
+		// 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, build file does not exist",
+		dirsInTrees: []string{"0/1/2/3"},
+		buildFiles:  []string{},
+		dirs:        []string{"1/2/3"},
+		curDir:      "0",
+		errStr:      "Build file not found for 0/1/2/3 directory",
+	}, {
+		description: "one target dir specified, invalid targets specified",
+		dirsInTrees: []string{"0/1/2/3"},
+		buildFiles:  []string{},
+		dirs:        []string{"1/2/3:t1:t2"},
+		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, 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, no targets and has a comma",
+		dirsInTrees: []string{"0/1/2/3"},
+		buildFiles:  []string{"0/1/2/3/Android.bp"},
+		dirs:        []string{"1/2/3:,"},
+		curDir:      "0",
+		errStr:      "0/1/2/3 not in proper directory:target1,target2,... format",
+	}, {
+		description: "one target dir specified, improper targets defined",
+		dirsInTrees: []string{"0/1/2/3"},
+		buildFiles:  []string{"0/1/2/3/Android.bp"},
+		dirs:        []string{"1/2/3:,t1"},
+		curDir:      "0",
+		errStr:      "0/1/2/3 not in proper directory:target1,target2,... format",
+	}, {
+		description: "one target dir specified, blank target",
+		dirsInTrees: []string{"0/1/2/3"},
+		buildFiles:  []string{"0/1/2/3/Android.bp"},
+		dirs:        []string{"1/2/3:t1,"},
+		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, 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",
+	}, {
+		description: "one target dir specified, one target 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:t1"},
+		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:        "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, 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: "two dirs specified, only one dir exist",
+		dirsInTrees: []string{"0/1/2/3"},
+		buildFiles:  []string{"0/1/2/3/Android.mk"},
+		dirs:        []string{"1/2/3:t1", "3/4"},
+		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: "no directories 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{},
+		curDir:      ".",
+	}}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				if tt.errStr == "" {
+					t.Fatalf("Got unexpected error: %v", err)
+				}
+				if tt.errStr != err.Error() {
+					t.Errorf("expected %s, got %s", tt.errStr, err.Error())
+				}
+			})
+
+			// Create the root source tree.
+			topDir, err := ioutil.TempDir("", "")
+			if err != nil {
+				t.Fatalf("failed to create temp dir: %v", err)
+			}
+			defer os.RemoveAll(topDir)
+
+			createDirectories(t, topDir, tt.dirsInTrees)
+			createBuildFiles(t, topDir, tt.buildFiles)
+			r := setTop(t, topDir)
+			defer r()
+
+			targets, buildFiles := 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 != "" {
+				t.Errorf("expecting error %s", tt.errStr)
+			}
+		})
+	}
+}
+
+func TestConfigFindBuildFile(t *testing.T) {
+	ctx := testContext()
+
+	tests := []struct {
+		// ********* Setup *********
+		// Test description.
+		description string
+
+		// Array of build files to create in dir.
+		buildFiles []string
+
+		// ********* Action *********
+		// Directory to create, also the base directory is where findBuildFile is invoked.
+		dir string
+
+		// ********* Validation *********
+		// Expected build file path to find.
+		expectedBuildFile string
+	}{{
+		description:       "build file exists at leaf directory",
+		buildFiles:        []string{"1/2/3/Android.bp"},
+		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"},
+		dir:               "1/2/3",
+		expectedBuildFile: "1/2/3/Android.mk",
+	}, {
+		description:       "build file does not exist in all directory paths",
+		buildFiles:        []string{},
+		dir:               "1/2/3",
+		expectedBuildFile: "",
+	}, {
+		description:       "build file exists only at top directory",
+		buildFiles:        []string{"Android.bp"},
+		dir:               "1/2/3",
+		expectedBuildFile: "",
+	}, {
+		description:       "build file exist in a subdirectory",
+		buildFiles:        []string{"1/2/Android.bp"},
+		dir:               "1/2/3",
+		expectedBuildFile: "1/2/Android.mk",
+	}, {
+		description:       "build file exists in a subdirectory",
+		buildFiles:        []string{"1/Android.mk"},
+		dir:               "1/2/3",
+		expectedBuildFile: "1/Android.mk",
+	}, {
+		description:       "top directory",
+		buildFiles:        []string{"Android.bp"},
+		dir:               ".",
+		expectedBuildFile: "",
+	}}
+
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				t.Fatalf("Got unexpected error: %v", err)
+			})
+
+			topDir, err := ioutil.TempDir("", "")
+			if err != nil {
+				t.Fatalf("failed to create temp dir: %v", err)
+			}
+			defer os.RemoveAll(topDir)
+
+			if tt.dir != "" {
+				createDirectories(t, topDir, []string{tt.dir})
+			}
+
+			createBuildFiles(t, topDir, tt.buildFiles)
+
+			curDir, err := os.Getwd()
+			if err != nil {
+				t.Fatalf("Could not get working directory: %v", err)
+			}
+			defer func() { os.Chdir(curDir) }()
+			if err := os.Chdir(topDir); err != nil {
+				t.Fatalf("Could not change top dir to %s: %v", topDir, err)
+			}
+
+			buildFile := findBuildFile(ctx, tt.dir)
+			if buildFile != tt.expectedBuildFile {
+				t.Errorf("expected %q, got %q for build file", tt.expectedBuildFile, buildFile)
+			}
+		})
+	}
+}
+
+func TestConfigSplitArgs(t *testing.T) {
+	tests := []struct {
+		// ********* Setup *********
+		// Test description.
+		description string
+
+		// ********* Action *********
+		// Arguments passed in to soong_ui.
+		args []string
+
+		// ********* Validation *********
+		// Expected newArgs list after extracting the directories.
+		expectedNewArgs []string
+
+		// Expected directories
+		expectedDirs []string
+	}{{
+		description:     "flags but no directories specified",
+		args:            []string{"showcommands", "-j", "-k"},
+		expectedNewArgs: []string{"showcommands", "-j", "-k"},
+		expectedDirs:    []string{},
+	}, {
+		description:     "flags and one directory specified",
+		args:            []string{"snod", "-j", "dir:target1,target2"},
+		expectedNewArgs: []string{"snod", "-j"},
+		expectedDirs:    []string{"dir:target1,target2"},
+	}, {
+		description:     "flags and directories specified",
+		args:            []string{"dist", "-k", "dir1", "dir2:target1,target2"},
+		expectedNewArgs: []string{"dist", "-k"},
+		expectedDirs:    []string{"dir1", "dir2:target1,target2"},
+	}, {
+		description:     "only directories specified",
+		args:            []string{"dir1", "dir2", "dir3:target1,target2"},
+		expectedNewArgs: []string{},
+		expectedDirs:    []string{"dir1", "dir2", "dir3:target1,target2"},
+	}}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			args, dirs := splitArgs(tt.args)
+			if !reflect.DeepEqual(tt.expectedNewArgs, args) {
+				t.Errorf("expected %v, got %v for arguments", tt.expectedNewArgs, args)
+			}
+			if !reflect.DeepEqual(tt.expectedDirs, dirs) {
+				t.Errorf("expected %v, got %v for directories", tt.expectedDirs, dirs)
+			}
+		})
+	}
+}
+
+type envVar struct {
+	name  string
+	value string
+}
+
+type buildActionTestCase struct {
+	// ********* Setup *********
+	// Test description.
+	description string
+
+	// Directories that exist in the source tree.
+	dirsInTrees []string
+
+	// Build files that exists in the source tree.
+	buildFiles []string
+
+	// Create root symlink that points to topDir.
+	rootSymlink bool
+
+	// ********* Action *********
+	// Arguments passed in to soong_ui.
+	args []string
+
+	// Directory where the build action was invoked.
+	curDir string
+
+	// WITH_TIDY_ONLY environment variable specified.
+	tidyOnly string
+
+	// ********* Validation *********
+	// Expected arguments to be in Config instance.
+	expectedArgs []string
+
+	// Expected environment variables to be set.
+	expectedEnvVars []envVar
+}
+
+func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) {
+	ctx := testContext()
+
+	// Environment variables to set it to blank on every test case run.
+	resetEnvVars := []string{
+		"ONE_SHOT_MAKEFILE",
+		"WITH_TIDY_ONLY",
+	}
+
+	for _, name := range resetEnvVars {
+		if err := os.Unsetenv(name); err != nil {
+			t.Fatalf("failed to unset environment variable %s: %v", name, err)
+		}
+	}
+	if tt.tidyOnly != "" {
+		if err := os.Setenv("WITH_TIDY_ONLY", tt.tidyOnly); err != nil {
+			t.Errorf("failed to set WITH_TIDY_ONLY to %s: %v", tt.tidyOnly, err)
+		}
+	}
+
+	// Create the root source tree.
+	topDir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatalf("failed to create temp dir: %v", err)
+	}
+	defer os.RemoveAll(topDir)
+
+	createDirectories(t, topDir, tt.dirsInTrees)
+	createBuildFiles(t, topDir, tt.buildFiles)
+
+	if tt.rootSymlink {
+		// Create a secondary root source tree which points to the true root source tree.
+		symlinkTopDir, err := ioutil.TempDir("", "")
+		if err != nil {
+			t.Fatalf("failed to create symlink temp dir: %v", err)
+		}
+		defer os.RemoveAll(symlinkTopDir)
+
+		symlinkTopDir = filepath.Join(symlinkTopDir, "root")
+		err = os.Symlink(topDir, symlinkTopDir)
+		if err != nil {
+			t.Fatalf("failed to create symlink: %v", err)
+		}
+		topDir = symlinkTopDir
+	}
+
+	r := setTop(t, topDir)
+	defer r()
+
+	// The next block is to create the root build file.
+	rootBuildFileDir := filepath.Dir(srcDirFileCheck)
+	if err := os.MkdirAll(rootBuildFileDir, 0755); err != nil {
+		t.Fatalf("Failed to create %s directory: %v", rootBuildFileDir, err)
+	}
+
+	if err := ioutil.WriteFile(srcDirFileCheck, []byte{}, 0644); err != nil {
+		t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
+	}
+
+	args := getConfigArgs(action, tt.curDir, buildDependencies, 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)
+		}
+	}
+}
+
+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 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, 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 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 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{},
+	}}
+	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)
+		})
+	}
+}
+
+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:     "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, 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 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 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 in symlink",
+			dirsInTrees:     []string{},
+			buildFiles:      []string{},
+			rootSymlink:     true,
+			args:            []string{},
+			curDir:          ".",
+			tidyOnly:        "",
+			expectedArgs:    []string{},
+			expectedEnvVars: []envVar{},
+		}, {
+			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:     "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:     "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:     "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{},
+		}}
+	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)
+		})
+	}
+}
+
+func TestGetConfigArgsBuildModulesInDirectories(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/", "3.2/", "3.3/"},
+		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"},
+		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/Android.bp"},
+		args:         []string{"GET-INSTALL-PATH", "2/3.1/", "2/3.2", "3"},
+		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"},
+		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"},
+		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"},
+		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
+		rootSymlink:  false,
+		args:         []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
+		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"},
+		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
+		rootSymlink:  true,
+		args:         []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
+		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)
+		})
+	}
+}
diff --git a/ui/build/context.go b/ui/build/context.go
index 249e898..3945ce0 100644
--- a/ui/build/context.go
+++ b/ui/build/context.go
@@ -16,12 +16,12 @@
 
 import (
 	"context"
+	"io"
 
 	"android/soong/ui/logger"
 	"android/soong/ui/metrics"
 	"android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/status"
-	"android/soong/ui/terminal"
 	"android/soong/ui/tracer"
 )
 
@@ -35,7 +35,7 @@
 
 	Metrics *metrics.Metrics
 
-	Writer terminal.Writer
+	Writer io.Writer
 	Status *status.Status
 
 	Thread tracer.Thread
@@ -70,7 +70,7 @@
 	if c.Metrics != nil {
 		realTime := end - begin
 		c.Metrics.SetTimeMetrics(
-			metrics_proto.PerfInfo{
+			soong_metrics_proto.PerfInfo{
 				Desc:      &desc,
 				Name:      &name,
 				StartTime: &begin,
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 3e387c1..266130f 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -200,17 +200,45 @@
 		// Whether --werror_overriding_commands will work
 		"BUILD_BROKEN_DUP_RULES",
 
-		// Used to turn on --werror_ options in Kati
-		"BUILD_BROKEN_PHONY_TARGETS",
-
 		// Whether to enable the network during the build
 		"BUILD_BROKEN_USES_NETWORK",
 
 		// Not used, but useful to be in the soong.log
 		"BOARD_VNDK_VERSION",
-		"BUILD_BROKEN_ANDROIDMK_EXPORTS",
-		"BUILD_BROKEN_DUP_COPY_HEADERS",
-		"BUILD_BROKEN_ENG_DEBUG_TAGS",
+
+		"DEFAULT_WARNING_BUILD_MODULE_TYPES",
+		"DEFAULT_ERROR_BUILD_MODULE_TYPES",
+		"BUILD_BROKEN_USES_BUILD_AUX_EXECUTABLE",
+		"BUILD_BROKEN_USES_BUILD_AUX_STATIC_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
+		"BUILD_BROKEN_USES_BUILD_EXECUTABLE",
+		"BUILD_BROKEN_USES_BUILD_FUZZ_TEST",
+		"BUILD_BROKEN_USES_BUILD_HEADER_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_DALVIK_JAVA_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_EXECUTABLE",
+		"BUILD_BROKEN_USES_BUILD_HOST_FUZZ_TEST",
+		"BUILD_BROKEN_USES_BUILD_HOST_JAVA_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_NATIVE_TEST",
+		"BUILD_BROKEN_USES_BUILD_HOST_PREBUILT",
+		"BUILD_BROKEN_USES_BUILD_HOST_SHARED_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_STATIC_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_STATIC_TEST_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_HOST_TEST_CONFIG",
+		"BUILD_BROKEN_USES_BUILD_JAVA_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_MULTI_PREBUILT",
+		"BUILD_BROKEN_USES_BUILD_NATIVE_BENCHMARK",
+		"BUILD_BROKEN_USES_BUILD_NATIVE_TEST",
+		"BUILD_BROKEN_USES_BUILD_NOTICE_FILE",
+		"BUILD_BROKEN_USES_BUILD_PACKAGE",
+		"BUILD_BROKEN_USES_BUILD_PHONY_PACKAGE",
+		"BUILD_BROKEN_USES_BUILD_PREBUILT",
+		"BUILD_BROKEN_USES_BUILD_RRO_PACKAGE",
+		"BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_STATIC_TEST_LIBRARY",
+		"BUILD_BROKEN_USES_BUILD_TARGET_TEST_CONFIG",
 	}, exportEnvVars...), BannerVars...)
 
 	make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true)
@@ -221,7 +249,7 @@
 	env := config.Environment()
 	// Print the banner like make does
 	if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
-		ctx.Writer.Print(Banner(make_vars))
+		fmt.Fprintln(ctx.Writer, Banner(make_vars))
 	}
 
 	// Populate the environment
@@ -240,6 +268,5 @@
 
 	config.SetPdkBuild(make_vars["TARGET_BUILD_PDK"] == "true")
 	config.SetBuildBrokenDupRules(make_vars["BUILD_BROKEN_DUP_RULES"] == "true")
-	config.SetBuildBrokenPhonyTargets(make_vars["BUILD_BROKEN_PHONY_TARGETS"] == "true")
 	config.SetBuildBrokenUsesNetwork(make_vars["BUILD_BROKEN_USES_NETWORK"] == "true")
 }
diff --git a/ui/build/exec.go b/ui/build/exec.go
index 5c312bc..e435c53 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -15,7 +15,10 @@
 package build
 
 import (
+	"bufio"
+	"io"
 	"os/exec"
+	"strings"
 )
 
 // Cmd is a wrapper of os/exec.Cmd that integrates with the build context for
@@ -139,3 +142,34 @@
 	st.Finish()
 	c.reportError(err)
 }
+
+// RunAndStreamOrFatal will run the command, while running print
+// any output, then handle any errors with a call to ctx.Fatal
+func (c *Cmd) RunAndStreamOrFatal() {
+	out, err := c.StdoutPipe()
+	if err != nil {
+		c.ctx.Fatal(err)
+	}
+	c.Stderr = c.Stdout
+
+	st := c.ctx.Status.StartTool()
+
+	c.StartOrFatal()
+
+	buf := bufio.NewReaderSize(out, 2*1024*1024)
+	for {
+		// Attempt to read whole lines, but write partial lines that are too long to fit in the buffer or hit EOF
+		line, err := buf.ReadString('\n')
+		if line != "" {
+			st.Print(strings.TrimSuffix(line, "\n"))
+		} else if err == io.EOF {
+			break
+		} else if err != nil {
+			c.ctx.Fatal(err)
+		}
+	}
+
+	err = c.Wait()
+	st.Finish()
+	c.reportError(err)
+}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 959d0bd..5ad966a 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -81,6 +81,9 @@
 		"--werror_suffix_rules",
 		"--warn_real_to_phony",
 		"--warn_phony_looks_real",
+		"--werror_real_to_phony",
+		"--werror_phony_looks_real",
+		"--werror_writable",
 		"--top_level_phony",
 		"--kati_stats",
 	}, args...)
@@ -138,13 +141,6 @@
 		args = append(args, "--werror_overriding_commands")
 	}
 
-	if !config.BuildBrokenPhonyTargets() {
-		args = append(args,
-			"--werror_real_to_phony",
-			"--werror_phony_looks_real",
-			"--werror_writable")
-	}
-
 	args = append(args, config.KatiArgs()...)
 
 	args = append(args,
@@ -162,11 +158,8 @@
 
 	args := []string{
 		"--writable", config.DistDir() + "/",
-		"--werror_writable",
 		"--werror_implicit_rules",
 		"--werror_overriding_commands",
-		"--werror_real_to_phony",
-		"--werror_phony_looks_real",
 		"-f", "build/make/packaging/main.mk",
 		"KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(),
 	}
@@ -202,11 +195,8 @@
 	defer ctx.EndTrace()
 
 	runKati(ctx, config, katiCleanspecSuffix, []string{
-		"--werror_writable",
 		"--werror_implicit_rules",
 		"--werror_overriding_commands",
-		"--werror_real_to_phony",
-		"--werror_phony_looks_real",
 		"-f", "build/make/core/cleanbuild.mk",
 		"SOONG_MAKEVARS_MK=" + config.SoongMakeVarsMk(),
 		"TARGET_DEVICE_DIR=" + config.TargetDeviceDir(),
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 7994f3a..b41ac20 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -103,7 +103,7 @@
 	}()
 
 	ctx.Status.Status("Starting ninja...")
-	cmd.RunAndPrintOrFatal()
+	cmd.RunAndStreamOrFatal()
 }
 
 type statusChecker struct {
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index f4bb89f..a4be2ac 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,12 +74,14 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"bash":     Allowed,
-	"bc":       Allowed,
+	"bash": Allowed,
+	"bc":   Allowed,
+	// We need bzip2 here even though we provide a bzip2 binary because
+	// GNU tar seems to avoid calling ours.
 	"bzip2":    Allowed,
-	"date":     Allowed,
 	"dd":       Allowed,
 	"diff":     Allowed,
+	"dlv":      Allowed,
 	"egrep":    Allowed,
 	"expr":     Allowed,
 	"find":     Allowed,
@@ -87,26 +89,24 @@
 	"getopt":   Allowed,
 	"git":      Allowed,
 	"grep":     Allowed,
+	"gzcat":    Allowed,
 	"gzip":     Allowed,
 	"hexdump":  Allowed,
 	"jar":      Allowed,
 	"java":     Allowed,
 	"javap":    Allowed,
 	"lsof":     Allowed,
-	"m4":       Allowed,
+	"m4":       Log,
 	"openssl":  Allowed,
 	"patch":    Allowed,
 	"pstree":   Allowed,
 	"python3":  Allowed,
 	"realpath": Allowed,
 	"rsync":    Allowed,
-	"sed":      Allowed,
 	"sh":       Allowed,
 	"tar":      Allowed,
-	"timeout":  Allowed,
 	"tr":       Allowed,
 	"unzip":    Allowed,
-	"xz":       Allowed,
 	"zip":      Allowed,
 	"zipinfo":  Allowed,
 
@@ -132,6 +132,7 @@
 	"cp":        LinuxOnlyPrebuilt,
 	"comm":      LinuxOnlyPrebuilt,
 	"cut":       LinuxOnlyPrebuilt,
+	"date":      LinuxOnlyPrebuilt,
 	"dirname":   LinuxOnlyPrebuilt,
 	"du":        LinuxOnlyPrebuilt,
 	"echo":      LinuxOnlyPrebuilt,
@@ -155,6 +156,7 @@
 	"readlink":  LinuxOnlyPrebuilt,
 	"rm":        LinuxOnlyPrebuilt,
 	"rmdir":     LinuxOnlyPrebuilt,
+	"sed":       LinuxOnlyPrebuilt,
 	"seq":       LinuxOnlyPrebuilt,
 	"setsid":    LinuxOnlyPrebuilt,
 	"sha1sum":   LinuxOnlyPrebuilt,
@@ -165,6 +167,7 @@
 	"stat":      LinuxOnlyPrebuilt,
 	"tail":      LinuxOnlyPrebuilt,
 	"tee":       LinuxOnlyPrebuilt,
+	"timeout":   LinuxOnlyPrebuilt,
 	"touch":     LinuxOnlyPrebuilt,
 	"true":      LinuxOnlyPrebuilt,
 	"uname":     LinuxOnlyPrebuilt,
diff --git a/ui/build/proc_sync.go b/ui/build/proc_sync.go
index 857786d..0cfe798 100644
--- a/ui/build/proc_sync.go
+++ b/ui/build/proc_sync.go
@@ -34,6 +34,14 @@
 	if err != nil {
 		ctx.Logger.Fatal(err)
 	}
+	lockfilePollDuration := time.Second
+	lockfileTimeout := time.Second * 10
+	if envTimeout := os.Getenv("SOONG_LOCK_TIMEOUT"); envTimeout != "" {
+		lockfileTimeout, err = time.ParseDuration(envTimeout)
+		if err != nil {
+			ctx.Logger.Fatalf("failure parsing SOONG_LOCK_TIMEOUT %q: %s", envTimeout, err)
+		}
+	}
 	err = lockSynchronous(*lockingInfo, newSleepWaiter(lockfilePollDuration, lockfileTimeout), ctx.Logger)
 	if err != nil {
 		ctx.Logger.Fatal(err)
@@ -41,9 +49,6 @@
 	return lockingInfo
 }
 
-var lockfileTimeout = time.Second * 10
-var lockfilePollDuration = time.Second
-
 type lockable interface {
 	tryLock() error
 	Unlock() error
@@ -80,15 +85,18 @@
 			return nil
 		}
 
-		waited = true
-
 		done, description := waiter.checkDeadline()
 
+		if !waited {
+			logger.Printf("Waiting up to %s to lock %v to ensure no other Soong process is running in the same output directory\n", description, lock.description())
+		}
+
+		waited = true
+
 		if done {
 			return fmt.Errorf("Tried to lock %s, but timed out %s . Make sure no other Soong process is using it",
 				lock.description(), waiter.summarize())
 		} else {
-			logger.Printf("Waiting up to %s to lock %v to ensure no other Soong process is running in the same output directory\n", description, lock.description())
 			waiter.wait()
 		}
 	}
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index b94db74..11ff667 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -162,6 +162,10 @@
 		c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
 		c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
 		sandboxArgs = append(sandboxArgs, "-N")
+	} else if dlv, _ := c.config.Environment().Get("SOONG_DELVE"); dlv != "" {
+		// The debugger is enabled and soong_build will pause until a remote delve process connects, allow
+		// network connections.
+		sandboxArgs = append(sandboxArgs, "-N")
 	}
 
 	// Stop nsjail from parsing arguments
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 2ce1ac9..3388417 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -120,7 +120,7 @@
 			"--frontend_file", fifo,
 			"-f", filepath.Join(config.SoongOutDir(), file))
 		cmd.Sandbox = soongSandbox
-		cmd.RunAndPrintOrFatal()
+		cmd.RunAndStreamOrFatal()
 	}
 
 	ninja("minibootstrap", ".minibootstrap/build.ninja")
diff --git a/ui/build/util.go b/ui/build/util.go
index 0676a86..75e6753 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -44,6 +44,17 @@
 	return indexList(s, list) != -1
 }
 
+// removeFromlist removes all occurrences of the string in list.
+func removeFromList(s string, list []string) []string {
+	filteredList := make([]string, 0, len(list))
+	for _, ls := range list {
+		if s != ls {
+			filteredList = append(filteredList, ls)
+		}
+	}
+	return filteredList
+}
+
 // ensureDirectoriesExist is a shortcut to os.MkdirAll, sending errors to the ctx logger.
 func ensureDirectoriesExist(ctx Context, dirs ...string) {
 	for _, dir := range dirs {
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 790b67a..bc86f0a 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -33,19 +33,19 @@
 )
 
 type Metrics struct {
-	metrics    metrics_proto.MetricsBase
+	metrics    soong_metrics_proto.MetricsBase
 	TimeTracer TimeTracer
 }
 
 func New() (metrics *Metrics) {
 	m := &Metrics{
-		metrics:    metrics_proto.MetricsBase{},
+		metrics:    soong_metrics_proto.MetricsBase{},
 		TimeTracer: &timeTracerImpl{},
 	}
 	return m
 }
 
-func (m *Metrics) SetTimeMetrics(perf metrics_proto.PerfInfo) {
+func (m *Metrics) SetTimeMetrics(perf soong_metrics_proto.PerfInfo) {
 	switch perf.GetName() {
 	case RunKati:
 		m.metrics.KatiRuns = append(m.metrics.KatiRuns, &perf)
@@ -76,11 +76,11 @@
 		case "TARGET_BUILD_VARIANT":
 			switch v {
 			case "user":
-				m.metrics.TargetBuildVariant = metrics_proto.MetricsBase_USER.Enum()
+				m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_USER.Enum()
 			case "userdebug":
-				m.metrics.TargetBuildVariant = metrics_proto.MetricsBase_USERDEBUG.Enum()
+				m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_USERDEBUG.Enum()
 			case "eng":
-				m.metrics.TargetBuildVariant = metrics_proto.MetricsBase_ENG.Enum()
+				m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_ENG.Enum()
 			default:
 				// ignored
 			}
@@ -112,18 +112,18 @@
 	}
 }
 
-func (m *Metrics) getArch(arch string) *metrics_proto.MetricsBase_ARCH {
+func (m *Metrics) getArch(arch string) *soong_metrics_proto.MetricsBase_Arch {
 	switch arch {
 	case "arm":
-		return metrics_proto.MetricsBase_ARM.Enum()
+		return soong_metrics_proto.MetricsBase_ARM.Enum()
 	case "arm64":
-		return metrics_proto.MetricsBase_ARM64.Enum()
+		return soong_metrics_proto.MetricsBase_ARM64.Enum()
 	case "x86":
-		return metrics_proto.MetricsBase_X86.Enum()
+		return soong_metrics_proto.MetricsBase_X86.Enum()
 	case "x86_64":
-		return metrics_proto.MetricsBase_X86_64.Enum()
+		return soong_metrics_proto.MetricsBase_X86_64.Enum()
 	default:
-		return metrics_proto.MetricsBase_UNKNOWN.Enum()
+		return soong_metrics_proto.MetricsBase_UNKNOWN.Enum()
 	}
 }
 
@@ -148,7 +148,7 @@
 		return err
 	}
 	tempPath := outputPath + ".tmp"
-	err = ioutil.WriteFile(tempPath, []byte(data), 0777)
+	err = ioutil.WriteFile(tempPath, []byte(data), 0644)
 	if err != nil {
 		return err
 	}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index feefc89..5486ec1 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -1,11 +1,13 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // source: metrics.proto
 
-package metrics_proto
+package soong_metrics_proto
 
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	math "math"
+)
 
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
@@ -16,65 +18,70 @@
 // is compatible with the proto package it is being compiled against.
 // A compilation error at this line likely means your copy of the
 // proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
 
-type MetricsBase_BUILDVARIANT int32
+type MetricsBase_BuildVariant int32
 
 const (
-	MetricsBase_USER      MetricsBase_BUILDVARIANT = 0
-	MetricsBase_USERDEBUG MetricsBase_BUILDVARIANT = 1
-	MetricsBase_ENG       MetricsBase_BUILDVARIANT = 2
+	MetricsBase_USER      MetricsBase_BuildVariant = 0
+	MetricsBase_USERDEBUG MetricsBase_BuildVariant = 1
+	MetricsBase_ENG       MetricsBase_BuildVariant = 2
 )
 
-var MetricsBase_BUILDVARIANT_name = map[int32]string{
+var MetricsBase_BuildVariant_name = map[int32]string{
 	0: "USER",
 	1: "USERDEBUG",
 	2: "ENG",
 }
-var MetricsBase_BUILDVARIANT_value = map[string]int32{
+
+var MetricsBase_BuildVariant_value = map[string]int32{
 	"USER":      0,
 	"USERDEBUG": 1,
 	"ENG":       2,
 }
 
-func (x MetricsBase_BUILDVARIANT) Enum() *MetricsBase_BUILDVARIANT {
-	p := new(MetricsBase_BUILDVARIANT)
+func (x MetricsBase_BuildVariant) Enum() *MetricsBase_BuildVariant {
+	p := new(MetricsBase_BuildVariant)
 	*p = x
 	return p
 }
-func (x MetricsBase_BUILDVARIANT) String() string {
-	return proto.EnumName(MetricsBase_BUILDVARIANT_name, int32(x))
+
+func (x MetricsBase_BuildVariant) String() string {
+	return proto.EnumName(MetricsBase_BuildVariant_name, int32(x))
 }
-func (x *MetricsBase_BUILDVARIANT) UnmarshalJSON(data []byte) error {
-	value, err := proto.UnmarshalJSONEnum(MetricsBase_BUILDVARIANT_value, data, "MetricsBase_BUILDVARIANT")
+
+func (x *MetricsBase_BuildVariant) UnmarshalJSON(data []byte) error {
+	value, err := proto.UnmarshalJSONEnum(MetricsBase_BuildVariant_value, data, "MetricsBase_BuildVariant")
 	if err != nil {
 		return err
 	}
-	*x = MetricsBase_BUILDVARIANT(value)
+	*x = MetricsBase_BuildVariant(value)
 	return nil
 }
-func (MetricsBase_BUILDVARIANT) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptor_metrics_9e7b895801991242, []int{0, 0}
+
+func (MetricsBase_BuildVariant) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_6039342a2ba47b72, []int{0, 0}
 }
 
-type MetricsBase_ARCH int32
+type MetricsBase_Arch int32
 
 const (
-	MetricsBase_UNKNOWN MetricsBase_ARCH = 0
-	MetricsBase_ARM     MetricsBase_ARCH = 1
-	MetricsBase_ARM64   MetricsBase_ARCH = 2
-	MetricsBase_X86     MetricsBase_ARCH = 3
-	MetricsBase_X86_64  MetricsBase_ARCH = 4
+	MetricsBase_UNKNOWN MetricsBase_Arch = 0
+	MetricsBase_ARM     MetricsBase_Arch = 1
+	MetricsBase_ARM64   MetricsBase_Arch = 2
+	MetricsBase_X86     MetricsBase_Arch = 3
+	MetricsBase_X86_64  MetricsBase_Arch = 4
 )
 
-var MetricsBase_ARCH_name = map[int32]string{
+var MetricsBase_Arch_name = map[int32]string{
 	0: "UNKNOWN",
 	1: "ARM",
 	2: "ARM64",
 	3: "X86",
 	4: "X86_64",
 }
-var MetricsBase_ARCH_value = map[string]int32{
+
+var MetricsBase_Arch_value = map[string]int32{
 	"UNKNOWN": 0,
 	"ARM":     1,
 	"ARM64":   2,
@@ -82,63 +89,70 @@
 	"X86_64":  4,
 }
 
-func (x MetricsBase_ARCH) Enum() *MetricsBase_ARCH {
-	p := new(MetricsBase_ARCH)
+func (x MetricsBase_Arch) Enum() *MetricsBase_Arch {
+	p := new(MetricsBase_Arch)
 	*p = x
 	return p
 }
-func (x MetricsBase_ARCH) String() string {
-	return proto.EnumName(MetricsBase_ARCH_name, int32(x))
+
+func (x MetricsBase_Arch) String() string {
+	return proto.EnumName(MetricsBase_Arch_name, int32(x))
 }
-func (x *MetricsBase_ARCH) UnmarshalJSON(data []byte) error {
-	value, err := proto.UnmarshalJSONEnum(MetricsBase_ARCH_value, data, "MetricsBase_ARCH")
+
+func (x *MetricsBase_Arch) UnmarshalJSON(data []byte) error {
+	value, err := proto.UnmarshalJSONEnum(MetricsBase_Arch_value, data, "MetricsBase_Arch")
 	if err != nil {
 		return err
 	}
-	*x = MetricsBase_ARCH(value)
+	*x = MetricsBase_Arch(value)
 	return nil
 }
-func (MetricsBase_ARCH) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptor_metrics_9e7b895801991242, []int{0, 1}
+
+func (MetricsBase_Arch) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_6039342a2ba47b72, []int{0, 1}
 }
 
-type ModuleTypeInfo_BUILDSYSTEM int32
+type ModuleTypeInfo_BuildSystem int32
 
 const (
-	ModuleTypeInfo_UNKNOWN ModuleTypeInfo_BUILDSYSTEM = 0
-	ModuleTypeInfo_SOONG   ModuleTypeInfo_BUILDSYSTEM = 1
-	ModuleTypeInfo_MAKE    ModuleTypeInfo_BUILDSYSTEM = 2
+	ModuleTypeInfo_UNKNOWN ModuleTypeInfo_BuildSystem = 0
+	ModuleTypeInfo_SOONG   ModuleTypeInfo_BuildSystem = 1
+	ModuleTypeInfo_MAKE    ModuleTypeInfo_BuildSystem = 2
 )
 
-var ModuleTypeInfo_BUILDSYSTEM_name = map[int32]string{
+var ModuleTypeInfo_BuildSystem_name = map[int32]string{
 	0: "UNKNOWN",
 	1: "SOONG",
 	2: "MAKE",
 }
-var ModuleTypeInfo_BUILDSYSTEM_value = map[string]int32{
+
+var ModuleTypeInfo_BuildSystem_value = map[string]int32{
 	"UNKNOWN": 0,
 	"SOONG":   1,
 	"MAKE":    2,
 }
 
-func (x ModuleTypeInfo_BUILDSYSTEM) Enum() *ModuleTypeInfo_BUILDSYSTEM {
-	p := new(ModuleTypeInfo_BUILDSYSTEM)
+func (x ModuleTypeInfo_BuildSystem) Enum() *ModuleTypeInfo_BuildSystem {
+	p := new(ModuleTypeInfo_BuildSystem)
 	*p = x
 	return p
 }
-func (x ModuleTypeInfo_BUILDSYSTEM) String() string {
-	return proto.EnumName(ModuleTypeInfo_BUILDSYSTEM_name, int32(x))
+
+func (x ModuleTypeInfo_BuildSystem) String() string {
+	return proto.EnumName(ModuleTypeInfo_BuildSystem_name, int32(x))
 }
-func (x *ModuleTypeInfo_BUILDSYSTEM) UnmarshalJSON(data []byte) error {
-	value, err := proto.UnmarshalJSONEnum(ModuleTypeInfo_BUILDSYSTEM_value, data, "ModuleTypeInfo_BUILDSYSTEM")
+
+func (x *ModuleTypeInfo_BuildSystem) UnmarshalJSON(data []byte) error {
+	value, err := proto.UnmarshalJSONEnum(ModuleTypeInfo_BuildSystem_value, data, "ModuleTypeInfo_BuildSystem")
 	if err != nil {
 		return err
 	}
-	*x = ModuleTypeInfo_BUILDSYSTEM(value)
+	*x = ModuleTypeInfo_BuildSystem(value)
 	return nil
 }
-func (ModuleTypeInfo_BUILDSYSTEM) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptor_metrics_9e7b895801991242, []int{2, 0}
+
+func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_6039342a2ba47b72, []int{2, 0}
 }
 
 type MetricsBase struct {
@@ -151,17 +165,17 @@
 	// The target product information, eg. aosp_arm.
 	TargetProduct *string `protobuf:"bytes,4,opt,name=target_product,json=targetProduct" json:"target_product,omitempty"`
 	// The target build variant information, eg. eng.
-	TargetBuildVariant *MetricsBase_BUILDVARIANT `protobuf:"varint,5,opt,name=target_build_variant,json=targetBuildVariant,enum=build_metrics.MetricsBase_BUILDVARIANT,def=2" json:"target_build_variant,omitempty"`
+	TargetBuildVariant *MetricsBase_BuildVariant `protobuf:"varint,5,opt,name=target_build_variant,json=targetBuildVariant,enum=soong_build_metrics.MetricsBase_BuildVariant,def=2" json:"target_build_variant,omitempty"`
 	// The target arch information, eg. arm.
-	TargetArch *MetricsBase_ARCH `protobuf:"varint,6,opt,name=target_arch,json=targetArch,enum=build_metrics.MetricsBase_ARCH,def=0" json:"target_arch,omitempty"`
+	TargetArch *MetricsBase_Arch `protobuf:"varint,6,opt,name=target_arch,json=targetArch,enum=soong_build_metrics.MetricsBase_Arch,def=0" json:"target_arch,omitempty"`
 	// The target arch variant information, eg. armv7-a-neon.
 	TargetArchVariant *string `protobuf:"bytes,7,opt,name=target_arch_variant,json=targetArchVariant" json:"target_arch_variant,omitempty"`
 	// The target cpu variant information, eg. generic.
 	TargetCpuVariant *string `protobuf:"bytes,8,opt,name=target_cpu_variant,json=targetCpuVariant" json:"target_cpu_variant,omitempty"`
 	// The host arch information, eg. x86_64.
-	HostArch *MetricsBase_ARCH `protobuf:"varint,9,opt,name=host_arch,json=hostArch,enum=build_metrics.MetricsBase_ARCH,def=0" json:"host_arch,omitempty"`
+	HostArch *MetricsBase_Arch `protobuf:"varint,9,opt,name=host_arch,json=hostArch,enum=soong_build_metrics.MetricsBase_Arch,def=0" json:"host_arch,omitempty"`
 	// The host 2nd arch information, eg. x86.
-	Host_2NdArch *MetricsBase_ARCH `protobuf:"varint,10,opt,name=host_2nd_arch,json=host2ndArch,enum=build_metrics.MetricsBase_ARCH,def=0" json:"host_2nd_arch,omitempty"`
+	Host_2NdArch *MetricsBase_Arch `protobuf:"varint,10,opt,name=host_2nd_arch,json=host2ndArch,enum=soong_build_metrics.MetricsBase_Arch,def=0" json:"host_2nd_arch,omitempty"`
 	// The host os information, eg. linux.
 	HostOs *string `protobuf:"bytes,11,opt,name=host_os,json=hostOs" json:"host_os,omitempty"`
 	// The host os extra information, eg. Linux-4.17.0-3rodete2-amd64-x86_64-Debian-GNU.
@@ -191,16 +205,17 @@
 func (m *MetricsBase) String() string { return proto.CompactTextString(m) }
 func (*MetricsBase) ProtoMessage()    {}
 func (*MetricsBase) Descriptor() ([]byte, []int) {
-	return fileDescriptor_metrics_9e7b895801991242, []int{0}
+	return fileDescriptor_6039342a2ba47b72, []int{0}
 }
+
 func (m *MetricsBase) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_MetricsBase.Unmarshal(m, b)
 }
 func (m *MetricsBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 	return xxx_messageInfo_MetricsBase.Marshal(b, m, deterministic)
 }
-func (dst *MetricsBase) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_MetricsBase.Merge(dst, src)
+func (m *MetricsBase) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_MetricsBase.Merge(m, src)
 }
 func (m *MetricsBase) XXX_Size() int {
 	return xxx_messageInfo_MetricsBase.Size(m)
@@ -211,10 +226,10 @@
 
 var xxx_messageInfo_MetricsBase proto.InternalMessageInfo
 
-const Default_MetricsBase_TargetBuildVariant MetricsBase_BUILDVARIANT = MetricsBase_ENG
-const Default_MetricsBase_TargetArch MetricsBase_ARCH = MetricsBase_UNKNOWN
-const Default_MetricsBase_HostArch MetricsBase_ARCH = MetricsBase_UNKNOWN
-const Default_MetricsBase_Host_2NdArch MetricsBase_ARCH = MetricsBase_UNKNOWN
+const Default_MetricsBase_TargetBuildVariant MetricsBase_BuildVariant = MetricsBase_ENG
+const Default_MetricsBase_TargetArch MetricsBase_Arch = MetricsBase_UNKNOWN
+const Default_MetricsBase_HostArch MetricsBase_Arch = MetricsBase_UNKNOWN
+const Default_MetricsBase_Host_2NdArch MetricsBase_Arch = MetricsBase_UNKNOWN
 
 func (m *MetricsBase) GetBuildDateTimestamp() int64 {
 	if m != nil && m.BuildDateTimestamp != nil {
@@ -244,14 +259,14 @@
 	return ""
 }
 
-func (m *MetricsBase) GetTargetBuildVariant() MetricsBase_BUILDVARIANT {
+func (m *MetricsBase) GetTargetBuildVariant() MetricsBase_BuildVariant {
 	if m != nil && m.TargetBuildVariant != nil {
 		return *m.TargetBuildVariant
 	}
 	return Default_MetricsBase_TargetBuildVariant
 }
 
-func (m *MetricsBase) GetTargetArch() MetricsBase_ARCH {
+func (m *MetricsBase) GetTargetArch() MetricsBase_Arch {
 	if m != nil && m.TargetArch != nil {
 		return *m.TargetArch
 	}
@@ -272,14 +287,14 @@
 	return ""
 }
 
-func (m *MetricsBase) GetHostArch() MetricsBase_ARCH {
+func (m *MetricsBase) GetHostArch() MetricsBase_Arch {
 	if m != nil && m.HostArch != nil {
 		return *m.HostArch
 	}
 	return Default_MetricsBase_HostArch
 }
 
-func (m *MetricsBase) GetHost_2NdArch() MetricsBase_ARCH {
+func (m *MetricsBase) GetHost_2NdArch() MetricsBase_Arch {
 	if m != nil && m.Host_2NdArch != nil {
 		return *m.Host_2NdArch
 	}
@@ -378,16 +393,17 @@
 func (m *PerfInfo) String() string { return proto.CompactTextString(m) }
 func (*PerfInfo) ProtoMessage()    {}
 func (*PerfInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_metrics_9e7b895801991242, []int{1}
+	return fileDescriptor_6039342a2ba47b72, []int{1}
 }
+
 func (m *PerfInfo) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_PerfInfo.Unmarshal(m, b)
 }
 func (m *PerfInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 	return xxx_messageInfo_PerfInfo.Marshal(b, m, deterministic)
 }
-func (dst *PerfInfo) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_PerfInfo.Merge(dst, src)
+func (m *PerfInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_PerfInfo.Merge(m, src)
 }
 func (m *PerfInfo) XXX_Size() int {
 	return xxx_messageInfo_PerfInfo.Size(m)
@@ -435,7 +451,7 @@
 
 type ModuleTypeInfo struct {
 	// The build system, eg. Soong or Make.
-	BuildSystem *ModuleTypeInfo_BUILDSYSTEM `protobuf:"varint,1,opt,name=build_system,json=buildSystem,enum=build_metrics.ModuleTypeInfo_BUILDSYSTEM,def=0" json:"build_system,omitempty"`
+	BuildSystem *ModuleTypeInfo_BuildSystem `protobuf:"varint,1,opt,name=build_system,json=buildSystem,enum=soong_build_metrics.ModuleTypeInfo_BuildSystem,def=0" json:"build_system,omitempty"`
 	// The module type, eg. java_library, cc_binary, and etc.
 	ModuleType *string `protobuf:"bytes,2,opt,name=module_type,json=moduleType" json:"module_type,omitempty"`
 	// The number of logical modules.
@@ -449,16 +465,17 @@
 func (m *ModuleTypeInfo) String() string { return proto.CompactTextString(m) }
 func (*ModuleTypeInfo) ProtoMessage()    {}
 func (*ModuleTypeInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_metrics_9e7b895801991242, []int{2}
+	return fileDescriptor_6039342a2ba47b72, []int{2}
 }
+
 func (m *ModuleTypeInfo) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_ModuleTypeInfo.Unmarshal(m, b)
 }
 func (m *ModuleTypeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 	return xxx_messageInfo_ModuleTypeInfo.Marshal(b, m, deterministic)
 }
-func (dst *ModuleTypeInfo) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_ModuleTypeInfo.Merge(dst, src)
+func (m *ModuleTypeInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ModuleTypeInfo.Merge(m, src)
 }
 func (m *ModuleTypeInfo) XXX_Size() int {
 	return xxx_messageInfo_ModuleTypeInfo.Size(m)
@@ -469,9 +486,9 @@
 
 var xxx_messageInfo_ModuleTypeInfo proto.InternalMessageInfo
 
-const Default_ModuleTypeInfo_BuildSystem ModuleTypeInfo_BUILDSYSTEM = ModuleTypeInfo_UNKNOWN
+const Default_ModuleTypeInfo_BuildSystem ModuleTypeInfo_BuildSystem = ModuleTypeInfo_UNKNOWN
 
-func (m *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BUILDSYSTEM {
+func (m *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem {
 	if m != nil && m.BuildSystem != nil {
 		return *m.BuildSystem
 	}
@@ -493,65 +510,65 @@
 }
 
 func init() {
-	proto.RegisterType((*MetricsBase)(nil), "build_metrics.MetricsBase")
-	proto.RegisterType((*PerfInfo)(nil), "build_metrics.PerfInfo")
-	proto.RegisterType((*ModuleTypeInfo)(nil), "build_metrics.ModuleTypeInfo")
-	proto.RegisterEnum("build_metrics.MetricsBase_BUILDVARIANT", MetricsBase_BUILDVARIANT_name, MetricsBase_BUILDVARIANT_value)
-	proto.RegisterEnum("build_metrics.MetricsBase_ARCH", MetricsBase_ARCH_name, MetricsBase_ARCH_value)
-	proto.RegisterEnum("build_metrics.ModuleTypeInfo_BUILDSYSTEM", ModuleTypeInfo_BUILDSYSTEM_name, ModuleTypeInfo_BUILDSYSTEM_value)
+	proto.RegisterEnum("soong_build_metrics.MetricsBase_BuildVariant", MetricsBase_BuildVariant_name, MetricsBase_BuildVariant_value)
+	proto.RegisterEnum("soong_build_metrics.MetricsBase_Arch", MetricsBase_Arch_name, MetricsBase_Arch_value)
+	proto.RegisterEnum("soong_build_metrics.ModuleTypeInfo_BuildSystem", ModuleTypeInfo_BuildSystem_name, ModuleTypeInfo_BuildSystem_value)
+	proto.RegisterType((*MetricsBase)(nil), "soong_build_metrics.MetricsBase")
+	proto.RegisterType((*PerfInfo)(nil), "soong_build_metrics.PerfInfo")
+	proto.RegisterType((*ModuleTypeInfo)(nil), "soong_build_metrics.ModuleTypeInfo")
 }
 
-func init() { proto.RegisterFile("metrics.proto", fileDescriptor_metrics_9e7b895801991242) }
+func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
 
-var fileDescriptor_metrics_9e7b895801991242 = []byte{
-	// 783 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0xdb, 0x36,
-	0x14, 0xae, 0x62, 0x25, 0x96, 0x8e, 0x62, 0x57, 0x61, 0x02, 0x44, 0xc5, 0x50, 0x34, 0x30, 0xf6,
-	0x93, 0x01, 0x9b, 0x57, 0x18, 0x81, 0x11, 0x04, 0xbb, 0xb1, 0x13, 0xa3, 0x35, 0x5a, 0xdb, 0x85,
-	0x6c, 0x67, 0xdd, 0x2e, 0x46, 0x68, 0x12, 0xdd, 0x68, 0xb3, 0x44, 0x81, 0xa4, 0x8a, 0xf9, 0x21,
-	0xf6, 0x8c, 0x7b, 0x91, 0x5d, 0x0c, 0x3c, 0xb4, 0x5c, 0xa5, 0x17, 0x29, 0x72, 0x47, 0x9d, 0xef,
-	0x87, 0xdf, 0x91, 0xc8, 0x23, 0x68, 0x65, 0x4c, 0x89, 0x34, 0x96, 0xdd, 0x42, 0x70, 0xc5, 0x49,
-	0xeb, 0x8f, 0x32, 0x5d, 0x27, 0x74, 0x5b, 0xec, 0xfc, 0xe7, 0x80, 0x37, 0x31, 0xeb, 0x61, 0x24,
-	0x19, 0x79, 0x09, 0x27, 0x86, 0x90, 0x44, 0x8a, 0x51, 0x95, 0x66, 0x4c, 0xaa, 0x28, 0x2b, 0x02,
-	0xeb, 0xcc, 0x3a, 0x6f, 0x84, 0x04, 0xb1, 0x9b, 0x48, 0xb1, 0x45, 0x85, 0x90, 0x67, 0xe0, 0x18,
-	0x45, 0x9a, 0x04, 0x7b, 0x67, 0xd6, 0xb9, 0x1b, 0x36, 0xf1, 0x79, 0x9c, 0x90, 0x2b, 0x78, 0x56,
-	0xac, 0x23, 0xb5, 0xe2, 0x22, 0xa3, 0x1f, 0x99, 0x90, 0x29, 0xcf, 0x69, 0xcc, 0x13, 0x96, 0x47,
-	0x19, 0x0b, 0x1a, 0xc8, 0x3d, 0xad, 0x08, 0xb7, 0x06, 0xbf, 0xde, 0xc2, 0xe4, 0x1b, 0x68, 0xab,
-	0x48, 0x7c, 0x60, 0x8a, 0x16, 0x82, 0x27, 0x65, 0xac, 0x02, 0x1b, 0x05, 0x2d, 0x53, 0x7d, 0x67,
-	0x8a, 0xe4, 0x77, 0x38, 0xd9, 0xd2, 0x4c, 0x88, 0x8f, 0x91, 0x48, 0xa3, 0x5c, 0x05, 0xfb, 0x67,
-	0xd6, 0x79, 0xbb, 0xf7, 0x5d, 0xf7, 0x5e, 0xb7, 0xdd, 0x5a, 0xa7, 0xdd, 0xe1, 0x72, 0xfc, 0xf6,
-	0xe6, 0x76, 0x10, 0x8e, 0x07, 0xd3, 0xc5, 0x55, 0x63, 0x34, 0x7d, 0x15, 0x12, 0xe3, 0x34, 0xd4,
-	0x92, 0x5b, 0xe3, 0x43, 0xc6, 0xe0, 0x6d, 0xfd, 0x23, 0x11, 0xdf, 0x05, 0x07, 0x68, 0xfb, 0xe2,
-	0x01, 0xdb, 0x41, 0x78, 0xfd, 0xfa, 0xaa, 0xb9, 0x9c, 0xbe, 0x99, 0xce, 0x7e, 0x99, 0x86, 0x60,
-	0xc4, 0x03, 0x11, 0xdf, 0x91, 0x2e, 0x1c, 0xd7, 0xac, 0x76, 0x49, 0x9b, 0xd8, 0xd6, 0xd1, 0x27,
-	0x62, 0xb5, 0xf5, 0x0f, 0xb0, 0x0d, 0x44, 0xe3, 0xa2, 0xdc, 0xd1, 0x1d, 0xa4, 0xfb, 0x06, 0xb9,
-	0x2e, 0xca, 0x8a, 0x3d, 0x02, 0xf7, 0x8e, 0xcb, 0x6d, 0x4c, 0xf7, 0x91, 0x31, 0x1d, 0x2d, 0xc5,
-	0x90, 0x6f, 0xa1, 0x85, 0x36, 0xbd, 0x3c, 0x31, 0x56, 0xf0, 0x48, 0x2b, 0x4f, 0xcb, 0x7b, 0x79,
-	0x82, 0x6e, 0xa7, 0xd0, 0x44, 0x37, 0x2e, 0x03, 0x0f, 0x73, 0x1f, 0xe8, 0xc7, 0x99, 0x24, 0x9d,
-	0xed, 0x36, 0x5c, 0x52, 0xf6, 0xb7, 0x12, 0x51, 0x70, 0x88, 0xb0, 0x67, 0xe0, 0x91, 0x2e, 0xed,
-	0x38, 0xb1, 0xe0, 0x52, 0x6a, 0x8b, 0xd6, 0x27, 0xce, 0xb5, 0xae, 0xcd, 0x24, 0xf9, 0x16, 0x9e,
-	0xd6, 0x38, 0x18, 0xb8, 0x6d, 0x8e, 0xc9, 0x8e, 0x85, 0x41, 0x7e, 0x84, 0xe3, 0x1a, 0x6f, 0xd7,
-	0xdc, 0x53, 0xf3, 0x32, 0x77, 0xdc, 0x5a, 0x6e, 0x5e, 0x2a, 0x9a, 0xa4, 0x22, 0xf0, 0x4d, 0x6e,
-	0x5e, 0xaa, 0x9b, 0x54, 0x90, 0x4b, 0xf0, 0x24, 0x53, 0x65, 0x41, 0x15, 0xe7, 0x6b, 0x19, 0x1c,
-	0x9d, 0x35, 0xce, 0xbd, 0xde, 0xe9, 0x67, 0x2f, 0xe7, 0x1d, 0x13, 0xab, 0x71, 0xbe, 0xe2, 0x21,
-	0x20, 0x77, 0xa1, 0xa9, 0xe4, 0x02, 0xdc, 0xbf, 0x22, 0x95, 0x52, 0x51, 0xe6, 0x32, 0x20, 0x0f,
-	0xeb, 0x1c, 0xcd, 0x0c, 0xcb, 0x5c, 0x92, 0x3e, 0x80, 0xe4, 0x3c, 0xff, 0x60, 0x64, 0xc7, 0x0f,
-	0xcb, 0x5c, 0xa4, 0x56, 0xba, 0x3c, 0xcd, 0xff, 0x8c, 0x8c, 0xee, 0xe4, 0x0b, 0x3a, 0xa4, 0x6a,
-	0x5d, 0xe7, 0x25, 0x1c, 0xd6, 0xef, 0x05, 0x71, 0xc0, 0x5e, 0xce, 0x47, 0xa1, 0xff, 0x84, 0xb4,
-	0xc0, 0xd5, 0xab, 0x9b, 0xd1, 0x70, 0xf9, 0xca, 0xb7, 0x48, 0x13, 0xf4, 0x95, 0xf1, 0xf7, 0x3a,
-	0x3f, 0x83, 0xad, 0x0f, 0x00, 0xf1, 0xa0, 0x3a, 0x02, 0xfe, 0x13, 0x8d, 0x0e, 0xc2, 0x89, 0x6f,
-	0x11, 0x17, 0xf6, 0x07, 0xe1, 0xa4, 0x7f, 0xe1, 0xef, 0xe9, 0xda, 0xfb, 0xcb, 0xbe, 0xdf, 0x20,
-	0x00, 0x07, 0xef, 0x2f, 0xfb, 0xb4, 0x7f, 0xe1, 0xdb, 0x9d, 0x7f, 0x2c, 0x70, 0xaa, 0x1c, 0x84,
-	0x80, 0x9d, 0x30, 0x19, 0xe3, 0xac, 0x71, 0x43, 0x5c, 0xeb, 0x1a, 0x4e, 0x0b, 0x33, 0x59, 0x70,
-	0x4d, 0x9e, 0x03, 0x48, 0x15, 0x09, 0x85, 0xe3, 0x09, 0xe7, 0x88, 0x1d, 0xba, 0x58, 0xd1, 0x53,
-	0x89, 0x7c, 0x05, 0xae, 0x60, 0xd1, 0xda, 0xa0, 0x36, 0xa2, 0x8e, 0x2e, 0x20, 0xf8, 0x1c, 0x20,
-	0x63, 0x19, 0x17, 0x1b, 0x5a, 0x4a, 0x86, 0x53, 0xc2, 0x0e, 0x5d, 0x53, 0x59, 0x4a, 0xd6, 0xf9,
-	0xd7, 0x82, 0xf6, 0x84, 0x27, 0xe5, 0x9a, 0x2d, 0x36, 0x05, 0xc3, 0x54, 0x4b, 0x38, 0x34, 0xef,
-	0x4d, 0x6e, 0xa4, 0x62, 0x19, 0xa6, 0x6b, 0xf7, 0xbe, 0xff, 0xfc, 0x42, 0xdc, 0x13, 0x99, 0xe1,
-	0x32, 0xff, 0x75, 0xbe, 0x18, 0x4d, 0x6a, 0x57, 0x03, 0x25, 0x73, 0xb4, 0x21, 0x2f, 0xc0, 0xcb,
-	0x50, 0x43, 0xd5, 0xa6, 0xa8, 0xfa, 0x83, 0x6c, 0x67, 0x43, 0xbe, 0x86, 0x76, 0x5e, 0x66, 0x94,
-	0xaf, 0xa8, 0x29, 0x4a, 0xec, 0xb4, 0x15, 0x1e, 0xe6, 0x65, 0x36, 0x5b, 0x99, 0xfd, 0x64, 0xe7,
-	0x27, 0xf0, 0x6a, 0x7b, 0xdd, 0xff, 0x0a, 0x2e, 0xec, 0xcf, 0x67, 0xb3, 0xa9, 0xfe, 0x5c, 0x0e,
-	0xd8, 0x93, 0xc1, 0x9b, 0x91, 0xbf, 0x37, 0x3c, 0x7a, 0xdd, 0xf8, 0xad, 0xfa, 0x25, 0x50, 0xfc,
-	0x25, 0xfc, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xd4, 0x8d, 0x19, 0x89, 0x22, 0x06, 0x00, 0x00,
+var fileDescriptor_6039342a2ba47b72 = []byte{
+	// 769 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x6f, 0x6b, 0xdb, 0x46,
+	0x18, 0xaf, 0x62, 0x25, 0x96, 0x1e, 0xc5, 0xae, 0x7a, 0xc9, 0xa8, 0xca, 0x08, 0x33, 0x66, 0x1d,
+	0x7e, 0xb1, 0xba, 0xc5, 0x14, 0x53, 0x4c, 0x19, 0xd8, 0x89, 0x29, 0x25, 0xd8, 0x2e, 0x4a, 0xdc,
+	0x95, 0xed, 0xc5, 0xa1, 0x4a, 0xe7, 0x46, 0x9b, 0xa5, 0x13, 0x77, 0xa7, 0x32, 0x7f, 0x88, 0x7d,
+	0x93, 0x7d, 0xad, 0x7d, 0x8f, 0x71, 0xcf, 0x49, 0x8e, 0x02, 0x81, 0x85, 0xbe, 0x3b, 0x3d, 0xbf,
+	0x3f, 0xf7, 0x7b, 0x4e, 0xba, 0x47, 0xd0, 0xc9, 0x98, 0x12, 0x69, 0x2c, 0x87, 0x85, 0xe0, 0x8a,
+	0x93, 0x13, 0xc9, 0x79, 0xfe, 0x85, 0x7e, 0x2e, 0xd3, 0x6d, 0x42, 0x2b, 0xa8, 0xff, 0x8f, 0x0b,
+	0xde, 0xc2, 0xac, 0x67, 0x91, 0x64, 0xe4, 0x15, 0x9c, 0x1a, 0x42, 0x12, 0x29, 0x46, 0x55, 0x9a,
+	0x31, 0xa9, 0xa2, 0xac, 0x08, 0xac, 0x9e, 0x35, 0x68, 0x85, 0x04, 0xb1, 0x8b, 0x48, 0xb1, 0xeb,
+	0x1a, 0x21, 0xcf, 0xc0, 0x31, 0x8a, 0x34, 0x09, 0x0e, 0x7a, 0xd6, 0xc0, 0x0d, 0xdb, 0xf8, 0xfc,
+	0x3e, 0x21, 0x13, 0x78, 0x56, 0x6c, 0x23, 0xb5, 0xe1, 0x22, 0xa3, 0x5f, 0x99, 0x90, 0x29, 0xcf,
+	0x69, 0xcc, 0x13, 0x96, 0x47, 0x19, 0x0b, 0x5a, 0xc8, 0x7d, 0x5a, 0x13, 0x3e, 0x1a, 0xfc, 0xbc,
+	0x82, 0xc9, 0x73, 0xe8, 0xaa, 0x48, 0x7c, 0x61, 0x8a, 0x16, 0x82, 0x27, 0x65, 0xac, 0x02, 0x1b,
+	0x05, 0x1d, 0x53, 0xfd, 0x60, 0x8a, 0x24, 0x81, 0xd3, 0x8a, 0x66, 0x42, 0x7c, 0x8d, 0x44, 0x1a,
+	0xe5, 0x2a, 0x38, 0xec, 0x59, 0x83, 0xee, 0xe8, 0xc5, 0xf0, 0x9e, 0x9e, 0x87, 0x8d, 0x7e, 0x87,
+	0x33, 0x8d, 0x7c, 0x34, 0xa2, 0x49, 0x6b, 0xbe, 0x7c, 0x17, 0x12, 0xe3, 0xd7, 0x04, 0xc8, 0x0a,
+	0xbc, 0x6a, 0x97, 0x48, 0xc4, 0x37, 0xc1, 0x11, 0x9a, 0x3f, 0xff, 0x5f, 0xf3, 0xa9, 0x88, 0x6f,
+	0x26, 0xed, 0xf5, 0xf2, 0x72, 0xb9, 0xfa, 0x75, 0x19, 0x82, 0xb1, 0xd0, 0x45, 0x32, 0x84, 0x93,
+	0x86, 0xe1, 0x3e, 0x75, 0x1b, 0x5b, 0x7c, 0x72, 0x4b, 0xac, 0x03, 0xfc, 0x0c, 0x55, 0x2c, 0x1a,
+	0x17, 0xe5, 0x9e, 0xee, 0x20, 0xdd, 0x37, 0xc8, 0x79, 0x51, 0xd6, 0xec, 0x4b, 0x70, 0x6f, 0xb8,
+	0xac, 0xc2, 0xba, 0xdf, 0x14, 0xd6, 0xd1, 0x06, 0x18, 0x35, 0x84, 0x0e, 0x9a, 0x8d, 0xf2, 0xc4,
+	0x18, 0xc2, 0x37, 0x19, 0x7a, 0xda, 0x64, 0x94, 0x27, 0xe8, 0xf9, 0x14, 0xda, 0xe8, 0xc9, 0x65,
+	0xe0, 0x61, 0x0f, 0x47, 0xfa, 0x71, 0x25, 0x49, 0xbf, 0xda, 0x8c, 0x4b, 0xca, 0xfe, 0x52, 0x22,
+	0x0a, 0x8e, 0x11, 0xf6, 0x0c, 0x3c, 0xd7, 0xa5, 0x3d, 0x27, 0x16, 0x5c, 0x4a, 0x6d, 0xd1, 0xb9,
+	0xe5, 0x9c, 0xeb, 0xda, 0x4a, 0x92, 0x9f, 0xe0, 0x71, 0x83, 0x83, 0xb1, 0xbb, 0xe6, 0xf3, 0xd9,
+	0xb3, 0x30, 0xc8, 0x0b, 0x38, 0x69, 0xf0, 0xf6, 0x2d, 0x3e, 0x36, 0x07, 0xbb, 0xe7, 0x36, 0x72,
+	0xf3, 0x52, 0xd1, 0x24, 0x15, 0x81, 0x6f, 0x72, 0xf3, 0x52, 0x5d, 0xa4, 0x82, 0xfc, 0x02, 0x9e,
+	0x64, 0xaa, 0x2c, 0xa8, 0xe2, 0x7c, 0x2b, 0x83, 0x27, 0xbd, 0xd6, 0xc0, 0x1b, 0x9d, 0xdd, 0x7b,
+	0x44, 0x1f, 0x98, 0xd8, 0xbc, 0xcf, 0x37, 0x3c, 0x04, 0x54, 0x5c, 0x6b, 0x01, 0x99, 0x80, 0xfb,
+	0x67, 0xa4, 0x52, 0x2a, 0xca, 0x5c, 0x06, 0xe4, 0x21, 0x6a, 0x47, 0xf3, 0xc3, 0x32, 0x97, 0xe4,
+	0x2d, 0x80, 0x61, 0xa2, 0xf8, 0xe4, 0x21, 0x62, 0x17, 0xd1, 0x5a, 0x9d, 0xa7, 0xf9, 0x1f, 0x91,
+	0x51, 0x9f, 0x3e, 0x48, 0x8d, 0x02, 0xad, 0xee, 0xbf, 0x82, 0xe3, 0x3b, 0x17, 0xc5, 0x01, 0x7b,
+	0x7d, 0x35, 0x0f, 0xfd, 0x47, 0xa4, 0x03, 0xae, 0x5e, 0x5d, 0xcc, 0x67, 0xeb, 0x77, 0xbe, 0x45,
+	0xda, 0xa0, 0x2f, 0x97, 0x7f, 0xd0, 0x7f, 0x0b, 0x36, 0x1e, 0xa5, 0x07, 0xf5, 0xa7, 0xe1, 0x3f,
+	0xd2, 0xe8, 0x34, 0x5c, 0xf8, 0x16, 0x71, 0xe1, 0x70, 0x1a, 0x2e, 0xc6, 0xaf, 0xfd, 0x03, 0x5d,
+	0xfb, 0xf4, 0x66, 0xec, 0xb7, 0x08, 0xc0, 0xd1, 0xa7, 0x37, 0x63, 0x3a, 0x7e, 0xed, 0xdb, 0xfd,
+	0xbf, 0x2d, 0x70, 0xea, 0x1c, 0x84, 0x80, 0x9d, 0x30, 0x19, 0xe3, 0x6c, 0x72, 0x43, 0x5c, 0xeb,
+	0x1a, 0x4e, 0x17, 0x33, 0x89, 0x70, 0x4d, 0xce, 0x00, 0xa4, 0x8a, 0x84, 0xc2, 0x71, 0x86, 0x73,
+	0xc7, 0x0e, 0x5d, 0xac, 0xe8, 0x29, 0x46, 0xbe, 0x07, 0x57, 0xb0, 0x68, 0x6b, 0x50, 0x1b, 0x51,
+	0x47, 0x17, 0x10, 0x3c, 0x03, 0xc8, 0x58, 0xc6, 0xc5, 0x8e, 0x96, 0x92, 0xe1, 0x54, 0xb1, 0x43,
+	0xd7, 0x54, 0xd6, 0x92, 0xf5, 0xff, 0xb5, 0xa0, 0xbb, 0xe0, 0x49, 0xb9, 0x65, 0xd7, 0xbb, 0x82,
+	0x61, 0xaa, 0xdf, 0xe1, 0xd8, 0x9c, 0x9b, 0xdc, 0x49, 0xc5, 0x32, 0x4c, 0xd7, 0x1d, 0xbd, 0xbc,
+	0xff, 0xba, 0xdc, 0x91, 0x9a, 0x61, 0x74, 0x85, 0xb2, 0xc6, 0xc5, 0xf9, 0x7c, 0x5b, 0x25, 0x3f,
+	0x80, 0x97, 0xa1, 0x86, 0xaa, 0x5d, 0x51, 0x77, 0x09, 0xd9, 0xde, 0x86, 0xfc, 0x08, 0xdd, 0xbc,
+	0xcc, 0x28, 0xdf, 0x50, 0x53, 0x94, 0xd8, 0x6f, 0x27, 0x3c, 0xce, 0xcb, 0x6c, 0xb5, 0x31, 0xfb,
+	0xc9, 0xfe, 0x4b, 0xf0, 0x1a, 0x7b, 0xdd, 0x7d, 0x17, 0x2e, 0x1c, 0x5e, 0xad, 0x56, 0x4b, 0xfd,
+	0xd2, 0x1c, 0xb0, 0x17, 0xd3, 0xcb, 0xb9, 0x7f, 0x30, 0xfb, 0xee, 0xb7, 0xea, 0xef, 0x51, 0x25,
+	0xa7, 0xf8, 0x4b, 0xf9, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x81, 0xd0, 0x84, 0x23, 0x62, 0x06, 0x00,
+	0x00,
 }
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index b3de2f4..93034eb 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -14,10 +14,8 @@
 
 syntax = "proto2";
 
-option optimize_for = LITE_RUNTIME;
-
-package build_metrics;
-option go_package = "metrics_proto";
+package soong_build_metrics;
+option go_package = "soong_metrics_proto";
 
 message MetricsBase {
   // Timestamp generated when the build starts.
@@ -32,15 +30,15 @@
   // The target product information, eg. aosp_arm.
   optional string target_product = 4;
 
-  enum BUILDVARIANT {
+  enum BuildVariant {
     USER = 0;
     USERDEBUG = 1;
     ENG = 2;
   }
   // The target build variant information, eg. eng.
-  optional BUILDVARIANT target_build_variant = 5 [default = ENG];
+  optional BuildVariant target_build_variant = 5 [default = ENG];
 
-  enum ARCH {
+  enum Arch {
     UNKNOWN = 0;
     ARM = 1;
     ARM64 = 2;
@@ -48,7 +46,7 @@
     X86_64 = 4;
   }
   // The target arch information, eg. arm.
-  optional ARCH target_arch = 6 [default = UNKNOWN];
+  optional Arch target_arch = 6 [default = UNKNOWN];
 
   // The target arch variant information, eg. armv7-a-neon.
   optional string target_arch_variant = 7;
@@ -57,10 +55,10 @@
   optional string target_cpu_variant = 8;
 
   // The host arch information, eg. x86_64.
-  optional ARCH host_arch = 9 [default = UNKNOWN];
+  optional Arch host_arch = 9 [default = UNKNOWN];
 
   // The host 2nd arch information, eg. x86.
-  optional ARCH host_2nd_arch = 10 [default = UNKNOWN];
+  optional Arch host_2nd_arch = 10 [default = UNKNOWN];
 
   // The host os information, eg. linux.
   optional string host_os = 11;
@@ -113,13 +111,13 @@
 }
 
 message ModuleTypeInfo {
-  enum BUILDSYSTEM {
+  enum BuildSystem {
     UNKNOWN = 0;
     SOONG = 1;
     MAKE = 2;
   }
   // The build system, eg. Soong or Make.
-  optional BUILDSYSTEM build_system = 1 [default = UNKNOWN];
+  optional BuildSystem build_system = 1 [default = UNKNOWN];
 
   // The module type, eg. java_library, cc_binary, and etc.
   optional string module_type = 2;
diff --git a/ui/metrics/time.go b/ui/metrics/time.go
index 7e8801a..b8baf16 100644
--- a/ui/metrics/time.go
+++ b/ui/metrics/time.go
@@ -30,7 +30,7 @@
 
 type TimeTracer interface {
 	Begin(name, desc string, thread tracer.Thread)
-	End(thread tracer.Thread) metrics_proto.PerfInfo
+	End(thread tracer.Thread) soong_metrics_proto.PerfInfo
 }
 
 type timeTracerImpl struct {
@@ -51,11 +51,11 @@
 	t.activeEvents = append(t.activeEvents, timeEvent{name: name, desc: desc, atNanos: atNanos})
 }
 
-func (t *timeTracerImpl) End(thread tracer.Thread) metrics_proto.PerfInfo {
+func (t *timeTracerImpl) End(thread tracer.Thread) soong_metrics_proto.PerfInfo {
 	return t.endAt(t.now())
 }
 
-func (t *timeTracerImpl) endAt(atNanos uint64) metrics_proto.PerfInfo {
+func (t *timeTracerImpl) endAt(atNanos uint64) soong_metrics_proto.PerfInfo {
 	if len(t.activeEvents) < 1 {
 		panic("Internal error: No pending events for endAt to end!")
 	}
@@ -63,7 +63,7 @@
 	t.activeEvents = t.activeEvents[:len(t.activeEvents)-1]
 	realTime := atNanos - lastEvent.atNanos
 
-	return metrics_proto.PerfInfo{
+	return soong_metrics_proto.PerfInfo{
 		Desc:      &lastEvent.desc,
 		Name:      &lastEvent.name,
 		StartTime: &lastEvent.atNanos,
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index 901a713..ec929b3 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -19,14 +19,17 @@
         "golang-protobuf-proto",
         "soong-ui-logger",
         "soong-ui-status-ninja_frontend",
+        "soong-ui-status-build_error_proto",
     ],
     srcs: [
+        "critical_path.go",
         "kati.go",
         "log.go",
         "ninja.go",
         "status.go",
     ],
     testSrcs: [
+        "critical_path_test.go",
         "kati_test.go",
         "ninja_test.go",
         "status_test.go",
@@ -41,3 +44,12 @@
         "ninja_frontend/frontend.pb.go",
     ],
 }
+
+bootstrap_go_package {
+    name: "soong-ui-status-build_error_proto",
+    pkgPath: "android/soong/ui/status/build_error_proto",
+    deps: ["golang-protobuf-proto"],
+    srcs: [
+        "build_error_proto/build_error.pb.go",
+    ],
+}
diff --git a/ui/status/build_error_proto/build_error.pb.go b/ui/status/build_error_proto/build_error.pb.go
new file mode 100644
index 0000000..d4d0a6e
--- /dev/null
+++ b/ui/status/build_error_proto/build_error.pb.go
@@ -0,0 +1,175 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: build_error.proto
+
+package soong_build_error_proto
+
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type BuildError struct {
+	// List of error messages of the overall build. The error messages
+	// are not associated with a build action.
+	ErrorMessages []string `protobuf:"bytes,1,rep,name=error_messages,json=errorMessages" json:"error_messages,omitempty"`
+	// List of build action errors.
+	ActionErrors         []*BuildActionError `protobuf:"bytes,2,rep,name=action_errors,json=actionErrors" json:"action_errors,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}            `json:"-"`
+	XXX_unrecognized     []byte              `json:"-"`
+	XXX_sizecache        int32               `json:"-"`
+}
+
+func (m *BuildError) Reset()         { *m = BuildError{} }
+func (m *BuildError) String() string { return proto.CompactTextString(m) }
+func (*BuildError) ProtoMessage()    {}
+func (*BuildError) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a2e15b05802a5501, []int{0}
+}
+
+func (m *BuildError) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_BuildError.Unmarshal(m, b)
+}
+func (m *BuildError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_BuildError.Marshal(b, m, deterministic)
+}
+func (m *BuildError) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BuildError.Merge(m, src)
+}
+func (m *BuildError) XXX_Size() int {
+	return xxx_messageInfo_BuildError.Size(m)
+}
+func (m *BuildError) XXX_DiscardUnknown() {
+	xxx_messageInfo_BuildError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildError proto.InternalMessageInfo
+
+func (m *BuildError) GetErrorMessages() []string {
+	if m != nil {
+		return m.ErrorMessages
+	}
+	return nil
+}
+
+func (m *BuildError) GetActionErrors() []*BuildActionError {
+	if m != nil {
+		return m.ActionErrors
+	}
+	return nil
+}
+
+// Build is composed of a list of build action. There can be a set of build
+// actions that can failed.
+type BuildActionError struct {
+	// Description of the command.
+	Description *string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"`
+	// The command name that raised the error.
+	Command *string `protobuf:"bytes,2,opt,name=command" json:"command,omitempty"`
+	// The command output stream.
+	Output *string `protobuf:"bytes,3,opt,name=output" json:"output,omitempty"`
+	// List of artifacts (i.e. files) that was produced by the command.
+	Artifacts []string `protobuf:"bytes,4,rep,name=artifacts" json:"artifacts,omitempty"`
+	// The error string produced by the build action.
+	Error                *string  `protobuf:"bytes,5,opt,name=error" json:"error,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *BuildActionError) Reset()         { *m = BuildActionError{} }
+func (m *BuildActionError) String() string { return proto.CompactTextString(m) }
+func (*BuildActionError) ProtoMessage()    {}
+func (*BuildActionError) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a2e15b05802a5501, []int{1}
+}
+
+func (m *BuildActionError) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_BuildActionError.Unmarshal(m, b)
+}
+func (m *BuildActionError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_BuildActionError.Marshal(b, m, deterministic)
+}
+func (m *BuildActionError) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BuildActionError.Merge(m, src)
+}
+func (m *BuildActionError) XXX_Size() int {
+	return xxx_messageInfo_BuildActionError.Size(m)
+}
+func (m *BuildActionError) XXX_DiscardUnknown() {
+	xxx_messageInfo_BuildActionError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildActionError proto.InternalMessageInfo
+
+func (m *BuildActionError) GetDescription() string {
+	if m != nil && m.Description != nil {
+		return *m.Description
+	}
+	return ""
+}
+
+func (m *BuildActionError) GetCommand() string {
+	if m != nil && m.Command != nil {
+		return *m.Command
+	}
+	return ""
+}
+
+func (m *BuildActionError) GetOutput() string {
+	if m != nil && m.Output != nil {
+		return *m.Output
+	}
+	return ""
+}
+
+func (m *BuildActionError) GetArtifacts() []string {
+	if m != nil {
+		return m.Artifacts
+	}
+	return nil
+}
+
+func (m *BuildActionError) GetError() string {
+	if m != nil && m.Error != nil {
+		return *m.Error
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*BuildError)(nil), "soong_build_error.BuildError")
+	proto.RegisterType((*BuildActionError)(nil), "soong_build_error.BuildActionError")
+}
+
+func init() { proto.RegisterFile("build_error.proto", fileDescriptor_a2e15b05802a5501) }
+
+var fileDescriptor_a2e15b05802a5501 = []byte{
+	// 229 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xc1, 0x4a, 0xc3, 0x40,
+	0x10, 0x86, 0x49, 0x63, 0x95, 0x4c, 0xad, 0xd8, 0x41, 0x74, 0x04, 0x0f, 0xa1, 0x22, 0xe4, 0x94,
+	0x83, 0x6f, 0x60, 0x41, 0xf0, 0xe2, 0x25, 0x47, 0x2f, 0x61, 0xdd, 0xac, 0x65, 0xc1, 0x64, 0xc2,
+	0xce, 0xe6, 0xe8, 0x8b, 0xf8, 0xb4, 0x92, 0x69, 0xa5, 0xa5, 0x39, 0x7e, 0xdf, 0x3f, 0xfb, 0xef,
+	0xce, 0xc2, 0xea, 0x73, 0xf0, 0xdf, 0x4d, 0xed, 0x42, 0xe0, 0x50, 0xf6, 0x81, 0x23, 0xe3, 0x4a,
+	0x98, 0xbb, 0x6d, 0x7d, 0x14, 0xac, 0x7f, 0x00, 0x36, 0x23, 0xbe, 0x8e, 0x84, 0x4f, 0x70, 0xa5,
+	0xba, 0x6e, 0x9d, 0x88, 0xd9, 0x3a, 0xa1, 0x24, 0x4f, 0x8b, 0xac, 0x5a, 0xaa, 0x7d, 0xdf, 0x4b,
+	0x7c, 0x83, 0xa5, 0xb1, 0xd1, 0x73, 0xb7, 0x2b, 0x11, 0x9a, 0xe5, 0x69, 0xb1, 0x78, 0x7e, 0x2c,
+	0x27, 0xfd, 0xa5, 0x96, 0xbf, 0xe8, 0xb0, 0x5e, 0x51, 0x5d, 0x9a, 0x03, 0xc8, 0xfa, 0x37, 0x81,
+	0xeb, 0xd3, 0x11, 0xcc, 0x61, 0xd1, 0x38, 0xb1, 0xc1, 0xf7, 0xa3, 0xa3, 0x24, 0x4f, 0x8a, 0xac,
+	0x3a, 0x56, 0x48, 0x70, 0x61, 0xb9, 0x6d, 0x4d, 0xd7, 0xd0, 0x4c, 0xd3, 0x7f, 0xc4, 0x5b, 0x38,
+	0xe7, 0x21, 0xf6, 0x43, 0xa4, 0x54, 0x83, 0x3d, 0xe1, 0x03, 0x64, 0x26, 0x44, 0xff, 0x65, 0x6c,
+	0x14, 0x3a, 0xd3, 0xa5, 0x0e, 0x02, 0x6f, 0x60, 0xae, 0xcf, 0xa5, 0xb9, 0x1e, 0xda, 0xc1, 0xe6,
+	0xfe, 0xe3, 0x6e, 0xb2, 0x50, 0xad, 0x3f, 0xf9, 0x17, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x18, 0x9e,
+	0x17, 0x5d, 0x01, 0x00, 0x00,
+}
diff --git a/ui/status/build_error_proto/build_error.proto b/ui/status/build_error_proto/build_error.proto
new file mode 100644
index 0000000..9c8470d
--- /dev/null
+++ b/ui/status/build_error_proto/build_error.proto
@@ -0,0 +1,46 @@
+// 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.
+
+syntax = "proto2";
+
+package soong_build_error;
+option go_package = "soong_build_error_proto";
+
+message BuildError {
+  // List of error messages of the overall build. The error messages
+  // are not associated with a build action.
+  repeated string error_messages = 1;
+
+  // List of build action errors.
+  repeated BuildActionError action_errors = 2;
+}
+
+// Build is composed of a list of build action. There can be a set of build
+// actions that can failed.
+message BuildActionError {
+  // Description of the command.
+  optional string description = 1;
+
+  // The command name that raised the error.
+  optional string command = 2;
+
+  // The command output stream.
+  optional string output = 3;
+
+  // List of artifacts (i.e. files) that was produced by the command.
+  repeated string artifacts = 4;
+
+  // The error string produced by the build action.
+  optional string error = 5;
+}
diff --git a/ui/status/build_error_proto/regen.sh b/ui/status/build_error_proto/regen.sh
new file mode 100755
index 0000000..7c3ec8f
--- /dev/null
+++ b/ui/status/build_error_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. build_error.proto
diff --git a/ui/status/critical_path.go b/ui/status/critical_path.go
new file mode 100644
index 0000000..444327b
--- /dev/null
+++ b/ui/status/critical_path.go
@@ -0,0 +1,152 @@
+// 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 status
+
+import (
+	"time"
+
+	"android/soong/ui/logger"
+)
+
+func NewCriticalPath(log logger.Logger) StatusOutput {
+	return &criticalPath{
+		log:     log,
+		running: make(map[*Action]time.Time),
+		nodes:   make(map[string]*node),
+		clock:   osClock{},
+	}
+}
+
+type criticalPath struct {
+	log logger.Logger
+
+	nodes   map[string]*node
+	running map[*Action]time.Time
+
+	start, end time.Time
+
+	clock clock
+}
+
+type clock interface {
+	Now() time.Time
+}
+
+type osClock struct{}
+
+func (osClock) Now() time.Time { return time.Now() }
+
+// A critical path node stores the critical path (the minimum time to build the node and all of its dependencies given
+// perfect parallelism) for an node.
+type node struct {
+	action             *Action
+	cumulativeDuration time.Duration
+	duration           time.Duration
+	input              *node
+}
+
+func (cp *criticalPath) StartAction(action *Action, counts Counts) {
+	start := cp.clock.Now()
+	if cp.start.IsZero() {
+		cp.start = start
+	}
+	cp.running[action] = start
+}
+
+func (cp *criticalPath) FinishAction(result ActionResult, counts Counts) {
+	if start, ok := cp.running[result.Action]; ok {
+		delete(cp.running, result.Action)
+
+		// Determine the input to this edge with the longest cumulative duration
+		var criticalPathInput *node
+		for _, input := range result.Action.Inputs {
+			if x := cp.nodes[input]; x != nil {
+				if criticalPathInput == nil || x.cumulativeDuration > criticalPathInput.cumulativeDuration {
+					criticalPathInput = x
+				}
+			}
+		}
+
+		end := cp.clock.Now()
+		duration := end.Sub(start)
+
+		cumulativeDuration := duration
+		if criticalPathInput != nil {
+			cumulativeDuration += criticalPathInput.cumulativeDuration
+		}
+
+		node := &node{
+			action:             result.Action,
+			cumulativeDuration: cumulativeDuration,
+			duration:           duration,
+			input:              criticalPathInput,
+		}
+
+		for _, output := range result.Action.Outputs {
+			cp.nodes[output] = node
+		}
+
+		cp.end = end
+	}
+}
+
+func (cp *criticalPath) Flush() {
+	criticalPath := cp.criticalPath()
+
+	if len(criticalPath) > 0 {
+		// Log the critical path to the verbose log
+		criticalTime := criticalPath[0].cumulativeDuration.Round(time.Second)
+		cp.log.Verbosef("critical path took %s", criticalTime.String())
+		if !cp.start.IsZero() {
+			elapsedTime := cp.end.Sub(cp.start).Round(time.Second)
+			cp.log.Verbosef("elapsed time %s", elapsedTime.String())
+			cp.log.Verbosef("perfect parallelism ratio %d%%",
+				int(float64(criticalTime)/float64(elapsedTime)*100))
+		}
+		cp.log.Verbose("critical path:")
+		for i := len(criticalPath) - 1; i >= 0; i-- {
+			duration := criticalPath[i].duration
+			duration = duration.Round(time.Second)
+			seconds := int(duration.Seconds())
+			cp.log.Verbosef("   %2d:%02d %s",
+				seconds/60, seconds%60, criticalPath[i].action.Description)
+		}
+	}
+}
+
+func (cp *criticalPath) Message(level MsgLevel, msg string) {}
+
+func (cp *criticalPath) Write(p []byte) (n int, err error) { return len(p), nil }
+
+func (cp *criticalPath) criticalPath() []*node {
+	var max *node
+
+	// Find the node with the longest critical path
+	for _, node := range cp.nodes {
+		if max == nil || node.cumulativeDuration > max.cumulativeDuration {
+			max = node
+		}
+	}
+
+	// Follow the critical path back to the leaf node
+	var criticalPath []*node
+	node := max
+	for node != nil {
+		criticalPath = append(criticalPath, node)
+		node = node.input
+	}
+
+	return criticalPath
+}
diff --git a/ui/status/critical_path_test.go b/ui/status/critical_path_test.go
new file mode 100644
index 0000000..965e0ad
--- /dev/null
+++ b/ui/status/critical_path_test.go
@@ -0,0 +1,166 @@
+// 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 status
+
+import (
+	"reflect"
+	"testing"
+	"time"
+)
+
+type testCriticalPath struct {
+	*criticalPath
+	Counts
+
+	actions map[int]*Action
+}
+
+type testClock time.Time
+
+func (t testClock) Now() time.Time { return time.Time(t) }
+
+func (t *testCriticalPath) start(id int, startTime time.Duration, outputs, inputs []string) {
+	t.clock = testClock(time.Unix(0, 0).Add(startTime))
+	action := &Action{
+		Description: outputs[0],
+		Outputs:     outputs,
+		Inputs:      inputs,
+	}
+
+	t.actions[id] = action
+	t.StartAction(action, t.Counts)
+}
+
+func (t *testCriticalPath) finish(id int, endTime time.Duration) {
+	t.clock = testClock(time.Unix(0, 0).Add(endTime))
+	t.FinishAction(ActionResult{
+		Action: t.actions[id],
+	}, t.Counts)
+}
+
+func TestCriticalPath(t *testing.T) {
+	tests := []struct {
+		name     string
+		msgs     func(*testCriticalPath)
+		want     []string
+		wantTime time.Duration
+	}{
+		{
+			name: "empty",
+			msgs: func(cp *testCriticalPath) {},
+		},
+		{
+			name: "duplicate",
+			msgs: func(cp *testCriticalPath) {
+				cp.start(0, 0, []string{"a"}, nil)
+				cp.start(1, 0, []string{"a"}, nil)
+				cp.finish(0, 1000)
+				cp.finish(0, 2000)
+			},
+			want:     []string{"a"},
+			wantTime: 1000,
+		},
+		{
+			name: "linear",
+			//  a
+			//  |
+			//  b
+			//  |
+			//  c
+			msgs: func(cp *testCriticalPath) {
+				cp.start(0, 0, []string{"a"}, nil)
+				cp.finish(0, 1000)
+				cp.start(1, 1000, []string{"b"}, []string{"a"})
+				cp.finish(1, 2000)
+				cp.start(2, 3000, []string{"c"}, []string{"b"})
+				cp.finish(2, 4000)
+			},
+			want:     []string{"c", "b", "a"},
+			wantTime: 3000,
+		},
+		{
+			name: "diamond",
+			//  a
+			//  |\
+			//  b c
+			//  |/
+			//  d
+			msgs: func(cp *testCriticalPath) {
+				cp.start(0, 0, []string{"a"}, nil)
+				cp.finish(0, 1000)
+				cp.start(1, 1000, []string{"b"}, []string{"a"})
+				cp.start(2, 1000, []string{"c"}, []string{"a"})
+				cp.finish(1, 2000)
+				cp.finish(2, 3000)
+				cp.start(3, 3000, []string{"d"}, []string{"b", "c"})
+				cp.finish(3, 4000)
+			},
+			want:     []string{"d", "c", "a"},
+			wantTime: 4000,
+		},
+		{
+			name: "multiple",
+			//  a d
+			//  | |
+			//  b e
+			//  |
+			//  c
+			msgs: func(cp *testCriticalPath) {
+				cp.start(0, 0, []string{"a"}, nil)
+				cp.start(3, 0, []string{"d"}, nil)
+				cp.finish(0, 1000)
+				cp.finish(3, 1000)
+				cp.start(1, 1000, []string{"b"}, []string{"a"})
+				cp.start(4, 1000, []string{"e"}, []string{"d"})
+				cp.finish(1, 2000)
+				cp.start(2, 2000, []string{"c"}, []string{"b"})
+				cp.finish(2, 3000)
+				cp.finish(4, 4000)
+
+			},
+			want:     []string{"e", "d"},
+			wantTime: 4000,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			cp := &testCriticalPath{
+				criticalPath: NewCriticalPath(nil).(*criticalPath),
+				actions:      make(map[int]*Action),
+			}
+
+			tt.msgs(cp)
+
+			criticalPath := cp.criticalPath.criticalPath()
+
+			var descs []string
+			for _, x := range criticalPath {
+				descs = append(descs, x.action.Description)
+			}
+
+			if !reflect.DeepEqual(descs, tt.want) {
+				t.Errorf("criticalPath.criticalPath() = %v, want %v", descs, tt.want)
+			}
+
+			var gotTime time.Duration
+			if len(criticalPath) > 0 {
+				gotTime = criticalPath[0].cumulativeDuration
+			}
+			if gotTime != tt.wantTime {
+				t.Errorf("cumulativeDuration[0].cumulativeDuration = %v, want %v", gotTime, tt.wantTime)
+			}
+		})
+	}
+}
diff --git a/ui/status/log.go b/ui/status/log.go
index 921aa44..9090f49 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -15,11 +15,17 @@
 package status
 
 import (
-	"android/soong/ui/logger"
 	"compress/gzip"
+	"errors"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"strings"
+
+	"github.com/golang/protobuf/proto"
+
+	"android/soong/ui/logger"
+	"android/soong/ui/status/build_error_proto"
 )
 
 type verboseLog struct {
@@ -71,9 +77,13 @@
 	fmt.Fprintf(v.w, "%s%s\n", level.Prefix(), message)
 }
 
-type errorLog struct {
-	w io.WriteCloser
+func (v *verboseLog) Write(p []byte) (int, error) {
+	fmt.Fprint(v.w, string(p))
+	return len(p), nil
+}
 
+type errorLog struct {
+	w     io.WriteCloser
 	empty bool
 }
 
@@ -97,20 +107,17 @@
 		return
 	}
 
-	cmd := result.Command
-	if cmd == "" {
-		cmd = result.Description
-	}
-
 	if !e.empty {
 		fmt.Fprintf(e.w, "\n\n")
 	}
 	e.empty = false
 
 	fmt.Fprintf(e.w, "FAILED: %s\n", result.Description)
+
 	if len(result.Outputs) > 0 {
 		fmt.Fprintf(e.w, "Outputs: %s\n", strings.Join(result.Outputs, " "))
 	}
+
 	fmt.Fprintf(e.w, "Error: %s\n", result.Error)
 	if result.Command != "" {
 		fmt.Fprintf(e.w, "Command: %s\n", result.Command)
@@ -134,3 +141,60 @@
 
 	fmt.Fprintf(e.w, "error: %s\n", message)
 }
+
+func (e *errorLog) Write(p []byte) (int, error) {
+	fmt.Fprint(e.w, string(p))
+	return len(p), nil
+}
+
+type errorProtoLog struct {
+	errorProto soong_build_error_proto.BuildError
+	filename   string
+	log        logger.Logger
+}
+
+func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
+	return &errorProtoLog{
+		errorProto: soong_build_error_proto.BuildError{},
+		filename:   filename,
+		log:        log,
+	}
+}
+
+func (e *errorProtoLog) StartAction(action *Action, counts Counts) {}
+
+func (e *errorProtoLog) FinishAction(result ActionResult, counts Counts) {
+	if result.Error == nil {
+		return
+	}
+
+	e.errorProto.ActionErrors = append(e.errorProto.ActionErrors, &soong_build_error_proto.BuildActionError{
+		Description: proto.String(result.Description),
+		Command:     proto.String(result.Command),
+		Output:      proto.String(result.Output),
+		Artifacts:   result.Outputs,
+		Error:       proto.String(result.Error.Error()),
+	})
+}
+
+func (e *errorProtoLog) Flush() {
+	data, err := proto.Marshal(&e.errorProto)
+	if err != nil {
+		e.log.Println("Failed to marshal build status proto: %v", err)
+		return
+	}
+	err = ioutil.WriteFile(e.filename, []byte(data), 0644)
+	if err != nil {
+		e.log.Println("Failed to write file %s: %v", e.errorProto, err)
+	}
+}
+
+func (e *errorProtoLog) Message(level MsgLevel, message string) {
+	if level > ErrorLvl {
+		e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
+	}
+}
+
+func (e *errorProtoLog) Write(p []byte) (int, error) {
+	return 0, errors.New("not supported")
+}
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index ee2a2da..9cf2f6a 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -142,6 +142,7 @@
 			action := &Action{
 				Description: msg.EdgeStarted.GetDesc(),
 				Outputs:     msg.EdgeStarted.Outputs,
+				Inputs:      msg.EdgeStarted.Inputs,
 				Command:     msg.EdgeStarted.GetCommand(),
 			}
 			n.status.StartAction(action)
diff --git a/ui/status/status.go b/ui/status/status.go
index 46ec72e..df33baa 100644
--- a/ui/status/status.go
+++ b/ui/status/status.go
@@ -32,6 +32,10 @@
 	// but they can be any string.
 	Outputs []string
 
+	// Inputs is the (optional) list of inputs. Usually these are files,
+	// but they can be any string.
+	Inputs []string
+
 	// Command is the actual command line executed to perform the action.
 	// It's optional, but one of either Description or Command should be
 	// set.
@@ -173,6 +177,9 @@
 	// Flush is called when your outputs should be flushed / closed. No
 	// output is expected after this call.
 	Flush()
+
+	// Write lets StatusOutput implement io.Writer
+	Write(p []byte) (n int, err error)
 }
 
 // Status is the multiplexer / accumulator between ToolStatus instances (via
diff --git a/ui/status/status_test.go b/ui/status/status_test.go
index e62785f..9494582 100644
--- a/ui/status/status_test.go
+++ b/ui/status/status_test.go
@@ -27,6 +27,11 @@
 func (c counterOutput) Message(level MsgLevel, msg string) {}
 func (c counterOutput) Flush()                             {}
 
+func (c counterOutput) Write(p []byte) (int, error) {
+	// Discard writes
+	return len(p), nil
+}
+
 func (c counterOutput) Expect(t *testing.T, counts Counts) {
 	if Counts(c) == counts {
 		return
diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp
index 7104a50..b533b0d 100644
--- a/ui/terminal/Android.bp
+++ b/ui/terminal/Android.bp
@@ -17,11 +17,15 @@
     pkgPath: "android/soong/ui/terminal",
     deps: ["soong-ui-status"],
     srcs: [
+        "dumb_status.go",
+        "format.go",
+        "smart_status.go",
         "status.go",
-        "writer.go",
+        "stdio.go",
         "util.go",
     ],
     testSrcs: [
+        "status_test.go",
         "util_test.go",
     ],
     darwin: {
diff --git a/ui/terminal/dumb_status.go b/ui/terminal/dumb_status.go
new file mode 100644
index 0000000..201770f
--- /dev/null
+++ b/ui/terminal/dumb_status.go
@@ -0,0 +1,71 @@
+// 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 terminal
+
+import (
+	"fmt"
+	"io"
+
+	"android/soong/ui/status"
+)
+
+type dumbStatusOutput struct {
+	writer    io.Writer
+	formatter formatter
+}
+
+// NewDumbStatusOutput returns a StatusOutput that represents the
+// current build status similarly to Ninja's built-in terminal
+// output.
+func NewDumbStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
+	return &dumbStatusOutput{
+		writer:    w,
+		formatter: formatter,
+	}
+}
+
+func (s *dumbStatusOutput) Message(level status.MsgLevel, message string) {
+	if level >= status.StatusLvl {
+		fmt.Fprintln(s.writer, s.formatter.message(level, message))
+	}
+}
+
+func (s *dumbStatusOutput) StartAction(action *status.Action, counts status.Counts) {
+}
+
+func (s *dumbStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
+	str := result.Description
+	if str == "" {
+		str = result.Command
+	}
+
+	progress := s.formatter.progress(counts) + str
+
+	output := s.formatter.result(result)
+	output = string(stripAnsiEscapes([]byte(output)))
+
+	if output != "" {
+		fmt.Fprint(s.writer, progress, "\n", output)
+	} else {
+		fmt.Fprintln(s.writer, progress)
+	}
+}
+
+func (s *dumbStatusOutput) Flush() {}
+
+func (s *dumbStatusOutput) Write(p []byte) (int, error) {
+	fmt.Fprint(s.writer, string(p))
+	return len(p), nil
+}
diff --git a/ui/terminal/format.go b/ui/terminal/format.go
new file mode 100644
index 0000000..4205bdc
--- /dev/null
+++ b/ui/terminal/format.go
@@ -0,0 +1,123 @@
+// 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 terminal
+
+import (
+	"fmt"
+	"strings"
+	"time"
+
+	"android/soong/ui/status"
+)
+
+type formatter struct {
+	format string
+	quiet  bool
+	start  time.Time
+}
+
+// newFormatter returns a formatter for formatting output to
+// the terminal in a format similar to Ninja.
+// format takes nearly all the same options as NINJA_STATUS.
+// %c is currently unsupported.
+func newFormatter(format string, quiet bool) formatter {
+	return formatter{
+		format: format,
+		quiet:  quiet,
+		start:  time.Now(),
+	}
+}
+
+func (s formatter) message(level status.MsgLevel, message string) string {
+	if level >= status.ErrorLvl {
+		return fmt.Sprintf("FAILED: %s", message)
+	} else if level > status.StatusLvl {
+		return fmt.Sprintf("%s%s", level.Prefix(), message)
+	} else if level == status.StatusLvl {
+		return message
+	}
+	return ""
+}
+
+func (s formatter) progress(counts status.Counts) string {
+	if s.format == "" {
+		return fmt.Sprintf("[%3d%% %d/%d] ", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions)
+	}
+
+	buf := &strings.Builder{}
+	for i := 0; i < len(s.format); i++ {
+		c := s.format[i]
+		if c != '%' {
+			buf.WriteByte(c)
+			continue
+		}
+
+		i = i + 1
+		if i == len(s.format) {
+			buf.WriteByte(c)
+			break
+		}
+
+		c = s.format[i]
+		switch c {
+		case '%':
+			buf.WriteByte(c)
+		case 's':
+			fmt.Fprintf(buf, "%d", counts.StartedActions)
+		case 't':
+			fmt.Fprintf(buf, "%d", counts.TotalActions)
+		case 'r':
+			fmt.Fprintf(buf, "%d", counts.RunningActions)
+		case 'u':
+			fmt.Fprintf(buf, "%d", counts.TotalActions-counts.StartedActions)
+		case 'f':
+			fmt.Fprintf(buf, "%d", counts.FinishedActions)
+		case 'o':
+			fmt.Fprintf(buf, "%.1f", float64(counts.FinishedActions)/time.Since(s.start).Seconds())
+		case 'c':
+			// TODO: implement?
+			buf.WriteRune('?')
+		case 'p':
+			fmt.Fprintf(buf, "%3d%%", 100*counts.FinishedActions/counts.TotalActions)
+		case 'e':
+			fmt.Fprintf(buf, "%.3f", time.Since(s.start).Seconds())
+		default:
+			buf.WriteString("unknown placeholder '")
+			buf.WriteByte(c)
+			buf.WriteString("'")
+		}
+	}
+	return buf.String()
+}
+
+func (s formatter) result(result status.ActionResult) string {
+	var ret string
+	if result.Error != nil {
+		targets := strings.Join(result.Outputs, " ")
+		if s.quiet || result.Command == "" {
+			ret = fmt.Sprintf("FAILED: %s\n%s", targets, result.Output)
+		} else {
+			ret = fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output)
+		}
+	} else if result.Output != "" {
+		ret = result.Output
+	}
+
+	if len(ret) > 0 && ret[len(ret)-1] != '\n' {
+		ret += "\n"
+	}
+
+	return ret
+}
diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go
new file mode 100644
index 0000000..8659d4d
--- /dev/null
+++ b/ui/terminal/smart_status.go
@@ -0,0 +1,427 @@
+// 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 terminal
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"os/signal"
+	"strconv"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+
+	"android/soong/ui/status"
+)
+
+const tableHeightEnVar = "SOONG_UI_TABLE_HEIGHT"
+
+type actionTableEntry struct {
+	action    *status.Action
+	startTime time.Time
+}
+
+type smartStatusOutput struct {
+	writer    io.Writer
+	formatter formatter
+
+	lock sync.Mutex
+
+	haveBlankLine bool
+
+	tableMode             bool
+	tableHeight           int
+	requestedTableHeight  int
+	termWidth, termHeight int
+
+	runningActions  []actionTableEntry
+	ticker          *time.Ticker
+	done            chan bool
+	sigwinch        chan os.Signal
+	sigwinchHandled chan bool
+}
+
+// NewSmartStatusOutput returns a StatusOutput that represents the
+// 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,
+
+		done:     make(chan bool),
+		sigwinch: make(chan os.Signal),
+	}
+
+	s.updateTermSize()
+
+	if s.tableMode {
+		// Add empty lines at the bottom of the screen to scroll back the existing history
+		// and make room for the action table.
+		// TODO: read the cursor position to see if the empty lines are necessary?
+		for i := 0; i < s.tableHeight; i++ {
+			fmt.Fprintln(w)
+		}
+
+		// Hide the cursor to prevent seeing it bouncing around
+		fmt.Fprintf(s.writer, ansi.hideCursor())
+
+		// Configure the empty action table
+		s.actionTable()
+
+		// Start a tick to update the action table periodically
+		s.startActionTableTick()
+	}
+
+	s.startSigwinch()
+
+	return s
+}
+
+func (s *smartStatusOutput) Message(level status.MsgLevel, message string) {
+	if level < status.StatusLvl {
+		return
+	}
+
+	str := s.formatter.message(level, message)
+
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	if level > status.StatusLvl {
+		s.print(str)
+	} else {
+		s.statusLine(str)
+	}
+}
+
+func (s *smartStatusOutput) StartAction(action *status.Action, counts status.Counts) {
+	startTime := time.Now()
+
+	str := action.Description
+	if str == "" {
+		str = action.Command
+	}
+
+	progress := s.formatter.progress(counts)
+
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.runningActions = append(s.runningActions, actionTableEntry{
+		action:    action,
+		startTime: startTime,
+	})
+
+	s.statusLine(progress + str)
+}
+
+func (s *smartStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
+	str := result.Description
+	if str == "" {
+		str = result.Command
+	}
+
+	progress := s.formatter.progress(counts) + str
+
+	output := s.formatter.result(result)
+
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	for i, runningAction := range s.runningActions {
+		if runningAction.action == result.Action {
+			s.runningActions = append(s.runningActions[:i], s.runningActions[i+1:]...)
+			break
+		}
+	}
+
+	if output != "" {
+		s.statusLine(progress)
+		s.requestLine()
+		s.print(output)
+	} else {
+		s.statusLine(progress)
+	}
+}
+
+func (s *smartStatusOutput) Flush() {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.stopSigwinch()
+
+	s.requestLine()
+
+	s.runningActions = nil
+
+	if s.tableMode {
+		s.stopActionTableTick()
+
+		// Update the table after clearing runningActions to clear it
+		s.actionTable()
+
+		// Reset the scrolling region to the whole terminal
+		fmt.Fprintf(s.writer, ansi.resetScrollingMargins())
+		_, height, _ := termSize(s.writer)
+		// Move the cursor to the top of the now-blank, previously non-scrolling region
+		fmt.Fprintf(s.writer, ansi.setCursor(height-s.tableHeight, 0))
+		// Turn the cursor back on
+		fmt.Fprintf(s.writer, ansi.showCursor())
+	}
+}
+
+func (s *smartStatusOutput) Write(p []byte) (int, error) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+	s.print(string(p))
+	return len(p), nil
+}
+
+func (s *smartStatusOutput) requestLine() {
+	if !s.haveBlankLine {
+		fmt.Fprintln(s.writer)
+		s.haveBlankLine = true
+	}
+}
+
+func (s *smartStatusOutput) print(str string) {
+	if !s.haveBlankLine {
+		fmt.Fprint(s.writer, "\r", ansi.clearToEndOfLine())
+		s.haveBlankLine = true
+	}
+	fmt.Fprint(s.writer, str)
+	if len(str) == 0 || str[len(str)-1] != '\n' {
+		fmt.Fprint(s.writer, "\n")
+	}
+}
+
+func (s *smartStatusOutput) statusLine(str string) {
+	idx := strings.IndexRune(str, '\n')
+	if idx != -1 {
+		str = str[0:idx]
+	}
+
+	// Limit line width to the terminal width, otherwise we'll wrap onto
+	// another line and we won't delete the previous line.
+	str = elide(str, s.termWidth)
+
+	// Move to the beginning on the line, turn on bold, print the output,
+	// turn off bold, then clear the rest of the line.
+	start := "\r" + ansi.bold()
+	end := ansi.regular() + ansi.clearToEndOfLine()
+	fmt.Fprint(s.writer, start, str, end)
+	s.haveBlankLine = false
+}
+
+func elide(str string, width int) string {
+	if width > 0 && len(str) > width {
+		// TODO: Just do a max. Ninja elides the middle, but that's
+		// more complicated and these lines aren't that important.
+		str = str[:width]
+	}
+
+	return str
+}
+
+func (s *smartStatusOutput) startActionTableTick() {
+	s.ticker = time.NewTicker(time.Second)
+	go func() {
+		for {
+			select {
+			case <-s.ticker.C:
+				s.lock.Lock()
+				s.actionTable()
+				s.lock.Unlock()
+			case <-s.done:
+				return
+			}
+		}
+	}()
+}
+
+func (s *smartStatusOutput) stopActionTableTick() {
+	s.ticker.Stop()
+	s.done <- true
+}
+
+func (s *smartStatusOutput) startSigwinch() {
+	signal.Notify(s.sigwinch, syscall.SIGWINCH)
+	go func() {
+		for _ = range s.sigwinch {
+			s.lock.Lock()
+			s.updateTermSize()
+			if s.tableMode {
+				s.actionTable()
+			}
+			s.lock.Unlock()
+			if s.sigwinchHandled != nil {
+				s.sigwinchHandled <- true
+			}
+		}
+	}()
+}
+
+func (s *smartStatusOutput) stopSigwinch() {
+	signal.Stop(s.sigwinch)
+	close(s.sigwinch)
+}
+
+func (s *smartStatusOutput) updateTermSize() {
+	if w, h, ok := termSize(s.writer); ok {
+		firstUpdate := s.termHeight == 0 && s.termWidth == 0
+		oldScrollingHeight := s.termHeight - s.tableHeight
+
+		s.termWidth, s.termHeight = w, h
+
+		if s.tableMode {
+			tableHeight := s.requestedTableHeight
+			if tableHeight > s.termHeight-1 {
+				tableHeight = s.termHeight - 1
+			}
+			s.tableHeight = tableHeight
+
+			scrollingHeight := s.termHeight - s.tableHeight
+
+			if !firstUpdate {
+				// If the scrolling region has changed, attempt to pan the existing text so that it is
+				// not overwritten by the table.
+				if scrollingHeight < oldScrollingHeight {
+					pan := oldScrollingHeight - scrollingHeight
+					if pan > s.tableHeight {
+						pan = s.tableHeight
+					}
+					fmt.Fprint(s.writer, ansi.panDown(pan))
+				}
+			}
+		}
+	}
+}
+
+func (s *smartStatusOutput) actionTable() {
+	scrollingHeight := s.termHeight - s.tableHeight
+
+	// Update the scrolling region in case the height of the terminal changed
+	fmt.Fprint(s.writer, ansi.setScrollingMargins(0, scrollingHeight))
+	// Move the cursor to the first line of the non-scrolling region
+	fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight+1, 0))
+
+	// Write as many status lines as fit in the table
+	var tableLine int
+	var runningAction actionTableEntry
+	for tableLine, runningAction = range s.runningActions {
+		if tableLine >= s.tableHeight {
+			break
+		}
+
+		seconds := int(time.Since(runningAction.startTime).Round(time.Second).Seconds())
+
+		desc := runningAction.action.Description
+		if desc == "" {
+			desc = runningAction.action.Command
+		}
+
+		color := ""
+		if seconds >= 60 {
+			color = ansi.red() + ansi.bold()
+		} else if seconds >= 30 {
+			color = ansi.yellow() + ansi.bold()
+		}
+
+		durationStr := fmt.Sprintf("   %2d:%02d ", seconds/60, seconds%60)
+		desc = elide(desc, s.termWidth-len(durationStr))
+		durationStr = color + durationStr + ansi.regular()
+
+		fmt.Fprint(s.writer, durationStr, desc, ansi.clearToEndOfLine())
+		if tableLine < s.tableHeight-1 {
+			fmt.Fprint(s.writer, "\n")
+		}
+	}
+
+	// Clear any remaining lines in the table
+	for ; tableLine < s.tableHeight; tableLine++ {
+		fmt.Fprint(s.writer, ansi.clearToEndOfLine())
+		if tableLine < s.tableHeight-1 {
+			fmt.Fprint(s.writer, "\n")
+		}
+	}
+
+	// Move the cursor back to the last line of the scrolling region
+	fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight, 0))
+}
+
+var ansi = ansiImpl{}
+
+type ansiImpl struct{}
+
+func (ansiImpl) clearToEndOfLine() string {
+	return "\x1b[K"
+}
+
+func (ansiImpl) setCursor(row, column int) string {
+	// Direct cursor address
+	return fmt.Sprintf("\x1b[%d;%dH", row, column)
+}
+
+func (ansiImpl) setScrollingMargins(top, bottom int) string {
+	// Set Top and Bottom Margins DECSTBM
+	return fmt.Sprintf("\x1b[%d;%dr", top, bottom)
+}
+
+func (ansiImpl) resetScrollingMargins() string {
+	// Set Top and Bottom Margins DECSTBM
+	return fmt.Sprintf("\x1b[r")
+}
+
+func (ansiImpl) red() string {
+	return "\x1b[31m"
+}
+
+func (ansiImpl) yellow() string {
+	return "\x1b[33m"
+}
+
+func (ansiImpl) bold() string {
+	return "\x1b[1m"
+}
+
+func (ansiImpl) regular() string {
+	return "\x1b[0m"
+}
+
+func (ansiImpl) showCursor() string {
+	return "\x1b[?25h"
+}
+
+func (ansiImpl) hideCursor() string {
+	return "\x1b[?25l"
+}
+
+func (ansiImpl) panDown(lines int) string {
+	return fmt.Sprintf("\x1b[%dS", lines)
+}
+
+func (ansiImpl) panUp(lines int) string {
+	return fmt.Sprintf("\x1b[%dT", lines)
+}
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 2445c5b..69a2a09 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -15,131 +15,23 @@
 package terminal
 
 import (
-	"fmt"
-	"strings"
-	"time"
+	"io"
 
 	"android/soong/ui/status"
 )
 
-type statusOutput struct {
-	writer Writer
-	format string
-
-	start time.Time
-	quiet bool
-}
-
 // NewStatusOutput returns a StatusOutput that represents the
 // current build status similarly to Ninja's built-in terminal
 // output.
 //
 // statusFormat takes nearly all the same options as NINJA_STATUS.
 // %c is currently unsupported.
-func NewStatusOutput(w Writer, statusFormat string, quietBuild bool) status.StatusOutput {
-	return &statusOutput{
-		writer: w,
-		format: statusFormat,
+func NewStatusOutput(w io.Writer, statusFormat string, quietBuild bool) status.StatusOutput {
+	formatter := newFormatter(statusFormat, quietBuild)
 
-		start: time.Now(),
-		quiet: quietBuild,
-	}
-}
-
-func (s *statusOutput) Message(level status.MsgLevel, message string) {
-	if level >= status.ErrorLvl {
-		s.writer.Print(fmt.Sprintf("FAILED: %s", message))
-	} else if level > status.StatusLvl {
-		s.writer.Print(fmt.Sprintf("%s%s", level.Prefix(), message))
-	} else if level == status.StatusLvl {
-		s.writer.StatusLine(message)
-	}
-}
-
-func (s *statusOutput) StartAction(action *status.Action, counts status.Counts) {
-	if !s.writer.isSmartTerminal() {
-		return
-	}
-
-	str := action.Description
-	if str == "" {
-		str = action.Command
-	}
-
-	s.writer.StatusLine(s.progress(counts) + str)
-}
-
-func (s *statusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
-	str := result.Description
-	if str == "" {
-		str = result.Command
-	}
-
-	progress := s.progress(counts) + str
-
-	if result.Error != nil {
-		targets := strings.Join(result.Outputs, " ")
-		if s.quiet || result.Command == "" {
-			s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s", targets, result.Output))
-		} else {
-			s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output))
-		}
-	} else if result.Output != "" {
-		s.writer.StatusAndMessage(progress, result.Output)
+	if isSmartTerminal(w) {
+		return NewSmartStatusOutput(w, formatter)
 	} else {
-		s.writer.StatusLine(progress)
+		return NewDumbStatusOutput(w, formatter)
 	}
 }
-
-func (s *statusOutput) Flush() {}
-
-func (s *statusOutput) progress(counts status.Counts) string {
-	if s.format == "" {
-		return fmt.Sprintf("[%3d%% %d/%d] ", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions)
-	}
-
-	buf := &strings.Builder{}
-	for i := 0; i < len(s.format); i++ {
-		c := s.format[i]
-		if c != '%' {
-			buf.WriteByte(c)
-			continue
-		}
-
-		i = i + 1
-		if i == len(s.format) {
-			buf.WriteByte(c)
-			break
-		}
-
-		c = s.format[i]
-		switch c {
-		case '%':
-			buf.WriteByte(c)
-		case 's':
-			fmt.Fprintf(buf, "%d", counts.StartedActions)
-		case 't':
-			fmt.Fprintf(buf, "%d", counts.TotalActions)
-		case 'r':
-			fmt.Fprintf(buf, "%d", counts.RunningActions)
-		case 'u':
-			fmt.Fprintf(buf, "%d", counts.TotalActions-counts.StartedActions)
-		case 'f':
-			fmt.Fprintf(buf, "%d", counts.FinishedActions)
-		case 'o':
-			fmt.Fprintf(buf, "%.1f", float64(counts.FinishedActions)/time.Since(s.start).Seconds())
-		case 'c':
-			// TODO: implement?
-			buf.WriteRune('?')
-		case 'p':
-			fmt.Fprintf(buf, "%3d%%", 100*counts.FinishedActions/counts.TotalActions)
-		case 'e':
-			fmt.Fprintf(buf, "%.3f", time.Since(s.start).Seconds())
-		default:
-			buf.WriteString("unknown placeholder '")
-			buf.WriteByte(c)
-			buf.WriteString("'")
-		}
-	}
-	return buf.String()
-}
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
new file mode 100644
index 0000000..81aa238
--- /dev/null
+++ b/ui/terminal/status_test.go
@@ -0,0 +1,284 @@
+// Copyright 2018 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 terminal
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"syscall"
+	"testing"
+
+	"android/soong/ui/status"
+)
+
+func TestStatusOutput(t *testing.T) {
+	tests := []struct {
+		name  string
+		calls func(stat status.StatusOutput)
+		smart string
+		dumb  string
+	}{
+		{
+			name:  "two actions",
+			calls: twoActions,
+			smart: "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+			dumb:  "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+		},
+		{
+			name:  "two parallel actions",
+			calls: twoParallelActions,
+			smart: "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+			dumb:  "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+		},
+		{
+			name:  "action with output",
+			calls: actionsWithOutput,
+			smart: "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+			dumb:  "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+		},
+		{
+			name:  "action with output without newline",
+			calls: actionsWithOutputWithoutNewline,
+			smart: "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+			dumb:  "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+		},
+		{
+			name:  "action with error",
+			calls: actionsWithError,
+			smart: "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+			dumb:  "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
+		},
+		{
+			name:  "action with empty description",
+			calls: actionWithEmptyDescription,
+			smart: "\r\x1b[1m[  0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
+			dumb:  "[100% 1/1] command1\n",
+		},
+		{
+			name:  "messages",
+			calls: actionsWithMessages,
+			smart: "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+			dumb:  "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
+		},
+		{
+			name:  "action with long description",
+			calls: actionWithLongDescription,
+			smart: "\r\x1b[1m[  0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
+			dumb:  "[ 50% 1/2] action with very long description to test eliding\n",
+		},
+		{
+			name:  "action with output with ansi codes",
+			calls: actionWithOuptutWithAnsiCodes,
+			smart: "\r\x1b[1m[  0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
+			dumb:  "[100% 1/1] action1\ncolor\n",
+		},
+	}
+
+	os.Setenv(tableHeightEnVar, "")
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			t.Run("smart", func(t *testing.T) {
+				smart := &fakeSmartTerminal{termWidth: 40}
+				stat := NewStatusOutput(smart, "", false)
+				tt.calls(stat)
+				stat.Flush()
+
+				if g, w := smart.String(), tt.smart; g != w {
+					t.Errorf("want:\n%q\ngot:\n%q", w, g)
+				}
+			})
+
+			t.Run("dumb", func(t *testing.T) {
+				dumb := &bytes.Buffer{}
+				stat := NewStatusOutput(dumb, "", false)
+				tt.calls(stat)
+				stat.Flush()
+
+				if g, w := dumb.String(), tt.dumb; g != w {
+					t.Errorf("want:\n%q\ngot:\n%q", w, g)
+				}
+			})
+		})
+	}
+}
+
+type runner struct {
+	counts status.Counts
+	stat   status.StatusOutput
+}
+
+func newRunner(stat status.StatusOutput, totalActions int) *runner {
+	return &runner{
+		counts: status.Counts{TotalActions: totalActions},
+		stat:   stat,
+	}
+}
+
+func (r *runner) startAction(action *status.Action) {
+	r.counts.StartedActions++
+	r.counts.RunningActions++
+	r.stat.StartAction(action, r.counts)
+}
+
+func (r *runner) finishAction(result status.ActionResult) {
+	r.counts.FinishedActions++
+	r.counts.RunningActions--
+	r.stat.FinishAction(result, r.counts)
+}
+
+func (r *runner) finishAndStartAction(result status.ActionResult, action *status.Action) {
+	r.counts.FinishedActions++
+	r.stat.FinishAction(result, r.counts)
+
+	r.counts.StartedActions++
+	r.stat.StartAction(action, r.counts)
+}
+
+var (
+	action1 = &status.Action{Description: "action1"}
+	result1 = status.ActionResult{Action: action1}
+	action2 = &status.Action{Description: "action2"}
+	result2 = status.ActionResult{Action: action2}
+	action3 = &status.Action{Description: "action3"}
+	result3 = status.ActionResult{Action: action3}
+)
+
+func twoActions(stat status.StatusOutput) {
+	runner := newRunner(stat, 2)
+	runner.startAction(action1)
+	runner.finishAction(result1)
+	runner.startAction(action2)
+	runner.finishAction(result2)
+}
+
+func twoParallelActions(stat status.StatusOutput) {
+	runner := newRunner(stat, 2)
+	runner.startAction(action1)
+	runner.startAction(action2)
+	runner.finishAction(result1)
+	runner.finishAction(result2)
+}
+
+func actionsWithOutput(stat status.StatusOutput) {
+	result2WithOutput := status.ActionResult{Action: action2, Output: "output1\noutput2\n"}
+
+	runner := newRunner(stat, 3)
+	runner.startAction(action1)
+	runner.finishAction(result1)
+	runner.startAction(action2)
+	runner.finishAction(result2WithOutput)
+	runner.startAction(action3)
+	runner.finishAction(result3)
+}
+
+func actionsWithOutputWithoutNewline(stat status.StatusOutput) {
+	result2WithOutputWithoutNewline := status.ActionResult{Action: action2, Output: "output1\noutput2"}
+
+	runner := newRunner(stat, 3)
+	runner.startAction(action1)
+	runner.finishAction(result1)
+	runner.startAction(action2)
+	runner.finishAction(result2WithOutputWithoutNewline)
+	runner.startAction(action3)
+	runner.finishAction(result3)
+}
+
+func actionsWithError(stat status.StatusOutput) {
+	action2WithError := &status.Action{Description: "action2", Outputs: []string{"f1", "f2"}, Command: "touch f1 f2"}
+	result2WithError := status.ActionResult{Action: action2WithError, Output: "error1\nerror2\n", Error: fmt.Errorf("error1")}
+
+	runner := newRunner(stat, 3)
+	runner.startAction(action1)
+	runner.finishAction(result1)
+	runner.startAction(action2WithError)
+	runner.finishAction(result2WithError)
+	runner.startAction(action3)
+	runner.finishAction(result3)
+}
+
+func actionWithEmptyDescription(stat status.StatusOutput) {
+	action1 := &status.Action{Command: "command1"}
+	result1 := status.ActionResult{Action: action1}
+
+	runner := newRunner(stat, 1)
+	runner.startAction(action1)
+	runner.finishAction(result1)
+}
+
+func actionsWithMessages(stat status.StatusOutput) {
+	runner := newRunner(stat, 2)
+
+	runner.startAction(action1)
+	runner.finishAction(result1)
+
+	stat.Message(status.VerboseLvl, "verbose")
+	stat.Message(status.StatusLvl, "status")
+	stat.Message(status.PrintLvl, "print")
+	stat.Message(status.ErrorLvl, "error")
+
+	runner.startAction(action2)
+	runner.finishAction(result2)
+}
+
+func actionWithLongDescription(stat status.StatusOutput) {
+	action1 := &status.Action{Description: "action with very long description to test eliding"}
+	result1 := status.ActionResult{Action: action1}
+
+	runner := newRunner(stat, 2)
+
+	runner.startAction(action1)
+
+	runner.finishAction(result1)
+}
+
+func actionWithOuptutWithAnsiCodes(stat status.StatusOutput) {
+	result1WithOutputWithAnsiCodes := status.ActionResult{Action: action1, Output: "\x1b[31mcolor\x1b[0m"}
+
+	runner := newRunner(stat, 1)
+	runner.startAction(action1)
+	runner.finishAction(result1WithOutputWithAnsiCodes)
+}
+
+func TestSmartStatusOutputWidthChange(t *testing.T) {
+	os.Setenv(tableHeightEnVar, "")
+
+	smart := &fakeSmartTerminal{termWidth: 40}
+	stat := NewStatusOutput(smart, "", false)
+	smartStat := stat.(*smartStatusOutput)
+	smartStat.sigwinchHandled = make(chan bool)
+
+	runner := newRunner(stat, 2)
+
+	action := &status.Action{Description: "action with very long description to test eliding"}
+	result := status.ActionResult{Action: action}
+
+	runner.startAction(action)
+	smart.termWidth = 30
+	// Fake a SIGWINCH
+	smartStat.sigwinch <- syscall.SIGWINCH
+	<-smartStat.sigwinchHandled
+	runner.finishAction(result)
+
+	stat.Flush()
+
+	w := "\r\x1b[1m[  0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very lo\x1b[0m\x1b[K\n"
+
+	if g := smart.String(); g != w {
+		t.Errorf("want:\n%q\ngot:\n%q", w, g)
+	}
+}
diff --git a/ui/terminal/stdio.go b/ui/terminal/stdio.go
new file mode 100644
index 0000000..dec2963
--- /dev/null
+++ b/ui/terminal/stdio.go
@@ -0,0 +1,55 @@
+// Copyright 2018 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 terminal provides a set of interfaces that can be used to interact
+// with the terminal (including falling back when the terminal is detected to
+// be a redirect or other dumb terminal)
+package terminal
+
+import (
+	"io"
+	"os"
+)
+
+// StdioInterface represents a set of stdin/stdout/stderr Reader/Writers
+type StdioInterface interface {
+	Stdin() io.Reader
+	Stdout() io.Writer
+	Stderr() io.Writer
+}
+
+// StdioImpl uses the OS stdin/stdout/stderr to implement StdioInterface
+type StdioImpl struct{}
+
+func (StdioImpl) Stdin() io.Reader  { return os.Stdin }
+func (StdioImpl) Stdout() io.Writer { return os.Stdout }
+func (StdioImpl) Stderr() io.Writer { return os.Stderr }
+
+var _ StdioInterface = StdioImpl{}
+
+type customStdio struct {
+	stdin  io.Reader
+	stdout io.Writer
+	stderr io.Writer
+}
+
+func NewCustomStdio(stdin io.Reader, stdout, stderr io.Writer) StdioInterface {
+	return customStdio{stdin, stdout, stderr}
+}
+
+func (c customStdio) Stdin() io.Reader  { return c.stdin }
+func (c customStdio) Stdout() io.Writer { return c.stdout }
+func (c customStdio) Stderr() io.Writer { return c.stderr }
+
+var _ StdioInterface = customStdio{}
diff --git a/ui/terminal/util.go b/ui/terminal/util.go
index a85a517..7a603d7 100644
--- a/ui/terminal/util.go
+++ b/ui/terminal/util.go
@@ -22,18 +22,23 @@
 	"unsafe"
 )
 
-func isTerminal(w io.Writer) bool {
+func isSmartTerminal(w io.Writer) bool {
 	if f, ok := w.(*os.File); ok {
+		if term, ok := os.LookupEnv("TERM"); ok && term == "dumb" {
+			return false
+		}
 		var termios syscall.Termios
 		_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, f.Fd(),
 			ioctlGetTermios, uintptr(unsafe.Pointer(&termios)),
 			0, 0, 0)
 		return err == 0
+	} else if _, ok := w.(*fakeSmartTerminal); ok {
+		return true
 	}
 	return false
 }
 
-func termWidth(w io.Writer) (int, bool) {
+func termSize(w io.Writer) (width int, height int, ok bool) {
 	if f, ok := w.(*os.File); ok {
 		var winsize struct {
 			ws_row, ws_column    uint16
@@ -42,9 +47,11 @@
 		_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, f.Fd(),
 			syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&winsize)),
 			0, 0, 0)
-		return int(winsize.ws_column), err == 0
+		return int(winsize.ws_column), int(winsize.ws_row), err == 0
+	} else if f, ok := w.(*fakeSmartTerminal); ok {
+		return f.termWidth, f.termHeight, true
 	}
-	return 0, false
+	return 0, 0, false
 }
 
 // stripAnsiEscapes strips ANSI control codes from a byte array in place.
@@ -99,3 +106,8 @@
 
 	return input
 }
+
+type fakeSmartTerminal struct {
+	bytes.Buffer
+	termWidth, termHeight int
+}
diff --git a/ui/terminal/writer.go b/ui/terminal/writer.go
deleted file mode 100644
index ebe4b2a..0000000
--- a/ui/terminal/writer.go
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2018 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 terminal provides a set of interfaces that can be used to interact
-// with the terminal (including falling back when the terminal is detected to
-// be a redirect or other dumb terminal)
-package terminal
-
-import (
-	"fmt"
-	"io"
-	"os"
-	"strings"
-	"sync"
-)
-
-// Writer provides an interface to write temporary and permanent messages to
-// the terminal.
-//
-// The terminal is considered to be a dumb terminal if TERM==dumb, or if a
-// terminal isn't detected on stdout/stderr (generally because it's a pipe or
-// file). Dumb terminals will strip out all ANSI escape sequences, including
-// colors.
-type Writer interface {
-	// Print prints the string to the terminal, overwriting any current
-	// status being displayed.
-	//
-	// On a dumb terminal, the status messages will be kept.
-	Print(str string)
-
-	// Status prints the first line of the string to the terminal,
-	// overwriting any previous status line. Strings longer than the width
-	// of the terminal will be cut off.
-	//
-	// On a dumb terminal, previous status messages will remain, and the
-	// entire first line of the string will be printed.
-	StatusLine(str string)
-
-	// StatusAndMessage prints the first line of status to the terminal,
-	// similarly to StatusLine(), then prints the full msg below that. The
-	// status line is retained.
-	//
-	// There is guaranteed to be no other output in between the status and
-	// message.
-	StatusAndMessage(status, msg string)
-
-	// Finish ensures that the output ends with a newline (preserving any
-	// current status line that is current displayed).
-	//
-	// This does nothing on dumb terminals.
-	Finish()
-
-	// Write implements the io.Writer interface. This is primarily so that
-	// the logger can use this interface to print to stderr without
-	// breaking the other semantics of this interface.
-	//
-	// Try to use any of the other functions if possible.
-	Write(p []byte) (n int, err error)
-
-	isSmartTerminal() bool
-}
-
-// NewWriter creates a new Writer based on the stdio and the TERM
-// environment variable.
-func NewWriter(stdio StdioInterface) Writer {
-	w := &writerImpl{
-		stdio: stdio,
-
-		haveBlankLine: true,
-	}
-
-	if term, ok := os.LookupEnv("TERM"); ok && term != "dumb" {
-		w.smartTerminal = isTerminal(stdio.Stdout())
-	}
-	w.stripEscapes = !w.smartTerminal
-
-	return w
-}
-
-type writerImpl struct {
-	stdio StdioInterface
-
-	haveBlankLine bool
-
-	// Protecting the above, we assume that smartTerminal and stripEscapes
-	// does not change after initial setup.
-	lock sync.Mutex
-
-	smartTerminal bool
-	stripEscapes  bool
-}
-
-func (w *writerImpl) isSmartTerminal() bool {
-	return w.smartTerminal
-}
-
-func (w *writerImpl) requestLine() {
-	if !w.haveBlankLine {
-		fmt.Fprintln(w.stdio.Stdout())
-		w.haveBlankLine = true
-	}
-}
-
-func (w *writerImpl) Print(str string) {
-	if w.stripEscapes {
-		str = string(stripAnsiEscapes([]byte(str)))
-	}
-
-	w.lock.Lock()
-	defer w.lock.Unlock()
-	w.print(str)
-}
-
-func (w *writerImpl) print(str string) {
-	if !w.haveBlankLine {
-		fmt.Fprint(w.stdio.Stdout(), "\r", "\x1b[K")
-		w.haveBlankLine = true
-	}
-	fmt.Fprint(w.stdio.Stdout(), str)
-	if len(str) == 0 || str[len(str)-1] != '\n' {
-		fmt.Fprint(w.stdio.Stdout(), "\n")
-	}
-}
-
-func (w *writerImpl) StatusLine(str string) {
-	w.lock.Lock()
-	defer w.lock.Unlock()
-
-	w.statusLine(str)
-}
-
-func (w *writerImpl) statusLine(str string) {
-	if !w.smartTerminal {
-		fmt.Fprintln(w.stdio.Stdout(), str)
-		return
-	}
-
-	idx := strings.IndexRune(str, '\n')
-	if idx != -1 {
-		str = str[0:idx]
-	}
-
-	// Limit line width to the terminal width, otherwise we'll wrap onto
-	// another line and we won't delete the previous line.
-	//
-	// Run this on every line in case the window has been resized while
-	// we're printing. This could be optimized to only re-run when we get
-	// SIGWINCH if it ever becomes too time consuming.
-	if max, ok := termWidth(w.stdio.Stdout()); ok {
-		if len(str) > max {
-			// TODO: Just do a max. Ninja elides the middle, but that's
-			// more complicated and these lines aren't that important.
-			str = str[:max]
-		}
-	}
-
-	// Move to the beginning on the line, print the output, then clear
-	// the rest of the line.
-	fmt.Fprint(w.stdio.Stdout(), "\r", str, "\x1b[K")
-	w.haveBlankLine = false
-}
-
-func (w *writerImpl) StatusAndMessage(status, msg string) {
-	if w.stripEscapes {
-		msg = string(stripAnsiEscapes([]byte(msg)))
-	}
-
-	w.lock.Lock()
-	defer w.lock.Unlock()
-
-	w.statusLine(status)
-	w.requestLine()
-	w.print(msg)
-}
-
-func (w *writerImpl) Finish() {
-	w.lock.Lock()
-	defer w.lock.Unlock()
-
-	w.requestLine()
-}
-
-func (w *writerImpl) Write(p []byte) (n int, err error) {
-	w.Print(string(p))
-	return len(p), nil
-}
-
-// StdioInterface represents a set of stdin/stdout/stderr Reader/Writers
-type StdioInterface interface {
-	Stdin() io.Reader
-	Stdout() io.Writer
-	Stderr() io.Writer
-}
-
-// StdioImpl uses the OS stdin/stdout/stderr to implement StdioInterface
-type StdioImpl struct{}
-
-func (StdioImpl) Stdin() io.Reader  { return os.Stdin }
-func (StdioImpl) Stdout() io.Writer { return os.Stdout }
-func (StdioImpl) Stderr() io.Writer { return os.Stderr }
-
-var _ StdioInterface = StdioImpl{}
-
-type customStdio struct {
-	stdin  io.Reader
-	stdout io.Writer
-	stderr io.Writer
-}
-
-func NewCustomStdio(stdin io.Reader, stdout, stderr io.Writer) StdioInterface {
-	return customStdio{stdin, stdout, stderr}
-}
-
-func (c customStdio) Stdin() io.Reader  { return c.stdin }
-func (c customStdio) Stdout() io.Writer { return c.stdout }
-func (c customStdio) Stderr() io.Writer { return c.stderr }
-
-var _ StdioInterface = customStdio{}
diff --git a/ui/tracer/status.go b/ui/tracer/status.go
index af50e2d..c831255 100644
--- a/ui/tracer/status.go
+++ b/ui/tracer/status.go
@@ -85,3 +85,8 @@
 
 func (s *statusOutput) Flush()                                        {}
 func (s *statusOutput) Message(level status.MsgLevel, message string) {}
+
+func (s *statusOutput) Write(p []byte) (int, error) {
+	// Discard writes
+	return len(p), nil
+}
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index b4f75f7..fba2e4b 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -105,12 +105,6 @@
 	nonDeflatedFiles = make(uniqueSet)
 )
 
-func usage() {
-	fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n")
-	flag.PrintDefaults()
-	os.Exit(2)
-}
-
 func main() {
 	var expandedArgs []string
 	for _, arg := range os.Args {
@@ -128,7 +122,11 @@
 	}
 
 	flags := flag.NewFlagSet("flags", flag.ExitOnError)
-	flags.Usage = usage
+	flags.Usage = func() {
+		fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n")
+		flags.PrintDefaults()
+		os.Exit(2)
+	}
 
 	out := flags.String("o", "", "file to write zip file to")
 	manifest := flags.String("m", "", "input jar manifest file name")
@@ -138,6 +136,7 @@
 	writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
 	ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist")
 	symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them")
+	srcJar := flags.Bool("srcjar", false, "move .java files to locations that match their package statement")
 
 	parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use")
 	cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file")
@@ -193,6 +192,7 @@
 		FileArgs:                 fileArgsBuilder.FileArgs(),
 		OutputFilePath:           *out,
 		EmulateJar:               *emulateJar,
+		SrcJar:                   *srcJar,
 		AddDirectoryEntriesToZip: *directories,
 		CompressionLevel:         *compLevel,
 		ManifestSourcePath:       *manifest,
diff --git a/zip/zip.go b/zip/zip.go
index 1f5fe43..707c4ef 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -210,6 +210,7 @@
 	FileArgs                 []FileArg
 	OutputFilePath           string
 	EmulateJar               bool
+	SrcJar                   bool
 	AddDirectoryEntriesToZip bool
 	CompressionLevel         int
 	ManifestSourcePath       string
@@ -364,7 +365,7 @@
 		}
 	}
 
-	return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.NumParallelJobs)
+	return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SrcJar, args.NumParallelJobs)
 }
 
 func Zip(args ZipArgs) error {
@@ -446,7 +447,9 @@
 	sort.SliceStable(mappings, less)
 }
 
-func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error {
+func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar, srcJar bool,
+	parallelJobs int) error {
+
 	z.errors = make(chan error)
 	defer close(z.errors)
 
@@ -489,7 +492,7 @@
 			if emulateJar && ele.dest == jar.ManifestFile {
 				err = z.addManifest(ele.dest, ele.src, ele.zipMethod)
 			} else {
-				err = z.addFile(ele.dest, ele.src, ele.zipMethod, emulateJar)
+				err = z.addFile(ele.dest, ele.src, ele.zipMethod, emulateJar, srcJar)
 			}
 			if err != nil {
 				z.errors <- err
@@ -588,7 +591,7 @@
 }
 
 // imports (possibly with compression) <src> into the zip at sub-path <dest>
-func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar bool) error {
+func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar, srcJar bool) error {
 	var fileSize int64
 	var executable bool
 
@@ -606,12 +609,9 @@
 			return nil
 		}
 		return err
-	} else if s.IsDir() {
-		if z.directories {
-			return z.writeDirectory(dest, src, emulateJar)
-		}
-		return nil
-	} else {
+	}
+
+	createParentDirs := func(dest, src string) error {
 		if err := z.writeDirectory(filepath.Dir(dest), src, emulateJar); err != nil {
 			return err
 		}
@@ -625,32 +625,64 @@
 
 		z.createdFiles[dest] = src
 
-		if s.Mode()&os.ModeSymlink != 0 {
-			return z.writeSymlink(dest, src)
-		} else if !s.Mode().IsRegular() {
-			return fmt.Errorf("%s is not a file, directory, or symlink", src)
+		return nil
+	}
+
+	if s.IsDir() {
+		if z.directories {
+			return z.writeDirectory(dest, src, emulateJar)
+		}
+		return nil
+	} else if s.Mode()&os.ModeSymlink != 0 {
+		err = createParentDirs(dest, src)
+		if err != nil {
+			return err
+		}
+
+		return z.writeSymlink(dest, src)
+	} else if s.Mode().IsRegular() {
+		r, err := z.fs.Open(src)
+		if err != nil {
+			return err
+		}
+
+		if srcJar && filepath.Ext(src) == ".java" {
+			// rewrite the destination using the package path if it can be determined
+			pkg, err := jar.JavaPackage(r, src)
+			if err != nil {
+				// ignore errors for now, leaving the file at in its original location in the zip
+			} else {
+				dest = filepath.Join(filepath.Join(strings.Split(pkg, ".")...), filepath.Base(src))
+			}
+
+			_, err = r.Seek(0, io.SeekStart)
+			if err != nil {
+				return err
+			}
 		}
 
 		fileSize = s.Size()
 		executable = s.Mode()&0100 != 0
-	}
 
-	r, err := z.fs.Open(src)
-	if err != nil {
-		return err
-	}
+		header := &zip.FileHeader{
+			Name:               dest,
+			Method:             method,
+			UncompressedSize64: uint64(fileSize),
+		}
 
-	header := &zip.FileHeader{
-		Name:               dest,
-		Method:             method,
-		UncompressedSize64: uint64(fileSize),
-	}
+		if executable {
+			header.SetMode(0700)
+		}
 
-	if executable {
-		header.SetMode(0700)
-	}
+		err = createParentDirs(dest, src)
+		if err != nil {
+			return err
+		}
 
-	return z.writeFileContents(header, r)
+		return z.writeFileContents(header, r)
+	} else {
+		return fmt.Errorf("%s is not a file, directory, or symlink", src)
+	}
 }
 
 func (z *ZipWriter) addManifest(dest string, src string, method uint16) error {
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 93c5f3d..84317d1 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -40,14 +40,15 @@
 )
 
 var mockFs = pathtools.MockFs(map[string][]byte{
-	"a/a/a":            fileA,
-	"a/a/b":            fileB,
-	"a/a/c -> ../../c": nil,
-	"a/a/d -> b":       nil,
-	"c":                fileC,
-	"l":                []byte("a/a/a\na/a/b\nc\n"),
-	"l2":               []byte("missing\n"),
-	"manifest.txt":     fileCustomManifest,
+	"a/a/a":               fileA,
+	"a/a/b":               fileB,
+	"a/a/c -> ../../c":    nil,
+	"dangling -> missing": nil,
+	"a/a/d -> b":          nil,
+	"c":                   fileC,
+	"l":                   []byte("a/a/a\na/a/b\nc\n"),
+	"l2":                  []byte("missing\n"),
+	"manifest.txt":        fileCustomManifest,
 })
 
 func fh(name string, contents []byte, method uint16) zip.FileHeader {
@@ -210,6 +211,17 @@
 			},
 		},
 		{
+			name: "dangling symlinks",
+			args: fileArgsBuilder().
+				File("dangling"),
+			compressionLevel: 9,
+			storeSymlinks:    true,
+
+			files: []zip.FileHeader{
+				fhLink("dangling", "missing"),
+			},
+		},
+		{
 			name: "list",
 			args: fileArgsBuilder().
 				List("l"),
@@ -554,3 +566,70 @@
 		})
 	}
 }
+
+func TestSrcJar(t *testing.T) {
+	mockFs := pathtools.MockFs(map[string][]byte{
+		"wrong_package.java":       []byte("package foo;"),
+		"foo/correct_package.java": []byte("package foo;"),
+		"src/no_package.java":      nil,
+		"src2/parse_error.java":    []byte("error"),
+	})
+
+	want := []string{
+		"foo/",
+		"foo/wrong_package.java",
+		"foo/correct_package.java",
+		"no_package.java",
+		"src2/",
+		"src2/parse_error.java",
+	}
+
+	args := ZipArgs{}
+	args.FileArgs = NewFileArgsBuilder().File("**/*.java").FileArgs()
+
+	args.SrcJar = true
+	args.AddDirectoryEntriesToZip = true
+	args.Filesystem = mockFs
+	args.Stderr = &bytes.Buffer{}
+
+	buf := &bytes.Buffer{}
+	err := ZipTo(args, buf)
+	if err != nil {
+		t.Fatalf("got error %v", err)
+	}
+
+	br := bytes.NewReader(buf.Bytes())
+	zr, err := zip.NewReader(br, int64(br.Len()))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var got []string
+	for _, f := range zr.File {
+		r, err := f.Open()
+		if err != nil {
+			t.Fatalf("error when opening %s: %s", f.Name, err)
+		}
+
+		crc := crc32.NewIEEE()
+		len, err := io.Copy(crc, r)
+		r.Close()
+		if err != nil {
+			t.Fatalf("error when reading %s: %s", f.Name, err)
+		}
+
+		if uint64(len) != f.UncompressedSize64 {
+			t.Errorf("incorrect length for %s, want %d got %d", f.Name, f.UncompressedSize64, len)
+		}
+
+		if crc.Sum32() != f.CRC32 {
+			t.Errorf("incorrect crc for %s, want %x got %x", f.Name, f.CRC32, crc)
+		}
+
+		got = append(got, f.Name)
+	}
+
+	if !reflect.DeepEqual(want, got) {
+		t.Errorf("want files %q, got %q", want, got)
+	}
+}