4、WiFi HAL 接口定义:AIDL/HIDL 接口、HAL 版本演进(从 HAL1 到 HAL2)、关键方法说明

WiFi HAL(Hardware Abstraction Layer)是 Android 系统中连接 Framework 与 Vendor 驱动实现的关键桥梁。它的核心价值在于:将 Wi-Fi 芯片厂商的具体实现(如高通、博通、联发科)与 Android 上层框架解耦,使得系统开发者无需关心底层硬件差异,即可通过统一的接口完成 Wi-Fi 的扫描、连接、漫游、热点等操作。本章将深入剖析 WiFi HAL 的接口定义方式(AIDL 与 HIDL 的差异与适用场景)、HAL 版本从 HAL1 到 HAL2 的演进逻辑,以及关键方法的设计意图与调用链。

WiFi HAL 接口定义与版本演进全景图 Android Framework (WifiService / WifiNative) 调用 SupplicantStaIfaceHal / VendorHal 等系统服务 WiFi HAL 接口层 HIDL (HAL1 时代) android.hardware.wifi@1.0 ~ 1.6 IWifi / IWifiStaIface / IWifiApIface AIDL (HAL2 时代) android.hardware.wifi@1.0 (AIDL) IWifi / IWifiStaIface / IWifiApIface Vendor HAL 实现 (C++ / C) 高通: qcacld / 博通: bcmdhd / 联发科: mt66xx 通过 libwifi-hal.so 暴露服务,处理 HIDL/AIDL 调用 Kernel Driver + Wi-Fi Chipset cfg80211 / nl80211 / wlan.ko HAL 版本演进关键节点 HAL1 (HIDL 1.0-1.6): 基于 HIDL,进程间通信使用 Binder 化 HIDL,接口粒度较粗 HAL2 (AIDL): 基于 AIDL,支持更细粒度控制、异步回调、数据流优化 统一了 Treble 架构下的接口风格

上图展示了 WiFi HAL 在 Android 系统架构中的位置以及 HAL1/HAL2 的共存关系。从 Android 8.0 引入 Treble 架构开始,HAL 接口经历了从传统 libhardware_legacy 到 HIDL,再到 AIDL 的演进。当前主流 Android 13/14 设备上,HAL2(AIDL 版本)已成为默认选择,但 HAL1 的 HIDL 接口仍广泛存在于旧设备或特定场景中。理解两者的差异,是进行 WiFi 驱动移植、系统定制和问题定位的基础。

4.1 核心原理:HIDL 与 AIDL 的接口设计哲学

HIDL(HAL Interface Definition Language)和 AIDL(Android Interface Definition Language)都是 Android 用于定义进程间通信(IPC)接口的语言,但它们在设计目标和使用场景上有显著差异。

HIDL 的设计初衷:服务于 Treble 架构,将 Vendor 实现与 System 镜像完全隔离。HIDL 接口使用 .hal 文件定义,编译后生成 C++ 或 Java 的 binder 客户端/服务端代码。HIDL 强调稳定性和版本管理,每个接口都有明确的版本号(如 @1.0、@1.5),且接口一旦发布便不可修改,只能通过继承扩展新版本。

AIDL 的回归与统一:Android 11 开始,Google 逐步推动 HAL 接口从 HIDL 迁移到 AIDL。AIDL 并非新事物,它一直是 Android 应用层 IPC 的标准方式。将其引入 HAL 层,主要基于以下考虑:

  • 统一工具链:AIDL 在 SDK/NDK 中均有成熟支持,开发者无需额外学习 HIDL 的代码生成规则。
  • 更灵活的异步支持:AIDL 的 oneway 关键字和 Callback 机制比 HIDL 的 I*Callback 更简洁。
  • 减少重复代码:HIDL 需要为每个接口生成独立的 Bp* 和 Bn* 类,而 AIDL 的泛型支持更好。
  • 性能优化:AIDL 在传输大数据块(如 RTT 结果、信道信息)时,支持共享内存和文件描述符传递,减少拷贝。

从接口定义角度看,HIDL 和 AIDL 的语法非常相似,都支持基本数据类型、结构体、枚举、数组和回调接口。但 HIDL 强制要求显式声明 @version,而 AIDL 则通过包名和接口名管理版本。例如,HIDL 的 IWifiStaIface 在 android.hardware.wifi@1.5::IWifiStaIface 中定义,而 AIDL 版本则位于 android.hardware.wifi.IWifiStaIface。

对比维度HIDL (HAL1)AIDL (HAL2)
定义文件后缀.hal.aidl
版本管理显式版本号(@1.0 ~ @1.6)包名 + 接口名,通过 @VendorNative 注解
异步回调需定义独立的 I*Callback 接口支持 oneway 和 Callback 直接定义
数据传递仅支持 Binder 传输,大数据需分段支持 SharedMemory 和 FileDescriptor
代码生成生成 C++/Java 的 Bp/Bn 类生成 C++/Java/NDK 的 Stub/Proxy 类
适用场景Android 8.0 ~ 11 的 Treble 设备Android 11+ 的新设备,逐步成为主流

