最近某项目组提交了一台跑 Android 16 的 EDLA 设备做兼容性认证,结果在 CTS 阶段被CtsConnectivityMultiDevicesTestCases这个模块卡住了,挂了五个用例。这个模块是专门测多设备连接场景的,Wi-Fi Direct、蓝牙、USB网络共享、热点、以太网全在里面,EDLA设备因为系统定制深、策略多,跑这个模块出问题一点都不意外。
我接手排查后,把每个失败项的日志、复现路径、根因和最终处理方式都记录了下来,整理成这篇排查实录。内容会比较细,适合正在做 Android 厂商定制、EDLA认证、或者被 CTS 连接类用例折磨过的系统工程师参考。如果你刚入行,也能通过这篇文章理解 CTS 多设备测试的运行逻辑和排查思路。
1. CtsConnectivityMultiDevicesTestCases到底在测什么
1.1 这个模块覆盖的连接能力地图
CtsConnectivityMultiDevicesTestCases是 CTS 里专门针对多设备交互场景的验证用例集,名字已经写得很直接:MultiDevices。它假设被测设备和另一台标准设备之间能够建立不同类型的连接,并完成数据收发、服务发现、配对绑定等操作。
具体覆盖这几个方向:
- Wi-Fi Direct(P2P):设备间点对点发现、连接、传输文件
- 蓝牙经典模式:扫描、配对、连接、传输数据
- BLE 低功耗蓝牙:广播扫描、GATT 连接、服务发现
- USB 网络共享(Tethering):设备通过 USB 线给另一台设备提供网络
- Wi-Fi 热点:设备作为 AP 提供网络接入
- 以太网(如果设备有网口):有线连接的启用和配置
在普通消费手机上,这些功能看起来只是“设置里的几个开关”。但在 EDLA 设备上,它们往往是核心业务通道。比如手持扫码终端要通过 Wi-Fi Direct 连接打印机,工业平板的 BLE 要对接多个外设传感器,POS 机要用 USB 共享网络给配套设备联网。所以这个模块对 EDLA 认证来说不是可选项,而是实打实的必过项。
用例的执行方式也很有特点:不是单机自测,而是测试框架会把两台设备(一台被测设备 DUT、一台辅助设备 Helper)拉到同一个场景里,让它们互相发现、互相连接,最后校验连接结果是否符合预期。所以这个模块的失败,既可能出在被测设备,也可能出在辅助设备,甚至可能出在两台设备之间的环境协作上。
1.2 为什么 EDLA 设备一跑这个模块就容易翻车
我做过几个 EDLA 设备的兼容性适配,最大的感受是:这个模块在定制系统上出问题的概率,远高于普通手机。
第一个原因是 ROM 裁剪和功能收紧。EDLA 设备往往是专用设备,系统镜像很小,厂商会把认为“用不上”的组件裁掉,比如去掉部分网络服务、去掉蓝牙模块的某些 profile、或者禁用 Wi-Fi Direct 的自动连接策略。这些裁剪在业务 App 跑起来可能没感觉,但 CTS 是用系统级 API 的方式去调用的,比如直接调用 WifiP2pManager.discoverPeers(),系统底层一旦缺了对应的 service,调用就返回异常,用例直接失败。
第二个原因是企业设备管理策略。EDLA 这个协议本身就是面向企业受管设备的,所以设备上很可能预置了 Device Owner 或 Managed Profile。CA 一旦存在,某些系统行为就会变,比如 USB 网络共享被策略禁用、蓝牙配对弹窗被拦截、Wi-Fi Direct 的邀请被静默拒绝。这些策略在真机业务场景里可能是正确的(比如企业不希望员工随便开热点),但在 CTS 环境里,它们会让原生功能不可用,导致测试断言失败。
第三个原因是硬件能力差异。很多 EDLA 设备用的是工业级模组,蓝牙连接数、Wi-Fi Direct 并发能力、天线性能都跟旗舰手机没法比。CTS 里有些用例是并发场景,比如同一时间连接两台 BLE 设备,如果蓝牙模组的并发连接数上限被设成 1,那第二个连接必然失败。
所以每次看到这个模块有 fail 项,我的第一反应不是“设备坏了”,而是先去确认:是不是策略挡了?是不是裁剪裁掉了?是不是硬件能力不够?这些因素占比加起来,比真正的兼容性 BUG 多得多。
2. 上手排查的正确姿势:先看懂失败,再动手改
2.1 失败信息里藏着三种情况,别一上来就改代码
拿到一个 fail 项,第一步不是打开源码找逻辑,而是先把失败信息读透。CTS 的失败输出会明确告诉你这个用例是哪种失败类型,常见的有三种。
第一种是环境类失败,典型表现是 timeout、setup failed、device disconnected。这种失败意味着测试根本没能进入验证环节,可能只是两台设备没配对成功、USB 掉线了、或者网络没通。环境类失败里,很大一部分是测试现场的问题,比如辅助设备没进入测试模式、USB 线松动、Wi-Fi 信号干扰。
第二种是行为类失败,表现是 assertion failed、expected true but was false。这种说明测试确实跑到了验证逻辑,但设备返回的结果不符合 CTS 预期。这类失败才真正指向设备行为问题,需要深入看 log。
第三种是崩溃类失败,表现是 crash、process crashed、exception。这种情况通常是系统服务在调用过程中抛了异常,比如某个 Binder 服务没绑定、某个 service 进程被杀掉。
区分这三种情况有个简单的判读方法:看测试输出的 failure line 前面有没有“setup”字样。setup 阶段失败,优先查环境和前置条件;断言阶段失败,才需要盯着设备日志分析。我见过不少人拿一个 timeout 日志去翻了一个下午源码,最后发现就是 USB 没插紧,这种冤枉路没必要走。
2.2 日志取证顺序:从tradefed到systrace
确认失败类型之后,就要按顺序收集现场证据。这个顺序很重要,因为先拿到全局信息,再往下钻细节,比一开始就扎进某一行 log 要高效得多。
第一步是看 tradefed 的命令行输出。跑模块的时候,控制台会打印每个用例的执行结果和失败摘要。把这些信息保存下来,先确认失败的是哪几个用例、失败类型是什么、有没有相关联的前置用例。
第二步是抓 bugreport。在测试失败之后,立即执行 adb bugreport,它会打包系统的当前状态、运行中的服务、网络配置、最近的事件日志。EDLA 设备还能看到 enterprise policy 的快照,这对于判断“是不是策略拦截”非常有用。
第三步是抓两台设备的 logcat。注意,这里说的是两台设备,不是只有被测设备。因为多设备用例里辅助设备也在参与交互,很多问题其实是辅助设备那边的行为导致的。抓日志建议用 adb logcat -b all -v threadtime,把 buffer 全带上,时间戳要准确,不然后续对日志时序会很痛苦。
第四步是确认偶发性。如果一个用例失败但它不是稳定复现,就先别急着分析,可以用 retry 选项重跑几次。命令行里一般是这样:
run cts -m CtsConnectivityMultiDevicesTestCases --retry 3retry 3 之后如果用例能过,那大概率是环境抖动,比如蓝牙被微波炉干扰了一下。如果 retry 还是挂,再去深挖。对于偶现问题,我给的建议是抓 systrace,因为 systrace 能看到系统服务之间的调用时序,很多“时好时坏”的问题只有从时序里才能看出端倪。
在 EDLA 设备上,还要额外留意一个关键词:EnterpriseDevicePolicyController。这个类负责企业策略的裁决,如果 logcat 里出现这个类的调用记录,尤其是带 denial、not allowed、restricted 这类关键字,那基本可以确定某个功能是被设备所有者策略挡住的。这也是 EDLA 设备和普通设备在排查上最大的区别。
3. 三个真实失败项的排查实录
3.1 案例一:Wi-Fi Direct 扫描超过两分钟还没发现对端
这台被测设备是一台 X 型手持终端,Android 16 预览版固件,跑 CtsConnectivityMultiDevicesTestCases 时,Wi-Fi Direct 相关的几个用例报 TimeoutException,具体表现是:discoverPeers() 调用返回成功,但 onPeersAvailable 一直没回调,或者回调里 peers 列表为空。
我一开始以为是 Wi-Fi 信号问题,手动测了一下设备自带的 Wi-Fi Direct 功能,结果有个奇怪的现象:设备 A 能扫到设备 B,但设备 B 扫不到设备 A。这个不对称实在太可疑了,问题大概率出在被测设备的 P2P 协议栈这一层。
然后抓了 wpa_supplicant 的日志,发现 p2p0 接口状态一直是 DISABLED。进一步查系统的网络策略配置,发现某厂商的定制网络模块里加了一条接口过滤规则,把除 wlan0、eth0、usb0 之外的所有接口都列为不托管状态。p2p0 虽然创建了,但没有被纳入系统的网络管理范畴,所以 wpa_supplicant 的 group 始终建不起来,P2P 设备发现自然无法完成。
处理方式很直接:修改网络策略配置,把 p2p 接口纳入管理范围。具体说来是在该定制功能的接口白名单里加上 p2p0,同时保留其他接口的配置不变。改完之后重新刷固件,再跑这个模块,Wi-Fi Direct 相关用例全部通过。
这个案例给我一个提醒:EDLA 设备经常有自定义的网络策略,这些策略在 ROM 里写得比较隐蔽,不一定会主动报错,但 CTS 对系统 API 的调用是全链路的,任何一个环节被掐断,都会以超时或断言失败的形式暴露出来。
3.2 案例二:BLE 多连接场景第二台设备连接失败
这个项目的工件是一台 Y 型工业平板,测试用例要求被测设备能够同时建立多个 BLE 连接,然后对每个连接的设备分别执行 GATT 操作。第一次跑的时候,第一台辅助设备连接成功,第二台辅助设备一直回调 onConnectionStateChange 为 STATUS_CONNECTION_FAILED。
反复跑了几次都一样,排除环境干扰。抓了 Bluetooth 相关的所有日志,发现一个关键信息:底层 HCI 层的 connection handle 只分配了一个,之后新的连接请求直接返回资源不足。这就基本锁定了问题方向——蓝牙控制器或驱动层的并发连接数被限制。
查了这台设备的蓝牙配置,原来是某厂商的蓝牙模组在适配时,把最大并发连接数(max_connections)设成了 1。这个限制对普通扫码场景够用,因为一次只需要连一台打印机,但 CTS 的 BLE 并发用例要求至少能同时连接两台设备。这不是功能逻辑出错,而是硬件能力和测试要求不匹配。
处理方式是修改蓝牙配置文件的连接数参数,把 max_connections 调整为 2,同时把相关白名单里的 peripheral 设备数量限制也放开。改完之后重新编译并刷入固件,BLE 多连接用例稳定通过。
这个案例需要提醒一点:提高并发连接数之后,一定要做长时间稳定性测试。因为连接的设备数量上去之后,功耗和中断处理压力都会增加。临时放开参数如果只对测试开了绿灯,没有做压力验证,后续设备在真实场景里可能会因为资源分配问题出现蓝牙连接假死。
3.3 案例三:USB 网络共享在 EDLA 受管环境下被策略屏蔽
第三个案例比较典型。被测设备是一台 Z 型手持 POS 机,Android 16 EDLA 固件里预置了 Device Owner 配置。CtsConnectivityMultiDevicesTestCases 里有个 USB 网络共享的用例,一跑到 Tethering 步骤就失败,手动开启 USB 网络共享也只能维持一瞬间,随即自动关闭。
抓 logcat 的时候,我发现一行很有代表性的日志:EnterpriseDevicePolicyController 判断当前 USB tethering 请求被拒绝,原因是设备所有者设置了 USER_RESTRICTION_DISALLOW_USB_TETHERING。这说明不是系统和硬件不支持 USB 网络共享,而是企业策略从源头把这个功能禁用了。
这个问题的根源是 CTS 跑在了一套“带完整企业策略”的固件上。对实际业务来说,POS 机的企业管理员确实不希望 USB 共享网络被随意打开,所以这个策略本身是合理的。但对 CTS 认证来说,它需要验证的是原生系统的兼容性,而不是业务策略的正确性。
处理和前面两个案例不一样,不是改网络配置,而是调整测试环境的策略预设。我把测试用的固件切成了“未配置 Device Owner”的干净版本,让它处于非受管状态,然后重新跑 USB tethering 相关用例,结果全部通过。业务版本的系统保留原有的企业策略,并通过了另外一套企业专项测试。
这是个非常重要的教训:EDLA 设备的 CTS 验证,应该尽量在一台没有叠加企业策略的干净固件上进行。如果条件不允许,至少要在测试计划里明确区分“纯净版的 CTS 结果”和“受管版的企业专项测试结果”,不要混在一起看。不然很容易把策略行为误判成系统兼容性 BUG,白白浪费排查时间。
4. 常见失败速查表与提交测试前的检查清单
4.1 一张表快速定位常见失败
结合这几个项目里实际遇到过的问题,我整理了一张速查表。如果你也被这个模块卡住,可以先对照看看:
| 失败表现 | 可能根因 | 排查命令 / 关注点 |
|---|---|---|
| Wi-Fi P2P 扫描超时 | p2p 接口被网络策略排除 | 抓 wpa_supplicant 日志,检查接口状态 |
| BLE 第二台设备连接失败 | 蓝牙模组并发连接数限制 | 查看 max_connections 配置,抓 HCI 层日志 |
| USB Tethering 打开后立刻关闭 | 设备所有者策略禁用 | 搜索 EnterpriseDevicePolicyController 日志 |
| 蓝牙配对弹窗没有出现 | 配对确认被静默拦截 | 检查 Device Owner 是否设置了默认拒绝 |
| 热点开启失败 | 系统裁剪了 SoftAP 服务 | 检查 wlan0 的 AP 模式和驱动能力 |
| 用例直接 NotExecuted | 前置用例失败或设备不支持 | 看 tradefed 输出的 skipped reason |
| Ethernet 连接不生效 | 系统网络管家未纳入有线网卡 | 查看 EthernetNetworkFactory 是否正常注册 |
这个表只是起点,不能替代日志分析。但它能帮你快速建立怀疑方向,至少知道该去哪里找证据,而不是毫无头绪地翻系统源码。
4.2 提交 CTS 前在 EDLA 设备上先做这几件事
与其等 CTS 挂了再去查,不如在提交测试前把环境检查做扎实。EDLA 设备有几个高发坑,提前处理能省掉大半麻烦。
第一,确认 Wi-Fi 国家码。很多用例和 Wi-Fi 信道有关,国家码没设置好会导致某些信道不可用,进而影响 P2P 和热点测试。执行 adb shell cmd wifi set-country-code 可以快速设置。
第二,检查蓝牙白名单和连接数。如果设备用蓝牙模组是外购的,先确认驱动层最大连接数参数是否符合 CTS 的并发要求,别等测试跑挂了再去查。
第三,确认测试版本不带 Device Owner。除非企业专项测试,否则 CTS 一定要跑在非受管状态。如果固件里预置了策略,先用 adb shell dpm remove-active-admin 清掉再测。
第四,确认 USB 调试授权状态。多设备模块里,被测设备和辅助设备之间的连接有时候依赖 adb,USB 授权状态不对会导致测试直接 setup 失败。重启电脑后建议重新授权一次。
第五,跑模块前先重启设备。我遇到过蓝牙协议栈状态残留导致用例连续失败的情况,重启之后所有用例直接通过。这个动作成本极低,建议作为固定流程。
第六,做完整测试的设备尽量用稳定版驱动。EDLA 设备有的还在用工程版驱动,下载或编译一个带硬件加速的 wifi 驱动有时也能解决偶发问题。
这六件事听起来基础,但很多项目组就是没做全。尤其是 Device Owner 这个坑,EDLA 设备几乎每个都中招,而且中招之后的表现千奇百怪,很容易让人误判成系统兼容性问题。
自己跑过一轮之后,我最大的体会是:CtsConnectivityMultiDevicesTestCases 的失败项,超过一半是环境问题或企业策略问题,真正的兼容性缺陷反而没有想象中那么多。所以每次拿到 fail,先别急着改代码,把日志按顺序收齐,把策略关掉,把环境还原到干净状态,问题往往自己就浮出来了。
最后分享一个小技巧:遇到偶发失败,先用 --retry 重跑两三轮,如果还能过,基本可以判断是环境抖动。如果重跑还是挂,再手动复现三次。三次里面只要有一次能复现,就值得深入排查;三次都复现不了,建议优先怀疑测试现场的硬件和网络环境。这个方法帮我过滤掉了不少“假失败”,希望对你也有用。