本文是 Systrace 系列文章的第六篇,主要是对 Systrace 中的 Input 进行简单介绍,介绍其 Input 的流程; Systrace 中 Input 信息的体现 ,以及如何结合 Input 信息,分析与 Input 相关的问题
本系列的目的是通过 Systrace 这个工具,从另外一个角度来看待 Android 系统整体的运行,同时也从另外一个角度来对 Framework 进行学习。也许你看了很多讲 Framework 的文章,但是总是记不住代码,或者不清楚其运行的流程,也许从 Systrace 这个图形化的角度,你可以理解的更深入一些。
版本说明(2026-10-13 技术复核): 保留 2019 年截图和原始 dumpsys 数据,旧实现以 AOSP
android-9.0.0_r1为参照,并补充 Android 16 与 Perfetto 观测边界。原图中的队列/埋点不是所有系统固定接口;本次读取了两个公开附件中的 Trace 文本,没有重新运行设备实验。
本文目录
- 系列文章目录
- 正文
- Input in Systrace
- InputDown 事件在 SystemServer 的工作流
- InputDown 事件在 App 的工作流
- 关键知识点和流程
- Input 刷新与 Vsync
- Input 调试信息
- 参考
- 附件
- 本文其他地址
- 关于我 && 博客
系列文章目录
- Systrace 简介
- Systrace 基础知识 - Systrace 预备知识
- Systrace 基础知识 - Why 60 fps ?
- Systrace 基础知识 - SystemServer 解读
- Systrace 基础知识 - SurfaceFlinger 解读
- Systrace 基础知识 - Input 解读
- Systrace 基础知识 - Vsync 解读
- Systrace 基础知识 - Vsync-App :基于 Choreographer 的渲染机制详解
- Systrace 基础知识 - MainThread 和 RenderThread 解读
- Systrace 基础知识 - Binder 和锁竞争解读
- Systrace 基础知识 - Triple Buffer 解读
- Systrace 基础知识 - CPU Info 解读
- Systrace 流畅性实战 1 :了解卡顿原理
- Systrace 流畅性实战 2 :案例分析: MIUI 桌面滑动卡顿分析
- Systrace 流畅性实战 3 :卡顿分析过程中的一些疑问
- Systrace 响应速度实战 1 :了解响应速度原理
- Systrace 响应速度实战 2 :响应速度实战分析-以启动速度为例
- Systrace 响应速度实战 3 :响应速度延伸知识
- Systrace 线程 CPU 运行状态分析技巧 - Runnable 篇
- Systrace 线程 CPU 运行状态分析技巧 - Running 篇
- Systrace 线程 CPU 运行状态分析技巧 - Sleep 和 Uninterruptible Sleep 篇
正文
这篇 Input 文章可与 Perfetto 5:Choreographer 渲染流程、Perfetto 7:MainThread 和 RenderThread 一起读。排查时先定位事件进入系统、选择目标、写入 InputChannel、App 接收与处理、完成确认,再关联需要更新的帧和实际呈现。输入确认完成与画面显示完成是两条不同的边界。
Choreographer 篇已经区分了 Looper 消息分发与 native FD 回调。输入通道可读时也会通过 native Looper 进入 Java,因此不能把所有输入都理解成一个普通 Handler Message。本文主要讨论触摸 MotionEvent;按键 KeyEvent 的焦点选择、策略拦截与回退处理另有分支,Home/Back 也不能概括成必定交给当前 App 的普通按键。
典型触摸路径是:
- 触摸控制器按设备策略采样,经驱动形成内核输入事件;硬件采样、报告、InputReader 被调度的频率不必一一相同。
- EventHub 读取事件,InputReader 按设备/mapper 处理坐标、动作等,再通知后续分发链。
- InputDispatcher 根据事件类型、显示、窗口触摸区域、手势状态和策略选择目标连接;不是向所有“注册输入的 App”广播。
- App 接收后按适用路径立即或批量处理。UI 状态变化可能促成下一帧更新,请求会合并,不是每个输入都对应一个新帧。
时间轴从左到右,但比较的是已对时的事件/区间边界,跨线程的先后关系并不能单独证明因果。仍要对照 channel、序号、调用栈和调度信息。我希望大家在看基于 Systrace 的源码流程分析之后,脑子里有一个图形化的、立体的流程图,你跟的代码走到哪一步了,在图形里也能快速定位。
Input in Systrace
以下保留桌面单指滑动案例:通常从 DOWN 开始,经过若干 MOVE,以 UP 或 CANCEL 结束;多指还会有 POINTER_DOWN/POINTER_UP,不能把所有手势都固定为 Down-Move-Up。

