ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Android 13双网并存:4G与WiFi网络切换的原理与排查实践

Android 13双网并存:4G与WiFi网络切换的原理与排查实践

这批Android 13设备在4G网络环境和WiFi内网之间来回切换时的表现,把人折腾得够呛。现场最常见的情况是:设备明明连着WiFi,右上角也显示WiFi图标,可应用上报数据时偏偏走的还是4G流量;反过来,4G有信号格,但业务App提示"无网络"。调试过一批Android 13设备之后,我对这个系统在网络选路、网络能力评估上的处理逻辑有了更完整的认识。这篇内容就把Android 13在4G蜂窝网络和WiFi内网场景下的链路原理、配置要点、排查思路完整讲一遍,适合正在做设备管理、现场集成、Android系统调试以及相关App开发的同事参考,理解这套逻辑之后,很多"玄学"问题其实都能定位到具体环节。

1. 先搞清楚双网并存的底层机制

1.1 为什么手机能同时开着WiFi和4G

Android的联网架构并不是"同一时间只能有一个网络在工作"。系统里的核心服务ConnectivityService同时管理着多个NetworkAgent,WiFi是一个网络代理,蜂窝数据是另一个网络代理,它们各自独立注册,独立维护链路状态,互为备份也互为竞争关系。所以"WiFi和4G同时打开"这件事,在系统层面是常态,不是异常。

Android 13沿用了这套多网络管理框架,并且在新版本里对网络能力的细分更严格了。每个网络都会上报自己的能力集,比如是否具备访问公网的能力、是否属于计费网络、当前信号强度、链路带宽估算值等。系统根据这些信息给每个活跃网络打分,分数最高的那一个成为"默认网络",也就是承载默认路由、大多数应用流量实际走向的网络。其他网络依然存在,但除非应用显式绑定,否则普通流量不会走到它们上面。

这里要纠正一个常见误区:很多人以为"WiFi断开之后4G才会启用",实际上两个数据链路一直共存,系统只是在路由层面决定默认流量走哪条。Android 13引入的"网络逃生舱"机制甚至允许某些应用在默认网络无公网能力时自动寻找替代网络,这种设计背后的数据走向,是做现场联调时需要非常清楚的。

1.2 网络评分机制怎么决定默认网络

可以把网络评分理解成系统内部的"综合体检表"。Android框架层有一个专门负责给网络打分的服务,其评估维度可以简单概括为下表的几项。

评估维度说明对默认网络的影响
INTERNET能力网络是否通过了公网连通性验证未通过验证的网络评分大幅降低
NOT_METERED能力是否属于不限流量网络计费网络在同等条件下评分偏低
信号强度4G的RSRP/RSRQ、WiFi的RSSI信号太差会扣分
链路带宽理论上下行速率估算值带宽明显更高时加分
验证结果是否成功访问了系统的网络验证服务器验证失败视为无公网能力

具体到Android 13,系统会维护一个NetworkCapabilities对象,里面有CAPABILITY_INTERNET、CAPABILITY_NOT_METERED、CAPABILITY_VALIDATED这些能力位。默认网络的选择,就是从当前所有活跃网络里挑出综合条件最好的那个。带公网能力的网络比不带公网能力的网络拥有更高优先级的规则,这也是为什么一个验证有效的4G网络,往往能压过只提供内网访问、无法通过公网验证的WiFi,成为默认网络。

现场调试时最让人困惑的"明明连着WiFi,数据却走4G",十有八九就是这个原因:WiFi网络所在的内网无法访问公网验证服务器,系统判定该WiFi不具备INTERNET能力,于是默认网络被评分更高的4G拿走。

1.3 不同视角下的链路差异

站在不同角色的位置上,理解同一套机制的方式不太一样。

对终端使用者来说,关注的是"图标显示什么、流量走了哪条线";对开发者或调试人员来说,更关心的是"系统的网络状态机处于哪个阶段";而站在设备管理角度,"设备同时连着两个网络,哪些流量走了哪个接口"才是核心问题。

Android 13里还有一项需要留意的行为:当WiFi内网被判定为"无公网能力"时,系统状态栏上WiFi图标下面可能出现一个感叹号。这个感叹号不代表网络故障,它只是告诉你"这个网络通不了公网"。很多现场人员一看到感叹号就以为是WiFi坏了,其实内网访问完全正常,数据走4G只是因为系统默认路由策略使然。

