Demo:Advanced
应用退出的情形:
主动自杀。Process.killProcess()、exit() 等。
崩溃。出现了 Java 或 Native 崩溃。
系统重启;系统出现异常、断电、用户主动重启等,我们可以通过比较应用开机运行时间是否比之前记录的值更小。
被系统杀死。被 low memory killer 杀掉、从系统的任务管理器中划掉等。
ANR。
Android 崩溃分为 Java 崩溃和 Native 崩溃。
第三方平台腾讯的Bugly、阿里的啄木鸟平台、网易云捕。
Java
Java 崩溃的捕获比较简单。
try…catch显式的捕获并处理
UncaughtExceptionHandler
参考demo中的CrashActivity
Native
Android 平台 Native 代码的崩溃捕获机制及实现
一个完整的 Native 崩溃从捕获到解析要经历的流程
编译端。编译 C/C++ 代码时,需要将带符号信息的文件保留下来。
客户端。捕获到崩溃时候,将收集到尽可能多的有用信息写入日志文件,然后选择合适的时机上传到服务器。
服务端。读取客户端上报的日志文件,寻找适合的符号文件,生成可读的 C/C++ 调用栈。
收集难点
提前申请文件句柄 fd 预留,防止出现文件句柄泄漏这种情况。使用常见的 signalstack,防止防止栈溢出导致进程没有空间创建调用栈执行处理函数。
参考示例,工程里面已经集成了Breakpad, 来获取发生 native crash 时候的系统信息和线程堆栈信息。Breakpad 会从原进程 fork 出子进程去收集崩溃现场,此外涉及与 Java 相关的,一般也会用子进程去操作。这样即使出现二次崩溃,只是这部分的信息丢失,我们的父进程后面还可以继续获取其他的信息。在一些特殊的情况,我们还可能需要从子进程 fork 出孙进程。
Anr
使用 FileObserver 监听 /data/anr/traces.txt 的变化。单多高版本的 ROM,已经没有读取这个文件的权限了,可以参考Hardcoder实现。
两个概念:
PV浏览量,页面点击量,每次刷新就算一次浏览,多次打开同一页面会累加。
UV访客数,就是指一天之内到底有多少不同的用户访问了你的网站。
我们可以统计UV和PV,之后计算UV 崩溃率与PV 崩溃率,当然还需要更加注重启动崩溃率的统计,这种崩溃对用户带来的伤害最大,应用无法启动往往通过热修复也无法拯救。可以看下安全模式:天猫App启动保护实践
我们可以在应用启动的时候设定一个标志,在主动自杀或崩溃后更新标志,这样下次启动时通过检测这个标志就能确认运行期间是否发生过异常退出。
Java 崩溃类型比较明显,比如 NullPointerException 是空指针,OutOfMemoryError 是资源不足,这个时候需要去进一步查看日志中的 “内存信息”和“资源信息”。
Native 崩溃。需要观察 signal、code、fault addr 等内容,以及崩溃时 Java 的堆栈。关于各 signal 含义的介绍,你可以查看崩溃信号介绍。比较常见的是有 SIGSEGV 和 SIGABRT,前者一般是由于空指针、非法指针造成,后者主要因为 ANR 和调用 abort() 退出所导致。
ANR。先看看主线程的堆栈,是否是因为锁等待导致。接着看看 ANR 日志中 iowait、CPU、GC、system server 等信息,进一步确定是 I/O 问题,或是 CPU 竞争问题,还是由于大量 GC 导致卡死。
解决思路
通过上面的共性归类,我们先看看是某个系统版本的问题,还是某个厂商特定 ROM 的问题。
查看可疑的代码调用,是否使用了不恰当的 API,是否可以更换其他的实现方式规避。