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 的麻烦。
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 是负载均衡。车载场景我建议用主备模式。为什么?因为负载均衡在某些交换机上会有兼容性问题,而主备模式简单可靠。
在 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 调优后,记得检查 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。每一步都有坑,但只要你理解了原理,加上实际测试,就能搞定。
下一章我们会聊更深入的网络诊断和故障排查。到时候我会分享一个我亲手踩过的「车载网络断连」大坑,保证让你印象深刻。