深入理解 Android 9.0 Crash 机制 读懂底层原理 看清表面逻辑( 二 )

  • 1.当System进程Crash的信息:
开头 FATAL EXCEPTION IN SYSTEM PROCESS [线程名],接着输出Crash时的调用栈信息;
  • 2.当app进程Crash时的信息:
开头 FATAL EXCEPTION: [线程名],紧接着 Process: [进程名], PID: [进程id];最后输出发生Crash时的调用栈信息 。
看到这里 , 你就会发现要从log中搜索Crash信息 , 只需要搜索关键词 FATAL EXCEPTION,即可查看出是那种异常;如果需要进一步筛选只搜索系统crash信息 , 则可以搜索的关键词可以有多样 , 比如 FATAL EXCEPTION IN SYSTEM PROCESS 。
当输出完Crash信息到logcat里面 , 这只是Crash流程的刚开始阶段 , 接下来弹出Crash对话框 , ActivityManagerNative.getDefault()返回的是ActivityManagerProxy(简称AMP) , AMP经过binder调用最终交给ActivityManagerService(简称AMS)中相应的方法去处理,然后调用的是AMS.handleApplicationCrash() 。
分析完LoggingHandler后 , 我们继续看setDefaultUncaughtExceptionHandler() , 它只是将异常处理器handler对象赋给Thread成员变量,即Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler)); 。接下来看看KillApplicationHandler对象实例化过程 。
2. KillApplicationHandler
RuntimeInit.java
KillApplicationHandler 实现 Thread.UncaughtExceptionHandler方法,主要处理由于未捕获的异常Crash导致APP 崩溃,运行在Main Thread的Framework 代码会捕获这些异常 。
KillApplicationHandler 方法需要传递一个LoggingHandler的参数 , 
既 LoggingHandler loggingHandler = new LoggingHandler(); , LoggingHandler在上文已经分析过 , 接下来我们看看KillApplicationHandler方法.
KillApplicationHandler方法如下:
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler { private final LoggingHandler mLoggingHandler; public KillApplicationHandler(LoggingHandler loggingHandler) { // 构造方法 , 初始化 loggingHandlerthis.mLoggingHandler = Objects.requireNonNull(loggingHandler); } @Override public void uncaughtException(Thread t, Throwable e) { try { ensureLogging(t, e); // 保证crash处理过程不会重入 if (mCrashing) return; mCrashing = true; ... ... //启动crash对话框 , 等待处理完成 【见小节2.1和3】 ActivityManager.getService().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e)); } catch (Throwable t2) { ... ...} finally { //确保当前进程彻底杀掉【见小节11】 Process.killProcess(Process.myPid()); System.exit(10); } } ... ...}接下来我们看看启动Crash弹窗的处理 。new ApplicationErrorReport.ParcelableCrashInfo(e)方法 。
2.1 ApplicationErrorReport.ParcelableCrashInfo
ApplicationErrorReport 主要用来描述 APP Error信息 。
APP ERROR 信息分类如下:
  • TYPE_CRASH: APP Crash 信息
  • TYPE_ANR: APP ANR 信息
  • TYPE_BATTERY: Battery 使用信息
  • TYPE_RUNNING_SERVICE: 正在运行的Service 相关信息
// 主要处理 APP Error 信息public class ApplicationErrorReport implements Parcelable { ... ... public static class ParcelableCrashInfo extends CrashInfo implements Parcelable { //创建 CrashInfo 实例 , 初始化异常信息 public ParcelableCrashInfo(Throwable tr) { super(tr); } ... ...public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public ParcelableCrashInfo createFromParcel(Parcel in) { return new ParcelableCrashInfo(in); } @Override public ParcelableCrashInfo[] newArray(int size) { return new ParcelableCrashInfo[size]; } }; } ... ...}ParcelableCrashInfo 继承 CrashInfo,接下来我们看看 CrashInfo的实现 。
CrashInfo
**CrashInfo ** 主要是将Crash信息文件名 , 类名 , 方法名 , 对应行号以及异常信息都封装到CrashInfo对象 。
// 描述 Crash 信息 public static class CrashInfo { ... ... public CrashInfo() { } //CrashInfo 初始化实例public CrashInfo(Throwable tr) { StringWriter sw = new StringWriter(); PrintWriter pw = new FastPrintWriter(sw, false, 256); //输出栈trace tr.printStackTrace(pw); pw.flush(); stackTrace = sanitizeString(sw.toString()); exceptionMessage = tr.getMessage(); // 显示异常的根本原因 Throwable rootTr = tr; while (tr.getCause() != null) { tr = tr.getCause(); if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) { rootTr = tr; } String msg = tr.getMessage(); if (msg != null && msg.length() > 0) { exceptionMessage = msg; } } // Crash 异常类名称exceptionClassName = rootTr.getClass().getName(); if (rootTr.getStackTrace().length > 0) { StackTraceElement trace = rootTr.getStackTrace()[0]; // 获取 trace 文件名、类名、方法名、Crash 行号 throwFileName = trace.getFileName(); throwClassName = trace.getClassName(); throwMethodName = trace.getMethodName(); throwLineNumber = trace.getLineNumber(); } else { throwFileName = "unknown"; ... ...} exceptionMessage = sanitizeString(exceptionMessage); }


推荐阅读