4.2 判断方法:如何识别设备使用的是 HAL1 还是 HAL2

在实际开发和调试中,快速判断当前设备 WiFi HAL 的版本类型至关重要。以下是几种常用的判断方法:

  1. 查看系统属性:执行 adb shell getprop | grep wifi,关注 ro.vendor.wifi.hal 或 wifi.interface 等属性。部分厂商会直接暴露 HAL 类型。
  2. 检查 HAL 服务列表:使用 adb shell lshal | grep wifi,如果输出包含 android.hardware.wifi@1.x::IWifi,则为 HIDL 版本;如果显示 android.hardware.wifi.IWifi,则为 AIDL 版本。
  3. 查看进程和库文件:adb shell ps -A | grep wifi 查看 wificond 或 hostapd 进程;adb shell ls /vendor/lib64/hw/ 中是否存在 wifi.default.so 或 wifi.aidl.so。
  4. 代码层面判断:在 AOSP 源码中,hardware/interfaces/wifi/ 目录下同时存在 1.0 到 1.6 的 HIDL 子目录和 aidl 目录。查看设备 manifest.xml 中注册的 HAL 条目即可确认。

经验提醒:部分设备为了兼容旧应用,会同时注册 HIDL 和 AIDL 两套接口,但实际生效的只有一套。此时应通过 lshal 查看哪个接口处于 running 状态,而非仅看注册列表。

4.3 关键方法说明:从 IWifi 到 IWifiStaIface

无论 HAL1 还是 HAL2,WiFi HAL 的核心接口都围绕三个主要对象展开:IWifi(全局控制)、IWifiStaIface(STA 模式)、IWifiApIface(AP 模式)。下面以 HAL2(AIDL)为例,解析关键方法的设计意图。

4.3.1 IWifi 接口:生命周期与能力查询

interface IWifi {
    boolean isSupported();
    boolean isReady();
    void registerEventCallback(IWifiEventCallback callback);
    IWifiChip getChip(int chipId);
    int[] getChipIds();
    void start();
    void stop();
}
  • isSupported():查询设备是否支持 Wi-Fi 功能,用于 Framework 启动时的能力探测。
  • registerEventCallback():注册事件回调,用于接收固件加载状态、芯片恢复等异步通知。
  • getChip():获取指定 ID 的 Wi-Fi 芯片对象。一个 SoC 可能集成多个 Wi-Fi 芯片(如 2.4G/5G 独立芯片),通过 chipId 区分。
  • start()/stop():控制 HAL 服务的启动与停止,通常在 Wi-Fi 开关切换时调用。

4.3.2 IWifiStaIface:STA 模式核心操作

interface IWifiStaIface {
    void connect(IWifiStaIfaceCallback callback, String ifaceName);
    void disconnect();
    void startScan(ScanRequest request);
    void getScanResults(IScanResultsCallback callback);
    void enableSupplicant();
    void getFeatureSet();
    void setCountryCode(String code);
    void getLinkLayerStats();
}

这些方法中,startScan() 和 getScanResults() 是高频调用。值得注意的是,HAL2 引入了 ScanRequest 结构体,允许携带更丰富的扫描参数(如信道列表、SSID 过滤、BSSID 过滤),而 HAL1 的扫描参数相对简单。此外,getLinkLayerStats() 返回的 LinkLayerStats 包含了 RSSI、信道利用率、吞吐量等指标,是 Wi-Fi 诊断和性能优化的数据基础。

4.3.3 IWifiApIface:热点模式关键方法

interface IWifiApIface {
    void startHostapd();
    void stopHostapd();
    void setHostapdConfig(HostapdConfig config);
    void getHostapdConfig();
    void registerApEventCallback(IWifiApEventCallback callback);
}

AP 模式的核心是 setHostapdConfig(),它接收 SSID、加密方式、信道、最大客户端数等配置。HAL2 的 HostapdConfig 支持更细粒度的频段选择(2.4G/5G/6G)和 WPA3 配置,而 HAL1 的配置项相对有限。

风险提示:在调用 startHostapd() 之前,必须确保 STA 模式已完全关闭,否则可能导致固件资源冲突。部分芯片在切换模式时需要重新加载固件,耗时可能达到数百毫秒,Framework 层应做好状态机管理。

4.4 案例拆解:从 HAL1 迁移到 HAL2 的实战过程

假设我们有一款基于 Android 11 的设备,原厂使用 HIDL HAL1(android.hardware.wifi@1.5),现在需要升级到 Android 14 并迁移到 AIDL HAL2。以下是完整的迁移案例。

