Allow generating source stamp in apksig locally am: 530fd3ea8c

Change-Id: I2c241c0c9f3b837b219d07296adb6ff1fc429640
diff --git a/src/apksigner/java/com/android/apksigner/ApkSignerTool.java b/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
index f864595..d2f8a1b 100644
--- a/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
+++ b/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
@@ -128,6 +128,7 @@
         int maxSdkVersion = Integer.MAX_VALUE;
         List<SignerParams> signers = new ArrayList<>(1);
         SignerParams signerParams = new SignerParams();
+        SignerParams sourceStampSignerParams = new SignerParams();
         SigningCertificateLineage lineage = null;
         List<ProviderInstallSpec> providers = new ArrayList<>();
         ProviderInstallSpec providerParams = new ProviderInstallSpec();
@@ -135,6 +136,7 @@
         String optionName;
         String optionOriginalForm = null;
         boolean v4SigningFlagFound = false;
+        boolean sourceStampFlagFound = false;
         while ((optionName = optionsParser.nextOption()) != null) {
             optionOriginalForm = optionsParser.getOptionOriginalForm();
             if (("help".equals(optionName)) || ("h".equals(optionName))) {
@@ -224,6 +226,9 @@
             } else if ("provider-pos".equals(optionName)) {
                 providerParams.position =
                         optionsParser.getRequiredIntValue("JCA Provider position");
+            } else if ("stamp-signer".equals(optionName)) {
+                sourceStampFlagFound = true;
+                sourceStampSignerParams = processSignerParams(optionsParser);
             } else {
                 throw new ParameterException(
                         "Unsupported option: " + optionOriginalForm + ". See --help for supported"
@@ -280,49 +285,27 @@
             providerInstallSpec.installProvider();
         }
 
+        ApkSigner.SignerConfig sourceStampSignerConfig = null;
         List<ApkSigner.SignerConfig> signerConfigs = new ArrayList<>(signers.size());
         int signerNumber = 0;
         try (PasswordRetriever passwordRetriever = new PasswordRetriever()) {
             for (SignerParams signer : signers) {
                 signerNumber++;
                 signer.setName("signer #" + signerNumber);
-                try {
-                    signer.loadPrivateKeyAndCerts(passwordRetriever);
-                } catch (ParameterException e) {
-                    System.err.println(
-                            "Failed to load signer \"" + signer.getName() + "\": "
-                                    + e.getMessage());
-                    System.exit(2);
-                    return;
-                } catch (Exception e) {
-                    System.err.println("Failed to load signer \"" + signer.getName() + "\"");
-                    e.printStackTrace();
-                    System.exit(2);
+                ApkSigner.SignerConfig signerConfig = getSignerConfig(signer, passwordRetriever);
+                if (signerConfig == null) {
                     return;
                 }
-                String v1SigBasename;
-                if (signer.getV1SigFileBasename() != null) {
-                    v1SigBasename = signer.getV1SigFileBasename();
-                } else if (signer.getKeystoreKeyAlias() != null) {
-                    v1SigBasename = signer.getKeystoreKeyAlias();
-                } else if (signer.getKeyFile() != null) {
-                    String keyFileName = new File(signer.getKeyFile()).getName();
-                    int delimiterIndex = keyFileName.indexOf('.');
-                    if (delimiterIndex == -1) {
-                        v1SigBasename = keyFileName;
-                    } else {
-                        v1SigBasename = keyFileName.substring(0, delimiterIndex);
-                    }
-                } else {
-                    throw new RuntimeException(
-                            "Neither KeyStore key alias nor private key file available");
-                }
-                ApkSigner.SignerConfig signerConfig =
-                        new ApkSigner.SignerConfig.Builder(
-                                v1SigBasename, signer.getPrivateKey(), signer.getCerts())
-                                .build();
                 signerConfigs.add(signerConfig);
             }
+            if (sourceStampFlagFound) {
+                sourceStampSignerParams.setName("stamp signer");
+                sourceStampSignerConfig =
+                        getSignerConfig(sourceStampSignerParams, passwordRetriever);
+                if (sourceStampSignerConfig == null) {
+                    return;
+                }
+            }
         }
 
         if (outputApk == null) {
@@ -355,6 +338,9 @@
             Files.deleteIfExists(outputV4SignatureFile.toPath());
             apkSignerBuilder.setV4SignatureOutputFile(outputV4SignatureFile);
         }
+        if (sourceStampSignerConfig != null) {
+            apkSignerBuilder.setSourceStampSignerConfig(sourceStampSignerConfig);
+        }
         ApkSigner apkSigner = apkSignerBuilder.build();
         try {
             apkSigner.sign();
@@ -378,6 +364,44 @@
         }
     }
 
+    private static ApkSigner.SignerConfig getSignerConfig(
+            SignerParams signer, PasswordRetriever passwordRetriever) {
+        try {
+            signer.loadPrivateKeyAndCerts(passwordRetriever);
+        } catch (ParameterException e) {
+            System.err.println(
+                    "Failed to load signer \"" + signer.getName() + "\": " + e.getMessage());
+            System.exit(2);
+            return null;
+        } catch (Exception e) {
+            System.err.println("Failed to load signer \"" + signer.getName() + "\"");
+            e.printStackTrace();
+            System.exit(2);
+            return null;
+        }
+        String v1SigBasename;
+        if (signer.getV1SigFileBasename() != null) {
+            v1SigBasename = signer.getV1SigFileBasename();
+        } else if (signer.getKeystoreKeyAlias() != null) {
+            v1SigBasename = signer.getKeystoreKeyAlias();
+        } else if (signer.getKeyFile() != null) {
+            String keyFileName = new File(signer.getKeyFile()).getName();
+            int delimiterIndex = keyFileName.indexOf('.');
+            if (delimiterIndex == -1) {
+                v1SigBasename = keyFileName;
+            } else {
+                v1SigBasename = keyFileName.substring(0, delimiterIndex);
+            }
+        } else {
+            throw new RuntimeException("Neither KeyStore key alias nor private key file available");
+        }
+        ApkSigner.SignerConfig signerConfig =
+                new ApkSigner.SignerConfig.Builder(
+                        v1SigBasename, signer.getPrivateKey(), signer.getCerts())
+                        .build();
+        return signerConfig;
+    }
+
     private static void verify(String[] params) throws Exception {
         if (params.length == 0) {
             printUsage(HELP_PAGE_VERIFY);
@@ -500,6 +524,7 @@
                 System.out.println(
                         "Verified using v4 scheme (APK Signature Scheme v4): "
                                 + result.isVerifiedUsingV4Scheme());
+                System.out.println("Verified for SourceStamp: " + result.isSourceStampVerified());
                 System.out.println("Number of signers: " + signerCerts.size());
             }
             if (printCerts) {
@@ -558,6 +583,14 @@
             }
         }
 
+        ApkVerifier.Result.SourceStampInfo sourceStampInfo = result.getSourceStampInfo();
+        for (ApkVerifier.IssueWithParams error : sourceStampInfo.getErrors()) {
+            System.err.println("ERROR: SourceStamp: " + error);
+        }
+        for (ApkVerifier.IssueWithParams warning : sourceStampInfo.getWarnings()) {
+            warningsOut.println("WARNING: SourceStamp: " + warning);
+        }
+
         if (!verified) {
             System.exit(1);
             return;
diff --git a/src/apksigner/java/com/android/apksigner/help_sign.txt b/src/apksigner/java/com/android/apksigner/help_sign.txt
index b9d0146..5efd952 100644
--- a/src/apksigner/java/com/android/apksigner/help_sign.txt
+++ b/src/apksigner/java/com/android/apksigner/help_sign.txt
@@ -91,6 +91,9 @@
                       (aka v1 scheme) signature of this signer. By default,
                       KeyStore key alias or basename of key file is used.
 
+--stamp-signer        The signing information for the signer of the source stamp
+                      to be included in the APK.
+
         PER-SIGNER SIGNING KEY & CERTIFICATE OPTIONS
 There are two ways to provide the signer's private key and certificate: (1) Java
 KeyStore (see --ks), or (2) private key file in PKCS #8 format and certificate