dsh-go-plugin-adb:讓 Agent 在手機上給自己開一個 adb shell

前言

在手機上跑 DSH(DeepSeek Harness)時,Agent 想裝個 App、看一段日誌、截一張屏,通常是兩條路:把它們接到一臺插着數據線的電腦上走 adb,或者退而求其次用無障礙服務一點點點屏幕。前者需要額外的機器和局域網,後者只能模擬點擊,拿不到真正的 shell。

jminn0/dsh-go-plugin-adb 走的是第三條路:插件的 adb 客戶端和 adbd 都在同一臺手機裏,Agent 連的是迴環地址 127.0.0.1:5555。不需要 root,不需要電腦,配對一次之後關掉 WiFi、開飛行模式也不影響。下面介紹它的連接方式、安裝步驟、一次性配對流程和六個工具的實際能力。

這是什麼

由 JMINN0 維護的 DSH 插件,歸類在工作流方向。它能給 Agent 提供一個真實的 adb shell,用來在這臺手機自身上執行 pm、am、logcat、dumpsys、screencap 等命令,權限是 uid 2000。

版本 2026.1105.1908(年.月日.時.分格式)。驗證環境是 nubia REDMAGIC NX809J / Android 16 (SDK 36) / adb 34.0.4 / DSH 0.2.2-rc.1。README 標註穩定性 10/10、工具定義 6/6。它是純 ESM 的 JS 插件,沒有構建步驟,也沒有 npm install。

關鍵點:端口還是 5555,只是地址換成了迴環

這一點值得先說清,因爲容易和常規 adb 用法混淆。端口沒有變,仍然是 5555;變的是「連哪個地址」——常規做法連局域網 IP,這個插件連 127.0.0.1,流量走回環網卡。

帶來的結果:

  • 關 WiFi、開飛行模式都不會斷;
  • 不依賴路由器,也不需要手機和別的設備在同一局域網;
  • 同一局域網內的其他機器理論上也能連到這個端口,不過仍需持有本機的 adb 私鑰才能進入。

adb tcpip 之後 adbd 監聽的是整個網絡棧,本機連回環因此可行。但這一步會重啓 adbd,把 Shizuku 之類的其它客戶端一起踢掉,所以插件自己不執行它(詳見下文配對部分)。

前提條件和安裝

DSH Go 跑在手機內部的 proot Ubuntu 裏,插件相關的命令也都在這裏執行,不在電腦上執行。先確認幾件事:

  1. 一部開了開發者選項的 Android 手機;
  2. 無線調試可用(用於一次性配對);
  3. 首次配對時手機要連着 WiFi——配對走局域網,之後就不再需要了;
  4. proot 環境裏能裝上 adb 客戶端:
apt-get update && apt-get install -y android-tools-adb

裝完驗證:

adb version
# Android Debug Bridge version 1.0.41

需要注意:DSH Go 升級運行時鏡像時,apt 裝的東西會全部丟失,adb 需要重裝一次。

包從哪來

這個包目前沒有發佈到 npm registry,只存在於 GitHub 倉庫。dsh plugin add 支持本地目錄和包名兩種目標,這裏要用本地目錄:

git clone https://github.com/JMINN0/dsh-go-plugin-adb.git
cd dsh-go-plugin-adb
dsh plugin --profile web add .

add 後面的 . 表示當前目錄,必須先進入倉庫目錄再執行,否則會報找不到包。

--profile web 不能省。DSH 可以有多套 profile,手機本機引擎加載的那套叫 web;裝到默認 profile,手機 App 不會加載這個插件。

裝完要重啓引擎

安裝只改配置,不重載代碼。在 App 裏走:設置 → 引擎 → 重啓引擎。

重啓後工具列表裏會多出 6 個 adb_*。不重啓就看不到工具,這是最容易漏的一條。

驗證裝好了

