Правила сопоставления

Две пары матриц совместимости и манифесты предназначены для согласования, чтобы убедиться, что платформа и реализация поставщика могут работать друг с другом. Эта проверка считается успешной при совпадении между матрицей совместимости платформы и манифестом устройства, а также между манифестом платформы и матрицей совместимости устройства.

Эта проверка выполняется во время сборки, во время создания пакета обновлений OTA , во время загрузки и в тестах совместимости VTS.

В следующих разделах подробно описаны правила сопоставления, используемые различными компонентами.

Версия матрицы совместимости фреймворка соответствует

Чтобы манифест устройства соответствовал матрице совместимости платформы, версия FCM доставки, указанная в manifest.target-level , должна точно совпадать с версией FCM, указанной в compatibility-matrix.level . В противном случае нет совпадения.

Когда матрица совместимости фреймворка запрашивается с помощью libvintf , это совпадение всегда успешно, потому что libvintf открывает манифест устройства, извлекает версию FCM для доставки и возвращает матрицу совместимости фреймворка для этой версии FCM для доставки (плюс некоторые необязательные HAL из матриц совместимости для более высоких значений FCM). версии).

HAL соответствует

Правило соответствия HAL определяет версии элементов hal в файле манифеста, которые считаются поддерживаемыми владельцем соответствующей матрицы совместимости.

HIDL и собственные HAL

Правила соответствия для HIDL и собственных HAL следующие.

  • Несколько элементов <hal> оцениваются с помощью одного отношения AND .
  • Элементы <hal> могут иметь <hal optional="true"> , чтобы пометить их как ненужные.
  • Несколько элементов <version> внутри одного <hal> имеют отношение ИЛИ . Если указано два или более, необходимо реализовать только одну из версий. (См. пример DRM ниже.)
  • Несколько элементов <instance> и <regex-instance> в одном <hal> оцениваются с помощью одного отношения AND , когда требуется <hal> . (См. Пример DRM ниже.)

Пример: успешное соответствие HAL для модуля

Для HAL версии 2.5 правило соответствия выглядит следующим образом:

Матрица Соответствующий манифест
2.5 2,5-2,∞. В матрице совместимости 2.5 — это сокращение от 2.5-5 .
2.5-7 2,5-2,∞. Указывает следующее:
  • 2.5 — это минимальная требуемая версия, что означает, что манифест, предоставляющий HAL 2.0-2.4, несовместим.
  • 2.7 — это максимальная версия, которую можно запросить, а это означает, что владелец матрицы совместимости (платформы или устройства) не будет запрашивать версии выше 2.7. Владелец соответствующего манифеста по-прежнему может предоставлять версию 2.10 (в качестве примера), когда запрашивается версия 2.7. Владелец матрицы совместимости знает только, что запрошенный сервис совместим с API версии 2.7.
  • -7 носит информационный характер и не влияет на процесс OTA-обновления.
Таким образом, устройство с HAL версии 2.10 в файле манифеста остается совместимым с инфраструктурой, которая указывает 2.5-7 в своей матрице совместимости.

Пример: успешное совпадение HAL для модуля DRM

В матрице совместимости фреймворка указана следующая информация о версии 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 более поздние, чем Android 11 (за исключением Android 11), поддерживают версии для AIDL HAL в VINTF. Правила сопоставления для AIDL HAL аналогичны правилам HIDL и собственных HAL, за исключением того, что нет основных версий и существует ровно одна версия для каждого экземпляра HAL ( 1 , если версия не указана).

  • Несколько элементов <hal> оцениваются с помощью одного отношения AND .
  • Элементы <hal> могут иметь <hal optional="true"> , чтобы пометить их как ненужные.
  • Несколько элементов <instance> и <regex-instance> в одном <hal> оцениваются с помощью одного отношения AND , когда требуется <hal> . (См. пример вибратора ниже.)

Пример: успешное соответствие HAL для модуля

Для HAL версии 5 правило соответствия выглядит следующим образом:

