车载网络系统定制:ConnectivityService定制、WIFI与以太网管理、车载热点与Tethering、网络策略优化

各位好,我是老张。今天咱们聊聊车载网络系统定制。说实话,这部分内容在手机Android上已经非常成熟了,但一搬到车上,问题就全变了。我最早做车载项目时,以为直接拿手机代码改改就行,结果被车载以太网和热点策略折腾得够呛。嗯,今天就把这些坑和经验分享给大家。

8.1 ConnectivityService 定制:车载场景下的网络中枢改造

ConnectivityService 是 Android 网络框架的核心。它负责管理所有网络类型(WiFi、以太网、蜂窝等)的注册、评分、切换。在手机上,默认逻辑是“有WiFi优先用WiFi,WiFi不行切蜂窝”。但在车上,这个逻辑完全行不通。

为什么? 因为车载场景下,网络来源非常复杂:

  • 车载以太网(OBD、诊断、高精地图数据流)
  • 车载WiFi Station(连接停车场/家庭热点)
  • 车载WiFi AP(车内乘客热点)
  • 内置eSIM/4G/5G蜂窝
  • USB Tethering(手机投屏共享网络)

我见过一个项目,默认的 ConnectivityService 把以太网和 WiFi 评分搞混了,导致高精地图数据走的是 WiFi 而不是有线以太网,延迟直接飙到 200ms。所以,定制 ConnectivityService 的第一步,就是重写网络评分策略

8.1.1 网络评分策略定制

Android 的 NetworkAgent 在注册时会携带一个 score(评分),ConnectivityService 根据 score 选择默认网络。默认 WiFi 是 60,以太网是 70,蜂窝是 50。但在车上,我们需要重新定义:

// 车载网络评分建议
// 以太网(高精地图、诊断):90
// 车载WiFi Station(乘客娱乐):70
// 内置蜂窝(紧急呼叫、OTA):80
// USB Tethering(开发调试):50
// 车载热点(AP模式):40

具体怎么改?我习惯在 NetworkAgentInfo.javagetCurrentScore() 方法中注入车载策略。比如:

// 伪代码示例
if (networkType == TRANSPORT_ETHERNET) {
    // 车载以太网优先级最高
    score = 90;
    // 如果是诊断口,再+10
    if (isDiagnosticPort()) score += 10;
} else if (networkType == TRANSPORT_WIFI) {
    // 判断是Station还是AP
    if (isWifiStationMode()) {
        score = 70;
    } else {
        // AP模式(热点)评分最低
        score = 40;
    }
}
注意: 不要直接修改 framework 层的 score 常量。我建议通过 SystemProperties 或 Vendor Overlay 动态注入,方便不同车型适配。

8.1.2 网络切换策略优化

手机上网络切换很频繁,但车上不行。你想想看,车辆在高速行驶中,如果 WiFi 信号稍微弱一点就切到蜂窝,会导致地图数据中断、语音通话卡顿。我建议的策略是:

  • 增加切换阈值:默认 score 差 5 就切换,车载建议差 15 以上才切换
  • 引入“粘滞”机制:一旦连接到以太网,除非断开超过 5 秒,否则不主动切换
  • 场景感知:车辆行驶中(车速 > 10km/h),禁止从以太网切到 WiFi
// 粘滞机制示例
private boolean shouldSwitchNetwork(NetworkAgentInfo current, NetworkAgentInfo candidate) {
    if (current.networkType == TRANSPORT_ETHERNET && isVehicleMoving()) {
        // 行驶中,以太网粘滞
        return false;
    }
    // 正常评分比较
    return candidate.getCurrentScore() - current.getCurrentScore() > SWITCH_THRESHOLD;
}

8.2 WiFi 与以太网管理:双网卡共存与优先级

车载系统通常同时存在 WiFi 和以太网。以太网用于高带宽、低延迟的数据(地图、诊断),WiFi 用于乘客娱乐。但 Android 默认只允许一个默认网络。怎么办?

我的做法是: 利用 NetworkFactoryNetworkCapabilities 做网络分流。让高精地图 App 绑定以太网,让浏览器、视频 App 走 WiFi。

8.2.1 网络绑定(Network Binding)

在 Android 中,App 可以通过 ConnectivityManager.bindProcessToNetwork() 绑定到特定网络。但车载场景下,我们更希望系统自动分流。我封装了一个 VehicleNetworkPolicyManager

// 车载网络策略管理器
public class VehicleNetworkPolicyManager {
    // 高精地图App包名
    private static final String MAP_PACKAGE = "com.vehicle.map";
    // 诊断App包名
    private static final String DIAG_PACKAGE = "com.vehicle.diag";

    public void onAppStarted(String packageName) {
        if (MAP_PACKAGE.equals(packageName) || DIAG_PACKAGE.equals(packageName)) {
            // 绑定到以太网
            bindToEthernet(packageName);
        } else {
            // 其他App默认走WiFi或蜂窝
            bindToDefaultNetwork(packageName);
        }
    }
}
小技巧: 我曾在项目中遇到一个问题:地图 App 绑定了以太网,但以太网 DHCP 还没拿到 IP,导致 App 启动时无网络。解决方案是监听以太网连接状态,等 NetworkCallback.onAvailable() 后再绑定。

8.2.2 以太网 DHCP 与静态 IP 管理

车载以太网通常有两种场景:

  • 诊断口:固定 IP(如 192.168.1.100),不需要 DHCP
  • 数据口:DHCP 获取 IP(连接 T-Box 或 OBD 网关)

我建议在 EthernetManager 的配置中增加一个 isDiagnosticPort 标志。如果是诊断口,直接跳过 DHCP,使用静态 IP:

