В Android 8.1 и выше система сборки имеет встроенную поддержку VNDK. Когда поддержка VNDK включена, система сборки проверяет зависимости между модулями, создает специфичный для поставщика вариант для модулей поставщика и автоматически устанавливает эти модули в назначенные каталоги.
Пример поддержки сборки VNDK
В этом примере определение модуля Android.bp
определяет библиотеку с именем libexample
. Свойство vendor_available
указывает, что модули фреймворка и модули вендора могут зависеть от libexample
:
Рисунок 1. Поддержка включена.
Как исполняемый файл фреймворка /system/bin/foo
так и исполняемый файл поставщика /vendor/bin/bar
зависят от libexample
и имеют libexample
в своих свойствах shared_libs
.
Если libexample
используется как модулями фреймворка, так и модулями вендора, то создаются два варианта libexample
. Основной вариант (названный в честь libexample
) используется модулями фреймворка, а вариант вендора (названный в честь libexample.vendor
) используется модулями вендора. Два варианта устанавливаются в разные каталоги:
- Основной вариант устанавливается в
/system/lib[64]/libexample.so
. - Вариант поставщика установлен в VNDK APEX, поскольку
vndk.enabled
имеетtrue
.
Более подробную информацию см. в разделе Определение модуля .
Настроить поддержку сборки
Чтобы включить полную поддержку системы сборки для устройства продукта, добавьте BOARD_VNDK_VERSION
в BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Этот параметр имеет глобальный эффект: при определении в BoardConfig.mk
проверяются все модули. Поскольку нет механизма для внесения в черный или белый список проблемного модуля, следует очистить все ненужные зависимости перед добавлением BOARD_VNDK_VERSION
. Вы можете протестировать и скомпилировать модуль, установив BOARD_VNDK_VERSION
в переменных среды:
$ BOARD_VNDK_VERSION=current m module_name.vendor
При включении BOARD_VNDK_VERSION
удаляются несколько путей поиска глобальных заголовков по умолчанию. К ним относятся:
-
frameworks/av/include
-
frameworks/native/include
-
frameworks/native/opengl/include
-
hardware/libhardware/include
-
hardware/libhardware_legacy/include
-
hardware/ril/include
-
libnativehelper/include
-
libnativehelper/include_deprecated
-
system/core/include
-
system/media/audio/include
Если модуль зависит от заголовков из этих каталогов, необходимо указать (явно) зависимости с помощью header_libs
, static_libs
и/или shared_libs
.
ВНДК АПЕКС
В Android 10 и ниже модули с vndk.enabled
устанавливались в /system/lib[64]/vndk[-sp]-${VER}
. В Android 11 и выше библиотеки VNDK упакованы в формате APEX, а имя VNDK APEX — com.android.vndk.v${VER}
. В зависимости от конфигурации устройства VNDK APEX может быть сжатым или не сжатым и доступен по каноническому пути /apex/com.android.vndk.v${VER}
.
Рисунок 2. ВЕРШИНА VNDK.
Определение модуля
Чтобы собрать Android с BOARD_VNDK_VERSION
, необходимо пересмотреть определение модуля в Android.mk
или Android.bp
. В этом разделе описываются различные виды определений модулей, несколько свойств модулей, связанных с VNDK, и проверки зависимостей, реализованные в системе сборки.
Модули поставщика
Модули поставщика — это исполняемые файлы или общие библиотеки, специфичные для поставщика, которые должны быть установлены в раздел поставщика. В файлах Android.bp
модули поставщика должны устанавливать свойство поставщика или проприетарного свойства в true
. В файлах Android.mk
модули поставщика должны устанавливать LOCAL_VENDOR_MODULE
или LOCAL_PROPRIETARY_MODULE
в true
.
Если определен BOARD_VNDK_VERSION
, система сборки запрещает зависимости между модулями поставщика и модулями фреймворка и выдает ошибки, если:
- модуль без
vendor:true
зависит от модуля сvendor:true
, или - Модуль с
vendor:true
зависит от модуля, отличного отllndk_library
, у которого нет ниvendor:true
, ниvendor_available:true
.
Проверка зависимостей применяется к header_libs
, static_libs
и shared_libs
в Android.bp
, а также к LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
и LOCAL_SHARED_LIBRARIES
в Android.mk
.
LL-NDK
Общие библиотеки LL-NDK — это общие библиотеки со стабильными ABI. Как фреймворк, так и модули поставщика используют одну и ту же и последнюю реализацию. Для каждой общей библиотеки LL-NDK cc_library
содержит свойство llndk
с файлом символов:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
Файл символов описывает символы, видимые модулям поставщика. Например:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
На основе файла символов система сборки генерирует разделяемую библиотеку-заглушку для модулей вендора, которые связываются с этими библиотеками, когда включен BOARD_VNDK_VERSION
. Символ включается в разделяемую библиотеку-заглушку только в том случае, если он:
- Не определено в разделе, заканчивающемся на
_PRIVATE
или_PLATFORM
, - Не имеет тега
#platform-only
и - Не имеет тегов
#introduce*
или тег совпадает с целевым.
ВНДК
В файлах Android.bp
определения модулей cc_library
, cc_library_static
, cc_library_shared
и cc_library_headers
поддерживают три свойства, связанных с VNDK: vendor_available
, vndk.enabled
и vndk.support_system_process
.
Если vendor_available
или vndk.enabled
имеет значение true
, могут быть построены два варианта ( core и vendor ). Основной вариант следует рассматривать как модуль фреймворка, а вариант поставщика следует рассматривать как модуль поставщика. Если некоторые модули фреймворка зависят от этого модуля, строится основной вариант. Если некоторые модули поставщика зависят от этого модуля, строится вариант поставщика. Система сборки применяет следующие проверки зависимостей:
- Основной вариант всегда доступен только фреймворку и недоступен для модулей поставщика.
- Вариант поставщика всегда недоступен для модулей фреймворка.
- Все зависимости варианта поставщика, указанные в
header_libs
,static_libs
и/илиshared_libs
, должны быть либоllndk_library
, либо модулем сvendor_available
илиvndk.enabled
. - Если
vendor_available
имеетtrue
, вариант поставщика доступен всем модулям поставщика. - Если
vendor_available
имеет значениеfalse
, вариант поставщика доступен только для других модулей VNDK или VNDK-SP (т. е. модули сvendor:true
не могут связывать модулиvendor_available:false
).
Путь установки по умолчанию для cc_library
или cc_library_shared
определяется следующими правилами:
- Основной вариант устанавливается в
/system/lib[64]
. - Путь установки варианта поставщика может отличаться:
- Если
vndk.enabled
имеетfalse
, то вариант поставщика устанавливается в/vendor/lib[64]
. - Если
vndk.enabled
имеетtrue
, вариант поставщика устанавливается в VNDK APEX (com.android.vndk.v${VER}
).
- Если
В таблице ниже показано, как система сборки обрабатывает варианты поставщиков:
поставщик_доступен | вндк включено | вндк поддержка_системного_процесса | Описания вариантов поставщиков |
---|---|---|---|
true | false | false | Варианты поставщика — VND-ONLY . Общие библиотеки устанавливаются в /vendor/lib[64] . |
true | Недействительно (Ошибка сборки) | ||
true | false | Варианты поставщика — VNDK . Общие библиотеки устанавливаются в VNDK APEX. | |
true | Варианты поставщика — VNDK-SP . Общие библиотеки устанавливаются в VNDK APEX. | ||
| | | Нет вариантов поставщика. Этот модуль FWK-ONLY . |
true | Недействительно (Ошибка сборки) | ||
true | false | Варианты поставщика — VNDK-Private . Общие библиотеки устанавливаются в VNDK APEX. Они не должны напрямую использоваться модулями поставщика. | |
true | Варианты поставщика — VNDK-SP-Private . Общие библиотеки устанавливаются в VNDK APEX. Они не должны напрямую использоваться модулями поставщика. |
Расширения VNDK
Расширения VNDK — это общие библиотеки VNDK с дополнительными API. Расширения устанавливаются в /vendor/lib[64]/vndk[-sp]
(без суффикса версии) и переопределяют исходные общие библиотеки VNDK во время выполнения.
Определить расширения VNDK
В Android 9 и выше Android.bp
изначально поддерживает расширения VNDK. Чтобы создать расширение VNDK, определите другой модуль со свойством vendor:true
и extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Модуль со свойствами vendor:true
, vndk.enabled:true
и extends
определяет расширение VNDK:
- Свойство
extends
должно указывать базовое имя общей библиотеки VNDK (или имя общей библиотеки VNDK-SP). - Расширения VNDK (или расширения VNDK-SP) называются по именам базовых модулей, от которых они расширяются. Например, выходной двоичный файл
libvndk_ext
—libvndk.so
вместоlibvndk_ext.so
. - Расширения VNDK устанавливаются в
/vendor/lib[64]/vndk
. - Расширения VNDK-SP устанавливаются в
/vendor/lib[64]/vndk-sp
. - Базовые общие библиотеки должны иметь как
vndk.enabled:true
, так иvendor_available:true
.
Расширение VNDK-SP должно расширяться из общей библиотеки VNDK-SP ( vndk.support_system_process
должен быть равен):
cc_library { name: "libvndk_sp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } cc_library { name: "libvndk_sp_ext", vendor: true, vndk: { enabled: true, extends: "libvndk_sp", support_system_process: true, }, }
Расширения VNDK (или расширения VNDK-SP) могут зависеть от других общих библиотек поставщиков:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, shared_libs: [ "libvendor", ], } cc_library { name: "libvendor", vendor: true, }
Используйте расширения VNDK
Если модуль поставщика зависит от дополнительных API, определенных расширениями VNDK, модуль должен указать имя расширения VNDK в своем свойстве shared_libs
:
// A vendor shared library example cc_library { name: "libvendor", vendor: true, shared_libs: [ "libvndk_ext", ], } // A vendor executable example cc_binary { name: "vendor-example", vendor: true, shared_libs: [ "libvndk_ext", ], }
Если модуль поставщика зависит от расширений VNDK, эти расширения VNDK устанавливаются в /vendor/lib[64]/vndk[-sp]
автоматически. Если модуль больше не зависит от расширения VNDK, добавьте шаг очистки в CleanSpec.mk
для удаления общей библиотеки. Например:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Условная компиляция
В этом разделе описывается, как справляться с тонкими различиями (например, добавление или удаление функции из одного из вариантов) между следующими тремя общими библиотеками VNDK:
- Основной вариант (например,
/system/lib[64]/libexample.so
) - Вариант поставщика (например,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Расширение VNDK (например,
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Флаги условного компилятора
Система сборки Android определяет __ANDROID_VNDK__
для вариантов поставщиков и расширений VNDK по умолчанию. Вы можете защитить код с помощью препроцессорных защит C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
В дополнение к __ANDROID_VNDK__
, в Android.bp
могут быть указаны различные cflags
или cppflags
. cflags
или cppflags
указанные в target.vendor
специфичны для варианта поставщика.
Например, следующий Android.bp
определяет libexample
и libexample_ext
:
cc_library { name: "libexample", srcs: ["src/example.c"], vendor_available: true, vndk: { enabled: true, }, target: { vendor: { cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"], }, }, } cc_library { name: "libexample_ext", srcs: ["src/example.c"], vendor: true, vndk: { enabled: true, extends: "libexample", }, cflags: [ "-DLIBEXAMPLE_ENABLE_VNDK=1", "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1", ], }
А это листинг кода src/example.c
:
void all() { } #if !defined(LIBEXAMPLE_ENABLE_VNDK) void framework_only() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK) void vndk() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK_EXT) void vndk_ext() { } #endif
Согласно этим двум файлам, система сборки генерирует общие библиотеки со следующими экспортированными символами:
Путь установки | Экспортированные символы |
---|---|
/system/lib[64]/libexample.so | all , framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so | all , vndk |
/vendor/lib[64]/vndk/libexample.so | all , vndk , vndk_ext |
Требования к экспортируемым символам
Средство проверки ABI VNDK сравнивает ABI вариантов поставщиков VNDK и расширений VNDK с эталонными дампами ABI в prebuilts/abi-dumps/vndk
.
- Символы, экспортируемые вариантами поставщиков VNDK (например,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
), должны быть идентичны символам, определенным в дампах ABI (а не являться их надмножествами). - Символы, экспортируемые расширениями VNDK (например,
/vendor/lib[64]/vndk/libexample.so
), должны быть надмножествами символов, определенных в дампах ABI.
Если варианты поставщика VNDK или расширения VNDK не соответствуют вышеуказанным требованиям, средство проверки ABI VNDK выдает ошибки сборки и останавливает сборку.
Исключить исходные файлы или общие библиотеки из вариантов поставщика
Чтобы исключить исходные файлы из варианта поставщика, добавьте их в свойство exclude_srcs
. Аналогично, чтобы гарантировать, что общие библиотеки не связаны с вариантом поставщика, добавьте эти библиотеки в свойство exclude_shared_libs
. Например:
cc_library { name: "libexample_cond_exclude", srcs: ["fwk.c", "both.c"], shared_libs: ["libfwk_only", "libboth"], vendor_available: true, target: { vendor: { exclude_srcs: ["fwk.c"], exclude_shared_libs: ["libfwk_only"], }, }, }
В этом примере основной вариант libexample_cond_exclude
включает код из fwk.c
и both.c
и зависит от общих библиотек libfwk_only
и libboth
. Вариант поставщика libexample_cond_exclude
включает только код из both.c
, поскольку fwk.c
исключен свойством exclude_srcs
. Аналогично, он зависит только от общей библиотеки libboth
поскольку libfwk_only
исключена свойством exclude_shared_libs
.
Экспорт заголовков из расширений VNDK
Расширение VNDK может добавлять новые классы или новые функции в общую библиотеку VNDK. Рекомендуется хранить эти объявления в независимых заголовках и избегать изменения существующих заголовков.
Например, для расширения VNDK libexample_ext
создается новый заголовочный файл include-ext/example/ext/feature_name.h
:
- Android.bp
- include-ext/example/ext/имя_функции.h
- включить/пример/пример.h
- src/example.c
- src/ext/имя_функции.c
В следующем Android.bp
libexample
экспортирует только include
, тогда как libexample_ext
экспортирует и include
и include-ext
. Это гарантирует, что feature_name.h
не будет неправильно включен пользователями libexample
:
cc_library { name: "libexample", srcs: ["src/example.c"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample_ext", srcs: [ "src/example.c", "src/ext/feature_name.c", ], export_include_dirs: [ "include", "include-ext", ], vendor: true, vndk: { enabled: true, extends: "libexample", }, }
Если разделение расширений на независимые файлы заголовков невозможно, альтернативой является добавление защитных схем #ifdef
. Однако убедитесь, что все пользователи расширений VNDK добавляют флаги определения. Вы можете определить cc_defaults
для добавления флагов определения в cflags
и связывания общих библиотек с shared_libs
.
Например, чтобы добавить новую функцию-член Example2::get_b()
в расширение VNDK libexample2_ext
, необходимо изменить существующий заголовочный файл и добавить защиту #ifdef
:
#ifndef LIBEXAMPLE2_EXAMPLE_H_ #define LIBEXAMPLE2_EXAMPLE_H_ class Example2 { public: Example2(); void get_a(); #ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT void get_b(); #endif private: void *impl_; }; #endif // LIBEXAMPLE2_EXAMPLE_H_
Для пользователей libexample2_ext
определен cc_defaults
с именем libexample2_ext_defaults
:
cc_library { name: "libexample2", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample2_ext", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor: true, vndk: { enabled: true, extends: "libexample2", }, cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], } cc_defaults { name: "libexample2_ext_defaults", shared_libs: [ "libexample2_ext", ], cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], }
Пользователи libexample2_ext
могут просто включить libexample2_ext_defaults
в свое свойство defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Пакеты продуктов
В системе сборки Android переменная PRODUCT_PACKAGES
указывает исполняемые файлы, общие библиотеки или пакеты, которые должны быть установлены на устройство. Транзитивные зависимости указанных модулей также неявно устанавливаются на устройство.
Если BOARD_VNDK_VERSION
включен, модули с vendor_available
или vndk.enabled
получают специальную обработку. Если модуль фреймворка зависит от модуля с vendor_available
или vndk.enabled
, вариант ядра включается в транзитивный набор установки. Если модуль поставщика зависит от модуля с vendor_available
, вариант поставщика включается в транзитивный набор установки. Однако варианты поставщика модулей с vndk.enabled
устанавливаются независимо от того, используются ли они модулями поставщика.
Если зависимости невидимы для системы сборки (например, общие библиотеки, которые можно открыть с помощью dlopen()
во время выполнения), необходимо указать имена модулей в PRODUCT_PACKAGES
, чтобы явно установить эти модули.
Если модуль имеет vendor_available
или vndk.enabled
, имя модуля соответствует его основному варианту. Чтобы явно указать вариант поставщика в PRODUCT_PACKAGES
, добавьте суффикс .vendor
к имени модуля. Например:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
В этом примере libexample
означает /system/lib[64]/libexample.so
, а libexample.vendor
означает /vendor/lib[64]/libexample.so
. Чтобы установить /vendor/lib[64]/libexample.so
, добавьте libexample.vendor
в PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor