Merge changes Ie274263a,I45993324

* changes:
  Adds droidstubs support to sdk module
  Simplify building an SDK snapshot from the command line
diff --git a/android/sdk.go b/android/sdk.go
index d66816d..73cb256 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -164,6 +164,9 @@
 	// to the zip
 	CopyToSnapshot(src Path, dest string)
 
+	// Unzip the supplied zip into the snapshot relative directory destDir.
+	UnzipToSnapshot(zipPath Path, destDir string)
+
 	// Get the AndroidBpFile for the snapshot.
 	AndroidBpFile() GeneratedSnapshotFile
 
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 54f93fe..83a1ad5 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -37,6 +37,8 @@
 
 	android.RegisterModuleType("droidstubs", DroidstubsFactory)
 	android.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)
+
+	android.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
 }
 
 var (
@@ -1163,6 +1165,7 @@
 //
 type Droidstubs struct {
 	Javadoc
+	android.SdkBase
 
 	properties              DroidstubsProperties
 	apiFile                 android.WritablePath
@@ -1208,6 +1211,7 @@
 		&module.Javadoc.properties)
 
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
@@ -1913,3 +1917,88 @@
 func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) {
 	rule.Command().Text("rm -rf").Text(srcJarDir.String())
 }
+
+var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)
+
+type PrebuiltStubsSourcesProperties struct {
+	Srcs []string `android:"path"`
+}
+
+type PrebuiltStubsSources struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	prebuilt android.Prebuilt
+	android.SdkBase
+
+	properties PrebuiltStubsSourcesProperties
+
+	srcs        android.Paths
+	stubsSrcJar android.ModuleOutPath
+}
+
+func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.srcs = android.PathsForModuleSrc(ctx, p.properties.Srcs)
+}
+
+func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
+	return &p.prebuilt
+}
+
+func (p *PrebuiltStubsSources) Name() string {
+	return p.prebuilt.Name(p.ModuleBase.Name())
+}
+
+func (p *PrebuiltStubsSources) Srcs() android.Paths {
+	return append(android.Paths{}, p.srcs...)
+}
+
+// prebuilt_stubs_sources imports a set of java source files as if they were
+// generated by droidstubs.
+//
+// By default, a prebuilt_stubs_sources has a single variant that expects a
+// set of `.java` files generated by droidstubs.
+//
+// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
+// for host modules.
+//
+// Intended only for use by sdk snapshots.
+func PrebuiltStubsSourcesFactory() android.Module {
+	module := &PrebuiltStubsSources{}
+
+	module.AddProperties(&module.properties)
+
+	android.InitPrebuiltModule(module, &module.properties.Srcs)
+	android.InitSdkAwareModule(module)
+	InitDroiddocModule(module, android.HostAndDeviceSupported)
+	return module
+}
+
+func (d *Droidstubs) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder) {
+	stubsSrcJar := d.stubsSrcJar
+
+	snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
+	builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
+
+	name := d.Name()
+	bp := builder.AndroidBpFile()
+	bp.Printfln("prebuilt_stubs_sources {")
+	bp.Indent()
+	bp.Printfln("name: %q,", builder.VersionedSdkMemberName(name))
+	bp.Printfln("sdk_member_name: %q,", name)
+	bp.Printfln("srcs: [%q],", snapshotRelativeDir)
+	bp.Dedent()
+	bp.Printfln("}")
+	bp.Printfln("")
+
+	// This module is for the case when the source tree for the unversioned module
+	// doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
+	// so that this module does not eclipse the unversioned module if it exists.
+	bp.Printfln("prebuilt_stubs_sources {")
+	bp.Indent()
+	bp.Printfln("name: %q,", name)
+	bp.Printfln("srcs: [%q],", snapshotRelativeDir)
+	bp.Printfln("prefer: false,")
+	bp.Dedent()
+	bp.Printfln("}")
+	bp.Printfln("")
+}
diff --git a/java/java_test.go b/java/java_test.go
index 0f7e6de..71aba3a 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -89,6 +89,7 @@
 	ctx.RegisterModuleType("droiddoc", android.ModuleFactoryAdaptor(DroiddocFactory))
 	ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
 	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory))
+	ctx.RegisterModuleType("prebuilt_stubs_sources", android.ModuleFactoryAdaptor(PrebuiltStubsSourcesFactory))
 	ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory))
 	ctx.RegisterModuleType("java_sdk_library_import", android.ModuleFactoryAdaptor(sdkLibraryImportFactory))
 	ctx.RegisterModuleType("override_android_app", android.ModuleFactoryAdaptor(OverrideAndroidAppModuleFactory))
@@ -207,6 +208,9 @@
 		"cert/new_cert.pk8":      nil,
 
 		"testdata/data": nil,
+
+		"stubs-sources/foo/Foo.java": nil,
+		"stubs/sources/foo/Foo.java": nil,
 	}
 
 	for k, v := range fs {
@@ -415,7 +419,7 @@
 	ctx, _ := testJava(t, `
 		java_library {
 			name: "foo",
-			srcs: ["a.java"],
+			srcs: ["a.java", ":stubs-source"],
 			libs: ["bar", "sdklib"],
 			static_libs: ["baz"],
 		}
@@ -439,6 +443,11 @@
 			name: "sdklib",
 			jars: ["b.jar"],
 		}
+
+		prebuilt_stubs_sources {
+			name: "stubs-source",
+			srcs: ["stubs/sources/**/*.java"],
+		}
 		`)
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
@@ -447,6 +456,19 @@
 	bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output
 	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
 
+	inputs := []string{}
+	for _, p := range javac.BuildParams.Inputs {
+		inputs = append(inputs, p.String())
+	}
+
+	expected := []string{
+		"a.java",
+		"stubs/sources/foo/Foo.java",
+	}
+	if !reflect.DeepEqual(expected, inputs) {
+		t.Errorf("foo inputs incorrect: expected %q, found %q", expected, inputs)
+	}
+
 	if !strings.Contains(javac.Args["classpath"], barJar.String()) {
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
 	}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 4eb3665..ed2f26c 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"io"
 	"strconv"
 
 	"github.com/google/blueprint"
@@ -50,6 +51,8 @@
 	Java_libs []string
 	// The list of native libraries in this SDK
 	Native_shared_libs []string
+	// The list of stub sources in this SDK
+	Stubs_sources []string
 
 	Snapshot bool `blueprint:"mutated"`
 }
@@ -121,6 +124,13 @@
 		OutputFile: s.snapshotFile,
 		DistFile:   s.snapshotFile,
 		Include:    "$(BUILD_PHONY_PACKAGE)",
+		ExtraFooters: []android.AndroidMkExtraFootersFunc{
+			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+				// Allow the sdk to be built by simply passing its name on the command line.
+				fmt.Fprintln(w, ".PHONY:", s.Name())
+				fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String())
+			},
+		},
 	}
 }
 
@@ -167,6 +177,7 @@
 func memberMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*sdk); ok {
 		mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...)
+		mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Stubs_sources...)
 
 		targets := mctx.MultiTargets()
 		for _, target := range targets {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 3471bc9..99192be 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -45,6 +45,8 @@
 	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
 	ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
+	ctx.RegisterModuleType("droidstubs", android.ModuleFactoryAdaptor(java.DroidstubsFactory))
+	ctx.RegisterModuleType("prebuilt_stubs_sources", android.ModuleFactoryAdaptor(java.PrebuiltStubsSourcesFactory))
 
 	// from cc package
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
@@ -104,6 +106,8 @@
 		"include/Test.h":                             nil,
 		"aidl/foo/bar/Test.aidl":                     nil,
 		"libfoo.so":                                  nil,
+		"stubs-sources/foo/bar/Foo.java":             nil,
+		"foo/bar/Foo.java":                           nil,
 	})
 
 	return ctx, config
@@ -323,6 +327,39 @@
 	ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
 }
 
+// Note: This test does not verify that a droidstubs can be referenced, either
+// directly or indirectly from an APEX as droidstubs can never be a part of an
+// apex.
+func TestBasicSdkWithDroidstubs(t *testing.T) {
+	testSdk(t, `
+		sdk {
+				name: "mysdk",
+				stubs_sources: ["mystub"],
+		}
+		sdk_snapshot {
+				name: "mysdk@10",
+				stubs_sources: ["mystub_mysdk@10"],
+		}
+		prebuilt_stubs_sources {
+				name: "mystub_mysdk@10",
+				sdk_member_name: "mystub",
+				srcs: ["stubs-sources/foo/bar/Foo.java"],
+		}
+		droidstubs {
+				name: "mystub",
+				srcs: ["foo/bar/Foo.java"],
+				sdk_version: "none",
+				system_modules: "none",
+		}
+		java_library {
+				name: "myjavalib",
+				srcs: [":mystub"],
+				sdk_version: "none",
+				system_modules: "none",
+		}
+	`)
+}
+
 func TestDepNotInRequiredSdks(t *testing.T) {
 	testSdkError(t, `module "myjavalib".*depends on "otherlib".*that isn't part of the required SDKs:.*`, `
 		sdk {
@@ -417,6 +454,7 @@
 			name: "mysdk",
 			java_libs: ["myjavalib"],
 			native_shared_libs: ["mynativelib"],
+			stubs_sources: ["myjavaapistubs"],
 		}
 
 		java_library {
@@ -444,15 +482,26 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
+
+		droidstubs {
+			name: "myjavaapistubs",
+			srcs: ["foo/bar/Foo.java"],
+			system_modules: "none",
+			sdk_version: "none",
+		}
 	`)
 
 	var copySrcs []string
 	var copyDests []string
 	buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests()
+	var zipBp android.BuildParams
 	for _, bp := range buildParams {
-		if bp.Rule.String() == "android/soong/android.Cp" {
+		ruleString := bp.Rule.String()
+		if ruleString == "android/soong/android.Cp" {
 			copySrcs = append(copySrcs, bp.Input.String())
 			copyDests = append(copyDests, bp.Output.Rel()) // rooted at the snapshot root
+		} else if ruleString == "<local rule>:m.mysdk_android_common.snapshot" {
+			zipBp = bp
 		}
 	}
 
@@ -472,6 +521,19 @@
 	ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/Test.h")
 	ensureListContains(t, copyDests, "java/myjavalib.jar")
 	ensureListContains(t, copyDests, "arm64/lib/mynativelib.so")
+
+	// Ensure that the droidstubs .srcjar as repackaged into a temporary zip file
+	// and then merged together with the intermediate snapshot zip.
+	snapshotCreationInputs := zipBp.Implicits.Strings()
+	ensureListContains(t, snapshotCreationInputs,
+		filepath.Join(buildDir, ".intermediates/mysdk/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"))
+	ensureListContains(t, snapshotCreationInputs,
+		filepath.Join(buildDir, ".intermediates/mysdk/android_common/mysdk-current.unmerged.zip"))
+	actual := zipBp.Output.String()
+	expected := filepath.Join(buildDir, ".intermediates/mysdk/android_common/mysdk-current.zip")
+	if actual != expected {
+		t.Errorf("Expected snapshot output to be %q but was %q", expected, actual)
+	}
 }
 
 var buildDir string
diff --git a/sdk/update.go b/sdk/update.go
index 9fa9e04..7daede3 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -80,6 +80,16 @@
 	return result
 }
 
+func (s *sdk) stubsSources(ctx android.ModuleContext) []android.SdkAware {
+	result := []android.SdkAware{}
+	ctx.VisitDirectDeps(func(m android.Module) {
+		if j, ok := m.(*java.Droidstubs); ok {
+			result = append(result, j)
+		}
+	})
+	return result
+}
+
 // archSpecificNativeLibInfo represents an arch-specific variant of a native lib
 type archSpecificNativeLibInfo struct {
 	name                      string
@@ -236,8 +246,8 @@
 		ctx:           ctx,
 		version:       "current",
 		snapshotDir:   snapshotDir.OutputPath,
-		androidBpFile: bp,
 		filesToZip:    []android.Path{bp.path},
+		androidBpFile: bp,
 	}
 
 	// copy exported AIDL files and stub jar files
@@ -246,6 +256,12 @@
 		m.BuildSnapshot(ctx, builder)
 	}
 
