21、Binder 的调试与优化:使用 dumpsys、binder_stats、binder_trace 进行问题定位

Binder 这玩意儿,平时跑得好好的,一出问题就让人头大。死锁、卡顿、服务挂掉……我见过太多同事对着 logcat 发呆,半天找不到根因。

其实,Android 系统早就给我们准备了三把利器:dumpsysbinder_statsbinder_trace。用好它们,Binder 问题基本无处遁形。

今天我就把这几个工具怎么用、怎么看、怎么定位问题,一次性讲清楚。

一、dumpsys:Binder 的“体检报告”

dumpsys 是 Android 系统最强大的诊断命令之一。我个人习惯,遇到 Binder 相关异常,第一件事就是跑 dumpsys binder

1.1 查看 Binder 节点状态

adb shell dumpsys binder --binder

这条命令会输出当前系统中所有 Binder 节点的信息。包括:

  • 每个 Binder 实体的引用计数
  • 本地和远程的强/弱引用数量
  • 死亡通知的注册情况

我在项目中遇到过一个问题:某个服务频繁崩溃,但 log 里没有任何异常。跑了一遍 dumpsys binder,发现某个 Binder 节点的引用计数异常高——有个模块忘记释放引用,导致服务无法正常销毁。

关键字段解读:
refs:当前引用数
deathRecipients:注册的死亡通知数
localBinder:本地 Binder 对象地址

1.2 查看 Binder 线程池

adb shell dumpsys binder --threads

Binder 线程池默认有 16 个线程。如果所有线程都被占满,新的 Binder 调用就会阻塞。

我曾经排查过一个 ANR 问题,用这条命令发现 16 个线程全部处于 waiting 状态——都在等同一个锁。说白了,就是死锁了。

线程状态 含义
WAITING 线程空闲,等待任务
RUNNING 正在处理 Binder 调用
BLOCKED 被锁阻塞,可能死锁

二、binder_stats:Binder 调用的“流量监控”

binder_stats/proc/binder/stats 里。它能告诉你每个进程的 Binder 调用情况。

2.1 查看进程级统计

adb shell cat /proc/binder/stats

输出内容大致如下:

proc 1234
  threads: 8
  requested threads: 0
  ready threads: 8
  free async space: 524288
  transactions: 1024
  pending: 0

这里我最关注两个指标:

  • transactions:该进程发起的 Binder 事务总数。如果增长过快,说明有频繁的跨进程调用。
  • pending:等待处理的事务数。如果这个值持续不为 0,说明处理速度跟不上请求速度。
我的经验: 如果 pending 值持续增长,大概率是 Binder 线程池不够用,或者目标服务处理太慢。可以适当调大线程池,或者优化服务端的处理逻辑。

2.2 查看事务类型分布

adb shell cat /proc/binder/transactions

这个文件会列出当前所有未完成的 Binder 事务。包括:

  • 事务的发起方和接收方
  • 事务的代码(code)
  • 事务的状态(active/complete)

嗯,这里要注意:如果某个事务长时间处于 active 状态,那基本可以断定它卡住了。

三、binder_trace:Binder 的“黑匣子”

binder_trace 是内核提供的 Binder 事件追踪机制。它能记录每一次 Binder 调用的完整生命周期。

3.1 开启 Binder 追踪

adb shell echo 1 > /sys/kernel/debug/tracing/events/binder/enable
adb shell cat /sys/kernel/debug/tracing/trace_pipe

这样就能实时看到 Binder 调用的日志了。每条日志包含:

  • 事务 ID
  • 发起进程和线程
  • 目标进程和线程
  • 事务的 code 和 flags
  • 耗时(从发起到底层驱动处理完成)

3.2 分析典型问题

举个例子。我曾经遇到一个 ANR,log 里只看到 Waiting for binder transaction。开启 binder_trace 后,发现某个事务的耗时高达 5 秒——目标进程在做一个耗时的文件操作,把 Binder 线程给堵死了。

注意: binder_trace 会产生大量日志,生产环境慎用。建议只在调试阶段开启,用完立刻关闭。

四、核心知识体系

下面这张图,是我总结的 Binder 调试三板斧。你想想看,遇到问题先对号入座,能省不少时间。

Binder 调试三板斧 dumpsys binder_stats binder_trace 查看节点状态 线程池使用情况 引用计数分析 事务统计 进程级流量监控 pending 事务分析 事务生命周期追踪 耗时分析 死锁定位 适用场景:ANR、服务挂死、跨进程通信卡顿、引用泄漏 推荐排查顺序 dumpsys(快速体检)→ binder_stats(定位进程)→ binder_trace(深挖根因)

五、实战:一个完整的排查案例

我记得有一次,系统服务 SurfaceFlinger 频繁 ANR。log 里只有一句:

W/ActivityManager: ANR in com.android.systemui (SurfaceFlinger)
  Reason: Waiting for binder transaction

我按顺序排查:

  1. dumpsys binder --threads:发现 SurfaceFlinger 的 16 个 Binder 线程全部 WAITING。
  2. cat /proc/binder/transactions:发现有一个事务处于 active 状态,已经持续了 3 秒。
  3. 开启 binder_trace:看到这个事务的目标进程是某个第三方应用,code 是 TRANSACTION_SCREENSHOT

真相大白:那个第三方应用在截图时,做了大量的 Bitmap 处理,占用了 Binder 线程不放。SurfaceFlinger 想发新事务,只能排队等着。

解决方案: 在应用层,把耗时操作放到工作线程,不要占用 Binder 线程。在系统层,可以适当增加 Binder 线程池大小。

六、避坑指南

我曾经踩过几个坑,分享给你:

  • 不要只看 logcat:Binder 问题很多时候 logcat 里只有一句“Waiting for binder transaction”,根本看不出根因。必须结合内核层的工具。
  • binder_trace 别开太久:它会产生大量日志,容易把磁盘写满。我一般只开 10 秒,抓到关键信息就关。
  • 注意权限:有些设备需要 root 才能访问 /proc/binder/ 下的文件。没有 root 的话,可以用 dumpsys 替代部分功能。

好了,Binder 调试三板斧就讲到这里。下次遇到 Binder 问题,别慌,按这个流程走一遍,基本都能找到根因。

公众号:蓝海资料掘金营,微信deep3321