Wsparcie systemu budowania VNDK

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

W systemie Android 8.1 i nowszych 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 wariant specyficzny dla dostawcy dla modułów dostawców 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 vendor_available:true i vndk.enabled:true

Rysunek 1. Włączona obsługa VNDK

Zarówno wykonywalny framework /system/bin/foo , jak i plik wykonywalny /vendor/bin/bar zależą od libexample i mają libexample we właściwościach shared_libs .

Jeśli libexample jest używany zarówno przez moduły frameworka, jak i moduły dostawcy, budowane są dwa warianty libexample . Wariant podstawowy (o nazwie libexample ) jest używany przez moduły frameworka, a wariant dostawcy (o nazwie libexample.vendor ) jest używany przez moduły dostawcy. Dwa warianty są instalowane w różnych katalogach:

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

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

Konfiguracja wsparcia dla 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 : Po zdefiniowaniu w BoardConfig.mk wszystkie moduły są sprawdzane. Ponieważ nie ma mechanizmu na czarną lub białą listę naruszającego modułu, należy wyczyścić wszystkie niepotrzebne zależności przed dodaniem BOARD_VNDK_VERSION . Możesz przetestować i skompilować moduł, ustawiając BOARD_VNDK_VERSION w zmiennych środowiskowych:

$ BOARD_VNDK_VERSION=current m module_name.vendor

Gdy BOARD_VNDK_VERSION jest włączona, kilka domyślnych ścieżek wyszukiwania nagłówków globalnych 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/lub shared_libs .

VNDK APEX

W systemie Android 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 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, VNDK APEX jest spłaszczony lub niespłaszczony i jest dostępny ze ścieżki kanonicznej /apex/com.android.vndk.v${VER} .

VNDK APEX

Rysunek 2. APEX VNDK

Definicja modułu

Aby zbudować system Android 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 kontrole zależności zaimplementowane w systemie kompilacji.

Moduły dostawcy

Moduły dostawcy to pliki wykonywalne specyficzne dla dostawcy lub biblioteki współdzielone, 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ą ustawić LOCAL_VENDOR_MODULE lub LOCAL_PROPRIETARY_MODULE na true .

Jeśli BOARD_VNDK_VERSION jest zdefiniowany, system kompilacji nie zezwala na zależności między modułami dostawcy a modułami frameworka 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 frameworka, jak i dostawcy mają tę samą i najnowszą implementację. Dla każdej biblioteki współdzielonej LL-NDK, Android.bp zawiera definicję modułu llndk_library :

llndk_library {
    name: "libvndksupport",
    symbol_file: "libvndksupport.map.txt",
}

Ta definicja modułu określa nazwę modułu i plik symboli, który opisuje symbole widoczne dla modułów dostawców. Na przykład:

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

Na podstawie pliku symboli system kompilacji generuje skrótową bibliotekę współdzieloną dla modułów dostawców, która łączy się z tymi bibliotekami, gdy włączona jest opcja BOARD_VNDK_VERSION . Symbol jest dołączany do skrótowej biblioteki współdzielonej tylko wtedy, gdy:

  • Nie jest zdefiniowany w sekcji kończącej się na _PRIVATE lub _PLATFORM ,
  • Nie ma tagu #platform-only oraz
  • Nie zawiera tagów #introduce* ani tagów zgodnych z celem.

VNDK

W plikach cc_library_shared definicje modułów Android.bp , cc_library , cc_library_static 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 wartość true , można zbudować dwa warianty ( core i vendor ). Wariant core należy traktować jako moduł frameworka, a wariant dostawcy jako moduł dostawcy. Jeśli niektóre moduły frameworka zależą od tego modułu, budowany jest wariant core. Jeśli niektóre moduły dostawcy zależą od tego modułu, budowany jest wariant dostawcy. System kompilacji wymusza następujące sprawdzenia zależności:

  • Wariant podstawowy jest zawsze tylko frameworkiem i niedostępny dla modułów dostawców.
  • Wariant dostawcy jest zawsze niedostępny dla modułów frameworka.
  • Wszystkie zależności wariantu dostawcy, które są określone w header_libs , static_libs i/lub shared_libs , muszą być llndk_library lub 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 dla cc_library lub cc_library_shared jest określona przez następujące reguły:

  • Wariant podstawowy jest instalowany w /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 ma wartość true , wariant dostawcy jest instalowany w VNDK APEX ( com.android.vndk.v${VER} ).

