Merge "[idsig] Use SignatureAlgorithmID from apkverify"
diff --git a/libs/apkverify/tests/apkverify_test.rs b/libs/apkverify/tests/apkverify_test.rs
index 3818259..d7b1dc2 100644
--- a/libs/apkverify/tests/apkverify_test.rs
+++ b/libs/apkverify/tests/apkverify_test.rs
@@ -15,7 +15,7 @@
  */
 
 use apkverify::{testing::assert_contains, verify};
-use std::matches;
+use std::{fs, matches, path::Path};
 
 const KEY_NAMES_DSA: &[&str] = &["1024", "2048", "3072"];
 const KEY_NAMES_ECDSA: &[&str] = &["p256", "p384", "p521"];
@@ -34,7 +34,7 @@
 
 #[test]
 fn test_verify_v3() {
-    assert!(verify("tests/data/test.apex").is_ok());
+    validate_apk_public_key("tests/data/test.apex");
 }
 
 #[test]
@@ -49,32 +49,34 @@
 #[test]
 fn test_verify_v3_ecdsa_sha256() {
     for key_name in KEY_NAMES_ECDSA.iter() {
-        assert!(verify(format!("tests/data/v3-only-with-ecdsa-sha256-{}.apk", key_name)).is_ok());
+        validate_apk_public_key(format!("tests/data/v3-only-with-ecdsa-sha256-{}.apk", key_name));
     }
 }
 
 #[test]
 fn test_verify_v3_ecdsa_sha512() {
     for key_name in KEY_NAMES_ECDSA.iter() {
-        assert!(verify(format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name)).is_ok());
+        validate_apk_public_key(format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name));
     }
 }
 
 #[test]
 fn test_verify_v3_rsa_sha256() {
     for key_name in KEY_NAMES_RSA.iter() {
-        assert!(
-            verify(format!("tests/data/v3-only-with-rsa-pkcs1-sha256-{}.apk", key_name)).is_ok()
-        );
+        validate_apk_public_key(format!(
+            "tests/data/v3-only-with-rsa-pkcs1-sha256-{}.apk",
+            key_name
+        ));
     }
 }
 
 #[test]
 fn test_verify_v3_rsa_sha512() {
     for key_name in KEY_NAMES_RSA.iter() {
-        assert!(
-            verify(format!("tests/data/v3-only-with-rsa-pkcs1-sha512-{}.apk", key_name)).is_ok()
-        );
+        validate_apk_public_key(format!(
+            "tests/data/v3-only-with-rsa-pkcs1-sha512-{}.apk",
+            key_name
+        ));
     }
 }
 
@@ -167,20 +169,45 @@
 
 #[test]
 fn test_verify_v3_unknown_additional_attr() {
-    assert!(verify("tests/data/v3-only-unknown-additional-attr.apk").is_ok());
+    validate_apk_public_key("tests/data/v3-only-unknown-additional-attr.apk");
 }
 
 #[test]
 fn test_verify_v3_unknown_pair_in_apk_sig_block() {
-    assert!(verify("tests/data/v3-only-unknown-pair-in-apk-sig-block.apk").is_ok());
+    validate_apk_public_key("tests/data/v3-only-unknown-pair-in-apk-sig-block.apk");
 }
 
 #[test]
 fn test_verify_v3_ignorable_unsupported_sig_algs() {
-    assert!(verify("tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk").is_ok());
+    validate_apk_public_key("tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk");
 }
 
 #[test]
 fn test_verify_v3_stamp() {
-    assert!(verify("tests/data/v3-only-with-stamp.apk").is_ok());
+    validate_apk_public_key("tests/data/v3-only-with-stamp.apk");
+}
+
+fn validate_apk_public_key<P: AsRef<Path>>(apk_path: P) {
+    // Validates public key from verification == expected public key.
+    let public_key_from_verification = verify(apk_path.as_ref());
+    let public_key_from_verification =
+        public_key_from_verification.expect("Error in verification result");
+
+    let expected_public_key_path = format!("{}.der", apk_path.as_ref().to_str().unwrap());
+    assert!(
+        fs::metadata(&expected_public_key_path).is_ok(),
+        "File does not exist. You can re-create it with:\n$ echo -en {} > {}\n",
+        public_key_from_verification.iter().map(|b| format!("\\\\x{:02x}", b)).collect::<String>(),
+        expected_public_key_path
+    );
+    let expected_public_key = fs::read(&expected_public_key_path).unwrap();
+    assert_eq!(
+        expected_public_key,
+        public_key_from_verification.as_ref(),
+        "{}",
+        expected_public_key_path
+    );
+
+    // TODO(b/239534874): Validates public key extracted directly from apk
+    // (without verification) == expected public key.
 }
