Обеспечьте соблюдение интерфейсов разделов продуктов

В Android 11 раздел product отделен от system и vendor разделов, что делает его независимым от них. В рамках этих изменений теперь можно контролировать доступ раздела product к собственным и Java-интерфейсам (аналогично тому, как работает принудительное использование интерфейсов для vendor разделов).

Внедрить нативные интерфейсы

Чтобы включить проверку соответствия собственному интерфейсу, установите параметр PRODUCT_PRODUCT_VNDK_VERSION в current . (Версия автоматически устанавливается в current , если уровень API для целевой платформы превышает 29.) Проверка соответствия позволяет:

  • Встроенные модули в разделе product для связывания:
    • Статически или динамически подключаться к другим модулям в разделе product , включающим статические, разделяемые или заголовочные библиотеки.
    • Динамически подключается к библиотекам VNDK в system разделе.
  • Библиотеки JNI в распакованных APK-файлах в разделе product позволяют создавать ссылки на библиотеки в /product/lib или /product/lib64 (это в дополнение к библиотекам NDK).

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

Контроль времени сборки (Android.bp)

В Android 11 системные модули могут создавать вариант образа продукта в дополнение к вариантам образа ядра и поставщика. Когда включена проверка нативного интерфейса ( PRODUCT_PRODUCT_VNDK_VERSION установлено в current ):

  • Нативные модули в разделе product находятся в варианте продукта, а не в варианте ядра.

  • Модули, в файлах Android.bp которых указано product_available: true доступны для варианта продукта.

  • Библиотеки или исполняемые файлы, в которых указано product_specific: true могут ссылаться на другие библиотеки, в файлах Android.bp которых указано product_specific: true или product_available: true .

  • В файлах Android.bp библиотек VNDK должна быть указана product_available: true , чтобы исполняемые файлы product могли связываться с библиотеками VNDK.

В следующей таблице приведено краткое описание свойств файла Android.bp , используемых для создания вариантов изображений.

Свойства в Android.bp Созданы варианты.
До применения мер принуждения После применения мер принуждения
по умолчанию (нет) основной
(включает /system , /system_ext и /product )
основной
(включает /system и /system_ext , но не /product )
system_ext_specific: true основной основной
product_specific: true основной продукт
vendor: true продавец продавец
vendor_available: true ядро, поставщик ядро, поставщик
product_available: true Н/Д ядро, продукт
vendor_available: true AND product_available: true Н/Д ядро, продукт, поставщик
system_ext_specific: true AND vendor_available: true ядро, поставщик ядро, поставщик
product_specific: true AND vendor_available: true ядро, поставщик продукт, поставщик

Контроль времени сборки (Android.mk)

Когда включена проверка нативного интерфейса, нативные модули, установленные в раздел product имеют тип ссылки native:product , который может связываться только с другими модулями native:product или native:vndk . Попытка связаться с любыми модулями, кроме этих, приводит к тому, что система сборки генерирует ошибку проверки типа ссылки.

Контроль выполнения во время выполнения

Когда включена функция принудительного использования нативного интерфейса, конфигурация компоновщика для бионического компоновщика не позволяет системным процессам использовать библиотеки product , создавая раздел product для процессов product , которые не могут связываться с библиотеками за пределами раздела product (однако такие процессы могут связываться с библиотеками VNDK). Попытки нарушить конфигурацию компоновки во время выполнения приводят к сбою процесса и генерации сообщения об ошибке CANNOT LINK EXECUTABLE ».

Внедрить Java-интерфейсы

Чтобы включить принудительное применение Java-интерфейса, установите параметр PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE в true . (Значение автоматически устанавливается в true , если уровень API для целевой платформы превышает 29.) При включении принудительное применение разрешает или запрещает следующий доступ:

API /система /system_ext /продукт /продавец /данные
Публичный API
@SystemApi
@скрыть API

Как и в разделе vendor , в разделе product приложением или библиотекой Java разрешено использовать только общедоступные и системные API; связывание с библиотекой, использующей скрытые API, не допускается. Это ограничение включает в себя связывание во время сборки и рефлексию во время выполнения.

