供应商原生开发套件 (VNDK) 是一组库,可供供应商分区或产品分区中的其他库或二进制文件在 dlopen 运行时期间使用。
废弃
供应商 NDK 在 Android 8.0 中引入,用于在框架和供应商代码之间提供 API。虽然 VNDK 已成功使用多年,但它也存在一些缺点:- 存储空间
- 单个 VNDK APEX 会打包所有 VNDK 库,无论这些库是否在设备上使用。
- GSI 包含多个版本的 VNDK APEX,以支持多个版本的供应商映像。
- 可更新性
- 很难单独更新 VNDK APEX,而不进行平台更新。
- 供应商映像经常通过无线下载 (OTA) 更新,这会降低将 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 版本上皆可正常工作,有以下两种方法:
- 使框架共享库的 ABI/API 保持稳定。 新的框架模块和旧的供应商模块可以使用同一共享库,以减少内存占用和存储空间占用。此外,通过使用同一共享库,还可以避免一些双重加载问题。不过,保持稳定的 ABI/API 的开发成本很高,因此让每个框架共享库导出的所有 ABI/API 都保持稳定是不现实的。
- 复制旧的框架共享库。此方法会严重限制边信道,即在框架模块与供应商模块之间进行通信的所有机制,包括(但不限于)binder、套接字、管道、共享内存、共享文件和系统属性。除非通信协议被冻结且保持稳定(例如通过 hwbinder 的 HIDL),否则不能进行通信。双重加载共享库也可能会导致出现问题;例如,如果将新库创建的对象传递到旧库的函数中,则可能会出错,因为这些库可能会以不同的方式解读该对象。
根据共享库的特性不同,使用的方法也有差异。因此,框架共享库可分为以下三个子类别:
- LL-NDK 库是已知稳定的框架共享库。它们的开发者致力于保持其 API/ABI 稳定性。
- LL-NDK 包含以下库:
libEGL.so
、libGLESv1_CM.so
、libGLESv2.so
、libGLESv3.so
、libandroid_net.so
、libc.so
、libdl.so
、liblog.so
、libm.so
、libnativewindow.so
、libneuralnetworks.so
、libsync.so
、libvndksupport.so
和libvulkan.so
。
- LL-NDK 包含以下库:
- 符合条件的 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_CODENAME
为REL
,则使用PLATFORM_SDK_VERSION
(例如28
)。 - 否则使用
PLATFORM_VERSION_CODENAME
(例如P
)。
供应商测试套件 (VTS)
Android 供应商测试套件 (VTS) 强制要求存在非空 ro.vndk.version
属性。新发布的设备和升级设备都必须定义 ro.vndk.version
。一些 VNDK 测试用例(例如 VtsVndkFilesTest
和 VtsVndkDependencyTest
)依赖 ro.vndk.version
属性来加载符合条件且匹配的 VNDK 库数据集。