Merge "Implement DPI variants in android_app_import."
diff --git a/cc/config/global.go b/cc/config/global.go
index 0a7d984..24075d9 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -84,6 +84,7 @@
 		"-Wl,--fatal-warnings",
 		"-Wl,--no-undefined-version",
 		"-Wl,--exclude-libs,libgcc.a",
+		"-Wl,--exclude-libs,libgcc_stripped.a",
 	}
 
 	deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index d6999c5..5f9bd01 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -32,42 +32,89 @@
 	"android/soong/ui/tracer"
 )
 
+// A command represents an operation to be executed in the soong build
+// system.
+type command struct {
+	// the flag name (must have double dashes)
+	flag string
+
+	// description for the flag (to display when running help)
+	description string
+
+	// Creates the build configuration based on the args and build context.
+	config func(ctx build.Context, args ...string) build.Config
+
+	// Returns what type of IO redirection this Command requires.
+	stdio func() terminal.StdioInterface
+
+	// run the command
+	run func(ctx build.Context, config build.Config, args []string, logsDir string)
+}
+
+const makeModeFlagName = "--make-mode"
+
+// list of supported commands (flags) supported by soong ui
+var commands []command = []command{
+	{
+		flag:        makeModeFlagName,
+		description: "build the modules by the target name (i.e. soong_docs)",
+		config: func(ctx build.Context, args ...string) build.Config {
+			return build.NewConfig(ctx, args...)
+		},
+		stdio: func() terminal.StdioInterface {
+			return terminal.StdioImpl{}
+		},
+		run: make,
+	}, {
+		flag:        "--dumpvar-mode",
+		description: "print the value of the legacy make variable VAR to stdout",
+		config:      dumpVarConfig,
+		stdio:       customStdio,
+		run:         dumpVar,
+	}, {
+		flag:        "--dumpvars-mode",
+		description: "dump the values of one or more legacy make variables, in shell syntax",
+		config:      dumpVarConfig,
+		stdio:       customStdio,
+		run:         dumpVars,
+	},
+}
+
+// indexList returns the index of first found s. -1 is return if s is not
+// found.
 func indexList(s string, list []string) int {
 	for i, l := range list {
 		if l == s {
 			return i
 		}
 	}
-
 	return -1
 }
 
+// inList returns true if one or more of s is in the list.
 func inList(s string, list []string) bool {
 	return indexList(s, list) != -1
 }
 
+// Main execution of soong_ui. The command format is as follows:
+//
+//    soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+//
+// Command is the type of soong_ui execution. Only one type of
+// execution is specified. The args are specific to the command.
 func main() {
-	var stdio terminal.StdioInterface
-	stdio = terminal.StdioImpl{}
-
-	// dumpvar uses stdout, everything else should be in stderr
-	if os.Args[1] == "--dumpvar-mode" || os.Args[1] == "--dumpvars-mode" {
-		stdio = terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+	c, args := getCommand(os.Args)
+	if c == nil {
+		fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
+		os.Exit(1)
 	}
 
-	writer := terminal.NewWriter(stdio)
+	writer := terminal.NewWriter(c.stdio())
 	defer writer.Finish()
 
 	log := logger.New(writer)
 	defer log.Cleanup()
 
-	if len(os.Args) < 2 || !(inList("--make-mode", os.Args) ||
-		os.Args[1] == "--dumpvars-mode" ||
-		os.Args[1] == "--dumpvar-mode") {
-
-		log.Fatalln("The `soong` native UI is not yet available.")
-	}
-
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 
@@ -96,12 +143,8 @@
 		Writer:  writer,
 		Status:  stat,
 	}}
-	var config build.Config
-	if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" {
-		config = build.NewConfig(buildCtx)
-	} else {
-		config = build.NewConfig(buildCtx, os.Args[1:]...)
-	}
+
+	config := c.config(buildCtx, args...)
 
 	build.SetupOutDir(buildCtx, config)
 
@@ -136,31 +179,10 @@
 	defer f.Shutdown()
 	build.FindSources(buildCtx, config, f)
 
-	if os.Args[1] == "--dumpvar-mode" {
-		dumpVar(buildCtx, config, os.Args[2:])
-	} else if os.Args[1] == "--dumpvars-mode" {
-		dumpVars(buildCtx, config, os.Args[2:])
-	} else {
-		if config.IsVerbose() {
-			writer.Print("! The argument `showcommands` is no longer supported.")
-			writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
-			writer.Print("!")
-			writer.Print(fmt.Sprintf("!   gzip -cd %s/verbose.log.gz | less -R", logsDir))
-			writer.Print("!")
-			writer.Print("! Older versions are saved in verbose.log.#.gz files")
-			writer.Print("")
-			time.Sleep(5 * time.Second)
-		}
-
-		toBuild := build.BuildAll
-		if config.Checkbuild() {
-			toBuild |= build.RunBuildTests
-		}
-		build.Build(buildCtx, config, toBuild)
-	}
+	c.run(buildCtx, config, args, logsDir)
 }
 
-func dumpVar(ctx build.Context, config build.Config, args []string) {
+func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
 	flags.Usage = func() {
 		fmt.Fprintf(os.Stderr, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
@@ -210,7 +232,7 @@
 	}
 }
 
-func dumpVars(ctx build.Context, config build.Config, args []string) {
+func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
 	flags.Usage = func() {
 		fmt.Fprintf(os.Stderr, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
@@ -277,3 +299,59 @@
 		fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
 	}
 }
+
+func customStdio() terminal.StdioInterface {
+	return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+}
+
+// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
+func dumpVarConfig(ctx build.Context, args ...string) build.Config {
+	return build.NewConfig(ctx)
+}
+
+func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
+	if config.IsVerbose() {
+		writer := ctx.Writer
+		writer.Print("! The argument `showcommands` is no longer supported.")
+		writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
+		writer.Print("!")
+		writer.Print(fmt.Sprintf("!   gzip -cd %s/verbose.log.gz | less -R", logsDir))
+		writer.Print("!")
+		writer.Print("! Older versions are saved in verbose.log.#.gz files")
+		writer.Print("")
+		time.Sleep(5 * time.Second)
+	}
+
+	toBuild := build.BuildAll
+	if config.Checkbuild() {
+		toBuild |= build.RunBuildTests
+	}
+	build.Build(ctx, config, toBuild)
+}
+
+// getCommand finds the appropriate command based on args[1] flag. args[0]
+// is the soong_ui filename.
+func getCommand(args []string) (*command, []string) {
+	if len(args) < 2 {
+		return nil, args
+	}
+
+	for _, c := range commands {
+		if c.flag == args[1] {
+			return &c, args[2:]
+		}
+
+		// special case for --make-mode: if soong_ui was called from
+		// build/make/core/main.mk, the makeparallel with --ninja
+		// option specified puts the -j<num> before --make-mode.
+		// TODO: Remove this hack once it has been fixed.
+		if c.flag == makeModeFlagName {
+			if inList(makeModeFlagName, args) {
+				return &c, args[1:]
+			}
+		}
+	}
+
+	// command not found
+	return nil, args
+}
diff --git a/java/aar.go b/java/aar.go
index 5e1f88e..7332e76 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -647,6 +647,10 @@
 	return nil
 }
 
+func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
+	return nil, nil
+}
+
 var _ android.PrebuiltInterface = (*Import)(nil)
 
 // android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9c883e5..b92f4d7 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -34,6 +34,9 @@
 	implementationAndResourceJars android.Paths
 	resourceJars                  android.Paths
 
+	srcJarArgs []string
+	srcJarDeps android.Paths
+
 	combinedHeaderJar         android.Path
 	combinedImplementationJar android.Path
 }
@@ -100,6 +103,10 @@
 			d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
 			d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
 			d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+
+			srcJarArgs, srcJarDeps := dep.SrcJarArgs()
+			d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...)
+			d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...)
 		} else {
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
@@ -157,6 +164,10 @@
 	return nil
 }
 
+func (d *DeviceHostConverter) SrcJarArgs() ([]string, android.Paths) {
+	return d.srcJarArgs, d.srcJarDeps
+}
+
 func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
diff --git a/java/java.go b/java/java.go
index 47dd957..e764ec3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -290,6 +290,10 @@
 	// jar file containing only resources including from static library dependencies
 	resourceJar android.Path
 
+	// args and dependencies to package source files into a srcjar
+	srcJarArgs []string
+	srcJarDeps android.Paths
+
 	// jar file containing implementation classes and resources including static library
 	// dependencies
 	implementationAndResourcesJar android.Path
@@ -340,6 +344,9 @@
 	// list of additional targets for checkbuild
 	additionalCheckedModules android.Paths
 
+	// Extra files generated by the module type to be added as java resources.
+	extraResources android.Paths
+
 	hiddenAPI
 	dexpreopter
 }
@@ -362,6 +369,7 @@
 	DexJar() android.Path
 	AidlIncludeDirs() android.Paths
 	ExportedSdkLibs() []string
+	SrcJarArgs() ([]string, android.Paths)
 }
 
 type SdkLibraryDependency interface {
@@ -1110,9 +1118,18 @@
 		}
 	}
 