Контроль за соблюдением сроков сборки

На этапе сборки Make и Soong проверяют, не используют ли Java-модули в разделе product скрытые API, проверяя поля platform_apis и sdk_version . Поле sdk_version приложений в разделе product должно быть заполнено значением current , system_current или числовой версией API, а поле platform_apis должно быть пустым.

Контроль выполнения во время выполнения

Среда выполнения Android проверяет, не используют ли приложения в разделе product скрытые API, включая рефлексию. Подробнее см. раздел «Ограничения на интерфейсы, не относящиеся к SDK» .

Включить принудительное использование интерфейса продукта

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

Шаг Задача Необходимый
1 Создайте собственный системный makefile, который определяет пакеты для system раздела, а затем установите проверку требований к пути к артефактам в device.mk (чтобы предотвратить установку несистемных модулей в system раздел). Н
2 Упорядочить список разрешенных объектов. Н
3 Обеспечить корректное использование нативных интерфейсов и выявлять ошибки компоновки во время выполнения (может выполняться параллельно с обеспечением корректного использования Java). Я
4 Обеспечивать соблюдение требований к интерфейсам Java и проверять поведение во время выполнения (может выполняться параллельно с проверкой нативных интерфейсов). Я
5 Проверьте поведение во время выполнения. Я
6 Обновите файл device.mk , добавив проверку интерфейса продукта. Я

Шаг 1: Создайте файл makefile и включите проверку пути к артефакту.

На этом шаге вы определяете system makefile.

  1. Создайте файл makefile, определяющий пакеты для system раздела. Например, создайте файл oem_system.mk со следующим содержимым:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk)
    $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk)
    
    # Applications
    PRODUCT_PACKAGES += \
        CommonSystemApp1 \
        CommonSystemApp2 \
        CommonSystemApp3 \
    
    # Binaries
    PRODUCT_PACKAGES += \
        CommonSystemBin1 \
        CommonSystemBin2 \
        CommonSystemBin3 \
    
    # Libraries
    PRODUCT_PACKAGES += \
        CommonSystemLib1 \
        CommonSystemLib2 \
        CommonSystemLib3 \
    
    PRODUCT_SYSTEM_NAME := oem_system
    PRODUCT_SYSTEM_BRAND := Android
    PRODUCT_SYSTEM_MANUFACTURER := Android
    PRODUCT_SYSTEM_MODEL := oem_system
    PRODUCT_SYSTEM_DEVICE := generic
    
    # For system-as-root devices, system.img should be mounted at /, so we
    # include ROOT here.
    _my_paths := \
     $(TARGET_COPY_OUT_ROOT)/ \
     $(TARGET_COPY_OUT_SYSTEM)/ \
    
    $(call require-artifacts-in-path, $(_my_paths),)
    
  2. В файле device.mk необходимо унаследовать общий makefile для system раздела и включить проверку требований к путям к артефактам. Например:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

О требованиях к пути к артефактам

Если параметру PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS присвоено значение true или strict , система сборки предотвращает установку пакетов, определенных в других make-файлах, в пути, указанные в require-artifacts-in-path , и предотвращает установку артефактов, определенных в текущем make-файле, за пределы путей, указанных в require-artifacts-in-path .

В приведенном выше примере, при установке PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS в strict , make-файлы вне oem_system.mk не могут включать модули, установленные в root или system раздел. Чтобы включить эти модули, необходимо определить их либо в самом файле oem_system.mk , либо в подключаемом make-файле. Попытки установить модули в запрещенные пути приводят к сбоям сборки. Для устранения сбоев выполните одно из следующих действий:

  • Вариант 1: Включить системный модуль в make-файлы, содержащиеся в oem_system.mk . Это позволит выполнить требование к пути к артефактам (поскольку модули теперь существуют во включенном make-файле) и, таким образом, обеспечит установку в набор путей, указанных в `require-artifacts-in-path`.

  • Вариант 2: Установите модули в раздел system_ext или product (и не устанавливайте модули в system раздел).

  • Вариант 3: Добавьте модули в список PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST . В этом списке перечислены разрешенные для установки модули.

