20、网络与连接:Wi-Fi HAL、Bluetooth 协议栈、NFC、Ethernet 管理

嵌入式 Android 设备,说白了就是一台「会联网的盒子」。不管是智能音箱、车机还是工业平板,网络连接都是命脉。今天我们来聊聊 Android 系统中四大连接模块:Wi-Fi、蓝牙、NFC 和以太网。每个模块我都踩过坑,咱们一个一个说。

20.1 Wi-Fi HAL:从框架到芯片的桥梁

Wi-Fi 在 Android 里分两层:上层是 WifiService,下层是芯片厂商的驱动。中间连接的,就是 Wi-Fi HAL(硬件抽象层)。

我个人习惯把 Wi-Fi HAL 理解为「翻译官」。上层说「我要扫描」,HAL 就把它翻译成芯片能懂的指令。Android 从 O 版本开始,强制使用 HIDL 接口,到了 S 版本又转向了 AIDL。嗯,这里要注意:不同版本的 HAL 接口差异很大,移植时最容易翻车。

核心接口:

  • IWifi.hal:定义 Wi-Fi 开关、扫描、连接等操作
  • IWifiStaIface.hal:Station 模式(客户端)接口
  • IWifiApIface.hal:AP 模式(热点)接口

我曾经在移植一款 Realtek 芯片时,发现扫描结果总是为空。折腾了两天,最后发现是 HAL 实现里没有正确填充 scanResults 的频段信息。你想想看,上层拿到空列表,自然以为周围没 Wi-Fi。这个坑,后来我在代码里加了个日志打印,每次扫描都 dump 一下原始数据,问题就一目了然了。

20.2 Bluetooth 协议栈:BlueZ 与 Fluoride 的恩怨

Android 的蓝牙协议栈经历过一次大换血。早期用 BlueZ(Linux 标准协议栈),后来 Google 自己搞了 Fluoride(基于 BlueDroid)。现在大部分设备跑的都是 Fluoride。

为什么换?说白了,BlueZ 太「Linux 化」了,和 Android 的权限模型、生命周期管理格格不入。Fluoride 则是为 Android 量身定做的。

蓝牙协议栈的分层结构大致如下:

Application Layer (Bluetooth App)
    |
GATT / RFCOMM / A2DP Profiles
    |
Bluetooth Host Stack (Fluoride)
    |
HCI (Host Controller Interface)
    |
Bluetooth Controller (芯片固件)

我在项目中遇到过最头疼的问题,是蓝牙与 Wi-Fi 共存。两者共用 2.4GHz 频段,互相干扰。尤其是做车载系统时,手机连着蓝牙放音乐,车机同时开 Wi-Fi 热点,音频就会断断续续。解决方案是启用 PTA(Packet Traffic Arbitration) 机制,让芯片在蓝牙和 Wi-Fi 之间做时分调度。嗯,这个功能需要芯片厂商的固件支持,不是光改软件就能搞定的。

调试小技巧:抓取蓝牙 HCI 日志可以用 adb shell btsnoop,生成的文件用 Wireshark 打开,能看到每一条蓝牙指令的交互过程。我曾经靠这个定位过一个 A2DP 卡顿问题,发现是手机端发送了不兼容的 SBC 编码参数。

20.3 NFC:近场通信的「近」有多近?

NFC 在 Android 里主要做三件事:卡模拟(HCE)、点对点通信、标签读写。底层依赖 NFC HALNFC Service

NFC 的物理层其实很简单,就是 13.56MHz 的射频通信。但 Android 的 NFC 协议栈却相当复杂,因为它要兼容多种芯片(NXP、ST、Broadcom 等)。

我记得有一次做门禁项目,NFC 读卡总是失败。排查后发现是天线匹配问题——嵌入式设备的外壳是金属的,严重影响了 NFC 天线的谐振频率。解决办法是调整匹配电容,让天线重新谐振在 13.56MHz。这个经验告诉我:NFC 的问题,一半在软件,一半在硬件。

避坑指南:我曾经在 Android 12 上发现 NFC 的 enable 接口调用后,底层没有响应。原因是新版本要求 HAL 实现必须支持 getConfig 方法,而我们的老驱动没有实现。Google 在 CTS 测试里会检查这个,通不过就直接报错。

20.4 Ethernet 管理:有线连接的那些事

很多人觉得 Ethernet 简单,插上网线就能用。但在嵌入式 Android 里,Ethernet 管理其实挺麻烦的。Android 原生偏向 Wi-Fi,Ethernet 的支持是后来才加上的。

Ethernet 的核心管理类是 EthernetManager,它通过 EthernetServiceImpl 与 HAL 交互。HAL 层负责检测网线插拔、配置 IP 地址等。

常见的 Ethernet 配置方式有两种:

方式 说明 适用场景
DHCP 自动获取 IP 大多数家用/办公网络
静态 IP 手动配置 IP、网关、DNS 工业现场、专网环境

我在做工业平板项目时,客户要求设备支持双网口——一个接内网,一个接外网。Android 原生只支持一个 Ethernet 接口,怎么办?我只好修改 EthernetNetworkFactory,让它能同时管理两个 NetworkInterface。嗯,这里要注意路由优先级,否则数据包会走错网口。

关键文件路径:

  • frameworks/opt/net/ethernet/:Ethernet 服务框架
  • hardware/libhardware/modules/ethernet/:Ethernet HAL 实现
  • device/<vendor>/<device>/ethernet/:设备级 Ethernet 配置

20.5 网络连接的整体架构

下面这张图展示了 Android 网络连接的整体架构。你会发现,无论是 Wi-Fi、蓝牙还是 Ethernet,最终都汇聚到 ConnectivityService 进行统一管理。

Android 网络连接架构 应用层 (App) ConnectivityService Wi-Fi HAL Bluetooth NFC Ethernet Wi-Fi 驱动 蓝牙驱动 NFC 驱动 以太网驱动 硬件层(Wi-Fi芯片 / 蓝牙芯片 / NFC控制器 / 以太网PHY)

从图中可以看出,ConnectivityService 是核心调度器。它根据网络优先级(Wi-Fi > Ethernet > 蜂窝)自动切换。但如果你做的是专用设备,比如工控机,可能需要调整这个优先级——让 Ethernet 优先于 Wi-Fi。修改方法是在 framework/base/core/res/res/values/config.xml 里调整 config_networkAvoidBadWifi 等参数。

个人经验:调试网络连接时,我最常用的命令是 adb shell dumpsys connectivity。它能列出当前所有网络的详细信息,包括 IP 地址、网关、DNS、路由表等。比看 logcat 直观多了。

20.6 小结

网络与连接这块,说白了就是「上层框架 + 底层 HAL + 芯片驱动」的三层结构。Wi-Fi 和蓝牙的 HAL 接口变化快,移植时要多看官方文档;NFC 的问题往往出在天线匹配上;Ethernet 虽然简单,但多网口场景需要自己改框架。

嗯,最后说一句:做嵌入式 Android 网络开发,别只盯着代码。示波器、频谱仪、甚至一根网线,有时候比代码调试更有用。我吃过这个亏,希望你少吃点。


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