Merge "Allow macro definition with space"
diff --git a/Android.bp b/Android.bp
index 32b89d1..1f6ebe2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5,6 +5,7 @@
     "fs",
     "finder",
     "jar",
+    "zip",
     "third_party/zip",
     "ui/*",
 ]
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 6743fb3..f781dd4 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -117,15 +117,23 @@
 // package-scoped variable's initialization.
 func (p AndroidPackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), []error{}}
-		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
-		if len(ctx.errors) > 0 {
-			return "", ctx.errors[0]
+		po, err := p.HostBinToolPath(config, path)
+		if err != nil {
+			return "", err
 		}
-		return p.String(), nil
+		return po.String(), nil
 	})
 }
 
+func (p AndroidPackageContext) HostBinToolPath(config interface{}, path string) (Path, error) {
+	ctx := &configErrorWrapper{p, config.(Config), []error{}}
+	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
+	if len(ctx.errors) > 0 {
+		return nil, ctx.errors[0]
+	}
+	return pa, nil
+}
+
 // HostJavaToolVariable returns a Variable whose value is the path to a host
 // tool in the frameworks directory for host targets. It may only be called
 // during a Go package's initialization - either from the init() function or as
diff --git a/android/paths.go b/android/paths.go
index ed1e607..7443547 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -199,9 +199,9 @@
 	if pathConfig(ctx).AllowMissingDependencies() {
 		if modCtx, ok := ctx.(ModuleContext); ok {
 			ret := make(Paths, 0, len(paths))
-			intermediates := filepath.Join(modCtx.ModuleDir(), modCtx.ModuleName(), modCtx.ModuleSubDir(), "missing")
+			intermediates := pathForModule(modCtx).withRel("missing")
 			for _, path := range paths {
-				p := ExistentPathForSource(ctx, intermediates, path)
+				p := ExistentPathForSource(ctx, intermediates.String(), path)
 				if p.Valid() {
 					ret = append(ret, p.Path())
 				} else {
@@ -572,6 +572,12 @@
 	basePath
 }
 
+func (p OutputPath) withRel(rel string) OutputPath {
+	p.basePath.path = filepath.Join(p.basePath.path, rel)
+	p.basePath.rel = rel
+	return p
+}
+
 var _ Path = OutputPath{}
 
 // PathForOutput joins the provided paths and returns an OutputPath that is
@@ -666,6 +672,10 @@
 
 var _ Path = ModuleOutPath{}
 
+func pathForModule(ctx ModuleContext) OutputPath {
+	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
+}
+
 // PathForVndkRefDump returns an OptionalPath representing the path of the reference
 // abi dump for the given module. This is not guaranteed to be valid.
 func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string, vndkOrNdk, isSourceDump bool) OptionalPath {
@@ -694,14 +704,15 @@
 // output directory.
 func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
 	p := validatePath(ctx, paths...)
-	return ModuleOutPath{PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), p)}
+	return ModuleOutPath{
+		OutputPath: pathForModule(ctx).withRel(p),
+	}
 }
 
 // ModuleGenPath is a Path representing the 'gen' directory in a module's output
 // directory. Mainly used for generated sources.
 type ModuleGenPath struct {
 	ModuleOutPath
-	path string
 }
 
 var _ Path = ModuleGenPath{}
@@ -713,8 +724,9 @@
 func PathForModuleGen(ctx ModuleContext, paths ...string) ModuleGenPath {
 	p := validatePath(ctx, paths...)
 	return ModuleGenPath{
-		PathForModuleOut(ctx, "gen", p),
-		p,
+		ModuleOutPath: ModuleOutPath{
+			OutputPath: pathForModule(ctx).withRel("gen").withRel(p),
+		},
 	}
 }
 
diff --git a/android/testing.go b/android/testing.go
index 667c1aa..f5777ba 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -95,6 +95,15 @@
 	panic(fmt.Errorf("couldn't find rule %q", rule))
 }
 
+func (m TestingModule) Description(desc string) ModuleBuildParams {
+	for _, p := range m.module.BuildParamsForTests() {
+		if p.Description == desc {
+			return p
+		}
+	}
+	panic(fmt.Errorf("couldn't find description %q", desc))
+}
+
 func (m TestingModule) Output(file string) ModuleBuildParams {
 	for _, p := range m.module.BuildParamsForTests() {
 		outputs := append(WritablePaths(nil), p.Outputs...)
@@ -102,7 +111,7 @@
 			outputs = append(outputs, p.Output)
 		}
 		for _, f := range outputs {
-			if f.Base() == file {
+			if f.Rel() == file {
 				return p
 			}
 		}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index f5858a7..0de5009 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -135,6 +135,7 @@
 			"LOCAL_PROPRIETARY_MODULE":       "proprietary",
 			"LOCAL_VENDOR_MODULE":            "vendor",
 			"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
+			"LOCAL_DEX_PREOPT":               "dex_preopt",
 		})
 }
 
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index a49f620..5cb3f7a 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -80,11 +80,23 @@
 }
 
 func (f *bpFile) setMkPos(pos, end scanner.Position) {
-	if pos.Line < f.mkPos.Line {
-		panic(fmt.Errorf("out of order lines, %q after %q", pos, f.mkPos))
+	// It is unusual but not forbidden for pos.Line to be smaller than f.mkPos.Line
+	// For example:
+	//
+	// if true                       # this line is emitted 1st
+	// if true                       # this line is emitted 2nd
+	// some-target: some-file        # this line is emitted 3rd
+	//         echo doing something  # this recipe is emitted 6th
+	// endif #some comment           # this endif is emitted 4th; this comment is part of the recipe
+	//         echo doing more stuff # this is part of the recipe
+	// endif                         # this endif is emitted 5th
+	//
+	// However, if pos.Line < f.mkPos.Line, we treat it as though it were equal
+	if pos.Line >= f.mkPos.Line {
+		f.bpPos.Line += (pos.Line - f.mkPos.Line)
+		f.mkPos = end
 	}
-	f.bpPos.Line += (pos.Line - f.mkPos.Line)
-	f.mkPos = end
+
 }
 
 type conditional struct {
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 4681a7d..0b86540 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -425,6 +425,41 @@
   }
 }`,
 	},
+	{
+		// the important part of this test case is that it confirms that androidmk doesn't
+		// panic in this case
+		desc: "multiple directives inside recipe",
+		in: `
+ifeq ($(a),true)
+ifeq ($(b),false)
+imABuildStatement: somefile
+	echo begin
+endif # a==true
+	echo middle
+endif # b==false
+	echo end
+`,
+		expected: `
+// ANDROIDMK TRANSLATION ERROR: unsupported conditional
+// ifeq ($(a),true)
+
+// ANDROIDMK TRANSLATION ERROR: unsupported conditional
+// ifeq ($(b),false)
+
+// ANDROIDMK TRANSLATION ERROR: unsupported line
+// rule:       imABuildStatement: somefile
+// echo begin
+//  # a==true
+// echo middle
+//  # b==false
+// echo end
+//
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// endif
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// endif
+		`,
+	},
 }
 
 func reformatBlueprint(input string) string {
diff --git a/cc/library.go b/cc/library.go
index e963ecb..1434f2c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -64,6 +64,12 @@
 		// export headers generated from .proto sources
 		Export_proto_headers bool
 	}
+	Target struct {
+		Vendor struct {
+			// version script for this vendor variant
+			Version_script *string `android:"arch_variant"`
+		}
+	}
 }
 
 type LibraryMutatedProperties struct {
@@ -455,7 +461,11 @@
 		deps.StaticLibs = append(deps.StaticLibs, library.Properties.Shared.Static_libs...)
 		deps.SharedLibs = append(deps.SharedLibs, library.Properties.Shared.Shared_libs...)
 	}
-
+	if ctx.useVndk() {
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
+	}
 	return deps
 }
 
@@ -491,6 +501,9 @@
 	unexportedSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Unexported_symbols_list)
 	forceNotWeakSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Force_symbols_not_weak_list)
 	forceWeakSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Force_symbols_weak_list)
+	if ctx.useVndk() && library.Properties.Target.Vendor.Version_script != nil {
+		versionScript = android.OptionalPathForModuleSrc(ctx, library.Properties.Target.Vendor.Version_script)
+	}
 	if !ctx.Darwin() {
 		if versionScript.Valid() {
 			flags.LdFlags = append(flags.LdFlags, "-Wl,--version-script,"+versionScript.String())
diff --git a/cc/linker.go b/cc/linker.go
index 6ec5630..1cf3f61 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -89,6 +89,10 @@
 			// list of shared libs that should not be used to build
 			// the vendor variant of the C/C++ module.
 			Exclude_shared_libs []string
+
+			// list of static libs that should not be used to build
+			// the vendor variant of the C/C++ module.
+			Exclude_static_libs []string
 		}
 	}
 }
@@ -135,6 +139,9 @@
 	if ctx.useVndk() {
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs)
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
 	}
 
 	if ctx.ModuleName() != "libcompiler_rt-extras" {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b8b5ffa..74f4bdb 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -342,6 +342,10 @@
 		diagSanitizers = append(diagSanitizers, "address")
 	}
 
+	if Bool(sanitize.Properties.Sanitize.Thread) {
+		sanitizers = append(sanitizers, "thread")
+	}
+
 	if Bool(sanitize.Properties.Sanitize.Coverage) {
 		flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp")
 	}
@@ -408,6 +412,8 @@
 	runtimeLibrary := ""
 	if Bool(sanitize.Properties.Sanitize.Address) {
 		runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
+	} else if Bool(sanitize.Properties.Sanitize.Thread) {
+		runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(ctx.toolchain())
 	} else if len(diagSanitizers) > 0 {
 		runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
 	}
diff --git a/cc/test.go b/cc/test.go
index fa75f48..9df3467 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -175,11 +175,16 @@
 }
 
 func (test *testDecorator) linkerInit(ctx BaseModuleContext, linker *baseLinker) {
+	// add ../../lib[64] to rpath so that out/host/linux-x86/nativetest/<test dir>/<test> can
+	// find out/host/linux-x86/lib[64]/library.so
 	runpath := "../../lib"
 	if ctx.toolchain().Is64Bit() {
 		runpath += "64"
 	}
 	linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath)
+
+	// add "" to rpath so that test binaries can find libraries in their own test directory
+	linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, "")
 }
 
 func (test *testDecorator) linkerProps() []interface{} {
diff --git a/java/androidmk.go b/java/androidmk.go
index e349de4..c61b7e5 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -27,7 +27,7 @@
 func (library *Library) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(library.classpathFile),
+		OutputFile: android.OptionalPathForPath(library.implementationJarFile),
 		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
@@ -36,8 +36,12 @@
 				}
 				if library.dexJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
+					if library.deviceProperties.Dex_preopt == nil || *library.deviceProperties.Dex_preopt == false {
+						fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+					}
 				}
 				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.deviceProperties.Sdk_version)
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
 			},
 		},
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
@@ -48,13 +52,14 @@
 				fmt.Fprintln(w, "LOCAL_MODULE := "+name+"-hostdex")
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := JAVA_LIBRARIES")
-				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", library.classpathFile.String())
+				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", library.implementationJarFile.String())
 				if library.properties.Installable != nil && *library.properties.Installable == false {
 					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 				}
 				if library.dexJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
 				}
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.implementationJarFile.String())
 				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " "))
 				fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
 			}
@@ -70,6 +75,8 @@
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.combinedClasspathFile.String())
+				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", prebuilt.properties.Sdk_version)
 			},
 		},
 	}
@@ -78,7 +85,7 @@
 func (binary *Binary) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(binary.classpathFile),
+		OutputFile: android.OptionalPathForPath(binary.implementationJarFile),
 		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			android.WriteAndroidMkData(w, data)
diff --git a/java/builder.go b/java/builder.go
index 9086d51..193dfe7 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -87,6 +87,22 @@
 		},
 		"javacFlags", "sourcepath", "bootClasspath", "classpath", "outDir", "annoDir", "javaVersion")
 
+	turbine = pctx.AndroidStaticRule("turbine",
+		blueprint.RuleParams{
+			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
+				`${config.JavaCmd} -jar ${config.TurbineJar} --output $out.tmp ` +
+				`--temp_dir "$outDir" --sources @$out.rsp $sourcepath ` +
+				`--javacopts ${config.CommonJdkFlags} ` +
+				`$javacFlags -source $javaVersion -target $javaVersion $bootClasspath $classpath && ` +
+				`${config.Ziptime} $out.tmp && ` +
+				`(if cmp -s $out.tmp $out ; then rm $out.tmp ; else mv $out.tmp $out ; fi )`,
+			CommandDeps:    []string{"${config.TurbineJar}", "${config.JavaCmd}", "${config.Ziptime}"},
+			Rspfile:        "$out.rsp",
+			RspfileContent: "$in",
+			Restat:         true,
+		},
+		"javacFlags", "sourcepath", "bootClasspath", "classpath", "outDir", "javaVersion")
+
 	jar = pctx.AndroidStaticRule("jar",
 		blueprint.RuleParams{
 			Command:     `${config.SoongZipCmd} -jar -o $out $jarArgs`,
@@ -109,7 +125,7 @@
 				`$javaFlags ` +
 				`-jar ${config.DesugarJar} $classpathFlags $desugarFlags ` +
 				`-i $in -o $out`,
-			CommandDeps: []string{"${config.DesugarJar}"},
+			CommandDeps: []string{"${config.DesugarJar}", "${config.JavaCmd}"},
 		},
 		"javaFlags", "classpathFlags", "desugarFlags", "dumpDir")
 
@@ -160,7 +176,7 @@
 	srcFiles android.Paths, srcJars classpath,
 	flags javaBuilderFlags) {
 
-	classDir := android.PathForModuleOut(ctx, "classes-kt")
+	classDir := android.PathForModuleOut(ctx, "kotlinc", "classes")
 
 	inputs := append(android.Paths(nil), srcFiles...)
 	inputs = append(inputs, srcJars...)
@@ -171,7 +187,7 @@
 		Output:      outputFile,
 		Inputs:      inputs,
 		Args: map[string]string{
-			"classpath":    flags.kotlincClasspath.JavaClasspath(),
+			"classpath":    flags.kotlincClasspath.FormJavaClassPath("--classpath"),
 			"kotlincFlags": flags.kotlincFlags,
 			"outDir":       classDir.String(),
 			"javaVersion":  flags.javaVersion,
@@ -184,19 +200,57 @@
 	flags javaBuilderFlags, deps android.Paths) {
 
 	transformJavaToClasses(ctx, outputFile, srcFiles, srcJars, flags, deps,
-		"", "javac", javac)
+		"javac", "javac", javac)
 }
 
 func RunErrorProne(ctx android.ModuleContext, outputFile android.WritablePath,
-	srcFiles android.Paths, srcJars classpath,
-	flags javaBuilderFlags) {
+	srcFiles android.Paths, srcJars classpath, flags javaBuilderFlags) {
 
 	if config.ErrorProneJar == "" {
 		ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
 	}
 
 	transformJavaToClasses(ctx, outputFile, srcFiles, srcJars, flags, nil,
-		"-errorprone", "errorprone", errorprone)
+		"errorprone", "errorprone", errorprone)
+}
+
+func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
+	srcFiles android.Paths, srcJars classpath, flags javaBuilderFlags) {
+
+	var deps android.Paths
+	deps = append(deps, srcJars...)
+	deps = append(deps, flags.bootClasspath...)
+	deps = append(deps, flags.classpath...)
+
+	var bootClasspath string
+	if len(flags.bootClasspath) == 0 && ctx.Device() {
+		// explicitly specify -bootclasspath "" if the bootclasspath is empty to
+		// ensure java does not fall back to the default bootclasspath.
+		bootClasspath = `--bootclasspath ""`
+	} else {
+		bootClasspath = flags.bootClasspath.FormJavaClassPath("--bootclasspath")
+	}
+	var sourcepath string
+	if len(srcJars) > 0 {
+		sourcepath = "--sourcepath_jars" + " " + strings.Join(srcJars.Strings(), " ")
+	} else {
+		sourcepath = ""
+	}
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:        turbine,
+		Description: "turbine",
+		Output:      outputFile,
+		Inputs:      srcFiles,
+		Implicits:   deps,
+		Args: map[string]string{
+			"javacFlags":    flags.javacFlags,
+			"bootClasspath": bootClasspath,
+			"sourcepath":    sourcepath,
+			"classpath":     flags.classpath.FormJavaClassPath("--classpath"),
+			"outDir":        android.PathForModuleOut(ctx, "turbine", "classes").String(),
+			"javaVersion":   flags.javaVersion,
+		},
+	})
 }
 
 // transformJavaToClasses takes source files and converts them to a jar containing .class files.
@@ -211,17 +265,23 @@
 func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
 	srcFiles android.Paths, srcJars classpath,
 	flags javaBuilderFlags, deps android.Paths,
-	intermediatesSuffix, desc string, rule blueprint.Rule) {
+	intermediatesDir, desc string, rule blueprint.Rule) {
 
 	deps = append(deps, srcJars...)
 
 	var bootClasspath string
 	if flags.javaVersion == "1.9" {
 		deps = append(deps, flags.systemModules...)
-		bootClasspath = flags.systemModules.JavaSystemModules(ctx.Device())
+		bootClasspath = flags.systemModules.FormJavaSystemModulesPath("--system=", ctx.Device())
 	} else {
 		deps = append(deps, flags.bootClasspath...)
-		bootClasspath = flags.bootClasspath.JavaBootClasspath(ctx.Device())
+		if len(flags.bootClasspath) == 0 && ctx.Device() {
+			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
+			// ensure java does not fall back to the default bootclasspath.
+			bootClasspath = `-bootclasspath ""`
+		} else {
+			bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath")
+		}
 	}
 
 	deps = append(deps, flags.classpath...)
@@ -235,11 +295,13 @@
 		Args: map[string]string{
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
-			"sourcepath":    srcJars.JavaSourcepath(),
-			"classpath":     flags.classpath.JavaClasspath(),
-			"outDir":        android.PathForModuleOut(ctx, "classes"+intermediatesSuffix).String(),
-			"annoDir":       android.PathForModuleOut(ctx, "anno"+intermediatesSuffix).String(),
-			"javaVersion":   flags.javaVersion,
+			// Returns a -sourcepath argument in the form javac expects.  If the list is empty returns
+			// -sourcepath "" to ensure javac does not fall back to searching the classpath for sources.
+			"sourcepath":  srcJars.FormJavaClassPath("-sourcepath"),
+			"classpath":   flags.classpath.FormJavaClassPath("-classpath"),
+			"outDir":      android.PathForModuleOut(ctx, intermediatesDir, "classes").String(),
+			"annoDir":     android.PathForModuleOut(ctx, intermediatesDir, "anno").String(),
+			"javaVersion": flags.javaVersion,
 		},
 	})
 }
@@ -258,24 +320,30 @@
 	})
 }
 
-func TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
-	jars android.Paths, manifest android.OptionalPath, stripDirs bool) {
+func TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePath, desc string,
+	jars android.Paths, manifest android.OptionalPath, stripDirs bool, dirsToStrip []string) {
 
 	var deps android.Paths
 
 	var jarArgs []string
 	if manifest.Valid() {
-		jarArgs = append(jarArgs, "-m "+manifest.String())
+		jarArgs = append(jarArgs, "-m ", manifest.String())
 		deps = append(deps, manifest.Path())
 	}
 
+	if dirsToStrip != nil {
+		for _, dir := range dirsToStrip {
+			jarArgs = append(jarArgs, "-stripDir ", dir)
+		}
+	}
+
 	if stripDirs {
 		jarArgs = append(jarArgs, "-D")
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:        combineJar,
-		Description: "combine jars",
+		Description: desc,
 		Output:      outputFile,
 		Inputs:      jars,
 		Implicits:   deps,
@@ -288,7 +356,7 @@
 func TransformDesugar(ctx android.ModuleContext, outputFile android.WritablePath,
 	classesJar android.Path, flags javaBuilderFlags) {
 
-	dumpDir := android.PathForModuleOut(ctx, "desugar_dumped_classes")
+	dumpDir := android.PathForModuleOut(ctx, "desugar", "classes")
 
 	javaFlags := ""
 	if ctx.AConfig().UseOpenJDK9() {
@@ -296,8 +364,8 @@
 	}
 
 	var desugarFlags []string
-	desugarFlags = append(desugarFlags, flags.bootClasspath.DesugarBootClasspath()...)
-	desugarFlags = append(desugarFlags, flags.classpath.DesugarClasspath()...)
+	desugarFlags = append(desugarFlags, flags.bootClasspath.FormDesugarClasspath("--bootclasspath_entry")...)
+	desugarFlags = append(desugarFlags, flags.classpath.FormDesugarClasspath("--classpath_entry")...)
 
 	var deps android.Paths
 	deps = append(deps, flags.bootClasspath...)
@@ -353,42 +421,9 @@
 
 type classpath []android.Path
 
-// Returns a -sourcepath argument in the form javac expects.  If the list is empty returns
-// -sourcepath "" to ensure javac does not fall back to searching the classpath for sources.
-func (x *classpath) JavaSourcepath() string {
+func (x *classpath) FormJavaClassPath(optName string) string {
 	if len(*x) > 0 {
-		return "-sourcepath " + strings.Join(x.Strings(), ":")
-	} else {
-		return `-sourcepath ""`
-	}
-}
-
-// Returns a -classpath argument in the form java or javac expects
-func (x *classpath) JavaClasspath() string {
-	if len(*x) > 0 {
-		return "-classpath " + strings.Join(x.Strings(), ":")
-	} else {
-		return ""
-	}
-}
-
-// Returns a -processorpath argument in the form java or javac expects
-func (x *classpath) JavaProcessorpath() string {
-	if len(*x) > 0 {
-		return "-processorpath " + strings.Join(x.Strings(), ":")
-	} else {
-		return ""
-	}
-}
-
-// Returns a -bootclasspath argument in the form java or javac expects.  If forceEmpty is true,
-// returns -bootclasspath "" if the bootclasspath is empty to ensure javac does not fall back to the
-// default bootclasspath.
-func (x *classpath) JavaBootClasspath(forceEmpty bool) string {
-	if len(*x) > 0 {
-		return "-bootclasspath " + strings.Join(x.Strings(), ":")
-	} else if forceEmpty {
-		return `-bootclasspath ""`
+		return optName + " " + strings.Join(x.Strings(), ":")
 	} else {
 		return ""
 	}
@@ -397,37 +432,25 @@
 // Returns a --system argument in the form javac expects with -source 1.9.  If forceEmpty is true,
 // returns --system=none if the list is empty to ensure javac does not fall back to the default
 // system modules.
-func (x *classpath) JavaSystemModules(forceEmpty bool) string {
+func (x *classpath) FormJavaSystemModulesPath(optName string, forceEmpty bool) string {
 	if len(*x) > 1 {
 		panic("more than one system module")
 	} else if len(*x) == 1 {
-		return "--system=" + strings.TrimSuffix((*x)[0].String(), "lib/modules")
+		return optName + strings.TrimSuffix((*x)[0].String(), "lib/modules")
 	} else if forceEmpty {
-		return "--system=none"
+		return optName + "none"
 	} else {
 		return ""
 	}
 }
 
-func (x *classpath) DesugarBootClasspath() []string {
+func (x *classpath) FormDesugarClasspath(optName string) []string {
 	if x == nil || *x == nil {
 		return nil
 	}
 	flags := make([]string, len(*x))
 	for i, v := range *x {
-		flags[i] = "--bootclasspath_entry " + v.String()
-	}
-
-	return flags
-}
-
-func (x *classpath) DesugarClasspath() []string {
-	if x == nil || *x == nil {
-		return nil
-	}
-	flags := make([]string, len(*x))
-	for i, v := range *x {
-		flags[i] = "--classpath_entry " + v.String()
+		flags[i] = optName + " " + v.String()
 	}
 
 	return flags
diff --git a/java/config/config.go b/java/config/config.go
index eb71ddb..6509d80 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -73,13 +73,30 @@
 	pctx.SourcePathVariable("JlinkCmd", "${JavaToolchain}/jlink")
 	pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
 	pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar")
+	pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
 
 	pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 	pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips")
-	pctx.HostBinToolVariable("DxCmd", "dx")
+	pctx.VariableFunc("DxCmd", func(config interface{}) (string, error) {
+		dexer := "dx"
+		if config.(android.Config).Getenv("USE_D8") == "true" {
+			dexer = "d8"
+		}
+		if config.(android.Config).UnbundledBuild() {
+			return "prebuilts/build-tools/common/bin/" + dexer, nil
+		} else {
+			path, err := pctx.HostBinToolPath(config, dexer)
+			if err != nil {
+				return "", err
+			}
+			return path.String(), nil
+		}
+	})
+
 	pctx.HostJavaToolVariable("JarjarCmd", "jarjar.jar")
 	pctx.HostJavaToolVariable("DesugarJar", "desugar.jar")
+	pctx.HostJavaToolVariable("TurbineJar", "turbine.jar")
 
 	pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
 
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 6b49592..96fa92b 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -43,6 +43,9 @@
 	ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
 	ctx.Strict("JAVADOC", "${JavadocCmd}")
 	ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}")
+	ctx.Strict("DX", "${DxCmd}")
+	ctx.Strict("DX_COMMAND", "${DxCmd} -JXms16M -JXmx2048M")
+	ctx.Strict("TURBINE", "${TurbineJar}")
 
 	if ctx.Config().IsEnvTrue("RUN_ERROR_PRONE") {
 		ctx.Strict("TARGET_JAVAC", "${ErrorProneCmd}")
diff --git a/java/java.go b/java/java.go
index 76e574e..497b285 100644
--- a/java/java.go
+++ b/java/java.go
@@ -143,6 +143,10 @@
 	// If true, export a copy of the module as a -hostdex module for host testing.
 	Hostdex *bool
 
+	// If false, prevent dexpreopting and stripping the dex file from the final jar.  Defaults to
+	// true.
+	Dex_preopt *bool
+
 	// When targeting 1.9, override the modules to use with --system
 	System_modules *string
 }
@@ -156,8 +160,11 @@
 	protoProperties  android.ProtoProperties
 	deviceProperties CompilerDeviceProperties
 
-	// output file suitable for inserting into the classpath of another compile
-	classpathFile android.Path
+	// header jar file suitable for inserting into the bootclasspath/classpath of another compile
+	headerJarFile android.Path
+
+	// full implementation jar file suitable for static dependency of another module compile
+	implementationJarFile android.Path
 
 	// output file containing classes.dex
 	dexJarFile android.Path
@@ -178,7 +185,8 @@
 }
 
 type Dependency interface {
-	ClasspathFiles() android.Paths
+	HeaderJars() android.Paths
+	ImplementationJars() android.Paths
 	AidlIncludeDirs() android.Paths
 }
 
@@ -263,13 +271,13 @@
 		}
 	}
 
-	toModule := func(m string) sdkDep {
-		return sdkDep{
-			useModule:     true,
-			module:        m,
-			systemModules: m + "_system_modules",
-		}
-	}
+	//toModule := func(m string) sdkDep {
+	//	return sdkDep{
+	//		useModule:     true,
+	//		module:        m,
+	//		systemModules: m + "_system_modules",
+	//	}
+	//}
 
 	if ctx.AConfig().UnbundledBuild() && v != "" {
 		return toFile(v)
@@ -280,12 +288,14 @@
 		return sdkDep{
 			useDefaultLibs: true,
 		}
-	case "current":
-		return toModule("android_stubs_current")
-	case "system_current":
-		return toModule("android_system_stubs_current")
-	case "test_current":
-		return toModule("android_test_stubs_current")
+	// TODO(ccross): re-enable these once we generate stubs, until then
+	// use the stubs in prebuilts/sdk/*current
+	//case "current":
+	//	return toModule("android_stubs_current")
+	//case "system_current":
+	//	return toModule("android_system_stubs_current")
+	//case "test_current":
+	//	return toModule("android_test_stubs_current")
 	default:
 		return toFile(v)
 	}
@@ -375,6 +385,7 @@
 	classpath          android.Paths
 	bootClasspath      android.Paths
 	staticJars         android.Paths
+	staticHeaderJars   android.Paths
 	staticJarResources android.Paths
 	aidlIncludeDirs    android.Paths
 	srcJars            android.Paths
@@ -390,6 +401,7 @@
 	if sdkDep.invalidVersion {
 		ctx.AddMissingDependencies([]string{sdkDep.module})
 	} else if sdkDep.useFiles {
+		// sdkDep.jar is actually equivalent to turbine header.jar.
 		deps.classpath = append(deps.classpath, sdkDep.jar)
 		deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, sdkDep.aidl)
 	}
@@ -420,12 +432,13 @@
 
 		switch tag {
 		case bootClasspathTag:
-			deps.bootClasspath = append(deps.bootClasspath, dep.ClasspathFiles()...)
+			deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
 		case libTag:
-			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
+			deps.classpath = append(deps.classpath, dep.HeaderJars()...)
 		case staticLibTag:
-			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
-			deps.staticJars = append(deps.staticJars, dep.ClasspathFiles()...)
+			deps.classpath = append(deps.classpath, dep.HeaderJars()...)
+			deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
+			deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
 		case frameworkResTag:
 			if ctx.ModuleName() == "framework" {
 				// framework.jar has a one-off dependency on the R.java and Manifest.java files
@@ -433,7 +446,7 @@
 				// TODO(ccross): aapt java files should go in a src jar
 			}
 		case kotlinStdlibTag:
-			deps.kotlinStdlib = dep.ClasspathFiles()
+			deps.kotlinStdlib = dep.HeaderJars()
 		default:
 			panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 		}
@@ -444,20 +457,22 @@
 	return deps
 }
 
-func (j *Module) compile(ctx android.ModuleContext) {
-
-	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Export_aidl_include_dirs)
-
-	deps := j.collectDeps(ctx)
+func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaBuilderFlags {
 
 	var flags javaBuilderFlags
 
+	// javac flags.
 	javacFlags := j.properties.Javacflags
 	if ctx.AConfig().TargetOpenJDK9() {
 		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
-		j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
+	}
+	if len(javacFlags) > 0 {
+		// optimization.
+		ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
+		flags.javacFlags = "$javacFlags"
 	}
 
+	// javaVersion flag.
 	sdk := sdkStringToNumber(ctx, j.deviceProperties.Sdk_version)
 	if j.properties.Java_version != nil {
 		flags.javaVersion = *j.properties.Java_version
@@ -465,43 +480,56 @@
 		flags.javaVersion = "1.7"
 	} else if ctx.Device() && sdk <= 26 || !ctx.AConfig().TargetOpenJDK9() {
 		flags.javaVersion = "1.8"
+	} else if ctx.Device() && j.deviceProperties.Sdk_version != "" && sdk == 10000 {
+		// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
+		flags.javaVersion = "1.8"
 	} else {
 		flags.javaVersion = "1.9"
 	}
 
+	// classpath
 	flags.bootClasspath.AddPaths(deps.bootClasspath)
 	flags.classpath.AddPaths(deps.classpath)
-
+	// systemModules
 	if deps.systemModules != nil {
 		flags.systemModules = append(flags.systemModules, deps.systemModules)
 	}
 
-	if len(javacFlags) > 0 {
-		ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
-		flags.javacFlags = "$javacFlags"
-	}
-
+	// aidl flags.
 	aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
 	if len(aidlFlags) > 0 {
+		// optimization.
 		ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
 		flags.aidlFlags = "$aidlFlags"
 	}
 
-	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
+	return flags
+}
 
+func (j *Module) compile(ctx android.ModuleContext) {
+
+	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Export_aidl_include_dirs)
+
+	deps := j.collectDeps(ctx)
+	flags := j.collectBuilderFlags(ctx, deps)
+
+	if ctx.AConfig().TargetOpenJDK9() {
+		j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
+	}
+	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
 	if hasSrcExt(srcFiles.Strings(), ".proto") {
 		flags = protoFlags(ctx, &j.protoProperties, flags)
 	}
 
 	var srcJars classpath
 	srcFiles, srcJars = j.genSources(ctx, srcFiles, flags)
-
 	srcJars = append(srcJars, deps.srcJars...)
-
 	srcJars = append(srcJars, j.ExtraSrcJars...)
 
 	var jars android.Paths
 
+	jarName := ctx.ModuleName() + ".jar"
+
 	if srcFiles.HasExt(".kt") {
 		// If there are kotlin files, compile them first but pass all the kotlin and java files
 		// kotlinc will use the java files to resolve types referenced by the kotlin files, but
@@ -515,7 +543,7 @@
 		flags.kotlincClasspath = append(flags.kotlincClasspath, deps.kotlinStdlib...)
 		flags.kotlincClasspath = append(flags.kotlincClasspath, deps.classpath...)
 
-		kotlinJar := android.PathForModuleOut(ctx, "classes-kt.jar")
+		kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
 		TransformKotlinToClasses(ctx, kotlinJar, srcFiles, srcJars, flags)
 		if ctx.Failed() {
 			return
@@ -528,7 +556,27 @@
 		jars = append(jars, deps.kotlinStdlib...)
 	}
 
-	if javaSrcFiles := srcFiles.FilterByExt(".java"); len(javaSrcFiles) > 0 {
+	javaSrcFiles := srcFiles.FilterByExt(".java")
+	var uniqueSrcFiles android.Paths
+	set := make(map[string]bool)
+	for _, v := range javaSrcFiles {
+		if _, found := set[v.String()]; !found {
+			set[v.String()] = true
+			uniqueSrcFiles = append(uniqueSrcFiles, v)
+		}
+	}
+
+	if ctx.Device() && !ctx.AConfig().IsEnvFalse("TURBINE_ENABLED") {
+		// If sdk jar is java module, then directly return classesJar as header.jar
+		if j.Name() != "android_stubs_current" && j.Name() != "android_system_stubs_current" &&
+			j.Name() != "android_test_stubs_current" {
+			j.headerJarFile = j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName)
+			if ctx.Failed() {
+				return
+			}
+		}
+	}
+	if len(uniqueSrcFiles) > 0 {
 		var extraJarDeps android.Paths
 		if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
 			// If error-prone is enabled, add an additional rule to compile the java files into
@@ -536,13 +584,13 @@
 			// a rebuild when error-prone is turned off).
 			// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
 			//    enable error-prone without affecting the output class files.
-			errorprone := android.PathForModuleOut(ctx, "classes-errorprone.list")
+			errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
 			RunErrorProne(ctx, errorprone, javaSrcFiles, srcJars, flags)
 			extraJarDeps = append(extraJarDeps, errorprone)
 		}
 
 		// Compile java sources into .class files
-		classes := android.PathForModuleOut(ctx, "classes-compiled.jar")
+		classes := android.PathForModuleOut(ctx, "javac", jarName)
 		TransformJavaToClasses(ctx, classes, javaSrcFiles, srcJars, flags, extraJarDeps)
 		if ctx.Failed() {
 			return
@@ -570,7 +618,7 @@
 	}
 
 	if len(resArgs) > 0 {
-		resourceJar := android.PathForModuleOut(ctx, "res.jar")
+		resourceJar := android.PathForModuleOut(ctx, "res", jarName)
 		TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
 		if ctx.Failed() {
 			return
@@ -585,108 +633,165 @@
 	manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
 
 	// Combine the classes built from sources, any manifests, and any static libraries into
-	// classes.jar.  If there is only one input jar this step will be skipped.
+	// classes.jar. If there is only one input jar this step will be skipped.
 	var outputFile android.Path
 
 	if len(jars) == 1 && !manifest.Valid() {
 		// Optimization: skip the combine step if there is nothing to do
 		outputFile = jars[0]
 	} else {
-		combinedJar := android.PathForModuleOut(ctx, "classes.jar")
-		TransformJarsToJar(ctx, combinedJar, jars, manifest, false)
+		combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for javac", jars, manifest, false, nil)
 		outputFile = combinedJar
 	}
 
 	if j.properties.Jarjar_rules != nil {
 		jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
 		// Transform classes.jar into classes-jarjar.jar
-		jarjarFile := android.PathForModuleOut(ctx, "classes-jarjar.jar")
+		jarjarFile := android.PathForModuleOut(ctx, "jarjar", jarName)
 		TransformJarJar(ctx, jarjarFile, outputFile, jarjar_rules)
 		outputFile = jarjarFile
 		if ctx.Failed() {
 			return
 		}
 	}
-
-	j.classpathFile = outputFile
+	j.implementationJarFile = outputFile
+	if j.headerJarFile == nil {
+		j.headerJarFile = j.implementationJarFile
+	}
 
 	if ctx.Device() && j.installable() {
-		dxFlags := j.deviceProperties.Dxflags
-		if false /* emma enabled */ {
-			// If you instrument class files that have local variable debug information in
-			// them emma does not correctly maintain the local variable table.
-			// This will cause an error when you try to convert the class files for Android.
-			// The workaround here is to build different dex file here based on emma switch
-			// then later copy into classes.dex. When emma is on, dx is run with --no-locals
-			// option to remove local variable information
-			dxFlags = append(dxFlags, "--no-locals")
-		}
-
-		if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
-			dxFlags = append(dxFlags, "--no-optimize")
-		}
-
-		if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
-			dxFlags = append(dxFlags,
-				"--debug",
-				"--verbose",
-				"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
-				"--dump-width=1000")
-		}
-
-		var minSdkVersion string
-		switch 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, " ")
-
-		desugarFlags := []string{
-			"--min_sdk_version " + minSdkVersion,
-			"--desugar_try_with_resources_if_needed=false",
-			"--allow_empty_bootclasspath",
-		}
-
-		if inList("--core-library", dxFlags) {
-			desugarFlags = append(desugarFlags, "--core_library")
-		}
-
-		flags.desugarFlags = strings.Join(desugarFlags, " ")
-
-		desugarJar := android.PathForModuleOut(ctx, "classes-desugar.jar")
-		TransformDesugar(ctx, desugarJar, outputFile, flags)
-		outputFile = desugarJar
+		outputFile = j.compileDex(ctx, flags, outputFile, jarName)
 		if ctx.Failed() {
 			return
 		}
-
-		// Compile classes.jar into classes.dex and then javalib.jar
-		javalibJar := android.PathForModuleOut(ctx, "javalib.jar")
-		TransformClassesJarToDexJar(ctx, javalibJar, desugarJar, flags)
-		outputFile = javalibJar
-		if ctx.Failed() {
-			return
-		}
-
-		j.dexJarFile = outputFile
 	}
 	ctx.CheckbuildFile(outputFile)
 	j.outputFile = outputFile
 }
 
+func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles android.Paths, srcJars classpath,
+	deps deps, flags javaBuilderFlags, jarName string) android.Path {
+
+	var jars android.Paths
+	if len(srcFiles) > 0 {
+		// Compile java sources into turbine.jar.
+		turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
+		TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
+		if ctx.Failed() {
+			return nil
+		}
+		jars = append(jars, turbineJar)
+	}
+
+	// Combine any static header libraries into classes-header.jar. If there is only
+	// one input jar this step will be skipped.
+	var headerJar android.Path
+	jars = append(jars, deps.staticHeaderJars...)
+
+	if len(jars) == 0 {
+		panic("The turbine.jar is empty without any sources and static libs.")
+	} else {
+		// we cannot skip the combine step for now if there is only one jar
+		// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
+		combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{}, false, []string{"META-INF"})
+		headerJar = combinedJar
+	}
+
+	if j.properties.Jarjar_rules != nil {
+		jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
+		// Transform classes.jar into classes-jarjar.jar
+		jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
+		TransformJarJar(ctx, jarjarFile, headerJar, jarjar_rules)
+		headerJar = jarjarFile
+		if ctx.Failed() {
+			return nil
+		}
+	}
+
+	return headerJar
+}
+
+func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	dxFlags := j.deviceProperties.Dxflags
+	if false /* emma enabled */ {
+		// If you instrument class files that have local variable debug information in
+		// them emma does not correctly maintain the local variable table.
+		// This will cause an error when you try to convert the class files for Android.
+		// The workaround here is to build different dex file here based on emma switch
+		// then later copy into classes.dex. When emma is on, dx is run with --no-locals
+		// option to remove local variable information
+		dxFlags = append(dxFlags, "--no-locals")
+	}
+
+	if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
+		dxFlags = append(dxFlags, "--no-optimize")
+	}
+
+	if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
+		dxFlags = append(dxFlags,
+			"--debug",
+			"--verbose",
+			"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
+			"--dump-width=1000")
+	}
+
+	var minSdkVersion string
+	switch 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, " ")
+
+	desugarFlags := []string{
+		"--min_sdk_version " + minSdkVersion,
+		"--desugar_try_with_resources_if_needed=false",
+		"--allow_empty_bootclasspath",
+	}
+
+	if inList("--core-library", dxFlags) {
+		desugarFlags = append(desugarFlags, "--core_library")
+	}
+
+	flags.desugarFlags = strings.Join(desugarFlags, " ")
+
+	desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
+	TransformDesugar(ctx, desugarJar, classesJar, flags)
+	if ctx.Failed() {
+		return nil
+	}
+
+	// Compile classes.jar into classes.dex and then javalib.jar
+	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
+	TransformClassesJarToDexJar(ctx, javalibJar, desugarJar, flags)
+	if ctx.Failed() {
+		return nil
+	}
+
+	j.dexJarFile = javalibJar
+	return javalibJar
+}
+
 func (j *Module) installable() bool {
 	return j.properties.Installable == nil || *j.properties.Installable
 }
 
 var _ Dependency = (*Library)(nil)
 
-func (j *Module) ClasspathFiles() android.Paths {
-	return android.Paths{j.classpathFile}
+func (j *Module) HeaderJars() android.Paths {
+	return android.Paths{j.headerJarFile}
+}
+
+func (j *Module) ImplementationJars() android.Paths {
+	return android.Paths{j.implementationJarFile}
 }
 
 func (j *Module) AidlIncludeDirs() android.Paths {
@@ -813,6 +918,8 @@
 
 type ImportProperties struct {
 	Jars []string
+
+	Sdk_version string
 }
 
 type Import struct {
@@ -844,13 +951,17 @@
 	j.classpathFiles = android.PathsForModuleSrc(ctx, j.properties.Jars)
 
 	outputFile := android.PathForModuleOut(ctx, "classes.jar")
-	TransformJarsToJar(ctx, outputFile, j.classpathFiles, android.OptionalPath{}, false)
+	TransformJarsToJar(ctx, outputFile, "for prebuilts", j.classpathFiles, android.OptionalPath{}, false, nil)
 	j.combinedClasspathFile = outputFile
 }
 
 var _ Dependency = (*Import)(nil)
 
-func (j *Import) ClasspathFiles() android.Paths {
+func (j *Import) HeaderJars() android.Paths {
+	return j.classpathFiles
+}
+
+func (j *Import) ImplementationJars() android.Paths {
 	return j.classpathFiles
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index d64688f..451f58e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -123,8 +123,14 @@
 		"res/b":      nil,
 		"res2/a":     nil,
 
-		"prebuilts/sdk/14/android.jar":    nil,
-		"prebuilts/sdk/14/framework.aidl": nil,
+		"prebuilts/sdk/14/android.jar":                nil,
+		"prebuilts/sdk/14/framework.aidl":             nil,
+		"prebuilts/sdk/current/android.jar":           nil,
+		"prebuilts/sdk/current/framework.aidl":        nil,
+		"prebuilts/sdk/system_current/android.jar":    nil,
+		"prebuilts/sdk/system_current/framework.aidl": nil,
+		"prebuilts/sdk/test_current/android.jar":      nil,
+		"prebuilts/sdk/test_current/framework.aidl":   nil,
 	})
 
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -141,8 +147,11 @@
 		return name
 	case strings.HasSuffix(name, ".jar"):
 		return name
+	case name == "android_stubs_current" || name == "android_system_stubs_current" ||
+		name == "android_test_stubs_current":
+		return filepath.Join(buildDir, ".intermediates", name, "android_common", "javac", name+".jar")
 	default:
-		return filepath.Join(buildDir, ".intermediates", name, "android_common", "classes-compiled.jar")
+		return filepath.Join(buildDir, ".intermediates", name, "android_common", "turbine-combined", name+".jar")
 	}
 }
 
@@ -167,21 +176,22 @@
 	`)
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	combineJar := ctx.ModuleForTests("foo", "android_common").Rule("combineJar")
+	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
 
 	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", "android_common", "classes-compiled.jar")
-	baz := filepath.Join(buildDir, ".intermediates", "baz", "android_common", "classes-compiled.jar")
+	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
+	barTurbine := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
+	bazTurbine := filepath.Join(buildDir, ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
 
-	if !strings.Contains(javac.Args["classpath"], bar) {
-		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	if !strings.Contains(javac.Args["classpath"], barTurbine) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
 	}
 
-	if !strings.Contains(javac.Args["classpath"], baz) {
-		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], baz)
+	if !strings.Contains(javac.Args["classpath"], bazTurbine) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bazTurbine)
 	}
 
 	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
@@ -242,25 +252,25 @@
 
 		name:          "current",
 		properties:    `sdk_version: "current",`,
-		bootclasspath: []string{"android_stubs_current"},
-		system:        "android_stubs_current_system_modules",
-		classpath:     []string{},
+		bootclasspath: []string{`""`},
+		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+		classpath:     []string{"prebuilts/sdk/current/android.jar"},
 	},
 	{
 
 		name:          "system_current",
 		properties:    `sdk_version: "system_current",`,
-		bootclasspath: []string{"android_system_stubs_current"},
-		system:        "android_system_stubs_current_system_modules",
-		classpath:     []string{},
+		bootclasspath: []string{`""`},
+		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+		classpath:     []string{"prebuilts/sdk/system_current/android.jar"},
 	},
 	{
 
 		name:          "test_current",
 		properties:    `sdk_version: "test_current",`,
-		bootclasspath: []string{"android_test_stubs_current"},
-		system:        "android_test_stubs_current_system_modules",
-		classpath:     []string{},
+		bootclasspath: []string{`""`},
+		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+		classpath:     []string{"prebuilts/sdk/test_current/android.jar"},
 	},
 	{
 
@@ -421,7 +431,7 @@
 		`)
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	combineJar := ctx.ModuleForTests("foo", "android_common").Rule("combineJar")
+	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
 
 	bar := "a.jar"
 	if !strings.Contains(javac.Args["classpath"], bar) {
@@ -459,18 +469,18 @@
 		`)
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	combineJar := ctx.ModuleForTests("foo", "android_common").Rule("combineJar")
+	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
 
 	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", "android_common", "classes-compiled.jar")
