匹配规则

兼容性矩阵和清单这两对文件旨在进行协调,以验证框架和供应商实现能否彼此兼容。当框架兼容性矩阵与设备清单以及框架清单与设备兼容性矩阵之间匹配时,验证即成功。

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

以下部分详细介绍了各种组件使用的匹配规则。

框架兼容性矩阵版本匹配

为了使设备清单与框架兼容性矩阵匹配,manifest.target-level 指定的发货 FCM 版本必须与 compatibility-matrix.level 指定的 FCM 版本完全相等。否则不匹配。

当通过 libvintf 请求框架兼容性矩阵时,此匹配始终会成功,因为 libvintf 会打开设备清单,检索发货 FCM 版本,并返回该发货 FCM 版本(以及来自更高 FCM 版本的兼容性矩阵的一些可选 HAL)的框架兼容性矩阵。

HAL 匹配

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

HIDL 和原生 HAL

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

  • 多个 <hal> 元素使用单个 AND 关系进行评估。
  • <hal> 元素可以具有 <hal optional="true">,以将其标记为非必需项。警告:Android 15 之后不再支持此 optional
  • 同一 <hal> 中的多个 <version> 元素具有 OR 关系。如果指定了两个或多个版本,则只需实现其中一个版本。(请参阅下面的 DRM 示例。)
  • <hal> 为必需项时,同一 <hal> 中的多个 <instance><regex-instance> 元素使用单个 AND 关系进行评估。(请参阅下面的 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 版本(不包括 Android 11)都支持 VINTF 中 AIDL HAL 的版本。AIDL HAL 的匹配规则与 HIDL 和原生 HAL 的匹配规则类似,但没有主版本,并且每个 HAL 实例只有一个版本(如果未指定版本,则为 1)。

  • 多个 <hal> 元素使用单个 AND 关系进行评估。
  • <hal> 元素可以具有 <hal optional="true">,以将其标记为非必需项。警告:Android 15 之后不再支持此 optional
  • <hal> 为必需项时,同一 <hal> 中的多个 <instance><regex-instance> 元素使用单个 AND 关系进行评估。(请参阅下面的振动器示例。)

示例:模块的 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 对象根据 FCM 版本 5 中指定的 4.19-r 内核分支上的要求检查内核兼容性。这些要求是从 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> 部分,每个部分都使用格式

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

VINTF 对象仅考虑来自 FCM 的 <kernel> 部分,该 FCM 的 FCM 版本与设备内核的 ${ver}${major_rev} 相同(即,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 进行匹配。对于兼容性矩阵中的每个 config 元素,它会在 /proc/config.gz 中查找以查看配置是否存在。当匹配的 <kernel> 部分的兼容性矩阵中的 config 项设置为 n 时,它必须不存在于 /proc/config.gz 中。最后,兼容性矩阵中不存在的 config 项可能存在也可能不存在于 /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> 表示 config 项不得存在于 /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 版本 2 的矩阵读取内核要求。

然后,匹配内核版本。如果 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 Policy 匹配

SE Policy 需要以下匹配

  • <sepolicy-version> 为每个主版本定义了一个闭合的次要版本范围。设备报告的 sepolicy 版本必须落在这些范围之一内,才能与框架兼容。匹配规则与 HAL 版本类似;如果 sepolicy 版本高于或等于该范围的最低版本,则匹配。最大版本纯粹是信息性的。
  • <kernel-sepolicy-version>,即 policydb 版本。必须小于设备报告的 security_policyvers()

示例:SE Policy 成功匹配

框架兼容性矩阵声明了以下 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 Policy 版本必须是 25.0-∞ 或 26.0-∞ 之一。否则不匹配。(“26.0” 之后的“-3” 纯粹是信息性的。)

AVB 版本匹配

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

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

仅当已使用相应的 libavb 验证 AVB 元数据(并返回 OK)时,才会显示系统属性。如果发生验证失败(或根本未发生验证),则不存在。

兼容性匹配会比较以下内容

  • 系统属性 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
  • 系统属性 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 操作系统可能包含两个 libavb 库副本,每个副本对于升级设备和启动设备都具有不同的主版本。在这种情况下,可以共享相同的未签名系统映像,但最终的签名系统映像是不同的(具有不同的 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 版本。只有当该集合是框架清单的 manifest.system-sdk.version 中声明的提供的系统 SDK 版本子集时,才匹配。

  • 作为一种特殊情况,如果设备兼容性矩阵中未枚举任何系统 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。