做 WiFi 开发的朋友应该都对这两个角色不陌生:STA 是终端,连别人的热点上网;AP 是基站,开个热点让别的设备连进来。在 Android 设备上,这两个角色平时是互斥的——开热点就会断开 Wi-Fi 连接,连上 Wi-Fi 就不能开热点。但车载系统、工业手持终端、户外直播设备这些场景,偏偏需要“我一边连着路由器上网,一边还能让其他设备接入我的 AP 共享网络”。这个需求在行业里就叫 Android WLAN STA/AP 并发,属于 WiFi 系统定制开发里比较硬核的一块。
这篇文章我打算从实际项目经验出发,把 STA/AP 并发从硬件可行性、系统框架限制、RTOS 到 Android 的整体链路一步步拆开。内容会覆盖虚拟接口机制、hostapd/wpa_supplicant 配置、AOSP framework 修改、NAT 与路由策略,以及我在真机上踩过的那些坑。适合正在做 Android 系统定制、WiFi 驱动适配、或准备在车机/路由器/三防终端上做并发功能的开发者参考,内容偏实战,代码和命令都可以直接拿去验证。
1. 项目背景与并发需求解析
1.1 什么是 STA/AP 并发,它解决了什么问题
在 IEEE 802.11 协议体系里,STA(Station)和 AP(Access Point)是两种独立的角色。传统 WiFi 网卡在某个时刻只能绑定其中一个角色,要么作为客户端去关联别人的热点,要么作为热点等别人来连。Android 系统从一开始也遵循这个规则:Wi-Fi 开关和热点开关在 Settings 里是互斥按钮,framework 层的状态机也会在开启热点时主动断开已有的 STA 连接。
但真实设备的需求并不总是这么“守规矩”。我做过的几个项目就是典型例子:
- 车载前装中控屏:车机连着手机热点或车载 4G/5G 路由器上网,同时需要开放一个 AP 让后排乘客的平板连接,共享网络看电影。
- 工业手持 PDA:产线工人手里的终端连上工厂 Wi-Fi 收发数据,又需要临时开热点给旁边的扫描枪配对。
- 户外直播编码器:设备通过 5G CPE 上网,又要创建热点作为推流摄像头的接入点。
如果按照传统互斥逻辑,这类设备要么断网上不了数据,要么没法对外提供连接,业务直接瘫掉。所以 STA/AP 并发的核心价值,就是让一台设备同时在两个无线域里工作,做到“上行联网、下行组网”。
1.2 并发到底是“软件能做到”还是“硬件说了算”
很多刚接触这个需求的同学第一反应是改 Android framework 把那层互斥限制解除,但实际项目里最容易翻车的不是框架逻辑,而是硬件平台到底支不支持。
并发能力的第一决定因素是 WiFi 芯片和驱动。主流方案分成两类:
- 双射频(Dual Radio):芯片内部有两个独立的射频前端,比如一颗 SoC 里集成两个 Wi-Fi MAC/PHY,一个负责 STA,一个负责 AP。这种方案天然支持并发,两个角色可以跑不同信道、不同频段,吞吐互不干扰,但缺点是成本高、功耗高、PCB 面积大,而且 Android framework 默认也没有把双射频抽象成两个独立网络接口给你用。
- 单射频多虚拟接口(Multi-Virtual Interface):一颗射频芯片通过时分复用方式同时承载 STA 和 AP 两个角色。驱动在同一个物理网卡上创建多个虚拟网络接口,比如 wlan0 做 STA、wlan1 做 AP。这种方案成本低,绝大多数消费级 WiFi SoC 都支持,但两个角色必须工作在同一信道,吞吐会互相抢占,而且需要驱动层明确支持 interface combination 约束。
在 Android 平台上,项目最常用的其实是单射频多虚拟接口路线。原因很简单:量产成本敏感,双射频方案往往只能出现在高端路由器或专业设备上;而手机、车机、平板里那套 WiFi SoC 基本都有虚拟接口能力,关键看 BSP 里有没有把 hostapd 的 multi-interface 配置打开。
1.3 系统框架层面的“拦路虎”在哪
Android 从上层到下层大致是:Settings/SystemUI -> WifiManager -> WifiServiceImpl -> WifiStateMachine(或较新版本里的 ClientModeImpl) -> WifiNative -> wpa_supplicant/hostapd -> kernel driver。
历史上 Android 一直不允许 STA 和 AP 同时启用,有两个最关键的系统级原因。
第一,WifiServiceImpl 里有全局的“mode”互斥锁。即使在高通、MTK 等平台的私有实现里,setWifiApEnabled 接口被调用时,系统也会强制调用 disconnect() 去断开 STA 网络。框架设计者认为这不是一个正常用户会同时需要的功能,所以干脆做成互斥。
第二,ConnectivityService 对默认网络的判定非常严格。当热点开启后,Android 会认为设备变成了一个“软路由”,很多版本上 ConnectivityService 会停用 Wi-Fi 传输,或优先走蜂窝网络,导致 STA 虽然连接了但数据通路不稳定。
所以要实现并发,光靠解除 Settings 开关互斥是不够的,得从框架层把状态机的状态转移逻辑、ConnectivityService 的 netd 路由策略、以及 hostapd 的启动方式整体理顺。这也是这篇文章后面章节重点讲的内容。
2. 技术路线选型:AOSP 定制还是 Vendor 私有方案
2.1 三条主流实现路径对比
真要做 STA/AP 并发,业界大体有三条路可以走。我按实现难度和可维护性排个序。
| 方案 | 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 官方 LocalOnlyHotspot | 调用 WifiManager.startLocalOnlyHotspot() | 无需系统权限,API 稳定 | 不支持外部网络共享,AP 只能本地局域网 | 临时透传、设备互连 |
| AOSP 框架定制 + hostapd | 修改 WifiStateMachine/SoftApManager,让 AP 启动时不断开 STA,同时配置路由 NAT | 功能完整,可量产 | 需要修改系统镜像,周期长 | 车机、平板、行业终端 |
| Vendor 私有 SDK/命令行 | 直接通过 root 或系统应用启动 hostapd,手动配置 iptables | 快速验证,适配老平台 | 绕过 Android 框架,稳定性差 | 原型验证、小批量工具 |
从项目长期稳定性的角度讲,我大部分场景都推荐第二种,也就是 AOSP 框架定制。LocalOnlyHotspot 虽然安全,但它天然不支持为 AP 侧设备提供 NAT 上网,因为官方语义是“local network”,没有任何 Internet 共享能力,很多业务场景根本不能用。第三方命令行方案适合前期摸底,但量产固件里用 root 权限裸跑 hostapd,跟 Android 的 netd 策略冲突非常多,遇到 CTS 测试大概率过不了。
2.2 为什么建议走 multi-interface + hostapd 而不是 vendor 私有模式
在 Linux 内核和 Wi-Fi 驱动生态里,“一个物理网卡上创建多个 netdev”不是 Android 独有的,而是 mac80211/cfg80211 架构的标准能力。比如 QCA 平台的 wlan0、wlan1、wlan2,MTK 平台的 wlan0、ap0,都是同一颗射频芯片虚拟出来的接口。
Android 系统里,STA 侧由 wpa_supplicant 管理,AP 侧由 hostapd 管理。好消息是这俩用户态程序都能独立指定自己绑定的网络接口,而且可以同时运行,互不冲突。所以系统的并发能力其实早就具备,框架层想不想开放才是关键。
因此,技术路线选型上我强烈建议通过修改 AOSP SoftApManager 来支持“STA 已连接时允许开启 AP”的路径,驱动层只要确认支持多个 virtual interface 即可。具体来说,需要一个支持下列能力的 BSP:
- 内核 cfg80211 支持 interface combination,且允许
{ STA + AP }组合。 - 驱动已经创建好第二块网络接口(如 wlan1 或 ap0),并注册到 kernel。
- hostapd 版本支持通过
-i参数指定接口,或使用多 interface 配置文件。
这些条件对于高通、MTK、瑞昱、博通的近几年方案基本都能满足。如果你的平台比较老,可能得先找驱动 vendor 要一版支持 AP+STA 并发的固件和驱动。
2.3 StartLocalOnlyHotspot 的一个特殊用法
虽然 LocalOnlyHotspot 不提供 NAT 上网,但它在某些定制场景里非常有用:当你的产品只是想让同一局域网里的其他设备能够访问本机服务,比如智能家居网关让手机直连设备配置网络,这时候用 LocalOnlyHotspot 最干净、最安全,因为它不会把 STA 路由表搞乱,也不会影响默认网络的连通性。
另外,它的并发路径在 Android 10 里已经算是官方支持的:系统在启动 LocalOnlyHotspot 时,如果在 Wi-Fi 已连接的状态下调用,会自动进入一种“并发连接”模式,硬件支持时会创建 AP 虚拟接口。这让 AOSP 的框架代码里其实已经预留了并发实现的雏形,只是功能有限。
所以,如果在项目早期只是验证“芯片支不支持并发”,你可以先在未修改系统的情况下用 LocalOnlyHotspot 做个快速测试:如果 AP 接口能顺利起来,同时 STA 不断开,说明驱动和底层 OK,接下来就专心做 Framework 定制和路由策略,不用再担心硬件坑。
3. 核心实现细节与关键配置
3.1 硬件到底支不支持并发,先用这个命令验证
拿到一台设备,我建议第一步先不要改代码,直接到 ADB shell 里看底层的接口和模式支持情况,方法如下。
adb shell # 查看当前无线网络接口 iw dev # 查看物理射频能力与支持的接口组合 iw list重点看valid interface combinations这一段,kernel 驱动会明确告诉上层“这块网卡最多能同时支持多少个 STA、多少个 AP、多少个 P2P”。
比如你的板子上如果看到类似下面的输出,说明驱动已经支持 STA+AP 并发:
valid interface combinations: * #{ AP } <= 8, #{ STA } <= 1, total <= 8, #channels <= 1,这里#channels <= 1的含义是:所有并发接口必须工作在同一个信道上。这也是单射频方案不可避免的物理限制,后面做 AP 配置时要特别注意,不要把 AP 信道配成和 STA 当前工作信道不一致的值,否则驱动会直接返回失败。
如果iw list里只有单个接口组合,或者组合里没有同时允许 AP 和 STA,那后面框架改得再好也白搭,得先推动驱动升级。
3.2 虚拟接口的自动创建与 hostapd 配置
进入正题前,先确认一个事实:Android 的 SoftApManager 在启动热点时,默认会走WifiNative.startSoftAp()到 vendor HAL,再由 vendor 的 Wi-Fi HAL 调用 hostapd,而 HAL 里通常会使用wlan0作为 AP 接口,或者动态创建一个softap接口。但如果你在 STA 已连接的情况下启动 AP,很多 HAL 内部会先把wlan0从 supplicant 那里接过来,导致 STA 断网。
所以最简单的做法是绕开默认 HAL 的“自动选择接口”逻辑,在 framework 层显式指定一块和 STA 不同的接口来跑 AP。在 Android 10+ 的 SoftApManager 里,有一个mApInterface属性,可以通过 Vendor HAL 传给 hostapd。某些平台(如高通)还会读取/vendor/etc/wifi/softap.conf或ini配置来选择 AP 接口名。
我常用的方式是创建一个手工管理脚本,直接在启动 hostapd 前用iw命令创建第二块虚拟接口:
# 在 wlan0 所在物理设备上创建一块名为 ap0 的虚拟 AP 接口 iw dev wlan0 interface add ap0 type __ap ip link set ap0 up然后写一个独立的 hostapd 配置:
interface=ap0 driver=nl80211 ssid=MyShareAP hw_mode=g channel=6 wmm_enabled=1 ieee80211n=1 wpa=2 wpa_passphrase=12345678 wpa_key_mgmt=WPA-PSK rsn_pairwise=CCMP注意channel=6必须和当前 STA 所在信道保持一致,比如 STA 连接在 2.4G 的 6 信道,这里就写 6;如果你 STA 连的是 5G,那hw_mode=a,信道也要对应。实际项目中,更稳妥的做法是让应用通过WifiManager.getConnectionInfo()获取当前信道,再动态生成 hostapd 配置,避免写死。
driver=nl80211是 Linux 标准 WiFi 驱动接口,Android 上 hostapd 几乎都用它,兼容性最好。启动命令:
hostapd -B /data/misc/wifi/hostapd.conf如果 hostapd 能正常起来、iw dev能看到 ap0 处于 AP 模式,且 wlan0 的 STA 连接还在,那恭喜,底层的并发已经打通了。
3.3 给 AP 侧设备提供上网能力:NAT 与路由
底层的 AP 接口起来后,连上这个热点的设备默认只能二层通信,要想让它们通过设备的 STA 上网,需要手动把包转发和 NAT 配置好。这一步在 Android 定制系统里,实际上是由 netd 和 iptables 完成的,但在 Root 调试阶段,可以直接用命令验证。
先开启内核 IP 转发:
echo 1 > /proc/sys/net/ipv4/ip_forward然后给 AP 接口配置一个网段地址,比如 192.168.43.1,子网掩码 255.255.255.0。Android 默认热点的网段就是这个,便于和系统其他组件兼容。
ip addr add 192.168.43.1/24 dev ap0接下来启动 dnsmasq 做 DHCP 和 DNS 服务。Android 系统镜像里一般自带 dnsmasq,属于 netd 的依赖组件,但 Root 环境可以直接手动跑:
dnsmasq --interface=ap0 --dhcp-range=192.168.43.100,192.168.43.200,255.255.255.0 --no-daemon最后配置 iptables 伪装:
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE这里-o wlan0是指流量从 STA 接口出去时做源地址转换。测试时可以在手机连上该热点后打开网页确认网络通不通。如果通,说明核心数据链路已经 OK。
如果还要做成量产系统,建议不要用命令行脚本裸跑,而是把 AP 启动逻辑整合到 SoftApManager 的代码里,通过 Netd 的NetworkController接口管理路由规则和 NAT,否则 Android 的 ConnectivityService 会反复重置 iptables 规则,导致你手动加的规则莫名失效。
3.4 Framework 层如何避开关闭 STA 的逻辑
命令行验证通过后,回到 AOSP 层面做正式定制。以 Android 10/11 为例,我需要动的主要是WifiServiceImpl和SoftApManager。
在WifiServiceImpl.setWifiApEnabled或startSoftAp入口里,默认的逻辑会在开启 AP 前调用mClientModeImpl.disconnect();在最新版本中也可能表现为直接 reject 当前 STA 连接。要改的核心思路就是:在 AP 状态机进入 enabled 状态时,不要切断 STA 连接,而是让 STA 保持 connected,同时创建 AP 接口并启动 hostapd。
具体 patch 位置因版本差异很大,但有一个通用做法:在SoftApManager的startSoftAp()里,把超时关闭 STA 的逻辑注释掉,并确保WifiNative.startSoftAp()使用的是独立的ap0接口而不是wlan0。
另外别忘了一个特别容易踩雷的地方:WifiConfigStore和WifiInjector可能会在 AP 启动时保存“禁用 Wi-Fi”的持久化设置,导致系统重启后 STA 默认关闭。我通常会在开启并发模式时,把相关设置改成保持 Wi-Fi 开启。
3.5 双频段下的行为差异
做了几个项目后,我对不同频段的并发行为也有了一个比较直观的感知,这里单独列出来提醒大家。
- 2.4G STA + 2.4G AP:最容易实现,几乎所以支持虚拟接口的芯片都能跑,而且 hostapd 配置特别简单。但 2.4G 频段干扰严重,加上 STA 和 AP 共享射频,整体吞吐量可能只有单独工作时的 50%-70%。如果设备离路由器远,体验会很差。
- 5G STA + 5G AP:需要芯片支持同时在同一 5G 信道上收发,部分芯片也支持,但要注意 DFS 信道问题——如果 STA 当前在 DFS 信道,而 AP 也要用相同信道,可能是非法的或需要额外 radar detection,实际产品里建议避开。
- 5G STA + 2.4G AP:这是很多产品最想要的组合,但单射频芯片基本做不到,因为射频前端一次只能工作在一个频段。能做到的只有双射频方案,也就是前面说的 Dual Radio。所以在立项评估时,建议先明确“是不是必须跨频段”,如果是,请预留双射频的硬件选型。
4. 实操过程:从真机调试到功能落地
4.1 搭建可复现的实验环境
要完整走通这个功能,建议准备一台可刷入自定义系统的 Android 测试机或开发板。我一般用 Pixel 系列或高通的开发板(如高通 RB5、QRB5165),因为它们的 BSP 资料齐全,WiFi 驱动也比较开放。主板需要解锁 bootloader,并编译一个 userdebug 版本的 AOSP 系统。
环境安装方面需要以下几样:
- AOSP 源码树,版本建议选 Android 10 或 Android 12,别选太新的版本,因为框架改动频繁,社区资料多为这两个版本。
- 对应设备的 vendor blob 和 kernel 源码。
- ADB 和 fastboot 工具,最好在 Ubuntu 20.04 或 22.04 上操作。
- 一块 USB WiFi 网卡作为备用调试工具,方便在设备 STA 断开时还能远程访问设备。
实验环境搭好后,我的调试节奏是:先编译原始 AOSP 系统,验证设备能正常连接 STA 和开启 AP,然后再分别打 patch,一步步叠加改动,避免一次性改动太大出问题定位不了。
4.2 分步验证并发功能的最小闭环
我把整个验证过程整理成下面几个步骤,每一步都有清晰的通过标准,方便你在自己的设备上复现。
- 确认 STA 可以正常连接:系统启动后连上一个已知 SSID,用
iw dev wlan0 link检查关联状态。这一步的目标是排除射频硬件问题。 - 手动创建 AP 接口:通过 adb root 执行
iw dev wlan0 interface add ap0 type __ap,再配置 IP 和 hostapd。该步骤验证驱动是否允许在 STA 活跃时创建 AP 接口。 - 验证数据通路:AP 侧设备连接后,确认能拿到 IP,并能 ping 通 8.8.8.8 或网关。这一步验证 NAT 和 IP 转发没问题。
- 把逻辑搬到 AOSP framework:修改 SoftApManager,并保证编译进系统后,通过系统 UI 或 API 可以正常开启并发热点。
- 反复开关和断网重连测试:验证 STA 断开后自动重连、AP 关闭后再启动、以及双接口并发状态变化时系统不崩溃。
第 2 步其实是最关键的一步。如果这一步直接失败,比如驱动返回Operation not supported,那后面的框架改动都不需要做了。
4.3 框架 patch 示例与关键代码走读
写下这段时我假设你的 AOSP 路径是frameworks/opt/net/wifi,不同版本会有一点点差异,但核心逻辑是通用的。
在WifiServiceImpl.java中,找到setWifiApEnabled或startSoftAp方法。默认逻辑大概是:
public void startSoftAp(SoftApConfiguration config) { // 在开启 AP 前会强制关闭客户端模式 mClientModeImpl.disconnect(); mSoftApManager.start(config); }改动方式可以这样:
public void startSoftAp(SoftApConfiguration config) { // 并发模式下不直接 disconnect; // 而是先确认已经有 STA 网络,则直接启动 AP if (mClientModeImpl.getWifiState() != WifiClientModeImpl.WIFI_STATE_CONNECTED) { mClientModeImpl.disconnect(); } mSoftApManager.start(config); }同时,在SoftApManager.java启动 hostapd 时,需要确认传给 native 层的接口名不是wlan0,而是额外的ap0。部分平台支持通过WifiNative.setSoftApInterface(String iface)设置,我建议在 HAL 层加一个判断:如果上层传入了ap0,就跳过 HAL 内部自动选择的默认接口。
另外,在WifiNative的startSoftAp实现里,原有的mWificondControl.setSoftApMode或mSupplicantControl可能会恢复默认接口策略,这块要仔细排查,否则你改了上层,底层又给你切回wlan0。
4.4 路由策略和系统网络属性的调整
NAT 配好后,还有一个很容易被忽略的点:Android 上层有一个评分机制,它会认为“设备连着 Wi-Fi”和“设备开着热点”这两种状态不应该同时存在。如果你不做处理,即使底层正常,状态栏也可能不显示热点图标,或者网络共享服务会被杀死。
这里我的经验是:在ConnectivityService的网络评分里,给 AP 接口创建的网络添加一个TRANSPORT_WIFI的附属网络,并把它标记为LOCAL_NETWORK,这样系统知道这是本地软路由网络,不会去和默认的 STA 网络抢“默认网络”的位置。
如果这部分不想深改,也可以不变更框架逻辑,而是通过一个常驻前台服务持续监控两个接口的状态,发现问题后用ConnectivityManager.setProcessDefaultNetwork之类的 API 做兜底。这算是一个偏业务层的 hack,但稳定性不如直接改 ConnectivityService。
4.5 真机性能与吞吐量评估参考
并发模式下的性能是不能回避的问题。我实测过的某高通平台方案(单射频 2x2 MIMO)在近距离无干扰环境下,STA 单独吞吐约 400Mbps;开启 AP 并发后,STA 下行和 AP 下行总吞吐在 250Mbps 左右,损耗接近 40%。这个损耗主要来自射频时分和驱动调度开销,属于正常现象。
如果你做的产品对吞吐要求很高,可以尝试几个优化方向:
- 在驱动配置里调整 beacon interval 和 DTIM 周期,减少 AP 空口开销。
- 降低 AP 侧协商速率上限,比如把
ieee80211n的 MCS 速率限制在 MCS7,避免低质量链路拖慢整体空口调度。 - 优先保证 STA 侧的数据优先级,可以通过
iptables -t mangle给 STA 方向包打上高优先级 DSCP 标记。 - 关闭 AP 侧的省电模式,
wpa_cli -i ap0 set ap_scan 1,防止 STA 侧设备进入省电后长期不响应。
上面这些调优不是每个平台都有效,得结合芯片原厂文档来做,但算是我实际踩出来的方向,可以先从这几项开始试。
5. 常见问题与排查技巧实录
5.1 热点起不来,AP 接口创建失败
这是最常见的开局问题。表现是调用iw创建接口时提示command failed: Operation not supported (-95),或者 hostapd 启动后立即退出,日志里报nl80211: Failed to set interface into AP mode。
排查顺序我建议是这样:
| 步骤 | 命令/操作 | 目的 |
|---|---|---|
| 1. 查看内核接口组合 | iw list查看 valid interface combinations | 确认驱动支持 STA+AP 组合 |
| 2. 查看 kill switch | rfkill list | 确认射频没有因为 RF kill 被锁定 |
| 3. 查看驱动参数 | dmesg | grep -i wlan | 确认系统加载的是哪个驱动模块 |
| 4. 查看接口占用 | iw dev | 确认 wlan0 是否已被 wpa_supplicant 独占 |
| 5. 手动换接口名 | 创建ap0而非默认wlan1 | 排除接口名被 HAL 预留的问题 |
特别是第 4 步,很多驱动在 wpa_supplicant 绑定主接口后,会限制用户的额外接口创建请求。解决办法是在 wpa_supplicant 的配置里加上ap_scan=1或interface参数,或者用wpa_cli interface_add来创建辅助接口,而不是直接用iw。
5.2 STA 正常,但 AP 连上的设备无法上网
这种问题九成出在 NAT 和路由上。先做一套自检:
ip route看有没有到 192.168.43.0/24 的路由。iptables -t nat -L POSTROUTING -n -v看 MASQUERADE 规则计数是否为 0。如果计数为 0,说明 AP 侧包根本没走到 POSTROUTING。echo 1 > /proc/sys/net/ipv4/ip_forward确认转发是否打开。- 用
tcpdump -i ap0看 AP 侧是否收到客户端的 DNS 请求。
还有一个很隐蔽的坑:目标 IP 在局域网内时,iptables 的 MASQUERADE 不会生效。如果你的测试是“AP 侧设备 ping 路由器 LAN 内其他设备”,那本身就不走 NAT,不需要上网;但如果 ping 外网不通,就要重点看 DNS 解析是否从 STA 侧转发出去。很多系统镜像里的 dnsmasq 配置默认只监听 loopback 接口,需要加上--interface=ap0 --bind-interfaces或者修改/etc/dnsmasq.conf。
5.3 应用层获取不到热点状态,或状态栏显示异常
Framework 定制后,如果 Settings 里的热点开关状态和实际 hostapd 状态不一致,通常是 system server 里的WifiController或SoftApStateMachine状态没同步。一个简单处理方式是,在 hostapd 起来后,通过WifiManager发广播通知系统更新热点状态:
Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_ENABLED); mContext.sendBroadcast(intent);如果是在定制系统里,建议直接在 SoftApManager 的状态回调里补上广播发送逻辑,这样其他应用比如设置菜单、SystemUI 都能感知到状态变更。
5.4 STA 频繁断开,AP 侧设备也掉线
这大概率与射频调度有关。单射频方案下,当 AP 侧有数据传输时,驱动会频繁切换 STA 和 AP 的收发窗口,如果信号质量不好,STA 的 beacon 丢失率会升高,最终触发 supplicant 的 disconnect。这种问题不是软件 bug,而是射频资源竞争。
我踩过几次坑后的处理办法:
- 如果 STA 侧信号在 -70dBm 以下,优先提高 STA 侧的 roaming 阈值,让设备尽快漫游到信号更好的 AP。
- 在驱动里调整并发模式的 TX/RX 时间权重,比如 MTK 平台有
wifi_concurrent_timeslot参数,高通平台有类似gConcurrentTxRxRatio,可以把更多时隙分配给 STA。 - 如果必须保持弱信号环境下并发,建议降低 AP 侧带宽,从 40MHz 降到 20MHz,给 STA 留出更多空口时间。
这些参数不同平台差异较大,可以直接找平台原厂 FAE 要他们家推荐的并发调优配置,比自己盲目调省事很多。
5.5 并发场景下的功耗问题与温度控制
STA/AP 并发会让 WiFi 芯片持续处于高负载状态,功耗比单一模式高出不少。我在某款手持终端上实测过:并发时 WiFi 模块整机耗流增加了 300mA 左右,如果再加上 AP 侧有持续视频流,SoC 温度很容易突破 60 度。
产品化时建议做三件事:
- 在 AP 侧实现无流量自动关闭热点的机制,比如用
conntrack统计连接数,连续 5 分钟无活动就把 AP 关掉。 - 通过温度传感器做降频策略,比如温度超过 55 度时把 AP 从 802.11n 降到 802.11g,或者降低发射功率。
- 如果产品长时间依赖并发模式,最好评估散热设计,比如增加导热硅脂或石墨片。
6. 模块化复用与后续扩展思路
这个功能做完之后,你会发现它其实可以沉淀成一个“并发热点能力模块”,后续在产品里直接复用。比如同一套代码,稍微改改配置,就能做出这几个变体:
- Wi-Fi 中继器模式:STA 连上级路由,AP 广播同名 SSID,下层设备透明上网。
- 双 Wi-Fi 加速:部分旗舰平台支持一路 STA 走 2.4G、一路走 5G,同时连接到两个 AP,实现带宽叠加或链路备份,底层用的也是多虚拟接口机制。
- Wi-Fi Direct + STA 并发:P2P 接口和 STA 接口并发,这在 Android 很早就有支持,原理上和 AP/STA 并发类似。
如果团队后续要做这些功能,建议一开始就把接口抽象好,比如用 AIDL 暴露一个“并发热点控制服务”,把 hostapd 启动、NAT 配置、状态回调都封装在里面,业务层只调startConcurrentSoftAp(config)和stopConcurrentSoftAp(),这样上层不管怎么换,底层都能复用。
最后再分享一个小技巧。在真机调试并发功能时,建议打开 wpa_supplicant 和 hostapd 的详细日志,并定期抓取dmesg里 cfg80211 的报错信息。我见过很多看起来像上层框架 bug 的问题,最后定位到都是驱动在并发模式下协议栈处理不完善。抓日志时用logcat -b all加dmesg -w一起开,两个日志时间线对齐,排查效率会高很多。