# ① 配置裏有沒有這個 bundle
python3 -c "
import json
d=json.load(open('$HOME/.dsh/profiles/web/package.json'))
print([b for b in d['dsh']['profile']['bundles'] if 'adb' in b])"
# 期望輸出:['dsh-go-plugin-adb']

# ② 引擎有沒有加載失敗
grep -i "apply failed" ~/.dsh/dsh-app/diagnostics.md 2>/dev/null | grep adb || echo "沒有加載錯誤 ✅"

這兩步只證明配置對了,不證明工具能用。最後一關是在 DSH Go 對話裏直接說:

用 adb_devices 看看現在連着哪些設備

期望返回:

127.0.0.1:5555  device

看到這行纔算真的裝好了。如果 Agent 回覆「沒有這個工具」,回到重啓引擎那一步;如果返回「連不上,已試過端口」,回到下面的配對流程。

一次性配對

這是 adb 的標準流程,不是插件特有的。順序很重要,跳步會報 no devices/emulators found。

  1. 手機上:開發者選項 → 無線調試 → 使用配對碼配對設備。屏幕會顯示配對用的 IP:端口(例如 192.168.1.100:37123)和 6 位配對碼。注意「無線調試」主頁面還有一個「IP 地址和端口」(例如 192.168.1.100:41000),那個端口每次開無線調試都會變,和配對端口不是同一個。

  2. 用配對端口配對:

adb pair 192.168.1.100:37123
# 提示 Enter pairing code: 時輸入 6 位碼
# 成功顯示 Successfully paired to ...
  1. 連上無線調試端口:
adb connect 192.168.1.100:41000
adb -s 192.168.1.100:41000 shell id
# uid=2000(shell) ...
  1. 最後連回環,這是插件默認走的路:
adb connect 127.0.0.1:5555
adb -s 127.0.0.1:5555 shell id

配對成功後密鑰存在 ~/.android/adbkey,之後不用再配對,重裝 adb 也不會丟。

不要用 adb tcpip 5555 去固定端口

早期文檔教過這一步,現在明確不要做。README 裏記錄的實測結果是:執行 adb tcpip 5555 之前 adbd、shizuku_server、GKD 用戶服務都存在,執行 8 秒之後 adbd 的 PID 變了(重啓了),Shizuku 和 GKD 的服務進程都沒了。原因是 adb tcpip 會重啓 adbd,而 adbd 是多個客戶端共享的資源——Shizuku 在 adb 模式下本身就是 adbd 的一個客戶端,重啓等於把別人踢下線。

對照組是 adb kill-server + start-server,這兩個操作不會動 adbd。插件自己的 ensure() 裏也永遠不調 tcpip,只「搭車」:用當前可用的連接,或者掃迴環端口找出 adbd 現在掛在哪個端口上。

手機重啓後怎麼恢復

adb tcpip 的設置不持久,重啓就丟,但不需要再執行它:

  1. 手機上確認「無線調試」開着;
  2. 插件會自己掃端口找回連接(掃 127.0.0.1:30000-50000,約 6 秒);
  3. 掃不到的話,讀出無線調試頁面上「IP 地址和端口」那個號,手動 adb connect <IP>:<端口>。

adb_reconnect 工具也能強制重建連接,手機重啓後或 adb_devices 顯示 offline 時用它。

六個工具

六個工具都是給 Agent 調用的,正常對話時由 Agent 自己決定調用哪個,也可以直接點名。

adb_devices

列出當前連接的設備,無參數。

adb_devices
→ 127.0.0.1:5555  device

adb_shell

執行任意 shell 命令,最常用的一個。command 支持管道、重定向、&&、$();timeoutMs 可設超時,默認 60000 毫秒,範圍 1000–600000。

adb_shell { command: "getprop ro.build.version.release" }   → 16
adb_shell { command: "pm list packages | grep tencent" }
adb_shell { command: "dumpsys battery | grep -E 'level|status'" }

