Merge "Add support for thin LTO"
diff --git a/Android.bp b/Android.bp
index cc28c98..0875a2b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -53,6 +53,7 @@
         "android/package_ctx.go",
         "android/paths.go",
         "android/prebuilt.go",
+        "android/proto.go",
         "android/register.go",
         "android/testing.go",
         "android/util.go",
@@ -222,6 +223,7 @@
     ],
     srcs: [
         "java/config/config.go",
+        "java/config/error_prone.go",
         "java/config/makevars.go",
     ],
 }
@@ -237,6 +239,7 @@
         "python/androidmk.go",
         "python/binary.go",
         "python/builder.go",
+        "python/defaults.go",
         "python/installer.go",
         "python/library.go",
         "python/python.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 46e7fcf..319f711 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -42,6 +42,7 @@
 	SubName    string
 	OutputFile OptionalPath
 	Disabled   bool
+	Include    string
 
 	Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
 
@@ -163,6 +164,10 @@
 
 	data := provider.AndroidMk()
 
+	if data.Include == "" {
+		data.Include = "$(BUILD_PREBUILT)"
+	}
+
 	// Make does not understand LinuxBionic
 	if amod.Os() == LinuxBionic {
 		return nil
@@ -232,6 +237,9 @@
 		if amod.commonProperties.Owner != nil {
 			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
 		}
+		if amod.commonProperties.Notice != nil {
+			fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", "$(LOCAL_PATH)/"+*amod.commonProperties.Notice)
+		}
 	}
 
 	if host {
@@ -265,5 +273,5 @@
 		extra(w, data.OutputFile.Path())
 	}
 
-	fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+	fmt.Fprintln(w, "include "+data.Include)
 }
diff --git a/android/api_levels.go b/android/api_levels.go
index 370d553..2c4ae1a 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -67,6 +67,7 @@
 		"M":     23,
 		"N":     24,
 		"N-MR1": 25,
+		"O":     26,
 	}
 	for i, codename := range ctx.Config().(Config).PlatformVersionCombinedCodenames() {
 		apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/config.go b/android/config.go
index c435e85..4f35114 100644
--- a/android/config.go
+++ b/android/config.go
@@ -84,7 +84,8 @@
 
 	inMake bool
 
-	captureBuild bool // true for tests, saves build parameters for each module
+	captureBuild      bool // true for tests, saves build parameters for each module
+	ignoreEnvironment bool // true for tests, returns empty from all Getenv calls
 
 	OncePer
 }
@@ -173,8 +174,9 @@
 			DeviceName: stringPtr("test_device"),
 		},
 
-		buildDir:     buildDir,
-		captureBuild: true,
+		buildDir:          buildDir,
+		captureBuild:      true,
+		ignoreEnvironment: true,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
@@ -314,7 +316,9 @@
 		if c.envFrozen {
 			panic("Cannot access new environment variables after envdeps are frozen")
 		}
-		val, _ = originalEnv[key]
+		if !c.ignoreEnvironment {
+			val, _ = originalEnv[key]
+		}
 		c.envDeps[key] = val
 	}
 	return val
@@ -382,6 +386,14 @@
 	return 14
 }
 
+func (c *config) DefaultAppTargetSdkInt() int {
+	if Bool(c.ProductVariables.Platform_sdk_final) {
+		return c.PlatformSdkVersionInt()
+	} else {
+		return 10000
+	}
+}
+
 // Codenames that are active in the current lunch target.
 func (c *config) PlatformVersionActiveCodenames() []string {
 	return c.ProductVariables.Platform_version_active_codenames
diff --git a/android/defs.go b/android/defs.go
index ec8dcf9..cd8b4e3 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -52,6 +52,13 @@
 		},
 		"cpFlags")
 
+	CpExecutable = pctx.AndroidStaticRule("CpExecutable",
+		blueprint.RuleParams{
+			Command:     "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out",
+			Description: "cp $out",
+		},
+		"cpFlags")
+
 	// A timestamp touch rule.
 	Touch = pctx.AndroidStaticRule("Touch",
 		blueprint.RuleParams{
diff --git a/android/module.go b/android/module.go
index 3a3d173..bacf666 100644
--- a/android/module.go
+++ b/android/module.go
@@ -83,8 +83,8 @@
 	ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths
 	Glob(globPattern string, excludes []string) Paths
 
-	InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath
-	InstallFileName(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
+	InstallExecutable(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
+	InstallFile(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
 	InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath
 	CheckbuildFile(srcPath Path)
 
@@ -162,6 +162,9 @@
 	// names of other modules to install if this module is installed
 	Required []string `android:"arch_variant"`
 
+	// relative path to a file to include in the list of notices for the device
+	Notice *string
+
 	// Set by TargetMutator
 	CompileTarget  Target `blueprint:"mutated"`
 	CompilePrimary bool   `blueprint:"mutated"`
@@ -717,8 +720,18 @@
 	return false
 }
 
-func (a *androidModuleContext) InstallFileName(installPath OutputPath, name string, srcPath Path,
+func (a *androidModuleContext) InstallFile(installPath OutputPath, name string, srcPath Path,
 	deps ...Path) OutputPath {
+	return a.installFile(installPath, name, srcPath, Cp, deps)
+}
+
+func (a *androidModuleContext) InstallExecutable(installPath OutputPath, name string, srcPath Path,
+	deps ...Path) OutputPath {
+	return a.installFile(installPath, name, srcPath, CpExecutable, deps)
+}
+
+func (a *androidModuleContext) installFile(installPath OutputPath, name string, srcPath Path,
+	rule blueprint.Rule, deps []Path) OutputPath {
 
 	fullInstallPath := installPath.Join(a, name)
 	a.module.base().hooks.runInstallHooks(a, fullInstallPath, false)
@@ -738,7 +751,7 @@
 		}
 
 		a.ModuleBuild(pctx, ModuleBuildParams{
-			Rule:        Cp,
+			Rule:        rule,
 			Description: "install " + fullInstallPath.Base(),
 			Output:      fullInstallPath,
 			Input:       srcPath,
@@ -753,10 +766,6 @@
 	return fullInstallPath
 }
 
-func (a *androidModuleContext) InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath {
-	return a.InstallFileName(installPath, filepath.Base(srcPath.String()), srcPath, deps...)
-}
-
 func (a *androidModuleContext) InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath {
 	fullInstallPath := installPath.Join(a, name)
 	a.module.base().hooks.runInstallHooks(a, fullInstallPath, true)
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 2bc98aa..6743fb3 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
@@ -75,6 +76,25 @@
 	})
 }
 
+// SourcePathsVariable returns a Variable whose value is the source directory
+// appended with the supplied paths, joined with separator. It may only be
+// called during a Go package's initialization - either from the init()
+// function or as part of a package-scoped variable's initialization.
+func (p AndroidPackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
+	return p.VariableFunc(name, func(config interface{}) (string, error) {
+		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+		var ret []string
+		for _, path := range paths {
+			p := safePathForSource(ctx, path)
+			if len(ctx.errors) > 0 {
+				return "", ctx.errors[0]
+			}
+			ret = append(ret, p.String())
+		}
+		return strings.Join(ret, separator), nil
+	})
+}
+
 // SourcePathVariableWithEnvOverride returns a Variable whose value is the source directory
 // appended with the supplied path, or the value of the given environment variable if it is set.
 // The environment variable is not required to point to a path inside the source tree.
diff --git a/android/paths.go b/android/paths.go
index b5b4730..9c8e93a 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -283,6 +283,23 @@
 	return ret
 }
 
+// FirstUniqueElements returns all unique elements of a slice, keeping the first copy of each
+// modifies the slice contents in place, and returns a subslice of the original slice
+func FirstUniquePaths(list Paths) Paths {
+	k := 0
+outer:
+	for i := 0; i < len(list); i++ {
+		for j := 0; j < k; j++ {
+			if list[i] == list[j] {
+				continue outer
+			}
+		}
+		list[k] = list[i]
+		k++
+	}
+	return list[:k]
+}
+
 // WritablePaths is a slice of WritablePaths, used for multiple outputs.
 type WritablePaths []WritablePath
 
diff --git a/android/proto.go b/android/proto.go
new file mode 100644
index 0000000..9bb9cfb
--- /dev/null
+++ b/android/proto.go
@@ -0,0 +1,103 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"github.com/google/blueprint"
+)
+
+func init() {
+	pctx.HostBinToolVariable("protocCmd", "aprotoc")
+}
+
+var (
+	proto = pctx.AndroidStaticRule("protoc",
+		blueprint.RuleParams{
+			Command:     "$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in",
+			CommandDeps: []string{"$protocCmd"},
+		}, "protoFlags", "protoOut", "protoOutFlags", "outDir")
+)
+
+// TODO(ccross): protos are often used to communicate between multiple modules.  If the only
+// way to convert a proto to source is to reference it as a source file, and external modules cannot
+// reference source files in other modules, then every module that owns a proto file will need to
+// export a library for every type of external user (lite vs. full, c vs. c++ vs. java).  It would
+// be better to support a proto module type that exported a proto file along with some include dirs,
+// and then external modules could depend on the proto module but use their own settings to
+// generate the source.
+
+func GenProto(ctx ModuleContext, protoFile Path,
+	protoFlags string, protoOut, protoOutFlags string, extensions []string) WritablePaths {
+
+	var outFiles WritablePaths
+	for _, ext := range extensions {
+		outFiles = append(outFiles, GenPathWithExt(ctx, "proto", protoFile, ext))
+	}
+
+	ctx.ModuleBuild(pctx, ModuleBuildParams{
+		Rule:        proto,
+		Description: "protoc " + protoFile.Rel(),
+		Outputs:     outFiles,
+		Input:       protoFile,
+		Args: map[string]string{
+			"outDir":        ProtoDir(ctx).String(),
+			"protoOut":      protoOut,
+			"protoOutFlags": protoOutFlags,
+			"protoFlags":    protoFlags,
+		},
+	})
+
+	return outFiles
+}
+
+func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string {
+	var protoFlags []string
+	if len(p.Proto.Local_include_dirs) > 0 {
+		localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
+		protoFlags = append(protoFlags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
+	}
+	if len(p.Proto.Include_dirs) > 0 {
+		rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
+		protoFlags = append(protoFlags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
+	}
+
+	protoFlags = append(protoFlags, "-I .")
+
+	return protoFlags
+}
+
+// ProtoDir returns the module's "gen/proto" directory
+func ProtoDir(ctx ModuleContext) ModuleGenPath {
+	return PathForModuleGen(ctx, "proto")
+}
+
+// ProtoSubDir returns the module's "gen/proto/path/to/module" directory
+func ProtoSubDir(ctx ModuleContext) ModuleGenPath {
+	return PathForModuleGen(ctx, "proto", ctx.ModuleDir())
+}
+
+type ProtoProperties struct {
+	Proto struct {
+		// Proto generator type.  C++: full or lite.  Java: micro, nano, stream, or lite.
+		Type *string `android:"arch_variant"`
+
+		// list of directories that will be added to the protoc include paths.
+		Include_dirs []string
+
+		// list of directories relative to the bp file that will
+		// be added to the protoc include paths.
+		Local_include_dirs []string
+	} `android:"arch_variant"`
+}
diff --git a/android/variable.go b/android/variable.go
index 1ecd9fb..9dd9d25 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -108,6 +108,7 @@
 	Make_suffix *string `json:",omitempty"`
 
 	Platform_sdk_version              *int     `json:",omitempty"`
+	Platform_sdk_final                *bool    `json:",omitempty"`
 	Platform_version_active_codenames []string `json:",omitempty"`
 	Platform_version_future_codenames []string `json:",omitempty"`
 
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 19ed4ec..bdd3e97 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -37,6 +37,7 @@
 	"LOCAL_SANITIZE":              sanitize(""),
 	"LOCAL_SANITIZE_DIAG":         sanitize("diag."),
 	"LOCAL_CFLAGS":                cflags,
+	"LOCAL_UNINSTALLABLE_MODULE":  invert("installable"),
 
 	// composite functions
 	"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
@@ -74,6 +75,8 @@
 			"LOCAL_PROTOC_OPTIMIZE_TYPE":    "proto.type",
 			"LOCAL_MODULE_OWNER":            "owner",
 			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
+			"LOCAL_NOTICE_FILE":             "notice",
+			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
 		})
 	addStandardProperties(bpparser.ListType,
 		map[string]string{
@@ -112,23 +115,25 @@
 			"LOCAL_AAPT_FLAGS":            "aaptflags",
 			"LOCAL_PACKAGE_SPLITS":        "package_splits",
 			"LOCAL_COMPATIBILITY_SUITE":   "test_suites",
+
+			"LOCAL_ANNOTATION_PROCESSORS":        "annotation_processors",
+			"LOCAL_ANNOTATION_PROCESSOR_CLASSES": "annotation_processor_classes",
 		})
 	addStandardProperties(bpparser.BoolType,
 		map[string]string{
 			// Bool properties
-			"LOCAL_IS_HOST_MODULE":          "host",
-			"LOCAL_CLANG":                   "clang",
-			"LOCAL_FORCE_STATIC_EXECUTABLE": "static_executable",
-			"LOCAL_NATIVE_COVERAGE":         "native_coverage",
-			"LOCAL_NO_CRT":                  "nocrt",
-			"LOCAL_ALLOW_UNDEFINED_SYMBOLS": "allow_undefined_symbols",
-			"LOCAL_RTTI_FLAG":               "rtti",
-			"LOCAL_NO_STANDARD_LIBRARIES":   "no_standard_libraries",
-			"LOCAL_PACK_MODULE_RELOCATIONS": "pack_relocations",
-			"LOCAL_TIDY":                    "tidy",
-			"LOCAL_PROPRIETARY_MODULE":      "proprietary",
-			"LOCAL_VENDOR_MODULE":           "vendor",
-
+			"LOCAL_IS_HOST_MODULE":           "host",
+			"LOCAL_CLANG":                    "clang",
+			"LOCAL_FORCE_STATIC_EXECUTABLE":  "static_executable",
+			"LOCAL_NATIVE_COVERAGE":          "native_coverage",
+			"LOCAL_NO_CRT":                   "nocrt",
+			"LOCAL_ALLOW_UNDEFINED_SYMBOLS":  "allow_undefined_symbols",
+			"LOCAL_RTTI_FLAG":                "rtti",
+			"LOCAL_NO_STANDARD_LIBRARIES":    "no_standard_libs",
+			"LOCAL_PACK_MODULE_RELOCATIONS":  "pack_relocations",
+			"LOCAL_TIDY":                     "tidy",
+			"LOCAL_PROPRIETARY_MODULE":       "proprietary",
+			"LOCAL_VENDOR_MODULE":            "vendor",
 			"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
 		})
 }
@@ -527,6 +532,19 @@
 	return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx)
 }
 
+func invert(name string) func(ctx variableAssignmentContext) error {
+	return func(ctx variableAssignmentContext) error {
+		val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.BoolType)
+		if err != nil {
+			return err
+		}
+
+		val.(*bpparser.Bool).Value = !val.(*bpparser.Bool).Value
+
+		return setVariable(ctx.file, ctx.append, ctx.prefix, name, val, true)
+	}
+}
+
 // given a conditional, returns a function that will insert a variable assignment or not, based on the conditional
 func includeVariableIf(bpVar bpVariable, conditional func(ctx variableAssignmentContext) bool) func(ctx variableAssignmentContext) error {
 	return func(ctx variableAssignmentContext) error {
@@ -643,6 +661,15 @@
 	return fmt.Sprintf("%s/**/*.java", dir)
 }
 
+func allProtoFilesUnder(args []string) string {
+	dir := ""
+	if len(args) > 0 {
+		dir = strings.TrimSpace(args[0])
+	}
+
+	return fmt.Sprintf("%s/**/*.proto", dir)
+}
+
 func allSubdirJavaFiles(args []string) string {
 	return "**/*.java"
 }
@@ -671,7 +698,7 @@
 	"SHARED_LIBRARIES": "cc_prebuilt_library_shared",
 	"STATIC_LIBRARIES": "cc_prebuilt_library_static",
 	"EXECUTABLES":      "cc_prebuilt_binary",
-	"JAVA_LIBRARIES":   "prebuilt_java_library",
+	"JAVA_LIBRARIES":   "java_import",
 }
 
 var soongModuleTypes = map[string]bool{}
@@ -681,6 +708,7 @@
 	globalScope.Set("CLEAR_VARS", clear_vars)
 	globalScope.SetFunc("my-dir", mydir)
 	globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
+	globalScope.SetFunc("all-proto-files-under", allProtoFilesUnder)
 	globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles)
 
 	for k, v := range moduleTypes {
diff --git a/cc/binary.go b/cc/binary.go
index f6e62b7..4ddaf94 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -35,6 +35,9 @@
 	// if set, add an extra objcopy --prefix-symbols= step
 	Prefix_symbols string
 
+	// local file name to pass to the linker as --version_script
+	Version_script *string `android:"arch_variant"`
+
 	// if set, install a symlink to the preferred architecture
 	Symlink_preferred_arch bool
 
@@ -231,7 +234,6 @@
 				"-Bstatic",
 				"-Wl,--gc-sections",
 			)
