9.9 KiB
Boss Android ADB 无线保活设计
1. 背景
当前 Boss 仓库已经有原生 Android 客户端、APK/AAB 构建脚本和真机验证习惯,但没有一套稳定的 Android 无线 ADB 保活方案。实际调试中,Android 的无线调试会因为重启、切 Wi-Fi、ADB server 重启、USB 调试切换等原因自动失效,导致每次真机回归都需要重新恢复连接。
这次工作的目标不是绕过 Android 系统限制,也不是把设备管理做成 MDM,而是在本机增加一套可长期后台运行的自动重连守护流程,尽量降低“设备本来还允许 TCP/IP ADB,但连接自己掉了”这类问题的人工恢复成本。
2. 目标与非目标
2.1 目标
- 支持多台 Android 设备在同一局域网内自动重连 ADB 无线连接。
- 后台常驻运行,不要求人工一直开终端窗口守着。
- 自动扫描当前所在子网的
5555端口,但只对白名单设备或历史已成功授权的设备执行自动重连。 - 提供明确的状态、日志和失败退避,避免误连和刷屏。
- 与 Boss 当前本机运维方式保持一致,优先走
scripts/+launchd。
2.2 非目标
- 不负责替 Android 设备开启开发者选项、USB 调试或无线调试。
- 不尝试绕过 Android 的系统限制,不能承诺“永久保持无线调试开启”。
- 不做跨子网、跨 VPN、跨公网的设备发现。
- 不做完整移动设备管理平台,不接入 Web/Android 前台页面。
3. 方案对比
3.1 方案 A:全网段无差别扫描并直接 adb connect
做法:周期性扫描当前子网所有开放 5555 的主机,发现后直接 adb connect <ip>:5555。
优点:
- 配置最少。
- 自动化程度最高。
缺点:
- 容易误连同网段里的其他 Android、电视盒子或调试设备。
- 日志会混入大量非目标主机。
- 风险和噪音都偏高,不适合默认行为。
结论:不采用。
3.2 方案 B:仅对固定 IP 清单做重连
做法:只维护一份静态 IP 列表,循环对这些地址做 adb connect。
优点:
- 最稳、最可控。
- 实现简单。
缺点:
- 手机 IP 一变就失效。
- 不符合“自动扫描同网段”的目标。
结论:可作为降级模式保留,但不作为主方案。
3.3 方案 C:自动扫描同网段,但只对白名单或历史已授权设备重连
做法:周期性推断当前活跃子网,扫描开放 5555 的主机;只对白名单设备或历史上曾成功连接并被缓存的设备执行 adb connect。
优点:
- 满足自动扫描同网段的要求。
- 风险可控,不会默认接入陌生主机。
- 适合多设备长期保活。
缺点:
- 需要维护配置文件与运行态缓存。
- 新设备第一次仍需手工建立一次可信连接。
结论:采用本方案。
4. 目标架构
新增一套本机运维脚本与守护配置:
scripts/adb-wireless-keeper.mjsscripts/adb-wireless-keeper-once.shscripts/adb-wireless-keeper-status.shscripts/install-adb-wireless-keeper.shscripts/uninstall-adb-wireless-keeper.shconfig/adb-wireless-keeper.jsondeployment/launchd/com.hyzq.boss.adb-wireless-keeper.plistdata/adb-wireless-keeper-state.jsondata/adb-wireless-keeper.log.jsonl
职责分层:
adb-wireless-keeper.mjs- 负责扫描、识别、重连、退避和状态落盘。
*-once.sh- 负责单次执行,便于人工调试。
*-status.sh- 负责打印当前守护状态、最近扫描和最近失败原因。
install/uninstall- 负责安装和卸载
launchd常驻服务。
- 负责安装和卸载
launchd plist- 负责开机自启、异常自动拉起。
5. 配置模型
配置文件建议为 config/adb-wireless-keeper.json:
{
"subnets": [],
"scanIntervalSeconds": 30,
"connectTimeoutMs": 4000,
"adbPath": "",
"logFile": "data/adb-wireless-keeper.log.jsonl",
"stateFile": "data/adb-wireless-keeper-state.json",
"allowedDevices": [
{
"label": "boss-oppo-main",
"serialHint": "8KE0219724012168",
"ipHint": "192.168.31.18"
}
]
}
约束:
subnets为空时,脚本自动根据当前默认路由推断活跃子网。allowedDevices是自动重连的上限范围;未知设备默认只记录日志,不直接接管。serialHint与ipHint允许为空,但至少应有一个可用于匹配。adbPath为空时,优先走 PATH 中的adb。
6. 运行态模型
运行态文件 data/adb-wireless-keeper-state.json 至少记录:
{
"lastSubnet": "192.168.31.0/24",
"lastScanAt": "2026-04-05T12:00:00.000Z",
"nextScanAt": "2026-04-05T12:00:30.000Z",
"knownDevices": {
"boss-oppo-main": {
"serial": "8KE0219724012168",
"lastKnownIp": "192.168.31.18",
"lastConnectedAt": "2026-04-05T11:59:58.000Z",
"lastFailureAt": "",
"failureCount": 0,
"backoffUntil": ""
}
}
}
用途:
- 记住最近成功连接的
serial <-> ip映射。 - 为失败退避提供依据。
- 让
status脚本直接读取当前状态,而不必解析全量日志。
7. 扫描与重连策略
7.1 子网推断
- 读取当前默认路由对应的活跃网卡。
- 获取该网卡 IPv4 地址。
- 默认把扫描范围收敛到当前主机所在的
/24。 - 如果配置文件显式给了
subnets,优先使用显式配置。
这样做的原因是:家庭/办公网络里经常出现大网段,直接扫更大的 CIDR 成本和噪音都太高。
7.2 每轮扫描步骤
- 先执行
adb devices -l,记录当前已在线设备。 - 扫描目标子网中开放
5555的主机。 - 对每个开放地址:
- 若命中白名单或命中历史成功缓存,进入候选集。
- 若是陌生地址,仅记录
device_skipped_unknown日志,不直接接入。
- 对候选集里当前离线的设备执行
adb connect <ip>:5555。 - 成功则更新状态文件;失败则更新失败计数和退避时间。
7.3 新设备接入
新设备第一次不自动纳管。建议流程:
- 用户先通过 USB 或手工
adb connect成功连一次。 - 将设备补进
allowedDevices。 - 守护脚本后续自动接管该设备的无线重连。
8. 失败处理与退避
脚本必须把“掉线可恢复”和“系统级失效不可恢复”分开处理。
8.1 可恢复场景
- 局域网短时抖动。
adb连接断开,但设备仍允许 TCP/IP ADB。- ADB server 重启后需要重新
connect。
这些场景应自动恢复。
8.2 不可恢复场景
- 设备重启后无线调试被系统关闭。
- 用户关闭开发者选项或 USB 调试。
- 手机切到其他 Wi-Fi、热点或 VPN 导致不在同一子网。
- 设备根本不再监听
5555。
这些场景脚本只能记录并退避,不能声称“已经修复”。
8.3 退避规则
建议采用分级退避:
- 第 1 次失败:30 秒后再试
- 第 2-3 次失败:2 分钟后再试
- 第 4 次及以上失败:5 分钟后再试
目的:
- 避免在设备失效时疯狂刷
adb connect。 - 保留可读日志。
- 降低对局域网的无意义探测。
9. 日志设计
日志采用 JSONL,每行一个事件,路径默认 data/adb-wireless-keeper.log.jsonl。
字段建议:
tseventsubnetipseriallabelresultreason
事件枚举建议:
scan_startedscan_finishedhost_port_opendevice_alloweddevice_skipped_unknowndevice_already_onlineconnect_attemptconnect_successconnect_failedbackoff_applied
10. 运维入口
10.1 安装
scripts/install-adb-wireless-keeper.sh
职责:
- 校验
adb是否存在。 - 校验配置文件是否存在。
- 渲染并安装
launchdplist。 - 启动守护进程。
10.2 卸载
scripts/uninstall-adb-wireless-keeper.sh
职责:
- 停止并卸载
launchd服务。 - 保留日志和状态文件,不自动删除。
10.3 状态查看
scripts/adb-wireless-keeper-status.sh
输出至少包含:
- 当前守护状态。
- 当前扫描子网。
- 当前在线设备。
- 最近失败原因。
- 下次扫描时间。
10.4 单次调试
scripts/adb-wireless-keeper-once.sh
用于本地人工验证“一轮扫描 + 一轮重连”,不需要先装 launchd。
11. 验收标准
必须同时满足以下 4 条:
- 已纳管设备掉线后,守护脚本能在设定周期内自动恢复
adb connect。 - 陌生
5555主机不会被自动长期接入,只会记录日志。 - 设备重启或系统撤销无线调试时,脚本进入退避,不会疯狂重试。
status命令能直接给出当前子网、在线设备、最近失败原因和下一次扫描时间。
12. 测试策略
优先补 Node 侧单测,不引入 Android 侧改动。
建议覆盖:
- 配置解析。
- 子网收敛逻辑。
- 白名单过滤逻辑。
- 历史成功设备匹配逻辑。
- 失败退避逻辑。
- 状态文件读写。
- 日志事件格式。
此外保留一轮人工验证:
- 先手工把一台已纳管设备连上无线 ADB。
- 手工执行
adb disconnect <ip>:5555。 - 观察守护脚本是否在预期周期内自动恢复。
13. 风险与边界
- Android 系统没有官方“永久保持无线调试开启”的机制,所以这个方案只能做自动恢复,不能承诺永不失效。
- 自动扫描网络天然有噪音,必须坚持“只对白名单或历史已授权设备自动重连”的边界。
- 大网段环境下必须收敛扫描范围,默认仅扫当前
/24。 - 如果用户要求“绝不掉线”,仍应保留 USB 作为最终兜底方案。
14. 实施建议
推荐按以下顺序实施:
- 先完成
adb-wireless-keeper.mjs的纯逻辑与单测。 - 再补
status/once/install/uninstall四个壳脚本。 - 最后补
launchdplist 与 README 文档入口。
这样做的原因是:先把可测试的核心逻辑收口,再把平台相关的守护安装步骤补上,调试成本最低。