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 库。
- 示例 1:如果供应商向
根据模块所使用的功能,可将模块分为 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 模块。
- 示例 1:如果修改后的
定义的功能和使用的功能相互独立:
使用的功能 | |||
---|---|---|---|
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 库可能会无法进行关联或会出现未定义的行为。