4. Vendor接口基础

在 Android 系统架构中,Vendor 接口是连接 Framework 层与 Vendor 实现层的关键契约。理解 HAL 接口的分类方式、HIDL 与 AIDL 的差异,以及 Vendor 接口的边界定义,是进行 VINTF 适配的前提。本章将从接口形态、语言演进和边界划分三个维度展开。

一、HAL 接口的两种形态:Binderized 与 Passthrough

Android 8.0 引入 Treble 架构后,HAL 接口被明确划分为两种运行形态:Binderized(绑定式)和 Passthrough(直通式)。这两种形态决定了 HAL 实现与调用方之间的通信方式、进程边界和生命周期管理。

Binderized HAL 运行在独立的 Vendor 进程中,通过 Binder IPC 与 Framework 通信。调用方通过 getService() 获取接口代理,所有调用都跨越进程边界。这种形态的优势是隔离性强、可独立更新、支持权限控制,是 Android 8.0 之后的主流形态。

Passthrough HAL 则以共享库形式被加载到调用方进程中,通常用于兼容旧版 HAL 或对性能敏感的场景。它通过 dlopen 加载 .so 文件,直接进行函数调用,不涉及 IPC 开销。Passthrough 模式在 Android 8.0 到 10 之间作为过渡方案存在,Android 11 之后逐步被 Binderized 取代。

核心区别:Binderized 是跨进程调用,Passthrough 是同进程调用。前者通过 hwservicemanager 注册和发现服务,后者通过 hw_get_module() 加载共享库。

HAL 接口两种形态:Binderized 与 Passthrough Framework 进程 CameraService / AudioFlinger ICameraProvider (AIDL/HIDL Proxy) Vendor 进程 CameraProvider Service ICameraDevice (Stub 实现) Binder IPC 跨进程 Passthrough 模式(同进程加载) 调用方进程 dlopen("camera.vendor.so") HAL 共享库 (.so) 直接函数调用,无 IPC 函数调用 Passthrough 通过 hw_get_module() 加载,适用于旧版 HAL 兼容或低延迟场景 Android 11+ 要求新 HAL 必须为 Binderized,Passthrough 仅用于遗留模块

二、HIDL 与 AIDL 的区别

HIDL(HAL Interface Definition Language)是 Android 8.0 为 Treble 架构设计的接口描述语言,而 AIDL(Android Interface Definition Language)原本用于应用层 Binder 通信,从 Android 11 开始被引入 HAL 领域。两者在语法、版本管理、类型系统和适用场景上存在显著差异。

对比维度 HIDL AIDL (HAL 场景)
引入版本 Android 8.0 Android 11 起支持 HAL
语法风格 类 C++,使用 interface、package 类 Java/C++,使用 interface、parcelable
版本管理 包名中嵌入主版本号,如 android.hardware.camera@2.4 通过 @VintfStability 和版本化接口管理
数据类型 自定义类型系统,支持 vec、fmq、memory 复用 AIDL 类型系统,支持 Parcelable、List
通信机制 Binder + hwbinder 域 Binder + 标准 binder 域(可配置)
Passthrough 支持 原生支持 @passthrough 不支持 Passthrough,仅 Binderized
当前状态 维护阶段,新 HAL 不推荐 推荐方向,Android 13+ 主推

从代码风格看,HIDL 接口定义如下:

// HIDL 示例:android.hardware.camera.provider@2.4
package android.hardware.camera.provider@2.4;

interface ICameraProvider {
    getCameraIdList() generates (vec<string> cameraDeviceNames);
    getCameraDeviceInterface_V3_x(string cameraDeviceName)
        generates (ICameraDevice cameraDevice);
};

而 AIDL 的 HAL 接口定义更接近应用层写法:

// AIDL 示例:android.hardware.camera.provider.ICameraProvider
@VintfStability
interface ICameraProvider {
    String[] getCameraIdList();
    ICameraDevice getCameraDeviceInterface(String cameraDeviceName);
}

迁移建议:新项目应优先使用 AIDL 定义 HAL 接口,并添加 @VintfStability 注解以确保 VINTF 兼容性。已有 HIDL 接口可继续维护,但需在 manifest.xml 中正确声明。

三、Vendor 接口的边界定义

Vendor 接口的边界是指 Framework 与 Vendor 之间必须严格遵守的隔离线。这条边界不仅体现在代码层面,还体现在进程、分区、版本和兼容性声明中。

分区边界:Framework 代码位于 system 分区,Vendor 实现位于 vendor 分区。两者通过 /vendor/etc/vintf/manifest.xml 和 /system/etc/vintf/manifest.xml 声明各自提供的接口。

进程边界:Binderized HAL 运行在独立 Vendor 进程中,Framework 不能直接链接 Vendor 的 .so 文件。所有交互必须通过 Binder 接口完成。

版本边界:Vendor 接口必须声明版本号,Framework 根据版本号决定调用哪个接口。VINTF 兼容性矩阵(compatibility matrix)定义了 Framework 要求的接口版本范围与 Vendor 实际提供的版本之间的匹配规则。

类型边界:跨边界传递的数据类型必须是 VINTF 稳定的(VintfStability),不能使用仅 Framework 可见的内部类型。AIDL 中通过 @VintfStability 标记,HIDL 中通过 @1.0 等版本化包名保证。

常见误区:很多开发者认为只要接口定义正确就能通过 VINTF 检查,实际上还需要在 manifest.xml 中声明接口、在 compatibility matrix 中匹配版本,并确保 SELinux 策略允许跨分区访问。三者缺一不可。

四、案例与复盘:Camera HAL 的接口演进

以 Camera HAL 为例,Android 8.0 使用 android.hardware.camera.provider@2.4 HIDL 接口,运行在独立进程中,通过 hwbinder 通信。Android 11 开始引入 AIDL 版本的 android.hardware.camera.provider.ICameraProvider,Android 13 全面转向 AIDL。

在适配过程中,常见问题包括:

  • manifest 中声明了 HIDL 接口但未声明 AIDL 接口,导致新 Framework 找不到服务;
  • compatibility matrix 中版本范围写错,如将 2.4 写成 2.5,导致匹配失败;
  • Passthrough 模式下未正确设置 hw_get_module 的模块 ID,导致加载失败;
  • AIDL 接口未添加 @VintfStability,导致 VINTF 检查报错。

复盘要点:Vendor 接口适配的核心是“声明—匹配—访问”三步闭环。声明在 manifest,匹配在 compatibility matrix,访问在 SELinux 策略。任何一步缺失都会导致接口不可用。理解 Binderized 与 Passthrough 的差异、HIDL 与 AIDL 的演进方向,以及边界的严格定义,是完成 VINTF 适配的基础能力。