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

供应商原生开发套件 (VNDK) 是专门用来让供应商实现其 HAL 的一组库。VNDK 包含在 system.img 中,并在运行时与供应商代码动态关联。

为何要使用 VNDK?

Android 8.0 及更高版本支持框架专用更新,在此类更新中,系统分区可以升级到最新版本,而供应商分区保持不变。这意味着在不同时间编译的二进制文件必须能够相互配合使用;VNDK 为 Android 版本迭代时发生的 API/ABI 变更所导致的问题提供了解决途径。

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

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

为了克服这些挑战,Android 8.0 引入了一些技术,例如 VNDK(本部分对其进行了介绍)、HIDL、hwbinder、设备树叠加层和 sepolicy 叠加层。

VNDK 资源

本部分包含以下 VNDK 资源:

  • VNDK 概念:(请参阅下文)介绍了框架共享库、Same-Process HAL (SP-HAL) 和 VNDK 术语。
  • VNDK 扩展:对专门针对供应商的更改进行了分类。例如,具有供应商模块所依赖的扩展功能的库必须复制到供应商分区中,但禁止进行 ABI 不兼容的更改。
  • VNDK 编译系统支持:介绍了与 VNDK 相关的编译系统配置和模块定义语法。
  • VNDK 定义工具:可协助您将源代码树迁移到 Android 8.0 及更高版本。
  • 链接器命名空间:提供对共享库关联的精细控制。
  • 目录、规则和 sepolicy:定义了搭载 Android 8.0 及更高版本的设备的目录结构,以及 VNDK 规则和关联的 sepolicy。
  • Android O 中的 VDNK 设计演示文稿:阐述了 Android O 中使用的 VDNK 基本概念。

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

以下库是 SP-HAL 可以访问的 VNDK-SP 库:

  • android.hardware.graphics.common@1.0.so
  • android.hardware.graphics.mapper@2.0.so
  • android.hardware.renderscript@1.0.so (Renderscript)
  • libRS_internal.so (Renderscript)
  • libbase.so
  • libc++.so
  • libcutils.so
  • libhardware.so
  • libhidlbase.so
  • libhidltransport.so
  • libhwbinder.so
  • libion.so
  • libutils.so
  • libz.so

以下 VNDK-SP 依赖项 (VNDK-SP-Private) 对 SP-HAL 来说是不可见的:

  • libRSCpuRef.so (Renderscript)
  • libRSDriver.so (Renderscript)
  • libbacktrace.so
  • libblas.so (Renderscript)
  • libbcinfo.so (Renderscript)
  • liblzma.so
  • libunwind.so

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

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

VNDK 术语

  • 模块是指共享库或可执行文件。
  • 进程是指可执行文件产生的操作系统任务。
  • 以“框架”打头的术语是指与系统分区相关的概念。
  • 以“供应商”打头的术语是指与供应商分区相关的概念。

例如:

  • 框架可执行文件是指 /system/bin/system/xbin 中的可执行文件。
  • 框架共享库是指 /system/lib[64] 下的共享库。
  • 框架模块是指框架共享库和框架可执行文件。
  • 框架进程是指从框架可执行文件衍生而来的进程(例如 /system/bin/app_process)。
  • 供应商可执行文件是指 /vendor/bin 中的可执行文件
  • 供应商共享库是指 /vendor/lib[64] 下的共享库。
  • 供应商模块是指供应商可执行文件和供应商共享库。
  • 供应商进程是指供应商可执行文件(例如
  • /vendor/bin/android.hardware.camera.provider@2.4-service)产生的进程。

VNDK 版本编号

在 Android P 中,VNDK 共享库带有版本编号:

  • ro.vndk.version 系统属性将自动添加到 /vendor/default.prop
  • VNDK 共享库将安装到 /system/lib[64]/vndk-${ro.vndk.version} 中。
  • VNDK-SP 共享库将安装到 /system/lib[64]/vndk-sp-${ro.vndk.version} 中。
  • 动态链接器配置文件将安装到 /system/etc/ld.config.${ro.vndk.version}.txt 中。

系统将按以下算法选择 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)。

升级设备

如果 Android 8.x 设备停用了 VNDK 运行时增强功能(即,编译时未使用 BOARD_VNDK_VERSION 或使用了 BOARD_VNDK_RUNTIME_DISABLE),则在升级到 Android P 时,可能会将 PRODUCT_USE_VNDK_OVERRIDE := false 添加 BoardConfig.mk

如果 PRODUCT_USE_VNDK_OVERRIDEfalse,则 ro.vndk.lite 属性将自动添加到 /vendor/default.prop,且其值将为 true。因此,动态链接器将加载 /system/etc/ld.config.vndk_lite.txt 中的链接器命名空间配置,这仅会隔离 SP-HAL 和 VNDK-SP。

如果要将搭载 Android 7.0(或更低版本)的设备升级到 Android P,请将 PRODUCT_TREBLE_LINKER_NAMESPACES_OVERRIDE := false 添加到 BoardConfig.mk

供应商测试套件 (VTS)

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

如果 ro.product.first_api_level 属性大于 27,则不能定义 ro.vndk.lite 属性。 如果在新推出的 Android P 设备中定义了 ro.vndk.lite,则 VtsTreblePlatformVersionTest 将失败。

文档历史记录

本部分跟踪了对 VNDK 文档进行的更改。

Android P 的变化

  • 添加了“VNDK 版本编号”部分。
  • 添加了“VTS”部分。
  • 更改了部分 VNDK 类别的名称:
    • LL-NDK-Indirect 已改名为 LL-NDK-Private。
    • VNDK-Indirect 已改名为 VNDK-Private。
    • VNDK-SP-Indirect-Private 已改名为 VNDK-SP-Private。
    • 移除了 VNDK-SP-Indirect。

Android 8.1 的变化

  • SP-NDK 库已合并到 LL-NDK 库中。
  • 在 RS 命名空间部分中将 libui.so 替换为 libft2.so。包含 libui.so 会出错。
  • libGLESv3.solibandroid_net.so 添加到 LL-NDK 库中。
  • libion.so 添加到 VNDK-SP 库中。
  • 从 LL-NDK 库中移除 libstdc++.so。改用 libc++.so。某些版本的独立工具链可以将 -lstdc++ 添加到默认链接器标记中。要停用默认设置,请将 -nodefaultlibs -lc -lm -ldl 添加到 LDFLAGS 中。
  • libz.so 从 LL-NDK 移到 VNDK-SP 库中。在某些配置中,libz.so 可能仍是 LL-NDK。但是,应该没有明显的差异。