diff --git a/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt b/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt index 7d06752cba..af32191f53 100644 --- a/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt +++ b/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt @@ -34,20 +34,21 @@ internal class AndroidExceptionPreHandler : override fun handleException(context: CoroutineContext, exception: Throwable) { /* - * If we are on old SDK, then use Android's `Thread.getUncaughtExceptionPreHandler()` that ensures that - * an exception is logged before crashing the application. + * Android Oreo introduced private API for a global pre-handler for uncaught exceptions, to ensure that the + * exceptions are logged even if the default uncaught exception handler is replaced by the app. The pre-handler + * is invoked from the Thread's private dispatchUncaughtException() method, so our manual invocation of the + * Thread's uncaught exception handler bypasses the pre-handler in Android Oreo, and uncaught coroutine + * exceptions are not logged. This issue was addressed in Android Pie, which added a check in the default + * uncaught exception handler to invoke the pre-handler if it was not invoked already (see + * https://android-review.googlesource.com/c/platform/frameworks/base/+/654578/). So the issue is present only + * in Android Oreo. * - * Since Android Pie default uncaught exception handler always ensures that exception is logged without interfering with - * pre-handler, so reflection hack is no longer needed. - * - * See https://android-review.googlesource.com/c/platform/frameworks/base/+/654578/ + * We're fixing this by manually invoking the pre-handler using reflection, if running on an Android Oreo SDK + * version (26 and 27). */ - val thread = Thread.currentThread() - if (Build.VERSION.SDK_INT >= 28) { - thread.uncaughtExceptionHandler.uncaughtException(thread, exception) - } else { + if (Build.VERSION.SDK_INT in 26..27) { (preHandler()?.invoke(null) as? Thread.UncaughtExceptionHandler) - ?.uncaughtException(thread, exception) + ?.uncaughtException(Thread.currentThread(), exception) } } }