这篇文章是 Android ANR 系列的第二篇,主要介绍了 ANR 的分析方法和关键日志,旨在帮助开发者掌握 ANR 问题的排查技巧。以下是详细总结:
一、ANR 分析基本流程
-
确定 ANR 日志有效性
- 通过 EventLog 搜索 “am_anr”,确认 ANR 发生时间与日志时间是否一致,避免因系统资源紧张导致日志延迟。
-
提取关键信息
- 从 MainLog 或 SystemLog 中获取 ANR 进程名、PID、触发原因(如输入事件超时、服务启动超时等)、CPU 和内存负载等。
-
收集系统状态
- 包括 CPU 使用率、内存压力、IO 负载、进程调度信息等,可通过
adb bugreport获取完整日志。
- 包括 CPU 使用率、内存压力、IO 负载、进程调度信息等,可通过
-
区分应用与系统问题
- 分析应用是否存在主线程耗时操作、死锁、Binder 调用延迟等;同时检查系统资源(如 CPU 负载、内存不足、IO 瓶颈)是否异常。
二、ANR 日志核心内容解析
-
线程状态与堆栈
- 线程状态:如 “state=S” 表示睡眠,“Blocked” 表示阻塞,可通过
traces.txt查看线程堆栈,识别主线程阻塞位置(如等待锁、IO 操作)。 - 正常 vs 异常堆栈:正常主线程常处于 “nativePollOnce” 等待消息状态,异常堆栈会显示具体阻塞方法(如
DiskStorageCache.e())。
- 线程状态:如 “state=S” 表示睡眠,“Blocked” 表示阻塞,可通过
-
CPU 使用率分析
- 负载指标:通过 “Load: 15.29 / 5.19 / 1.87” 判断系统负荷(1 分钟、5 分钟、15 分钟平均负载),超过 0.7 需警惕,超过 1.0 需立即优化。
- 进程 CPU 占比:如 “30% 5991/com.xxx.launcher” 表示应用用户态和内核态 CPU 占用率,结合 “faults” 判断 IO 操作频率(major fault 为磁盘 IO)。
-
内存与 IO 负载
- 内存压力:从
/proc/pressure/memory获取 “some” 和 “full” 阻塞时间占比,“full” 过高(如超过 10%)表明系统资源竞争严重。 - IO 负载:通过 “major faults” 数量判断磁盘 IO 频率,大量 major fault 可能导致主线程阻塞。
- 内存压力:从
三、系统关键日志与异常场景
-
ANR 相关系统日志
- Slow operation:AMS 任务耗时超过 50ms,如 “Slow operation: 138ms so far”,提示系统卡顿。
- Looper Slow dispatch/delivery:消息分发或处理超时,如 “Slow dispatch took 418ms”,表明主线程消息队列阻塞。
- dvm_lock_sample:线程等待锁超时(如 1500ms),显示持锁线程和阻塞位置。
- binder_sample:Binder 跨进程调用耗时超过阈值(如 2010ms),可通过接口 Code 定位具体方法。
-
进程异常与杀进程日志
- am_kill:记录进程被杀原因,如 “remove task”“anr”“crash” 等,区分主动杀进程(如用户强制停止)和被动杀进程(如 ANR、OOM)。
- lowmemorykiller:内核日志中记录因内存不足杀进程,如 “Kill 'com.heytap.themestore' to free 105068kB”。
- am_proc_died:进程异常死亡,需结合堆栈分析崩溃原因。
-
应用冻结与调度异常
- 应用冻结:日志如 “xxxHansManager : freeze uid”,因功耗优化导致应用暂停,可能触发 ANR。
- D 状态进程:进程处于不可中断睡眠状态,如 “__refrigerator” 调用,需检查内核调度或功耗策略。
四、典型场景日志分析
-
灭屏与亮屏
- 关键日志:
power_screen_state、screen_toggled,灭屏时screen_toggled=0,亮屏时=1,结合power_screen_broadcast_done时间判断耗时。
- 关键日志:
-
解锁与应用启动
- 解锁流程:通过
wm_set_keyguard_shown日志跟踪 Keyguard 状态变化,如从锁屏到桌面的焦点转移。 - 应用启动:记录
wm_create_activity、am_proc_start等事件,计算启动耗时(如wm_activity_launch_time: 471ms)。
- 解锁流程:通过
-
窗口焦点变化
- 焦点转移日志:如 “Changing focus from Launcher to App”,异常时可能触发 “No Focused Window ANR”。
五、ANR 治理方法论
-
被动分析
- 堆栈对比:比较 ANR 前后堆栈变化,识别线程状态迁移(如从 Runnable 到 Blocked)。
- 动态追踪:使用
systrace、Perfetto监控主线程消息处理周期,定位耗时操作(如 SharedPreferences 写入)。
-
主动防御
- 架构优化:限制跨进程调用层级,为业务模块分配 Binder 事务配额,强化异步边界(如 HandlerThread)。
- 机器学习预测:通过 CPU 调度、内存回收等指标建模,提前识别 ANR 风险(如 Google Android Vitals 技术)。
六、参考资料与工具
- 日志抓取:
adb bugreport获取系统全量日志,traces.txt存储 ANR 线程堆栈。 - 性能工具:Android Studio CPU Profiler、Systrace、Perfetto。
- 案例参考:西瓜视频、今日头条、高爷 ANR 优化实践系列文章,以及 Gityuan 等技术博客。
通过上述方法,开发者可从日志中提取关键信息,逐步定位 ANR 根因,结合系统设计与应用代码优化,提升应用响应性能。