Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Force Crash with Uncaught Exception in Thread

I'm developing an app, and every once in a while one of my background worker threads will have an uncaught exception of one sort or another. These exceptions crash that thread, but since it's not on the UI thread the App keeps running. How can I force these uncaught exceptions in the background threads to crash the whole app? It would be nice if the same contextual crash information (such as the stack trace) were available.

I want to do this so that when I release the app to my testers it doesn't become unresponsive. Instead, when the background thread has an uncaught exception the App will go to it's crash handler and send me a report (I'm using ACRA, but that shouldn't matter). That's better than an app that silently fails.

like image 604
srlm Avatar asked Jul 07 '13 09:07

srlm


2 Answers

Late answer, but I was asking myself the same question.

We use Crashlytics in Production, but if the app is build for development, some assertion are enabled, and logging an error actually throws it, so that we developer can detect any incorrect behavior.

But as you remarked, throwing an error in a background thread doesn't crash the app.

To ensure the app crashes immediately when build for development we simply use an Handler on the main looper to throw the exception on the main thread.

It looks a bit like this :


public static void assertTrue(boolean condition, String msg) {
    if (condition) {
        return;
    }

    final IllegalStateException e = new IllegalStateException(message);
    if (BuildConfig.RELEASE) {
        Crashlytics.logException(e);
        return;
    }

    Log.e("ASSERT", message, e);
    if (Looper.getMainLooper() != Looper.myLooper()) {
        mMainThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                throw e;
            }
        });
    }

    throw e;
}
like image 200
Xval Avatar answered Nov 10 '22 02:11

Xval


Original version below

Actually, after further testing I have found that you can simplify your code by just handing the exception to your main thread directly.

public static <T extends Exception> void throwOnMainThread(T exception) {
    Thread mainThread = Looper.getMainLooper().getThread();
    mainThread.getUncaughtExceptionHandler().uncaughtException(mainThread, exception);
}

This will crash the main thread from anywhere and is safe to call even without setting a custom UncaughtExceptionHandler.

Original answer:

Consider the following static method for crashing the main thread from a background thread:

public static <T extends Exception> void throwOnMainThread(final T exception) {
    Handler mainThreadHandler = new Handler(Looper.getMainLooper());
    mainThreadHandler.post(new Runnable() {
        @Override
        public void run() {
            Thread currentThread = Thread.currentThread();
            currentThread.getUncaughtExceptionHandler().uncaughtException(currentThread, exception);
        }
    });
}

First we get a Handler for the Main Thread via the main Looper. Then we post a Runnable which will invoke the UncaughtExceptionHandler of that thread and hand it our exception.

Put this into a utils class and you will be able to throw exceptions on the main thread from basically anywhere.

Crashing the main thread could then be achieved by using

ThreadUtils.throwOnMainThread(new RuntimeException());

for example.

like image 29
A. Steenbergen Avatar answered Nov 10 '22 00:11

A. Steenbergen