4. Input系统分发队列与ANR定位:触摸无响应、dumpsys input命令、InputDispatcher队列、等待时间与超时分析

4.1 现象识别

触摸无响应(Touch Not Responding)是用户最直观的ANR表现:点击屏幕后界面不变化,或长时间卡顿后弹出“应用无响应”对话框。此类问题通常由InputDispatcher队列堆积或等待超时引起。

⚠️ 关键判断规则:如果触摸事件后界面完全无反馈,且 dumpsys input 中 Current state 显示 WaitQueue 非空且 DispatchCycle 超时,则极可能是Input分发线程阻塞或应用主线程卡死。

现象可能原因初步定位命令
触摸后无动画、无响应InputDispatcher队列满,目标窗口未消费事件adb shell dumpsys input
屏幕冻结后弹出ANR分发等待时间超过5s阈值dumpsys input 中 waitQueueDuration
部分区域触摸有效,部分无效视图层级错误,事件被上层View拦截dumpsys input windows

4.2 数据采集:dumpsys input 关键字段解读

执行 adb shell dumpsys input 后,重点关注以下队列状态区块。

Input Dispatcher State:
  DispatchEnabled: true
  DispatchFrozen: false
  FocusedApplication: AppWindowToken{...} =xxx
  FocusedWindow: Window{xxx}
  TouchState: UNHANDLED
  WaitQueue:
    length=3
    head=Event{id=102, type=MOTION, target=Window{...}}
    tail=Event{id=105, type=KEY, target=Window{...}}
  waitQueueDuration: 4200ms
  DispatchCycle:
    currentTime=1234567890
    pendingEvent: Event{id=102, dispatchTime=1234563690}  // 已分发4200ms未完成
    dispatchTimeout: 5000ms

🔍 字段速查表

  • WaitQueue:等待应用窗口处理的事件队列。长度>0说明事件堆积。
  • waitQueueDuration:最久未处理事件的等待毫秒数。超过5000ms即触发ANR。
  • DispatchCycle:当前分发周期状态,pendingEvent + dispatchTime 可计算已耗时。
  • TouchState: UNHANDLED 表示触摸事件未被任何窗口处理完毕。

4.3 原因定位:故障树与排查表

使用以下故障树逐层排查Input分发超时根因。

Input分发超时故障树 触摸无响应 / ANR InputDispatcher队列满 应用主线程阻塞 事件消费过慢 WaitQueue > 0 主线程休眠/死锁 onTouchEvent耗时 同步锁 竞争 快速定位口诀:查WaitQueue长度→看waitQueueDuration→对比dispatchTimeout 若waitQueueDuration接近5000ms,则ANR即将触发

4.4 修复动作

根据定位结果采取对应措施:

根因修复动作验证方法
InputDispatcher队列满(WaitQueue>0)优化View层级,减少冗余触摸监听;检查是否有View占据焦点却未消费事件再次执行dumpsys input确认WaitQueue清零
主线程阻塞使用StrictMode检测主线程耗时操作;将I/O、网络、编解码移至子线程抓取systrace查看主线程vsync帧间隔
事件消费过慢(onTouchEvent耗时>16ms)拆分onTouchEvent逻辑,使用RecyclerView/ViewPager2减少绘制计算使用dumpsys gfxinfo测量帧率
同步锁竞争用Lock替换synchronized,降低锁粒度;使用并发集合Thread Dump分析锁持有时间

4.5 复测

修复后执行以下复测清单:

  1. 安装修复版本,执行 adb shell am start -W com.example.app/.MainActivity 记录启动时间。
  2. 快速连续点击屏幕10次,同时执行 adb shell dumpsys input | grep -E "WaitQueue|waitQueueDuration|DispatchCycle",确保WaitQueue长度不超过1且waitQueueDuration < 1000ms。
  3. Monkey测试:adb shell monkey -p com.example.app --pct-touch 70 -v 500,观察期间有无ANR日志。
  4. 使用 adb shell dumpsys dropbox --print data_app_anr 检查是否存在新ANR记录。

4.6 预防

💡 最佳实践:

  • 开发阶段集成StrictMode,禁止主线程执行磁盘IO或网络操作。
  • 性能热区加入Choreographer帧回调,任何超过16ms的帧都输出日志。
  • 在CI/CD管道中添加dumpsys input 基线检查:对比每次版本发布时WaitQueue的数据,若长度比上一个版本增长超过阈值则告警。
  • 定期分析/data/anr/traces.txt中主线程堆栈,提前暴露死锁或长时间同步等待。