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
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
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 过滤条件,再调用:
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,并列出下一处应联读的源码或日志。
