供应商原生开发套件 (VNDK) 概览

供应商原生开发套件 (VNDK) 是一组库,可供供应商分区或产品分区中的其他库或二进制文件在 dlopen 运行时期间使用。

废弃

供应商 NDK 是在 Android 8.0 中引入的,用于在框架和供应商代码之间提供 API。虽然 VNDK 已成功使用多年,但它也存在一些缺点:
  • 存储
    • 单个 VNDK APEX 会打包所有 VNDK 库,无论这些库是否在设备上使用。
    • GSI 包含多个版本的 VNDK APEX,以支持多个版本的供应商映像。
  • 可更新性
    • 很难单独更新 VNDK APEX,而不进行平台更新。
    • 供应商映像经常通过无线下载 (OTA) 更新,这会降低将 VNDK 打包到系统映像中的优势。
鉴于这些问题,我们决定从 Android 15 开始废弃 VNDK。

有关废弃 VNDK 的详细信息

所有 VNDK 库都打包到 VNDK APEX 中,并安装到系统 (-ext) 映像中。随着 VNDK 被废弃,以前的 VNDK 库会安装在供应商(或产品)映像中,与其他供应商可用的库一样。 随着 VNDK 被废弃,以下功能也将被移除:
  • 适用于 Android 15 的 VNDK APEX
  • 如果 vendor 或 product 分区针对 Android 15 进行构建,指示目标 VNDK 版本的系统属性会被移除:
    • ro.vndk.version
    • ro.product.vndk.version
  • 由于没有 VNDK,因此无法使用 VNDK 优化功能:
    • TARGET_VNDK_USING_CORE_VARIANT,适用于 Android Go 设备
    • use_vndk_as_stable,适用于供应商 APEX
  • 供应商快照,高度依赖于 VNDK

废弃情况的例外情况

以下功能不会因 VNDK 被废弃而发生变化:
  • 需要用来支持现有供应商映像的 VNDK APEX,其 VNDK 版本为 14 或更低版本。
  • LL-NDK 不是 VNDK 的一部分。

为何要使用 VNDK?

AOSP 允许进行框架专用更新,进行此类更新时,系统分区可以升级到最新的框架版本,而供应商分区则保持不变。尽管每个分区中的二进制文件的构建时间不同,但这些文件必须能够相互配合使用。

框架专用更新面临着以下挑战:

  • 框架模块与供应商模块之间的依赖关系。 在 Android 8.0 之前的版本中,供应商分区和系统分区中的模块可以相互关联。但是,来自供应商模块的依赖关系对框架模块开发施加了不必要的限制。
  • AOSP 库的扩展。Android 要求所有 Android 设备在系统分区被替换为标准通用系统映像 (GSI) 时,都必须通过 CTS 测试。但是,当供应商扩展 AOSP 库以提高性能或为其 HIDL 实现添加额外功能时,使用标准 GSI 来刷写系统分区可能会破坏供应商的 HIDL 实现有关如何防止此类破坏的指南,请参阅 VNDK 扩展

为了应对这些挑战,Android 中包含一些功能,例如 VNDK(如本部分中所述)、HIDL、hwbinder、设备树叠加层和 sepolicy 叠加层。

VNDK 专用术语

VNDK 相关文档使用以下术语:
  • 模块是指共享库或可执行文件。模块会建立构建时依赖关系。
  • 进程是指从可执行文件衍生而来的操作系统任务。进程会建立运行时依赖关系。
  • 以“框架”开头的术语system 分区相关:
    • 框架可执行文件是指 /system/bin/system/xbin 中的可执行文件。
    • 框架共享库是指 /system/lib[64] 下的共享库。
    • 框架模块是指框架共享库和框架可执行文件。
    • 框架进程是指从框架可执行文件衍生而来的进程,例如 /system/bin/app_process
  • 以“供应商”开头的术语与 vendor 分区相关:
    • 供应商可执行文件是指 /vendor/bin 中的可执行文件。
    • 供应商共享库是指 /vendor/lib[64] 下的共享库。
    • 供应商模块是指供应商可执行文件和供应商共享库。
    • 供应商进程是指从供应商可执行文件衍生而来的进程,例如 /vendor/bin/android.hardware.camera.provider@2.4-service

VNDK 概念

在理想的 Android 8.0 及更高版本环境中,框架进程不加载供应商共享库,所有供应商进程仅加载供应商共享库(和一部分框架共享库),而框架进程与供应商进程之间的通信由 HIDL 和硬件 binder 控制。

这样的环境存在以下可能:来自框架共享库的稳定、公共 API 可能不足以满足供应商模块开发者的需求(尽管 API 在不同的 Android 版本之间会有所变化),要防止出现这种情况,供应商进程需要能够访问一部分框架共享库。此外,由于性能要求可能会导致折中方案,因此必须区别对待某些对响应时间要求严格的 HAL。

以下部分详细介绍了 VNDK 如何处理适用于供应商的框架共享库以及 Same-Process HAL (SP-HAL)。