Шаг 2: Очистите список разрешенных действий.

На этом шаге вы оставляете пустым поле PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST , чтобы все устройства, использующие oem_system.mk могли также использовать один и тот же образ system . Чтобы очистить список разрешенных модулей, переместите все модули из списка в раздел system_ext или product , либо добавьте их в файлы сборки system . Этот шаг необязателен, поскольку определение общего образа system не требуется для включения принудительного использования интерфейса продукта. Однако очистка списка разрешенных модулей полезна для определения границ system с помощью system_ext .

Шаг 3: Внедрение нативных интерфейсов

На этом шаге вы устанавливаете PRODUCT_PRODUCT_VNDK_VERSION := current , затем ищете ошибки сборки и выполнения и устраняете их. Чтобы проверить загрузку устройства и журналы, а также найти и исправить сбои в работе каналов во время выполнения:

  1. Установите PRODUCT_PRODUCT_VNDK_VERSION := current .

  2. Соберите устройство и проверьте наличие ошибок сборки. Вероятно, вы обнаружите несколько сбоев сборки, связанных с отсутствующими вариантами продукта или основными вариантами. К распространенным сбоям относятся:

    • Любой модуль hidl_interface , у которого product_specific: true будет недоступен для системных модулей. Для исправления замените product_specific: true на system_ext_specific: true .
    • В модулях может отсутствовать необходимый для них вариант продукта. Для исправления этой проблемы сделайте модуль доступным для раздела product , установив параметр product_available: true , или переместите модуль в раздел product , установив параметр product_specific: true .
  3. Устраните ошибки сборки и убедитесь, что устройство успешно собрано.

  4. Прошейте образ и проверьте наличие ошибок во время выполнения в журналах загрузки устройства и в логах.

    • Если в linker тестового случая отображается сообщение CANNOT LINK EXECUTABLE , значит, в файле make отсутствует зависимость (и она не была зафиксирована во время сборки).
    • Чтобы проверить это из системы сборки, добавьте необходимую библиотеку в поле shared_libs: или required:
  5. Устраните отсутствующие зависимости, используя приведенные выше инструкции.

Шаг 4: Внедрение Java-интерфейсов

На этом шаге вы устанавливаете PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true , затем находите и исправляете возникшие ошибки сборки. Ищите два конкретных типа ошибок:

  • Ошибки типа компоновки. Эта ошибка указывает на то, что приложение использует модули Java с более широким значением sdk_version . Для исправления можно расширить sdk_version приложения или ограничить значение sdk_version библиотеки. Пример ошибки:

    error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
    
  • Ошибки символов. Эта ошибка указывает на то, что символ не найден, поскольку он находится в скрытом API. Для исправления используйте видимый (нескрытый) API или найдите альтернативный вариант. Пример ошибки:

    frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol
                ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
                                               ^
      symbol:   class ProxyAuthenticate
      location: class SipSessionGroup.SipSessionImpl
    

Шаг 5: Проверка поведения во время выполнения.

На этом этапе вы проверяете, соответствует ли поведение во время выполнения ожидаемому. Для приложений, которые можно отлаживать, вы можете отслеживать использование скрытых API, регистрируя его с помощью StrictMode.detectNonSdkApiUsage (этот метод генерирует лог, когда приложение использует скрытый API). В качестве альтернативы вы можете использовать инструмент статического анализа Veridex , чтобы получить тип использования (связывание или рефлексия), уровень ограничения и стек вызовов.

  • Синтаксис Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
  • Пример результата проверки Veridex:

    #1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s):
           Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V
    
    #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s):
           Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
    

Подробную информацию об использовании Veridex см. в разделе «Тестирование с помощью инструмента Veridex» .

Шаг 6: Обновите файл device.mk

После устранения всех ошибок сборки и выполнения, а также проверки корректности работы во время выполнения, в device.mk установите следующие параметры:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true