apex_sets is added to apexkeys.txt

apex_sets is a new module type that can be used to deliver pre-signed
APEXes, which previously could be done only via prebuilt_apex.

Soon gnow understands apex_sets module types and emits the signing info
of the modules to apexkeys.txt

Bug: 162464887
Bug: 158729168
Test: m
Merged-In: I9507375342ec053309660d94c931a79bf4f21218
Change-Id: I9507375342ec053309660d94c931a79bf4f21218
diff --git a/apex/apex.go b/apex/apex.go
index cac519b..4dca961 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1528,6 +1528,10 @@
 	return a.prebuilt.Name(a.ModuleBase.Name())
 }
 
+func (a *ApexSet) Overrides() []string {
+	return a.properties.Overrides
+}
+
 // prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
 func apexSetFactory() android.Module {
 	module := &ApexSet{}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index a2610f6..08011fd 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -77,6 +77,7 @@
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
 	})
+	ctx.RegisterSingletonType("apex_keys_text", android.SingletonFactoryAdaptor(apexKeysTextFactory))
 
 	ctx.Register()
 
@@ -1331,3 +1332,36 @@
 		t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
 	}
 }
+
+func TestApexKeysTxt(t *testing.T) {
+	ctx := testApex(t, `
+		prebuilt_apex {
+			name: "myapex",
+			prefer: true,
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
+		}
+
+		apex_set {
+			name: "myapex_set",
+			set: "myapex.apks",
+			filename: "myapex_set.apex",
+			overrides: ["myapex"],
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.Platform_sdk_version = intPtr(30)
+		config.TestProductVariables.DeviceArch = proptools.StringPtr("arm")
+		config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm64")
+	})
+
+	apexKeysText := ctx.SingletonForTests("apex_keys_text")
+	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED"`)
+	ensureNotContains(t, content, "myapex.apex")
+}
diff --git a/apex/key.go b/apex/key.go
index 6ee3dca..ec28134 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -107,10 +107,36 @@
 
 func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
 	s.output = android.PathForOutput(ctx, "apexkeys.txt")
-	apexModulesMap := make(map[string]android.Module)
+	type apexKeyEntry struct {
+		name                  string
+		presigned             bool
+		public_key            string
+		private_key           string
+		container_certificate string
+		container_private_key string
+		partition             string
+	}
+	toString := func(e apexKeyEntry) string {
+		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n"
+		if e.presigned {
+			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED")
+		} else {
+			return fmt.Sprintf(format, e.name, e.public_key, e.private_key, e.container_certificate, e.container_private_key)
+		}
+	}
+
+	apexKeyMap := make(map[string]apexKeyEntry)
 	ctx.VisitAllModules(func(module android.Module) {
 		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
-			apexModulesMap[m.Name()] = m
+			apexKeyMap[m.Name()] = apexKeyEntry{
+				name:                  m.Name() + ".apex",
+				presigned:             false,
+				public_key:            m.public_key_file.String(),
+				private_key:           m.private_key_file.String(),
+				container_certificate: m.container_certificate_file.String(),
+				container_private_key: m.container_private_key_file.String(),
+				partition:             m.PartitionTag(ctx.DeviceConfig()),
+			}
 		}
 	})
 
@@ -118,34 +144,43 @@
 	ctx.VisitAllModules(func(module android.Module) {
 		if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
 			m.Prebuilt().UsePrebuilt() {
-			apexModulesMap[m.BaseModuleName()] = m
+			apexKeyMap[m.BaseModuleName()] = apexKeyEntry{
+				name:      m.InstallFilename(),
+				presigned: true,
+				partition: m.PartitionTag(ctx.DeviceConfig()),
+			}
+		}
+	})
+
+	// Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass
+	// so that apex_set are not overridden by prebuilts.
+	ctx.VisitAllModules(func(module android.Module) {
+		if m, ok := module.(*ApexSet); ok && m.Enabled() {
+			entry := apexKeyEntry{
+				name:      m.InstallFilename(),
+				presigned: true,
+				partition: m.PartitionTag(ctx.DeviceConfig()),
+			}
+
+			for _, om := range m.Overrides() {
+				if _, ok := apexKeyMap[om]; ok {
+					delete(apexKeyMap, om)
+				}
+			}
+			apexKeyMap[m.BaseModuleName()] = entry
 		}
 	})
 
 	// iterating over map does not give consistent ordering in golang
 	var moduleNames []string
-	for key, _ := range apexModulesMap {
+	for key, _ := range apexKeyMap {
 		moduleNames = append(moduleNames, key)
 	}
 	sort.Strings(moduleNames)
 
 	var filecontent strings.Builder
-	for _, key := range moduleNames {
-		module := apexModulesMap[key]
-		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())
-		} else if m, ok := module.(*Prebuilt); ok {
-			fmt.Fprintf(&filecontent,
-				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
-				m.InstallFilename(),
-				"PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED")
-		}
+	for _, name := range moduleNames {
+		fmt.Fprintf(&filecontent, "%s", toString(apexKeyMap[name]))
 	}
 
 	ctx.Build(pctx, android.BuildParams{