Merge "Add target.linux for linux kernel based targets"
diff --git a/Android.bp b/Android.bp
index 0e57c12..ae31a60 100644
--- a/Android.bp
+++ b/Android.bp
@@ -209,6 +209,7 @@
         "java/builder.go",
         "java/gen.go",
         "java/java.go",
+        "java/proto.go",
         "java/resources.go",
     ],
     testSrcs: [
diff --git a/android/proto.go b/android/proto.go
index 9bb9cfb..1c70656 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -14,22 +14,6 @@
 
 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
@@ -38,30 +22,6 @@
 // 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 {
diff --git a/cc/cc.go b/cc/cc.go
index b4b70ed..4f10a11 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -673,6 +673,12 @@
 	if c.compiler != nil {
 		deps = c.compiler.compilerDeps(ctx, deps)
 	}
+	// Add the PGO dependency (the clang_rt.profile runtime library), which
+	// sometimes depends on symbols from libgcc, before libgcc gets added
+	// in linkerDeps().
+	if c.pgo != nil {
+		deps = c.pgo.deps(ctx, deps)
+	}
 	if c.linker != nil {
 		deps = c.linker.linkerDeps(ctx, deps)
 	}
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index d62ebe4..796ccfb 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -233,6 +233,10 @@
 	return SanitizerRuntimeLibrary(t, "tsan")
 }
 
+func ProfileRuntimeLibrary(t Toolchain) string {
+	return SanitizerRuntimeLibrary(t, "profile")
+}
+
 func ToolPath(t Toolchain) string {
 	if p := t.ToolPath(); p != "" {
 		return p
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 3f079a4..6d361b5 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -159,6 +159,8 @@
 		strings.Join(ClangFilterUnknownCflags(darwinX8664Cflags), " "))
 	pctx.StaticVariable("DarwinX86ClangLdflags", strings.Join(darwinX86ClangLdflags, " "))
 	pctx.StaticVariable("DarwinX8664ClangLdflags", strings.Join(darwinX8664ClangLdflags, " "))
+	pctx.StaticVariable("DarwinX86YasmFlags", "-f macho -m x86")
+	pctx.StaticVariable("DarwinX8664YasmFlags", "-f macho -m amd64")
 }
 
 func xcrun(config android.Config, args ...string) (string, error) {
@@ -276,6 +278,14 @@
 	return "${config.DarwinClangLdflags} ${config.DarwinX8664ClangLdflags}"
 }
 
+func (t *toolchainDarwinX86) YasmFlags() string {
+	return "${config.DarwinX86YasmFlags}"
+}
+
+func (t *toolchainDarwinX8664) YasmFlags() string {
+	return "${config.DarwinX8664YasmFlags}"
+}
+
 func (t *toolchainDarwin) ShlibSuffix() string {
 	return ".dylib"
 }
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 75416bd..88bd514 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -159,6 +159,9 @@
 	pctx.StaticVariable("LinuxX8664ClangLdflags", strings.Join(linuxX8664ClangLdflags, " "))
 	pctx.StaticVariable("LinuxX86ClangCppflags", strings.Join(linuxX86ClangCppflags, " "))
 	pctx.StaticVariable("LinuxX8664ClangCppflags", strings.Join(linuxX8664ClangCppflags, " "))
+	// Yasm flags
+	pctx.StaticVariable("LinuxX86YasmFlags", "-f elf32 -m x86")
+	pctx.StaticVariable("LinuxX8664YasmFlags", "-f elf64 -m amd64")
 }
 
 type toolchainLinux struct {
@@ -251,6 +254,14 @@
 	return "${config.LinuxClangLdflags} ${config.LinuxX8664ClangLdflags}"
 }
 
+func (t *toolchainLinuxX86) YasmFlags() string {
+	return "${config.LinuxX86YasmFlags}"
+}
+
+func (t *toolchainLinuxX8664) YasmFlags() string {
+	return "${config.LinuxX8664YasmFlags}"
+}
+
 func (t *toolchainLinux) AvailableLibraries() []string {
 	return linuxAvailableLibraries
 }
diff --git a/cc/gen.go b/cc/gen.go
index 9fc14c5..2280e0f 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -153,10 +153,9 @@
 			srcFiles[i] = cppFile
 			genLex(ctx, srcFile, cppFile)
 		case ".proto":