diff --git a/libs/apkverify/tests/data/test.apex.der b/libs/apkverify/tests/data/test.apex.der
new file mode 100644
index 0000000..abeb1eb
--- /dev/null
+++ b/libs/apkverify/tests/data/test.apex.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-unknown-additional-attr.apk.der b/libs/apkverify/tests/data/v3-only-unknown-additional-attr.apk.der
new file mode 100644
index 0000000..27535ca
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-unknown-additional-attr.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-unknown-pair-in-apk-sig-block.apk.der b/libs/apkverify/tests/data/v3-only-unknown-pair-in-apk-sig-block.apk.der
new file mode 100644
index 0000000..6aafd09
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-unknown-pair-in-apk-sig-block.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p256.apk.der b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p256.apk.der
new file mode 100644
index 0000000..01927af
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p256.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p384.apk.der b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p384.apk.der
new file mode 100644
index 0000000..95baf40
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p384.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p521.apk.der b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p521.apk.der
new file mode 100644
index 0000000..b68f925
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p521.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p256.apk.der b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p256.apk.der
new file mode 100644
index 0000000..01927af
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p256.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p384.apk.der b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p384.apk.der
new file mode 100644
index 0000000..95baf40
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p384.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p521.apk.der b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p521.apk.der
new file mode 100644
index 0000000..b68f925
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha512-p521.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk.der b/libs/apkverify/tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk.der
new file mode 100644
index 0000000..96dc543
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-1024.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-1024.apk.der
new file mode 100644
index 0000000..6aafd09
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-1024.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-16384.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-16384.apk.der
new file mode 100644
index 0000000..31abdc7
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-16384.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-2048.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-2048.apk.der
new file mode 100644
index 0000000..96dc543
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-2048.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-3072.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-3072.apk.der
new file mode 100644
index 0000000..bd70f5f
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-3072.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-4096.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-4096.apk.der
new file mode 100644
index 0000000..951648e
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-4096.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-8192.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-8192.apk.der
new file mode 100644
index 0000000..15e5edf
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-8192.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-1024.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-1024.apk.der
new file mode 100644
index 0000000..6aafd09
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-1024.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-16384.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-16384.apk.der
new file mode 100644
index 0000000..31abdc7
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-16384.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-2048.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-2048.apk.der
new file mode 100644
index 0000000..96dc543
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-2048.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-3072.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-3072.apk.der
new file mode 100644
index 0000000..bd70f5f
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-3072.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-4096.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-4096.apk.der
new file mode 100644
index 0000000..951648e
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-4096.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-8192.apk.der b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-8192.apk.der
new file mode 100644
index 0000000..15e5edf
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha512-8192.apk.der
Binary files differ
diff --git a/libs/apkverify/tests/data/v3-only-with-stamp.apk.der b/libs/apkverify/tests/data/v3-only-with-stamp.apk.der
new file mode 100644
index 0000000..01927af
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-stamp.apk.der
Binary files differ
diff --git a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
index eeadae1..e5eee27 100644
--- a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
+++ b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
@@ -39,6 +39,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
@@ -56,6 +57,11 @@
     private static final String SYSTEM_SERVER_COMPILER_FILTER_PROP_NAME =
             "dalvik.vm.systemservercompilerfilter";
 
+    private static final String BOOTLOADER_TIME_PROP_NAME = "ro.boot.boottime";
+    private static final String BOOTLOADER_PREFIX = "bootloader-";
+    private static final String BOOTLOADER_TIME = "bootloader_time";
+    private static final String BOOTLOADER_PHASE_SW = "SW";
+
     /** Boot time test related variables */
     private static final int REINSTALL_APEX_RETRY_INTERVAL_MS = 5 * 1000;
     private static final int REINSTALL_APEX_TIMEOUT_SEC = 15;
@@ -89,72 +95,124 @@
     }
 
     @Test
