Merge "Have diff_build_graphs.sh print the number of lines in the diff"
diff --git a/Android.bp b/Android.bp
index 4dddb28..a296da1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -135,6 +135,7 @@
         "cc/tidy.go",
         "cc/util.go",
         "cc/vndk.go",
+        "cc/vndk_prebuilt.go",
 
         "cc/cmakelists.go",
         "cc/compiler.go",
@@ -222,6 +223,7 @@
         "java/system_modules.go",
     ],
     testSrcs: [
+        "java/app_test.go",
         "java/java_test.go",
     ],
     pluginFor: ["soong_build"],
diff --git a/android/androidmk.go b/android/androidmk.go
index aff43fa..d88ba8f 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -60,9 +60,7 @@
 type androidMkSingleton struct{}
 
 func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
-	config := ctx.Config().(Config)
-
-	if !config.EmbeddedInMake() {
+	if !ctx.Config().EmbeddedInMake() {
 		return
 	}
 
@@ -74,7 +72,7 @@
 
 	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
 	}
@@ -184,8 +182,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
 		}
 	}
diff --git a/android/api_levels.go b/android/api_levels.go
index bdfbc43..a519117 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -66,7 +66,7 @@
 		"N-MR1": 25,
 		"O":     26,
 	}
-	for i, codename := range ctx.Config().(Config).PlatformVersionCombinedCodenames() {
+	for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() {
 		apiLevelsMap[codename] = baseApiLevel + i
 	}
 
diff --git a/android/arch.go b/android/arch.go
index 5ea9759..7f9abc6 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)
diff --git a/android/config.go b/android/config.go
index 2589f71..0eebb5f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -475,27 +475,37 @@
 }
 
 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")
+	defaultCert := String(c.ProductVariables.DefaultAppCertificate)
+	if defaultCert != "" {
+		return PathForSource(ctx, defaultCert)
+	} else {
+		return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
+	}
 }
 
 func (c *config) AllowMissingDependencies() bool {
@@ -622,11 +632,12 @@
 	return "vendor"
 }
 
-func (c *deviceConfig) CompileVndk() bool {
-	if c.config.ProductVariables.DeviceVndkVersion == nil {
-		return false
-	}
-	return *c.config.ProductVariables.DeviceVndkVersion == "current"
+func (c *deviceConfig) VndkVersion() string {
+	return String(c.config.ProductVariables.DeviceVndkVersion)
+}
+
+func (c *deviceConfig) ExtraVndkVersions() []string {
+	return c.config.ProductVariables.ExtraVndkVersions
 }
 
 func (c *deviceConfig) BtConfigIncludeDir() string {
@@ -676,3 +687,11 @@
 	}
 	return prefixInList(path, *c.ProductVariables.CFIIncludePaths)
 }
+
+func stringSlice(s *[]string) []string {
+	if s != nil {
+		return *s
+	} else {
+		return nil
+	}
+}
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 d323613..00a20f5 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -105,13 +105,11 @@
 }
 
 func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	config := ctx.Config().(Config)
-
-	if !config.EmbeddedInMake() {
+	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
@@ -120,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 0eb4820..c728487 100644
--- a/android/module.go
+++ b/android/module.go
@@ -19,6 +19,7 @@
 	"path/filepath"
 	"sort"
 	"strings"
+	"text/scanner"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
@@ -70,13 +71,36 @@
 }
 
 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 PackageContext, params ModuleBuildParams)
@@ -482,7 +506,7 @@
 			Rule:      blueprint.Phony,
 			Output:    name,
 			Implicits: allInstalledFiles,
-			Default:   !ctx.Config().(Config).EmbeddedInMake(),
+			Default:   !ctx.Config().EmbeddedInMake(),
 		})
 		deps = append(deps, name)
 		a.installTarget = name
