1. 主线程卡顿现象识别
主线程卡顿是一系列可被用户、系统或工具感知的异常行为的总称。准确的现象识别是后续数据采集与原因定位的前提。根据异常表现的严重程度与触发条件,可将主线程卡顿分为三类:ANR 弹窗、掉帧感知、用户操作无响应。下面通过一张故障树梳理三者之间的关系与判别路径。
1.1 现象分类与识别依据
| 现象类别 | 触发条件 | 用户感知 | 系统输出 | 识别证据 |
|---|---|---|---|---|
| ANR 弹窗 | 主线程阻塞超过 5s(前台)/ 10s(广播)/ 60s(输入) | 屏幕出现“应用无响应”对话框,无法操作 | logcat 输出 ANR in xxx + traces 文件 | dumpsys dropbox 中 anr 记录 |
| 掉帧感知 | 单帧绘制时间 > 16.67ms(60fps)或 > 8.33ms(120fps) | 滑动/动画出现跳跃、延迟,视觉不流畅 | Choreographer 跳帧日志,GPU 渲染时间线 | Perfetto 中 SurfaceFlinger 帧间隔 > 1 vsync |
| 操作无响应 | 主线程事件队列长时间排队,未触发 ANR 超时 | 点击/触摸后界面 > 200ms 无任何反馈 | TouchEvent 分发起始延迟长,InputReader 记录 | Perfetto 中 InputTransport 耗时 > 200ms |
关键判断规则:
- 看到系统弹框 → 直接定位为 ANR 现象。
- 滑动时有肉眼可察卡顿但无弹框 → 优先视为掉帧现象,需进一步获取帧渲染数据。
- 用户反复点击后无反应,且 logcat 无 ANR 标识 → 归为操作无响应,注意与线程死锁或消息队列阻塞有关。
1.2 现象识别实操:命令行与日志验证
当收到用户反馈或监控告警后,先通过以下快速命令确认现象归属。
# 检查最近 ANR 记录
adb shell dumpsys dropbox --print | grep -A 20 "ANR"
# 检查当前是否有 pending 的 ANR
adb shell dumpsys activity processes | grep "waitingForTransition|anr"
# 实时观察帧率(需要设备支持)
adb shell dumpsys gfxinfo [package] framestats
# 抓取主线程消息队列时间分布
adb shell dumpsys activity messages | grep "MessageQueue idleTime"
经验提示:
现象识别阶段不要急于分析源码。先通过系统日志和用户复现路径确认是哪种卡顿现象,不同现象对应的 Perfetto 采集配置(后续章节)会截然不同。例如 ANR 需要抓取系统全局 traces 和进程 CPU 状态,而掉帧感知更适合采集 GPU 渲染 Pipeline。
1.3 从现象到采集的决策矩阵
识别出具体现象后,可以快速决定下一步采集方案。以下矩阵帮助你在现象识别完成后直接跳到对应的数据采集章节。
| 识别结果 | 推荐采集切入点(章节) | 关键 Perfetto 数据源 |
|---|---|---|
| ANR 弹窗 | 第 3 章 · 系统 ANR traces 抓取 | android.anr / kernel.sched / process.cpu |
| 掉帧感知 | 第 5 章 · 帧渲染 Pipeline 追踪 | gpu.renderstage / composition / SurfaceFlinger |
| 操作无响应 | 第 7 章 · 主线程 MessageQueue 分析 | android.choreographer / input / binder |
常见误判:
- 将系统 GC 引起的瞬时掉帧误判为 ANR(可通过 Perfetto 中 Java Heap 区确认)。
- 将网络请求超时导致的表象无响应误判为卡顿(需区分主线程是否在等待锁)。
- 将低端机性能不足导致的常态掉帧当作异常(需与环境基线对比)。
本章完成了卡顿现象的识别与分类。接下来按照上述决策矩阵,选择对应的数据采集章节,进入后续的量化分析阶段。