本文嘗試列舉用戶端能夠發送給ADB伺服器的所有請求。關於adb用戶端、adb伺服器、adbd守護進程、adb服務的概念,以及這些組件如何相互配合完成ADB工作的細節,請參考之前發的文章《Android Debug Bridge 技術實現》。
==============================
主機服務
==============================
host:version
請求ADB伺服器的組建號。作為一個特殊的例外,伺服器將用4位元組的十六進位字串回應,返回伺服器組建號,回應中沒有“OKAY”和“FAIL”。
host:kill
請求ADB伺服器立即退出。用於ADB用戶端檢測到在升級之後有廢棄的ADB伺服器仍在啟動並執行情況。
host:devices
請求返回可用的Android裝置及其狀態的列表。在“OKAY”之後是4個位元組的長度定義,然後是指定長度的表明當前裝置狀況的字串,返回之後串連關閉。
host:track-devices
“host:devices”的一個變種,它不關閉串連;相反,每次添加或移除裝置或者指定裝置的狀態發生變化,一個新的裝置列表描述被發送。這就使得像DDMS這樣的工具能夠即時跟蹤串連裝置的狀態,而不用重複輪訓伺服器。
host:emulator:<port>
這是一個特殊的請求,當啟動一個新的模擬器時,該請求被發送到ADB伺服器。<port>是一個十進位數字代表模擬器的ADB協議連接埠號碼,比如:模擬器將自動轉寄到adbd守護進程的TCP連接埠號碼。這個機制使得ADB伺服器能夠知道新的模擬器執行個體啟動。
host:transport:<serial-number>
請求切換串連到<serial-number>指示的裝置或模擬器。接到“OKAY”回應之後,所有的用戶端請求將被直接發送給運行在指定裝置上的adbd守護進程。(用來實現-s)
host:transport-usb
請求切換串連到通過USB串連到主機的裝置上。如果存在多個這樣的裝置,請求將失敗。(用來實現-d)
host:transport-local
請求切換串連到通過TCP串連的模擬器。如果有多個這樣的模擬器執行個體在運行,請求將失敗。(用來實現-e)
host:transport-any
另一個“host:transport”變種。請求切換串連到已串連的裝置或正在啟動並執行模擬器。如果可用的裝置或模擬器多於一個,請求將失敗。(用在-s、-d、-e都不被提供時)
host-serial:<serial-number>:<request>
這是一個特殊形式的請求,首碼“host-serial:<serial-number>:”表明用戶端正在請求ADB伺服器獲得指定裝置的資訊。<request>可以是下述格式的一種。
host-usb:<request>
host-serial的一個變種,用於將串連到主機的唯一USB裝置作為目標。如果沒有這樣的裝置或有多個這樣的裝置,請求將失敗。
host-local:<request>
host-serial的一個變種,用於將運行在主機上唯一的模擬器執行個體作為目標。如果沒有這樣的模擬器或有多個這樣的模擬器,請求將失敗。
host:<request>
當請求裝置相關的資訊時,“host:”也能被解釋為“任何串連到主機的唯一裝置或運行在主機上的唯一模擬器”。
<host-prefix>:get-product
暫無解釋。
<host-prefix>:get-serialno
返回對應裝置或模擬器的序號。注意模擬器序號是“emulator-5544”的形式。
<host-prefix>:get-state
返回指定裝置的狀態字串。
<host-prefix>:forward:<local>;<remote>
請求ADB伺服器將本地串連從<local>轉移到指定裝置上的<remote>地址。
這裡的<host-prefix>可以是上面描述的host-serial、host-usb、host-local、host的任意一個,它表明目標是哪個裝置或模擬器。
<local>的格式有以下幾種:
tcp:<port> -> 在localhost:<port>上的TCP串連
local:<path> -> 在<path>上的Unix本地區通訊端(Unix domain socket)
<remote>的格式有以下幾種:
tcp:<port> -> 在裝置上localhost:<port>的TCP串連
local:<path> -> 在裝置上的Unix本地區通訊端
jdwp:<pid> -> 在虛擬機器進程<pid>中的JDWP線程
或者下面所描述的本地服務的任何一種。
==============================
本地服務
==============================
下面所有的請求都假設你已經切換傳輸到實際的裝置,或者你使用上面所描述的請求首碼。
shell:command arg1 arg2 ...
在裝置的shell中運行“command arg1 arg2 ...”,返回輸出資料流及錯誤流。注意命令參數必須用空格分隔。如果一個參數包含空格,應該對它使用雙引號。參數不能包含雙引號和其他會導致錯誤的符號。
這是“adb shell”的非互動版本。
shell:
在裝置上啟動一個互動的shell會話。恰當的重新導向標準輸入、標準輸出和標準錯誤輸出。ADB伺服器使用這個服務來實現“adb shell”,但是在輸入被發送到裝置之前,ADB伺服器也會對輸入做加工。(參考commandline.c中的interactive_shell()函數)
remount:
請求adbd守護進程重新掛載裝置的檔案系統到讀/寫入模式下,而不是唯讀模式。在執行“adb sync”或者“adb push”之前,通常都需要這個服務。
在不允許該操作的特定的系統中,這個請求可能不成功。
dev:<path>
開啟一個裝置檔案,直接將用戶端串連到這個檔案去執行讀寫。該服務對於調試除錯很有用,但是需要特殊的許可權,不能在所有的裝置上運行。<path>是從檔案系統根目錄開始的全路徑。
tcp:<port>
嘗試串連到loclhost的tcp連接埠<port>上。
tcp:<port>:<server-name>
嘗試從裝置串連到<server-name>所指定機器的tcp連接埠<port>上。這個服務對調試只能在裝置上顯示的網路或代理問題很有用。
local:<path>
嘗試串連到裝置上的Unix域通訊端<path>。
localreserved:<path>
localabstract:<path>
localfilesystem:<path>
幾個local:<path>的變種,用來訪問其他Android通訊端命名空間。
log:<name>
開啟一個系統日誌(/dev/log/<name>),允許用戶端直接讀取。用來實現“adb logcat”。資料流對用戶端是唯讀。
framebuffer:
這個服務用來向用戶端發送framebuffer的快照。它需要足夠的許可權,工作原理如下:
在“OKAY”之後,服務發送包含下欄欄位的16位元組的二進位結構(低位優先格式):
depth: uint32_t: framebuffer深度
size: uint32_t: framebuffer大小(單位:位元組)
width: uint32_t: framebuffer寬度(單位:像素)
height: uint32_t: framebuffer高度(單位:像素)
在當前的實現中,framebuffer深度總是16,大小總是:寬度*高度*2。
每當用戶端想要一個快照時,它應該通過通道發送一個位元組,觸發服務將framebuffer資料按framebuffer大小指定的位元組數發送給它。
如果adbd守護進程沒有足夠的許可權開啟framebuffer裝置,那麼串連會立即關閉。
dns:<server-name>
這個服務是個例外,因為它僅僅運行在ADB伺服器中。它被用來實現USB連網,比如:通過主機為裝置提供一個網路連接。
它用來在主機上執行gethostbyname(<address>),IP地址以4個位元組的字串返回。
recover:<size>
這個服務上傳一個recovery影像到裝置中。<size>必須與recovery影像檔案大小一樣。工作原理如下:
- 建立一個命名為/tmp/update的檔案;
- 從用戶端讀取<size>大小的位元組數,將它們寫入到/tmp/update;
- 當影像檔案成功讀取之後,建立一個命名為/tmp/update.start的檔案。
只有當裝置處於recovery模式時,這個服務才能工作。此外,如果/tmp目錄不存在,串連會立即關閉。
jdwp:<pid>
串連到運行在虛擬機器進程<pid>中的JDWP線程。
track-jdwp
用於周期性的向用戶端發送JDWP pids列表。返回資料格式如下:
<hex4>: 4個字元的十六進位字串指定所有內容的長度
<content>: 一連串的格式為<pid> "/n"的ASCII行
DDMS使用這個服務知道裝置或模擬器上正在運行哪些可以調試的進程。
注意沒有僅擷取一次列表的單步服務。
sync:
這個請求開機檔案系統同步服務,用來實現“adb push”和“adb pull”。因為這個服務相當複雜,需要專門的文章來解釋說明,如果有朋友感興趣,我們以後專門討論。