原图中的 InputReader 和 InputDispatcher 是 system_server 的 native 线程。其余标记需要分别理解:
- InputReader 处理 EventHub 读入的数据,触摸路径使用 Motion 通知,按键使用 Key 通知。
- InputDispatcher 选择目标并维护分发状态。队列和名称属于该版本实现,厂商及新系统埋点可能不同。
oq:是某个 Connection 的 outbound 队列计数,连接可能对应窗口或 monitor,一个 App 可以有多个窗口/连接。wq:记录已成功发布、仍待 finished 协议处理的条目;不是“只有业务返回 true 才算成功”。aq:pending是 ViewRootImpl 待取出的输入队列计数,不等于全部正在处理/等待确认的输入数。deliverInputEvent是 App 分发处理的跟踪区间,不是内核唤醒时刻;需要另看 sched_wakeup/sched_switch。- 旧查看器的
Input Response/Rendering Response是交互分析分组,不是通用硬件触摸到屏幕的直接测量。 - 手指抬起后,满足手势/速度条件时可以继续 fling;并非每次 UP 必触发 fling。
下面先看 DOWN。MOVE 的批处理、历史采样和重采样差异会影响时序,不能当作可忽略的小差异。
InputDown 事件在 SystemServer 的工作流
原图展示 Reader 工作、Dispatcher 调度以及连接计数变化。颜色和计数提供线索,精确时延要选取对应事件并读时间值:

InputDown 事件在 App 的工作流
普通 DOWN 通常不走 MOVE 的批量等待路径,可以在输入通道可读后进入分发;这不取决于“系统有没有 VSync”。主线程忙、可运行但未获 CPU 或其他输入阶段等待时,仍可能延后。

App 的 Pending 队列

原图说明“处理完变 0”过于简化。Android 9 ViewRootImpl.doProcessInputEvents()在取出一个 QueuedInputEvent 后,先减小 pending 计数,再调用 deliverInputEvent()。所以计数归零时,该事件可能正在处理、等待异步阶段或尚未回传 finished;主线程阻塞在 native 通道读取之前时,这个 Java 队列也不一定先堆起来。
主线程处理 Input 事件
图中可见 native poll → InputEventReceiver → ViewRootImpl 输入阶段 → DecorView/Activity/View 分发。这是该事件的路径,不表示所有类型都经过同一组 stage,也不能从 MethodTrace 插桩时长直接推正常运行成本。

关键知识点和流程
正常路径可以概括为:Reader 通知 Dispatcher → 事件进入 inbound/pending → 选择目标并进入各连接 outbound → 发布成功后进入 wait → App 处理 → 通过同一输入通道返回 finished 序号和 handled 状态 → Dispatcher 处理确认并清理或按策略继续。
数据和确认主要走 InputChannel socket 协议,不是每个触摸都用 Binder 回调 Java InputManagerService。handled=false 也可以是一次合法处理结果,finished 不等于 UI 已经重绘。异常连接清理也可能让队列减少,因此要结合连接状态读计数。
InputReader
以 AOSP android-9.0.0_r1 为源码参照:EventHub 监听输入设备 FD 及设备变化;每轮读出的 RawEvent 由 mapper 处理。该版本缓冲数组容量为 256,指 RawEvent 容量,不是 256 个完整手势、采样率或所有版本固定常量。触摸形成 NotifyMotionArgs/MotionEntry 路径,Key 才是 NotifyKeyArgs/KeyEntry。
下面的历史图包括 interceptKeyBeforeQueueing 等按键分支,不能当作所有触摸都必经的函数链:

