Move SSD crash handler fallback to typed Kotlin

ober

97c692fc4911688a671dd8b767274900c75225d4

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 4bd3072..3e59813 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -5628,6 +5628,33 @@
               (json-object-put-string! out "status" text)
               out)))))
 
+    (typed-kotlin-file "com/sfb/ssdreview/ClientCrash.kt"
+      (kotlin-imports (java lang Thread)
+                      (java lang Thread UncaughtExceptionHandler))
+      (typed-library (com sfb ssdreview)
+        (export finishUncaughtException)
+        (type Int32)
+        (type Thread)
+        (type Throwable)
+        (type UncaughtExceptionHandler)
+        (extern (systemExit (code : Int32)) : Unit
+          (kotlin-call java lang System exit))
+        (extern (handlerUncaughtException (handler : UncaughtExceptionHandler)
+                                          (crashingThread : Thread)
+                                          (error : Throwable)) : Unit
+          (kotlin-member-call uncaughtException))
+        (def (finishUncaughtException
+               (handler : (Nullable UncaughtExceptionHandler))
+               (crashingThread : Thread)
+               (error : Throwable)
+               (exitCode : Int32)) : Unit
+          (if (nullable-null? handler)
+            (systemExit exitCode)
+            (handlerUncaughtException
+              (nullable-get handler)
+              crashingThread
+              error)))))
+
     (typed-kotlin-file "com/sfb/ssdreview/TruthIndexSelect.kt"
       (typed-library (com sfb ssdreview)
         (export bestTruthIndexForSession truthIndexEntryPresent)
@@ -6309,7 +6336,6 @@
        "import java.net.URL"
        "import java.util.UUID"
        "import kotlin.concurrent.thread"
-       "import kotlin.system.exitProcess"
        ""
        "class MainActivity : Activity() {"
        "    private lateinit var truthStore: TruthStore"
@@ -7784,7 +7810,7 @@
        "            } catch (_: Exception) {"
        "                // Diagnostics must not change Android crash handling."
        "            }"
-       "            if (previous != null) previous.uncaughtException(crashingThread, throwable) else exitProcess(2)"
+       "            finishUncaughtException(previous, crashingThread, throwable, 2)"
        "        }"
        "    }"
        ""