-    public void testBootEnableAndDisablePKVM() throws Exception {
-        skipIfPKVMStatusSwitchNotSupported();
-
-        List<Double> bootWithPKVMEnableTime = new ArrayList<>(ROUND_COUNT);
-        List<Double> bootWithoutPKVMEnableTime = new ArrayList<>(ROUND_COUNT);
-
-        for (int round = 0; round < ROUND_COUNT; ++round) {
-
-            setPKVMStatusWithRebootToBootloader(true);
-            long start = System.nanoTime();
-            rebootFromBootloaderAndWaitBootCompleted();
-            long elapsedWithPKVMEnable = System.nanoTime() - start;
-            double elapsedSec = elapsedWithPKVMEnable / NANOS_IN_SEC;
-            bootWithPKVMEnableTime.add(elapsedSec);
-            CLog.i("Boot time with PKVM enable took " + elapsedSec + "s");
-
-            setPKVMStatusWithRebootToBootloader(false);
-            start = System.nanoTime();
-            rebootFromBootloaderAndWaitBootCompleted();
-            long elapsedWithoutPKVMEnable = System.nanoTime() - start;
-            elapsedSec = elapsedWithoutPKVMEnable / NANOS_IN_SEC;
-            bootWithoutPKVMEnableTime.add(elapsedSec);
-            CLog.i("Boot time with PKVM disable took " + elapsedSec + "s");
-        }
-
-        reportMetric(bootWithPKVMEnableTime, "boot_time_with_pkvm_enable", "s");
-        reportMetric(bootWithoutPKVMEnableTime, "boot_time_with_pkvm_disable", "s");
+    public void testBootEnablePKVM() throws Exception {
+        enableDisablePKVMTestHelper(true);
     }
 
     @Test
-    public void testBootWithAndWithoutCompOS() throws Exception {
-        assumeFalse(isCuttlefish());
+    public void testBootDisablePKVM() throws Exception {
+        enableDisablePKVMTestHelper(false);
+    }
 
-        List<Double> bootWithCompOsTime = new ArrayList<>(ROUND_COUNT);
-        List<Double> bootWithoutCompOsTime = new ArrayList<>(ROUND_COUNT);
+    @Test
+    public void testBootWithCompOS() throws Exception {
+        composTestHelper(true);
+    }
 
+    @Test
+    public void testBootWithoutCompOS() throws Exception {
+        composTestHelper(false);
+    }
+
+    private void updateBootloaderTimeInfo(Map<String, List<Double>> bootloaderTime)
+            throws Exception {
+
+        String bootLoaderVal = getDevice().getProperty(BOOTLOADER_TIME_PROP_NAME);
+        // Sample Output : 1BLL:89,1BLE:590,2BLL:0,2BLE:1344,SW:6734,KL:1193
+        if (bootLoaderVal != null) {
+            String[] bootLoaderPhases = bootLoaderVal.split(",");
+            double bootLoaderTotalTime = 0d;
+            for (String bootLoaderPhase : bootLoaderPhases) {
+                String[] bootKeyVal = bootLoaderPhase.split(":");
+                String key = String.format("%s%s", BOOTLOADER_PREFIX, bootKeyVal[0]);
+
+                bootloaderTime.computeIfAbsent(key,
+                        k -> new ArrayList<>()).add(Double.parseDouble(bootKeyVal[1]));
+                // SW is the time spent on the warning screen. So ignore it in
+                // final boot time calculation.
+                if (BOOTLOADER_PHASE_SW.equalsIgnoreCase(bootKeyVal[0])) {
+                    continue;
+                }
+                bootLoaderTotalTime += Double.parseDouble(bootKeyVal[1]);
+            }
+            bootloaderTime.computeIfAbsent(BOOTLOADER_TIME,
+                    k -> new ArrayList<>()).add(bootLoaderTotalTime);
+        }
+    }
+
+    private Double getDmesgBootTime() throws Exception {
+
+        CommandRunner android = new CommandRunner(getDevice());
+        String result = android.run("dmesg");
+        Pattern pattern = Pattern.compile("\\[(.*)\\].*sys.boot_completed=1.*");
+        for (String line : result.split("[\r\n]+")) {
+            Matcher matcher = pattern.matcher(line);
+            if (matcher.find()) {
+                return Double.valueOf(matcher.group(1));
+            }
+        }
+        throw new IllegalArgumentException("Failed to get boot time info.");
+    }
+
+    private void enableDisablePKVMTestHelper(boolean isEnable) throws Exception {
+        skipIfPKVMStatusSwitchNotSupported();
+
+        List<Double> bootDmesgTime = new ArrayList<>(ROUND_COUNT);
+        Map<String, List<Double>> bootloaderTime = new HashMap<>();
+
+        setPKVMStatusWithRebootToBootloader(isEnable);
+        rebootFromBootloaderAndWaitBootCompleted();
         for (int round = 0; round < ROUND_COUNT; ++round) {
-
-            // Boot time with compilation OS test.
-            reInstallApex(REINSTALL_APEX_TIMEOUT_SEC);
-            compileStagedApex(COMPILE_STAGED_APEX_TIMEOUT_SEC);
             getDevice().nonBlockingReboot();
-            long start = System.nanoTime();
             waitForBootCompleted();
-            long elapsedWithCompOS = System.nanoTime() - start;
-            double elapsedSec = elapsedWithCompOS / NANOS_IN_SEC;
-            bootWithCompOsTime.add(elapsedSec);
-            CLog.i("Boot time with compilation OS took " + elapsedSec + "s");
 
-            // Boot time without compilation OS test.
-            reInstallApex(REINSTALL_APEX_TIMEOUT_SEC);
-            getDevice().nonBlockingReboot();
-            start = System.nanoTime();
-            waitForBootCompleted();
-            long elapsedWithoutCompOS = System.nanoTime() - start;
-            elapsedSec = elapsedWithoutCompOS / NANOS_IN_SEC;
-            bootWithoutCompOsTime.add(elapsedSec);
-            CLog.i("Boot time without compilation OS took " + elapsedSec + "s");
+            updateBootloaderTimeInfo(bootloaderTime);
+
+            double elapsedSec = getDmesgBootTime();
+            bootDmesgTime.add(elapsedSec);
         }
 
-        reportMetric(bootWithCompOsTime, "boot_time_with_compos", "s");
-        reportMetric(bootWithoutCompOsTime, "boot_time_without_compos", "s");
+        String suffix = "";
+        if (isEnable) {
+            suffix = "enable";
+        } else {
+            suffix = "disable";
+        }
+
+        reportMetric(bootDmesgTime, "dmesg_boot_time_with_pkvm_" + suffix, "s");
+        reportAggregatedMetrics(bootloaderTime,
+                "bootloader_time_with_pkvm_" + suffix, "ms");
+    }
+
+    private void composTestHelper(boolean isWithCompos) throws Exception {
+        assumeFalse("Skip on CF; too slow", isCuttlefish());
+
+        List<Double> bootDmesgTime = new ArrayList<>(ROUND_COUNT);
+
+        for (int round = 0; round < ROUND_COUNT; ++round) {
+            reInstallApex(REINSTALL_APEX_TIMEOUT_SEC);
+            if (isWithCompos) {
+                compileStagedApex(COMPILE_STAGED_APEX_TIMEOUT_SEC);
+            }
+            getDevice().nonBlockingReboot();
+            waitForBootCompleted();
+
+            double elapsedSec = getDmesgBootTime();
+            bootDmesgTime.add(elapsedSec);
+        }
+
+        String suffix = "";
+        if (isWithCompos) {
+            suffix = "with_compos";
+        } else {
+            suffix = "without_compos";
+        }
+
+        reportMetric(bootDmesgTime, "dmesg_boot_time_" + suffix, "s");
     }
 
     private void skipIfPKVMStatusSwitchNotSupported() throws Exception {
-        assumeFalse(isCuttlefish());
+        assumeFalse("Skip on CF; can't reboot to bootloader", isCuttlefish());
 
         if (!getDevice().isStateBootloaderOrFastbootd()) {
             getDevice().rebootIntoBootloader();
@@ -171,12 +229,22 @@
     }
 
     private void reportMetric(List<Double> data, String name, String unit) {
+        CLog.d("Report metric " + name + "(" + unit + ") : " + data.toString());
         Map<String, Double> stats = mMetricsProcessor.computeStats(data, name, unit);
         for (Map.Entry<String, Double> entry : stats.entrySet()) {
+            CLog.d("Add test metrics " + entry.getKey() + " : " + entry.getValue().toString());
             mMetrics.addTestMetric(entry.getKey(), entry.getValue().toString());
         }
     }
 
+    private void reportAggregatedMetrics(Map<String, List<Double>> bootloaderTime,
+            String prefix, String unit) {
+
+        for (Map.Entry<String, List<Double>> entry : bootloaderTime.entrySet()) {
+            reportMetric(entry.getValue(), prefix + "_" + entry.getKey(), unit);
+        }
+    }
+
     private void setPKVMStatusWithRebootToBootloader(boolean isEnable) throws Exception {
 
         if (!getDevice().isStateBootloaderOrFastbootd()) {