Supporto del sistema di build VNDK

In Android 8.1 e versioni successive, il sistema di compilazione ha il supporto VNDK integrato. Quando l'assistenza VNDK è attivata, il sistema di compilazione controlla le dipendenze tra i moduli, crea una variante specifica per il fornitore per i moduli del fornitore e li installa automaticamente in directory designate.

Esempio di supporto per la compilazione VNDK

In questo esempio, la definizione del modulo Android.bp definisce una libreria denominata libexample. La proprietà vendor_available indica che i moduli del framework e i moduli del fornitore possono dipendere da libexample:

libexample vendor_available:true e vndk.enabled:true

Supporto Figura 1. attivato.

Sia l'eseguibile del framework /system/bin/foo sia l'eseguibile del fornitore /vendor/bin/bar dipendono da libexample e hanno libexample nelle proprietà shared_libs.

Se libexample viene utilizzato sia dai moduli del framework sia dai moduli del fornitore, vengono create due varianti di libexample. La variante di base (nome basato su libexample) viene utilizzata dai moduli del framework e la variante del fornitore (nome basato su libexample.vendor) viene utilizzata dai moduli del fornitore. Le due varianti vengono installate in directory diverse:

  • La variante principale è installata in /system/lib[64]/libexample.so.
  • La variante del fornitore è installata in VNDK APEX perché vndk.enabled è true.

Per ulteriori dettagli, consulta Definizione del modulo.

Configurare il supporto per la compilazione

Per attivare il supporto completo del sistema di compilazione per un dispositivo di prodotto, aggiungi BOARD_VNDK_VERSION a BoardConfig.mk:

BOARD_VNDK_VERSION := current

Questa impostazione ha un effetto globale: se definita in BoardConfig.mk, vengono selezionati tutti i moduli. Poiché non esiste un meccanismo per inserire un modulo in una lista consentita o bloccata, devi eliminare tutte le dipendenze non necessarie prima di aggiungere BOARD_VNDK_VERSION. Puoi testare e compilare un modulo impostando BOARD_VNDK_VERSION nelle variabili di ambiente:

$ BOARD_VNDK_VERSION=current m module_name.vendor

Quando BOARD_VNDK_VERSION è attivato, diversi percorsi di ricerca delle intestazioni globali predefinite vengono rimossi. come le seguenti.

  • 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

Se un modulo dipende dalle intestazioni di queste directory, devi specificare (esplicitamente) le dipendenze con header_libs, static_libs e/o shared_libs.

VNDK APEX

In Android 10 e versioni precedenti, i moduli con vndk.enabled sono stati installati in /system/lib[64]/vndk[-sp]-${VER}. In Android 11 e versioni successive, le librerie VNDK sono pacchettizzate in formato APEX e il nome VNDK APEX è com.android.vndk.v${VER}. A seconda della configurazione del dispositivo, VNDK APEX è appiattito o non appiattito ed è disponibile dal percorso canonico /apex/com.android.vndk.v${VER}.

VNDK APEX

Figura 2. VNDK APEX.

Definizione del modulo

Per compilare Android con BOARD_VNDK_VERSION, devi rivedere la definizione del modulo in Android.mk o Android.bp. Questa sezione descrive diversi tipi di definizioni di moduli, diverse proprietà dei moduli relative a VNDK e controlli delle dipendenze implementati nel sistema di compilazione.

Moduli del fornitore

I moduli del fornitore sono eseguibili o librerie condivise specifici del fornitore che devono essere installati in una partizione del fornitore. Nei file Android.bp, i moduli del fornitore devono impostare la proprietà del fornitore o proprietaria su true. Nei file Android.mk, i moduli del fornitore devono impostare LOCAL_VENDOR_MODULE o LOCAL_PROPRIETARY_MODULE su true.

Se è definito BOARD_VNDK_VERSION, il sistema di compilazione non consente le dipendenze tra i moduli del fornitore e i moduli del framework ed emette errori se:

  • un modulo senza vendor:true dipende da un modulo con vendor:true oppure
  • un modulo con vendor:true dipende da un modulo non llndk_library che non ha né vendor:truevendor_available:true.