2. 4G蜂窝数据链路:从APN到数据通道

2.1 APN参数到底影响什么

APN在很多文章里被轻描淡写成"接入点名称",但它在Android蜂窝网络里承担的任务要复杂得多。APN是一组参数集合,决定了终端与运营商核心网之间建立的PDN连接类型。它包含APN名称、MCC/MNC、APN协议(IPv4或IPv6)、APN漫游协议、鉴权类型、用户名密码等字段。

Android 13在开机注册网络时,通过TelephonyNetworkFactory发起数据连接请求,系统根据当前SIM卡信息去匹配运营商预置的APN配置,匹配成功后才发起PDP/PDN上下文激活。这里有个容易踩坑的地方:某些设备因为运营商配置更新不及时,或者手动改过APN字段,导致系统实际激活的PDN连接类型与业务平台预期不一致。

实际操作中遇到4G无法拨号上网,我的排查习惯是先看当前设备用的是哪个APN。打开设置里的接入点名称,检查APN协议是否设成了IPv6,而业务服务器只监听IPv4,这种错配现场非常常见。直接用adb也可以查询:

adb shell dumpsys telephony.registry | grep -E "mDataRegState|mDataNetworkType|mApnSetting"

看到mDataNetworkType显示LTE的同时,还要确认mDataRegState是否为IN_SERVICE。如果注册状态异常,只看APN没有任何意义,需要先解决网络注册问题。

2.2 信号格与数据通道是两回事

信号格显示的其实是射频层面的信号质量,比如LTE场景下对应的RSRP、RSRQ、SINR这些指标。而"能不能上网"取决于网络注册状态、PDN上下文是否激活、数据业务是否被运营商放行。这两个层面的状态并不总是同步。

最常见的翻车现场就是"信号满格,但应用刷不出数据"。这时候先别怀疑天线,用命令查看数据注册状态:

adb shell dumpsys telephony.registry | grep -E "mDataRegState|mDataNetworkType|mServiceState"

如果注册状态正常,再确认移动数据开关状态:

adb shell settings get global mobile_data

返回1代表开启,0代表关闭。Android 13里即使数据开关开启,若设备的数据漫游开关没打开,在漫游地也一样出现"有信号没数据"。有些项目设备插的是物联网卡,这类卡经常被运营商限制数据业务或限制特定APN,排查时要先把卡换到普通手机上做交叉验证,这一步能快速判断问题在卡侧还是设备侧。

2.3 4G下的DNS与MTU细节

蜂窝网络的DNS地址通常由运营商通过DHCP或PCO(Protocol Configuration Options)下发给终端,Android 13默认使用这条链路上的DNS配置,不需要手动设置。但很多项目为了统一解析内网域名,会去修改私有DNS或者让设备使用固定DNS,这里存在一个隐藏风险:如果4G和WiFi内网使用不同的DNS策略,应用在两个网络之间切换时,域名解析行为会跟着改变,导致一些依赖内网域名的服务时通时断。

MTU同样值得关注。4G链路常见的MTU是1500,但在某些专网或运营商核心网配置下,实际可用MTU可能只有1400甚至更小。表现为大包传输卡顿、视频加载不了,但小流量却正常。验证方法是用ping命令测试大包分片:

adb shell ping -s 1472 -c 3 8.8.8.8

注意这里不是鼓励大家折腾公网地址,只是说明排查大包问题时的通用方法。ping不能确认MTU问题时,配合抓包看TCP握手后的分段情况会更准确。

3. WiFi内网要搞明白的几个关键点

3.1 DHCP和静态IP的选择

WiFi内网的地址分配无非DHCP和静态IP两种方式。现场设备量大、需要固定身份的时候,我一般建议直接配静态IP,避免DHCP地址池不够用或者租约过期导致设备掉线。

Android 13的WiFi设置入口里可以修改IP设置,从DHCP改为静态之后,需要手动填写IP地址、子网掩码、网关和DNS。这里有一个很常见的低级错误:子网掩码填错。比如设备IP是192.168.10.50,掩码却填了255.255.255.0以外的值,内网交换机转发就会出问题。另一个低级错误是网关填错,指向了不存在的地址,结果设备能拿到IP却出不了内网。

静态IP场景下,DNS配置建议直接指向内网DNS服务器,而不是运营商DNS,否则可能出现内网域名解析失败。修改完成后,可以立即用命令验证连通性:

adb shell ping -c 3 网关IP adb shell ping -c 3 内网服务器IP