下面是 Android 9 的完整 loopOnce() 方法,可以看到阻塞读取和 listener flush 均在 Reader 锁外;它仍属于系统源码,不是独立应用示例:
1 | void InputReader::loopOnce() { |
InputDispatcher
Reader 的 listener 通知可能使 Dispatcher 入队并唤醒,但策略过滤和其他唤醒来源也存在。下图的具体 Runnable 选区显示唤醒来自 TID 25669(图中 Reader),不能将此推广到每一次 Dispatcher 唤醒:

Android 9 Dispatcher分别处理 Key 与 Motion。Key 常围绕焦点窗口和按键策略;触摸还要命中测试、维护手势目标、处理 split/cancel 等情况。下面旧图中的 dispatchKeyLocked、findFocusedWindowTargetsLocked、publishKeyEvent 明确是 Key 分支,不能直接替代本文的触摸路径。

下面用流程伪码概括队列边界:
1 | dispatchOnce: |
deliveryTime 在这版 startDispatchCycleLocked() 尝试发布条目时设置;不是硬件采样时刻,也不能不顾后续等待把最初进入 dispatchOnce 的时间当成所有事件统一的投递时刻。WOULD_BLOCK 等背压/错误需要单独处理,不能先假定已经进入 wait。策略命令还可能通过命令队列在合适的锁边界执行。
InboundQueue
notifyKey 与 notifyMotion 经相应检查后可封装并入队。取出条目成为 mPendingEvent 后,iq 计数可以减少,但该事件仍可能等待目标或继续分发,所以 iq=0 不代表系统输入工作全做完。

OutboundQueue
这是每个 Connection 待发布的条目队列;同一输入可能按规则有多个目标,也可能被过滤。一个进程有多个窗口,monitor 又有独立用途,不能把 Connection 简化成“一 App 一个队列”。下图选中的是 StatusBar 连接,值为 1,不是 Launcher 的所有输入数。

WaitQueue
发布成功后,Dispatcher 将条目从 outbound 移入 wait。App 的 finishInputEvent(event, handled) 经 native InputConsumer 发送确认;Dispatcher 按连接和序号处理后再移除相应条目,必要时还涉及回退策略。详见 InputTransport 和 InputEventReceiver。
wait 长时间增长是调查线索,原因可能是 App 未获调度、处理耗时、MOVE 批量等待、确认传送/处理或连接问题。长度不等于时长,也不是 ANR 判据。 下图来自 sample.tencent.mat... 的另一份列表案例,选区 32.276 ms,一个计数值为 8;不能把它当成桌面那份 Trace 或八个事件都尚未进入 App。

整体逻辑
原图来自 Gityuan 博客,包含 KeyboardInputMapper/notifyKey;它是历史阅读线索,不是 Android 16 所有触摸输入的精确调用链。现代源码仍需按自己版本跟踪。

Input 刷新与 Vsync
那么,是不是屏幕采样率越高越好?先区分触摸采样率、输入报告/调度频率、显示刷新率和 App 实际帧率。120Hz 的周期约 8.33ms,160Hz 为 6.25ms;原文的 120Hz“8ms”只是粗略近似,且这些不是今天所有设备的固定规格。

我当时在图中把设备标为 160Hz,但 Reader 工作间隔还受报告批次和调度影响。WaitQueue 短暂积累也不等于 App 永远不消费。批量 MOVE 可在 Choreographer INPUT 阶段按帧时间消费,DOWN/UP 等不能用同一规则概括。
多个采样点不等于只留最新、其余全丢。 MotionEvent 的 batching 合同允许一个 ACTION_MOVE 携带多个历史样本;应用可先读 getHistoricalX/Y() 和历史时间,再读当前样本。Android 9 InputConsumer.consumeBatch/consumeSamples()会选取合适时间范围的样本、加入 MotionEvent history,并维护对应确认序号链;启用重采样时还会根据帧时间和样本估计位置。
因此不能从 60Hz 显示推出“120Hz 触摸足够”,也不能从 90Hz 推出“必须 180Hz”。更高采样可能减少部分输入等待或提供更细数据,也可能增加功耗/处理负担;2/3 个样本交替成批本身并不证明 UI 必抖。要结合事件时间、历史点/重采样、实际呈现与端到端延迟做对照,不要求采样率必须恰好为刷新率两倍。
Input 调试信息
1 | adb shell dumpsys input |
这个命令输出比较多,我截取了 Device、InputReader 和 InputDispatcher 三段来看。以下保留当时的设备快照。字段和格式以设备版本为准;它不是整段交互的连续记录。unknown、空字段与大整数哨兵应按其含义解释。
Device 信息
设备路径、Descriptor、vendor/product 和映射文件属于这份快照,event6 不是所有手机固定的触摸节点,也不能仅凭这些示例值判定厂商。
1 | 3: main_touch |
Input Reader 状态
Raw 与 Cooked 坐标分开:例中 raw (660, 1338) 转为 cooked (659.389, 1337.401),反映映射/校准后的结果。PhysicalWidth 这里明确是 px,不是毫米;unknown range 不等于零范围。External Stylus 的 9223372036854775807 是该旧状态中的无有效截止时间等哨兵,不能当成真实输入时刻。
1 | Device 3: main_touch |
InputDispatcher 状态
重点区分 FocusedApplication 与 FocusedWindow、各显示的触摸目标、窗口列表、monitor 通道与连接。MonitoringChannels 不是每个 Window 的普通输入通道清单;下面也只是摘录。DispatchFrozen 是分发状态,不是后来的 cached-app freezer 状态。
1 | Input Dispatcher State: |
这份输出有 3 个 MOVE 等待项,age 为从事件时间到 dump 时刻的差,wait 为从该条目的 deliveryTime 到 dump 时刻的差;都不是画面响应总耗时。5000.000ms 是这里报告的分发超时设置,不是所有设备、所有 ANR 类型的统一规则。官方输入分发 ANR 说明给出的默认值为 5 秒,也讨论无焦点窗口等场景;判断时需关联超时日志、目标窗口和阻塞原因,不能把 3 个待确认事件直接叫 ANR。
新版本中怎么继续查
AOSP Android 16 的 InputDispatcher已有 Perfetto 输入事件追踪后端,但该标签明确要求 userdebug/eng 构建并开启相应 feature flag。不能承诺普通 user 设备只开一个开关就有 android.input.inputevent 数据。
支持并采到相关 ATrace 时,Perfetto 的 android.input 模块可进一步拆分发送、接收、处理和 ACK 往返;结构化 android.input.inputevent 则有独立数据来源和字段。两者不能混为一套必定存在的数据。输入到帧的关联还可能缺失或属于推测,ACK 往返不是物理触摸到屏幕的完整时间;缺数据记为不可用,不能当零延迟。
参考
本文部分图文参考和拷贝自下面几篇文章,同时下面几篇文章讲解了 Input 流程的细节部分,推荐大家在看完这篇文章后,如果对代码细节感兴趣,可以仔细研读下面这几篇非常棒的文章。
- http://gityuan.com/2016/12/11/input-reader/
- http://gityuan.com/2016/12/10/input-manager/
- http://gityuan.com/2016/12/17/input-dispatcher/
- https://zhuanlan.zhihu.com/p/29386642
附件
附件目录包含 trace_input_blog_launcher_scroll.html.zip 和 trace_input_blog_list_jank.html.zip,分别是桌面滑动与列表卡顿案例;解压后为带旧查看器的 HTML。本次确认两份文件可读取,内部包含 process dump 与 ftrace 数据,且目标进程不同。旧 HTML 查看器在当前浏览器的兼容性没有在本次复核中验证;也可用支持旧 Systrace 数据的工具导入并核对事件。
点此链接下载文章所涉及到的 Systrace 附件
本文其他地址
由于博客留言交流不方便,点赞或者交流,可以移步本文的知乎或者掘金页面
掘金 - Systrace 基础知识 - Input 解读
关于我 && 博客
下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!
- 博主个人介绍 :里面有个人的微信和微信群链接。
- 本博客内容导航 :个人博客内容的一个导航。
- 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
- Android性能优化知识星球:付费社群已于 2026 年停止运营,不再招收新成员;此处保留历史介绍。
一个人可以走的更快 , 一群人可以走的更远
