Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will an exception thrown in a Different thread will crash the main thread?

I have a doubt on this, for example, in a Java class's main method, I have some codes below:

public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                throw new IllegalStateException("sss");
            }
        }).start();


        try {
            Thread.sleep(2000);
        } catch (Exception e) {

        }

        System.out.println("xxx");

    }

this IllegalStateException will not stop the main method from executing, and I can see i print "xxx".

However, in Android development, if i do the same in Activity's oncreate() method , it will crash the App .

I wonder how does Android handle this and why it will crash the app.

Thanks

logcat logs:

FATAL EXCEPTION: Thread-248

                                                        Process: com.abc.android, PID: 3673
                                                        java.lang.IllegalStateException: sss
                                                            at com.abc.android.MainActivity$1.run(MainActivity.java:80)
                                                            at java.lang.Thread.run(Thread.java:818)
like image 988
Qing Avatar asked Jan 04 '23 23:01

Qing


1 Answers

Every Thread has an option to set an uncaught handler which will be called when the thread encounters an exception

Fron Android's documentation over here:

void setDefaultUncaughtExceptionHandler (Thread.UncaughtExceptionHandler eh): Set the default handler invoked when a thread abruptly terminates due to an uncaught exception, and no other handler has been defined for that thread.

Uncaught exception handling is controlled first by the thread, then by the thread's ThreadGroup object and finally by the default uncaught exception handler. If the thread does not have an explicit uncaught exception handler set, and the thread's thread group (including parent thread groups) does not specialize its uncaughtException method, then the default handler's uncaughtException method will be invoked.

By setting the default uncaught exception handler, an application can change the way in which uncaught exceptions are handled (such as logging to a specific device, or file) for those threads that would already accept whatever "default" behavior the system provided.

Note that the default uncaught exception handler should not usually defer to the thread's ThreadGroup object, as that could cause infinite recursion.

Also note that the setDefaultUncaughtExceptionHandler is a static method, which would mean that it would apply to all of the Thread's created by the application.

Now if you dig deeper, you will find that the Android Framework defines a default uncaught exception handler for all the Threads in the RuntimeInit.java, which goes on to report the crash and kill the process.

/**
 * Use this to log a message when a thread exits due to an uncaught
 * exception.  The framework catches these for the main threads, so
 * this should only matter for threads created by applications.
 */
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
    public void uncaughtException(Thread t, Throwable e) {
        try {
            // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
            if (mCrashing) return;
            mCrashing = true;
            if (mApplicationObject == null) {
                Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
            } else {
                Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
            }
            // Bring up crash dialog, wait for it to be dismissed
            ActivityManagerNative.getDefault().handleApplicationCrash(
                    mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
        } catch (Throwable t2) {
            try {
                Slog.e(TAG, "Error reporting crash", t2);
            } catch (Throwable t3) {
                // Even Slog.e() fails!  Oh well.
            }
        } finally {
            // Try everything to make sure this process goes away.
            Process.killProcess(Process.myPid());
            System.exit(10);
        }
    }
}
private static final void commonInit() {
    if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
    /* set default handler; this applies to all threads in the VM */
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

Remember that you can override the uncaught exception handler for a specific thread by calling,setUncaughtExceptionHandler of that thread. If you do that in your example above, you will notice that the app doesn't crash anymore.

like image 137
Saurabh Avatar answered Jan 07 '23 12:01

Saurabh