Android dumpsys簡(jiǎn)介
一、需求
- 了解dumpsys原理,助于我們進(jìn)一步了解Android系統(tǒng)的設(shè)計(jì)
- 幫助我們分析問(wèn)題,定位系統(tǒng)狀態(tài)
- 設(shè)計(jì)新功能的需要
二、環(huán)境
- 版本:Android 12
- 平臺(tái):SL8541E SPRD
三、相關(guān)概念
3.1 dumpsys
dumpsys 是一種在 Android 設(shè)備上運(yùn)行的工具,可提供有關(guān)系統(tǒng)服務(wù)的信息??梢允褂?Android 調(diào)試橋 (adb) 從命令行調(diào)用 dumpsys,獲取在連接的設(shè)備上運(yùn)行的所有系統(tǒng)服務(wù)的診斷輸出。
3.2 Binder
Binder是Android提供的一套進(jìn)程間相互通信框架。用來(lái)實(shí)現(xiàn)多進(jìn)程間發(fā)送消息,同步和共享內(nèi)存。

3.3 管道
管道是一種IPC通信方式,分為有名管道和無(wú)名管道,無(wú)論是有名管道還是無(wú)名管道其原理都是在內(nèi)核開(kāi)辟一塊緩存空間,這段緩存空間的操作是通過(guò)文件讀寫(xiě)方式進(jìn)行的。
有名管道與無(wú)名管道:
有名管道: 有名管道的通信可以通過(guò)管道名進(jìn)行通信,進(jìn)程間不需要有關(guān)系。
無(wú)名管道: 無(wú)名管道就是匿名管道,匿名管道通信的進(jìn)程必須是父子進(jìn)程。
管道為分半雙工和全雙工:
半雙工: 半雙工管道是單向通信,進(jìn)程1只能向管道寫(xiě)數(shù)據(jù),進(jìn)程2只能從管道讀取數(shù)據(jù)。只有一個(gè)代表讀或者寫(xiě)的FD(文件描述符)。
全雙工: 全雙工管道是雙向通信,有兩個(gè)文件描述符,代表讀和寫(xiě)。

四、dumpsys指令的使用
4.1 dumpsys使用
如下為執(zhí)行"adb shell dumpsys"指令,控制臺(tái)打印的內(nèi)容,其使用如下:
dumpsys執(zhí)行
4.2 dumpsys指令語(yǔ)法
(1)使用 dumpsys 的一般語(yǔ)法如下:
adb shell dumpsys [-t timeout] [--help | -l | --skip services | service [arguments] | -c | -h]
(2)如需獲取所連接設(shè)備的所有系統(tǒng)服務(wù)的診斷輸出,請(qǐng)運(yùn)行 adb shell dumpsys。不過(guò),這樣輸出的信息比您通常想要的信息多得多。若要使輸出更加可控,您可以通過(guò)在命令中添加相應(yīng)服務(wù)來(lái)指定要檢查的服務(wù)。例如,下面的命令會(huì)提供輸入組件(如觸摸屏或內(nèi)置鍵盤(pán))的系統(tǒng)數(shù)據(jù):
adb shell dumpsys input
(3)如需查看可與 dumpsys 配合使用的系統(tǒng)服務(wù)的完整列表,請(qǐng)使用以下命令:
adb shell dumpsys -l
(4)命令行選項(xiàng)如下:
| 選項(xiàng) | 說(shuō)明 |
|---|---|
| -t timeout | 指定超時(shí)期限(秒)。如果未指定,默認(rèn)值為 10 秒。 |
| –help | 輸出 dumpsys 工具的幫助文本。 |
| -l | 輸出可與 dumpsys 配合使用的系統(tǒng)服務(wù)的完整列表。 |
| –skip services | 指定您不希望包含在輸出中的 services。 |
| service [arguments] | 指定您希望輸出的 service。某些服務(wù)可能允許您傳遞可選 arguments。如需了解這些可選參數(shù),請(qǐng)將 -h 選項(xiàng)與服務(wù)一起傳遞:adb shell dumpsys procstats -h |
| -c | 指定某些服務(wù)時(shí),附加此選項(xiàng)能以計(jì)算機(jī)可讀的格式輸出數(shù)據(jù)。 |
| -h | 對(duì)于某些服務(wù),附加此選項(xiàng)可查看該服務(wù)的幫助文本和其他選項(xiàng)。 |
五、詳細(xì)設(shè)計(jì)
5.1 dumpsys流程圖