@@ -501,7 +525,7 @@
 
 	if len(deps) > 0 {
 		suffix := ""
-		if ctx.Config().(Config).EmbeddedInMake() {
+		if ctx.Config().EmbeddedInMake() {
 			suffix = "-soong"
 		}
 
@@ -605,6 +629,10 @@
 	return
 }
 
+func (a *androidModuleContext) Config() Config {
+	return a.ModuleContext.Config().(Config)
+}
+
 func (a *androidModuleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
 	a.Build(pctx, BuildParams(params))
 }
@@ -692,7 +720,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))
@@ -850,11 +878,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
 		}
 	}
@@ -899,7 +927,7 @@
 			Input:       srcPath,
 			Implicits:   implicitDeps,
 			OrderOnly:   orderOnlyDeps,
-			Default:     !a.AConfig().EmbeddedInMake(),
+			Default:     !a.Config().EmbeddedInMake(),
 		})
 
 		a.installFiles = append(a.installFiles, fullInstallPath)
@@ -919,7 +947,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(),
 			},
@@ -1094,7 +1122,7 @@
 	})
 
 	suffix := ""
-	if ctx.Config().(Config).EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		suffix = "-soong"
 	}
 
@@ -1106,7 +1134,7 @@
 	})
 
 	// Make will generate the MODULES-IN-* targets
-	if ctx.Config().(Config).EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		return
 	}
 
@@ -1151,7 +1179,7 @@
 			Implicits: modulesInDir[dir],
 			// HACK: checkbuild should be an optional build, but force it
 			// enabled for now in standalone builds
-			Default: !ctx.Config().(Config).EmbeddedInMake(),
+			Default: !ctx.Config().EmbeddedInMake(),
 		})
 	}
 
diff --git a/android/mutator.go b/android/mutator.go
index cc3f1f3..db3eaa3 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -108,7 +108,7 @@
 type AndroidTopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
-	blueprint.BaseModuleContext
+	BaseModuleContext
 	androidBaseContext
 
 	OtherModuleExists(name string) bool
@@ -139,8 +139,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 +207,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/package_ctx.go b/android/package_ctx.go
index 1626f76..3f6a253 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"runtime"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -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{}) {
@@ -141,7 +142,7 @@
 	})
 }
 
-// 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.
@@ -164,6 +165,33 @@
 	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
diff --git a/android/paths.go b/android/paths.go
index 71049ee..e0cbd21 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.
@@ -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{})
 }
 
@@ -476,14 +467,14 @@
 // 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
@@ -501,14 +492,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
@@ -536,14 +527,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{}
@@ -652,7 +643,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() {}
@@ -853,7 +844,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:
@@ -905,7 +896,7 @@
 	if strings.ContainsAny(phony, "$/") {
 		reportPathError(ctx, "Phony target contains invalid character ($ or /): %s", phony)
 	}
-	return OutputPath{basePath{phony, pathConfig(ctx), ""}}
+	return OutputPath{basePath{phony, ctx.Config(), ""}}
 }
 
 type testPath struct {
diff --git a/android/paths_test.go b/android/paths_test.go
index 82ae4dc..1e4ba53 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
 }
 
diff --git a/android/register.go b/android/register.go
index 78ae481..6c88af1 100644
--- a/android/register.go
+++ b/android/register.go
@@ -99,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
index f2f575f..87910fd 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -21,8 +21,7 @@
 
 // SingletonContext
 type SingletonContext interface {
-	// TODO(ccross): make this return an android.Config
-	Config() interface{}
+	Config() Config
 
 	ModuleName(module blueprint.Module) string
 	ModuleDir(module blueprint.Module) string
@@ -87,6 +86,10 @@
 	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)
 }
