Merge "Delete output files before copying to them."
diff --git a/Android.bp b/Android.bp
index 496dcd2..82be0fa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,7 @@
         "android/paths.go",
         "android/prebuilt.go",
         "android/register.go",
+        "android/testing.go",
         "android/util.go",
         "android/variable.go",
 
@@ -123,6 +124,7 @@
         "cc/strip.go",
         "cc/tidy.go",
         "cc/util.go",
+        "cc/vndk.go",
 
         "cc/cmakelists.go",
         "cc/compiler.go",
@@ -201,6 +203,9 @@
         "java/java.go",
         "java/resources.go",
     ],
+    testSrcs: [
+        "java/java_test.go",
+    ],
     pluginFor: ["soong_build"],
 }
 
diff --git a/android/androidmk.go b/android/androidmk.go
index b81cc2a..6197f59 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -61,8 +61,6 @@
 		return
 	}
 
-	ctx.SetNinjaBuildDir(pctx, filepath.Join(config.buildDir, ".."))
-
 	var androidMkModulesList []Module
 
 	ctx.VisitAllModules(func(module blueprint.Module) {
@@ -246,8 +244,8 @@
 		if amod.commonProperties.Vendor {
 			fmt.Fprintln(w, "LOCAL_VENDOR_MODULE := true")
 		}
-		if amod.commonProperties.Owner != "" {
-			fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", amod.commonProperties.Owner)
+		if amod.commonProperties.Owner != nil {
+			fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
 		}
 	}
 
diff --git a/android/arch.go b/android/arch.go
index 67ce30e..08421a1 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -879,10 +879,12 @@
 		{"arm", "armv7-a-neon", "denver", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "kryo", []string{"armeabi-v7a"}},
+		{"arm", "armv7-a-neon", "exynos-m2", []string{"armeabi-v7a"}},
 		{"arm64", "armv8-a", "cortex-a53", []string{"arm64-v8a"}},
 		{"arm64", "armv8-a", "cortex-a73", []string{"arm64-v8a"}},
 		{"arm64", "armv8-a", "denver64", []string{"arm64-v8a"}},
 		{"arm64", "armv8-a", "kryo", []string{"arm64-v8a"}},
+		{"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}},
 		{"mips", "mips32-fp", "", []string{"mips"}},
 		{"mips", "mips32r2-fp", "", []string{"mips"}},
 		{"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
diff --git a/android/config.go b/android/config.go
index 3de1ef1..5dcc59b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -84,6 +84,8 @@
 
 	inMake bool
 
+	captureBuild bool // true for tests, saves build parameters for each module
+
 	OncePer
 }
 
@@ -171,7 +173,8 @@
 			DeviceName: stringPtr("test_device"),
 		},
 
-		buildDir: buildDir,
+		buildDir:     buildDir,
+		captureBuild: true,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
@@ -527,20 +530,21 @@
 func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
 	coverage := false
 	if c.config.ProductVariables.CoveragePaths != nil {
-		for _, prefix := range *c.config.ProductVariables.CoveragePaths {
-			if strings.HasPrefix(path, prefix) {
-				coverage = true
-				break
-			}
+		if prefixInList(path, *c.config.ProductVariables.CoveragePaths) {
+			coverage = true
 		}
 	}
 	if coverage && c.config.ProductVariables.CoverageExcludePaths != nil {
-		for _, prefix := range *c.config.ProductVariables.CoverageExcludePaths {
-			if strings.HasPrefix(path, prefix) {
-				coverage = false
-				break
-			}
+		if prefixInList(path, *c.config.ProductVariables.CoverageExcludePaths) {
+			coverage = false
 		}
 	}
 	return coverage
 }
+
+func (c *config) IntegerOverflowDisabledForPath(path string) bool {
+	if c.ProductVariables.IntegerOverflowExcludePaths == nil {
+		return false
+	}
+	return prefixInList(path, *c.ProductVariables.IntegerOverflowExcludePaths)
+}
diff --git a/android/defaults.go b/android/defaults.go
index 0776405..4bf872e 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -29,16 +29,16 @@
 	Defaults []string
 }
 
-type DefaultableModule struct {
+type DefaultableModuleBase struct {
 	defaultsProperties    defaultsProperties
 	defaultableProperties []interface{}
 }
 
-func (d *DefaultableModule) defaults() *defaultsProperties {
+func (d *DefaultableModuleBase) defaults() *defaultsProperties {
 	return &d.defaultsProperties
 }
 
-func (d *DefaultableModule) setProperties(props []interface{}) {
+func (d *DefaultableModuleBase) setProperties(props []interface{}) {
 	d.defaultableProperties = props
 }
 
@@ -48,17 +48,21 @@
 	applyDefaults(TopDownMutatorContext, []Defaults)
 }
 
-var _ Defaultable = (*DefaultableModule)(nil)
-
-func InitDefaultableModule(module Module, d Defaultable) {
-
-	d.setProperties(module.GetProperties())
-
-	module.AddProperties(d.defaults())
+type DefaultableModule interface {
+	Module
+	Defaultable
 }
 
-type DefaultsModule struct {
-	DefaultableModule
+var _ Defaultable = (*DefaultableModuleBase)(nil)
+
+func InitDefaultableModule(module DefaultableModule) {
+	module.(Defaultable).setProperties(module.(Module).GetProperties())
+
+	module.AddProperties(module.defaults())
+}
+
+type DefaultsModuleBase struct {
+	DefaultableModuleBase
 	defaultProperties []interface{}
 }
 
@@ -68,31 +72,31 @@
 	properties() []interface{}
 }
 
-func (d *DefaultsModule) isDefaults() bool {
+func (d *DefaultsModuleBase) isDefaults() bool {
 	return true
 }
 
-func (d *DefaultsModule) properties() []interface{} {
+func (d *DefaultsModuleBase) properties() []interface{} {
 	return d.defaultableProperties
 }
 
-func InitDefaultsModule(module Module, d Defaults) {
+func InitDefaultsModule(module DefaultableModule) {
 	module.AddProperties(
 		&hostAndDeviceProperties{},
 		&commonProperties{},
 		&variableProperties{})
 
 	InitArchModule(module)
-	InitDefaultableModule(module, d)
+	InitDefaultableModule(module)
 
 	module.AddProperties(&module.base().nameProperties)
 
 	module.base().module = module
 }
 
-var _ Defaults = (*DefaultsModule)(nil)
+var _ Defaults = (*DefaultsModuleBase)(nil)
 
-func (defaultable *DefaultableModule) applyDefaults(ctx TopDownMutatorContext,
+func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
 	defaultsList []Defaults) {
 
 	for _, defaults := range defaultsList {
@@ -113,6 +117,11 @@
 	}
 }
 
+func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
+	ctx.TopDown("defaults", defaultsMutator).Parallel()
+}
+
 func defaultsDepsMutator(ctx BottomUpMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
 		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
diff --git a/android/module.go b/android/module.go
index 7f541be..3a3d173 100644
--- a/android/module.go
+++ b/android/module.go
@@ -111,6 +111,8 @@
 
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
+
+	BuildParamsForTests() []ModuleBuildParams
 }
 
 type nameProperties struct {
@@ -145,7 +147,7 @@
 	Proprietary bool
 
 	// vendor who owns this module
-	Owner string
+	Owner *string
 
 	// whether this module is device specific and should be installed into /vendor
 	Vendor bool
@@ -291,6 +293,9 @@
 	hooks hooks
 
 	registerProps []interface{}
+
+	// For tests
+	buildParams []ModuleBuildParams
 }
 
 func (a *ModuleBase) AddProperties(props ...interface{}) {
@@ -301,6 +306,10 @@
 	return a.registerProps
 }
 
+func (a *ModuleBase) BuildParamsForTests() []ModuleBuildParams {
+	return a.buildParams
+}
+
 // Name returns the name of the module.  It may be overridden by individual module types, for
 // example prebuilts will prepend prebuilt_ to the name.
 func (a *ModuleBase) Name() string {
@@ -520,6 +529,8 @@
 			return
 		}
 	}
+
+	a.buildParams = androidCtx.buildParams
 }
 
 type androidBaseContextImpl struct {
@@ -538,6 +549,9 @@
 	checkbuildFiles Paths
 	missingDeps     []string
 	module          Module
+
+	// For tests
+	buildParams []ModuleBuildParams
 }
 
 func (a *androidModuleContext) ninjaError(desc string, outputs []string, err error) {
@@ -566,6 +580,10 @@
 }
 
 func (a *androidModuleContext) ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) {
+	if a.config.captureBuild {
+		a.buildParams = append(a.buildParams, params)
+	}
+
 	bparams := blueprint.BuildParams{
 		Rule:            params.Rule,
 		Deps:            params.Deps,
diff --git a/android/mutator.go b/android/mutator.go
index bb49487..c8f3e8f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"sync"
-
 	"github.com/google/blueprint"
 )
 
@@ -27,9 +25,6 @@
 //   Deps
 //   PostDeps
 
-var registerMutatorsOnce sync.Once
-var registeredMutators []*mutator
-
 func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
 	for _, t := range mutators {
 		var handle blueprint.MutatorHandle
@@ -44,56 +39,24 @@
 	}
 }
 
-func registerMutators(ctx *blueprint.Context) {
-
-	registerMutatorsOnce.Do(func() {
-		ctx := &registerMutatorsContext{}
-
-		register := func(funcs []RegisterMutatorFunc) {
-			for _, f := range funcs {
-				f(ctx)
-			}
-		}
-
-		ctx.TopDown("load_hooks", loadHookMutator).Parallel()
-		ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
-		ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
-		ctx.TopDown("defaults", defaultsMutator).Parallel()
-
-		register(preArch)
-
-		ctx.BottomUp("arch", archMutator).Parallel()
-		ctx.TopDown("arch_hooks", archHookMutator).Parallel()
-
-		register(preDeps)
-
-		ctx.BottomUp("deps", depsMutator).Parallel()
-
-		ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
-		ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
-
-		register(postDeps)
-
-		registeredMutators = ctx.mutators
-	})
-
-	registerMutatorsToContext(ctx, registeredMutators)
-}
-
-func RegisterTestMutators(ctx *blueprint.Context) {
-	mutators := &registerMutatorsContext{}
+func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps []RegisterMutatorFunc) {
+	mctx := &registerMutatorsContext{}
 
 	register := func(funcs []RegisterMutatorFunc) {
 		for _, f := range funcs {
-			f(mutators)
+			f(mctx)
 		}
 	}
 
-	register(testPreDeps)
-	mutators.BottomUp("deps", depsMutator).Parallel()
-	register(testPostDeps)
+	register(preArch)
 
-	registerMutatorsToContext(ctx, mutators.mutators)
+	register(preDeps)
+
+	mctx.BottomUp("deps", depsMutator).Parallel()
+
+	register(postDeps)
+
+	registerMutatorsToContext(ctx, mctx.mutators)
 }
 
 type registerMutatorsContext struct {
@@ -107,7 +70,24 @@
 
 type RegisterMutatorFunc func(RegisterMutatorsContext)
 
-var preArch, preDeps, postDeps, testPreDeps, testPostDeps []RegisterMutatorFunc
+var preArch = []RegisterMutatorFunc{
+	func(ctx RegisterMutatorsContext) {
+		ctx.TopDown("load_hooks", loadHookMutator).Parallel()
+	},
+	registerPrebuiltsPreArchMutators,
+	RegisterDefaultsPreArchMutators,
+}
+
+var preDeps = []RegisterMutatorFunc{
+	func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("arch", archMutator).Parallel()
+		ctx.TopDown("arch_hooks", archHookMutator).Parallel()
+	},
+}
+
+var postDeps = []RegisterMutatorFunc{
+	registerPrebuiltsPostDepsMutators,
+}
 
 func PreArchMutators(f RegisterMutatorFunc) {
 	preArch = append(preArch, f)
@@ -121,14 +101,6 @@
 	postDeps = append(postDeps, f)
 }
 
-func TestPreDepsMutators(f RegisterMutatorFunc) {
-	testPreDeps = append(testPreDeps, f)
-}
-
-func TeststPostDepsMutators(f RegisterMutatorFunc) {
-	testPostDeps = append(testPostDeps, f)
-}
-
 type AndroidTopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 772df7a..080df91 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -61,6 +61,15 @@
 	Prebuilt() *Prebuilt
 }
 
+func registerPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
+}
+
+func registerPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
+	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
+	ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
+}
+
 // prebuiltMutator ensures that there is always a module with an undecorated name, and marks
 // prebuilt modules that have both a prebuilt and a source module.
 func prebuiltMutator(ctx BottomUpMutatorContext) {
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 5fa2032..fe763ed 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -122,9 +122,12 @@
 
 	for _, test := range prebuiltsTests {
 		t.Run(test.name, func(t *testing.T) {
-			ctx := NewContext()
+			ctx := NewTestContext()
+			ctx.PreArchMutators(registerPrebuiltsPreArchMutators)
+			ctx.PostDepsMutators(registerPrebuiltsPostDepsMutators)
 			ctx.RegisterModuleType("prebuilt", ModuleFactoryAdaptor(newPrebuiltModule))
 			ctx.RegisterModuleType("source", ModuleFactoryAdaptor(newSourceModule))
+			ctx.Register()
 			ctx.MockFileSystem(map[string][]byte{
 				"Blueprints": []byte(`
 					source {
@@ -139,13 +142,10 @@
 			_, errs = ctx.PrepareBuildActions(config)
 			fail(t, errs)
 
-			foo := findModule(ctx, "foo")
-			if foo == nil {
-				t.Fatalf("failed to find module foo")
-			}
+			foo := ctx.ModuleForTests("foo", "")
 
 			var dependsOnSourceModule, dependsOnPrebuiltModule bool
-			ctx.VisitDirectDeps(foo, func(m blueprint.Module) {
+			ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
 				if _, ok := m.(*sourceModule); ok {
 					dependsOnSourceModule = true
 				}
@@ -228,16 +228,6 @@
 func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 }
 
-func findModule(ctx *blueprint.Context, name string) blueprint.Module {
-	var ret blueprint.Module
-	ctx.VisitAllModules(func(m blueprint.Module) {
-		if ctx.ModuleName(m) == name {
-			ret = m
-		}
-	})
-	return ret
-}
-
 func fail(t *testing.T, errs []error) {
 	if len(errs) > 0 {
 		for _, err := range errs {
diff --git a/android/register.go b/android/register.go
index 76a1cc9..226e790 100644
--- a/android/register.go
+++ b/android/register.go
@@ -60,9 +60,15 @@
 	singletons = append(singletons, singleton{name, factory})
 }
 
-func NewContext() *blueprint.Context {
-	ctx := blueprint.NewContext()
+type Context struct {
+	*blueprint.Context
+}
 
+func NewContext() *Context {
+	return &Context{blueprint.NewContext()}
+}
+
+func (ctx *Context) Register() {
 	for _, t := range moduleTypes {
 		ctx.RegisterModuleType(t.name, t.factory)
 	}
@@ -71,9 +77,7 @@
 		ctx.RegisterSingletonType(t.name, t.factory)
 	}
 
-	registerMutators(ctx)
+	registerMutators(ctx.Context, preArch, preDeps, postDeps)
 
 	ctx.RegisterSingletonType("env", EnvSingleton)
-
-	return ctx
 }
diff --git a/android/testing.go b/android/testing.go
new file mode 100644
index 0000000..4144775
--- /dev/null
+++ b/android/testing.go
@@ -0,0 +1,98 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/google/blueprint"
+)
+
+func NewTestContext() *TestContext {
+	return &TestContext{
+		Context: blueprint.NewContext(),
+	}
+}
+
+type TestContext struct {
+	*blueprint.Context
+	preArch, preDeps, postDeps []RegisterMutatorFunc
+}
+
+func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
+	ctx.preArch = append(ctx.preArch, f)
+}
+
+func (ctx *TestContext) PreDepsMutators(f RegisterMutatorFunc) {
+	ctx.preDeps = append(ctx.preDeps, f)
+}
+
+func (ctx *TestContext) PostDepsMutators(f RegisterMutatorFunc) {
+	ctx.postDeps = append(ctx.postDeps, f)
+}
+
+func (ctx *TestContext) Register() {
+	registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
+
+	ctx.RegisterSingletonType("env", EnvSingleton)
+}
+
+func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
+	var module Module
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant {
+			module = m.(Module)
+		}
+	})
+
+	if module == nil {
+		panic(fmt.Errorf("failed to find module %q variant %q", name, variant))
+	}
+
+	return TestingModule{module}
+}
+
+type TestingModule struct {
+	module Module
+}
+
+func (m TestingModule) Module() Module {
+	return m.module
+}
+
+func (m TestingModule) Rule(rule string) ModuleBuildParams {
+	for _, p := range m.module.BuildParamsForTests() {
+		if strings.Contains(p.Rule.String(), rule) {
+			return p
+		}
+	}
+	panic(fmt.Errorf("couldn't find rule %q", rule))
+}
+
+func (m TestingModule) Output(file string) ModuleBuildParams {
+	for _, p := range m.module.BuildParamsForTests() {
+		outputs := append(WritablePaths(nil), p.Outputs...)
+		if p.Output != nil {
+			outputs = append(outputs, p.Output)
+		}
+		for _, f := range outputs {
+			if f.Base() == file {
+				return p
+			}
+		}
+	}
+	panic(fmt.Errorf("couldn't find output %q", file))
+}
diff --git a/android/util.go b/android/util.go
index 8cee256..80c7870 100644
--- a/android/util.go
+++ b/android/util.go
@@ -68,6 +68,15 @@
 	return indexList(s, list) != -1
 }
 
+func prefixInList(s string, list []string) bool {
+	for _, prefix := range list {
+		if strings.HasPrefix(s, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
 // checkCalledFromInit panics if a Go package's init function is not on the
 // call stack.
 func checkCalledFromInit() {
diff --git a/android/variable.go b/android/variable.go
index 7ca7a55..8462d0d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -140,6 +140,8 @@
 	Treble                     *bool `json:",omitempty"`
 	Pdk                        *bool `json:",omitempty"`
 
+	IntegerOverflowExcludePaths *[]string `json:",omitempty"`
+
 	VendorPath *string `json:",omitempty"`
 
 	ClangTidy  *bool   `json:",omitempty"`
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 78395c3..194b2c9 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -102,11 +102,11 @@
 			"LOCAL_RENDERSCRIPT_INCLUDES": "renderscript.include_dirs",
 			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
 
-			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
+			"LOCAL_JAVA_RESOURCE_DIRS":    "resource_dirs",
 			"LOCAL_JAVACFLAGS":            "javacflags",
 			"LOCAL_DX_FLAGS":              "dxflags",
-			"LOCAL_JAVA_LIBRARIES":        "java_libs",
-			"LOCAL_STATIC_JAVA_LIBRARIES": "java_static_libs",
+			"LOCAL_JAVA_LIBRARIES":        "libs",
+			"LOCAL_STATIC_JAVA_LIBRARIES": "static_libs",
 			"LOCAL_AIDL_INCLUDES":         "aidl.include_dirs",
 			"LOCAL_AAPT_FLAGS":            "aaptflags",
 			"LOCAL_PACKAGE_SPLITS":        "package_splits",
diff --git a/bootstrap.bash b/bootstrap.bash
index e48f480..dbc6eb2 100755
--- a/bootstrap.bash
+++ b/bootstrap.bash
@@ -17,25 +17,21 @@
 fi
 export SRCDIR="."
 export BOOTSTRAP="${SRCDIR}/bootstrap.bash"
+export BLUEPRINTDIR="${SRCDIR}/build/blueprint"
 
 export TOPNAME="Android.bp"
-export BOOTSTRAP_MANIFEST="${SRCDIR}/build/soong/build.ninja.in"
 export RUN_TESTS="-t"
 
 case $(uname) in
     Linux)
-	export GOOS="linux"
 	export PREBUILTOS="linux-x86"
 	;;
     Darwin)
-	export GOOS="darwin"
 	export PREBUILTOS="darwin-x86"
 	;;
     *) echo "unknown OS:" $(uname) && exit 1;;
 esac
-export GOROOT="${SRCDIR}/prebuilts/go/$PREBUILTOS/"
-export GOARCH="amd64"
-export GOCHAR="6"
+export GOROOT="${SRCDIR}/prebuilts/go/$PREBUILTOS"
 
 if [[ $# -eq 0 ]]; then
     mkdir -p $BUILDDIR
diff --git a/build.ninja.in b/build.ninja.in
deleted file mode 100644
index 9449d73..0000000
--- a/build.ninja.in
+++ /dev/null
@@ -1,567 +0,0 @@
-# ******************************************************************************
-# ***            This file is generated and should not be edited             ***
-# ******************************************************************************
-#
-# This file contains variables, rules, and pools with name prefixes indicating
-# they were generated by the following Go packages:
-#
-#     bootstrap [from Go package github.com/google/blueprint/bootstrap]
-#
-ninja_required_version = 1.7.0
-
-g.bootstrap.buildDir = @@BuildDir@@
-
-g.bootstrap.BinDir = ${g.bootstrap.buildDir}/.bootstrap/bin
-
-g.bootstrap.bootstrapCmd = @@Bootstrap@@
-
-g.bootstrap.compileCmd = @@GoCompile@@
-
-g.bootstrap.goRoot = @@GoRoot@@
-
-g.bootstrap.goTestMainCmd = ${g.bootstrap.buildDir}/.bootstrap/bin/gotestmain
-
-g.bootstrap.goTestRunnerCmd = ${g.bootstrap.buildDir}/.bootstrap/bin/gotestrunner
-
-g.bootstrap.linkCmd = @@GoLink@@
-
-g.bootstrap.srcDir = @@SrcDir@@
-
-builddir = ${g.bootstrap.buildDir}/.minibootstrap
-
-rule g.bootstrap.bootstrap
-    command = BUILDDIR=${g.bootstrap.buildDir} ${g.bootstrap.bootstrapCmd} -i ${in}
-    description = bootstrap ${in}
-    generator = true
-
-rule g.bootstrap.build.ninja
-    command = ${builder} ${extra} -b ${g.bootstrap.buildDir} -d ${out}.d -o ${out} ${in}
-    depfile = ${out}.d
-    description = ${builder} ${out}
-    restat = true
-
-rule g.bootstrap.compile
-    command = GOROOT='${g.bootstrap.goRoot}' ${g.bootstrap.compileCmd} -o ${out} -p ${pkgPath} -complete ${incFlags} -pack ${in}
-    description = compile ${out}
-
-rule g.bootstrap.cp
-    command = cp ${in} ${out}
-    description = cp ${out}
-
-rule g.bootstrap.gotestmain
-    command = ${g.bootstrap.goTestMainCmd} -o ${out} -pkg ${pkg} ${in}
-    description = gotestmain ${out}
-
-rule g.bootstrap.link
-    command = GOROOT='${g.bootstrap.goRoot}' ${g.bootstrap.linkCmd} -o ${out} ${libDirFlags} ${in}
-    description = link ${out}
-
-rule g.bootstrap.test
-    command = ${g.bootstrap.goTestRunnerCmd} -p ${pkgSrcDir} -f ${out} -- ${in} -test.short
-    description = test ${pkg}
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:1:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/github.com/google/blueprint.a $
-        : g.bootstrap.compile ${g.bootstrap.srcDir}/build/blueprint/context.go $
-        ${g.bootstrap.srcDir}/build/blueprint/glob.go $
-        ${g.bootstrap.srcDir}/build/blueprint/live_tracker.go $
-        ${g.bootstrap.srcDir}/build/blueprint/mangle.go $
-        ${g.bootstrap.srcDir}/build/blueprint/module_ctx.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_defs.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_strings.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_writer.go $
-        ${g.bootstrap.srcDir}/build/blueprint/package_ctx.go $
-        ${g.bootstrap.srcDir}/build/blueprint/scope.go $
-        ${g.bootstrap.srcDir}/build/blueprint/singleton_ctx.go $
-        ${g.bootstrap.srcDir}/build/blueprint/unpack.go $
-        ${g.bootstrap.srcDir}/build/blueprint/context_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_strings_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_writer_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/splice_modules_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/unpack_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/visit_test.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg
-    pkgPath = github.com/google/blueprint
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/github.com/google/blueprint.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.go: $
-        g.bootstrap.gotestmain $
-        ${g.bootstrap.srcDir}/build/blueprint/context_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_strings_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_writer_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/splice_modules_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/unpack_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/visit_test.go | $
-        ${g.bootstrap.goTestMainCmd}
-    pkg = github.com/google/blueprint
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.go
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/github.com/google/blueprint.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint/test
-    pkgPath = main
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test: g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.a | $
-        ${g.bootstrap.linkCmd}
-    libDirFlags = -L ${g.bootstrap.buildDir}/.bootstrap/blueprint/test -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.passed: $
-        g.bootstrap.test $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test | $
-        ${g.bootstrap.goTestRunnerCmd} || $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.passed $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.passed $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.passed
-    pkg = github.com/google/blueprint
-    pkgSrcDir = ${g.bootstrap.srcDir}/build/blueprint
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.passed
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg/github.com/google/blueprint.a $
-        : g.bootstrap.compile ${g.bootstrap.srcDir}/build/blueprint/context.go $
-        ${g.bootstrap.srcDir}/build/blueprint/glob.go $
-        ${g.bootstrap.srcDir}/build/blueprint/live_tracker.go $
-        ${g.bootstrap.srcDir}/build/blueprint/mangle.go $
-        ${g.bootstrap.srcDir}/build/blueprint/module_ctx.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_defs.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_strings.go $
-        ${g.bootstrap.srcDir}/build/blueprint/ninja_writer.go $
-        ${g.bootstrap.srcDir}/build/blueprint/package_ctx.go $
-        ${g.bootstrap.srcDir}/build/blueprint/scope.go $
-        ${g.bootstrap.srcDir}/build/blueprint/singleton_ctx.go $
-        ${g.bootstrap.srcDir}/build/blueprint/unpack.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg
-    pkgPath = github.com/google/blueprint
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg/github.com/google/blueprint.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint-bootstrap
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:89:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap/pkg/github.com/google/blueprint/bootstrap.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/bootstrap.go $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/cleanup.go $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/command.go $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/config.go $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/doc.go $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/glob.go $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/writedocs.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg/github.com/google/blueprint.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg/github.com/google/blueprint/bootstrap/bpdoc.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg
-    pkgPath = github.com/google/blueprint/bootstrap
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap/pkg/github.com/google/blueprint/bootstrap.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint-bootstrap-bpdoc
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:109:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg/github.com/google/blueprint/bootstrap/bpdoc.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/bpdoc/bpdoc.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg/github.com/google/blueprint.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg
-    pkgPath = github.com/google/blueprint/bootstrap/bpdoc
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg/github.com/google/blueprint/bootstrap/bpdoc.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint-deptools
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:49:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/deptools/depfile.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = github.com/google/blueprint/deptools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint-parser
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:33:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/github.com/google/blueprint/parser.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/ast.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/modify.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/parser.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/printer.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/sort.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/parser_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/printer_test.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = github.com/google/blueprint/parser
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/github.com/google/blueprint/parser.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.go: $
-        g.bootstrap.gotestmain $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/parser_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/printer_test.go | $
-        ${g.bootstrap.goTestMainCmd}
-    pkg = github.com/google/blueprint/parser
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.go
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/github.com/google/blueprint/parser.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test
-    pkgPath = main
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test: $
-        g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.a | $
-        ${g.bootstrap.linkCmd}
-    libDirFlags = -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.passed: $
-        g.bootstrap.test $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test | $
-        ${g.bootstrap.goTestRunnerCmd}
-    pkg = github.com/google/blueprint/parser
-    pkgSrcDir = ${g.bootstrap.srcDir}/build/blueprint/parser
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.passed
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/ast.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/modify.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/parser.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/printer.go $
-        ${g.bootstrap.srcDir}/build/blueprint/parser/sort.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = github.com/google/blueprint/parser
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint-pathtools
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:55:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/github.com/google/blueprint/pathtools.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/lists.go $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/fs.go $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/glob.go $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/glob_test.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg
-    pkgPath = github.com/google/blueprint/pathtools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/github.com/google/blueprint/pathtools.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.go: $
-        g.bootstrap.gotestmain $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/glob_test.go | $
-        ${g.bootstrap.goTestMainCmd}
-    pkg = github.com/google/blueprint/pathtools
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.go
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/github.com/google/blueprint/pathtools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test
-    pkgPath = main
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test: $
-        g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.a | $
-        ${g.bootstrap.linkCmd}
-    libDirFlags = -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.passed: $
-        g.bootstrap.test $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test | $
-        ${g.bootstrap.goTestRunnerCmd}
-    pkg = github.com/google/blueprint/pathtools
-    pkgSrcDir = ${g.bootstrap.srcDir}/build/blueprint/pathtools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.passed
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/lists.go $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/fs.go $
-        ${g.bootstrap.srcDir}/build/blueprint/pathtools/glob.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg
-    pkgPath = github.com/google/blueprint/pathtools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  blueprint-proptools
-# Variant:
-# Type:    bootstrap_go_package
-# Factory: github.com/google/blueprint/bootstrap.newGoPackageModuleFactory.func1
-# Defined: build/blueprint/Blueprints:71:1
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/github.com/google/blueprint/proptools.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/clone.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/escape.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/extend.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/proptools.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/typeequal.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/clone_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/escape_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/extend_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/typeequal_test.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = github.com/google/blueprint/proptools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/github.com/google/blueprint/proptools.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.go: $
-        g.bootstrap.gotestmain $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/clone_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/escape_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/extend_test.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/typeequal_test.go | $
-        ${g.bootstrap.goTestMainCmd}
-    pkg = github.com/google/blueprint/proptools
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.go
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/github.com/google/blueprint/proptools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test
-    pkgPath = main
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test: $
-        g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.a | $
-        ${g.bootstrap.linkCmd}
-    libDirFlags = -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test
-default ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test
-
-build ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.passed: $
-        g.bootstrap.test $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test | $
-        ${g.bootstrap.goTestRunnerCmd}
-    pkg = github.com/google/blueprint/proptools
-    pkgSrcDir = ${g.bootstrap.srcDir}/build/blueprint/proptools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.passed
-
-build $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
-        : g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/clone.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/escape.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/extend.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/proptools.go $
-        ${g.bootstrap.srcDir}/build/blueprint/proptools/typeequal.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = github.com/google/blueprint/proptools
-default $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  bpglob
-# Variant:
-# Type:    bootstrap_core_go_binary
-# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModuleFactory.func1
-# Defined: build/blueprint/Blueprints:130:1
-
-build ${g.bootstrap.buildDir}/.bootstrap/bpglob/obj/bpglob.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/bpglob/bpglob.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg
-    pkgPath = bpglob
-default ${g.bootstrap.buildDir}/.bootstrap/bpglob/obj/bpglob.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/bpglob/obj/a.out: g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/bpglob/obj/bpglob.a | $
-        ${g.bootstrap.linkCmd}
-    libDirFlags = -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg
-default ${g.bootstrap.buildDir}/.bootstrap/bpglob/obj/a.out
-
-build ${g.bootstrap.BinDir}/bpglob: g.bootstrap.cp $
-        ${g.bootstrap.buildDir}/.bootstrap/bpglob/obj/a.out || $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.passed
-default ${g.bootstrap.BinDir}/bpglob
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  gotestmain
-# Variant:
-# Type:    bootstrap_core_go_binary
-# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModuleFactory.func1
-# Defined: build/blueprint/Blueprints:148:1
-
-build ${g.bootstrap.buildDir}/.bootstrap/gotestmain/obj/gotestmain.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/gotestmain/gotestmain.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = gotestmain
-default ${g.bootstrap.buildDir}/.bootstrap/gotestmain/obj/gotestmain.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/gotestmain/obj/a.out: $
-        g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/gotestmain/obj/gotestmain.a | $
-        ${g.bootstrap.linkCmd}
-default ${g.bootstrap.buildDir}/.bootstrap/gotestmain/obj/a.out
-
-build ${g.bootstrap.BinDir}/gotestmain: g.bootstrap.cp $
-        ${g.bootstrap.buildDir}/.bootstrap/gotestmain/obj/a.out
-default ${g.bootstrap.BinDir}/gotestmain
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  gotestrunner
-# Variant:
-# Type:    bootstrap_core_go_binary
-# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModuleFactory.func1
-# Defined: build/blueprint/Blueprints:153:1
-
-build ${g.bootstrap.buildDir}/.bootstrap/gotestrunner/obj/gotestrunner.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/gotestrunner/gotestrunner.go | $
-        ${g.bootstrap.compileCmd}
-    pkgPath = gotestrunner
-default ${g.bootstrap.buildDir}/.bootstrap/gotestrunner/obj/gotestrunner.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/gotestrunner/obj/a.out: $
-        g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/gotestrunner/obj/gotestrunner.a | $
-        ${g.bootstrap.linkCmd}
-default ${g.bootstrap.buildDir}/.bootstrap/gotestrunner/obj/a.out
-
-build ${g.bootstrap.BinDir}/gotestrunner: g.bootstrap.cp $
-        ${g.bootstrap.buildDir}/.bootstrap/gotestrunner/obj/a.out
-default ${g.bootstrap.BinDir}/gotestrunner
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Module:  minibp
-# Variant:
-# Type:    bootstrap_core_go_binary
-# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModuleFactory.func1
-# Defined: build/blueprint/Blueprints:121:1
-
-build ${g.bootstrap.buildDir}/.bootstrap/minibp/obj/minibp.a: $
-        g.bootstrap.compile $
-        ${g.bootstrap.srcDir}/build/blueprint/bootstrap/minibp/main.go | $
-        ${g.bootstrap.compileCmd} $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg/github.com/google/blueprint.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg/github.com/google/blueprint/bootstrap/bpdoc.a $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap/pkg/github.com/google/blueprint/bootstrap.a
-    incFlags = -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg -I ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap/pkg
-    pkgPath = minibp
-default ${g.bootstrap.buildDir}/.bootstrap/minibp/obj/minibp.a
-
-build ${g.bootstrap.buildDir}/.bootstrap/minibp/obj/a.out: g.bootstrap.link $
-        ${g.bootstrap.buildDir}/.bootstrap/minibp/obj/minibp.a | $
-        ${g.bootstrap.linkCmd}
-    libDirFlags = -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-deptools/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap-bpdoc/pkg -L ${g.bootstrap.buildDir}/.bootstrap/blueprint-bootstrap/pkg
-default ${g.bootstrap.buildDir}/.bootstrap/minibp/obj/a.out
-
-build ${g.bootstrap.BinDir}/minibp: g.bootstrap.cp $
-        ${g.bootstrap.buildDir}/.bootstrap/minibp/obj/a.out || $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-parser/test/test.passed $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-pathtools/test/test.passed $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint-proptools/test/test.passed $
-        ${g.bootstrap.buildDir}/.bootstrap/blueprint/test/test.passed
-default ${g.bootstrap.BinDir}/minibp
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Singleton: bootstrap
-# Factory:   github.com/google/blueprint/bootstrap.newSingletonFactory.func1
-
-build ${g.bootstrap.buildDir}/.bootstrap/build.ninja: g.bootstrap.build.ninja $
-        ${g.bootstrap.srcDir}/Android.bp | ${builder}
-    builder = ${g.bootstrap.BinDir}/minibp
-    extra = --build-primary -t
-default ${g.bootstrap.buildDir}/.bootstrap/build.ninja
-
-build ${g.bootstrap.buildDir}/.minibootstrap/build.ninja.in: $
-        g.bootstrap.build.ninja ${g.bootstrap.srcDir}/Android.bp | ${builder}
-    builder = ${g.bootstrap.BinDir}/minibp
-    extra =  -t
-default ${g.bootstrap.buildDir}/.minibootstrap/build.ninja.in
-
-build ${g.bootstrap.buildDir}/.minibootstrap/build.ninja: $
-        g.bootstrap.bootstrap $
-        ${g.bootstrap.buildDir}/.minibootstrap/build.ninja.in | $
-        ${g.bootstrap.bootstrapCmd}
-default ${g.bootstrap.buildDir}/.minibootstrap/build.ninja
-
diff --git a/build_test.bash b/build_test.bash
index ab841cb..065d7f6 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -28,7 +28,7 @@
 export TRACE_BEGIN_SOONG=$(date +%s%N)
 
 export TOP=$(cd $(dirname ${BASH_SOURCE[0]})/../..; PWD= /bin/pwd)
-source "${TOP}/build/soong/cmd/microfactory/microfactory.bash"
+source "${TOP}/build/soong/scripts/microfactory.bash"
 
 case $(uname) in
   Linux)
@@ -36,5 +36,5 @@
     ;;
 esac
 
-build_go multiproduct_kati android/soong/cmd/multiproduct_kati
+soong_build_go multiproduct_kati android/soong/cmd/multiproduct_kati
 exec "$(getoutdir)/multiproduct_kati" "$@"
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 2a3b344..940e7c7 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -23,6 +23,10 @@
 	"android/soong/android"
 )
 
+var (
+	vendorSuffix = ".vendor"
+)
+
 type AndroidMkContext interface {
 	Target() android.Target
 	subAndroidMk(*android.AndroidMkData, interface{})
@@ -81,13 +85,34 @@
 	}
 	c.subAndroidMk(&ret, c.installer)
 
-	if c.vndk() {
-		ret.SubName += ".vendor"
+	if c.vndk() && Bool(c.Properties.Vendor_available) {
+		// .vendor suffix is added only when we will have two variants: core and vendor.
+		// The suffix is not added for vendor-only module.
+		ret.SubName += vendorSuffix
 	}
 
 	return ret, nil
 }
 
+func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, ret *android.AndroidMkData) {
+	var testFiles []string
+	for _, d := range data {
+		rel := d.Rel()
+		path := d.String()
+		if !strings.HasSuffix(path, rel) {
+			panic(fmt.Errorf("path %q does not end with %q", path, rel))
+		}
+		path = strings.TrimSuffix(path, rel)
+		testFiles = append(testFiles, path+":"+rel)
+	}
+	if len(testFiles) > 0 {
+		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
+			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(testFiles, " "))
+			return nil
+		})
+	}
+}
+
 func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
 	exportedFlags := library.exportedFlags()
 	if len(exportedFlags) > 0 {
@@ -212,6 +237,8 @@
 		}
 		return nil
 	})
+
+	androidMkWriteTestData(benchmark.data, ctx, ret)
 }
 
 func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
@@ -229,22 +256,7 @@
 		return nil
 	})
 
-	var testFiles []string
-	for _, d := range test.data {
-		rel := d.Rel()
-		path := d.String()
-		if !strings.HasSuffix(path, rel) {
-			panic(fmt.Errorf("path %q does not end with %q", path, rel))
-		}
-		path = strings.TrimSuffix(path, rel)
-		testFiles = append(testFiles, path+":"+rel)
-	}
-	if len(testFiles) > 0 {
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
-			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(testFiles, " "))
-			return nil
-		})
-	}
+	androidMkWriteTestData(test.data, ctx, ret)
 }
 
 func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
diff --git a/cc/cc.go b/cc/cc.go
index c17b95e..0f754a6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -183,6 +183,8 @@
 	sdk() bool
 	sdkVersion() string
 	vndk() bool
+	isVndk() bool
+	isVndkSp() bool
 	createVndkSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
@@ -273,7 +275,7 @@
 // to construct the output file.  Behavior can be customized with a Customizer interface
 type Module struct {
 	android.ModuleBase
-	android.DefaultableModule
+	android.DefaultableModuleBase
 
 	Properties BaseProperties
 	unused     UnusedProperties
@@ -291,6 +293,7 @@
 	sanitize  *sanitize
 	coverage  *coverage
 	sabi      *sabi
+	vndkdep   *vndkdep
 
 	androidMkSharedLibDeps []string
 
@@ -327,13 +330,16 @@
 	if c.sabi != nil {
 		c.AddProperties(c.sabi.props()...)
 	}
+	if c.vndkdep != nil {
+		c.AddProperties(c.vndkdep.props()...)
+	}
 	for _, feature := range c.features {
 		c.AddProperties(feature.props()...)
 	}
 
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
 
-	android.InitDefaultableModule(c, c)
+	android.InitDefaultableModule(c)
 
 	return c
 }
@@ -353,6 +359,13 @@
 	return c.Properties.UseVndk
 }
 
+func (c *Module) isVndk() bool {
+	if c.vndkdep != nil {
+		return c.vndkdep.isVndk()
+	}
+	return false
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -368,10 +381,10 @@
 	moduleContextImpl
 }
 
-// Vendor returns true for vendor modules so that they get installed onto the
-// correct partition
+// Vendor returns true for vendor modules excluding VNDK libraries so that
+// they get installed onto the correct partition
 func (ctx *moduleContext) Vendor() bool {
-	return ctx.ModuleContext.Vendor() || ctx.moduleContextImpl.mod.Properties.UseVndk
+	return ctx.ModuleContext.Vendor() || (ctx.mod.vndk() && !ctx.mod.isVndk())
 }
 
 type moduleContextImpl struct {
@@ -431,9 +444,20 @@
 	return ctx.mod.vndk()
 }
 
+func (ctx *moduleContextImpl) isVndk() bool {
+	return ctx.mod.isVndk()
+}
+
+func (ctx *moduleContextImpl) isVndkSp() bool {
+	if vndk := ctx.mod.vndkdep; vndk != nil {
+		return vndk.isVndkSp()
+	}
+	return false
+}
+
 // Create source abi dumps if the module belongs to the list of VndkLibraries.
 func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
-	return ctx.ctx.Device() && ((Bool(ctx.mod.Properties.Vendor_available)) || (inList(ctx.baseModuleName(), config.LLndkLibraries())))
+	return ctx.ctx.Device() && (ctx.mod.isVndk() || inList(ctx.baseModuleName(), config.LLndkLibraries()))
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
@@ -463,6 +487,7 @@
 	module.sanitize = &sanitize{}
 	module.coverage = &coverage{}
 	module.sabi = &sabi{}
+	module.vndkdep = &vndkdep{}
 	return module
 }
 
@@ -591,6 +616,9 @@
 	if c.sabi != nil {
 		c.sabi.begin(ctx)
 	}
+	if c.vndkdep != nil {
+		c.vndkdep.begin(ctx)
+	}
 	for _, feature := range c.features {
 		feature.begin(ctx)
 	}
@@ -624,6 +652,9 @@
 	if c.sabi != nil {
 		deps = c.sabi.deps(ctx, deps)
 	}
+	if c.vndkdep != nil {
+		deps = c.vndkdep.deps(ctx, deps)
+	}
 	for _, feature := range c.features {
 		deps = feature.deps(ctx, deps)
 	}
@@ -689,9 +720,6 @@
 
 	deps := c.deps(ctx)
 
-	c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.SharedLibs...)
-	c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.LateSharedLibs...)
-
 	variantNdkLibs := []string{}
 	variantLateNdkLibs := []string{}
 	if ctx.Os() == android.Android {
@@ -828,7 +856,12 @@
 			return
 		}
 		if from.Properties.UseVndk {
-			// Vendor code is already limited by the vendor mutator
+			// Though vendor code is limited by the vendor mutator,
+			// each vendor-available module needs to check
+			// link-type for VNDK.
+			if from.vndkdep != nil {
+				from.vndkdep.vndkCheckLinkType(ctx, to)
+			}
 			return
 		}
 		if from.Properties.Sdk_version == "" {
@@ -1065,6 +1098,26 @@
 			}
 			*depPtr = append(*depPtr, dep.Path())
 		}
+
+		// Export the shared libs to the make world. In doing so, .vendor suffix
+		// is added if the lib has both core and vendor variants and this module
+		// is building against vndk. This is because the vendor variant will be
+		// have .vendor suffix in its name in the make world. However, if the
+		// lib is a vendor-only lib or this lib is not building against vndk,
+		// then the suffix is not added.
+		switch tag {
+		case sharedDepTag, sharedExportDepTag, lateSharedDepTag:
+			libName := strings.TrimSuffix(name, llndkLibrarySuffix)
+			libName = strings.TrimPrefix(libName, "prebuilt_")
+			isLLndk := inList(libName, config.LLndkLibraries())
+			if c.vndk() && (Bool(cc.Properties.Vendor_available) || isLLndk) {
+				libName += vendorSuffix
+			}
+			// Note: the order of libs in this list is not important because
+			// they merely serve as dependencies in the make world and do not
+			// affect this lib itself.
+			c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, libName)
+		}
 	})
 
 	// Dedup exported flags from dependencies
@@ -1102,7 +1155,7 @@
 //
 type Defaults struct {
 	android.ModuleBase
-	android.DefaultsModule
+	android.DefaultsModuleBase
 }
 
 func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1136,9 +1189,10 @@
 		&TidyProperties{},
 		&CoverageProperties{},
 		&SAbiProperties{},
+		&VndkProperties{},
 	)
 
-	android.InitDefaultsModule(module, module)
+	android.InitDefaultsModule(module)
 
 	return module
 }
@@ -1169,6 +1223,18 @@
 			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
 		return
 	}
+	if vndk := m.vndkdep; vndk != nil {
+		if vndk.isVndk() && !Bool(m.Properties.Vendor_available) {
+			mctx.PropertyErrorf("vndk",
+				"has to define `vendor_available: true` to enable vndk")
+			return
+		}
+		if !vndk.isVndk() && vndk.isVndkSp() {
+			mctx.PropertyErrorf("vndk",
+				"must set `enabled: true` to set `support_system_process: true`")
+			return
+		}
+	}
 
 	if !mctx.DeviceConfig().CompileVndk() {
 		// If the device isn't compiling against the VNDK, we always
@@ -1180,6 +1246,7 @@
 		mctx.CreateVariations(vendorMode)
 	} else if Bool(m.Properties.Vendor_available) {
 		// This will be available in both /system and /vendor
+		// or a /system directory that is available to vendor.
 		mod := mctx.CreateVariations(coreMode, vendorMode)
 		mod[1].(*Module).Properties.UseVndk = true
 	} else if mctx.Vendor() && m.Properties.Sdk_version == "" {
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index a371cf6..139c901 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -81,6 +81,9 @@
 			// don't support a Kryo specific target yet.
 			"-mcpu=cortex-a57",
 		},
+		"exynos-m2": []string{
+			"-mcpu=exynos-m2",
+		},
 	}
 
 	arm64ClangCpuVariantCflags = copyVariantFlags(arm64CpuVariantCflags)
@@ -96,6 +99,7 @@
 		"cortex-a53",
 		"cortex-a73",
 		"kryo",
+		"exynos-m2",
 		"denver64")
 
 	// Clang supports specific Kryo targeting
@@ -124,6 +128,11 @@
 		strings.Join(arm64CpuVariantCflags["kryo"], " "))
 	pctx.StaticVariable("Arm64ClangKryoCflags",
 		strings.Join(arm64ClangCpuVariantCflags["kryo"], " "))
+
+	pctx.StaticVariable("Arm64ExynosM2Cflags",
+		strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
+	pctx.StaticVariable("Arm64ClangExynosM2Cflags",
+		strings.Join(arm64ClangCpuVariantCflags["exynos-m2"], " "))
 }
 
 var (
@@ -132,6 +141,7 @@
 		"cortex-a53": "${config.Arm64CortexA53Cflags}",
 		"cortex-a73": "${config.Arm64CortexA53Cflags}",
 		"kryo":       "${config.Arm64KryoCflags}",
+		"exynos-m2":  "${config.Arm64ExynosM2Cflags}",
 	}
 
 	arm64ClangCpuVariantCflagsVar = map[string]string{
@@ -139,6 +149,7 @@
 		"cortex-a53": "${config.Arm64ClangCortexA53Cflags}",
 		"cortex-a73": "${config.Arm64ClangCortexA53Cflags}",
 		"kryo":       "${config.Arm64ClangKryoCflags}",
+		"exynos-m2":  "${config.Arm64ClangExynosM2Cflags}",
 	}
 )
 
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 6606100..e97e723 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -182,6 +182,7 @@
 		"cortex-a73",
 		"krait",
 		"kryo",
+		"exynos-m2",
 		"denver")
 
 	android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon")
@@ -274,6 +275,7 @@
 		"cortex-a73":     "${config.ArmCortexA53Cflags}",
 		"krait":          "${config.ArmKraitCflags}",
 		"kryo":           "${config.ArmKryoCflags}",
+		"exynos-m2":      "${config.ArmCortexA53Cflags}",
 		"denver":         "${config.ArmCortexA15Cflags}",
 	}
 
@@ -293,6 +295,7 @@
 		"cortex-a73":     "${config.ArmClangCortexA53Cflags}",
 		"krait":          "${config.ArmClangKraitCflags}",
 		"kryo":           "${config.ArmClangKryoCflags}",
+		"exynos-m2":      "${config.ArmClangCortexA53Cflags}",
 		"denver":         "${config.ArmClangCortexA15Cflags}",
 	}
 )
diff --git a/cc/config/global.go b/cc/config/global.go
index 4ae22c9..f4a1230 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -124,7 +124,7 @@
 	// This is used by non-NDK modules to get jni.h. export_include_dirs doesn't help
 	// with this, since there is no associated library.
 	pctx.PrefixedExistentPathsForSourcesVariable("CommonNativehelperInclude", "-I",
-		[]string{"libnativehelper/include/nativehelper"})
+		[]string{"libnativehelper/include_deprecated"})
 
 	pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
 	pctx.VariableFunc("ClangBase", func(config interface{}) (string, error) {
diff --git a/cc/installer.go b/cc/installer.go
index 112a7ea..7bedc56 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -48,6 +48,7 @@
 
 	dir      string
 	dir64    string
+	subDir   string
 	relative string
 	location installLocation
 
@@ -61,17 +62,17 @@
 }
 
 func (installer *baseInstaller) installDir(ctx ModuleContext) android.OutputPath {
-	subDir := installer.dir
+	dir := installer.dir
 	if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
-		subDir = installer.dir64
+		dir = installer.dir64
 	}
 	if !ctx.Host() && !ctx.Arch().Native {
-		subDir = filepath.Join(subDir, ctx.Arch().ArchType.String())
+		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
 	if installer.location == InstallInData && ctx.vndk() {
-		subDir = filepath.Join(subDir, "vendor")
+		dir = filepath.Join(dir, "vendor")
 	}
-	return android.PathForModuleInstall(ctx, subDir, installer.Properties.Relative_install_path, installer.relative)
+	return android.PathForModuleInstall(ctx, dir, installer.subDir, installer.Properties.Relative_install_path, installer.relative)
 }
 
 func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go
index c66fca6..42dc770 100644
--- a/cc/kernel_headers.go
+++ b/cc/kernel_headers.go
@@ -40,12 +40,9 @@
 		libraryDecorator: library,
 	}
 
-	module.compiler = nil
 	module.linker = stub
-	module.installer = nil
 
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
-	return module
+	return module.Init()
 }
 
 func init() {
diff --git a/cc/library.go b/cc/library.go
index c7c1142..3d463bd 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -156,7 +156,7 @@
 }
 
 func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
-	if ctx.Vendor() && f.Properties.Target.Vendor.Export_include_dirs != nil {
+	if ctx.vndk() && f.Properties.Target.Vendor.Export_include_dirs != nil {
 		return android.PathsForModuleSrc(ctx, f.Properties.Target.Vendor.Export_include_dirs)
 	} else {
 		return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs)
@@ -351,7 +351,7 @@
 		}
 		return Objects{}
 	}
-	if (ctx.createVndkSourceAbiDump() || (library.sabi.Properties.CreateSAbiDumps && ctx.Device())) && !ctx.Vendor() {
+	if ctx.createVndkSourceAbiDump() {
 		exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
@@ -596,7 +596,7 @@
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
 	//Also take into account object re-use.
-	if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() && !ctx.Vendor() {
+	if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() {
 		refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true)
 		versionScript := android.OptionalPathForModuleSrc(ctx, library.Properties.Version_script)
 		var symbolFile android.OptionalPath
@@ -699,6 +699,15 @@
 
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if library.shared() {
+		if ctx.Device() {
+			if ctx.vndk() {
+				if ctx.isVndkSp() {
+					library.baseInstaller.subDir = "vndk-sp"
+				} else if ctx.isVndk() {
+					library.baseInstaller.subDir = "vndk"
+				}
+			}
+		}
 		library.baseInstaller.install(ctx, file)
 	}
 }
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 66ffc9f..c3d3462 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -61,6 +61,11 @@
 	versionScriptPath      android.ModuleGenPath
 }
 
+func (stub *llndkStubDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+	flags = stub.baseCompiler.compilerFlags(ctx, flags)
+	return addStubLibraryCompilerFlags(flags)
+}
+
 func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	objs, versionScript := compileStubLibrary(ctx, flags, stub.Properties.Symbol_file, "current", "--vndk")
 	stub.versionScriptPath = versionScript
diff --git a/cc/makevars.go b/cc/makevars.go
index 11c3162..294f3e6 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -82,6 +82,16 @@
 
 	ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}")
 
+	nativeHelperIncludeFlags, err := ctx.Eval("${config.CommonNativehelperInclude}")
+	if err != nil {
+		panic(err)
+	}
+	nativeHelperIncludes, nativeHelperSystemIncludes := splitSystemIncludes(ctx, nativeHelperIncludeFlags)
+	if len(nativeHelperSystemIncludes) > 0 {
+		panic("native helper may not have any system includes")
+	}
+	ctx.Strict("JNI_H_INCLUDE", strings.Join(nativeHelperIncludes, " "))
+
 	includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes}")
 	if err != nil {
 		panic(err)
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 5765aa9..dbfc5be 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -242,6 +242,25 @@
 	ndkMigratedLibs = append(ndkMigratedLibs, name)
 }
 
+func addStubLibraryCompilerFlags(flags Flags) Flags {
+	flags.CFlags = append(flags.CFlags,
+		// We're knowingly doing some otherwise unsightly things with builtin
+		// functions here. We're just generating stub libraries, so ignore it.
+		"-Wno-incompatible-library-redeclaration",
+		"-Wno-builtin-requires-header",
+		"-Wno-invalid-noreturn",
+		// These libraries aren't actually used. Don't worry about unwinding
+		// (avoids the need to link an unwinder into a fake library).
+		"-fno-unwind-tables",
+	)
+	return flags
+}
+
+func (stub *stubDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+	flags = stub.baseCompiler.compilerFlags(ctx, flags)
+	return addStubLibraryCompilerFlags(flags)
+}
+
 func compileStubLibrary(ctx ModuleContext, flags Flags, symbolFile, apiLevel, vndk string) (Objects, android.ModuleGenPath) {
 	arch := ctx.Arch().ArchType.String()
 
@@ -263,18 +282,6 @@
 		},
 	})
 
-	flags.CFlags = append(flags.CFlags,
-		// We're knowingly doing some otherwise unsightly things with builtin
-		// functions here. We're just generating stub libraries, so ignore it.
-		"-Wno-incompatible-library-redeclaration",
-		"-Wno-builtin-requires-header",
-		"-Wno-invalid-noreturn",
-
-		// These libraries aren't actually used. Don't worry about unwinding
-		// (avoids the need to link an unwinder into a fake library).
-		"-fno-unwind-tables",
-	)
-
 	subdir := ""
 	srcs := []android.Path{stubSrcPath}
 	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil), versionScriptPath
diff --git a/cc/sabi.go b/cc/sabi.go
index 9aff738..1a5361d 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -67,12 +67,19 @@
 	// Assuming that the cflags which clang LibTooling tools cannot
 	// understand have not been converted to ninja variables yet.
 	flags.ToolingCFlags = filterOutWithPrefix(flags.CFlags, config.ClangLibToolingUnknownCflags)
+
+	// RSClang does not support recent mcpu option likes exynos-m2.
+	// So we need overriding mcpu option when we want to use it.
+	if ctx.Arch().CpuVariant == "exynos-m2" {
+		flags.ToolingCFlags = append(flags.ToolingCFlags, "-mcpu=cortex-a53")
+	}
+
 	return flags
 }
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		(Bool(c.Properties.Vendor_available) || (inList(c.Name(), config.LLndkLibraries())) ||
+		(c.isVndk() || inList(c.Name(), config.LLndkLibraries()) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m blueprint.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 49bd0f3..1fcb32c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -116,7 +116,8 @@
 type sanitize struct {
 	Properties SanitizeProperties
 
-	runtimeLibrary string
+	runtimeLibrary          string
+	androidMkRuntimeLibrary string
 }
 
 func (sanitize *sanitize) props() []interface{} {
@@ -188,7 +189,9 @@
 		}
 
 		if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
-			s.Integer_overflow = boolPtr(true)
+			if !ctx.AConfig().IntegerOverflowDisabledForPath(ctx.ModuleDir()) {
+				s.Integer_overflow = boolPtr(true)
+			}
 		}
 
 		if len(globalSanitizers) > 0 {
@@ -283,9 +286,6 @@
 
 	if Bool(sanitize.Properties.Sanitize.All_undefined) {
 		sanitizers = append(sanitizers, "undefined")
-		if ctx.Device() {
-			ctx.ModuleErrorf("ubsan is not yet supported on the device")
-		}
 	} else {
 		if Bool(sanitize.Properties.Sanitize.Undefined) {
 			sanitizers = append(sanitizers,
@@ -420,12 +420,18 @@
 		runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
 	}
 
-	// ASan runtime library must be the first in the link order.
 	if runtimeLibrary != "" {
+		// ASan runtime library must be the first in the link order.
 		flags.libFlags = append([]string{
 			"${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(),
 		}, flags.libFlags...)
 		sanitize.runtimeLibrary = runtimeLibrary
+
+		// When linking against VNDK, use the vendor variant of the runtime lib
+		sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary
+		if ctx.vndk() {
+			sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary + vendorSuffix
+		}
 	}
 
 	blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)
@@ -439,8 +445,8 @@
 
 func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
-		if sanitize.runtimeLibrary != "" {
-			fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.runtimeLibrary)
+		if sanitize.androidMkRuntimeLibrary != "" {
+			fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.androidMkRuntimeLibrary)
 		}
 
 		return nil
diff --git a/cc/stl.go b/cc/stl.go
index 9e67145..65d7e40 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -23,7 +23,7 @@
 	// select the STL library to use.  Possible values are "libc++", "libc++_static",
 	// "stlport", "stlport_static", "ndk", "libstdc++", or "none".  Leave blank to select the
 	// default
-	Stl *string
+	Stl *string `android:"arch_variant"`
 
 	SelectedStl string `blueprint:"mutated"`
 }
diff --git a/cc/test.go b/cc/test.go
index ea05ba5..a52e94a 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -298,6 +298,10 @@
 }
 
 type BenchmarkProperties struct {
+	// list of files or filegroup modules that provide data that should be installed alongside
+	// the test
+	Data []string
+
 	// list of compatibility suites (for example "cts", "vts") that the module should be
 	// installed into.
 	Test_suites []string
@@ -306,6 +310,7 @@
 type benchmarkDecorator struct {
 	*binaryDecorator
 	Properties BenchmarkProperties
+	data       android.Paths
 }
 
 func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) {
@@ -324,12 +329,14 @@
 }
 
 func (benchmark *benchmarkDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
+	android.ExtractSourcesDeps(ctx, benchmark.Properties.Data)
 	deps = benchmark.binaryDecorator.linkerDeps(ctx, deps)
 	deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark")
 	return deps
 }
 
 func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) {
+	benchmark.data = ctx.ExpandSources(benchmark.Properties.Data, nil)
 	benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.install(ctx, file)
diff --git a/cc/test_data_test.go b/cc/test_data_test.go
index a798919..962bde5 100644
--- a/cc/test_data_test.go
+++ b/cc/test_data_test.go
@@ -23,8 +23,6 @@
 
 	"android/soong/android"
 	"android/soong/genrule"
-
-	"github.com/google/blueprint"
 )
 
 type dataFile struct {
@@ -123,8 +121,7 @@
 
 	for _, test := range testDataTests {
 		t.Run(test.name, func(t *testing.T) {
-			ctx := blueprint.NewContext()
-			android.RegisterTestMutators(ctx)
+			ctx := android.NewTestContext()
 			ctx.MockFileSystem(map[string][]byte{
 				"Blueprints":     []byte(`subdirs = ["dir"]`),
 				"dir/Blueprints": []byte(test.modules),
@@ -135,18 +132,16 @@
 				android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
 			ctx.RegisterModuleType("test",
 				android.ModuleFactoryAdaptor(newTest))
+			ctx.Register()
 
 			_, errs := ctx.ParseBlueprintsFiles("Blueprints")
 			fail(t, errs)
 			_, errs = ctx.PrepareBuildActions(config)
 			fail(t, errs)
 
-			foo := findModule(ctx, "foo")
-			if foo == nil {
-				t.Fatalf("failed to find module foo")
-			}
+			foo := ctx.ModuleForTests("foo", "")
 
-			got := foo.(*testDataTest).data
+			got := foo.Module().(*testDataTest).data
 			if len(got) != len(test.data) {
 				t.Errorf("expected %d data files, got %d",
 					len(test.data), len(got))
@@ -192,16 +187,6 @@
 	test.data = ctx.ExpandSources(test.Properties.Data, nil)
 }
 
-func findModule(ctx *blueprint.Context, name string) blueprint.Module {
-	var ret blueprint.Module
-	ctx.VisitAllModules(func(m blueprint.Module) {
-		if ctx.ModuleName(m) == name {
-			ret = m
-		}
-	})
-	return ret
-}
-
 func fail(t *testing.T, errs []error) {
 	if len(errs) > 0 {
 		for _, err := range errs {
diff --git a/cc/vndk.go b/cc/vndk.go
new file mode 100644
index 0000000..fd1bdcb
--- /dev/null
+++ b/cc/vndk.go
@@ -0,0 +1,98 @@
+// 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 (
+	"android/soong/android"
+)
+
+type VndkProperties struct {
+	Vndk struct {
+		// declared as a VNDK or VNDK-SP module. The vendor variant
+		// will be installed in /system instead of /vendor partition.
+		//
+		// `vendor_available: true` must set to together for VNDK
+		// modules.
+		Enabled *bool
+
+		// declared as a VNDK-SP module, which is a subset of VNDK.
+		//
+		// `vndk: { enabled: true }` must set together.
+		//
+		// All these modules are allowed to link to VNDK-SP or LL-NDK
+		// modules only. Other dependency will cause link-type errors.
+		//
+		// If `support_system_process` is not set or set to false,
+		// the module is VNDK-core and can link to other VNDK-core,
+		// VNDK-SP or LL-NDK modules only.
+		Support_system_process *bool
+	}
+}
+
+type vndkdep struct {
+	Properties VndkProperties
+}
+
+func (vndk *vndkdep) props() []interface{} {
+	return []interface{}{&vndk.Properties}
+}
+
+func (vndk *vndkdep) begin(ctx BaseModuleContext) {}
+
+func (vndk *vndkdep) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return deps
+}
+
+func (vndk *vndkdep) isVndk() bool {
+	return Bool(vndk.Properties.Vndk.Enabled)
+}
+
+func (vndk *vndkdep) isVndkSp() bool {
+	return Bool(vndk.Properties.Vndk.Support_system_process)
+}
+
+func (vndk *vndkdep) typeName() string {
+	if !vndk.isVndk() {
+		return "native:vendor"
+	}
+	if !vndk.isVndkSp() {
+		return "native:vendor:vndk"
+	}
+	return "native:vendor:vndksp"
+}
+
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module) {
+	if to.linker == nil {
+		return
+	}
+	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
+		// Check only shared libraries.
+		// Other (static and LL-NDK) libraries are allowed to link.
+		return
+	}
+	if !to.Properties.UseVndk {
+		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
+			vndk.typeName(), to.Name())
+		return
+	}
+	if to.vndkdep == nil {
+		return
+	}
+	if (vndk.isVndk() && !to.vndkdep.isVndk()) || (vndk.isVndkSp() && !to.vndkdep.isVndkSp()) {
+		ctx.ModuleErrorf("(%s) should not link to %q(%s)",
+			vndk.typeName(), to.Name(), to.vndkdep.typeName())
+		return
+	}
+}
diff --git a/cmd/microfactory/Android.bp b/cmd/microfactory/Android.bp
deleted file mode 100644
index a457f43..0000000
--- a/cmd/microfactory/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-blueprint_go_binary {
-    name: "microfactory",
-    srcs: [
-        "microfactory.go",
-    ],
-    testSrcs: [
-        "microfactory_test.go",
-    ],
-}
diff --git a/cmd/microfactory/microfactory.bash b/cmd/microfactory/microfactory.bash
deleted file mode 100644
index 7489fe3..0000000
--- a/cmd/microfactory/microfactory.bash
+++ /dev/null
@@ -1,88 +0,0 @@
-# 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.
-
-# Set of utility functions to build and run go code with microfactory
-#
-# Inputs:
-#  ${TOP}: The top of the android source tree
-#  ${OUT_DIR}: The output directory location (defaults to ${TOP}/out)
-#  ${OUT_DIR_COMMON_BASE}: Change the default out directory to
-#    ${OUT_DIR_COMMON_BASE}/$(basename ${TOP})
-
-# Ensure GOROOT is set to the in-tree version.
-case $(uname) in
-    Linux)
-        export GOROOT="${TOP}/prebuilts/go/linux-x86/"
-        ;;
-    Darwin)
-        export GOROOT="${TOP}/prebuilts/go/darwin-x86/"
-        ;;
-    *) echo "unknown OS:" $(uname) >&2 && exit 1;;
-esac
-
-# Find the output directory
-function getoutdir
-{
-    local out_dir="${OUT_DIR-}"
-    if [ -z "${out_dir}" ]; then
-        if [ "${OUT_DIR_COMMON_BASE-}" ]; then
-            out_dir="${OUT_DIR_COMMON_BASE}/$(basename ${TOP})"
-        else
-            out_dir="${TOP}/out"
-        fi
-    fi
-    echo "${out_dir}"
-}
-
-# Bootstrap microfactory from source if necessary and use it to build the
-# requested binary.
-#
-# Arguments:
-#  $1: name of the requested binary
-#  $2: package name
-function build_go
-{
-    # Increment when microfactory changes enough that it cannot rebuild itself.
-    # For example, if we use a new command line argument that doesn't work on older versions.
-    local mf_version=2
-
-    local mf_src="${TOP}/build/soong/cmd/microfactory"
-
-    local out_dir=$(getoutdir)
-    local mf_bin="${out_dir}/microfactory_$(uname)"
-    local mf_version_file="${out_dir}/.microfactory_$(uname)_version"
-    local built_bin="${out_dir}/$1"
-    local from_src=1
-
-    if [ -f "${mf_bin}" ] && [ -f "${mf_version_file}" ]; then
-        if [ "${mf_version}" -eq "$(cat "${mf_version_file}")" ]; then
-            from_src=0
-        fi
-    fi
-
-    local mf_cmd
-    if [ $from_src -eq 1 ]; then
-        mf_cmd="${GOROOT}/bin/go run ${mf_src}/microfactory.go"
-    else
-        mf_cmd="${mf_bin}"
-    fi
-
-    ${mf_cmd} -s "${mf_src}" -b "${mf_bin}" \
-            -pkg-path "android/soong=${TOP}/build/soong" -trimpath "${TOP}/build/soong" \
-            -o "${built_bin}" $2
-
-    if [ $from_src -eq 1 ]; then
-        echo "${mf_version}" >"${mf_version_file}"
-    fi
-}
diff --git a/cmd/microfactory/microfactory.go b/cmd/microfactory/microfactory.go
deleted file mode 100644
index 6c062e2..0000000
--- a/cmd/microfactory/microfactory.go
+++ /dev/null
@@ -1,572 +0,0 @@
-// 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.
-
-// Microfactory is a tool to incrementally compile a go program. It's similar
-// to `go install`, but doesn't require a GOPATH. A package->path mapping can
-// be specified as command line options:
-//
-//   -pkg-path android/soong=build/soong
-//   -pkg-path github.com/google/blueprint=build/blueprint
-//
-// The paths can be relative to the current working directory, or an absolute
-// path. Both packages and paths are compared with full directory names, so the
-// android/soong-test package wouldn't be mapped in the above case.
-//
-// Microfactory will ignore *_test.go files, and limits *_darwin.go and
-// *_linux.go files to MacOS and Linux respectively. It does not support build
-// tags or any other suffixes.
-//
-// Builds are incremental by package. All input files are hashed, and if the
-// hash of an input or dependency changes, the package is rebuilt.
-//
-// It also exposes the -trimpath option from go's compiler so that embedded
-// path names (such as in log.Llongfile) are relative paths instead of absolute
-// paths.
-//
-// If you don't have a previously built version of Microfactory, when used with
-// -s <microfactory_src_dir> -b <microfactory_bin_file>, Microfactory can
-// rebuild itself as necessary. Combined with a shell script like soong_ui.bash
-// that uses `go run` to run Microfactory for the first time, go programs can be
-// quickly bootstrapped entirely from source (and a standard go distribution).
-package main
-
-import (
-	"bytes"
-	"crypto/sha1"
-	"flag"
-	"fmt"
-	"go/ast"
-	"go/parser"
-	"go/token"
-	"io"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"runtime"
-	"sort"
-	"strconv"
-	"strings"
-	"sync"
-	"syscall"
-)
-
-var (
-	race    = false
-	verbose = false
-
-	goToolDir = filepath.Join(runtime.GOROOT(), "pkg", "tool", runtime.GOOS+"_"+runtime.GOARCH)
-	goVersion = findGoVersion()
-)
-
-func findGoVersion() string {
-	if version, err := ioutil.ReadFile(filepath.Join(runtime.GOROOT(), "VERSION")); err == nil {
-		return string(version)
-	}
-
-	cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), "version")
-	if version, err := cmd.Output(); err == nil {
-		return string(version)
-	} else {
-		panic(fmt.Sprintf("Unable to discover go version: %v", err))
-	}
-}
-
-type GoPackage struct {
-	Name string
-
-	// Inputs
-	directDeps []*GoPackage // specified directly by the module
-	allDeps    []*GoPackage // direct dependencies and transitive dependencies
-	files      []string
-
-	// Outputs
-	pkgDir     string
-	output     string
-	hashResult []byte
-
-	// Status
-	mutex    sync.Mutex
-	compiled bool
-	failed   error
-	rebuilt  bool
-}
-
-// LinkedHashMap<string, GoPackage>
-type linkedDepSet struct {
-	packageSet  map[string](*GoPackage)
-	packageList []*GoPackage
-}
-
-func newDepSet() *linkedDepSet {
-	return &linkedDepSet{packageSet: make(map[string]*GoPackage)}
-}
-func (s *linkedDepSet) tryGetByName(name string) (*GoPackage, bool) {
-	pkg, contained := s.packageSet[name]
-	return pkg, contained
-}
-func (s *linkedDepSet) getByName(name string) *GoPackage {
-	pkg, _ := s.tryGetByName(name)
-	return pkg
-}
-func (s *linkedDepSet) add(name string, goPackage *GoPackage) {
-	s.packageSet[name] = goPackage
-	s.packageList = append(s.packageList, goPackage)
-}
-func (s *linkedDepSet) ignore(name string) {
-	s.packageSet[name] = nil
-}
-
-// FindDeps searches all applicable go files in `path`, parses all of them
-// for import dependencies that exist in pkgMap, then recursively does the
-// same for all of those dependencies.
-func (p *GoPackage) FindDeps(path string, pkgMap *pkgPathMapping) error {
-	depSet := newDepSet()
-	err := p.findDeps(path, pkgMap, depSet)
-	if err != nil {
-		return err
-	}
-	p.allDeps = depSet.packageList
-	return nil
-}
-
-// findDeps is the recursive version of FindDeps. allPackages is the map of
-// all locally defined packages so that the same dependency of two different
-// packages is only resolved once.
-func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages *linkedDepSet) error {
-	// If this ever becomes too slow, we can look at reading the files once instead of twice
-	// But that just complicates things today, and we're already really fast.
-	foundPkgs, err := parser.ParseDir(token.NewFileSet(), path, func(fi os.FileInfo) bool {
-		name := fi.Name()
-		if fi.IsDir() || strings.HasSuffix(name, "_test.go") || name[0] == '.' || name[0] == '_' {
-			return false
-		}
-		if runtime.GOOS != "darwin" && strings.HasSuffix(name, "_darwin.go") {
-			return false
-		}
-		if runtime.GOOS != "linux" && strings.HasSuffix(name, "_linux.go") {
-			return false
-		}
-		return true
-	}, parser.ImportsOnly)
-	if err != nil {
-		return fmt.Errorf("Error parsing directory %q: %v", path, err)
-	}
-
-	var foundPkg *ast.Package
-	// foundPkgs is a map[string]*ast.Package, but we only want one package
-	if len(foundPkgs) != 1 {
-		return fmt.Errorf("Expected one package in %q, got %d", path, len(foundPkgs))
-	}
-	// Extract the first (and only) entry from the map.
-	for _, pkg := range foundPkgs {
-		foundPkg = pkg
-	}
-
-	var deps []string
-	localDeps := make(map[string]bool)
-
-	for filename, astFile := range foundPkg.Files {
-		p.files = append(p.files, filename)
-
-		for _, importSpec := range astFile.Imports {
-			name, err := strconv.Unquote(importSpec.Path.Value)
-			if err != nil {
-				return fmt.Errorf("%s: invalid quoted string: <%s> %v", filename, importSpec.Path.Value, err)
-			}
-
-			if pkg, ok := allPackages.tryGetByName(name); ok {
-				if pkg != nil {
-					if _, ok := localDeps[name]; !ok {
-						deps = append(deps, name)
-						localDeps[name] = true
-					}
-				}
-				continue
-			}
-
-			var pkgPath string
-			if path, ok, err := pkgMap.Path(name); err != nil {
-				return err
-			} else if !ok {
-				// Probably in the stdlib, but if not, then the compiler will fail with a reasonable error message
-				// Mark it as such so that we don't try to decode its path again.
-				allPackages.ignore(name)
-				continue
-			} else {
-				pkgPath = path
-			}
-
-			pkg := &GoPackage{
-				Name: name,
-			}
-			deps = append(deps, name)
-			allPackages.add(name, pkg)
-			localDeps[name] = true
-
-			if err := pkg.findDeps(pkgPath, pkgMap, allPackages); err != nil {
-				return err
-			}
-		}
-	}
-
-	sort.Strings(p.files)
-
-	if verbose {
-		fmt.Fprintf(os.Stderr, "Package %q depends on %v\n", p.Name, deps)
-	}
-
-	for _, dep := range deps {
-		p.directDeps = append(p.directDeps, allPackages.getByName(dep))
-	}
-
-	return nil
-}
-
-func (p *GoPackage) Compile(outDir, trimPath string) error {
-	p.mutex.Lock()
-	defer p.mutex.Unlock()
-	if p.compiled {
-		return p.failed
-	}
-	p.compiled = true
-
-	// Build all dependencies in parallel, then fail if any of them failed.
-	var wg sync.WaitGroup
-	for _, dep := range p.directDeps {
-		wg.Add(1)
-		go func(dep *GoPackage) {
-			defer wg.Done()
-			dep.Compile(outDir, trimPath)
-		}(dep)
-	}
-	wg.Wait()
-	for _, dep := range p.directDeps {
-		if dep.failed != nil {
-			p.failed = dep.failed
-			return p.failed
-		}
-	}
-
-	p.pkgDir = filepath.Join(outDir, p.Name)
-	p.output = filepath.Join(p.pkgDir, p.Name) + ".a"
-	shaFile := p.output + ".hash"
-
-	hash := sha1.New()
-	fmt.Fprintln(hash, runtime.GOOS, runtime.GOARCH, goVersion)
-
-	cmd := exec.Command(filepath.Join(goToolDir, "compile"),
-		"-o", p.output,
-		"-p", p.Name,
-		"-complete", "-pack", "-nolocalimports")
-	if race {
-		cmd.Args = append(cmd.Args, "-race")
-		fmt.Fprintln(hash, "-race")
-	}
-	if trimPath != "" {
-		cmd.Args = append(cmd.Args, "-trimpath", trimPath)
-		fmt.Fprintln(hash, trimPath)
-	}
-	for _, dep := range p.directDeps {
-		cmd.Args = append(cmd.Args, "-I", dep.pkgDir)
-		hash.Write(dep.hashResult)
-	}
-	for _, filename := range p.files {
-		cmd.Args = append(cmd.Args, filename)
-		fmt.Fprintln(hash, filename)
-
-		// Hash the contents of the input files
-		f, err := os.Open(filename)
-		if err != nil {
-			f.Close()
-			err = fmt.Errorf("%s: %v", filename, err)
-			p.failed = err
-			return err
-		}
-		_, err = io.Copy(hash, f)
-		if err != nil {
-			f.Close()
-			err = fmt.Errorf("%s: %v", filename, err)
-			p.failed = err
-			return err
-		}
-		f.Close()
-	}
-	p.hashResult = hash.Sum(nil)
-
-	var rebuild bool
-	if _, err := os.Stat(p.output); err != nil {
-		rebuild = true
-	}
-	if !rebuild {
-		if oldSha, err := ioutil.ReadFile(shaFile); err == nil {
-			rebuild = !bytes.Equal(oldSha, p.hashResult)
-		} else {
-			rebuild = true
-		}
-	}
-
-	if !rebuild {
-		return nil
-	}
-
-	err := os.RemoveAll(p.pkgDir)
-	if err != nil {
-		err = fmt.Errorf("%s: %v", p.Name, err)
-		p.failed = err
-		return err
-	}
-
-	err = os.MkdirAll(filepath.Dir(p.output), 0777)
-	if err != nil {
-		err = fmt.Errorf("%s: %v", p.Name, err)
-		p.failed = err
-		return err
-	}
-
-	cmd.Stdin = nil
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	if verbose {
-		fmt.Fprintln(os.Stderr, cmd.Args)
-	}
-	err = cmd.Run()
-	if err != nil {
-		err = fmt.Errorf("%s: %v", p.Name, err)
-		p.failed = err
-		return err
-	}
-
-	err = ioutil.WriteFile(shaFile, p.hashResult, 0666)
-	if err != nil {
-		err = fmt.Errorf("%s: %v", p.Name, err)
-		p.failed = err
-		return err
-	}
-
-	p.rebuilt = true
-
-	return nil
-}
-
-func (p *GoPackage) Link(out string) error {
-	if p.Name != "main" {
-		return fmt.Errorf("Can only link main package")
-	}
-
-	shaFile := filepath.Join(filepath.Dir(out), "."+filepath.Base(out)+"_hash")
-
-	if !p.rebuilt {
-		if _, err := os.Stat(out); err != nil {
-			p.rebuilt = true
-		} else if oldSha, err := ioutil.ReadFile(shaFile); err != nil {
-			p.rebuilt = true
-		} else {
-			p.rebuilt = !bytes.Equal(oldSha, p.hashResult)
-		}
-	}
-	if !p.rebuilt {
-		return nil
-	}
-
-	err := os.Remove(shaFile)
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	}
-	err = os.Remove(out)
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	}
-
-	cmd := exec.Command(filepath.Join(goToolDir, "link"), "-o", out)
-	if race {
-		cmd.Args = append(cmd.Args, "-race")
-	}
-	for _, dep := range p.allDeps {
-		cmd.Args = append(cmd.Args, "-L", dep.pkgDir)
-	}
-	cmd.Args = append(cmd.Args, p.output)
-	cmd.Stdin = nil
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	if verbose {
-		fmt.Fprintln(os.Stderr, cmd.Args)
-	}
-	err = cmd.Run()
-	if err != nil {
-		return fmt.Errorf("command %s failed with error %v", cmd.Args, err)
-	}
-
-	return ioutil.WriteFile(shaFile, p.hashResult, 0666)
-}
-
-// rebuildMicrofactory checks to see if microfactory itself needs to be rebuilt,
-// and if does, it will launch a new copy instead of returning.
-func rebuildMicrofactory(mybin, mysrc string, pkgMap *pkgPathMapping) {
-	intermediates := filepath.Join(filepath.Dir(mybin), "."+filepath.Base(mybin)+"_intermediates")
-
-	err := os.MkdirAll(intermediates, 0777)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, "Failed to create intermediates directory: %v", err)
-		os.Exit(1)
-	}
-
-	pkg := &GoPackage{
-		Name: "main",
-	}
-
-	if err := pkg.FindDeps(mysrc, pkgMap); err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
-	}
-
-	if err := pkg.Compile(intermediates, mysrc); err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
-	}
-
-	if err := pkg.Link(mybin); err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
-	}
-
-	if !pkg.rebuilt {
-		return
-	}
-
-	cmd := exec.Command(mybin, os.Args[1:]...)
-	cmd.Stdin = os.Stdin
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	if err := cmd.Run(); err == nil {
-		os.Exit(0)
-	} else if e, ok := err.(*exec.ExitError); ok {
-		os.Exit(e.ProcessState.Sys().(syscall.WaitStatus).ExitStatus())
-	}
-	os.Exit(1)
-}
-
-func main() {
-	var output, mysrc, mybin, trimPath string
-	var pkgMap pkgPathMapping
-
-	flags := flag.NewFlagSet("", flag.ExitOnError)
-	flags.BoolVar(&race, "race", false, "enable data race detection.")
-	flags.BoolVar(&verbose, "v", false, "Verbose")
-	flags.StringVar(&output, "o", "", "Output file")
-	flags.StringVar(&mysrc, "s", "", "Microfactory source directory (for rebuilding microfactory if necessary)")
-	flags.StringVar(&mybin, "b", "", "Microfactory binary location")
-	flags.StringVar(&trimPath, "trimpath", "", "remove prefix from recorded source file paths")
-	flags.Var(&pkgMap, "pkg-path", "Mapping of package prefixes to file paths")
-	err := flags.Parse(os.Args[1:])
-
-	if err == flag.ErrHelp || flags.NArg() != 1 || output == "" {
-		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "-o out/binary <main-package>")
-		flags.PrintDefaults()
-		os.Exit(1)
-	}
-
-	if mybin != "" && mysrc != "" {
-		rebuildMicrofactory(mybin, mysrc, &pkgMap)
-	}
-
-	mainPackage := &GoPackage{
-		Name: "main",
-	}
-
-	if path, ok, err := pkgMap.Path(flags.Arg(0)); err != nil {
-		fmt.Fprintln(os.Stderr, "Error finding main path:", err)
-		os.Exit(1)
-	} else if !ok {
-		fmt.Fprintln(os.Stderr, "Cannot find path for", flags.Arg(0))
-	} else {
-		if err := mainPackage.FindDeps(path, &pkgMap); err != nil {
-			fmt.Fprintln(os.Stderr, err)
-			os.Exit(1)
-		}
-	}
-
-	intermediates := filepath.Join(filepath.Dir(output), "."+filepath.Base(output)+"_intermediates")
-
-	err = os.MkdirAll(intermediates, 0777)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, "Failed to create intermediates directory: %ve", err)
-		os.Exit(1)
-	}
-
-	err = mainPackage.Compile(intermediates, trimPath)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, "Failed to compile:", err)
-		os.Exit(1)
-	}
-
-	err = mainPackage.Link(output)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, "microfactory.go failed to link:", err)
-		os.Exit(1)
-	}
-}
-
-// pkgPathMapping can be used with flag.Var to parse -pkg-path arguments of
-// <package-prefix>=<path-prefix> mappings.
-type pkgPathMapping struct {
-	pkgs []string
-
-	paths map[string]string
-}
-
-func (pkgPathMapping) String() string {
-	return "<package-prefix>=<path-prefix>"
-}
-
-func (p *pkgPathMapping) Set(value string) error {
-	equalPos := strings.Index(value, "=")
-	if equalPos == -1 {
-		return fmt.Errorf("Argument must be in the form of: %q", p.String())
-	}
-
-	pkgPrefix := strings.TrimSuffix(value[:equalPos], "/")
-	pathPrefix := strings.TrimSuffix(value[equalPos+1:], "/")
-
-	if p.paths == nil {
-		p.paths = make(map[string]string)
-	}
-	if _, ok := p.paths[pkgPrefix]; ok {
-		return fmt.Errorf("Duplicate package prefix: %q", pkgPrefix)
-	}
-
-	p.pkgs = append(p.pkgs, pkgPrefix)
-	p.paths[pkgPrefix] = pathPrefix
-
-	return nil
-}
-
-// Path takes a package name, applies the path mappings and returns the resulting path.
-//
-// If the package isn't mapped, we'll return false to prevent compilation attempts.
-func (p *pkgPathMapping) Path(pkg string) (string, bool, error) {
-	if p.paths == nil {
-		return "", false, fmt.Errorf("No package mappings")
-	}
-
-	for _, pkgPrefix := range p.pkgs {
-		if pkg == pkgPrefix {
-			return p.paths[pkgPrefix], true, nil
-		} else if strings.HasPrefix(pkg, pkgPrefix+"/") {
-			return filepath.Join(p.paths[pkgPrefix], strings.TrimPrefix(pkg, pkgPrefix+"/")), true, nil
-		}
-	}
-
-	return "", false, nil
-}
diff --git a/cmd/microfactory/microfactory_test.go b/cmd/microfactory/microfactory_test.go
deleted file mode 100644
index 8c02bcf..0000000
--- a/cmd/microfactory/microfactory_test.go
+++ /dev/null
@@ -1,422 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
-	"flag"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"reflect"
-	"runtime"
-	"testing"
-	"time"
-)
-
-func TestSimplePackagePathMap(t *testing.T) {
-	t.Parallel()
-
-	var pkgMap pkgPathMapping
-	flags := flag.NewFlagSet("", flag.ContinueOnError)
-	flags.Var(&pkgMap, "m", "")
-	err := flags.Parse([]string{
-		"-m", "android/soong=build/soong/",
-		"-m", "github.com/google/blueprint/=build/blueprint",
-	})
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	compare := func(got, want interface{}) {
-		if !reflect.DeepEqual(got, want) {
-			t.Errorf("Unexpected values in .pkgs:\nwant: %v\n got: %v",
-				want, got)
-		}
-	}
-
-	wantPkgs := []string{"android/soong", "github.com/google/blueprint"}
-	compare(pkgMap.pkgs, wantPkgs)
-	compare(pkgMap.paths[wantPkgs[0]], "build/soong")
-	compare(pkgMap.paths[wantPkgs[1]], "build/blueprint")
-
-	got, ok, err := pkgMap.Path("android/soong/ui/test")
-	if err != nil {
-		t.Error("Unexpected error in pkgMap.Path(soong):", err)
-	} else if !ok {
-		t.Error("Expected a result from pkgMap.Path(soong)")
-	} else {
-		compare(got, "build/soong/ui/test")
-	}
-
-	got, ok, err = pkgMap.Path("github.com/google/blueprint")
-	if err != nil {
-		t.Error("Unexpected error in pkgMap.Path(blueprint):", err)
-	} else if !ok {
-		t.Error("Expected a result from pkgMap.Path(blueprint)")
-	} else {
-		compare(got, "build/blueprint")
-	}
-}
-
-func TestBadPackagePathMap(t *testing.T) {
-	t.Parallel()
-
-	var pkgMap pkgPathMapping
-	if _, _, err := pkgMap.Path("testing"); err == nil {
-		t.Error("Expected error if no maps are specified")
-	}
-	if err := pkgMap.Set(""); err == nil {
-		t.Error("Expected error with blank argument, but none returned")
-	}
-	if err := pkgMap.Set("a=a"); err != nil {
-		t.Error("Unexpected error: %v", err)
-	}
-	if err := pkgMap.Set("a=b"); err == nil {
-		t.Error("Expected error with duplicate package prefix, but none returned")
-	}
-	if _, ok, err := pkgMap.Path("testing"); err != nil {
-		t.Error("Unexpected error: %v", err)
-	} else if ok {
-		t.Error("Expected testing to be consider in the stdlib")
-	}
-}
-
-// TestSingleBuild ensures that just a basic build works.
-func TestSingleBuild(t *testing.T) {
-	t.Parallel()
-
-	setupDir(t, func(dir string, loadPkg loadPkgFunc) {
-		// The output binary
-		out := filepath.Join(dir, "out", "test")
-
-		pkg := loadPkg()
-
-		if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-			t.Fatalf("Got error when compiling:", err)
-		}
-
-		if err := pkg.Link(out); err != nil {
-			t.Fatal("Got error when linking:", err)
-		}
-
-		if _, err := os.Stat(out); err != nil {
-			t.Error("Cannot stat output:", err)
-		}
-	})
-}
-
-// testBuildAgain triggers two builds, running the modify function in between
-// each build. It verifies that the second build did or did not actually need
-// to rebuild anything based on the shouldRebuild argument.
-func testBuildAgain(t *testing.T,
-	shouldRecompile, shouldRelink bool,
-	modify func(dir string, loadPkg loadPkgFunc),
-	after func(pkg *GoPackage)) {
-
-	t.Parallel()
-
-	setupDir(t, func(dir string, loadPkg loadPkgFunc) {
-		// The output binary
-		out := filepath.Join(dir, "out", "test")
-
-		pkg := loadPkg()
-
-		if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-			t.Fatal("Got error when compiling:", err)
-		}
-
-		if err := pkg.Link(out); err != nil {
-			t.Fatal("Got error when linking:", err)
-		}
-
-		var firstTime time.Time
-		if stat, err := os.Stat(out); err == nil {
-			firstTime = stat.ModTime()
-		} else {
-			t.Fatal("Failed to stat output file:", err)
-		}
-
-		// mtime on HFS+ (the filesystem on darwin) are stored with 1
-		// second granularity, so the timestamp checks will fail unless
-		// we wait at least a second. Sleeping 1.1s to be safe.
-		if runtime.GOOS == "darwin" {
-			time.Sleep(1100 * time.Millisecond)
-		}
-
-		modify(dir, loadPkg)
-
-		pkg = loadPkg()
-
-		if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-			t.Fatal("Got error when compiling:", err)
-		}
-		if shouldRecompile {
-			if !pkg.rebuilt {
-				t.Fatal("Package should have recompiled, but was not recompiled.")
-			}
-		} else {
-			if pkg.rebuilt {
-				t.Fatal("Package should not have needed to be recompiled, but was recompiled.")
-			}
-		}
-
-		if err := pkg.Link(out); err != nil {
-			t.Fatal("Got error while linking:", err)
-		}
-		if shouldRelink {
-			if !pkg.rebuilt {
-				t.Error("Package should have relinked, but was not relinked.")
-			}
-		} else {
-			if pkg.rebuilt {
-				t.Error("Package should not have needed to be relinked, but was relinked.")
-			}
-		}
-
-		if stat, err := os.Stat(out); err == nil {
-			if shouldRelink {
-				if stat.ModTime() == firstTime {
-					t.Error("Output timestamp should be different, but both were", firstTime)
-				}
-			} else {
-				if stat.ModTime() != firstTime {
-					t.Error("Output timestamp should be the same.")
-					t.Error(" first:", firstTime)
-					t.Error("second:", stat.ModTime())
-				}
-			}
-		} else {
-			t.Fatal("Failed to stat output file:", err)
-		}
-
-		after(pkg)
-	})
-}
-
-// TestRebuildAfterNoChanges ensures that we don't rebuild if nothing
-// changes
-func TestRebuildAfterNoChanges(t *testing.T) {
-	testBuildAgain(t, false, false, func(dir string, loadPkg loadPkgFunc) {}, func(pkg *GoPackage) {})
-}
-
-// TestRebuildAfterTimestamp ensures that we don't rebuild because
-// timestamps of important files have changed. We should only rebuild if the
-// content hashes are different.
-func TestRebuildAfterTimestampChange(t *testing.T) {
-	testBuildAgain(t, false, false, func(dir string, loadPkg loadPkgFunc) {
-		// Ensure that we've spent some amount of time asleep
-		time.Sleep(100 * time.Millisecond)
-
-		newTime := time.Now().Local()
-		os.Chtimes(filepath.Join(dir, "test.fact"), newTime, newTime)
-		os.Chtimes(filepath.Join(dir, "main/main.go"), newTime, newTime)
-		os.Chtimes(filepath.Join(dir, "a/a.go"), newTime, newTime)
-		os.Chtimes(filepath.Join(dir, "a/b.go"), newTime, newTime)
-		os.Chtimes(filepath.Join(dir, "b/a.go"), newTime, newTime)
-	}, func(pkg *GoPackage) {})
-}
-
-// TestRebuildAfterGoChange ensures that we rebuild after a content change
-// to a package's go file.
-func TestRebuildAfterGoChange(t *testing.T) {
-	testBuildAgain(t, true, true, func(dir string, loadPkg loadPkgFunc) {
-		if err := ioutil.WriteFile(filepath.Join(dir, "a", "a.go"), []byte(go_a_a+"\n"), 0666); err != nil {
-			t.Fatal("Error writing a/a.go:", err)
-		}
-	}, func(pkg *GoPackage) {
-		if !pkg.directDeps[0].rebuilt {
-			t.Fatal("android/soong/a should have rebuilt")
-		}
-		if !pkg.directDeps[1].rebuilt {
-			t.Fatal("android/soong/b should have rebuilt")
-		}
-	})
-}
-
-// TestRebuildAfterMainChange ensures that we don't rebuild any dependencies
-// if only the main package's go files are touched.
-func TestRebuildAfterMainChange(t *testing.T) {
-	testBuildAgain(t, true, true, func(dir string, loadPkg loadPkgFunc) {
-		if err := ioutil.WriteFile(filepath.Join(dir, "main", "main.go"), []byte(go_main_main+"\n"), 0666); err != nil {
-			t.Fatal("Error writing main/main.go:", err)
-		}
-	}, func(pkg *GoPackage) {
-		if pkg.directDeps[0].rebuilt {
-			t.Fatal("android/soong/a should not have rebuilt")
-		}
-		if pkg.directDeps[1].rebuilt {
-			t.Fatal("android/soong/b should not have rebuilt")
-		}
-	})
-}
-
-// TestRebuildAfterRemoveOut ensures that we rebuild if the output file is
-// missing, even if everything else doesn't need rebuilding.
-func TestRebuildAfterRemoveOut(t *testing.T) {
-	testBuildAgain(t, false, true, func(dir string, loadPkg loadPkgFunc) {
-		if err := os.Remove(filepath.Join(dir, "out", "test")); err != nil {
-			t.Fatal("Failed to remove output:", err)
-		}
-	}, func(pkg *GoPackage) {})
-}
-
-// TestRebuildAfterPartialBuild ensures that even if the build was interrupted
-// between the recompile and relink stages, we'll still relink when we run again.
-func TestRebuildAfterPartialBuild(t *testing.T) {
-	testBuildAgain(t, false, true, func(dir string, loadPkg loadPkgFunc) {
-		if err := ioutil.WriteFile(filepath.Join(dir, "main", "main.go"), []byte(go_main_main+"\n"), 0666); err != nil {
-			t.Fatal("Error writing main/main.go:", err)
-		}
-
-		pkg := loadPkg()
-
-		if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-			t.Fatal("Got error when compiling:", err)
-		}
-		if !pkg.rebuilt {
-			t.Fatal("Package should have recompiled, but was not recompiled.")
-		}
-	}, func(pkg *GoPackage) {})
-}
-
-// BenchmarkInitialBuild computes how long a clean build takes (for tiny test
-// inputs).
-func BenchmarkInitialBuild(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		setupDir(b, func(dir string, loadPkg loadPkgFunc) {
-			pkg := loadPkg()
-			if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-				b.Fatal("Got error when compiling:", err)
-			}
-
-			if err := pkg.Link(filepath.Join(dir, "out", "test")); err != nil {
-				b.Fatal("Got error when linking:", err)
-			}
-		})
-	}
-}
-
-// BenchmarkMinIncrementalBuild computes how long an incremental build that
-// doesn't actually need to build anything takes.
-func BenchmarkMinIncrementalBuild(b *testing.B) {
-	setupDir(b, func(dir string, loadPkg loadPkgFunc) {
-		pkg := loadPkg()
-
-		if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-			b.Fatal("Got error when compiling:", err)
-		}
-
-		if err := pkg.Link(filepath.Join(dir, "out", "test")); err != nil {
-			b.Fatal("Got error when linking:", err)
-		}
-
-		b.ResetTimer()
-
-		for i := 0; i < b.N; i++ {
-			pkg := loadPkg()
-
-			if err := pkg.Compile(filepath.Join(dir, "out"), ""); err != nil {
-				b.Fatal("Got error when compiling:", err)
-			}
-
-			if err := pkg.Link(filepath.Join(dir, "out", "test")); err != nil {
-				b.Fatal("Got error when linking:", err)
-			}
-
-			if pkg.rebuilt {
-				b.Fatal("Should not have rebuilt anything")
-			}
-		}
-	})
-}
-
-///////////////////////////////////////////////////////
-// Templates used to create fake compilable packages //
-///////////////////////////////////////////////////////
-
-const go_main_main = `
-package main
-import (
-	"fmt"
-	"android/soong/a"
-	"android/soong/b"
-)
-func main() {
-	fmt.Println(a.Stdout, b.Stdout)
-}
-`
-
-const go_a_a = `
-package a
-import "os"
-var Stdout = os.Stdout
-`
-
-const go_a_b = `
-package a
-`
-
-const go_b_a = `
-package b
-import "android/soong/a"
-var Stdout = a.Stdout
-`
-
-type T interface {
-	Fatal(args ...interface{})
-	Fatalf(format string, args ...interface{})
-}
-
-type loadPkgFunc func() *GoPackage
-
-func setupDir(t T, test func(dir string, loadPkg loadPkgFunc)) {
-	dir, err := ioutil.TempDir("", "test")
-	if err != nil {
-		t.Fatalf("Error creating temporary directory: %#v", err)
-	}
-	defer os.RemoveAll(dir)
-
-	writeFile := func(name, contents string) {
-		if err := ioutil.WriteFile(filepath.Join(dir, name), []byte(contents), 0666); err != nil {
-			t.Fatalf("Error writing %q: %#v", name, err)
-		}
-	}
-	mkdir := func(name string) {
-		if err := os.Mkdir(filepath.Join(dir, name), 0777); err != nil {
-			t.Fatalf("Error creating %q directory: %#v", name, err)
-		}
-	}
-	mkdir("main")
-	mkdir("a")
-	mkdir("b")
-	writeFile("main/main.go", go_main_main)
-	writeFile("a/a.go", go_a_a)
-	writeFile("a/b.go", go_a_b)
-	writeFile("b/a.go", go_b_a)
-
-	loadPkg := func() *GoPackage {
-		pkg := &GoPackage{
-			Name: "main",
-		}
-		pkgMap := &pkgPathMapping{}
-		pkgMap.Set("android/soong=" + dir)
-		if err := pkg.FindDeps(filepath.Join(dir, "main"), pkgMap); err != nil {
-			t.Fatalf("Error finding deps: %v", err)
-		}
-		return pkg
-	}
-
-	test(dir, loadPkg)
-}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index ed8f2fd..e15a6bd 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -32,6 +32,7 @@
 	srcDir := filepath.Dir(flag.Arg(0))
 
 	ctx := android.NewContext()
+	ctx.Register()
 
 	configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir)
 	if err != nil {
@@ -44,5 +45,5 @@
 
 	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
 
-	bootstrap.Main(ctx, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
+	bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
 }
diff --git a/cmd/soong_env/Android.bp b/cmd/soong_env/Android.bp
index b0d827c..4cdc396 100644
--- a/cmd/soong_env/Android.bp
+++ b/cmd/soong_env/Android.bp
@@ -20,5 +20,6 @@
     srcs: [
         "soong_env.go",
     ],
+    default: true,
 }
 
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 26887ae..94d6d5c 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -89,6 +89,10 @@
 				buildCtx.CompleteTrace("startup", start_time, uint64(time.Now().UnixNano()))
 			}
 		}
+
+		if executable, err := os.Executable(); err == nil {
+			trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
+		}
 	}
 
 	build.Build(buildCtx, config, build.BuildAll)
diff --git a/java/androidmk.go b/java/androidmk.go
index 9ffd35f..086ba7a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -20,14 +20,14 @@
 	"android/soong/android"
 )
 
-func (*JavaLibrary) AndroidMk() (ret android.AndroidMkData, err error) {
+func (*Library) AndroidMk() (ret android.AndroidMkData, err error) {
 	ret.Class = "JAVA_LIBRARIES"
 	// TODO
 	err = fmt.Errorf("Not yet implemented")
 	return
 }
 
-func (*JavaPrebuilt) AndroidMk() (ret android.AndroidMkData, err error) {
+func (*Prebuilt) AndroidMk() (ret android.AndroidMkData, err error) {
 	ret.Class = "JAVA_LIBRARIES"
 	// TODO
 	err = fmt.Errorf("Not yet implemented")
diff --git a/java/app.go b/java/app.go
index 2f2b899..8a221ef 100644
--- a/java/app.go
+++ b/java/app.go
@@ -68,17 +68,14 @@
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
 
-	var deps []string
 	if !a.properties.No_standard_libraries {
 		switch a.deviceProperties.Sdk_version { // TODO: Res_sdk_version?
 		case "current", "system_current", "":
-			deps = append(deps, "framework-res")
+			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
 		default:
 			// We'll already have a dependency on an sdk prebuilt android.jar
 		}
 	}
-
-	ctx.AddDependency(ctx.Module(), nil, deps...)
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -237,7 +234,7 @@
 		var depFile android.OptionalPath
 		if sdkDep, ok := module.(sdkDependency); ok {
 			depFile = android.OptionalPathForPath(sdkDep.ClasspathFile())
-		} else if javaDep, ok := module.(JavaDependency); ok {
+		} else if javaDep, ok := module.(Dependency); ok {
 			if ctx.OtherModuleName(module) == "framework-res" {
 				depFile = android.OptionalPathForPath(javaDep.(*AndroidApp).exportPackage)
 			}
diff --git a/java/builder.go b/java/builder.go
index 041c303..ed9d82c 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -40,7 +40,7 @@
 	javac = pctx.AndroidGomaStaticRule("javac",
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-				`${config.JavacWrapper}$javacCmd ` +
+				`${JavacWrapper}$javacCmd ` +
 				`-encoding UTF-8 $javacFlags $bootClasspath $classpath ` +
 				`-extdirs "" -d $outDir @$out.rsp || ( rm -rf "$outDir"; exit 41 ) && ` +
 				`find $outDir -name "*.class" > $out`,
diff --git a/java/java.go b/java/java.go
index 3cc552f..1ef1c26 100644
--- a/java/java.go
+++ b/java/java.go
@@ -30,13 +30,15 @@
 )
 
 func init() {
-	android.RegisterModuleType("java_library", JavaLibraryFactory)
-	android.RegisterModuleType("java_library_static", JavaLibraryFactory)
-	android.RegisterModuleType("java_library_host", JavaLibraryHostFactory)
-	android.RegisterModuleType("java_binary", JavaBinaryFactory)
-	android.RegisterModuleType("java_binary_host", JavaBinaryHostFactory)
-	android.RegisterModuleType("prebuilt_java_library", JavaPrebuiltFactory)
-	android.RegisterModuleType("prebuilt_sdk", SdkPrebuiltFactory)
+	android.RegisterModuleType("java_defaults", defaultsFactory)
+
+	android.RegisterModuleType("java_library", LibraryFactory)
+	android.RegisterModuleType("java_library_static", LibraryFactory)
+	android.RegisterModuleType("java_library_host", LibraryHostFactory)
+	android.RegisterModuleType("java_binary", BinaryFactory)
+	android.RegisterModuleType("java_binary_host", BinaryHostFactory)
+	android.RegisterModuleType("java_prebuilt_library", PrebuiltFactory)
+	android.RegisterModuleType("android_prebuilt_sdk", SdkPrebuiltFactory)
 	android.RegisterModuleType("android_app", AndroidAppFactory)
 
 	android.RegisterSingletonType("logtags", LogtagsSingleton)
@@ -55,7 +57,7 @@
 // DroidDoc
 // Findbugs
 
-type compilerProperties struct {
+type CompilerProperties struct {
 	// list of source files used to compile the Java module.  May be .java, .logtags, .proto,
 	// or .aidl files.
 	Srcs []string `android:"arch_variant"`
@@ -65,10 +67,10 @@
 	Exclude_srcs []string `android:"arch_variant"`
 
 	// list of directories containing Java resources
-	Java_resource_dirs []string `android:"arch_variant"`
+	Resource_dirs []string `android:"arch_variant"`
 
-	// list of directories that should be excluded from java_resource_dirs
-	Exclude_java_resource_dirs []string `android:"arch_variant"`
+	// list of directories that should be excluded from resource_dirs
+	Exclude_resource_dirs []string `android:"arch_variant"`
 
 	// don't build against the default libraries (legacy-test, core-junit,
 	// ext, and framework for device targets)
@@ -78,10 +80,10 @@
 	Javacflags []string `android:"arch_variant"`
 
 	// list of of java libraries that will be in the classpath
-	Java_libs []string `android:"arch_variant"`
+	Libs []string `android:"arch_variant"`
 
 	// list of java libraries that will be compiled into the resulting jar
-	Java_static_libs []string `android:"arch_variant"`
+	Static_libs []string `android:"arch_variant"`
 
 	// manifest file to be included in resulting jar
 	Manifest *string
@@ -90,7 +92,7 @@
 	Jarjar_rules *string
 }
 
-type compilerDeviceProperties struct {
+type CompilerDeviceProperties struct {
 	// list of module-specific flags that will be used for dex compiles
 	Dxflags []string `android:"arch_variant"`
 
@@ -112,9 +114,10 @@
 // Module contains the properties and members used by all java module types
 type Module struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
-	properties       compilerProperties
-	deviceProperties compilerDeviceProperties
+	properties       CompilerProperties
+	deviceProperties CompilerDeviceProperties
 
 	// output file suitable for inserting into the classpath of another compile
 	classpathFile android.Path
@@ -140,52 +143,58 @@
 	installFile android.Path
 }
 
-type JavaDependency interface {
+type Dependency interface {
 	ClasspathFile() android.Path
 	ClassJarSpecs() []jarSpec
 	ResourceJarSpecs() []jarSpec
 	AidlIncludeDirs() android.Paths
 }
 
-func (j *Module) BootClasspath(ctx android.BaseContext) string {
-	if ctx.Device() {
-		switch j.deviceProperties.Sdk_version {
-		case "":
-			return "core-libart"
-		case "current":
-			// TODO: !TARGET_BUILD_APPS
-			// TODO: export preprocessed framework.aidl from android_stubs_current
-			return "android_stubs_current"
-		case "system_current":
-			return "android_system_stubs_current"
-		default:
-			return "sdk_v" + j.deviceProperties.Sdk_version
-		}
-	} else {
-		if j.deviceProperties.Dex {
-			return "core-libart"
-		} else {
-			return ""
-		}
-	}
+func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
+	android.InitAndroidArchModule(module, hod, android.MultilibCommon)
+	android.InitDefaultableModule(module)
 }
 
-func (j *Module) deps(ctx android.BottomUpMutatorContext) {
-	var deps []string
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
 
+var (
+	staticLibTag     = dependencyTag{name: "staticlib"}
+	libTag           = dependencyTag{name: "javalib"}
+	bootClasspathTag = dependencyTag{name: "bootclasspath"}
+	frameworkResTag  = dependencyTag{name: "framework-res"}
+	sdkDependencyTag = dependencyTag{name: "sdk"}
+)
+
+func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if !j.properties.No_standard_libraries {
-		bootClasspath := j.BootClasspath(ctx)
-		if bootClasspath != "" {
-			deps = append(deps, bootClasspath)
+		if ctx.Device() {
+			switch j.deviceProperties.Sdk_version {
+			case "":
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+			case "current":
+				// TODO: !TARGET_BUILD_APPS
+				// TODO: export preprocessed framework.aidl from android_stubs_current
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_stubs_current")
+			case "system_current":
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_system_stubs_current")
+			default:
+				ctx.AddDependency(ctx.Module(), sdkDependencyTag, "sdk_v"+j.deviceProperties.Sdk_version)
+			}
+		} else {
+			if j.deviceProperties.Dex {
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+			}
 		}
+
 		if ctx.Device() && j.deviceProperties.Sdk_version == "" {
-			deps = append(deps, config.DefaultLibraries...)
+			ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
 		}
 	}
-	deps = append(deps, j.properties.Java_libs...)
-	deps = append(deps, j.properties.Java_static_libs...)
-
-	ctx.AddDependency(ctx.Module(), nil, deps...)
+	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
+	ctx.AddDependency(ctx.Module(), staticLibTag, j.properties.Static_libs...)
 }
 
 func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
@@ -203,7 +212,9 @@
 	flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
 	flags = append(flags, android.JoinWithPrefix(localAidlIncludes.Strings(), "-I"))
 	flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
-	flags = append(flags, "-I"+android.PathForModuleSrc(ctx, "src").String())
+	if src := android.ExistentPathForSource(ctx, "", "src"); src.Valid() {
+		flags = append(flags, "-I"+src.String())
+	}
 
 	return flags
 }
@@ -214,38 +225,48 @@
 
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		otherName := ctx.OtherModuleName(module)
-		if javaDep, ok := module.(JavaDependency); ok {
-			if otherName == j.BootClasspath(ctx) {
-				bootClasspath = android.OptionalPathForPath(javaDep.ClasspathFile())
-			} else if inList(otherName, config.DefaultLibraries) {
-				classpath = append(classpath, javaDep.ClasspathFile())
-			} else if inList(otherName, j.properties.Java_libs) {
-				classpath = append(classpath, javaDep.ClasspathFile())
-			} else if inList(otherName, j.properties.Java_static_libs) {
-				classpath = append(classpath, javaDep.ClasspathFile())
-				classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
-				resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
-			} else if otherName == "framework-res" {
-				if ctx.ModuleName() == "framework" {
-					// framework.jar has a one-off dependency on the R.java and Manifest.java files
-					// generated by framework-res.apk
-					srcFileLists = append(srcFileLists, module.(*AndroidApp).aaptJavaFileList)
-				}
-			} else {
-				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
+		tag := ctx.OtherModuleDependencyTag(module)
+
+		dep, _ := module.(Dependency)
+		if dep == nil {
+			switch tag {
+			case android.DefaultsDepTag, android.SourceDepTag:
+			default:
+				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
-			aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...)
-			if sdkDep, ok := module.(sdkDependency); ok {
-				if sdkDep.AidlPreprocessed().Valid() {
-					if aidlPreprocess.Valid() {
-						ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
-							aidlPreprocess, sdkDep.AidlPreprocessed())
-					} else {
-						aidlPreprocess = sdkDep.AidlPreprocessed()
-					}
-				}
-			}
+			return
 		}
+
+		switch tag {
+		case bootClasspathTag:
+			bootClasspath = android.OptionalPathForPath(dep.ClasspathFile())
+		case libTag:
+			classpath = append(classpath, dep.ClasspathFile())
+		case staticLibTag:
+			classpath = append(classpath, dep.ClasspathFile())
+			classJarSpecs = append(classJarSpecs, dep.ClassJarSpecs()...)
+			resourceJarSpecs = append(resourceJarSpecs, dep.ResourceJarSpecs()...)
+		case frameworkResTag:
+			if ctx.ModuleName() == "framework" {
+				// framework.jar has a one-off dependency on the R.java and Manifest.java files
+				// generated by framework-res.apk
+				srcFileLists = append(srcFileLists, module.(*AndroidApp).aaptJavaFileList)
+			}
+		case sdkDependencyTag:
+			sdkDep := module.(sdkDependency)
+			if sdkDep.AidlPreprocessed().Valid() {
+				if aidlPreprocess.Valid() {
+					ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
+						aidlPreprocess, sdkDep.AidlPreprocessed())
+				} else {
+					aidlPreprocess = sdkDep.AidlPreprocessed()
+				}
+			}
+		default:
+			panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
+		}
+
+		aidlIncludeDirs = append(aidlIncludeDirs, dep.AidlIncludeDirs()...)
 	})
 
 	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
@@ -273,16 +294,16 @@
 		flags.aidlFlags = "$aidlFlags"
 	}
 
-	var javacDeps android.Paths
+	var deps android.Paths
 
 	if bootClasspath.Valid() {
 		flags.bootClasspath = "-bootclasspath " + bootClasspath.String()
-		javacDeps = append(javacDeps, bootClasspath.Path())
+		deps = append(deps, bootClasspath.Path())
 	}
 
 	if len(classpath) > 0 {
 		flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":")
-		javacDeps = append(javacDeps, classpath...)
+		deps = append(deps, classpath...)
 	}
 
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
@@ -299,7 +320,7 @@
 
 	if len(srcFiles) > 0 {
 		// Compile java sources into .class files
-		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, javacDeps)
+		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, deps)
 		if ctx.Failed() {
 			return
 		}
@@ -307,7 +328,7 @@
 		classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
 	}
 
-	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs),
+	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs, j.properties.Exclude_resource_dirs),
 		resourceJarSpecs...)
 
 	manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
@@ -376,7 +397,7 @@
 	j.outputFile = outputFile
 }
 
-var _ JavaDependency = (*JavaLibrary)(nil)
+var _ Dependency = (*Library)(nil)
 
 func (j *Module) ClasspathFile() android.Path {
 	return j.classpathFile
@@ -404,22 +425,22 @@
 // Java libraries (.jar file)
 //
 
-type JavaLibrary struct {
+type Library struct {
 	Module
 }
 
-func (j *JavaLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.compile(ctx)
 
 	j.installFile = ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile)
 }
 
-func (j *JavaLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
 	j.deps(ctx)
 }
 
-func JavaLibraryFactory() android.Module {
-	module := &JavaLibrary{}
+func LibraryFactory() android.Module {
+	module := &Library{}
 
 	module.deviceProperties.Dex = true
 
@@ -427,16 +448,16 @@
 		&module.Module.properties,
 		&module.Module.deviceProperties)
 
-	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
 
-func JavaLibraryHostFactory() android.Module {
-	module := &JavaLibrary{}
+func LibraryHostFactory() android.Module {
+	module := &Library{}
 
 	module.AddProperties(&module.Module.properties)
 
-	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+	InitJavaModule(module, android.HostSupported)
 	return module
 }
 
@@ -444,19 +465,19 @@
 // Java Binaries (.jar file plus wrapper script)
 //
 
-type javaBinaryProperties struct {
+type binaryProperties struct {
 	// installable script to execute the resulting jar
 	Wrapper string
 }
 
-type JavaBinary struct {
-	JavaLibrary
+type Binary struct {
+	Library
 
-	binaryProperties javaBinaryProperties
+	binaryProperties binaryProperties
 }
 
-func (j *JavaBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.JavaLibrary.GenerateAndroidBuildActions(ctx)
+func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	j.Library.GenerateAndroidBuildActions(ctx)
 
 	// Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
 	// another build rule before the jar has been installed.
@@ -464,12 +485,12 @@
 		j.installFile)
 }
 
-func (j *JavaBinary) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	j.deps(ctx)
 }
 
-func JavaBinaryFactory() android.Module {
-	module := &JavaBinary{}
+func BinaryFactory() android.Module {
+	module := &Binary{}
 
 	module.deviceProperties.Dex = true
 
@@ -478,19 +499,19 @@
 		&module.Module.deviceProperties,
 		&module.binaryProperties)
 
-	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
 
-func JavaBinaryHostFactory() android.Module {
-	module := &JavaBinary{}
+func BinaryHostFactory() android.Module {
+	module := &Binary{}
 
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
 		&module.binaryProperties)
 
-	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+	InitJavaModule(module, android.HostSupported)
 	return module
 }
 
@@ -498,28 +519,23 @@
 // Java prebuilts
 //
 
-type javaPrebuiltProperties struct {
-	Srcs []string
-}
-
-type JavaPrebuilt struct {
+type Prebuilt struct {
 	android.ModuleBase
-
-	properties javaPrebuiltProperties
+	prebuilt android.Prebuilt
 
 	classpathFile                   android.Path
 	classJarSpecs, resourceJarSpecs []jarSpec
 }
 
-func (j *JavaPrebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (j *Prebuilt) Prebuilt() *android.Prebuilt {
+	return &j.prebuilt
 }
 
-func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if len(j.properties.Srcs) != 1 {
-		ctx.ModuleErrorf("expected exactly one jar in srcs")
-		return
-	}
-	prebuilt := android.PathForModuleSrc(ctx, j.properties.Srcs[0])
+func (j *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
+}
+
+func (j *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	prebuilt := j.prebuilt.Path(ctx)
 
 	classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt)
 
@@ -529,28 +545,28 @@
 	ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.classpathFile)
 }
 
-var _ JavaDependency = (*JavaPrebuilt)(nil)
+var _ Dependency = (*Prebuilt)(nil)
 
-func (j *JavaPrebuilt) ClasspathFile() android.Path {
+func (j *Prebuilt) ClasspathFile() android.Path {
 	return j.classpathFile
 }
 
-func (j *JavaPrebuilt) ClassJarSpecs() []jarSpec {
+func (j *Prebuilt) ClassJarSpecs() []jarSpec {
 	return j.classJarSpecs
 }
 
-func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec {
+func (j *Prebuilt) ResourceJarSpecs() []jarSpec {
 	return j.resourceJarSpecs
 }
 
-func (j *JavaPrebuilt) AidlIncludeDirs() android.Paths {
+func (j *Prebuilt) AidlIncludeDirs() android.Paths {
 	return nil
 }
 
-func JavaPrebuiltFactory() android.Module {
-	module := &JavaPrebuilt{}
+func PrebuiltFactory() android.Module {
+	module := &Prebuilt{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(&module.prebuilt.Properties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	return module
@@ -561,7 +577,7 @@
 //
 
 type sdkDependency interface {
-	JavaDependency
+	Dependency
 	AidlPreprocessed() android.OptionalPath
 }
 
@@ -572,7 +588,7 @@
 }
 
 type sdkPrebuilt struct {
-	JavaPrebuilt
+	Prebuilt
 
 	sdkProperties sdkPrebuiltProperties
 
@@ -580,7 +596,7 @@
 }
 
 func (j *sdkPrebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.JavaPrebuilt.GenerateAndroidBuildActions(ctx)
+	j.Prebuilt.GenerateAndroidBuildActions(ctx)
 
 	j.aidlPreprocessed = android.OptionalPathForModuleSrc(ctx, j.sdkProperties.Aidl_preprocessed)
 }
@@ -593,7 +609,7 @@
 	module := &sdkPrebuilt{}
 
 	module.AddProperties(
-		&module.properties,
+		&module.prebuilt.Properties,
 		&module.sdkProperties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
@@ -608,3 +624,35 @@
 	}
 	return false
 }
+
+//
+// Defaults
+//
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
+}
+
+func defaultsFactory() android.Module {
+	return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+	module := &Defaults{}
+
+	module.AddProperties(props...)
+	module.AddProperties(
+		&CompilerProperties{},
+		&CompilerDeviceProperties{},
+	)
+
+	android.InitDefaultsModule(module)
+
+	return module
+}
diff --git a/java/java_test.go b/java/java_test.go
new file mode 100644
index 0000000..3443610
--- /dev/null
+++ b/java/java_test.go
@@ -0,0 +1,285 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_java_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testJava(t *testing.T, bp string) *android.TestContext {
+	config := android.TestConfig(buildDir)
+
+	ctx := android.NewTestContext()
+	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory))
+	ctx.RegisterModuleType("java_prebuilt_library", android.ModuleFactoryAdaptor(PrebuiltFactory))
+	ctx.RegisterModuleType("java_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.Register()
+
+	extraModules := []string{"core-libart", "frameworks", "sdk_v14"}
+
+	for _, extra := range extraModules {
+		bp += fmt.Sprintf(`
+			java_library {
+				name: "%s",
+				no_standard_libraries: true,
+			}
+		`, extra)
+	}
+
+	ctx.MockFileSystem(map[string][]byte{
+		"Android.bp": []byte(bp),
+		"a.java":     nil,
+		"b.java":     nil,
+		"c.java":     nil,
+		"a.jar":      nil,
+		"b.jar":      nil,
+	})
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	fail(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	fail(t, errs)
+
+	return ctx
+}
+
+func TestSimple(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			libs: ["bar"],
+			static_libs: ["baz"],
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["c.java"],
+		}
+		`)
+
+	javac := ctx.ModuleForTests("foo", "").Rule("javac")
+	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+
+	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	}
+
+	bar := filepath.Join(buildDir, ".intermediates", "bar", "classes-full-debug.jar")
+	if !strings.Contains(javac.Args["classpath"], bar) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	}
+
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.list")
+	if !strings.Contains(jar.Args["jarArgs"], baz) {
+		t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+	}
+}
+
+func TestSdk(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo1",
+			srcs: ["a.java"],
+		}
+
+		java_library {
+			name: "foo2",
+			srcs: ["a.java"],
+			sdk_version: "",
+		}
+
+		java_library {
+			name: "foo3",
+			srcs: ["a.java"],
+			sdk_version: "14",
+		}
+
+		java_library {
+			name: "foo4",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+
+		java_library {
+			name: "foo5",
+			srcs: ["a.java"],
+			sdk_version: "system_current",
+		}
+
+		java_library {
+			name: "foo6",
+			srcs: ["a.java"],
+			sdk_version: "test_current",
+		}
+		`)
+
+	type depType int
+	const (
+		staticLib = iota
+		classpathLib
+		bootclasspathLib
+	)
+
+	check := func(module, dep string, depType depType) {
+		if dep != "" {
+			dep = filepath.Join(buildDir, ".intermediates", dep, "classes-full-debug.jar")
+		}
+
+		javac := ctx.ModuleForTests(module, "").Rule("javac")
+
+		if depType == bootclasspathLib {
+			got := strings.TrimPrefix(javac.Args["bootClasspath"], "-bootclasspath ")
+			if got != dep {
+				t.Errorf("module %q bootclasspath %q != %q", module, got, dep)
+			}
+		} else if depType == classpathLib {
+			got := strings.TrimPrefix(javac.Args["classpath"], "-classpath ")
+			if got != dep {
+				t.Errorf("module %q classpath %q != %q", module, got, dep)
+			}
+		}
+
+		if len(javac.Implicits) != 1 || javac.Implicits[0].String() != dep {
+			t.Errorf("module %q implicits != [%q]", dep)
+		}
+	}
+
+	check("foo1", "core-libart", bootclasspathLib)
+}
+
+func TestPrebuilts(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			libs: ["bar"],
+			static_libs: ["baz"],
+		}
+
+		java_prebuilt_library {
+			name: "bar",
+			srcs: ["a.jar"],
+		}
+
+		java_prebuilt_library {
+			name: "baz",
+			srcs: ["b.jar"],
+		}
+		`)
+
+	javac := ctx.ModuleForTests("foo", "").Rule("javac")
+	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+
+	bar := "a.jar"
+	if !strings.Contains(javac.Args["classpath"], bar) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	}
+
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "extracted", "classes.list")
+	if !strings.Contains(jar.Args["jarArgs"], baz) {
+		t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+	}
+}
+
+func TestDefaults(t *testing.T) {
+	ctx := testJava(t, `
+		java_defaults {
+			name: "defaults",
+			srcs: ["a.java"],
+			libs: ["bar"],
+			static_libs: ["baz"],
+		}
+
+		java_library {
+			name: "foo",
+			defaults: ["defaults"],
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["c.java"],
+		}
+		`)
+
+	javac := ctx.ModuleForTests("foo", "").Rule("javac")
+	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+
+	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	}
+
+	bar := filepath.Join(buildDir, ".intermediates", "bar", "classes-full-debug.jar")
+	if !strings.Contains(javac.Args["classpath"], bar) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	}
+
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.list")
+	if !strings.Contains(jar.Args["jarArgs"], baz) {
+		t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+	}
+}
+
+func fail(t *testing.T, errs []error) {
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Error(err)
+		}
+		t.FailNow()
+	}
+}
diff --git a/python/python_test.go b/python/python_test.go
index 57aaa34..4c30d95 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -26,8 +26,6 @@
 	"testing"
 
 	"android/soong/android"