适用于供应商的框架共享库

本部分介绍了供应商进程可访问的共享库的分类标准。要让供应商模块在多个 Android 版本上皆可正常工作,有以下两种方法:

  1. 使框架共享库的 ABI/API 保持稳定。 新的框架模块和旧的供应商模块可以使用同一共享库,以减少内存占用和存储空间占用。此外,通过使用同一共享库,还可以避免一些双重加载问题。不过,保持稳定的 ABI/API 的开发成本很高,因此让每个框架共享库导出的所有 ABI/API 都保持稳定是不现实的。
  2. 复制旧的框架共享库。此方法会严重限制边信道,即在框架模块与供应商模块之间进行通信的所有机制,包括(但不限于)binder、套接字、管道、共享内存、共享文件和系统属性。除非通信协议被冻结且保持稳定(例如通过 hwbinder 的 HIDL),否则不能进行通信。双重加载共享库也可能会导致出现问题;例如,如果将新库创建的对象传递到旧库的函数中,则可能会出错,因为这些库可能会以不同的方式解读该对象。

根据共享库的特性不同,使用的方法也有差异。因此,框架共享库可分为以下三个子类别:

  • LL-NDK 库是已知稳定的框架共享库。它们的开发者致力于保持其 API/ABI 稳定性。
    • LL-NDK 包含以下库:libEGL.solibGLESv1_CM.solibGLESv2.solibGLESv3.solibandroid_net.solibc.solibdl.soliblog.solibm.solibnativewindow.solibneuralnetworks.solibsync.solibvndksupport.solibvulkan.so
  • 符合条件的 VNDK 库 (VNDK) 是指可以安全复制两次的框架共享库。框架模块和供应商模块可以与其各自的副本相关联。框架共享库只有满足以下条件才能成为符合条件的 VNDK 库:
    • 不向框架发送或从框架接收 IPC。
    • 与 ART 虚拟机无关。
    • 不读取/写入文件格式不稳定的文件/分区。
    • 没有需要法律审查的特殊软件许可。
    • 其代码所有者不反对供应商使用该库。
  • 框架专用库 (FWK-ONLY) 是指不属于上述类别的框架共享库。此类库具有以下特点:
    • 被视为框架内部实现细节。
    • 不得由供应商模块访问。
    • 具有不稳定的 ABI/API,无 API/ABI 兼容性保证。
    • 不会被复制。

Same-Process HAL (SP-HAL)

Same-Process HAL (SP-HAL) 是一组预先确定的 HAL,作为供应商共享库进行实现,并被加载到框架进程中。SP-HAL 由链接器命名空间(控制共享库可见的库和符号)进行隔离。SP-HAL 必须仅依赖于 LL-NDK 和 VNDK-SP

VNDK-SP 是一部分预定义的符合条件的 VNDK 库。我们会仔细审查 VNDK-SP 库,以确保将 VNDK-SP 库双重加载到框架进程中不会导致问题。SP-HAL 和 VNDK-SP 均由 Google 定义。

以下库是经过批准的 SP-HAL:

  • libGLESv1_CM_${driver}.so
  • libGLESv2_${driver}.so
  • libGLESv3_${driver}.so
  • libEGL_${driver}.so
  • vulkan.${driver}.so
  • android.hardware.renderscript@1.0-impl.so
  • android.hardware.graphics.mapper@2.0-impl.so

VNDK-SP 库会在其 Android.bp 文件中指定 vndk: { support_system_process: true }。如果还指定了 vndk: {private:true},则这些库称为 VNDK-SP-Private,并且对 SP-HALS 不可见。

以下是具有 RS 例外的框架专用库 (FWK-ONLY-RS):

  • libft2.so (Renderscript)
  • libmediandk.so (Renderscript)

VNDK 版本控制

VNDK 共享库带有版本编号:

  • ro.vndk.version 系统属性将自动添加到 /vendor/default.prop
  • VNDK 和 VNDK-SP 共享库会以 VNDK APEX com.android.vndk.v${ro.vndk.version} 的形式安装,并装载到 /apex/com.android.vndk.v${ro.vndk.version} 上。

系统将按以下算法选择 ro.vndk.version 的值:

  • 如果 BOARD_VNDK_VERSION 不等于 current,则使用 BOARD_VNDK_VERSION
  • 如果 BOARD_VNDK_VERSION 等于 current
    • 如果 PLATFORM_VERSION_CODENAMEREL,则使用 PLATFORM_SDK_VERSION(例如 28)。
    • 否则使用 PLATFORM_VERSION_CODENAME(例如 P)。

供应商测试套件 (VTS)

Android 供应商测试套件 (VTS) 强制要求存在非空 ro.vndk.version 属性。新发布的设备和升级设备都必须定义 ro.vndk.version。一些 VNDK 测试用例(例如 VtsVndkFilesTestVtsVndkDependencyTest)依赖 ro.vndk.version 属性来加载符合条件且匹配的 VNDK 库数据集。