diff --git a/android/testing.go b/android/testing.go
index 3d5e9d9..fc58cec 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -54,7 +54,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 {
@@ -131,7 +131,7 @@
 			outputs = append(outputs, p.Output)
 		}
 		for _, f := range outputs {
-			if f.Rel() == file {
+			if f.String() == file || f.Rel() == file {
 				return p
 			}
 		}
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 13b5abf..a3920a1 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -141,6 +141,8 @@
 	AAPTPreferredConfig *string   `json:",omitempty"`
 	AAPTPrebuiltDPI     *[]string `json:",omitempty"`
 
+	DefaultAppCertificate *string `json:",omitempty"`
+
 	AppsDefaultVersionName *string `json:",omitempty"`
 
 	Allow_missing_dependencies *bool `json:",omitempty"`
@@ -190,6 +192,8 @@
 
 	DeviceKernelHeaders []string `json:",omitempty"`
 	DistDir             *string  `json:",omitempty"`
+
+	ExtraVndkVersions []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -258,7 +262,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/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index df01cf4..18756a9 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 {
@@ -92,6 +93,7 @@
 			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
 			"LOCAL_NOTICE_FILE":             "notice",
 			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
+			"LOCAL_INSTRUMENTATION_FOR":     "instrumentation_for",
 		})
 	addStandardProperties(bpparser.ListType,
 		map[string]string{
@@ -661,6 +663,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)": {
@@ -693,6 +697,10 @@
 	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",
@@ -729,6 +737,10 @@
 	globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
 	globalScope.SetFunc("all-proto-files-under", allProtoFilesUnder)
 	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..9986889 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -460,6 +460,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 44e977f..6d1c44f 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -348,3 +348,24 @@
 		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)
+	})
+}
\ No newline at end of file
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/cc.go b/cc/cc.go
index e18b2cc..c31cf04 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -945,7 +945,7 @@
 			clang = true
 		}
 
-		if ctx.Device() && ctx.AConfig().DeviceUsesClang() {
+		if ctx.Device() && ctx.Config().DeviceUsesClang() {
 			clang = true
 		}
 	}
@@ -1372,7 +1372,7 @@
 
 	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)
@@ -1408,7 +1408,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)
@@ -1419,6 +1419,12 @@
 	} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
 		// ... and LL-NDK headers as well
 		mctx.CreateVariations(vendorMode)
+	} 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.
@@ -1441,10 +1447,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/cmakelists.go b/cc/cmakelists.go
index 9b32182..c25578e 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -82,7 +82,7 @@
 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 {
diff --git a/cc/compiler.go b/cc/compiler.go
index fc2eeec..40dbea4 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -218,7 +218,7 @@
 }
 
 func addToModuleList(ctx ModuleContext, list string, module string) {
-	getWallWerrorMap(ctx.AConfig(), list).Store(module, true)
+	getWallWerrorMap(ctx.Config(), list).Store(module, true)
 }
 
 // Create a Flags struct that collects the compile flags from global values,
@@ -360,7 +360,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__")
 	}
 
@@ -488,7 +488,6 @@
 				addToModuleList(ctx, modulesAddedWall, module)
 				flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
 			} else {
-				addToModuleList(ctx, modulesAddedWerror, module)
 				flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
 			}
 		}
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 8881b4b..fb71e6a 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -120,10 +120,7 @@
 	ClangDefaultShortVersion = "5.0.1"
 
 	WarningAllowedProjects = []string{
-		"external/boringssl/",
 		"external/libese/third_party/NXPNFC_P61_JCOP_Kit/",
-		"external/mdnsresponder/",
-		"external/protobuf/",
 		"external/skia/",
 		"device/",
 		"frameworks/av/media/libeffects/factory/",
@@ -135,8 +132,6 @@
 		"frameworks/native/libs/vr/libdvr/tests/",
 		"frameworks/native/services/surfaceflinger/tests/",
 		"frameworks/native/services/vr/",
-		"hardware/interfaces/audio/effect/",
-		"hardware/interfaces/biometrics/fingerprint/",
 		"vendor/",
 	}
 
@@ -145,15 +140,12 @@
 		"cts/hostsidetests/security/securityPatch/",
 		"cts/tests/tests/permission/jni/",
 		"development/tutorials/ReverseDebug/",
-		"external/freetype/",
 		"frameworks/av/drm/mediacas/plugins/",
