匹配规则

两对兼容性矩阵和清单旨在 OTA 时进行协调,以验证框架和供应商实现是否可以相互协同工作。当框架兼容性矩阵与设备清单之间以及框架清单与设备兼容性矩阵之间匹配时,便成功通过此验证。下面几部分将详细介绍各种组件使用的匹配规则。

框架兼容性矩阵版本匹配

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

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

HAL 匹配

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

  • 多个 <hal> 元素具有 AND 关系。
  • 同一 <hal> 中的多个 <version> 元素具有 OR 关系。如果指定了两个或两个以上版本,则只需要实现其中一个版本(请参见下面的 DRM 示例)。
  • 同一 <hal> 中的多个 <instance><regex-instance> 元素具有 AND 关系(请参见下面的 DRM 示例)。

示例:相机模块的成功 HAL 匹配

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

矩阵 匹配清单
2.5 2.5-2.∞. 2.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,而某个框架的兼容性矩阵中指明 camera: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

内核匹配

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

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

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

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

如果 <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 或十六进制对等数字匹配。

示例:成功的内核匹配

框架兼容性矩阵包含以下内核信息:

<kernel version="3.18.51">
   <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>

首先匹配内核版本。如果 uname() 中的设备报告:

  • 3.10.73(除非有一个含有 <kernel version="3.10.x"> 的单独内核部分且其中的 x <= 73,否则与矩阵不匹配)
  • 3.18.50(与矩阵不匹配,小于 version
  • 3.18.51(与矩阵匹配)
  • 3.18.52(与矩阵匹配)
  • 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 should not 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 操作系统可能包含 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 或更低版本的设备,在 OTA 期间,系统会将框架兼容性矩阵中的 AVB 版本要求与设备上的当前 AVB 版本进行匹配。如果 AVB 版本在 OTA 期间进行主要版本升级(例如,从 0.0 升级到 1.0),则 OTA 中的检查不会反映 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。