+	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
+
+	var includeSrcJar android.WritablePath
+	if Bool(j.properties.Include_srcs) {
+		includeSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+".srcjar")
+		TransformResourcesToJar(ctx, includeSrcJar, j.srcJarArgs, j.srcJarDeps)
+	}
+
 	dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
 		j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
 	fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
+	extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
 
 	var resArgs []string
 	var resDeps android.Paths
@@ -1123,11 +1140,8 @@
 	resArgs = append(resArgs, fileArgs...)
 	resDeps = append(resDeps, fileDeps...)
 
-	if Bool(j.properties.Include_srcs) {
-		srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
-		resArgs = append(resArgs, srcArgs...)
-		resDeps = append(resDeps, srcDeps...)
-	}
+	resArgs = append(resArgs, extraArgs...)
+	resDeps = append(resDeps, extraDeps...)
 
 	if len(resArgs) > 0 {
 		resourceJar := android.PathForModuleOut(ctx, "res", jarName)
@@ -1138,17 +1152,22 @@
 		}
 	}
 
-	if len(deps.staticResourceJars) > 0 {
-		var jars android.Paths
-		if j.resourceJar != nil {
-			jars = append(jars, j.resourceJar)
-		}
-		jars = append(jars, deps.staticResourceJars...)
+	var resourceJars android.Paths
+	if j.resourceJar != nil {
+		resourceJars = append(resourceJars, j.resourceJar)
+	}
+	if Bool(j.properties.Include_srcs) {
+		resourceJars = append(resourceJars, includeSrcJar)
+	}
+	resourceJars = append(resourceJars, deps.staticResourceJars...)
 
+	if len(resourceJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
 			false, nil, nil)
 		j.resourceJar = combinedJar
+	} else if len(resourceJars) == 1 {
+		j.resourceJar = resourceJars[0]
 	}
 
 	jars = append(jars, deps.staticJars...)
@@ -1436,6 +1455,10 @@
 	return j.exportedSdkLibs
 }
 
+func (j *Module) SrcJarArgs() ([]string, android.Paths) {
+	return j.srcJarArgs, j.srcJarDeps
+}
+
 var _ logtagsProducer = (*Module)(nil)
 
 func (j *Module) logtags() android.Paths {
@@ -1913,6 +1936,10 @@
 	return j.exportedSdkLibs
 }
 
+func (j *Import) SrcJarArgs() ([]string, android.Paths) {
+	return nil, nil
+}
+
 // Add compile time check for interface implementation
 var _ android.IDEInfo = (*Import)(nil)
 var _ android.IDECustomizedModuleName = (*Import)(nil)
diff --git a/java/java_resources.go b/java/java_resources.go
index 7161168..787d74a 100644
--- a/java/java_resources.go
+++ b/java/java_resources.go
@@ -85,19 +85,19 @@
 	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 := android.PathsForModuleSrcExcludes(ctx, res, exclude)
 
+	args = resourcePathsToJarArgs(files)
+
+	return args, files
+}
+
+func resourcePathsToJarArgs(files android.Paths) []string {
+	var args []string
+
 	lastDir := ""
 	for i, f := range files {
 		rel := f.Rel()
@@ -113,5 +113,5 @@
 		lastDir = dir
 	}
 
-	return args, files
+	return args
 }
diff --git a/java/java_test.go b/java/java_test.go
index 4b850ef..3d8baee 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -484,12 +484,6 @@
 			args: "-C java-res -f java-res/a/a -f java-res/b/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 -f b.java -f c.java",
-		},
-		{
 			// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
 			name: "wildcard dirs",
 			prop: `java_resource_dirs: ["java-res/*"]`,
@@ -557,6 +551,69 @@
 	}
 }
 
+func TestIncludeSrcs(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			include_srcs: true,
+		}
+
+		java_library {
+			name: "bar",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			java_resource_dirs: ["java-res"],
+			include_srcs: true,
+		}
+	`)
+
+	// Test a library with include_srcs: true
+	foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
+	fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
+
+	if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("foo combined jars %v does not contain %q", w, g)
+	}
+
+	if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+		t.Errorf("foo source jar args %q is not %q", w, g)
+	}
+
+	// Test a library with include_srcs: true and resources
+	bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
+	barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
+	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
+	barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
+
+	if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
+		t.Errorf("bar combined jars %v does not contain %q", w, g)
+	}
+
+	if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+		t.Errorf("bar source jar args %q is not %q", w, g)
+	}
+
+	if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
+		t.Errorf("bar resource jar args %q is not %q", w, g)
+	}
+}
+
 func TestGeneratedSources(t *testing.T) {
 	ctx := testJava(t, `
 		java_library {