匹配规则

两对兼容性矩阵和清单旨在进行协调,以验证框架和供应商实现是否可以相互协同工作。当框架兼容性矩阵与设备清单之间以及框架清单与设备兼容性矩阵之间匹配时,便会成功通过此验证。

系统会在构建时、在 OTA 更新软件包生成时、启动时以及 VTS 兼容性测试中完成此验证。

下面几部分将详细介绍各种组件使用的匹配规则。

框架兼容性矩阵版本匹配

如需使设备清单与框架兼容性矩阵相匹配,manifest.target-level 指定的 Shipping FCM 版本必须与 compatibility-matrix.level 指定的 FCM 版本完全相同。否则,这二者将不匹配。

如果使用 libvintf 请求框架兼容性矩阵,则此匹配始终都会成功,因为 libvintf 会打开设备清单,检索 Shipping FCM 版本,并返回该 Shipping FCM 版本的框架兼容性矩阵(以及更高 FCM 版本的兼容性矩阵中的一些可选 HAL)。

HAL 匹配

HAL 匹配规则可以识别清单文件中被视为受相应兼容性矩阵的所有者支持的 hal 元素的版本。

HIDL 和原生 HAL

HIDL 和原生 HAL 的匹配规则如下。

  • 多个 <hal> 元素具有 AND 关系。
  • <hal> 元素可以具有 <hal optional="true">,用以将它们标记为不需要。
  • 同一个 <hal> 中的多个 <version> 元素具有 OR 关系。如果指定了两个或两个以上版本,则只需要实现其中一个版本(请参见下面的 DRM 示例)。
  • 当需要 <hal> 时,同一个 <hal> 中的多个 <instance><regex-instance> 元素具有 AND 关系(请参见下面的 <ahref="#drm">DRM 示例)。</ahref="#drm">

示例:模块的成功 HAL 匹配

对于 2.5 版的 HAL,匹配规则如下:

矩阵 匹配清单
2.5 2.5-2.∞. 在兼容性矩阵中,2.52.5-5 的简写形式。
2.5-7 2.5-2.∞. 表示以下含义:
  • 2.5 是要求的最低版本,这意味着提供 HAL 2.0-2.4 的清单不兼容。
  • 2.7 是可以请求的最高版本,这意味着兼容性矩阵(框架或设备)的所有者将不会请求超过 2.7 的版本。请求版本 2.7 时,匹配清单的所有者仍然可以提供版本 2.10(以此为例)。兼容性矩阵所有者只知道请求的服务与 API 版本 2.7 兼容。
  • -7 仅供参考,不影响 OTA 更新流程。
因此,如果某个设备的清单文件中的 HAL 版本为 2.10,而某个框架的兼容性矩阵中指明 2.5-7,则该设备与此框架保持兼容。

示例:DRM 模块的成功 HAL 匹配

框架兼容性矩阵指明了 DRM HAL 的以下版本信息:

<hal>
    <name>android.hardware.drm
    <version>1.0</version>
    <version>3.1-2</version>
    <interface>
        <name>IDrmFactory</name>
        <instance>default</instance>
        <instance>specific</instance>
    </interface>
</hal>
<hal>
    <name>android.hardware.drm
    <version>2.0</version>
    <interface>
        <name>ICryptoFactory</name>
        <instance>default</instance>
        <regex-instance>[a-z]+/[0-9]+</regex-instance>
    </interface>
</hal>

供应商必须实现以下实例之一:

android.hardware.drm@1.x::IDrmFactory/default          // where x >= 0
android.hardware.drm@1.x::IDrmFactory/specific         // where x >= 0
android.hardware.drm@3.y::IDrmFactory/default          // where y >= 1
android.hardware.drm@3.y::IDrmFactory/specific         // where y >= 1

并且还必须实现以下所有实例:

android.hardware.drm@2.z::ICryptoFactory/default       // where z >= 0
android.hardware.drm@2.z::ICryptoFactory/${INSTANCE}
            // where z >= 0 and ${INSTANCE} matches [a-z]+/[0-9]+
            // e.g. legacy/0

AIDL HAL