// EthernetConfigStore.java 定制
if (isDiagnosticPort(iface)) {
    IpConfiguration config = new IpConfiguration();
    config.setIpAssignment(IpConfiguration.IpAssignment.STATIC);
    StaticIpConfiguration staticConfig = new StaticIpConfiguration();
    staticConfig.ipAddress = new LinkAddress("192.168.1.100", 24);
    staticConfig.gateway = new InetAddress("192.168.1.1");
    config.setStaticIpConfiguration(staticConfig);
    return config;
}

8.3 车载热点与 Tethering:乘客娱乐与安全隔离

车载热点是刚需。乘客要刷视频、玩游戏,但热点不能影响车辆本身的网络通信。这里有两个关键点:网络隔离带宽限制

8.3.1 热点与车载网络隔离

默认的 Android Tethering 会把热点流量直接路由到蜂窝或 WiFi。但在车上,热点流量应该走独立的网络栈,不能和以太网(高精地图)混在一起。我采用 VLAN 或 iptables 标记 的方式隔离:

# 创建独立的网络命名空间
ip netns add hotspot_ns
# 将热点接口移入该命名空间
ip link set wlan1 netns hotspot_ns
# 在命名空间中配置独立的路由和 NAT
ip netns exec hotspot_ns iptables -t nat -A POSTROUTING -o rmnet0 -j MASQUERADE

这样,热点流量和车载以太网流量完全隔离。即使乘客把带宽占满,也不会影响地图导航。

我曾经踩过的坑: 有次项目测试,发现开启热点后,车载以太网延迟从 5ms 飙升到 500ms。查了半天,发现是默认的 Tethering 把以太网也加入了路由表。解决方案是在 Tethering.java 中排除以太网接口。

8.3.2 带宽限制与 QoS

乘客看视频可以,但不能影响驾驶安全相关的网络。我建议在热点的 iptables 中做带宽限制:

# 限制热点总带宽为 20Mbps
iptables -A FORWARD -i wlan1 -o rmnet0 -m limit --limit 20mbit -j ACCEPT
iptables -A FORWARD -i wlan1 -o rmnet0 -j DROP

同时,为高优先级流量(如地图更新、OTA)预留带宽:

# 为地图App预留 10Mbps
iptables -t mangle -A OUTPUT -p tcp --dport 443 -m owner --uid-owner map_app_uid -j CLASSIFY --set-class 1:10

8.4 网络策略优化:省电、安全与稳定性

车载网络策略和手机完全不同。手机可以随时开关 WiFi、切换网络,但车不行。车辆启动后,网络必须快速就绪,而且不能频繁切换。

8.4.1 网络唤醒与快速连接

车辆从休眠到唤醒,网络模块需要快速上线。我建议:

  • 以太网:使用 WoL(Wake-on-LAN)功能,车辆解锁即唤醒以太网 PHY
  • WiFi:保存上次连接的 BSSID,跳过扫描阶段,直接尝试连接
  • 蜂窝:保持 RRC 连接(不进入 IDLE 态),减少 RRC 重建时间
// WiFi 快速连接示例
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// 跳过扫描,直接连接已知网络
wifiManager.connect(wifiManager.getConfiguredNetworks().get(0), null);

8.4.2 省电策略:按需关闭网络

车辆熄火后,网络模块不能一直开着,否则电瓶会亏电。我建议的策略是:

车辆状态 以太网 WiFi 蜂窝
行驶中 开启 开启(乘客) 开启(OTA)
停车(ACC ON) 开启 开启 开启
停车(ACC OFF) 关闭 关闭 低功耗模式(仅接收紧急消息)
休眠 关闭 关闭 关闭(RTC 定时唤醒检查 OTA)

这个策略我是在 VehicleNetworkPolicyService 中实现的,监听车辆电源状态广播,动态开关网络接口。

8.4.3 安全策略:防止网络劫持

车载网络的安全性不容忽视。我见过一个案例,黑客通过车载 WiFi 热点入侵了以太网,篡改了地图数据。解决方案是:

  • 网络隔离:热点和车载网络使用不同的 VLAN
  • 防火墙:在以太网接口上只允许特定端口(如 443、1234)
  • 证书校验:所有 OTA 和地图更新必须校验服务器证书
# 以太网防火墙规则示例
iptables -A INPUT -i eth0 -p tcp --dport 22 -j DROP  # 禁止SSH
iptables -A INPUT -i eth0 -p tcp --dport 443 -j ACCEPT  # 只允许HTTPS
iptables -A INPUT -i eth0 -j DROP  # 其他全部丢弃

知识体系总览

下面这张图是我梳理的车载网络系统定制核心逻辑,大家可以对照着看:

车载网络系统定制核心架构 ConnectivityService 定制 WiFi 管理 以太网管理 热点与Tethering • Station/AP模式切换 • 快速连接(跳过扫描) • 网络评分调整 • DHCP/静态IP管理 • 诊断口识别 • WoL唤醒 • 网络隔离(VLAN) • 带宽限制(QoS) • 安全防火墙 网络策略优化(省电/安全/稳定性)

好了,以上就是车载网络系统定制的核心内容。从 ConnectivityService 的评分策略,到 WiFi/以太网的双网卡管理,再到热点隔离和网络策略优化,每一步都有不少细节。我个人觉得,最关键的是要理解车载场景的特殊性——网络不是给一个人用的,而是给车和乘客同时用的,优先级和隔离必须做好。

如果你在实际项目中遇到网络切换异常、热点影响车载通信等问题,可以回头看看今天讲的这几个点。嗯,今天就到这里。

公众号:蓝海资料掘金营,微信deep3321