В 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