ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Android WLAN STA/AP并发实战:从硬件验证到NAT转发全攻略

Android WLAN STA/AP并发实战:从硬件验证到NAT转发全攻略 做 Android 系统开发的朋友应该都有过这种遭遇客户提了个需求手机连着公司 Wi-Fi 上网STA 模式还得同时开个热点AP 模式让工位上的 IoT 设备、开发板也连进来调试。两个开关听起来是“同时打开”而已结果一提交到驱动、框架那一层发现根本不是你想象的那么简单。这就是标题里说的——Android WLAN STA/AP 并发。这套机制到底能不能做、怎么做、坑在哪我花了不少时间在这上面源码、固件、抓包、路由转发都折腾过一遍。这篇文章就专门把这些经历整理出来。它适合正在做 Android 系统定制、Wi-Fi 驱动/BSP 开发、无线测试工具链搭建的工程师也适合想搞明白“手机热点为什么不能和 Wi-Fi 同时用”的嵌入式开发。我会从底层架构一直讲到实操命令最后给你一份能直接拿去排查的问题清单。1. STA/AP 并发到底是什么为什么默认做不了1.1 从 Android WLAN 架构看并发难在哪先理清术语。STAStation就是普通的 Wi-Fi 客户端手机连路由器时就是 STA。APAccess Point就是无线接入点手机开热点时就是 AP。并发自然指的是同一个设备上一边作为 STA 连外部网络一边作为 AP 给其他终端提供接入。Android 默认不允许这么干因为它把 Wi-Fi 当作单一用途的资源在管理。框架层有 WifiService、WifiNative再往下还有一个状态机整体设计思路是“同一时刻一个 Wi-Fi 芯片只能处于一种模式”。你开着 Wi-Fi 的时候去开热点系统直接提示“先关闭 WLAN 才能开启热点”反过来也一样。这个限制不是用户界面层面的策略而是底层框架对 Wi-Fi 模式切换的互斥控制。除非直接改框架代码或者跳过框架用 root shell 硬拉接口否则这个开关永远不会被你“同时打开”。但真正决定能不能并发的不在框架层而在芯片和驱动。这也是很多人一开始走弯路的地方以为改改 Java 层逻辑就行结果改了半天驱动层直接报错。我在后面会展开说。1.2 芯片与固件层面并发不是软件开关Wi-Fi 芯片有一个关键参数叫“接口组合能力”interface combinations。芯片固件支持多少条 virtual interface、能不能同时出现 managedSTA模式和 AP 模式全看硬件。你可以用iw list查valid interface combinations: * #{ managed } 1, #{ AP } 1, total 2, #channels 1这条信息的意思是这个芯片最多同时存在 1 个 STA 和 1 个 AP总共 2 个虚拟接口但只能占用 1 个信道。也就是说从硬件出生那天起它就有并发能力只是 Android 框架把它锁死了。也有更差的芯片比如 total 1这种即便是 root 硬拉接口也成不了。所以做并发方案第一步一定不是改代码而是先验证手上的机器支不支持。支持的才有后面这些文章可写。不支持的就只能走双 Wi-Fi 芯片方案成本高不少。STA/AP 并发最常见的落地场景有这么几类产测工具手机连产线服务器拿测试指令同时自己开热点让待测设备接入上报数据。Wi-Fi 中继/信号扩展Android 设备接收主路由信号再以热点方式放大覆盖范围。车载/工业手持终端设备连外部 4G/5G 路由器上网同时给车内设备提供 Wi-Fi 配置入口。局域网组网测试用一台 Android 设备模拟 AP让多台 STA 设备连入做压力测试。这些场景对数据路径的要求差异很大。中继需要完整的 NAT 和转发产测可能只需要二层互通。选型的时候要想清楚不然方案做出来不是性能不够就是功能多余。2. 并发方案怎么选四种路线对比分析2.1 单芯片软并发与双 Wi-Fi 硬桥接怎么权衡STA/AP 并发的硬件实现我归纳下来有几种路线各有利弊。方案 A单 Wi-Fi 芯片 固件支持多虚拟接口软并发。这是 Android 设备上最常见的做法。启用方式STA 正常连路由器AP 挂在同一个物理芯片的另一个虚拟接口上框架层绕过默认限制。优点是成本低、不用加硬件缺点是同信道收发会互相抢空口时间吞吐和时延都会打折扣。方案 B双 Wi-Fi 芯片一个管 STA、一个管 AP硬并发。这基本就是路由器的做法。手机里塞两颗 Wi-Fi 芯片不现实但在工业主板上很常见。优点是性能好STA 和 AP 可以跑不同频段、不同信道互不干扰缺点是成本高需要处理 PCIe/SDIO 总线资源、天线布局、两个芯片的共存干扰驱动集成的工作量也大。方案 C单芯片 其他回传链路做 AP。严格来说不是 WLAN STA/AP 并发但做产品时常会遇到。比如设备用有线以太网或 4G 模块上联Wi-Fi 只作为 AP 使用。这种场景没有空口竞争问题软件实现也简单但标题里说的“WLAN STA/AP”并发不覆盖这个。方案 D纯软件虚拟 AP无硬件加速。用 mac80211_hwsim 这类虚拟驱动在开发板上模拟 Wi-Fi适合跑协议测试不适合真实场景。这种方案在 Android 真机上几乎不会用但在大规模无线测试平台里很常见。选路线的核心判断标准我一句话总结看你需要并发到什么级别。只做产测、配置工具这种短数据交互方案 A 完全够要做中继、精品网速要求的至少是方案 B或者接受方案 A 的性能损失。2.2 选型判断标准需求特征与硬件能力我第一次做这个需求时上来就按“方案 A 一定可行”的思路走结果同事拿了一台老平台测试机iw list里 interface combinations 明显不支持 APSTA 同时存在白折腾了两周。后来我总结了一套快速判断流程先看四件事看iw list的 interface combinations确认支持 managed AP 同时存在总接口数是否够。看驱动代码里是否注册了多个 virtual interface比如 ath9k、mt76 这类驱动通常天然支持多接口而某些闭源驱动只暴露一个接口。看 Android 框架版本。Android 9 以前框架限制相对松可以通过设置wifi_interface或修改WifiStateMachine绕开Android 10 之后的 netd、bpf 策略对转发的限制变多root 环境反而更容易做实验验证。看实际吞吐需求。如果下游设备要跑视频流同信道并发基本做不到提前跟产品说清楚。这里还要提一个容易踩的误区很多人觉得“开热点 连 Wi-Fi”就是并发其实部署在 Android 10 以后还有一层“热点的接口名可能是 wlan0”而 STA 也是 wlan0两者会竞争同一个接口。真正能实现并发的设备驱动会给 AP 单独创建 ap0、softap0 这样的虚拟接口。如果没有这个独立接口说明驱动层面根本没做多接口支持。3. 实操在 Android 上把 STA 和 AP 同时拉起来3.1 编译与内核环境准备先声明我这里讲的是工程机 root 权限下的验证流程适合开发和产测阶段。量产产品的做法是在 AOSP 源码里修改 framework去掉模式互斥再配合驱动的多接口能力原理是一样的。准备一个可 root 的 Android 工程机最好系统是 userdebug 或 eng 版本。然后确认内核支持CONFIG_NF_NAT、CONFIG_NETFILTER_XT_TARGET_MASQUERADE、CONFIG_IP_ADVANCED_ROUTER。绝大多数的 Android 内核默认开启 NAT 相关模块但某些精简内核会去掉导致后面 iptables 规则不生效。接着打开 Wi-Fi 连接路由器确认 STA 已经起来adb root adb shell ifconfig -a正常情况下你能看到 wlan0 接口并且已经拿到 IP。接下来要做的是看驱动是否会自动为 AP 创建一个新接口。部分驱动比如 qcacld会在加载固件时默认创建两个接口一个用 wlan0另一个可能叫 wlan1 或 ap0。如果没有也没关系可以用 iw 手动添加iw dev wlan0 interface add ap0 type __ap如果这条命令报operation not supported基本可以确定驱动或固件不支持 APSTA 组合后面的内容就不用看了。3.2 手写 hostapd 配置并拉起 APAndroid 系统里已经内置了 hostapd只不过框架层用它来启动热点。我们可以直接手动调 hostapd把 AP 拉起来。先写一个最简配置cat /data/local/tmp/hostapd.conf EOF interfaceap0 drivernl80211 ssidConcurrentTest_AP hw_modeg channel6 wmm_enabled1 macaddr_acl0 auth_algs1 ignore_broadcast_ssid0 wpa2 wpa_passphrase12345678 wpa_key_mgmtWPA-PSK rsn_pairwiseCCMP EOF然后启动hostapd -B /data/local/tmp/hostapd.conf留意两个参数。hw_modeg表示 2.4GHzchannel6是具体信道。如果你的 STA 已经连在 2.4G 信道的路由器上AP 最好选一个跟 STA 不重叠的信道比如 STA 在信道 1AP 就选 6 或 11。但这里有个矛盾很多芯片的 interface combinations 写的是#channels 1这意味着即使你配置了不同信道它也只会在一个物理信道上收发。这种情况下选信道就不是为了规避干扰更多是为了满足 AP 本身的合法性要求。hostapd 起来之后用iw dev查看接口状态正常会看到 ap0 处于 AP 模式iw dev Interface ap0 ifindex 8 wdev 0x2 addr 02:00:00:00:00:01 type AP到这一步STA 和 AP 的物理层并发已经打通了。但注意现在 AP 只是起来了连上热点的设备还上不了网因为数据从 AP 口进来之后不知道怎么转到 STA 口出去。3.3 打通路由、NAT、DNS 与转发策略这一步是 STA/AP 并发里最核心的软件工作也是问题最容易出现的环节。网络拓扑是这样的ap0 接口是 192.168.43.1/24给下游终端分配地址wlan0 是 STA 接口IP 为 192.168.1.100/24网关是公司路由器的 192.168.1.1。下游终端访问互联网数据包从 ap0 进经过内核转发到 wlan0 出再上外网。这就要求内核打开 IPv4 转发echo 1 /proc/sys/net/ipv4/ip_forward然后给 ap0 配 IP并启动 dnsmasq 做 DHCP 服务。Android 自带 dnsmasq如果系统里有可以直接用没有的话也可以临时用 busybox 的 udhcpd但 dnsmasq 更省事ifconfig ap0 192.168.43.1 netmask 255.255.255.0 up dnsmasq --interfaceap0 --dhcp-range192.168.43.10,192.168.43.200,255.255.255.0,12h \ --no-daemon 地址池范围怎么定我一般是 192.168.43.10 到 192.168.43.200网关就是 ap0 本身 192.168.43.1。因为 Android 热点默认网段就是 192.168.43.0/24沿用这个段一方面是习惯另一方面很多深度定制的 ROM 默认放行这个网段不容易碰到防火墙拦截。接下来是关键配 NATiptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE iptables -A FORWARD -i ap0 -o wlan0 -j ACCEPT iptables -A FORWARD -i wlan0 -o ap0 -m state --state RELATED,ESTABLISHED -j ACCEPT这里解释一下每条规则的作用。第一条把从 ap0 进、从 wlan0 出的数据包的源 IP 改成 wlan0 的 IP这样公司路由器只看到一个 STA 设备在访问外网回包才能正确送回来。第二条允许从 AP 侧发起的新连接进入转发链路。第三条允许已经建立的连接回包从 wlan0 回到 ap0。少了任何一条下游设备都会出现“能连上热点但上不了网”的典型症状。DNS 方面要特别注意。Android 的 netd 可能会管理 /etc/resolv.conf手动改不一定生效。最稳妥的方案是在 dnsmasq 里显式指定上游 DNS比如dnsmasq --interfaceap0 --dhcp-range192.168.43.10,192.168.43.200,255.255.255.0,12h \ --server8.8.8.8 --server223.5.5.5 --no-daemon 这样 dnsmasq 会把 DNS 下发给下游终端终端拿到的 DNS server 就是 ap0 的 IP由 dnsmasq 代替它们做递归解析避免安卓系统 DNS 配置改动带来的问题。到这里一个最基本的 STA/AP 并发数据通路就通了。我用手机连上 ConcurrentTest_AP打开浏览器能正常访问网页。但真正的工程评估才刚刚开始——你得抓包确认每个环节没问题还要测吞吐、排查各种奇奇怪怪的连接问题。4. 抓包与性能验证怎么确认并发生效了4.1 STA 关联报文与 AP DHCP 握手抓包分析光看界面显示“已连接”不算数网络问题最终都要用数据说话。开发中我们经常要抓两类包一类是 STA 连接 AP 的关联报文一类是 DHCP 交互报文。在 STA 侧抓包直接用 tcpdump 抓 wlan0tcpdump -i wlan0 -w /sdcard/sta.pcap同时用一个待测设备去连接 ConcurrentTest_AP正常情况下 pcap 里能抓到 Authentication Request、Association Request 以及四次握手4-way handshake的 EAPOL 报文。如果只能看到 Authentication Request没有后续的 Association Response那大概率是 AP 侧 hostapd 配置有问题比如密码算法不匹配。在 AP 侧抓 DHCP抓 ap0tcpdump -i ap0 -w /sdcard/ap_dhcp.pcap port 67 or port 68然后下游设备重新连接热点你会依次看到 DHCP Discover、Offer、Request、Ack 四步。如果只有 Discover 没有 Offer说明 dnsmasq 没启动或者地址池已经耗尽。如果 Offer 发出去了但没有 Request可能是终端的 DHCP 客户端对 Offer 里的网关或 DNS 参数不满意这时抓包看一眼 payload 里的 option 字段就明白了。判断 forwarding 是否正常一个更直接的命令是查 conntrackcat /proc/net/nf_conntrack | grep 192.168.43.10如果看到src192.168.43.10 dst... sport... dport443这类条目说明连接跟踪已经建立数据正在走 NAT 转发路径。如果 conntrack 里查不到说明内核转发没生效或者包根本没到 ap0。4.2 转发链路验证与吞吐实测连接通了之后性能是第二个关键指标。STA 和 AP 同时工作时因为收发共用一个物理射频吞吐会明显下降这是物理定律决定的。但下降多少、是不是异常需要实测。最常用的工具是 iperf3。在 PC 上跑服务端Android 设备通过热点口接的下游设备跑客户端反向再测一次# 服务端PC连在同一个 STA 所连的内网 iperf3 -s # 客户端下游设备连着测试 AP iperf3 -c 192.168.1.100我实测下来2.4GHz 单天线设备纯 STA 模式单向吞吐大概 60~80Mbps开了 AP 并发之后通常掉到 20~40Mbps。这个数字如果远低于预期一般不是软件问题而是射频干扰太严重。可以尝试把 AP 放在 5GHz 频段如果芯片支持同时收 2.4G 的 STA、发 5G 的 AP那会舒服很多。还有一个小技巧测吞吐之前先确认没有 Android 厂商自己的流量策略在捣乱。某些系统版本默认对后台热点做带宽限制直接改settings put global tether_supported 1、settings put global tether_offload_disabled 1可以关掉部分限制。但注意这个方法不同品牌差异很大不要指望一句命令解决所有问题。5. 踩坑实录并发场景的常见问题速查表5.1 连接、转发、性能三类问题与解法这里把我遇到过的、以及同行交流时高频出现的问题整理成一张表直接照着查就行。现象排查方向常用解法AP 起不来hostapd 报 interface up 失败驱动没创建虚拟接口固件不支持组合检查iw listinterface combinations用iw dev wlan0 interface add ap0 type __ap测试换固件版本AP 能起但下游手机搜不到热点hostapd 配置 SSID 广播关闭信道被雷达占用检查配置ignore_broadcast_ssid0换信道或调为 auto手机连上热点但无法上网NAT 规则缺失转发未开启DNS 配置错误检查cat /proc/sys/net/ipv4/ip_forward重新执行 iptables 三条规则dnsmasq 加--server能上网但访问部分 App 报unauthorized/401HTTP API 鉴权请求失败通常是网络代理或 DNS 异常检查终端能否解析域名有些云接口需要固定出口 IPAP 后的 NAT 会改变源 IP需要业务侧加白名单STA 频繁断连STA 和 AP 同信道干扰驱动固件并发稳定性差尝试改用 5GHz AP升级驱动固件降低 AP 发射功率热点连接设备多了之后新设备连不上DHCP 地址池耗尽NAT 连接表满调整 dhcp-range 范围sysctl net.netfilter.nf_conntrack_max适当调大转发链路 iperf3 吞吐极低同信道自干扰bpf/流量策略限速先关掉系统热点限速再用 5G 频段 AP 验证如果双频并发吞吐会明显改善iptables 规则加不上报 Permission denied内核配置缺少 NETFILTERSELinux 拦截检查CONFIG_NETFILTER临时setenforce 0验证仅工程机这个 401 unauthorized 单独说一下。很多开发者做并发联调时会遇到服务端返回{code:api_key_required,message:...}第一反应是 Wi-Fi 并发搞坏了网络。其实大部分情况下就是 HTTP 请求本身缺凭证、或者 API Key 失效。网络层的原因最多是——设备经过 AP 的 NAT 出去后服务端看到的源 IP 变了如果你在服务端按 IP 做了白名单限制就会误杀。5.2 几个容易被忽略的底层细节最后再补充三条经验都是容易被忽略但很影响结果的东西。第一条SELinux 是并发调试的隐形杀手。Android 的 SELinux 策略默认只允许 system_server 操作热点相关的 netlink 和 iptables。你用 adb shell 手动加规则时如果没切换到 permissive 模式有些规则会“静默失败”——命令不报错但实际没生效。遇到“配置了却不工作”的情况先执行setenforce 0再试。生产环境要改的话需要为相关进程单独写 te 策略不能全程 permissive。第二条连接数限制的问题。很多 Android 设备的热点默认只支持 8 或 16 个终端连接这个限制来自驱动或框架层的 softap 配置。并发场景下STA 本身又是一个连接所以实际可用的 AP 连接数可能要减 1。如果产品要求“能下沉终端 32 个”你得确认驱动对关联表大小的支持而不是只改 hostapd 的max_num_sta。第三条MAC 地址随机化会干扰产测。Android 10 之后终端默认对每个 Wi-Fi 网络使用随机 MAC这会导致你从 AP 侧看到一堆陌生的 MAC 地址完全对应不上设备。产测场景建议在 hostapd 里配置macaddr_acl白名单或者从测试 App 里读取终端真实 MAC 再上报否则后续定位问题特别痛苦。写在最后的一点心得做 STA/AP 并发这个功能给我最大的教训就是先验硬件再谈软件。我见过太多人一上来就研究 Android 源码怎么改最后项目复盘时才发现芯片根本不支持并发整个方案推到重来。正确顺序永远是先看iw list、先找原厂确认固件能力、先用 root shell 手动拉通一条最小通路再考虑框架层的定制。这个顺序能帮你省下一大半的无用功。另外并发功能的调试周期通常比预期长因为它横跨驱动、框架、网络协议栈三层。遇到问题不要只盯一个层面我会习惯性同时开三个终端一个看 dmesg、一个看 tcpdump、一个盯着 iptables 和 conntrack 的状态很多时候答案就在三者交叉的瞬间跳出来。希望这篇文章能让你少踩几个坑。
返回列表