前言:看AMS和WMS的相關(guān)狀態(tài),這個(gè)命令十分有用,不止是這兩個(gè)服務(wù),其他系統(tǒng)級別的服務(wù)均能用該命令去dump出來重要信息,而且我們自己實(shí)現(xiàn)的服務(wù),只要添加到了ServiceManager中可查詢到,而且復(fù)寫了Binder的dump()函數(shù),均可以像源碼一樣dump出來我們想要的信息,所以對這套流程很有興趣,因此看了dumpsys的代碼實(shí)現(xiàn)流程,記錄下來。
? 1.dumpsys的用法
? ? 簡單說一下dumpsys的用法,就是用來dump系統(tǒng)級別的service的某個(gè)時(shí)刻的關(guān)鍵信息,幫助我們debug用的,可以先使用命令:dumpsys -l,去查詢我們能去dump的所有服務(wù),這里以AMS為例子,它在ServiceManager中的名字為activity,所以使用dumpsys activity便可,同理,其他service的dump方法也是一樣的。由于某些service的信息量比較龐大,比如AMS的信息量就極其龐大,所以我們可以narrow down一下查詢信息,比如用dumpsys activity a或者dumpsys activity activities,去查詢所有activity的信息,而忽略諸如廣播注冊等信息,這樣可以幫助我們只關(guān)注我們想要的信息。
? 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進(jìn)程起來的時(shí)候是在開機(jī)流程中,init進(jìn)程里面實(shí)例化的。命令的處理主要邏輯在frameworks/native/cmds/dumpsys/dumpsys.cpp里的main()函數(shù)當(dāng)中,截取其中的重要部分:
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);
}
}
? ? 主要是啟動一個(gè)線程去執(zhí)行某個(gè)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;
}
? 在新起的線程中,執(zhí)行某個(gè)service的dump函數(shù),如此我們就只要看某個(gè)service的dump函數(shù)實(shí)現(xiàn)就好了,注意我們這些處理邏輯目前都是在native層,但是我們知道安卓是建立在Binder通信的CS架構(gòu),該dump()函數(shù)的聲明是在Binder類中的,也就是我們需要找到服務(wù)端的dump()函數(shù)的真正實(shí)現(xiàn)哪里,如果是dumpsys activity a,那么真正實(shí)現(xiàn)是在java層的ActivityManagerService中,其他服務(wù)同理,當(dāng)然在native層實(shí)現(xiàn)該dump()函數(shù)也是ok的,這個(gè)并不重要。以dumpsys activity a為例,到目前為止,我們已經(jīng)解析完了dumpsys activity的含義,就是調(diào)用AMS的dump()函數(shù),那么后面的參數(shù) a 呢?答案需要在AMS的dump函數(shù)中找:
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
?? PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
? 最終會調(diào)用到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);
? ? ? ? ?? }
? 該函數(shù)還會解析其他的參數(shù),具體可在該函數(shù)中看,或者使用dumpsys activity -h可以查詢到所有支持的參數(shù)以及它們的含義,dumpsys activity a的全部含義就是調(diào)用到ActivityTaskManagerService的dump函數(shù),它會遍歷內(nèi)部結(jié)構(gòu),把重要信息全部輸出到console上,具體可見ATMS的dumpActivitiesLocked()函數(shù)是如何把信息全部打印出來的。
? 至此,主要代碼流程就走完了,dumpsys的其他命令也是走的一樣的流程,我們可以在此基礎(chǔ)上加入自己的邏輯,使其能dump出來我們需要的信息,注意不要跟現(xiàn)有的命令參數(shù)同名就好。