build apexkeys.txt

apexkeys.txt is a text file having APEX-to-keys mappings. The file is
included in the target-files package where it is used when re-sign the
APEXes with release keys.

Each line of the file consists of 5 fields:
1) name: file name of the APEX
2) public_key: the public key for the apex_payload.img of the APEX
3) private_key: the private key used to sign the apex_payload.img
4) container_certificate: the certificate used to sign the APEX zip
container
5) container_private_key: the private key used to sign the APEX zip
container

Bug: 124406181
Test: m out/soong/apexkeys.txt and inspect the content
Test: TARGET_BUILD_APPS=com.android.tzdata m dist and make sure
out/dist/apexkeys.txt exists
Change-Id: I1daa13ec50956323b97e15e8df7f1fbe5ea21d63
diff --git a/apex/key.go b/apex/key.go
index 5282416..4c83861 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"io"
+	"strings"
 
 	"android/soong/android"
 
@@ -27,6 +28,8 @@
 
 func init() {
 	android.RegisterModuleType("apex_key", apexKeyFactory)
+	android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
+	android.RegisterMakeVarsProvider(pctx, apexKeysFileProvider)
 }
 
 type apexKey struct {
@@ -102,3 +105,53 @@
 		},
 	}
 }
+
+////////////////////////////////////////////////////////////////////////
+// apex_keys_text
+type apexKeysText struct{}
+
+func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
+	output := android.PathForOutput(ctx, "apexkeys.txt")
+	*apexKeysFile(ctx.Config()) = output.String()
+	var filecontent strings.Builder
+	ctx.VisitAllModules(func(module android.Module) {
+		if m, ok := module.(android.Module); ok && !m.Enabled() {
+			return
+		}
+
+		if m, ok := module.(*apexBundle); ok {
+			fmt.Fprintf(&filecontent,
+				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+				m.Name()+".apex",
+				m.public_key_file.String(),
+				m.private_key_file.String(),
+				m.container_certificate_file.String(),
+				m.container_private_key_file.String())
+		}
+	})
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Description: "apex_keys.txt",
+		Output:      output,
+		Args: map[string]string{
+			"content": filecontent.String(),
+		},
+	})
+}
+
+var apexKeysFileKey = android.NewOnceKey("apexKeysFile")
+
+func apexKeysFile(config android.Config) *string {
+	return config.Once(apexKeysFileKey, func() interface{} {
+		str := ""
+		return &str
+	}).(*string)
+}
+
+func apexKeysTextFactory() android.Singleton {
+	return &apexKeysText{}
+}
+
+func apexKeysFileProvider(ctx android.MakeVarsContext) {
+	ctx.Strict("SOONG_APEX_KEYS_FILE", *apexKeysFile(ctx.Config()))
+}