-
 		} else {
 			if flags.DynamicLinker == "" {
 				if binary.Properties.DynamicLinker != "" {
@@ -266,6 +268,7 @@
 				"-Wl,--gc-sections",
 				"-Wl,-z,nocopyreloc",
 			)
+
 		}
 	} else {
 		if binary.static() {
@@ -282,6 +285,7 @@
 func (binary *binaryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
+	versionScript := android.OptionalPathForModuleSrc(ctx, binary.Properties.Version_script)
 	fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := outputFile
@@ -291,6 +295,15 @@
 	sharedLibs := deps.SharedLibs
 	sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
 
+	if versionScript.Valid() {
+		if ctx.Darwin() {
+			ctx.PropertyErrorf("version_script", "Not supported on Darwin")
+		} else {
+			flags.LdFlags = append(flags.LdFlags, "-Wl,--version-script,"+versionScript.String())
+			linkerDeps = append(linkerDeps, versionScript.Path())
+		}
+	}
+
 	if flags.DynamicLinker != "" {
 		flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
 	}
diff --git a/cc/builder.go b/cc/builder.go
index 1a4f505..b5bdc3d 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -158,6 +158,13 @@
 		},
 		"asFlags")
 
+	windres = pctx.AndroidStaticRule("windres",
+		blueprint.RuleParams{
+			Command:     "$windresCmd $flags -I$$(dirname $in) -i $in -o $out",
+			CommandDeps: []string{"$windresCmd"},
+		},
+		"windresCmd", "flags")
+
 	_ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper")
 
 	// -w has been added since header-abi-dumper does not need to produce any sort of diagnostic information.
@@ -332,7 +339,8 @@
 
 		objFiles[i] = objFile
 
-		if srcFile.Ext() == ".asm" {
+		switch srcFile.Ext() {
+		case ".asm":
 			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 				Rule:        yasm,
 				Description: "yasm " + srcFile.Rel(),
@@ -344,6 +352,19 @@
 				},
 			})
 			continue
+		case ".rc":
+			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+				Rule:        windres,
+				Description: "windres " + srcFile.Rel(),
+				Output:      objFile,
+				Input:       srcFile,
+				OrderOnly:   deps,
+				Args: map[string]string{
+					"windresCmd": gccCmd(flags.toolchain, "windres"),
+					"flags":      flags.toolchain.WindresFlags(),
+				},
+			})
+			continue
 		}
 
 		var moduleCflags string
diff --git a/cc/cc.go b/cc/cc.go
index 4dafc63..fe9c4a4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -465,7 +465,7 @@
 
 // Create source abi dumps if the module belongs to the list of VndkLibraries.
 func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
-	return ctx.ctx.Device() && (ctx.mod.isVndk() || inList(ctx.baseModuleName(), llndkLibraries))
+	return ctx.ctx.Device() && ((ctx.vndk() && ctx.isVndk()) || inList(ctx.baseModuleName(), llndkLibraries))
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
@@ -1138,6 +1138,13 @@
 
 	// Dedup exported flags from dependencies
 	depPaths.Flags = firstUniqueElements(depPaths.Flags)
+	depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
+	depPaths.ReexportedFlags = firstUniqueElements(depPaths.ReexportedFlags)
+	depPaths.ReexportedFlagsDeps = android.FirstUniquePaths(depPaths.ReexportedFlagsDeps)
+
+	if c.sabi != nil {
+		c.sabi.Properties.ReexportedIncludeFlags = firstUniqueElements(c.sabi.Properties.ReexportedIncludeFlags)
+	}
 
 	return depPaths
 }
@@ -1166,6 +1173,10 @@
 	return c.installer.hostToolPath()
 }
 
+func (c *Module) IntermPathForModuleOut() android.OptionalPath {
+	return c.outputFile
+}
+
 //
 // Defaults
 //
diff --git a/cc/compiler.go b/cc/compiler.go
index 0cc809d..a65ddf8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -141,6 +141,11 @@
 		}
 	}
 
+	Proto struct {
+		// Link statically against the protobuf runtime
+		Static bool `android:"arch_variant"`
+	} `android:"arch_variant"`
+
 	// Stores the original list of source files before being cleared by library reuse
 	OriginalSrcs []string `blueprint:"mutated"`
 }
@@ -151,7 +156,7 @@
 
 type baseCompiler struct {
 	Properties BaseCompilerProperties
-	Proto      ProtoProperties
+	Proto      android.ProtoProperties
 	deps       android.Paths
 	srcs       android.Paths
 	flags      builderFlags
@@ -188,7 +193,7 @@
 	android.ExtractSourcesDeps(ctx, compiler.Properties.Srcs)
 
 	if compiler.hasSrcExt(".proto") {
-		deps = protoDeps(ctx, deps, &compiler.Proto)
+		deps = protoDeps(ctx, deps, &compiler.Proto, compiler.Properties.Proto.Static)
 	}
 
 	return deps
@@ -429,6 +434,11 @@
 			"-I"+android.PathForModuleGen(ctx, "yacc", ctx.ModuleDir()).String())
 	}
 
+	if compiler.hasSrcExt(".mc") {
+		flags.GlobalFlags = append(flags.GlobalFlags,
+			"-I"+android.PathForModuleGen(ctx, "windmc", ctx.ModuleDir()).String())
+	}
+
 	if compiler.hasSrcExt(".aidl") {
 		if len(compiler.Properties.Aidl.Local_include_dirs) > 0 {
 			localAidlIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Aidl.Local_include_dirs)
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index fc0282b..d62ebe4 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -70,6 +70,8 @@
 
 	YasmFlags() string
 
+	WindresFlags() string
+
 	Is64Bit() bool
 
 	ShlibSuffix() string
@@ -135,6 +137,10 @@
 	return ""
 }
 
+func (toolchainBase) WindresFlags() string {
+	return ""
+}
+
 func (toolchainBase) SanitizerRuntimeLibraryArch() string {
 	return ""
 }
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 4709823..270084e 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -81,7 +81,10 @@
 	windowsAvailableLibraries = addPrefix([]string{
 		"gdi32",
 		"imagehlp",
+		"iphlpapi",
+		"netapi32",
 		"ole32",
+		"powrprof",
 		"psapi",
 		"pthread",
 		"userenv",
@@ -172,6 +175,14 @@
 	return "${config.WindowsIncludeFlags}"
 }
 
+func (t *toolchainWindowsX86) WindresFlags() string {
+	return "-F pe-i386"
+}
+
+func (t *toolchainWindowsX8664) WindresFlags() string {
+	return "-F pe-x86-64"
+}
+
 func (t *toolchainWindows) ClangSupported() bool {
 	return false
 }
diff --git a/cc/gen.go b/cc/gen.go
index 7a22abd..9fc14c5 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -54,6 +54,13 @@
 			Deps:        blueprint.DepsGCC,
 		},
 		"aidlFlags", "outDir")
+
+	windmc = pctx.AndroidStaticRule("windmc",
+		blueprint.RuleParams{
+			Command:     "$windmcCmd -r$$(dirname $out) -h$$(dirname $out) $in",
+			CommandDeps: []string{"$windmcCmd"},
+		},
+		"windmcCmd")
 )
 
 func genYacc(ctx android.ModuleContext, yaccFile android.Path, outFile android.ModuleGenPath, yaccFlags string) (headerFile android.ModuleGenPath) {
@@ -100,6 +107,26 @@
 	})
 }
 
+func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
+	headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h")
+	rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc")
+
+	windmcCmd := gccCmd(flags.toolchain, "windmc")
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:           windmc,
+		Description:    "windmc " + srcFile.Rel(),
+		Output:         rcFile,
+		ImplicitOutput: headerFile,
+		Input:          srcFile,
+		Args: map[string]string{
+			"windmcCmd": windmcCmd,
+		},
+	})
+
+	return rcFile, headerFile
+}
+
 func genSources(ctx android.ModuleContext, srcFiles android.Paths,
 	buildFlags builderFlags) (android.Paths, android.Paths) {
 
@@ -126,9 +153,10 @@
 			srcFiles[i] = cppFile
 			genLex(ctx, srcFile, cppFile)
 		case ".proto":
-			cppFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags)
-			srcFiles[i] = cppFile
-			deps = append(deps, headerFile)
+			protoFiles := android.GenProto(ctx, srcFile, buildFlags.protoFlags,
+				"--cpp_out", "", []string{"pb.cc", "pb.h"})
+			srcFiles[i] = protoFiles[0]
+			deps = append(deps, protoFiles[1])
 		case ".aidl":
 			cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
 			srcFiles[i] = cppFile
@@ -137,6 +165,10 @@
 			cppFile := rsGeneratedCppFile(ctx, srcFile)
 			rsFiles = append(rsFiles, srcFiles[i])
 			srcFiles[i] = cppFile
+		case ".mc":
+			rcFile, headerFile := genWinMsg(ctx, srcFile, buildFlags)
+			srcFiles[i] = rcFile
+			deps = append(deps, headerFile)
 		}
 	}
 
diff --git a/cc/installer.go b/cc/installer.go
index 7bedc56..027d191 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -76,7 +76,7 @@
 }
 
 func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