實際邊界:

  • 輸出上限 32MB,超出返回失敗但前 32MB 仍在;
  • 輸出按 UTF-8 解碼,直接 cat 圖片這類二進制內容會損壞,要看二進制得用 od / base64 繞一下;
  • 不支持 stdin,top、vi 這類交互式命令用不了;
  • 命令退出碼非 0 不算工具失敗,輸出照常返回,附帶退出碼說明;
  • 每次調用多一次連接探測,約 50ms,換來斷線自愈。

adb_install

安裝 APK。

參數 類型 必填 說明
path string 是 設備上的絕對路徑,如 /sdcard/app.apk
reinstall boolean 加 -r 保留數據,默認 true
downgrade boolean 加 -d 允許降級,默認 false
adb_install { path: "/sdcard/Download/app.apk" }
→ { text: "安裝成功:<路徑>" }

path 用的是設備側路徑,不是 proot 裏的路徑;proot 裏的文件要先 push 到設備上。簽名不一致時會失敗,要麼先卸載舊包(數據會丟),要麼用同一密鑰重新簽名。

adb_logcat

讀日誌尾部,不會留長駐進程。lines 默認 200,最大 20000;filter 支持正則,走 grep -E。

adb_logcat { filter: "FATAL", lines: 100 }
adb_logcat { filter: "AndroidRuntime|FATAL|ANR", lines: 200 }

匹配不到時返回「(最近 N 行裏沒有匹配 "X" 的內容)」,這是正常結果不是錯誤。

adb_screencap

截圖並保存。兩個參數都可選,adb_screencap {} 也合法。

參數 類型 說明
outPath string 設備側路徑,默認 /sdcard/dsh-screencap.png
localPath string 同時拉回到 proot 的本地路徑,如 /tmp/shot.png
adb_screencap {}
adb_screencap { outPath: "/sdcard/a.png", localPath: "/tmp/a.png" }
→ { text: "截圖已保存:/sdcard/a.png" }

截的是主屏。要截虛擬屏上的內容,用另一個插件 dsh-go-plugin-screen,不是這個。

adb_reconnect

強制重建連接:殺本地 adb server、重啓、把無線調試端口遷移到 5555、驗證 uid 2000。無參數。

能做什麼,不能做什麼

README 裏列的已實測能力包括:

pm list packages / pm path / pm install / pm uninstall
am start / am force-stop / am broadcast
logcat / dumpsys / getprop / settings
screencap / input / cmd window / cmd notification

cmd package 的 uninstall / clear 會卸包清數據,其餘子命令(如 list packages)只是查詢。

不能做的幾件事:讀不了 /data/data(SELinux 擋着 uid 2000);沒有 stdin,交互式命令用不了;二進制輸出會按 UTF-8 解碼而損壞;超時之後設備側的命令可能還在跑,取消工具不會殺遠端進程。

適用場景與注意事項

適合:已經在手機內部 proot 裏跑 DSH Go、希望 Agent 直接操作本機、又不想依賴外部電腦或局域網的場景。社區目錄頁把分類歸在工作流。

用之前要看的幾點:

  • 插件以當前 dsh 進程的權限運行,adb_shell 沒有攔截、沒有白名單、沒有二次確認,能卸包、刪文件、重啓、改設置。安裝前應先讀一遍源碼。
  • 許可證是 MIT。GitHub 倉庫星標爲 0,倉庫創建於 2026-11-04,屬於很新的項目。
  • 驗證只有單機型:Android 16、adb 34.0.4、nubia REDMAGIC NX809J。其他 Android 版本、其他廠商 adbd、其他 adb 版本都未驗證。
  • 目前沒有發佈到 npm registry,只能從 GitHub 裝。
  • 安裝只改配置,必須手動重啓引擎,否則工具不會出現。

下面是目錄頁和源碼地址:

  • 目錄頁:https://www.skillhub.cn/plugins/JMINN0/dsh-go-plugin-adb
  • GitHub:https://github.com/JMINN0/dsh-go-plugin-adb
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