+	// copy stubs sources
+	stubsSources := s.stubsSources(ctx)
+	for _, m := range stubsSources {
+		m.BuildSnapshot(ctx, builder)
+	}
+
 	// copy exported header files and stub *.so files
 	nativeLibInfos := s.nativeMemberInfos(ctx)
 	for _, info := range nativeLibInfos {
@@ -266,6 +282,15 @@
 		bp.Dedent()
 		bp.Printfln("],") // java_libs
 	}
+	if len(stubsSources) > 0 {
+		bp.Printfln("stubs_sources: [")
+		bp.Indent()
+		for _, m := range stubsSources {
+			bp.Printfln("%q,", builder.VersionedSdkMemberName(m.Name()))
+		}
+		bp.Dedent()
+		bp.Printfln("],") // stubs_sources
+	}
 	if len(nativeLibInfos) > 0 {
 		bp.Printfln("native_shared_libs: [")
 		bp.Indent()
@@ -284,16 +309,45 @@
 	filesToZip := builder.filesToZip
 
 	// zip them all
-	zipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
+	outputZipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
+	outputRuleName := "snapshot"
+	outputDesc := "Building snapshot for " + ctx.ModuleName()
+
+	// If there are no zips to merge then generate the output zip directly.
+	// Otherwise, generate an intermediate zip file into which other zips can be
+	// merged.
+	var zipFile android.OutputPath
+	var ruleName string
+	var desc string
+	if len(builder.zipsToMerge) == 0 {
+		zipFile = outputZipFile
+		ruleName = outputRuleName
+		desc = outputDesc
+	} else {
+		zipFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.unmerged.zip").OutputPath
+		ruleName = "intermediate snapshot"
+		desc = "Building intermediate snapshot for " + ctx.ModuleName()
+	}
+
 	rb := android.NewRuleBuilder()
 	rb.Command().
 		BuiltTool(ctx, "soong_zip").
 		FlagWithArg("-C ", builder.snapshotDir.String()).
 		FlagWithRspFileInputList("-l ", filesToZip).
 		FlagWithOutput("-o ", zipFile)
-	rb.Build(pctx, ctx, "snapshot", "Building snapshot for "+ctx.ModuleName())
+	rb.Build(pctx, ctx, ruleName, desc)
 
-	return zipFile
+	if len(builder.zipsToMerge) != 0 {
+		rb := android.NewRuleBuilder()
+		rb.Command().
+			BuiltTool(ctx, "merge_zips").
+			Output(outputZipFile).
+			Input(zipFile).
+			Inputs(builder.zipsToMerge)
+		rb.Build(pctx, ctx, outputRuleName, outputDesc)
+	}
+
+	return outputZipFile
 }
 
 func buildSharedNativeLibSnapshot(ctx android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder) {
@@ -404,8 +458,9 @@
 	ctx           android.ModuleContext
 	version       string
 	snapshotDir   android.OutputPath
-	filesToZip    android.Paths
 	androidBpFile *generatedFile
+	filesToZip    android.Paths
+	zipsToMerge   android.Paths
 }
 
 func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -418,6 +473,25 @@
 	s.filesToZip = append(s.filesToZip, path)
 }
 
+func (s *snapshotBuilder) UnzipToSnapshot(zipPath android.Path, destDir string) {
+	ctx := s.ctx
+
+	// Repackage the zip file so that the entries are in the destDir directory.
+	// This will allow the zip file to be merged into the snapshot.
+	tmpZipPath := android.PathForModuleOut(ctx, "tmp", destDir+".zip").OutputPath
+	rb := android.NewRuleBuilder()
+	rb.Command().
+		BuiltTool(ctx, "zip2zip").
+		FlagWithInput("-i ", zipPath).
+		FlagWithOutput("-o ", tmpZipPath).
+		Flag("**/*:" + destDir)
+	rb.Build(pctx, ctx, "repackaging "+destDir,
+		"Repackaging zip file "+destDir+" for snapshot "+ctx.ModuleName())
+
+	// Add the repackaged zip file to the files to merge.
+	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
+}
+
 func (s *snapshotBuilder) AndroidBpFile() android.GeneratedSnapshotFile {
 	return s.androidBpFile
 }