Merge "Ignore 'extern "C++"' section in a version script"
diff --git a/Android.bp b/Android.bp
index b57b0cc..ebf1038 100644
--- a/Android.bp
+++ b/Android.bp
@@ -50,21 +50,26 @@
         "android/makevars.go",
         "android/module.go",
         "android/mutator.go",
+        "android/namespace.go",
         "android/onceper.go",
         "android/package_ctx.go",
         "android/paths.go",
         "android/prebuilt.go",
         "android/proto.go",
         "android/register.go",
+        "android/singleton.go",
         "android/testing.go",
         "android/util.go",
         "android/variable.go",
+        "android/writedocs.go",
 
         // Lock down environment access last
         "android/env.go",
     ],
     testSrcs: [
+        "android/config_test.go",
         "android/expand_test.go",
+        "android/namespace_test.go",
         "android/paths_test.go",
         "android/prebuilt_test.go",
         "android/util_test.go",
@@ -133,6 +138,7 @@
         "cc/tidy.go",
         "cc/util.go",
         "cc/vndk.go",
+        "cc/vndk_prebuilt.go",
 
         "cc/cmakelists.go",
         "cc/compiler.go",
@@ -207,17 +213,21 @@
         "soong-java-config",
     ],
     srcs: [
+        "java/aapt2.go",
         "java/androidmk.go",
         "java/app_builder.go",
         "java/app.go",
         "java/builder.go",
         "java/gen.go",
+        "java/genrule.go",
+        "java/jacoco.go",
         "java/java.go",
         "java/proto.go",
         "java/resources.go",
         "java/system_modules.go",
     ],
     testSrcs: [
+        "java/app_test.go",
         "java/java_test.go",
     ],
     pluginFor: ["soong_build"],
diff --git a/OWNERS b/OWNERS
index 89b446a..004d638 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1,7 @@
 ccross@android.com
 dwillemsen@google.com
+
+per-file * = ccross@android.com
+per-file * = dwillemsen@google.com
+per-file *gen_stub_libs.py = danalbert@google.com
+per-file ndk_*.go = danalbert@google.com
diff --git a/README.md b/README.md
index 3d24e75..4013a2a 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,38 @@
 }
 ```
 
+### Name resolution
+
+Soong provides the ability for modules in different directories to specify
+the same name, as long as each module is declared within a separate namespace.
+A namespace can be declared like this:
+
+```
+soong_namespace {
+    imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
+}
+```
+
+Each Soong module is assigned a namespace based on its location in the tree.
+Each Soong module is considered to be in the namespace defined by the
+soong_namespace found in an Android.bp in the current directory or closest
+ancestor directory, unless no such soong_namespace module is found, in which
+case the module is considered to be in the implicit root namespace.
+
+When Soong attempts to resolve dependency D declared my module M in namespace
+N which imports namespaces I1, I2, I3..., then if D is a fully-qualified name
+of the form "//namespace:module", only the specified namespace will be searched
+for the specified module name. Otherwise, Soong will first look for a module
+named D declared in namespace N. If that module does not exist, Soong will look
+for a module named D in namespaces I1, I2, I3... Lastly, Soong will look in the
+root namespace.
+
+Until we have fully converted from Make to Soong, it will be necessary for the
+Make product config to specify a value of PRODUCT_SOONG_NAMESPACES. Its value
+should be a space-separated list of namespaces that Soong export to Make to be
+built by the `m` command. After we have fully converted from Make to Soong, the
+details of enabling namespaces could potentially change.
+
 ### Formatter
 
 Soong includes a canonical formatter for blueprint files, similar to
diff --git a/android/androidmk.go b/android/androidmk.go
index 19d5ea6..704b560 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -53,30 +53,26 @@
 
 type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
 
-func AndroidMkSingleton() blueprint.Singleton {
+func AndroidMkSingleton() Singleton {
 	return &androidMkSingleton{}
 }
 
 type androidMkSingleton struct{}
 
-func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
-	config := ctx.Config().(Config)
-
-	if !config.EmbeddedInMake() {
+func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
+	if !ctx.Config().EmbeddedInMake() {
 		return
 	}
 
 	var androidMkModulesList []Module
 
-	ctx.VisitAllModules(func(module blueprint.Module) {
-		if amod, ok := module.(Module); ok {
-			androidMkModulesList = append(androidMkModulesList, amod)
-		}
+	ctx.VisitAllModules(func(module Module) {
+		androidMkModulesList = append(androidMkModulesList, module)
 	})
 
 	sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
 
-	transMk := PathForOutput(ctx, "Android"+String(config.ProductVariables.Make_suffix)+".mk")
+	transMk := PathForOutput(ctx, "Android"+String(ctx.Config().ProductVariables.Make_suffix)+".mk")
 	if ctx.Failed() {
 		return
 	}
@@ -86,14 +82,13 @@
 		ctx.Errorf(err.Error())
 	}
 
-	ctx.Build(pctx, blueprint.BuildParams{
-		Rule:     blueprint.Phony,
-		Outputs:  []string{transMk.String()},
-		Optional: true,
+	ctx.Build(pctx, BuildParams{
+		Rule:   blueprint.Phony,
+		Output: transMk,
 	})
 }
 
-func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []Module) error {
+func translateAndroidMk(ctx SingletonContext, mkFile string, mods []Module) error {
 	buf := &bytes.Buffer{}
 
 	fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
@@ -145,7 +140,7 @@
 	return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
 }
 
-func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
+func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
 	provider, ok := mod.(AndroidMkDataProvider)
 	if !ok {
 		return nil
@@ -162,6 +157,12 @@
 		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?
+		return nil
+	}
+
 	data := provider.AndroidMk()
 
 	if data.Include == "" {
@@ -187,8 +188,7 @@
 
 		}
 
-		config := ctx.Config().(Config)
-		if amod.Arch().ArchType != config.Targets[amod.Os().Class][0].Arch.ArchType {
+		if amod.Arch().ArchType != ctx.Config().Targets[amod.Os().Class][0].Arch.ArchType {
 			prefix = "2ND_" + prefix
 		}
 	}
@@ -224,18 +224,21 @@
 			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
 		}
 
-		if len(amod.commonProperties.Logtags) > 0 {
-			fmt.Fprintln(&data.preamble, "LOCAL_LOGTAGS_FILES := ", strings.Join(amod.commonProperties.Logtags, " "))
-		}
 		if len(amod.commonProperties.Init_rc) > 0 {
 			fmt.Fprintln(&data.preamble, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " "))
 		}
 		if Bool(amod.commonProperties.Proprietary) {
 			fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true")
 		}
-		if Bool(amod.commonProperties.Vendor) {
+		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_OEM_MODULE := true")
+		}
 		if amod.commonProperties.Owner != nil {
 			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
 		}
diff --git a/android/api_levels.go b/android/api_levels.go
index 2c4ae1a..a519117 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -16,22 +16,19 @@
 
 import (
 	"encoding/json"
-	"path/filepath"
-
-	"github.com/google/blueprint"
 )
 
 func init() {
 	RegisterSingletonType("api_levels", ApiLevelsSingleton)
 }
 
-func ApiLevelsSingleton() blueprint.Singleton {
+func ApiLevelsSingleton() Singleton {
 	return &apiLevelsSingleton{}
 }
 
 type apiLevelsSingleton struct{}
 
-func createApiLevelsJson(ctx blueprint.SingletonContext, file string,
+func createApiLevelsJson(ctx SingletonContext, file WritablePath,
 	apiLevelsMap map[string]int) {
 
 	jsonStr, err := json.Marshal(apiLevelsMap)
@@ -39,21 +36,21 @@
 		ctx.Errorf(err.Error())
 	}
 
-	ctx.Build(pctx, blueprint.BuildParams{
+	ctx.Build(pctx, BuildParams{
 		Rule:        WriteFile,
-		Description: "generate " + filepath.Base(file),
-		Outputs:     []string{file},
+		Description: "generate " + file.Base(),
+		Output:      file,
 		Args: map[string]string{
 			"content": string(jsonStr[:]),
 		},
 	})
 }
 
-func GetApiLevelsJson(ctx PathContext) Path {
+func GetApiLevelsJson(ctx PathContext) WritablePath {
 	return PathForOutput(ctx, "api_levels.json")
 }
 
-func (a *apiLevelsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
 	baseApiLevel := 9000
 	apiLevelsMap := map[string]int{
 		"G":     9,
@@ -69,10 +66,10 @@
 		"N-MR1": 25,
 		"O":     26,
 	}
-	for i, codename := range ctx.Config().(Config).PlatformVersionCombinedCodenames() {
+	for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() {
 		apiLevelsMap[codename] = baseApiLevel + i
 	}
 
 	apiLevelsJson := GetApiLevelsJson(ctx)
-	createApiLevelsJson(ctx, apiLevelsJson.String(), apiLevelsMap)
+	createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
 }
diff --git a/android/arch.go b/android/arch.go
index 5ea9759..3a22569 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -305,7 +305,7 @@
 	primaryModules := make(map[int]bool)
 
 	for _, class := range osClasses {
-		targets := mctx.AConfig().Targets[class]
+		targets := mctx.Config().Targets[class]
 		if len(targets) == 0 {
 			continue
 		}
@@ -325,7 +325,7 @@
 		var prefer32 bool
 		switch class {
 		case Device:
-			prefer32 = mctx.AConfig().DevicePrefer32BitExecutables()
+			prefer32 = mctx.Config().DevicePrefer32BitExecutables()
 		case HostCross:
 			// Windows builds always prefer 32-bit
 			prefer32 = true
@@ -774,7 +774,7 @@
 		// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
 		// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
 		if os.Class == Device {
-			if ctx.AConfig().Android64() {
+			if ctx.Config().Android64() {
 				field := "Android64"
 				prefix := "target.android64"
 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
@@ -785,13 +785,13 @@
 			}
 
 			if arch.ArchType == X86 && (hasArmAbi(arch) ||
-				hasArmAndroidArch(ctx.AConfig().Targets[Device])) {
+				hasArmAndroidArch(ctx.Config().Targets[Device])) {
 				field := "Arm_on_x86"
 				prefix := "target.arm_on_x86"
 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
 			}
 			if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
-				hasArmAndroidArch(ctx.AConfig().Targets[Device])) {
+				hasArmAndroidArch(ctx.Config().Targets[Device])) {
 				field := "Arm_on_x86_64"
 				prefix := "target.arm_on_x86_64"
 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
@@ -971,7 +971,7 @@
 
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
-		{"arm", "armv5te", "", []string{"armeabi"}},
+		{"arm", "armv7-a", "", []string{"armeabi"}},
 		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
 		{"x86", "", "", []string{"x86"}},
 		{"x86_64", "", "", []string{"x86_64"}},
@@ -1072,19 +1072,30 @@
 	return ret
 }
 
+func preferTargets(targets []Target, filters ...string) []Target {
+	for _, filter := range filters {
+		buildTargets := filterMultilibTargets(targets, filter)
+		if len(buildTargets) > 0 {
+			return buildTargets
+		}
+	}
+	return nil
+}
+
 // Use the module multilib setting to select one or more targets from a target list
 func decodeMultilib(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
 	buildTargets := []Target{}
-	if multilib == "first" {
-		if prefer32 {
-			multilib = "prefer32"
-		} else {
-			multilib = "prefer64"
-		}
-	}
+
 	switch multilib {
 	case "common":
-		buildTargets = append(buildTargets, getCommonTargets(targets)...)
+		buildTargets = getCommonTargets(targets)
+	case "common_first":
+		buildTargets = getCommonTargets(targets)
+		if prefer32 {
+			buildTargets = append(buildTargets, preferTargets(targets, "lib32", "lib64")...)
+		} else {
+			buildTargets = append(buildTargets, preferTargets(targets, "lib64", "lib32")...)
+		}
 	case "both":
 		if prefer32 {
 			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
@@ -1097,16 +1108,14 @@
 		buildTargets = filterMultilibTargets(targets, "lib32")
 	case "64":
 		buildTargets = filterMultilibTargets(targets, "lib64")
+	case "first":
+		if prefer32 {
+			buildTargets = preferTargets(targets, "lib32", "lib64")
+		} else {
+			buildTargets = preferTargets(targets, "lib64", "lib32")
+		}
 	case "prefer32":
-		buildTargets = filterMultilibTargets(targets, "lib32")
-		if len(buildTargets) == 0 {
-			buildTargets = filterMultilibTargets(targets, "lib64")
-		}
-	case "prefer64":
-		buildTargets = filterMultilibTargets(targets, "lib64")
-		if len(buildTargets) == 0 {
-			buildTargets = filterMultilibTargets(targets, "lib32")
-		}
+		buildTargets = preferTargets(targets, "lib32", "lib64")
 	default:
 		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", or "prefer32" found %q`,
 			multilib)
diff --git a/android/config.go b/android/config.go
index 79ff32a..887291d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -25,6 +25,7 @@
 	"strings"
 	"sync"
 
+	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -67,6 +68,7 @@
 	FileConfigurableOptions
 	ProductVariables productVariables
 
+	PrimaryBuilder           string
 	ConfigFileName           string
 	ProductVariablesFileName string
 
@@ -91,6 +93,8 @@
 	useOpenJDK9    bool // Use OpenJDK9, but possibly target 1.8
 	targetOpenJDK9 bool // Use OpenJDK9 and target 1.9
 
+	stopBefore bootstrap.StopBefore
+
 	OncePer
 }
 
@@ -175,7 +179,12 @@
 func TestConfig(buildDir string, env map[string]string) Config {
 	config := &config{
 		ProductVariables: productVariables{
-			DeviceName: stringPtr("test_device"),
+			DeviceName:           stringPtr("test_device"),
+			Platform_sdk_version: intPtr(26),
+			AAPTConfig:           &[]string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+			AAPTPreferredConfig:  stringPtr("xhdpi"),
+			AAPTCharacteristics:  stringPtr("nosdcard"),
+			AAPTPrebuiltDPI:      &[]string{"xhdpi", "xxhdpi"},
 		},
 
 		buildDir:     buildDir,
@@ -307,14 +316,22 @@
 	return nil
 }
 
-func (c *config) RemoveAbandonedFiles() bool {
-	return false
+func (c *config) StopBefore() bootstrap.StopBefore {
+	return c.stopBefore
 }
 
+func (c *config) SetStopBefore(stopBefore bootstrap.StopBefore) {
+	c.stopBefore = stopBefore
+}
+
+var _ bootstrap.ConfigStopBefore = (*config)(nil)
+
 func (c *config) BlueprintToolLocation() string {
 	return filepath.Join(c.buildDir, "host", c.PrebuiltOS(), "bin")
 }
 
+var _ bootstrap.ConfigBlueprintToolLocation = (*config)(nil)
+
 // HostSystemTool looks for non-hermetic tools from the system we're running on.
 // Generally shouldn't be used, but useful to find the XCode SDK, etc.
 func (c *config) HostSystemTool(name string) string {
@@ -417,12 +434,11 @@
 	return true
 }
 
-func (c *config) ResourceOverlays() []SourcePath {
-	return nil
-}
-
-func (c *config) PlatformVersion() string {
-	return "M"
+func (c *config) ResourceOverlays() []string {
+	if c.ProductVariables.ResourceOverlays == nil {
+		return nil
+	}
+	return *c.ProductVariables.ResourceOverlays
 }
 
 func (c *config) PlatformSdkVersionInt() int {
@@ -445,6 +461,10 @@
 	}
 }
 
+func (c *config) AppsDefaultVersionName() string {
+	return String(c.ProductVariables.AppsDefaultVersionName)
+}
+
 // Codenames that are active in the current lunch target.
 func (c *config) PlatformVersionActiveCodenames() []string {
 	return c.ProductVariables.Platform_version_active_codenames
@@ -466,32 +486,39 @@
 	return combined
 }
 
-func (c *config) BuildNumber() string {
-	return "000000"
-}
-
 func (c *config) ProductAAPTConfig() []string {
-	return *c.ProductVariables.AAPTConfig
+	return stringSlice(c.ProductVariables.AAPTConfig)
 }
 
 func (c *config) ProductAAPTPreferredConfig() string {
-	return *c.ProductVariables.AAPTPreferredConfig
+	return String(c.ProductVariables.AAPTPreferredConfig)
 }
 
 func (c *config) ProductAAPTCharacteristics() string {
-	return *c.ProductVariables.AAPTCharacteristics
+	return String(c.ProductVariables.AAPTCharacteristics)
 }
 
 func (c *config) ProductAAPTPrebuiltDPI() []string {
-	return *c.ProductVariables.AAPTPrebuiltDPI
+	return stringSlice(c.ProductVariables.AAPTPrebuiltDPI)
 }
 
 func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
-	return PathForSource(ctx, "build/target/product/security")
+	defaultCert := String(c.ProductVariables.DefaultAppCertificate)
+	if defaultCert != "" {
+		return PathForSource(ctx, filepath.Dir(defaultCert))
+	} else {
+		return PathForSource(ctx, "build/target/product/security")
+	}
 }
 
-func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
-	return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
+func (c *config) DefaultAppCertificate(ctx PathContext) (pem, key SourcePath) {
+	defaultCert := String(c.ProductVariables.DefaultAppCertificate)
+	if defaultCert != "" {
+		return PathForSource(ctx, defaultCert+".x509.pem"), PathForSource(ctx, defaultCert+".pk8")
+	} else {
+		defaultDir := c.DefaultAppCertificateDir(ctx)
+		return defaultDir.Join(ctx, "testkey.x509.pem"), defaultDir.Join(ctx, "testkey.pk8")
+	}
 }
 
 func (c *config) AllowMissingDependencies() bool {
@@ -557,6 +584,10 @@
 	return false
 }
 
+func (c *config) UseD8Desugar() bool {
+	return c.IsEnvTrue("USE_D8_DESUGAR")
+}
+
 func (c *config) UseGoma() bool {
 	return Bool(c.ProductVariables.UseGoma)
 }
@@ -618,11 +649,30 @@
 	return "vendor"
 }
 
-func (c *deviceConfig) CompileVndk() bool {
-	if c.config.ProductVariables.DeviceVndkVersion == nil {
-		return false
+func (c *deviceConfig) VndkVersion() string {
+	return String(c.config.ProductVariables.DeviceVndkVersion)
+}
+
+func (c *deviceConfig) PlatformVndkVersion() string {
+	return String(c.config.ProductVariables.Platform_vndk_version)
+}
+
+func (c *deviceConfig) ExtraVndkVersions() []string {
+	return c.config.ProductVariables.ExtraVndkVersions
+}
+
+func (c *deviceConfig) OdmPath() string {
+	if c.config.ProductVariables.OdmPath != nil {
+		return *c.config.ProductVariables.OdmPath
 	}
-	return *c.config.ProductVariables.DeviceVndkVersion == "current"
+	return "odm"
+}
+
+func (c *deviceConfig) OemPath() string {
+	if c.config.ProductVariables.OemPath != nil {
+		return *c.config.ProductVariables.OemPath
+	}
+	return "oem"
 }
 
 func (c *deviceConfig) BtConfigIncludeDir() string {
@@ -672,3 +722,11 @@
 	}
 	return prefixInList(path, *c.ProductVariables.CFIIncludePaths)
 }
+
+func stringSlice(s *[]string) []string {
+	if s != nil {
+		return *s
+	} else {
+		return nil
+	}
+}
diff --git a/android/config_test.go b/android/config_test.go
new file mode 100644
index 0000000..5eb6ed5
--- /dev/null
+++ b/android/config_test.go
@@ -0,0 +1,86 @@
+// 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 android
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func validateConfigAnnotations(configurable jsonConfigurable) (err error) {
+	reflectType := reflect.TypeOf(configurable)
+	reflectType = reflectType.Elem()
+	for i := 0; i < reflectType.NumField(); i++ {
+		field := reflectType.Field(i)
+		jsonTag := field.Tag.Get("json")
+		// Check for mistakes in the json tag
+		if jsonTag != "" && !strings.HasPrefix(jsonTag, ",") {
+			if !strings.Contains(jsonTag, ",") {
+				// Probably an accidental rename, most likely "omitempty" instead of ",omitempty"
+				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
+					"Did you mean to use an annotation of %q?\n"+
+					"(Alternatively, to change the json name of the field, rename the field in source instead.)",
+					reflectType.Name(), field.Name, field.Tag, jsonTag, ","+jsonTag)
+			} else {
+				// Although this rename was probably intentional,
+				// a json annotation is still more confusing than renaming the source variable
+				requestedName := strings.Split(jsonTag, ",")[0]
+				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
+					"To change the json name of the field, rename the field in source instead.",
+					reflectType.Name(), field.Name, field.Tag, requestedName)
+
+			}
+		}
+	}
+	return nil
+}
+
+type configType struct {
+	populateMe *bool `json:"omitempty"`
+}
+
+func (c *configType) SetDefaultConfig() {
+}
+
+// tests that ValidateConfigAnnotation works
+func TestValidateConfigAnnotations(t *testing.T) {
+	config := configType{}
+	err := validateConfigAnnotations(&config)
+	expectedError := `Field configType.populateMe has tag json:"omitempty" which specifies to change its json field name to "omitempty".
+Did you mean to use an annotation of ",omitempty"?
+(Alternatively, to change the json name of the field, rename the field in source instead.)`
+	if err.Error() != expectedError {
+		t.Errorf("Incorrect error; expected:\n"+
+			"%s\n"+
+			"got:\n"+
+			"%s",
+			expectedError, err.Error())
+	}
+}
+
+// run validateConfigAnnotations against each type that might have json annotations
+func TestProductConfigAnnotations(t *testing.T) {
+	err := validateConfigAnnotations(&productVariables{})
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	validateConfigAnnotations(&FileConfigurableOptions{})
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+}
diff --git a/android/env.go b/android/env.go
index ec5794e..469dfff 100644
--- a/android/env.go
+++ b/android/env.go
@@ -19,8 +19,6 @@
 	"strings"
 
 	"android/soong/env"
-
-	"github.com/google/blueprint"
 )
 
 // This file supports dependencies on environment variables.  During build manifest generation,
@@ -43,14 +41,14 @@
 	os.Clearenv()
 }
 
-func EnvSingleton() blueprint.Singleton {
+func EnvSingleton() Singleton {
 	return &envSingleton{}
 }
 
 type envSingleton struct{}
 
-func (c *envSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
-	envDeps := ctx.Config().(Config).EnvDeps()
+func (c *envSingleton) GenerateBuildActions(ctx SingletonContext) {
+	envDeps := ctx.Config().EnvDeps()
 
 	envFile := PathForOutput(ctx, ".soong.environment")
 	if ctx.Failed() {
diff --git a/android/hooks.go b/android/hooks.go
index a9bfd33..57560d2 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -26,7 +26,7 @@
 // before the module has been split into architecture variants, and before defaults modules have
 // been applied.
 type LoadHookContext interface {
-	// TODO: a new context that includes AConfig() but not Target(), etc.?
+	// TODO: a new context that includes Config() but not Target(), etc.?
 	BaseContext
 	AppendProperties(...interface{})
 	PrependProperties(...interface{})
diff --git a/android/makevars.go b/android/makevars.go
index 024e015..00a20f5 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -21,7 +21,6 @@
 	"os"
 	"strconv"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -66,7 +65,7 @@
 
 type MakeVarsProvider func(ctx MakeVarsContext)
 
-func RegisterMakeVarsProvider(pctx blueprint.PackageContext, provider MakeVarsProvider) {
+func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
 	makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
 }
 
@@ -76,14 +75,14 @@
 	RegisterSingletonType("makevars", makeVarsSingletonFunc)
 }
 
-func makeVarsSingletonFunc() blueprint.Singleton {
+func makeVarsSingletonFunc() Singleton {
 	return &makeVarsSingleton{}
 }
 
 type makeVarsSingleton struct{}
 
 type makeVarsProvider struct {
-	pctx blueprint.PackageContext
+	pctx PackageContext
 	call MakeVarsProvider
 }
 
@@ -91,8 +90,8 @@
 
 type makeVarsContext struct {
 	config Config
-	ctx    blueprint.SingletonContext
-	pctx   blueprint.PackageContext
+	ctx    SingletonContext
+	pctx   PackageContext
 	vars   []makeVarsVariable
 }
 
@@ -105,14 +104,12 @@
 	strict bool
 }
 
-func (s *makeVarsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
-	config := ctx.Config().(Config)
-
-	if !config.EmbeddedInMake() {
+func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
+	if !ctx.Config().EmbeddedInMake() {
 		return
 	}
 
-	outFile := PathForOutput(ctx, "make_vars"+proptools.String(config.ProductVariables.Make_suffix)+".mk").String()
+	outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().ProductVariables.Make_suffix)+".mk").String()
 
 	if ctx.Failed() {
 		return
@@ -121,7 +118,7 @@
 	vars := []makeVarsVariable{}
 	for _, provider := range makeVarsProviders {
 		mctx := &makeVarsContext{
-			config: config,
+			config: ctx.Config(),
 			ctx:    ctx,
 			pctx:   provider.pctx,
 		}
diff --git a/android/module.go b/android/module.go
index 66859fa..cb068ab 100644
--- a/android/module.go
+++ b/android/module.go
@@ -17,7 +17,9 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
+	"text/scanner"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
@@ -63,24 +65,51 @@
 	Windows() bool
 	Debug() bool
 	PrimaryArch() bool
-	InstallOnVendorPartition() bool
+	Platform() bool
+	DeviceSpecific() bool
+	SocSpecific() bool
+	ProductSpecific() bool
 	AConfig() Config
 	DeviceConfig() DeviceConfig
 }
 
 type BaseContext interface {
-	blueprint.BaseModuleContext
+	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
+	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
-	blueprint.BaseModuleContext
+	BaseModuleContext
 
 	// Deprecated: use ModuleContext.Build instead.
-	ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams)
+	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
 
 	ExpandSources(srcFiles, excludes []string) Paths
+	ExpandSource(srcFile, prop string) Path
 	ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths
 	Glob(globPattern string, excludes []string) Paths
 
@@ -115,17 +144,18 @@
 	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
 	WalkDeps(visit func(Module, Module) bool)
 
-	Variable(pctx blueprint.PackageContext, name, value string)
-	Rule(pctx blueprint.PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
+	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,
 	// and performs more verification.
-	Build(pctx blueprint.PackageContext, params BuildParams)
+	Build(pctx PackageContext, params BuildParams)
 
-	PrimaryModule() blueprint.Module
-	FinalModule() blueprint.Module
-	VisitAllModuleVariants(visit func(blueprint.Module))
+	PrimaryModule() Module
+	FinalModule() Module
+	VisitAllModuleVariants(visit func(Module))
 
 	GetMissingDependencies() []string
+	Namespace() blueprint.Namespace
 }
 
 type Module interface {
@@ -185,12 +215,25 @@
 	// vendor who owns this module
 	Owner *string
 
-	// whether this module is device specific and should be installed into /vendor
+	// whether this module is specific to an SoC (System-On-a-Chip). When set to true,
+	// it is installed into /vendor (or /system/vendor if vendor partition does not exist).
+	// Use `soc_specific` instead for better meaning.
 	Vendor *bool
 
-	// *.logtags files, to combine together in order to generate the /system/etc/event-log-tags
-	// file
-	Logtags []string
+	// whether this module is specific to an SoC (System-On-a-Chip). When set to true,
+	// it is installed into /vendor (or /system/vendor if vendor partition does not exist).
+	Soc_specific *bool
+
+	// whether this module is specific to a device, not only for SoC, but also for off-chip
+	// peripherals. When set to true, it is installed into /odm (or /vendor/odm if odm partition
+	// does not exist, or /system/vendor/odm if both odm and vendor partitions do not exist).
+	// This implies `soc_specific:true`.
+	Device_specific *bool
+
+	// whether this module is specific to a software configuration of a product (e.g. country,
+	// network operator, etc). When set to true, it is installed into /oem (or /system/oem if
+	// oem partition does not exist).
+	Product_specific *bool
 
 	// init.rc files to be installed if this module is installed
 	Init_rc []string
@@ -210,6 +253,8 @@
 	ArchSpecific          bool                  `blueprint:"mutated"`
 
 	SkipInstall bool `blueprint:"mutated"`
+
+	NamespaceExportedToMake bool `blueprint:"mutated"`
 }
 
 type hostAndDeviceProperties struct {
@@ -220,10 +265,11 @@
 type Multilib string
 
 const (
-	MultilibBoth    Multilib = "both"
-	MultilibFirst   Multilib = "first"
-	MultilibCommon  Multilib = "common"
-	MultilibDefault Multilib = ""
+	MultilibBoth        Multilib = "both"
+	MultilibFirst       Multilib = "first"
+	MultilibCommon      Multilib = "common"
+	MultilibCommonFirst Multilib = "common_first"
+	MultilibDefault     Multilib = ""
 )
 
 type HostOrDeviceSupported int
@@ -238,6 +284,30 @@
 	NeitherHostNorDeviceSupported
 )
 
+type moduleKind int
+
+const (
+	platformModule moduleKind = iota
+	deviceSpecificModule
+	socSpecificModule
+	productSpecificModule
+)
+
+func (k moduleKind) String() string {
+	switch k {
+	case platformModule:
+		return "platform"
+	case deviceSpecificModule:
+		return "device-specific"
+	case socSpecificModule:
+		return "soc-specific"
+	case productSpecificModule:
+		return "product-specific"
+	default:
+		panic(fmt.Errorf("unknown module kind %d", k))
+	}
+}
+
 func InitAndroidModule(m Module) {
 	base := m.base()
 	base.module = m
@@ -325,8 +395,8 @@
 
 	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
 	// Only set on the final variant of each module
-	installTarget    string
-	checkbuildTarget string
+	installTarget    WritablePath
+	checkbuildTarget WritablePath
 	blueprintDir     string
 
 	hooks hooks
@@ -464,36 +534,40 @@
 	return false
 }
 
-func (a *ModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
+func (a *ModuleBase) generateModuleTarget(ctx ModuleContext) {
 	allInstalledFiles := Paths{}
 	allCheckbuildFiles := Paths{}
-	ctx.VisitAllModuleVariants(func(module blueprint.Module) {
-		a := module.(Module).base()
+	ctx.VisitAllModuleVariants(func(module Module) {
+		a := module.base()
 		allInstalledFiles = append(allInstalledFiles, a.installFiles...)
 		allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...)
 	})
 
-	deps := []string{}
+	var deps Paths
+
+	namespacePrefix := ctx.Namespace().(*Namespace).id
+	if namespacePrefix != "" {
+		namespacePrefix = namespacePrefix + "-"
+	}
 
 	if len(allInstalledFiles) > 0 {
-		name := ctx.ModuleName() + "-install"
-		ctx.Build(pctx, blueprint.BuildParams{
+		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-install")
+		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{name},
-			Implicits: allInstalledFiles.Strings(),
-			Optional:  ctx.Config().(Config).EmbeddedInMake(),
+			Output:    name,
+			Implicits: allInstalledFiles,
+			Default:   !ctx.Config().EmbeddedInMake(),
 		})
 		deps = append(deps, name)
 		a.installTarget = name
 	}
 
 	if len(allCheckbuildFiles) > 0 {
-		name := ctx.ModuleName() + "-checkbuild"
-		ctx.Build(pctx, blueprint.BuildParams{
+		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-checkbuild")
+		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{name},
-			Implicits: allCheckbuildFiles.Strings(),
-			Optional:  true,
+			Output:    name,
+			Implicits: allCheckbuildFiles,
 		})
 		deps = append(deps, name)
 		a.checkbuildTarget = name
@@ -501,47 +575,84 @@
 
 	if len(deps) > 0 {
 		suffix := ""
-		if ctx.Config().(Config).EmbeddedInMake() {
+		if ctx.Config().EmbeddedInMake() {
 			suffix = "-soong"
 		}
 
-		ctx.Build(pctx, blueprint.BuildParams{
+		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+suffix)
+		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{ctx.ModuleName() + suffix},
+			Outputs:   []WritablePath{name},
 			Implicits: deps,
-			Optional:  true,
 		})
 
 		a.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)
+
+	if ((socSpecific || deviceSpecific) && productSpecific) || (socSpecific && deviceSpecific) {
+		msg := "conflicting value set here"
+		if productSpecific {
+			ctx.PropertyErrorf("product_specific", "a module cannot be specific to SoC or device and product at the same time.")
+			if deviceSpecific {
+				ctx.PropertyErrorf("device_specific", msg)
+			}
+		} else {
+			ctx.PropertyErrorf("device_specific", "a module cannot be specific to SoC and device at the same time.")
+		}
+		if Bool(a.commonProperties.Vendor) {
+			ctx.PropertyErrorf("vendor", msg)
+		}
+		if Bool(a.commonProperties.Proprietary) {
+			ctx.PropertyErrorf("proprietary", msg)
+		}
+		if Bool(a.commonProperties.Soc_specific) {
+			ctx.PropertyErrorf("soc_specific", msg)
+		}
+	}
+
+	if productSpecific {
+		return productSpecificModule
+	} else if deviceSpecific {
+		return deviceSpecificModule
+	} else if socSpecific {
+		return socSpecificModule
+	} else {
+		return platformModule
+	}
+}
+
 func (a *ModuleBase) androidBaseContextFactory(ctx blueprint.BaseModuleContext) androidBaseContextImpl {
 	return androidBaseContextImpl{
 		target:        a.commonProperties.CompileTarget,
 		targetPrimary: a.commonProperties.CompilePrimary,
-		vendor:        Bool(a.commonProperties.Proprietary) || Bool(a.commonProperties.Vendor),
+		kind:          determineModuleKind(a, ctx),
 		config:        ctx.Config().(Config),
 	}
 }
 
-func (a *ModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
-	androidCtx := &androidModuleContext{
+func (a *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
+	ctx := &androidModuleContext{
 		module:                 a.module,
-		ModuleContext:          ctx,
-		androidBaseContextImpl: a.androidBaseContextFactory(ctx),
-		installDeps:            a.computeInstallDeps(ctx),
+		ModuleContext:          blueprintCtx,
+		androidBaseContextImpl: a.androidBaseContextFactory(blueprintCtx),
+		installDeps:            a.computeInstallDeps(blueprintCtx),
 		installFiles:           a.installFiles,
-		missingDeps:            ctx.GetMissingDependencies(),
+		missingDeps:            blueprintCtx.GetMissingDependencies(),
 	}
 
 	desc := "//" + ctx.ModuleDir() + ":" + ctx.ModuleName() + " "
 	var suffix []string
-	if androidCtx.Os().Class != Device && androidCtx.Os().Class != Generic {
-		suffix = append(suffix, androidCtx.Os().String())
+	if ctx.Os().Class != Device && ctx.Os().Class != Generic {
+		suffix = append(suffix, ctx.Os().String())
 	}
-	if !androidCtx.PrimaryArch() {
-		suffix = append(suffix, androidCtx.Arch().ArchType.String())
+	if !ctx.PrimaryArch() {
+		suffix = append(suffix, ctx.Arch().ArchType.String())
 	}
 
 	ctx.Variable(pctx, "moduleDesc", desc)
@@ -553,13 +664,13 @@
 	ctx.Variable(pctx, "moduleDescSuffix", s)
 
 	if a.Enabled() {
-		a.module.GenerateAndroidBuildActions(androidCtx)
+		a.module.GenerateAndroidBuildActions(ctx)
 		if ctx.Failed() {
 			return
 		}
 
-		a.installFiles = append(a.installFiles, androidCtx.installFiles...)
-		a.checkbuildFiles = append(a.checkbuildFiles, androidCtx.checkbuildFiles...)
+		a.installFiles = append(a.installFiles, ctx.installFiles...)
+		a.checkbuildFiles = append(a.checkbuildFiles, ctx.checkbuildFiles...)
 	}
 
 	if a == ctx.FinalModule().(Module).base() {
@@ -569,14 +680,14 @@
 		}
 	}
 
-	a.buildParams = androidCtx.buildParams
+	a.buildParams = ctx.buildParams
 }
 
 type androidBaseContextImpl struct {
 	target        Target
 	targetPrimary bool
 	debug         bool
-	vendor        bool
+	kind          moduleKind
 	config        Config
 }
 
@@ -594,7 +705,7 @@
 }
 
 func (a *androidModuleContext) ninjaError(desc string, outputs []string, err error) {
-	a.ModuleContext.Build(pctx, blueprint.BuildParams{
+	a.ModuleContext.Build(pctx.PackageContext, blueprint.BuildParams{
 		Rule:        ErrorRule,
 		Description: desc,
 		Outputs:     outputs,
@@ -606,17 +717,18 @@
 	return
 }
 
-func (a *androidModuleContext) ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) {
+func (a *androidModuleContext) Config() Config {
+	return a.ModuleContext.Config().(Config)
+}
+
+func (a *androidModuleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
 	a.Build(pctx, BuildParams(params))
 }
 
-func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params BuildParams) {
-	if a.config.captureBuild {
-		a.buildParams = append(a.buildParams, params)
-	}
-
+func convertBuildParams(params BuildParams) blueprint.BuildParams {
 	bparams := blueprint.BuildParams{
 		Rule:            params.Rule,
+		Description:     params.Description,
 		Deps:            params.Deps,
 		Outputs:         params.Outputs.Strings(),
 		ImplicitOutputs: params.ImplicitOutputs.Strings(),
@@ -627,10 +739,6 @@
 		Optional:        !params.Default,
 	}
 
-	if params.Description != "" {
-		bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
-	}
-
 	if params.Depfile != nil {
 		bparams.Depfile = params.Depfile.String()
 	}
@@ -647,6 +755,30 @@
 		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
 	}
 
+	return bparams
+}
+
+func (a *androidModuleContext) Variable(pctx PackageContext, name, value string) {
+	a.ModuleContext.Variable(pctx.PackageContext, name, value)
+}
+
+func (a *androidModuleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
+	argNames ...string) blueprint.Rule {
+
+	return a.ModuleContext.Rule(pctx.PackageContext, name, params, argNames...)
+}
+
+func (a *androidModuleContext) Build(pctx PackageContext, params BuildParams) {
+	if a.config.captureBuild {
+		a.buildParams = append(a.buildParams, params)
+	}
+
+	bparams := convertBuildParams(params)
+
+	if bparams.Description != "" {
+		bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
+	}
+
 	if a.missingDeps != nil {
 		a.ninjaError(bparams.Description, bparams.Outputs,
 			fmt.Errorf("module %s missing dependencies: %s\n",
@@ -654,7 +786,7 @@
 		return
 	}
 
-	a.ModuleContext.Build(pctx, bparams)
+	a.ModuleContext.Build(pctx.PackageContext, bparams)
 }
 
 func (a *androidModuleContext) GetMissingDependencies() []string {
@@ -676,7 +808,7 @@
 	}
 
 	if !aModule.Enabled() {
-		if a.AConfig().AllowMissingDependencies() {
+		if a.Config().AllowMissingDependencies() {
 			a.AddMissingDependencies([]string{a.OtherModuleName(aModule)})
 		} else {
 			a.ModuleErrorf("depends on disabled module %q", a.OtherModuleName(aModule))
@@ -751,6 +883,20 @@
 	})
 }
 
+func (a *androidModuleContext) VisitAllModuleVariants(visit func(Module)) {
+	a.ModuleContext.VisitAllModuleVariants(func(module blueprint.Module) {
+		visit(module.(Module))
+	})
+}
+
+func (a *androidModuleContext) PrimaryModule() Module {
+	return a.ModuleContext.PrimaryModule().(Module)
+}
+
+func (a *androidModuleContext) FinalModule() Module {
+	return a.ModuleContext.FinalModule().(Module)
+}
+
 func (a *androidBaseContextImpl) Target() Target {
 	return a.target
 }
@@ -802,8 +948,20 @@
 	return DeviceConfig{a.config.deviceConfig}
 }
 
-func (a *androidBaseContextImpl) InstallOnVendorPartition() bool {
-	return a.vendor
+func (a *androidBaseContextImpl) Platform() bool {
+	return a.kind == platformModule
+}
+
+func (a *androidBaseContextImpl) DeviceSpecific() bool {
+	return a.kind == deviceSpecificModule
+}
+
+func (a *androidBaseContextImpl) SocSpecific() bool {
+	return a.kind == socSpecificModule
+}
+
+func (a *androidBaseContextImpl) ProductSpecific() bool {
+	return a.kind == productSpecificModule
 }
 
 func (a *androidModuleContext) InstallInData() bool {
@@ -820,11 +978,11 @@
 	}
 
 	if a.Device() {
-		if a.AConfig().SkipDeviceInstall() {
+		if a.Config().SkipDeviceInstall() {
 			return true
 		}
 
-		if a.AConfig().SkipMegaDeviceInstall(fullInstallPath.String()) {
+		if a.Config().SkipMegaDeviceInstall(fullInstallPath.String()) {
 			return true
 		}
 	}
@@ -869,7 +1027,7 @@
 			Input:       srcPath,
 			Implicits:   implicitDeps,
 			OrderOnly:   orderOnlyDeps,
-			Default:     !a.AConfig().EmbeddedInMake(),
+			Default:     !a.Config().EmbeddedInMake(),
 		})
 
 		a.installFiles = append(a.installFiles, fullInstallPath)
@@ -889,7 +1047,7 @@
 			Description: "install symlink " + fullInstallPath.Base(),
 			Output:      fullInstallPath,
 			OrderOnly:   Paths{srcPath},
-			Default:     !a.AConfig().EmbeddedInMake(),
+			Default:     !a.Config().EmbeddedInMake(),
 			Args: map[string]string{
 				"fromPath": srcPath.String(),
 			},
@@ -941,8 +1099,8 @@
 
 var SourceDepTag sourceDependencyTag
 
-// Returns a list of modules that must be depended on to satisfy filegroup or generated sources
-// modules listed in srcFiles using ":module" syntax
+// Adds necessary dependencies to satisfy filegroup or generated sources modules listed in srcFiles
+// using ":module" syntax, if any.
 func ExtractSourcesDeps(ctx BottomUpMutatorContext, srcFiles []string) {
 	var deps []string
 	set := make(map[string]bool)
@@ -961,6 +1119,16 @@
 	ctx.AddDependency(ctx.Module(), SourceDepTag, deps...)
 }
 
+// Adds necessary dependencies to satisfy filegroup or generated sources modules specified in s
+// using ":module" syntax, if any.
+func ExtractSourceDeps(ctx BottomUpMutatorContext, s *string) {
+	if s != nil {
+		if m := SrcIsModule(*s); m != "" {
+			ctx.AddDependency(ctx.Module(), SourceDepTag, m)
+		}
+	}
+}
+
 type SourceFileProducer interface {
 	Srcs() Paths
 }
@@ -971,6 +1139,18 @@
 	return ctx.ExpandSourcesSubDir(srcFiles, excludes, "")
 }
 
+// Returns a single path expanded from globs and modules referenced using ":module" syntax.
+// ExtractSourceDeps must have already been called during the dependency resolution phase.
+func (ctx *androidModuleContext) ExpandSource(srcFile, prop string) Path {
+	srcFiles := ctx.ExpandSourcesSubDir([]string{srcFile}, nil, "")
+	if len(srcFiles) == 1 {
+		return srcFiles[0]
+	} else {
+		ctx.PropertyErrorf(prop, "module providing %s must produce exactly one file", prop)
+		return nil
+	}
+}
+
 func (ctx *androidModuleContext) ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths {
 	prefix := PathForModuleSrc(ctx).String()
 
@@ -1027,7 +1207,7 @@
 	RegisterSingletonType("buildtarget", BuildTargetSingleton)
 }
 
-func BuildTargetSingleton() blueprint.Singleton {
+func BuildTargetSingleton() Singleton {
 	return &buildTargetSingleton{}
 }
 
@@ -1038,50 +1218,57 @@
 
 type buildTargetSingleton struct{}
 
-func (c *buildTargetSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
-	checkbuildDeps := []string{}
+func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
+	var checkbuildDeps Paths
 
-	mmTarget := func(dir string) string {
-		return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1)
+	mmTarget := func(dir string) WritablePath {
+		return PathForPhony(ctx,
+			"MODULES-IN-"+strings.Replace(filepath.Clean(dir), "/", "-", -1))
 	}
 
-	modulesInDir := make(map[string][]string)
+	modulesInDir := make(map[string]Paths)
 
-	ctx.VisitAllModules(func(module blueprint.Module) {
-		if a, ok := module.(Module); ok {
-			blueprintDir := a.base().blueprintDir
-			installTarget := a.base().installTarget
-			checkbuildTarget := a.base().checkbuildTarget
+	ctx.VisitAllModules(func(module Module) {
+		blueprintDir := module.base().blueprintDir
+		installTarget := module.base().installTarget
+		checkbuildTarget := module.base().checkbuildTarget
 
-			if checkbuildTarget != "" {
-				checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
-				modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], checkbuildTarget)
-			}
+		if checkbuildTarget != nil {
+			checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
+			modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], checkbuildTarget)
+		}
 
-			if installTarget != "" {
-				modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget)
-			}
+		if installTarget != nil {
+			modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget)
 		}
 	})
 
 	suffix := ""
-	if ctx.Config().(Config).EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		suffix = "-soong"
 	}
 
 	// Create a top-level checkbuild target that depends on all modules
-	ctx.Build(pctx, blueprint.BuildParams{
+	ctx.Build(pctx, BuildParams{
 		Rule:      blueprint.Phony,
-		Outputs:   []string{"checkbuild" + suffix},
+		Output:    PathForPhony(ctx, "checkbuild"+suffix),
 		Implicits: checkbuildDeps,
-		Optional:  true,
 	})
 
 	// Make will generate the MODULES-IN-* targets
-	if ctx.Config().(Config).EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		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)
 	for _, dir := range dirs {
@@ -1108,28 +1295,26 @@
 	// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp
 	// files.
 	for _, dir := range dirs {
-		ctx.Build(pctx, blueprint.BuildParams{
+		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{mmTarget(dir)},
+			Output:    mmTarget(dir),
 			Implicits: modulesInDir[dir],
 			// HACK: checkbuild should be an optional build, but force it
 			// enabled for now in standalone builds
-			Optional: ctx.Config().(Config).EmbeddedInMake(),
+			Default: !ctx.Config().EmbeddedInMake(),
 		})
 	}
 
 	// Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild.
 	osDeps := map[OsType]Paths{}
-	ctx.VisitAllModules(func(module blueprint.Module) {
-		if a, ok := module.(Module); ok {
-			if a.Enabled() {
-				os := a.Target().Os
-				osDeps[os] = append(osDeps[os], a.base().checkbuildFiles...)
-			}
+	ctx.VisitAllModules(func(module Module) {
+		if module.Enabled() {
+			os := module.Target().Os
+			osDeps[os] = append(osDeps[os], module.base().checkbuildFiles...)
 		}
 	})
 
-	osClass := make(map[string][]string)
+	osClass := make(map[string]Paths)
 	for os, deps := range osDeps {
 		var className string
 
@@ -1144,25 +1329,23 @@
 			continue
 		}
 
-		name := className + "-" + os.Name
+		name := PathForPhony(ctx, className+"-"+os.Name)
 		osClass[className] = append(osClass[className], name)
 
-		ctx.Build(pctx, blueprint.BuildParams{
+		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{name},
-			Implicits: deps.Strings(),
-			Optional:  true,
+			Output:    name,
+			Implicits: deps,
 		})
 	}
 
 	// Wrap those into host|host-cross|target phony rules
 	osClasses := sortedKeys(osClass)
 	for _, class := range osClasses {
-		ctx.Build(pctx, blueprint.BuildParams{
+		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{class},
+			Output:    PathForPhony(ctx, class),
 			Implicits: osClass[class],
-			Optional:  true,
 		})
 	}
 }
diff --git a/android/mutator.go b/android/mutator.go
index cc3f1f3..876d161 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -86,6 +86,7 @@
 }
 
 var preDeps = []RegisterMutatorFunc{
+	RegisterNamespaceMutator,
 	registerArchMutator,
 }
 
@@ -108,7 +109,7 @@
 type AndroidTopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
-	blueprint.BaseModuleContext
+	BaseModuleContext
 	androidBaseContext
 
 	OtherModuleExists(name string) bool
@@ -139,8 +140,22 @@
 type AndroidBottomUpMutator func(BottomUpMutatorContext)
 
 type BottomUpMutatorContext interface {
-	blueprint.BottomUpMutatorContext
+	BaseModuleContext
 	androidBaseContext
+
+	OtherModuleExists(name string) bool
+	Rename(name string)
+	Module() blueprint.Module
+
+	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
+	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
+	CreateVariations(...string) []blueprint.Module
+	CreateLocalVariations(...string) []blueprint.Module
+	SetDependencyVariation(string)
+	AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+	AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+	AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
+	ReplaceDependencies(string)
 }
 
 type androidBottomUpMutatorContext struct {
@@ -193,6 +208,14 @@
 	}
 }
 
+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
diff --git a/android/namespace.go b/android/namespace.go
new file mode 100644
index 0000000..1f8ef5a
--- /dev/null
+++ b/android/namespace.go
@@ -0,0 +1,423 @@
+// 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 android
+
+import (
+	"errors"
+	"fmt"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/google/blueprint"
+)
+
+// This file implements namespaces
+const (
+	namespacePrefix = "//"
+	modulePrefix    = ":"
+)
+
+func init() {
+	RegisterModuleType("soong_namespace", NamespaceFactory)
+}
+
+// threadsafe sorted list
+type sortedNamespaces struct {
+	lock   sync.Mutex
+	items  []*Namespace
+	sorted bool
+}
+
+func (s *sortedNamespaces) add(namespace *Namespace) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+	if s.sorted {
+		panic("It is not supported to call sortedNamespaces.add() after sortedNamespaces.sortedItems()")
+	}
+	s.items = append(s.items, namespace)
+}
+
+func (s *sortedNamespaces) sortedItems() []*Namespace {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+	if !s.sorted {
+		less := func(i int, j int) bool {
+			return s.items[i].Path < s.items[j].Path
+		}
+		sort.Slice(s.items, less)
+		s.sorted = true
+	}
+	return s.items
+}
+
+func (s *sortedNamespaces) index(namespace *Namespace) int {
+	for i, candidate := range s.sortedItems() {
+		if namespace == candidate {
+			return i
+		}
+	}
+	return -1
+}
+
+// A NameResolver implements blueprint.NameInterface, and implements the logic to
+// find a module from namespaces based on a query string.
+// A query string can be a module name or can be be "//namespace_path:module_path"
+type NameResolver struct {
+	rootNamespace *Namespace
+
+	// id counter for atomic.AddInt32
+	nextNamespaceId int32
+
+	// All namespaces, without duplicates.
+	sortedNamespaces sortedNamespaces
+
+	// Map from dir to namespace. Will have duplicates if two dirs are part of the same namespace.
+	namespacesByDir sync.Map // if generics were supported, this would be sync.Map[string]*Namespace
+
+	// func telling whether to export a namespace to Kati
+	namespaceExportFilter func(*Namespace) bool
+}
+
+func NewNameResolver(namespaceExportFilter func(*Namespace) bool) *NameResolver {
+	namespacesByDir := sync.Map{}
+
+	r := &NameResolver{
+		namespacesByDir:       namespacesByDir,
+		namespaceExportFilter: namespaceExportFilter,
+	}
+	r.rootNamespace = r.newNamespace(".")
+	r.rootNamespace.visibleNamespaces = []*Namespace{r.rootNamespace}
+	r.addNamespace(r.rootNamespace)
+
+	return r
+}
+
+func (r *NameResolver) newNamespace(path string) *Namespace {
+	namespace := NewNamespace(path)
+
+	namespace.exportToKati = r.namespaceExportFilter(namespace)
+
+	return namespace
+}
+
+func (r *NameResolver) addNewNamespaceForModule(module *NamespaceModule, path string) error {
+	fileName := filepath.Base(path)
+	if fileName != "Android.bp" {
+		return errors.New("A namespace may only be declared in a file named Android.bp")
+	}
+	dir := filepath.Dir(path)
+
+	namespace := r.newNamespace(dir)
+	module.namespace = namespace
+	module.resolver = r
+	namespace.importedNamespaceNames = module.properties.Imports
+	return r.addNamespace(namespace)
+}
+
+func (r *NameResolver) addNamespace(namespace *Namespace) (err error) {
+	existingNamespace, exists := r.namespaceAt(namespace.Path)
+	if exists {
+		if existingNamespace.Path == namespace.Path {
+			return fmt.Errorf("namespace %v already exists", namespace.Path)
+		} else {
+			// It would probably confuse readers if namespaces were declared anywhere but
+			// the top of the file, so we forbid declaring namespaces after anything else.
+			return fmt.Errorf("a namespace must be the first module in the file")
+		}
+	}
+	r.sortedNamespaces.add(namespace)
+
+	r.namespacesByDir.Store(namespace.Path, namespace)
+	return nil
+}
+
+// non-recursive check for namespace
+func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) {
+	mapVal, found := r.namespacesByDir.Load(path)
+	if !found {
+		return nil, false
+	}
+	return mapVal.(*Namespace), true
+}
+
+// recursive search upward for a namespace
+func (r *NameResolver) findNamespace(path string) (namespace *Namespace) {
+	namespace, found := r.namespaceAt(path)
+	if found {
+		return namespace
+	}
+	parentDir := filepath.Dir(path)
+	if parentDir == path {
+		return nil
+	}
+	namespace = r.findNamespace(parentDir)
+	r.namespacesByDir.Store(path, namespace)
+	return namespace
+}
+
+func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
+	// if this module is a namespace, then save it to our list of namespaces
+	newNamespace, ok := module.(*NamespaceModule)
+	if ok {
+		err := r.addNewNamespaceForModule(newNamespace, ctx.ModulePath())
+		if err != nil {
+			return nil, []error{err}
+		}
+		return nil, nil
+	}
+
+	// if this module is not a namespace, then save it into the appropriate namespace
+	ns := r.findNamespaceFromCtx(ctx)
+
+	_, errs = ns.moduleContainer.NewModule(ctx, moduleGroup, module)
+	if len(errs) > 0 {
+		return nil, errs
+	}
+
+	amod, ok := module.(Module)
+	if ok {
+		// inform the module whether its namespace is one that we want to export to Make
+		amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati
+	}
+
+	return ns, nil
+}
+
+func (r *NameResolver) AllModules() []blueprint.ModuleGroup {
+	childLists := [][]blueprint.ModuleGroup{}
+	totalCount := 0
+	for _, namespace := range r.sortedNamespaces.sortedItems() {
+		newModules := namespace.moduleContainer.AllModules()
+		totalCount += len(newModules)
+		childLists = append(childLists, newModules)
+	}
+
+	allModules := make([]blueprint.ModuleGroup, 0, totalCount)
+	for _, childList := range childLists {
+		allModules = append(allModules, childList...)
+	}
+	return allModules
+}
+
+// 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) {
+		return "", "", false
+	}
+	name = strings.TrimPrefix(name, namespacePrefix)
+	components := strings.Split(name, modulePrefix)
+	if len(components) != 2 {
+		return "", "", false
+	}
+	return components[0], components[1], true
+
+}
+
+func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace *Namespace) (searchOrder []*Namespace) {
+	return sourceNamespace.visibleNamespaces
+}
+
+func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
+	// handle fully qualified references like "//namespace_path:module_name"
+	nsName, moduleName, isAbs := r.parseFullyQualifiedName(name)
+	if isAbs {
+		namespace, found := r.namespaceAt(nsName)
+		if !found {
+			return blueprint.ModuleGroup{}, false
+		}
+		container := namespace.moduleContainer
+		return container.ModuleFromName(moduleName, nil)
+	}
+	for _, candidate := range r.getNamespacesToSearchForModule(namespace.(*Namespace)) {
+		group, found = candidate.moduleContainer.ModuleFromName(name, nil)
+		if found {
+			return group, true
+		}
+	}
+	return blueprint.ModuleGroup{}, false
+
+}
+
+func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
+	oldNs := r.findNamespace(oldName)
+	newNs := r.findNamespace(newName)
+	if oldNs != newNs {
+		return []error{fmt.Errorf("cannot rename %v to %v because the destination is outside namespace %v", oldName, newName, oldNs.Path)}
+	}
+
+	oldName, err := filepath.Rel(oldNs.Path, oldName)
+	if err != nil {
+		panic(err)
+	}
+	newName, err = filepath.Rel(newNs.Path, newName)
+	if err != nil {
+		panic(err)
+	}
+
+	return oldNs.moduleContainer.Rename(oldName, newName, nil)
+}
+
+// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
+func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) {
+	namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
+	// search itself first
+	namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace)
+	// search its imports next
+	for _, name := range namespace.importedNamespaceNames {
+		imp, ok := r.namespaceAt(name)
+		if !ok {
+			return fmt.Errorf("namespace %v does not exist", name)
+		}
+		namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp)
+	}
+	// search the root namespace last
+	namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace)
+	return nil
+}
+
+func (r *NameResolver) chooseId(namespace *Namespace) {
+	id := r.sortedNamespaces.index(namespace)
+	if id < 0 {
+		panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id))
+	}
+	namespace.id = strconv.Itoa(id)
+}
+
+func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) {
+	text := fmt.Sprintf("%q depends on undefined module %q", depender, depName)
+
+	_, _, isAbs := r.parseFullyQualifiedName(depName)
+	if isAbs {
+		// if the user gave a fully-qualified name, we don't need to look for other
+		// modules that they might have been referring to
+		return fmt.Errorf(text)
+	}
+
+	// determine which namespaces the module can be found in
+	foundInNamespaces := []string{}
+	for _, namespace := range r.sortedNamespaces.sortedItems() {
+		_, found := namespace.moduleContainer.ModuleFromName(depName, nil)
+		if found {
+			foundInNamespaces = append(foundInNamespaces, namespace.Path)
+		}
+	}
+	if len(foundInNamespaces) > 0 {
+		// determine which namespaces are visible to dependerNamespace
+		dependerNs := dependerNamespace.(*Namespace)
+		searched := r.getNamespacesToSearchForModule(dependerNs)
+		importedNames := []string{}
+		for _, ns := range searched {
+			importedNames = append(importedNames, ns.Path)
+		}
+		text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
+		text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
+	}
+
+	return fmt.Errorf(text)
+}
+
+func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
+	return r.findNamespaceFromCtx(ctx)
+}
+
+func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace {
+	return r.findNamespace(filepath.Dir(ctx.ModulePath()))
+}
+
+func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) {
+	prefix := r.findNamespaceFromCtx(ctx).id
+	if prefix != "" {
+		prefix = prefix + "-"
+	}
+	return prefix + name
+}
+
+var _ blueprint.NameInterface = (*NameResolver)(nil)
+
+type Namespace struct {
+	blueprint.NamespaceMarker
+	Path string
+
+	// names of namespaces listed as imports by this namespace
+	importedNamespaceNames []string
+	// all namespaces that should be searched when a module in this namespace declares a dependency
+	visibleNamespaces []*Namespace
+
+	id string
+
+	exportToKati bool
+
+	moduleContainer blueprint.NameInterface
+}
+
+func NewNamespace(path string) *Namespace {
+	return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()}
+}
+
+var _ blueprint.Namespace = (*Namespace)(nil)
+
+type NamespaceModule struct {
+	ModuleBase
+
+	namespace *Namespace
+	resolver  *NameResolver
+
+	properties struct {
+		Imports []string
+	}
+}
+
+func (n *NamespaceModule) DepsMutator(context BottomUpMutatorContext) {
+}
+
+func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
+}
+
+func (n *NamespaceModule) Name() (name string) {
+	return *n.nameProperties.Name
+}
+
+func NamespaceFactory() Module {
+	module := &NamespaceModule{}
+
+	name := "soong_namespace"
+	module.nameProperties.Name = &name
+
+	module.AddProperties(&module.properties)
+	return module
+}
+
+func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("namespace_deps", namespaceMutator).Parallel()
+}
+
+func namespaceMutator(ctx BottomUpMutatorContext) {
+	module, ok := ctx.Module().(*NamespaceModule)
+	if ok {
+		err := module.resolver.FindNamespaceImports(module.namespace)
+		if err != nil {
+			ctx.ModuleErrorf(err.Error())
+		}
+
+		module.resolver.chooseId(module.namespace)
+	}
+}
diff --git a/android/namespace_test.go b/android/namespace_test.go
new file mode 100644
index 0000000..9ab186b
--- /dev/null
+++ b/android/namespace_test.go
@@ -0,0 +1,703 @@
+// 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 android
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/google/blueprint"
+)
+
+func TestDependingOnModuleInSameNamespace(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	a := getModule(ctx, "a")
+	b := getModule(ctx, "b")
+	if !dependsOn(ctx, b, a) {
+		t.Errorf("module b does not depend on module a in the same namespace")
+	}
+}
+
+func TestDependingOnModuleInRootNamespace(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			".": `
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+		},
+	)
+
+	a := getModule(ctx, "a")
+	b := getModule(ctx, "b")
+	if !dependsOn(ctx, b, a) {
+		t.Errorf("module b in root namespace does not depend on module a in the root namespace")
+	}
+}
+
+func TestImplicitlyImportRootNamespace(t *testing.T) {
+	_ = setupTest(t,
+		map[string]string{
+			".": `
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	// setupTest will report any errors
+}
+
+func TestDependingOnModuleInImportedNamespace(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+				imports: ["dir1"],
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	a := getModule(ctx, "a")
+	b := getModule(ctx, "b")
+	if !dependsOn(ctx, b, a) {
+		t.Errorf("module b does not depend on module a in the same namespace")
+	}
+}
+
+func TestDependingOnModuleInNonImportedNamespace(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir3": `
+			soong_namespace {
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(
+			`dir3/Android.bp:4:4: "b" depends on undefined module "a"
+Module "b" is defined in namespace "dir3" which can read these 2 namespaces: ["dir3" "."]
+Module "a" can be found in these namespaces: ["dir1" "dir2"]`),
+	}
+
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestDependingOnModuleByFullyQualifiedReference(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+			}
+			test_module {
+				name: "b",
+				deps: ["//dir1:a"],
+			}
+			`,
+		},
+	)
+	a := getModule(ctx, "a")
+	b := getModule(ctx, "b")
+	if !dependsOn(ctx, b, a) {
+		t.Errorf("module b does not depend on module a")
+	}
+}
+
+func TestSameNameInTwoNamespaces(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				id: "1",
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+				id: "2",
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				id:"3",
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+				id:"4",
+			}
+			`,
+		},
+	)
+
+	one := findModuleById(ctx, "1")
+	two := findModuleById(ctx, "2")
+	three := findModuleById(ctx, "3")
+	four := findModuleById(ctx, "4")
+	if !dependsOn(ctx, two, one) {
+		t.Fatalf("Module 2 does not depend on module 1 in its namespace")
+	}
+	if dependsOn(ctx, two, three) {
+		t.Fatalf("Module 2 depends on module 3 in another namespace")
+	}
+	if !dependsOn(ctx, four, three) {
+		t.Fatalf("Module 4 does not depend on module 3 in its namespace")
+	}
+	if dependsOn(ctx, four, one) {
+		t.Fatalf("Module 4 depends on module 1 in another namespace")
+	}
+}
+
+func TestSearchOrder(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				id: "1",
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				id:"2",
+			}
+			test_module {
+				name: "b",
+				id:"3",
+			}
+			`,
+			"dir3": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				id:"4",
+			}
+			test_module {
+				name: "b",
+				id:"5",
+			}
+			test_module {
+				name: "c",
+				id:"6",
+			}
+			`,
+			".": `
+			test_module {
+				name: "a",
+				id: "7",
+			}
+			test_module {
+				name: "b",
+				id: "8",
+			}
+			test_module {
+				name: "c",
+				id: "9",
+			}
+			test_module {
+				name: "d",
+				id: "10",
+			}
+			`,
+			"dir4": `
+			soong_namespace {
+				imports: ["dir1", "dir2", "dir3"]
+			}
+			test_module {
+				name: "test_me",
+				id:"0",
+				deps: ["a", "b", "c", "d"],
+			}
+			`,
+		},
+	)
+
+	testMe := findModuleById(ctx, "0")
+	if !dependsOn(ctx, testMe, findModuleById(ctx, "1")) {
+		t.Errorf("test_me doesn't depend on id 1")
+	}
+	if !dependsOn(ctx, testMe, findModuleById(ctx, "3")) {
+		t.Errorf("test_me doesn't depend on id 3")
+	}
+	if !dependsOn(ctx, testMe, findModuleById(ctx, "6")) {
+		t.Errorf("test_me doesn't depend on id 6")
+	}
+	if !dependsOn(ctx, testMe, findModuleById(ctx, "10")) {
+		t.Errorf("test_me doesn't depend on id 10")
+	}
+	if numDeps(ctx, testMe) != 4 {
+		t.Errorf("num dependencies of test_me = %v, not 4\n", numDeps(ctx, testMe))
+	}
+}
+
+func TestTwoNamespacesCanImportEachOther(t *testing.T) {
+	_ = setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+				imports: ["dir2"]
+			}
+			test_module {
+				name: "a",
+			}
+			test_module {
+				name: "c",
+				deps: ["b"],
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+				imports: ["dir1"],
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	// setupTest will report any errors
+}
+
+func TestImportingNonexistentNamespace(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+				imports: ["a_nonexistent_namespace"]
+			}
+			test_module {
+				name: "a",
+				deps: ["a_nonexistent_module"]
+			}
+			`,
+		},
+	)
+
+	// should complain about the missing namespace and not complain about the unresolvable dependency
+	expectedErrors := []error{
+		errors.New(`dir1/Android.bp:2:4: module "soong_namespace": namespace a_nonexistent_namespace does not exist`),
+	}
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestNamespacesDontInheritParentNamespaces(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir1/subdir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(`dir1/subdir1/Android.bp:4:4: "b" depends on undefined module "a"
+Module "b" is defined in namespace "dir1/subdir1" which can read these 2 namespaces: ["dir1/subdir1" "."]
+Module "a" can be found in these namespaces: ["dir1"]`),
+	}
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestModulesDoReceiveParentNamespace(t *testing.T) {
+	_ = setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir1/subdir": `
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	// setupTest will report any errors
+}
+
+func TestNamespaceImportsNotTransitive(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+			}
+			`,
+			"dir2": `
+			soong_namespace {
+				imports: ["dir1"],
+			}
+			test_module {
+				name: "b",
+				deps: ["a"],
+			}
+			`,
+			"dir3": `
+			soong_namespace {
+				imports: ["dir2"],
+			}
+			test_module {
+				name: "c",
+				deps: ["a"],
+			}
+			`,
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(`dir3/Android.bp:5:4: "c" depends on undefined module "a"
+Module "c" is defined in namespace "dir3" which can read these 3 namespaces: ["dir3" "dir2" "."]
+Module "a" can be found in these namespaces: ["dir1"]`),
+	}
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestTwoNamepacesInSameDir(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			soong_namespace {
+			}
+			`,
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(`dir1/Android.bp:4:4: namespace dir1 already exists`),
+	}
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestNamespaceNotAtTopOfFile(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			test_module {
+				name: "a"
+			}
+			soong_namespace {
+			}
+			`,
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(`dir1/Android.bp:5:4: a namespace must be the first module in the file`),
+	}
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestTwoModulesWithSameNameInSameNamespace(t *testing.T) {
+	_, errs := setupTestExpectErrs(
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a"
+			}
+			test_module {
+				name: "a"
+			}
+			`,
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(`dir1/Android.bp:7:4: module "a" already defined
+       dir1/Android.bp:4:4 <-- previous definition here`),
+	}
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+func TestDeclaringNamespaceInNonAndroidBpFile(t *testing.T) {
+	_, errs := setupTestFromFiles(
+		map[string][]byte{
+			"Android.bp": []byte(`
+				build = ["include.bp"]
+			`),
+			"include.bp": []byte(`
+				soong_namespace {
+				}
+			`),
+		},
+	)
+
+	expectedErrors := []error{
+		errors.New(`include.bp:2:5: A namespace may only be declared in a file named Android.bp`),
+	}
+
+	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
+		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
+	}
+}
+
+// so that the generated .ninja file will have consistent names
+func TestConsistentNamespaceNames(t *testing.T) {
+	ctx := setupTest(t,
+		map[string]string{
+			"dir1": "soong_namespace{}",
+			"dir2": "soong_namespace{}",
+			"dir3": "soong_namespace{}",
+		})
+
+	ns1, _ := ctx.NameResolver.namespaceAt("dir1")
+	ns2, _ := ctx.NameResolver.namespaceAt("dir2")
+	ns3, _ := ctx.NameResolver.namespaceAt("dir3")
+	actualIds := []string{ns1.id, ns2.id, ns3.id}
+	expectedIds := []string{"1", "2", "3"}
+	if !reflect.DeepEqual(actualIds, expectedIds) {
+		t.Errorf("Incorrect namespace ids.\nactual: %s\nexpected: %s\n", actualIds, expectedIds)
+	}
+}
+
+// some utils to support the tests
+
+func mockFiles(bps map[string]string) (files map[string][]byte) {
+	files = make(map[string][]byte, len(bps))
+	files["Android.bp"] = []byte("")
+	for dir, text := range bps {
+		files[filepath.Join(dir, "Android.bp")] = []byte(text)
+	}
+	return files
+}
+
+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.PreDepsMutators(RegisterNamespaceMutator)
+	ctx.Register()
+
+	_, errs = ctx.ParseBlueprintsFiles("Android.bp")
+	if len(errs) > 0 {
+		return ctx, errs
+	}
+	_, errs = ctx.PrepareBuildActions(config)
+	return ctx, errs
+}
+
+func setupTestExpectErrs(bps map[string]string) (ctx *TestContext, errs []error) {
+	files := make(map[string][]byte, len(bps))
+	files["Android.bp"] = []byte("")
+	for dir, text := range bps {
+		files[filepath.Join(dir, "Android.bp")] = []byte(text)
+	}
+	return setupTestFromFiles(files)
+}
+
+func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) {
+	ctx, errs := setupTestExpectErrs(bps)
+	failIfErrored(t, errs)
+	return ctx
+}
+
+func dependsOn(ctx *TestContext, module TestingModule, possibleDependency TestingModule) bool {
+	depends := false
+	visit := func(dependency blueprint.Module) {
+		if dependency == possibleDependency.module {
+			depends = true
+		}
+	}
+	ctx.VisitDirectDeps(module.module, visit)
+	return depends
+}
+
+func numDeps(ctx *TestContext, module TestingModule) int {
+	count := 0
+	visit := func(dependency blueprint.Module) {
+		count++
+	}
+	ctx.VisitDirectDeps(module.module, visit)
+	return count
+}
+
+func getModule(ctx *TestContext, moduleName string) TestingModule {
+	return ctx.ModuleForTests(moduleName, "")
+}
+
+func findModuleById(ctx *TestContext, id string) (module TestingModule) {
+	visit := func(candidate blueprint.Module) {
+		testModule, ok := candidate.(*testModule)
+		if ok {
+			if testModule.properties.Id == id {
+				module = TestingModule{testModule}
+			}
+		}
+	}
+	ctx.VisitAllModules(visit)
+	return module
+}
+
+type testModule struct {
+	ModuleBase
+	properties struct {
+		Deps []string
+		Id   string
+	}
+}
+
+func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
+	for _, d := range m.properties.Deps {
+		ctx.AddDependency(ctx.Module(), nil, d)
+	}
+}
+
+func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+func newTestModule() Module {
+	m := &testModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidModule(m)
+	return m
+}
+
+func failIfErrored(t *testing.T, errs []error) {
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Error(err)
+		}
+		t.FailNow()
+	}
+}
diff --git a/android/package_ctx.go b/android/package_ctx.go
index d32e82b..0dbcea5 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -16,20 +16,21 @@
 
 import (
 	"fmt"
+	"runtime"
 	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 )
 
-// AndroidPackageContext is a wrapper for blueprint.PackageContext that adds
+// PackageContext is a wrapper for blueprint.PackageContext that adds
 // some android-specific helper functions.
-type AndroidPackageContext struct {
+type PackageContext struct {
 	blueprint.PackageContext
 }
 
-func NewPackageContext(pkgPath string) AndroidPackageContext {
-	return AndroidPackageContext{blueprint.NewPackageContext(pkgPath)}
+func NewPackageContext(pkgPath string) PackageContext {
+	return PackageContext{blueprint.NewPackageContext(pkgPath)}
 }
 
 // configErrorWrapper can be used with Path functions when a Context is not
@@ -39,7 +40,7 @@
 // The most common use here will be with VariableFunc, where only a config is
 // provided, and an error should be returned.
 type configErrorWrapper struct {
-	pctx   AndroidPackageContext
+	pctx   PackageContext
 	config Config
 	errors []error
 }
@@ -47,7 +48,7 @@
 var _ PathContext = &configErrorWrapper{}
 var _ errorfContext = &configErrorWrapper{}
 
-func (e *configErrorWrapper) Config() interface{} {
+func (e *configErrorWrapper) Config() Config {
 	return e.config
 }
 func (e *configErrorWrapper) Errorf(format string, args ...interface{}) {
@@ -61,13 +62,43 @@
 	return nil
 }
 
+// VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config
+// argument to a Config.
+func (p PackageContext) VariableFunc(name string,
+	f func(Config) (string, error)) blueprint.Variable {
+
+	return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) {
+		return f(config.(Config))
+	})
+}
+
+// PoolFunc wraps blueprint.PackageContext.PoolFunc, converting the interface{} config
+// argument to a Config.
+func (p PackageContext) PoolFunc(name string,
+	f func(Config) (blueprint.PoolParams, error)) blueprint.Pool {
+
+	return p.PackageContext.PoolFunc(name, func(config interface{}) (blueprint.PoolParams, error) {
+		return f(config.(Config))
+	})
+}
+
+// RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config
+// argument to a Config.
+func (p PackageContext) RuleFunc(name string,
+	f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
+
+	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
+		return f(config.(Config))
+	}, argNames...)
+}
+
 // SourcePathVariable returns a Variable whose value is the source directory
 // appended with the supplied path. It may only be called during a Go package's
 // initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
-func (p AndroidPackageContext) SourcePathVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) SourcePathVariable(name, path string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		ctx := &configErrorWrapper{p, config, []error{}}
 		p := safePathForSource(ctx, path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -80,9 +111,9 @@
 // appended with the supplied paths, joined with separator. It may only be
 // called during a Go package's initialization - either from the init()
 // function or as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		ctx := &configErrorWrapper{p, config, []error{}}
 		var ret []string
 		for _, path := range paths {
 			p := safePathForSource(ctx, path)
@@ -100,23 +131,23 @@
 // The environment variable is not required to point to a path inside the source tree.
 // It may only be called during a Go package's initialization - either from the init() function or
 // as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable {
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		ctx := &configErrorWrapper{p, config, []error{}}
 		p := safePathForSource(ctx, path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
 		}
-		return config.(Config).GetenvWithDefault(env, p.String()), nil
+		return config.GetenvWithDefault(env, p.String()), nil
 	})
 }
 
-// HostBinVariable returns a Variable whose value is the path to a host tool
+// HostBinToolVariable returns a Variable whose value is the path to a host tool
 // in the bin directory for host targets. It may only be called during a Go
 // package's initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
-func (p AndroidPackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
+func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
 		po, err := p.HostBinToolPath(config, path)
 		if err != nil {
 			return "", err
@@ -125,8 +156,8 @@
 	})
 }
 
-func (p AndroidPackageContext) HostBinToolPath(config interface{}, path string) (Path, error) {
-	ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) HostBinToolPath(config Config, path string) (Path, error) {
+	ctx := &configErrorWrapper{p, config, []error{}}
 	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
 	if len(ctx.errors) > 0 {
 		return nil, ctx.errors[0]
@@ -134,13 +165,40 @@
 	return pa, nil
 }
 
+// HostJNIToolVariable returns a Variable whose value is the path to a host tool
+// in the lib directory for host targets. It may only be called during a Go
+// package's initialization - either from the init() function or as part of a
+// package-scoped variable's initialization.
+func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		po, err := p.HostJNIToolPath(config, path)
+		if err != nil {
+			return "", err
+		}
+		return po.String(), nil
+	})
+}
+
+func (p PackageContext) HostJNIToolPath(config Config, path string) (Path, error) {
+	ctx := &configErrorWrapper{p, config, []error{}}
+	ext := ".so"
+	if runtime.GOOS == "darwin" {
+		ext = ".dylib"
+	}
+	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "lib64", path+ext)
+	if len(ctx.errors) > 0 {
+		return nil, ctx.errors[0]
+	}
+	return pa, nil
+}
+
 // HostJavaToolVariable returns a Variable whose value is the path to a host
 // tool in the frameworks directory for host targets. It may only be called
 // during a Go package's initialization - either from the init() function or as
 // part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		ctx := &configErrorWrapper{p, config, []error{}}
 		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -149,8 +207,8 @@
 	})
 }
 
-func (p AndroidPackageContext) HostJavaToolPath(config interface{}, path string) (Path, error) {
-	ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) HostJavaToolPath(config Config, path string) (Path, error) {
+	ctx := &configErrorWrapper{p, config, []error{}}
 	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
 	if len(ctx.errors) > 0 {
 		return nil, ctx.errors[0]
@@ -162,9 +220,9 @@
 // directory appended with the supplied path. It may only be called during a Go
 // package's initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
-func (p AndroidPackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		ctx := &configErrorWrapper{p, config, []error{}}
 		p := PathForIntermediates(ctx, path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -177,11 +235,11 @@
 // list of present source paths prefixed with the supplied prefix. It may only
 // be called during a Go package's initialization - either from the init()
 // function or as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) PrefixedExistentPathsForSourcesVariable(
+func (p PackageContext) PrefixedExistentPathsForSourcesVariable(
 	name, prefix string, paths []string) blueprint.Variable {
 
-	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+	return p.VariableFunc(name, func(config Config) (string, error) {
+		ctx := &configErrorWrapper{p, config, []error{}}
 		paths := ExistentPathsForSources(ctx, "", paths)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -190,13 +248,8 @@
 	})
 }
 
-type RuleParams struct {
-	blueprint.RuleParams
-	GomaSupported bool
-}
-
 // AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
-func (p AndroidPackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
+func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
 	return p.AndroidRuleFunc(name, func(Config) (blueprint.RuleParams, error) {
 		return params, nil
@@ -204,16 +257,16 @@
 }
 
 // AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled
-func (p AndroidPackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
+func (p PackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
 	return p.StaticRule(name, params, argNames...)
 }
 
-func (p AndroidPackageContext) AndroidRuleFunc(name string,
+func (p PackageContext) AndroidRuleFunc(name string,
 	f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
-	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
-		params, err := f(config.(Config))
-		if config.(Config).UseGoma() && params.Pool == nil {
+	return p.RuleFunc(name, func(config Config) (blueprint.RuleParams, error) {
+		params, err := f(config)
+		if config.UseGoma() && params.Pool == nil {
 			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
 			// local parallelism value
 			params.Pool = localPool
diff --git a/android/paths.go b/android/paths.go
index 4adaa2d..4d9c858 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -29,7 +29,7 @@
 // Path methods.
 type PathContext interface {
 	Fs() pathtools.FileSystem
-	Config() interface{}
+	Config() Config
 	AddNinjaFileDeps(deps ...string)
 }
 
@@ -37,8 +37,8 @@
 	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
 }
 
-var _ PathContext = blueprint.SingletonContext(nil)
-var _ PathContext = blueprint.ModuleContext(nil)
+var _ PathContext = SingletonContext(nil)
+var _ PathContext = ModuleContext(nil)
 
 type ModuleInstallPathContext interface {
 	PathContext
@@ -67,15 +67,6 @@
 
 var _ moduleErrorf = blueprint.ModuleContext(nil)
 
-// pathConfig returns the android Config interface associated to the context.
-// Panics if the context isn't affiliated with an android build.
-func pathConfig(ctx PathContext) Config {
-	if ret, ok := ctx.Config().(Config); ok {
-		return ret
-	}
-	panic("Paths may only be used on Soong builds")
-}
-
 // reportPathError will register an error with the attached context. It
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
@@ -101,7 +92,7 @@
 
 	// Rel returns the portion of the path relative to the directory it was created from.  For
 	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
-	// directory.
+	// directory, and OutputPath.Join("foo").Rel() would return "foo".
 	Rel() string
 }
 
@@ -197,7 +188,7 @@
 
 // PathsForSource returns Paths rooted from SrcDir
 func PathsForSource(ctx PathContext, paths []string) Paths {
-	if pathConfig(ctx).AllowMissingDependencies() {
+	if ctx.Config().AllowMissingDependencies() {
 		if modCtx, ok := ctx.(ModuleContext); ok {
 			ret := make(Paths, 0, len(paths))
 			intermediates := pathForModule(modCtx).withRel("missing")
@@ -247,7 +238,7 @@
 // source directory, but strip the local source directory from the beginning of
 // each string.
 func pathsForModuleSrcFromFullPath(ctx ModuleContext, paths []string) Paths {
-	prefix := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir()) + "/"
+	prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
 	if prefix == "./" {
 		prefix = ""
 	}
@@ -271,7 +262,7 @@
 	}
 	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
 	// is created, we're run again.
-	path := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir(), def)
+	path := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir(), def)
 	return ctx.Glob(path, []string{})
 }
 
@@ -428,6 +419,18 @@
 	return ret
 }
 
+// Paths returns the WritablePaths as a Paths
+func (p WritablePaths) Paths() Paths {
+	if p == nil {
+		return nil
+	}
+	ret := make(Paths, len(p))
+	for i, path := range p {
+		ret[i] = path
+	}
+	return ret
+}
+
 type basePath struct {
 	path   string
 	config Config
@@ -449,6 +452,16 @@
 	return p.path
 }
 
+func (p basePath) String() string {
+	return p.path
+}
+
+func (p basePath) withRel(rel string) basePath {
+	p.path = filepath.Join(p.path, rel)
+	p.rel = rel
+	return p
+}
+
 // SourcePath is a Path representing a file path rooted from SrcDir
 type SourcePath struct {
 	basePath
@@ -456,18 +469,23 @@
 
 var _ Path = SourcePath{}
 
+func (p SourcePath) withRel(rel string) SourcePath {
+	p.basePath = p.basePath.withRel(rel)
+	return p
+}
+
 // safePathForSource is for paths that we expect are safe -- only for use by go
 // code that is embedding ninja variables in paths
 func safePathForSource(ctx PathContext, path string) SourcePath {
 	p := validateSafePath(ctx, path)
-	ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
+	ret := SourcePath{basePath{p, ctx.Config(), ""}}
 
 	abs, err := filepath.Abs(ret.String())
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
 	}
-	buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
@@ -485,14 +503,14 @@
 // On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
 func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
 	p := validatePath(ctx, pathComponents...)
-	ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
+	ret := SourcePath{basePath{p, ctx.Config(), ""}}
 
 	abs, err := filepath.Abs(ret.String())
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
 	}
-	buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
@@ -520,14 +538,14 @@
 	}
 
 	p := validatePath(ctx, pathComponents...)
-	path := SourcePath{basePath{p, pathConfig(ctx), ""}}
+	path := SourcePath{basePath{p, ctx.Config(), ""}}
 
 	abs, err := filepath.Abs(path.String())
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return OptionalPath{}
 	}
-	buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return OptionalPath{}
@@ -582,7 +600,7 @@
 // provided paths... may not use '..' to escape from the current path.
 func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath {
 	path := validatePath(ctx, paths...)
-	return PathForSource(ctx, p.path, path)
+	return p.withRel(path)
 }
 
 // OverlayPath returns the overlay for `path' if it exists. This assumes that the
@@ -624,8 +642,7 @@
 }
 
 func (p OutputPath) withRel(rel string) OutputPath {
-	p.basePath.path = filepath.Join(p.basePath.path, rel)
-	p.basePath.rel = rel
+	p.basePath = p.basePath.withRel(rel)
 	return p
 }
 
@@ -636,7 +653,7 @@
 // On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
 func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
 	path := validatePath(ctx, pathComponents...)
-	return OutputPath{basePath{path, pathConfig(ctx), ""}}
+	return OutputPath{basePath{path, ctx.Config(), ""}}
 }
 
 func (p OutputPath) writablePath() {}
@@ -653,7 +670,7 @@
 // provided paths... may not use '..' to escape from the current path.
 func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath {
 	path := validatePath(ctx, paths...)
-	return PathForOutput(ctx, p.path, path)
+	return p.withRel(path)
 }
 
 // PathForIntermediates returns an OutputPath representing the top-level
@@ -828,8 +845,12 @@
 		var partition string
 		if ctx.InstallInData() {
 			partition = "data"
-		} else if ctx.InstallOnVendorPartition() {
+		} else if ctx.SocSpecific() {
 			partition = ctx.DeviceConfig().VendorPath()
+		} else if ctx.DeviceSpecific() {
+			partition = ctx.DeviceConfig().OdmPath()
+		} else if ctx.ProductSpecific() {
+			partition = ctx.DeviceConfig().OemPath()
 		} else {
 			partition = "system"
 		}
@@ -837,7 +858,7 @@
 		if ctx.InstallInSanitizerDir() {
 			partition = "data/asan/" + partition
 		}
-		outPaths = []string{"target", "product", ctx.AConfig().DeviceName(), partition}
+		outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
 	} else {
 		switch ctx.Os() {
 		case Linux:
@@ -885,6 +906,22 @@
 	return validateSafePath(ctx, pathComponents...)
 }
 
+func PathForPhony(ctx PathContext, phony string) WritablePath {
+	if strings.ContainsAny(phony, "$/") {
+		reportPathError(ctx, "Phony target contains invalid character ($ or /): %s", phony)
+	}
+	return PhonyPath{basePath{phony, ctx.Config(), ""}}
+}
+
+type PhonyPath struct {
+	basePath
+}
+
+func (p PhonyPath) writablePath() {}
+
+var _ Path = PhonyPath{}
+var _ WritablePath = PhonyPath{}
+
 type testPath struct {
 	basePath
 }
diff --git a/android/paths_test.go b/android/paths_test.go
index 82ae4dc..110974f 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -194,7 +194,7 @@
 	return pathtools.MockFs(nil)
 }
 
-func (m moduleInstallPathContextImpl) Config() interface{} {
+func (m moduleInstallPathContextImpl) Config() Config {
 	return m.androidBaseContextImpl.config
 }
 
@@ -246,12 +246,34 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
 				},
 			},
 			in:  []string{"bin", "my_test"},
 			out: "target/product/test_device/vendor/bin/my_test",
 		},
+		{
+			name: "odm binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/odm/bin/my_test",
+		},
+		{
+			name: "oem binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
+				},
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/oem/bin/my_test",
+		},
 
 		{
 			name: "system native test binary",
@@ -269,7 +291,31 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
+				},
+				inData: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/nativetest/my_test",
+		},
+		{
+			name: "odm native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+				inData: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/nativetest/my_test",
+		},
+		{
+			name: "oem native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
 				},
 				inData: true,
 			},
@@ -293,13 +339,37 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
 				},
 				inSanitizerDir: true,
 			},
 			in:  []string{"bin", "my_test"},
 			out: "target/product/test_device/data/asan/vendor/bin/my_test",
 		},
+		{
+			name: "sanitized odm binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+				inSanitizerDir: true,
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/data/asan/odm/bin/my_test",
+		},
+		{
+			name: "sanitized oem binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
+				},
+				inSanitizerDir: true,
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/data/asan/oem/bin/my_test",
+		},
 
 		{
 			name: "sanitized system native test binary",
@@ -318,7 +388,33 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
+				},
+				inData:         true,
+				inSanitizerDir: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+		},
+		{
+			name: "sanitized odm native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+				inData:         true,
+				inSanitizerDir: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+		},
+		{
+			name: "sanitized oem native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
 				},
 				inData:         true,
 				inSanitizerDir: true,
diff --git a/android/proto.go b/android/proto.go
index 1c70656..0cf7c26 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -23,7 +23,9 @@
 // generate the source.
 
 func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string {
-	var protoFlags []string
+	// -I . must come first, it affects where protoc places the output files.
+	protoFlags := []string{"-I ."}
+
 	if len(p.Proto.Local_include_dirs) > 0 {
 		localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
 		protoFlags = append(protoFlags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
@@ -33,8 +35,6 @@
 		protoFlags = append(protoFlags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
 	}
 
-	protoFlags = append(protoFlags, "-I .")
-
 	return protoFlags
 }
 
diff --git a/android/register.go b/android/register.go
index 81a266d..6c88af1 100644
--- a/android/register.go
+++ b/android/register.go
@@ -44,7 +44,7 @@
 
 type ModuleFactory func() Module
 
-// ModuleFactoryAdaptor Wraps a ModuleFactory into a blueprint.ModuleFactory by converting an Module
+// ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module
 // into a blueprint.Module and a list of property structs
 func ModuleFactoryAdaptor(factory ModuleFactory) blueprint.ModuleFactory {
 	return func() (blueprint.Module, []interface{}) {
@@ -53,16 +53,27 @@
 	}
 }
 
+type SingletonFactory func() Singleton
+
+// SingletonFactoryAdaptor wraps a SingletonFactory into a blueprint.SingletonFactory by converting
+// a Singleton into a blueprint.Singleton
+func SingletonFactoryAdaptor(factory SingletonFactory) blueprint.SingletonFactory {
+	return func() blueprint.Singleton {
+		singleton := factory()
+		return singletonAdaptor{singleton}
+	}
+}
+
 func RegisterModuleType(name string, factory ModuleFactory) {
 	moduleTypes = append(moduleTypes, moduleType{name, ModuleFactoryAdaptor(factory)})
 }
 
-func RegisterSingletonType(name string, factory blueprint.SingletonFactory) {
-	singletons = append(singletons, singleton{name, factory})
+func RegisterSingletonType(name string, factory SingletonFactory) {
+	singletons = append(singletons, singleton{name, SingletonFactoryAdaptor(factory)})
 }
 
-func RegisterPreSingletonType(name string, factory blueprint.SingletonFactory) {
-	preSingletons = append(preSingletons, singleton{name, factory})
+func RegisterPreSingletonType(name string, factory SingletonFactory) {
+	preSingletons = append(preSingletons, singleton{name, SingletonFactoryAdaptor(factory)})
 }
 
 type Context struct {
@@ -88,5 +99,5 @@
 
 	registerMutators(ctx.Context, preArch, preDeps, postDeps)
 
-	ctx.RegisterSingletonType("env", EnvSingleton)
+	ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
 }
diff --git a/android/singleton.go b/android/singleton.go
new file mode 100644
index 0000000..f577b0a
--- /dev/null
+++ b/android/singleton.go
@@ -0,0 +1,165 @@
+// 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 android
+
+import (
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
+)
+
+// SingletonContext
+type SingletonContext interface {
+	Config() Config
+
+	ModuleName(module blueprint.Module) string
+	ModuleDir(module blueprint.Module) string
+	ModuleSubDir(module blueprint.Module) string
+	ModuleType(module blueprint.Module) string
+	BlueprintFile(module blueprint.Module) string
+
+	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+	Errorf(format string, args ...interface{})
+	Failed() bool
+
+	Variable(pctx PackageContext, name, value string)
+	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
+	Build(pctx PackageContext, params BuildParams)
+	RequireNinjaVersion(major, minor, micro int)
+
+	// SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable
+	// that controls where Ninja stores its build log files.  This value can be
+	// set at most one time for a single build, later calls are ignored.
+	SetNinjaBuildDir(pctx PackageContext, value string)
+
+	// Eval takes a string with embedded ninja variables, and returns a string
+	// with all of the variables recursively expanded. Any variables references
+	// are expanded in the scope of the PackageContext.
+	Eval(pctx PackageContext, ninjaStr string) (string, error)
+
+	VisitAllModules(visit func(Module))
+	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
+	VisitDepsDepthFirst(module Module, visit func(Module))
+	VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
+		visit func(Module))
+
+	VisitAllModuleVariants(module Module, visit func(Module))
+
+	PrimaryModule(module Module) Module
+	FinalModule(module Module) Module
+
+	AddNinjaFileDeps(deps ...string)
+
+	// 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
+}
+
+type singletonAdaptor struct {
+	Singleton
+}
+
+func (s singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
+	s.Singleton.GenerateBuildActions(singletonContextAdaptor{ctx})
+}
+
+type Singleton interface {
+	GenerateBuildActions(SingletonContext)
+}
+
+type singletonContextAdaptor struct {
+	blueprint.SingletonContext
+}
+
+func (s singletonContextAdaptor) Config() Config {
+	return s.SingletonContext.Config().(Config)
+}
+
+func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
+	s.SingletonContext.Variable(pctx.PackageContext, name, value)
+}
+
+func (s singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
+	return s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
+}
+
+func (s singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
+	bparams := convertBuildParams(params)
+	s.SingletonContext.Build(pctx.PackageContext, bparams)
+
+}
+
+func (s singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
+	s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value)
+}
+
+func (s singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
+	return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr)
+}
+
+// visitAdaptor wraps a visit function that takes an android.Module parameter into
+// a function that takes an blueprint.Module parameter and only calls the visit function if the
+// blueprint.Module is an android.Module.
+func visitAdaptor(visit func(Module)) func(blueprint.Module) {
+	return func(module blueprint.Module) {
+		if aModule, ok := module.(Module); ok {
+			visit(aModule)
+		}
+	}
+}
+
+// predAdaptor wraps a pred function that takes an android.Module parameter
+// into a function that takes an blueprint.Module parameter and only calls the visit function if the
+// blueprint.Module is an android.Module, otherwise returns false.
+func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool {
+	return func(module blueprint.Module) bool {
+		if aModule, ok := module.(Module); ok {
+			return pred(aModule)
+		} else {
+			return false
+		}
+	}
+}
+
+func (s singletonContextAdaptor) VisitAllModules(visit func(Module)) {
+	s.SingletonContext.VisitAllModules(visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
+	s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
+	s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
+	s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
+	s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) PrimaryModule(module Module) Module {
+	return s.SingletonContext.PrimaryModule(module).(Module)
+}
+
+func (s singletonContextAdaptor) FinalModule(module Module) Module {
+	return s.SingletonContext.FinalModule(module).(Module)
+}
diff --git a/android/testing.go b/android/testing.go
index e79562d..ae012b0 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -16,15 +16,26 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint"
 )
 
 func NewTestContext() *TestContext {
-	return &TestContext{
-		Context: blueprint.NewContext(),
+	namespaceExportFilter := func(namespace *Namespace) bool {
+		return true
 	}
+
+	nameResolver := NewNameResolver(namespaceExportFilter)
+	ctx := &TestContext{
+		Context:      blueprint.NewContext(),
+		NameResolver: nameResolver,
+	}
+
+	ctx.SetNameInterface(nameResolver)
+
+	return ctx
 }
 
 func NewTestArchContext() *TestContext {
@@ -36,6 +47,7 @@
 type TestContext struct {
 	*blueprint.Context
 	preArch, preDeps, postDeps []RegisterMutatorFunc
+	NameResolver               *NameResolver
 }
 
 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -53,7 +65,7 @@
 func (ctx *TestContext) Register() {
 	registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
 
-	ctx.RegisterSingletonType("env", EnvSingleton)
+	ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
 }
 
 func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
@@ -78,6 +90,25 @@
 	return TestingModule{module}
 }
 
+// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
+// filenames to contents stored as a byte slice.
+func (ctx *TestContext) MockFileSystem(files map[string][]byte) {
+	// no module list file specified; find every file named Blueprints or Android.bp
+	pathsToParse := []string{}
+	for candidate := range files {
+		base := filepath.Base(candidate)
+		if base == "Blueprints" || base == "Android.bp" {
+			pathsToParse = append(pathsToParse, candidate)
+		}
+	}
+	if len(pathsToParse) < 1 {
+		panic(fmt.Sprintf("No Blueprint or Android.bp files found in mock filesystem: %v\n", files))
+	}
+	files[blueprint.MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
+
+	ctx.Context.MockFileSystem(files)
+}
+
 type TestingModule struct {
 	module Module
 }
@@ -105,16 +136,19 @@
 }
 
 func (m TestingModule) Output(file string) BuildParams {
+	var searchedOutputs []string
 	for _, p := range m.module.BuildParamsForTests() {
 		outputs := append(WritablePaths(nil), p.Outputs...)
 		if p.Output != nil {
 			outputs = append(outputs, p.Output)
 		}
 		for _, f := range outputs {
-			if f.Rel() == file {
+			if f.String() == file || f.Rel() == file {
 				return p
 			}
+			searchedOutputs = append(searchedOutputs, f.Rel())
 		}
 	}
-	panic(fmt.Errorf("couldn't find output %q", file))
+	panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v",
+		file, searchedOutputs))
 }
diff --git a/android/util.go b/android/util.go
index 4d30a74..29bb9b1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -157,3 +157,10 @@
 	ok = true
 	return
 }
+
+func GetNumericSdkVersion(v string) string {
+	if strings.Contains(v, "system_") {
+		return strings.Replace(v, "system_", "", 1)
+	}
+	return v
+}
diff --git a/android/variable.go b/android/variable.go
index 4272817..6962b0f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -67,10 +67,13 @@
 			Cflags []string
 		}
 
-		// treble is true when a build is a Treble compliant device.  This is automatically set when
-		// a build is shipped with Android O, but can be overriden.  This controls such things as
-		// the sepolicy split and enabling the Treble linker namespaces.
-		Treble struct {
+		// treble_linker_namespaces is true when the system/vendor linker namespace separation is
+		// enabled.
+		Treble_linker_namespaces struct {
+			Cflags []string
+		}
+		// enforce_vintf_manifest is true when a device is required to have a vintf manifest.
+		Enforce_vintf_manifest struct {
 			Cflags []string
 		}
 
@@ -111,6 +114,7 @@
 	Platform_sdk_final                *bool    `json:",omitempty"`
 	Platform_version_active_codenames []string `json:",omitempty"`
 	Platform_version_future_codenames []string `json:",omitempty"`
+	Platform_vndk_version             *string  `json:",omitempty"`
 
 	DeviceName        *string   `json:",omitempty"`
 	DeviceArch        *string   `json:",omitempty"`
@@ -141,6 +145,8 @@
 	AAPTPreferredConfig *string   `json:",omitempty"`
 	AAPTPrebuiltDPI     *[]string `json:",omitempty"`
 
+	DefaultAppCertificate *string `json:",omitempty"`
+
 	AppsDefaultVersionName *string `json:",omitempty"`
 
 	Allow_missing_dependencies *bool `json:",omitempty"`
@@ -154,7 +160,9 @@
 	Debuggable                 *bool `json:",omitempty"`
 	Eng                        *bool `json:",omitempty"`
 	Device_uses_hwc2           *bool `json:",omitempty"`
-	Treble                     *bool `json:",omitempty"`
+	Treble_linker_namespaces   *bool `json:",omitempty"`
+	Sepolicy_split             *bool `json:",omitempty"`
+	Enforce_vintf_manifest     *bool `json:",omitempty"`
 	Pdk                        *bool `json:",omitempty"`
 	Uml                        *bool `json:",omitempty"`
 	MinimizeJavaDebugInfo      *bool `json:",omitempty"`
@@ -166,6 +174,8 @@
 	CFIIncludePaths *[]string `json:",omitempty"`
 
 	VendorPath *string `json:",omitempty"`
+	OdmPath    *string `json:",omitempty"`
+	OemPath    *string `json:",omitempty"`
 
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
@@ -189,6 +199,11 @@
 	Override_rs_driver *string `json:",omitempty"`
 
 	DeviceKernelHeaders []string `json:",omitempty"`
+	DistDir             *string  `json:",omitempty"`
+
+	ExtraVndkVersions []string `json:",omitempty"`
+
+	NamespacesToExport []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -257,7 +272,7 @@
 		property := "product_variables." + proptools.PropertyNameForField(name)
 
 		// Check that the variable was set for the product
-		val := reflect.ValueOf(mctx.Config().(Config).ProductVariables).FieldByName(name)
+		val := reflect.ValueOf(mctx.Config().ProductVariables).FieldByName(name)
 		if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() {
 			continue
 		}
diff --git a/android/writedocs.go b/android/writedocs.go
new file mode 100644
index 0000000..9737030
--- /dev/null
+++ b/android/writedocs.go
@@ -0,0 +1,73 @@
+// 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 (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterSingletonType("writedocs", DocsSingleton)
+}
+
+func DocsSingleton() Singleton {
+	return &docsSingleton{}
+}
+
+type docsSingleton struct{}
+
+func primaryBuilderPath(ctx SingletonContext) Path {
+	primaryBuilder, err := filepath.Rel(ctx.Config().BuildDir(), os.Args[0])
+	if err != nil {
+		ctx.Errorf("path to primary builder %q is not in build dir %q",
+			os.Args[0], ctx.Config().BuildDir())
+	}
+
+	return PathForOutput(ctx, primaryBuilder)
+}
+
+func (c *docsSingleton) GenerateBuildActions(ctx SingletonContext) {
+	// Generate build system docs for the primary builder.  Generating docs reads the source
+	// files used to build the primary builder, but that dependency will be picked up through
+	// the dependency on the primary builder itself.  There are no dependencies on the
+	// Blueprints files, as any relevant changes to the Blueprints files would have caused
+	// a rebuild of the primary builder.
+	docsFile := PathForOutput(ctx, "docs", "soong_build.html")
+	primaryBuilder := primaryBuilderPath(ctx)
+	soongDocs := ctx.Rule(pctx, "soongDocs",
+		blueprint.RuleParams{
+			Command: fmt.Sprintf("%s --soong_docs %s %s",
+				primaryBuilder.String(), docsFile.String(), strings.Join(os.Args[1:], " ")),
+			CommandDeps: []string{primaryBuilder.String()},
+			Description: fmt.Sprintf("%s docs $out", primaryBuilder.Base()),
+		})
+
+	ctx.Build(pctx, BuildParams{
+		Rule:   soongDocs,
+		Output: docsFile,
+	})
+
+	// Add a phony target for building the documentation
+	ctx.Build(pctx, BuildParams{
+		Rule:   blueprint.Phony,
+		Output: PathForPhony(ctx, "soong_docs"),
+		Input:  docsFile,
+	})
+}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index df01cf4..82b5eb9 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -24,7 +24,8 @@
 )
 
 const (
-	clear_vars = "__android_mk_clear_vars"
+	clear_vars      = "__android_mk_clear_vars"
+	include_ignored = "__android_mk_include_ignored"
 )
 
 type bpVariable struct {
@@ -48,7 +49,6 @@
 	"LOCAL_MODULE_CLASS":          prebuiltClass,
 	"LOCAL_MODULE_STEM":           stem,
 	"LOCAL_MODULE_HOST_OS":        hostOs,
-	"LOCAL_SRC_FILES":             srcFiles,
 	"LOCAL_SANITIZE":              sanitize(""),
 	"LOCAL_SANITIZE_DIAG":         sanitize("diag."),
 	"LOCAL_CFLAGS":                cflags,
@@ -92,9 +92,13 @@
 			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
 			"LOCAL_NOTICE_FILE":             "notice",
 			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
+			"LOCAL_INSTRUMENTATION_FOR":     "instrumentation_for",
+
+			"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
 		})
 	addStandardProperties(bpparser.ListType,
 		map[string]string{
+			"LOCAL_SRC_FILES":                     "srcs",
 			"LOCAL_SRC_FILES_EXCLUDE":             "exclude_srcs",
 			"LOCAL_HEADER_LIBRARIES":              "header_libs",
 			"LOCAL_SHARED_LIBRARIES":              "shared_libs",
@@ -148,8 +152,14 @@
 			"LOCAL_TIDY":                     "tidy",
 			"LOCAL_PROPRIETARY_MODULE":       "proprietary",
 			"LOCAL_VENDOR_MODULE":            "vendor",
+			"LOCAL_ODM_MODULE":               "device_specific",
+			"LOCAL_OEM_MODULE":               "product_specific",
 			"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
-			"LOCAL_DEX_PREOPT":               "dex_preopt",
+			"LOCAL_PRIVILEGED_MODULE":        "privileged",
+
+			"LOCAL_DEX_PREOPT":                  "dex_preopt.enabled",
+			"LOCAL_DEX_PREOPT_APP_IMAGE":        "dex_preopt.app_image",
+			"LOCAL_DEX_PREOPT_GENERATE_PROFILE": "dex_preopt.profile_guided",
 		})
 }
 
@@ -382,50 +392,6 @@
 	return err
 }
 
-func splitSrcsLogtags(value bpparser.Expression) (string, bpparser.Expression, error) {
-	switch v := value.(type) {
-	case *bpparser.Variable:
-		// TODO: attempt to split variables?
-		return "srcs", value, nil
-	case *bpparser.Operator:
-		// TODO: attempt to handle expressions?
-		return "srcs", value, nil
-	case *bpparser.String:
-		if strings.HasSuffix(v.Value, ".logtags") {
-			return "logtags", value, nil
-		}
-		return "srcs", value, nil
-	default:
-		return "", nil, fmt.Errorf("splitSrcsLogtags expected a string, got %s", value.Type())
-	}
-
-}
-
-func srcFiles(ctx variableAssignmentContext) error {
-	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
-	if err != nil {
-		return err
-	}
-
-	lists, err := splitBpList(val, splitSrcsLogtags)
-
-	if srcs, ok := lists["srcs"]; ok && !emptyList(srcs) {
-		err = setVariable(ctx.file, ctx.append, ctx.prefix, "srcs", srcs, true)
-		if err != nil {
-			return err
-		}
-	}
-
-	if logtags, ok := lists["logtags"]; ok && !emptyList(logtags) {
-		err = setVariable(ctx.file, true, ctx.prefix, "logtags", logtags, true)
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
 func sanitize(sub string) func(ctx variableAssignmentContext) error {
 	return func(ctx variableAssignmentContext) error {
 		val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
@@ -661,6 +627,8 @@
 		false: "target.not_linux_glibc"},
 	"(,$(TARGET_BUILD_APPS))": {
 		false: "product_variables.unbundled_build"},
+	"($(TARGET_BUILD_APPS),)": {
+		false: "product_variables.unbundled_build"},
 	"($(TARGET_BUILD_PDK),true)": {
 		true: "product_variables.pdk"},
 	"($(TARGET_BUILD_PDK), true)": {
@@ -671,28 +639,25 @@
 	return "."
 }
 
-func allJavaFilesUnder(args []string) string {
-	dir := ""
-	if len(args) > 0 {
-		dir = strings.TrimSpace(args[0])
+func allFilesUnder(wildcard string) func(args []string) string {
+	return func(args []string) string {
+		dir := ""
+		if len(args) > 0 {
+			dir = strings.TrimSpace(args[0])
+		}
+
+		return fmt.Sprintf("%s/**/"+wildcard, dir)
 	}
-
-	return fmt.Sprintf("%s/**/*.java", dir)
-}
-
-func allProtoFilesUnder(args []string) string {
-	dir := ""
-	if len(args) > 0 {
-		dir = strings.TrimSpace(args[0])
-	}
-
-	return fmt.Sprintf("%s/**/*.proto", dir)
 }
 
 func allSubdirJavaFiles(args []string) string {
 	return "**/*.java"
 }
 
+func includeIgnored(args []string) string {
+	return include_ignored
+}
+
 var moduleTypes = map[string]string{
 	"BUILD_SHARED_LIBRARY":        "cc_library_shared",
 	"BUILD_STATIC_LIBRARY":        "cc_library_static",
@@ -726,9 +691,16 @@
 	globalScope := mkparser.NewScope(nil)
 	globalScope.Set("CLEAR_VARS", clear_vars)
 	globalScope.SetFunc("my-dir", mydir)
-	globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
-	globalScope.SetFunc("all-proto-files-under", allProtoFilesUnder)
+	globalScope.SetFunc("all-java-files-under", allFilesUnder("*.java"))
+	globalScope.SetFunc("all-proto-files-under", allFilesUnder("*.proto"))
+	globalScope.SetFunc("all-aidl-files-under", allFilesUnder("*.aidl"))
+	globalScope.SetFunc("all-Iaidl-files-under", allFilesUnder("I*.aidl"))
+	globalScope.SetFunc("all-logtags-files-under", allFilesUnder("*.logtags"))
 	globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles)
+	globalScope.SetFunc("all-makefiles-under", includeIgnored)
+	globalScope.SetFunc("first-makefiles-under", includeIgnored)
+	globalScope.SetFunc("all-named-subdir-makefiles", includeIgnored)
+	globalScope.SetFunc("all-subdir-makefiles", includeIgnored)
 
 	for k, v := range moduleTypes {
 		globalScope.Set(k, v)
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 660d9a0..385690c 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -177,6 +177,9 @@
 					makeModule(file, val)
 				case val == clear_vars:
 					resetModule(file)
+				case val == include_ignored:
+					// subdirs are already automatically included in Soong
+					continue
 				default:
 					file.errorf(x, "unsupported include")
 					continue
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 0b86540..22a52d4 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -213,35 +213,6 @@
 `,
 	},
 	{
-		desc: "*.logtags in LOCAL_SRC_FILES",
-		in: `
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := events.logtags
-LOCAL_SRC_FILES += a.c events2.logtags
-include $(BUILD_SHARED_LIBRARY)
-`,
-		expected: `
-cc_library_shared {
-    logtags: ["events.logtags"] + ["events2.logtags"],
-    srcs: ["a.c"],
-}
-`,
-	},
-	{
-		desc: "LOCAL_LOGTAGS_FILES and *.logtags in LOCAL_SRC_FILES",
-		in: `
-include $(CLEAR_VARS)
-LOCAL_LOGTAGS_FILES := events.logtags
-LOCAL_SRC_FILES := events2.logtags
-include $(BUILD_SHARED_LIBRARY)
-`,
-		expected: `
-cc_library_shared {
-    logtags: ["events.logtags"] + ["events2.logtags"],
-}
-`,
-	},
-	{
 		desc: "_<OS> suffixes",
 		in: `
 include $(CLEAR_VARS)
@@ -460,6 +431,13 @@
 // endif
 		`,
 	},
+	{
+		desc: "ignore all-makefiles-under",
+		in: `
+include $(call all-makefiles-under,$(LOCAL_PATH))
+`,
+		expected: ``,
+	},
 }
 
 func reformatBlueprint(input string) string {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 065d0aa..efd4ee7 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -60,6 +60,9 @@
 		OutputFile: c.outputFile,
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
+				if len(c.Properties.Logtags) > 0 {
+					fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(c.Properties.Logtags, " "))
+				}
 				fmt.Fprintln(w, "LOCAL_SANITIZE := never")
 				if len(c.Properties.AndroidMkSharedLibs) > 0 {
 					fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(c.Properties.AndroidMkSharedLibs, " "))
@@ -318,7 +321,7 @@
 	ret.Class = "SHARED_LIBRARIES"
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		path, file := filepath.Split(c.installPath)
+		path, file := filepath.Split(c.installPath.String())
 		stem := strings.TrimSuffix(file, filepath.Ext(file))
 		fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=")
 		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+outputFile.Ext())
@@ -348,3 +351,35 @@
 		fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
 	})
 }
+
+func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ret.Class = "SHARED_LIBRARIES"
+
+	ret.SubName = vndkSuffix + c.version()
+
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		c.libraryDecorator.androidMkWriteExportedFlags(w)
+
+		path := c.path.RelPathString()
+		dir, file := filepath.Split(path)
+		stem := strings.TrimSuffix(file, filepath.Ext(file))
+		fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+		fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=")
+		fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+outputFile.Ext())
+		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+filepath.Ext(file))
+		fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+	})
+}
+
+func (c *ndkPrebuiltStlLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ret.Class = "SHARED_LIBRARIES"
+
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		// Prevent make from installing the libraries to obj/lib (since we have
+		// dozens of libraries with the same name, they'll clobber each other
+		// and the real versions of the libraries from the platform).
+		fmt.Fprintln(w, "LOCAL_COPY_TO_INTERMEDIATE_LIBRARIES := false")
+	})
+}
diff --git a/cc/binary.go b/cc/binary.go
index 5f81866..206237a 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -182,7 +182,7 @@
 
 	if !ctx.toolchain().Bionic() {
 		if ctx.Os() == android.Linux {
-			if binary.Properties.Static_executable == nil && Bool(ctx.AConfig().ProductVariables.HostStaticBinaries) {
+			if binary.Properties.Static_executable == nil && Bool(ctx.Config().ProductVariables.HostStaticBinaries) {
 				binary.Properties.Static_executable = BoolPtr(true)
 			}
 		} else {
@@ -204,7 +204,7 @@
 	flags = binary.baseLinker.linkerFlags(ctx, flags)
 
 	if ctx.Host() && !binary.static() {
-		if !ctx.AConfig().IsEnvTrue("DISABLE_HOST_PIE") {
+		if !ctx.Config().IsEnvTrue("DISABLE_HOST_PIE") {
 			flags.LdFlags = append(flags.LdFlags, "-pie")
 			if ctx.Windows() {
 				flags.LdFlags = append(flags.LdFlags, "-Wl,-e_mainCRTStartup")
diff --git a/cc/builder.go b/cc/builder.go
index a81dc89..de85d6e 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -196,11 +196,19 @@
 
 	_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
 
-	// Abidiff check turned on in advice-only mode. Builds will not fail on abi incompatibilties / extensions.
-	sAbiDiff = pctx.AndroidStaticRule("sAbiDiff",
-		blueprint.RuleParams{
-			Command:     "$sAbiDiffer $allowFlags -lib $libName -arch $arch -check-all-apis -o ${out} -new $in -old $referenceDump",
-			CommandDeps: []string{"$sAbiDiffer"},
+	sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff",
+		func(config android.Config) (blueprint.RuleParams, error) {
+
+			commandStr := "($sAbiDiffer $allowFlags -lib $libName -arch $arch -check-all-apis -o ${out} -new $in -old $referenceDump)"
+			distDir := config.ProductVariables.DistDir
+			if distDir != nil && *distDir != "" {
+				distAbiDiffDir := *distDir + "/abidiffs/"
+				commandStr += "  || (mkdir -p " + distAbiDiffDir + " && cp ${out} " + distAbiDiffDir + " && exit 1)"
+			}
+			return blueprint.RuleParams{
+				Command:     commandStr,
+				CommandDeps: []string{"$sAbiDiffer"},
+			}, nil
 		},
 		"allowFlags", "referenceDump", "libName", "arch")
 
@@ -223,27 +231,28 @@
 }
 
 type builderFlags struct {
-	globalFlags   string
-	arFlags       string
-	asFlags       string
-	cFlags        string
-	toolingCFlags string // A separate set of Cflags for clang LibTooling tools
-	conlyFlags    string
-	cppFlags      string
-	ldFlags       string
-	libFlags      string
-	yaccFlags     string
-	protoFlags    string
-	tidyFlags     string
-	sAbiFlags     string
-	yasmFlags     string
-	aidlFlags     string
-	rsFlags       string
-	toolchain     config.Toolchain
-	clang         bool
-	tidy          bool
-	coverage      bool
-	sAbiDump      bool
+	globalFlags    string
+	arFlags        string
+	asFlags        string
+	cFlags         string
+	toolingCFlags  string // A separate set of Cflags for clang LibTooling tools
+	conlyFlags     string
+	cppFlags       string
+	ldFlags        string
+	libFlags       string
+	yaccFlags      string
+	protoFlags     string
+	protoOutParams string
+	tidyFlags      string
+	sAbiFlags      string
+	yasmFlags      string
+	aidlFlags      string
+	rsFlags        string
+	toolchain      config.Toolchain
+	clang          bool
+	tidy           bool
+	coverage       bool
+	sAbiDump       bool
 
 	systemIncludeFlags string
 
@@ -281,7 +290,7 @@
 
 // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
 func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths,
-	flags builderFlags, deps android.Paths) Objects {
+	flags builderFlags, pathDeps android.Paths, genDeps android.Paths) Objects {
 
 	objFiles := make(android.Paths, len(srcFiles))
 	var tidyFiles android.Paths
@@ -354,7 +363,8 @@
 				Description: "yasm " + srcFile.Rel(),
 				Output:      objFile,
 				Input:       srcFile,
-				OrderOnly:   deps,
+				Implicits:   pathDeps,
+				OrderOnly:   genDeps,
 				Args: map[string]string{
 					"asFlags": flags.yasmFlags,
 				},
@@ -366,7 +376,8 @@
 				Description: "windres " + srcFile.Rel(),
 				Output:      objFile,
 				Input:       srcFile,
-				OrderOnly:   deps,
+				Implicits:   pathDeps,
+				OrderOnly:   genDeps,
 				Args: map[string]string{
 					"windresCmd": gccCmd(flags.toolchain, "windres"),
 					"flags":      flags.toolchain.WindresFlags(),
@@ -434,7 +445,8 @@
 			Output:          objFile,
 			ImplicitOutputs: implicitOutputs,
 			Input:           srcFile,
-			OrderOnly:       deps,
+			Implicits:       pathDeps,
+			OrderOnly:       genDeps,
 			Args: map[string]string{
 				"cFlags": moduleCflags,
 				"ccCmd":  ccCmd,
diff --git a/cc/cc.go b/cc/cc.go
index 384b240..13d0e3b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -116,6 +116,7 @@
 	ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
 	YaccFlags       []string // Flags that apply to Yacc source files
 	protoFlags      []string // Flags that apply to proto source files
+	protoOutParams  []string // Flags that modify the output of proto generated 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
@@ -164,6 +165,10 @@
 	PreventInstall      bool     `blueprint:"mutated"`
 
 	UseVndk bool `blueprint:"mutated"`
+
+	// *.logtags files, to combine together in order to generate the /system/etc/event-log-tags
+	// file
+	Logtags []string
 }
 
 type VendorProperties struct {
@@ -326,9 +331,12 @@
 	flags Flags
 
 	// When calling a linker, if module A depends on module B, then A must precede B in its command
-	// line invocation. staticDepsInLinkOrder stores the proper ordering of all of the transitive
+	// line invocation. depsInLinkOrder stores the proper ordering of all of the transitive
 	// deps of this module
-	staticDepsInLinkOrder android.Paths
+	depsInLinkOrder android.Paths
+
+	// only non-nil when this is a shared library that reuses the objects of a static library
+	staticVariant *Module
 }
 
 func (c *Module) Init() android.Module {
@@ -417,8 +425,9 @@
 	moduleContextImpl
 }
 
-func (ctx *moduleContext) InstallOnVendorPartition() bool {
-	return ctx.ModuleContext.InstallOnVendorPartition() || (ctx.mod.useVndk() && !ctx.mod.isVndk())
+func (ctx *moduleContext) SocSpecific() bool {
+	return ctx.ModuleContext.SocSpecific() ||
+		(ctx.mod.hasVendorVariant() && ctx.mod.useVndk() && !ctx.mod.isVndk())
 }
 
 type moduleContextImpl struct {
@@ -537,7 +546,8 @@
 // orderDeps reorders dependencies into a list such that if module A depends on B, then
 // A will precede B in the resultant list.
 // This is convenient for passing into a linker.
-func orderDeps(directDeps []android.Path, transitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
+// Note that directSharedDeps should be the analogous static library for each shared lib dep
+func orderDeps(directStaticDeps []android.Path, directSharedDeps []android.Path, allTransitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
 	// If A depends on B, then
 	//   Every list containing A will also contain B later in the list
 	//   So, after concatenating all lists, the final instance of B will have come from the same
@@ -545,38 +555,46 @@
 	//   So, the final instance of B will be later in the concatenation than the final A
 	//   So, keeping only the final instance of A and of B ensures that A is earlier in the output
 	//     list than B
-	for _, dep := range directDeps {
+	for _, dep := range directStaticDeps {
 		orderedAllDeps = append(orderedAllDeps, dep)
-		orderedAllDeps = append(orderedAllDeps, transitiveDeps[dep]...)
+		orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
+	}
+	for _, dep := range directSharedDeps {
+		orderedAllDeps = append(orderedAllDeps, dep)
+		orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
 	}
 
 	orderedAllDeps = android.LastUniquePaths(orderedAllDeps)
 
-	// We don't want to add any new dependencies into directDeps (to allow the caller to
+	// We don't want to add any new dependencies into directStaticDeps (to allow the caller to
 	// intentionally exclude or replace any unwanted transitive dependencies), so we limit the
-	// resultant list to only what the caller has chosen to include in directDeps
-	_, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directDeps)
+	// resultant list to only what the caller has chosen to include in directStaticDeps
+	_, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directStaticDeps)
 
 	return orderedAllDeps, orderedDeclaredDeps
 }
 
-func orderStaticModuleDeps(module *Module, deps []*Module) (results []android.Path) {
-	// make map of transitive dependencies
-	transitiveStaticDepNames := make(map[android.Path][]android.Path, len(deps))
-	for _, dep := range deps {
-		transitiveStaticDepNames[dep.outputFile.Path()] = dep.staticDepsInLinkOrder
+func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*Module) (results []android.Path) {
+	// convert Module to Path
+	allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
+	staticDepFiles := []android.Path{}
+	for _, dep := range staticDeps {
+		allTransitiveDeps[dep.outputFile.Path()] = dep.depsInLinkOrder
+		staticDepFiles = append(staticDepFiles, dep.outputFile.Path())
 	}
-	// get the output file for each declared dependency
-	depFiles := []android.Path{}
-	for _, dep := range deps {
-		depFiles = append(depFiles, dep.outputFile.Path())
+	sharedDepFiles := []android.Path{}
+	for _, sharedDep := range sharedDeps {
+		staticAnalogue := sharedDep.staticVariant
+		if staticAnalogue != nil {
+			allTransitiveDeps[staticAnalogue.outputFile.Path()] = staticAnalogue.depsInLinkOrder
+			sharedDepFiles = append(sharedDepFiles, staticAnalogue.outputFile.Path())
+		}
 	}
 
 	// reorder the dependencies based on transitive dependencies
-	module.staticDepsInLinkOrder, results = orderDeps(depFiles, transitiveStaticDepNames)
+	module.depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
 
 	return results
-
 }
 
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
@@ -933,7 +951,7 @@
 			clang = true
 		}
 
-		if ctx.Device() && ctx.AConfig().DeviceUsesClang() {
+		if ctx.Device() && ctx.Config().DeviceUsesClang() {
 			clang = true
 		}
 	}
@@ -1019,6 +1037,27 @@
 		ctx.ModuleErrorf("links %q built against newer API version %q",
 			ctx.OtherModuleName(to), String(to.Properties.Sdk_version))
 	}
+
+	// Also check that the two STL choices are compatible.
+	fromStl := from.stl.Properties.SelectedStl
+	toStl := to.stl.Properties.SelectedStl
+	if fromStl == "" || toStl == "" {
+		// Libraries that don't use the STL are unrestricted.
+		return
+	}
+
+	if fromStl == "ndk_system" || toStl == "ndk_system" {
+		// We can be permissive with the system "STL" since it is only the C++
+		// ABI layer, but in the future we should make sure that everyone is
+		// using either libc++ or nothing.
+		return
+	}
+
+	if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) {
+		ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q",
+			from.stl.Properties.SelectedStl, ctx.OtherModuleName(to),
+			to.stl.Properties.SelectedStl)
+	}
 }
 
 // Convert dependencies to paths.  Returns a PathDeps containing paths
@@ -1026,6 +1065,7 @@
 	var depPaths PathDeps
 
 	directStaticDeps := []*Module{}
+	directSharedDeps := []*Module{}
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
@@ -1092,6 +1132,7 @@
 		// re-exporting flags
 		if depTag == reuseObjTag {
 			if l, ok := ccDep.compiler.(libraryInterface); ok {
+				c.staticVariant = ccDep
 				objs, flags, deps := l.reuseObjs()
 				depPaths.Objs = depPaths.Objs.Append(objs)
 				depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
@@ -1130,6 +1171,7 @@
 			ptr = &depPaths.SharedLibs
 			depPtr = &depPaths.SharedLibsDeps
 			depFile = ccDep.linker.(libraryInterface).toc()
+			directSharedDeps = append(directSharedDeps, ccDep)
 		case lateSharedDepTag, ndkLateStubDepTag:
 			ptr = &depPaths.LateSharedLibs
 			depPtr = &depPaths.LateSharedLibsDeps
@@ -1221,7 +1263,7 @@
 	})
 
 	// use the ordered dependencies as this module's dependencies
-	depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps)...)
+	depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps, directSharedDeps)...)
 
 	// Dedup exported flags from dependencies
 	depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
@@ -1357,11 +1399,11 @@
 
 	if genrule, ok := mctx.Module().(*genrule.Module); ok {
 		if props, ok := genrule.Extra.(*VendorProperties); ok {
-			if !mctx.DeviceConfig().CompileVndk() {
+			if mctx.DeviceConfig().VndkVersion() == "" {
 				mctx.CreateVariations(coreMode)
 			} else if Bool(props.Vendor_available) {
 				mctx.CreateVariations(coreMode, vendorMode)
-			} else if mctx.InstallOnVendorPartition() {
+			} else if mctx.SocSpecific() || mctx.DeviceSpecific() {
 				mctx.CreateVariations(vendorMode)
 			} else {
 				mctx.CreateVariations(coreMode)
@@ -1375,9 +1417,9 @@
 	}
 
 	// Sanity check
-	if m.VendorProperties.Vendor_available != nil && mctx.InstallOnVendorPartition() {
+	if m.VendorProperties.Vendor_available != nil && (mctx.SocSpecific() || mctx.DeviceSpecific()) {
 		mctx.PropertyErrorf("vendor_available",
-			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
+			"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
 		return
 	}
 	if vndk := m.vndkdep; vndk != nil {
@@ -1393,7 +1435,7 @@
 		}
 	}
 
-	if !mctx.DeviceConfig().CompileVndk() {
+	if mctx.DeviceConfig().VndkVersion() == "" {
 		// If the device isn't compiling against the VNDK, we always
 		// use the core mode.
 		mctx.CreateVariations(coreMode)
@@ -1403,7 +1445,15 @@
 		mctx.CreateVariations(vendorMode)
 	} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
 		// ... and LL-NDK headers as well
-		mctx.CreateVariations(vendorMode)
+		mod := mctx.CreateVariations(vendorMode)
+		vendor := mod[0].(*Module)
+		vendor.Properties.UseVndk = true
+	} else if _, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
+		// PRODUCT_EXTRA_VNDK_VERSIONS.
+		mod := mctx.CreateVariations(vendorMode)
+		vendor := mod[0].(*Module)
+		vendor.Properties.UseVndk = true
 	} else if m.hasVendorVariant() {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
@@ -1411,8 +1461,8 @@
 		vendor := mod[1].(*Module)
 		vendor.Properties.UseVndk = true
 		squashVendorSrcs(vendor)
-	} else if mctx.InstallOnVendorPartition() && String(m.Properties.Sdk_version) == "" {
-		// This will be available in /vendor only
+	} else if (mctx.SocSpecific() || mctx.DeviceSpecific()) && String(m.Properties.Sdk_version) == "" {
+		// This will be available in /vendor (or /odm) only
 		mod := mctx.CreateVariations(vendorMode)
 		vendor := mod[0].(*Module)
 		vendor.Properties.UseVndk = true
@@ -1426,10 +1476,10 @@
 }
 
 func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
-	if ctx.AConfig().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
+	if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
 		return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
 	}
-	return ctx.AConfig().PlatformSdkVersion()
+	return ctx.Config().PlatformSdkVersion()
 }
 
 var Bool = proptools.Bool
diff --git a/cc/cc_test.go b/cc/cc_test.go
index bdc8c17..15e45d0 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -61,6 +61,7 @@
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
+	ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -138,6 +139,7 @@
 		"bar.c":      nil,
 		"a.proto":    nil,
 		"b.aidl":     nil,
+		"my_include": nil,
 	})
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
@@ -289,7 +291,11 @@
 var staticLinkDepOrderTestCases = []struct {
 	// This is a string representation of a map[moduleName][]moduleDependency .
 	// It models the dependencies declared in an Android.bp file.
-	in string
+	inStatic string
+
+	// This is a string representation of a map[moduleName][]moduleDependency .
+	// It models the dependencies declared in an Android.bp file.
+	inShared string
 
 	// allOrdered is a string representation of a map[moduleName][]moduleDependency .
 	// The keys of allOrdered specify which modules we would like to check.
@@ -305,82 +311,99 @@
 }{
 	// Simple tests
 	{
-		in:         "",
+		inStatic:   "",
 		outOrdered: "",
 	},
 	{
-		in:         "a:",
+		inStatic:   "a:",
 		outOrdered: "a:",
 	},
 	{
-		in:         "a:b; b:",
+		inStatic:   "a:b; b:",
 		outOrdered: "a:b; b:",
 	},
 	// Tests of reordering
 	{
 		// diamond example
-		in:         "a:d,b,c; b:d; c:d; d:",
+		inStatic:   "a:d,b,c; b:d; c:d; d:",
 		outOrdered: "a:b,c,d; b:d; c:d; d:",
 	},
 	{
 		// somewhat real example
-		in:         "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
+		inStatic:   "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
 		outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
 	},
 	{
 		// multiple reorderings
-		in:         "a:b,c,d,e; d:b; e:c",
+		inStatic:   "a:b,c,d,e; d:b; e:c",
 		outOrdered: "a:d,b,e,c; d:b; e:c",
 	},
 	{
 		// should reorder without adding new transitive dependencies
-		in:         "bin:lib2,lib1;             lib1:lib2,liboptional",
+		inStatic:   "bin:lib2,lib1;             lib1:lib2,liboptional",
 		allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
 		outOrdered: "bin:lib1,lib2;             lib1:lib2,liboptional",
 	},
 	{
 		// multiple levels of dependencies
-		in:         "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
+		inStatic:   "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
 		allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
 		outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
 	},
+	// shared dependencies
+	{
+		// Note that this test doesn't recurse, to minimize the amount of logic it tests.
+		// So, we don't actually have to check that a shared dependency of c will change the order
+		// of a library that depends statically on b and on c.  We only need to check that if c has
+		// a shared dependency on b, that that shows up in allOrdered.
+		inShared:   "c:b",
+		allOrdered: "c:b",
+		outOrdered: "c:",
+	},
+	{
+		// This test doesn't actually include any shared dependencies but it's a reminder of what
+		// the second phase of the above test would look like
+		inStatic:   "a:b,c; c:b",
+		allOrdered: "a:c,b; c:b",
+		outOrdered: "a:c,b; c:b",
+	},
 	// tiebreakers for when two modules specifying different orderings and there is no dependency
 	// to dictate an order
 	{
 		// if the tie is between two modules at the end of a's deps, then a's order wins
-		in:         "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
+		inStatic:   "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
 		outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
 	},
 	{
 		// if the tie is between two modules at the start of a's deps, then c's order is used
-		in:         "a1:d,e,b1,c1; b1:d,e; c1:e,d;   a2:d,e,b2,c2; b2:d,e; c2:d,e",
+		inStatic:   "a1:d,e,b1,c1; b1:d,e; c1:e,d;   a2:d,e,b2,c2; b2:d,e; c2:d,e",
 		outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d;   a2:b2,c2,d,e; b2:d,e; c2:d,e",
 	},
 	// Tests involving duplicate dependencies
 	{
 		// simple duplicate
-		in:         "a:b,c,c,b",
+		inStatic:   "a:b,c,c,b",
 		outOrdered: "a:c,b",
 	},
 	{
 		// duplicates with reordering
-		in:         "a:b,c,d,c; c:b",
+		inStatic:   "a:b,c,d,c; c:b",
 		outOrdered: "a:d,c,b",
 	},
 	// Tests to confirm the nonexistence of infinite loops.
 	// These cases should never happen, so as long as the test terminates and the
 	// result is deterministic then that should be fine.
 	{
-		in:         "a:a",
+		inStatic:   "a:a",
 		outOrdered: "a:a",
 	},
 	{
-		in:         "a:b;   b:c;   c:a",
+		inStatic:   "a:b;   b:c;   c:a",
 		allOrdered: "a:b,c; b:c,a; c:a,b",
 		outOrdered: "a:b;   b:c;   c:a",
 	},
 	{
-		in:         "a:b,c;   b:c,a;   c:a,b",
+		inStatic:   "a:b,c;   b:c,a;   c:a,b",
 		allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
 		outOrdered: "a:c,b;   b:a,c;   c:b,a",
 	},
@@ -427,43 +450,47 @@
 	return modulesInOrder, allDeps
 }
 
-func TestStaticLinkDependencyOrdering(t *testing.T) {
+func TestLinkReordering(t *testing.T) {
 	for _, testCase := range staticLinkDepOrderTestCases {
 		errs := []string{}
 
 		// parse testcase
-		_, givenTransitiveDeps := parseModuleDeps(testCase.in)
+		_, givenTransitiveDeps := parseModuleDeps(testCase.inStatic)
 		expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
 		if testCase.allOrdered == "" {
 			// allow the test case to skip specifying allOrdered
 			testCase.allOrdered = testCase.outOrdered
 		}
 		_, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
+		_, givenAllSharedDeps := parseModuleDeps(testCase.inShared)
 
 		// For each module whose post-reordered dependencies were specified, validate that
 		// reordering the inputs produces the expected outputs.
 		for _, moduleName := range expectedModuleNames {
 			moduleDeps := givenTransitiveDeps[moduleName]
-			orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
+			givenSharedDeps := givenAllSharedDeps[moduleName]
+			orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenSharedDeps, givenTransitiveDeps)
 
 			correctAllOrdered := expectedAllDeps[moduleName]
 			if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
 				errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
-					"\nInput:    %q"+
+					"\nin static:%q"+
+					"\nin shared:%q"+
 					"\nmodule:   %v"+
 					"\nexpected: %s"+
 					"\nactual:   %s",
-					testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
+					testCase.inStatic, testCase.inShared, moduleName, correctAllOrdered, orderedAllDeps))
 			}
 
 			correctOutputDeps := expectedTransitiveDeps[moduleName]
 			if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
 				errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
-					"\nInput:    %q"+
+					"\nin static:%q"+
+					"\nin shared:%q"+
 					"\nmodule:   %v"+
 					"\nexpected: %s"+
 					"\nactual:   %s",
-					testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
+					testCase.inStatic, testCase.inShared, moduleName, correctOutputDeps, orderedDeclaredDeps))
 			}
 		}
 
@@ -493,7 +520,7 @@
 	return paths
 }
 
-func TestLibDeps(t *testing.T) {
+func TestStaticLibDepReordering(t *testing.T) {
 	ctx := testCc(t, `
 	cc_library {
 		name: "a",
@@ -514,7 +541,7 @@
 
 	variant := "android_arm64_armv8-a_core_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := moduleA.staticDepsInLinkOrder
+	actual := moduleA.depsInLinkOrder
 	expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
 
 	if !reflect.DeepEqual(actual, expected) {
@@ -527,6 +554,65 @@
 	}
 }
 
+func TestStaticLibDepReorderingWithShared(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library {
+		name: "a",
+		static_libs: ["b", "c"],
+	}
+	cc_library {
+		name: "b",
+	}
+	cc_library {
+		name: "c",
+		shared_libs: ["b"],
+	}
+
+	`)
+
+	variant := "android_arm64_armv8-a_core_static"
+	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
+	actual := moduleA.depsInLinkOrder
+	expected := getOutputPaths(ctx, variant, []string{"c", "b"})
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Errorf("staticDeps orderings did not account for shared libs"+
+			"\nactual:   %v"+
+			"\nexpected: %v",
+			actual,
+			expected,
+		)
+	}
+}
+
+func TestLlndkHeaders(t *testing.T) {
+	ctx := testCc(t, `
+	llndk_headers {
+		name: "libllndk_headers",
+		export_include_dirs: ["my_include"],
+	}
+	llndk_library {
+		name: "libllndk",
+		export_llndk_headers: ["libllndk_headers"],
+	}
+	cc_library {
+		name: "libvendor",
+		shared_libs: ["libllndk"],
+		vendor: true,
+		srcs: ["foo.c"],
+		no_libgcc : true,
+		nocrt : true,
+	}
+	`)
+
+	// _static variant is used since _shared reuses *.o from the static variant
+	cc := ctx.ModuleForTests("libvendor", "android_arm_armv7-a-neon_vendor_static").Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, "-Imy_include") {
+		t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags)
+	}
+}
+
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index 13a2e8e..c25578e 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -23,8 +23,6 @@
 	"path"
 	"path/filepath"
 	"strings"
-
-	"github.com/google/blueprint"
 )
 
 // This singleton generates CMakeLists.txt files. It does so for each blueprint Android.bp resulting in a cc.Module
@@ -35,7 +33,7 @@
 	android.RegisterSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
 }
 
-func cMakeListsGeneratorSingleton() blueprint.Singleton {
+func cMakeListsGeneratorSingleton() android.Singleton {
 	return &cmakelistsGeneratorSingleton{}
 }
 
@@ -57,14 +55,14 @@
 // This is done to ease investigating bug reports.
 var outputDebugInfo = false
 
-func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	if getEnvVariable(envVariableGenerateCMakeLists, ctx) != envVariableTrue {
 		return
 	}
 
 	outputDebugInfo = (getEnvVariable(envVariableGenerateDebugInfo, ctx) == envVariableTrue)
 
-	ctx.VisitAllModules(func(module blueprint.Module) {
+	ctx.VisitAllModules(func(module android.Module) {
 		if ccModule, ok := module.(*Module); ok {
 			if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
 				generateCLionProject(compiledModule, ctx, ccModule)
@@ -81,10 +79,10 @@
 	return
 }
 
-func getEnvVariable(name string, ctx blueprint.SingletonContext) string {
+func getEnvVariable(name string, ctx android.SingletonContext) string {
 	// Using android.Config.Getenv instead of os.getEnv to guarantee soong will
 	// re-run in case this environment variable changes.
-	return ctx.Config().(android.Config).Getenv(name)
+	return ctx.Config().Getenv(name)
 }
 
 func exists(path string) bool {
@@ -116,7 +114,7 @@
 	return nil
 }
 
-func generateCLionProject(compiledModule CompiledInterface, ctx blueprint.SingletonContext, ccModule *Module) {
+func generateCLionProject(compiledModule CompiledInterface, ctx android.SingletonContext, ccModule *Module) {
 	srcs := compiledModule.Srcs()
 	if len(srcs) == 0 {
 		return
@@ -287,7 +285,7 @@
 	return flag
 }
 
-func parseCompilerParameters(params []string, ctx blueprint.SingletonContext, f *os.File) compilerParameters {
+func parseCompilerParameters(params []string, ctx android.SingletonContext, f *os.File) compilerParameters {
 	var compilerParameters = makeCompilerParameters()
 
 	for i, str := range params {
@@ -388,7 +386,7 @@
 	c1.flags = append(c1.flags, c2.flags...)
 }
 
-func evalVariable(ctx blueprint.SingletonContext, str string) (string, error) {
+func evalVariable(ctx android.SingletonContext, str string) (string, error) {
 	evaluated, err := ctx.Eval(pctx, str)
 	if err == nil {
 		return evaluated, nil
@@ -396,7 +394,7 @@
 	return "", err
 }
 
-func getCMakeListsForModule(module *Module, ctx blueprint.SingletonContext) string {
+func getCMakeListsForModule(module *Module, ctx android.SingletonContext) string {
 	return filepath.Join(getAndroidSrcRootDirectory(ctx),
 		cLionOutputProjectsDirectory,
 		path.Dir(ctx.BlueprintFile(module)),
@@ -406,7 +404,7 @@
 		cMakeListsFilename)
 }
 
-func getAndroidSrcRootDirectory(ctx blueprint.SingletonContext) string {
+func getAndroidSrcRootDirectory(ctx android.SingletonContext) string {
 	srcPath, _ := filepath.Abs(android.PathForSource(ctx).String())
 	return srcPath
 }
diff --git a/cc/compiler.go b/cc/compiler.go
index ca68a00..7e8e8b8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -148,6 +148,9 @@
 
 	// Stores the original list of source files before being cleared by library reuse
 	OriginalSrcs []string `blueprint:"mutated"`
+
+	// Build and link with OpenMP
+	Openmp *bool `android:"arch_variant"`
 }
 
 func NewBaseCompiler() *baseCompiler {
@@ -157,7 +160,8 @@
 type baseCompiler struct {
 	Properties BaseCompilerProperties
 	Proto      android.ProtoProperties
-	deps       android.Paths
+	genDeps    android.Paths
+	pathDeps   android.Paths
 	flags      builderFlags
 
 	// Sources that were passed to the C/C++ compiler
@@ -203,9 +207,28 @@
 		deps = protoDeps(ctx, deps, &compiler.Proto, Bool(compiler.Properties.Proto.Static))
 	}
 
+	if Bool(compiler.Properties.Openmp) {
+		deps.StaticLibs = append(deps.StaticLibs, "libomp")
+	}
+
 	return deps
 }
 
+// Return true if the module is in the WarningAllowedProjects.
+func warningsAreAllowed(subdir string) bool {
+	subdir += "/"
+	for _, prefix := range config.WarningAllowedProjects {
+		if strings.HasPrefix(subdir, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
+func addToModuleList(ctx ModuleContext, list string, module string) {
+	getWallWerrorMap(ctx.Config(), list).Store(module, true)
+}
+
 // Create a Flags struct that collects the compile flags from global values,
 // per-target values, module type values, and per-module Blueprints properties
 func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -345,7 +368,7 @@
 			fmt.Sprintf("${config.%sGlobalCflags}", hod))
 	}
 
-	if Bool(ctx.AConfig().ProductVariables.Brillo) {
+	if Bool(ctx.Config().ProductVariables.Brillo) {
 		flags.GlobalFlags = append(flags.GlobalFlags, "-D__BRILLO__")
 	}
 
@@ -464,6 +487,24 @@
 		flags = rsFlags(ctx, flags, &compiler.Properties)
 	}
 
+	if len(compiler.Properties.Srcs) > 0 {
+		module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+		if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
+			addToModuleList(ctx, modulesUsingWnoError, module)
+		} else if !inList("-Werror", flags.CFlags) && !inList("-Werror", flags.CppFlags) {
+			if warningsAreAllowed(ctx.ModuleDir()) {
+				addToModuleList(ctx, modulesAddedWall, module)
+				flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
+			} else {
+				flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
+			}
+		}
+	}
+
+	if Bool(compiler.Properties.Openmp) {
+		flags.CFlags = append(flags.CFlags, "-fopenmp")
+	}
+
 	return flags
 }
 
@@ -493,7 +534,7 @@
 	if ctx.useSdk() {
 		// The NDK sysroot timestamp file depends on all the NDK sysroot files
 		// (headers and libraries).
-		return android.Paths{getNdkSysrootTimestampFile(ctx)}
+		return android.Paths{getNdkBaseTimestampFile(ctx)}
 	}
 	return nil
 }
@@ -507,17 +548,16 @@
 	srcs := append(android.Paths(nil), compiler.srcsBeforeGen...)
 
 	srcs, genDeps := genSources(ctx, srcs, buildFlags)
-
-	pathDeps = append(pathDeps, genDeps...)
 	pathDeps = append(pathDeps, flags.CFlagsDeps...)
 
-	compiler.deps = pathDeps
+	compiler.pathDeps = pathDeps
+	compiler.genDeps = genDeps
 
 	// Save src, buildFlags and context
 	compiler.srcs = srcs
 
 	// Compile files listed in c.Properties.Srcs into objects
-	objs := compileObjs(ctx, buildFlags, "", srcs, compiler.deps)
+	objs := compileObjs(ctx, buildFlags, "", srcs, pathDeps, genDeps)
 
 	if ctx.Failed() {
 		return Objects{}
@@ -528,7 +568,7 @@
 
 // Compile a list of source files into objects a specified subdirectory
 func compileObjs(ctx android.ModuleContext, flags builderFlags,
-	subdir string, srcFiles, deps android.Paths) Objects {
+	subdir string, srcFiles, pathDeps android.Paths, genDeps android.Paths) Objects {
 
-	return TransformSourceToObj(ctx, subdir, srcFiles, flags, deps)
+	return TransformSourceToObj(ctx, subdir, srcFiles, flags, pathDeps, genDeps)
 }
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 0f28d1e..fda4f9d 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -115,7 +115,9 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"kryo": []string{
-			"-mcpu=cortex-a15",
+			// Use cortex-a53 because the GNU assembler doesn't recognize -mcpu=kryo
+			// even though clang does.
+			"-mcpu=cortex-a53",
 			"-mfpu=neon-fp-armv8",
 			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
 			// don't advertise.
@@ -158,10 +160,9 @@
 	android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon")
 	android.RegisterArchVariantFeatures(android.Arm, "armv8-a", "neon")
 
-	// Krait and Kryo targets are not supported by GCC, but are supported by Clang,
-	// so override the definitions when building modules with Clang.
+	// Krait is not supported by GCC, but is supported by Clang, so
+	// override the definitions when building modules with Clang.
 	replaceFirst(armClangCpuVariantCflags["krait"], "-mcpu=cortex-a15", "-mcpu=krait")
-	replaceFirst(armClangCpuVariantCflags["kryo"], "-mcpu=cortex-a15", "-mcpu=krait")
 
 	// The reason we use "-march=armv8-a+crc", instead of "-march=armv8-a", for
 	// gcc is the latter would conflict with any specified/supported -mcpu!
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 2ef153b..302c68e 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -77,6 +77,9 @@
 	"-fno-inline-functions-called-once",
 	"-mfpmath=sse",
 	"-mbionic",
+
+	// windows
+	"--enable-stdcall-fixup",
 })
 
 var ClangLibToolingUnknownCflags = []string{
diff --git a/cc/config/global.go b/cc/config/global.go
index 44ad30b..c10c60a 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -118,6 +118,16 @@
 	ClangDefaultBase         = "prebuilts/clang/host"
 	ClangDefaultVersion      = "clang-4393122"
 	ClangDefaultShortVersion = "5.0.1"
+
+	WarningAllowedProjects = []string{
+		"device/",
+		"vendor/",
+	}
+
+	// Some Android.mk files still have warnings.
+	WarningAllowedOldProjects = []string{
+		"hardware/qcom/",
+	}
 )
 
 var pctx = android.NewPackageContext("android/soong/cc/config")
@@ -171,14 +181,14 @@
 		[]string{"libnativehelper/include_deprecated"})
 
 	pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
-	pctx.VariableFunc("ClangBase", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("LLVM_PREBUILTS_BASE"); override != "" {
+	pctx.VariableFunc("ClangBase", func(config android.Config) (string, error) {
+		if override := config.Getenv("LLVM_PREBUILTS_BASE"); override != "" {
 			return override, nil
 		}
 		return "${ClangDefaultBase}", nil
 	})
-	pctx.VariableFunc("ClangVersion", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("LLVM_PREBUILTS_VERSION"); override != "" {
+	pctx.VariableFunc("ClangVersion", func(config android.Config) (string, error) {
+		if override := config.Getenv("LLVM_PREBUILTS_VERSION"); override != "" {
 			return override, nil
 		}
 		return ClangDefaultVersion, nil
@@ -186,8 +196,8 @@
 	pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
 	pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
 
-	pctx.VariableFunc("ClangShortVersion", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("LLVM_RELEASE_VERSION"); override != "" {
+	pctx.VariableFunc("ClangShortVersion", func(config android.Config) (string, error) {
+		if override := config.Getenv("LLVM_RELEASE_VERSION"); override != "" {
 			return override, nil
 		}
 		return ClangDefaultShortVersion, nil
@@ -213,8 +223,8 @@
 			"frameworks/rs/script_api/include",
 		})
 
-	pctx.VariableFunc("CcWrapper", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("CC_WRAPPER"); override != "" {
+	pctx.VariableFunc("CcWrapper", func(config android.Config) (string, error) {
+		if override := config.Getenv("CC_WRAPPER"); override != "" {
 			return override + " ", nil
 		}
 		return "", nil
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index a2fa5a2..76a5f9e 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -25,8 +25,8 @@
 	// Global tidy checks include only google*, performance*,
 	// and misc-macro-parentheses, but not google-readability*
 	// or google-runtime-references.
-	pctx.VariableFunc("TidyDefaultGlobalChecks", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
+	pctx.VariableFunc("TidyDefaultGlobalChecks", func(config android.Config) (string, error) {
+		if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
 			return override, nil
 		}
 		return strings.Join([]string{
@@ -41,8 +41,8 @@
 
 	// There are too many clang-tidy warnings in external and vendor projects.
 	// Enable only some google checks for these projects.
-	pctx.VariableFunc("TidyExternalVendorChecks", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
+	pctx.VariableFunc("TidyExternalVendorChecks", func(config android.Config) (string, error) {
+		if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
 			return override, nil
 		}
 		return strings.Join([]string{
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 8d805c9..dbaa6fa 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -107,25 +107,25 @@
 )
 
 func init() {
-	pctx.VariableFunc("macSdkPath", func(config interface{}) (string, error) {
-		xcodeselect := config.(android.Config).HostSystemTool("xcode-select")
+	pctx.VariableFunc("macSdkPath", func(config android.Config) (string, error) {
+		xcodeselect := config.HostSystemTool("xcode-select")
 		bytes, err := exec.Command(xcodeselect, "--print-path").Output()
 		return strings.TrimSpace(string(bytes)), err
 	})
-	pctx.VariableFunc("macSdkRoot", func(config interface{}) (string, error) {
-		return xcrunSdk(config.(android.Config), "--show-sdk-path")
+	pctx.VariableFunc("macSdkRoot", func(config android.Config) (string, error) {
+		return xcrunSdk(config, "--show-sdk-path")
 	})
 	pctx.StaticVariable("macMinVersion", "10.8")
-	pctx.VariableFunc("MacArPath", func(config interface{}) (string, error) {
-		return xcrun(config.(android.Config), "--find", "ar")
+	pctx.VariableFunc("MacArPath", func(config android.Config) (string, error) {
+		return xcrun(config, "--find", "ar")
 	})
 
-	pctx.VariableFunc("MacStripPath", func(config interface{}) (string, error) {
-		return xcrun(config.(android.Config), "--find", "strip")
+	pctx.VariableFunc("MacStripPath", func(config android.Config) (string, error) {
+		return xcrun(config, "--find", "strip")
 	})
 
-	pctx.VariableFunc("MacToolPath", func(config interface{}) (string, error) {
-		path, err := xcrun(config.(android.Config), "--find", "ld")
+	pctx.VariableFunc("MacToolPath", func(config android.Config) (string, error) {
+		path, err := xcrun(config, "--find", "ld")
 		return filepath.Dir(path), err
 	})
 
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index c9bafe6..016e711 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -41,15 +41,30 @@
 
 		"--sysroot ${WindowsGccRoot}/${WindowsGccTriple}",
 	}
+	windowsClangCflags = append(ClangFilterUnknownCflags(windowsCflags), []string{}...)
 
 	windowsIncludeFlags = []string{
 		"-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include",
 		"-isystem ${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3/include",
 	}
 
+	windowsClangCppflags = []string{
+		"-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3",
+		"-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3/backward",
+	}
+
+	windowsX86ClangCppflags = []string{
+		"-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3/${WindowsGccTriple}/32",
+	}
+
+	windowsX8664ClangCppflags = []string{
+		"-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3/${WindowsGccTriple}",
+	}
+
 	windowsLdflags = []string{
 		"--enable-stdcall-fixup",
 	}
+	windowsClangLdflags = append(ClangFilterUnknownCflags(windowsLdflags), []string{}...)
 
 	windowsX86Cflags = []string{
 		"-m32",
@@ -64,11 +79,21 @@
 		"-Wl,--large-address-aware",
 		"-L${WindowsGccRoot}/${WindowsGccTriple}/lib32",
 	}
+	windowsX86ClangLdflags = append(ClangFilterUnknownCflags(windowsX86Ldflags), []string{
+		"-B${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3/32",
+		"-L${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3/32",
+		"-B${WindowsGccRoot}/${WindowsGccTriple}/lib32",
+	}...)
 
 	windowsX8664Ldflags = []string{
 		"-m64",
 		"-L${WindowsGccRoot}/${WindowsGccTriple}/lib64",
 	}
+	windowsX8664ClangLdflags = append(ClangFilterUnknownCflags(windowsX8664Ldflags), []string{
+		"-B${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3",
+		"-L${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3",
+		"-B${WindowsGccRoot}/${WindowsGccTriple}/lib64",
+	}...)
 
 	windowsAvailableLibraries = addPrefix([]string{
 		"gdi32",
@@ -101,11 +126,24 @@
 	pctx.StaticVariable("WindowsCflags", strings.Join(windowsCflags, " "))
 	pctx.StaticVariable("WindowsLdflags", strings.Join(windowsLdflags, " "))
 
+	pctx.StaticVariable("WindowsClangCflags", strings.Join(windowsClangCflags, " "))
+	pctx.StaticVariable("WindowsClangLdflags", strings.Join(windowsClangLdflags, " "))
+	pctx.StaticVariable("WindowsClangCppflags", strings.Join(windowsClangCppflags, " "))
+
 	pctx.StaticVariable("WindowsX86Cflags", strings.Join(windowsX86Cflags, " "))
 	pctx.StaticVariable("WindowsX8664Cflags", strings.Join(windowsX8664Cflags, " "))
 	pctx.StaticVariable("WindowsX86Ldflags", strings.Join(windowsX86Ldflags, " "))
 	pctx.StaticVariable("WindowsX8664Ldflags", strings.Join(windowsX8664Ldflags, " "))
 
+	pctx.StaticVariable("WindowsX86ClangCflags",
+		strings.Join(ClangFilterUnknownCflags(windowsX86Cflags), " "))
+	pctx.StaticVariable("WindowsX8664ClangCflags",
+		strings.Join(ClangFilterUnknownCflags(windowsX8664Cflags), " "))
+	pctx.StaticVariable("WindowsX86ClangLdflags", strings.Join(windowsX86ClangLdflags, " "))
+	pctx.StaticVariable("WindowsX8664ClangLdflags", strings.Join(windowsX8664ClangLdflags, " "))
+	pctx.StaticVariable("WindowsX86ClangCppflags", strings.Join(windowsX86ClangCppflags, " "))
+	pctx.StaticVariable("WindowsX8664ClangCppflags", strings.Join(windowsX8664ClangCppflags, " "))
+
 	pctx.StaticVariable("WindowsIncludeFlags", strings.Join(windowsIncludeFlags, " "))
 }
 
@@ -179,20 +217,36 @@
 	return false
 }
 
-func (t *toolchainWindows) ClangTriple() string {
-	panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX86) ClangTriple() string {
+	return "i686-windows-gnu"
 }
 
-func (t *toolchainWindows) ClangCflags() string {
-	panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX8664) ClangTriple() string {
+	return "x86_64-pc-windows-gnu"
 }
 
-func (t *toolchainWindows) ClangCppflags() string {
-	panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX86) ClangCflags() string {
+	return "${config.WindowsClangCflags} ${config.WindowsX86ClangCflags}"
 }
 
-func (t *toolchainWindows) ClangLdflags() string {
-	panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX8664) ClangCflags() string {
+	return "${config.WindowsClangCflags} ${config.WindowsX8664ClangCflags}"
+}
+
+func (t *toolchainWindowsX86) ClangCppflags() string {
+	return "${config.WindowsClangCppflags} ${config.WindowsX86ClangCppflags}"
+}
+
+func (t *toolchainWindowsX8664) ClangCppflags() string {
+	return "${config.WindowsClangCppflags} ${config.WindowsX8664ClangCppflags}"
+}
+
+func (t *toolchainWindowsX86) ClangLdflags() string {
+	return "${config.WindowsClangLdflags} ${config.WindowsX86ClangLdflags}"
+}
+
+func (t *toolchainWindowsX8664) ClangLdflags() string {
+	return "${config.WindowsClangLdflags} ${config.WindowsX8664ClangLdflags}"
 }
 
 func (t *toolchainWindows) ShlibSuffix() string {
diff --git a/cc/gen.go b/cc/gen.go
index 15b37b5..e9d1e2a 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -153,7 +153,8 @@
 			srcFiles[i] = cppFile
 			genLex(ctx, srcFile, cppFile)
 		case ".proto":
-			ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags)
+			ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags,
+				buildFlags.protoOutParams)
 			srcFiles[i] = ccFile
 			deps = append(deps, headerFile)
 		case ".aidl":
diff --git a/cc/library.go b/cc/library.go
index 192496a..9bd12a9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -85,9 +85,6 @@
 	VariantIsShared bool `blueprint:"mutated"`
 	// This variant is static
 	VariantIsStatic bool `blueprint:"mutated"`
-	// Location of the static library in the sysroot. Empty if the library is
-	// not included in the NDK.
-	NdkSysrootPath string `blueprint:"mutated"`
 }
 
 type FlagExporterProperties struct {
@@ -246,6 +243,10 @@
 	// Source Abi Diff
 	sAbiDiff android.OptionalPath
 
+	// Location of the static library in the sysroot. Empty if the library is
+	// not included in the NDK.
+	ndkSysrootPath android.Path
+
 	// Decorated interafaces
 	*baseCompiler
 	*baseLinker
@@ -383,11 +384,11 @@
 	if library.static() {
 		srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
 		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
-			srcs, library.baseCompiler.deps))
+			srcs, library.baseCompiler.pathDeps, library.baseCompiler.genDeps))
 	} else if library.shared() {
 		srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
 		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
-			srcs, library.baseCompiler.deps))
+			srcs, library.baseCompiler.pathDeps, library.baseCompiler.genDeps))
 	}
 
 	return objs
@@ -670,8 +671,8 @@
 			}
 			library.reexportFlags(flags)
 			library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
-			library.reexportDeps(library.baseCompiler.deps) // TODO: restrict to aidl deps
-			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.deps...)
+			library.reexportDeps(library.baseCompiler.genDeps) // TODO: restrict to aidl deps
+			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.genDeps...)
 		}
 	}
 
@@ -683,8 +684,8 @@
 			}
 			library.reexportFlags(flags)
 			library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
-			library.reexportDeps(library.baseCompiler.deps) // TODO: restrict to proto deps
-			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.deps...)
+			library.reexportDeps(library.baseCompiler.genDeps) // TODO: restrict to proto deps
+			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.genDeps...)
 		}
 	}
 
@@ -719,19 +720,21 @@
 
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if library.shared() {
-		if ctx.Device() {
-			if ctx.useVndk() {
-				if ctx.isVndkSp() {
-					library.baseInstaller.subDir = "vndk-sp"
-				} else if ctx.isVndk() {
-					library.baseInstaller.subDir = "vndk"
-				}
+		if ctx.Device() && ctx.useVndk() {
+			if ctx.isVndkSp() {
+				library.baseInstaller.subDir = "vndk-sp"
+			} else if ctx.isVndk() {
+				library.baseInstaller.subDir = "vndk"
+			}
+			if ctx.isVndk() && ctx.DeviceConfig().PlatformVndkVersion() != "current" {
+				library.baseInstaller.subDir += "-" + ctx.DeviceConfig().PlatformVndkVersion()
 			}
 		}
 		library.baseInstaller.install(ctx, file)
 	}
 
-	if Bool(library.Properties.Static_ndk_lib) && library.static() {
+	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
+		!ctx.useVndk() && ctx.Device() {
 		installPath := getNdkSysrootBase(ctx).Join(
 			ctx, "usr/lib", ctx.toolchain().ClangTriple(), file.Base())
 
@@ -742,7 +745,7 @@
 			Input:       file,
 		})
 
-		library.MutatedProperties.NdkSysrootPath = installPath.String()
+		library.ndkSysrootPath = installPath
 	}
 }
 
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 9a29964..e824d0f 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -191,7 +191,6 @@
 func llndkHeadersFactory() android.Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.HeaderOnly()
-	library.setStatic()
 
 	decorator := &llndkHeadersDecorator{
 		libraryDecorator: library,
diff --git a/cc/lto.go b/cc/lto.go
index fdb7688..b1e7cfa 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -40,10 +40,15 @@
 	// Lto must violate capitialization style for acronyms so that it can be
 	// referred to in blueprint files as "lto"
 	Lto struct {
-		Full *bool `android:"arch_variant"`
-		Thin *bool `android:"arch_variant"`
+		Never *bool `android:"arch_variant"`
+		Full  *bool `android:"arch_variant"`
+		Thin  *bool `android:"arch_variant"`
 	} `android:"arch_variant"`
-	LTODep bool `blueprint:"mutated"`
+
+	// Dep properties indicate that this module needs to be built with LTO
+	// since it is an object dependency of an LTO module.
+	FullDep bool `blueprint:"mutated"`
+	ThinDep bool `blueprint:"mutated"`
 }
 
 type lto struct {
@@ -84,7 +89,7 @@
 
 // Can be called with a null receiver
 func (lto *lto) LTO() bool {
-	if lto == nil {
+	if lto == nil || lto.Disabled() {
 		return false
 	}
 
@@ -93,41 +98,91 @@
 	return full || thin
 }
 
+// Is lto.never explicitly set to true?
+func (lto *lto) Disabled() bool {
+	return lto.Properties.Lto.Never != nil && *lto.Properties.Lto.Never
+}
+
 // Propagate lto requirements down from binaries
 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() {
-		full := Bool(c.lto.Properties.Lto.Full)
-		thin := Bool(c.lto.Properties.Lto.Thin)
+	if m, ok := mctx.Module().(*Module); ok && m.lto.LTO() {
+		full := Bool(m.lto.Properties.Lto.Full)
+		thin := Bool(m.lto.Properties.Lto.Thin)
 		if full && thin {
 			mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
 		}
 
-		mctx.VisitDepsDepthFirst(func(m android.Module) {
-			tag := mctx.OtherModuleDependencyTag(m)
+		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+			tag := mctx.OtherModuleDependencyTag(dep)
 			switch tag {
 			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
-				if cc, ok := m.(*Module); ok && cc.lto != nil {
-					cc.lto.Properties.LTODep = true
+				if dep, ok := dep.(*Module); ok && dep.lto != nil &&
+					!dep.lto.Disabled() {
+					if full && !Bool(dep.lto.Properties.Lto.Full) {
+						dep.lto.Properties.FullDep = true
+					}
+					if thin && !Bool(dep.lto.Properties.Lto.Thin) {
+						dep.lto.Properties.ThinDep = true
+					}
 				}
+
+				// Recursively walk static dependencies
+				return true
 			}
+
+			// Do not recurse down non-static dependencies
+			return false
 		})
 	}
 }
 
 // Create lto variants for modules that need them
 func ltoMutator(mctx android.BottomUpMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.lto != nil {
-		if c.lto.LTO() {
-			mctx.SetDependencyVariation("lto")
-		} else if c.lto.Properties.LTODep {
-			modules := mctx.CreateVariations("", "lto")
-			modules[0].(*Module).lto.Properties.Lto.Full = boolPtr(false)
-			modules[0].(*Module).lto.Properties.Lto.Thin = boolPtr(false)
-			modules[0].(*Module).lto.Properties.LTODep = false
-			modules[1].(*Module).lto.Properties.LTODep = false
-			modules[1].(*Module).Properties.PreventInstall = true
-			modules[1].(*Module).Properties.HideFromMake = true
+	if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
+		// Create variations for LTO types required as static
+		// dependencies
+		variationNames := []string{""}
+		if m.lto.Properties.FullDep && !Bool(m.lto.Properties.Lto.Full) {
+			variationNames = append(variationNames, "lto-full")
 		}
-		c.lto.Properties.LTODep = false
+		if m.lto.Properties.ThinDep && !Bool(m.lto.Properties.Lto.Thin) {
+			variationNames = append(variationNames, "lto-thin")
+		}
+
+		// Use correct dependencies if LTO property is explicitly set
+		// (mutually exclusive)
+		if Bool(m.lto.Properties.Lto.Full) {
+			mctx.SetDependencyVariation("lto-full")
+		}
+		if Bool(m.lto.Properties.Lto.Thin) {
+			mctx.SetDependencyVariation("lto-thin")
+		}
+
+		if len(variationNames) > 1 {
+			modules := mctx.CreateVariations(variationNames...)
+			for i, name := range variationNames {
+				variation := modules[i].(*Module)
+				// Default module which will be
+				// installed. Variation set above according to
+				// explicit LTO properties
+				if name == "" {
+					continue
+				}
+
+				// LTO properties for dependencies
+				if name == "lto-full" {
+					variation.lto.Properties.Lto.Full = boolPtr(true)
+					variation.lto.Properties.Lto.Thin = boolPtr(false)
+				}
+				if name == "lto-thin" {
+					variation.lto.Properties.Lto.Full = boolPtr(false)
+					variation.lto.Properties.Lto.Thin = boolPtr(true)
+				}
+				variation.Properties.PreventInstall = true
+				variation.Properties.HideFromMake = true
+				variation.lto.Properties.FullDep = false
+				variation.lto.Properties.ThinDep = false
+			}
+		}
 	}
 }
diff --git a/cc/makevars.go b/cc/makevars.go
index 7befb11..0d2569a 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -18,15 +18,50 @@
 	"fmt"
 	"sort"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 	"android/soong/cc/config"
 )
 
+const (
+	modulesAddedWall     = "ModulesAddedWall"
+	modulesUsingWnoError = "ModulesUsingWnoError"
+)
+
 func init() {
 	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
 }
 
+func getWallWerrorMap(config android.Config, name string) *sync.Map {
+	return config.Once(name, func() interface{} {
+		return &sync.Map{}
+	}).(*sync.Map)
+}
+
+func makeStringOfKeys(ctx android.MakeVarsContext, setName string) string {
+	set := getWallWerrorMap(ctx.Config(), setName)
+	keys := []string{}
+	set.Range(func(key interface{}, value interface{}) bool {
+		keys = append(keys, key.(string))
+		return true
+	})
+	sort.Strings(keys)
+	return strings.Join(keys, " ")
+}
+
+func makeStringOfWarningAllowedProjects() string {
+	allProjects := append([]string{}, config.WarningAllowedProjects...)
+	allProjects = append(allProjects, config.WarningAllowedOldProjects...)
+	sort.Strings(allProjects)
+	// Makefile rules use pattern "path/%" to match module paths.
+	if len(allProjects) > 0 {
+		return strings.Join(allProjects, "% ") + "%"
+	} else {
+		return ""
+	}
+}
+
 func makeVarsProvider(ctx android.MakeVarsContext) {
 	ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
 	ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
@@ -64,6 +99,10 @@
 	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
 	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
 
+	ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
+	ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWall))
+	ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoError))
+
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", strings.Join(asanLibs, " "))
@@ -238,6 +277,10 @@
 		// This is used by external/gentoo/...
 		ctx.Strict("CLANG_CONFIG_"+target.Arch.ArchType.Name+"_"+typePrefix+"TRIPLE",
 			toolchain.ClangTriple())
+
+		ctx.Strict(makePrefix+"CLANG_SUPPORTED", "true")
+	} else {
+		ctx.Strict(makePrefix+"CLANG_SUPPORTED", "")
 	}
 
 	ctx.Strict(makePrefix+"CC", gccCmd(toolchain, "gcc"))
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 0458fb6..d7c2a06 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"github.com/google/blueprint"
 
@@ -73,7 +74,7 @@
 
 	properties headerProperies
 
-	installPaths []string
+	installPaths android.Paths
 	licensePath  android.ModuleSrcPath
 }
 
@@ -119,6 +120,14 @@
 
 	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
 
+	// When generating NDK prebuilts, skip installing MIPS headers,
+	// but keep them when doing regular platform build.
+	// Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh
+	// TODO: Revert this once MIPS is supported in NDK again.
+	if Bool(ctx.AConfig().Ndk_abis) && strings.Contains(ctx.ModuleName(), "mips") {
+		return
+	}
+
 	srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
 	for _, header := range srcFiles {
 		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
@@ -130,7 +139,7 @@
 				"expected header install path (%q) not equal to actual install path %q",
 				installPath, installedPath))
 		}
-		m.installPaths = append(m.installPaths, installPath.String())
+		m.installPaths = append(m.installPaths, installPath)
 	}
 
 	if len(m.installPaths) == 0 {
@@ -177,7 +186,7 @@
 
 	properties preprocessedHeaderProperies
 
-	installPaths []string
+	installPaths android.Paths
 	licensePath  android.ModuleSrcPath
 }
 
@@ -199,7 +208,7 @@
 		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
 		installPath := installDir.Join(ctx, header.Base())
 		installPaths = append(installPaths, installPath)
-		m.installPaths = append(m.installPaths, installPath.String())
+		m.installPaths = append(m.installPaths, installPath)
 	}
 
 	if len(m.installPaths) == 0 {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c517523..5a76666 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -98,7 +98,7 @@
 	properties libraryProperties
 
 	versionScriptPath android.ModuleGenPath
-	installPath       string
+	installPath       android.Path
 }
 
 // OMG GO
@@ -117,7 +117,7 @@
 		return apiLevel, nil
 	}
 
-	minVersion := ctx.AConfig().MinSupportedSdkVersion()
+	minVersion := ctx.Config().MinSupportedSdkVersion()
 	firstArchVersions := map[android.ArchType]int{
 		android.Arm:    minVersion,
 		android.Arm64:  21,
@@ -188,7 +188,7 @@
 }
 
 func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) {
-	platformVersion := mctx.AConfig().PlatformSdkVersionInt()
+	platformVersion := mctx.Config().PlatformSdkVersionInt()
 
 	firstSupportedVersion, err := normalizeNdkApiLevel(mctx, String(c.properties.First_version),
 		mctx.Arch())
@@ -207,7 +207,7 @@
 	for version := firstGenVersion; version <= platformVersion; version++ {
 		versionStrs = append(versionStrs, strconv.Itoa(version))
 	}
-	versionStrs = append(versionStrs, mctx.AConfig().PlatformVersionActiveCodenames()...)
+	versionStrs = append(versionStrs, mctx.Config().PlatformVersionActiveCodenames()...)
 	versionStrs = append(versionStrs, "current")
 
 	modules := mctx.CreateVariations(versionStrs...)
@@ -251,6 +251,8 @@
 		"-Wno-incompatible-library-redeclaration",
 		"-Wno-builtin-requires-header",
 		"-Wno-invalid-noreturn",
+		"-Wall",
+		"-Werror",
 		// These libraries aren't actually used. Don't worry about unwinding
 		// (avoids the need to link an unwinder into a fake library).
 		"-fno-unwind-tables",
@@ -286,7 +288,7 @@
 
 	subdir := ""
 	srcs := []android.Path{stubSrcPath}
-	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil), versionScriptPath
+	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil, nil), versionScriptPath
 }
 
 func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -342,7 +344,7 @@
 
 	installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
 		"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
-	stub.installPath = ctx.InstallFile(installDir, path.Base(), path).String()
+	stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
 }
 
 func newStubLibrary() *Module {
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 13424e3..69e07b9 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -141,7 +141,10 @@
 	module.compiler = nil
 	module.linker = linker
 	module.installer = nil
-	module.Properties.HideFromMake = true
+	minVersionString := "minimum"
+	noStlString := "none"
+	module.Properties.Sdk_version = &minVersionString
+	module.stl.Properties.Stl = &noStlString
 	return module.Init()
 }
 
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index e213965..c7ba588 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -53,8 +53,6 @@
 // TODO(danalbert): Write `ndk_static_library` rule.
 
 import (
-	"github.com/google/blueprint"
-
 	"android/soong/android"
 )
 
@@ -76,32 +74,42 @@
 	return getNdkInstallBase(ctx).Join(ctx, "sysroot")
 }
 
-func getNdkSysrootTimestampFile(ctx android.PathContext) android.Path {
+// The base timestamp file depends on the NDK headers and stub shared libraries,
+// but not the static libraries. This distinction is needed because the static
+// libraries themselves might need to depend on the base sysroot.
+func getNdkBaseTimestampFile(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "ndk_base.timestamp")
+}
+
+// The full timestamp file depends on the base timestamp *and* the static
+// libraries.
+func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath {
 	return android.PathForOutput(ctx, "ndk.timestamp")
 }
 
-func NdkSingleton() blueprint.Singleton {
+func NdkSingleton() android.Singleton {
 	return &ndkSingleton{}
 }
 
 type ndkSingleton struct{}
 
-func (n *ndkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
-	installPaths := []string{}
-	licensePaths := []string{}
-	ctx.VisitAllModules(func(module blueprint.Module) {
+func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var staticLibInstallPaths android.Paths
+	var installPaths android.Paths
+	var licensePaths android.Paths
+	ctx.VisitAllModules(func(module android.Module) {
 		if m, ok := module.(android.Module); ok && !m.Enabled() {
 			return
 		}
 
 		if m, ok := module.(*headerModule); ok {
 			installPaths = append(installPaths, m.installPaths...)
-			licensePaths = append(licensePaths, m.licensePath.String())
+			licensePaths = append(licensePaths, m.licensePath)
 		}
 
 		if m, ok := module.(*preprocessedHeaderModule); ok {
 			installPaths = append(installPaths, m.installPaths...)
-			licensePaths = append(licensePaths, m.licensePath.String())
+			licensePaths = append(licensePaths, m.licensePath)
 		}
 
 		if m, ok := module.(*Module); ok {
@@ -110,30 +118,37 @@
 			}
 
 			if library, ok := m.linker.(*libraryDecorator); ok {
-				if library.MutatedProperties.NdkSysrootPath != "" {
-					installPaths = append(installPaths, library.MutatedProperties.NdkSysrootPath)
+				if library.ndkSysrootPath != nil {
+					staticLibInstallPaths = append(
+						staticLibInstallPaths, library.ndkSysrootPath)
 				}
 			}
 		}
 	})
 
 	combinedLicense := getNdkInstallBase(ctx).Join(ctx, "NOTICE")
-	ctx.Build(pctx, blueprint.BuildParams{
+	ctx.Build(pctx, android.BuildParams{
 		Rule:        android.Cat,
 		Description: "combine licenses",
-		Outputs:     []string{combinedLicense.String()},
+		Output:      combinedLicense,
 		Inputs:      licensePaths,
-		Optional:    true,
 	})
 
-	depPaths := append(installPaths, combinedLicense.String())
+	baseDepPaths := append(installPaths, combinedLicense)
 
 	// There's a dummy "ndk" rule defined in ndk/Android.mk that depends on
 	// this. `m ndk` will build the sysroots.
-	ctx.Build(pctx, blueprint.BuildParams{
+	ctx.Build(pctx, android.BuildParams{
 		Rule:      android.Touch,
-		Outputs:   []string{getNdkSysrootTimestampFile(ctx).String()},
-		Implicits: depPaths,
-		Optional:  true,
+		Output:    getNdkBaseTimestampFile(ctx),
+		Implicits: baseDepPaths,
+	})
+
+	fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:      android.Touch,
+		Output:    getNdkFullTimestampFile(ctx),
+		Implicits: fullDepPaths,
 	})
 }
diff --git a/cc/pgo.go b/cc/pgo.go
index ea23124..fef962e 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -42,6 +42,9 @@
 		Profile_file       *string `android:"arch_variant"`
 		Benchmarks         []string
 		Enable_profile_use *bool `android:"arch_variant"`
+		// Additional compiler flags to use when building this module
+		// for profiling (either instrumentation or sampling).
+		Cflags []string `android:"arch_variant"`
 	} `android:"arch_variant"`
 
 	PgoPresent          bool `blueprint:"mutated"`
@@ -65,6 +68,8 @@
 }
 
 func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
+
 	if props.isInstrumentation() {
 		flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
 		// The profile runtime is added below in deps().  Add the below
@@ -181,7 +186,7 @@
 	//
 	// TODO Validate that each benchmark instruments at least one module
 	pgo.Properties.ShouldProfileModule = false
-	pgoBenchmarks := ctx.AConfig().Getenv("ANDROID_PGO_INSTRUMENT")
+	pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
 	pgoBenchmarksMap := make(map[string]bool)
 	for _, b := range strings.Split(pgoBenchmarks, ",") {
 		pgoBenchmarksMap[b] = true
@@ -215,7 +220,7 @@
 		return props.addProfileGatherFlags(ctx, flags)
 	}
 
-	if !ctx.AConfig().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
+	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
 		return props.addProfileUseFlags(ctx, flags)
 	}
 
diff --git a/cc/proto.go b/cc/proto.go
index e7f1d41..3b5fd3b 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -16,6 +16,7 @@
 
 import (
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -27,15 +28,15 @@
 var (
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
-			Command:     "$protocCmd --cpp_out=$outDir $protoFlags $in",
+			Command:     "$protocCmd --cpp_out=$protoOutParams:$outDir $protoFlags $in",
 			CommandDeps: []string{"$protocCmd"},
-		}, "protoFlags", "outDir")
+		}, "protoFlags", "protoOutParams", "outDir")
 )
 
 // genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
 // the paths to the generated files.
 func genProto(ctx android.ModuleContext, protoFile android.Path,
-	protoFlags string) (ccFile, headerFile android.WritablePath) {
+	protoFlags string, protoOutParams string) (ccFile, headerFile android.WritablePath) {
 
 	ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc")
 	headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
@@ -46,8 +47,9 @@
 		Outputs:     android.WritablePaths{ccFile, headerFile},
 		Input:       protoFile,
 		Args: map[string]string{
-			"outDir":     android.ProtoDir(ctx).String(),
-			"protoFlags": protoFlags,
+			"outDir":         android.ProtoDir(ctx).String(),
+			"protoFlags":     protoFlags,
+			"protoOutParams": protoOutParams,
 		},
 	})
 
@@ -97,5 +99,9 @@
 
 	flags.protoFlags = android.ProtoFlags(ctx, p)
 
+	if proptools.String(p.Proto.Type) == "lite" {
+		flags.protoOutParams = []string{"lite"}
+	}
+
 	return flags
 }
diff --git a/cc/relocation_packer.go b/cc/relocation_packer.go
index 614f15c..5006623 100644
--- a/cc/relocation_packer.go
+++ b/cc/relocation_packer.go
@@ -53,7 +53,7 @@
 	if ctx.Target().Os != android.Android {
 		enabled = false
 	}
-	if ctx.AConfig().Getenv("DISABLE_RELOCATION_PACKER") == "true" {
+	if ctx.Config().Getenv("DISABLE_RELOCATION_PACKER") == "true" {
 		enabled = false
 	}
 	if ctx.useSdk() {
@@ -68,7 +68,7 @@
 }
 
 func (p *relocationPacker) needsPacking(ctx ModuleContext) bool {
-	if ctx.AConfig().EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		return false
 	}
 	return p.Properties.PackingRelocations
diff --git a/cc/rs.go b/cc/rs.go
index c2335dd..68ba54b 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -86,7 +86,7 @@
 		case "current", "system_current", "test_current":
 			// Nothing
 		default:
-			targetApi = ctx.sdkVersion()
+			targetApi = android.GetNumericSdkVersion(ctx.sdkVersion())
 		}
 	}
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 70aa412..1afec26 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -17,7 +17,9 @@
 import (
 	"fmt"
 	"io"
+	"sort"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 	"android/soong/cc/config"
@@ -36,9 +38,10 @@
 		"-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"}
 	cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi",
 		"-Wl,-plugin-opt,O1"}
-	cfiArflags        = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"}
-	cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
-	cfiExportsMap     android.Path
+	cfiArflags         = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"}
+	cfiExportsMapPath  = "build/soong/cc/config/cfi_exports.map"
+	cfiExportsMap      android.Path
+	cfiStaticLibsMutex sync.Mutex
 
 	intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"}
 )
@@ -122,6 +125,10 @@
 	androidMkRuntimeLibrary string
 }
 
+func init() {
+	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
+}
+
 func (sanitize *sanitize) props() []interface{} {
 	return []interface{}{&sanitize.Properties}
 }
@@ -144,12 +151,12 @@
 
 	if ctx.clang() {
 		if ctx.Host() {
-			globalSanitizers = ctx.AConfig().SanitizeHost()
+			globalSanitizers = ctx.Config().SanitizeHost()
 		} else {
-			arches := ctx.AConfig().SanitizeDeviceArch()
+			arches := ctx.Config().SanitizeDeviceArch()
 			if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) {
-				globalSanitizers = ctx.AConfig().SanitizeDevice()
-				globalSanitizersDiag = ctx.AConfig().SanitizeDeviceDiag()
+				globalSanitizers = ctx.Config().SanitizeDevice()
+				globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
 			}
 		}
 	}
@@ -187,13 +194,13 @@
 		}
 
 		if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil {
-			if !ctx.AConfig().CFIDisabledForPath(ctx.ModuleDir()) {
+			if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) {
 				s.Cfi = boolPtr(true)
 			}
 		}
 
 		if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
-			if !ctx.AConfig().IntegerOverflowDisabledForPath(ctx.ModuleDir()) {
+			if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) {
 				s.Integer_overflow = boolPtr(true)
 			}
 		}
@@ -218,15 +225,15 @@
 	}
 
 	// Enable CFI for all components in the include paths
-	if s.Cfi == nil && ctx.AConfig().CFIEnabledForPath(ctx.ModuleDir()) {
+	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) {
 		s.Cfi = boolPtr(true)
-		if inList("cfi", ctx.AConfig().SanitizeDeviceDiag()) {
+		if inList("cfi", ctx.Config().SanitizeDeviceDiag()) {
 			s.Diag.Cfi = boolPtr(true)
 		}
 	}
 
 	// CFI needs gold linker, and mips toolchain does not have one.
-	if !ctx.AConfig().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 {
+	if !ctx.Config().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 {
 		s.Cfi = nil
 		s.Diag.Cfi = nil
 	}
@@ -243,6 +250,12 @@
 		s.Diag.Cfi = nil
 	}
 
+	// Also disable CFI for host builds.
+	if ctx.Host() {
+		s.Cfi = nil
+		s.Diag.Cfi = nil
+	}
+
 	if ctx.staticBinary() {
 		s.Address = nil
 		s.Coverage = nil
@@ -474,12 +487,11 @@
 			fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.androidMkRuntimeLibrary)
 		}
 	})
-	if ctx.Target().Os.Class == android.Device {
-		if Bool(sanitize.Properties.Sanitize.Cfi) {
-			ret.SubName += ".cfi"
-		} else if Bool(sanitize.Properties.Sanitize.Address) {
-			ret.SubName += ".asan"
-		}
+
+	// Add a suffix for CFI-enabled static libraries to allow surfacing both to make without a
+	// name conflict.
+	if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Cfi) {
+		ret.SubName += ".cfi"
 	}
 }
 
@@ -584,27 +596,44 @@
 
 				modules[0].(*Module).sanitize.Properties.SanitizeDep = false
 				modules[1].(*Module).sanitize.Properties.SanitizeDep = false
-				if mctx.Device() {
-					// CFI and ASAN are currently mutually exclusive so disable
-					// CFI if this is an ASAN variant.
-					if t == asan {
+
+				// We don't need both variants active for anything but CFI-enabled
+				// target static libraries, so suppress the appropriate variant in
+				// all other cases.
+				if t == cfi {
+					if c.static() {
+						if !mctx.Device() {
+							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 {
+							cfiStaticLibs := cfiStaticLibs(mctx.Config())
+
+							cfiStaticLibsMutex.Lock()
+							*cfiStaticLibs = append(*cfiStaticLibs, c.Name())
+							cfiStaticLibsMutex.Unlock()
+						}
+					} else {
+						modules[0].(*Module).Properties.PreventInstall = true
+						modules[0].(*Module).Properties.HideFromMake = true
+					}
+				} else if t == asan {
+					if mctx.Device() {
+						// CFI and ASAN are currently mutually exclusive so disable
+						// CFI if this is an ASAN variant.
 						modules[1].(*Module).sanitize.Properties.InSanitizerDir = true
 						modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
 					}
-				} else {
-					if mctx.AConfig().EmbeddedInMake() {
-						if isSanitizerEnabled {
-							modules[0].(*Module).Properties.HideFromMake = true
-						} else {
-							modules[1].(*Module).Properties.HideFromMake = true
-						}
-					}
-				}
-				if !mctx.AConfig().EmbeddedInMake() || !mctx.Device() {
 					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
 					}
 				}
 			}
@@ -612,3 +641,15 @@
 		}
 	}
 }
+
+func cfiStaticLibs(config android.Config) *[]string {
+	return config.Once("cfiStaticLibs", func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
+	cfiStaticLibs := cfiStaticLibs(ctx.Config())
+	sort.Strings(*cfiStaticLibs)
+	ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " "))
+}
diff --git a/cc/stl.go b/cc/stl.go
index 347db99..338db84 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -19,6 +19,25 @@
 	"fmt"
 )
 
+func getNdkStlFamily(ctx android.ModuleContext, m *Module) string {
+	stl := m.stl.Properties.SelectedStl
+	switch stl {
+	case "ndk_libc++_shared", "ndk_libc++_static":
+		return "libc++"
+	case "ndk_libstlport_shared", "ndk_libstlport_static":
+		return "stlport"
+	case "ndk_libgnustl_static":
+		return "gnustl"
+	case "ndk_system":
+		return "system"
+	case "":
+		return "none"
+	default:
+		ctx.ModuleErrorf("stl: %q is not a valid STL", stl)
+		return ""
+	}
+}
+
 type StlProperties struct {
 	// select the STL library to use.  Possible values are "libc++", "libc++_static",
 	// "stlport", "stlport_static", "ndk", "libstdc++", or "none".  Leave blank to select the
diff --git a/cc/strip.go b/cc/strip.go
index 0bb29c1..a7c2d4e 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -30,7 +30,7 @@
 }
 
 func (stripper *stripper) needsStrip(ctx ModuleContext) bool {
-	return !ctx.AConfig().EmbeddedInMake() && !Bool(stripper.StripProperties.Strip.None)
+	return !ctx.Config().EmbeddedInMake() && !Bool(stripper.StripProperties.Strip.None)
 }
 
 func (stripper *stripper) strip(ctx ModuleContext, in, out android.ModuleOutPath,
diff --git a/cc/tidy.go b/cc/tidy.go
index c31f5ae..67fd3db 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -58,7 +58,7 @@
 	}
 
 	// If not explicitly set, check the global tidy flag
-	if tidy.Properties.Tidy == nil && !ctx.AConfig().ClangTidy() {
+	if tidy.Properties.Tidy == nil && !ctx.Config().ClangTidy() {
 		return flags
 	}
 
@@ -77,12 +77,17 @@
 		flags.TidyFlags = append(flags.TidyFlags, headerFilter)
 	}
 
+	// If clang-tidy is not enabled globally, add the -quiet flag.
+	if !ctx.Config().ClangTidy() {
+		flags.TidyFlags = append(flags.TidyFlags, "-quiet")
+	}
+
 	// We might be using the static analyzer through clang tidy.
 	// https://bugs.llvm.org/show_bug.cgi?id=32914
 	flags.TidyFlags = append(flags.TidyFlags, "-extra-arg-before=-D__clang_analyzer__")
 
 	tidyChecks := "-checks="
-	if checks := ctx.AConfig().TidyChecks(); len(checks) > 0 {
+	if checks := ctx.Config().TidyChecks(); len(checks) > 0 {
 		tidyChecks += checks
 	} else {
 		tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
diff --git a/cc/util.go b/cc/util.go
index cc89af6..7041029 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -97,27 +97,28 @@
 
 func flagsToBuilderFlags(in Flags) builderFlags {
 	return builderFlags{
-		globalFlags:   strings.Join(in.GlobalFlags, " "),
-		arFlags:       strings.Join(in.ArFlags, " "),
-		asFlags:       strings.Join(in.AsFlags, " "),
-		cFlags:        strings.Join(in.CFlags, " "),
-		toolingCFlags: strings.Join(in.ToolingCFlags, " "),
-		conlyFlags:    strings.Join(in.ConlyFlags, " "),
-		cppFlags:      strings.Join(in.CppFlags, " "),
-		yaccFlags:     strings.Join(in.YaccFlags, " "),
-		protoFlags:    strings.Join(in.protoFlags, " "),
-		aidlFlags:     strings.Join(in.aidlFlags, " "),
-		rsFlags:       strings.Join(in.rsFlags, " "),
-		ldFlags:       strings.Join(in.LdFlags, " "),
-		libFlags:      strings.Join(in.libFlags, " "),
-		tidyFlags:     strings.Join(in.TidyFlags, " "),
-		sAbiFlags:     strings.Join(in.SAbiFlags, " "),
-		yasmFlags:     strings.Join(in.YasmFlags, " "),
-		toolchain:     in.Toolchain,
-		clang:         in.Clang,
-		coverage:      in.Coverage,
-		tidy:          in.Tidy,
-		sAbiDump:      in.SAbiDump,
+		globalFlags:    strings.Join(in.GlobalFlags, " "),
+		arFlags:        strings.Join(in.ArFlags, " "),
+		asFlags:        strings.Join(in.AsFlags, " "),
+		cFlags:         strings.Join(in.CFlags, " "),
+		toolingCFlags:  strings.Join(in.ToolingCFlags, " "),
+		conlyFlags:     strings.Join(in.ConlyFlags, " "),
+		cppFlags:       strings.Join(in.CppFlags, " "),
+		yaccFlags:      strings.Join(in.YaccFlags, " "),
+		protoFlags:     strings.Join(in.protoFlags, " "),
+		protoOutParams: strings.Join(in.protoOutParams, ":"),
+		aidlFlags:      strings.Join(in.aidlFlags, " "),
+		rsFlags:        strings.Join(in.rsFlags, " "),
+		ldFlags:        strings.Join(in.LdFlags, " "),
+		libFlags:       strings.Join(in.libFlags, " "),
+		tidyFlags:      strings.Join(in.TidyFlags, " "),
+		sAbiFlags:      strings.Join(in.SAbiFlags, " "),
+		yasmFlags:      strings.Join(in.YasmFlags, " "),
+		toolchain:      in.Toolchain,
+		clang:          in.Clang,
+		coverage:       in.Coverage,
+		tidy:           in.Tidy,
+		sAbiDump:       in.SAbiDump,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
diff --git a/cc/vndk.go b/cc/vndk.go
index 03297df..a61b74c 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -172,6 +172,5 @@
 				}
 			}
 		}
-
 	}
 }
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
new file mode 100644
index 0000000..9ccab03
--- /dev/null
+++ b/cc/vndk_prebuilt.go
@@ -0,0 +1,140 @@
+// 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 cc
+
+import (
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	vndkSuffix = ".vndk."
+)
+
+// Creates vndk prebuilts that include the VNDK version.
+//
+// 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"],
+//         },
+//     },
+// }
+//
+type vndkPrebuiltProperties struct {
+	// VNDK snapshot version that is formated as {SDK_ver}.{Major}.{Minor}.
+	Version string
+
+	// Prebuilt files for each arch.
+	Srcs []string `android:"arch_variant"`
+}
+
+type vndkPrebuiltLibraryDecorator struct {
+	*libraryDecorator
+	properties vndkPrebuiltProperties
+}
+
+func (p *vndkPrebuiltLibraryDecorator) Name(name string) string {
+	return name + vndkSuffix + p.version()
+}
+
+func (p *vndkPrebuiltLibraryDecorator) version() string {
+	return p.properties.Version
+}
+
+func (p *vndkPrebuiltLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), vndkSuffix+p.version())
+	return p.libraryDecorator.linkerFlags(ctx, flags)
+}
+
+func (p *vndkPrebuiltLibraryDecorator) singleSourcePath(ctx ModuleContext) android.Path {
+	if len(p.properties.Srcs) == 0 {
+		ctx.PropertyErrorf("srcs", "missing prebuilt source file")
+		return nil
+	}
+
+	if len(p.properties.Srcs) > 1 {
+		ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+		return nil
+	}
+
+	return android.PathForModuleSrc(ctx, p.properties.Srcs[0])
+}
+
+func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
+	flags Flags, deps PathDeps, objs Objects) android.Path {
+	if len(p.properties.Srcs) > 0 && p.shared() {
+		// current VNDK prebuilts are only shared libs.
+		return p.singleSourcePath(ctx)
+	}
+	return nil
+}
+
+func (p *vndkPrebuiltLibraryDecorator) install(ctx ModuleContext, file android.Path) {
+	if p.shared() {
+		if ctx.Device() && ctx.useVndk() {
+			if ctx.isVndkSp() {
+				p.baseInstaller.subDir = "vndk-sp-" + p.version()
+			} else if ctx.isVndk() {
+				p.baseInstaller.subDir = "vndk-" + p.version()
+			}
+		}
+		p.baseInstaller.install(ctx, file)
+	}
+}
+
+func vndkPrebuiltSharedLibrary() *Module {
+	module, library := NewLibrary(android.DeviceSupported)
+	library.BuildOnlyShared()
+	module.stl = nil
+	module.sanitize = nil
+	library.StripProperties.Strip.None = BoolPtr(true)
+
+	prebuilt := &vndkPrebuiltLibraryDecorator{
+		libraryDecorator: library,
+	}
+
+	module.compiler = nil
+	module.linker = prebuilt
+	module.installer = prebuilt
+
+	module.AddProperties(
+		&prebuilt.properties,
+	)
+
+	return module
+}
+
+func vndkPrebuiltSharedFactory() android.Module {
+	module := vndkPrebuiltSharedLibrary()
+	return module.Init()
+}
+
+func init() {
+	android.RegisterModuleType("vndk_prebuilt_shared", vndkPrebuiltSharedFactory)
+}
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 207b161..df04358 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -19,6 +19,7 @@
 	"flag"
 	"fmt"
 	"hash/crc32"
+	"io/ioutil"
 	"log"
 	"os"
 	"path/filepath"
@@ -54,13 +55,16 @@
 }
 
 var (
-	sortEntries     = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
-	emulateJar      = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
-	stripDirs       fileList
-	stripFiles      fileList
-	zipsToNotStrip  = make(zipsToNotStripSet)
-	stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
-	manifest        = flag.String("m", "", "manifest file to insert in jar")
+	sortEntries      = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
+	emulateJar       = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
+	emulatePar       = flag.Bool("p", false, "merge zip entries based on par format")
+	stripDirs        fileList
+	stripFiles       fileList
+	zipsToNotStrip   = make(zipsToNotStripSet)
+	stripDirEntries  = flag.Bool("D", false, "strip directory entries from the output zip file")
+	manifest         = flag.String("m", "", "manifest file to insert in jar")
+	entrypoint       = flag.String("e", "", "par entrypoint file to insert in par")
+	ignoreDuplicates = flag.Bool("ignore-duplicates", false, "take each entry from the first zip it exists in and don't warn")
 )
 
 func init() {
@@ -71,7 +75,7 @@
 
 func main() {
 	flag.Usage = func() {
-		fmt.Fprintln(os.Stderr, "usage: merge_zips [-jsD] [-m manifest] output [inputs...]")
+		fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [-e entrypoint] output [inputs...]")
 		flag.PrintDefaults()
 	}
 
@@ -117,8 +121,13 @@
 		log.Fatal(errors.New("must specify -j when specifying a manifest via -m"))
 	}
 
+	if *entrypoint != "" && !*emulatePar {
+		log.Fatal(errors.New("must specify -p when specifying a entrypoint via -e"))
+	}
+
 	// do merge
-	err = mergeZips(readers, writer, *manifest, *sortEntries, *emulateJar, *stripDirEntries)
+	err = mergeZips(readers, writer, *manifest, *entrypoint, *sortEntries, *emulateJar, *emulatePar,
+		*stripDirEntries, *ignoreDuplicates)
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -209,8 +218,8 @@
 	source zipSource
 }
 
-func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest string,
-	sortEntries, emulateJar, stripDirEntries bool) error {
+func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest, entrypoint string,
+	sortEntries, emulateJar, emulatePar, stripDirEntries, ignoreDuplicates bool) error {
 
 	sourceByDest := make(map[string]zipSource, 0)
 	orderedMappings := []fileMapping{}
@@ -243,6 +252,68 @@
 		addMapping(jar.ManifestFile, fileSource)
 	}
 
+	if entrypoint != "" {
+		buf, err := ioutil.ReadFile(entrypoint)
+		if err != nil {
+			return err
+		}
+		fh := &zip.FileHeader{
+			Name:               "entry_point.txt",
+			Method:             zip.Store,
+			UncompressedSize64: uint64(len(buf)),
+		}
+		fh.SetMode(0700)
+		fh.SetModTime(jar.DefaultTime)
+		fileSource := bufferEntry{fh, buf}
+		addMapping("entry_point.txt", fileSource)
+	}
+
+	if emulatePar {
+		// the runfiles packages needs to be populated with "__init__.py".
+		newPyPkgs := []string{}
+		// the runfiles dirs have been treated as packages.
+		existingPyPkgSet := make(map[string]bool)
+		// put existing __init__.py files to a set first. This set is used for preventing
+		// generated __init__.py files from overwriting existing ones.
+		for _, namedReader := range readers {
+			for _, file := range namedReader.reader.File {
+				if filepath.Base(file.Name) != "__init__.py" {
+					continue
+				}
+				pyPkg := pathBeforeLastSlash(file.Name)
+				if _, found := existingPyPkgSet[pyPkg]; found {
+					panic(fmt.Errorf("found __init__.py path duplicates during pars merging: %q.", file.Name))
+				} else {
+					existingPyPkgSet[pyPkg] = true
+				}
+			}
+		}
+		for _, namedReader := range readers {
+			for _, file := range namedReader.reader.File {
+				var parentPath string /* the path after trimming last "/" */
+				if filepath.Base(file.Name) == "__init__.py" {
+					// for existing __init__.py files, we should trim last "/" for twice.
+					// eg. a/b/c/__init__.py ---> a/b
+					parentPath = pathBeforeLastSlash(pathBeforeLastSlash(file.Name))
+				} else {
+					parentPath = pathBeforeLastSlash(file.Name)
+				}
+				populateNewPyPkgs(parentPath, existingPyPkgSet, &newPyPkgs)
+			}
+		}
+		for _, pkg := range newPyPkgs {
+			var emptyBuf []byte
+			fh := &zip.FileHeader{
+				Name:               filepath.Join(pkg, "__init__.py"),
+				Method:             zip.Store,
+				UncompressedSize64: uint64(len(emptyBuf)),
+			}
+			fh.SetMode(0700)
+			fh.SetModTime(jar.DefaultTime)
+			fileSource := bufferEntry{fh, emptyBuf}
+			addMapping(filepath.Join(pkg, "__init__.py"), fileSource)
+		}
+	}
 	for _, namedReader := range readers {
 		_, skipStripThisZip := zipsToNotStrip[namedReader.path]
 		for _, file := range namedReader.reader.File {
@@ -266,6 +337,9 @@
 					return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
 						dest, existingSource, source)
 				}
+				if ignoreDuplicates {
+					continue
+				}
 				if emulateJar &&
 					file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass {
 					// Skip manifest and module info files that are not from the first input file
@@ -301,6 +375,29 @@
 	return nil
 }
 
+// Sets the given directory and all its ancestor directories as Python packages.
+func populateNewPyPkgs(pkgPath string, existingPyPkgSet map[string]bool, newPyPkgs *[]string) {
+	for pkgPath != "" {
+		if _, found := existingPyPkgSet[pkgPath]; !found {
+			existingPyPkgSet[pkgPath] = true
+			*newPyPkgs = append(*newPyPkgs, pkgPath)
+			// Gets its ancestor directory by trimming last slash.
+			pkgPath = pathBeforeLastSlash(pkgPath)
+		} else {
+			break
+		}
+	}
+}
+
+func pathBeforeLastSlash(path string) string {
+	ret := filepath.Dir(path)
+	// filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/".
+	if ret == "." || ret == "/" {
+		return ""
+	}
+	return ret
+}
+
 func shouldStripFile(emulateJar bool, name string) bool {
 	for _, dir := range stripDirs {
 		if strings.HasPrefix(name, dir+"/") {
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 2fee1f7..06c5626 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -24,6 +24,7 @@
 	"runtime"
 	"strings"
 	"sync"
+	"syscall"
 	"time"
 
 	"android/soong/ui/build"
@@ -159,6 +160,30 @@
 	return s.failed
 }
 
+// TODO(b/70370883): This tool uses a lot of open files -- over the default
+// soft limit of 1024 on some systems. So bump up to the hard limit until I fix
+// the algorithm.
+func setMaxFiles(log logger.Logger) {
+	var limits syscall.Rlimit
+
+	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
+	if err != nil {
+		log.Println("Failed to get file limit:", err)
+		return
+	}
+
+	log.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
+	if limits.Cur == limits.Max {
+		return
+	}
+
+	limits.Cur = limits.Max
+	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
+	if err != nil {
+		log.Println("Failed to increase file limit:", err)
+	}
+}
+
 func inList(str string, list []string) bool {
 	for _, other := range list {
 		if str == other {
@@ -228,6 +253,8 @@
 		trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
 	}
 
+	setMaxFiles(log)
+
 	vars, err := build.DumpMakeVars(buildCtx, config, nil, []string{"all_named_products"})
 	if err != nil {
 		log.Fatal(err)
diff --git a/cmd/pom2mk/pom2mk.go b/cmd/pom2mk/pom2mk.go
index 4596db9..33d7ff9 100644
--- a/cmd/pom2mk/pom2mk.go
+++ b/cmd/pom2mk/pom2mk.go
@@ -55,13 +55,15 @@
 	return nil
 }
 
-func (r *RewriteNames) Rewrite(name string) string {
+func (r *RewriteNames) MavenToMk(groupId string, artifactId string) string {
 	for _, r := range *r {
-		if r.regexp.MatchString(name) {
-			return r.regexp.ReplaceAllString(name, r.repl)
+		if r.regexp.MatchString(groupId + ":" + artifactId) {
+			return r.regexp.ReplaceAllString(groupId+":"+artifactId, r.repl)
+		} else if r.regexp.MatchString(artifactId) {
+			return r.regexp.ReplaceAllString(artifactId, r.repl)
 		}
 	}
-	return name
+	return artifactId
 }
 
 var rewriteNames = RewriteNames{}
@@ -102,6 +104,7 @@
 
 	PomFile      string `xml:"-"`
 	ArtifactFile string `xml:"-"`
+	MakeTarget   string `xml:"-"`
 
 	GroupId    string `xml:"groupId"`
 	ArtifactId string `xml:"artifactId"`
@@ -112,7 +115,10 @@
 }
 
 func (p Pom) MkName() string {
-	return rewriteNames.Rewrite(p.ArtifactId)
+	if p.MakeTarget == "" {
+		p.MakeTarget = rewriteNames.MavenToMk(p.GroupId, p.ArtifactId)
+	}
+	return p.MakeTarget
 }
 
 func (p Pom) MkDeps() []string {
@@ -121,7 +127,7 @@
 		if d.Type != "aar" {
 			continue
 		}
-		name := rewriteNames.Rewrite(d.ArtifactId)
+		name := rewriteNames.MavenToMk(d.GroupId, d.ArtifactId)
 		ret = append(ret, name)
 		ret = append(ret, extraDeps[name]...)
 	}
@@ -137,7 +143,7 @@
 		if d.Type != "" {
 			continue
 		}
-		if depPom, ok := modules[d.ArtifactId]; ok {
+		if depPom, ok := modules[p.MkName()]; ok {
 			d.Type = depPom.Packaging
 		}
 	}
@@ -195,9 +201,11 @@
 Usage: %s [--rewrite <regex>=<replace>] [--extra-deps <module>=<module>[,<module>]] <dir>
 
   -rewrite <regex>=<replace>
-     rewrite can be used to specify mappings between the artifactId in the pom files and module
-     names in the Android.mk files. This can be specified multiple times, the first matching
-     regex will be used.
+     rewrite can be used to specify mappings between Maven projects and Make modules. The -rewrite
+     option can be specified multiple times. When determining the Make module for a given Maven
+     project, mappings are searched in the order they were specified. The first <regex> matching
+     either the Maven project's <groupId>:<artifactId> or <artifactId> will be used to generate
+     the Make module name using <replace>. If no matches are found, <artifactId> is used.
   -extra-deps <module>=<module>[,<module>]
      Some Android.mk modules have transitive dependencies that must be specified when they are
      depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
@@ -282,13 +290,14 @@
 
 		if pom != nil {
 			poms = append(poms, pom)
+			key := pom.MkName()
 
-			if old, ok := modules[pom.ArtifactId]; ok {
-				fmt.Fprintln(os.Stderr, "Module", pom.ArtifactId, "defined twice:", old.PomFile, pom.PomFile)
+			if old, ok := modules[key]; ok {
+				fmt.Fprintln(os.Stderr, "Module", key, "defined twice:", old.PomFile, pom.PomFile)
 				os.Exit(1)
 			}
 
-			modules[pom.ArtifactId] = pom
+			modules[key] = pom
 		}
 	}
 
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 558bc3f..3b41c90 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -15,6 +15,7 @@
 package main
 
 import (
+	"errors"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -78,6 +79,22 @@
 	}
 }
 
+func findAllFilesUnder(root string) (paths []string) {
+	paths = []string{}
+	filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+		if !info.IsDir() {
+			relPath, err := filepath.Rel(root, path)
+			if err != nil {
+				// couldn't find relative path from ancestor?
+				panic(err)
+			}
+			paths = append(paths, relPath)
+		}
+		return nil
+	})
+	return paths
+}
+
 func run() error {
 	if rawCommand == "" {
 		usageViolation("-c <commandToRun> is required and must be non-empty")
@@ -196,23 +213,49 @@
 	}
 
 	// validate that all files are created properly
-	var outputErrors []error
+	var missingOutputErrors []string
 	for _, filePath := range allOutputs {
 		tempPath := filepath.Join(tempDir, filePath)
 		fileInfo, err := os.Stat(tempPath)
 		if err != nil {
-			outputErrors = append(outputErrors, fmt.Errorf("failed to create expected output file: %s\n", tempPath))
+			missingOutputErrors = append(missingOutputErrors, fmt.Sprintf("%s: does not exist", filePath))
 			continue
 		}
 		if fileInfo.IsDir() {
-			outputErrors = append(outputErrors, fmt.Errorf("Output path %s refers to a directory, not a file. This is not permitted because it prevents robust up-to-date checks\n", filePath))
+			missingOutputErrors = append(missingOutputErrors, fmt.Sprintf("%s: not a file", filePath))
 		}
 	}
-	if len(outputErrors) > 0 {
+	if len(missingOutputErrors) > 0 {
+		// find all created files for making a more informative error message
+		createdFiles := findAllFilesUnder(tempDir)
+
+		// build error message
+		errorMessage := "mismatch between declared and actual outputs\n"
+		errorMessage += "in sbox command(" + commandDescription + ")\n\n"
+		errorMessage += "in sandbox " + tempDir + ",\n"
+		errorMessage += fmt.Sprintf("failed to create %v files:\n", len(missingOutputErrors))
+		for _, missingOutputError := range missingOutputErrors {
+			errorMessage += "  " + missingOutputError + "\n"
+		}
+		if len(createdFiles) < 1 {
+			errorMessage += "created 0 files."
+		} else {
+			errorMessage += fmt.Sprintf("did create %v files:\n", len(createdFiles))
+			creationMessages := createdFiles
+			maxNumCreationLines := 10
+			if len(creationMessages) > maxNumCreationLines {
+				creationMessages = creationMessages[:maxNumCreationLines]
+				creationMessages = append(creationMessages, fmt.Sprintf("...%v more", len(createdFiles)-maxNumCreationLines))
+			}
+			for _, creationMessage := range creationMessages {
+				errorMessage += "  " + creationMessage + "\n"
+			}
+		}
+
 		// Keep the temporary output directory around in case a user wants to inspect it for debugging purposes.
 		// Soong will delete it later anyway.
 		keepOutDir = true
-		return fmt.Errorf("mismatch between declared and actual outputs in sbox command (%s):\n%v", commandDescription, outputErrors)
+		return errors.New(errorMessage)
 	}
 	// the created files match the declared files; now move them
 	for _, filePath := range allOutputs {
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index d9daafc..2536a53 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -23,6 +23,7 @@
     ],
     srcs: [
         "main.go",
+        "writedocs.go",
     ],
     primaryBuilder: true,
 }
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index e15a6bd..40beab8 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -25,6 +25,30 @@
 	"android/soong/android"
 )
 
+var (
+	docFile string
+)
+
+func init() {
+	flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
+}
+
+func newNameResolver(config android.Config) *android.NameResolver {
+	namespacePathsToExport := make(map[string]bool)
+
+	for _, namespaceName := range config.ProductVariables.NamespacesToExport {
+		namespacePathsToExport[namespaceName] = true
+	}
+
+	namespacePathsToExport["."] = true // always export the root namespace
+
+	exportFilter := func(namespace *android.Namespace) bool {
+		return namespacePathsToExport[namespace.Path]
+	}
+
+	return android.NewNameResolver(exportFilter)
+}
+
 func main() {
 	flag.Parse()
 
@@ -40,10 +64,17 @@
 		os.Exit(1)
 	}
 
-	// Temporary hack
-	//ctx.SetIgnoreUnknownModuleTypes(true)
+	if docFile != "" {
+		configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
+	}
+
+	ctx.SetNameInterface(newNameResolver(configuration))
 
 	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
 
 	bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
+
+	if docFile != "" {
+		writeDocs(ctx, docFile)
+	}
 }
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
new file mode 100644
index 0000000..a6686c0
--- /dev/null
+++ b/cmd/soong_build/writedocs.go
@@ -0,0 +1,129 @@
+// 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 main
+
+import (
+	"android/soong/android"
+	"bytes"
+	"html/template"
+	"io/ioutil"
+
+	"github.com/google/blueprint/bootstrap"
+)
+
+func writeDocs(ctx *android.Context, filename string) error {
+	moduleTypeList, err := bootstrap.ModuleTypeDocs(ctx.Context)
+	if err != nil {
+		return err
+	}
+
+	buf := &bytes.Buffer{}
+
+	unique := 0
+
+	tmpl, err := template.New("file").Funcs(map[string]interface{}{
+		"unique": func() int {
+			unique++
+			return unique
+		}}).Parse(fileTemplate)
+	if err != nil {
+		return err
+	}
+
+	err = tmpl.Execute(buf, moduleTypeList)
+	if err != nil {
+		return err
+	}
+
+	err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+const (
+	fileTemplate = `
+<html>
+<head>
+<title>Build Docs</title>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
+</head>
+<body>
+<h1>Build Docs</h1>
+<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
+  {{range .}}
+    {{ $collapseIndex := unique }}
+    <div class="panel panel-default">
+      <div class="panel-heading" role="tab" id="heading{{$collapseIndex}}">
+        <h2 class="panel-title">
+          <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{$collapseIndex}}" aria-expanded="false" aria-controls="collapse{{$collapseIndex}}">
+             {{.Name}}
+          </a>
+        </h2>
+      </div>
+    </div>
+    <div id="collapse{{$collapseIndex}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{$collapseIndex}}">
+      <div class="panel-body">
+        <p>{{.Text}}</p>
+        {{range .PropertyStructs}}
+          <p>{{.Text}}</p>
+          {{template "properties" .Properties}}
+        {{end}}
+      </div>
+    </div>
+  {{end}}
+</div>
+</body>
+</html>
+
+{{define "properties"}}
+  <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
+    {{range .}}
+      {{$collapseIndex := unique}}
+      {{if .Properties}}
+        <div class="panel panel-default">
+          <div class="panel-heading" role="tab" id="heading{{$collapseIndex}}">
+            <h4 class="panel-title">
+              <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{$collapseIndex}}" aria-expanded="false" aria-controls="collapse{{$collapseIndex}}">
+                 {{.Name}}{{range .OtherNames}}, {{.}}{{end}}
+              </a>
+            </h4>
+          </div>
+        </div>
+        <div id="collapse{{$collapseIndex}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{$collapseIndex}}">
+          <div class="panel-body">
+            <p>{{.Text}}</p>
+            {{range .OtherTexts}}<p>{{.}}</p>{{end}}
+            {{template "properties" .Properties}}
+          </div>
+        </div>
+      {{else}}
+        <div>
+          <h4>{{.Name}}{{range .OtherNames}}, {{.}}{{end}}</h4>
+          <p>{{.Text}}</p>
+          {{range .OtherTexts}}<p>{{.}}</p>{{end}}
+          <p><i>Type: {{.Type}}</i></p>
+          {{if .Default}}<p><i>Default: {{.Default}}</i></p>{{end}}
+        </div>
+      {{end}}
+    {{end}}
+  </div>
+{{end}}
+`
+)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0619b5c..2ca7ebf 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -114,7 +114,11 @@
 	} else if os.Args[1] == "--dumpvars-mode" {
 		dumpVars(buildCtx, config, os.Args[2:])
 	} else {
-		build.Build(buildCtx, config, build.BuildAll)
+		toBuild := build.BuildAll
+		if config.Checkbuild() {
+			toBuild |= build.RunBuildTests
+		}
+		build.Build(buildCtx, config, toBuild)
 	}
 }
 
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 6420219..68d8bc7 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -15,8 +15,9 @@
 blueprint_go_binary {
     name: "zip2zip",
     deps: [
-      "android-archive-zip",
-      "soong-jar",
+        "android-archive-zip",
+        "blueprint-pathtools",
+        "soong-jar",
     ],
     srcs: [
         "zip2zip.go",
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index f48d458..e8ea9b9 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -24,6 +24,8 @@
 	"strings"
 	"time"
 
+	"github.com/google/blueprint/pathtools"
+
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
@@ -36,8 +38,14 @@
 	setTime   = flag.Bool("t", false, "set timestamps to 2009-01-01 00:00:00")
 
 	staticTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
+
+	excludes excludeArgs
 )
 
+func init() {
+	flag.Var(&excludes, "x", "exclude a filespec from the output")
+}
+
 func main() {
 	flag.Usage = func() {
 		fmt.Fprintln(os.Stderr, "usage: zip2zip -i zipfile -o zipfile [-s|-j] [-t] [filespec]...")
@@ -45,15 +53,14 @@
 		fmt.Fprintln(os.Stderr, "  filespec:")
 		fmt.Fprintln(os.Stderr, "    <name>")
 		fmt.Fprintln(os.Stderr, "    <in_name>:<out_name>")
-		fmt.Fprintln(os.Stderr, "    <glob>:<out_dir>/")
+		fmt.Fprintln(os.Stderr, "    <glob>[:<out_dir>]")
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "<glob> uses the rules at https://golang.org/pkg/path/filepath/#Match")
-		fmt.Fprintln(os.Stderr, "As a special exception, '**' is supported to specify all files in the input zip.")
+		fmt.Fprintln(os.Stderr, "<glob> uses the rules at https://godoc.org/github.com/google/blueprint/pathtools/#Match")
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, "Files will be copied with their existing compression from the input zipfile to")
 		fmt.Fprintln(os.Stderr, "the output zipfile, in the order of filespec arguments.")
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "If no filepsec is provided all files are copied (equivalent to '**').")
+		fmt.Fprintln(os.Stderr, "If no filepsec is provided all files and directories are copied.")
 	}
 
 	flag.Parse()
@@ -85,7 +92,9 @@
 		}
 	}()
 
-	if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime, flag.Args()); err != nil {
+	if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime,
+		flag.Args(), excludes); err != nil {
+
 		log.Fatal(err)
 	}
 }
@@ -95,91 +104,126 @@
 	newName string
 }
 
-func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, sortJava, setTime bool, args []string) error {
-	if len(args) == 0 {
-		// If no filespec is provided, default to copying everything
-		args = []string{"**"}
-	}
-	for _, arg := range args {
-		var input string
-		var output string
+func zip2zip(reader *zip.Reader, writer *zip.Writer, sortOutput, sortJava, setTime bool,
+	includes []string, excludes []string) error {
 
+	matches := []pair{}
+
+	sortMatches := func(matches []pair) {
+		if sortJava {
+			sort.SliceStable(matches, func(i, j int) bool {
+				return jar.EntryNamesLess(matches[i].newName, matches[j].newName)
+			})
+		} else if sortOutput {
+			sort.SliceStable(matches, func(i, j int) bool {
+				return matches[i].newName < matches[j].newName
+			})
+		}
+	}
+
+	for _, include := range includes {
 		// Reserve escaping for future implementation, so make sure no
 		// one is using \ and expecting a certain behavior.
-		if strings.Contains(arg, "\\") {
+		if strings.Contains(include, "\\") {
 			return fmt.Errorf("\\ characters are not currently supported")
 		}
 
-		args := strings.SplitN(arg, ":", 2)
-		input = args[0]
-		if len(args) == 2 {
-			output = args[1]
-		}
+		input, output := includeSplit(include)
 
-		matches := []pair{}
-		if strings.IndexAny(input, "*?[") >= 0 {
-			matchAll := input == "**"
-			if !matchAll && strings.Contains(input, "**") {
-				return fmt.Errorf("** is only supported on its own, not with other characters")
-			}
+		var includeMatches []pair
 
-			for _, file := range reader.File {
-				match := matchAll
-
-				if !match {
-					var err error
-					match, err = filepath.Match(input, file.Name)
-					if err != nil {
-						return err
-					}
-				}
-
-				if match {
-					var newName string
-					if output == "" {
-						newName = file.Name
-					} else {
+		for _, file := range reader.File {
+			var newName string
+			if match, err := pathtools.Match(input, file.Name); err != nil {
+				return err
+			} else if match {
+				if output == "" {
+					newName = file.Name
+				} else {
+					if pathtools.IsGlob(input) {
+						// If the input is a glob then the output is a directory.
 						_, name := filepath.Split(file.Name)
 						newName = filepath.Join(output, name)
+					} else {
+						// Otherwise it is a file.
+						newName = output
 					}
-					matches = append(matches, pair{file, newName})
 				}
-			}
-
-			if sortJava {
-				jarSort(matches)
-			} else if sortGlobs {
-				sort.SliceStable(matches, func(i, j int) bool {
-					return matches[i].newName < matches[j].newName
-				})
-			}
-		} else {
-			if output == "" {
-				output = input
-			}
-			for _, file := range reader.File {
-				if input == file.Name {
-					matches = append(matches, pair{file, output})
-					break
-				}
+				includeMatches = append(includeMatches, pair{file, newName})
 			}
 		}
 
-		for _, match := range matches {
-			if setTime {
-				match.File.SetModTime(staticTime)
-			}
-			if err := writer.CopyFrom(match.File, match.newName); err != nil {
+		sortMatches(includeMatches)
+		matches = append(matches, includeMatches...)
+	}
+
+	if len(includes) == 0 {
+		// implicitly match everything
+		for _, file := range reader.File {
+			matches = append(matches, pair{file, file.Name})
+		}
+		sortMatches(matches)
+	}
+
+	var matchesAfterExcludes []pair
+	seen := make(map[string]*zip.File)
+
+	for _, match := range matches {
+		// Filter out matches whose original file name matches an exclude filter
+		excluded := false
+		for _, exclude := range excludes {
+			if excludeMatch, err := pathtools.Match(exclude, match.File.Name); err != nil {
 				return err
+			} else if excludeMatch {
+				excluded = true
+				break
 			}
 		}
+
+		if excluded {
+			continue
+		}
+
+		// Check for duplicate output names, ignoring ones that come from the same input zip entry.
+		if prev, exists := seen[match.newName]; exists {
+			if prev != match.File {
+				return fmt.Errorf("multiple entries for %q with different contents", match.newName)
+			}
+			continue
+		}
+		seen[match.newName] = match.File
+
+		matchesAfterExcludes = append(matchesAfterExcludes, match)
+	}
+
+	for _, match := range matchesAfterExcludes {
+		if setTime {
+			match.File.SetModTime(staticTime)
+		}
+		if err := writer.CopyFrom(match.File, match.newName); err != nil {
+			return err
+		}
 	}
 
 	return nil
 }
 
-func jarSort(files []pair) {
-	sort.SliceStable(files, func(i, j int) bool {
-		return jar.EntryNamesLess(files[i].newName, files[j].newName)
-	})
+func includeSplit(s string) (string, string) {
+	split := strings.SplitN(s, ":", 2)
+	if len(split) == 2 {
+		return split[0], split[1]
+	} else {
+		return split[0], ""
+	}
+}
+
+type excludeArgs []string
+
+func (e *excludeArgs) String() string {
+	return strings.Join(*e, " ")
+}
+
+func (e *excludeArgs) Set(s string) error {
+	*e = append(*e, s)
+	return nil
 }
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 53c8ce2..212ab28 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -30,6 +30,7 @@
 	sortGlobs  bool
 	sortJava   bool
 	args       []string
+	excludes   []string
 
 	outputFiles []string
 	err         error
@@ -41,13 +42,6 @@
 
 		err: fmt.Errorf("\\ characters are not currently supported"),
 	},
-	{
-		name: "unsupported **",
-
-		args: []string{"a/**:b"},
-
-		err: fmt.Errorf("** is only supported on its own, not with other characters"),
-	},
 	{ // This is modelled after the update package build rules in build/make/core/Makefile
 		name: "filter globs",
 
@@ -95,16 +89,19 @@
 		name: "sort all",
 
 		inputFiles: []string{
+			"RADIO/",
 			"RADIO/a",
+			"IMAGES/",
 			"IMAGES/system.img",
 			"IMAGES/b.txt",
 			"IMAGES/recovery.img",
 			"IMAGES/vendor.img",
+			"OTA/",
 			"OTA/b",
 			"OTA/android-info.txt",
 		},
 		sortGlobs: true,
-		args:      []string{"**"},
+		args:      []string{"**/*"},
 
 		outputFiles: []string{
 			"IMAGES/b.txt",
@@ -120,11 +117,14 @@
 		name: "sort all implicit",
 
 		inputFiles: []string{
+			"RADIO/",
 			"RADIO/a",
+			"IMAGES/",
 			"IMAGES/system.img",
 			"IMAGES/b.txt",
 			"IMAGES/recovery.img",
 			"IMAGES/vendor.img",
+			"OTA/",
 			"OTA/b",
 			"OTA/android-info.txt",
 		},
@@ -132,12 +132,15 @@
 		args:      nil,
 
 		outputFiles: []string{
+			"IMAGES/",
 			"IMAGES/b.txt",
 			"IMAGES/recovery.img",
 			"IMAGES/system.img",
 			"IMAGES/vendor.img",
+			"OTA/",
 			"OTA/android-info.txt",
 			"OTA/b",
+			"RADIO/",
 			"RADIO/a",
 		},
 	},
@@ -177,7 +180,7 @@
 			"b",
 			"a",
 		},
-		args: []string{"a:a2", "**"},
+		args: []string{"a:a2", "**/*"},
 
 		outputFiles: []string{
 			"a2",
@@ -185,6 +188,69 @@
 			"a",
 		},
 	},
+	{
+		name: "multiple matches",
+
+		inputFiles: []string{
+			"a/a",
+		},
+		args: []string{"a/a", "a/*"},
+
+		outputFiles: []string{
+			"a/a",
+		},
+	},
+	{
+		name: "multiple conflicting matches",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args: []string{"a/b:a/a", "a/*"},
+
+		err: fmt.Errorf(`multiple entries for "a/a" with different contents`),
+	},
+	{
+		name: "excludes",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     nil,
+		excludes: []string{"a/a"},
+
+		outputFiles: []string{
+			"a/b",
+		},
+	},
+	{
+		name: "excludes with include",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     []string{"a/*"},
+		excludes: []string{"a/a"},
+
+		outputFiles: []string{
+			"a/b",
+		},
+	},
+	{
+		name: "excludes with glob",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     []string{"a/*"},
+		excludes: []string{"a/*"},
+
+		outputFiles: nil,
+	},
 }
 
 func errorString(e error) string {
@@ -216,7 +282,7 @@
 			}
 
 			outputWriter := zip.NewWriter(outputBuf)
-			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args)
+			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args, testCase.excludes)
 			if errorString(testCase.err) != errorString(err) {
 				t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
 			}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index c142c53..4f3ba93 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -131,21 +131,17 @@
 
 func (g *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
 	android.ExtractSourcesDeps(ctx, g.properties.Srcs)
+	android.ExtractSourcesDeps(ctx, g.properties.Tool_files)
 	if g, ok := ctx.Module().(*Module); ok {
 		if len(g.properties.Tools) > 0 {
 			ctx.AddFarVariationDependencies([]blueprint.Variation{
-				{"arch", ctx.AConfig().BuildOsVariant},
+				{"arch", ctx.Config().BuildOsVariant},
 			}, hostToolDepTag, g.properties.Tools...)
 		}
 	}
 }
 
 func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
-		ctx.ModuleErrorf("at least one `tools` or `tool_files` is required")
-		return
-	}
-
 	if len(g.properties.Export_include_dirs) > 0 {
 		for _, dir := range g.properties.Export_include_dirs {
 			g.exportedIncludeDirs = append(g.exportedIncludeDirs,
@@ -168,7 +164,7 @@
 
 				if t, ok := module.(HostToolProvider); ok {
 					if !t.(android.Module).Enabled() {
-						if ctx.AConfig().AllowMissingDependencies() {
+						if ctx.Config().AllowMissingDependencies() {
 							ctx.AddMissingDependencies([]string{tool})
 						} else {
 							ctx.ModuleErrorf("depends on disabled module %q", tool)
@@ -208,13 +204,13 @@
 		return
 	}
 
-	for _, tool := range g.properties.Tool_files {
-		toolPath := android.PathForModuleSrc(ctx, tool)
-		g.deps = append(g.deps, toolPath)
-		if _, exists := tools[tool]; !exists {
-			tools[tool] = toolPath
+	toolFiles := ctx.ExpandSources(g.properties.Tool_files, nil)
+	for _, tool := range toolFiles {
+		g.deps = append(g.deps, tool)
+		if _, exists := tools[tool.Rel()]; !exists {
+			tools[tool.Rel()] = tool
 		} else {
-			ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], toolPath.String())
+			ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool.Rel()], tool.Rel())
 		}
 	}
 
@@ -226,10 +222,14 @@
 	rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
 		switch name {
 		case "location":
+			if len(g.properties.Tools) == 0 && len(toolFiles) == 0 {
+				return "", fmt.Errorf("at least one `tools` or `tool_files` is required if $(location) is used")
+			}
+
 			if len(g.properties.Tools) > 0 {
 				return tools[g.properties.Tools[0]].String(), nil
 			} else {
-				return tools[g.properties.Tool_files[0]].String(), nil
+				return tools[toolFiles[0].Rel()].String(), nil
 			}
 		case "in":
 			return "${in}", nil
@@ -277,7 +277,10 @@
 	}
 
 	genDir := android.PathForModuleGen(ctx)
-	sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %q %s $allouts", sandboxPath, genDir, rawCommand, depfilePlaceholder)
+	// Escape the command for the shell
+	rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
+	sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
+		sandboxPath, genDir, rawCommand, depfilePlaceholder)
 
 	ruleParams := blueprint.RuleParams{
 		Command:     sandboxCommand,
diff --git a/java/aapt2.go b/java/aapt2.go
new file mode 100644
index 0000000..84e3729
--- /dev/null
+++ b/java/aapt2.go
@@ -0,0 +1,166 @@
+// 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 java
+
+import (
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+const AAPT2_SHARD_SIZE = 100
+
+// Convert input resource file path to output file path.
+// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
+// For other resource file, just replace the last "/" with "_" and
+// add .flat extension.
+func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
+
+	name := res.Base()
+	subDir := filepath.Dir(res.String())
+	subDir, lastDir := filepath.Split(subDir)
+	if strings.HasPrefix(lastDir, "values") {
+		name = strings.TrimSuffix(name, ".xml") + ".arsc"
+	}
+	name = lastDir + "_" + name + ".flat"
+	return android.PathForModuleOut(ctx, "aapt2", subDir, name)
+}
+
+func pathsToAapt2Paths(ctx android.ModuleContext, resPaths android.Paths) android.WritablePaths {
+	outPaths := make(android.WritablePaths, len(resPaths))
+
+	for i, res := range resPaths {
+		outPaths[i] = pathToAapt2Path(ctx, res)
+	}
+
+	return outPaths
+}
+
+var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
+	blueprint.RuleParams{
+		Command:     `${config.Aapt2Cmd} compile -o $outDir $cFlags --legacy $in`,
+		CommandDeps: []string{"${config.Aapt2Cmd}"},
+	},
+	"outDir", "cFlags")
+
+func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths) android.WritablePaths {
+	shards := shardPaths(paths, AAPT2_SHARD_SIZE)
+
+	ret := make(android.WritablePaths, 0, len(paths))
+
+	for i, shard := range shards {
+		outPaths := pathsToAapt2Paths(ctx, shard)
+		ret = append(ret, outPaths...)
+
+		shardDesc := ""
+		if i != 0 {
+			shardDesc = " " + strconv.Itoa(i+1)
+		}
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        aapt2CompileRule,
+			Description: "aapt2 compile " + dir.String() + shardDesc,
+			Inputs:      shard,
+			Outputs:     outPaths,
+			Args: map[string]string{
+				"outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(),
+				"cFlags": "--pseudo-localize",
+			},
+		})
+	}
+
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].String() < ret[j].String()
+	})
+	return ret
+}
+
+var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
+	blueprint.RuleParams{
+		Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions $inFlags && ` +
+			`${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir`,
+		CommandDeps: []string{
+			"${config.Aapt2Cmd}",
+			"${config.SoongZipCmd}",
+		},
+		Restat: true,
+	},
+	"flags", "inFlags", "proguardOptions", "genDir", "genJar")
+
+var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
+	blueprint.RuleParams{
+		Command:        `cp $out.rsp $out`,
+		Rspfile:        "$out.rsp",
+		RspfileContent: "$in",
+	})
+
+func aapt2Link(ctx android.ModuleContext,
+	packageRes, genJar, proguardOptions android.WritablePath,
+	flags []string, deps android.Paths,
+	compiledRes, compiledOverlay android.Paths) {
+
+	genDir := android.PathForModuleGen(ctx, "aapt2", "R")
+
+	var inFlags []string
+
+	if len(compiledRes) > 0 {
+		resFileList := android.PathForModuleOut(ctx, "aapt2", "res.list")
+		// Write out file lists to files
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        fileListToFileRule,
+			Description: "resource file list",
+			Inputs:      compiledRes,
+			Output:      resFileList,
+		})
+
+		deps = append(deps, compiledRes...)
+		deps = append(deps, resFileList)
+		inFlags = append(inFlags, "@"+resFileList.String())
+	}
+
+	if len(compiledOverlay) > 0 {
+		overlayFileList := android.PathForModuleOut(ctx, "aapt2", "overlay.list")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        fileListToFileRule,
+			Description: "overlay resource file list",
+			Inputs:      compiledOverlay,
+			Output:      overlayFileList,
+		})
+
+		deps = append(deps, compiledOverlay...)
+		deps = append(deps, overlayFileList)
+		inFlags = append(inFlags, "-R", "@"+overlayFileList.String())
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:            aapt2LinkRule,
+		Description:     "aapt2 link",
+		Implicits:       deps,
+		Output:          packageRes,
+		ImplicitOutputs: android.WritablePaths{proguardOptions, genJar},
+		Args: map[string]string{
+			"flags":           strings.Join(flags, " "),
+			"inFlags":         strings.Join(inFlags, " "),
+			"proguardOptions": proguardOptions.String(),
+			"genDir":          genDir.String(),
+			"genJar":          genJar.String(),
+		},
+	})
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 1c0526a..24fe43a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -31,17 +31,47 @@
 		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
+				if len(library.logtagsSrcs) > 0 {
+					var logtags []string
+					for _, l := range library.logtagsSrcs {
+						logtags = append(logtags, l.Rel())
+					}
+					fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(logtags, " "))
+				}
+
 				if library.properties.Installable != nil && *library.properties.Installable == false {
 					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 				}
 				if library.dexJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
-					if library.deviceProperties.Dex_preopt == nil || *library.deviceProperties.Dex_preopt == false {
-						fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+					if library.deviceProperties.Dex_preopt.Enabled != nil {
+						fmt.Fprintln(w, "LOCAL_DEX_PREOPT :=", *library.deviceProperties.Dex_preopt.Enabled)
+					}
+					if library.deviceProperties.Dex_preopt.App_image != nil {
+						fmt.Fprintln(w, "LOCAL_DEX_PREOPT_APP_IMAGE :=", *library.deviceProperties.Dex_preopt.App_image)
+					}
+					if library.deviceProperties.Dex_preopt.Profile_guided != nil {
+						fmt.Fprintln(w, "LOCAL_DEX_PREOPT_GENERATE_PROFILE :=", *library.deviceProperties.Dex_preopt.Profile_guided)
+					}
+					if library.deviceProperties.Dex_preopt.Profile != nil {
+						fmt.Fprintln(w, "LOCAL_DEX_PREOPT_GENERATE_PROFILE := true")
+						fmt.Fprintln(w, "LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING := $(LOCAL_PATH)/"+*library.deviceProperties.Dex_preopt.Profile)
 					}
 				}
 				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", String(library.deviceProperties.Sdk_version))
 				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
+
+				if library.jacocoReportClassesFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", library.jacocoReportClassesFile.String())
+				}
+
+				// 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" {
+					fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCS :=", strings.Join(library.compiledJavaSrcs.Strings(), " "))
+					fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCJARS :=", strings.Join(library.compiledSrcJars.Strings(), " "))
+				}
 			},
 		},
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
@@ -83,27 +113,83 @@
 }
 
 func (binary *Binary) AndroidMk() android.AndroidMkData {
+
+	if !binary.isWrapperVariant {
+		return android.AndroidMkData{
+			Class:      "JAVA_LIBRARIES",
+			OutputFile: android.OptionalPathForPath(binary.implementationJarFile),
+			Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+				android.WriteAndroidMkData(w, data)
+
+				fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
+			},
+		}
+	} else {
+		return android.AndroidMkData{
+			Class:      "EXECUTABLES",
+			OutputFile: android.OptionalPathForPath(binary.wrapperFile),
+			Extra: []android.AndroidMkExtraFunc{
+				func(w io.Writer, outputFile android.Path) {
+					fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+				},
+			},
+			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+				android.WriteAndroidMkData(w, data)
+
+				// Ensure that the wrapper script timestamp is always updated when the jar is updated
+				fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
+				fmt.Fprintln(w, "jar_installed_module :=")
+			},
+		}
+	}
+}
+
+func (app *AndroidApp) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
-		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(binary.implementationJarFile),
-		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
-		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-			android.WriteAndroidMkData(w, data)
+		Class:      "APPS",
+		OutputFile: android.OptionalPathForPath(app.outputFile),
+		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
+				if app.dexJarFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
+				}
+				if app.implementationJarFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", app.implementationJarFile)
+				}
+				if app.headerJarFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", app.headerJarFile.String())
+				}
+				if app.jacocoReportClassesFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
+				}
 
-			fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
-			fmt.Fprintln(w, "include $(CLEAR_VARS)")
-			fmt.Fprintln(w, "LOCAL_MODULE := "+name)
-			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := EXECUTABLES")
-			if strings.Contains(prefix, "HOST_") {
-				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
-			}
-			fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
-			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", binary.wrapperFile.String())
-			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+				if app.Name() == "framework-res" {
+					fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+					// Make base_rules.mk not put framework-res in a subdirectory called
+					// framework_res.
+					fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
+				}
 
-			// Ensure that the wrapper script timestamp is always updated when the jar is updated
-			fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
-			fmt.Fprintln(w, "jar_installed_module :=")
+				if len(app.rroDirs) > 0 {
+					fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(app.rroDirs.Strings(), " "))
+				}
+
+				if Bool(app.appProperties.Export_package_resources) {
+					fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES := true")
+				}
+
+				fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String())
+
+				if Bool(app.appProperties.Privileged) {
+					fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
+				}
+
+				fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.pem.String())
+			},
 		},
 	}
+
 }
diff --git a/java/app.go b/java/app.go
index 05cc975..df53375 100644
--- a/java/app.go
+++ b/java/app.go
@@ -25,6 +25,11 @@
 	"android/soong/android"
 )
 
+func init() {
+	android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+	android.RegisterModuleType("android_app", AndroidAppFactory)
+}
+
 // AAR prebuilts
 // AndroidManifest.xml merging
 // package splits
@@ -54,6 +59,13 @@
 	// list of directories relative to the Blueprints file containing
 	// Android resources
 	Resource_dirs []string
+
+	Instrumentation_for *string
+
+	// 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
 }
 
 type AndroidApp struct {
@@ -61,16 +73,23 @@
 
 	appProperties androidAppProperties
 
-	aaptJavaFileList android.Path
-	exportPackage    android.Path
+	aaptSrcJar    android.Path
+	exportPackage android.Path
+	rroDirs       android.Paths
+	manifestPath  android.Path
+	certificate   certificate
+}
+
+type certificate struct {
+	pem, key android.Path
 }
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
 
-	if !proptools.Bool(a.properties.No_standard_libs) {
+	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
 		switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
-		case "current", "system_current", "":
+		case "current", "system_current", "test_current", "":
 			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
 		default:
 			// We'll already have a dependency on an sdk prebuilt android.jar
@@ -79,38 +98,29 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	aaptFlags, aaptDeps, hasResources := a.aaptFlags(ctx)
+	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
 
-	if hasResources {
-		// First generate R.java so we can build the .class files
-		aaptRJavaFlags := append([]string(nil), aaptFlags...)
+	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
+	srcJar := android.PathForModuleGen(ctx, "R.jar")
+	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
 
-		publicResourcesFile, proguardOptionsFile, aaptJavaFileList :=
-			CreateResourceJavaFiles(ctx, aaptRJavaFlags, aaptDeps)
-		a.aaptJavaFileList = aaptJavaFileList
-		// TODO(ccross):  export aapt generated java files as a src jar
-
-		if Bool(a.appProperties.Export_package_resources) {
-			aaptPackageFlags := append([]string(nil), aaptFlags...)
-			var hasProduct bool
-			for _, f := range aaptPackageFlags {
-				if strings.HasPrefix(f, "--product") {
-					hasProduct = true
-					break
-				}
-			}
-
-			if !hasProduct {
-				aaptPackageFlags = append(aaptPackageFlags,
-					"--product "+ctx.AConfig().ProductAAPTCharacteristics())
-			}
-			a.exportPackage = CreateExportPackage(ctx, aaptPackageFlags, aaptDeps)
-			ctx.CheckbuildFile(a.exportPackage)
-		}
-		ctx.CheckbuildFile(publicResourcesFile)
-		ctx.CheckbuildFile(proguardOptionsFile)
-		ctx.CheckbuildFile(aaptJavaFileList)
+	var compiledRes, compiledOverlay android.Paths
+	for _, dir := range resDirs {
+		compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
 	}
+	for _, dir := range overlayDirs {
+		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+	}
+
+	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
+		linkFlags, linkDeps, compiledRes, compiledOverlay)
+
+	a.exportPackage = packageRes
+	a.aaptSrcJar = srcJar
+
+	ctx.CheckbuildFile(proguardOptionsFile)
+	ctx.CheckbuildFile(a.exportPackage)
+	ctx.CheckbuildFile(a.aaptSrcJar)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -119,38 +129,56 @@
 	//	a.properties.Proguard.Enabled = true
 	//}
 
-	a.Module.compile(ctx)
+	if String(a.appProperties.Instrumentation_for) == "" {
+		a.properties.Instrument = true
+	}
 
-	aaptPackageFlags := append([]string(nil), aaptFlags...)
-	var hasProduct bool
-	for _, f := range aaptPackageFlags {
-		if strings.HasPrefix(f, "--product") {
-			hasProduct = true
-			break
+	if ctx.ModuleName() != "framework-res" {
+		a.Module.compile(ctx, a.aaptSrcJar)
+	}
+
+	c := String(a.appProperties.Certificate)
+	switch {
+	case c == "":
+		pem, key := ctx.Config().DefaultAppCertificate(ctx)
+		a.certificate = certificate{pem, key}
+	case strings.ContainsRune(c, '/'):
+		a.certificate = certificate{
+			android.PathForSource(ctx, c+".x509.pem"),
+			android.PathForSource(ctx, c+".pk8"),
+		}
+	default:
+		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+		a.certificate = certificate{
+			defaultDir.Join(ctx, c+".x509.pem"),
+			defaultDir.Join(ctx, c+".pk8"),
 		}
 	}
 
-	if !hasProduct {
-		aaptPackageFlags = append(aaptPackageFlags,
-			"--product "+ctx.AConfig().ProductAAPTCharacteristics())
-	}
-
-	certificate := String(a.appProperties.Certificate)
-	if certificate == "" {
-		certificate = ctx.AConfig().DefaultAppCertificate(ctx).String()
-	} else if dir, _ := filepath.Split(certificate); dir == "" {
-		certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(ctx).String(), certificate)
-	} else {
-		certificate = filepath.Join(android.PathForSource(ctx).String(), certificate)
-	}
-
-	certificates := []string{certificate}
+	certificates := []certificate{a.certificate}
 	for _, c := range a.appProperties.Additional_certificates {
-		certificates = append(certificates, filepath.Join(android.PathForSource(ctx).String(), c))
+		certificates = append(certificates, certificate{
+			android.PathForSource(ctx, c+".x509.pem"),
+			android.PathForSource(ctx, c+".pk8"),
+		})
 	}
 
-	a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates)
-	ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	packageFile := android.PathForModuleOut(ctx, "package.apk")
+
+	CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
+
+	a.outputFile = packageFile
+	a.rroDirs = rroDirs
+	a.manifestPath = manifestPath
+
+	if ctx.ModuleName() == "framework-res" {
+		// framework-res.apk is installed as system/framework/framework-res.apk
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".apk", a.outputFile)
+	} else if Bool(a.appProperties.Privileged) {
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "priv-app"), ctx.ModuleName()+".apk", a.outputFile)
+	} else {
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	}
 }
 
 var aaptIgnoreFilenames = []string{
@@ -165,57 +193,57 @@
 	"*~",
 }
 
-func (a *AndroidApp) aaptFlags(ctx android.ModuleContext) ([]string, android.Paths, bool) {
-	aaptFlags := a.appProperties.Aaptflags
+type globbedResourceDir struct {
+	dir   android.Path
+	files android.Paths
+}
+
+func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
+	resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
+
 	hasVersionCode := false
 	hasVersionName := false
-	for _, f := range aaptFlags {
+	hasProduct := false
+	for _, f := range a.appProperties.Aaptflags {
 		if strings.HasPrefix(f, "--version-code") {
 			hasVersionCode = true
 		} else if strings.HasPrefix(f, "--version-name") {
 			hasVersionName = true
+		} else if strings.HasPrefix(f, "--product") {
+			hasProduct = true
 		}
 	}
 
-	if true /* is not a test */ {
-		aaptFlags = append(aaptFlags, "-z")
-	}
+	var linkFlags []string
 
+	// Flags specified in Android.bp
+	linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
+
+	linkFlags = append(linkFlags, "--no-static-lib-packages")
+
+	// Find implicit or explicit asset and resource dirs
 	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
 	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
 
-	var overlayResourceDirs android.Paths
-	// For every resource directory, check if there is an overlay directory with the same path.
-	// If found, it will be prepended to the list of resource directories.
-	for _, overlayDir := range ctx.AConfig().ResourceOverlays() {
-		for _, resourceDir := range resourceDirs {
-			overlay := overlayDir.OverlayPath(ctx, resourceDir)
-			if overlay.Valid() {
-				overlayResourceDirs = append(overlayResourceDirs, overlay.Path())
-			}
-		}
+	var linkDeps android.Paths
+
+	// Glob directories into lists of paths
+	for _, dir := range resourceDirs {
+		resDirs = append(resDirs, globbedResourceDir{
+			dir:   dir,
+			files: resourceGlob(ctx, dir),
+		})
+		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+		overlayDirs = append(overlayDirs, resOverlayDirs...)
+		rroDirs = append(rroDirs, resRRODirs...)
 	}
 
-	if len(overlayResourceDirs) > 0 {
-		resourceDirs = append(overlayResourceDirs, resourceDirs...)
+	var assetFiles android.Paths
+	for _, dir := range assetDirs {
+		assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
 	}
 
-	// aapt needs to rerun if any files are added or modified in the assets or resource directories,
-	// use glob to create a filelist.
-	var aaptDeps android.Paths
-	var hasResources bool
-	for _, d := range resourceDirs {
-		newDeps := ctx.Glob(filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames)
-		aaptDeps = append(aaptDeps, newDeps...)
-		if len(newDeps) > 0 {
-			hasResources = true
-		}
-	}
-	for _, d := range assetDirs {
-		newDeps := ctx.Glob(filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames)
-		aaptDeps = append(aaptDeps, newDeps...)
-	}
-
+	// App manifest file
 	var manifestFile string
 	if a.properties.Manifest == nil {
 		manifestFile = "AndroidManifest.xml"
@@ -223,51 +251,74 @@
 		manifestFile = *a.properties.Manifest
 	}
 
-	manifestPath := android.PathForModuleSrc(ctx, manifestFile)
-	aaptDeps = append(aaptDeps, manifestPath)
+	manifestPath = android.PathForModuleSrc(ctx, manifestFile)
+	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
+	linkDeps = append(linkDeps, manifestPath)
 
-	aaptFlags = append(aaptFlags, "-M "+manifestPath.String())
-	aaptFlags = append(aaptFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
-	aaptFlags = append(aaptFlags, android.JoinWithPrefix(resourceDirs.Strings(), "-S "))
+	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
+	linkDeps = append(linkDeps, assetFiles...)
 
+	// Include dirs
 	ctx.VisitDirectDeps(func(module android.Module) {
 		var depFiles android.Paths
 		if javaDep, ok := module.(Dependency); ok {
+			// TODO: shared android libraries
 			if ctx.OtherModuleName(module) == "framework-res" {
 				depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
 			}
 		}
 
 		for _, dep := range depFiles {
-			aaptFlags = append(aaptFlags, "-I "+dep.String())
+			linkFlags = append(linkFlags, "-I "+dep.String())
 		}
-		aaptDeps = append(aaptDeps, depFiles...)
+		linkDeps = append(linkDeps, depFiles...)
 	})
 
+	// SDK version flags
 	sdkVersion := String(a.deviceProperties.Sdk_version)
-	if sdkVersion == "" {
-		sdkVersion = ctx.AConfig().PlatformSdkVersion()
+	switch sdkVersion {
+	case "", "current", "system_current", "test_current":
+		sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
 	}
 
-	aaptFlags = append(aaptFlags, "--min-sdk-version "+sdkVersion)
-	aaptFlags = append(aaptFlags, "--target-sdk-version "+sdkVersion)
+	linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
+	linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
 
+	// Product characteristics
+	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+		linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
+	}
+
+	// Product AAPT config
+	for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
+		linkFlags = append(linkFlags, "-c", aaptConfig)
+	}
+
+	// Product AAPT preferred config
+	if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
+		linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
+	}
+
+	// Version code
 	if !hasVersionCode {
-		aaptFlags = append(aaptFlags, "--version-code "+ctx.AConfig().PlatformSdkVersion())
+		linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
 	}
 
 	if !hasVersionName {
-		aaptFlags = append(aaptFlags,
-			"--version-name "+ctx.AConfig().PlatformVersion()+"-"+ctx.AConfig().BuildNumber())
+		versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+		linkFlags = append(linkFlags, "--version-name ", versionName)
+	}
+
+	if String(a.appProperties.Instrumentation_for) != "" {
+		linkFlags = append(linkFlags,
+			"--rename-instrumentation-target-package",
+			String(a.appProperties.Instrumentation_for))
 	}
 
 	// TODO: LOCAL_PACKAGE_OVERRIDES
 	//    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
 
-	// TODO: LOCAL_INSTRUMENTATION_FOR
-	//    $(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR))
-
-	return aaptFlags, aaptDeps, hasResources
+	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
 }
 
 func AndroidAppFactory() android.Module {
@@ -281,3 +332,114 @@
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
+
+func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
+	var ret android.Paths
+	files := ctx.Glob(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
+	for _, f := range files {
+		if isDir, err := ctx.Fs().IsDir(f.String()); err != nil {
+			ctx.ModuleErrorf("error in IsDir(%s): %s", f.String(), err.Error())
+			return nil
+		} else if !isDir {
+			ret = append(ret, f)
+		}
+	}
+	return ret
+}
+
+type overlayGlobResult struct {
+	dir   string
+	paths android.DirectorySortedPaths
+
+	// Set to true of the product has selected that values in this overlay should not be moved to
+	// Runtime Resource Overlay (RRO) packages.
+	excludeFromRRO bool
+}
+
+const overlayDataKey = "overlayDataKey"
+
+func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+	rroDirs android.Paths) {
+
+	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
+
+	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
+	rroEnabled := false
+	enforceRROTargets := ctx.Config().ProductVariables.EnforceRROTargets
+	if enforceRROTargets != nil {
+		if len(*enforceRROTargets) == 1 && (*enforceRROTargets)[0] == "*" {
+			rroEnabled = true
+		} else if inList(ctx.ModuleName(), *enforceRROTargets) {
+			rroEnabled = true
+		}
+	}
+
+	for _, data := range overlayData {
+		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
+		if len(files) > 0 {
+			overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
+			// If enforce RRO is enabled for this module and this overlay is not in the
+			// exclusion list, ignore the overlay.  The list of ignored overlays will be
+			// passed to Make to be turned into an RRO package.
+			if rroEnabled && !data.excludeFromRRO {
+				rroDirs = append(rroDirs, overlayModuleDir)
+			} else {
+				res = append(res, globbedResourceDir{
+					dir:   overlayModuleDir,
+					files: files,
+				})
+			}
+		}
+	}
+
+	return res, rroDirs
+}
+
+func OverlaySingletonFactory() android.Singleton {
+	return overlaySingleton{}
+}
+
+type overlaySingleton struct{}
+
+func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+
+	// Specific overlays may be excluded from Runtime Resource Overlays by the product config
+	var rroExcludedOverlays []string
+	if ctx.Config().ProductVariables.EnforceRROExcludedOverlays != nil {
+		rroExcludedOverlays = *ctx.Config().ProductVariables.EnforceRROExcludedOverlays
+	}
+
+	var overlayData []overlayGlobResult
+	for _, overlay := range ctx.Config().ResourceOverlays() {
+		var result overlayGlobResult
+		result.dir = overlay
+
+		// Mark overlays that will not have Runtime Resource Overlays enforced on them
+		for _, exclude := range rroExcludedOverlays {
+			if strings.HasPrefix(overlay, exclude) {
+				result.excludeFromRRO = true
+			}
+		}
+
+		files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
+		if err != nil {
+			ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
+			continue
+		}
+		var paths android.Paths
+		for _, f := range files {
+			if isDir, err := ctx.Fs().IsDir(f); err != nil {
+				ctx.Errorf("error in IsDir(%s): %s", f, err.Error())
+				return
+			} else if !isDir {
+				paths = append(paths, android.PathForSource(ctx, f))
+			}
+		}
+		result.paths = android.PathsToDirectorySortedPaths(paths)
+		overlayData = append(overlayData, result)
+	}
+
+	ctx.Config().Once(overlayDataKey, func() interface{} {
+		return overlayData
+	})
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index ed7abce..945d7bd 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -27,35 +27,11 @@
 )
 
 var (
-	aaptCreateResourceJavaFile = pctx.AndroidStaticRule("aaptCreateResourceJavaFile",
-		blueprint.RuleParams{
-			Command: `rm -rf "$javaDir" && mkdir -p "$javaDir" && ` +
-				`$aaptCmd package -m $aaptFlags -P $publicResourcesFile -G $proguardOptionsFile ` +
-				`-J $javaDir || ( rm -rf "$javaDir/*"; exit 41 ) && ` +
-				`find $javaDir -name "*.java" > $javaFileList`,
-			CommandDeps: []string{"$aaptCmd"},
-		},
-		"aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
-
-	aaptCreateAssetsPackage = pctx.AndroidStaticRule("aaptCreateAssetsPackage",
-		blueprint.RuleParams{
-			Command:     `rm -f $out && $aaptCmd package $aaptFlags -F $out`,
-			CommandDeps: []string{"$aaptCmd"},
-		},
-		"aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
-
-	aaptAddResources = pctx.AndroidStaticRule("aaptAddResources",
-		blueprint.RuleParams{
-			// TODO: add-jni-shared-libs-to-package
-			Command:     `cp -f $in $out.tmp && $aaptCmd package -u $aaptFlags -F $out.tmp && mv $out.tmp $out`,
-			CommandDeps: []string{"$aaptCmd"},
-		},
-		"aaptFlags")
-
 	signapk = pctx.AndroidStaticRule("signapk",
 		blueprint.RuleParams{
-			Command:     `java -jar $signapkCmd $certificates $in $out`,
-			CommandDeps: []string{"$signapkCmd"},
+			Command: `${config.JavaCmd} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
+				`-jar $signapkCmd $certificates $in $out`,
+			CommandDeps: []string{"$signapkCmd", "$signapkJniLibrary"},
 		},
 		"certificates")
 
@@ -73,79 +49,50 @@
 	pctx.SourcePathVariable("androidManifestMergerCmd", "prebuilts/devtools/tools/lib/manifest-merger.jar")
 	pctx.HostBinToolVariable("aaptCmd", "aapt")
 	pctx.HostJavaToolVariable("signapkCmd", "signapk.jar")
+	// TODO(ccross): this should come from the signapk dependencies, but we don't have any way
+	// to express host JNI dependencies yet.
+	pctx.HostJNIToolVariable("signapkJniLibrary", "libconscrypt_openjdk_jni")
 }
 
-func CreateResourceJavaFiles(ctx android.ModuleContext, flags []string,
-	deps android.Paths) (android.Path, android.Path, android.Path) {
-	javaDir := android.PathForModuleGen(ctx, "R")
-	javaFileList := android.PathForModuleOut(ctx, "R.filelist")
-	publicResourcesFile := android.PathForModuleOut(ctx, "public_resources.xml")
-	proguardOptionsFile := android.PathForModuleOut(ctx, "proguard.options")
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        aaptCreateResourceJavaFile,
-		Description: "aapt create R.java",
-		Outputs:     android.WritablePaths{publicResourcesFile, proguardOptionsFile, javaFileList},
-		Implicits:   deps,
-		Args: map[string]string{
-			"aaptFlags":           strings.Join(flags, " "),
-			"publicResourcesFile": publicResourcesFile.String(),
-			"proguardOptionsFile": proguardOptionsFile.String(),
-			"javaDir":             javaDir.String(),
-			"javaFileList":        javaFileList.String(),
-		},
+var combineApk = pctx.AndroidStaticRule("combineApk",
+	blueprint.RuleParams{
+		Command:     `${config.MergeZipsCmd} $out $in`,
+		CommandDeps: []string{"${config.MergeZipsCmd}"},
 	})
 
-	return publicResourcesFile, proguardOptionsFile, javaFileList
-}
+func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
+	resJarFile, dexJarFile android.Path, certificates []certificate) {
 
-func CreateExportPackage(ctx android.ModuleContext, flags []string, deps android.Paths) android.ModuleOutPath {
-	outputFile := android.PathForModuleOut(ctx, "package-export.apk")
+	// TODO(ccross): JNI libs
+
+	unsignedApk := android.PathForModuleOut(ctx, "unsigned.apk")
+
+	inputs := android.Paths{resJarFile}
+	if dexJarFile != nil {
+		inputs = append(inputs, dexJarFile)
+	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        aaptCreateAssetsPackage,
-		Description: "aapt export package",
-		Output:      outputFile,
-		Implicits:   deps,
-		Args: map[string]string{
-			"aaptFlags": strings.Join(flags, " "),
-		},
+		Rule:   combineApk,
+		Inputs: inputs,
+		Output: unsignedApk,
 	})
 
-	return outputFile
-}
-
-func CreateAppPackage(ctx android.ModuleContext, flags []string, jarFile android.Path,
-	certificates []string) android.Path {
-
-	resourceApk := android.PathForModuleOut(ctx, "resources.apk")
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        aaptAddResources,
-		Description: "aapt package",
-		Output:      resourceApk,
-		Input:       jarFile,
-		Args: map[string]string{
-			"aaptFlags": strings.Join(flags, " "),
-		},
-	})
-
-	outputFile := android.PathForModuleOut(ctx, "package.apk")
-
 	var certificateArgs []string
 	for _, c := range certificates {
-		certificateArgs = append(certificateArgs, c+".x509.pem", c+".pk8")
+		certificateArgs = append(certificateArgs, c.pem.String(), c.key.String())
 	}
 
+	// TODO(ccross): sometimes uncompress dex
+	// TODO(ccross): sometimes strip dex
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        signapk,
 		Description: "signapk",
 		Output:      outputFile,
-		Input:       resourceApk,
+		Input:       unsignedApk,
 		Args: map[string]string{
 			"certificates": strings.Join(certificateArgs, " "),
 		},
 	})
-
-	return outputFile
 }
diff --git a/java/app_test.go b/java/app_test.go
new file mode 100644
index 0000000..73ac3f7
--- /dev/null
+++ b/java/app_test.go
@@ -0,0 +1,239 @@
+// 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 java
+
+import (
+	"android/soong/android"
+	"reflect"
+	"sort"
+	"testing"
+)
+
+var (
+	resourceFiles = []string{
+		"res/layout/layout.xml",
+		"res/values/strings.xml",
+		"res/values-en-rUS/strings.xml",
+	}
+
+	compiledResourceFiles = []string{
+		"aapt2/res/layout_layout.xml.flat",
+		"aapt2/res/values_strings.arsc.flat",
+		"aapt2/res/values-en-rUS_strings.arsc.flat",
+	}
+)
+
+func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext {
+	appFS := map[string][]byte{}
+	for k, v := range fs {
+		appFS[k] = v
+	}
+
+	for _, file := range resourceFiles {
+		appFS[file] = nil
+	}
+
+	return testContext(config, bp, appFS)
+}
+
+func testApp(t *testing.T, bp string) *android.TestContext {
+	config := testConfig(nil)
+
+	ctx := testAppContext(config, bp, nil)
+
+	run(t, ctx, config)
+
+	return ctx
+}
+
+func TestApp(t *testing.T) {
+	ctx := testApp(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	expectedLinkImplicits := []string{"AndroidManifest.xml"}
+
+	frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
+	expectedLinkImplicits = append(expectedLinkImplicits,
+		frameworkRes.Output("package-res.apk").Output.String())
+
+	// Test the mapping from input files to compiled output file names
+	compile := foo.Output(compiledResourceFiles[0])
+	if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
+		t.Errorf("expected aapt2 compile inputs expected:\n  %#v\n got:\n  %#v",
+			resourceFiles, compile.Inputs.Strings())
+	}
+
+	compiledResourceOutputs := compile.Outputs.Strings()
+	sort.Strings(compiledResourceOutputs)
+
+	expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
+
+	list := foo.Output("aapt2/res.list")
+	expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
+
+	// Check that the link rule uses
+	res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
+	if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
+		t.Errorf("expected aapt2 link implicits expected:\n  %#v\n got:\n  %#v",
+			expectedLinkImplicits, res.Implicits.Strings())
+	}
+}
+
+var testEnforceRROTests = []struct {
+	name                       string
+	enforceRROTargets          []string
+	enforceRROExcludedOverlays []string
+	fooOverlayFiles            []string
+	fooRRODirs                 []string
+	barOverlayFiles            []string
+	barRRODirs                 []string
+}{
+	{
+		name:                       "no RRO",
+		enforceRROTargets:          nil,
+		enforceRROExcludedOverlays: nil,
+		fooOverlayFiles: []string{
+			"device/vendor/blah/overlay/foo/res/values/strings.xml",
+			"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+		},
+		fooRRODirs: nil,
+		barOverlayFiles: []string{
+			"device/vendor/blah/overlay/bar/res/values/strings.xml",
+			"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+		},
+		barRRODirs: nil,
+	},
+	{
+		name:                       "enforce RRO on foo",
+		enforceRROTargets:          []string{"foo"},
+		enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+		fooOverlayFiles: []string{
+			"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+		},
+		fooRRODirs: []string{
+			"device/vendor/blah/overlay/foo/res",
+		},
+		barOverlayFiles: []string{
+			"device/vendor/blah/overlay/bar/res/values/strings.xml",
+			"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+		},
+		barRRODirs: nil,
+	},
+	{
+		name:                       "enforce RRO on all",
+		enforceRROTargets:          []string{"*"},
+		enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+		fooOverlayFiles: []string{
+			"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+		},
+		fooRRODirs: []string{
+			"device/vendor/blah/overlay/foo/res",
+		},
+		barOverlayFiles: []string{
+			"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+		},
+		barRRODirs: []string{
+			"device/vendor/blah/overlay/bar/res",
+		},
+	},
+}
+
+func TestEnforceRRO(t *testing.T) {
+	resourceOverlays := []string{
+		"device/vendor/blah/overlay",
+		"device/vendor/blah/overlay2",
+		"device/vendor/blah/static_overlay",
+	}
+
+	fs := map[string][]byte{
+		"foo/res/res/values/strings.xml":                               nil,
+		"bar/res/res/values/strings.xml":                               nil,
+		"device/vendor/blah/overlay/foo/res/values/strings.xml":        nil,
+		"device/vendor/blah/overlay/bar/res/values/strings.xml":        nil,
+		"device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
+		"device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
+		"device/vendor/blah/overlay2/res/values/strings.xml":           nil,
+	}
+
+	bp := `
+			android_app {
+				name: "foo",
+				resource_dirs: ["foo/res"],
+			}
+
+			android_app {
+				name: "bar",
+				resource_dirs: ["bar/res"],
+			}
+		`
+
+	for _, testCase := range testEnforceRROTests {
+		t.Run(testCase.name, func(t *testing.T) {
+			config := testConfig(nil)
+			config.ProductVariables.ResourceOverlays = &resourceOverlays
+			if testCase.enforceRROTargets != nil {
+				config.ProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
+			}
+			if testCase.enforceRROExcludedOverlays != nil {
+				config.ProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
+			}
+
+			ctx := testAppContext(config, bp, fs)
+			run(t, ctx, config)
+
+			getOverlays := func(moduleName string) ([]string, []string) {
+				module := ctx.ModuleForTests(moduleName, "android_common")
+				overlayCompiledPaths := module.Output("aapt2/overlay.list").Inputs.Strings()
+
+				var overlayFiles []string
+				for _, o := range overlayCompiledPaths {
+					overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
+				}
+
+				rroDirs := module.Module().(*AndroidApp).rroDirs.Strings()
+
+				return overlayFiles, rroDirs
+			}
+
+			fooOverlayFiles, fooRRODirs := getOverlays("foo")
+			barOverlayFiles, barRRODirs := getOverlays("bar")
+
+			if !reflect.DeepEqual(fooOverlayFiles, testCase.fooOverlayFiles) {
+				t.Errorf("expected foo overlay files:\n  %#v\n got:\n  %#v",
+					testCase.fooOverlayFiles, fooOverlayFiles)
+			}
+			if !reflect.DeepEqual(fooRRODirs, testCase.fooRRODirs) {
+				t.Errorf("expected foo rroDirs:  %#v\n got:\n  %#v",
+					testCase.fooRRODirs, fooRRODirs)
+			}
+
+			if !reflect.DeepEqual(barOverlayFiles, testCase.barOverlayFiles) {
+				t.Errorf("expected bar overlay files:\n  %#v\n got:\n  %#v",
+					testCase.barOverlayFiles, barOverlayFiles)
+			}
+			if !reflect.DeepEqual(barRRODirs, testCase.barRRODirs) {
+				t.Errorf("expected bar rroDirs:  %#v\n got:\n  %#v",
+					testCase.barRRODirs, barRRODirs)
+			}
+
+		})
+	}
+}
diff --git a/java/builder.go b/java/builder.go
index 4be3b04..dd0d927 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -161,6 +161,20 @@
 		},
 		"outDir", "dxFlags")
 
+	d8 = pctx.AndroidStaticRule("d8",
+		blueprint.RuleParams{
+			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
+				`${config.D8Cmd} --output $outDir $dxFlags $in && ` +
+				`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
+				`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
+			CommandDeps: []string{
+				"${config.DxCmd}",
+				"${config.SoongZipCmd}",
+				"${config.MergeZipsCmd}",
+			},
+		},
+		"outDir", "dxFlags")
+
 	jarjar = pctx.AndroidStaticRule("jarjar",
 		blueprint.RuleParams{
 			Command:     "${config.JavaCmd} -jar ${config.JarjarCmd} process $rulesFile $in $out",
@@ -186,8 +200,9 @@
 	kotlincFlags     string
 	kotlincClasspath classpath
 
-	protoFlags   []string
-	protoOutFlag string
+	protoFlags       []string
+	protoOutTypeFlag string // The flag itself: --java_out
+	protoOutParams   string // Parameters to that flag: --java_out=$protoOutParams:$outDir
 }
 
 func TransformKotlinToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -199,11 +214,15 @@
 	inputs := append(android.Paths(nil), srcFiles...)
 	inputs = append(inputs, srcJars...)
 
+	var deps android.Paths
+	deps = append(deps, flags.kotlincClasspath...)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        kotlinc,
 		Description: "kotlinc",
 		Output:      outputFile,
 		Inputs:      inputs,
+		Implicits:   deps,
 		Args: map[string]string{
 			"classpath":    flags.kotlincClasspath.FormJavaClassPath("-classpath"),
 			"kotlincFlags": flags.kotlincFlags,
@@ -386,7 +405,7 @@
 	dumpDir := android.PathForModuleOut(ctx, "desugar", "classes")
 
 	javaFlags := ""
-	if ctx.AConfig().UseOpenJDK9() {
+	if ctx.Config().UseOpenJDK9() {
 		javaFlags = "--add-opens java.base/java.lang.invoke=ALL-UNNAMED"
 	}
 
@@ -420,9 +439,15 @@
 
 	outDir := android.PathForModuleOut(ctx, "dex")
 
+	rule := dx
+	desc := "dx"
+	if ctx.Config().UseD8Desugar() {
+		rule = d8
+		desc = "d8"
+	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        dx,
-		Description: "dx",
+		Rule:        rule,
+		Description: desc,
 		Output:      outputFile,
 		Input:       classesJar,
 		Args: map[string]string{
diff --git a/java/config/config.go b/java/config/config.go
index 3cd2841..c43f9a3 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -15,6 +15,8 @@
 package config
 
 import (
+	"path/filepath"
+	"runtime"
 	"strings"
 
 	_ "github.com/google/blueprint/bootstrap"
@@ -28,6 +30,16 @@
 	DefaultBootclasspathLibraries = []string{"core-oj", "core-libart"}
 	DefaultSystemModules          = "core-system-modules"
 	DefaultLibraries              = []string{"ext", "framework", "okhttp"}
+
+	DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+
+	InstrumentFrameworkModules = []string{
+		"framework",
+		"telephony-common",
+		"services",
+		"android.car",
+		"android.car7",
+	}
 )
 
 func init() {
@@ -54,9 +66,9 @@
 
 	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 
-	pctx.VariableFunc("JavaHome", func(config interface{}) (string, error) {
+	pctx.VariableFunc("JavaHome", func(config android.Config) (string, error) {
 		// This is set up and guaranteed by soong_ui
-		return config.(android.Config).Getenv("ANDROID_JAVA_HOME"), nil
+		return config.Getenv("ANDROID_JAVA_HOME"), nil
 	})
 
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
@@ -74,9 +86,10 @@
 	pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 	pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips")
-	pctx.VariableFunc("DxCmd", func(config interface{}) (string, error) {
-		if config.(android.Config).IsEnvFalse("USE_D8") {
-			if config.(android.Config).UnbundledBuild() || config.(android.Config).IsPdkBuild() {
+	pctx.HostBinToolVariable("Zip2ZipCmd", "zip2zip")
+	pctx.VariableFunc("DxCmd", func(config android.Config) (string, error) {
+		if config.IsEnvFalse("USE_D8") {
+			if config.UnbundledBuild() || config.IsPdkBuild() {
 				return "prebuilts/build-tools/common/bin/dx", nil
 			} else {
 				path, err := pctx.HostBinToolPath(config, "dx")
@@ -93,9 +106,16 @@
 			return path.String(), nil
 		}
 	})
-	pctx.VariableFunc("TurbineJar", func(config interface{}) (string, error) {
+	pctx.VariableFunc("D8Cmd", func(config android.Config) (string, error) {
+		path, err := pctx.HostBinToolPath(config, "d8")
+		if err != nil {
+			return "", err
+		}
+		return path.String(), nil
+	})
+	pctx.VariableFunc("TurbineJar", func(config android.Config) (string, error) {
 		turbine := "turbine.jar"
-		if config.(android.Config).UnbundledBuild() {
+		if config.UnbundledBuild() {
 			return "prebuilts/build-tools/common/framework/" + turbine, nil
 		} else {
 			path, err := pctx.HostJavaToolPath(config, turbine)
@@ -111,10 +131,28 @@
 
 	pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
 
-	pctx.VariableFunc("JavacWrapper", func(config interface{}) (string, error) {
-		if override := config.(android.Config).Getenv("JAVAC_WRAPPER"); override != "" {
+	pctx.VariableFunc("JavacWrapper", func(config android.Config) (string, error) {
+		if override := config.Getenv("JAVAC_WRAPPER"); override != "" {
 			return override + " ", nil
 		}
 		return "", nil
 	})
+
+	pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
+
+	hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
+		pctx.VariableFunc(name, func(config android.Config) (string, error) {
+			if config.UnbundledBuild() || config.IsPdkBuild() {
+				return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool), nil
+			} else {
+				if path, err := pctx.HostBinToolPath(config, tool); err != nil {
+					return "", err
+				} else {
+					return path.String(), nil
+				}
+			}
+		})
+	}
+
+	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
 }
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
index 31cbf2c..862217f 100644
--- a/java/config/error_prone.go
+++ b/java/config/error_prone.go
@@ -14,6 +14,8 @@
 
 package config
 
+import "android/soong/android"
+
 var (
 	// These will be filled out by external/error_prone/soong/error_prone.go if it is available
 	ErrorProneJavacJar    string
@@ -25,7 +27,7 @@
 
 // Wrapper that grabs value of val late so it can be initialized by a later module's init function
 func errorProneVar(name string, val *string) {
-	pctx.VariableFunc(name, func(config interface{}) (string, error) {
+	pctx.VariableFunc(name, func(config android.Config) (string, error) {
 		return *val, nil
 	})
 }
diff --git a/java/config/makevars.go b/java/config/makevars.go
index dabf2e7..c382cc1 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -36,6 +36,8 @@
 	}
 
 	ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
+	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}")
@@ -43,8 +45,17 @@
 	ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
 	ctx.Strict("JAVADOC", "${JavadocCmd}")
 	ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}")
-	ctx.Strict("DX", "${DxCmd}")
-	ctx.Strict("DX_COMMAND", "${DxCmd} -JXms16M -JXmx2048M")
+
+	if ctx.Config().UseD8Desugar() {
+		ctx.Strict("DX", "${D8Cmd}")
+		ctx.Strict("DX_COMMAND", "${D8Cmd} -JXms16M -JXmx2048M")
+		ctx.Strict("USE_D8_DESUGAR", "true")
+	} else {
+		ctx.Strict("DX", "${DxCmd}")
+		ctx.Strict("DX_COMMAND", "${DxCmd} -JXms16M -JXmx2048M")
+		ctx.Strict("USE_D8_DESUGAR", "false")
+	}
+
 	ctx.Strict("TURBINE", "${TurbineJar}")
 
 	if ctx.Config().IsEnvTrue("RUN_ERROR_PRONE") {
@@ -62,4 +73,7 @@
 
 	ctx.Strict("SOONG_JAVAC_WRAPPER", "${SoongJavacWrapper}")
 	ctx.Strict("EXTRACT_SRCJARS", "${ExtractSrcJarsCmd}")
+
+	ctx.Strict("JACOCO_CLI_JAR", "${JacocoCLIJar}")
+	ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ","))
 }
diff --git a/java/gen.go b/java/gen.go
index b5973ec..4893e88 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -28,8 +28,6 @@
 	pctx.HostBinToolVariable("aidlCmd", "aidl")
 	pctx.SourcePathVariable("logtagsCmd", "build/tools/java-event-log-tags.py")
 	pctx.SourcePathVariable("mergeLogtagsCmd", "build/tools/merge-event-log-tags.py")
-
-	pctx.IntermediatesPathVariable("allLogtagsFile", "all-event-log-tags.txt")
 }
 
 var (
@@ -109,7 +107,7 @@
 	if len(protoFiles) > 0 {
 		protoSrcJar := android.PathForModuleGen(ctx, "proto.srcjar")
 		genProto(ctx, protoSrcJar, protoFiles,
-			flags.protoFlags, flags.protoOutFlag, "")
+			flags.protoFlags, flags.protoOutTypeFlag, flags.protoOutParams)
 
 		outSrcFiles = append(outSrcFiles, protoSrcJar)
 	}
@@ -117,7 +115,7 @@
 	return outSrcFiles
 }
 
-func LogtagsSingleton() blueprint.Singleton {
+func LogtagsSingleton() android.Singleton {
 	return &logtagsSingleton{}
 }
 
@@ -127,18 +125,18 @@
 
 type logtagsSingleton struct{}
 
-func (l *logtagsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+func (l *logtagsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var allLogtags android.Paths
-	ctx.VisitAllModules(func(module blueprint.Module) {
+	ctx.VisitAllModules(func(module android.Module) {
 		if logtags, ok := module.(logtagsProducer); ok {
 			allLogtags = append(allLogtags, logtags.logtags()...)
 		}
 	})
 
-	ctx.Build(pctx, blueprint.BuildParams{
+	ctx.Build(pctx, android.BuildParams{
 		Rule:        mergeLogtags,
 		Description: "merge logtags",
-		Outputs:     []string{"$allLogtagsFile"},
-		Inputs:      allLogtags.Strings(),
+		Output:      android.PathForIntermediates(ctx, "all-event-log-tags.txt"),
+		Inputs:      allLogtags,
 	})
 }
diff --git a/java/genrule.go b/java/genrule.go
new file mode 100644
index 0000000..80b7030
--- /dev/null
+++ b/java/genrule.go
@@ -0,0 +1,35 @@
+// 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 java
+
+import (
+	"android/soong/android"
+	"android/soong/genrule"
+)
+
+func init() {
+	android.RegisterModuleType("java_genrule", genRuleFactory)
+}
+
+// java_genrule is a genrule that can depend on other java_* objects.
+// The cmd may be run multiple times, once for each of the different host/device
+// variations.
+func genRuleFactory() android.Module {
+	module := genrule.NewGenRule()
+
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+
+	return module
+}
diff --git a/java/jacoco.go b/java/jacoco.go
new file mode 100644
index 0000000..59f2fd3
--- /dev/null
+++ b/java/jacoco.go
@@ -0,0 +1,121 @@
+// 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 java
+
+// Rules for instrumenting classes using jacoco
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+var (
+	jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{
+		Command: `${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
+			`${config.JavaCmd} -jar ${config.JacocoCLIJar} instrument -quiet -dest $instrumentedJar $strippedJar && ` +
+			`${config.Ziptime} $instrumentedJar && ` +
+			`${config.MergeZipsCmd} --ignore-duplicates -j $out $instrumentedJar $in`,
+		CommandDeps: []string{
+			"${config.Zip2ZipCmd}",
+			"${config.JavaCmd}",
+			"${config.JacocoCLIJar}",
+			"${config.Ziptime}",
+			"${config.MergeZipsCmd}",
+		},
+	},
+		"strippedJar", "stripSpec", "instrumentedJar")
+)
+
+func jacocoInstrumentJar(ctx android.ModuleContext, outputJar, strippedJar android.WritablePath,
+	inputJar android.Path, stripSpec string) {
+	instrumentedJar := android.PathForModuleOut(ctx, "jacoco/instrumented.jar")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:           jacoco,
+		Description:    "jacoco",
+		Output:         outputJar,
+		ImplicitOutput: strippedJar,
+		Input:          inputJar,
+		Args: map[string]string{
+			"strippedJar":     strippedJar.String(),
+			"stripSpec":       stripSpec,
+			"instrumentedJar": instrumentedJar.String(),
+		},
+	})
+}
+
+func (j *Module) jacocoModuleToZipCommand(ctx android.ModuleContext) string {
+	includes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Include_filter)
+	if err != nil {
+		ctx.PropertyErrorf("jacoco.include_filter", "%s", err.Error())
+	}
+	excludes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Exclude_filter)
+	if err != nil {
+		ctx.PropertyErrorf("jacoco.exclude_filter", "%s", err.Error())
+	}
+
+	return jacocoFiltersToZipCommand(includes, excludes)
+}
+
+func jacocoFiltersToZipCommand(includes, excludes []string) string {
+	specs := ""
+	if len(excludes) > 0 {
+		specs += android.JoinWithPrefix(excludes, "-x ") + " "
+	}
+	if len(includes) > 0 {
+		specs += strings.Join(includes, " ")
+	} else {
+		specs += "**/*.class"
+	}
+	return specs
+}
+
+func jacocoFiltersToSpecs(filters []string) ([]string, error) {
+	specs := make([]string, len(filters))
+	var err error
+	for i, f := range filters {
+		specs[i], err = jacocoFilterToSpec(f)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return specs, nil
+}
+
+func jacocoFilterToSpec(filter string) (string, error) {
+	wildcard := strings.HasSuffix(filter, "*")
+	filter = strings.TrimSuffix(filter, "*")
+	recursiveWildcard := wildcard && (strings.HasSuffix(filter, ".") || filter == "")
+
+	if strings.ContainsRune(filter, '*') {
+		return "", fmt.Errorf("'*' is only supported as the last character in a filter")
+	}
+
+	spec := strings.Replace(filter, ".", "/", -1)
+
+	if recursiveWildcard {
+		spec += "**/*.class"
+	} else if wildcard {
+		spec += "*.class"
+	} else {
+		spec += ".class"
+	}
+
+	return spec, nil
+}
diff --git a/java/jacoco_test.go b/java/jacoco_test.go
new file mode 100644
index 0000000..6e8b026
--- /dev/null
+++ b/java/jacoco_test.go
@@ -0,0 +1,95 @@
+// 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 java
+
+import "testing"
+
+func TestJacocoFilterToSpecs(t *testing.T) {
+	testCases := []struct {
+		name, in, out string
+	}{
+		{
+			name: "class",
+			in:   "package.Class",
+			out:  "package/Class.class",
+		},
+		{
+			name: "class wildcard",
+			in:   "package.Class*",
+			out:  "package/Class*.class",
+		},
+		{
+			name: "package wildcard",
+			in:   "package.*",
+			out:  "package/**/*.class",
+		},
+		{
+			name: "all wildcard",
+			in:   "*",
+			out:  "**/*.class",
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got, err := jacocoFilterToSpec(testCase.in)
+			if err != nil {
+				t.Error(err)
+			}
+			if got != testCase.out {
+				t.Errorf("expected %q got %q", testCase.out, got)
+			}
+		})
+	}
+}
+
+func TestJacocoFiltersToZipCommand(t *testing.T) {
+	testCases := []struct {
+		name               string
+		includes, excludes []string
+		out                string
+	}{
+		{
+			name:     "implicit wildcard",
+			includes: []string{},
+			out:      "**/*.class",
+		},
+		{
+			name:     "only include",
+			includes: []string{"package/Class.class"},
+			out:      "package/Class.class",
+		},
+		{
+			name:     "multiple includes",
+			includes: []string{"package/Class.class", "package2/Class.class"},
+			out:      "package/Class.class package2/Class.class",
+		},
+		{
+			name:     "excludes",
+			includes: []string{"package/**/*.class"},
+			excludes: []string{"package/Class.class"},
+			out:      "-x package/Class.class package/**/*.class",
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got := jacocoFiltersToZipCommand(testCase.includes, testCase.excludes)
+			if got != testCase.out {
+				t.Errorf("expected %q got %q", testCase.out, got)
+			}
+		})
+	}
+}
diff --git a/java/java.go b/java/java.go
index b2bd2b0..e6ed931 100644
--- a/java/java.go
+++ b/java/java.go
@@ -41,7 +41,6 @@
 	android.RegisterModuleType("java_binary_host", BinaryHostFactory)
 	android.RegisterModuleType("java_import", ImportFactory)
 	android.RegisterModuleType("java_import_host", ImportFactoryHost)
-	android.RegisterModuleType("android_app", AndroidAppFactory)
 
 	android.RegisterSingletonType("logtags", LogtagsSingleton)
 }
@@ -51,9 +50,6 @@
 //  Renderscript
 // Post-jar passes:
 //  Proguard
-//  Jacoco
-//  Jarjar
-//  Dex
 // Rmtypedefs
 // DroidDoc
 // Findbugs
@@ -127,6 +123,31 @@
 		// List of javac flags that should only be used when passing -source 1.9
 		Javacflags []string
 	}
+
+	Jacoco struct {
+		// List of classes to include for instrumentation with jacoco to collect coverage
+		// information at runtime when building with coverage enabled.  If unset defaults to all
+		// classes.
+		// Supports '*' as the last character of an entry in the list as a wildcard match.
+		// If preceded by '.' it matches all classes in the package and subpackages, otherwise
+		// it matches classes in the package that have the class name as a prefix.
+		Include_filter []string
+
+		// List of classes to exclude from instrumentation with jacoco to collect coverage
+		// information at runtime when building with coverage enabled.  Overrides classes selected
+		// by the include_filter property.
+		// Supports '*' as the last character of an entry in the list as a wildcard match.
+		// If preceded by '.' it matches all classes in the package and subpackages, otherwise
+		// it matches classes in the package that have the class name as a prefix.
+		Exclude_filter []string
+	}
+
+	Proto struct {
+		// List of extra options that will be passed to the proto generator.
+		Output_params []string
+	}
+
+	Instrument bool `blueprint:"mutated"`
 }
 
 type CompilerDeviceProperties struct {
@@ -151,9 +172,24 @@
 	// If true, export a copy of the module as a -hostdex module for host testing.
 	Hostdex *bool
 
-	// If false, prevent dexpreopting and stripping the dex file from the final jar.  Defaults to
-	// true.
-	Dex_preopt *bool
+	Dex_preopt struct {
+		// If false, prevent dexpreopting and stripping the dex file from the final jar.  Defaults to
+		// true.
+		Enabled *bool
+
+		// If true, generate an app image (.art file) for this module.
+		App_image *bool
+
+		// If true, use a checked-in profile to guide optimization.  Defaults to false unless
+		// a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
+		// that matches the name of this module, in which case it is defaulted to true.
+		Profile_guided *bool
+
+		// 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
+	}
 
 	// When targeting 1.9, override the modules to use with --system
 	System_modules *string
@@ -177,6 +213,9 @@
 	// output file containing classes.dex
 	dexJarFile android.Path
 
+	// output file containing uninstrumented classes that will be instrumented by jacoco
+	jacocoReportClassesFile android.Path
+
 	// output file suitable for installing or running
 	outputFile android.Path
 
@@ -184,14 +223,20 @@
 
 	logtagsSrcs android.Paths
 
-	// jars containing source files that should be included in the javac command line,
-	// for example R.java generated by aapt for android apps
-	ExtraSrcJars android.Paths
-
 	// installed file for binary dependency
 	installFile android.Path
+
+	// list of .java files and srcjars that was passed to javac
+	compiledJavaSrcs android.Paths
+	compiledSrcJars  android.Paths
 }
 
+func (j *Module) Srcs() android.Paths {
+	return android.Paths{j.implementationJarFile}
+}
+
+var _ android.SourceFileProducer = (*Module)(nil)
+
 type Dependency interface {
 	HeaderJars() android.Paths
 	ImplementationJars() android.Paths
@@ -232,7 +277,7 @@
 	case "", "current", "system_current", "test_current":
 		return 10000
 	default:
-		if i, err := strconv.Atoi(v); err != nil {
+		if i, err := strconv.Atoi(android.GetNumericSdkVersion(v)); err != nil {
 			ctx.PropertyErrorf("sdk_version", "invalid sdk version")
 			return -1
 		} else {
@@ -255,7 +300,13 @@
 		jarPath := android.ExistentPathForSource(ctx, "sdkdir", jar)
 		aidlPath := android.ExistentPathForSource(ctx, "sdkdir", aidl)
 
-		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.AConfig().AllowMissingDependencies() {
+		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
+			if strings.Contains(v, "system_") {
+				return sdkDep{
+					invalidVersion: true,
+					module:         "vsdk_v" + strings.Replace(v, "system_", "", 1),
+				}
+			}
 			return sdkDep{
 				invalidVersion: true,
 				module:         "sdk_v" + v,
@@ -287,7 +338,7 @@
 	//	}
 	//}
 
-	if ctx.AConfig().UnbundledBuild() && v != "" {
+	if ctx.Config().UnbundledBuild() && v != "" {
 		return toFile(v)
 	}
 
@@ -315,14 +366,14 @@
 			sdkDep := decodeSdkDep(ctx, String(j.deviceProperties.Sdk_version))
 			if sdkDep.useDefaultLibs {
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, config.DefaultBootclasspathLibraries...)
-				if ctx.AConfig().TargetOpenJDK9() {
+				if ctx.Config().TargetOpenJDK9() {
 					ctx.AddDependency(ctx.Module(), systemModulesTag, config.DefaultSystemModules)
 				}
 				if !proptools.Bool(j.properties.No_framework_libs) {
 					ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
 				}
 			} else if sdkDep.useModule {
-				if ctx.AConfig().TargetOpenJDK9() {
+				if ctx.Config().TargetOpenJDK9() {
 					ctx.AddDependency(ctx.Module(), systemModulesTag, sdkDep.systemModules)
 				}
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
@@ -330,9 +381,12 @@
 		} 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?")
-		} else if *j.deviceProperties.System_modules != "none" && ctx.AConfig().TargetOpenJDK9() {
+		} else if *j.deviceProperties.System_modules != "none" && ctx.Config().TargetOpenJDK9() {
 			ctx.AddDependency(ctx.Module(), systemModulesTag, *j.deviceProperties.System_modules)
 		}
+		if ctx.ModuleName() == "framework" {
+			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
+		}
 	}
 
 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
@@ -341,6 +395,7 @@
 
 	android.ExtractSourcesDeps(ctx, j.properties.Srcs)
 	android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
+	android.ExtractSourceDeps(ctx, j.properties.Manifest)
 
 	if j.hasSrcExt(".proto") {
 		protoDeps(ctx, &j.protoProperties)
@@ -418,6 +473,15 @@
 	kotlinStdlib       android.Paths
 }
 
+func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) {
+	for _, f := range dep.Srcs() {
+		if f.Ext() != ".jar" {
+			ctx.ModuleErrorf("genrule %q must generate files ending with .jar to be used as a libs or static_libs dependency",
+				ctx.OtherModuleName(dep.(blueprint.Module)))
+		}
+	}
+}
+
 func (j *Module) collectDeps(ctx android.ModuleContext) deps {
 	var deps deps
 
@@ -434,8 +498,46 @@
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
 
-		dep, _ := module.(Dependency)
-		if dep == nil {
+		switch dep := module.(type) {
+		case Dependency:
+			switch tag {
+			case bootClasspathTag:
+				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
+			case libTag:
+				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
+			case staticLibTag:
+				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
+				deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
+				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
+			case frameworkResTag:
+				if ctx.ModuleName() == "framework" {
+					// framework.jar has a one-off dependency on the R.java and Manifest.java files
+					// generated by framework-res.apk
+					deps.srcJars = append(deps.srcJars, dep.(*AndroidApp).aaptSrcJar)
+				}
+			case kotlinStdlibTag:
+				deps.kotlinStdlib = dep.HeaderJars()
+			default:
+				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
+			}
+
+			deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
+		case android.SourceFileProducer:
+			switch tag {
+			case libTag:
+				checkProducesJars(ctx, dep)
+				deps.classpath = append(deps.classpath, dep.Srcs()...)
+			case staticLibTag:
+				checkProducesJars(ctx, dep)
+				deps.classpath = append(deps.classpath, dep.Srcs()...)
+				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
+				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
+			case android.DefaultsDepTag, android.SourceDepTag:
+				// Nothing to do
+			default:
+				ctx.ModuleErrorf("dependency on genrule %q may only be in srcs, libs, or static_libs", otherName)
+			}
+		default:
 			switch tag {
 			case android.DefaultsDepTag, android.SourceDepTag:
 				// Nothing to do
@@ -451,31 +553,7 @@
 			default:
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
-			return
 		}
-
-		switch tag {
-		case bootClasspathTag:
-			deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
-		case libTag:
-			deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-		case staticLibTag:
-			deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-			deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
-			deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
-		case frameworkResTag:
-			if ctx.ModuleName() == "framework" {
-				// framework.jar has a one-off dependency on the R.java and Manifest.java files
-				// generated by framework-res.apk
-				// TODO(ccross): aapt java files should go in a src jar
-			}
-		case kotlinStdlibTag:
-			deps.kotlinStdlib = dep.HeaderJars()
-		default:
-			panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
-		}
-
-		deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 	})
 
 	return deps
@@ -487,10 +565,10 @@
 
 	// javac flags.
 	javacFlags := j.properties.Javacflags
-	if ctx.AConfig().TargetOpenJDK9() {
+	if ctx.Config().TargetOpenJDK9() {
 		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
 	}
-	if ctx.AConfig().MinimizeJavaDebugInfo() {
+	if ctx.Config().MinimizeJavaDebugInfo() {
 		// Override the -g flag passed globally to remove local variable debug info to reduce
 		// disk and memory usage.
 		javacFlags = append(javacFlags, "-g:source,lines")
@@ -507,7 +585,7 @@
 		flags.javaVersion = *j.properties.Java_version
 	} else if ctx.Device() && sdk <= 23 {
 		flags.javaVersion = "1.7"
-	} else if ctx.Device() && sdk <= 26 || !ctx.AConfig().TargetOpenJDK9() {
+	} else if ctx.Device() && sdk <= 26 || !ctx.Config().TargetOpenJDK9() {
 		flags.javaVersion = "1.8"
 	} else if ctx.Device() && String(j.deviceProperties.Sdk_version) != "" && sdk == 10000 {
 		// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
@@ -535,26 +613,26 @@
 	return flags
 }
 
-func (j *Module) compile(ctx android.ModuleContext) {
+func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path) {
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
 	deps := j.collectDeps(ctx)
 	flags := j.collectBuilderFlags(ctx, deps)
 
-	if ctx.AConfig().TargetOpenJDK9() {
+	if ctx.Config().TargetOpenJDK9() {
 		j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
 	}
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
 	if hasSrcExt(srcFiles.Strings(), ".proto") {
-		flags = protoFlags(ctx, &j.protoProperties, flags)
+		flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
 	}
 
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
-	srcJars = append(srcJars, j.ExtraSrcJars...)
+	srcJars = append(srcJars, extraSrcJars...)
 
 	var jars android.Paths
 
@@ -596,8 +674,13 @@
 		}
 	}
 
+	// Store the list of .java files that was passed to javac
+	j.compiledJavaSrcs = uniqueSrcFiles
+	j.compiledSrcJars = srcJars
+	fullD8 := ctx.Config().UseD8Desugar()
+
 	enable_sharding := false
-	if ctx.Device() && !ctx.AConfig().IsEnvFalse("TURBINE_ENABLED") {
+	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
 		if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
 			enable_sharding = true
 			if len(j.properties.Annotation_processors) != 0 ||
@@ -618,7 +701,7 @@
 	}
 	if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
 		var extraJarDeps android.Paths
-		if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
+		if ctx.Config().IsEnvTrue("RUN_ERROR_PRONE") {
 			// If error-prone is enabled, add an additional rule to compile the java files into
 			// a separate set of classes (so that they don't overwrite the normal ones and require
 			// a rebuild when error-prone is turned off).
@@ -687,7 +770,10 @@
 	// static classpath jars have the resources in them, so the resource jars aren't necessary here
 	jars = append(jars, deps.staticJars...)
 
-	manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
+	var manifest android.OptionalPath
+	if j.properties.Manifest != nil {
+		manifest = android.OptionalPathForPath(ctx.ExpandSource(*j.properties.Manifest, "manifest"))
+	}
 
 	// Combine the classes built from sources, any manifests, and any static libraries into
 	// classes.jar. If there is only one input jar this step will be skipped.
@@ -717,8 +803,26 @@
 		j.headerJarFile = j.implementationJarFile
 	}
 
+	if !fullD8 && ctx.Device() && j.installable() {
+		outputFile = j.desugar(ctx, flags, outputFile, jarName)
+	}
+
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+		if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
+			j.properties.Instrument = true
+		}
+	}
+
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") && j.properties.Instrument {
+		outputFile = j.instrument(ctx, flags, outputFile, jarName)
+	}
+
 	if ctx.Device() && j.installable() {
-		outputFile = j.compileDex(ctx, flags, outputFile, jarName)
+		if fullD8 {
+			outputFile = j.compileDexFullD8(ctx, flags, outputFile, jarName)
+		} else {
+			outputFile = j.compileDex(ctx, flags, outputFile, jarName)
+		}
 		if ctx.Failed() {
 			return
 		}
@@ -766,51 +870,16 @@
 	return headerJar
 }
 
-func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
+func (j *Module) desugar(ctx android.ModuleContext, flags javaBuilderFlags,
 	classesJar android.Path, jarName string) android.Path {
 
-	dxFlags := j.deviceProperties.Dxflags
-	if false /* emma enabled */ {
-		// If you instrument class files that have local variable debug information in
-		// them emma does not correctly maintain the local variable table.
-		// This will cause an error when you try to convert the class files for Android.
-		// The workaround here is to build different dex file here based on emma switch
-		// then later copy into classes.dex. When emma is on, dx is run with --no-locals
-		// option to remove local variable information
-		dxFlags = append(dxFlags, "--no-locals")
-	}
-
-	if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
-		dxFlags = append(dxFlags, "--no-optimize")
-	}
-
-	if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
-		dxFlags = append(dxFlags,
-			"--debug",
-			"--verbose",
-			"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
-			"--dump-width=1000")
-	}
-
-	var minSdkVersion string
-	switch String(j.deviceProperties.Sdk_version) {
-	case "", "current", "test_current", "system_current":
-		minSdkVersion = strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
-	default:
-		minSdkVersion = String(j.deviceProperties.Sdk_version)
-	}
-
-	dxFlags = append(dxFlags, "--min-sdk-version="+minSdkVersion)
-
-	flags.dxFlags = strings.Join(dxFlags, " ")
-
 	desugarFlags := []string{
-		"--min_sdk_version " + minSdkVersion,
+		"--min_sdk_version " + j.minSdkVersionNumber(ctx),
 		"--desugar_try_with_resources_if_needed=false",
 		"--allow_empty_bootclasspath",
 	}
 
-	if inList("--core-library", dxFlags) {
+	if inList("--core-library", j.deviceProperties.Dxflags) {
 		desugarFlags = append(desugarFlags, "--core_library")
 	}
 
@@ -818,21 +887,110 @@
 
 	desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
 	TransformDesugar(ctx, desugarJar, classesJar, flags)
-	if ctx.Failed() {
-		return nil
+
+	return desugarJar
+}
+
+func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	specs := j.jacocoModuleToZipCommand(ctx)
+
+	jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco", "jacoco-report-classes.jar")
+	instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)
+
+	jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs)
+
+	j.jacocoReportClassesFile = jacocoReportClassesFile
+
+	return instrumentedJar
+}
+
+func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	dxFlags := j.deviceProperties.Dxflags
+
+	if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
+		dxFlags = append(dxFlags, "--no-optimize")
 	}
 
+	if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
+		dxFlags = append(dxFlags,
+			"--debug",
+			"--verbose",
+			"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
+			"--dump-width=1000")
+	}
+
+	dxFlags = append(dxFlags, "--min-sdk-version="+j.minSdkVersionNumber(ctx))
+
+	flags.dxFlags = strings.Join(dxFlags, " ")
+
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
-	TransformClassesJarToDexJar(ctx, javalibJar, desugarJar, flags)
-	if ctx.Failed() {
-		return nil
-	}
+	TransformClassesJarToDexJar(ctx, javalibJar, classesJar, flags)
 
 	j.dexJarFile = javalibJar
 	return javalibJar
 }
 
+func (j *Module) compileDexFullD8(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	// Translate all the DX flags to D8 ones until all the build files have been migrated
+	// to D8 flags. See: b/69377755
+	var dxFlags []string
+	for _, x := range j.deviceProperties.Dxflags {
+		if x == "--core-library" {
+			continue
+		}
+		if x == "--dex" {
+			continue
+		}
+		if x == "--multi-dex" {
+			continue
+		}
+		if x == "--no-locals" {
+			dxFlags = append(dxFlags, "--release")
+			continue
+		}
+		dxFlags = append(dxFlags, x)
+	}
+
+	if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
+		dxFlags = append(dxFlags, "--debug")
+	}
+
+	if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
+		dxFlags = append(dxFlags,
+			"--debug",
+			"--verbose")
+	}
+
+	dxFlags = append(dxFlags, "--min-api "+j.minSdkVersionNumber(ctx))
+
+	flags.dxFlags = strings.Join(dxFlags, " ")
+
+	// Compile classes.jar into classes.dex and then javalib.jar
+	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
+	TransformClassesJarToDexJar(ctx, javalibJar, classesJar, flags)
+
+	j.dexJarFile = javalibJar
+	return javalibJar
+}
+
+// Returns a sdk version as a string that is guaranteed to be a parseable as a number.  For
+// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns "10000".
+func (j *Module) minSdkVersionNumber(ctx android.ModuleContext) string {
+	switch String(j.deviceProperties.Sdk_version) {
+	case "", "current", "test_current", "system_current":
+		return strconv.Itoa(ctx.Config().DefaultAppTargetSdkInt())
+	default:
+		return android.GetNumericSdkVersion(String(j.deviceProperties.Sdk_version))
+	}
+}
+
 func (j *Module) installable() bool {
 	return j.properties.Installable == nil || *j.properties.Installable
 }
@@ -921,7 +1079,9 @@
 
 	binaryProperties binaryProperties
 
-	wrapperFile android.SourcePath
+	isWrapperVariant bool
+
+	wrapperFile android.Path
 	binaryFile  android.OutputPath
 }
 
@@ -930,21 +1090,34 @@
 }
 
 func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.Library.GenerateAndroidBuildActions(ctx)
-
-	// Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
-	// another build rule before the jar has been installed.
-	if String(j.binaryProperties.Wrapper) != "" {
-		j.wrapperFile = android.PathForModuleSrc(ctx, String(j.binaryProperties.Wrapper)).SourcePath
+	if ctx.Arch().ArchType == android.Common {
+		// Compile the jar
+		j.Library.GenerateAndroidBuildActions(ctx)
 	} else {
-		j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+		// Handle the binary wrapper
+		j.isWrapperVariant = true
+
+		if j.binaryProperties.Wrapper != nil {
+			j.wrapperFile = ctx.ExpandSource(*j.binaryProperties.Wrapper, "wrapper")
+		} else {
+			j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+		}
+
+		// Depend on the installed jar so that the wrapper doesn't get executed by
+		// another build rule before the jar has been installed.
+		jarFile := ctx.PrimaryModule().(*Binary).installFile
+
+		j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
+			ctx.ModuleName(), j.wrapperFile, jarFile)
 	}
-	j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
-		ctx.ModuleName(), j.wrapperFile, j.installFile)
 }
 
 func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
-	j.deps(ctx)
+	if ctx.Arch().ArchType == android.Common {
+		j.deps(ctx)
+	} else {
+		android.ExtractSourceDeps(ctx, j.binaryProperties.Wrapper)
+	}
 }
 
 func BinaryFactory() android.Module {
@@ -956,7 +1129,8 @@
 		&module.Module.protoProperties,
 		&module.binaryProperties)
 
-	InitJavaModule(module, android.HostAndDeviceSupported)
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
+	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -969,7 +1143,8 @@
 		&module.Module.protoProperties,
 		&module.binaryProperties)
 
-	InitJavaModule(module, android.HostSupported)
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
+	android.InitDefaultableModule(module)
 	return module
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index e1c90ee..84fe903 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -51,25 +51,30 @@
 
 	os.Exit(run())
 }
-func testJava(t *testing.T, bp string) *android.TestContext {
-	return testJavaWithEnv(t, bp, nil)
+
+func testConfig(env map[string]string) android.Config {
+	return android.TestArchConfig(buildDir, env)
+
 }
 
-func testJavaWithEnv(t *testing.T, bp string, env map[string]string) *android.TestContext {
-	config := android.TestArchConfig(buildDir, env)
+func testContext(config android.Config, bp string,
+	fs map[string][]byte) *android.TestContext {
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+	ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory(true)))
 	ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
 	ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(ImportFactory))
 	ctx.RegisterModuleType("java_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
 	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(SystemModulesFactory))
+	ctx.RegisterModuleType("java_genrule", android.ModuleFactoryAdaptor(genRuleFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
 	ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(genrule.GenRuleFactory))
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
 	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
 	ctx.Register()
 
 	extraModules := []string{
@@ -95,34 +100,39 @@
 		`, extra)
 	}
 
-	if config.TargetOpenJDK9() {
-		systemModules := []string{
-			"core-system-modules",
-			"android_stubs_current_system_modules",
-			"android_system_stubs_current_system_modules",
-			"android_test_stubs_current_system_modules",
+	bp += `
+		android_app {
+			name: "framework-res",
+			no_framework_libs: true,
 		}
+	`
 
-		for _, extra := range systemModules {
-			bp += fmt.Sprintf(`
+	systemModules := []string{
+		"core-system-modules",
+		"android_stubs_current_system_modules",
+		"android_system_stubs_current_system_modules",
+		"android_test_stubs_current_system_modules",
+	}
+
+	for _, extra := range systemModules {
+		bp += fmt.Sprintf(`
 			java_system_modules {
 				name: "%s",
 			}
 		`, extra)
-		}
 	}
 
-	ctx.MockFileSystem(map[string][]byte{
-		"Android.bp": []byte(bp),
-		"a.java":     nil,
-		"b.java":     nil,
-		"c.java":     nil,
-		"b.kt":       nil,
-		"a.jar":      nil,
-		"b.jar":      nil,
-		"res/a":      nil,
-		"res/b":      nil,
-		"res2/a":     nil,
+	mockFS := map[string][]byte{
+		"Android.bp":  []byte(bp),
+		"a.java":      nil,
+		"b.java":      nil,
+		"c.java":      nil,
+		"b.kt":        nil,
+		"a.jar":       nil,
+		"b.jar":       nil,
+		"java-res/a":  nil,
+		"java-res/b":  nil,
+		"java-res2/a": nil,
 
 		"prebuilts/sdk/14/android.jar":                nil,
 		"prebuilts/sdk/14/framework.aidl":             nil,
@@ -130,14 +140,40 @@
 		"prebuilts/sdk/current/framework.aidl":        nil,
 		"prebuilts/sdk/system_current/android.jar":    nil,
 		"prebuilts/sdk/system_current/framework.aidl": nil,
+		"prebuilts/sdk/system_14/android.jar":         nil,
+		"prebuilts/sdk/system_14/framework.aidl":      nil,
 		"prebuilts/sdk/test_current/android.jar":      nil,
 		"prebuilts/sdk/test_current/framework.aidl":   nil,
-	})
 
+		// For framework-res, which is an implicit dependency for framework
+		"AndroidManifest.xml":                   nil,
+		"build/target/product/security/testkey": nil,
+
+		"build/soong/scripts/jar-wrapper.sh": nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
+
+func run(t *testing.T, ctx *android.TestContext, config android.Config) {
+	t.Helper()
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	fail(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
 	fail(t, errs)
+}
+
+func testJava(t *testing.T, bp string) *android.TestContext {
+	t.Helper()
+	config := testConfig(nil)
+	ctx := testContext(config, bp, nil)
+	run(t, ctx, config)
 
 	return ctx
 }
@@ -219,6 +255,35 @@
 	}
 }
 
+func TestBinary(t *testing.T) {
+	ctx := testJava(t, `
+		java_library_host {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+
+		java_binary_host {
+			name: "bar",
+			srcs: ["b.java"],
+			static_libs: ["foo"],
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+
+	bar := ctx.ModuleForTests("bar", buildOS+"_common")
+	barJar := bar.Output("bar.jar").Output.String()
+	barWrapper := ctx.ModuleForTests("bar", buildOS+"_x86_64")
+	barWrapperDeps := barWrapper.Output("bar").Implicits.Strings()
+
+	// Test that the install binary wrapper depends on the installed jar file
+	if len(barWrapperDeps) != 1 || barWrapperDeps[0] != barJar {
+		t.Errorf("expected binary wrapper implicits [%q], got %v",
+			barJar, barWrapperDeps)
+	}
+
+}
+
 var classpathTestcases = []struct {
 	name          string
 	moduleType    string
@@ -267,6 +332,14 @@
 	},
 	{
 
+		name:          "system_14",
+		properties:    `sdk_version: "system_14",`,
+		bootclasspath: []string{`""`},
+		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+		classpath:     []string{"prebuilts/sdk/system_14/android.jar"},
+	},
+	{
+
 		name:          "test_current",
 		properties:    `sdk_version: "test_current",`,
 		bootclasspath: []string{`""`},
@@ -394,7 +467,9 @@
 
 			// Test again with javac 1.9
 			t.Run("1.9", func(t *testing.T) {
-				ctx := testJavaWithEnv(t, bp, map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+				config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+				ctx := testContext(config, bp, nil)
+				run(t, ctx, config)
 
 				javac := ctx.ModuleForTests("foo", variant).Rule("javac")
 				got := javac.Args["bootClasspath"]
@@ -497,14 +572,14 @@
 		{
 			// Test that a module with java_resource_dirs includes the files
 			name: "resource dirs",
-			prop: `java_resource_dirs: ["res"]`,
-			args: "-C res -f res/a -f res/b",
+			prop: `java_resource_dirs: ["java-res"]`,
+			args: "-C java-res -f java-res/a -f java-res/b",
 		},
 		{
 			// Test that a module with java_resources includes the files
 			name: "resource files",
-			prop: `java_resources: ["res/a", "res/b"]`,
-			args: "-C . -f res/a -f res/b",
+			prop: `java_resources: ["java-res/a", "java-res/b"]`,
+			args: "-C . -f java-res/a -f java-res/b",
 		},
 		{
 			// Test that a module with a filegroup in java_resources includes the files with the
@@ -514,10 +589,10 @@
 			extra: `
 				filegroup {
 					name: "foo-res",
-					path: "res",
-					srcs: ["res/a", "res/b"],
+					path: "java-res",
+					srcs: ["java-res/a", "java-res/b"],
 				}`,
-			args: "-C res -f res/a -f res/b",
+			args: "-C java-res -f java-res/a -f java-res/b",
 		},
 		{
 			// Test that a module with "include_srcs: true" includes its source files in the resources jar
@@ -562,21 +637,21 @@
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
-			java_resource_dirs: ["res", "res2"],
-			exclude_java_resource_dirs: ["res2"],
+			java_resource_dirs: ["java-res", "java-res2"],
+			exclude_java_resource_dirs: ["java-res2"],
 		}
 
 		java_library {
 			name: "bar",
 			srcs: ["a.java"],
-			java_resources: ["res/*"],
-			exclude_java_resources: ["res/b"],
+			java_resources: ["java-res/*"],
+			exclude_java_resources: ["java-res/b"],
 		}
 	`)
 
 	fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
 
-	expected := "-C res -f res/a -f res/b"
+	expected := "-C java-res -f java-res/a -f java-res/b"
 	if fooRes.Args["jarArgs"] != expected {
 		t.Errorf("foo resource jar args %q is not %q",
 			fooRes.Args["jarArgs"], expected)
@@ -585,7 +660,7 @@
 
 	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
 
-	expected = "-C . -f res/a"
+	expected = "-C . -f java-res/a"
 	if barRes.Args["jarArgs"] != expected {
 		t.Errorf("bar resource jar args %q is not %q",
 			barRes.Args["jarArgs"], expected)
@@ -606,7 +681,7 @@
 
 		genrule {
 			name: "gen",
-			tool_files: ["res/a"],
+			tool_files: ["java-res/a"],
 			out: ["gen.java"],
 		}
 	`)
@@ -630,43 +705,61 @@
 	ctx := testJava(t, `
 		java_library {
 			name: "foo",
-                        srcs: ["a.java", "b.kt"],
+			srcs: ["a.java", "b.kt"],
 		}
 
 		java_library {
 			name: "bar",
-                        srcs: ["b.kt"],
+			srcs: ["b.kt"],
+			libs: ["foo"],
+			static_libs: ["baz"],
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["c.java"],
 		}
 		`)
 
-	kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
-	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	jar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
+	fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
+	fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+	fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
 
-	if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" ||
-		kotlinc.Inputs[1].String() != "b.kt" {
-		t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
+	if len(fooKotlinc.Inputs) != 2 || fooKotlinc.Inputs[0].String() != "a.java" ||
+		fooKotlinc.Inputs[1].String() != "b.kt" {
+		t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, fooKotlinc.Inputs)
 	}
 
-	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
-		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	if len(fooJavac.Inputs) != 1 || fooJavac.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, fooJavac.Inputs)
 	}
 
-	if !strings.Contains(javac.Args["classpath"], kotlinc.Output.String()) {
+	if !strings.Contains(fooJavac.Args["classpath"], fooKotlinc.Output.String()) {
 		t.Errorf("foo classpath %v does not contain %q",
-			javac.Args["classpath"], kotlinc.Output.String())
+			fooJavac.Args["classpath"], fooKotlinc.Output.String())
 	}
 
-	if !inList(kotlinc.Output.String(), jar.Inputs.Strings()) {
+	if !inList(fooKotlinc.Output.String(), fooJar.Inputs.Strings()) {
 		t.Errorf("foo jar inputs %v does not contain %q",
-			jar.Inputs.Strings(), kotlinc.Output.String())
+			fooJar.Inputs.Strings(), fooKotlinc.Output.String())
 	}
 
-	kotlinc = ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
-	jar = ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
+	fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar")
+	bazHeaderJar := ctx.ModuleForTests("baz", "android_common").Output("turbine-combined/baz.jar")
+	barKotlinc := ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
 
-	if len(kotlinc.Inputs) != 1 || kotlinc.Inputs[0].String() != "b.kt" {
-		t.Errorf(`bar kotlinc inputs %v != ["b.kt"]`, kotlinc.Inputs)
+	if len(barKotlinc.Inputs) != 1 || barKotlinc.Inputs[0].String() != "b.kt" {
+		t.Errorf(`bar kotlinc inputs %v != ["b.kt"]`, barKotlinc.Inputs)
+	}
+
+	if !inList(fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
+		t.Errorf(`expected %q in bar implicits %v`,
+			fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
+	}
+
+	if !inList(bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
+		t.Errorf(`expected %q in bar implicits %v`,
+			bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
 	}
 }
 
@@ -679,7 +772,7 @@
 
 		java_library {
 			name: "bar",
-                        srcs: ["b.java"],
+			srcs: ["b.java"],
 			static_libs: ["foo"],
 		}
 
@@ -735,7 +828,62 @@
 	}
 }
 
+func TestJarGenrules(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+
+		java_genrule {
+			name: "jargen",
+			tool_files: ["b.java"],
+			cmd: "$(location b.java) $(in) $(out)",
+			out: ["jargen.jar"],
+			srcs: [":foo"],
+		}
+
+		java_library {
+			name: "bar",
+			static_libs: ["jargen"],
+			srcs: ["c.java"],
+		}
+
+		java_library {
+			name: "baz",
+			libs: ["jargen"],
+			srcs: ["c.java"],
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common").Output("javac/foo.jar")
+	jargen := ctx.ModuleForTests("jargen", "android_common").Output("jargen.jar")
+	bar := ctx.ModuleForTests("bar", "android_common").Output("javac/bar.jar")
+	baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar")
+	barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
+
+	if len(jargen.Inputs) != 1 || jargen.Inputs[0].String() != foo.Output.String() {
+		t.Errorf("expected jargen inputs [%q], got %q", foo.Output.String(), jargen.Inputs.Strings())
+	}
+
+	if !strings.Contains(bar.Args["classpath"], jargen.Output.String()) {
+		t.Errorf("bar classpath %v does not contain %q", bar.Args["classpath"], jargen.Output.String())
+	}
+
+	if !strings.Contains(baz.Args["classpath"], jargen.Output.String()) {
+		t.Errorf("baz classpath %v does not contain %q", baz.Args["classpath"], jargen.Output.String())
+	}
+
+	if len(barCombined.Inputs) != 2 ||
+		barCombined.Inputs[0].String() != bar.Output.String() ||
+		barCombined.Inputs[1].String() != jargen.Output.String() {
+		t.Errorf("bar combined jar inputs %v is not [%q, %q]",
+			barCombined.Inputs.Strings(), bar.Output.String(), jargen.Output.String())
+	}
+}
+
 func fail(t *testing.T, errs []error) {
+	t.Helper()
 	if len(errs) > 0 {
 		for _, err := range errs {
 			t.Error(err)
diff --git a/java/proto.go b/java/proto.go
index 17f02a3..226fac0 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -31,17 +31,17 @@
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
 			Command: `rm -rf $outDir && mkdir -p $outDir && ` +
-				`$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in && ` +
+				`$protocCmd $protoOut=$protoOutParams:$outDir $protoFlags $in && ` +
 				`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
 			CommandDeps: []string{
 				"$protocCmd",
 				"${config.SoongZipCmd}",
 			},
-		}, "protoFlags", "protoOut", "protoOutFlags", "outDir")
+		}, "protoFlags", "protoOut", "protoOutParams", "outDir")
 )
 
 func genProto(ctx android.ModuleContext, outputSrcJar android.WritablePath,
-	protoFiles android.Paths, protoFlags []string, protoOut, protoOutFlags string) {
+	protoFiles android.Paths, protoFlags []string, protoOut, protoOutParams string) {
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        proto,
@@ -49,10 +49,10 @@
 		Output:      outputSrcJar,
 		Inputs:      protoFiles,
 		Args: map[string]string{
-			"outDir":        android.ProtoDir(ctx).String(),
-			"protoOut":      protoOut,
-			"protoOutFlags": protoOutFlags,
-			"protoFlags":    strings.Join(protoFlags, " "),
+			"outDir":         android.ProtoDir(ctx).String(),
+			"protoOut":       protoOut,
+			"protoOutParams": protoOutParams,
+			"protoFlags":     strings.Join(protoFlags, " "),
 		},
 	})
 }
@@ -77,19 +77,31 @@
 	}
 }
 
-func protoFlags(ctx android.ModuleContext, p *android.ProtoProperties, flags javaBuilderFlags) javaBuilderFlags {
+func protoFlags(ctx android.ModuleContext, j *CompilerProperties, p *android.ProtoProperties,
+	flags javaBuilderFlags) javaBuilderFlags {
+
 	switch proptools.String(p.Proto.Type) {
 	case "micro":
-		flags.protoOutFlag = "--javamicro_out"
+		flags.protoOutTypeFlag = "--javamicro_out"
 	case "nano":
-		flags.protoOutFlag = "--javanano_out"
-	case "lite", "full", "":
-		flags.protoOutFlag = "--java_out"
+		flags.protoOutTypeFlag = "--javanano_out"
+	case "lite":
+		flags.protoOutTypeFlag = "--java_out"
+		flags.protoOutParams = "lite"
+	case "full", "":
+		flags.protoOutTypeFlag = "--java_out"
 	default:
 		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
 			proptools.String(p.Proto.Type))
 	}
 
+	if len(j.Proto.Output_params) > 0 {
+		if flags.protoOutParams != "" {
+			flags.protoOutParams += ","
+		}
+		flags.protoOutParams += strings.Join(j.Proto.Output_params, ",")
+	}
+
 	flags.protoFlags = android.ProtoFlags(ctx, p)
 
 	return flags
diff --git a/java/system_modules.go b/java/system_modules.go
index c3e40ca..5234d17 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -121,7 +121,7 @@
 
 	jars = append(jars, android.PathsForModuleSrc(ctx, system.properties.Jars)...)
 
-	if ctx.AConfig().TargetOpenJDK9() {
+	if ctx.Config().TargetOpenJDK9() {
 		system.outputFile = TransformJarsToSystemModules(ctx, "java.base", jars)
 	}
 }
diff --git a/python/androidmk.go b/python/androidmk.go
index 4c94450..5fa01ab 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -39,7 +39,7 @@
 }
 
 func (p *Module) AndroidMk() android.AndroidMkData {
-	ret := android.AndroidMkData{}
+	ret := android.AndroidMkData{OutputFile: p.installSource}
 
 	p.subAndroidMk(&ret, p.installer)
 
@@ -55,7 +55,7 @@
 				strings.Join(p.binaryProperties.Test_suites, " "))
 		}
 	})
-	base.subAndroidMk(ret, p.baseInstaller)
+	base.subAndroidMk(ret, p.pythonInstaller)
 }
 
 func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
@@ -67,7 +67,7 @@
 				strings.Join(p.binaryDecorator.binaryProperties.Test_suites, " "))
 		}
 	})
-	base.subAndroidMk(ret, p.binaryDecorator.baseInstaller)
+	base.subAndroidMk(ret, p.binaryDecorator.pythonInstaller)
 }
 
 func (installer *pythonInstaller) AndroidMk(base *Module, ret *android.AndroidMkData) {
diff --git a/python/binary.go b/python/binary.go
index 14c4952..457c7fa 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -49,24 +49,20 @@
 type binaryDecorator struct {
 	binaryProperties BinaryProperties
 
-	baseInstaller *pythonInstaller
+	*pythonInstaller
 }
 
 type IntermPathProvider interface {
 	IntermPathForModuleOut() android.OptionalPath
 }
 
-func (binary *binaryDecorator) install(ctx android.ModuleContext, file android.Path) {
-	binary.baseInstaller.install(ctx, file)
-}
-
 var (
 	stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
 )
 
 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
 	module := newModule(hod, android.MultilibFirst)
-	decorator := &binaryDecorator{baseInstaller: NewPythonInstaller("bin")}
+	decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")}
 
 	module.bootstrapper = decorator
 	module.installer = decorator
diff --git a/python/installer.go b/python/installer.go
index 04698c5..ab3d9b4 100644
--- a/python/installer.go
+++ b/python/installer.go
@@ -15,26 +15,47 @@
 package python
 
 import (
+	"path/filepath"
+
 	"android/soong/android"
 )
 
 // This file handles installing python executables into their final location
 
+type installLocation int
+
+const (
+	InstallInData installLocation = iota
+)
+
 type pythonInstaller struct {
-	dir string
+	dir      string
+	dir64    string
+	relative string
 
 	path android.OutputPath
 }
 
-func NewPythonInstaller(dir string) *pythonInstaller {
+func NewPythonInstaller(dir, dir64 string) *pythonInstaller {
 	return &pythonInstaller{
-		dir: dir,
+		dir:   dir,
+		dir64: dir64,
 	}
 }
 
 var _ installer = (*pythonInstaller)(nil)
 
+func (installer *pythonInstaller) installDir(ctx android.ModuleContext) android.OutputPath {
+	dir := installer.dir
+	if ctx.Arch().ArchType.Multilib == "lib64" && installer.dir64 != "" {
+		dir = installer.dir64
+	}
+	if !ctx.Host() && !ctx.Arch().Native {
+		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
+	}
+	return android.PathForModuleInstall(ctx, dir, installer.relative)
+}
+
 func (installer *pythonInstaller) install(ctx android.ModuleContext, file android.Path) {
-	installer.path = ctx.InstallFile(android.PathForModuleInstall(ctx, installer.dir),
-		file.Base(), file)
+	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
 }
diff --git a/python/library.go b/python/library.go
index 58ee55f..65c1352 100644
--- a/python/library.go
+++ b/python/library.go
@@ -22,6 +22,7 @@
 
 func init() {
 	android.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
+	android.RegisterModuleType("python_library", PythonLibraryFactory)
 }
 
 func PythonLibraryHostFactory() android.Module {
@@ -29,3 +30,9 @@
 
 	return module.Init()
 }
+
+func PythonLibraryFactory() android.Module {
+	module := newModule(android.HostAndDeviceSupported, android.MultilibBoth)
+
+	return module.Init()
+}
diff --git a/python/python.go b/python/python.go
index 9d6d6a7..9a3b1bb 100644
--- a/python/python.go
+++ b/python/python.go
@@ -242,6 +242,14 @@
 	}
 }
 
+func (p *Module) HostToolPath() android.OptionalPath {
+	if p.installer == nil {
+		// python_library is just meta module, and doesn't have any installer.
+		return android.OptionalPath{}
+	}
+	return android.OptionalPathForPath(p.installer.(*binaryDecorator).path)
+}
+
 func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
 	switch actual_version {
 	case pyVersion2:
@@ -558,5 +566,9 @@
 	return true
 }
 
+func (p *Module) InstallInData() bool {
+	return true
+}
+
 var Bool = proptools.Bool
 var String = proptools.String
diff --git a/python/test.go b/python/test.go
index de2b13e..825e63c 100644
--- a/python/test.go
+++ b/python/test.go
@@ -22,6 +22,7 @@
 
 func init() {
 	android.RegisterModuleType("python_test_host", PythonTestHostFactory)
+	android.RegisterModuleType("python_test", PythonTestFactory)
 }
 
 type testDecorator struct {
@@ -29,13 +30,18 @@
 }
 
 func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) {
-	test.binaryDecorator.baseInstaller.install(ctx, file)
+	test.binaryDecorator.pythonInstaller.dir = "nativetest"
+	test.binaryDecorator.pythonInstaller.dir64 = "nativetest64"
+
+	test.binaryDecorator.pythonInstaller.relative = ctx.ModuleName()
+
+	test.binaryDecorator.pythonInstaller.install(ctx, file)
 }
 
 func NewTest(hod android.HostOrDeviceSupported) *Module {
 	module, binary := NewBinary(hod)
 
-	binary.baseInstaller = NewPythonInstaller("nativetest")
+	binary.pythonInstaller = NewPythonInstaller("nativetest", "nativetest64")
 
 	test := &testDecorator{binaryDecorator: binary}
 
@@ -50,3 +56,10 @@
 
 	return module.Init()
 }
+
+func PythonTestFactory() android.Module {
+	module := NewTest(android.HostAndDeviceSupported)
+	module.multilib = android.MultilibBoth
+
+	return module.Init()
+}
diff --git a/scripts/diff_build_graphs.sh b/scripts/diff_build_graphs.sh
index e7d8749..81010f3 100755
--- a/scripts/diff_build_graphs.sh
+++ b/scripts/diff_build_graphs.sh
@@ -120,7 +120,7 @@
   diff -r "$unzipped1" "$unzipped2" -x build_date.txt -x build_number.txt -x '\.*' -x '*.log' -x build_fingerprint.txt -x build.ninja.d -x '*.zip' > $diffFile || true
   if [[ -s "$diffFile" ]]; then
     # outputs are different, so remove the unzipped versions but keep the zipped versions
-    echo "Some differences for product $product:"
+    echo "First few differences (total diff linecount=$(wc -l $diffFile)) for product $product:"
     cat "$diffFile" | head -n 10
     echo "End of differences for product $product"
     rm -rf "$unzipped1" "$unzipped2"
diff --git a/scripts/setup_go_workspace_for_soong.sh b/scripts/setup_go_workspace_for_soong.sh
index 1c9a0b7..e2fb9fa 100755
--- a/scripts/setup_go_workspace_for_soong.sh
+++ b/scripts/setup_go_workspace_for_soong.sh
@@ -53,6 +53,7 @@
   bindOne "${ANDROID_PATH}/build/soong" "${OUTPUT_PATH}/src/android/soong"
 
   bindOne "${ANDROID_PATH}/art/build" "${OUTPUT_PATH}/src/android/soong/art"
+  bindOne "${ANDROID_PATH}/external/golang-protobuf" "${OUTPUT_PATH}/src/github.com/golang/protobuf"
   bindOne "${ANDROID_PATH}/external/llvm/soong" "${OUTPUT_PATH}/src/android/soong/llvm"
   bindOne "${ANDROID_PATH}/external/clang/soong" "${OUTPUT_PATH}/src/android/soong/clang"
   echo
@@ -64,7 +65,14 @@
   existingPath="$1"
   newPath="$2"
   mkdir -p "$newPath"
-  echoAndDo bindfs "${existingPath}" "${newPath}"
+  case $(uname -s) in
+    Darwin)
+      echoAndDo bindfs -o allow_recursion -n "${existingPath}" "${newPath}"
+      ;;
+    Linux)
+      echoAndDo bindfs "${existingPath}" "${newPath}"
+      ;;
+  esac
 }
 
 function echoAndDo() {
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d1b4943..5809894 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -36,6 +36,7 @@
         "proc_sync.go",
         "signal.go",
         "soong.go",
+        "test_build.go",
         "util.go",
     ],
     testSrcs: [
diff --git a/ui/build/build.go b/ui/build/build.go
index 0df22b3..78eb6a3 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -68,6 +68,7 @@
 	BuildSoong         = 1 << iota
 	BuildKati          = 1 << iota
 	BuildNinja         = 1 << iota
+	RunBuildTests      = 1 << iota
 	BuildAll           = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
 )
 
@@ -172,14 +173,18 @@
 		}
 	}
 
+	// Write combined ninja file
+	createCombinedBuildNinjaFile(ctx, config)
+
+	if what&RunBuildTests != 0 {
+		testForDanglingRules(ctx, config)
+	}
+
 	if what&BuildNinja != 0 {
 		if !config.SkipMake() {
 			installCleanIfNecessary(ctx, config)
 		}
 
-		// Write combined ninja file
-		createCombinedBuildNinjaFile(ctx, config)
-
 		// Run ninja
 		runNinja(ctx, config)
 	}
diff --git a/ui/build/config.go b/ui/build/config.go
index 6e5559d..c975243 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -34,11 +34,12 @@
 	environ   *Environment
 
 	// From the arguments
-	parallel  int
-	keepGoing int
-	verbose   bool
-	dist      bool
-	skipMake  bool
+	parallel   int
+	keepGoing  int
+	verbose    bool
+	checkbuild bool
+	dist       bool
+	skipMake   bool
 
 	// From the product config
 	katiArgs     []string
@@ -145,14 +146,16 @@
 	}
 
 	// Configure Java-related variables, including adding it to $PATH
+	java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
+	java9Home := filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
 	javaHome := func() string {
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
 			return override
 		}
 		if v, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK9"); ok && v != "" && v != "false" {
-			return filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
+			return java9Home
 		}
-		return filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
+		return java8Home
 	}()
 	absJavaHome := absPath(ctx, javaHome)
 
@@ -163,6 +166,8 @@
 	ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
 	ret.environ.Set("JAVA_HOME", absJavaHome)
 	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
+	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
+	ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	return Config{ret}
@@ -206,6 +211,8 @@
 		} else {
 			if arg == "dist" {
 				c.dist = true
+			} else if arg == "checkbuild" {
+				c.checkbuild = true
 			}
 			c.arguments = append(c.arguments, arg)
 		}
@@ -313,6 +320,12 @@
 	panic("SetKatiSuffix has not been called")
 }
 
+// Checkbuild returns true if "checkbuild" was one of the build goals, which means that the
+// user is interested in additional checks at the expense of build time.
+func (c *configImpl) Checkbuild() bool {
+	return c.checkbuild
+}
+
 func (c *configImpl) Dist() bool {
 	return c.dist
 }
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index fb20d63..96f2274 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -106,6 +106,7 @@
 	"AUX_OS_VARIANT_LIST",
 	"TARGET_BUILD_PDK",
 	"PDK_FUSION_PLATFORM_ZIP",
+	"PRODUCT_SOONG_NAMESPACES",
 }
 
 func Banner(make_vars map[string]string) string {
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 05dec3a..a0f5d08 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -38,15 +38,28 @@
 	if err != nil {
 		ctx.Fatalf("No working directory for module-finder: %v", err.Error())
 	}
+	filesystem := fs.OsFs
+
+	// if the root dir is ignored, then the subsequent error messages are very confusing,
+	// so check for that upfront
+	pruneFiles := []string{".out-dir", ".find-ignore"}
+	for _, name := range pruneFiles {
+		prunePath := filepath.Join(dir, name)
+		_, statErr := filesystem.Lstat(prunePath)
+		if statErr == nil {
+			ctx.Fatalf("%v must not exist", prunePath)
+		}
+	}
+
 	cacheParams := finder.CacheParams{
 		WorkingDirectory: dir,
 		RootDirs:         []string{"."},
 		ExcludeDirs:      []string{".git", ".repo"},
-		PruneFiles:       []string{".out-dir", ".find-ignore"},
-		IncludeFiles:     []string{"Android.mk", "Android.bp", "Blueprints", "CleanSpec.mk"},
+		PruneFiles:       pruneFiles,
+		IncludeFiles:     []string{"Android.mk", "Android.bp", "Blueprints", "CleanSpec.mk", "TEST_MAPPING"},
 	}
 	dumpDir := config.FileListDir()
-	f, err = finder.New(cacheParams, fs.OsFs, logger.New(ioutil.Discard),
+	f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard),
 		filepath.Join(dumpDir, "files.db"))
 	if err != nil {
 		ctx.Fatalf("Could not create module-finder: %v", err)
@@ -74,17 +87,17 @@
 		ctx.Fatalf("Could not export module list: %v", err)
 	}
 
-	isBlueprintFile := func(dir finder.DirEntries) (dirs []string, files []string) {
-		files = []string{}
-		for _, file := range dir.FileNames {
-			if file == "Android.bp" || file == "Blueprints" {
-				files = append(files, file)
-			}
-		}
-
-		return dir.DirNames, files
+	testMappings := f.FindNamedAt(".", "TEST_MAPPING")
+	err = dumpListToFile(testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
+	if err != nil {
+		ctx.Fatalf("Could not find modules: %v", err)
 	}
-	androidBps := f.FindMatching(".", isBlueprintFile)
+
+	androidBps := f.FindNamedAt(".", "Android.bp")
+	androidBps = append(androidBps, f.FindNamedAt("build/blueprint", "Blueprints")...)
+	if len(androidBps) == 0 {
+		ctx.Fatalf("No Android.bp found")
+	}
 	err = dumpListToFile(androidBps, filepath.Join(dumpDir, "Android.bp.list"))
 	if err != nil {
 		ctx.Fatalf("Could not find modules: %v", err)
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
new file mode 100644
index 0000000..940f0c8
--- /dev/null
+++ b/ui/build/test_build.go
@@ -0,0 +1,85 @@
+// 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 build
+
+import (
+	"bufio"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+// Checks for files in the out directory that have a rule that depends on them but no rule to
+// create them. This catches a common set of build failures where a rule to generate a file is
+// deleted (either by deleting a module in an Android.mk file, or by modifying the build system
+// incorrectly).  These failures are often not caught by a local incremental build because the
+// previously built files are still present in the output directory.
+func testForDanglingRules(ctx Context, config Config) {
+	// Many modules are disabled on mac.  Checking for dangling rules would cause lots of build
+	// breakages, and presubmit wouldn't catch them, so just disable the check.
+	if runtime.GOOS != "linux" {
+		return
+	}
+
+	ctx.BeginTrace("test for dangling rules")
+	defer ctx.EndTrace()
+
+	// Get a list of leaf nodes in the dependency graph from ninja
+	executable := config.PrebuiltBuildTool("ninja")
+
+	args := []string{}
+	args = append(args, config.NinjaArgs()...)
+	args = append(args, "-f", config.CombinedNinjaFile())
+	args = append(args, "-t", "targets", "rule")
+
+	cmd := Command(ctx, config, "ninja", executable, args...)
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		ctx.Fatal(err)
+	}
+
+	cmd.StartOrFatal()
+
+	outDir := config.OutDir()
+	bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
+	miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
+
+	var danglingRules []string
+
+	scanner := bufio.NewScanner(stdout)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if !strings.HasPrefix(line, outDir) {
+			// Leaf node is not in the out directory.
+			continue
+		}
+		if strings.HasPrefix(line, bootstrapDir) || strings.HasPrefix(line, miniBootstrapDir) {
+			// Leaf node is in one of Soong's bootstrap directories, which do not have
+			// full build rules in the primary build.ninja file.
+			continue
+		}
+		danglingRules = append(danglingRules, line)
+	}
+
+	cmd.WaitOrFatal()
+
+	if len(danglingRules) > 0 {
+		ctx.Println("Dependencies in out found with no rule to create them:")
+		for _, dep := range danglingRules {
+			ctx.Println(dep)
+		}
+		ctx.Fatal("")
+	}
+}