Google 致力于为黑人社区推动种族平等。查看具体举措

适用于 HAL 的 AIDL

Android 11 引入了在 Android 中使用 AIDL 实现 HAL 的功能。这样就可以在不使用 HIDL 的情况下实现 Android 的部分代码。我们强烈建议尽量将 HAL 转换为只使用 AIDL(如果上游 HAL 使用 HIDL,则必须使用 HIDL)。

如果 HAL 使用 AIDL 在框架组件(例如 system.img 中的组件)和硬件组件(例如 vendor.img 中的组件)之间进行通信,则必须使用稳定的 AIDL。不过,如需在分区内进行通信(例如从一个 HAL 到另一个),则对所使用的 IPC 机制没有任何限制。

动机

AIDL 出现在 HIDL 之前,而且在 Android 框架组件之间或应用内等其他很多地方都有使用。现在,由于 AIDL 具备了稳定性支持,就可以只使用一个 IPC 运行时环境实现整个栈。此外,AIDL 的版本控制系统也优于 HIDL。

  • 只使用一种 IPC 语言意味着只需要了解、调试、优化和保护一个运行时环境。
  • AIDL 可为接口所有者提供内建的版本控制机制。
    • 所有者可以将方法添加到 Parcelable 的接口或字段的末尾。这意味着可以在持续多年的开发过程中简化对代码的版本控制,并逐年降低产生的开销(可以就地修改类型,而且更新接口版本不需要新增额外的库)。
    • 扩展接口可以在运行时附加,而不是在类型系统中附加,因此无需将下游扩展 rebase 到新版接口上。
  • 如果现有 AIDL 接口的所有者选择使其稳定化,此类接口可以直接使用。如果是在以前,必须用 HIDL 创建接口的完整副本。

编写 AIDL HAL 接口

为了让系统和供应商都可使用某个 AIDL 接口,需要对该接口进行两项更改:

  • 每个类型定义都需要带有 @VintfStability 注释
  • aidl_interface 声明需要包含 stability: "vintf",

只有接口所有者可以进行这些更改。

此外,为了最大限度地提高代码可移植性并避免出现潜在问题(例如不必要的额外库),建议您停用 CPP 后端。

    aidl_interface: {
        ...
        backends: {
            cpp: {
                enabled: false,
            },
        },
    }

查找 AIDL HAL 接口

AOSP 中 HAL 的稳定 AIDL 接口所在的基础目录与 HIDL 接口所在的基础目录相同,位于 aidl 文件夹中。

  • hardware/interfaces
  • frameworks/hardware/interfaces
  • system/hardware/interfaces

