В 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