-	if !strings.Contains(javac.Args["classpath"], bar) {
-		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	barTurbine := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
+	if !strings.Contains(javac.Args["classpath"], barTurbine) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
 	}
 
-	baz := filepath.Join(buildDir, ".intermediates", "baz", "android_common", "classes-compiled.jar")
+	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
 	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
 		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
 	}
@@ -530,8 +540,8 @@
 				}
 			`+test.extra)
 
-			foo := ctx.ModuleForTests("foo", "android_common").Output("classes.jar")
-			fooRes := ctx.ModuleForTests("foo", "android_common").Output("res.jar")
+			foo := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
+			fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
 
 			if !inList(fooRes.Output.String(), foo.Inputs.Strings()) {
 				t.Errorf("foo combined jars %v does not contain %q",
@@ -563,7 +573,7 @@
 		}
 	`)
 
-	fooRes := ctx.ModuleForTests("foo", "android_common").Output("res.jar")
+	fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
 
 	expected := "-C res -f res/a -f res/b"
 	if fooRes.Args["jarArgs"] != expected {
@@ -572,7 +582,7 @@
 
 	}
 
-	barRes := ctx.ModuleForTests("bar", "android_common").Output("res.jar")
+	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
 
 	expected = "-C . -f res/a"
 	if barRes.Args["jarArgs"] != expected {
@@ -625,7 +635,7 @@
 
 	kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	jar := ctx.ModuleForTests("foo", "android_common").Output("classes.jar")
+	jar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
 
 	if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" ||
 		kotlinc.Inputs[1].String() != "b.kt" {
diff --git a/java/system_modules.go b/java/system_modules.go
index ddfc5cf..ce66a7c 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -115,7 +115,7 @@
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		if ctx.OtherModuleDependencyTag(module) == libTag {
 			dep, _ := module.(Dependency)
-			jars = append(jars, dep.ClasspathFiles()...)
+			jars = append(jars, dep.HeaderJars()...)
 		}
 	})
 
