Bundle public keys with APEX

When an apex key is marked as 'installable: false' and the build is
debuggable, the pubic key file for the apex key is bundled with the APEX
that is signed with the key.

This eliminates the need to install the public keys for the
testing-purpose APEX in the system partition.

Bug: 122047804
Test: m
Change-Id: Ifa5914891463dbf4c21484ea440836521b2f90b1
diff --git a/apex/apex.go b/apex/apex.go
index 71ecbdb..79b79e8 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -56,12 +56,12 @@
 			`--file_contexts ${file_contexts} ` +
 			`--canned_fs_config ${canned_fs_config} ` +
 			`--payload_type image ` +
-			`--key ${key} ${image_dir} ${out} `,
+			`--key ${key} ${opt_flags} ${image_dir} ${out} `,
 		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
 			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
 			"${soong_zip}", "${zipalign}", "${aapt2}"},
 		Description: "APEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key")
+	}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key", "opt_flags")
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -518,6 +518,7 @@
 	filesInfo := []apexFile{}
 
 	var keyFile android.Path
+	var pubKeyFile android.Path
 	var certificate java.Certificate
 
 	if a.properties.Payload_type == nil || *a.properties.Payload_type == "image" {
@@ -576,6 +577,12 @@
 			case keyTag:
 				if key, ok := child.(*apexKey); ok {
 					keyFile = key.private_key_file
+					if !key.installable() && ctx.Config().Debuggable() {
+						// If the key is not installed, bundled it with the APEX.
+						// Note: this bundled key is valid only for non-production builds
+						// (eng/userdebug).
+						pubKeyFile = key.public_key_file
+					}
 					return false
 				} else {
 					ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
@@ -640,18 +647,19 @@
 	a.filesInfo = filesInfo
 
 	if a.apexTypes.zip() {
-		a.buildUnflattenedApex(ctx, keyFile, certificate, zipApex)
+		a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, zipApex)
 	}
 	if a.apexTypes.image() {
 		if ctx.Config().FlattenApex() {
 			a.buildFlattenedApex(ctx)
 		} else {
-			a.buildUnflattenedApex(ctx, keyFile, certificate, imageApex)
+			a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, imageApex)
 		}
 	}
 }
 
-func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile android.Path, certificate java.Certificate, apexType apexPackaging) {
+func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile android.Path,
+	pubKeyFile android.Path, certificate java.Certificate, apexType apexPackaging) {
 	cert := String(a.properties.Certificate)
 	if cert != "" && android.SrcIsModule(cert) == "" {
 		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
@@ -739,8 +747,14 @@
 		}
 		fileContexts := fileContextsOptionalPath.Path()
 
+		optFlags := []string{}
+
 		// Additional implicit inputs.
 		implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, keyFile)
+		if pubKeyFile != nil {
+			implicitInputs = append(implicitInputs, pubKeyFile)
+			optFlags = append(optFlags, "--pubkey "+pubKeyFile.String())
+		}
 
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        apexRule,
@@ -755,6 +769,7 @@
 				"file_contexts":    fileContexts.String(),
 				"canned_fs_config": cannedFsConfig.String(),
 				"key":              keyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
 			},
 		})