Il controllo delle dipendenze si applica a header_libs, static_libs e shared_libs in Android.bp e a LOCAL_HEADER_LIBRARIES, LOCAL_STATIC_LIBRARIES e LOCAL_SHARED_LIBRARIES in Android.mk.

LL-NDK

Le librerie condivise LL-NDK sono librerie condivise con ABI stabili. Sia i moduli del framework sia i moduli del fornitore condividono la stessa implementazione e la più recente. Per ogni libreria condivisa LL-NDK, cc_library contiene una proprietà llndk con un file di simboli:

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

Il file dei simboli descrive i simboli visibili nei moduli del fornitore. Ad esempio:

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

In base al file dei simboli, il sistema di compilazione genera una libreria condivisa stub per i moduli del fornitore, che si collegano a queste librerie quando BOARD_VNDK_VERSION è abilitato. Un simbolo viene incluso nella libreria condivisa dello stub solo se:

  • Non è definito nella sezione che termina con _PRIVATE o _PLATFORM,
  • Non ha il tag #platform-only e
  • Non ha tag #introduce* o il tag corrisponde al target.

VNDK

Nei file Android.bp, le definizioni dei moduli cc_library, cc_library_static, cc_library_shared e cc_library_headers supportano tre proprietà relative al VNDK: vendor_available, vndk.enabled e vndk.support_system_process.

Se vendor_available o vndk.enabled è true, è possibile creare due varianti (core e vendor). La variante principale deve essere trattata come un modulo del framework e la variante del fornitore deve essere trattata come un modulo del fornitore. Se alcuni moduli del framework dipendono da questo modulo, viene compilata la variante di base. Se alcuni moduli del fornitore dipendono da questo modulo, viene creata la variante del fornitore. Il sistema di compilazione applica i seguenti controlli delle dipendenze:

  • La variante di base è sempre solo per il framework e non è accessibile ai moduli del fornitore.
  • La variante del fornitore è sempre inaccessibile ai moduli del framework.
  • Tutte le dipendenze della variante del fornitore, specificate in header_libs, static_libs e/o shared_libs, devono essere un llndk_library o un modulo con vendor_available o vndk.enabled.
  • Se vendor_available è true, la variante del fornitore è accessibile a tutti i moduli del fornitore.
  • Se vendor_available è false, la variante del fornitore è accessibile solo ad altri moduli VNDK o VNDK-SP (ovvero i moduli con vendor:true non possono collegare i moduli vendor_available:false).

Il percorso di installazione predefinito per cc_library o cc_library_shared è determinato dalle seguenti regole:

  • La variante principale è installata in /system/lib[64].
  • Il percorso di installazione della variante del fornitore può variare:
    • Se vndk.enabled è false, la variante del fornitore viene installata in /vendor/lib[64].
    • Se vndk.enabled è true, la variante del fornitore viene installata in VNDK APEX(com.android.vndk.v${VER}).

La tabella seguente riassume il modo in cui il sistema di compilazione gestisce le varianti del fornitore:

vendor_available vndk
enabled
vndk
support_same_process
Descrizioni delle varianti del fornitore
true false false Le varianti del fornitore sono SOLO VND. Le librerie condivise sono installate in /vendor/lib[64].
true Non valido (errore di compilazione)
true false Le varianti del fornitore sono VNDK. Le librerie condivise vengono installate in VNDK APEX.
true Le varianti del fornitore sono VNDK-SP. Le librerie condivise vengono installate in VNDK APEX.

false

false

false

Nessuna variante del fornitore. Questo modulo è SOLO PER IL FRAMEWORK.

true Non valido (errore di compilazione)
true false Le varianti del fornitore sono VNDK-Private. Le librerie condivise vengono installate in VNDK APEX. Questi non devono essere utilizzati direttamente dai moduli del fornitore.
true Le varianti del fornitore sono VNDK-SP-Private. Le librerie condivise vengono installate in VNDK APEX. Non devono essere utilizzati direttamente dai moduli del fornitore.

Estensioni VNDK

Le estensioni VNDK sono librerie condivise VNDK con API aggiuntive. Le estensioni vengono installate in /vendor/lib[64]/vndk[-sp] (senza suffisso di versione) e sostituiscono le librerie condivise VNDK originali in fase di esecuzione.

Definizione delle estensioni VNDK

In Android 9 e versioni successive, Android.bp supporta in modo nativo le estensioni VNDK. Per creare un'estensione VNDK, definisci un altro modulo con una proprietà vendor:true e extends:

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
}

Un modulo con le proprietà vendor:true, vndk.enabled:true e extends definisce l'estensione VNDK:

  • La proprietà extends deve specificare un nome di libreria condivisa VNDK di base (o il nome di una libreria condivisa VNDK-SP).
  • Le estensioni VNDK (o estensioni VNDK-SP) prendono il nome dai nomi dei moduli di base da cui si estendono. Ad esempio, il programma binario di output di libvndk_ext è libvndk.so anziché libvndk_ext.so.
  • Le estensioni VNDK vengono installate in /vendor/lib[64]/vndk.
  • Le estensioni VNDK-SP vengono installate in /vendor/lib[64]/vndk-sp.
  • Le librerie condivise di base devono avere sia vndk.enabled:true che vendor_available:true.

Un'estensione VNDK-SP deve estendersi da una libreria condivisa VNDK-SP (vndk.support_system_process deve essere uguale a):

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,
    },
}

Le estensioni VNDK (o VNDK-SP) possono dipendere da altre librerie condivise del fornitore:

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,
}

Utilizzare le estensioni VNDK

Se un modulo del fornitore dipende da API aggiuntive definite dalle estensioni VNDK, il modulo deve specificare il nome dell'estensione VNDK nella sua proprietà 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",
    ],
}

Se un modulo del fornitore dipende da estensioni VNDK, queste estensioni VNDK vengono installate automaticamente in /vendor/lib[64]/vndk[-sp]. Se un modulo non dipende più da un'estensione VNDK, aggiungi un passaggio pulito a CleanSpec.mk per rimuovere la libreria condivisa. Ad esempio:

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

Compilazione condizionale

Questa sezione descrive come gestire le piccole differenze (ad es. l'aggiunta o la rimozione di una funzionalità da una delle varianti) tra le seguenti tre librerie condivise VNDK:

  • Variante principale (ad es. /system/lib[64]/libexample.so)
  • Variante del fornitore (ad es. /apex/com.android.vndk.v${VER}/lib[64]/libexample.so)
  • Estensione VNDK (ad es. /vendor/lib[64]/vndk[-sp]/libexample.so)

Flag del compilatore condizionale

Per impostazione predefinita, il sistema di build di Android definisce __ANDROID_VNDK__ per le varianti del fornitore e le estensioni VNDK. Puoi proteggere il codice con protezioni del preprocessore C:

void all() { }

#if !defined(__ANDROID_VNDK__)
void framework_only() { }
#endif

#if defined(__ANDROID_VNDK__)
void vndk_only() { }
#endif

Oltre a __ANDROID_VNDK__, in Android.bp è possibile specificare diversi cflags o cppflags. Il valore cflags o cppflags specificato in target.vendor è specifico per la variante del fornitore.

Ad esempio, il seguente Android.bp definisce libexample e 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",
    ],
}

Questa è la lista di codici di 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

In base a questi due file, il sistema di compilazione genera librerie condivise con i seguenti simboli esportati:

Percorso di installazione Simboli esportati
/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 e vndk_ext

Requisiti relativi ai simboli esportati

Lo strumento VNDK ABI checker confronta l'ABI delle varianti del fornitore VNDK e delle estensioni VNDK con i dump ABI di riferimento in prebuilts/abi-dumps/vndk.

  • I simboli esportati dalle varianti del fornitore VNDK (ad es. /apex/com.android.vndk.v${VER}/lib[64]/libexample.so) devono essere identici (non i soprainsiemi) ai simboli definiti nei dump delle ABI.
  • I simboli esportati dalle estensioni VNDK (ad es. /vendor/lib[64]/vndk/libexample.so) devono essere superset dei simboli definiti nei dump ABI.

Se le varianti del fornitore VNDK o le estensioni VNDK non rispettano i requisiti precedenti, lo strumento di controllo ABI VNDK emette errori di compilazione e interrompe la compilation.