-		"frameworks/av/media/libaaudio/examples/",
 		"frameworks/av/services/mediaextractor/",
 		"frameworks/base/core/tests/webkit/apk_with_native_libs/jni/",
 		"frameworks/base/tests/backup/",
 		"frameworks/native/cmds/cmd/",
 		"frameworks/webview/chromium/",
-		"hardware/interfaces/audio/2.0/",
 		"hardware/libhardware/modules/",
 		"hardware/libhardware/tests/",
 		"hardware/qcom/",
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/makevars.go b/cc/makevars.go
index f7f8b60..0d2569a 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -26,7 +26,6 @@
 
 const (
 	modulesAddedWall     = "ModulesAddedWall"
-	modulesAddedWerror   = "ModulesAddedWerror"
 	modulesUsingWnoError = "ModulesUsingWnoError"
 )
 
@@ -102,7 +101,6 @@
 
 	ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
 	ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWall))
-	ctx.Strict("SOONG_MODULES_ADDED_WERROR", makeStringOfKeys(ctx, modulesAddedWerror))
 	ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoError))
 
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
@@ -279,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_library.go b/cc/ndk_library.go
index e69128c..459d980 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.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...)
diff --git a/cc/pgo.go b/cc/pgo.go
index ea23124..9fea154 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -181,7 +181,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 +215,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/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 bf58d0f..1afec26 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -151,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()
 			}
 		}
 	}
@@ -194,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)
 			}
 		}
@@ -225,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
 	}
@@ -611,7 +611,7 @@
 								modules[1].(*Module).Properties.HideFromMake = true
 							}
 						} else {
-							cfiStaticLibs := cfiStaticLibs(mctx.AConfig())
+							cfiStaticLibs := cfiStaticLibs(mctx.Config())
 
 							cfiStaticLibsMutex.Lock()
 							*cfiStaticLibs = append(*cfiStaticLibs, c.Name())
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..6d7c957 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
 	}
 
@@ -82,7 +82,7 @@
 	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/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..a1a164f
--- /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)
+}
\ No newline at end of file
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_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/genrule/genrule.go b/genrule/genrule.go
index c142c53..651ec15 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -134,7 +134,7 @@
 	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...)
 		}
 	}
@@ -168,7 +168,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)
diff --git a/java/aapt2.go b/java/aapt2.go
index ce307fe..84e3729 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -54,7 +55,7 @@
 
 var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
 	blueprint.RuleParams{
-		Command:     `${config.Aapt2Cmd compile -o $outDir $cFlags --legacy $in`,
+		Command:     `${config.Aapt2Cmd} compile -o $outDir $cFlags --legacy $in`,
 		CommandDeps: []string{"${config.Aapt2Cmd}"},
 	},
 	"outDir", "cFlags")
@@ -85,15 +86,18 @@
 		})
 	}
 
+	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: `$aapt2Cmd link -o $out $flags --java $genDir --proguard $proguardOptions $inFlags && ` +
+		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{
-			"$aapt2Cmd",
+			"${config.Aapt2Cmd}",
 			"${config.SoongZipCmd}",
 		},
 		Restat: true,
diff --git a/java/androidmk.go b/java/androidmk.go
index df83faa..2e67639 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -46,6 +46,14 @@
 				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) {
@@ -111,3 +119,40 @@
 		},
 	}
 }
+
+func (app *AndroidApp) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "APPS",
+		OutputFile: android.OptionalPathForPath(app.outputFile),
+		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				if Bool(app.appProperties.Export_package_resources) {
+					if app.dexJarFile != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
+					}
+					fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
+
+					if app.jacocoReportClassesFile != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
+					}
+
+					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")
+					}
+
+					if len(app.rroDirs) > 0 {
+						fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(app.rroDirs.Strings(), " "))
+					}
+					fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES :=",
+						Bool(app.appProperties.Export_package_resources))
+					fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String())
+				}
+			},
+		},
+	}
+
+}
diff --git a/java/app.go b/java/app.go
index fd1fe33..ed6a9db 100644
--- a/java/app.go
+++ b/java/app.go
@@ -27,6 +27,7 @@
 
 func init() {
 	android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+	android.RegisterModuleType("android_app", AndroidAppFactory)
 }
 
 // AAR prebuilts