-	installer.path = ctx.InstallFile(installer.installDir(ctx), file)
+	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
 }
 
 func (installer *baseInstaller) inData() bool {
diff --git a/cc/library.go b/cc/library.go
index 1537fd4..2a866dc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -349,7 +349,7 @@
 		return Objects{}
 	}
 	if ctx.createVndkSourceAbiDump() || library.sabi.Properties.CreateSAbiDumps {
-		exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
 			SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
@@ -600,7 +600,7 @@
 		if versionScript.Valid() {
 			symbolFile = versionScript
 		}
-		exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
 			SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
@@ -655,8 +655,8 @@
 	if library.Properties.Proto.Export_proto_headers {
 		if library.baseCompiler.hasSrcExt(".proto") {
 			flags := []string{
-				"-I" + protoSubDir(ctx).String(),
-				"-I" + protoDir(ctx).String(),
+				"-I" + android.ProtoSubDir(ctx).String(),
+				"-I" + android.ProtoDir(ctx).String(),
 			}
 			library.reexportFlags(flags)
 			library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
diff --git a/cc/linker.go b/cc/linker.go
index 678b992..59c979d 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -213,6 +213,18 @@
 			CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs)
 
 			flags.LdFlags = append(flags.LdFlags, linker.Properties.Host_ldlibs...)
+
+			if !ctx.Windows() {
+				// Add -ldl, -lpthread and -lrt to host builds to match the default behavior of device
+				// builds
+				flags.LdFlags = append(flags.LdFlags,
+					"-ldl",
+					"-lpthread",
+				)
+				if !ctx.Darwin() {
+					flags.LdFlags = append(flags.LdFlags, "-lrt")
+				}
+			}
 		}
 	}
 
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5fa3232..140cc2f 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -122,7 +122,7 @@
 	srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
 	for _, header := range srcFiles {
 		installDir := getHeaderInstallDir(ctx, header, m.properties.From, m.properties.To)
-		installedPath := ctx.InstallFile(installDir, header)
+		installedPath := ctx.InstallFile(installDir, header.Base(), header)
 		installPath := installDir.Join(ctx, header.Base())
 		if installPath != installedPath {
 			panic(fmt.Sprintf(
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index fc7cd91..a408fc5 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -341,7 +341,7 @@
 
 	installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
 		"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
-	stub.installPath = ctx.InstallFile(installDir, path).String()
+	stub.installPath = ctx.InstallFile(installDir, path.Base(), path).String()
 }
 
 func newStubLibrary() *Module {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 089ce28..9fca053 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -125,7 +125,7 @@
 		outputFile := android.PathForModuleOut(ctx, fileName)
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-			Rule:        android.Cp,
+			Rule:        android.CpExecutable,
 			Description: "prebuilt",
 			Output:      outputFile,
 			Input:       p.Prebuilt.SingleSourcePath(ctx),
diff --git a/cc/proto.go b/cc/proto.go
index 6c1789a..6049d44 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -15,81 +15,13 @@
 package cc
 
 import (
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
 
-func init() {
-	pctx.HostBinToolVariable("protocCmd", "aprotoc")
-}
-
-var (
-	proto = pctx.AndroidStaticRule("protoc",
-		blueprint.RuleParams{
-			Command:     "$protocCmd --cpp_out=$outDir $protoFlags $in",
-			CommandDeps: []string{"$protocCmd"},
-		}, "protoFlags", "outDir")
-)
-
-// TODO(ccross): protos are often used to communicate between multiple modules.  If the only
-// way to convert a proto to source is to reference it as a source file, and external modules cannot
-// reference source files in other modules, then every module that owns a proto file will need to
-// export a library for every type of external user (lite vs. full, c vs. c++ vs. java).  It would
-// be better to support a proto module type that exported a proto file along with some include dirs,
-// and then external modules could depend on the proto module but use their own settings to
-// generate the source.
-
-func genProto(ctx android.ModuleContext, protoFile android.Path,
-	protoFlags string) (android.ModuleGenPath, android.ModuleGenPath) {
-
-	outFile := android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc")
-	headerFile := android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
-	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:        proto,
-		Description: "protoc " + protoFile.Rel(),
-		Outputs:     android.WritablePaths{outFile, headerFile},
-		Input:       protoFile,
-		Args: map[string]string{
-			"outDir":     protoDir(ctx).String(),
-			"protoFlags": protoFlags,
-		},
-	})
-
-	return outFile, headerFile
-}
-
-// protoDir returns the module's "gen/proto" directory
-func protoDir(ctx android.ModuleContext) android.ModuleGenPath {
-	return android.PathForModuleGen(ctx, "proto")
-}
-
-// protoSubDir returns the module's "gen/proto/path/to/module" directory
-func protoSubDir(ctx android.ModuleContext) android.ModuleGenPath {
-	return android.PathForModuleGen(ctx, "proto", ctx.ModuleDir())
-}
-
-type ProtoProperties struct {
-	Proto struct {
-		// Proto generator type (full, lite)
-		Type *string `android:"arch_variant"`
-
-		// Link statically against the protobuf runtime
-		Static bool `android:"arch_variant"`
-
-		// list of directories that will be added to the protoc include paths.
-		Include_dirs []string
-
-		// list of directories relative to the Android.bp file that will
-		// be added to the protoc include paths.
-		Local_include_dirs []string
-	} `android:"arch_variant"`
-}
-
-func protoDeps(ctx BaseModuleContext, deps Deps, p *ProtoProperties) Deps {
+func protoDeps(ctx BaseModuleContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
 	var lib string
-	var static bool
 
 	switch proptools.String(p.Proto.Type) {
 	case "full":
@@ -105,9 +37,6 @@
 			static = true
 		} else {
 			lib = "libprotobuf-cpp-lite"
-			if p.Proto.Static {
-				static = true
-			}
 		}
 	default:
 		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
@@ -125,23 +54,14 @@
 	return deps
 }
 
-func protoFlags(ctx ModuleContext, flags Flags, p *ProtoProperties) Flags {
+func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags {
 	flags.CFlags = append(flags.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
 	flags.GlobalFlags = append(flags.GlobalFlags,
-		"-I"+protoSubDir(ctx).String(),
-		"-I"+protoDir(ctx).String(),
+		"-I"+android.ProtoSubDir(ctx).String(),
+		"-I"+android.ProtoDir(ctx).String(),
 	)
 
-	if len(p.Proto.Local_include_dirs) > 0 {
-		localProtoIncludeDirs := android.PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
-		flags.protoFlags = append(flags.protoFlags, includeDirsToFlags(localProtoIncludeDirs))
-	}
-	if len(p.Proto.Include_dirs) > 0 {
-		rootProtoIncludeDirs := android.PathsForSource(ctx, p.Proto.Include_dirs)
-		flags.protoFlags = append(flags.protoFlags, includeDirsToFlags(rootProtoIncludeDirs))
-	}
-
-	flags.protoFlags = append(flags.protoFlags, "-I .")
+	flags.protoFlags = android.ProtoFlags(ctx, p)
 
 	return flags
 }
diff --git a/cc/sabi.go b/cc/sabi.go
index 15d980c..e45b040 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -79,7 +79,7 @@
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		(c.isVndk() || inList(c.Name(), llndkLibraries) ||
+		((c.isVndk() && c.vndk()) || inList(c.Name(), llndkLibraries) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m blueprint.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/test.go b/cc/test.go
index a52e94a..1501a26 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -337,8 +337,8 @@
 
 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.dir = filepath.Join("benchmarktest", ctx.ModuleName())
+	benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.install(ctx, file)
 }
 
@@ -355,7 +355,7 @@
 
 	module, binary := NewBinary(hod)
 	module.multilib = android.MultilibBoth
-	binary.baseInstaller = NewTestInstaller()
+	binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData)
 
 	benchmark := &benchmarkDecorator{
 		binaryDecorator: binary,
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
new file mode 100644
index 0000000..ace079d
--- /dev/null
+++ b/cmd/merge_zips/Android.bp
@@ -0,0 +1,25 @@
+// 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: "merge_zips",
+    deps: [
+      "android-archive-zip",
+      "soong-jar",
+    ],
+    srcs: [
+        "merge_zips.go",
+    ],
+}
+
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
new file mode 100644
index 0000000..7874a41
--- /dev/null
+++ b/cmd/merge_zips/merge_zips.go
@@ -0,0 +1,182 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"sort"
+	"strings"
+
+	"android/soong/jar"
+	"android/soong/third_party/zip"
+)
+
+var (
+	sortEntries = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
+	emulateJar  = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
+)
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintln(os.Stderr, "usage: merge_zips [-j] output [inputs...]")
+		flag.PrintDefaults()
+	}
+
+	// parse args
+	flag.Parse()
+	args := flag.Args()
+	if len(args) < 2 {
+		flag.Usage()
+		os.Exit(1)
+	}
+	outputPath := args[0]
+	inputs := args[1:]
+
+	log.SetFlags(log.Lshortfile)
+
+	// make writer
+	output, err := os.Create(outputPath)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer output.Close()
+	writer := zip.NewWriter(output)
+	defer func() {
+		err := writer.Close()
+		if err != nil {
+			log.Fatal(err)
+		}
+	}()
+
+	// make readers
+	readers := []namedZipReader{}
+	for _, input := range inputs {
+		reader, err := zip.OpenReader(input)
+		if err != nil {
+			log.Fatal(err)
+		}
+		defer reader.Close()
+		namedReader := namedZipReader{path: input, reader: reader}
+		readers = append(readers, namedReader)
+	}
+
+	// do merge
+	if err := mergeZips(readers, writer, *sortEntries, *emulateJar); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// a namedZipReader reads a .zip file and can say which file it's reading
+type namedZipReader struct {
+	path   string
+	reader *zip.ReadCloser
+}
+
+// a zipEntryPath refers to a file contained in a zip
+type zipEntryPath struct {
+	zipName   string
+	entryName string
+}
+
+func (p zipEntryPath) String() string {
+	return p.zipName + "/" + p.entryName
+}
+
+// a zipEntry knows the location and content of a file within a zip
+type zipEntry struct {
+	path    zipEntryPath
+	content *zip.File
+}
+
+// a fileMapping specifies to copy a zip entry from one place to another
+type fileMapping struct {
+	source zipEntry
+	dest   string
+}
+
+func mergeZips(readers []namedZipReader, writer *zip.Writer, sortEntries bool, emulateJar bool) error {
+
+	mappingsByDest := make(map[string]fileMapping, 0)
+	orderedMappings := []fileMapping{}
+
+	for _, namedReader := range readers {
+		for _, file := range namedReader.reader.File {
+			// check for other files or directories destined for the same path
+			dest := file.Name
+			mapKey := dest
+			if strings.HasSuffix(mapKey, "/") {
+				mapKey = mapKey[:len(mapKey)-1]
+			}
+			existingMapping, exists := mappingsByDest[mapKey]
+
+			// make a new entry to add
+			source := zipEntry{path: zipEntryPath{zipName: namedReader.path, entryName: file.Name}, content: file}
+			newMapping := fileMapping{source: source, dest: dest}
+
+			if exists {
+				// handle duplicates
+				wasDir := existingMapping.source.content.FileHeader.FileInfo().IsDir()
+				isDir := newMapping.source.content.FileHeader.FileInfo().IsDir()
+				if wasDir != isDir {
+					return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
+						dest, existingMapping.source.path, newMapping.source.path)
+				}
+				if emulateJar &&
+					file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass {
+					// Skip manifest and module info files that are not from the first input file
+					continue
+				}
+				if !isDir {
+					return fmt.Errorf("Duplicate path %v found in %v and %v\n",
+						dest, existingMapping.source.path, newMapping.source.path)
+				}
+			} else {
+				// save entry
+				mappingsByDest[mapKey] = newMapping
+				orderedMappings = append(orderedMappings, newMapping)
+			}
+		}
+
+	}
+
+	if emulateJar {
+		jarSort(orderedMappings)
+	} else if sortEntries {
+		alphanumericSort(orderedMappings)
+	}
+
+	for _, entry := range orderedMappings {
+		if err := writer.CopyFrom(entry.source.content, entry.dest); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func jarSort(files []fileMapping) {
+	sort.SliceStable(files, func(i, j int) bool {
+		return jar.EntryNamesLess(files[i].dest, files[j].dest)
+	})
+}
+
+func alphanumericSort(files []fileMapping) {
+	sort.SliceStable(files, func(i, j int) bool {
+		return files[i].dest < files[j].dest
+	})
+}
diff --git a/cmd/soong_zip/soong_zip.go b/cmd/soong_zip/soong_zip.go
index bb2a70f..4cf0764 100644
--- a/cmd/soong_zip/soong_zip.go
+++ b/cmd/soong_zip/soong_zip.go
@@ -57,9 +57,15 @@
 	return nil
 }
 
+type byteReaderCloser struct {
+	bytes.Reader
+	io.Closer
+}
+
 type fileArg struct {
 	pathPrefixInZip, sourcePrefixToStrip string
 	sourceFiles                          []string
+	globDir                              string
 }
 
 type pathMapping struct {
@@ -89,13 +95,15 @@
 
 type listFiles struct{}
 
+type dir struct{}
+
 func (f *file) String() string {
 	return `""`
 }
 
 func (f *file) Set(s string) error {
 	if *relativeRoot == "" {
-		return fmt.Errorf("must pass -C before -f or -l")
+		return fmt.Errorf("must pass -C before -f")
 	}
 
 	fArgs = append(fArgs, fileArg{
@@ -113,7 +121,7 @@
 
 func (l *listFiles) Set(s string) error {
 	if *relativeRoot == "" {
-		return fmt.Errorf("must pass -C before -f or -l")
+		return fmt.Errorf("must pass -C before -l")
 	}
 
 	list, err := ioutil.ReadFile(s)
@@ -130,12 +138,30 @@
 	return nil
 }
 
+func (d *dir) String() string {
+	return `""`
+}
+
+func (d *dir) Set(s string) error {
+	if *relativeRoot == "" {
+		return fmt.Errorf("must pass -C before -D")
+	}
+
+	fArgs = append(fArgs, fileArg{
+		pathPrefixInZip:     filepath.Clean(*rootPrefix),
+		sourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		globDir:             filepath.Clean(s),
+	})
+
+	return nil
+}
+
 var (
 	out          = flag.String("o", "", "file to write zip file to")
 	manifest     = flag.String("m", "", "input jar manifest file name")
 	directories  = flag.Bool("d", false, "include directories in zip")
 	rootPrefix   = flag.String("P", "", "path prefix within the zip at which to place files")
-	relativeRoot = flag.String("C", "", "path to use as relative root of files in next -f or -l argument")
+	relativeRoot = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments")
 	parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use")
 	compLevel    = flag.Int("L", 5, "deflate compression level (0-9)")
 	emulateJar   = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
@@ -149,6 +175,7 @@
 
 func init() {
 	flag.Var(&listFiles{}, "l", "file containing list of .class files")
+	flag.Var(&dir{}, "D", "directory to include in zip")
 	flag.Var(&file{}, "f", "file to include in zip")
 	flag.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
 }
@@ -160,9 +187,10 @@
 }
 
 type zipWriter struct {
-	time        time.Time
-	createdDirs map[string]bool
-	directories bool
+	time         time.Time
+	createdFiles map[string]string
+	createdDirs  map[string]string
+	directories  bool
 
 	errors   chan error
 	writeOps chan chan *zipEntry
@@ -224,19 +252,23 @@
 	}
 
 	w := &zipWriter{
-		time:        time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
-		createdDirs: make(map[string]bool),
-		directories: *directories,
-		compLevel:   *compLevel,
+		time:         time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
+		createdDirs:  make(map[string]string),
+		createdFiles: make(map[string]string),
+		directories:  *directories,
+		compLevel:    *compLevel,
 	}
 
 	pathMappings := []pathMapping{}
-	set := make(map[string]string)
 
 	for _, fa := range fArgs {
-		for _, src := range fa.sourceFiles {
+		srcs := fa.sourceFiles
+		if fa.globDir != "" {
+			srcs = append(srcs, recursiveGlobFiles(fa.globDir)...)
+		}
+		for _, src := range srcs {
 			if err := fillPathPairs(fa.pathPrefixInZip,
-				fa.sourcePrefixToStrip, src, set, &pathMappings); err != nil {
+				fa.sourcePrefixToStrip, src, &pathMappings); err != nil {
 				log.Fatal(err)
 			}
 		}
@@ -249,7 +281,7 @@
 	}
 }
 
-func fillPathPairs(prefix, rel, src string, set map[string]string, pathMappings *[]pathMapping) error {
+func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping) error {
 	src = strings.TrimSpace(src)
 	if src == "" {
 		return nil
@@ -261,14 +293,6 @@
 	}
 	dest = filepath.Join(prefix, dest)
 
-	if _, found := set[dest]; found {
-		return fmt.Errorf("found two file paths to be copied into dest path: %q,"+
-			" both [%q]%q and [%q]%q!",
-			dest, dest, src, dest, set[dest])
-	} else {
-		set[dest] = src
-	}
-
 	zipMethod := zip.Deflate
 	if _, found := nonDeflatedFiles[dest]; found {
 		zipMethod = zip.Store
@@ -286,6 +310,13 @@
 	sort.SliceStable(mappings, less)
 }
 
+type readerSeekerCloser interface {
+	io.Reader
+	io.ReaderAt
+	io.Closer
+	io.Seeker
+}
+
 func (z *zipWriter) write(out string, pathMappings []pathMapping, manifest string) error {
 	f, err := os.Create(out)
 	if err != nil {
@@ -326,7 +357,7 @@
 		if !*emulateJar {
 			return errors.New("must specify --jar when specifying a manifest via -m")
 		}
-		pathMappings = append(pathMappings, pathMapping{"META-INF/MANIFEST.MF", manifest, zip.Deflate})
+		pathMappings = append(pathMappings, pathMapping{jar.ManifestFile, manifest, zip.Deflate})
 	}
 
 	if *emulateJar {
@@ -338,7 +369,11 @@
 		defer close(z.writeOps)
 
 		for _, ele := range pathMappings {
-			err = z.writeFile(ele.dest, ele.src, ele.zipMethod)
+			if *emulateJar && ele.dest == jar.ManifestFile {
+				err = z.addManifest(ele.dest, ele.src, ele.zipMethod)
+			} else {
+				err = z.addFile(ele.dest, ele.src, ele.zipMethod)
+			}
 			if err != nil {
 				z.errors <- err
 				return
@@ -434,7 +469,8 @@
 	}
 }
 
-func (z *zipWriter) writeFile(dest, src string, method uint16) error {
+// imports (possibly with compression) <src> into the zip at sub-path <dest>
+func (z *zipWriter) addFile(dest, src string, method uint16) error {
 	var fileSize int64
 	var executable bool
 
@@ -442,42 +478,31 @@
 		return err
 	} else if s.IsDir() {
 		if z.directories {
-			return z.writeDirectory(dest)
+			return z.writeDirectory(dest, src)
 		}
 		return nil
-	} else if s.Mode()&os.ModeSymlink != 0 {
-		return z.writeSymlink(dest, src)
-	} else if !s.Mode().IsRegular() {
-		return fmt.Errorf("%s is not a file, directory, or symlink", src)
 	} else {
-		fileSize = s.Size()
-		executable = s.Mode()&0100 != 0
-	}
-
-	if z.directories {
-		dir, _ := filepath.Split(dest)
-		err := z.writeDirectory(dir)
-		if err != nil {
+		if err := z.writeDirectory(filepath.Dir(dest), src); err != nil {
 			return err
 		}
-	}
 
-	compressChan := make(chan *zipEntry, 1)
-	z.writeOps <- compressChan
+		if prev, exists := z.createdDirs[dest]; exists {
+			return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
+		}
+		if prev, exists := z.createdFiles[dest]; exists {
+			return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+		}
 
-	// Pre-fill a zipEntry, it will be sent in the compressChan once
-	// we're sure about the Method and CRC.
-	ze := &zipEntry{
-		fh: &zip.FileHeader{
-			Name:   dest,
-			Method: method,
+		z.createdFiles[dest] = src
 
-			UncompressedSize64: uint64(fileSize),
-		},
-	}
-	ze.fh.SetModTime(z.time)
-	if executable {
-		ze.fh.SetMode(0700)
+		if s.Mode()&os.ModeSymlink != 0 {
+			return z.writeSymlink(dest, src)
+		} else if !s.Mode().IsRegular() {
+			return fmt.Errorf("%s is not a file, directory, or symlink", src)
+		}
+
+		fileSize = s.Size()
+		executable = s.Mode()&0100 != 0
 	}
 
 	r, err := os.Open(src)
@@ -485,11 +510,78 @@
 		return err
 	}
 
-	ze.allocatedSize = fileSize
+	header := &zip.FileHeader{
+		Name:               dest,
+		Method:             method,
+		UncompressedSize64: uint64(fileSize),
+	}
+
+	if executable {
+		header.SetMode(0700)
+	}
+
+	return z.writeFileContents(header, r)
+}
+
+func (z *zipWriter) addManifest(dest string, src string, method uint16) error {
+	givenBytes, err := ioutil.ReadFile(src)
+	if err != nil {
+		return err
+	}
+
+	if prev, exists := z.createdDirs[dest]; exists {
+		return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
+	}
+	if prev, exists := z.createdFiles[dest]; exists {
+		return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+	}
+
+	manifestMarker := []byte("Manifest-Version:")
+	header := append(manifestMarker, []byte(" 1.0\nCreated-By: soong_zip\n")...)
+
+	var finalBytes []byte
+	if !bytes.Contains(givenBytes, manifestMarker) {
+		finalBytes = append(append(header, givenBytes...), byte('\n'))
+	} else {
+		finalBytes = givenBytes
+	}
+
+	byteReader := bytes.NewReader(finalBytes)
+
+	reader := &byteReaderCloser{*byteReader, ioutil.NopCloser(nil)}
+
+	fileHeader := &zip.FileHeader{
+		Name:               dest,
+		Method:             zip.Store,
+		UncompressedSize64: uint64(byteReader.Len()),
+	}
+
+	return z.writeFileContents(fileHeader, reader)
+}
+
+func (z *zipWriter) writeFileContents(header *zip.FileHeader, r readerSeekerCloser) (err error) {
+
+	header.SetModTime(z.time)
+
+	compressChan := make(chan *zipEntry, 1)
+	z.writeOps <- compressChan
+
+	// Pre-fill a zipEntry, it will be sent in the compressChan once
+	// we're sure about the Method and CRC.
+	ze := &zipEntry{
+		fh: header,
+	}
+
+	ze.allocatedSize = int64(header.UncompressedSize64)
 	z.cpuRateLimiter.Request()
 	z.memoryRateLimiter.Request(ze.allocatedSize)
 
-	if method == zip.Deflate && fileSize >= minParallelFileSize {
+	fileSize := int64(header.UncompressedSize64)
+	if fileSize == 0 {
+		fileSize = int64(header.UncompressedSize)
+	}
+
+	if header.Method == zip.Deflate && fileSize >= minParallelFileSize {
 		wg := new(sync.WaitGroup)
 
 		// Allocate enough buffer to hold all readers. We'll limit
@@ -499,7 +591,7 @@
 		// Calculate the CRC in the background, since reading the entire
 		// file could take a while.
 		//
-		// We could split this up into chuncks as well, but it's faster
+		// We could split this up into chunks as well, but it's faster
 		// than the compression. Due to the Go Zip API, we also need to
 		// know the result before we can begin writing the compressed
 		// data out to the zipfile.
@@ -517,6 +609,9 @@
 			var dict []byte
 			if start >= windowSize {
 				dict, err = ioutil.ReadAll(io.NewSectionReader(r, start-windowSize, windowSize))
+				if err != nil {
+					return err
+				}
 			}
 
 			wg.Add(1)
@@ -526,12 +621,15 @@
 		close(ze.futureReaders)
 
 		// Close the file handle after all readers are done
-		go func(wg *sync.WaitGroup, f *os.File) {
+		go func(wg *sync.WaitGroup, closer io.Closer) {
 			wg.Wait()
-			f.Close()
+			closer.Close()
 		}(wg, r)
 	} else {
-		go z.compressWholeFile(ze, r, compressChan)
+		go func() {
+			z.compressWholeFile(ze, r, compressChan)
+			r.Close()
+		}()
 	}
 
 	return nil
@@ -601,8 +699,7 @@
 	return buf, nil
 }
 
-func (z *zipWriter) compressWholeFile(ze *zipEntry, r *os.File, compressChan chan *zipEntry) {
-	defer r.Close()
+func (z *zipWriter) compressWholeFile(ze *zipEntry, r io.ReadSeeker, compressChan chan *zipEntry) {
 
 	crc := crc32.NewIEEE()
 	_, err := io.Copy(crc, r)
@@ -619,13 +716,13 @@
 		return
 	}
 
-	readFile := func(r *os.File) ([]byte, error) {
-		_, err = r.Seek(0, 0)
+	readFile := func(reader io.ReadSeeker) ([]byte, error) {
+		_, err := reader.Seek(0, 0)
 		if err != nil {
 			return nil, err
 		}
 
-		buf, err := ioutil.ReadAll(r)
+		buf, err := ioutil.ReadAll(reader)
 		if err != nil {
 			return nil, err
 		}
@@ -686,53 +783,57 @@
 	zipHeader.Extra = append(zipHeader.Extra, data...)
 }
 
-func (z *zipWriter) writeDirectory(dir string) error {
+// writeDirectory annotates that dir is a directory created for the src file or directory, and adds
+// the directory entry to the zip file if directories are enabled.
+func (z *zipWriter) writeDirectory(dir, src string) error {
 	// clean the input
-	cleanDir := filepath.Clean(dir)
+	dir = filepath.Clean(dir)
 
 	// discover any uncreated directories in the path
 	zipDirs := []string{}
-	for cleanDir != "" && cleanDir != "." && !z.createdDirs[cleanDir] {
+	for dir != "" && dir != "." {
+		if _, exists := z.createdDirs[dir]; exists {
+			break
+		}
 
-		z.createdDirs[cleanDir] = true
+		if prev, exists := z.createdFiles[dir]; exists {
+			return fmt.Errorf("destination %q is both a directory %q and a file %q", dir, src, prev)
+		}
+
+		z.createdDirs[dir] = src
 		// parent directories precede their children
-		zipDirs = append([]string{cleanDir}, zipDirs...)
+		zipDirs = append([]string{dir}, zipDirs...)
 
-		cleanDir = filepath.Dir(cleanDir)
+		dir = filepath.Dir(dir)
 	}
 
-	// make a directory entry for each uncreated directory
-	for _, cleanDir := range zipDirs {
-		dirHeader := &zip.FileHeader{
-			Name: cleanDir + "/",
-		}
-		dirHeader.SetMode(0700 | os.ModeDir)
-		dirHeader.SetModTime(z.time)
+	if z.directories {
+		// make a directory entry for each uncreated directory
+		for _, cleanDir := range zipDirs {
+			dirHeader := &zip.FileHeader{
+				Name: cleanDir + "/",
+			}
+			dirHeader.SetMode(0700 | os.ModeDir)
+			dirHeader.SetModTime(z.time)
 
-		if *emulateJar && dir == "META-INF/" {
-			// Jar files have a 0-length extra field with header "CAFE"
-			z.addExtraField(dirHeader, [2]byte{0xca, 0xfe}, []byte{})
-		}
+			if *emulateJar && dir == "META-INF/" {
+				// Jar files have a 0-length extra field with header "CAFE"
+				z.addExtraField(dirHeader, [2]byte{0xca, 0xfe}, []byte{})
+			}
 
-		ze := make(chan *zipEntry, 1)
-		ze <- &zipEntry{
-			fh: dirHeader,
+			ze := make(chan *zipEntry, 1)
+			ze <- &zipEntry{
+				fh: dirHeader,
+			}
+			close(ze)
+			z.writeOps <- ze
 		}
-		close(ze)
-		z.writeOps <- ze
 	}
 
 	return nil
 }
 
 func (z *zipWriter) writeSymlink(rel, file string) error {
-	if z.directories {
-		dir, _ := filepath.Split(rel)
-		if err := z.writeDirectory(dir); err != nil {
-			return err
-		}
-	}
-
 	fileHeader := &zip.FileHeader{
 		Name: rel,
 	}
@@ -761,3 +862,15 @@
 
 	return nil
 }
+
+func recursiveGlobFiles(path string) []string {
+	var files []string
+	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+		if !info.IsDir() {
+			files = append(files, path)
+		}
+		return nil
+	})
+
+	return files
+}
diff --git a/jar/jar.go b/jar/jar.go
index d8f063c..5960bf0 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -19,6 +19,12 @@
 	"strings"
 )
 
+const (
+	MetaDir         = "META-INF/"
+	ManifestFile    = MetaDir + "MANIFEST.MF"
+	ModuleInfoClass = "module-info.class"
+)
+
 // EntryNamesLess tells whether <filepathA> should precede <filepathB> in
 // the order of files with a .jar
 func EntryNamesLess(filepathA string, filepathB string) (less bool) {
@@ -39,9 +45,9 @@
 }
 
 var jarOrder = []string{
-	"META-INF/",
-	"META-INF/MANIFEST.MF",
-	"META-INF/*",
+	MetaDir,
+	ManifestFile,
+	MetaDir + "*",
 	"*",
 }
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 12643cf..680d864 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -26,9 +26,12 @@
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
 		OutputFile: android.OptionalPathForPath(library.outputFile),
+		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
-				fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := .jar")
+				if library.properties.Installable != nil && *library.properties.Installable == false {
+					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+				}
 			},
 		},
 	}
@@ -38,9 +41,10 @@
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
 		OutputFile: android.OptionalPathForPath(prebuilt.combinedClasspathFile),
+		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
-				fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := .jar")
+				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 			},
 		},
 	}
@@ -50,10 +54,11 @@
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
 		OutputFile: android.OptionalPathForPath(binary.outputFile),
-		SubName:    ".jar",
+		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			android.WriteAndroidMkData(w, data)
 
+			fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
 			fmt.Fprintln(w, "include $(CLEAR_VARS)")
 			fmt.Fprintln(w, "LOCAL_MODULE := "+name)
 			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := EXECUTABLES")
@@ -61,9 +66,12 @@
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 			}
 			fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
-			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+name+".jar")
-			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE := "+binary.wrapperFile.String())
+			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", binary.wrapperFile.String())
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+
+			// Ensure that the wrapper script timestamp is always updated when the jar is updated
+			fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
+			fmt.Fprintln(w, "jar_installed_module :=")
 		},
 	}
 }
diff --git a/java/app.go b/java/app.go
index ceb7791..e6b91a7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -21,6 +21,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -68,7 +69,7 @@
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
 
-	if !a.properties.No_standard_libraries {
+	if !proptools.Bool(a.properties.No_standard_libs) {
 		switch a.deviceProperties.Sdk_version { // TODO: Res_sdk_version?
 		case "current", "system_current", "":
 			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
@@ -150,7 +151,7 @@
 	}
 
 	a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates)
-	ctx.InstallFileName(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+	ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
 }
 
 var aaptIgnoreFilenames = []string{
diff --git a/java/builder.go b/java/builder.go
index efe0a6b..d6f8c5b 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -21,9 +21,10 @@
 import (
 	"strings"
 
-	"android/soong/android"
-
 	"github.com/google/blueprint"
+
+	"android/soong/android"
+	"android/soong/java/config"
 )
 
 var (
@@ -38,12 +39,31 @@
 	javac = pctx.AndroidGomaStaticRule("javac",
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" "$annoDir" && mkdir -p "$outDir" "$annoDir" && ` +
-				`${config.JavacWrapper}${config.JavacCmd} ${config.CommonJdkFlags} ` +
+				`${config.JavacWrapper}${config.JavacCmd} ${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
 				`$javacFlags $bootClasspath $classpath ` +
 				`-source $javaVersion -target $javaVersion ` +
 				`-d $outDir -s $annoDir @$out.rsp && ` +
-				`find $outDir -type f | sort | ${config.JarArgsCmd} $outDir > $out`,
-			CommandDeps:    []string{"${config.JavacCmd}", "${config.JarArgsCmd}"},
+				`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
+			CommandDeps:    []string{"${config.JavacCmd}", "${config.SoongZipCmd}"},
+			Rspfile:        "$out.rsp",
+			RspfileContent: "$in",
+		},
+		"javacFlags", "bootClasspath", "classpath", "outDir", "annoDir", "javaVersion")
+
+	errorprone = pctx.AndroidStaticRule("errorprone",
+		blueprint.RuleParams{
+			Command: `rm -rf "$outDir" "$annoDir" && mkdir -p "$outDir" "$annoDir" && ` +
+				`${config.ErrorProneCmd} ` +
+				`$javacFlags $bootClasspath $classpath ` +
+				`-source $javaVersion -target $javaVersion ` +
+				`-d $outDir -s $annoDir @$out.rsp && ` +
+				`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
+			CommandDeps: []string{
+				"${config.JavaCmd}",
+				"${config.ErrorProneJavacJar}",
+				"${config.ErrorProneJar}",
+				"${config.SoongZipCmd}",
+			},
 			Rspfile:        "$out.rsp",
 			RspfileContent: "$in",
 		},
@@ -51,17 +71,24 @@
 
 	jar = pctx.AndroidStaticRule("jar",
 		blueprint.RuleParams{
-			Command:     `${config.JarCmd} $operation ${out}.tmp $manifest $jarArgs && ${config.Zip2ZipCmd} -t -i ${out}.tmp -o ${out} && rm ${out}.tmp`,
-			CommandDeps: []string{"${config.JarCmd}"},
+			Command:     `${config.SoongZipCmd} -jar -o $out $jarArgs`,
+			CommandDeps: []string{"${config.SoongZipCmd}"},
 		},
-		"operation", "manifest", "jarArgs")
+		"jarArgs")
+
+	combineJar = pctx.AndroidStaticRule("combineJar",
+		blueprint.RuleParams{
+			Command:     `${config.MergeZipsCmd} -j $out $in`,
+			CommandDeps: []string{"${config.MergeZipsCmd}"},
+		},
+		"outDir")
 
 	dx = pctx.AndroidStaticRule("dx",
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-				`${config.DxCmd} --dex --output=$outDir $dxFlags $in && ` +
-				`find "$outDir" -name "classes*.dex" | sort | ${config.JarArgsCmd} ${outDir} > $out`,
-			CommandDeps: []string{"${config.DxCmd}", "${config.JarArgsCmd}"},
+				`${config.DxCmd} --dex --output=$outDir $dxFlags $in || ( rm -rf "$outDir"; exit 41 ) && ` +
+				`find "$outDir" -name "classes*.dex" | sort > $out`,
+			CommandDeps: []string{"${config.DxCmd}"},
 		},
 		"outDir", "dxFlags")
 
@@ -71,22 +98,6 @@
 			CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
 		},
 		"rulesFile")
-
-	extractPrebuilt = pctx.AndroidStaticRule("extractPrebuilt",
-		blueprint.RuleParams{
-			Command: `rm -rf $outDir && unzip -qo $in -d $outDir && ` +
-				`find $outDir -name "*.class" | sort | ${config.JarArgsCmd} ${outDir} > $classFile && ` +
-				`find $outDir -type f -a \! -name "*.class" -a \! -name "MANIFEST.MF" | sort | ${config.JarArgsCmd} ${outDir} > $resourceFile`,
-			CommandDeps: []string{"${config.JarArgsCmd}"},
-		},
-		"outDir", "classFile", "resourceFile")
-
-	fileListToJarArgs = pctx.AndroidStaticRule("fileListToJarArgs",
-		blueprint.RuleParams{
-			Command:     `${config.JarArgsCmd} -f $in -p ${outDir} -o $out`,
-			CommandDeps: []string{"${config.JarjarCmd}"},
-		},
-		"outDir")
 )
 
 func init() {
@@ -103,23 +114,19 @@
 }
 
 type jarSpec struct {
-	android.ModuleOutPath
+	fileList, dir android.Path
 }
 
-func (j jarSpec) jarArgs() string {
-	return "@" + j.String()
+func (j jarSpec) soongJarArgs() string {
+	return "-C " + j.dir.String() + " -l " + j.fileList.String()
 }
 
-func (j jarSpec) path() android.Path {
-	return j.ModuleOutPath
-}
-
-func TransformJavaToClasses(ctx android.ModuleContext, srcFiles android.Paths, srcFileLists android.Paths,
-	flags javaBuilderFlags, deps android.Paths) jarSpec {
+func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
+	flags javaBuilderFlags, deps android.Paths) android.ModuleOutPath {
 
 	classDir := android.PathForModuleOut(ctx, "classes")
 	annoDir := android.PathForModuleOut(ctx, "anno")
-	classFileList := android.PathForModuleOut(ctx, "classes.list")
+	classJar := android.PathForModuleOut(ctx, "classes.jar")
 
 	javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@")
 
@@ -128,6 +135,41 @@
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:        javac,
 		Description: "javac",
+		Output:      classJar,
+		Inputs:      srcFiles,
+		Implicits:   deps,
+		Args: map[string]string{
+			"javacFlags":    javacFlags,
+			"bootClasspath": flags.bootClasspath,
+			"classpath":     flags.classpath,
+			"outDir":        classDir.String(),
+			"annoDir":       annoDir.String(),
+			"javaVersion":   flags.javaVersion,
+		},
+	})
+
+	return classJar
+}
+
+func RunErrorProne(ctx android.ModuleContext, srcFiles android.Paths, srcFileLists android.Paths,
+	flags javaBuilderFlags, deps android.Paths) android.Path {
+
+	if config.ErrorProneJar == "" {
+		ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
+		return nil
+	}
+
+	classDir := android.PathForModuleOut(ctx, "classes-errorprone")
+	annoDir := android.PathForModuleOut(ctx, "anno-errorprone")
+	classFileList := android.PathForModuleOut(ctx, "classes-errorprone.list")
+
+	javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@")
+
+	deps = append(deps, srcFileLists...)
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:        errorprone,
+		Description: "errorprone",
 		Output:      classFileList,
 		Inputs:      srcFiles,
 		Implicits:   deps,
@@ -141,26 +183,24 @@
 		},
 	})
 
-	return jarSpec{classFileList}
+	return classFileList
 }
 
-func TransformClassesToJar(ctx android.ModuleContext, classes []jarSpec,
-	manifest android.OptionalPath) android.Path {
+func TransformResourcesToJar(ctx android.ModuleContext, resources []jarSpec,
+	manifest android.OptionalPath, deps android.Paths) android.Path {
 
-	outputFile := android.PathForModuleOut(ctx, "classes-full-debug.jar")
+	outputFile := android.PathForModuleOut(ctx, "res.jar")
 
-	deps := android.Paths{}
 	jarArgs := []string{}
 
-	for _, j := range classes {
-		deps = append(deps, j.path())
-		jarArgs = append(jarArgs, j.jarArgs())
+	for _, j := range resources {
+		deps = append(deps, j.fileList)
+		jarArgs = append(jarArgs, j.soongJarArgs())
 	}
 
-	operation := "cf"
 	if manifest.Valid() {
-		operation = "cfm"
 		deps = append(deps, manifest.Path())
+		jarArgs = append(jarArgs, "-m "+manifest.String())
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@@ -169,15 +209,31 @@
 		Output:      outputFile,
 		Implicits:   deps,
 		Args: map[string]string{
-			"jarArgs":   strings.Join(jarArgs, " "),
-			"operation": operation,
-			"manifest":  manifest.String(),
+			"jarArgs": strings.Join(jarArgs, " "),
 		},
 	})
 
 	return outputFile
 }
 
+func TransformJarsToJar(ctx android.ModuleContext, stem string, jars android.Paths) android.Path {
+
+	outputFile := android.PathForModuleOut(ctx, stem)
+
+	if len(jars) == 1 {
+		return jars[0]
+	}
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:        combineJar,
+		Description: "combine jars",
+		Output:      outputFile,
+		Inputs:      jars,
+	})
+
+	return outputFile
+}
+
 func TransformClassesJarToDex(ctx android.ModuleContext, classesJar android.Path,
 	flags javaBuilderFlags) jarSpec {
 
@@ -195,7 +251,7 @@
 		},
 	})
 
-	return jarSpec{outputFile}
+	return jarSpec{outputFile, outDir}
 }
 
 func TransformDexToJavaLib(ctx android.ModuleContext, resources []jarSpec,
@@ -206,12 +262,12 @@
 	var jarArgs []string
 
 	for _, j := range resources {
-		deps = append(deps, j.path())
-		jarArgs = append(jarArgs, j.jarArgs())
+		deps = append(deps, j.fileList)
+		jarArgs = append(jarArgs, j.soongJarArgs())
 	}
 
-	deps = append(deps, dexJarSpec.path())
-	jarArgs = append(jarArgs, dexJarSpec.jarArgs())
+	deps = append(deps, dexJarSpec.fileList)
+	jarArgs = append(jarArgs, dexJarSpec.soongJarArgs())
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:        jar,
@@ -219,15 +275,14 @@
 		Output:      outputFile,
 		Implicits:   deps,
 		Args: map[string]string{
-			"operation": "cf",
-			"jarArgs":   strings.Join(jarArgs, " "),
+			"jarArgs": strings.Join(jarArgs, " "),
 		},
 	})
 
 	return outputFile
 }
 
-func TransformJarJar(ctx android.ModuleContext, classesJar android.Path, rulesFile android.Path) android.Path {
+func TransformJarJar(ctx android.ModuleContext, classesJar android.Path, rulesFile android.Path) android.ModuleOutPath {
 	outputFile := android.PathForModuleOut(ctx, "classes-jarjar.jar")
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:        jarjar,
@@ -242,41 +297,3 @@
 
 	return outputFile
 }
-
-func TransformPrebuiltJarToClasses(ctx android.ModuleContext,
-	subdir string, prebuilt android.Path) (classJarSpec, resourceJarSpec jarSpec) {
-
-	classDir := android.PathForModuleOut(ctx, subdir, "classes")
-	classFileList := android.PathForModuleOut(ctx, subdir, "classes.list")
-	resourceFileList := android.PathForModuleOut(ctx, subdir, "resources.list")
-
-	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:        extractPrebuilt,
-		Description: "extract classes",
-		Outputs:     android.WritablePaths{classFileList, resourceFileList},
-		Input:       prebuilt,
-		Args: map[string]string{
-			"outDir":       classDir.String(),
-			"classFile":    classFileList.String(),
-			"resourceFile": resourceFileList.String(),
-		},
-	})
-
-	return jarSpec{classFileList}, jarSpec{resourceFileList}
-}
-
-func TransformFileListToJarSpec(ctx android.ModuleContext, dir, fileListFile android.Path) jarSpec {
-	outputFile := android.PathForModuleOut(ctx, fileListFile.Base()+".jarArgs")
-
-	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:        fileListToJarArgs,
-		Description: "file list to jar args",
-		Output:      outputFile,
-		Input:       fileListFile,
-		Args: map[string]string{
-			"outDir": dir.String(),
-		},
-	})
-
-	return jarSpec{outputFile}
-}
diff --git a/java/config/config.go b/java/config/config.go
index 90d0fb5..5773164 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -32,8 +32,10 @@
 func init() {
 	pctx.Import("github.com/google/blueprint/bootstrap")
 
+	pctx.StaticVariable("JavacHeapSize", "2048M")
+	pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
+
 	pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
-		`-J-Xmx2048M`,
 		`-Xmaxerrs 9999999`,
 		`-encoding UTF-8`,
 		`-sourcepath ""`,
@@ -52,9 +54,12 @@
 	pctx.SourcePathVariable("JavaCmd", "${JavaToolchain}/java")
 	pctx.SourcePathVariable("JarCmd", "${JavaToolchain}/jar")
 	pctx.SourcePathVariable("JavadocCmd", "${JavaToolchain}/javadoc")
+	pctx.SourcePathVariable("JlinkCmd", "${JavaToolchain}/jlink")
+	pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
 
-	pctx.StaticVariable("Zip2ZipCmd", filepath.Join("${bootstrap.ToolDir}", "zip2zip"))
 	pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
+	pctx.StaticVariable("SoongZipCmd", filepath.Join("${bootstrap.ToolDir}", "soong_zip"))
+	pctx.StaticVariable("MergeZipsCmd", filepath.Join("${bootstrap.ToolDir}", "merge_zips"))
 	pctx.HostBinToolVariable("DxCmd", "dx")
 	pctx.HostJavaToolVariable("JarjarCmd", "jarjar.jar")
 
@@ -65,3 +70,17 @@
 		return "", nil
 	})
 }
+
+func StripJavac9Flags(flags []string) []string {
+	var ret []string
+	for _, f := range flags {
+		switch {
+		case strings.HasPrefix(f, "-J--add-modules="):
+			// drop
+		default:
+			ret = append(ret, f)
+		}
+	}
+
+	return ret
+}
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
new file mode 100644
index 0000000..31cbf2c
--- /dev/null
+++ b/java/config/error_prone.go
@@ -0,0 +1,45 @@
+// 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 config
+
+var (
+	// These will be filled out by external/error_prone/soong/error_prone.go if it is available
+	ErrorProneJavacJar    string
+	ErrorProneJar         string
+	ErrorProneClasspath   string
+	ErrorProneChecksError string
+	ErrorProneFlags       string
+)
+
+// Wrapper that grabs value of val late so it can be initialized by a later module's init function
+func errorProneVar(name string, val *string) {
+	pctx.VariableFunc(name, func(config interface{}) (string, error) {
+		return *val, nil
+	})
+}
+
+func init() {
+	errorProneVar("ErrorProneJar", &ErrorProneJar)
+	errorProneVar("ErrorProneJavacJar", &ErrorProneJavacJar)
+	errorProneVar("ErrorProneClasspath", &ErrorProneClasspath)
+	errorProneVar("ErrorProneChecksError", &ErrorProneChecksError)
+	errorProneVar("ErrorProneFlags", &ErrorProneFlags)
+
+	pctx.StaticVariable("ErrorProneCmd",
+		"${JavaCmd} -Xmx${JavacHeapSize} -Xbootclasspath/p:${ErrorProneJavacJar} "+
+			"-cp ${ErrorProneJar}:${ErrorProneClasspath} "+
+			"${ErrorProneFlags} ${CommonJdkFlags} ${ErrorProneChecksError}")
+
+}
diff --git a/java/config/makevars.go b/java/config/makevars.go
index ac02782..eda6c09 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -37,4 +37,17 @@
 	ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
 	ctx.Strict("JAVADOC", "${JavadocCmd}")
 	ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}")
+
+	if ctx.Config().IsEnvTrue("RUN_ERROR_PRONE") {
+		ctx.Strict("TARGET_JAVAC", "${ErrorProneCmd}")
+		ctx.Strict("HOST_JAVAC", "${ErrorProneCmd}")
+	} else {
+		ctx.Strict("TARGET_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
+		ctx.Strict("HOST_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
+	}
+
+	if ctx.Config().IsEnvTrue("EXPERIMENTAL_USE_OPENJDK9") {
+		ctx.Strict("JLINK", "${JlinkCmd}")
+		ctx.Strict("JMOD", "${JmodCmd}")
+	}
 }
diff --git a/java/java.go b/java/java.go
index ac88020..2298acc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	"android/soong/genrule"
@@ -76,7 +77,7 @@
 
 	// don't build against the default libraries (legacy-test, core-junit,
 	// ext, and framework for device targets)
-	No_standard_libraries bool
+	No_standard_libs *bool
 
 	// list of module-specific flags that will be used for javac compiles
 	Javacflags []string `android:"arch_variant"`
@@ -95,6 +96,15 @@
 
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
+
+	// If set to false, don't allow this module to be installed.  Defaults to true.
+	Installable *bool
+
+	// List of modules to use as annotation processors
+	Annotation_processors []string
+
+	// List of classes to pass to javac to use as annotation processors
+	Annotation_processor_classes []string
 }
 
 type CompilerDeviceProperties struct {
@@ -130,12 +140,6 @@
 	// output file suitable for installing or running
 	outputFile android.Path
 
-	// jarSpecs suitable for inserting classes from a static library into another jar
-	classJarSpecs []jarSpec
-
-	// jarSpecs suitable for inserting resources from a static library into another jar
-	resourceJarSpecs []jarSpec
-
 	exportAidlIncludeDirs android.Paths
 
 	logtagsSrcs android.Paths
@@ -150,8 +154,6 @@
 
 type Dependency interface {
 	ClasspathFiles() android.Paths
-	ClassJarSpecs() []jarSpec
-	ResourceJarSpecs() []jarSpec
 	AidlIncludeDirs() android.Paths
 }
 
@@ -166,23 +168,27 @@
 }
 
 var (
-	staticLibTag     = dependencyTag{name: "staticlib"}
-	libTag           = dependencyTag{name: "javalib"}
-	bootClasspathTag = dependencyTag{name: "bootclasspath"}
-	frameworkResTag  = dependencyTag{name: "framework-res"}
-	sdkDependencyTag = dependencyTag{name: "sdk"}
+	staticLibTag           = dependencyTag{name: "staticlib"}
+	libTag                 = dependencyTag{name: "javalib"}
+	bootClasspathTag       = dependencyTag{name: "bootclasspath"}
+	frameworkResTag        = dependencyTag{name: "framework-res"}
+	sdkDependencyTag       = dependencyTag{name: "sdk"}
+	annotationProcessorTag = dependencyTag{name: "annotation processor"}
 )
 
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
-	if !j.properties.No_standard_libraries {
+	if !proptools.Bool(j.properties.No_standard_libs) {
 		if ctx.Device() {
 			switch j.deviceProperties.Sdk_version {
 			case "":
-				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-oj", "core-libart")
+				ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
 			case "current":
 				// TODO: !TARGET_BUILD_APPS
 				// TODO: export preprocessed framework.aidl from android_stubs_current
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_stubs_current")
+			case "test_current":
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_test_stubs_current")
 			case "system_current":
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_system_stubs_current")
 			default:
@@ -190,16 +196,15 @@
 			}
 		} else {
 			if j.deviceProperties.Dex {
-				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-oj", "core-libart")
 			}
 		}
-
-		if ctx.Device() && j.deviceProperties.Sdk_version == "" {
-			ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
-		}
 	}
 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
 	ctx.AddDependency(ctx.Module(), staticLibTag, j.properties.Static_libs...)
+	ctx.AddDependency(ctx.Module(), annotationProcessorTag, j.properties.Annotation_processors...)
+
+	android.ExtractSourcesDeps(ctx, j.properties.Srcs)
 }
 
 func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
@@ -224,10 +229,18 @@
 	return flags
 }
 
-func (j *Module) collectDeps(ctx android.ModuleContext) (classpath android.Paths,
-	bootClasspath android.Paths, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess android.OptionalPath,
-	aidlIncludeDirs android.Paths, srcFileLists android.Paths) {
+type deps struct {
+	classpath            android.Paths
+	bootClasspath        android.Paths
+	staticJars           android.Paths
+	aidlIncludeDirs      android.Paths
+	srcFileLists         android.Paths
+	annotationProcessors android.Paths
+	aidlPreprocess       android.OptionalPath
+}
 
+func (j *Module) collectDeps(ctx android.ModuleContext) deps {
+	var deps deps
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -244,50 +257,62 @@
 
 		switch tag {
 		case bootClasspathTag:
-			bootClasspath = append(bootClasspath, dep.ClasspathFiles()...)
+			deps.bootClasspath = append(deps.bootClasspath, dep.ClasspathFiles()...)
 		case libTag:
-			classpath = append(classpath, dep.ClasspathFiles()...)
+			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
 		case staticLibTag:
-			classpath = append(classpath, dep.ClasspathFiles()...)
-			classJarSpecs = append(classJarSpecs, dep.ClassJarSpecs()...)
-			resourceJarSpecs = append(resourceJarSpecs, dep.ResourceJarSpecs()...)
+			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
+			deps.staticJars = append(deps.staticJars, dep.ClasspathFiles()...)
+		case annotationProcessorTag:
+			deps.annotationProcessors = append(deps.annotationProcessors, dep.ClasspathFiles()...)
 		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)
+				deps.srcFileLists = append(deps.srcFileLists, module.(*AndroidApp).aaptJavaFileList)
 			}
 		case sdkDependencyTag:
 			sdkDep := module.(sdkDependency)
+			deps.bootClasspath = append(deps.bootClasspath, sdkDep.ClasspathFiles()...)
 			if sdkDep.AidlPreprocessed().Valid() {
-				if aidlPreprocess.Valid() {
+				if deps.aidlPreprocess.Valid() {
 					ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
-						aidlPreprocess, sdkDep.AidlPreprocessed())
+						deps.aidlPreprocess, sdkDep.AidlPreprocessed())
 				} else {
-					aidlPreprocess = sdkDep.AidlPreprocessed()
+					deps.aidlPreprocess = sdkDep.AidlPreprocessed()
 				}
 			}
 		default:
 			panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 		}
 
-		aidlIncludeDirs = append(aidlIncludeDirs, dep.AidlIncludeDirs()...)
+		deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 	})
 
-	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
-		aidlIncludeDirs, srcFileLists
+	return deps
 }
 
 func (j *Module) compile(ctx android.ModuleContext) {
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Export_aidl_include_dirs)
 
-	classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
-		aidlIncludeDirs, srcFileLists := j.collectDeps(ctx)
+	deps := j.collectDeps(ctx)
 
 	var flags javaBuilderFlags
 
 	javacFlags := j.properties.Javacflags
+	if ctx.AConfig().Getenv("EXPERIMENTAL_USE_OPENJDK9") == "" {
+		javacFlags = config.StripJavac9Flags(javacFlags)
+	}
+
+	if len(deps.annotationProcessors) > 0 {
+		javacFlags = append(javacFlags,
+			"-processorpath "+strings.Join(deps.annotationProcessors.Strings(), ":"))
+	}
+
+	for _, c := range j.properties.Annotation_processor_classes {
+		javacFlags = append(javacFlags, "-processor "+c)
+	}
 
 	if j.properties.Java_version != nil {
 		flags.javaVersion = *j.properties.Java_version
@@ -300,22 +325,25 @@
 		flags.javacFlags = "$javacFlags"
 	}
 
-	aidlFlags := j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs)
+	aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
 	if len(aidlFlags) > 0 {
 		ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
 		flags.aidlFlags = "$aidlFlags"
 	}
 
-	var deps android.Paths
+	var extraDeps android.Paths
 
-	if len(bootClasspath) > 0 {
-		flags.bootClasspath = "-bootclasspath " + strings.Join(bootClasspath.Strings(), ":")
-		deps = append(deps, bootClasspath...)
+	if len(deps.bootClasspath) > 0 {
+		flags.bootClasspath = "-bootclasspath " + strings.Join(deps.bootClasspath.Strings(), ":")
+		extraDeps = append(extraDeps, deps.bootClasspath...)
+	} else if ctx.Device() {
+		// Explicitly clear the bootclasspath for device builds
+		flags.bootClasspath = `-bootclasspath ""`
 	}
 
-	if len(classpath) > 0 {
-		flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":")
-		deps = append(deps, classpath...)
+	if len(deps.classpath) > 0 {
+		flags.classpath = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
+		extraDeps = append(extraDeps, deps.classpath...)
 	}
 
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
@@ -328,46 +356,61 @@
 		}
 	})
 
-	srcFileLists = append(srcFileLists, j.ExtraSrcLists...)
+	deps.srcFileLists = append(deps.srcFileLists, j.ExtraSrcLists...)
+
+	var extraJarDeps android.Paths
+
+	var jars android.Paths
 
 	if len(srcFiles) > 0 {
 		// Compile java sources into .class files
-		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, deps)
+		classes := TransformJavaToClasses(ctx, srcFiles, deps.srcFileLists, flags, extraDeps)
 		if ctx.Failed() {
 			return
 		}
 
-		classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
+		if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
+			// If error-prone is enabled, add an additional rule to compile the java files into
+			// a separate set of classes (so that they don't overwrite the normal ones and require
+			// a rebuild when error-prone is turned off).  Add the classes as a dependency to
+			// the jar command so the two compiles can run in parallel.
+			// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
+			//    enable error-prone without affecting the output class files.
+			errorprone := RunErrorProne(ctx, srcFiles, deps.srcFileLists, flags, extraDeps)
+			extraJarDeps = append(extraJarDeps, errorprone)
+		}
+
+		jars = append(jars, classes)
 	}
 
-	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs, j.properties.Exclude_resource_dirs),
-		resourceJarSpecs...)
-
+	resourceJarSpecs := ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs, j.properties.Exclude_resource_dirs)
 	manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
 
-	allJarSpecs := append([]jarSpec(nil), classJarSpecs...)
-	allJarSpecs = append(allJarSpecs, resourceJarSpecs...)
+	if len(resourceJarSpecs) > 0 || manifest.Valid() {
+		// Combine classes + resources into classes-full-debug.jar
+		resourceJar := TransformResourcesToJar(ctx, resourceJarSpecs, manifest, extraJarDeps)
+		if ctx.Failed() {
+			return
+		}
 
-	// Combine classes + resources into classes-full-debug.jar
-	outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest)
-	if ctx.Failed() {
-		return
+		jars = append(jars, resourceJar)
 	}
 
+	jars = append(jars, deps.staticJars...)
+
+	// Combine the classes built from sources, any manifests, and any static libraries into
+	// classes-combined.jar.  If there is only one input jar this step will be skipped.
+	outputFile := TransformJarsToJar(ctx, "classes-combined.jar", jars)
+
 	if j.properties.Jarjar_rules != nil {
 		jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
-		// Transform classes-full-debug.jar into classes-jarjar.jar
+		// Transform classes-combined.jar into classes-jarjar.jar
 		outputFile = TransformJarJar(ctx, outputFile, jarjar_rules)
 		if ctx.Failed() {
 			return
 		}
-
-		classes, _ := TransformPrebuiltJarToClasses(ctx, "jarjar_extracted", outputFile)
-		classJarSpecs = []jarSpec{classes}
 	}
 
-	j.resourceJarSpecs = resourceJarSpecs
-	j.classJarSpecs = classJarSpecs
 	j.classpathFile = outputFile
 
 	if j.deviceProperties.Dex && len(srcFiles) > 0 {
@@ -394,6 +437,16 @@
 				"--dump-width=1000")
 		}
 
+		var minSdkVersion string
+		switch j.deviceProperties.Sdk_version {
+		case "", "current", "test_current", "system_current":
+			minSdkVersion = strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
+		default:
+			minSdkVersion = j.deviceProperties.Sdk_version
+		}
+
+		dxFlags = append(dxFlags, "--min-sdk-version="+minSdkVersion)
+
 		flags.dxFlags = strings.Join(dxFlags, " ")
 
 		// Compile classes.jar into classes.dex
@@ -415,14 +468,6 @@
 	return android.Paths{j.classpathFile}
 }
 
-func (j *Module) ClassJarSpecs() []jarSpec {
-	return j.classJarSpecs
-}
-
-func (j *Module) ResourceJarSpecs() []jarSpec {
-	return j.resourceJarSpecs
-}
-
 func (j *Module) AidlIncludeDirs() android.Paths {
 	return j.exportAidlIncludeDirs
 }
@@ -444,7 +489,10 @@
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.compile(ctx)
 
-	j.installFile = ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile)
+	if j.properties.Installable == nil || *j.properties.Installable == true {
+		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+			ctx.ModuleName()+".jar", j.outputFile)
+	}
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -497,8 +545,8 @@
 	// 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.
 	j.wrapperFile = android.PathForModuleSrc(ctx, j.binaryProperties.Wrapper)
-	j.binaryFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"),
-		j.wrapperFile, j.installFile)
+	j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
+		ctx.ModuleName(), j.wrapperFile, j.installFile)
 }
 
 func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -545,9 +593,8 @@
 
 	properties ImportProperties
 
-	classpathFiles                  android.Paths
-	combinedClasspathFile           android.Path
-	classJarSpecs, resourceJarSpecs []jarSpec
+	classpathFiles        android.Paths
+	combinedClasspathFile android.Path
 }
 
 func (j *Import) Prebuilt() *android.Prebuilt {
@@ -568,17 +615,7 @@
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.classpathFiles = android.PathsForModuleSrc(ctx, j.properties.Jars)
 
-	for i, prebuilt := range j.classpathFiles {
-		subdir := "extracted" + strconv.Itoa(i)
-		classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, subdir, prebuilt)
-		j.classJarSpecs = append(j.classJarSpecs, classJarSpec)
-		j.resourceJarSpecs = append(j.resourceJarSpecs, resourceJarSpec)
-	}
-
-	j.combinedClasspathFile = TransformClassesToJar(ctx, j.classJarSpecs, android.OptionalPath{})
-
-	ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"),
-		ctx.ModuleName()+".jar", j.combinedClasspathFile)
+	j.combinedClasspathFile = TransformJarsToJar(ctx, "classes.jar", j.classpathFiles)
 }
 
 var _ Dependency = (*Import)(nil)
@@ -587,14 +624,6 @@
 	return j.classpathFiles
 }
 
-func (j *Import) ClassJarSpecs() []jarSpec {
-	return j.classJarSpecs
-}
-
-func (j *Import) ResourceJarSpecs() []jarSpec {
-	return j.resourceJarSpecs
-}
-
 func (j *Import) AidlIncludeDirs() android.Paths {
 	return nil
 }
diff --git a/java/java_test.go b/java/java_test.go
index eb116c9..4f5c0ec 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"reflect"
 	"strings"
 	"testing"
 )
@@ -62,13 +63,14 @@
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	ctx.Register()
 
-	extraModules := []string{"core-libart", "frameworks", "sdk_v14"}
+	extraModules := []string{"core-oj", "core-libart", "frameworks", "sdk_v14"}
 
 	for _, extra := range extraModules {
 		bp += fmt.Sprintf(`
 			java_library {
 				name: "%s",
-				no_standard_libraries: true,
+				srcs: ["a.java"],
+				no_standard_libs: true,
 			}
 		`, extra)
 	}
@@ -111,20 +113,25 @@
 		`)
 
 	javac := ctx.ModuleForTests("foo", "").Rule("javac")
-	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+	combineJar := ctx.ModuleForTests("foo", "").Rule("combineJar")
 
 	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")
+	bar := filepath.Join(buildDir, ".intermediates", "bar", "classes.jar")
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.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)
+	if !strings.Contains(javac.Args["classpath"], baz) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], baz)
+	}
+
+	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
+		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
 	}
 }
 
@@ -173,10 +180,11 @@
 		bootclasspathLib
 	)
 
-	check := func(module, dep string, depType depType) {
-		if dep != "" {
-			dep = filepath.Join(buildDir, ".intermediates", dep, "classes-full-debug.jar")
+	check := func(module string, depType depType, deps ...string) {
+		for i := range deps {
+			deps[i] = filepath.Join(buildDir, ".intermediates", deps[i], "classes.jar")
 		}
+		dep := strings.Join(deps, ":")
 
 		javac := ctx.ModuleForTests(module, "").Rule("javac")
 
@@ -192,12 +200,18 @@
 			}
 		}
 
-		if len(javac.Implicits) != 1 || javac.Implicits[0].String() != dep {
-			t.Errorf("module %q implicits != [%q]", dep)
+		if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
+			t.Errorf("module %q implicits %q != %q", module, javac.Implicits.Strings(), deps)
 		}
 	}
 
-	check("foo1", "core-libart", bootclasspathLib)
+	check("foo1", bootclasspathLib, "core-oj", "core-libart")
+	check("foo2", bootclasspathLib, "core-oj", "core-libart")
+	// TODO(ccross): these need the arch mutator to run to work correctly
+	//check("foo3", bootclasspathLib, "sdk_v14")
+	//check("foo4", bootclasspathLib, "android_stubs_current")
+	//check("foo5", bootclasspathLib, "android_system_stubs_current")
+	//check("foo6", bootclasspathLib, "android_test_stubs_current")
 }
 
 func TestPrebuilts(t *testing.T) {
@@ -221,16 +235,15 @@
 		`)
 
 	javac := ctx.ModuleForTests("foo", "").Rule("javac")
-	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+	combineJar := ctx.ModuleForTests("foo", "").Rule("combineJar")
 
 	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", "extracted0", "classes.list")
-	if !strings.Contains(jar.Args["jarArgs"], baz) {
-		t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != "b.jar" {
+		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, "b.jar")
 	}
 }
 
@@ -260,20 +273,20 @@
 		`)
 
 	javac := ctx.ModuleForTests("foo", "").Rule("javac")
-	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+	combineJar := ctx.ModuleForTests("foo", "").Rule("combineJar")
 
 	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")
+	bar := filepath.Join(buildDir, ".intermediates", "bar", "classes.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)
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.jar")
+	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
+		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
 	}
 }
 
diff --git a/java/resources.go b/java/resources.go
index f1c9d06..60dc934 100644
--- a/java/resources.go
+++ b/java/resources.go
@@ -63,7 +63,7 @@
 
 			pattern := filepath.Join(dir.String(), "**/*")
 			bootstrap.GlobFile(ctx, pattern, excludes, fileListFile.String(), depFile)
-			jarSpecs = append(jarSpecs, TransformFileListToJarSpec(ctx, dir, fileListFile))
+			jarSpecs = append(jarSpecs, jarSpec{fileListFile, dir})
 		}
 	}
 
diff --git a/python/androidmk.go b/python/androidmk.go
index ab24e99..25abdc9 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -23,10 +23,10 @@
 )
 
 type subAndroidMkProvider interface {
-	AndroidMk(*pythonBaseModule, *android.AndroidMkData)
+	AndroidMk(*Module, *android.AndroidMkData)
 }
 
-func (p *pythonBaseModule) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (p *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
 	if p.subAndroidMkOnce == nil {
 		p.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
 	}
@@ -38,7 +38,7 @@
 	}
 }
 
