前言:看AMS和WMS的相关状态,这个命令十分有用,不止是这两个服务,其他系统级别的服务均能用该命令去dump出来重要信息,而且我们自己实现的服务,只要添加到了ServiceManager中可查询到,而且复写了Binder的dump()函数,均可以像源码一样dump出来我们想要的信息,所以对这套流程很有兴趣,因此看了dumpsys的代码实现流程,记录下来。
1.dumpsys的用法
简单说一下dumpsys的用法,就是用来dump系统级别的service的某个时刻的关键信息,帮助我们debug用的,可以先使用命令:dumpsys -l,去查询我们能去dump的所有服务,这里以AMS为例子,它在ServiceManager中的名字为activity,所以使用dumpsys activity便可,同理,其他service的dump方法也是一样的。由于某些service的信息量比较庞大,比如AMS的信息量就极其庞大,所以我们可以narrow down一下查询信息,比如用dumpsys activity a或者dumpsys activity activities,去查询所有activity的信息,而忽略诸如广播注册等信息,这样可以帮助我们只关注我们想要的信息。
2.代码逻辑
我们以dumpsys activity a这句命令为例去了解流程。frameworks/native/cmds/dumpsys/main.cpp,该目录是framework处理dumpsys命令的入口:
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if (sm == nullptr) {
ALOGE("Unable to get default service manager!");
std::cerr << "dumpsys: Unable to get default service manager!" << std::endl;
return 20;
}
Dumpsys dumpsys(sm.get());
return dumpsys.main(argc, argv);
}
如果ServiceManager还没起来,无法处理命令,所以需要判空,SM进程起来的时候是在开机流程中,init进程里面实例化的。命令的处理主要逻辑在frameworks/native/cmds/dumpsys/dumpsys.cpp里的main()函数当中,截取其中的重要部分:
int Dumpsys::main(int argc, char* const argv[]) {
if (startDumpThread(type, serviceName, args) == OK) {
bool addSeparator = (N > 1);
if (addSeparator) {
writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
}
std::chrono::duration<double> elapsedDuration;
size_t bytesWritten = 0;
status_t status =
writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs),
asProto, elapsedDuration, bytesWritten);
if (status == TIMED_OUT) {
std::cout << std::endl
<< "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
<< "ms) EXPIRED ***" << std::endl
<< std::endl;
}
if (addSeparator) {
writeDumpFooter(STDOUT_FILENO, serviceName, elapsedDuration);
}
bool dumpComplete = (status == OK);
stopDumpThread(dumpComplete);
}
}
主要是启动一个线程去执行某个service的dump的具体命令:
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
// dump blocks until completion, so spawn a thread..
activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
status_t err = 0;
switch (type) {
case Type::DUMP:
err = service->dump(remote_end.get(), args);
break;
});
return OK;
}
在新起的线程中,执行某个service的dump函数,如此我们就只要看某个service的dump函数实现就好了,注意我们这些处理逻辑目前都是在native层,但是我们知道安卓是建立在Binder通信的CS架构,该dump()函数的声明是在Binder类中的,也就是我们需要找到服务端的dump()函数的真正实现哪里,如果是dumpsys activity a,那么真正实现是在java层的ActivityManagerService中,其他服务同理,当然在native层实现该dump()函数也是ok的,这个并不重要。以dumpsys activity a为例,到目前为止,我们已经解析完了dumpsys activity的含义,就是调用AMS的dump()函数,那么后面的参数 a 呢?答案需要在AMS的dump函数中找:
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
最终会调用到doDump():
private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
// Is the caller requesting to dump a particular piece of data?
if (opti < args.length) {
String cmd = args[opti];
opti++;
if (DUMP_ACTIVITIES_SHORT_CMD.equals(cmd)) { //DUMP_ACTIVITIES_SHORT_CMD = "a"
mAtmInternal.dump(
cmd, fd, pw, args, opti, true /* dumpAll */, dumpClient, dumpPackage);
}
该函数还会解析其他的参数,具体可在该函数中看,或者使用dumpsys activity -h可以查询到所有支持的参数以及它们的含义,dumpsys activity a的全部含义就是调用到ActivityTaskManagerService的dump函数,它会遍历内部结构,把重要信息全部输出到console上,具体可见ATMS的dumpActivitiesLocked()函数是如何把信息全部打印出来的。
至此,主要代码流程就走完了,dumpsys的其他命令也是走的一样的流程,我们可以在此基础上加入自己的逻辑,使其能dump出来我们需要的信息,注意不要跟现有的命令参数同名就好。