Add an assertNoCrashes function to CTS

Bug: 134613999
Test: None
Change-Id: I6c94638c76f79a60d24add0ca4371f422aff6387
Merged-In: I6c94638c76f79a60d24add0ca4371f422aff6387
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 954d1ce..6c52b8f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,6 +16,7 @@
 
 package android.security.cts;
 
+import com.android.compatibility.common.util.CrashUtils;
 import com.android.ddmlib.NullOutputReceiver;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -27,13 +28,16 @@
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.List;
+import java.util.regex.Pattern;
 import java.util.concurrent.TimeUnit;
 import java.util.Scanner;
-
 import java.util.regex.Pattern;
-import java.lang.Thread;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import static org.junit.Assert.*;
-import junit.framework.Assert;
 
 public class AdbUtils {
 
@@ -291,6 +295,72 @@
     }
 
     /**
+     * Runs the poc binary and asserts that there are no security crashes that match the expected
+     * process pattern.
+     * @param pocName a string path to poc from the /res folder
+     * @param device device to be ran on
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
+            String... processPatternStrings) throws Exception {
+        AdbUtils.runCommandLine("logcat -c", device);
+        // account for the poc timer of 5 minutes (+15 seconds for safety)
+        AdbUtils.runPocNoOutput(pocName, device, 315);
+        assertNoCrashes(device, processPatternStrings);
+    }
+
+    /**
+     * Dumps logcat and asserts that there are no security crashes that match the expected process.
+     * By default, checks min crash addresses
+     * pattern. Ensure that adb logcat -c is called beforehand.
+     * @param device device to be ran on
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
+            throws Exception {
+        assertNoCrashes(device, true, processPatternStrings);
+    }
+
+    /**
+     * Dumps logcat and asserts that there are no security crashes that match the expected process
+     * pattern. Ensure that adb logcat -c is called beforehand.
+     * @param device device to be ran on
+     * @param checkMinAddress if the minimum fault address should be respected
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void assertNoCrashes(ITestDevice device, boolean checkMinAddress,
+            String... processPatternStrings) throws Exception {
+        String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
+
+        Pattern[] processPatterns = new Pattern[processPatternStrings.length];
+        for (int i = 0; i < processPatternStrings.length; i++) {
+            processPatterns[i] = Pattern.compile(processPatternStrings[i]);
+        }
+        JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
+        JSONArray securityCrashes =
+                CrashUtils.matchSecurityCrashes(crashes, checkMinAddress, processPatterns);
+
+        if (securityCrashes.length() == 0) {
+            return; // no security crashes detected
+        }
+
+        StringBuilder error = new StringBuilder();
+        error.append("Security crash detected:\n");
+        error.append("Process patterns:");
+        for (String pattern : processPatternStrings) {
+            error.append(String.format(" '%s'", pattern));
+        }
+        error.append("\nCrashes:\n");
+        for (int i = 0; i < crashes.length(); i++) {
+            try {
+                JSONObject crash = crashes.getJSONObject(i);
+                error.append(String.format("%s\n", crash));
+            } catch (JSONException e) {}
+        }
+        fail(error.toString());
+    }
+
+    /**
      * Executes a given poc within a given timeout. Returns error if the
      * given poc doesnt complete its execution within timeout. It also deletes
      * the list of files provided.
@@ -317,11 +387,11 @@
                 }
             }
             if (test_failed == true) {
-                Assert.fail("PoC was interrupted");
+                fail("PoC was interrupted");
             }
         }
         if (t.isAlive()) {
-            Assert.fail("PoC not completed within timeout of " + timeout + " ms");
+            fail("PoC not completed within timeout of " + timeout + " ms");
         }
     }