2. Binder节点监控

任务目标

在运行Android或通用Linux内核(已开启CONFIG_ANDROID_BINDER_IPC与CONFIG_FTRACE)的设备上,通过tracefs/ftrace捕获一次Binder事务从发送端到接收端的完整内核事件流,并据此还原事务的发起进程、目标进程、事务栈与耗时分布。

前置条件

  • 内核版本 ≥ 4.14(推荐5.10+),已挂载tracefs:mount -t tracefs nodev /sys/kernel/tracing(或使用旧路径/sys/kernel/debug/tracing)
  • 确认Binder跟踪点存在:ls /sys/kernel/tracing/events/binder/binder_transaction 应列出该事件目录
  • 设备已root,或当前shell具有tracefs写权限

实现步骤

1. 启用Binder事件跟踪

清空旧跟踪缓冲并启用全部binder事件(共8个跟踪点,覆盖事务生命周期):

# 切换到tracefs目录
cd /sys/kernel/tracing

# 清空历史跟踪
echo > trace

# 启用binder相关全部事件
echo 1 > events/binder/enable

# 设置跟踪缓冲大小为1MB(避免丢失事件)
echo 1024 > buffer_size_kb

# 确认已启用
cat events/binder/enable   # 应输出 1

2. 触发一次Binder事务

在另一个终端执行任意Binder调用(例如启动一个Activity、调用系统服务),或使用以下最小触发命令:

# 触发一次servicemanager查询(任何应用进程都会在启动时执行)
# 若设备空闲,可强制触发:
cmd notification help > /dev/null 2>&1
# 或使用service call命令直接发起一次Binder调用:
service call activity 42 s16 "test" > /dev/null 2>&1

3. 停止跟踪并导出数据

# 停止跟踪
echo 0 > events/binder/enable

# 导出跟踪日志(包含时间戳、进程名、PID、事务数据)
cat trace > /data/local/tmp/binder_trace.txt

4. 分析事务流程

导出的trace中,一次完整事务由以下事件序列构成(按时间顺序):

# 关键事件序列(示例格式,实际内容取决于内核版本)
binder_transaction:      transaction=3049 dest_node=1 dest_proc=system_server dest_thread=... reply=0 flags=0x10 code=0x2a
binder_transaction_received: transaction=3049 proc=system_server thread=...
binder_transaction_alloc_buf: transaction=3049 data_size=128 offsets_size=8
binder_transaction_buffer_release: transaction=3049
binder_transaction_failed: transaction=3049 reply=0 (仅在失败时出现)

使用以下命令提取关键字段:

# 查看所有binder_transaction事件(发起端)
grep "binder_transaction:" binder_trace.txt | head -20

# 查看所有binder_transaction_received事件(接收端)
grep "binder_transaction_received:" binder_trace.txt | head -20

# 按事务ID关联收发两端
grep "transaction=3049" binder_trace.txt

验证方法

满足以下条件即判定跟踪成功:

  1. cat events/binder/enable 输出 1,且trace文件非空
  2. 跟踪日志中同时出现 binder_transaction 与 binder_transaction_received 事件,且两者具有相同的 transaction= ID
  3. 能从日志中识别出发起进程(事件前的进程名/PID)与目标进程(dest_proc=字段)
  4. 若调用成功,日志中不会出现 binder_transaction_failed 事件

常见问题

  • events/binder目录不存在:内核未开启CONFIG_ANDROID_BINDER_IPC或CONFIG_FTRACE,需重新编译内核
  • 跟踪无输出:确认触发命令确实执行了Binder调用(可用service list验证servicemanager响应);部分设备需设置echo 0 > options/overwrite防止缓冲覆盖
  • 事务ID不匹配:高并发下多个事务交错,按transaction=字段过滤即可,不影响单次事务分析

可视化:Binder事务跟踪事件流

Binder事务跟踪事件流(ftrace捕获) t 客户端 (Client Proc) 服务端 (Server Proc) 1 binder_transaction transaction=3049 dest_proc=system_server 4 binder_transaction_buffer_release transaction=3049 2 binder_transaction_received transaction=3049 proc=system_server 3 binder_transaction_alloc_buf transaction=3049 data_size=128 binder驱动转发 buffer释放通知 t0: 发起调用 t1: 驱动接收 t2: 服务端处理 t3: 释放完成 客户端事件 服务端事件 binder驱动通信

上图展示了通过ftrace捕获的Binder事务事件序列。实际分析时,使用grep "transaction=3049"即可将同一事务的四个事件关联起来,形成完整调用链。若在binder_transaction与binder_transaction_received之间出现binder_transaction_failed,则说明驱动层拒绝了该事务(常见原因为权限不足或节点不存在)。