В Android 8.1 и выше система сборки имеет встроенную поддержку VNDK. Когда поддержка VNDK включена, система сборки проверяет зависимости между модулями, создает вариант для конкретных поставщиков для модулей поставщиков и автоматически устанавливает эти модули в назначенные каталоги.
Пример поддержки сборки VNDK
В этом примере определение модуля Android.bp
определяет библиотеку с именем libexample
. Свойство vendor_available
указывает, что модули фреймворка и модули вендора могут зависеть от libexample
:
И исполняемый файл фреймворка /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}
.
Определение модуля
Чтобы собрать 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 — это общие библиотеки со стабильными ABI. Модули платформы и поставщика используют одну и ту же самую последнюю реализацию. Для каждой общей библиотеки LL-NDK файл Android.bp
содержит определение модуля llndk_library
:
llndk_library { name: "libvndksupport", 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
, могут быть собраны два варианта ( ядро и поставщик ). Базовый вариант следует рассматривать как модуль платформы, а вариант поставщика — как модуль поставщика. Если от этого модуля зависят какие-то модули фреймворка, строится базовый вариант. Если от этого модуля зависят какие-либо модули вендора, будет построен вариант вендора. Система сборки применяет следующие проверки зависимостей:
- Основной вариант всегда предназначен только для фреймворка и недоступен для модулей поставщиков.
- Вариант поставщика всегда недоступен для модулей фреймворка.
- Все зависимости варианта поставщика, указанные в
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}
).
- Если
В таблице ниже показано, как система сборки обрабатывает варианты поставщиков:
продавец_доступен | вндк включено | вндк support_same_process | Описание вариантов поставщиков |
---|---|---|---|
true | false | false | Варианты поставщика ТОЛЬКО VND . Общие библиотеки устанавливаются в /vendor/lib[64] . |
true | Недействительно (ошибка сборки) | ||
true | false | Варианты поставщиков: VNDK . Общие библиотеки устанавливаются на VNDK APEX. | |
true | Варианты производителя: VNDK-SP . Общие библиотеки устанавливаются на VNDK APEX. | ||
| | | Вариантов поставщиков нет. Этот модуль предназначен только для FWK . |
true | Недействительно (ошибка сборки) | ||
true | false | Варианты поставщика — VNDK-Private . Общие библиотеки устанавливаются на VNDK APEX. Они не должны напрямую использоваться модулями поставщика. | |
true | Варианты поставщиков: VNDK-SP-Private . Общие библиотеки устанавливаются на VNDK APEX. Они не должны напрямую использоваться модулями поставщика. |
Расширения ВНДК
Расширения 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 |
Требования к экспортируемым символам
Средство проверки VNDK ABI сравнивает 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 не соответствуют приведенным выше требованиям, средство проверки VNDK ABI выдает ошибки сборки и останавливает сборку.
Исключение исходных файлов или общих библиотек из вариантов поставщиков
Чтобы исключить исходные файлы из варианта поставщика, добавьте их в свойство 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. Рекомендуется хранить эти объявления в независимых заголовках и избегать изменения существующих заголовков.
Например, для расширения libexample_ext
создается новый заголовочный файл include-ext/example/ext/feature_name.h
:
- Android.bp
- include-ext/example/ext/feature_name.h
- включить/пример/example.h
- источник/example.c
- src/ext/feature_name.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()
в расширение 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_
cc_defaults
именем libexample2_ext_defaults
определен для пользователей libexample2_ext
:
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