Wsparcie systemu budowania VNDK

W systemie Android 8.1 i nowszych wersjach system kompilacji ma wbudowaną obsługę VNDK. Gdy obsługa VNDK jest włączona, system kompilacji sprawdza zależności między modułami, tworzy warianty modułów dostawcy specyficzne dla dostawcy i automatycznie instaluje te moduły w wyznaczonych katalogach.

Przykład wsparcia 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 frameworka i moduły dostawcy mogą zależeć od libexample :

libexample sprzedawca_dostępny:true i vndk.enabled:true

Rysunek 1. Włączona obsługa VNDK

Zarówno plik wykonywalny frameworka /system/bin/foo jak i plik wykonywalny dostawcy /vendor/bin/bar zależą od libexample i mają libexample we shared_libs .

Jeśli libexample jest używane zarówno przez moduły frameworka, jak i moduły dostawcy, tworzone są dwa warianty libexample . Wariant podstawowy (nazwany na cześć libexample ) jest używany przez moduły frameworka, a wariant dostawcy (nazwany na cześć libexample.vendor ) jest używany przez moduły dostawcy. Obydwa warianty są instalowane w różnych katalogach:

  • Wariant podstawowy jest instalowany w /system/lib[64]/libexample.so .
  • Wariant dostawcy jest zainstalowany w VNDK APEX, ponieważ vndk.enabled ma true .

Aby uzyskać więcej informacji, zobacz Definicja modułu .

Konfigurowanie obsługi kompilacji

Aby włączyć pełną obsługę systemu kompilacji dla urządzenia produktu, dodaj BOARD_VNDK_VERSION do BoardConfig.mk :

BOARD_VNDK_VERSION := current

To ustawienie ma efekt globalny : jeśli jest zdefiniowane w BoardConfig.mk , sprawdzane są wszystkie moduły. Ponieważ nie ma mechanizmu umieszczania na czarnej lub białej liście modułu naruszającego zasady, przed dodaniem BOARD_VNDK_VERSION należy wyczyścić wszystkie niepotrzebne zależności. Możesz przetestować i skompilować moduł, ustawiając BOARD_VNDK_VERSION w zmiennych środowiskowych:

$ BOARD_VNDK_VERSION=current m module_name.vendor

Gdy włączona jest BOARD_VNDK_VERSION , kilka domyślnych globalnych ścieżek wyszukiwania nagłówków jest usuwanych . Obejmują one:

  • 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 określić (jawnie) zależności za pomocą header_libs , static_libs i/ shared_libs .

VNDK wierzchołek

W Androidzie 10 i niższych moduły z vndk.enabled zostały zainstalowane w /system/lib[64]/vndk[-sp]-${VER} . W systemie Android 11 i nowszych bibliotekach VNDK są spakowane w formacie APEX, a nazwa VNDK APEX to com.android.vndk.v${VER} . W zależności od konfiguracji urządzenia VNDK APEX jest spłaszczony lub niespłaszczony i jest dostępny ze ścieżki kanonicznej /apex/com.android.vndk.v${VER} .

VNDK wierzchołek

Rysunek 2. Wierzchołek VNDK

Definicja modułu

Aby zbudować Androida z BOARD_VNDK_VERSION , musisz zmienić definicję modułu w Android.mk lub Android.bp . W tej sekcji opisano różne rodzaje definicji modułów, kilka właściwości modułów związanych z VNDK i sprawdzanie zależności zaimplementowane w systemie kompilacji.

Moduły dostawcy

Moduły dostawcy to specyficzne dla dostawcy pliki wykonywalne lub współdzielone biblioteki, które należy zainstalować na partycji dostawcy. W plikach Android.bp moduły dostawcy muszą ustawić właściwość dostawcy lub zastrzeżoną na true . W plikach Android.mk moduły dostawcy muszą mieć ustawioną LOCAL_VENDOR_MODULE lub LOCAL_PROPRIETARY_MODULE na true .

