探秘Android系統(tǒng):dumpsys命令獲取系統(tǒng)服務(wù)詳細信息
dumpsys是Android系統(tǒng)中的一個可執(zhí)行文件,主要作用是將當前Android系統(tǒng)的一些信息dump出來,例如Activity、package等。是一個分析Android設(shè)備問題、查看運行狀態(tài)、使用情況等十分有效的工具。可以獲取各種系統(tǒng)信息和狀態(tài),如進程的PSS值,分析了解進程對RAM的占用情況。
dumpsys的語法提供了靈活的方式來獲取和分析Android系統(tǒng)中各種服務(wù)的信息。基本語法結(jié)構(gòu)如下:
adb shell dumpsys [-t timeout] [--help | -l | --skipservices | service[arguments] | -c | -h]
- [-t timeout]:可選參數(shù),用于指定命令執(zhí)行的超時時間(以秒為單位)。默認為10秒。
- [--help | -l | --skipservices | service[arguments] | -c | -h]:命令行選項,用于定制dumpsys的輸出和行為。
--help:打印dumpsys的使用方法說明。
-l:列出dumpsys支持的所有系統(tǒng)服務(wù)列表。
--skipservices:指定不需要打印的服務(wù)列表。
service[arguments]:指定要查詢的特定服務(wù)及其可選參數(shù)。通過指定服務(wù)名稱,可以獲取特定服務(wù)的詳細信息。
-c:以機器友好的格式(通常是鍵值對)輸出信息,對于自動化腳本解析可能很有用,對于人類閱讀可能不太友好。
-h:用在指定的服務(wù)后面,打印服務(wù)支持哪些參數(shù)或如何使用該服務(wù)。
% adb shell dumpsys -l
Currently running services:
DisplayFeatureControl
DockObserver
MiuiBackup
MiuiCarService
MiuiInit
MiuiWifiService
ProcessManager
SchedBoostService
SlaveWifiService
SurfaceFlinger
accessibility
account
activity
activity_task
adb
如果dumpsys不加任何參數(shù),會輸出所有系統(tǒng)服務(wù)的詳細信息,輸出的內(nèi)容是非常多的。實際解決具體問題時,我們通常只關(guān)注一些特定系統(tǒng)服務(wù)的輸出,只需要將服務(wù)名作為dumpsys命令的參數(shù),就可以只輸出特定服務(wù)的信息。比如要輸出磁盤使用的統(tǒng)計信息,則可以將diskstats這個系統(tǒng)服務(wù)名作為參數(shù)。
% adb shell dumpsys diskstats
Latency: 1ms [512B Data Write]
Recent Disk Write Speed (kB/s) = 45546
Data-Free: 53243072K / 113006560K total = 47% free
Cache-Free: 53243072K / 113006560K total = 47% free
System-Free: 0K / 5192648K total = 0% free
File-based Encryption: true
App Size: 16656406016
App Data Size: 33915740160
App Cache Size: 2662189568
Photos Size: 77041664
Videos Size: 17559552
Audio Size: 38887424
Downloads Size: 0
System Size: 128000000000
Other Size: 9238536192
工作原理
dumpsys基于Android系統(tǒng)的服務(wù)管理和進程間通信機制。通過調(diào)用Android系統(tǒng)底層的ServiceManager服務(wù),來獲取系統(tǒng)中所有已注冊服務(wù)的信息。ServiceManager是Android系統(tǒng)中的一個核心服務(wù),負責管理系統(tǒng)中的所有服務(wù),提供統(tǒng)一的注冊、發(fā)現(xiàn)和通信機制。
當dumpsys被調(diào)用時,會通過Binder進程間通信(IPC)框架與ServiceManager進行交互。Binder是Android提供的一套進程間相互通信的框架,允許不同的進程之間進行高效的通信和數(shù)據(jù)交換。通過Binder,dumpsys能夠請求ServiceManager提供當前系統(tǒng)中所有已注冊服務(wù)的列表,以及每個服務(wù)的詳細信息。
ServiceManager會響應(yīng)dumpsys的請求,返回系統(tǒng)中所有服務(wù)的狀態(tài)信息。包括服務(wù)的名稱、狀態(tài)、運行時的統(tǒng)計數(shù)據(jù)等。dumpsys接收到這些信息后,會進行解析和整理,并以一種可讀的方式展示。
int main(int argc, char* const argv[])
{
...
// 1. 首先獲取 servicemanager
sp<IServiceManager> sm = defaultServiceManager();
...
// 2. 進行命令行參數(shù)解析
bool showListOnly = false;
if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) {
// 2.1 當參數(shù)僅為 "-l" 時,設(shè)置只羅列出所有的服務(wù)名
showListOnly = true;
}
if ((argc == 1) || showListOnly) {
// 2.2 當不帶任何參數(shù)時,則附加 "-a" 參數(shù),表示輸出所有系統(tǒng)服務(wù)信息
services = sm->listServices();
services.sort(sort_func);
args.add(String16("-a"));
} else {
// 2.3 當帶了一個參數(shù)時,表示僅輸出指定的系統(tǒng)服務(wù)信息
services.add(String16(argv[1]));
for (int i=2; i<argc; i++) {
args.add(String16(argv[i]));
}
}
// 3. 羅列出services這個數(shù)組中的服務(wù)名稱,到這一步為止,都還只是在dumpsys本身的邏輯中轉(zhuǎn)悠
const size_t N = services.size();
if (N > 1) {
aout << "Currently running services:" << endl;
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm->checkService(services[i]);
if (service != NULL) {
aout << " " << services[i] << endl;
}
}
}
if (showListOnly) {
return 0;
}
// 4. 輸出services這個數(shù)組中所包含系統(tǒng)服務(wù)的詳細信息
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm->checkService(services[i]);
if (service != NULL) {
...
// 4.1 調(diào)用service的dump方法,來輸出service的具體信息
int err = service->dump(STDOUT_FILENO, args);
...
}
...
}
return 0;
}
- 獲取servicemanager,所有的系統(tǒng)服務(wù)都會向servicemanager注冊
- 進行命令行參數(shù)解析,根據(jù)參數(shù)的不同設(shè)置后續(xù)的執(zhí)行指令序列
- 簡單的羅列了一下需要輸出的系統(tǒng)服務(wù)名稱
- 調(diào)用具體系統(tǒng)服務(wù)的dump()方法完成系統(tǒng)服務(wù)詳細信息的輸出
以上面adb shell dumpsys diskstats命令為例,最終調(diào)用dump()方法完成輸出:
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
// 1. 權(quán)限檢查
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
// 2. 生成一個大小為512B的臨時文件
byte[] junk = new byte[512];
for (int i = 0; i < junk.length; i++) junk[i] = (byte) i; // Write nonzero bytes
File tmp = new File(Environment.getDataDirectory(), "system/perftest.tmp");
// 3. 將512B的臨時文件寫入磁盤,目的是為了快速的測試寫磁盤的延遲
long before = SystemClock.uptimeMillis();
...
fos = new FileOutputStream(tmp);
fos.write(junk);
...
long after = SystemClock.uptimeMillis();
...
pw.print("Latency: ");
pw.print(after - before);
pw.println("ms [512B Data Write]");
...
// 4. 輸出Data, Cache和System這幾個分區(qū)的磁盤使用信息
reportFreeSpace(Environment.getDataDirectory(), "Data", pw);
reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
reportFreeSpace(new File("/system"), "System", pw);
....
}