4、车载以太网优化:EthernetManager 使用、链路聚合配置、MTU 调优实战

好,咱们进入第四章。这一章聊的是车载以太网优化。说实话,在 Automotive 项目里,以太网这块坑不少。我最早接触车载以太网时,以为跟普通 Linux 以太网差不多,结果被狠狠上了一课。

车载环境对网络的要求很特殊。延迟要低,带宽要稳,还得考虑电磁干扰。你想想看,一辆车在高速上跑,网络突然卡顿,导航地图加载不出来,那体验多糟糕。所以,优化是必须的。

4.1 EthernetManager 的正确打开方式

Android Automotive 里,网络管理不是直接操作 Linux 的 ifconfig 或 ip 命令。系统提供了 EthernetManager 这个 API。说白了,它就是车载以太网的控制中心。

我个人习惯,在写网络相关代码时,第一件事就是检查 EthernetManager 是否可用。别笑,我见过有人直接调用,结果在非 Automotive 设备上 crash 了。

// 获取 EthernetManager
EthernetManager ethernetManager = context.getSystemService(EthernetManager.class);
if (ethernetManager == null) {
    // 非 Automotive 设备,或者以太网不可用
    return;
}

拿到实例后,最常用的操作是监听网络状态。嗯,这里要注意,EthernetManager 的回调是在 Binder 线程里触发的,别直接做 UI 操作。

EthernetManager.Listener listener = new EthernetManager.Listener() {
    @Override
    public void onAvailabilityChanged(String iface, boolean isAvailable) {
        // isAvailable 为 true 表示网卡可用
        // 我建议在这里做网络配置的初始化
        if (isAvailable) {
            configureNetwork(iface);
        }
    }
};

// 注册监听
ethernetManager.addListener(mainExecutor, listener);

为什么强调用 mainExecutor?因为回调里你可能要更新 UI 状态,比如显示网络连接图标。用主线程执行器可以省去 handler 的麻烦。

小技巧: 在车载项目中,我习惯在 EthernetManager 回调里加上日志。因为车载以太网有时会出现物理层断开又重连的情况,日志能帮你快速定位是硬件问题还是软件问题。

4.2 链路聚合配置实战

链路聚合,听着挺唬人。其实就是为了提高带宽和冗余。车载场景下,有时候会用两条物理网线连接到同一个交换机,做负载均衡或故障切换。

我曾经在一个项目中,客户要求实现双网口冗余。一条线断了,另一条要无缝切换。当时我第一反应是用 Linux 的 bonding 驱动。但 Android 系统对 bonding 的支持有限,需要自己配置。

配置链路聚合,核心是创建 bonding 设备,然后把物理网口绑定上去。下面是我在项目中用过的脚本思路:

// 通过 Shell 执行配置(需要 root 权限或系统权限)
String[] commands = {
    "echo '+bond0' > /sys/class/net/bonding_masters",
    "echo 'mode=1' > /sys/class/net/bond0/bonding/mode",  // 主备模式
    "echo 'eth0' > /sys/class/net/bond0/bonding/slaves",
    "echo 'eth1' > /sys/class/net/bond0/bonding/slaves",
    "ifconfig bond0 up"
};

for (String cmd : commands) {
    Runtime.getRuntime().exec(cmd);
}

这里 mode=1 是主备模式,mode=0 是负载均衡。车载场景我建议用主备模式。为什么?因为负载均衡在某些交换机上会有兼容性问题,而主备模式简单可靠。

避坑指南: 我曾经在配置 bonding 时,忘记把物理网口从原来的网络栈中移除。结果 bonding 设备起来了,但物理网口还在独立工作,导致网络冲突。正确的做法是先 down 掉物理网口,再添加到 bonding。

在 Android 系统里,更推荐的做法是通过 ConnectivityManager 来管理聚合后的网络。因为 Android 的网络评分机制会自动选择最优网络。你只需要把 bonding 设备注册为系统网络即可。

4.3 MTU 调优实战

MTU,最大传输单元。车载以太网默认 MTU 是 1500 字节。但说实话,这个值在车载场景下不一定最优。

我遇到过一个问题:车载摄像头传输视频流时,偶尔出现画面撕裂。排查了很久,最后发现是 MTU 设置不合理。视频数据包太大,被分片后重组时出了乱序。

调优 MTU 的核心思路是:找到那个「不丢包、不延迟」的最大值。方法很简单,用 ping 命令测试:

// 测试不带分片的包大小
ping -M do -s 1472 192.168.1.1
// -M do 表示禁止分片
// -s 1472 表示 ICMP 负载大小,加上 IP 头 20 字节和 ICMP 头 8 字节,正好 1500

如果 ping 通了,说明当前 MTU 没问题。如果不通,就减小 -s 的值,直到找到临界点。我一般从 1472 开始,每次减 10,直到能通为止。

在代码里设置 MTU,可以通过 EthernetManager 或者直接操作系统文件:

// 通过 EthernetManager 设置(需要系统权限)
EthernetManager ethernetManager = context.getSystemService(EthernetManager.class);
if (ethernetManager != null) {
    // 设置 MTU 为 9000(巨型帧)
    ethernetManager.setMtu("eth0", 9000);
}

// 或者直接写文件
try {
    FileWriter fw = new FileWriter("/sys/class/net/eth0/mtu");
    fw.write("9000");
    fw.close();
} catch (IOException e) {
    e.printStackTrace();
}
重要提醒: 设置 MTU 不是越大越好。巨型帧(9000 字节)能减少 CPU 中断次数,提高吞吐量。但如果你的交换机或对端设备不支持,反而会导致丢包。我建议在车载内部网络(如摄像头到域控制器)用巨型帧,对外通信保持 1500。

还有一个细节:MTU 调优后,记得检查 TCP 的 MSS(最大分段大小)。MSS 会自动根据 MTU 调整,但有些老旧设备不会。你可以用 ip tcp_metrics 命令查看。

嗯,这里再补充一点。车载以太网有时会使用 VLAN。VLAN 标签会占用 4 个字节,所以实际可用 MTU 要减 4。如果你设置了 1500,加上 VLAN 标签后实际包大小是 1504,有些交换机可能会丢弃。我习惯把 MTU 设为 1504 或更大,给 VLAN 留出空间。

场景 推荐 MTU 说明
普通数据通信 1500 兼容性最好
视频流传输 4000-9000 减少分片,降低延迟
VLAN 环境 1504 为 VLAN 标签预留空间
诊断/OTA 升级 9000 提高大文件传输效率

最后总结一下。车载以太网优化,说白了就是三件事:用好 EthernetManager 的 API、配好链路聚合、调好 MTU。每一步都有坑,但只要你理解了原理,加上实际测试,就能搞定。

下一章我们会聊更深入的网络诊断和故障排查。到时候我会分享一个我亲手踩过的「车载网络断连」大坑,保证让你印象深刻。