您应将扩展接口放入 vendorhardware 中的其他 hardware/interfaces 子目录。强烈建议您在所有设备之间保持接口一致。扩展可以通过两种不同方式进行注册:

  • 在运行时注册(请参阅附加的扩展
  • 独立注册(在全局注册和在 VINTF 内注册)

针对 AIDL 运行时环境进行构建

AIDL 具有三个不同的后端:Java、NDK、CPP。如需使用稳定的 AIDL,您必须始终使用位于 system/lib*/libbinder.so 的 libbinder 的系统副本,并能够访问 /dev/binder。对于供应商映像中的代码,这意味着 libbinder(来自 VNDK)无法使用:此库包含不稳定的 C++ API 和不稳定的内件。而原生供应商代码必须使用 AIDL 的 NDK 后端,链接到 libbinder_ndk(由系统 libbinder.so 提供支持),并链接到由 aidl_interface 条目创建的 -ndk_platform 库。

AIDL HAL 服务器实例名称

按照惯例,AIDL HAL 服务的实例名称应采用以下格式:$package.$type/$instance。例如,振动器 HAL 实例的注册名称为 android.hardware.vibrator.IVibrator/default

编写 AIDL HAL 服务器

必须在 VINTF 清单中声明 AIDL 服务器,示例如下:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <fqname>IVibrator/default</fqname>
    </hal>

否则,它们应该正常注册 AIDL 服务。运行 VTS 测试时,所有已声明的 AIDL HAL 应该都是可用的。

编写 AIDL 客户端

AIDL 客户端必须在兼容性矩阵中声明自己,示例如下:

    <name>android.hardware.vibrator</name>
    <interface>
        <name>IVibrator</name>
        <instance>default</instance>
    </interface>

将现有 HAL 从 HIDL 转换为 AIDL

使用 hidl2aidl 工具将 HIDL 接口转换为 AIDL。按照下面的步骤操作,将 .hal 文件包转换为 .aidl 文件:

  1. 构建该工具(位于 system/tools/hidl/hidl2aidl 中)。

    m hidl2aidl
    
  2. 使用以下命令执行该工具:输出目录,后接要转换的文件包。

    hidl2aidl -o <output directory> <package>
    

    例如:

    hidl2aidl -o . android.hardware.nfc@1.2
    
  3. 仔细阅读生成的文件,并解决任何转换方面的问题。

    • conversion.log 包含应该先解决的所有尚未解决的问题。
    • 生成的 .aidl 文件可能包含一些需要您进行相应处理的警告和建议。这些注释以 // 开头。
    • 请抓住这个机会,对文件包进行清理并加以改进。

适用于 AIDL HAL 的 sepolicy

对供应商代码可见的 AIDL 服务类型必须具有 vendor_service 属性。否则,sepolicy 配置将与任何其他 AIDL 服务相同。

    type hal_power_service, service_manager_type, vendor_service;

对于平台定义的大多数服务,已经添加了具有正确类型的服务上下文(例如,android.hardware.power.IPower/default 已标记为 hal_power_service)。但是,如果框架客户端支持多种实例名称,则必须在设备专用 service_contexts 文件中添加其他实例名称。

    android.hardware.power.IPower/custom_instance u:object_r:hal_power_service:s0

附加的扩展接口

扩展可以附加到任何 Binder 接口(无论是直接向服务管理器注册的顶级接口,还是子接口)。获取扩展时,您必须确认扩展类型符合预期。扩展只能通过传送 Binder 的进程进行设置。

每当有扩展修改现有 HAL 的功能时,都应使用附加的扩展。需要全新功能时,不需要使用此机制,而可以直接向服务管理器注册扩展接口。

如需在 Binder 中设置扩展,请使用以下 API:

  • 在 NDK 后端中:AIBinder_setExtension
  • 在 Java 后端中:android.os.Binder.setExtension
  • 在 CPP 后端:android::Binder::setExtension

要在 Binder 中获取扩展,请使用以下 API:

  • 在 NDK 后端中:AIBinder_getExtension
  • 在 Java 后端中:android.os.IBinder.getExtension
  • 在 CPP 后端:android::IBinder::getExtension

如需详细了解这些 API,请参阅相应后端的 getExtension 函数文档。有关如何使用扩展的示例,请访问 hardware/interfaces/tests/extension/vibrator

AIDL 与 HIDL 之间的主要差异

使用 AIDL HAL 或使用 AIDL HAL 接口时,请注意与编写 HIDL HAL 的差异。

  • AIDL 语言的语法更接近 Java。HIDL 语言的语法类似于 C++。
  • 所有 AIDL 接口都具有内置的错误状态。不要创建自定义状态类型,而应在接口文件中创建常量状态 int,并在 CPP/NDK 后端使用 EX_SERVICE_SPECIFIC,在 Java 后端使用 ServiceSpecificException
  • 未经检查的传输错误不会导致 AIDL 终止运行(未经检查的错误会导致 HIDL Return 终止运行)。
  • AIDL 只能为每个文件声明一种类型。
  • 除了 output 参数外,AIDL 参数还可以指定为 in/out/inout(没有“同步回调”)。
  • AIDL 将 fd 用作基元类型,而不是句柄。
  • HIDL 对不兼容的更改使用 Major 版本,对兼容的更改使用 Minor 版本。在 AIDL 中,向后兼容的更改已就位。 AIDL 没有对 Major 版本进行明确定义,而是将其并入软件包名称中。例如,AIDL 可能会使用软件包名称 bluetooth2