Escludere i file di origine o le librerie condivise dalle varianti del fornitore

Per escludere i file di origine dalla variante del fornitore, aggiungili alla proprietà exclude_srcs. Analogamente, per assicurarti che le librerie condivise non siano collegate alla variante del fornitore, aggiungile alla proprietà exclude_shared_libs. Ad esempio:

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"],
        },
    },
}

In questo esempio, la variante principale di libexample_cond_exclude include il codice di fwk.c e both.c e dipende dalle librerie condivise libfwk_only e libboth. La variante del fornitore di libexample_cond_exclude include solo il codice di both.c perché fwk.c è escluso dalla proprietà exclude_srcs. Analogamente, dipende solo dalla raccolta condivisa libboth perché libfwk_only è esclusa dalla proprietà exclude_shared_libs.

Esportare le intestazioni dalle estensioni VNDK

Un'estensione VNDK può aggiungere nuove classi o nuove funzioni a una libreria VNDK condivisa. Ti consigliamo di mantenere queste dichiarazioni in intestazioni indipendenti ed evitare di modificare quelle esistenti.

Ad esempio, viene creato un nuovo file di intestazioneinclude-ext/example/ext/feature_name.h per l'estensione VNDKlibexample_ext:

  • Android.bp
  • include-ext/example/ext/feature_name.h
  • include/example/example.h
  • src/example.c
  • src/ext/feature_name.c

Nel seguente Android.bp, libexample esporta solo include, mentre libexample_ext esporta sia include sia include-ext. In questo modo, feature_name.h non verrà incluso erroneamente dagli utenti di 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",
    },
}

Se non è possibile separare le estensioni in file di intestazione indipendenti, un'alternativa è aggiungere #ifdef guard. Tuttavia, assicurati che tutti gli utenti dell'estensione VNDK aggiungano i flag di definizione. Puoi definire cc_defaults per aggiungere flag di definizione a cflags e collegare le librerie condivise con shared_libs.

Ad esempio, per aggiungere una nuova funzione membro Example2::get_b() all'estensione VNDK libexample2_ext, devi modificare il file di intestazione esistente e aggiungere un'istruzione di guardia #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_

Per gli utenti di libexample2_ext è stato definito un cc_defaults denominato 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",
    ],
}

Gli utenti di libexample2_ext possono semplicemente includere libexample2_ext_defaults nella loro proprietà defaults:

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

Pacchetti di prodotti

Nel sistema di build Android, la variabile PRODUCT_PACKAGES specifica gli eseguibili, le librerie condivise o i pacchetti che devono essere installati nel dispositivo. Anche le dipendenze transitive dei moduli specificati vengono installate implicitamente nel dispositivo.

Se BOARD_VNDK_VERSION è attivato, i moduli con vendor_available o vndk.enabled ricevono un trattamento speciale. Se un modulo del framework dipende da un modulo con vendor_available o vndk.enabled, la variante di base è inclusa nel set di installazione transitivo. Se un modulo del fornitore dipende da un modulo con vendor_available, la variante del fornitore è inclusa nel set di installazione transitiva. Tuttavia, le varianti del fornitore dei moduli con vndk.enabled vengono installate indipendentemente dal fatto che vengano utilizzate o meno dai moduli del fornitore.

Quando le dipendenze sono invisibili al sistema di compilazione (ad es. le librerie condivise che possono essere aperte con dlopen() in fase di esecuzione), devi specificare i nomi dei moduli in PRODUCT_PACKAGES per installarli esplicitamente.

Se un modulo ha vendor_available o vndk.enabled, il nome del modulo indica la variante principale. Per specificare esplicitamente la variante del fornitore in PRODUCT_PACKAGES, aggiungi un suffisso .vendor al nome del modulo. Ad esempio:

cc_library {
    name: "libexample",
    srcs: ["example.c"],
    vendor_available: true,
}

In questo esempio, libexample indica /system/lib[64]/libexample.so e libexample.vendor indica /vendor/lib[64]/libexample.so. Per installare /vendor/lib[64]/libexample.so, aggiungi libexample.vendor a PRODUCT_PACKAGES:

PRODUCT_PACKAGES += libexample.vendor