VNDK 扩展

Android 设备制造商会出于各种原因而更改 AOSP 库的源代码。一些供应商会为了提高性能而重新实现 AOSP 库中的函数,另一些供应商则会向 AOSP 库添加新钩子、新 API 或新功能。本部分将介绍一些准则,用以说明如何在不破坏 CTS/VTS 的前提下扩展 AOSP 库。

简易替换

所有修改后的共享库都必须与其 AOSP 副本保持二进制兼容,且可以简易替换该副本。所有现有的 AOSP 用户都必须能在不进行重新编译的情况下使用修改后的共享库。此要求有以下几点含义:

  • 不得移除 AOSP 函数。
  • 不得更改面向用户提供的结构。
  • 不得强化函数的前提条件。
  • 函数必须提供等效功能。
  • 不得削弱函数的后置条件。

扩展后的模块分类

按模块所定义使用的功能对其进行分类。

注意:此处之所以使用“功能”一词而未使用 API/ABI,是因为可在不更改任何 API/ABI 的情况下添加功能。

根据模块中定义的功能,可将模块分为 DA 模块DX 模块

  • Defining-only-AOSP 模块(DA 模块)不会定义 AOSP 副本中未包含的新功能。
    • 示例 1:一个未经修改且完整无缺的 AOSP 库即是一个 DA 模块。
    • 示例 2:如果供应商使用 SIMD 指令重写 libcrypto.so 中的函数(不添加新函数),那么修改后的 libcrypto.so 将是一个 DA 模块。
  • Defining-Extension 模块(DX 模块)要么会定义新功能,要么没有 AOSP 副本。
    • 示例 1:如果供应商向 libjpeg.so 添加一个辅助函数用于访问某些内部数据,那么修改后的 libjpeg.so 将是一个 DX 库,而这个新增函数将是该库的扩展部分。
    • 示例 2:如果供应商定义了一个名为 libfoo.so 的非 AOSP 库,那么 libfoo.so 将是一个 DX 库。

根据模块所使用的功能,可将模块分为 UA 模块UX 模块

  • Using-only-AOSP 模块(UA 模块)仅会在其实现过程中使用 AOSP 功能。它们不依赖任何非 AOSP 扩展功能。
    • 示例 1:一个未经修改且完整无缺的 AOSP 库即是一个 UA 模块。
    • 示例 2:如果修改后的共享库 libjpeg.so 仅依赖于其他 AOSP API,那么它将是一个 UA 模块。
  • Using-Extension 模块(UX 模块)会在其实现过程中依赖某些非 AOSP 功能。
    • 示例 1:如果修改后的 libjpeg.so 依赖另一个名为 libjpeg_turbo2.so 的非 AOSP 库,那么修改后的 libjpeg.so 将是一个 UX 模块。
    • 示例 2:如果供应商向其修改后的 libexif.so 添加了一个新函数,并且其修改后的 libjpeg.so 使用 libexif.so 中新增的这个函数,那么修改后的 libjpeg.so 将是一个 UX 模块。

定义的功能和使用的功能相互独立:

使用的功能
Only AOSP (UA) Extended (UX)
定义的功能 Only AOSP (DA) DAUA DAUX
Extended (DX) DXUA DXUX

VNDK 扩展机制

由于同名的 AOSP 库不包含扩展功能,因此依赖扩展功能的供应商模块将无法正常工作。如果供应商模块直接或间接依赖扩展功能,则供应商应将 DAUX、DXUA 和 DXUX 共享库复制到供应商分区(供应商进程始终都会优先在供应商分区中查找共享库)。但是,由于不得复制 LL-NDK 库,因此供应商模块不得依赖由修改后的 LL-NDK 库定义的扩展功能。

当系统分区被通用系统映像 (GSI) 覆盖时,如果相应的 AOSP 库可以提供相同的功能,且供应商模块可以继续正常工作,DAUA 共享库便可保留在系统分区上。

简易替换非常重要,因为 GSI 中未经修改的 VNDK 库将会在名称冲突时与修改后的共享库关联。如果以 API/ABI 不兼容的方式修改 AOSP 库,那么 GSI 中的 AOSP 库可能会无法进行关联或会出现未定义的行为。