Матрица Соответствующий манифест
5 5-∞. В матрице совместимости 5 — это сокращение от 5-5 .
5-7 5-∞. Указывает следующее:
  • 5 — это минимальная требуемая версия, что означает, что манифест, предоставляющий HAL 1–4, несовместим.
  • 7 — это максимальная версия, которая может быть запрошена, а это означает, что владелец матрицы совместимости (платформа или устройство) не будет запрашивать версии выше 7. Владелец соответствующего манифеста по-прежнему может предоставлять версию 10 (например), когда запрашивается 7. . Владелец матрицы совместимости знает только, что запрошенный сервис совместим с 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 требуют, чтобы устройство явно указывало версию FCM ядра в манифесте устройства, /vendor/etc/vintf/manifest.xml , если выполняется одно из следующих условий:

  • Версия ядра 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. Эти требования собраны из kernel/configs/r/android-4.19 в дереве исходного кода Android.

Пример: определение ветки ядра для 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 рассматривает только раздел <kernel> из FCM с соответствующей версией FCM с теми же ${ver} и ${major_rev} , что и ядро ​​устройства (т. е version="${ver}.${major_rev}.${matrix_minor_rev}") ; другие разделы игнорируются. Кроме того, второстепенная версия ядра должна быть значением из матрицы совместимости ( ${kernel_minor_rev} >= ${matrix_minor_rev} ;). Если ни один из разделов <kernel> не соответствует этим требованиям, он считается несоответствующим.

Пример: выберите требования для сопоставления

Рассмотрим следующий гипотетический случай, когда FCM в /system/etc/vintf объявляют следующие требования (теги заголовка и нижнего колонтитула опущены):

<!-- 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 (П) неопределенные 4.4.106 Несоответствие (несоответствие второстепенной версии)
3 (П) неопределенные 4.4.107 4.4-p
3 (П) неопределенные 4.19.42 4.19-q (см. примечание ниже)
3 (П) неопределенные 5.4.41 5.4-r (см. примечание ниже)
3 (П) 3 (П) 4.4.107 4.4-p
3 (П) 3 (П) 4.19.42 Нет совпадений (нет ветки ядра 4.19-p )
3 (П) 4 (К) 4.19.42 4.19-q
4 (К) неопределенные 4.4.107 Нет соответствия (нет ветки ядра 4.4-q )
4 (К) неопределенные 4.9.165 4.9-q
4 (К) неопределенные 5.4.41 5.4-r (см. примечание ниже)
4 (К) 4 (К) 4.9.165 4.9-q
4 (К) 4 (К) 5.4.41 Нет соответствия (нет ветки ядра 5.4-q )
4 (К) 5 (Р) 4.14.105 4.14-r
4 (К) 5 (Р) 5.4.41 5.4-r
5 (Р) неопределенные Любые Сбой VTS (необходимо указать версию ядра FCM для целевой версии FCM 5)
5 (Р) 4 (К) Любые Сбой VTS (версия ядра FCM < целевой версии FCM)
5 (Р) 5 (Р) 4.14.180 4.14-r

Соответствие конфигурации ядра

Если раздел <kernel> совпадает, процесс продолжается, пытаясь сопоставить элементы config с /proc/config.gz . Для каждого элемента конфигурации в матрице совместимости он ищет /proc/config.gz , чтобы увидеть, присутствует ли конфигурация. Когда элемент конфигурации имеет значение n в матрице совместимости для соответствующего раздела <kernel> , он должен отсутствовать в /proc/config.gz . Наконец, элемент конфигурации, отсутствующий в матрице совместимости, может присутствовать или отсутствовать в /proc/config.gz .

Пример: сопоставление конфигураций ядра

  • <value type="string">bar</value> соответствует "bar" . Кавычки опущены в матрице совместимости, но присутствуют в /proc/config.gz .
  • <value type="int">4096</value> соответствует 4096 или 0x1000 или 0X1000 .
  • <value type="int">0x1000</value> соответствует 4096 , 0x1000 или 0X1000 .
  • <value type="int">0X1000</value> соответствует 4096 , 0x1000 или 0X1000 .
  • <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> соответствует 1 , 2 или 3 или шестнадцатеричному эквиваленту.

Пример: успешное совпадение ядра