Jeśli zdefiniowano BOARD_VNDK_VERSION , system kompilacji nie zezwala na zależności między modułami dostawcy a modułami platformy i emituje błędy, jeśli:

  • moduł bez vendor:true zależy od modułu z vendor:true lub
  • moduł z vendor:true zależy od modułu innego niż llndk_library , który nie ma ani vendor:true , ani vendor_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 współdzielone LL-NDK to biblioteki współdzielone ze stabilnymi ABI. Zarówno moduły platformy, jak i dostawcy mają tę samą i najnowszą implementację. Dla każdej biblioteki współdzielonej LL-NDK, cc_library zawiera właściwość llndk z plikiem symboli:

cc_library {
    name: "libvndksupport",
    llndk: {
        symbol_file: "libvndksupport.map.txt",
    },
}

Plik symboli opisuje symbole widoczne dla modułów dostawcy. Na przykład:

LIBVNDKSUPPORT {
  global:
    android_load_sphal_library; # llndk
    android_unload_sphal_library; # llndk
  local:
    *;
};

Na podstawie pliku symboli system kompilacji generuje bibliotekę współdzieloną pośredniczącą dla modułów dostawcy, która łączy się z tymi bibliotekami, gdy włączona jest wersja BOARD_VNDK_VERSION . Symbol jest dołączany do biblioteki współdzielonej pośredniczącej tylko wtedy, gdy:

  • Nie jest zdefiniowany na końcu sekcji za pomocą _PRIVATE lub _PLATFORM ,
  • Nie ma tagu #platform-only i
  • Nie zawiera tagów #introduce* lub tag pasuje do celu.

VNDK

W plikach Android.bp definicje modułów cc_library , cc_library_static , cc_library_shared i cc_library_headers obsługują trzy właściwości związane z VNDK: vendor_available , vndk.enabled i vndk.support_system_process .

Jeśli vendor_available lub vndk.enabled ma true , można zbudować dwa warianty ( rdzeniowy i dostawcy ). Wariant podstawowy należy traktować jako moduł platformy, a wariant dostawcy należy traktować jako moduł dostawcy. Jeśli niektóre moduły frameworku zależą od tego modułu, budowany jest wariant podstawowy. Jeśli niektóre moduły dostawcy zależą od tego modułu, tworzony jest wariant dostawcy. System kompilacji wymusza następujące kontrole zależności:

  • Wariant podstawowy jest zawsze dostępny tylko dla frameworka i niedostępny dla modułów dostawców.
  • Wariant dostawcy jest zawsze niedostępny dla modułów frameworku.
  • Wszystkie zależności wariantu dostawcy, które są określone w header_libs , static_libs i/lub shared_libs , muszą być albo llndk_library , albo modułem z vendor_available lub vndk.enabled .
  • Jeśli vendor_available ma wartość true , wariant dostawcy jest dostępny 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 (tj. moduły z vendor:true nie mogą łączyć modułów vendor_available:false ).

Domyślna ścieżka instalacji cc_library lub cc_library_shared jest określona przez następujące zasady:

  • Wariant podstawowy jest instalowany w /system/lib[64] .
  • Ścieżka instalacji wariantu dostawcy może się różnić:
    • Jeśli vndk.enabled ma false , wariant dostawcy jest instalowany w /vendor/lib[64] .
    • Jeśli vndk.enabled ma true , wariant dostawcy jest instalowany w VNDK APEX ( com.android.vndk.v${VER} ).

Poniższa tabela podsumowuje, jak system kompilacji obsługuje warianty dostawców:

dostawca_dostępny vndk
włączony
vndk
support_sam_process
Opisy wariantów dostawcy
true false false Warianty dostawców obejmują TYLKO VND . Biblioteki współdzielone są instalowane w /vendor/lib[64] .
true Nieprawidłowy (błąd kompilacji)
true false Warianty dostawcy to VNDK . Biblioteki współdzielone są instalowane w VNDK APEX.
true Warianty dostawcy to VNDK-SP . Biblioteki współdzielone są instalowane w VNDK APEX.

false

false

false

Brak wariantów dostawców. Ten moduł jest przeznaczony TYLKO dla FWK .