@@ -69,6 +70,8 @@
 
 	aaptSrcJar    android.Path
 	exportPackage android.Path
+	rroDirs       android.Paths
+	manifestPath  android.Path
 }
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -76,7 +79,7 @@
 
 	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
@@ -85,7 +88,7 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	linkFlags, linkDeps, resDirs, overlayDirs := a.aapt2Flags(ctx)
+	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
 
 	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
 	srcJar := android.PathForModuleGen(ctx, "R.jar")
@@ -116,13 +119,19 @@
 	//	a.properties.Proguard.Enabled = true
 	//}
 
-	a.Module.compile(ctx)
+	if String(a.appProperties.Instrumentation_for) == "" {
+		a.properties.Instrument = true
+	}
+
+	if ctx.ModuleName() != "framework-res" {
+		a.Module.compile(ctx, a.aaptSrcJar)
+	}
 
 	certificate := String(a.appProperties.Certificate)
 	if certificate == "" {
-		certificate = ctx.AConfig().DefaultAppCertificate(ctx).String()
+		certificate = ctx.Config().DefaultAppCertificate(ctx).String()
 	} else if dir, _ := filepath.Split(certificate); dir == "" {
-		certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(ctx).String(), certificate)
+		certificate = filepath.Join(ctx.Config().DefaultAppCertificateDir(ctx).String(), certificate)
 	} else {
 		certificate = filepath.Join(android.PathForSource(ctx).String(), certificate)
 	}
@@ -137,8 +146,15 @@
 	CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
 
 	a.outputFile = packageFile
+	a.rroDirs = rroDirs
+	a.manifestPath = manifestPath
 
-	ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	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 {
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	}
 }
 
 var aaptIgnoreFilenames = []string{
@@ -159,7 +175,7 @@
 }
 
 func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
-	resDirs, overlayDirs []globbedResourceDir) {
+	resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
 
 	hasVersionCode := false
 	hasVersionName := false
@@ -193,7 +209,9 @@
 			dir:   dir,
 			files: resourceGlob(ctx, dir),
 		})
-		overlayDirs = append(overlayDirs, overlayResourceGlob(ctx, dir)...)
+		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+		overlayDirs = append(overlayDirs, resOverlayDirs...)
+		rroDirs = append(rroDirs, resRRODirs...)
 	}
 
 	var assetFiles android.Paths
@@ -209,7 +227,7 @@
 		manifestFile = *a.properties.Manifest
 	}
 
-	manifestPath := android.PathForModuleSrc(ctx, manifestFile)
+	manifestPath = android.PathForModuleSrc(ctx, manifestFile)
 	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
 	linkDeps = append(linkDeps, manifestPath)
 
@@ -236,34 +254,34 @@
 	sdkVersion := String(a.deviceProperties.Sdk_version)
 	switch sdkVersion {
 	case "", "current", "system_current", "test_current":
-		sdkVersion = ctx.AConfig().AppsDefaultVersionName()
+		sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
 	}
 
 	linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
 	linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
 
 	// Product characteristics
-	if !hasProduct && len(ctx.AConfig().ProductAAPTCharacteristics()) > 0 {
-		linkFlags = append(linkFlags, "--product", ctx.AConfig().ProductAAPTCharacteristics())
+	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+		linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
 	}
 
 	// Product AAPT config
-	for _, aaptConfig := range ctx.AConfig().ProductAAPTConfig() {
+	for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
 		linkFlags = append(linkFlags, "-c", aaptConfig)
 	}
 
 	// Product AAPT preferred config