Android 11(不包括 Android 11)之后的所有 Android 版本都支持 VINTF 中的 AIDL HAL 版本。AIDL HAL 的匹配规则类似于 HIDL 和原生 HAL 的匹配规则,只是没有主要版本,并且每个 HAL 实例只有一个版本(如果未指定版本,则为 1)。

  • 多个 <hal> 元素具有 AND 关系。
  • <hal> 元素可以具有 <hal optional="true">,用以将它们标记为不需要。
  • 当需要 <hal> 时,同一个 <hal> 中的多个 <instance><regex-instance> 元素具有 AND 关系(请参见下面的<ahref="#vibrator">振动器示例)。</ahref="#vibrator">

示例:模块的成功 HAL 匹配

对于 5 版的 HAL,匹配规则如下:

矩阵 匹配清单
5 5-∞. 在兼容性矩阵中,55-5 的简写形式。
5-7 5-∞. 表示以下含义:
  • 5 是要求的最低版本,这意味着提供 HAL 1-4 的清单不兼容。
  • 7 是可以请求的最高版本,这意味着兼容性矩阵(框架或设备)的所有者将不会请求超过 7 的版本。请求版本 7 时,匹配清单的所有者仍然可以提供版本 10(以此为例)。兼容性矩阵所有者只知道请求的服务与 API 版本 7 兼容。
  • -7 仅供参考,不影响 OTA 更新流程。
因此,如果某个设备的清单文件中的 HAL 版本为 10,而某个框架的兼容性矩阵中指明 5-7,则该设备与此框架保持兼容。

示例:多个模块的成功 HAL 匹配

框架兼容性矩阵指明了振动器和相机 HAL 的以下版本信息:

<hal>
    <name>android.hardware.vibrator
    <version>1-2</version>
    <interface>
        <name>IVibrator</name>
        <instance>default</instance>
        <instance>specific</instance>
    </interface>
</hal>
<hal>
    <name>android.hardware.camera
    <version>5</version>
    <interface>
        <name>ICamera</name>
        <instance>default</instance>
        <regex-instance>[a-z]+/[0-9]+</regex-instance>
    </interface>
</hal>

供应商必须实现以下所有实例:

android.hardware.vibrator.IVibrator/default     // version >= 1
android.hardware.vibrator.IVibrator/specific    // version >= 1
android.hardware.camera.ICamera/default         // version >= 5
android.hardware.camera.ICamera/${INSTANCE}
            // with version >= 5, where ${INSTANCE} matches [a-z]+/[0-9]+
            // e.g. legacy/0

内核匹配

框架兼容性矩阵的 <kernel> 部分描述了框架对设备 Linux 内核的要求。该信息用于与设备的 VINTF 对象报告的内核相关信息进行匹配。

匹配内核分支

每个内核分支后缀(例如 5.4-r)会映射到唯一的内核 FCM 版本(例如 5)。映射与版本字母(例如 R)和 FCM 版本(例如 5)之间的映射相同。

如果满足以下任一条件,VTS 测试会强制设备在设备清单 /vendor/etc/vintf/manifest.xml 中明确指定内核 FCM 版本:

  • 内核 FCM 版本与目标 FCM 版本不同。例如,上述设备的目标 FCM 版本为 4,其内核 FCM 版本为 5(内核分支后缀为 r)。
  • 内核 FCM 版本高于或等于 5(内核分支后缀为 r)。

VTS 测试强制要求:如果指定了内核 FCM 版本,内核 FCM 版本应大于或等于设备清单中的目标 FCM 版本。

示例:确定内核分支

如果设备具有目标 FCM 版本 4(在 Android 10 中发布),但从 4.19-r 分支运行内核,设备清单应指定以下内容:

<manifest version="2.0" type="device" target-level="4">
   <kernel target-level="5" />
</manifest>

VINTF 对象会根据 4.19-r 内核分支上的要求检查内核兼容性,该内核分支在 FCM 版本 5 中指定。这些要求都是从 Android 源代码树中的 kernel/configs/r/android-4.19 构建的。

示例:确定 GKI 的内核分支

如果设备使用通用内核映像 (GKI),并且来自 /proc/version 的内核版本字符串如下所示:

