dumpsys activity activities
唯讀現在哪個 app 在前景,以及它背後的 task 與 stack 結構。
- 指令
- adb shell dumpsys activity activities
- 指令
- 系統服務(dumpsys)
- 風險
- 唯讀
語法
dumpsys activity activities範例
dumpsys activity activities | grep -E 'topResumedActivity|mResumedActivity' | head -n 12只取出前景元件。在裝置上先過濾,是把傳輸量壓小的關鍵。
dumpsys activity activities整份。在醒了一段時間的手機上大約是一百 KB。
輸出怎麼讀
完整的輸出會印出每個顯示器上每個 stack 裡的每個 task,所以請先過濾。有四種行都在回答「現在前面是什麼」,而它們不一定一致:優先用 `topResumedActivity`,因為那就是這個問題本身;把 `mCurrentFocus` 當成最後手段,因為它指的是「視窗」,而那可能是鍵盤或系統對話框,後面那個 app 對使用者來說才是他正在用的 app。
輸出欄位
| 欄位 | 意義 |
|---|---|
| topResumedActivity= | 唯一處於 top-resumed 狀態的 Activity。Android 10 之後才有。 |
| mResumedActivity: / ResumedActivity: | 某個 stack 的 resumed Activity。可能出現好幾行,通常第一行是答案。 |
| mFocusedApp= | 取得焦點的 app token。實務上是對的,只差一層間接。 |
| mCurrentFocus= | 取得焦點的視窗——可能是輸入法或對話框而不是 app。 |
| u0 com.example/.MainActivity | Android 使用者 id 加元件。元件常寫成相對於套件的形式。 |
需要什麼權限
`ActivityManagerService.doDump` 一開頭就用標籤 `ActivityManager` 呼叫 `DumpUtils.checkDumpAndUsageStatsPermission`,所以要 `android.permission.DUMP` 加上 `android.permission.PACKAGE_USAGE_STATS`,兩個都由 Shell 套件宣告,而 `SHELL_UID` 會讓 app-op 那道檢查直接短路。條件就這樣:不用 root、不用 `adb root`、不用無障礙服務,也不用在設定裡給「使用情況存取權」——這也是為什麼「讀出前景 app」是纜線在什麼都不解鎖的情況下,少數幾件看起來很特權的事。shell 拿不到的,是讓它變便宜的方法。用 `grep` 過濾是在 `system_server` 已經把整份 dump 組完之後才篩,所以手機上的工作量兩種寫法完全一樣,你省下的只有傳輸。還有一件參數解析會做、而且沒有任何權限保護得了你的事:當 `activity` 後面那個字不是它認得的段落時,這份 dump 會先拿去比對執行中的 Activity,比不到就把**整串參數交給 activity manager 的 shell 指令直譯器去執行**。所以 `dumpsys activity <某個字>` 並不保證是唯讀的。把 `activities` 這個字原封不動打對,或改用 Android System Monitor,它只送出那個過濾過的讀取形式。
失敗訊息對照
| 訊息 | 意義 |
|---|---|
| Bad activity command, or no activities match: activites | 印在標準輸出,後面接著 `Use -h for help.`,而在那之前已經試過三件事:這個字不是已知的段落、對不上任何執行中的 Activity,然後它被當成 activity manager 的 shell 指令執行了、而且回報失敗。打錯字在這裡之所以無害,只是因為那個 shell 指令也失敗了——一個剛好拼成某個真子指令的打錯,就不是打錯,那是一道指令。 |
| Unknown argument: --activities; use -h for help | 選項是有連字號前綴的那些;`activities` 是指令不是選項,所以加了連字號寫就會掉進選項迴圈。和套件管理員那個版本不同,activity 的 dump 印完這行就**立刻返回**,所以你只會拿到這一行而不是一份預設 dump——至少這讓錯誤很明顯。 |
| Permission Denial: can't dump ActivityManager from from pid=4821, uid=10231 due to missing android.permission.DUMP permission | 來自 `DumpUtils`,帶著那個確實是 AOSP 原文的重複 `from from`,寫在**標準輸出**、取代整份 dump。把它接進一個 `grep topResumedActivity` 就會無聲無息地消失,而結果和一台螢幕關著的手機分不出來。前景 app 的查詢回空的時候,去看沒有過濾的第一行。 |
| *** SERVICE 'activity' DUMP TIMEOUT (10000ms) EXPIRED *** | 截斷在這裡比多數 dump 更要緊。resumed activity 那幾行不在輸出的最前面,所以一份在十秒被切掉的 dump 可能弄丟 `topResumedActivity`,卻還留著大量 task 與 stack 的文字——讀起來會像「前景什麼都沒有」,而不是像一個不完整的答案。先用 `-t` 拉長等待,再考慮退而求其次去看 `mCurrentFocus` 這種比較弱的行。 |
版本與廠商注意事項
- 這裡的欄位名稱改過兩次,也被複製到別的服務裡,所以要比對一組拼法而不是單一拼法。
- 不論你有沒有過濾,binder 的工作都在手機上發生;過濾省下的是傳輸,而在纜線上那才是隨輸出大小成長的部分。
這個我們有 UI
Android System Monitor 會透過 USB 執行這個指令並解析回應——只要 Chromium 系瀏覽器,不必安裝 SDK,也不會上傳任何東西。
相關指令
和 dumpsys activity activities 會在同一次作業裡出現的指令。
| 指令 | 做什麼 |
|---|---|
| am start | 用元件或 intent 啟動 Activity——這是驗證 deep link 能不能被接走最快的方法。 |
| am force-stop | 殺掉屬於某個 app 的所有行程與服務。 |
| top | 一次性的行程表:CPU 占用、記憶體、狀態與指令列。 |
其他系統服務(dumpsys)指令
| 指令 | 做什麼 |
|---|---|
| dumpsys battery | 電池服務目前的狀態:電量、充電狀態、健康度、電壓與溫度。 |
| dumpsys diskstats | 每個分割區的剩餘空間、一次磁碟寫入延遲的實測,以及一份快取起來的各 app 空間用量。 |
| dumpsys thermalservice | 手機是不是正在因為溫度而降速,以及硬體層回報的每一個溫區,單位是攝氏。 |
| dumpsys sensorservice | 手機上的每一個感測器,含廠商、type、取樣率與批次能力,以及一段近期讀數的緩衝。 |
| dumpsys meminfo | 哪些行程最吃記憶體,量的是 PSS(按比例分攤的用量)。 |
| dumpsys package | 套件管理員知道的一切:版本、路徑、flags、安裝來源,以及每個使用者的狀態。 |
| dumpsys dropbox | 平台用來存放當機、ANR 與 tombstone 的環形緩衝——這是不用 root 讀 ANR 追蹤的方法。 |
這些行為是在撰寫 Web ADB 工具背後的解析程式時,對照 AOSP、toybox 與核心原始碼查證的。真的會因 Android 版本或廠牌而異的地方,這一頁會直接說明,而不是給你一個在半數手機上都是錯的數字。