-			protoFiles := android.GenProto(ctx, srcFile, buildFlags.protoFlags,
-				"--cpp_out", "", []string{"pb.cc", "pb.h"})
-			srcFiles[i] = protoFiles[0]
-			deps = append(deps, protoFiles[1])
+			ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags)
+			srcFiles[i] = ccFile
+			deps = append(deps, headerFile)
 		case ".aidl":
 			cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
 			srcFiles[i] = cppFile
diff --git a/cc/pgo.go b/cc/pgo.go
index ccddece..a99cbad 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -19,12 +19,13 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/cc/config"
 )
 
 var (
 	// Add flags to ignore warnings that profiles are old or missing for
 	// some functions
-	profileUseOtherFlags = []string{}
+	profileUseOtherFlags = []string{"-Wno-backend-plugin"}
 )
 
 const pgoProfileProject = "toolchain/pgo-profiles"
@@ -50,25 +51,38 @@
 	Properties PgoProperties
 }
 
+func (props *PgoProperties) isInstrumentation() bool {
+	return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
+}
+
+func (props *PgoProperties) isSampling() bool {
+	return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
+}
+
 func (pgo *pgo) props() []interface{} {
 	return []interface{}{&pgo.Properties}
 }
 
-func (pgo *pgo) profileGatherFlags(ctx ModuleContext) string {
-	if *pgo.Properties.Pgo.Instrumentation {
-		return profileInstrumentFlag
+func (pgo *pgo) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	if pgo.Properties.isInstrumentation() {
+		flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
+		// The profile runtime is added below in deps().  Add the below
+		// flag, which is the only other link-time action performed by
+		// the Clang driver during link.
+		flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
 	}
-	if *pgo.Properties.Pgo.Sampling {
-		return profileSamplingFlag
+	if pgo.Properties.isSampling() {
+		flags.CFlags = append(flags.CFlags, profileSamplingFlag)
+		flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
 	}
-	return ""
+	return flags
 }
 
 func (pgo *pgo) profileUseFlag(ctx ModuleContext, file string) string {
-	if *pgo.Properties.Pgo.Instrumentation {
+	if pgo.Properties.isInstrumentation() {
 		return fmt.Sprintf(profileUseInstrumentFormat, file)
 	}
-	if *pgo.Properties.Pgo.Sampling {
+	if pgo.Properties.isSampling() {
 		return fmt.Sprintf(profileUseSamplingFormat, file)
 	}
 	return ""
@@ -81,8 +95,8 @@
 }
 
 func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
-	isInstrumentation := props.Pgo.Instrumentation != nil
-	isSampling := props.Pgo.Sampling != nil
+	isInstrumentation := props.isInstrumentation()
+	isSampling := props.isSampling()
 
 	profileKindPresent := isInstrumentation || isSampling
 	filePresent := props.Pgo.Profile_file != nil
@@ -110,13 +124,14 @@
 	}
 
 	// Sampling not supported yet
-	//
-	// TODO When sampling support is turned on, check that instrumentation and
-	// sampling are not simultaneously specified
 	if isSampling {
 		ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
 	}
 
+	if isSampling && isInstrumentation {
+		ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
+	}
+
 	return true
 }
 
@@ -156,6 +171,14 @@
 	}
 }
 
+func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
+	if pgo.Properties.ShouldProfileModule {
+		runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
+		deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
+	}
+	return deps
+}
+
 func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
 	if ctx.Host() {
 		return flags
@@ -165,10 +188,7 @@
 
 	// Add flags to profile this module based on its profile_kind
 	if props.ShouldProfileModule {
-		profileGatherFlags := pgo.profileGatherFlags(ctx)
-		flags.LdFlags = append(flags.LdFlags, profileGatherFlags)
-		flags.CFlags = append(flags.CFlags, profileGatherFlags)
-		return flags
+		return pgo.addProfileGatherFlags(ctx, flags)
 	}
 
 	// If the PGO profiles project is found, and this module has PGO
diff --git a/cc/proto.go b/cc/proto.go
index 6049d44..a01951f 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -15,11 +15,46 @@
 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")
+)
+
+// genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
+// the paths to the generated files.
+func genProto(ctx android.ModuleContext, protoFile android.Path,
+	protoFlags string) (ccFile, headerFile android.WritablePath) {
+
+	ccFile = 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{ccFile, headerFile},
+		Input:       protoFile,
+		Args: map[string]string{
+			"outDir":     android.ProtoDir(ctx).String(),
+			"protoFlags": protoFlags,
+		},
+	})
+
+	return ccFile, headerFile
+}
+
 func protoDeps(ctx BaseModuleContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
 	var lib string
 
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a94392b..e16c00e 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -29,26 +29,26 @@
 	"android/soong/third_party/zip"
 )
 