Матрица совместимости фреймворка с 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> для каждого элемента <config> со значением, отличным от n , мы ожидаем, что соответствующая запись будет присутствовать в /proc/config.gz ; для каждого элемента <config> со значением n мы ожидаем, что соответствующая запись не будет присутствовать в /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>
    <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-∞. В противном случае это не совпадение. (" -3 " после " 26.0 " носит чисто информационный характер.)

Версия AVB соответствует

Версия AVB содержит MAJOR версию и MINOR версию в формате MAJOR.MINOR (например, 1.0, 2.1). Дополнительные сведения см. в разделе Управление версиями и совместимость . Версия AVB имеет следующие системные свойства:

  • ro.boot.vbmeta.avb_version — это версия libavb в загрузчике.
  • ro.boot.avb_version — это версия libavb в ОС Android ( 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 , каждая из которых имеет свою ОСНОВНУЮ версию для устройств обновления и устройств запуска. В этом случае можно поделиться одним и тем же неподписанным образом системы, но окончательные подписанные образы системы будут другими (с другой 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 

Соответствие версии AVB во время OTA

Для устройств, выпущенных с Android 9 или более ранней версией, при обновлении до Android 10 требования к версии AVB в матрице совместимости платформы сопоставляются с текущей версией AVB на устройстве. Если версия AVB имеет основное обновление версии во время OTA (например, с 0.0 до 1.0), проверка совместимости VINTF в OTA не отражает совместимость после OTA.

Чтобы смягчить проблему, OEM-производитель может поместить поддельную версию AVB в пакет OTA ( compatibility.zip ), чтобы пройти проверку. Для этого:

  1. Выберите следующие CL для исходного дерева Android 9:
  2. Определите BOARD_OTA_FRAMEWORK_VBMETA_VERSION_OVERRIDE для устройства. Его значение должно равняться версии AVB до OTA, то есть версии AVB устройства при его запуске.
  3. Пересоберите пакет OTA.

Эти изменения автоматически помещают BOARD_OTA_FRAMEWORK_VBMETA_VERSION_OVERRIDE в качестве compatibility-matrix.avb.vbmeta-version в следующие файлы:

  • /system/compatibility_matrix.xml (который не используется в Android 9) на устройстве
  • system_matrix.xml в compatibility.zip в пакете OTA

Эти изменения не влияют на другие матрицы совместимости фреймворков, включая /system/etc/vintf/compatibility_matrix.xml . После OTA новое значение в /system/etc/vintf/compatibility_matrix.xml вместо этого используется для проверки совместимости.

Версия VNDK совпадает

Матрица совместимости устройств объявляет требуемую версию VNDK в compatibility-matrix.vendor-ndk.version . Если в матрице совместимости устройств нет <vendor-ndk> , никаких требований не предъявляется, и, следовательно, это всегда считается совпадением.

Если в матрице совместимости устройств есть <vendor-ndk> , запись <vendor-ndk> с соответствующей <version> ищется в наборе моментальных снимков поставщиков VNDK, предоставленных платформой в манифесте платформы. Если такой записи не существует, совпадений нет.

Если такая запись существует, набор библиотек, перечисленных в матрице совместимости устройств, должен быть подмножеством набора библиотек, указанного в манифесте платформы; в противном случае запись не считается совпадением.

  • В качестве особого случая, если в матрице совместимости устройств не перечислено ни одной библиотеки, запись всегда считается совпадением, поскольку пустой набор является подмножеством любого набора.

Пример: успешное совпадение версии 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 совпадает

Матрица совместимости устройств объявляет набор требуемой версии System SDK в compatibility-matrix.system-sdk.version . Совпадение есть только в том случае, если набор является подмножеством предоставленных версий System SDK, как указано в manifest.system-sdk.version в манифесте платформы.

  • В качестве особого случая, если в матрице совместимости устройств не указаны версии System SDK, это всегда считается совпадением, поскольку пустой набор является подмножеством любого набора.

Пример: успешное совпадение версии System SDK

Если в матрице совместимости устройств указано следующее требование к System SDK:

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

Затем платформа должна предоставить System SDK версии 26 и 27 для соответствия.

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

Пример А — совпадение.

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

Пример Б — совпадение.

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

Пример C не подходит, так как System SDK версии 27 не предоставляется.