Adds droidstubs support to sdk module

Adds stubs_sources property to sdk and unzips the droidstubs srcjar
into the snapshot directory.

Adds an UnzipToSnapshot method to the SnapshotBuilder which creates
a rule that uses zip2zip to repackage the supplied zip content into a
temporary zip file that matches what the required snapshot structure.
e.g. if the supplied zip contains foo/Foo.java and that needs to be in
the snapshot directory java/foo/stubs then it will create a zip that
contains java/foo/stubs/foo/Foo.java.

The temporary zip that is the output of that rule is added to the
zipsToMerge field for merging later.

If the zipsToMerge is empty then the snapshot zip is created as
before. Otherwise, a temporary zip file is created. That is then
merged with the other zip files in zipsToMerge to create the final
snapshot zip.

Adds prebuilt_stubs_sources for use by the generated .bp module.

Bug: 143678475
Test: added conscrypt sdk module and attempted to build it
Change-Id: Ie274263af3a08e36a73c61c0dbf0c341fd6967e2
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
 }