背景与约束:设备使用高通骁龙 680 平台,Wi-Fi 芯片为 WCN6750。原 HAL 实现基于 C++,代码量约 2.3 万行。升级目标:在保持现有 Wi-Fi 功能(STA+AP+WPA3)不变的前提下,完成 HAL 接口迁移,并确保系统稳定性。

初始现象与目标:升级到 Android 14 后,系统默认要求 AIDL HAL。若继续使用 HIDL,需要额外兼容层,且无法使用 Android 14 新增的 Wi-Fi 7 相关特性。因此,必须完成迁移。

关键输入数据:

  • 原 HIDL 接口文件:android.hardware.wifi@1.5 共 12 个 .hal 文件
  • 原实现代码:wifi_hal.cpp、wifi_sta_iface.cpp、wifi_ap_iface.cpp
  • 依赖库:libwifi-hal、libwifi-system、libwifi-hal-qcom

分析判断过程:

  1. 对比 HIDL 和 AIDL 接口差异:AIDL 的 IWifiStaIface 将 HIDL 中的 getScanResults 拆分为 getScanResults 和 getScanResultsWithFilter,需要调整调用逻辑。
  2. 检查回调机制:HIDL 使用 IWifiStaIfaceCallback 接口,AIDL 使用 IWifiStaIfaceCallback 但方法签名有变化,如 onScanResultsAvailable 增加了 ScanResultFlags 参数。
  3. 评估数据传递:AIDL 支持 SharedMemory,对于 getLinkLayerStats 返回的大数据(约 4KB),可以避免 Binder 传输限制。

实际操作步骤:

# 1. 创建 AIDL 接口目录
mkdir -p hardware/interfaces/wifi/aidl/android/hardware/wifi/
# 2. 复制并修改接口定义
cp hardware/interfaces/wifi/1.5/IWifi.hal hardware/interfaces/wifi/aidl/android/hardware/wifi/IWifi.aidl
# 3. 修改接口语法(将 package 声明改为 AIDL 格式)
# 4. 更新 Android.bp 文件,添加 aidl_interface 模块
aidl_interface {
    name: "android.hardware.wifi",
    versions: ["1", "2"],
    stability: "vintf",
    srcs: ["android/hardware/wifi/*.aidl"],
}
# 5. 修改 Vendor 实现代码,将 HIDL 的 IWifi* 替换为 AIDL 的 IWifi*
# 6. 更新 manifest.xml,注册 AIDL HAL 服务
# 7. 编译并验证

结果对比:迁移后,Wi-Fi 扫描速度提升约 15%(得益于 AIDL 的共享内存传输),系统启动时 HAL 加载时间减少 20ms。但发现一个问题:AIDL 的 getScanResults 在弱信号环境下返回的数据比 HIDL 少了约 5% 的 BSSID,经排查是 AIDL 的 ScanResult 结构体中 timestamp 字段类型从 int64 变为 int64 但单位从微秒变为纳秒,导致上层过滤逻辑误判。

风险与代价:迁移过程中最大的风险是接口语义变化导致的隐性 bug。建议在迁移前编写接口对比测试用例,覆盖所有方法的边界条件。此外,AIDL 的版本管理不如 HIDL 严格,需要开发团队自行维护接口兼容性。

复盘经验:HAL 迁移不仅仅是语法替换,更重要的是理解接口背后的语义变化。建议在迁移前阅读 AOSP 的 hardware/interfaces/wifi/aidl/ 目录下的 README 和测试代码,这些文档详细说明了每个方法的设计意图和与 HIDL 的差异。

4.5 常见误区与总结复盘

在 WiFi HAL 开发中,以下误区需要特别注意:

误区一:认为 HAL2 只是 HAL1 的语法翻译。实际上,AIDL 版本在接口设计上做了大量优化,例如将 getScanResults 拆分为同步和异步两种模式,将 LinkLayerStats 改为共享内存传递。如果只是机械地翻译代码,会丢失这些优化带来的性能提升。

误区二:忽略回调线程模型。HIDL 的回调默认在 Binder 线程池中执行,而 AIDL 的回调可以在任意线程调用。如果 Vendor 实现中直接操作 UI 或持有锁,容易导致死锁。建议在回调中只做数据拷贝,实际处理放到独立工作线程。

经验总结:无论是 HAL1 还是 HAL2,WiFi HAL 的核心设计原则是"接口稳定、实现灵活"。在开发过程中,应充分利用 lshal、dumpsys wifi 等工具进行调试。对于新项目,建议直接采用 AIDL HAL2,避免后续迁移成本。对于维护旧项目,应评估 HIDL 兼容层的长期维护成本,尽早规划迁移路径。