Output apkcerts file for android_app_set.

Soong and Make have no ways to figure out what splits will be outputted
from a given android_app_set, so it's impossible for them to provide
full PACKAGES.$(LOCAL_MODULE).CERTIFICATE entries, which are required to
build a final apkcerts.txt. This change makes extract_apks produce
apkcerts.txt files for each input modules instead. The Make-side
counterpart of this change merges all local apkcerts.txt into a final
one.

Fixes: 160119159
Test: main_test.go
Test: m apkcerts-list
Change-Id: I321e80fd636a955213761f56a3ac64bfe7f7f7c0
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index e9a850e..db54ffb 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -24,6 +24,7 @@
 	"math"
 	"os"
 	"regexp"
+	"sort"
 	"strings"
 
 	"github.com/golang/protobuf/proto"
@@ -355,7 +356,7 @@
 
 // Writes out selected entries, renaming them as needed
 func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
-	writer Zip2ZipWriter) error {
+	writer Zip2ZipWriter, partition string) ([]string, error) {
 	// Renaming rules:
 	//  splits/MODULE-master.apk to STEM.apk
 	// else
@@ -389,10 +390,11 @@
 	}
 
 	entryOrigin := make(map[string]string) // output entry to input entry
+	var apkcerts []string
 	for _, apk := range selected.entries {
 		apkFile, ok := apkSet.entries[apk]
 		if !ok {
-			return fmt.Errorf("TOC refers to an entry %s which does not exist", apk)
+			return nil, fmt.Errorf("TOC refers to an entry %s which does not exist", apk)
 		}
 		inName := apkFile.Name
 		outName, ok := renamer(inName)
@@ -405,10 +407,15 @@
 		}
 		entryOrigin[outName] = inName
 		if err := writer.CopyFrom(apkFile, outName); err != nil {
-			return err
+			return nil, err
+		}
+		if partition != "" {
+			apkcerts = append(apkcerts, fmt.Sprintf(
+				`name="%s" certificate="PRESIGNED" private_key="" partition="%s"`, outName, partition))
 		}
 	}
-	return nil
+	sort.Strings(apkcerts)
+	return apkcerts, nil
 }
 
 func (apkSet *ApkSet) extractAndCopySingle(selected SelectionResult, outFile *os.File) error {
@@ -433,6 +440,9 @@
 	}
 	extractSingle = flag.Bool("extract-single", false,
 		"extract a single target and output it uncompressed. only available for standalone apks and apexes.")
+	apkcertsOutput = flag.String("apkcerts", "",
+		"optional apkcerts.txt output file containing signing info of all outputted apks")
+	partition = flag.String("partition", "", "partition string. required when -apkcerts is used.")
 )
 
 // Parse abi values
@@ -485,7 +495,8 @@
 func processArgs() {
 	flag.Usage = func() {
 		fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
-			`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] <APK set>`)
+			`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
+			`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
 		flag.PrintDefaults()
 		os.Exit(2)
 	}
@@ -498,7 +509,8 @@
 		"allow prereleased")
 	flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
 	flag.Parse()
-	if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || (targetConfig.stem == "" && !*extractSingle) {
+	if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
+		(targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") {
 		flag.Usage()
 	}
 	targetConfig.sdkVersion = int32(*version)
@@ -536,7 +548,20 @@
 				log.Fatal(err)
 			}
 		}()
-		err = apkSet.writeApks(sel, targetConfig, writer)
+		apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition)
+		if err == nil && *apkcertsOutput != "" {
+			apkcertsFile, err := os.Create(*apkcertsOutput)
+			if err != nil {
+				log.Fatal(err)
+			}
+			defer apkcertsFile.Close()
+			for _, a := range apkcerts {
+				_, err = apkcertsFile.WriteString(a + "\n")
+				if err != nil {
+					log.Fatal(err)
+				}
+			}
+		}
 	}
 	if err != nil {
 		log.Fatal(err)