dumpsys sensorservice
唯讀手機上的每一個感測器,含廠商、type、取樣率與批次能力,以及一段近期讀數的緩衝。
- 指令
- adb shell dumpsys sensorservice
- 指令
- 系統服務(dumpsys)
- 風險
- 唯讀
語法
dumpsys sensorservice範例
dumpsys sensorservice感測器表,以及每個感測器的近期讀數。
getevent -lp輸入這一側的另一半:原始的 evdev 裝置,含觸控面板。
輸出怎麼讀
輸出範例
Sensor List:
0x00000001) LSM6DSO Accelerometer | STMicro | ver: 1 | type: android.sensor.accelerometer(1) | perm: n/a | flags: 0x00000000
continuous | minRate=12.50Hz | maxRate=416.00Hz | FIFO (max,reserved) = (3000, 600) events | non-wakeUp
Accelerometer: last 50 events
1 (ts=12345.678901234, wall=13:37:01.234) 0.12, 9.81, 0.03,每個感測器是一個十六進位 handle、一個右括號,然後是用 `|` 分隔的欄位,接著是一行以 tab 縮排的取樣率與批次資訊。再往下的近期事件緩衝是用感測器的「名稱」而不是 handle 來索引的,而且由新到舊排列。欄位順序在不同版本與不同廠牌之間都不穩定,所以要靠標籤來讀。
輸出欄位
| 欄位 | 意義 |
|---|---|
| 0x…) | 感測器 handle。這是每個版本都一定會印的那個 token。 |
| type: android.sensor.x(N) | 平台的 type 字串與它的數值。 |
| minRate / maxRate | 單位是赫茲——而且命名和直覺相反:minRate 是從最大延遲算出來的,maxRate 是從最小延遲算出來的。 |
| FIFO (max,reserved) | 以事件數表示的批次容量。沒有批次能力時會改印 `no batching`。 |
| wakeUp / non-wakeUp | 這個感測器能不能把手機從休眠喚醒。 |
| ts= | boot time 時鐘的秒數,經過一次休眠後在緩衝裡可能不是單調遞增的。 |
| [value masked] | 呼叫方沒有那個感測器需要的權限;讀數是被遮住而不是不存在。 |
需要什麼權限
`SensorService` 是原生的,所以它的檢查不是常見的 Java 那套:`SensorService::dump` 向 `PermissionCache::checkCallingPermission` 要 `android.permission.DUMP`,那個權限 Shell 套件有,失敗時它會在清單該在的位置補上一行拒絕。看感測器表不需要 root。它上面還有第二道比較安靜的關卡,而那才是會讓你困惑的那一道。在同一個函式裡,`privileged` 是用 `getCallingUid() == 0` 算出來的——只有 root,沒有別人。`adb shell` 跑起來是 uid 2000,所以它永遠不是 privileged,於是每一個 `getRequiredPermission()` 非空的感測器,它的近期事件緩衝都會被切成遮蔽格式。沒有東西被拒絕,也不會印任何警告:時間戳照樣在,而數值該在的位置寫的是 `[value masked]`。那不是讀不到的讀數、不是睡著的感測器、也不是壞掉的驅動程式,而且重跑不會有任何改變。這是這一頁上唯一 `adb root` 會改變的東西,而正式版上 `adb root` 會被拒絕,所以在零售機上被遮住的感測器就是一直被遮著。感測器表本身——handle、廠商、取樣率、批次能力——永遠不會被遮,這也是 Android Sensor Tester 能用一個普通 shell 就把清單建起來的原因。
失敗訊息對照
| 訊息 | 意義 |
|---|---|
| Permission Denial: can't dump SensorService from pid=4821, uid=10231 | 這是原生程式碼,所以它**沒有** Java 那些 dump 的重複 `from from`,也不會指名缺了哪個權限——請把它當成自己的一組字串來比對。它被接在結果緩衝後面,所以會從標準輸出出現、而且是取代感測器清單,這也是為什麼它乍看之下像一台沒有感測器的手機。 |
| No Sensors on the device | 服務手上一個感測器都沒有時印的,緊接著一行 `devInitCheck : <n>` 帶著感測器裝置自己的初始化狀態。那裡是負值代表某個硬體層根本沒起來,回的是一個 errno——這和一份真的沒有任何感測器的模擬器映像是完全不同的問題,而且從這份輸出裡只能靠它把兩者分開。 |
| Can't find service: sensorservice | 在服務被接觸到之前,就由 `dumpsys` 這支程式印到標準錯誤:service manager 裡沒有 `sensorservice` 這一項。開機期間很正常。因為它走標準錯誤,一次沒帶 `2>&1` 的收集會得到一份空清單,而且裡面沒有任何地方解釋原因。 |
| *** SERVICE 'sensorservice' DUMP TIMEOUT (10000ms) EXPIRED *** | 十秒是 `dumpsys` 的預設,而這份 dump 在走過每個感測器與每個近期事件緩衝時,會持有服務的連線鎖。活下來的是輸出的開頭——感測器表;失去的是尾巴,也就是近期事件。被截斷的 dump 仍然是一份可用的清冊,但不是一份可用的讀數樣本。 |
版本與廠商注意事項
- 文字版輸出已經很多個版本都不印最大量程、解析度與耗電了。平台 API 與 proto 格式裡有,所以會顯示它們的版本是廠商改過的。
- 兩個同名的感測器會讓近期事件緩衝的對應變得有歧義,而錯誤的對應會把讀數畫到別的感測器上。
- 這是這一家族裡最不穩定的一份輸出:它的文字由好幾個不同元件各自組出來,中間沒有共用的結構定義。
這個我們有 UI
Android Sensor Tester 會透過 USB 執行這個指令並解析回應——只要 Chromium 系瀏覽器,不必安裝 SDK,也不會上傳任何東西。
相關指令
和 dumpsys sensorservice 會在同一次作業裡出現的指令。
| 指令 | 做什麼 |
|---|---|
| getevent | 直接從核心串流原始輸入事件,或列出每個輸入裝置能回報什麼。 |
| dumpsys thermalservice | 手機是不是正在因為溫度而降速,以及硬體層回報的每一個溫區,單位是攝氏。 |
| wm size | 回報顯示器的解析度,或覆寫它,讓手機假裝自己是另一塊螢幕。 |
其他系統服務(dumpsys)指令
| 指令 | 做什麼 |
|---|---|
| dumpsys battery | 電池服務目前的狀態:電量、充電狀態、健康度、電壓與溫度。 |
| dumpsys diskstats | 每個分割區的剩餘空間、一次磁碟寫入延遲的實測,以及一份快取起來的各 app 空間用量。 |
| dumpsys meminfo | 哪些行程最吃記憶體,量的是 PSS(按比例分攤的用量)。 |
| dumpsys package | 套件管理員知道的一切:版本、路徑、flags、安裝來源,以及每個使用者的狀態。 |
| dumpsys activity activities | 現在哪個 app 在前景,以及它背後的 task 與 stack 結構。 |
| dumpsys dropbox | 平台用來存放當機、ANR 與 tombstone 的環形緩衝——這是不用 root 讀 ANR 追蹤的方法。 |
這些行為是在撰寫 Web ADB 工具背後的解析程式時,對照 AOSP、toybox 與核心原始碼查證的。真的會因 Android 版本或廠牌而異的地方,這一頁會直接說明,而不是給你一個在半數手機上都是錯的數字。