Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

为什么抛出异常时 app 会退出 #58

Open
cnwutianhao opened this issue Sep 13, 2024 · 0 comments
Open

为什么抛出异常时 app 会退出 #58

cnwutianhao opened this issue Sep 13, 2024 · 0 comments

Comments

@cnwutianhao
Copy link
Owner

cnwutianhao commented Sep 13, 2024

在 Android 应用程序开发中,异常处理是一个至关重要的环节。当应用程序抛出未捕获的异常时,系统通常会终止应用程序进程,从而导致用户体验上的崩溃现象。本文将深入探讨 Android 系统在应用程序初始化和运行过程中如何处理未捕获的异常,并解释为什么在抛出异常时应用程序会退出。本文基于 Android 14,API 34 进行源码解析。

Android 应用程序初始化时会走到 RuntimeInitmain 方法里。

// RuntimeInit.java

@UnsupportedAppUsage
public static final void main(String[] argv) {
    ...

    commonInit();

    ...
}

在进程初始化时,RuntimeInitcommonInit 里会注入默认杀进程的 KillApplicationHandler

// RuntimeInit.java

protected static final void commonInit() {
    ...

    // 创建 LoggingHandler 实例,用于记录日志。
    LoggingHandler loggingHandler = new LoggingHandler();
    // 设置了一个预处理程序,在异常处理之前执行。
    RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
    // 设置了一个默认的未捕获异常处理程序,用于处理未捕获的异常并执行相应的操作。
    Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));

    ...
}

FinalizerWatchdogDaemon 是一个守护线程,用于监控 FinalizerDaemonReferenceQueueDaemon,确保它们在合理的时间内完成任务。如果这些守护线程检测到某个任务超时,它们会采取相应的措施,比如终止应用程序。

// Daemons.java

private static void timedOut(TimeoutException exception) {
    try {
        // 向当前进程发送 SIGQUIT 信号,以获取本地堆栈跟踪信息。
        Os.kill(Os.getpid(), OsConstants.SIGQUIT);
        // 发送信号后,线程会休眠 5 秒钟,以便堆栈跟踪信息有足够的时间打印出来。
        Thread.sleep(5000);
    } catch (Exception e) {
        System.logE("failed to send SIGQUIT", e);
    } catch (OutOfMemoryError ignored) {
    }

    // 检查当前线程是否有预处理程序或默认的未捕获异常处理程序。如果没有,它会记录异常信息并退出程序。
    if (Thread.getUncaughtExceptionPreHandler() == null &&
            Thread.getDefaultUncaughtExceptionHandler() == null) {
        System.logE(exception.getMessage(), exception);
        System.exit(2);
    }

    // 如果存在未捕获异常处理程序,当前线程会调用它来处理异常。
    Thread.currentThread().dispatchUncaughtException(exception);
}

如果我们没有实现自定义的 UncaughtExceptionHandler 时,dispatchUncaughtException 被调用就会走到 KillApplicationHandler 里,把当前的进程杀掉,即产生了一次用户感知的崩溃行为。

// Thread.java

public final void dispatchUncaughtException(Throwable e) {
    Thread.UncaughtExceptionHandler initialUeh =
            Thread.getUncaughtExceptionPreHandler();
    if (initialUeh != null) {
        try {
            initialUeh.uncaughtException(this, e);
        } catch (RuntimeException | Error ignored) {
        }
    }
    getUncaughtExceptionHandler().uncaughtException(this, e);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant