Android 崩溃分析 方法论
Android 崩溃分析 方法论
文章目录
- Android 崩溃分析 方法论
- 一. 崩溃现场信息收集
- 1. 崩溃信息
- 2. 系统信息
- 3. 内存信息
- 4. 资源信息
- 5. 应用信息
- 二. 崩溃信息分析
- 1. 确定严重程度
- 2. 确定崩溃信息
- 3. 汇集资源使用情况
- 4. 尝试复现
- 三. 崩溃问题修复
- 1. 查找可能的所有原因
- 2. 尝试规避
- 3. Hook解决
一. 崩溃现场信息收集
1. 崩溃信息
- 执行信息: 进程名称, 线程名称
- 执行状态: 前台进程, 后台进程, UI进程
- 崩溃类型: Java崩溃, Native崩溃, ANR, OOM
- 堆栈状态: Native堆栈, Java堆栈, 主线程堆栈
2. 系统信息
-
设备信息: 机型, 系统版本, 厂商, CPU, ABI, Linux版本, 网络, 电量, 磁盘等
-
Logcat: 查询 /system/etc/event-log-tags文件, 文件权限为 -rw-r–r--
system logcat:10-25 17:13:47.788 21430 21430 D dalvikvm: Trying to load lib ... event logcat:10-25 17:13:47.788 21430 21430 I am_on_resume_called: 生命周期10-25 17:13:47.788 21430 21430 I am_low_memory: 系统内存不足10-25 17:13:47.788 21430 21430 I am_destroy_activity: 销毁 Activty10-25 17:13:47.888 21430 21430 I am_anr: ANR 以及原因10-25 17:13:47.888 21430 21430 I am_kill: APP 被杀以及原因
3. 内存信息
-
系统内存: 系统剩余内存, 系统本身内存, 可以读取 /proc/meminfo查看
-
应用内存: RSS(Resident Set Size), PSS(Proportional Set Size), Java内存, Java栈, Native内存, Native栈
-
虚拟内存: App虚拟内存整体通过 /proc/pid/status查看, App虚拟内存细节, 通过 /proc/pid/maps查看
// 文件/proc/pid/statusName: com.sample.name // 进程名FDSize: 800 // 当前进程申请的文件句柄个数VmPeak: 3004628 kB // 当前进程的虚拟内存峰值大小VmSize: 2997032 kB // 当前进程的虚拟内存大小Threads: 600 // 当前进程包含的线程个数
4. 资源信息
-
文件句柄: 通过查询 /proc/pid/limits查询, 默认一个进程可打开最大句柄为1024, 所有句柄可在 /proc/pid/fd目录下查询
// 目录/proc/pid/fdlrwx------ 1 u0_a999 u0_a999 64 2019-05-31 11:32 0 -> /dev/nulllrwx------ 1 u0_a999 u0_a999 64 2019-05-31 11:32 1 -> /dev/nulllrwx------ 1 u0_a999 u0_a999 64 2019-05-31 11:32 2 -> /dev/null
-
线程数量: 通过查询 /proc/pid/status可以得到当前线程数量, 一个线程可能拥有2MB的虚拟内存
-
JNI: 注意引用失效, 引用报表等问题, 通过 DumpReferenceTables统计引用表, 进一步分析内存泄露
5. 应用信息
- 崩溃场景: 所在Activity或Fragment, 具体业务
- 操作步骤: 记录记录用户操作步骤, 便于开发环境重现
- 状态信息: 根据崩溃所处的业务模块, 收集相关联的模块状态信息
二. 崩溃信息分析
1. 确定严重程度
严重程度可分为 致命, 严重, 一般, 提示, 根据严重程度分出优先级; 还要注意迭代情况, 如果下一个版本就取消了该功能, 就可以放低该问题优先级
2. 确定崩溃信息
确定崩溃类型, 如 Java崩溃, Native崩溃, ANR, OOM
- ANR: 查看主线程堆栈, 是否是因为锁造成; 继续查看 /data/anr/traces.txt寻找 iowait, CPU, GC, system_server等信息
- Java崩溃: 可以直接查看栈信息进行排查
- Native崩溃: 注意singal、code、fault addr等内容, 以及Java堆栈信息, Native异常排查参考
信号量 | Value | 描述 | 例子 |
---|---|---|---|
SIGABRT | 6 | 进程发现错误或者主动调用abort(); | 很多C的库函数中, 如果发现异常会调用abort, 如strlen |
SIGBUS | 7, 10 | 不存在的物理地址, 硬件有误 | 更多的是因为硬件或者系统引起的 |
SIGFPE | 8 | 浮点数运算错误 | 如除0操作, 整形溢出 |
SIGILL | 4 | 非法指令 | 损坏的可执行文件或者代码区损坏 |
SIGSEGV | 11 | 段地址错误 | 空指针, 访问不存在的地址空间, 访问内核区, 写只读空间, 栈溢出, 数组越界, 野指针 |
SIGPIPE | 13 | 管道错误, 往没有reader的管道中写 | Linux中的socket, 如果断掉了继续写 |
3. 汇集资源使用情况
分析App内存, 磁盘, 网络, fd等资源信息, 汇总机型, 厂商, 系统, ABI等不同维度的信息
4. 尝试复现
不管是否已经找到原因, 都应该尝试用户的步骤进行重现, 这样既可以得到最新的问题资源信息, 也可以得到问题出现的大概位置和原因
三. 崩溃问题修复
1. 查找可能的所有原因
找到问题出现的点, 进一步分析为什么出现这种问题, 有没有其他位置也有类似的问题; 通过用户的操作步骤可以在其他模块进行尝试发掘新的问题
2. 尝试规避
代码中是否调用了不稳定的API, 或者调用方式不合规, 是否可以通过其他的方式达到相同的效果
3. Hook解决
有些问题是系统问题, 低版本可能出现频率大, 高版本不存在, 这时我们可以查看高版本代码如何写的, 利用Hook, 按照高版本的方式进行规避
更多相关文章
- 南青信息查询 for Android客户端
- Android进程
- 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图
- Android之rild进程启动源码分析
- Android系统启动流程(1) —— 解析init进程启动过程
- 【随心笔录】Android多进程实现,一个APP多个进程