5.4.42-android12-0-00544-ged21d463f856

然后,VINTF 对象会从内核版本获取 Android 版本,并据此确定内核 FCM 版本。在此示例中,android12 表示内核 FCM 版本 6(在 Android 12 中发布)。

如需详细了解如何解析内核版本字符串,请参阅 GKI 版本控制

匹配内核版本

矩阵可以包括多个 <kernel> 部分,每个部分使用不同的 version 属性,格式如下:

${ver}.${major_rev}.${kernel_minor_rev}

VINTF 对象仅将 FCM 中版本匹配且具有相同 ${ver}${major_rev}<kernel> 部分视为设备内核(即version="${ver}.${major_rev}.${matrix_minor_rev}")),而忽略其他部分。此外,内核的次要修订版本必须是兼容性矩阵 (${kernel_minor_rev} >= ${matrix_minor_rev}) 中的值。如果没有 <kernel> 部分满足这些要求,则不匹配。

示例:选择匹配要求

假设 /system/etc/vintf 中的 FCM 声明了以下要求(标头和页脚标记被省略):

<!-- compatibility_matrix.3.xml -->
<kernel version="4.4.107" level="3"/>
<!-- See kernel/configs/p/android-4.4/ for 4.4-p requirements -->
<kernel version="4.9.84" level="3"/>
<!-- See kernel/configs/p/android-4.9/ for 4.9-p requirements -->
<kernel version="4.14.42" level="3"/>
<!-- See kernel/configs/p/android-4.14/ for 4.14-p requirements -->

<!-- compatibility_matrix.4.xml -->
<kernel version="4.9.165" level="4"/>
<!-- See kernel/configs/q/android-4.9/ for 4.9-q requirements -->
<kernel version="4.14.105" level="4"/>
<!-- See kernel/configs/q/android-4.14/ for 4.14-q requirements -->
<kernel version="4.19.42" level="4"/>
<!-- See kernel/configs/q/android-4.19/ for 4.19-q requirements -->

<!-- compatibility_matrix.5.xml -->
<kernel version="4.14.180" level="5"/>
<!-- See kernel/configs/r/android-4.14/ for 4.14-r requirements -->
<kernel version="4.19.123" level="5"/>
<!-- See kernel/configs/r/android-4.19/ for 4.19-r requirements -->
<kernel version="5.4.41" level="5"/>
<!-- See kernel/configs/r/android-5.4/ for 5.4-r requirements -->

目标 FCM 版本、内核 FCM 版本和内核版本一起从 FCM 中选择内核要求:

目标 FCM 版本内核 FCM 版本内核版本匹配结果
3 (P)未指定4.4.106 不匹配(次要版本不一致)
3 (P)未指定4.4.107 4.4-p
3 (P)未指定4.19.42 4.19-q(请参见下面的备注)
3 (P)未指定5.4.41 5.4-r (请参见下面的备注)
3 (P)3 (P)4.4.107 4.4-p
3 (P)3 (P)4.19.42 不匹配(无 4.19-p 内核分支)
3 (P)4 (Q) 4.19.42 4.19-q
4 (Q)未指定4.4.107 不匹配(无 4.4-q 内核分支)
4 (Q)未指定4.9.165 4.9-q
4 (Q)未指定5.4.41 5.4-r (请参见下面的备注)
4 (Q)4 (Q) 4.9.165 4.9-q
4 (Q)4 (Q) 5.4.41 不匹配(无 5.4-q 内核分支)
4 (Q)5 (R)4.14.1054.14-r
4 (Q)5 (R)5.4.41 5.4-r
5 (R)未指定任意VTS 失败(必须为目标 FCM 版本 5 指定内核 FCM 版本)
5 (R)4 (Q) 任意VTS 失败(内核 FCM 版本 < 目标 FCM 版本)
5 (R)5 (R)4.14.1804.14-r

匹配内核配置

如果 <kernel> 部分匹配,则该过程接下来会尝试将 config 元素与 /proc/config.gz 进行匹配。对于兼容性矩阵中的每个配置元素,系统将查找 /proc/config.gz 以查看该配置是否存在。如果某个配置项在匹配的 <kernel> 部分的兼容性矩阵中设置为 n,便不得在 /proc/config.gz 中出现。最后,不在兼容性矩阵中的配置项不一定会包含在 /proc/config.gz 中。

