如何通过 Systrace 图表识别出由 Binder 调用引起的延迟?
解读
国内面试中,Systrace 是验证“真做过性能优化”的试金石。Binder 作为 Android 最高频的 IPC 通道,一旦阻塞会直接拉长应用主线程的“一帧”耗时,导致 16 ms 红线被击穿。面试官想确认两点:
- 你能否在一张混杂着 CPU、SurfaceFlinger、system_server 的 Systrace 里一眼定位 Binder;
- 你能否把 Binder 延迟与上层卡顿因果链串起来,而不是只报“Binder 很耗时”。
因此回答要体现“找得到、说得清、改得了”。
知识点
- Binder 在 kernel 层的 trace 事件:
binder_transaction(发起端)、binder_transaction_received(接收端)、binder_command/binder_return(ioctl 进出)。 - atrace 用户态标签:
binder_driver(kernel)、binder_lock(阻塞点)、aidl/hwbinder(Framework 层)。 - 主线程被“epoll”或
binder_thread_read挂起时,sched 切片颜色为浅绿(Sleep),唤醒点标注binder_reply。 - 关键指标:
① 端到端 latency =binder_transaction_received时间戳 −binder_transaction时间戳;
② 排队等待时间 =binder_transaction到目标进程被唤醒的间隔;
③ 单次 ioctl 耗时 > 500 µs 即需警惕,> 2 ms 可判定为异常。 - 国内 ROM 常开
atrace_categories = "binder_driver,am,view,sched,irq,workq",抓 trace 前先adb shell setprop debug.atrace.tags.enableflags 0x1BF,否则 Binder 事件可能被裁剪。 - 与 GC、锁竞争区分:GC 的线程状态为“WaitingForGCToComplete”,锁竞争为“monitor contention”,而 Binder 一定伴随
binder_transaction事件。
答案
步骤化给出面试官想听的“现场破案”过程:
-
复现与抓图
在出现卡顿的用例上执行
adb shell atrace --async_start -b 32768 binder_driver am view sched gfx
操作完成后
atrace --async_stop -o /data/local/tmp/binder_delay.trace
拖回 PC 用perfetto.dev或Android Studio CPU Profiler打开。 -
快速定位主线程掉帧
在“Frames”轨道找到红色掉帧帧号,记其 VSYNC 时间戳区间 [t0, t0+16.6 ms]。 -
搜索 Binder 事件
在 kernel 轨道过滤binder_transaction,若发现主线程在 [t0, t0+16.6 ms] 内发出binder_transaction但对应的binder_transaction_received落在 t0+10 ms 之后,即可怀疑 Binder 延迟。 -
确认阻塞侧
查看目标进程(通常是 system_server 或 mediaserver)在同一 transaction ID 上的binder_transaction_received是否延迟,若目标进程在排队(binder_work堆积)或线程池耗尽(binder_thread_read无空闲线程),则排队时间为“元凶”。 -
量化耗时
用 Perfetto SQL:SELECT slice.name, slice.ts, slice.dur FROM slice WHERE slice.name LIKE 'binder_transaction%' AND slice.ts BETWEEN <t0> AND <t0+16600000>;计算 dur 列,若 > 2 ms 即异常。
-
给出调优方向
① 业务侧:把阻塞型 Binder 调用(如 PKMS 查权限、SettingsProvider 读配置)挪到异步线程或缓存结果;
② 系统侧:若排队严重,可建议厂商调高ro.config.binder_thread_count(默认 15→31)或把热点 aidl 接口改为oneway;
③ 监控侧:线上用bionic_malloc_dispatch+libbinder插桩,把 > 1 ms 的 transaction 采样上报,结合 traceId 还原现场。
一句话总结:在 Systrace 里先框定掉帧区间,再按 binder_transaction→binder_transaction_received 的时间差找异常 transaction,最后看对端进程是否排队或线程池耗尽,即可坐实 Binder 引起的延迟。
拓展思考
- 国内厂商对 Binder 驱动做过深度定制(如小米“MiBinder”、华为“LiteIPC”),trace 事件名可能带厂商前缀,抓图前需
grep binder /sys/kernel/debug/tracing/available_events确认实际关键字。 - Android 14 引入
libbinder_debug.so,支持把 transaction 调用栈直接打进 trace,可在adb shell setprop debug.binder.callstack 1后抓到 Java/Kotlin 层业务方法,直接关联到业务代码,无需再靠人工对照 pid/tid。 - 对端进程是 Native 服务时,需同时打开
hal与gfx标签,才能把HIDL::IMapper::getBuffer这类 hwbinder 延迟与上层掉帧串联,避免“只看到 system_server 很忙却找不到源头”。 - 线上若无法抓 Systrace,可用
bpftrace一行脚本采样 kernelbinder_transaction耗时,回传后离线对照mapping.txt还原 aidl 接口,实现“无 trace 也能定性”。