adbproxy 0.1.0__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adbproxy-1.0.0/PKG-INFO +357 -0
- adbproxy-1.0.0/README.md +336 -0
- adbproxy-1.0.0/pyproject.toml +101 -0
- adbproxy-1.0.0/src/adbproxy/cli/device.py +17 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/cli/main.py +0 -1
- adbproxy-1.0.0/src/adbproxy/cli/server.py +17 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/config.py +22 -8
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/app.py +76 -179
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/backend.py +15 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/connection.py +110 -87
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/session.py +11 -2
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/stream_table.py +1 -5
- adbproxy-1.0.0/src/adbproxy/observers/decompress.py +121 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/observers/install.py +10 -3
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/observers/shell.py +126 -81
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/observers/stream.py +16 -8
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/observers/sync.py +84 -159
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/adb.py +16 -2
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/payload/install.py +1 -1
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/payload/shell_v2.py +1 -1
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/smart_socket/classifier.py +22 -4
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/smart_socket/conversation.py +23 -7
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/transport/__init__.py +0 -6
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/transport/codec.py +1 -3
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/transport/constants.py +2 -3
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/runtime/adb_process.py +12 -0
- adbproxy-1.0.0/src/adbproxy/runtime/app.py +231 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/runtime/capture.py +0 -1
- adbproxy-1.0.0/src/adbproxy/runtime/idle.py +109 -0
- adbproxy-1.0.0/src/adbproxy/runtime/logging.py +278 -0
- adbproxy-1.0.0/src/adbproxy/runtime/timeouts.py +22 -0
- adbproxy-1.0.0/src/adbproxy/server/app.py +189 -0
- adbproxy-1.0.0/src/adbproxy/server/connection.py +391 -0
- adbproxy-1.0.0/src/adbproxy.egg-info/PKG-INFO +357 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy.egg-info/SOURCES.txt +9 -1
- adbproxy-1.0.0/tests/test_app_lifecycle.py +1008 -0
- adbproxy-1.0.0/tests/test_device_transport.py +625 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/tests/test_dynamic_commands.py +336 -63
- {adbproxy-0.1.0 → adbproxy-1.0.0}/tests/test_imports.py +4 -2
- adbproxy-1.0.0/tests/test_observers.py +606 -0
- adbproxy-1.0.0/tests/test_protocol_codecs.py +479 -0
- adbproxy-1.0.0/tests/test_server_connection.py +348 -0
- adbproxy-0.1.0/PKG-INFO +0 -254
- adbproxy-0.1.0/README.md +0 -233
- adbproxy-0.1.0/pyproject.toml +0 -37
- adbproxy-0.1.0/src/adbproxy/cli/device.py +0 -13
- adbproxy-0.1.0/src/adbproxy/cli/server.py +0 -13
- adbproxy-0.1.0/src/adbproxy/runtime/logging.py +0 -113
- adbproxy-0.1.0/src/adbproxy/server/app.py +0 -221
- adbproxy-0.1.0/src/adbproxy/server/connection.py +0 -378
- adbproxy-0.1.0/src/adbproxy.egg-info/PKG-INFO +0 -254
- adbproxy-0.1.0/tests/test_protocols.py +0 -1522
- {adbproxy-0.1.0 → adbproxy-1.0.0}/LICENSE +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/setup.cfg +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/__main__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/cli/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/device/banner.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/observers/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/observers/events.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/payload/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/payload/sync.py +2 -2
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/smart_socket/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/smart_socket/handshake.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/smart_socket/wire.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/protocols/transport/errors.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/runtime/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/runtime/sockets.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy/server/__init__.py +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy.egg-info/dependency_links.txt +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy.egg-info/entry_points.txt +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy.egg-info/requires.txt +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/src/adbproxy.egg-info/top_level.txt +0 -0
- {adbproxy-0.1.0 → adbproxy-1.0.0}/tests/test_cli_main.py +0 -0
adbproxy-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: adbproxy
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: ADB smart-socket and device transport proxies
|
|
5
|
+
Author: Forgo7ten
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Forgo7ten/adbproxy
|
|
8
|
+
Project-URL: Repository, https://github.com/Forgo7ten/adbproxy
|
|
9
|
+
Project-URL: Issues, https://github.com/Forgo7ten/adbproxy/issues
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: zstandard>=0.25.0
|
|
14
|
+
Provides-Extra: lz4
|
|
15
|
+
Requires-Dist: lz4>=4.3.0; extra == "lz4"
|
|
16
|
+
Provides-Extra: brotli
|
|
17
|
+
Requires-Dist: brotli>=1.1.0; extra == "brotli"
|
|
18
|
+
Provides-Extra: decompress
|
|
19
|
+
Requires-Dist: adbproxy[brotli,lz4]; extra == "decompress"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# adbproxy
|
|
23
|
+
|
|
24
|
+
在 ADB client 与 server / 设备之间插入透明代理,解析并记录 ADB 协议流量,同时保持原始字节原样转发。
|
|
25
|
+
|
|
26
|
+
适用于调试 adb 命令、观察 shell / sync / install 等协议交互、抓取 push/pull 文件内容。
|
|
27
|
+
|
|
28
|
+
## 功能
|
|
29
|
+
|
|
30
|
+
- **server-proxy**:MITM 本机 `adb client ↔ adb server` 的 smart-socket 链路(默认监听 `5037`,真实 server 挪到 `5038`)
|
|
31
|
+
- **device-proxy**:模拟网络 adbd,接受 transport 协议连接,再经系统 adb server 转发到真实设备
|
|
32
|
+
- 解析并记录 shell、sync、install、stream 等协议事件
|
|
33
|
+
- 可选落盘 sync / install 文件内容,以及 `--debug` 原始 hex
|
|
34
|
+
- 观察 / 解码 / 抓包失败时 fail-open,不中断透明转发
|
|
35
|
+
|
|
36
|
+
## 架构
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart LR
|
|
40
|
+
Client[adb client]
|
|
41
|
+
SP[server-proxy :5037]
|
|
42
|
+
Server[adb server :5038]
|
|
43
|
+
Dev[真实设备]
|
|
44
|
+
|
|
45
|
+
Client -->|smart socket| SP
|
|
46
|
+
SP -->|smart socket| Server
|
|
47
|
+
Server --> Dev
|
|
48
|
+
|
|
49
|
+
Client2[adb client]
|
|
50
|
+
ServerFront[adb server :5037]
|
|
51
|
+
DP[device-proxy :5566]
|
|
52
|
+
ServerBack[adb server :5037]
|
|
53
|
+
Dev2[真实设备]
|
|
54
|
+
|
|
55
|
+
Client2 -->|smart socket| ServerFront
|
|
56
|
+
ServerFront -->|transport| DP
|
|
57
|
+
DP -->|smart socket| ServerBack
|
|
58
|
+
ServerBack --> Dev2
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 环境要求
|
|
62
|
+
|
|
63
|
+
- Python ≥ 3.10
|
|
64
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
65
|
+
- 系统 `adb`(Android platform-tools)
|
|
66
|
+
|
|
67
|
+
## 安装
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
git clone <repo-url>
|
|
71
|
+
cd adbproxy # 或你的本地目录名
|
|
72
|
+
uv sync
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
也可从 PyPI:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install adbproxy
|
|
79
|
+
# 可选:sync 解压依赖
|
|
80
|
+
pip install "adbproxy[decompress]"
|
|
81
|
+
|
|
82
|
+
# 临时运行
|
|
83
|
+
uvx adbproxy server --help
|
|
84
|
+
uvx adbproxy device --help
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`uv sync` 会安装依赖,并根据 `pyproject.toml` 的 `[project.scripts]` 注册命令行入口:
|
|
88
|
+
|
|
89
|
+
| 命令 | 对应模块 | 作用 |
|
|
90
|
+
|------|----------|------|
|
|
91
|
+
| `adbproxy` | `adbproxy.cli.main:main` | **推荐**统一入口:`server` / `device` 子命令 |
|
|
92
|
+
| `adb-server-proxy` | `adbproxy.cli.server:main` | 兼容旧入口(等同 `adbproxy server`) |
|
|
93
|
+
| `adb-device-proxy` | `adbproxy.cli.device:main` | 兼容旧入口(等同 `adbproxy device`) |
|
|
94
|
+
|
|
95
|
+
推荐启动方式:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# 统一入口(推荐)
|
|
99
|
+
uv run adbproxy server --help
|
|
100
|
+
uv run adbproxy device --help
|
|
101
|
+
uv run python -m adbproxy server --help
|
|
102
|
+
uv run python -m adbproxy device --help
|
|
103
|
+
|
|
104
|
+
# 兼容旧 console script / 模块路径
|
|
105
|
+
uv run adb-server-proxy --help
|
|
106
|
+
uv run adb-device-proxy --help
|
|
107
|
+
uv run python -m adbproxy.cli.server --help
|
|
108
|
+
uv run python -m adbproxy.cli.device --help
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
下文示例统一使用 `adbproxy server` / `adbproxy device`。
|
|
112
|
+
|
|
113
|
+
## 使用
|
|
114
|
+
|
|
115
|
+
### 1. server-proxy(MITM 本机 5037)
|
|
116
|
+
|
|
117
|
+
启动前确认本机 `5038` 未被占用。代理会接管默认 `5037`,把真实 adb server 挪到 `5038`;退出时按所有权恢复。
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
uv run adbproxy server
|
|
121
|
+
# 等价:
|
|
122
|
+
# uv run python -m adbproxy server
|
|
123
|
+
# uv run adb-server-proxy
|
|
124
|
+
|
|
125
|
+
# 可选参数:
|
|
126
|
+
# --debug 将每段 recv 的原始 hex 落盘
|
|
127
|
+
# --no-capture 不落盘 sync/install 文件,仅打印摘要
|
|
128
|
+
# --log-format json 事件日志写成 JSONL(默认 text)
|
|
129
|
+
# --listen PORT 代理监听端口,即 adb client 连的那个(默认 5037)
|
|
130
|
+
# --adb-server-port PORT 转发到的真实 adb server 端口(默认 5038)
|
|
131
|
+
# --reuse-adb-server 复用已在运行的后端 server,不接管也不启停任何 server
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
两个端口成对使用:`--listen` 是要从真 adb server 手里接管的端口,`--adb-server-port`
|
|
135
|
+
是真 server 被挪去的地方。改这两个值可以同时跑多个实例,或在默认端口被别的工具占用时改道:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# 接管 6037,把真实 server 放到 6038
|
|
139
|
+
uv run adbproxy server --listen 6037 --adb-server-port 6038
|
|
140
|
+
adb -P 6037 devices -l
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### 复用模式(不接管任何 server)
|
|
144
|
+
|
|
145
|
+
`--reuse-adb-server` 让代理只做转发:不 kill 监听端口上的实例、不起新的后端、退出时也
|
|
146
|
+
没有要恢复的东西。适合本机还有别的 adb 客户端(IDE 之类)时挂一层观察——它们继续用
|
|
147
|
+
默认 5037,你用代理端口:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# 监听 6037,转发到已在运行的 5037
|
|
151
|
+
uv run adbproxy server --listen 6037 --adb-server-port 5037 --reuse-adb-server
|
|
152
|
+
adb -P 6037 shell echo hello # 经过代理
|
|
153
|
+
adb devices -l # 不经过代理,照常工作
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
两种模式的区别:
|
|
157
|
+
|
|
158
|
+
| | 默认(接管) | `--reuse-adb-server` |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| 监听端口上的真 server | 先 kill,退出时恢复 | 不碰(该端口必须空闲,否则 bind 失败) |
|
|
161
|
+
| 后端 server | 由代理启动并持有所有权 | 必须已在运行;代理不启不停 |
|
|
162
|
+
| 后端意外死掉 | 下一条连接自动重建 | 不重建(没有所有权) |
|
|
163
|
+
| 设备可见性 | 后端要重新独占 USB | 设备始终在原 server 上 |
|
|
164
|
+
|
|
165
|
+
另开终端正常使用 adb(默认走 5037,即经过代理):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
adb devices -l
|
|
169
|
+
adb shell echo hello
|
|
170
|
+
adb push local.apk /data/local/tmp/
|
|
171
|
+
adb install local.apk
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 2. device-proxy(模拟网络 adbd)
|
|
175
|
+
|
|
176
|
+
默认监听 `5566`,后端复用系统 `5037` adb server,把请求转发到指定真实设备。
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
uv run adbproxy device \
|
|
180
|
+
--listen 5566 \
|
|
181
|
+
--target serial:<设备序列号>
|
|
182
|
+
|
|
183
|
+
# 等价:
|
|
184
|
+
# uv run python -m adbproxy device \
|
|
185
|
+
# --listen 5566 \
|
|
186
|
+
# --target serial:<设备序列号>
|
|
187
|
+
# uv run adb-device-proxy \
|
|
188
|
+
# --listen 5566 \
|
|
189
|
+
# --target serial:<设备序列号>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`--target` 支持:
|
|
193
|
+
|
|
194
|
+
| 值 | 含义 |
|
|
195
|
+
|----|------|
|
|
196
|
+
| `usb` | 自动选择首个 USB 且状态为 `device` 的设备(默认) |
|
|
197
|
+
| `serial:<s>` | 指定序列号 |
|
|
198
|
+
| `net:<ip>:<port>` | 先 `adb connect` 到该网络设备 |
|
|
199
|
+
|
|
200
|
+
常用参数:
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
--listen PORT 监听端口,默认 5566
|
|
204
|
+
--adb-server-port PORT 后端 adb server 端口,默认 5037
|
|
205
|
+
--debug 原始 hex 落盘
|
|
206
|
+
--no-capture 禁用 sync/install 文件落盘
|
|
207
|
+
--banner-type TYPE CNXN banner 前缀,默认 device
|
|
208
|
+
--log-format {text,json} 事件日志格式,默认 text
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
另开终端连接并操作:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
adb connect 127.0.0.1:5566
|
|
215
|
+
adb -s 127.0.0.1:5566 get-state
|
|
216
|
+
adb -s 127.0.0.1:5566 shell echo hello
|
|
217
|
+
adb -s 127.0.0.1:5566 push local.apk /data/local/tmp/
|
|
218
|
+
adb disconnect 127.0.0.1:5566
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## 输出目录
|
|
222
|
+
|
|
223
|
+
| 路径 | 内容 |
|
|
224
|
+
|------|------|
|
|
225
|
+
| `out/logs/*.log` | 事件日志(默认 text 格式);加 `--debug` 时另有 debug hex 日志 |
|
|
226
|
+
| `out/logs/*.jsonl` | `--log-format json` 时的事件日志,每行一条 JSON |
|
|
227
|
+
| `out/logs/*.1` | 日志超过大小上限后转存的上一代文件(只保留一代) |
|
|
228
|
+
| `out/files/` | sync push/pull、install 流捕获(未加 `--no-capture` 时) |
|
|
229
|
+
|
|
230
|
+
单个日志文件超过 64 MiB 会转存为 `.1` 并重开,磁盘占用因此稳定在 2× 上限以内;
|
|
231
|
+
`--debug` 对每块 recv 落一整段 hexdump,长跑时增长很快,这个上限尤其有用。
|
|
232
|
+
用 `ADB_PROXY_MAX_LOG_BYTES` 调整。
|
|
233
|
+
|
|
234
|
+
JSONL 每行含 `ts` / `conn` / `level` / `msg` 四个字段(进程级消息没有 `conn`):
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
jq -r 'select(.level=="event") | "\(.conn)\t\(.msg)"' out/logs/*.jsonl
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`out/` 的位置:从源码树运行时落在项目根;通过 `pip install` / `uvx` 安装后落在当前工作目录。
|
|
241
|
+
两种情况都可用 `ADB_PROXY_OUT_DIR` 覆盖。
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
export ADB_PROXY_OUT_DIR=/tmp/adbproxy-out
|
|
245
|
+
# 写入 /tmp/adbproxy-out/logs 与 /tmp/adbproxy-out/files
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## 测试
|
|
249
|
+
|
|
250
|
+
### 准备
|
|
251
|
+
|
|
252
|
+
真机动态矩阵(push / pull / install)依赖测试 APK。仓库不附带该文件,运行前请自行放置:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# 任意可安装的 APK 即可
|
|
256
|
+
cp /path/to/your.apk tests/app.apk
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`tests/app.apk` 已在 `tests/.gitignore` 中忽略,不会被提交。
|
|
260
|
+
|
|
261
|
+
无设备的单元 / 静态测试不需要该文件。
|
|
262
|
+
|
|
263
|
+
### 环境变量
|
|
264
|
+
|
|
265
|
+
| 变量 | 说明 |
|
|
266
|
+
|------|------|
|
|
267
|
+
| `ADB_PROXY_REAL_DEVICE=1` | 启用真机动态用例;未设置时相关用例自动 skip |
|
|
268
|
+
| `ADB_PROXY_EXCLUSIVE_ADB=1` | 额外启用接管默认端口的用例;要求本机没有其它 adb 客户端 |
|
|
269
|
+
| `ADB_SERIAL` | 指定真机序列号;省略时取首个 USB 且状态为 `device` 的设备 |
|
|
270
|
+
| `ADB_PROXY_OUT_DIR` | 覆盖运行产物根目录(日志 / 抓包),默认见「输出目录」一节 |
|
|
271
|
+
| `ADB_PROXY_MAX_LOG_BYTES` | 单个日志文件的大小上限,超过即轮转,默认 64 MiB |
|
|
272
|
+
|
|
273
|
+
### 全部测试
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# 无设备:单元 + 静态;动态用例自动 skip
|
|
277
|
+
uv run python -B -m unittest discover -s tests -v
|
|
278
|
+
|
|
279
|
+
# 含真实设备动态矩阵(需先放置 tests/app.apk)
|
|
280
|
+
export ADB_PROXY_REAL_DEVICE=1
|
|
281
|
+
export ADB_SERIAL=<可选,默认取首个 USB device>
|
|
282
|
+
uv run python -B -m unittest discover -s tests -v
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 按文件运行
|
|
286
|
+
|
|
287
|
+
| 文件 | 覆盖范围 |
|
|
288
|
+
|------|----------|
|
|
289
|
+
| `tests/test_protocol_codecs.py` | smart-socket wire / classifier / conversation、payload、transport codec |
|
|
290
|
+
| `tests/test_server_connection.py` | server-proxy 转发与旁路观察、fail-open 不变量 |
|
|
291
|
+
| `tests/test_device_transport.py` | AdbdSession 决策、StreamTable、后端握手、front 传输行为 |
|
|
292
|
+
| `tests/test_observers.py` | StreamBuffer 路由、sync 分帧/压缩/落盘、install 抓包命名 |
|
|
293
|
+
| `tests/test_app_lifecycle.py` | 输出目录、cleanup 顺序、adb server lease、目标解析 |
|
|
294
|
+
| `tests/test_imports.py` | 包布局与导入 |
|
|
295
|
+
| `tests/test_cli_main.py` | 统一 CLI 分发 |
|
|
296
|
+
| `tests/test_dynamic_commands.py` | 真机动态矩阵(需 `tests/app.apk`) |
|
|
297
|
+
|
|
298
|
+
server-proxy 的动态矩阵跑在「监听空闲端口 + 复用现有 5037 作后端」的模式下,因此本机开着
|
|
299
|
+
Android Studio 之类的 adb 客户端也不影响它。接管默认端口那条路径是单独的用例,需要
|
|
300
|
+
`ADB_PROXY_EXCLUSIVE_ADB=1` 才会跑。
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
uv run python -B -m unittest tests.test_protocol_codecs -v
|
|
304
|
+
|
|
305
|
+
# 真机动态矩阵(server-proxy + device-proxy;需 tests/app.apk)
|
|
306
|
+
export ADB_PROXY_REAL_DEVICE=1
|
|
307
|
+
export ADB_SERIAL=<可选>
|
|
308
|
+
uv run python -B -m unittest tests.test_dynamic_commands -v
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 代码检查
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
uv sync --group dev
|
|
315
|
+
|
|
316
|
+
uv run ruff check . # lint
|
|
317
|
+
uv run mypy # 类型检查(协议层开启 check_untyped_defs)
|
|
318
|
+
uv run coverage run -m unittest discover -s tests && uv run coverage report
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
CI(`.github/workflows/ci.yml`)在 Python 3.10–3.13 上跑同一组命令,覆盖率低于 72% 会失败。
|
|
322
|
+
|
|
323
|
+
## 说明
|
|
324
|
+
|
|
325
|
+
- 代理是透明的:解析失败不会改写或阻断转发字节。观察器出错只降级、不影响转发,
|
|
326
|
+
被吞掉的异常在 `--debug` 下会连 traceback 写进 debug 日志,否则记一条 debug 级提示。
|
|
327
|
+
- 退出码:正常收尾为 `0`;若退出时没能把 adb server 恢复原状(例如 `adb start-server`
|
|
328
|
+
失败),返回 `1` 并在日志里给出需要手动执行的命令。
|
|
329
|
+
|
|
330
|
+
### adb kill-server 与后端自愈
|
|
331
|
+
|
|
332
|
+
`host:kill` 和别的请求一样原样转发,代理不改写这条语义:客户端拿到的是真实 server 的
|
|
333
|
+
应答,`adb kill-server` 的输出与退出码都和没有代理时一致(AOSP 服务端的处理是 `SendOkay`
|
|
334
|
+
后 `exit(0)`,因此客户端读到 OKAY 再看到连接关闭)。
|
|
335
|
+
|
|
336
|
+
后端就此退出。只要它的所有权在代理手上(默认模式下由代理启动的那个),下一条需要它的
|
|
337
|
+
连接会把它重建出来——`adb start-server`、`adb devices`、任何命令都算,这也正是 adb 自己
|
|
338
|
+
的语义:kill 之后任何需要 server 的命令都会重新唤起它。重建遵循和 lease 一样的规矩:
|
|
339
|
+
只在 ledger 能证明该端口上的 server 是本进程起的时候才动手,端口上换成了别人的实例就不碰。
|
|
340
|
+
|
|
341
|
+
自愈不只针对 kill-server:后端崩溃、被 `pkill`、被 OOM 杀掉都走同一条路径(下一条连接
|
|
342
|
+
连不上后端 → 重建 → 重试一次)。
|
|
343
|
+
|
|
344
|
+
`--reuse-adb-server` 下后端是别人的 server,代理不会替它重建;转发 kill 时日志会提醒
|
|
345
|
+
一句,之后需要自己 `adb start-server`。
|
|
346
|
+
|
|
347
|
+
顺带一提,`adb start-server` 没有对应的代理逻辑:客户端在发出 `host:start-server`
|
|
348
|
+
**之前**就 return 了(`adb_client.cpp`),线上真正到达 server 的只有 `host:version`。
|
|
349
|
+
|
|
350
|
+
### 已知限制
|
|
351
|
+
|
|
352
|
+
| 限制 | 说明 |
|
|
353
|
+
|------|------|
|
|
354
|
+
| 不支持 `A_AUTH` | device-proxy 收到 AUTH 包会终止该连接。前端需已授权、或用无需配对的连接方式 |
|
|
355
|
+
| 不支持 `A_STLS` | 同上,收到 STLS 即终止;不支持 TLS 化的 adb 连接 |
|
|
356
|
+
| v1 停等流控 | device-proxy 的 CNXN banner 会硬剥 `delayed_ack`,后端真机广告了也不透传 |
|
|
357
|
+
| 单文件捕获上限 | sync/install 落盘单文件超过 256 MiB 即停止写入并记日志 |
|
adbproxy-1.0.0/README.md
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# adbproxy
|
|
2
|
+
|
|
3
|
+
在 ADB client 与 server / 设备之间插入透明代理,解析并记录 ADB 协议流量,同时保持原始字节原样转发。
|
|
4
|
+
|
|
5
|
+
适用于调试 adb 命令、观察 shell / sync / install 等协议交互、抓取 push/pull 文件内容。
|
|
6
|
+
|
|
7
|
+
## 功能
|
|
8
|
+
|
|
9
|
+
- **server-proxy**:MITM 本机 `adb client ↔ adb server` 的 smart-socket 链路(默认监听 `5037`,真实 server 挪到 `5038`)
|
|
10
|
+
- **device-proxy**:模拟网络 adbd,接受 transport 协议连接,再经系统 adb server 转发到真实设备
|
|
11
|
+
- 解析并记录 shell、sync、install、stream 等协议事件
|
|
12
|
+
- 可选落盘 sync / install 文件内容,以及 `--debug` 原始 hex
|
|
13
|
+
- 观察 / 解码 / 抓包失败时 fail-open,不中断透明转发
|
|
14
|
+
|
|
15
|
+
## 架构
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
Client[adb client]
|
|
20
|
+
SP[server-proxy :5037]
|
|
21
|
+
Server[adb server :5038]
|
|
22
|
+
Dev[真实设备]
|
|
23
|
+
|
|
24
|
+
Client -->|smart socket| SP
|
|
25
|
+
SP -->|smart socket| Server
|
|
26
|
+
Server --> Dev
|
|
27
|
+
|
|
28
|
+
Client2[adb client]
|
|
29
|
+
ServerFront[adb server :5037]
|
|
30
|
+
DP[device-proxy :5566]
|
|
31
|
+
ServerBack[adb server :5037]
|
|
32
|
+
Dev2[真实设备]
|
|
33
|
+
|
|
34
|
+
Client2 -->|smart socket| ServerFront
|
|
35
|
+
ServerFront -->|transport| DP
|
|
36
|
+
DP -->|smart socket| ServerBack
|
|
37
|
+
ServerBack --> Dev2
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 环境要求
|
|
41
|
+
|
|
42
|
+
- Python ≥ 3.10
|
|
43
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
44
|
+
- 系统 `adb`(Android platform-tools)
|
|
45
|
+
|
|
46
|
+
## 安装
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone <repo-url>
|
|
50
|
+
cd adbproxy # 或你的本地目录名
|
|
51
|
+
uv sync
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
也可从 PyPI:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install adbproxy
|
|
58
|
+
# 可选:sync 解压依赖
|
|
59
|
+
pip install "adbproxy[decompress]"
|
|
60
|
+
|
|
61
|
+
# 临时运行
|
|
62
|
+
uvx adbproxy server --help
|
|
63
|
+
uvx adbproxy device --help
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`uv sync` 会安装依赖,并根据 `pyproject.toml` 的 `[project.scripts]` 注册命令行入口:
|
|
67
|
+
|
|
68
|
+
| 命令 | 对应模块 | 作用 |
|
|
69
|
+
|------|----------|------|
|
|
70
|
+
| `adbproxy` | `adbproxy.cli.main:main` | **推荐**统一入口:`server` / `device` 子命令 |
|
|
71
|
+
| `adb-server-proxy` | `adbproxy.cli.server:main` | 兼容旧入口(等同 `adbproxy server`) |
|
|
72
|
+
| `adb-device-proxy` | `adbproxy.cli.device:main` | 兼容旧入口(等同 `adbproxy device`) |
|
|
73
|
+
|
|
74
|
+
推荐启动方式:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# 统一入口(推荐)
|
|
78
|
+
uv run adbproxy server --help
|
|
79
|
+
uv run adbproxy device --help
|
|
80
|
+
uv run python -m adbproxy server --help
|
|
81
|
+
uv run python -m adbproxy device --help
|
|
82
|
+
|
|
83
|
+
# 兼容旧 console script / 模块路径
|
|
84
|
+
uv run adb-server-proxy --help
|
|
85
|
+
uv run adb-device-proxy --help
|
|
86
|
+
uv run python -m adbproxy.cli.server --help
|
|
87
|
+
uv run python -m adbproxy.cli.device --help
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
下文示例统一使用 `adbproxy server` / `adbproxy device`。
|
|
91
|
+
|
|
92
|
+
## 使用
|
|
93
|
+
|
|
94
|
+
### 1. server-proxy(MITM 本机 5037)
|
|
95
|
+
|
|
96
|
+
启动前确认本机 `5038` 未被占用。代理会接管默认 `5037`,把真实 adb server 挪到 `5038`;退出时按所有权恢复。
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uv run adbproxy server
|
|
100
|
+
# 等价:
|
|
101
|
+
# uv run python -m adbproxy server
|
|
102
|
+
# uv run adb-server-proxy
|
|
103
|
+
|
|
104
|
+
# 可选参数:
|
|
105
|
+
# --debug 将每段 recv 的原始 hex 落盘
|
|
106
|
+
# --no-capture 不落盘 sync/install 文件,仅打印摘要
|
|
107
|
+
# --log-format json 事件日志写成 JSONL(默认 text)
|
|
108
|
+
# --listen PORT 代理监听端口,即 adb client 连的那个(默认 5037)
|
|
109
|
+
# --adb-server-port PORT 转发到的真实 adb server 端口(默认 5038)
|
|
110
|
+
# --reuse-adb-server 复用已在运行的后端 server,不接管也不启停任何 server
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
两个端口成对使用:`--listen` 是要从真 adb server 手里接管的端口,`--adb-server-port`
|
|
114
|
+
是真 server 被挪去的地方。改这两个值可以同时跑多个实例,或在默认端口被别的工具占用时改道:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# 接管 6037,把真实 server 放到 6038
|
|
118
|
+
uv run adbproxy server --listen 6037 --adb-server-port 6038
|
|
119
|
+
adb -P 6037 devices -l
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### 复用模式(不接管任何 server)
|
|
123
|
+
|
|
124
|
+
`--reuse-adb-server` 让代理只做转发:不 kill 监听端口上的实例、不起新的后端、退出时也
|
|
125
|
+
没有要恢复的东西。适合本机还有别的 adb 客户端(IDE 之类)时挂一层观察——它们继续用
|
|
126
|
+
默认 5037,你用代理端口:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# 监听 6037,转发到已在运行的 5037
|
|
130
|
+
uv run adbproxy server --listen 6037 --adb-server-port 5037 --reuse-adb-server
|
|
131
|
+
adb -P 6037 shell echo hello # 经过代理
|
|
132
|
+
adb devices -l # 不经过代理,照常工作
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
两种模式的区别:
|
|
136
|
+
|
|
137
|
+
| | 默认(接管) | `--reuse-adb-server` |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| 监听端口上的真 server | 先 kill,退出时恢复 | 不碰(该端口必须空闲,否则 bind 失败) |
|
|
140
|
+
| 后端 server | 由代理启动并持有所有权 | 必须已在运行;代理不启不停 |
|
|
141
|
+
| 后端意外死掉 | 下一条连接自动重建 | 不重建(没有所有权) |
|
|
142
|
+
| 设备可见性 | 后端要重新独占 USB | 设备始终在原 server 上 |
|
|
143
|
+
|
|
144
|
+
另开终端正常使用 adb(默认走 5037,即经过代理):
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
adb devices -l
|
|
148
|
+
adb shell echo hello
|
|
149
|
+
adb push local.apk /data/local/tmp/
|
|
150
|
+
adb install local.apk
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 2. device-proxy(模拟网络 adbd)
|
|
154
|
+
|
|
155
|
+
默认监听 `5566`,后端复用系统 `5037` adb server,把请求转发到指定真实设备。
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
uv run adbproxy device \
|
|
159
|
+
--listen 5566 \
|
|
160
|
+
--target serial:<设备序列号>
|
|
161
|
+
|
|
162
|
+
# 等价:
|
|
163
|
+
# uv run python -m adbproxy device \
|
|
164
|
+
# --listen 5566 \
|
|
165
|
+
# --target serial:<设备序列号>
|
|
166
|
+
# uv run adb-device-proxy \
|
|
167
|
+
# --listen 5566 \
|
|
168
|
+
# --target serial:<设备序列号>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`--target` 支持:
|
|
172
|
+
|
|
173
|
+
| 值 | 含义 |
|
|
174
|
+
|----|------|
|
|
175
|
+
| `usb` | 自动选择首个 USB 且状态为 `device` 的设备(默认) |
|
|
176
|
+
| `serial:<s>` | 指定序列号 |
|
|
177
|
+
| `net:<ip>:<port>` | 先 `adb connect` 到该网络设备 |
|
|
178
|
+
|
|
179
|
+
常用参数:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
--listen PORT 监听端口,默认 5566
|
|
183
|
+
--adb-server-port PORT 后端 adb server 端口,默认 5037
|
|
184
|
+
--debug 原始 hex 落盘
|
|
185
|
+
--no-capture 禁用 sync/install 文件落盘
|
|
186
|
+
--banner-type TYPE CNXN banner 前缀,默认 device
|
|
187
|
+
--log-format {text,json} 事件日志格式,默认 text
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
另开终端连接并操作:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
adb connect 127.0.0.1:5566
|
|
194
|
+
adb -s 127.0.0.1:5566 get-state
|
|
195
|
+
adb -s 127.0.0.1:5566 shell echo hello
|
|
196
|
+
adb -s 127.0.0.1:5566 push local.apk /data/local/tmp/
|
|
197
|
+
adb disconnect 127.0.0.1:5566
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## 输出目录
|
|
201
|
+
|
|
202
|
+
| 路径 | 内容 |
|
|
203
|
+
|------|------|
|
|
204
|
+
| `out/logs/*.log` | 事件日志(默认 text 格式);加 `--debug` 时另有 debug hex 日志 |
|
|
205
|
+
| `out/logs/*.jsonl` | `--log-format json` 时的事件日志,每行一条 JSON |
|
|
206
|
+
| `out/logs/*.1` | 日志超过大小上限后转存的上一代文件(只保留一代) |
|
|
207
|
+
| `out/files/` | sync push/pull、install 流捕获(未加 `--no-capture` 时) |
|
|
208
|
+
|
|
209
|
+
单个日志文件超过 64 MiB 会转存为 `.1` 并重开,磁盘占用因此稳定在 2× 上限以内;
|
|
210
|
+
`--debug` 对每块 recv 落一整段 hexdump,长跑时增长很快,这个上限尤其有用。
|
|
211
|
+
用 `ADB_PROXY_MAX_LOG_BYTES` 调整。
|
|
212
|
+
|
|
213
|
+
JSONL 每行含 `ts` / `conn` / `level` / `msg` 四个字段(进程级消息没有 `conn`):
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
jq -r 'select(.level=="event") | "\(.conn)\t\(.msg)"' out/logs/*.jsonl
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`out/` 的位置:从源码树运行时落在项目根;通过 `pip install` / `uvx` 安装后落在当前工作目录。
|
|
220
|
+
两种情况都可用 `ADB_PROXY_OUT_DIR` 覆盖。
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
export ADB_PROXY_OUT_DIR=/tmp/adbproxy-out
|
|
224
|
+
# 写入 /tmp/adbproxy-out/logs 与 /tmp/adbproxy-out/files
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 测试
|
|
228
|
+
|
|
229
|
+
### 准备
|
|
230
|
+
|
|
231
|
+
真机动态矩阵(push / pull / install)依赖测试 APK。仓库不附带该文件,运行前请自行放置:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# 任意可安装的 APK 即可
|
|
235
|
+
cp /path/to/your.apk tests/app.apk
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
`tests/app.apk` 已在 `tests/.gitignore` 中忽略,不会被提交。
|
|
239
|
+
|
|
240
|
+
无设备的单元 / 静态测试不需要该文件。
|
|
241
|
+
|
|
242
|
+
### 环境变量
|
|
243
|
+
|
|
244
|
+
| 变量 | 说明 |
|
|
245
|
+
|------|------|
|
|
246
|
+
| `ADB_PROXY_REAL_DEVICE=1` | 启用真机动态用例;未设置时相关用例自动 skip |
|
|
247
|
+
| `ADB_PROXY_EXCLUSIVE_ADB=1` | 额外启用接管默认端口的用例;要求本机没有其它 adb 客户端 |
|
|
248
|
+
| `ADB_SERIAL` | 指定真机序列号;省略时取首个 USB 且状态为 `device` 的设备 |
|
|
249
|
+
| `ADB_PROXY_OUT_DIR` | 覆盖运行产物根目录(日志 / 抓包),默认见「输出目录」一节 |
|
|
250
|
+
| `ADB_PROXY_MAX_LOG_BYTES` | 单个日志文件的大小上限,超过即轮转,默认 64 MiB |
|
|
251
|
+
|
|
252
|
+
### 全部测试
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# 无设备:单元 + 静态;动态用例自动 skip
|
|
256
|
+
uv run python -B -m unittest discover -s tests -v
|
|
257
|
+
|
|
258
|
+
# 含真实设备动态矩阵(需先放置 tests/app.apk)
|
|
259
|
+
export ADB_PROXY_REAL_DEVICE=1
|
|
260
|
+
export ADB_SERIAL=<可选,默认取首个 USB device>
|
|
261
|
+
uv run python -B -m unittest discover -s tests -v
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 按文件运行
|
|
265
|
+
|
|
266
|
+
| 文件 | 覆盖范围 |
|
|
267
|
+
|------|----------|
|
|
268
|
+
| `tests/test_protocol_codecs.py` | smart-socket wire / classifier / conversation、payload、transport codec |
|
|
269
|
+
| `tests/test_server_connection.py` | server-proxy 转发与旁路观察、fail-open 不变量 |
|
|
270
|
+
| `tests/test_device_transport.py` | AdbdSession 决策、StreamTable、后端握手、front 传输行为 |
|
|
271
|
+
| `tests/test_observers.py` | StreamBuffer 路由、sync 分帧/压缩/落盘、install 抓包命名 |
|
|
272
|
+
| `tests/test_app_lifecycle.py` | 输出目录、cleanup 顺序、adb server lease、目标解析 |
|
|
273
|
+
| `tests/test_imports.py` | 包布局与导入 |
|
|
274
|
+
| `tests/test_cli_main.py` | 统一 CLI 分发 |
|
|
275
|
+
| `tests/test_dynamic_commands.py` | 真机动态矩阵(需 `tests/app.apk`) |
|
|
276
|
+
|
|
277
|
+
server-proxy 的动态矩阵跑在「监听空闲端口 + 复用现有 5037 作后端」的模式下,因此本机开着
|
|
278
|
+
Android Studio 之类的 adb 客户端也不影响它。接管默认端口那条路径是单独的用例,需要
|
|
279
|
+
`ADB_PROXY_EXCLUSIVE_ADB=1` 才会跑。
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
uv run python -B -m unittest tests.test_protocol_codecs -v
|
|
283
|
+
|
|
284
|
+
# 真机动态矩阵(server-proxy + device-proxy;需 tests/app.apk)
|
|
285
|
+
export ADB_PROXY_REAL_DEVICE=1
|
|
286
|
+
export ADB_SERIAL=<可选>
|
|
287
|
+
uv run python -B -m unittest tests.test_dynamic_commands -v
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### 代码检查
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
uv sync --group dev
|
|
294
|
+
|
|
295
|
+
uv run ruff check . # lint
|
|
296
|
+
uv run mypy # 类型检查(协议层开启 check_untyped_defs)
|
|
297
|
+
uv run coverage run -m unittest discover -s tests && uv run coverage report
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
CI(`.github/workflows/ci.yml`)在 Python 3.10–3.13 上跑同一组命令,覆盖率低于 72% 会失败。
|
|
301
|
+
|
|
302
|
+
## 说明
|
|
303
|
+
|
|
304
|
+
- 代理是透明的:解析失败不会改写或阻断转发字节。观察器出错只降级、不影响转发,
|
|
305
|
+
被吞掉的异常在 `--debug` 下会连 traceback 写进 debug 日志,否则记一条 debug 级提示。
|
|
306
|
+
- 退出码:正常收尾为 `0`;若退出时没能把 adb server 恢复原状(例如 `adb start-server`
|
|
307
|
+
失败),返回 `1` 并在日志里给出需要手动执行的命令。
|
|
308
|
+
|
|
309
|
+
### adb kill-server 与后端自愈
|
|
310
|
+
|
|
311
|
+
`host:kill` 和别的请求一样原样转发,代理不改写这条语义:客户端拿到的是真实 server 的
|
|
312
|
+
应答,`adb kill-server` 的输出与退出码都和没有代理时一致(AOSP 服务端的处理是 `SendOkay`
|
|
313
|
+
后 `exit(0)`,因此客户端读到 OKAY 再看到连接关闭)。
|
|
314
|
+
|
|
315
|
+
后端就此退出。只要它的所有权在代理手上(默认模式下由代理启动的那个),下一条需要它的
|
|
316
|
+
连接会把它重建出来——`adb start-server`、`adb devices`、任何命令都算,这也正是 adb 自己
|
|
317
|
+
的语义:kill 之后任何需要 server 的命令都会重新唤起它。重建遵循和 lease 一样的规矩:
|
|
318
|
+
只在 ledger 能证明该端口上的 server 是本进程起的时候才动手,端口上换成了别人的实例就不碰。
|
|
319
|
+
|
|
320
|
+
自愈不只针对 kill-server:后端崩溃、被 `pkill`、被 OOM 杀掉都走同一条路径(下一条连接
|
|
321
|
+
连不上后端 → 重建 → 重试一次)。
|
|
322
|
+
|
|
323
|
+
`--reuse-adb-server` 下后端是别人的 server,代理不会替它重建;转发 kill 时日志会提醒
|
|
324
|
+
一句,之后需要自己 `adb start-server`。
|
|
325
|
+
|
|
326
|
+
顺带一提,`adb start-server` 没有对应的代理逻辑:客户端在发出 `host:start-server`
|
|
327
|
+
**之前**就 return 了(`adb_client.cpp`),线上真正到达 server 的只有 `host:version`。
|
|
328
|
+
|
|
329
|
+
### 已知限制
|
|
330
|
+
|
|
331
|
+
| 限制 | 说明 |
|
|
332
|
+
|------|------|
|
|
333
|
+
| 不支持 `A_AUTH` | device-proxy 收到 AUTH 包会终止该连接。前端需已授权、或用无需配对的连接方式 |
|
|
334
|
+
| 不支持 `A_STLS` | 同上,收到 STLS 即终止;不支持 TLS 化的 adb 连接 |
|
|
335
|
+
| v1 停等流控 | device-proxy 的 CNXN banner 会硬剥 `delayed_ack`,后端真机广告了也不透传 |
|
|
336
|
+
| 单文件捕获上限 | sync/install 落盘单文件超过 256 MiB 即停止写入并记日志 |
|