如果网关通、服务器不通,重点检查交换机端口、VLAN权限和防火墙策略。

3.2 内网隔离与多AP场景

企业、园区、实验室的WiFi内网通常会做网络隔离。常见做法是同一个SSID下启用客户端隔离,终端之间互访被阻断,只允许访问网关或特定服务器。另一个做法是按VLAN划分访客网络和办公网络,访客网络访问不到核心业务网段。

现场排查"WiFi能连上但ping不通"时,先别急着怀疑设备,可以按这个顺序验证:先ping网关,网关通说明二层链路正常,问题大概率在路由或防火墙;网关不通说明终端压根没进入有效网络。再ping同网段的其他设备,如果同网段也不通,就要怀疑SSID背后的客户端隔离策略。

还有一种情况:多个AP部署时,手机连到了某个信号最好但归属VLAN不对的AP上,表现为某些区域正常、某些区域无法访问内网。这种情况可以引导终端主动切换SSID或关闭再打开WiFi,重新触发AP关联,问题通常会暴露得更明显。

3.3 双网卡并存:路由表和策略规则

Android 13在路由层面维护着一套策略路由规则。设备同时存在WiFi和蜂窝两个接口时,系统会为默认网络对应的网卡生成默认路由,同时为其他网络生成按需路由或仅限特定应用访问的路由。

查看设备当前网络接口和路由规则,最有用的命令是:

adb shell ip addr adb shell ip route show table all adb shell ip rule show

ip rule show的输出里能看到不同fwmark对应的路由表编号,优先级越高的规则越先匹配。Android默认网络对应的路由表优先级最高,这样设计是为了保证"默认流量走评分最高的网络"。如果想强制某个应用走WiFi内网,需要在应用层使用NetworkCallback绑定指定的Network对象,或者在有系统权限的情况下调整网络策略,单纯改路由表在Android 13里往往不够彻底,因为包会被netd的规则拦截。

4. 联网模式与开发者选项里的关键配置

4.1 移动数据开关和"始终开启移动数据"

开发者选项里有一个开关叫"始终开启移动数据",对应的系统设置项是Settings.Global.MOBILE_DATA_ALWAYS_ON。这个开关默认关闭时,当设备连上WiFi后,蜂窝数据链路会进入休眠状态;一旦WiFi断开,系统需要重新激活蜂窝链路,耗时经常在几秒甚至十几秒,现场设备如果在移动过程中频繁切换网络,业务就会明显卡顿。

把这个开关打开之后,WiFi存在时蜂窝链路继续保持连接,WiFi断开的瞬间数据通道立即接管,切换时间大幅缩短。代价是待机功耗会升高,因为射频模块一直保持数据连接。对于需要稳定在线的移动设备来说,这个取舍通常值得。调试命令如下:

adb shell settings put global mobile_data_always_on 1

修改完成后不需要重启,立即生效。

除了这个开关,还需要留意数据漫游开关。现场设备如果用了非本地归属的物联网卡,漫游开关关闭时,即使信号正常也无法上网。这个设置位于设置-网络-移动网络-数据漫游,修改后建议再执行一次飞行模式切换,强制重新注册网络。

4.2 私有DNS对两个网络的影响

Android 13支持配置私有DNS,有三种模式:关闭、自动、指定主机名。默认的自动模式使用网络下发的DNS配置;关闭模式表示完全禁用私有DNS;指定主机名模式会强制所有DNS查询走某个DoT服务器。

这个配置在4G和WiFi内网并存场景下非常容易出问题。如果设备配置了某个外部DoT服务器作为私有DNS,WiFi内网里那些依赖内网DNS解析的域名就会出现"能上内网IP但解析不了内网域名"的诡异现象,因为DNS查询全被导向了外部服务器,内网域名解析自然失败。

碰到内网域名解析异常,先检查私有DNS模式:

adb shell settings get global private_dns_mode

显示hostname就说明被强制指定了DoT服务器。临时恢复自动模式的方法:

adb shell settings put global private_dns_mode auto

对于纯内网项目,最稳妥的做法是把私有DNS设为关闭,完全走内网提供的DNS解析。

4.3 用命令行摸清真实网络状态

设置界面里显示的WiFi连接状态和系统实际网络状态并不总是一致,Android 13里最可靠的判断方式是直接看ConnectivityService的实时状态:

adb shell cmd connectivity monitor