diff --git a/cmd/soong_zip/Android.bp b/zip/Android.bp
similarity index 85%
copy from cmd/soong_zip/Android.bp
copy to zip/Android.bp
index 3e69336..d708089 100644
--- a/cmd/soong_zip/Android.bp
+++ b/zip/Android.bp
@@ -12,14 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-blueprint_go_binary {
-    name: "soong_zip",
+subdirs = ["cmd"]
+
+bootstrap_go_package {
+    name: "soong-zip",
+    pkgPath: "android/soong/zip",
     deps: [
         "android-archive-zip",
         "soong-jar",
     ],
     srcs: [
-        "soong_zip.go",
+        "zip.go",
         "rate_limit.go",
     ],
 }
+
diff --git a/cmd/soong_zip/Android.bp b/zip/cmd/Android.bp
similarity index 86%
rename from cmd/soong_zip/Android.bp
rename to zip/cmd/Android.bp
index 3e69336..6029a69 100644
--- a/cmd/soong_zip/Android.bp
+++ b/zip/cmd/Android.bp
@@ -15,11 +15,9 @@
 blueprint_go_binary {
     name: "soong_zip",
     deps: [
-        "android-archive-zip",
-        "soong-jar",
+        "soong-zip",
     ],
     srcs: [
-        "soong_zip.go",
-        "rate_limit.go",
+        "main.go",
     ],
 }
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
new file mode 100644
index 0000000..348728c
--- /dev/null
+++ b/zip/cmd/main.go
@@ -0,0 +1,171 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"android/soong/zip"
+)
+
+type byteReaderCloser struct {
+	*bytes.Reader
+	io.Closer
+}
+
+type pathMapping struct {
+	dest, src string
+	zipMethod uint16
+}
+
+type uniqueSet map[string]bool
+
+func (u *uniqueSet) String() string {
+	return `""`
+}
+
+func (u *uniqueSet) Set(s string) error {
+	if _, found := (*u)[s]; found {
+		return fmt.Errorf("File %q was specified twice as a file to not deflate", s)
+	} else {
+		(*u)[s] = true
+	}
+
+	return nil
+}
+
+type file struct{}
+
+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")
+	}
+
+	fArgs = append(fArgs, zip.FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		SourceFiles:         []string{s},
+	})
+
+	return nil
+}
+
+func (l *listFiles) String() string {
+	return `""`
+}
+
+func (l *listFiles) Set(s string) error {
+	if *relativeRoot == "" {
+		return fmt.Errorf("must pass -C before -l")
+	}
+
+	list, err := ioutil.ReadFile(s)
+	if err != nil {
+		return err
+	}
+
+	fArgs = append(fArgs, zip.FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		SourceFiles:         strings.Split(string(list), "\n"),
+	})
+
+	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, zip.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 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'")
+
+	fArgs            zip.FileArgs
+	nonDeflatedFiles = make(uniqueSet)
+
+	cpuProfile = flag.String("cpuprofile", "", "write cpu profile to file")
+	traceFile  = flag.String("trace", "", "write trace to file")
+)
+
+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")
+}
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func main() {
+	flag.Parse()
+
+	err := zip.Run(zip.ZipArgs{
+		FileArgs:                 fArgs,
+		OutputFilePath:           *out,
+		CpuProfileFilePath:       *cpuProfile,
+		TraceFilePath:            *traceFile,
+		EmulateJar:               *emulateJar,
+		AddDirectoryEntriesToZip: *directories,
+		CompressionLevel:         *compLevel,
+		ManifestSourcePath:       *manifest,
+		NumParallelJobs:          *parallelJobs,
+		NonDeflatedFiles:         nonDeflatedFiles,
+	})
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(1)
+	}
+}
diff --git a/cmd/soong_zip/rate_limit.go b/zip/rate_limit.go
similarity index 99%
rename from cmd/soong_zip/rate_limit.go
rename to zip/rate_limit.go
index 9cb5fdd..0ea2ef0 100644
--- a/cmd/soong_zip/rate_limit.go
+++ b/zip/rate_limit.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package zip
 
 import (
 	"fmt"
diff --git a/cmd/soong_zip/soong_zip.go b/zip/zip.go
similarity index 84%
rename from cmd/soong_zip/soong_zip.go
rename to zip/zip.go
index 2bcc9a5..95520fe 100644
--- a/cmd/soong_zip/soong_zip.go
+++ b/zip/zip.go
@@ -12,13 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package zip
 
 import (
 	"bytes"
 	"compress/flate"
 	"errors"
-	"flag"
 	"fmt"
 	"hash/crc32"
 	"io"
@@ -26,7 +25,6 @@
 	"log"
 	"os"
 	"path/filepath"
-	"runtime"
 	"runtime/pprof"
 	"runtime/trace"
 	"sort"
@@ -83,122 +81,6 @@
 	return nil
 }
 
-type file struct{}
-
-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")
-	}
-
-	fArgs = append(fArgs, FileArg{
-		PathPrefixInZip:     filepath.Clean(*rootPrefix),
-		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
-		SourceFiles:         []string{s},
-	})
-
-	return nil
-}
-
-func (l *listFiles) String() string {
-	return `""`
-}
-
-func (l *listFiles) Set(s string) error {
-	if *relativeRoot == "" {
-		return fmt.Errorf("must pass -C before -l")
-	}
-
-	list, err := ioutil.ReadFile(s)
-	if err != nil {
-		return err
-	}
-
-	fArgs = append(fArgs, FileArg{
-		PathPrefixInZip:     filepath.Clean(*rootPrefix),
-		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
-		SourceFiles:         strings.Split(string(list), "\n"),
-	})
-
-	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 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'")
-
-	fArgs            FileArgs
-	nonDeflatedFiles = make(uniqueSet)
-
-	cpuProfile = flag.String("cpuprofile", "", "write cpu profile to file")
-	traceFile  = flag.String("trace", "", "write trace to file")
-)
-
-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")
-}
-
-func usage() {
-	fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
-	flag.PrintDefaults()
-	os.Exit(2)
-}
-
-func main() {
-	flag.Parse()
-
-	err := Run(ZipArgs{
-		FileArgs:                 fArgs,
-		OutputFilePath:           *out,
-		CpuProfileFilePath:       *cpuProfile,
-		TraceFilePath:            *traceFile,
-		EmulateJar:               *emulateJar,
-		AddDirectoryEntriesToZip: *directories,
-		CompressionLevel:         *compLevel,
-		ManifestSourcePath:       *manifest,
-		NumParallelJobs:          *parallelJobs,
-		NonDeflatedFiles:         nonDeflatedFiles,
-	})
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Exit(1)
-	}
-}
-
 type FileArg struct {
 	PathPrefixInZip, SourcePrefixToStrip string
 	SourceFiles                          []string