Skip to content

dumpsys分析Binder

追踪 dumpsys 从 ServiceManager 枚举、DUMP_TRANSACTION、输出管道到 ActivityManager service 子命令的完整源码路径。

基于android-17.0.0_r1
AndroidBinderdumpsys调试

dumpsys分析Binder ​

dumpsys 的输出链跨越命令解析、ServiceManager 查询、Binder dump transaction、pipe 转发和服务端 dump 分派。超时可能发生在服务响应或 pipe 消费阶段,不能只看命令返回码。

本文承接 debugfs Binder节点 和 binder_transaction_log。dumpsys 展示的是服务主动实现的 dump 内容;debugfs 展示的是 Binder 驱动对象和事务状态。本文追踪 dumpsys activity service 从命令行参数、ServiceManager 查询、DUMP_TRANSACTION、fd 管道到 ActivityManagerService 的二次分派,说明输出卡住时应该检查哪一层。

1. 参数分流 ​

源码文件:frameworks/native/cmds/dumpsys/dumpsys.cpp

命令行第一个非选项参数进入 services,其余参数进入 args。因此 dumpsys activity service <name> 中,activity 是 ServiceManager 注册名,service <name> 原样传给 ActivityManagerService。没有指定服务时才调用 listServices 枚举全部服务,并按 dump priority/proto 过滤。

2. 服务发现 ​

源码文件:frameworks/native/cmds/dumpsys/dumpsys.cpp

默认使用 checkService,服务未启动就返回 NAME_NOT_FOUND;启用 wait 选项才使用 waitForService。列举模式调用 IServiceManager::listServices(priorityFlags),排序后逐项 dump。ServiceManager 只提供 Binder 引用和注册元数据,不生成目标服务的正文。

3. 输出管道 ​

startDumpThread 创建 pipe:本进程保留 read end,dump 线程持有 write end。单独线程调用服务是因为 IBinder::dump 同步阻塞;主线程可以 poll read end、转发到 stdout 并执行超时控制。

源码文件:frameworks/native/cmds/dumpsys/dumpsys.cpp

cpp
int sfd[2];
pipe(sfd);
redirectFd_ = unique_fd(sfd[0]);
unique_fd remote_end(sfd[1]);
activeThread_ = std::thread([service, args, remote_end = std::move(remote_end)]() mutable {
    service->dump(remote_end.get(), args);
});

服务写入的是 pipe fd,不是把整个 dump 文本放进 Binder reply Parcel,所以大输出不受 transaction buffer 的 1 MiB payload 限制。

4. DUMP事务 ​

源码文件:frameworks/native/libs/binder/BpBinder.cpp

cpp
status_t BpBinder::dump(int fd, const Vector<String16>& args) {
    Parcel send, reply;
    send.writeFileDescriptor(fd);
    send.writeInt32(args.size());
    for (const auto& arg : args) send.writeString16(arg);
    return transact(DUMP_TRANSACTION, send, &reply);
}

Binder 事务只携带输出 fd、参数数量和字符串。驱动把 fd translation 到服务进程;服务端写 fd 时,数据经 pipe 返回 dumpsys 进程。DUMP_TRANSACTION 本身仍是同步事务,服务 dump 卡住会占用一个 Binder 服务线程。

5. 服务端入口 ​

源码文件:frameworks/native/libs/binder/Binder.cpp

BBinder::onTransact 收到 DUMP_TRANSACTION 后读取 fd/argc/args,调用虚函数 dump(fd, args)。Java Binder 也通过 JNI 进入服务的 dump(FileDescriptor, PrintWriter, String[])。未覆写 Native dump 的默认实现直接返回 NO_ERROR,可能产生空输出但不表示服务不存在。

6. Activity分派 ​

源码文件:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

AMS 的 dump parser 读取第一个子命令。遇到 service 时,继续读取可选 service name 和剩余参数,构造 user 过滤条件,再调用:

java
mServices.dumpService(fd, pw, name, users, newArgs, 0, dumpAll)

因此 dumpsys activity service 先 dump activity Binder 服务,再由 AMS 查询它管理的运行中 Android Service;它不是让 ServiceManager 直接查业务 service name。

7. 超时处理 ​

writeDump poll pipe read end直到 EOF、错误或 timeout。超时时打印 SERVICE ... DUMP TIMEOUT,关闭 read end,并 detach 仍在运行的 dump 线程;成功才 join。关闭 dumpsys 读端不能强制终止远端服务的 dump 方法,服务线程可能继续运行并在写 pipe 时遇到错误。

8. 辅助信息 ​

dumpsys 还能请求 PID、stability、thread usage 和 client PIDs。client PID 查询通过 remote binder handle、service PID 和 Binder debug context 反查;本地 Binder 没有远端 handle 时明确返回不可用。这些辅助信息是元数据,不等同于服务自定义 dump。

9. 权限边界 ​

目标服务的 Java dump 通常检查 android.permission.DUMP、caller UID 或 shell/root;Binder fd translation 还受 SELinux file transfer。命令能找到服务但输出 permission denial,说明发现链成功、服务端授权失败;Can't find service 则发生在 ServiceManager 查询之前。

10. 测试边界 ​

源码文件:frameworks/native/cmds/dumpsys/tests/dumpsys_test.cpp

测试 mock listServices/checkService,让 Binder mock 向传入 fd 写文本,验证参数透传和 stdout 输出;ExpectDumpAndHang 模拟远端 dump 阻塞,覆盖 timeout 行为。它验证 dumpsys 的管道/超时 owner,不验证 AMS 某个业务 service 的 dump 内容。

11. 故障定位 ​

  • Can't find service: activity:ServiceManager 注册/启动问题。
  • 找到 activity 但 No services match:AMS ActiveServices 查询条件不匹配。
  • timeout:服务 Binder 线程卡在 dump、锁或下游同步调用;联读线程栈和 debugfs transactions。
  • 输出截断/pipe 错误:dumpsys 超时关闭 read end或服务提前关闭 fd。
  • permission denial:检查 DUMP 权限、caller UID 和 SELinux fd transfer。

12. 阅读检查 ​

从 dumpsys activity service foo 画出参数在 dumpsys、BpBinder、BBinder/Java Binder、AMS 和 ActiveServices 五层的形态。再分别解释“找不到 activity”“找不到 foo”“dump timeout”发生在哪个 owner,并列出下一处应联读的源码或日志。