Android crash 默认处理流程
来源:互联网 发布:剑雨江湖进阶数据仙羽 编辑:程序博客网 时间:2024/05/19 14:00
Android APP crash 的时候会弹出一个 Force close Dialog,这篇文章主要记录一下该 Dialog 的显示流程,以及由此引申出来的自定义 APP crash 处理流程
- Force close Dialog 的显示流程
- 自定义
Thread.UncaughtExceptionHandler
处理 APP crash
Force close 处理流程
Android 主要使用Thread.UncaughtExceptionHandler
机制来处理 APP Crash,这个defaultUncaughtException
定义在 RuntimeInit.commonInit()
private static final void commonInit() { ...... /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); ......}private static class UncaughtHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { try { ...... if (mApplicationObject == null) { Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); } else { StringBuilder message = new StringBuilder(); // 1) 把Exception信息打印到logcat中 message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n"); final String processName = ActivityThread.currentProcessName(); if (processName != null) { message.append("Process: ").append(processName).append(", "); } message.append("PID: ").append(Process.myPid()); Clog_e(TAG, message.toString(), e); } ...... // 2) 显示 ForceClose Dialog ActivityManagerNative.getDefault().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.CrashInfo(e)); } catch (Throwable t2) { ...... } finally { // Try everything to make sure this process goes away. Process.killProcess(Process.myPid()); System.exit(10); } }}
可以看到,这个默认的Thread.UncaughtExceptionHandler主要做了两件事
- 打印出Exception信息,这里TAG为
AndroidRuntime
,主要信息包含:线程名,进程名,进程ID,以及具体的Exception - 调用AMS.handleApplicationCrash 显示 Force close dialog
我们进入 AMS.handleApplicationCrash
public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) { ...... // 直接调用 handleApplicationCrashInner handleApplicationCrashInner("crash", r, processName, crashInfo);}void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName, ApplicationErrorReport.CrashInfo crashInfo) { EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(), UserHandle.getUserId(Binder.getCallingUid()), processName, r == null ? -1 : r.info.flags, crashInfo.exceptionClassName, crashInfo.exceptionMessage, crashInfo.throwFileName, crashInfo.throwLineNumber); addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo); mAppErrors.crashApplication(r, crashInfo);}
handleApplicationCrashInner 会首先把 crash 信息写入 EventLog 和 DropBox 中,关于这两个系统还不是很清楚,后续有机会再补上,在网上找到下面这一段描述:
- EventLog保存在/system/etc/event-log-tag中。
- Dropbox的log保存在/data/system/dropbox目录下,它的文件名以system_server或system_app或data_app打头,然后以_crash开始。
接着调用AppErrors.crashApplication
// AppErrors.javavoid crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { final long origId = Binder.clearCallingIdentity(); try { // 直接进入crashApplicationInner crashApplicationInner(r, crashInfo); } finally { Binder.restoreCallingIdentity(origId); }}void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { ...... AppErrorResult result = new AppErrorResult(); TaskRecord task; synchronized (mService) { ...... AppErrorDialog.Data data = new AppErrorDialog.Data(); data.result = result; data.proc = r; ...... 1)使用Handler发送显示Dialog消息 Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG; task = data.task; msg.obj = data; mService.mUiHandler.sendMessage(msg); } 2)等待用户对Dialog的处理结果 int res = result.get(); ...... if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) { res = AppErrorDialog.FORCE_QUIT; } // 根据用户的选择结果做不同的处理 synchronized (mService) { if (res == AppErrorDialog.MUTE) { ...... } if (res == AppErrorDialog.RESTART) { ...... } if (res == AppErrorDialog.FORCE_QUIT) { ...... } if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { ...... } ...... } ......}
这里先使用Handler发送一个显示Dialog的消息,再等待用户的选择结果
我们先看步骤2,这里其实只是简单的wait()
final class AppErrorResult { public void set(int res) { synchronized (this) { mHasResult = true; mResult = res; notifyAll(); } } public int get() { synchronized (this) { while (!mHasResult) { try { wait(); } catch (InterruptedException e) { } } } return mResult; } boolean mHasResult = false; int mResult;}
我们看到这里 result.get() 会一直等待直到 result.set() 被调用,也就是用户点击了对话框里的Button或者超时(5分钟)Dialog自动dismiss。
再看步骤1
// ActivityManagerService.javafinal class UiHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW_ERROR_UI_MSG: { mAppErrors.handleShowAppErrorUi(msg); ensureBootCompleted(); } break; ...... } }}// AppErrors.javavoid handleShowAppErrorUi(Message msg) { AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj; synchronized (mService) { ProcessRecord proc = data.proc; ...... if (mService.canShowErrorDialogs() && !crashSilenced) { // AppErrorDialog 是一个 AlertDialog proc.crashDialog = new AppErrorDialog(mContext, mService, data); } else { ...... } } // 显示Dialog if(data.proc.crashDialog != null) { data.proc.crashDialog.show(); }}
至此CrashDialog就显示出来了。
自定义 UncaughtExceptionHandler
系统默认弹出Force close Dialog 的方式对用户其实不是很友好,我们可以自定义一个UncaughtExceptionHandler,然后调用 Thread.setDefaultUncaughtExceptionHandler
将其设置为默认处理器(通常是在应用的Application.onCreate() 里设置),具体的可以参考 捕获全局异常UncaughtExceptionHandler
- Android crash 默认处理流程
- android app 默认的crash处理流程 (FATAL EXCEPTION)
- Android Crash处理流程分析
- 理解Android Crash处理流程 (Android M 6.0)
- android 2.3系统默认语言处理流程
- MT6573 android 系统默认语言处理流程
- ActivityManagerService native crash处理流程
- 理解Native Crash处理流程
- Android程序crash处理
- Android--应用Crash处理
- Android Crash异常处理
- android crash处理
- Android Crash抓取处理
- Android Crash抓取处理
- Android 应用Crash处理
- Android中crash处理
- Android-Crash处理----崩溃后禁止默认重启与崩溃后手动重启
- MT6573 android 2.3系统默认语言处理流程
- 归并排序
- 杭电1228 之 A + B
- BZOJ1034 [ZJOI2008]泡泡堂BNB 【贪心】
- C语言深度知识汇总(本文仅谈语言,且不适合初学者阅读)
- EasyDemo*回调函数
- Android crash 默认处理流程
- IO模型及select、poll、epoll和kqueue的区别
- 基于STM32F103的ID号对应用程序的保护方法(转)
- 消息中间件架构讨论
- 无题
- 计蒜客 区间包含(活动安排问题)
- 在实践中深入理解VMware虚拟机的上网模式:NAT模式
- LeetCode 190 Reverse Bits
- iPhone再出风波?网友:乔帮主要哭了!