-func (p *pythonBaseModule) AndroidMk() android.AndroidMkData {
+func (p *Module) AndroidMk() android.AndroidMkData {
 	ret := android.AndroidMkData{}
 
 	p.subAndroidMk(&ret, p.installer)
@@ -46,17 +46,17 @@
 	return ret
 }
 
-func (p *pythonBinaryHostDecorator) AndroidMk(base *pythonBaseModule, ret *android.AndroidMkData) {
+func (p *binaryDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
 	ret.Class = "EXECUTABLES"
-	base.subAndroidMk(ret, p.pythonDecorator.baseInstaller)
+	base.subAndroidMk(ret, p.baseInstaller)
 }
 
-func (p *pythonTestHostDecorator) AndroidMk(base *pythonBaseModule, ret *android.AndroidMkData) {
+func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
 	ret.Class = "NATIVE_TESTS"
-	base.subAndroidMk(ret, p.pythonDecorator.baseInstaller)
+	base.subAndroidMk(ret, p.binaryDecorator.baseInstaller)
 }
 
-func (installer *pythonInstaller) AndroidMk(base *pythonBaseModule, ret *android.AndroidMkData) {
+func (installer *pythonInstaller) AndroidMk(base *Module, ret *android.AndroidMkData) {
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
 	if base.Target().Os.Class == android.Host {
diff --git a/python/binary.go b/python/binary.go
index ae2693b..91b7a54 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -21,6 +21,8 @@
 	"path/filepath"
 	"strings"
 
+	"github.com/google/blueprint"
+
 	"android/soong/android"
 )
 
@@ -28,67 +30,63 @@
 	android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
 }
 
-type PythonBinaryBaseProperties struct {
+type BinaryProperties struct {
 	// the name of the source file that is the main entry point of the program.
 	// this file must also be listed in srcs.
 	// If left unspecified, module name is used instead.
 	// If name doesn’t match any filename in srcs, main must be specified.
-	Main string
+	Main string `android:"arch_variant"`
 
 	// set the name of the output binary.
-	Stem string
+	Stem string `android:"arch_variant"`
 
 	// append to the name of the output binary.
-	Suffix string
+	Suffix string `android:"arch_variant"`
 }
 
-type pythonBinaryBase struct {
-	pythonBaseModule
+type binaryDecorator struct {
+	binaryProperties BinaryProperties
 
-	binaryProperties PythonBinaryBaseProperties
-
-	// soong_zip arguments from all its dependencies.
-	depsParSpecs []parSpec
-
-	// Python runfiles paths from all its dependencies.
-	depsPyRunfiles []string
+	baseInstaller *pythonInstaller
 }
 
-type PythonBinaryHost struct {
-	pythonBinaryBase
+type IntermPathProvider interface {
+	IntermPathForModuleOut() android.OptionalPath
 }
 
-var _ PythonSubModule = (*PythonBinaryHost)(nil)
-
-type pythonBinaryHostDecorator struct {
-	pythonDecorator
-}
-
-func (p *pythonBinaryHostDecorator) install(ctx android.ModuleContext, file android.Path) {
-	p.pythonDecorator.baseInstaller.install(ctx, file)
+func (binary *binaryDecorator) install(ctx android.ModuleContext, file android.Path) {
+	binary.baseInstaller.install(ctx, file)
 }
 
 var (
 	stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
 )
 
-func PythonBinaryHostFactory() android.Module {
-	decorator := &pythonBinaryHostDecorator{
-		pythonDecorator: pythonDecorator{baseInstaller: NewPythonInstaller("bin")}}
+func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
+	module := newModule(hod, android.MultilibFirst)
+	decorator := &binaryDecorator{baseInstaller: NewPythonInstaller("bin")}
 
-	module := &PythonBinaryHost{}
-	module.pythonBaseModule.installer = decorator
-	module.AddProperties(&module.binaryProperties)
+	module.bootstrapper = decorator
+	module.installer = decorator
 
-	return InitPythonBaseModule(&module.pythonBinaryBase.pythonBaseModule,
-		&module.pythonBinaryBase, android.HostSupportedNoCross)
+	return module, decorator
 }
 
-func (p *pythonBinaryBase) GeneratePythonBuildActions(ctx android.ModuleContext) android.OptionalPath {
-	p.pythonBaseModule.GeneratePythonBuildActions(ctx)
+func PythonBinaryHostFactory() android.Module {
+	module, _ := NewBinary(android.HostSupportedNoCross)
 
-	// no Python source file for compiling par file.
-	if len(p.pythonBaseModule.srcsPathMappings) == 0 && len(p.depsPyRunfiles) == 0 {
+	return module.Init()
+}
+
+func (binary *binaryDecorator) bootstrapperProps() []interface{} {
+	return []interface{}{&binary.binaryProperties}
+}
+
+func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actual_version string,
+	embedded_launcher bool, srcsPathMappings []pathMapping, parSpec parSpec,
+	depsPyRunfiles []string, depsParSpecs []parSpec) android.OptionalPath {
+	// no Python source file for compiling .par file.
+	if len(srcsPathMappings) == 0 {
 		return android.OptionalPath{}
 	}
 
@@ -100,10 +98,10 @@
 	existingPyPkgSet := make(map[string]bool)
 
 	wholePyRunfiles := []string{}
-	for _, path := range p.pythonBaseModule.srcsPathMappings {
+	for _, path := range srcsPathMappings {
 		wholePyRunfiles = append(wholePyRunfiles, path.dest)
 	}
-	wholePyRunfiles = append(wholePyRunfiles, p.depsPyRunfiles...)
+	wholePyRunfiles = append(wholePyRunfiles, depsPyRunfiles...)
 
 	// find all the runfiles dirs which have been treated as packages.
 	for _, path := range wholePyRunfiles {
@@ -130,50 +128,62 @@
 		populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs)
 	}
 
-	main := p.getPyMainFile(ctx)
+	main := binary.getPyMainFile(ctx, srcsPathMappings)
 	if main == "" {
 		return android.OptionalPath{}
 	}
-	interp := p.getInterpreter(ctx)
-	if interp == "" {
-		return android.OptionalPath{}
+
+	var launcher_path android.Path
+	if embedded_launcher {
+		ctx.VisitDirectDeps(func(m blueprint.Module) {
+			if ctx.OtherModuleDependencyTag(m) != launcherTag {
+				return
+			}
+			if provider, ok := m.(IntermPathProvider); ok {
+				if launcher_path != nil {
+					panic(fmt.Errorf("launcher path was found before: %q",
+						launcher_path))
+				}
+				launcher_path = provider.IntermPathForModuleOut().Path()
+			}
+		})
 	}
 
-	// we need remove "runfiles/" suffix since stub script starts
-	// searching for main file in each sub-dir of "runfiles" directory tree.
-	binFile := registerBuildActionForParFile(ctx, p.getInterpreter(ctx),
-		strings.TrimPrefix(main, runFiles+"/"), p.getStem(ctx),
-		newPyPkgs, append(p.depsParSpecs, p.pythonBaseModule.parSpec))
+	binFile := registerBuildActionForParFile(ctx, embedded_launcher, launcher_path,
+		binary.getHostInterpreterName(ctx, actual_version),
+		main, binary.getStem(ctx), newPyPkgs, append(depsParSpecs, parSpec))
 
 	return android.OptionalPathForPath(binFile)
 }
 
-// get interpreter path.
-func (p *pythonBinaryBase) getInterpreter(ctx android.ModuleContext) string {
+// get host interpreter name.
+func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext,
+	actual_version string) string {
 	var interp string
-	switch p.pythonBaseModule.properties.ActualVersion {
+	switch actual_version {
 	case pyVersion2:
 		interp = "python2"
 	case pyVersion3:
 		interp = "python3"
 	default:
 		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
-			p.properties.ActualVersion, ctx.ModuleName()))
+			actual_version, ctx.ModuleName()))
 	}
 
 	return interp
 }
 
 // find main program path within runfiles tree.
-func (p *pythonBinaryBase) getPyMainFile(ctx android.ModuleContext) string {
+func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext,
+	srcsPathMappings []pathMapping) string {
 	var main string
-	if p.binaryProperties.Main == "" {
-		main = p.BaseModuleName() + pyExt
+	if binary.binaryProperties.Main == "" {
+		main = ctx.ModuleName() + pyExt
 	} else {
-		main = p.binaryProperties.Main
+		main = binary.binaryProperties.Main
 	}
 
-	for _, path := range p.pythonBaseModule.srcsPathMappings {
+	for _, path := range srcsPathMappings {
 		if main == path.src.Rel() {
 			return path.dest
 		}
@@ -183,13 +193,13 @@
 	return ""
 }
 
-func (p *pythonBinaryBase) getStem(ctx android.ModuleContext) string {
+func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string {
 	stem := ctx.ModuleName()
-	if p.binaryProperties.Stem != "" {
-		stem = p.binaryProperties.Stem
+	if binary.binaryProperties.Stem != "" {
+		stem = binary.binaryProperties.Stem
 	}
 
-	return stem + p.binaryProperties.Suffix
+	return stem + binary.binaryProperties.Suffix
 }
 
 // Sets the given directory and all its ancestor directories as Python packages.
diff --git a/python/builder.go b/python/builder.go
index b823fcb..a459d3d 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -17,6 +17,7 @@
 // This file contains Ninja build actions for building Python program.
 
 import (
+	"fmt"
 	"strings"
 
 	"android/soong/android"
@@ -28,7 +29,7 @@
 var (
 	pctx = android.NewPackageContext("android/soong/python")
 
-	par = pctx.AndroidStaticRule("par",
+	host_par = pctx.AndroidStaticRule("host_par",
 		blueprint.RuleParams{
 			Command: `touch $initFile && ` +
 				`sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' $template > $stub && ` +
@@ -37,6 +38,16 @@
 			CommandDeps: []string{"$parCmd", "$template"},
 		},
 		"initFile", "interp", "main", "template", "stub", "parCmd", "parFile", "parArgs")
+
+	embedded_par = pctx.AndroidStaticRule("embedded_par",
+		blueprint.RuleParams{
+			Command: `touch $initFile && ` +
+				`echo '$main' > $entry_point && ` +
+				`$parCmd -o $parFile $parArgs && cat $launcher | cat - $parFile > $out && ` +
+				`chmod +x $out && (rm -f $initFile; rm -f $entry_point; rm -f $parFile)`,
+			CommandDeps: []string{"$parCmd"},
+		},
+		"initFile", "main", "entry_point", "parCmd", "parFile", "parArgs", "launcher")
 )
 
 func init() {
@@ -58,10 +69,10 @@
 }
 
 func (p parSpec) soongParArgs() string {
-	ret := "-P " + p.rootPrefix
+	ret := `-P ` + p.rootPrefix
 
 	for _, spec := range p.fileListSpecs {
-		ret += " -C " + spec.relativeRoot + " -l " + spec.fileList.String()
+		ret += ` -C ` + spec.relativeRoot + ` -l ` + spec.fileList.String()
 	}
 
 	return ret
@@ -89,22 +100,17 @@
 	return fileList
 }
 
-func registerBuildActionForParFile(ctx android.ModuleContext,
-	interpreter, main, binName string, newPyPkgs []string, parSpecs []parSpec) android.Path {
+func registerBuildActionForParFile(ctx android.ModuleContext, embedded_launcher bool,
+	launcher_path android.Path, interpreter, main, binName string,
+	newPyPkgs []string, parSpecs []parSpec) android.Path {
 
-	// intermediate output path for __init__.py
+	// .intermediate output path for __init__.py
 	initFile := android.PathForModuleOut(ctx, initFileName).String()
 
-	// the path of stub_template_host.txt from source tree.
-	template := android.PathForSource(ctx, stubTemplateHost)
-
-	// intermediate output path for __main__.py
-	stub := android.PathForModuleOut(ctx, mainFileName).String()
-
-	// intermediate output path for par file.
+	// .intermediate output path for par file.
 	parFile := android.PathForModuleOut(ctx, binName+parFileExt)
 
-	// intermediate output path for bin executable.
+	// .intermediate output path for bin executable.
 	binFile := android.PathForModuleOut(ctx, binName)
 
 	// implicit dependency for parFile build action.
@@ -116,32 +122,68 @@
 	}
 
 	parArgs := []string{}
-	parArgs = append(parArgs, "-C "+strings.TrimSuffix(stub, mainFileName)+" -f "+stub)
-	parArgs = append(parArgs, "-C "+strings.TrimSuffix(initFile, initFileName)+" -f "+initFile)
+	parArgs = append(parArgs, `-P "" `+`-C `+strings.TrimSuffix(initFile, initFileName)+` -f `+initFile)
 	for _, pkg := range newPyPkgs {
-		parArgs = append(parArgs, "-P "+pkg+" -f "+initFile)
+		parArgs = append(parArgs, `-P `+pkg+` -f `+initFile)
 	}
 	for _, p := range parSpecs {
 		parArgs = append(parArgs, p.soongParArgs())
 	}
 
-	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:        par,
-		Description: "python archive",
-		Output:      binFile,
-		Implicits:   implicits,
-		Args: map[string]string{
-			"initFile": initFile,
-			// the "\" isn't being interpreted by regex parser, it's being
-			// interpreted in the string literal.
-			"interp":   strings.Replace(interpreter, "/", `\/`, -1),
-			"main":     strings.Replace(main, "/", `\/`, -1),
-			"template": template.String(),
-			"stub":     stub,
-			"parFile":  parFile.String(),
-			"parArgs":  strings.Join(parArgs, " "),
-		},
-	})
+	if !embedded_launcher {
+		// the path of stub_template_host.txt from source tree.
+		template := android.PathForSource(ctx, stubTemplateHost)
+
+		// intermediate output path for __main__.py
+		stub := android.PathForModuleOut(ctx, mainFileName).String()
+
+		// added stub file to the soong_zip args.
+		parArgs = append(parArgs, `-P "" `+`-C `+strings.TrimSuffix(stub, mainFileName)+` -f `+stub)
+
+		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+			Rule:        host_par,
+			Description: "host python archive",
+			Output:      binFile,
+			Implicits:   implicits,
+			Args: map[string]string{
+				"initFile": initFile,
+				"interp":   strings.Replace(interpreter, "/", `\/`, -1),
+				// we need remove "runfiles/" suffix since stub script starts
+				// searching for main file in each sub-dir of "runfiles" directory tree.
+				"main": strings.Replace(strings.TrimPrefix(main, runFiles+"/"),
+					"/", `\/`, -1),
+				"template": template.String(),
+				"stub":     stub,
+				"parFile":  parFile.String(),
+				"parArgs":  strings.Join(parArgs, " "),
+			},
+		})
+	} else {
+		// added launcher_path to the implicits Ninja dependencies.
+		implicits = append(implicits, launcher_path)
+
+		// .intermediate output path for entry_point.txt
+		entryPoint := android.PathForModuleOut(ctx, entryPointFile).String()
+
+		// added entry_point file to the soong_zip args.
+		parArgs = append(parArgs, `-P "" `+`-C `+fmt.Sprintf(
+			"%q", strings.TrimSuffix(entryPoint, entryPointFile))+` -f `+entryPoint)
+
+		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+			Rule:        embedded_par,
+			Description: "embedded python archive",
+			Output:      binFile,
+			Implicits:   implicits,
+			Args: map[string]string{
+				"initFile":    initFile,
+				"main":        main,
+				"entry_point": entryPoint,
+				"parFile":     parFile.String(),
+				"parArgs":     strings.Join(parArgs, " "),
+				"launcher":    launcher_path.String(),
+			},
+		})
+	}
 
 	return binFile
 }
diff --git a/python/defaults.go b/python/defaults.go
new file mode 100644
index 0000000..641aca4
--- /dev/null
+++ b/python/defaults.go
@@ -0,0 +1,51 @@
+// 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 python
+
+import (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("python_defaults", defaultsFactory)
+}
+
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func (d *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(
+		&BaseProperties{},
+	)
+
+	android.InitDefaultsModule(module)
+
+	return module
+}
diff --git a/python/installer.go b/python/installer.go
index 9c12f5f..04698c5 100644
--- a/python/installer.go
+++ b/python/installer.go
@@ -35,5 +35,6 @@
 var _ installer = (*pythonInstaller)(nil)
 
 func (installer *pythonInstaller) install(ctx android.ModuleContext, file android.Path) {
-	installer.path = ctx.InstallFile(android.PathForModuleInstall(ctx, installer.dir), file)
+	installer.path = ctx.InstallFile(android.PathForModuleInstall(ctx, installer.dir),
+		file.Base(), file)
 }
diff --git a/python/library.go b/python/library.go
index 2039e56..58ee55f 100644
--- a/python/library.go
+++ b/python/library.go
@@ -24,14 +24,8 @@
 	android.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
 }
 
-type PythonLibrary struct {
-	pythonBaseModule
-}
-
-var _ PythonSubModule = (*PythonLibrary)(nil)
-
 func PythonLibraryHostFactory() android.Module {
-	module := &PythonLibrary{}
+	module := newModule(android.HostSupportedNoCross, android.MultilibFirst)
 
-	return InitPythonBaseModule(&module.pythonBaseModule, module, android.HostSupportedNoCross)
+	return module.Init()
 }
diff --git a/python/python.go b/python/python.go
index df5999d..e63c26c 100644
--- a/python/python.go
+++ b/python/python.go
@@ -24,6 +24,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -35,58 +36,70 @@
 }
 
 // the version properties that apply to python libraries and binaries.
-type PythonVersionProperties struct {
+type VersionProperties struct {
 	// true, if the module is required to be built with this version.
-	Enabled *bool
-
-	// if specified, common src files are converted to specific version with converter tool.
-	// Converter bool
+	Enabled *bool `android:"arch_variant"`
 
 	// non-empty list of .py files under this strict Python version.
 	// srcs may reference the outputs of other modules that produce source files like genrule
 	// or filegroup using the syntax ":module".
-	Srcs []string
+	Srcs []string `android:"arch_variant"`
+
+	// list of source files that should not be used to build the Python module.
+	// This is most useful in the arch/multilib variants to remove non-common files
+	Exclude_srcs []string `android:"arch_variant"`
 
 	// list of the Python libraries under this Python version.
-	Libs []string
+	Libs []string `android:"arch_variant"`
+
+	// true, if the binary is required to be built with embedded launcher.
+	// TODO(nanzhang): Remove this flag when embedded Python3 is supported later.
+	Embedded_launcher *bool `android:"arch_variant"`
 }
 
 // properties that apply to python libraries and binaries.
-type PythonBaseModuleProperties struct {
+type BaseProperties struct {
 	// the package path prefix within the output artifact at which to place the source/data
 	// files of the current module.
 	// eg. Pkg_path = "a/b/c"; Other packages can reference this module by using
 	// (from a.b.c import ...) statement.
 	// if left unspecified, all the source/data files of current module are copied to
 	// "runfiles/" tree directory directly.
-	Pkg_path string
+	Pkg_path string `android:"arch_variant"`
+
+	// true, if the Python module is used internally, eg, Python std libs.
+	Is_internal *bool `android:"arch_variant"`
 
 	// list of source (.py) files compatible both with Python2 and Python3 used to compile the
 	// Python module.
 	// srcs may reference the outputs of other modules that produce source files like genrule
 	// or filegroup using the syntax ":module".
 	// Srcs has to be non-empty.
-	Srcs []string
+	Srcs []string `android:"arch_variant"`
+
+	// list of source files that should not be used to build the C/C++ module.
+	// This is most useful in the arch/multilib variants to remove non-common files
+	Exclude_srcs []string `android:"arch_variant"`
 
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test. the file extension can be arbitrary except for (.py).
-	Data []string
+	Data []string `android:"arch_variant"`
 
 	// list of the Python libraries compatible both with Python2 and Python3.
-	Libs []string
+	Libs []string `android:"arch_variant"`
 
 	Version struct {
 		// all the "srcs" or Python dependencies that are to be used only for Python2.
-		Py2 PythonVersionProperties
+		Py2 VersionProperties `android:"arch_variant"`
 
 		// all the "srcs" or Python dependencies that are to be used only for Python3.
-		Py3 PythonVersionProperties
-	}
+		Py3 VersionProperties `android:"arch_variant"`
+	} `android:"arch_variant"`
 
 	// the actual version each module uses after variations created.
 	// this property name is hidden from users' perspectives, and soong will populate it during
 	// runtime.
-	ActualVersion string `blueprint:"mutated"`
+	Actual_version string `blueprint:"mutated"`
 }
 
 type pathMapping struct {
@@ -94,11 +107,22 @@
 	src  android.Path
 }
 
-type pythonBaseModule struct {
+type Module struct {
 	android.ModuleBase
-	subModule PythonSubModule
+	android.DefaultableModuleBase
 
-	properties PythonBaseModuleProperties
+	properties BaseProperties
+
+	// initialize before calling Init
+	hod      android.HostOrDeviceSupported
+	multilib android.Multilib
+
+	// the bootstrapper is used to bootstrap .par executable.
+	// bootstrapper might be nil (Python library module).
+	bootstrapper bootstrapper
+
+	// the installer might be nil.
+	installer installer
 
 	// the Python files of current module after expanding source dependencies.
 	// pathMapping: <dest: runfile_path, src: source_path>
@@ -108,17 +132,37 @@
 	// pathMapping: <dest: runfile_path, src: source_path>
 	dataPathMappings []pathMapping
 
+	// soong_zip arguments of all its dependencies.
+	depsParSpecs []parSpec
+
+	// Python runfiles paths of all its dependencies.
+	depsPyRunfiles []string
+
+	// (.intermediate) module output path as installation source.
+	installSource android.OptionalPath
+
 	// the soong_zip arguments for zipping current module source/data files.
 	parSpec parSpec
 
-	// the installer might be nil.
-	installer installer
-
 	subAndroidMkOnce map[subAndroidMkProvider]bool
 }
 
-type PythonSubModule interface {
-	GeneratePythonBuildActions(ctx android.ModuleContext) android.OptionalPath
+func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+	return &Module{
+		hod:      hod,
+		multilib: multilib,
+	}
+}
+
+type bootstrapper interface {
+	bootstrapperProps() []interface{}
+	bootstrap(ctx android.ModuleContext, Actual_version string, embedded_launcher bool,
+		srcsPathMappings []pathMapping, parSpec parSpec,
+		depsPyRunfiles []string, depsParSpecs []parSpec) android.OptionalPath
+}
+
+type installer interface {
+	install(ctx android.ModuleContext, path android.Path)
 }
 
 type PythonDependency interface {
@@ -127,64 +171,59 @@
 	GetParSpec() parSpec
 }
 
-type pythonDecorator struct {
-	baseInstaller *pythonInstaller
-}
-
-type installer interface {
-	install(ctx android.ModuleContext, path android.Path)
-}
-
-func (p *pythonBaseModule) GetSrcsPathMappings() []pathMapping {
+func (p *Module) GetSrcsPathMappings() []pathMapping {
 	return p.srcsPathMappings
 }
 
-func (p *pythonBaseModule) GetDataPathMappings() []pathMapping {
+func (p *Module) GetDataPathMappings() []pathMapping {
 	return p.dataPathMappings
 }
 
-func (p *pythonBaseModule) GetParSpec() parSpec {
+func (p *Module) GetParSpec() parSpec {
 	return p.parSpec
 }
 
-var _ PythonDependency = (*pythonBaseModule)(nil)
+var _ PythonDependency = (*Module)(nil)
 
-var _ android.AndroidMkDataProvider = (*pythonBaseModule)(nil)
+var _ android.AndroidMkDataProvider = (*Module)(nil)
 
-func InitPythonBaseModule(baseModule *pythonBaseModule, subModule PythonSubModule,
-	hod android.HostOrDeviceSupported) android.Module {
+func (p *Module) Init() android.Module {
 
-	baseModule.subModule = subModule
+	p.AddProperties(&p.properties)
+	if p.bootstrapper != nil {
+		p.AddProperties(p.bootstrapper.bootstrapperProps()...)
+	}
 
-	baseModule.AddProperties(&baseModule.properties)
+	android.InitAndroidArchModule(p, p.hod, p.multilib)
+	android.InitDefaultableModule(p)
 
-	android.InitAndroidArchModule(baseModule, hod, android.MultilibCommon)
-
-	return baseModule
+	return p
 }
 
-// the tag used to mark dependencies within "py_libs" attribute.
-type pythonDependencyTag struct {
+type dependencyTag struct {
 	blueprint.BaseDependencyTag
+	name string
 }
 
-var pyDependencyTag pythonDependencyTag
-
 var (
+	pythonLibTag       = dependencyTag{name: "pythonLib"}
+	launcherTag        = dependencyTag{name: "launcher"}
 	pyIdentifierRegexp = regexp.MustCompile(`^([a-z]|[A-Z]|_)([a-z]|[A-Z]|[0-9]|_)*$`)
 	pyExt              = ".py"
 	pyVersion2         = "PY2"
 	pyVersion3         = "PY3"
 	initFileName       = "__init__.py"
 	mainFileName       = "__main__.py"
+	entryPointFile     = "entry_point.txt"
 	parFileExt         = ".zip"
 	runFiles           = "runfiles"
+	internal           = "internal"
 )
 
 // create version variants for modules.
 func versionSplitMutator() func(android.BottomUpMutatorContext) {
 	return func(mctx android.BottomUpMutatorContext) {
-		if base, ok := mctx.Module().(*pythonBaseModule); ok {
+		if base, ok := mctx.Module().(*Module); ok {
 			versionNames := []string{}
 			if base.properties.Version.Py2.Enabled != nil &&
 				*(base.properties.Version.Py2.Enabled) == true {
@@ -197,36 +236,61 @@
 			modules := mctx.CreateVariations(versionNames...)
 			for i, v := range versionNames {
 				// set the actual version for Python module.
-				modules[i].(*pythonBaseModule).properties.ActualVersion = v
+				modules[i].(*Module).properties.Actual_version = v
 			}
 		}
 	}
 }
 
-func (p *pythonBaseModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
+	switch actual_version {
+	case pyVersion2:
+		return proptools.Bool(p.properties.Version.Py2.Embedded_launcher)
+	case pyVersion3:
+		return proptools.Bool(p.properties.Version.Py3.Embedded_launcher)
+	}
+
+	return false
+}
+
+func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// deps from "data".
 	android.ExtractSourcesDeps(ctx, p.properties.Data)
 	// deps from "srcs".
 	android.ExtractSourcesDeps(ctx, p.properties.Srcs)
 
-	switch p.properties.ActualVersion {
+	switch p.properties.Actual_version {
 	case pyVersion2:
 		// deps from "version.py2.srcs" property.
 		android.ExtractSourcesDeps(ctx, p.properties.Version.Py2.Srcs)
 
-		ctx.AddVariationDependencies(nil, pyDependencyTag,
+		ctx.AddVariationDependencies(nil, pythonLibTag,
 			uniqueLibs(ctx, p.properties.Libs, "version.py2.libs",
 				p.properties.Version.Py2.Libs)...)
+
+		if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion2) {
+			ctx.AddVariationDependencies(nil, pythonLibTag, "py2-stdlib")
+			ctx.AddFarVariationDependencies([]blueprint.Variation{
+				{"arch", ctx.Target().String()},
+			}, launcherTag, "py2-launcher")
+		}
+
 	case pyVersion3:
 		// deps from "version.py3.srcs" property.
 		android.ExtractSourcesDeps(ctx, p.properties.Version.Py3.Srcs)
 
-		ctx.AddVariationDependencies(nil, pyDependencyTag,
+		ctx.AddVariationDependencies(nil, pythonLibTag,
 			uniqueLibs(ctx, p.properties.Libs, "version.py3.libs",
 				p.properties.Version.Py3.Libs)...)
+
+		if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion3) {
+			//TODO(nanzhang): Add embedded launcher for Python3.
+			ctx.PropertyErrorf("version.py3.embedded_launcher",
+				"is not supported yet for Python3.")
+		}
 	default:
-		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
-			p.properties.ActualVersion, ctx.ModuleName()))
+		panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
+			p.properties.Actual_version, ctx.ModuleName()))
 	}
 }
 
@@ -258,27 +322,43 @@
 	return ret
 }
 
-func (p *pythonBaseModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	installSource := p.subModule.GeneratePythonBuildActions(ctx)
+func (p *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.GeneratePythonBuildActions(ctx)
 
-	if p.installer != nil && installSource.Valid() {
-		p.installer.install(ctx, installSource.Path())
+	if p.bootstrapper != nil {
+		// TODO(nanzhang): Since embedded launcher is not supported for Python3 for now,
+		// so we initialize "embedded_launcher" to false.
+		embedded_launcher := false
+		if p.properties.Actual_version == pyVersion2 {
+			embedded_launcher = p.isEmbeddedLauncherEnabled(pyVersion2)
+		}
+		p.installSource = p.bootstrapper.bootstrap(ctx, p.properties.Actual_version,
+			embedded_launcher, p.srcsPathMappings, p.parSpec, p.depsPyRunfiles,
+			p.depsParSpecs)
 	}
+
+	if p.installer != nil && p.installSource.Valid() {
+		p.installer.install(ctx, p.installSource.Path())
+	}
+
 }
 
-func (p *pythonBaseModule) GeneratePythonBuildActions(ctx android.ModuleContext) android.OptionalPath {
+func (p *Module) GeneratePythonBuildActions(ctx android.ModuleContext) {
 	// expand python files from "srcs" property.
 	srcs := p.properties.Srcs
-	switch p.properties.ActualVersion {
+	exclude_srcs := p.properties.Exclude_srcs
+	switch p.properties.Actual_version {
 	case pyVersion2:
 		srcs = append(srcs, p.properties.Version.Py2.Srcs...)
+		exclude_srcs = append(exclude_srcs, p.properties.Version.Py2.Exclude_srcs...)
 	case pyVersion3:
 		srcs = append(srcs, p.properties.Version.Py3.Srcs...)
+		exclude_srcs = append(exclude_srcs, p.properties.Version.Py3.Exclude_srcs...)
 	default:
-		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
-			p.properties.ActualVersion, ctx.ModuleName()))
+		panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
+			p.properties.Actual_version, ctx.ModuleName()))
 	}
-	expandedSrcs := ctx.ExpandSources(srcs, nil)
+	expandedSrcs := ctx.ExpandSources(srcs, exclude_srcs)
 	if len(expandedSrcs) == 0 {
 		ctx.ModuleErrorf("doesn't have any source files!")
 	}
@@ -292,15 +372,26 @@
 		pkg_path = filepath.Clean(p.properties.Pkg_path)
 		if pkg_path == ".." || strings.HasPrefix(pkg_path, "../") ||
 			strings.HasPrefix(pkg_path, "/") {
-			ctx.PropertyErrorf("pkg_path", "%q is not a valid format.",
+			ctx.PropertyErrorf("pkg_path",
+				"%q must be a relative path contained in par file.",
 				p.properties.Pkg_path)
-			return android.OptionalPath{}
+			return
 		}
-		// pkg_path starts from "runfiles/" implicitly.
-		pkg_path = filepath.Join(runFiles, pkg_path)
+		if p.properties.Is_internal != nil && *p.properties.Is_internal {
+			// pkg_path starts from "internal/" implicitly.
+			pkg_path = filepath.Join(internal, pkg_path)
+		} else {
+			// pkg_path starts from "runfiles/" implicitly.
+			pkg_path = filepath.Join(runFiles, pkg_path)
+		}
 	} else {
-		// pkg_path starts from "runfiles/" implicitly.
-		pkg_path = runFiles
+		if p.properties.Is_internal != nil && *p.properties.Is_internal {
+			// pkg_path starts from "runfiles/" implicitly.
+			pkg_path = internal
+		} else {
+			// pkg_path starts from "runfiles/" implicitly.
+			pkg_path = runFiles
+		}
 	}
 
 	p.genModulePathMappings(ctx, pkg_path, expandedSrcs, expandedData)
@@ -308,13 +399,11 @@
 	p.parSpec = p.dumpFileList(ctx, pkg_path)
 
 	p.uniqWholeRunfilesTree(ctx)
-
-	return android.OptionalPath{}
 }
 
 // generate current module unique pathMappings: <dest: runfiles_path, src: source_path>
 // for python/data files.
-func (p *pythonBaseModule) genModulePathMappings(ctx android.ModuleContext, pkg_path string,
+func (p *Module) genModulePathMappings(ctx android.ModuleContext, pkg_path string,
 	expandedSrcs, expandedData android.Paths) {
 	// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
 	// check duplicates.
@@ -355,7 +444,7 @@
 }
 
 // register build actions to dump filelist to disk.
-func (p *pythonBaseModule) dumpFileList(ctx android.ModuleContext, pkg_path string) parSpec {
+func (p *Module) dumpFileList(ctx android.ModuleContext, pkg_path string) parSpec {
 	relativeRootMap := make(map[string]android.Paths)
 	// the soong_zip params in order to pack current module's Python/data files.
 	ret := parSpec{rootPrefix: pkg_path}
@@ -365,7 +454,8 @@
 	// "srcs" or "data" properties may have filegroup so it might happen that
 	// the relative root for each source path is different.
 	for _, path := range pathMappings {
-		relativeRoot := strings.TrimSuffix(path.src.String(), path.src.Rel())
+		var relativeRoot string
+		relativeRoot = strings.TrimSuffix(path.src.String(), path.src.Rel())
 		if v, found := relativeRootMap[relativeRoot]; found {
 			relativeRootMap[relativeRoot] = append(v, path.src)
 		} else {
@@ -392,8 +482,19 @@
 	return ret
 }
 
-// check Python/data files duplicates from current module and its whole dependencies.
-func (p *pythonBaseModule) uniqWholeRunfilesTree(ctx android.ModuleContext) {
+func isPythonLibModule(module blueprint.Module) bool {
+	if m, ok := module.(*Module); ok {
+		// Python library has no bootstrapper or installer.
+		if m.bootstrapper != nil || m.installer != nil {
+			return false
+		}
+		return true
+	}
+	return false
+}
+
+// check Python source/data files duplicates from current module and its whole dependencies.
+func (p *Module) uniqWholeRunfilesTree(ctx android.ModuleContext) {
 	// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
 	// check duplicates.
 	destToPySrcs := make(map[string]string)
@@ -408,16 +509,15 @@
 
 	// visit all its dependencies in depth first.
 	ctx.VisitDepsDepthFirst(func(module blueprint.Module) {
-		// module can only depend on Python library.
-		if base, ok := module.(*pythonBaseModule); ok {
-			if _, ok := base.subModule.(*PythonLibrary); !ok {
-				panic(fmt.Errorf(
-					"the dependency %q of module %q is not Python library!",
-					ctx.ModuleName(), ctx.OtherModuleName(module)))
-			}
-		} else {
+		if ctx.OtherModuleDependencyTag(module) != pythonLibTag {
 			return
 		}
+		// Python module cannot depend on modules, except for Python library.
+		if !isPythonLibModule(module) {
+			panic(fmt.Errorf(
+				"the dependency %q of module %q is not Python library!",
+				ctx.ModuleName(), ctx.OtherModuleName(module)))
+		}
 		if dep, ok := module.(PythonDependency); ok {
 			srcs := dep.GetSrcsPathMappings()
 			for _, path := range srcs {
@@ -428,9 +528,7 @@
 				}
 				// binary needs the Python runfiles paths from all its
 				// dependencies to fill __init__.py in each runfiles dir.
-				if sub, ok := p.subModule.(*pythonBinaryBase); ok {
-					sub.depsPyRunfiles = append(sub.depsPyRunfiles, path.dest)
-				}
+				p.depsPyRunfiles = append(p.depsPyRunfiles, path.dest)
 			}
 			data := dep.GetDataPathMappings()
 			for _, path := range data {
@@ -440,9 +538,7 @@
 			}
 			// binary needs the soong_zip arguments from all its
 			// dependencies to generate executable par file.
-			if sub, ok := p.subModule.(*pythonBinaryBase); ok {
-				sub.depsParSpecs = append(sub.depsParSpecs, dep.GetParSpec())
-			}
+			p.depsParSpecs = append(p.depsParSpecs, dep.GetParSpec())
 		}
 	})
 }
diff --git a/python/python_test.go b/python/python_test.go
index 4c30d95..8737302 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -28,7 +28,7 @@
 	"android/soong/android"
 )
 
-type pyBinary struct {
+type pyModule struct {
 	name           string
 	actualVersion  string
 	pyRunfiles     []string
@@ -41,7 +41,7 @@
 	buildNamePrefix          = "soong_python_test"
 	moduleVariantErrTemplate = "%s: module %q variant %q: "
 	pkgPathErrTemplate       = moduleVariantErrTemplate +
-		"pkg_path: %q is not a valid format."
+		"pkg_path: %q must be a relative path contained in par file."
 	badIdentifierErrTemplate = moduleVariantErrTemplate +
 		"srcs: the path %q contains invalid token %q."
 	dupRunfileErrTemplate = moduleVariantErrTemplate +
@@ -58,7 +58,7 @@
 		mockFiles map[string][]byte
 
 		errors           []string
-		expectedBinaries []pyBinary
+		expectedBinaries []pyModule
 	}{
 		{
 			desc: "module without any src files",
@@ -222,7 +222,28 @@
 			mockFiles: map[string][]byte{
 				bpFile: []byte(`subdirs = ["dir"]`),
 				filepath.Join("dir", bpFile): []byte(
-					`python_library_host {
+					`python_defaults {
+						name: "default_lib",
+						srcs: [
+							"default.py",
+						],
+						version: {
+							py2: {
+								enabled: true,
+								srcs: [
+									"default_py2.py",
+								],
+							},
+							py3: {
+								enabled: false,
+								srcs: [
+									"default_py3.py",
+								],
+							},
+						},
+					}
+
+					python_library_host {
 						name: "lib5",
 						pkg_path: "a/b/",
 						srcs: [
@@ -251,6 +272,7 @@
 
 					python_binary_host {
 						name: "bin",
+						defaults: ["default_lib"],
 						pkg_path: "e/",
 						srcs: [
 							"bin.py",
@@ -271,19 +293,24 @@
 						},
 					}`,
 				),
-				filepath.Join("dir", "file1.py"): nil,
-				filepath.Join("dir", "file2.py"): nil,
-				filepath.Join("dir", "bin.py"):   nil,
-				filepath.Join("dir", "file4.py"): nil,
+				filepath.Join("dir", "default.py"):     nil,
+				filepath.Join("dir", "default_py2.py"): nil,
+				filepath.Join("dir", "default_py3.py"): nil,
+				filepath.Join("dir", "file1.py"):       nil,
+				filepath.Join("dir", "file2.py"):       nil,
+				filepath.Join("dir", "bin.py"):         nil,
+				filepath.Join("dir", "file4.py"):       nil,
 				stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
 				MAIN_FILE = '%main%'`),
 			},
-			expectedBinaries: []pyBinary{
+			expectedBinaries: []pyModule{
 				{
 					name:          "bin",
 					actualVersion: "PY3",
 					pyRunfiles: []string{
+						"runfiles/e/default.py",
 						"runfiles/e/bin.py",
+						"runfiles/e/default_py3.py",
 						"runfiles/e/file4.py",
 					},
 					depsPyRunfiles: []string{
@@ -314,6 +341,9 @@
 				android.ModuleFactoryAdaptor(PythonLibraryHostFactory))
 			ctx.RegisterModuleType("python_binary_host",
 				android.ModuleFactoryAdaptor(PythonBinaryHostFactory))
+			ctx.RegisterModuleType("python_defaults",
+				android.ModuleFactoryAdaptor(defaultsFactory))
+			ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 			ctx.Register()
 			ctx.MockFileSystem(d.mockFiles)
 			_, testErrs := ctx.ParseBlueprintsFiles(bpFile)
@@ -363,14 +393,10 @@
 	expParSpec string, expDepsParSpecs []string) (testErrs []error) {
 	module := ctx.ModuleForTests(name, variant)
 
-	base, baseOk := module.Module().(*pythonBaseModule)
+	base, baseOk := module.Module().(*Module)
 	if !baseOk {
 		t.Fatalf("%s is not Python module!", name)
 	}
-	sub, subOk := base.subModule.(*pythonBinaryBase)
-	if !subOk {
-		t.Fatalf("%s is not Python binary!", name)
-	}
 
 	actPyRunfiles := []string{}
 	for _, path := range base.srcsPathMappings {
@@ -381,28 +407,28 @@
 		testErrs = append(testErrs, errors.New(fmt.Sprintf(
 			`binary "%s" variant "%s" has unexpected pyRunfiles: %q!`,
 			base.Name(),
-			base.properties.ActualVersion,
+			base.properties.Actual_version,
 			actPyRunfiles)))
 	}
 
-	if !reflect.DeepEqual(sub.depsPyRunfiles, expDepsPyRunfiles) {
+	if !reflect.DeepEqual(base.depsPyRunfiles, expDepsPyRunfiles) {
 		testErrs = append(testErrs, errors.New(fmt.Sprintf(
 			`binary "%s" variant "%s" has unexpected depsPyRunfiles: %q!`,
 			base.Name(),
-			base.properties.ActualVersion,
-			sub.depsPyRunfiles)))
+			base.properties.Actual_version,
+			base.depsPyRunfiles)))
 	}
 
 	if base.parSpec.soongParArgs() != strings.Replace(expParSpec, "@prefix@", buildDir, 1) {
 		testErrs = append(testErrs, errors.New(fmt.Sprintf(
 			`binary "%s" variant "%s" has unexpected parSpec: %q!`,
 			base.Name(),
-			base.properties.ActualVersion,
+			base.properties.Actual_version,
 			base.parSpec.soongParArgs())))
 	}
 
 	actDepsParSpecs := []string{}
-	for i, p := range sub.depsParSpecs {
+	for i, p := range base.depsParSpecs {
 		actDepsParSpecs = append(actDepsParSpecs, p.soongParArgs())
 		expDepsParSpecs[i] = strings.Replace(expDepsParSpecs[i], "@prefix@", buildDir, 1)
 	}
@@ -411,7 +437,7 @@
 		testErrs = append(testErrs, errors.New(fmt.Sprintf(
 			`binary "%s" variant "%s" has unexpected depsParSpecs: %q!`,
 			base.Name(),
-			base.properties.ActualVersion,
+			base.properties.Actual_version,
 			actDepsParSpecs)))
 	}
 
diff --git a/python/test.go b/python/test.go
index 837eb25..de2b13e 100644
--- a/python/test.go
+++ b/python/test.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-	"path/filepath"
 )
 
 // This file contains the module types for building Python test.
@@ -25,30 +24,29 @@
 	android.RegisterModuleType("python_test_host", PythonTestHostFactory)
 }
 
-type PythonTestHost struct {
-	pythonBinaryBase
+type testDecorator struct {
+	*binaryDecorator
 }
 
-var _ PythonSubModule = (*PythonTestHost)(nil)
-
-type pythonTestHostDecorator struct {
-	pythonDecorator
+func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) {
+	test.binaryDecorator.baseInstaller.install(ctx, file)
 }
 
-func (p *pythonTestHostDecorator) install(ctx android.ModuleContext, file android.Path) {
-	p.pythonDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName())
-	p.pythonDecorator.baseInstaller.install(ctx, file)
+func NewTest(hod android.HostOrDeviceSupported) *Module {
+	module, binary := NewBinary(hod)
+
+	binary.baseInstaller = NewPythonInstaller("nativetest")
+
+	test := &testDecorator{binaryDecorator: binary}
+
+	module.bootstrapper = test
+	module.installer = test
+
+	return module
 }
 
 func PythonTestHostFactory() android.Module {
-	decorator := &pythonTestHostDecorator{
-		pythonDecorator: pythonDecorator{baseInstaller: NewPythonInstaller("nativetest")}}
+	module := NewTest(android.HostSupportedNoCross)
 
-	module := &PythonBinaryHost{}
-	module.pythonBaseModule.installer = decorator
-
-	module.AddProperties(&module.binaryProperties)
-
-	return InitPythonBaseModule(&module.pythonBinaryBase.pythonBaseModule,
-		&module.pythonBinaryBase, android.HostSupportedNoCross)
+	return module.Init()
 }
diff --git a/root.bp b/root.bp
index 582552e..f27d28b 100644
--- a/root.bp
+++ b/root.bp
@@ -18,6 +18,7 @@
     "development/*",
     "device/*/*",
     "external/*",
+    "external/python/*",
     "frameworks/*",
     "frameworks/compile/*",
     "frameworks/hardware/interfaces",
@@ -35,5 +36,7 @@
     "system/tools/*",
     "test/vts",
     "test/vts-testcase/*",
+    "tools/*",
+    "toolchain/*",
     "vendor/*/*",
 ]
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index f8ce349..197a38d 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -13,7 +13,7 @@
 
 # PLATFORM_VERSION_ALL_CODESNAMES is a comma separated list like O,P. We need to
 # turn this into ["O","P"].
-PLATFORM_VERSION_ALL_CODENAMES=${PLATFORM_VERSION_ALL_CODENAMES/,/","}
+PLATFORM_VERSION_ALL_CODENAMES=${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}
 PLATFORM_VERSION_ALL_CODENAMES="[\"${PLATFORM_VERSION_ALL_CODENAMES}\"]"
 
 SOONG_OUT=${OUT_DIR}/soong
diff --git a/ui/build/config.go b/ui/build/config.go
index 1c2f73b..2b0da4d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -403,11 +403,7 @@
 }
 
 func (c *configImpl) ProductOut() string {
-	if buildType, ok := c.environ.Get("TARGET_BUILD_TYPE"); ok && buildType == "debug" {
-		return filepath.Join(c.OutDir(), "debug", "target", "product", c.TargetDevice())
-	} else {
-		return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
-	}
+	return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
 }
 
 func (c *configImpl) DevicePreviousProductConfig() string {
@@ -415,11 +411,7 @@
 }
 
 func (c *configImpl) hostOutRoot() string {
-	if buildType, ok := c.environ.Get("HOST_BUILD_TYPE"); ok && buildType == "debug" {
-		return filepath.Join(c.OutDir(), "debug", "host")
-	} else {
-		return filepath.Join(c.OutDir(), "host")
-	}
+	return filepath.Join(c.OutDir(), "host")
 }
 
 func (c *configImpl) HostOut() string {