示例:匹配内核配置

  • <value type="string">bar</value>"bar" 匹配。引号在兼容性矩阵中会被忽略,但会包含在 /proc/config.gz 中。
  • <value type="int">4096</value>40960x10000X1000 匹配。
  • <value type="int">0x1000</value>40960x10000X1000 匹配。
  • <value type="int">0X1000</value>40960x10000X1000 匹配。
  • <value type="tristate">y</value>y 匹配。
  • <value type="tristate">m</value>m 匹配。
  • <value type="tristate">n</value> 表示配置项不得存在于 /proc/config.gz 中。
  • <value type="range">1-0x3</value>123 或十六进制对等数字匹配。

示例:成功的内核匹配

FCM 版本 1 的框架兼容性矩阵包含以下内核信息:

<kernel version="4.14.42">
   <config>
      <key>CONFIG_TRI</key>
      <value type="tristate">y</value>
   </config>
   <config>
      <key>CONFIG_NOEXIST</key>
      <value type="tristate">n</value>
   </config>
   <config>
      <key>CONFIG_DEC</key>
      <value type="int">4096</value>
   </config>
   <config>
      <key>CONFIG_HEX</key>
      <value type="int">0XDEAD</value>
   </config>
   <config>
      <key>CONFIG_STR</key>
      <value type="string">str</value>
   </config>
   <config>
      <key>CONFIG_EMPTY</key>
      <value type="string"></value>
   </config>
</kernel>

首先匹配内核分支。内核分支在设备清单的 manifest.kernel.target-level 中指定,如果未指定,则默认为 manifest.level。如果设备清单中的内核分支:

  • 为 1,则继续执行下一步并检查内核版本。
  • 为 2,则与矩阵不匹配。VINTF 对象会从 FCM 版本的矩阵读取内核要求。