-	if len(ctx.AConfig().ProductAAPTPreferredConfig()) > 0 {
-		linkFlags = append(linkFlags, "--preferred-density", ctx.AConfig().ProductAAPTPreferredConfig())
+	if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
+		linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
 	}
 
 	// Version code
 	if !hasVersionCode {
-		linkFlags = append(linkFlags, "--version-code", ctx.AConfig().PlatformSdkVersion())
+		linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
 	}
 
 	if !hasVersionName {
-		versionName := proptools.NinjaEscape([]string{ctx.AConfig().AppsDefaultVersionName()})[0]
+		versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
 		linkFlags = append(linkFlags, "--version-name ", versionName)
 	}
 
@@ -276,7 +294,7 @@
 	// TODO: LOCAL_PACKAGE_OVERRIDES
 	//    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
 
-	return linkFlags, linkDeps, resDirs, overlayDirs
+	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
 }
 
 func AndroidAppFactory() android.Module {
@@ -308,26 +326,49 @@
 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) []globbedResourceDir {
-	overlayData := ctx.AConfig().Get(overlayDataKey).([]overlayGlobResult)
+func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+	rroDirs android.Paths) {
 
-	var ret []globbedResourceDir
+	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 {
-			ret = append(ret, globbedResourceDir{
-				dir:   android.PathForSource(ctx, data.dir, dir.String()),
-				files: files,
-			})
+			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 ret
+	return res, rroDirs
 }
 
 func OverlaySingletonFactory() android.Singleton {
@@ -337,10 +378,25 @@
 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().(android.Config).ResourceOverlays() {
+	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())
@@ -359,7 +415,7 @@
 		overlayData = append(overlayData, result)
 	}
 
-	ctx.Config().(android.Config).Once(overlayDataKey, func() interface{} {
+	ctx.Config().Once(overlayDataKey, func() interface{} {
 		return overlayData
 	})
 }
diff --git a/java/app_builder.go b/java/app_builder.go
index 82574ae..676ed58 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -29,8 +29,9 @@
 var (
 	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")
 
@@ -48,6 +49,9 @@
 	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")
 }
 
 var combineApk = pctx.AndroidStaticRule("combineApk",
@@ -79,6 +83,9 @@
 		certificateArgs = append(certificateArgs, c+".x509.pem", c+".pk8")
 	}
 
+	// TODO(ccross): sometimes uncompress dex
+	// TODO(ccross): sometimes strip dex
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        signapk,
 		Description: "signapk",
diff --git a/java/app_test.go b/java/app_test.go
index 0b1491e..73ac3f7 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"reflect"
+	"sort"
 	"testing"
 )
 
@@ -34,24 +35,27 @@
 	}
 )
 
-func testApp(t *testing.T, bp string) *android.TestContext {
-	bp += `
-		android_app {
-			name: "framework-res",
-			no_framework_libs: true,
-		}
-	`
-
-	appFs := map[string][]byte{
-		"AndroidManifest.xml":                   nil,
-		"build/target/product/security/testkey": nil,
+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
+		appFS[file] = nil
 	}
 
-	return testJavaWithEnvFs(t, bp, nil, appFs)
+	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) {
@@ -76,7 +80,11 @@
 		t.Errorf("expected aapt2 compile inputs expected:\n  %#v\n got:\n  %#v",
 			resourceFiles, compile.Inputs.Strings())
 	}
-	expectedLinkImplicits = append(expectedLinkImplicits, compile.Outputs.Strings()...)
+
+	compiledResourceOutputs := compile.Outputs.Strings()
+	sort.Strings(compiledResourceOutputs)
+
+	expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
 
 	list := foo.Output("aapt2/res.list")
 	expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
@@ -88,3 +96,144 @@
 			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..be40103 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -386,7 +386,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"
 	}
 
diff --git a/java/config/config.go b/java/config/config.go
index 603d43f..ad2f0ae 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -147,5 +147,5 @@
 		})
 	}
 
-	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilt/sdk/tools", "aapt2")
+	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
 }
diff --git a/java/java.go b/java/java.go
index 0a3b9b4..4355200 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)
 }
@@ -206,6 +205,10 @@
 
 	// 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
 }
 
 type Dependency interface {
@@ -248,7 +251,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 {
@@ -271,7 +274,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,
@@ -303,7 +312,7 @@
 	//	}
 	//}
 
-	if ctx.AConfig().UnbundledBuild() && v != "" {
+	if ctx.Config().UnbundledBuild() && v != "" {
 		return toFile(v)
 	}
 
@@ -331,14 +340,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)
@@ -346,9 +355,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...)
@@ -503,10 +515,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")
@@ -523,7 +535,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"
@@ -558,7 +570,7 @@
 	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)
@@ -612,8 +624,12 @@
 		}
 	}
 
+	// Store the list of .java files that was passed to javac
+	j.compiledJavaSrcs = uniqueSrcFiles
+	j.compiledSrcJars = srcJars
+
 	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 ||
@@ -634,7 +650,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).
@@ -737,13 +753,13 @@
 		outputFile = j.desugar(ctx, flags, outputFile, jarName)
 	}
 
-	if ctx.AConfig().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
 		if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
 			j.properties.Instrument = true
 		}
 	}
 
-	if ctx.AConfig().IsEnvTrue("EMMA_INSTRUMENT") && j.properties.Instrument {
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") && j.properties.Instrument {
 		outputFile = j.instrument(ctx, flags, outputFile, jarName)
 	}
 
@@ -846,11 +862,11 @@
 		dxFlags = append(dxFlags, "--no-locals")
 	}
 
-	if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
+	if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
 		dxFlags = append(dxFlags, "--no-optimize")
 	}
 
-	if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
+	if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
 		dxFlags = append(dxFlags,
 			"--debug",
 			"--verbose",
@@ -875,9 +891,9 @@
 func (j *Module) minSdkVersionNumber(ctx android.ModuleContext) string {
 	switch String(j.deviceProperties.Sdk_version) {
 	case "", "current", "test_current", "system_current":
-		return strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
+		return strconv.Itoa(ctx.Config().DefaultAppTargetSdkInt())
 	default:
-		return String(j.deviceProperties.Sdk_version)
+		return android.GetNumericSdkVersion(String(j.deviceProperties.Sdk_version))
 	}
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index cf5047b..dbecc70 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -51,13 +51,14 @@
 
 	os.Exit(run())
 }
-func testJava(t *testing.T, bp string) *android.TestContext {
-	return testJavaWithEnvFs(t, bp, nil, nil)
+
+func testConfig(env map[string]string) android.Config {
+	return android.TestArchConfig(buildDir, env)
+
 }
 
-func testJavaWithEnvFs(t *testing.T, bp string,
-	env map[string]string, fs map[string][]byte) *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))
@@ -97,21 +98,26 @@
 		`, 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)
-		}
 	}
 
 	mockFS := map[string][]byte{
@@ -132,8 +138,14 @@
 		"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,
 	}
 
 	for k, v := range fs {
@@ -142,10 +154,20 @@
 
 	ctx.MockFileSystem(mockFS)
 
+	return ctx
+}
+
+func run(t *testing.T, ctx *android.TestContext, config android.Config) {
 	_, 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 {
+	config := testConfig(nil)
+	ctx := testContext(config, bp, nil)
+	run(t, ctx, config)
 
 	return ctx
 }
@@ -275,6 +297,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{`""`},
@@ -402,7 +432,9 @@
 
 			// Test again with javac 1.9
 			t.Run("1.9", func(t *testing.T) {
-				ctx := testJavaWithEnvFs(t, bp, map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"}, nil)
+				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"]
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..05efbea 100644
--- a/python/python.go
+++ b/python/python.go
@@ -558,5 +558,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/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..df97d80 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
@@ -206,6 +207,8 @@
 		} else {
 			if arg == "dist" {
 				c.dist = true
+			} else if arg == "checkbuild" {
+				c.checkbuild = true
 			}
 			c.arguments = append(c.arguments, arg)
 		}
@@ -313,6 +316,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/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("")
+	}
+}