了解 adb 背後原理和運用。
adb forward
轉發 PC 端 4000 端口到手機的 9999 端口
1
| adb forward tcp:4000 tcp:9999
|
查看是否轉發成功
範例
Android 建立 server socket
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| private static class SocketThread extends Thread { ServerSocket serverSocket;
@Override public void run() { byte[] buffer = new byte[1024]; try { serverSocket = new ServerSocket(9999); Log.d("Mike", "socket open"); Socket clientSocket = serverSocket.accept(); Log.d("Mike", "socket accept");
InputStream is = clientSocket.getInputStream(); OutputStream os = clientSocket.getOutputStream(); while (!isInterrupted()) { int len = is.read(buffer); if (len > 0) { os.write(("echo " + new String(buffer, 0, len)).getBytes()); } } } catch (IOException e) { e.printStackTrace(); } Log.d("Mike", "socket end"); }
public void close() { if (serverSocket != null) { try { interrupt(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
|
PC 端用 python 建立 client socket
1 2 3 4
| client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((socket.gethostname(), 4000)) client.send(b'Hello') print(client.recv(1024))
|
adb 通道
adb server 啟動以後,在本地的 5037 端口監聽。adb client 通過本地的隨機端口與 5037 端口建立連接。
在這個通道上,client 向 server 發送的命令都遵循如下格式:
- 命令的長度(Length),由四位的十六進製表示
- 實際的命令(Payload),通過 ASCII 編碼
譬如,查看 adb 當前的版本,client 會發起如下命令:
000C 表示”host:version”這條命令的長度為 12 個字節。命令中使用了 host 前綴,目的是為了區分其他類型的命令,host 前綴的命令可以理解為只在 client 與 server 這個數據通道上存在。
server 收到 client 的請求後,返回的數據遵循如下格式:
- 如果成功,則返回四個字節的字符串”OKAY”
- 如果失敗,則返回四個字節的字符串”FAIL”和出錯原因
- 如果異常,則返回錯誤碼
當 Client 收到 Server 返回的”OKAY”後,就可以發繼續發起其他操作命令了。
當與 server 建立第一個通道的連接後,需要向 server 發送 transport 命令,表示接下來,要與 adbd 進行數據傳輸。
1
| host:transport:<serial-number>
|
當 server 返回“OKAY”後,client 後續發送的數據,就直接傳輸到 adbd 了。
範例
Android 建立 server socket
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private static class SocketThread extends Thread { LocalServerSocket serverSocket;
@Override public void run() { byte[] buffer = new byte[1024]; try { serverSocket = new LocalServerSocket("test"); Log.d("Mike", "socket open"); LocalSocket clientSocket = serverSocket.accept(); Log.d("Mike", "socket accept");
InputStream is = clientSocket.getInputStream(); OutputStream os = clientSocket.getOutputStream(); while (!isInterrupted()) { int len = is.read(buffer); if (len > 0) { os.write(("echo " + new String(buffer, 0, len)).getBytes()); } } } catch (IOException e) { e.printStackTrace(); } Log.d("Mike", "socket end"); }
public void close() { if (serverSocket != null) { try { interrupt(); LocalSocket mockSocket = new LocalSocket(); mockSocket.connect(serverSocket.getLocalSocketAddress()); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
|
PC 端用 python 建立 client socket
1 2 3 4 5 6 7 8 9 10 11 12
| client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) client.connect((socket.gethostname(), 5037))
transport = 'host:transport:192.168.2.131:5555' client.send(bytes('%0.4X' % len(transport) + transport, 'ascii')) print(client.recv(4)) client.send(b'0012localabstract:test') print(client.recv(4)) client.send(b'Hello') print(client.recv(1024))
|
參考https://duanqz.github.io/2015-05-21-Intro-adb