目前 mPaaS Android 是使用的是 Crash SDK 对闪退进行的处理,Crash SDK 是 Android 平台上一款功能强大的崩溃日志收集 SDK,有着极高的崩溃收集率和完整、全面的崩溃日志信息,生成的日志内容非常利于问题的跟进和解决。
在我们的日常运维中,经常遇到一些闪退,无法直接从闪退堆栈看到原因,尤其是一些非 Java 的 Native 的闪退,这里分享下在 mPaaS 框架下怎么使用 Crash SDK 对闪退进行分析。
闪退报文分析工具介绍
对于 mPaaS 的用户,从 MAS 上闪退分析平台导出的一般是原始的闪退信息,闪退信息比较多,如果直接阅读会比较困难,使用者可以通过下载 Chrome 的插件LogAnalyzer。
LogAnalyzer 会将 Crash SDK 生成的日志文本内容转化成可视效果较强的 HTML 页面展现,功能还是很强大的,主要包含:
高亮显示日志中重点信息,并使用不同颜色区分;
支持日志内容整体结构预览,快速定位重点内容;
常见崩溃原因提醒;
安装好 Chrome 插件后,还需要做以下配置
1. 修改闪退文件后缀为 .txt
由于 MAS 上默认下载的文件后缀是.dat,需要改为.txt,否则 LogAnalyzer 会不识别。
2. 修改插件配置
由于 Chrome 默认权限限制,任何 Chrome 插件默认都不能访问文件网址,需要在 Chrome 插件中进行如下操作。
1.打开 Chrome 插件管理页面 chrome://extensions/
2.找到 LogAnalyzer 插件,点击 “详细信息" 进入设置:
3.找到允许访问文件网址选项,并勾选;
4.打开或者刷新日志页面,LogAnalyzer 就生效了。
3. 生效效果
把日志文件直接拖到 Chrome 后,可以看到右边插件生效后,可以通过不同颜色显示闪退信息的各个字段。
首次打开后的使用说明如下:
正常查看闪退截图如下:
闪退分析举例
我们经常在日常运维中遇到一些非 Java 的 Native 模块闪退,比如 UC。这种时候很多时候只能去联系 UC 团队进行支撑,其实很多场景下,闪退的根因并不是 UC,只是最后的闪退点在 UC。
以最近日常运维中比较常遇到的 UC 内核的闪退为例,对一些案例的处理分享如下。
1. Java 空指针导致 UC 闪退
我们在闪退点上可以看到以下闪退(已经隐藏客户 apk 相关信息),如果只是从这看我们暂时没有任何线索,我们继续往下看日志:
当看到 logcat 节点信息的时候,我们发现了线索,首先我们看到关键字:begin to generate native report,表示当前是闪退日志上报的日志,我们再往前看,logcat 节点里打印了异常堆栈信息。
从堆栈信息可以看到,是由于 precreate 操作触发了底层的空指针,从而导致初始化异常,最后触发了闪退。解决方案就是临时关闭预创建,从而规避了闪退。
从上面的案例我们可以看出:
Native 的闪退不一定是 Native 模块的原因导致的,有可能是由于 Java 导致的异常,从而导致 Native 闪退;
begin to generate native report 附近可以看闪退相关的 logcat 信息,协助定位闪退的一些上下文日志。
2. 上层 OOM 导致 UC 闪退
首先我们看上报的闪退点的日志如下图所示,闪退在了 RenderThread 里,也是毫无头绪。
我们继续硬着头皮往下看,在 logcat 节点里查找 begin to generate native report 上报节点,我们看到了大量的底层 OOM 的异常日志,基本大概率确定是 OOM 的原因了。
剩下的就是查找 OOM 是哪里触发的。
点击闪退里的内存节点,基本原因就比较清晰了,当前手机的 Vmsize 基本已经到最大了,我们知道对于 32 位的进程,APP 可使用的 VmSize 最大为 3GB,不过当运行在 64 位 CPU 上时,VmSize 最大可超过 3GB,接近 4GB。
但是由于内核需要占据一部分,以及不同的 ROM 版本的差别,我们发现有以下规律:Android 8.1.0 及之后的系统,大部分 native oom crash 发生时 VmSize 分布在 3.5 - 3.9 G 的位置,相对较为集中。所以下面的案例的解决思路就变成了怎么解决 OOM 了。
3. FD 误关导致 UC 闪退
上报的日志如下图所示,我们大概只能看出 SIGILL 有可能是主动崩溃,崩溃 ILL_ILLOPC 表示非法操作。
然后我们继续看 logcat 节点的 begin to generate native report, 基本确认原因是因为 UC 使用的 FD 对象被其他程序关闭。
随后 UC 提供了带 FDscan 的工具包,通过我们复现后发现,是由于 UC 调用 shouldIntercept 回调的输入流对象被其他模块 close 掉了,导致 UC 使用的时候发现 FD 对象已经被关闭,从而做了崩溃处理。最后的处理方案就变成了用户解决其他模块的误关 FD 的问题。
总结
综合以上的 Case 分析,在遇到 Native 模块闪退的时候,一般如果从直接的闪退堆栈看不出原因的时候,不要心急,可以搜索 begin to generate native report 找到崩溃上下文,多看看 logcat 闪退上下文的日志,会有一些收获,同时对于 oom 类型的问题,可以结合当前内存统计来看。