true Nieprawidłowy (błąd kompilacji)
true false Warianty dostawcy to VNDK-Private . Biblioteki współdzielone są instalowane w VNDK APEX. Nie mogą one być bezpośrednio używane przez moduły dostawcy.
true Warianty dostawców to VNDK-SP-Private . Biblioteki współdzielone są instalowane w VNDK APEX. Nie mogą one być bezpośrednio używane przez moduły dostawcy.

Rozszerzenia VNDK

Rozszerzenia VNDK to biblioteki współdzielone VNDK z dodatkowymi interfejsami API. Rozszerzenia są instalowane w /vendor/lib[64]/vndk[-sp] (bez przyrostka wersji) i zastępują oryginalne biblioteki współdzielone VNDK w czasie wykonywania.

Definiowanie rozszerzeń VNDK

W systemie Android 9 i nowszych wersjach Android.bp natywnie obsługuje rozszerzenia VNDK. Aby zbudować rozszerzenie VNDK, zdefiniuj inny 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 vendor:true , vndk.enabled:true i extends definiuje rozszerzenie VNDK:

  • Właściwość extends musi określać podstawową nazwę biblioteki współdzielonej VNDK (lub nazwę biblioteki współdzielonej VNDK-SP).
  • Nazwy rozszerzeń VNDK (lub rozszerzeń VNDK-SP) pochodzą od nazw modułów podstawowych, z których się rozszerzają. Na przykład wyjściowy plik binarny libvndk_ext to libvndk.so zamiast libvndk_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ą mieć zarówno vndk.enabled:true jak i vendor_available:true .

Rozszerzenie VNDK-SP musi rozciągać się z biblioteki współdzielonej VNDK-SP ( vndk.support_system_process musi być równy):

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 bibliotek współdzielonych innych 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,
}

Korzystanie z rozszerzeń VNDK

Jeśli moduł dostawcy zależy od dodatkowych interfejsów API zdefiniowanych przez rozszerzenia VNDK, moduł musi określić nazwę rozszerzenia VNDK w swojej 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, te rozszerzenia VNDK są instalowane automatycznie w /vendor/lib[64]/vndk[-sp] . Jeśli moduł nie jest już zależny od rozszerzenia VNDK, dodaj czysty krok do CleanSpec.mk , aby usunąć bibliotekę współdzieloną. Na przykład:

$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)

Kompilacja warunkowa

W tej sekcji opisano, jak radzić sobie z subtelnymi różnicami (np. dodawaniem lub usuwaniem funkcji w jednym z wariantów) pomiędzy następującymi trzema bibliotekami współdzielonymi 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 )

Flagi kompilatora warunkowego

System kompilacji Androida domyślnie definiuje __ANDROID_VNDK__ dla wariantów dostawców i rozszerzeń VNDK. Możesz chronić kod za pomocą strażników 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 Android.bp można określić różne cflags lub cppflags . cflags lub cppflags określone w target.vendor są specyficzne dla wariantu dostawcy.

Na przykład następujący plik Android.bp definiuje 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 to jest lista kodów 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

Zgodnie z tymi dwoma plikami system kompilacji generuje biblioteki współdzielone z następującymi wyeksportowanymi symbolami:

Ścieżka instalacji Eksportowane 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

Narzędzie sprawdzające ABI VNDK porównuje ABI wariantów dostawcy VNDK i rozszerzeń VNDK z referencyjnymi zrzutami ABI w obszarze prebuilts/abi-dumps/vndk .

  • Symbole eksportowane przez warianty dostawcy VNDK (np. /apex/com.android.vndk.v${VER}/lib[64]/libexample.so ) muszą być identyczne z symbolami zdefiniowanymi w zrzutach ABI (a nie nadzbiorami).
  • Symbole eksportowane przez rozszerzenia VNDK (np. /vendor/lib[64]/vndk/libexample.so ) muszą być nadzbiorami symboli zdefiniowanych w zrzutach ABI.

Jeśli warianty dostawcy VNDK lub rozszerzenia VNDK nie spełniają powyższych wymagań, moduł sprawdzający VNDK ABI zgłosi błędy kompilacji i zatrzyma kompilację.

Z wyłączeniem plików źródłowych lub bibliotek współdzielonych z wariantów dostawcy

Aby wykluczyć pliki źródłowe z wariantu dostawcy, dodaj je do właściwości exclude_srcs . Podobnie, aby mieć pewność, że biblioteki współdzielone nie są powiązane z wariantem dostawcy, dodaj te biblioteki do właściwości exclude_shared_libs . Na 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 podstawowy wariant libexample_cond_exclude zawiera kod z fwk.c i both.c i zależy od bibliotek współdzielonych libfwk_only i libboth . Wariant dostawcy libexample_cond_exclude zawiera tylko kod z both.c , ponieważ fwk.c jest wykluczony przez właściwość exclude_srcs . Podobnie zależy to tylko od biblioteki współdzielonej libboth , ponieważ libfwk_only jest wykluczone przez właściwość exclude_shared_libs .

Eksportuj nagłówki z rozszerzeń VNDK

Rozszerzenie VNDK może dodawać nowe klasy lub nowe funkcje do współdzielonej biblioteki VNDK. Sugeruje się zachowanie tych deklaracji w niezależnych nagłówkach i unikanie zmiany istniejących nagłówków.

Na przykład tworzony jest nowy plik nagłówkowy include-ext/example/ext/feature_name.h dla rozszerzenia VNDK libexample_ext :

  • Android.bp
  • include-ext/przykład/ext/nazwa_funkcji.h
  • zawierać/przykład/przykład.h
  • src/przykład.c
  • src/ext/nazwa_funkcji.c

W następującym Android.bp eksporty libexample include tylko , podczas gdy eksporty libexample_ext include i include-ext . Dzięki temu użytkownicy libexample nie dołączą niepoprawnie 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 oddzielenie rozszerzeń niezależnych plików nagłówkowych nie jest możliwe, alternatywą jest dodanie osłon #ifdef . Upewnij się jednak, że wszyscy użytkownicy rozszerzenia VNDK dodali flagi definiowania. Możesz zdefiniować cc_defaults , aby dodać flagi definiujące do cflags i połączyć biblioteki współdzielone z shared_libs .

Na przykład, aby dodać nową funkcję członkowską Example2::get_b() do rozszerzenia VNDK libexample2_ext , musisz zmodyfikować istniejący plik nagłówkowy i dodać osłonę #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_

Zdefiniowano cc_defaults o nazwie libexample2_ext_defaults dla użytkowników 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",
    ],
}

Użytkownicy libexample2_ext mogą po prostu włączyć libexample2_ext_defaults do swojej 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 powinny zostać zainstalowane na urządzeniu. Zależności przechodnie określonych modułów są również domyślnie instalowane w urządzeniu.

Jeśli włączona jest BOARD_VNDK_VERSION , moduły z vendor_available lub vndk.enabled są traktowane w specjalny sposób. Jeśli moduł frameworka zależy od modułu z opcją vendor_available lub vndk.enabled , wariant podstawowy jest zawarty w przechodnim zestawie instalacyjnym. Jeśli moduł dostawcy zależy od modułu z vendor_available , wariant dostawcy jest zawarty w przechodnim zestawie instalacyjnym. Jednakże warianty modułów dostawcy z vndk.enabled są instalowane niezależnie od tego, czy są używane przez moduły dostawcy, czy nie.

Gdy zależności są niewidoczne dla systemu kompilacji (np. biblioteki współdzielone, które można otworzyć za pomocą dlopen() w czasie wykonywania), powinieneś określić nazwy modułów w PRODUCT_PACKAGES , aby jawnie zainstalować te moduły.

Jeśli moduł ma vendor_available lub vndk.enabled , nazwa modułu oznacza jego podstawowy wariant. Aby jawnie określić wariant dostawcy w PRODUCT_PACKAGES , do nazwy modułu dołącz przyrostek .vendor . Na 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 oznacza /vendor/lib[64]/libexample.so . Aby zainstalować /vendor/lib[64]/libexample.so , dodaj libexample.vendor do PRODUCT_PACKAGES :

PRODUCT_PACKAGES += libexample.vendor