5.2 dumpsys查看電池信息
5.2.1 dumpsys battery指令

5.2.2 service->dump打印函數(shù)
@frameworks\base\services\core\java\com\android\server\BatteryService.java
private final class BinderService extends Binder {
@Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
if (args.length > 0 && "--proto".equals(args[0])) {
dumpProto(fd);
} else {
dumpInternal(fd, pw, args);
}
}
...
}
private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mLock) {
if (args == null || args.length == 0 || "-a".equals(args[0])) {
pw.println("Current Battery Service state:");
if (mUpdatesStopped) {
pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
}
pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
pw.println(" status: " + mHealthInfo.batteryStatus);
pw.println(" health: " + mHealthInfo.batteryHealth);
pw.println(" present: " + mHealthInfo.batteryPresent);
pw.println(" level: " + mHealthInfo.batteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
pw.println(" voltage: " + mHealthInfo.batteryVoltage);
pw.println(" temperature: " + mHealthInfo.batteryTemperature);
pw.println(" technology: " + mHealthInfo.batteryTechnology);
} else {
Shell shell = new Shell();
shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
}
}
}5.3 dumpsys源碼分析
5.3.1 dumpsys服務(wù)編譯
dumpsys是個(gè)二進(jìn)制可執(zhí)行程序,其通過(guò)bp進(jìn)行編譯,并最終打包到system分區(qū)(system/bin/dumpsys)。
@frameworks\native\cmds\dumpsys\android.bp
cc_binary {
name: "dumpsys",
defaults: ["dumpsys_defaults"],
srcs: [
"main.cpp",
],
}5.3.2 dumpsys入口函數(shù)
我們通過(guò)執(zhí)行adb指令 “adb shell dumpsys”,可以啟動(dòng)dumpsys服務(wù),其對(duì)應(yīng)的入口函數(shù)如下:
@frameworks\native\cmds\dumpsys\main.cpp
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
sp<IServiceManager> sm = defaultServiceManager();//獲取SM對(duì)象
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);//進(jìn)入dumpsys服務(wù)
}這邊比較關(guān)鍵的點(diǎn)是獲取ServiceManager對(duì)象。
大家通過(guò)打印可以發(fā)現(xiàn),dumpsys指令打印的數(shù)據(jù)是java進(jìn)程的dump函數(shù),而dumpsys也是獨(dú)立的一個(gè)進(jìn)程,那么dumpsys進(jìn)程又是怎么和多個(gè)java進(jìn)程通信的呢?沒(méi)錯(cuò),就是通過(guò)ServiceManager對(duì)象。
那么,ServiceManager對(duì)象是什么呢?ServiceManager是Binder IPC通信的管家,本身也是一個(gè)Binder服務(wù),他相當(dāng)于 “DNS服務(wù)器”,內(nèi)部存儲(chǔ)了serviceName與其Binder Service的對(duì)應(yīng)關(guān)系,管理Java層和native層的service,支持addService()、getService()、checkService、listServices()等功能。(Binder機(jī)制此處就不展開(kāi)細(xì)說(shuō))
5.3.3 dumpsys服務(wù)打印
5.3.3.1 dumpsys解析參數(shù)
當(dāng)我們使用dumpsys指令,打印的數(shù)據(jù)太過(guò)冗長(zhǎng),一般會(huì)配合相關(guān)參數(shù)進(jìn)行使用,例如:“dumpsys -l”、“dumpsys -t 100 battery”、“dumpsys --help”,第一步我們會(huì)先解析目標(biāo)參數(shù)。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
...
while (1) {
...
c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);//獲取指令參數(shù)
...
switch (c) {
case 0://長(zhǎng)參數(shù)
if (!strcmp(longOptions[optionIndex].name, "skip")) {//跳過(guò)某些服務(wù)打印
skipServices = true;
} else if (!strcmp(longOptions[optionIndex].name, "proto")) {
asProto = true;
} else if (!strcmp(longOptions[optionIndex].name, "help")) {//指令幫助
usage();
return 0;
} else if (!strcmp(longOptions[optionIndex].name, "priority")) {
...
} else if (!strcmp(longOptions[optionIndex].name, "pid")) {//只顯示服務(wù)的pid
type = Type::PID;
} else if (!strcmp(longOptions[optionIndex].name, "thread")) {//僅顯示進(jìn)程使用情況
type = Type::THREAD;
}
break;
case 't'://超時(shí)時(shí)間設(shè)置,默認(rèn)10秒
...
break;
case 'T'://超時(shí)時(shí)間設(shè)置,默認(rèn)10秒
...
break;
case 'l'://顯示支持的服務(wù)列表
showListOnly = true;
break;
default://其他參數(shù)
fprintf(stderr, "\n");
usage();
return -1;
}
}
...
}5.3.3.2 skippedServices列表構(gòu)造
dumpsys內(nèi)部構(gòu)造了skippedServices集合,用于記錄需要忽略的服務(wù)。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
...
for (int i = optind; i < argc; i++) {
if (skipServices) {
skippedServices.add(String16(argv[i]));//配置待忽略的服務(wù)
} else {
...
}
...
}5.3.3.3 獲取支持服務(wù)列表
dumpsys通過(guò)ServiceManager獲取支持的服務(wù)集合,并排序。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
...
if (services.empty() || showListOnly) {
services = listServices(priorityFlags, asProto);
setServiceArgs(args, asProto, priorityFlags);
}
...
}
Vector<String16> Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {
Vector<String16> services = sm_->listServices(priorityFilterFlags);//通過(guò)sm獲取服務(wù)集合
services.sort(sort_func);//集合排序
...
return services;
}5.3.3.4 打印支持服務(wù)列表
在獲取了服務(wù)集合后,會(huì)先檢查服務(wù)是否存在,接著打印服務(wù)的名稱,且如果當(dāng)前指令設(shè)置了"-l"參數(shù),僅打印服務(wù)集合,即流程結(jié)束。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
...
const size_t N = services.size();//獲取支持的服務(wù)個(gè)數(shù)
if (N > 1 || showListOnly) {
// first print a list of the current services
std::cout << "Currently running services:" << std::endl;
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm_->checkService(services[i]);//檢查服務(wù)狀態(tài)
if (service != nullptr) {
bool skipped = IsSkipped(skippedServices, services[i]);
std::cout << " " << services[i] << (skipped ? " (skipped)" : "") << std::endl;//打印服務(wù)名稱
}
}
}
if (showListOnly) {//如果指令僅需要打印服務(wù)集合,則結(jié)束。
return 0;
}
...
}5.3.3.5 打印目標(biāo)服務(wù)
先遍歷所有需要打印的服務(wù),如果參數(shù)有指定服務(wù)名,即N為對(duì)應(yīng)服務(wù)的數(shù)量,否則N為所有支持的服務(wù)數(shù)量。接著,開(kāi)啟線程,通過(guò)servicemanager調(diào)用遠(yuǎn)端的dump函數(shù),利用管道和poll機(jī)制監(jiān)聽(tīng)遠(yuǎn)端數(shù)據(jù)。最后如果超時(shí)或者dump結(jié)束,則關(guān)閉線程,釋放相關(guān)資源。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
...
for (size_t i = 0; i < N; i++) {
const String16& serviceName = services[i];
if (IsSkipped(skippedServices, serviceName)) continue;//跳過(guò)部分服務(wù)
if (startDumpThread(type, serviceName, args) == OK) {//step 1.創(chuàng)建dump打印的線程
...
std::chrono::duration<double> elapsedDuration;
size_t bytesWritten = 0;
status_t status =
writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs),
asProto, elapsedDuration, bytesWritten);//step 2.dump執(zhí)行打印操作
if (status == TIMED_OUT) {//打印超時(shí)
std::cout << std::endl
<< "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
<< "ms) EXPIRED ***" << std::endl
<< std::endl;
}
...
bool dumpComplete = (status == OK);
stopDumpThread(dumpComplete);//step 3.結(jié)束dump打印線程
}
}
...
}step 1. 創(chuàng)建dumpsys打印線程
創(chuàng)建了一條管道,接著開(kāi)啟了一個(gè)線程,通過(guò)ServiceManager對(duì)象讀取目標(biāo)服務(wù)的dump函數(shù),即dump打印數(shù)據(jù)。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);//通過(guò)SM獲取service對(duì)象
int sfd[2];
if (pipe(sfd) != 0) {//創(chuàng)建管道,用于讀取service端數(shù)據(jù)
...
}
...
redirectFd_ = unique_fd(sfd[0]);
unique_fd remote_end(sfd[1]);
sfd[0] = sfd[1] = -1;
// dump blocks until completion, so spawn a thread..
activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {//創(chuàng)建線程
status_t err = 0;
switch (type) {
case Type::DUMP:
err = service->dump(remote_end.get(), args);//調(diào)用dump函數(shù)
break;
...
}
...
});
return OK;
}step 2. dumpsys打印到終端
通過(guò)poll機(jī)制用來(lái)監(jiān)聽(tīng)管道的數(shù)據(jù),并將讀取到的dump數(shù)據(jù),打印至控制臺(tái)。同時(shí),通過(guò)計(jì)算剩余的時(shí)間,來(lái)判斷當(dāng)前是否讀取超時(shí)。
@frameworks\native\cmds\dumpsys\dumpsys.cpp
status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
bool asProto, std::chrono::duration<double>& elapsedDuration,
size_t& bytesWritten) const {
...
int serviceDumpFd = redirectFd_.get();
struct pollfd pfd = {.fd = serviceDumpFd, .events = POLLIN};
while (true) {
...
int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));//poll機(jī)制檢測(cè)管道數(shù)據(jù)
if (rc < 0) {
...
} else if (rc == 0 || time_left_ms() == 0) {
status = TIMED_OUT;//計(jì)算剩余時(shí)間,來(lái)決定是否超時(shí)
break;
}
char buf[4096];
rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));//讀取遠(yuǎn)端的數(shù)據(jù)
...
if (!WriteFully(fd, buf, rc)) {//打印至控制臺(tái)
...
break;
}
totalBytes += rc;
}
...
return status;
}step 3. 關(guān)閉dumpsys打印線程
將dumpsys打印的線程detach掉,相關(guān)的fd句柄reset掉,釋放資源。
六、dumpsys的應(yīng)用
如后續(xù)有什么應(yīng)用dumpsys,或者有助于日常開(kāi)發(fā)調(diào)試的場(chǎng)景,再補(bǔ)充,未完待續(xù)。
6.1 dumpsys常用指令
| 服務(wù)名 | 類名 | 指令 | 功能 |
|---|---|---|---|
| activity | ActivityManagerService | 獲取某個(gè)應(yīng)用的Activity信息:adb shell dumpsys activity a packagename獲取某個(gè)應(yīng)用的Service信息: adb shell dumpsys activity s packagename獲取某個(gè)應(yīng)用的Broadcast信息: adb shell dumpsys activity b packagename獲取某個(gè)應(yīng)用的Provider信息: adb shell dumpsys activity prov packagename獲取某個(gè)應(yīng)用的進(jìn)程狀態(tài): adb shell dumpsys activity p packagename獲取當(dāng)前界面的Activity信息: adb shell dumpsys activity top | grep ACTIVITY | AMS相關(guān)信息 |
| package | PackageManagerService | adb shell dumpsys package | PMS相關(guān)信息 |
| window | WindowManagerService | adb shell dumpsys window | WMS相關(guān)信息 |
| input | InputManagerService | adb shell dumpsys input | IMS相關(guān)信息 |
| power | PowerManagerService | adb shell dumpsys power | PMS相關(guān)信息 |
| batterystats | BatterystatsService | adb shell dumpsys batterystats | 電池統(tǒng)計(jì)信息 |
| battery | BatteryService | adb shell dumpsys battery | 電池信息 |
| alarm | AlarmManagerService | adb shell dumpsys alarm | 鬧鐘信息 |
| dropbox | DropboxManagerService | adb shell dumpsys dropbox | 調(diào)試相關(guān) |
| procstats | ProcessStatsService | adb shell dumpsys procstats | 進(jìn)程統(tǒng)計(jì) |
| cpuinfo | CpuBinder | adb shell dumpsys cpuinfo | CPU |
| meminfo | MemBinder | adb shell dumpsys meminfo | 內(nèi)存 |
| gfxinfo | GraphicsBinder | adb shell dumpsys gfxinfo | 圖像 |
| dbinfo | DbBinder | adb shell dumpsys dbinfo | 數(shù)據(jù)庫(kù) |
七、參考資料
dumpsys指令介紹:
https://developer.android.google.cn/studio/command-line/dumpsys?hl=zh-cn
管道:
https://www.cnblogs.com/naray/p/15365954.html
Binder:
https://blog.csdn.net/shenxiaolinil/article/details/128972302
到此這篇關(guān)于Android dumpsys簡(jiǎn)介的文章就介紹到這了,更多相關(guān)Android dumpsys內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 類似UC瀏覽器的效果:向上滑動(dòng)地址欄隱藏功能
這篇文章主要介紹了Android 類似UC瀏覽器的效果:向上滑動(dòng)地址欄隱藏功能,需要的朋友可以參考下2017-12-12
兩分鐘讓你徹底明白Android Activity生命周期的詳解(圖文介紹)
本篇文章是對(duì)Android的生命周期進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Android編程之短信竊聽(tīng)器實(shí)現(xiàn)方法
這篇文章主要介紹了Android編程之短信竊聽(tīng)器實(shí)現(xiàn)方法,以實(shí)例形式較為詳細(xì)的分析了Android編程實(shí)現(xiàn)竊聽(tīng)器的具體步驟與實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
android Textview文字監(jiān)控(Textview使用方法)
以手機(jī)號(hào)充值為例,當(dāng)用戶輸入最后一位數(shù)時(shí)候,進(jìn)行匯率的變換,本文就實(shí)現(xiàn)類似這樣的功能2013-11-11
Android Studio做超好玩的拼圖游戲 附送詳細(xì)注釋源碼
這篇文章主要介紹了用Android Studio做的一個(gè)超好玩的拼圖游戲,你是0基礎(chǔ)Android小白也能包你學(xué)會(huì),另外附送超詳細(xì)注釋的源碼,建議收藏!2021-08-08
Android 彩色Toast的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 彩色Toast的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10
android實(shí)現(xiàn)上滑屏幕隱藏底部菜單欄的示例
這篇文章主要介紹了android實(shí)現(xiàn)上滑屏幕隱藏底部菜單欄的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
Android 解決sqlite無(wú)法創(chuàng)建新表的問(wèn)題
這篇文章主要介紹了Android 解決sqlite無(wú)法創(chuàng)建新表的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05

