W Androidzie 8.1 i nowszych system kompilacji ma wbudowane wsparcie dla VNDK. Gdy włączysz obsługę VNDK, system kompilacji sprawdza zależności między modułami, tworzy wersję dla dostawcy dla modułów dostawcy i automatycznie instaluje te moduły w wyznaczonych katalogach.
Przykład obsługi kompilacji VNDK
W tym przykładzie definicja modułu Android.bp
definiuje bibliotekę o nazwie libexample
. Właściwość vendor_available
wskazuje, że moduły frameworku i moduły dostawcy mogą zależeć od:libexample
:
Rysunek 1. Obsługa włączona.
Zarówno plik wykonywalny platformy /system/bin/foo
, jak i plik wykonywalny dostawcy /vendor/bin/bar
zależą od libexample
i mają w swoich właściwościach shared_libs
wartość libexample
.
Jeśli libexample
jest używany zarówno przez moduły frameworku, jak i moduły dostawcy, tworzone są 2 warianty libexample
. Wersja podstawowa (o nazwie libexample
) jest używana przez moduły platformy, a wersja dostawcy (o nazwie libexample.vendor
) jest używana przez moduły dostawcy. Oba warianty są instalowane w różnych katalogach:
- Wersja podstawowa jest instalowana w
/system/lib[64]/libexample.so
. - Wariant dostawcy jest instalowany w VNDK APEX, ponieważ
vndk.enabled
ma wartośćtrue
.
Więcej informacji znajdziesz w artykule Definicja modułu.
Konfigurowanie obsługi kompilacji
Aby włączyć pełną obsługę systemu kompilacji dla urządzenia, dodaj BOARD_VNDK_VERSION
do BoardConfig.mk
:
BOARD_VNDK_VERSION := current
To ustawienie ma globalny wpływ: gdy jest zdefiniowane w BoardConfig.mk
, sprawdzane są wszystkie moduły. Nie ma mechanizmu, który pozwalałby umieścić dany moduł na czarnej lub białej liście. Przed dodaniem BOARD_VNDK_VERSION
musisz usunąć wszystkie niepotrzebne zależności. Aby przetestować i skompilować moduł, ustaw BOARD_VNDK_VERSION
w swoich zmiennych środowiskowych:
$ BOARD_VNDK_VERSION=current m module_name.vendor
Gdy opcja BOARD_VNDK_VERSION
jest włączona, kilka domyślnych globalnych ścieżek wyszukiwania nagłówka zostaje usuniętych. Należą do nich:
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
Jeśli moduł zależy od nagłówków z tych katalogów, musisz wyraźnie określić zależności za pomocą atrybutów header_libs
, static_libs
lub shared_libs
.
VNDK APEX
W Androidzie 10 i starszych moduły z vndk.enabled
były instalowane w ramach /system/lib[64]/vndk[-sp]-${VER}
. W Androidzie 11 i nowszych biblioteki VNDK są pakowane w formacie APEX, a nazwa VNDK APEX to com.android.vndk.v${VER}
. W zależności od konfiguracji urządzenia biblioteka VNDK APEX jest spłaszczona lub niespłaszczona i jest dostępna pod ścieżką kanoniczną /apex/com.android.vndk.v${VER}
.
Rysunek 2. VNDK APEX.
Definicja modułu
Aby skompilować Androida z BOARD_VNDK_VERSION
, musisz zmienić definicję modułu w pliku Android.mk
lub Android.bp
. W tej sekcji opisujemy różne rodzaje definicji modułów, kilka właściwości modułów związanych z VNDK oraz mechanizmy sprawdzania zależności zaimplementowane w systemie kompilacji.
Moduły dostawców
Moduł dostawcy to plik wykonywalny lub biblioteka wspólna, które muszą zostać zainstalowane w partycji dostawcy. W plikach Android.bp
moduły dostawcy muszą ustawić własność dostawcy lub własność zastrzeżoną na wartość true
.
W plikach Android.mk
moduły dostawcy muszą mieć ustawioną wartość LOCAL_VENDOR_MODULE
lub LOCAL_PROPRIETARY_MODULE
na true
.
Jeśli parametr BOARD_VNDK_VERSION
jest zdefiniowany, system kompilacji nie zezwala na zależności między modułami dostawcy a modułami frameworku i wypisuje błędy, jeśli:
- moduł bez
vendor:true
zależy od modułu zvendor:true
, - moduł z wartością
vendor:true
jest zależny od modułu, który nie jest modułemllndk_library
i nie zawiera ani wartościvendor:true
, anivendor_available:true
;
Sprawdzanie zależności dotyczy header_libs
, static_libs
i shared_libs
w Android.bp
oraz LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
i LOCAL_SHARED_LIBRARIES
w Android.mk
.
LL-NDK
Biblioteki udostępnione LL-NDK to biblioteki udostępnione ze stabilnymi ABI. Oba moduły frameworku i moduły dostawców korzystają z tego samego najnowszego wdrożenia. W przypadku każdej biblioteki współdzielonej LL-NDK element cc_library
zawiera właściwość llndk
z plikiem symboli:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
Plik symboli zawiera opis symboli widocznych dla modułów dostawców. Przykład:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
Na podstawie pliku symboli system kompilacji generuje bibliotekę wspólną typu stub dla modułów dostawców, które są z nimi powiązane, gdy włączona jest opcja BOARD_VNDK_VERSION
. Symbol jest uwzględniany w bibliotece wspólnej tylko wtedy, gdy:
- nie jest zdefiniowany w sekcji kończącej się na
_PRIVATE
lub_PLATFORM
, - Nie zawiera tagu
#platform-only
i - Nie zawiera tagów
#introduce*
lub tag jest zgodny z docelowym.
VNDK
Definicje modułów Android.bp
, cc_library
, cc_library_static
, cc_library_shared
i cc_library_headers
obsługują 3 właściwości związane z VNDK: vendor_available
, vndk.enabled
i vndk.support_system_process
.
Jeśli vendor_available
lub vndk.enabled
jest true
, można utworzyć 2 warianty (core i vendor). Wariant podstawowy należy traktować jako moduł frameworku, a wariant dostawcy jako moduł dostawcy. Jeśli niektóre moduły platformy zależą od tego modułu, budowany jest wariant podstawowy. Jeśli niektóre moduły dostawcy zależą od tego modułu, wariant dostawcy jest tworzony. System kompilacji wymusza te kontrole zależności:
- Wersja podstawowa jest zawsze dostępna tylko w ramach frameworka i nie jest dostępna dla modułów dostawców.
- Wersja dostawcy jest zawsze niedostępna dla modułów platformy.
- Wszystkie zależności wariantu dostawcy, które są określone w
header_libs
,static_libs
lubshared_libs
, muszą być albo modułemllndk_library
, albo modułemvendor_available
lubvndk.enabled
. - Jeśli
vendor_available
totrue
, wersja dostawcy jest dostępna dla wszystkich modułów dostawcy. - Jeśli
vendor_available
ma wartośćfalse
, wariant dostawcy jest dostępny tylko dla innych modułów VNDK lub VNDK-SP (czyli moduły zvendor:true
nie mogą łączyć modułówvendor_available:false
).
Domyślna ścieżka instalacji dla cc_library
lub cc_library_shared
jest określana według tych reguł:
- Wersja podstawowa jest zainstalowana w wersji
/system/lib[64]
. - Ścieżka instalacji wariantu dostawcy może się różnić:
- Jeśli
vndk.enabled
ma wartośćfalse
, wariant dostawcy jest instalowany w/vendor/lib[64]
. - Jeśli
vndk.enabled
totrue
, wariant dostawcy jest instalowany w VNDK APEX(com.android.vndk.v${VER}
).
- Jeśli
W tabeli poniżej znajdziesz podsumowanie sposobu obsługiwania przez system kompilacji wariantów dostawcy:
vendor_available | vndk enabled |
vndk support_same_process |
Opisy wariantów dostawcy |
---|---|---|---|
true |
false |
false |
Wersje dostawcy są TYLKO VND. Biblioteki udostępnione są instalowane w /vendor/lib[64] . |
true |
Nieprawidłowa (błąd kompilacji) | ||
true |
false |
Wersje dostawcy to VNDK. Biblioteki udostępnione są instalowane w VNDK APEX. | |
true |
Wersje dostawcy to VNDK-SP. Biblioteki współdzielone są instalowane w VNDK APEX. | ||
|
|
|
Brak wersji dostawcy. Ten moduł jest przeznaczony TYLKO DO UŻYTKU Z FRAMTEWEM. |
true |
Nieprawidłowa (błąd kompilacji) | ||
true |
false |
Wersje dostawcy to VNDK-Private. Biblioteki udostępnione są instalowane w VNDK APEX. Nie mogą być one używane bezpośrednio przez moduły dostawców. | |
true |
Wersje dostawcy to VNDK-SP-Private. Biblioteki udostępnione są instalowane w VNDK APEX. Nie mogą być one używane bezpośrednio przez moduły dostawców. |
Rozszerzenia VNDK
Rozszerzenia VNDK to biblioteki udostępnione VNDK z dodatkowymi interfejsami API. Rozszerzenia są instalowane w katalogu /vendor/lib[64]/vndk[-sp]
(bez przyrostka wersji) i zastępują oryginalne biblioteki wspólne VNDK w czasie wykonywania.
Definiowanie rozszerzeń VNDK
Na Androidzie 9 i nowszych wersjach Android.bp
obsługuje natywnie rozszerzenia VNDK. Aby skompilować rozszerzenie VNDK, zdefiniuj kolejny moduł z właściwością vendor:true
i extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Moduł z właściwościami vendor:true
, vndk.enabled:true
i extends
definiuje rozszerzenie VNDK:
- Właściwość
extends
musi określać nazwę podstawowej biblioteki współdzielonej VNDK (lub nazwę biblioteki współdzielonej VNDK-SP). - Rozszerzenia VNDK (lub rozszerzenia VNDK-SP) są nazywane według nazwy modułu podstawowego, z którego korzystają. Na przykład kod binarny wyjściowy funkcji
libvndk_ext
tolibvndk.so
, a nielibvndk_ext.so
. - Rozszerzenia VNDK są instalowane w
/vendor/lib[64]/vndk
. - Rozszerzenia VNDK-SP są instalowane w
/vendor/lib[64]/vndk-sp
. - Podstawowe biblioteki współdzielone muszą zawierać zarówno
vndk.enabled:true
, jak ivendor_available:true
.
Rozszerzenie VNDK-SP musi być rozszerzeniem biblioteki współdzielonej VNDK-SP (vndk.support_system_process
musi być równe):
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, }, }
Rozszerzenia VNDK (lub rozszerzenia VNDK-SP) mogą zależeć od innych bibliotek współdzielonych dostawców:
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, }
Używanie rozszerzeń VNDK
Jeśli moduł dostawcy zależy od dodatkowych interfejsów API zdefiniowanych przez rozszerzenia VNDK, musi on określić nazwę rozszerzenia VNDK w swojej właściwości 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", ], }
Jeśli moduł dostawcy zależy od rozszerzeń VNDK, są one automatycznie instalowane na /vendor/lib[64]/vndk[-sp]
. Jeśli moduł
nie zależy już od rozszerzenia VNDK, dodaj krok czyszczenia do
CleanSpec.mk
, aby usunąć bibliotekę współdzieloną. Przykład:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Kompilacja warunkowa
Z tej sekcji dowiesz się, jak poradzić sobie z subtelnymi różnicami (np. dodawanie lub usuwanie funkcji z jednego z wariantów) między tymi 3 bibliotekami udostępnionymi VNDK:
- Wariant podstawowy (np.
/system/lib[64]/libexample.so
) - Wariant dostawcy (np.
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Rozszerzenie VNDK (np.
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Warunkowe flagi kompilatora
System kompilacji Androida domyślnie definiuje __ANDROID_VNDK__
dla wersji dostawcy i rozszerzeń VNDK. Kod możesz chronić za pomocą zabezpieczeń preprocesora C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
Oprócz __ANDROID_VNDK__
w parametrie Android.bp
można podać inną wartość cflags
lub cppflags
. Wartość cflags
lub cppflags
podana w target.vendor
jest specyficzna dla wersji dostawcy.
Na przykład ta definicja Android.bp
określa libexample
i 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", ], }
A tak wygląda kod pliku 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
Na podstawie tych 2 plików system kompilacji generuje biblioteki współdzielone z tymi wyeksportowanymi symbolami:
Ścieżka instalacji | Wyeksportowane symbole |
---|---|
/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 |
Wymagania dotyczące eksportowanych symboli
Sprawdzanie ABI VNDK
porównuje ABI wariantów dostawcy VNDK i rozszerzeń VNDK z pobranymi referencyjnymi zrzutami ABI w prebuilts/abi-dumps/vndk
.
- Symbole wyeksportowane przez warianty dostawcy VNDK (np.
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) muszą być identyczne z definiowanymi w zbiorach danych ABI (nie mogą być superzbiorami). - Symbole eksportowane przez rozszerzenia VNDK (np.
/vendor/lib[64]/vndk/libexample.so
) muszą być superzbiorami symboli zdefiniowanych w zrzutach ABI.
Jeśli warianty dostawcy VNDK lub rozszerzenia VNDK nie spełniają powyższych wymagań, sprawdzacz ABI VNDK wygeneruje błędy kompilacji i zatrzyma kompilację.
Wykluczanie plików źródłowych lub współdzielonych bibliotek z wariantów dostawcy
Aby wykluczyć pliki źródłowe z wariantu dostawcy, dodaj je do właściwości exclude_srcs
. Aby mieć pewność, że biblioteki współdzielone nie są powiązane z wariantem dostawcy, dodaj je do zasobu exclude_shared_libs
. Przykład:
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"], }, }, }
W tym przykładzie wariant podstawowy libexample_cond_exclude
zawiera kod z fwk.c
i both.c
oraz zależy od wspólnych bibliotek libfwk_only
i libboth
. Wersja dostawcy atrybutu libexample_cond_exclude
zawiera tylko kod z atrybutu both.c
, ponieważ atrybut fwk.c
jest wykluczony przez usługę exclude_srcs
. Podobnie zależy tylko od biblioteki udostępnionej libboth
, ponieważ libfwk_only
jest wykluczone przez właściwość exclude_shared_libs
.
Eksportowanie nagłówków z rozszerzeń VNDK
Rozszerzenie VNDK może dodać nowe klasy lub nowe funkcje do wspólnej biblioteki VNDK. Zalecamy umieszczanie tych deklaracji w niezależnych nagłówkach i niezmienianie dotychczasowych nagłówków.
Na przykład dla rozszerzenia VNDKlibexample_ext
zostanie utworzony nowy plik nagłówkainclude-ext/example/ext/feature_name.h
:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/nazwa_funkcji.c
W tym przykładzie Android.bp
, libexample
eksportuje tylko include
, a libexample_ext
eksportuje zarówno include
, jak i include-ext
. Dzięki temu użytkownicy libexample
nie będą nieprawidłowo uwzględniać feature_name.h
:
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", }, }
Jeśli rozdzielenie rozszerzeń do niezależnych plików nagłówków nie jest możliwe, alternatywą jest dodanie #ifdef
guardów. Upewnij się jednak, że wszyscy użytkownicy rozszerzenia VNDK dodają flagi definicji. Możesz zdefiniować cc_defaults
, aby dodać flagi do cflags
, oraz połączyć biblioteki udostępnione z shared_libs
.
Aby na przykład dodać do rozszerzenia VNDK libexample2_ext
nową funkcję członkowską Example2::get_b()
, musisz zmodyfikować istniejący plik nagłówka oraz dodać blokadę #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_
Dla użytkowników libexample2_ext
zdefiniowano cc_defaults
o nazwie 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", ], }
Użytkownicy usługi libexample2_ext
mogą po prostu umieścić wartość libexample2_ext_defaults
w właściwości defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Pakiety produktów
W systemie kompilacji Androida zmienna PRODUCT_PACKAGES
określa pliki wykonywalne, biblioteki współdzielone lub pakiety, które należy zainstalować na urządzeniu. Na urządzeniu są też domyślnie instalowane zależności pośrednie określonych modułów.
Jeśli opcja BOARD_VNDK_VERSION
jest włączona, moduły z wartością vendor_available
lub vndk.enabled
są traktowane w szczególny sposób. Jeśli moduł frameworku zależy od modułu z vendor_available
lub vndk.enabled
, wariant podstawowy jest uwzględniony w zestawie instalacji przejściowej. Jeśli moduł dostawcy
zależy od modułu z vendor_available
, wariant dostawcy jest
uwzględniony w transytywnym zestawie instalacji. Jednak warianty modułów dostawcy z vndk.enabled
są instalowane niezależnie od tego, czy są używane przez moduły dostawcy.
Jeśli zależności są niewidoczne dla systemu kompilacji (np. biblioteki współdzielone, które można otworzyć za pomocą dlopen()
w czasie wykonywania), należy podać nazwy modułów w PRODUCT_PACKAGES
, aby zainstalować te moduły w wyraźny sposób.
Jeśli moduł ma vendor_available
lub vndk.enabled
, nazwa modułu oznacza jego wariant podstawowy. Aby wyraźnie określić wariant dostawcy w elementach PRODUCT_PACKAGES
, dodaj sufiks .vendor
do nazwy modułu. Przykład:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
W tym przykładzie libexample
oznacza /system/lib[64]/libexample.so
, a libexample.vendor
– /vendor/lib[64]/libexample.so
. Aby zainstalować
/vendor/lib[64]/libexample.so
, dodaj libexample.vendor
do PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor