dumpsys diskstats
唯讀每個分割區的剩餘空間、一次磁碟寫入延遲的實測,以及一份快取起來的各 app 空間用量。
- 指令
- adb shell dumpsys diskstats
- 指令
- 系統服務(dumpsys)
- 風險
- 唯讀
語法
dumpsys diskstats範例
dumpsys diskstats服務手上的全部:即時那半與快取那半。
df -k /data對真正重要的那個分割區,再取一次獨立的剩餘空間讀數。
輸出怎麼讀
輸出範例
Latency: 3ms [512B Data Write]
Data-Free: 12345678K / 111222333K total = 11% free
Cache-Free: 1234K / 5678K total = 21% free
App Size: 45678901234
App Data Size: 23456789012
App Cache Size: 3456789012一份輸出裡有兩個互不相干的半邊。即時的那半——寫入延遲與 `*-Free:` 行——每次呼叫都會實測,它的 `K` 後綴是 KiB,換成位元組要乘 1024。另一半來自一個背景工作大約每天更新一次的檔案,儘管別處有個名字很像的欄位容易讓人誤會,這裡的大小是純位元組。如果那個工作從沒跑過,快取的那半會整段不存在。
輸出欄位
| 欄位 | 意義 |
|---|---|
| Latency: Nms [512B Data Write] | 現在往 /data 寫 512 個位元組花了多久。 |
| <partition>-Free: aK / bK total = c% free | 以 KiB 表示的剩餘與總量,加上裝置自己用整數除法算的百分比。 |
| <partition>-Error: … | 那個分割區量不到。輸出的其餘部分仍然有效。 |
| App Size / App Data Size / App Cache Size | 來自快取那半的程式碼、資料與快取總量,單位是位元組。 |
| Package Names / App Sizes / App Data Sizes / Cache Sizes | 四條只靠索引對齊的平行陣列。 |
需要什麼權限
這份輸出要的是兩個權限而不是一個:`DiskStatsService.dump` 一開頭就是 `DumpUtils.checkDumpAndUsageStatsPermission`,它要 `android.permission.DUMP` **加上** `android.permission.PACKAGE_USAGE_STATS` 以及對應的 `android:get_usage_stats` app-op。Shell 兩個都輕鬆通過——它的資訊清單宣告了這兩個權限,而 usage stats 那道檢查在碰到 app-op 之前,就會對 `ROOT_UID`、`SYSTEM_UID`、`SHELL_UID` 與 `INCIDENTD_UID` 直接放行。所以不用 root、不用 `adb root`,尤其不用跑去設定裡的「使用情況存取權」——那正是很多人看到權限名稱之後會去找的東西。這個指令真正需要、而這一頁其他讀取都不需要的,是一個可寫的 `/data`。那個延遲數字不是服務存起來的統計:`dump` 每次都會建立 `/data/system/perftest.tmp`、寫入 512 個非零位元組、關檔再刪掉,並用 `SystemClock.uptimeMillis()` 計時。這讓這一族裡看起來最無害的一份輸出,變成每跑一次就真的碰一次檔案系統的那一份,也是為什麼在忙碌的磁碟後面它會卡住、而 `df` 立刻就回。Android Storage Analyzer 就是因為這樣,每次掃描只送一次而不是掛在計時器上。
失敗訊息對照
| 訊息 | 意義 |
|---|---|
| Test-Error: java.io.IOException: /data/system/perftest.tmp: open failed: EACCES (Permission denied) | 那次 512 位元組的基準寫入失敗了,所以這一行是「取代」`Latency:` 那行,不是出現在它旁邊。輸出的其他部分完全不受影響:剩餘空間的行與快取的各 app 那半照樣接在後面,也照樣可信。不見的只有寫入延遲這個量測。 |
| Data-Error: java.lang.IllegalArgumentException: Invalid stat: bsize=0 avail=0 total=0 | `reportFreeSpace` 對那個分割區 stat 不到,就把例外印在數字該在的位置然後返回——而且只影響那一個分割區。同樣形狀的行也會以 `Cache-Error`、`System-Error` 或 `Metadata-Error` 出現。少了 `Metadata-Free:` 通常是年紀而不是故障:tag android-11.0.0_r1 與 android-12.0.0_r1 完全不回報 metadata 分割區,從 android-13.0.0_r1 起才有。 |
| Recent Disk Write Speed data unavailable | `storaged` 對「最近的寫入速度基準」這個請求回了 0,於是服務印出這行來取代 `Recent Disk Write Speed (kB/s) = …`。它的意思是最近沒有人跑過基準測試,不是磁碟很慢。如果 `storaged` 根本連不上,你在這裡看到的會是自成一行的例外原文。 |
| Permission Denial: can't dump DiskStatsService from from pid=4821, uid=10231 due to missing android.permission.PACKAGE_USAGE_STATS permission | 失敗的是那兩個權限裡的第二個。和每一個 `DumpUtils` 的拒絕一樣,重複的 `from from` 是 AOSP 原文,而且這行寫在**標準輸出**,所以它會落在空間數字本來該在的位置。從 `adb shell` 提示字元下看到它,代表這次呼叫不是來自 uid 2000——檢查一下你是不是在 `run-as` 裡面。 |
版本與廠商注意事項
- 各 app 的數字不是一筆一筆的記錄,而是四條各自獨立的陣列。只要有一條比較短,缺口之後的每一列都會被算到別的 app 身上。所以四條長度不一致時,那張表就沒有價值,該丟掉而不是硬拼起來。
- 這是真的會失敗的輸出之一:它會做一次同步磁碟寫入與一次 binder 往返,所以可能撞上 dumpsys 的逾時,也有版本以權限為由整份拒絕。
- 快取那半最多可能是一天前的。想要當下可信的數字,用 `df` 或 `du`。
這個我們有 UI
Android Storage Analyzer 會透過 USB 執行這個指令並解析回應——只要 Chromium 系瀏覽器,不必安裝 SDK,也不會上傳任何東西。
相關指令
和 dumpsys diskstats 會在同一次作業裡出現的指令。
| 指令 | 做什麼 |
|---|---|
| df | 回報每個已掛載檔案系統的剩餘與已用空間。 |
| du | 回報一棵目錄樹占掉多少磁碟空間。 |
| pm trim-caches | 要求系統一直丟掉快取檔案,直到剩下你指定的空間為止。 |
| find | 走過一棵目錄樹,印出符合條件的東西——大檔案、空資料夾、殘留物。 |
其他系統服務(dumpsys)指令
| 指令 | 做什麼 |
|---|---|
| dumpsys battery | 電池服務目前的狀態:電量、充電狀態、健康度、電壓與溫度。 |
| dumpsys thermalservice | 手機是不是正在因為溫度而降速,以及硬體層回報的每一個溫區,單位是攝氏。 |
| dumpsys sensorservice | 手機上的每一個感測器,含廠商、type、取樣率與批次能力,以及一段近期讀數的緩衝。 |
| dumpsys meminfo | 哪些行程最吃記憶體,量的是 PSS(按比例分攤的用量)。 |
| dumpsys package | 套件管理員知道的一切:版本、路徑、flags、安裝來源,以及每個使用者的狀態。 |
| dumpsys activity activities | 現在哪個 app 在前景,以及它背後的 task 與 stack 結構。 |
| dumpsys dropbox | 平台用來存放當機、ANR 與 tombstone 的環形緩衝——這是不用 root 讀 ANR 追蹤的方法。 |
這些行為是在撰寫 Web ADB 工具背後的解析程式時,對照 AOSP、toybox 與核心原始碼查證的。真的會因 Android 版本或廠牌而異的地方,這一頁會直接說明,而不是給你一個在半數手機上都是錯的數字。