Enable certificate overrides with product vars.

Currently it is only for android_app, though it can be easily ported to
apex.

The make-side change will be made later, along with a real application.

Bug: 122957760
Test: app_test.go
Change-Id: I41f0be84f8b9f93e9518a16160e10eaa649388cd
diff --git a/android/config.go b/android/config.go
index 07d0a87..106f245 100644
--- a/android/config.go
+++ b/android/config.go
@@ -893,7 +893,16 @@
 }
 
 func (c *deviceConfig) OverrideManifestPackageNameFor(name string) (manifestName string, overridden bool) {
-	overrides := c.config.productVariables.ManifestPackageNameOverrides
+	return findOverrideValue(c.config.productVariables.ManifestPackageNameOverrides, name,
+		"invalid override rule %q in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES should be <module_name>:<manifest_name>")
+}
+
+func (c *deviceConfig) OverrideCertificateFor(name string) (certificatePath string, overridden bool) {
+	return findOverrideValue(c.config.productVariables.CertificateOverrides, name,
+		"invalid override rule %q in PRODUCT_CERTIFICATE_OVERRIDES should be <module_name>:<certificate_module_name>")
+}
+
+func findOverrideValue(overrides []string, name string, errorMsg string) (newValue string, overridden bool) {
 	if overrides == nil || len(overrides) == 0 {
 		return "", false
 	}
@@ -901,7 +910,7 @@
 		split := strings.Split(o, ":")
 		if len(split) != 2 {
 			// This shouldn't happen as this is first checked in make, but just in case.
-			panic(fmt.Errorf("invalid override rule %q in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES should be <module_name>:<manifest_name>", o))
+			panic(fmt.Errorf(errorMsg, o))
 		}
 		if matchPattern(split[0], name) {
 			return substPattern(split[0], split[1], name), true
diff --git a/android/variable.go b/android/variable.go
index 6cf28ad..67e876a 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -270,6 +270,7 @@
 	DexpreoptGlobalConfig *string `json:",omitempty"`
 
 	ManifestPackageNameOverrides []string `json:",omitempty"`
+	CertificateOverrides         []string `json:",omitempty"`
 
 	EnforceSystemCertificate          *bool    `json:",omitempty"`
 	EnforceSystemCertificateWhitelist []string `json:",omitempty"`
diff --git a/java/app.go b/java/app.go
index 335d9fc..07a97ed 100644
--- a/java/app.go
+++ b/java/app.go
@@ -120,7 +120,7 @@
 		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
 	}
 
-	cert := android.SrcIsModule(String(a.appProperties.Certificate))
+	cert := android.SrcIsModule(a.getCertString(ctx))
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
@@ -241,7 +241,7 @@
 		return
 	}
 
-	cert := String(a.appProperties.Certificate)
+	cert := a.getCertString(ctx)
 	certModule := android.SrcIsModule(cert)
 	if certModule != "" {
 		a.certificate = certificateDeps[0]
@@ -327,6 +327,14 @@
 	return jniLibs, certificates
 }
 
+func (a *AndroidApp) getCertString(ctx android.BaseContext) string {
+	certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
+	if overridden {
+		return ":" + certificate
+	}
+	return String(a.appProperties.Certificate)
+}
+
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
diff --git a/java/app_test.go b/java/app_test.go
index f6476dc..9e2bc23 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -454,3 +454,89 @@
 		})
 	}
 }
+
+func TestCertificates(t *testing.T) {
+	testCases := []struct {
+		name                string
+		bp                  string
+		certificateOverride string
+		expected            string
+	}{
+		{
+			name: "default",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+				}
+			`,
+			certificateOverride: "",
+			expected:            "build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8",
+		},
+		{
+			name: "module certificate property",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					certificate: ":new_certificate"
+				}
+
+				android_app_certificate {
+					name: "new_certificate",
+			    certificate: "cert/new_cert",
+				}
+			`,
+			certificateOverride: "",
+			expected:            "cert/new_cert.x509.pem cert/new_cert.pk8",
+		},
+		{
+			name: "path certificate property",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					certificate: "expiredkey"
+				}
+			`,
+			certificateOverride: "",
+			expected:            "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
+		},
+		{
+			name: "certificate overrides",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					certificate: "expiredkey"
+				}
+
+				android_app_certificate {
+					name: "new_certificate",
+			    certificate: "cert/new_cert",
+				}
+			`,
+			certificateOverride: "foo:new_certificate",
+			expected:            "cert/new_cert.x509.pem cert/new_cert.pk8",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			config := testConfig(nil)
+			if test.certificateOverride != "" {
+				config.TestProductVariables.CertificateOverrides = []string{test.certificateOverride}
+			}
+			ctx := testAppContext(config, test.bp, nil)
+
+			run(t, ctx, config)
+			foo := ctx.ModuleForTests("foo", "android_common")
+
+			signapk := foo.Output("foo.apk")
+			signFlags := signapk.Args["certificates"]
+			if test.expected != signFlags {
+				t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags)
+			}
+		})
+	}
+}
diff --git a/java/java_test.go b/java/java_test.go
index a0d962e..a0b8952 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -71,6 +71,7 @@
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(AndroidAppCertificateFactory))
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
 	ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
@@ -226,6 +227,9 @@
 		"bar-doc/IFoo.aidl":              nil,
 		"bar-doc/known_oj_tags.txt":      nil,
 		"external/doclava/templates-sdk": nil,
+
+		"cert/new_cert.x509.pem": nil,
+		"cert/new_cert.pk8":      nil,
 	}
 
 	for k, v := range fs {