Poniższa tabela podsumowuje, jak system kompilacji obsługuje warianty dostawcy:

sprzedawca_dostępny vndk
włączony
vndk
support_same_process
Opisy wariantów dostawcy
true false false Warianty dostawcy to TYLKO VND . Współdzielone biblioteki są instalowane w /vendor/lib[64] .
true Nieprawidłowy (błąd kompilacji)
true false Warianty dostawcy to VNDK . Współdzielone biblioteki są instalowane w VNDK APEX.
true Warianty dostawcy to VNDK-SP . Współdzielone biblioteki są instalowane w VNDK APEX.

false

false

false

Brak wariantów dostawcy. Ten moduł jest TYLKO FWK .

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

Rozszerzenia VNDK

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

Definiowanie rozszerzeń VNDK

W systemie Android 9 i nowszych 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 właściwościami vendor:true , vndk.enabled:true i extends definiuje rozszerzenie VNDK:

  • Właściwość extends musi określać podstawową nazwę biblioteki współużytkowanej VNDK (lub nazwę biblioteki współużytkowanej VNDK-SP).
  • Rozszerzenia VNDK (lub rozszerzenia VNDK-SP) są nazywane po nazwach modułów podstawowych, z których się rozciągają. 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 pochodzić z 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 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 we 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, te rozszerzenia VNDK są automatycznie instalowane w katalogu /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 z jednego z wariantów) mię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 )

Warunkowe flagi kompilatora

System kompilacji Androida domyślnie definiuje __ANDROID_VNDK__ dla wariantów dostawcy i rozszerzeń VNDK. Możesz strzec kodu 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 poniższy 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 kodu 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 budowania generuje biblioteki współdzielone z następującymi 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

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

  • Symbole eksportowane przez warianty dostawców VNDK (np /apex/com.android.vndk.v${VER}/lib[64]/libexample.so ) muszą być identyczne (nie nadzbiorami) symboli zdefiniowanych w zrzutach ABI.
  • 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ń, program sprawdzający VNDK ABI emituje błędy kompilacji i zatrzymuje kompilację.

Wykluczanie 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 upewnić się, że biblioteki współdzielone nie są połączone 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 tylko od biblioteki współdzielonej libboth , ponieważ libfwk_only jest wykluczona przez właściwość exclude_shared_libs .

Eksportuj nagłówki z rozszerzeń VNDK

Rozszerzenie VNDK może dodawać nowe klasy lub nowe funkcje do biblioteki współdzielonej VNDK. Sugeruje się, aby te deklaracje zachować w niezależnych nagłówkach i unikać zmiany istniejących nagłówków.

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

  • Android.bp
  • include-ext/example/ext/feature_name.h
  • uwzględnij/przykład/przykład.h
  • src/przykład.c
  • src/ext/feature_name.c

W poniższym Android.bp , libexample eksportuje tylko include , podczas gdy libexample_ext eksportuje zarówno include , jak i include-ext . Gwarantuje to, że feature_name.h nie zostanie błędnie uwzględniony przez użytkowników 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",
    },
}

Jeśli rozdzielenie rozszerzeń na niezależne pliki nagłówkowe nie jest możliwe, alternatywą jest dodanie #ifdef guard. Należy jednak upewnić się, że wszyscy użytkownicy rozszerzenia VNDK dodają 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ę Example2::get_b() do rozszerzenia libexample2_ext , musisz zmodyfikować istniejący plik nagłówkowy i dodać strażnika #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 o nazwie libexample2_ext_defaults jest zdefiniowany 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 dołączyć libexample2_ext_defaults do swojej właściwości defaults :

cc_binary {
    name: "example2_user_executable",
    defaults: ["libexample2_ext_defaults"],
    vendor: true,
}

Opakowania produktów

W systemie kompilacji Android zmienna PRODUCT_PACKAGES określa pliki wykonywalne, biblioteki współdzielone lub pakiety, które powinny być zainstalowane na urządzeniu. Przechodnie zależności określonych modułów są również niejawnie instalowane w urządzeniu.

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

Gdy zależności są niewidoczne dla systemu budowania (np. biblioteki współdzielone, które można otworzyć za pomocą dlopen() w czasie wykonywania), należy 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łącz sufiks .vendor do nazwy modułu. 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