然后,匹配内核版本。如果 uname() 中的设备报告:

  • 4.9.84(除非有一个含有 <kernel version="4.9.x"> 的单独内核部分且其中的 x <= 84,否则与矩阵不匹配)
  • 4.14.41(与矩阵不匹配,小于 version
  • 4.14.42(与矩阵匹配)
  • 4.14.43(与矩阵匹配)
  • 4.1.22(除非有一个含有 <kernel version="4.1.x"> 的单独内核部分且其中的 x <= 22,否则与矩阵不匹配)

选择适当的 <kernel> 部分后,对于值不为 n 的每个 <config> 项,我们预计对应条目会存在于 /proc/config.gz 中;对于值为 n 的每个 <config> 项,我们预计对应条目不会存在于 /proc/config.gz 中。我们预计 <value> 的内容与等号后面的文本(包括引号)完全匹配,直到换行符或 #,开头和结尾的空格被截断。

以下内核配置是成功匹配的示例:

# comments don't matter
CONFIG_TRI=y
# CONFIG_NOEXIST shouldn't exist
CONFIG_DEC = 4096 # trailing comments and whitespaces are fine
CONFIG_HEX=57005  # 0XDEAD == 57005
CONFIG_STR="str"
CONFIG_EMPTY=""   # empty string must have quotes
CONFIG_EXTRA="extra config items are fine too"

以下内核配置是不成功匹配的示例:

CONFIG_TRI="y"   # mismatch: quotes
CONFIG_NOEXIST=y # mismatch: CONFIG_NOEXIST exists
CONFIG_HEX=0x0   # mismatch; value doesn't match
CONFIG_DEC=""    # mismatch; type mismatch (expect int)
CONFIG_EMPTY=1   # mismatch; expects ""
# mismatch: CONFIG_STR is missing

SE 策略匹配

SE 策略需要以下匹配:

  • <sepolicy-version> 定义了每个主要版本的次要版本的封闭范围。设备报告的 sepolicy 版本必须属于这些范围之一才能与框架兼容。匹配规则类似于 HAL 版本;如果 sepolicy 版本高于或等于范围内的最低版本,则匹配。最高版本仅供参考。
  • <kernel-sepolicy-version>(即 policydb 版本)必须低于设备报告的 security_policyvers()

示例:成功的 SE 策略匹配

框架兼容性矩阵指明了以下 sepolicy 信息:

<sepolicy>
    <kernel-sepolicy-version>30</kernel-sepolicy-version>
    <sepolicy-version>25.0</sepolicy-version>
    <sepolicy-version>26.0-3</sepolicy-version>
</sepolicy>

在设备上:

  • security_policyvers() 返回的值必须大于或等于 30。否则,不匹配。例如:
    • 如果设备返回 29,则不匹配。
    • 如果设备返回 31,则匹配。
  • SE 策略版本必须为 25.0-∞ 和 26.0-∞ 其中之一。否则,不匹配(“26.0”后面的“-3”仅供参考)。

AVB 版本匹配

AVB 版本包含 MAJOR 版本和 MINOR 版本,格式为 MAJOR.MINOR(例如 1.0 和 2.1)。有关详细信息,请参阅版本管理和兼容性。AVB 版本具有以下系统属性:

  • ro.boot.vbmeta.avb_version 是引导加载程序中的 libavb 版本
  • ro.boot.avb_version 是 Android 操作系统中的 libavb 版本 (init/fs_mgr)

仅当已使用对应的 libavb 验证 AVB 元数据(并且返回 OK)时,才会显示该系统属性。如果验证失败(或根本没有执行验证),则不会显示该系统属性。

兼容性匹配将比较以下内容:

  • sysprop ro.boot.vbmeta.avb_version 与框架兼容性矩阵中的 avb.vbmeta-version
    • ro.boot.vbmeta.avb_version.MAJOR == avb.vbmeta-version.MAJOR
    • ro.boot.vbmeta.avb_version.MINOR >= avb.vbmeta-version.MINOR
  • sysprop ro.boot.avb_version 与框架兼容性矩阵中的 avb.vbmeta-version
    • ro.boot.avb_version.MAJOR == avb.vbmeta-version.MAJOR
    • ro.boot.avb_version.MINOR >= avb.vbmeta-version.MINOR

引导加载程序或 Android OS 可能包含 libavb 库的两个副本,每个副本具有不同的 MAJOR 版本,用于升级设备和启动设备。在这种情况下,可以共享同一个未签名的系统映像,但最终的签名系统映像则不同(具有不同的 avb.vbmeta-version):

图 1. AVB 版本匹配(/system 为 P,其他所有分区均为 O)。



图 2. AVB 版本匹配(所有分区均为 P)。

示例:成功的 AVB 版本匹配

框架兼容性矩阵指明了以下 AVB 信息:

<avb>
    <vbmeta-version>2.1</vbmeta-version>
</avb>

在设备上:

ro.boot.avb_version              == 1.0 &&
ro.boot.vbmeta.avb_version       == 2.1  mismatch 
ro.boot.avb_version              == 2.1 &&
ro.boot.vbmeta.avb_version       == 3.0  mismatch 
ro.boot.avb_version              == 2.1 &&
ro.boot.vbmeta.avb_version       == 2.3  match 
ro.boot.avb_version              == 2.3 &&
ro.boot.vbmeta.avb_version       == 2.1  match 

在 OTA 期间匹配 AVB 版本

对于搭载 Android 9 或更低版本的设备,在更新到 Android 10 期间,系统会将框架兼容性矩阵中的 AVB 版本要求与设备上的当前 AVB 版本进行匹配。如果 AVB 版本在 OTA 期间进行主要版本升级(例如,从 0.0 升级到 1.0),那么 OTA 中的 VINTF 兼容性检查不会反映 OTA 之后的兼容性。

为了缓解这个问题,原始设备制造商 (OEM) 可以在 OTA 软件包 (compatibility.zip) 中放置一个假 AVB 版本来通过检查。为此,请执行以下操作:

  1. 择优挑选以下 CL 并将其添加到 Android 9 源代码树中:
  2. 为设备定义 BOARD_OTA_FRAMEWORK_VBMETA_VERSION_OVERRIDE。其值应该等于 OTA 之前的 AVB 版本,即设备启动时的 AVB 版本。
  3. 重新构建 OTA 软件包。

这些更改会自动将 BOARD_OTA_FRAMEWORK_VBMETA_VERSION_OVERRIDE 作为 compatibility-matrix.avb.vbmeta-version 放置在以下文件中:

  • 设备上的 /system/compatibility_matrix.xml(未在 Android 9 中使用)
  • OTA 软件包中 compatibility.zip 内的 system_matrix.xml

这些更改不会影响其他框架兼容性矩阵,包括 /system/etc/vintf/compatibility_matrix.xml。在 OTA 之后,/system/etc/vintf/compatibility_matrix.xml 中的新值将用于进行兼容性检查。

VNDK 版本匹配

设备兼容性矩阵在 compatibility-matrix.vendor-ndk.version 中声明所需的 VNDK 版本。如果设备兼容性矩阵没有 <vendor-ndk> 标记,系统将不会实施任何要求,因此始终将其视为匹配项。

如果设备兼容性矩阵具有 <vendor-ndk> 标记,系统便会从框架在框架清单中提供的 VNDK 供应商快照集中查找具有匹配 <version><vendor-ndk> 条目。如果不存在此类条目,则没有匹配项。

如果确实存在此类条目,设备兼容性矩阵中枚举的库集必须是框架清单中声明的一组库的子集;否则,系统不会将此类条目视为匹配项。

  • 一种特殊情况是,如果设备兼容性矩阵中未枚举任何库,系统会始终将该条目视为匹配项,因为空集是任何集的子集。

示例:成功的 VNDK 版本匹配

如果设备兼容性矩阵在 VNDK 上声明了以下要求:

<!-- Example Device Compatibility Matrix -->
<vendor-ndk>
    <version>27</version>
    <library>libjpeg.so</library>
    <library>libbase.so</library>
</vendor-ndk>

在框架清单中,系统仅会考虑具有版本 27 的条目。

<!-- Framework Manifest Example A -->
<vendor-ndk>
    <version>27</version>
    <library>libjpeg.so</library>
    <library>libbase.so</library>
    <library>libfoo.so</library>
</vendor-ndk>

示例 A 是匹配项,因为 VNDK 版本 27 在框架清单中,并且 {libjpeg.so, libbase.so, libfoo.so} ⊇ {libjpeg.so, libbase.so}

<!-- Framework Manifest Example B -->
<vendor-ndk>
    <version>26</version>
    <library>libjpeg.so</library>
    <library>libbase.so</library>
</vendor-ndk>
<vendor-ndk>
    <version>27</version>
    <library>libbase.so</library>
</vendor-ndk>

示例 B 不是匹配项。即使 VNDK 版本 27 在框架清单中,该快照中的框架也不支持 libjpeg.so。VNDK 版本 26 将被忽略。

系统 SDK 版本匹配

设备兼容性矩阵在 compatibility-matrix.system-sdk.version 中声明一组所需的系统 SDK 版本。只有当该集合是所提供的系统 SDK 版本(在框架清单的 manifest.system-sdk.version 中声明)的子集时,才存在匹配项。

  • 一种特殊情况是,如果设备兼容性矩阵中未枚举任何系统 SDK 版本,则系统会始终将该条目视为匹配项,因为空集是任何集的子集。

示例:成功的系统 SDK 版本匹配

如果设备兼容性矩阵在系统 SDK 上声明了以下要求:

<!-- Example Device Compatibility Matrix -->
<system-sdk>
    <version>26</version>
    <version>27</version>
</system-sdk>

然后,框架必须提供系统 SDK 版本 26 和 27 才能匹配。

<!-- Framework Manifest Example A -->
<system-sdk>
    <version>26</version>
    <version>27</version>
</system-sdk>

示例 A 是匹配项。

<!-- Framework Manifest Example B -->
<system-sdk>
    <version>26</version>
    <version>27</version>
    <version>28</version>
</system-sdk>

示例 B 是匹配项。

<!-- Framework Manifest Example C -->
<system-sdk>
    <version>26</version>
</system-sdk>

示例 C 不是匹配项,因为未提供系统 SDK 版本 27。