这个命令会持续输出网络变化事件,包括每个网络的验证结果、默认网络切换、能力变化等。信息量足够大,适合现场复现问题时挂机观察。如果只想看当前状态快照:

adb shell dumpsys connectivity | grep -E "NetworkAgentInfo|Default network|NetworkRequest"

我个人的习惯是先把dumpsys connectivity完整导出保存,再触发一次网络切换,对比前后的默认网络变化,多数"流量为什么走了A没走B"的问题都能在这个环节看出端倪。

5. 场景实操:4G与WiFi内网双网并存的排查流程

5.1 一套可复用的排查顺序

面对Android 13设备的联网问题,如果一上来就抓包或者改参数,效率很低。建议按"物理层-链路层-网络层-应用层"的顺序逐级排查,避免在错误层面耗费时间。

第一步确认物理关联状态:设备是否成功连接WiFi SSID、信号强度如何;4G是否有信号、是否注册上网络。第二步确认链路层:WiFi是否拿到IP、DHCP是否正常;4G的APN是否匹配、PDN是否激活。第三步确认网络层:路由表是否正常、默认网络是哪条链路、DNS解析是否正常。第四步才是应用层的权限、后台限制、接口地址等。

给出一个具体案例。某项目现场设备全部连接WiFi内网,但业务端后台看到大量设备上报的IP是4G运营商的IP。排查过程就是先ip route show table all,发现默认路由确实指向蜂窝网卡,再查dumpsys connectivity确认WiFi被判定为无INTERNET能力,最终因为在路由规则里加了针对内网网段的优先级策略,业务流量才稳定走WiFi接口。

5.2 高频问题速查表

现象可能原因排查命令解决建议
4G满格但无法上网数据开关关闭、漫游开关关闭、APN错配settings get global mobile_data、dumpsys telephony.registry开启数据开关,恢复APN默认配置,重新选择运营商
WiFi连上但提示无公网内网验证不到公网服务器,系统判定无INTERNET能力cmd connectivity monitor确认业务是否只走内网;若只走内网则按内网流量配置路由策略
内网域名解析失败私有DNS指向外部DoT服务器settings get global private_dns_mode关闭私有DNS或改为自动模式
WiFi连上但ping不同网关DHCP异常、VLAN隔离、交换机端口问题ip addr、ping 网关IP检查DHCP地址池、交换机配置,必要时指定静态IP
默认流量走4G而非WiFiWiFi被判定无INTERNET能力或评分过低dumpsys connectivity调整路由策略或网络请求绑定指定网络
耗电异常且WiFi存在时发热MOBILE_DATA_ALWAYS_ON开启确认开关状态关闭"始终开启移动数据"

5.3 日志与抓包定位网络切换问题

排查现场问题如果只靠状态快照,往往不够。需要日志来还原时间线,特别是网络切换相关的瞬时状态。

抓取系统网络服务日志的通用命令如下:

adb logcat -s ConnectivityService:V WifiService:V WifiStateMachine:V TelephonyRegistry:V

复现问题的同时挂上logcat,观察默认网络切换的日志时间点,再配合业务层的错误日志,基本能还原出"网络切换导致业务连接中断"的完整链路。对于更底层的网络报文,可以在root权限下使用tcpdump抓包,重点看ICMP、DNS、TCP SYN等关键报文。

日志级别上,ConnectivityService默认打印的信息已经覆盖了网络验证、网络评分、默认网络切换这些关键节点。WifiService的日志覆盖扫描、关联、DHCP过程。TelephonyRegistry则覆盖蜂窝注册和数据状态变化。这三个服务的日志足够覆盖绝大多数4G+WiFi内网的排查场景。

抓包定位到具体报文层面后,再回看系统设置项,比如确认是否因为网络评分机制导致路由迁移,还是因为目标服务器主动断开了旧连接,问题就清晰了。

我个人在实际调试过程中最深的体会是:Android 13在4G和WiFi内网并存场景下的表现,大部分"怪问题"都不是硬件故障,而是系统按规则选择了"最合理"的网络,但这个合理与否需要结合业务场景来判断。调试这类问题,先搞清楚设备当前默认网络是谁、为什么是它,比盲目改设置有效得多。最后再分享一个小技巧:现场调试时用adb shell cmd connectivity airplane-mode enable和disable来切换飞行模式,比手动在屏幕上点击稳定可靠,尤其在需要反复复现网络切换问题时,这个命令可以省下大量等待时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进