原文地址:https://juejin.cn/post/6844903972587716621#heading-56
稳定性
维度:Crash率,性能,业务可用性
重预防,稳监控
UV、PV
采集、处理(清洗、聚合、分类、趋势)、展示(数据还原、维度、版本分析)、预警
Crash优化治理
根据堆栈及现场信息分析原因
找共性:机型、OS、实验开关、资源包,考虑影响范围
线下复现、远程调试
Crash解决三步走
常规直接解、系统及Hook绕、疑难重点突破
常用代码
出现未捕获异常,导致出现异常退出,进程唯一
Thread.setDefaultUncaughtExceptionHandler();
获取主线程的堆栈信息:
Looper.getMainLooper().getThread().getStackTrace();
复制代码
获取当前线程的堆栈信息:
Thread.currentThread().getStackTrace();
复制代码
获取全部线程的堆栈信息:
Thread.getAllStackTraces();
复制代码
第三方Crash监控工具如 Fabric、腾讯Bugly,都是以字符串拼接的方式将数组StackTraceElement[]转换成字符串形式,进行保存、上报或者展示。
反混淆:Mapping映射
Java Crash
logcat日志流程,**应用层(logcat命令) --> liblog.so(hook liblog.so 中的 **__android_log_buf_write方法) --> logd(通过socket直接跟logd交互,底层使用 ring buffer 来存储数据。
Thread.getAllStackTraces()。
优点:简单,兼容性好。
缺点:1.成功率不高,依靠系统接口在极端情况也会失败。2.7.0之后这个接口是没有主线程堆栈。3.使用Java层的接口需要暂停线程。
hook libart.so。
通过hook ThreadList和Thread 的函数,获得跟ANR一样的堆栈。为了稳定性,需要在fork的子进程中执行。
优点:信息很全,基本跟ANR的日志一样,有native线程状态,锁信息等等。
缺点:黑科技的兼容性问题,失败时我们可以使用Thread.getAllStackTraces()兜底。
Crash流程
1、首先发生crash所在进程,在创建之初便准备好了defaultUncaughtHandler,用来处理Uncaught Exception,并输出当前crash的基本信息;
2、调用当前进程中的AMP.handleApplicationCrash;经过binder ipc机制,传递到system_server进程;
3、接下来,进入system_server进程,调用binder服务端执行AMS.handleApplicationCrash;
4、从mProcessNames查找到目标进程的ProcessRecord对象;并将进程crash信息输出到目录/data/system/dropbox;
5、执行makeAppCrashingLocked:
- 创建当前用户下的crash应用的error receiver,并忽略当前应用的广播;
- 停止当前进程中所有activity中的WMS的冻结屏幕消息,并执行相关一些屏幕相关操作;
6、再执行handleAppCrashLocked方法:
- 当1分钟内同一进程未发生连续crash两次时,则执行结束栈顶正在运行activity的流程;
- 当1分钟内同一进程连续crash两次时,且非persistent进程,则直接结束该应用所有activity,并杀死该进程以及同一个进程组下的所有进程。然后再恢复栈顶第一个非finishing状态的activity;
- 当1分钟内同一进程连续crash两次时,且persistent进程,则只执行恢复栈顶第一个非finishing状态的activity。
7、通过mUiHandler发送消息SHOW_ERROR_MSG,弹出crash对话框;
8、到此,system_server进程执行完成。回到crash进程开始执行杀掉当前进程的操作;
9、当crash进程被杀,通过binder死亡通知,告知system_server进程来执行appDiedLocked();
10、最后,执行清理应用相关的四大组件信息。
Binder 回收
由于Crash进程中拥有一个Binder服务端ApplicationThread,而应用进程在创建过程调用attachApplicationLocked(),从而attach到system_server进程,在system_server进程内有一个ApplicationThreadProxy,这是相对应的Binder客户端。当Binder服务端ApplicationThread所在进程(即Crash进程)挂掉后,则Binder客户端能收到相应的死亡通知,从而进入binderDied流程。
Native Crash
成熟方案:Google BreakPad、Crashpad
|