-
-	"github.com/google/blueprint"
 )
 
 type pyBinary struct {
@@ -306,17 +304,17 @@
 func TestPythonModule(t *testing.T) {
 	config, buildDir := setupBuildEnv(t)
 	defer tearDownBuildEnv(buildDir)
-	android.TestPreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
-	})
 	for _, d := range data {
 		t.Run(d.desc, func(t *testing.T) {
-			ctx := blueprint.NewContext()
-			android.RegisterTestMutators(ctx)
+			ctx := android.NewTestContext()
+			ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+				ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
+			})
 			ctx.RegisterModuleType("python_library_host",
 				android.ModuleFactoryAdaptor(PythonLibraryHostFactory))
 			ctx.RegisterModuleType("python_binary_host",
 				android.ModuleFactoryAdaptor(PythonBinaryHostFactory))
+			ctx.Register()
 			ctx.MockFileSystem(d.mockFiles)
 			_, testErrs := ctx.ParseBlueprintsFiles(bpFile)
 			fail(t, testErrs)
@@ -360,15 +358,12 @@
 	return
 }
 
-func expectModule(t *testing.T, ctx *blueprint.Context, buildDir, name, variant string,
+func expectModule(t *testing.T, ctx *android.TestContext, buildDir, name, variant string,
 	expPyRunfiles, expDepsPyRunfiles []string,
 	expParSpec string, expDepsParSpecs []string) (testErrs []error) {
-	module := findModule(ctx, name, variant)
-	if module == nil {
-		t.Fatalf("failed to find module %s!", name)
-	}
+	module := ctx.ModuleForTests(name, variant)
 
-	base, baseOk := module.(*pythonBaseModule)
+	base, baseOk := module.Module().(*pythonBaseModule)
 	if !baseOk {
 		t.Fatalf("%s is not Python module!", name)
 	}
@@ -438,16 +433,6 @@
 	os.RemoveAll(buildDir)
 }
 
-func findModule(ctx *blueprint.Context, name, variant string) blueprint.Module {
-	var ret blueprint.Module
-	ctx.VisitAllModules(func(m blueprint.Module) {
-		if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant {
-			ret = m
-		}
-	})
-	return ret
-}
-
 func fail(t *testing.T, errs []error) {
 	if len(errs) > 0 {
 		for _, err := range errs {
diff --git a/scripts/microfactory.bash b/scripts/microfactory.bash
new file mode 100644
index 0000000..65ba55d
--- /dev/null
+++ b/scripts/microfactory.bash
@@ -0,0 +1,66 @@
+# 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.
+
+# Set of utility functions to build and run go code with microfactory
+#
+# Inputs:
+#  ${TOP}: The top of the android source tree
+#  ${OUT_DIR}: The output directory location (defaults to ${TOP}/out)
+#  ${OUT_DIR_COMMON_BASE}: Change the default out directory to
+#    ${OUT_DIR_COMMON_BASE}/$(basename ${TOP})
+
+# Ensure GOROOT is set to the in-tree version.
+case $(uname) in
+    Linux)
+        export GOROOT="${TOP}/prebuilts/go/linux-x86/"
+        ;;
+    Darwin)
+        export GOROOT="${TOP}/prebuilts/go/darwin-x86/"
+        ;;
+    *) echo "unknown OS:" $(uname) >&2 && exit 1;;
+esac
+
+# Find the output directory
+function getoutdir
+{
+    local out_dir="${OUT_DIR-}"
+    if [ -z "${out_dir}" ]; then
+        if [ "${OUT_DIR_COMMON_BASE-}" ]; then
+            out_dir="${OUT_DIR_COMMON_BASE}/$(basename ${TOP})"
+        else
+            out_dir="out"
+        fi
+    fi
+    if [[ "${out_dir}" != /* ]]; then
+        out_dir="${TOP}/${out_dir}"
+    fi
+    echo "${out_dir}"
+}
+
+# Bootstrap microfactory from source if necessary and use it to build the
+# requested binary.
+#
+# Arguments:
+#  $1: name of the requested binary
+#  $2: package name
+function soong_build_go
+{
+    BUILDDIR=$(getoutdir) \
+      SRCDIR=${TOP} \
+      BLUEPRINTDIR=${TOP}/build/blueprint \
+      EXTRA_ARGS="-pkg-path android/soong=${TOP}/build/soong" \
+      build_go $@
+}
+
+source ${TOP}/build/blueprint/microfactory/microfactory.bash
diff --git a/soong_ui.bash b/soong_ui.bash
index 105af9f..a39aa9c 100755
--- a/soong_ui.bash
+++ b/soong_ui.bash
@@ -47,8 +47,12 @@
     fi
 }
 
+# Save the current PWD for use in soong_ui
+export ORIGINAL_PWD=${PWD}
 export TOP=$(gettop)
-source build/soong/cmd/microfactory/microfactory.bash
+source ${TOP}/build/soong/scripts/microfactory.bash
 
-build_go soong_ui android/soong/cmd/soong_ui
+soong_build_go soong_ui android/soong/cmd/soong_ui
+
+cd ${TOP}
 exec "$(getoutdir)/soong_ui" "$@"
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 489c06d..548baee 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -27,7 +27,6 @@
         "context.go",
         "environment.go",
         "exec.go",
-        "java.go",
         "kati.go",
         "make.go",
         "ninja.go",
@@ -37,6 +36,7 @@
         "util.go",
     ],
     testSrcs: [
+        "config_test.go",
         "environment_test.go",
         "util_test.go",
         "proc_sync_test.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 1400c48..32f4ba5 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -114,9 +114,6 @@
 		return
 	}
 
-	// Start getting java version as early as possible
-	getJavaVersions(ctx, config)
-
 	// Make sure that no other Soong process is running with the same output directory
 	buildLock := BecomeSingletonOrFail(ctx, config)
 	defer buildLock.Unlock()
@@ -148,9 +145,6 @@
 		runSoong(ctx, config)
 	}
 
-	// Check the java versions we read earlier
-	checkJavaVersion(ctx, config)
-
 	if what&BuildKati != 0 {
 		// Run ckati
 		runKati(ctx, config)
diff --git a/ui/build/config.go b/ui/build/config.go
index 16826f2..ef06157 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -53,6 +53,12 @@
 		environ: OsEnvironment(),
 	}
 
+	// Sane default matching ninja
+	ret.parallel = runtime.NumCPU() + 2
+	ret.keepGoing = 1
+
+	ret.parseArgs(ctx, args)
+
 	// Make sure OUT_DIR is set appropriately
 	if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
 		ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
@@ -92,15 +98,16 @@
 		// Variables that have caused problems in the past
 		"DISPLAY",
 		"GREP_OPTIONS",
+
+		// Drop make flags
+		"MAKEFLAGS",
+		"MAKELEVEL",
+		"MFLAGS",
 	)
 
 	// Tell python not to spam the source tree with .pyc files.
 	ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
 
-	// Sane default matching ninja
-	ret.parallel = runtime.NumCPU() + 2
-	ret.keepGoing = 1
-
 	// Precondition: the current directory is the top of the source tree
 	if _, err := os.Stat(srcDirFileCheck); err != nil {
 		if os.IsNotExist(err) {
@@ -135,38 +142,51 @@
 		log.Fatalln("Directory names containing spaces are not supported")
 	}
 
-	for _, arg := range args {
-		arg = strings.TrimSpace(arg)
+	return Config{ret}
+}
+
+func (c *configImpl) parseArgs(ctx Context, args []string) {
+	for i := 0; i < len(args); i++ {
+		arg := strings.TrimSpace(args[i])
 		if arg == "--make-mode" {
 			continue
 		} else if arg == "showcommands" {
-			ret.verbose = true
+			c.verbose = true
 			continue
 		} else if arg == "dist" {
-			ret.dist = true
+			c.dist = true
 		}
 		if arg[0] == '-' {
-			var err error
+			parseArgNum := func(def int) int {
+				if len(arg) > 2 {
+					p, err := strconv.ParseUint(arg[2:], 10, 31)
+					if err != nil {
+						ctx.Fatalf("Failed to parse %q: %v", arg, err)
+					}
+					return int(p)
+				} else if i+1 < len(args) {
+					p, err := strconv.ParseUint(args[i+1], 10, 31)
+					if err == nil {
+						i++
+						return int(p)
+					}
+				}
+				return def
+			}
+
 			if arg[1] == 'j' {
-				// TODO: handle space between j and number
-				// Unnecessary if used with makeparallel
-				ret.parallel, err = strconv.Atoi(arg[2:])
+				c.parallel = parseArgNum(c.parallel)
 			} else if arg[1] == 'k' {
-				// TODO: handle space between k and number
-				// Unnecessary if used with makeparallel
-				ret.keepGoing, err = strconv.Atoi(arg[2:])
+				c.keepGoing = parseArgNum(0)
 			} else {
 				ctx.Fatalln("Unknown option:", arg)
 			}
-			if err != nil {
-				ctx.Fatalln("Argument error:", err, arg)
-			}
+		} else if k, v, ok := decodeKeyValue(arg); ok && len(k) > 0 {
+			c.environ.Set(k, v)
 		} else {
-			ret.arguments = append(ret.arguments, arg)
+			c.arguments = append(c.arguments, arg)
 		}
 	}
-
-	return Config{ret}
 }
 
 // Lunch configures the environment for a specific product similarly to the
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
new file mode 100644
index 0000000..e4eab94
--- /dev/null
+++ b/ui/build/config_test.go
@@ -0,0 +1,174 @@
+// 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 (
+	"bytes"
+	"context"
+	"reflect"
+	"strings"
+	"testing"
+
+	"android/soong/ui/logger"
+)
+
+func testContext() Context {
+	return Context{&ContextImpl{
+		Context:        context.Background(),
+		Logger:         logger.New(&bytes.Buffer{}),
+		StdioInterface: NewCustomStdio(&bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}),
+	}}
+}
+
+func TestConfigParseArgsJK(t *testing.T) {
+	ctx := testContext()
+
+	testCases := []struct {
+		args []string
+
+		parallel  int
+		keepGoing int
+		remaining []string
+	}{
+		{nil, -1, -1, nil},
+
+		{[]string{"-j"}, -1, -1, nil},
+		{[]string{"-j1"}, 1, -1, nil},
+		{[]string{"-j1234"}, 1234, -1, nil},
+
+		{[]string{"-j", "1"}, 1, -1, nil},
+		{[]string{"-j", "1234"}, 1234, -1, nil},
+		{[]string{"-j", "1234", "abc"}, 1234, -1, []string{"abc"}},
+		{[]string{"-j", "abc"}, -1, -1, []string{"abc"}},
+		{[]string{"-j", "1abc"}, -1, -1, []string{"1abc"}},
+
+		{[]string{"-k"}, -1, 0, nil},
+		{[]string{"-k0"}, -1, 0, nil},
+		{[]string{"-k1"}, -1, 1, nil},
+		{[]string{"-k1234"}, -1, 1234, nil},
+
+		{[]string{"-k", "0"}, -1, 0, nil},
+		{[]string{"-k", "1"}, -1, 1, nil},
+		{[]string{"-k", "1234"}, -1, 1234, nil},
+		{[]string{"-k", "1234", "abc"}, -1, 1234, []string{"abc"}},
+		{[]string{"-k", "abc"}, -1, 0, []string{"abc"}},
+		{[]string{"-k", "1abc"}, -1, 0, []string{"1abc"}},
+
+		// TODO: These are supported in Make, should we support them?
+		//{[]string{"-kj"}, -1, 0},
+		//{[]string{"-kj8"}, 8, 0},
+
+		// -jk is not valid in Make
+	}
+
+	for _, tc := range testCases {
+		t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				t.Fatal(err)
+			})
+
+			c := &configImpl{
+				parallel:  -1,
+				keepGoing: -1,
+			}
+			c.parseArgs(ctx, tc.args)
+
+			if c.parallel != tc.parallel {
+				t.Errorf("for %q, parallel:\nwant: %d\n got: %d\n",
+					strings.Join(tc.args, " "),
+					tc.parallel, c.parallel)
+			}
+			if c.keepGoing != tc.keepGoing {
+				t.Errorf("for %q, keep going:\nwant: %d\n got: %d\n",
+					strings.Join(tc.args, " "),
+					tc.keepGoing, c.keepGoing)
+			}
+			if !reflect.DeepEqual(c.arguments, tc.remaining) {
+				t.Errorf("for %q, remaining arguments:\nwant: %q\n got: %q\n",
+					strings.Join(tc.args, " "),
+					tc.remaining, c.arguments)
+			}
+		})
+	}
+}
+
+func TestConfigParseArgsVars(t *testing.T) {
+	ctx := testContext()
+
+	testCases := []struct {
+		env  []string
+		args []string
+
+		expectedEnv []string
+		remaining   []string
+	}{
+		{},
+		{
+			env: []string{"A=bc"},
+
+			expectedEnv: []string{"A=bc"},
+		},
+		{
+			args: []string{"abc"},
+
+			remaining: []string{"abc"},
+		},
+
+		{
+			args: []string{"A=bc"},
+
+			expectedEnv: []string{"A=bc"},
+		},
+		{
+			env:  []string{"A=a"},
+			args: []string{"A=bc"},
+
+			expectedEnv: []string{"A=bc"},
+		},
+
+		{
+			env:  []string{"A=a"},
+			args: []string{"A=", "=b"},
+
+			expectedEnv: []string{"A="},
+			remaining:   []string{"=b"},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				t.Fatal(err)
+			})
+
+			e := Environment(tc.env)
+			c := &configImpl{
+				environ: &e,
+			}
+			c.parseArgs(ctx, tc.args)
+
+			if !reflect.DeepEqual([]string(*c.environ), tc.expectedEnv) {
+				t.Errorf("for env=%q args=%q, environment:\nwant: %q\n got: %q\n",
+					tc.env, tc.args,
+					tc.expectedEnv, []string(*c.environ))
+			}
+			if !reflect.DeepEqual(c.arguments, tc.remaining) {
+				t.Errorf("for env=%q args=%q, remaining arguments:\nwant: %q\n got: %q\n",
+					tc.env, tc.args,
+					tc.remaining, c.arguments)
+			}
+		})
+	}
+}
diff --git a/ui/build/java.go b/ui/build/java.go
deleted file mode 100644
index 473af01..0000000
--- a/ui/build/java.go
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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 (
-	"regexp"
-	"runtime"
-	"strings"
-	"sync"
-)
-
-const incompatibleJavacStr = "google"
-
-var javaVersionInfo = struct {
-	once      sync.Once
-	startOnce sync.Once
-
-	java_version_output  string
-	javac_version_output string
-}{}
-
-func getJavaVersions(ctx Context, config Config) {
-	javaVersionInfo.startOnce.Do(func() {
-		go func() {
-			if ctx.Tracer != nil {
-				thread := ctx.Tracer.NewThread("java_version")
-				ctx.Tracer.Begin("get version", thread)
-				defer ctx.Tracer.End(thread)
-			}
-
-			getJavaVersionsImpl(ctx, config)
-		}()
-	})
-}
-
-func getJavaVersionsImpl(ctx Context, config Config) {
-	javaVersionInfo.once.Do(func() {
-		cmd := Command(ctx, config, "java", "java", "-version")
-		cmd.Environment.Unset("_JAVA_OPTIONS")
-		javaVersionInfo.java_version_output = string(cmd.CombinedOutputOrFatal())
-
-		cmd = Command(ctx, config, "javac", "javac", "-version")
-		cmd.Environment.Unset("_JAVA_OPTIONS")
-		javaVersionInfo.javac_version_output = string(cmd.CombinedOutputOrFatal())
-	})
-}
-
-func checkJavaVersion(ctx Context, config Config) {
-	ctx.BeginTrace("java_version_check")
-	defer ctx.EndTrace()
-
-	getJavaVersionsImpl(ctx, config)
-
-	var required_java_version string
-	var java_version_regexp *regexp.Regexp
-	var javac_version_regexp *regexp.Regexp
-
-	oj9_env, _ := config.Environment().Get("EXPERIMENTAL_USE_OPENJDK9")
-	experimental_use_openjdk9 := oj9_env != ""
-
-	if experimental_use_openjdk9 {
-		required_java_version = "9"
-		java_version_regexp = regexp.MustCompile(`^java .* "9.*"`)
-		javac_version_regexp = regexp.MustCompile(`^javac 9`)
-	} else {
-		required_java_version = "1.8"
-		java_version_regexp = regexp.MustCompile(`[ "]1\.8[\. "$]`)
-		javac_version_regexp = java_version_regexp
-	}
-
-	java_version := javaVersionInfo.java_version_output
-	javac_version := javaVersionInfo.javac_version_output
-
-	found := false
-	for _, l := range strings.Split(java_version, "\n") {
-		if java_version_regexp.MatchString(l) {
-			java_version = l
-			found = true
-			break
-		}
-	}
-	if !found {
-		ctx.Println("***************************************************************")
-		ctx.Println("You are attempting to build with the incorrect version of java.")
-		ctx.Println()
-		ctx.Println("Your version is:", java_version)
-		ctx.Println("The required version is:", required_java_version+".x")
-		ctx.Println()
-		ctx.Println("Please follow the machine setup instructions at:")
-		ctx.Println("    https://source.android.com/source/initializing.html")
-		ctx.Println("***************************************************************")
-		ctx.Fatalln("stop")
-	}
-
-	if runtime.GOOS == "linux" {
-		// Early access builds of OpenJDK 9 do not contain the string "openjdk" in the
-		// version name. TODO(tobiast): Reconsider once the OpenJDK 9 toolchain is stable.
-		// http://b/62123342
-		if !strings.Contains(java_version, "openjdk") && !experimental_use_openjdk9 {
-			ctx.Println("*******************************************************")
-			ctx.Println("You are attempting to build with an unsupported JDK.")
-			ctx.Println()
-			ctx.Println("Only an OpenJDK based JDK is supported.")
-			ctx.Println()
-			ctx.Println("Please follow the machine setup instructions at:")
-			ctx.Println("    https://source.android.com/source/initializing.html")
-			ctx.Println("*******************************************************")
-			ctx.Fatalln("stop")
-		}
-	} else { // darwin
-		if strings.Contains(java_version, "openjdk") {
-			ctx.Println("*******************************************************")
-			ctx.Println("You are attempting to build with an unsupported JDK.")
-			ctx.Println()
-			ctx.Println("You use OpenJDK, but only Sun/Oracle JDK is supported.")
-			ctx.Println()
-			ctx.Println("Please follow the machine setup instructions at:")
-			ctx.Println("    https://source.android.com/source/initializing.html")
-			ctx.Println("*******************************************************")
-			ctx.Fatalln("stop")
-		}
-	}
-
-	incompatible_javac := strings.Contains(javac_version, incompatibleJavacStr)
-
-	found = false
-	for _, l := range strings.Split(javac_version, "\n") {
-		if javac_version_regexp.MatchString(l) {
-			javac_version = l
-			found = true
-			break
-		}
-	}
-	if !found || incompatible_javac {
-		ctx.Println("****************************************************************")
-		ctx.Println("You are attempting to build with the incorrect version of javac.")
-		ctx.Println()
-		ctx.Println("Your version is:", javac_version)
-		if incompatible_javac {
-			ctx.Println("The '" + incompatibleJavacStr + "' version is not supported for Android platform builds.")
-			ctx.Println("Use a publically available JDK and make sure you have run envsetup.sh / lunch.")
-		} else {
-			ctx.Println("The required version is:", required_java_version)
-		}
-		ctx.Println()
-		ctx.Println("Please follow the machine setup instructions at:")
-		ctx.Println("    https://source.android.com/source/initializing.html")
-		ctx.Println("****************************************************************")
-		ctx.Fatalln("stop")
-	}
-}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index ddfe666..d242805 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -24,6 +24,7 @@
 
 	cmd := Command(ctx, config, "soong bootstrap", "./bootstrap.bash")
 	cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
+	cmd.Environment.Set("NINJA_BUILDDIR", config.OutDir())
 	cmd.Sandbox = soongSandbox
 	cmd.Stdout = ctx.Stdout()
 	cmd.Stderr = ctx.Stderr()
diff --git a/ui/tracer/Android.bp b/ui/tracer/Android.bp
index 89812a1..9729c7e 100644
--- a/ui/tracer/Android.bp
+++ b/ui/tracer/Android.bp
@@ -17,6 +17,7 @@
     pkgPath: "android/soong/ui/tracer",
     deps: ["soong-ui-logger"],
     srcs: [
+        "microfactory.go",
         "ninja.go",
         "tracer.go",
     ],
diff --git a/ui/tracer/microfactory.go b/ui/tracer/microfactory.go
new file mode 100644
index 0000000..320d9d8
--- /dev/null
+++ b/ui/tracer/microfactory.go
@@ -0,0 +1,63 @@
+// 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 tracer
+
+import (
+	"bufio"
+	"os"
+	"strconv"
+	"strings"
+)
+
+func (t *tracerImpl) ImportMicrofactoryLog(filename string) {
+	if _, err := os.Stat(filename); err != nil {
+		return
+	}
+
+	f, err := os.Open(filename)
+	if err != nil {
+		t.log.Println("Error opening microfactory trace:", err)
+		return
+	}
+	defer f.Close()
+
+	entries := []*eventEntry{}
+	begin := map[string][]uint64{}
+	s := bufio.NewScanner(f)
+	for s.Scan() {
+		fields := strings.SplitN(s.Text(), " ", 3)
+		if len(fields) != 3 {
+			t.log.Verboseln("Unknown line in microfactory trace:", s.Text())
+			continue
+		}
+		timestamp, err := strconv.ParseUint(fields[0], 10, 64)
+		if err != nil {
+			t.log.Verboseln("Failed to parse timestamp in microfactory trace:", err)
+		}
+
+		if fields[1] == "B" {
+			begin[fields[2]] = append(begin[fields[2]], timestamp)
+		} else if beginTimestamps, ok := begin[fields[2]]; ok {
+			entries = append(entries, &eventEntry{
+				Name:  fields[2],
+				Begin: beginTimestamps[len(beginTimestamps)-1],
+				End:   timestamp,
+			})
+			begin[fields[2]] = beginTimestamps[:len(beginTimestamps)-1]
+		}
+	}
+
+	t.importEvents(entries)
+}
diff --git a/ui/tracer/ninja.go b/ui/tracer/ninja.go
index da558f1..1980559 100644
--- a/ui/tracer/ninja.go
+++ b/ui/tracer/ninja.go
@@ -23,16 +23,42 @@
 	"time"
 )
 
-type ninjaLogEntry struct {
+type eventEntry struct {
 	Name  string
-	Begin int
-	End   int
+	Begin uint64
+	End   uint64
 }
-type ninjaLogEntries []*ninjaLogEntry
 
-func (n ninjaLogEntries) Len() int           { return len(n) }
-func (n ninjaLogEntries) Less(i, j int) bool { return n[i].Begin < n[j].Begin }
-func (n ninjaLogEntries) Swap(i, j int)      { n[i], n[j] = n[j], n[i] }
+func (t *tracerImpl) importEvents(entries []*eventEntry) {
+	sort.Slice(entries, func(i, j int) bool {
+		return entries[i].Begin < entries[j].Begin
+	})
+
+	cpus := []uint64{}
+	for _, entry := range entries {
+		tid := -1
+		for cpu, endTime := range cpus {
+			if endTime <= entry.Begin {
+				tid = cpu
+				cpus[cpu] = entry.End
+				break
+			}
+		}
+		if tid == -1 {
+			tid = len(cpus)
+			cpus = append(cpus, entry.End)
+		}
+
+		t.writeEvent(&viewerEvent{
+			Name:  entry.Name,
+			Phase: "X",
+			Time:  entry.Begin,
+			Dur:   entry.End - entry.Begin,
+			Pid:   1,
+			Tid:   uint64(tid),
+		})
+	}
+}
 
 // ImportNinjaLog reads a .ninja_log file from ninja and writes the events out
 // to the trace.
@@ -61,8 +87,9 @@
 
 	s := bufio.NewScanner(f)
 	header := true
-	entries := ninjaLogEntries{}
+	entries := []*eventEntry{}
 	prevEnd := 0
+	offset := uint64(startOffset.UnixNano()) / 1000
 	for s.Scan() {
 		if header {
 			hdr := s.Text()
@@ -89,10 +116,10 @@
 			entries = nil
 		}
 		prevEnd = end
-		entries = append(entries, &ninjaLogEntry{
+		entries = append(entries, &eventEntry{
 			Name:  fields[3],
-			Begin: begin,
-			End:   end,
+			Begin: offset + uint64(begin)*1000,
+			End:   offset + uint64(end)*1000,
 		})
 	}
 	if err := s.Err(); err != nil {
@@ -100,31 +127,5 @@
 		return
 	}
 
-	sort.Sort(entries)
-
-	cpus := []int{}
-	offset := uint64(startOffset.UnixNano()) / 1000
-	for _, entry := range entries {
-		tid := -1
-		for cpu, endTime := range cpus {
-			if endTime <= entry.Begin {
-				tid = cpu
-				cpus[cpu] = entry.End
-				break
-			}
-		}
-		if tid == -1 {
-			tid = len(cpus)
-			cpus = append(cpus, entry.End)
-		}
-
-		t.writeEvent(&viewerEvent{
-			Name:  entry.Name,
-			Phase: "X",
-			Time:  offset + uint64(entry.Begin)*1000,
-			Dur:   uint64(entry.End-entry.Begin) * 1000,
-			Pid:   1,
-			Tid:   uint64(tid),
-		})
-	}
+	t.importEvents(entries)
 }
diff --git a/ui/tracer/tracer.go b/ui/tracer/tracer.go
index f19ac18..8705040 100644
--- a/ui/tracer/tracer.go
+++ b/ui/tracer/tracer.go
@@ -45,6 +45,7 @@
 	End(thread Thread)
 	Complete(name string, thread Thread, begin, end uint64)
 
+	ImportMicrofactoryLog(filename string)
 	ImportNinjaLog(thread Thread, filename string, startOffset time.Time)
 
 	NewThread(name string) Thread