-type stripDir struct{}
+type fileList []string
 
-func (s *stripDir) String() string {
+func (f *fileList) String() string {
 	return `""`
 }
 
-func (s *stripDir) Set(dir string) error {
-	stripDirs = append(stripDirs, filepath.Clean(dir))
+func (f *fileList) Set(name string) error {
+	*f = append(*f, filepath.Clean(name))
 
 	return nil
 }
 
-type zipToNotStrip struct{}
+type zipsToNotStripSet map[string]bool
 
-func (s *zipToNotStrip) String() string {
+func (s zipsToNotStripSet) String() string {
 	return `""`
 }
 
-func (s *zipToNotStrip) Set(zip_path string) error {
-	zipsToNotStrip[zip_path] = true
+func (s zipsToNotStripSet) Set(zip_path string) error {
+	s[zip_path] = true
 
 	return nil
 }
@@ -56,15 +56,17 @@
 var (
 	sortEntries     = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
 	emulateJar      = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
-	stripDirs       []string
-	zipsToNotStrip  = make(map[string]bool)
+	stripDirs       fileList
+	stripFiles      fileList
+	zipsToNotStrip  = make(zipsToNotStripSet)
 	stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
 	manifest        = flag.String("m", "", "manifest file to insert in jar")
 )
 
 func init() {
-	flag.Var(&stripDir{}, "stripDir", "the prefix of file path to be excluded from the output zip")
-	flag.Var(&zipToNotStrip{}, "zipToNotStrip", "the input zip file which is not applicable for stripping")
+	flag.Var(&stripDirs, "stripDir", "the prefix of file path to be excluded from the output zip")
+	flag.Var(&stripFiles, "stripFile", "filenames to be excluded from the output zip, accepts wildcards")
+	flag.Var(&zipsToNotStrip, "zipToNotStrip", "the input zip file which is not applicable for stripping")
 }
 
 func main() {
@@ -243,20 +245,9 @@
 
 	for _, namedReader := range readers {
 		_, skipStripThisZip := zipsToNotStrip[namedReader.path]
-	FileLoop:
 		for _, file := range namedReader.reader.File {
-			if !skipStripThisZip {
-				for _, dir := range stripDirs {
-					if strings.HasPrefix(file.Name, dir+"/") {
-						if emulateJar {
-							if file.Name != jar.MetaDir && file.Name != jar.ManifestFile {
-								continue FileLoop
-							}
-						} else {
-							continue FileLoop
-						}
-					}
-				}
+			if !skipStripThisZip && shouldStripFile(emulateJar, file.Name) {
+				continue
 			}
 
 			if stripDirEntries && file.FileInfo().IsDir() {
@@ -310,6 +301,28 @@
 	return nil
 }
 
+func shouldStripFile(emulateJar bool, name string) bool {
+	for _, dir := range stripDirs {
+		if strings.HasPrefix(name, dir+"/") {
+			if emulateJar {
+				if name != jar.MetaDir && name != jar.ManifestFile {
+					return true
+				}
+			} else {
+				return true
+			}
+		}
+	}
+	for _, pattern := range stripFiles {
+		if match, err := filepath.Match(pattern, filepath.Base(name)); err != nil {
+			panic(fmt.Errorf("%s: %s", err.Error(), pattern))
+		} else if match {
+			return true
+		}
+	}
+	return false
+}
+
 func jarSort(files []fileMapping) {
 	sort.SliceStable(files, func(i, j int) bool {
 		return jar.EntryNamesLess(files[i].dest, files[j].dest)
diff --git a/jar/jar.go b/jar/jar.go
index 08fa1ab..653e5ee 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -31,7 +31,7 @@
 	ModuleInfoClass = "module-info.class"
 )
 
-var DefaultTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
+var DefaultTime = time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC)
 
 var MetaDirExtra = [2]byte{0xca, 0xfe}
 
diff --git a/java/builder.go b/java/builder.go
index 95345d4..ca0d2c5 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -99,10 +99,12 @@
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
 				`${config.DxCmd} --dex --output=$outDir $dxFlags $in && ` +
-				`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
+				`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
+				`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
 			CommandDeps: []string{
 				"${config.DxCmd}",
 				"${config.SoongZipCmd}",
+				"${config.MergeZipsCmd}",
 			},
 		},
 		"outDir", "dxFlags")
@@ -127,6 +129,9 @@
 	desugarFlags  string
 	aidlFlags     string
 	javaVersion   string
+
+	protoFlags   string
+	protoOutFlag string
 }
 
 func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
@@ -136,7 +141,10 @@
 	annoDir := android.PathForModuleOut(ctx, "anno")
 	classJar := android.PathForModuleOut(ctx, "classes-compiled.jar")
 
-	javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@")
+	javacFlags := flags.javacFlags
+	if len(srcFileLists) > 0 {
+		javacFlags += " " + android.JoinWithPrefix(srcFileLists.Strings(), "@")
+	}
 
 	deps = append(deps, srcFileLists...)
 	deps = append(deps, flags.bootClasspath...)
@@ -161,8 +169,8 @@
 	return classJar
 }
 
-func RunErrorProne(ctx android.ModuleContext, srcFiles android.Paths, srcFileLists android.Paths,
-	flags javaBuilderFlags, deps android.Paths) android.Path {
+func RunErrorProne(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
+	flags javaBuilderFlags) android.Path {
 
 	if config.ErrorProneJar == "" {
 		ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
@@ -173,7 +181,12 @@
 	annoDir := android.PathForModuleOut(ctx, "anno-errorprone")
 	classFileList := android.PathForModuleOut(ctx, "classes-errorprone.list")
 
-	javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@")
+	javacFlags := flags.javacFlags
+	if len(srcFileLists) > 0 {
+		javacFlags += " " + android.JoinWithPrefix(srcFileLists.Strings(), "@")
+	}
+
+	var deps android.Paths
 
 	deps = append(deps, srcFileLists...)
 	deps = append(deps, flags.bootClasspath...)
@@ -287,11 +300,13 @@
 	return outputFile
 }
 
-func TransformClassesJarToDexJar(ctx android.ModuleContext, classesJar android.Path,
+// Converts a classes.jar file to classes*.dex, then combines the dex files with any resources
+// in the classes.jar file into a dex jar.
+func TransformClassesJarToDexJar(ctx android.ModuleContext, stem string, classesJar android.Path,
 	flags javaBuilderFlags) android.Path {
 
 	outDir := android.PathForModuleOut(ctx, "dex")
-	outputFile := android.PathForModuleOut(ctx, "classes.dex.jar")
+	outputFile := android.PathForModuleOut(ctx, stem)
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:        dx,
diff --git a/java/config/config.go b/java/config/config.go
index 4f74ef2..70b8fe5 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -53,8 +53,16 @@
 
 	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 
-	pctx.SourcePathVariableWithEnvOverride("JavaHome",
-		"prebuilts/jdk/jdk8/${hostPrebuiltTag}", "OVERRIDE_ANDROID_JAVA_HOME")
+	pctx.VariableFunc("JavaHome", func(config interface{}) (string, error) {
+		if override := config.(android.Config).Getenv("OVERRIDE_ANDROID_JAVA_HOME"); override != "" {
+			return override, nil
+		}
+		if jdk9 := config.(android.Config).Getenv("EXPERIMENTAL_USE_OPENJDK9"); jdk9 != "" {
+			return "prebuilts/jdk/jdk9/${hostPrebuiltTag}", nil
+		}
+		return "prebuilts/jdk/jdk8/${hostPrebuiltTag}", nil
+	})
+
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
 	pctx.SourcePathVariableWithEnvOverride("JavacCmd",
 		"${JavaToolchain}/javac", "ALTERNATE_JAVAC")
diff --git a/java/gen.go b/java/gen.go
index e473859..e55be91 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -85,21 +85,37 @@
 }
 
 func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths,
-	flags javaBuilderFlags) android.Paths {
+	flags javaBuilderFlags) (android.Paths, android.Paths) {
 
-	for i, srcFile := range srcFiles {
+	var protoFiles android.Paths
+	outSrcFiles := make(android.Paths, 0, len(srcFiles))
+
+	for _, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".aidl":
 			javaFile := genAidl(ctx, srcFile, flags.aidlFlags)
-			srcFiles[i] = javaFile
+			outSrcFiles = append(outSrcFiles, javaFile)
 		case ".logtags":
 			j.logtagsSrcs = append(j.logtagsSrcs, srcFile)
 			javaFile := genLogtags(ctx, srcFile)
-			srcFiles[i] = javaFile
+			outSrcFiles = append(outSrcFiles, javaFile)
+		case ".proto":
+			protoFiles = append(protoFiles, srcFile)
+		default:
+			outSrcFiles = append(outSrcFiles, srcFile)
 		}
 	}
 
-	return srcFiles
+	var outSrcFileLists android.Paths
+
+	if len(protoFiles) > 0 {
+		protoFileList := genProto(ctx, protoFiles,
+			flags.protoFlags, flags.protoOutFlag, "")
+
+		outSrcFileLists = append(outSrcFileLists, protoFileList)
+	}
+
+	return outSrcFiles, outSrcFileLists
 }
 
 func LogtagsSingleton() blueprint.Singleton {
diff --git a/java/java.go b/java/java.go
index d8bc0c2..bab77c5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -49,7 +49,6 @@
 
 // TODO:
 // Autogenerated files:
-//  Proto
 //  Renderscript
 // Post-jar passes:
 //  Proguard
@@ -145,6 +144,7 @@
 	android.DefaultableModuleBase
 
 	properties       CompilerProperties
+	protoProperties  android.ProtoProperties
 	deviceProperties CompilerDeviceProperties
 
 	// output file suitable for inserting into the classpath of another compile
@@ -153,9 +153,6 @@
 	// output file containing classes.dex
 	dexJarFile android.Path
 
-	// output files containing resources
-	resourceJarFiles android.Paths
-
 	// output file suitable for installing or running
 	outputFile android.Path
 
@@ -173,7 +170,6 @@
 
 type Dependency interface {
 	ClasspathFiles() android.Paths
-	ResourceJarFiles() android.Paths
 	AidlIncludeDirs() android.Paths
 }
 
@@ -285,9 +281,7 @@
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
 			}
 		} else {
-			if j.deviceProperties.Dex {
-				ctx.AddDependency(ctx.Module(), bootClasspathTag, config.DefaultBootclasspathLibraries...)
-			}
+			// TODO(ccross): add hostdex support
 		}
 	}
 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
@@ -296,6 +290,24 @@
 
 	android.ExtractSourcesDeps(ctx, j.properties.Srcs)
 	android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
+
+	if j.hasSrcExt(".proto") {
+		protoDeps(ctx, &j.protoProperties)
+	}
+}
+
+func hasSrcExt(srcs []string, ext string) bool {
+	for _, src := range srcs {
+		if filepath.Ext(src) == ext {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (j *Module) hasSrcExt(ext string) bool {
+	return hasSrcExt(j.properties.Srcs, ext)
 }
 
 func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
@@ -364,7 +376,6 @@
 		case staticLibTag:
 			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
 			deps.staticJars = append(deps.staticJars, dep.ClasspathFiles()...)
-			deps.staticJarResources = append(deps.staticJarResources, dep.ResourceJarFiles()...)
 		case frameworkResTag:
 			if ctx.ModuleName() == "framework" {
 				// framework.jar has a one-off dependency on the R.java and Manifest.java files
@@ -416,7 +427,15 @@
 
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
 
-	srcFiles = j.genSources(ctx, srcFiles, flags)
+	if hasSrcExt(srcFiles.Strings(), ".proto") {
+		flags = protoFlags(ctx, &j.protoProperties, flags)
+	}
+
+	var srcFileLists android.Paths
+
+	srcFiles, srcFileLists = j.genSources(ctx, srcFiles, flags)
+
+	srcFileLists = append(srcFileLists, deps.srcFileLists...)
 
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		if gen, ok := module.(genrule.SourceFileGenerator); ok {
@@ -424,7 +443,7 @@
 		}
 	})
 
-	deps.srcFileLists = append(deps.srcFileLists, j.ExtraSrcLists...)
+	srcFileLists = append(srcFileLists, j.ExtraSrcLists...)
 
 	var jars android.Paths
 
@@ -436,12 +455,12 @@
 			// 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 := RunErrorProne(ctx, srcFiles, deps.srcFileLists, flags, nil)
+			errorprone := RunErrorProne(ctx, srcFiles, srcFileLists, flags)
 			extraJarDeps = append(extraJarDeps, errorprone)
 		}
 
 		// Compile java sources into .class files
-		classes := TransformJavaToClasses(ctx, srcFiles, deps.srcFileLists, flags, extraJarDeps)
+		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, extraJarDeps)
 		if ctx.Failed() {
 			return
 		}
@@ -462,26 +481,20 @@
 	resDeps = append(resDeps, fileDeps...)
 
 	if proptools.Bool(j.properties.Include_srcs) {
-		srcArgs, srcDeps := ResourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+		srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
 		resArgs = append(resArgs, srcArgs...)
 		resDeps = append(resDeps, srcDeps...)
 	}
 
 	if len(resArgs) > 0 {
-		// Combine classes + resources into classes-full-debug.jar
 		resourceJar := TransformResourcesToJar(ctx, resArgs, resDeps)
 		if ctx.Failed() {
 			return
 		}
 
-		j.resourceJarFiles = append(j.resourceJarFiles, resourceJar)
 		jars = append(jars, resourceJar)
 	}
 
-	// Propagate the resources from the transitive closure of static dependencies for copying
-	// into dex jars
-	j.resourceJarFiles = append(j.resourceJarFiles, deps.staticJarResources...)
-
 	// static classpath jars have the resources in them, so the resource jars aren't necessary here
 	jars = append(jars, deps.staticJars...)
 
@@ -503,7 +516,7 @@
 	j.classpathFile = outputFile
 
 	// TODO(ccross): handle hostdex
-	if ctx.Device() && len(srcFiles) > 0 && j.installable() {
+	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
@@ -556,17 +569,12 @@
 			return
 		}
 
-		// Compile classes.jar into classes.dex
-		dexJarFile := TransformClassesJarToDexJar(ctx, desugarJar, flags)
+		// Compile classes.jar into classes.dex and then javalib.jar
+		outputFile = TransformClassesJarToDexJar(ctx, "javalib.jar", desugarJar, flags)
 		if ctx.Failed() {
 			return
 		}
 
-		jars := android.Paths{dexJarFile}
-		jars = append(jars, j.resourceJarFiles...)
-
-		outputFile = TransformJarsToJar(ctx, "javalib.jar", jars, android.OptionalPath{}, true)
-
 		j.dexJarFile = outputFile
 	}
 	ctx.CheckbuildFile(outputFile)
@@ -583,10 +591,6 @@
 	return android.Paths{j.classpathFile}
 }
 
-func (j *Module) ResourceJarFiles() android.Paths {
-	return j.resourceJarFiles
-}
-
 func (j *Module) AidlIncludeDirs() android.Paths {
 	return j.exportAidlIncludeDirs
 }
@@ -629,7 +633,8 @@
 
 		module.AddProperties(
 			&module.Module.properties,
-			&module.Module.deviceProperties)
+			&module.Module.deviceProperties,
+			&module.Module.protoProperties)
 
 		InitJavaModule(module, android.HostAndDeviceSupported)
 		return module
@@ -639,7 +644,9 @@
 func LibraryHostFactory() android.Module {
 	module := &Library{}
 
-	module.AddProperties(&module.Module.properties)
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.protoProperties)
 
 	InitJavaModule(module, android.HostSupported)
 	return module
@@ -685,6 +692,7 @@
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
+		&module.Module.protoProperties,
 		&module.binaryProperties)
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
@@ -697,6 +705,7 @@
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
+		&module.Module.protoProperties,
 		&module.binaryProperties)
 
 	InitJavaModule(module, android.HostSupported)
@@ -748,11 +757,6 @@
 	return j.classpathFiles
 }
 
-func (j *Import) ResourceJarFiles() android.Paths {
-	// resources are in the ClasspathFiles
-	return nil
-}
-
 func (j *Import) AidlIncludeDirs() android.Paths {
 	return nil
 }
diff --git a/java/java_test.go b/java/java_test.go
index 2b92f49..c2c7ee2 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -185,6 +185,7 @@
 
 var classpathTestcases = []struct {
 	name          string
+	moduleType    string
 	host          android.OsClass
 	properties    string
 	bootclasspath []string
@@ -239,27 +240,41 @@
 	{
 
 		name:       "host default",
-		host:       android.Host,
+		moduleType: "java_library_host",
 		properties: ``,
+		host:       android.Host,
 		classpath:  []string{},
 	},
 	{
 		name:       "host nostdlib",
+		moduleType: "java_library_host",
 		host:       android.Host,
 		properties: `no_standard_libs: true`,
 		classpath:  []string{},
 	},
+	{
+
+		name:       "host supported default",
+		host:       android.Host,
+		properties: `host_supported: true,`,
+		classpath:  []string{},
+	},
+	{
+		name:       "host supported nostdlib",
+		host:       android.Host,
+		properties: `host_supported: true, no_standard_libs: true`,
+		classpath:  []string{},
+	},
 }
 
 func TestClasspath(t *testing.T) {
 	for _, testcase := range classpathTestcases {
 		t.Run(testcase.name, func(t *testing.T) {
-			hostExtra := ""
-			if testcase.host == android.Host {
-				hostExtra = "_host"
+			moduleType := "java_library"
+			if testcase.moduleType != "" {
+				moduleType = testcase.moduleType
 			}
-			ctx := testJava(t, `
-			java_library`+hostExtra+` {
+			ctx := testJava(t, moduleType+` {
 				name: "foo",
 				srcs: ["a.java"],
 				`+testcase.properties+`
@@ -393,16 +408,16 @@
 		args  string
 	}{
 		{
-			// Test that a module with java_resource_dirs includes a file list file
+			// Test that a module with java_resource_dirs includes the files
 			name: "resource dirs",
 			prop: `java_resource_dirs: ["res"]`,
-			args: "-C res -l ",
+			args: "-C res -f res/a -f res/b",
 		},
 		{
 			// Test that a module with java_resources includes the files
 			name: "resource files",
 			prop: `java_resources: ["res/a", "res/b"]`,
-			args: "-C . -f res/a -C . -f res/b",
+			args: "-C . -f res/a -f res/b",
 		},
 		{
 			// Test that a module with a filegroup in java_resources includes the files with the
@@ -415,13 +430,13 @@
 					path: "res",
 					srcs: ["res/a", "res/b"],
 				}`,
-			args: "-C res -f res/a -C res -f res/b",
+			args: "-C res -f res/a -f res/b",
 		},
 		{
 			// Test that a module with "include_srcs: true" includes its source files in the resources jar
 			name: "include sources",
 			prop: `include_srcs: true`,
-			args: "-C . -f a.java -C . -f b.java -C . -f c.java",
+			args: "-C . -f a.java -f b.java -f c.java",
 		},
 	}
 
@@ -447,8 +462,8 @@
 					foo.Inputs.Strings(), fooRes.Output.String())
 			}
 
-			if !strings.Contains(fooRes.Args["jarArgs"], test.args) {
-				t.Errorf("foo resource jar args %q does not contain %q",
+			if fooRes.Args["jarArgs"] != test.args {
+				t.Errorf("foo resource jar args %q is not %q",
 					fooRes.Args["jarArgs"], test.args)
 			}
 		})
@@ -474,7 +489,7 @@
 
 	fooRes := ctx.ModuleForTests("foo", "android_common").Output("res.jar")
 
-	expected := "-C res -l " + fooRes.Implicits[0].String()
+	expected := "-C res -f res/a -f res/b"
 	if fooRes.Args["jarArgs"] != expected {
 		t.Errorf("foo resource jar args %q is not %q",
 			fooRes.Args["jarArgs"], expected)
diff --git a/java/proto.go b/java/proto.go
new file mode 100644
index 0000000..dd8cabd
--- /dev/null
+++ b/java/proto.go
@@ -0,0 +1,98 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+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: `rm -rf $outDir && mkdir -p $outDir && ` +
+				`$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in && ` +
+				`find $outDir -name "*.java" > $out`,
+			CommandDeps: []string{"$protocCmd"},
+		}, "protoFlags", "protoOut", "protoOutFlags", "outDir")
+)
+
+func genProto(ctx android.ModuleContext, protoFiles android.Paths,
+	protoFlags string, protoOut, protoOutFlags string) android.WritablePath {
+
+	protoFileList := android.PathForModuleGen(ctx, "proto.filelist")
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:        proto,
+		Description: "protoc " + protoFiles[0].Rel(),
+		Output:      protoFileList,
+		Inputs:      protoFiles,
+		Args: map[string]string{
+			"outDir":        android.ProtoDir(ctx).String(),
+			"protoOut":      protoOut,
+			"protoOutFlags": protoOutFlags,
+			"protoFlags":    protoFlags,
+		},
+	})
+
+	return protoFileList
+}
+
+func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) {
+	switch proptools.String(p.Proto.Type) {
+	case "micro":
+		ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-micro")
+	case "nano":
+		ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-nano")
+	case "stream":
+		// TODO(ccross): add dependency on protoc-gen-java-stream binary
+		ctx.PropertyErrorf("proto.type", `"stream" not supported yet`)
+		// No library for stream protobufs
+	case "lite", "":
+		ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-lite")
+	case "full":
+		if ctx.Host() {
+			ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-full")
+		} else {
+			ctx.PropertyErrorf("proto.type", "full java protos only supported on the host")
+		}
+	default:
+		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+			proptools.String(p.Proto.Type))
+	}
+}
+
+func protoFlags(ctx android.ModuleContext, p *android.ProtoProperties, flags javaBuilderFlags) javaBuilderFlags {
+	switch proptools.String(p.Proto.Type) {
+	case "micro":
+		flags.protoOutFlag = "--javamicro_out"
+	case "nano":
+		flags.protoOutFlag = "--javanano_out"
+	case "stream":
+		flags.protoOutFlag = "--javastream_out"
+	case "lite", "full", "":
+		flags.protoOutFlag = "--java_out"
+	default:
+		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+			proptools.String(p.Proto.Type))
+	}
+	return flags
+}
diff --git a/java/resources.go b/java/resources.go
index 85ebd52..a596fd7 100644
--- a/java/resources.go
+++ b/java/resources.go
@@ -19,8 +19,6 @@
 	"path/filepath"
 	"strings"
 
-	"github.com/google/blueprint/bootstrap"
-
 	"android/soong/android"
 )
 
@@ -33,15 +31,6 @@
 	"**/*~",
 }
 
-func isStringInSlice(str string, slice []string) bool {
-	for _, s := range slice {
-		if s == str {
-			return true
-		}
-	}
-	return false
-}
-
 func ResourceDirsToJarArgs(ctx android.ModuleContext,
 	resourceDirs, excludeDirs []string) (args []string, deps android.Paths) {
 	var excludes []string
@@ -53,40 +42,64 @@
 
 	excludes = append(excludes, resourceExcludes...)
 
-	for _, resourceDir := range resourceDirs {
-		if isStringInSlice(resourceDir, excludeDirs) {
-			continue
-		}
-		resourceDir := android.PathForModuleSrc(ctx, resourceDir)
-		dirs := ctx.Glob(resourceDir.String(), nil)
-		for _, dir := range dirs {
-			fileListFile := android.ResPathWithName(ctx, dir, "resources.list")
-			depFile := fileListFile.String() + ".d"
+	for _, dir := range resourceDirs {
+		dir := android.PathForModuleSrc(ctx, dir).String()
+		files := ctx.Glob(filepath.Join(dir, "**/*"), excludes)
 
-			pattern := filepath.Join(dir.String(), "**/*")
-			bootstrap.GlobFile(ctx, pattern, excludes, fileListFile.String(), depFile)
-			args = append(args,
-				"-C", dir.String(),
-				"-l", fileListFile.String())
-			deps = append(deps, fileListFile)
+		deps = append(deps, files...)
+
+		if len(files) > 0 {
+			args = append(args, "-C", dir)
+
+			for _, f := range files {
+				path := f.String()
+				if !strings.HasPrefix(path, dir) {
+					panic(fmt.Errorf("path %q does not start with %q", path, dir))
+				}
+				args = append(args, "-f", path)
+			}
 		}
 	}
 
 	return args, deps
 }
 
+// Convert java_resources properties to arguments to soong_zip -jar, ignoring common patterns
+// that should not be treated as resources (including *.java).
 func ResourceFilesToJarArgs(ctx android.ModuleContext,
 	res, exclude []string) (args []string, deps android.Paths) {
+
+	exclude = append([]string(nil), exclude...)
+	exclude = append(exclude, resourceExcludes...)
+	return resourceFilesToJarArgs(ctx, res, exclude)
+}
+
+// Convert java_resources properties to arguments to soong_zip -jar, keeping files that should
+// normally not used as resources like *.java
+func SourceFilesToJarArgs(ctx android.ModuleContext,
+	res, exclude []string) (args []string, deps android.Paths) {
+
+	return resourceFilesToJarArgs(ctx, res, exclude)
+}
+
+func resourceFilesToJarArgs(ctx android.ModuleContext,
+	res, exclude []string) (args []string, deps android.Paths) {
+
 	files := ctx.ExpandSources(res, exclude)
 
-	for _, f := range files {
+	lastDir := ""
+	for i, f := range files {
 		rel := f.Rel()
 		path := f.String()
 		if !strings.HasSuffix(path, rel) {
 			panic(fmt.Errorf("path %q does not end with %q", path, rel))
 		}
-		path = filepath.Clean(strings.TrimSuffix(path, rel))
-		args = append(args, "-C", filepath.Clean(path), "-f", f.String())
+		dir := filepath.Clean(strings.TrimSuffix(path, rel))
+		if i == 0 || dir != lastDir {
+			args = append(args, "-C", dir)
+		}
+		args = append(args, "-f", path)
+		lastDir = dir
 	}
 
 	return args, files