Supporto del sistema di creazione VNDK

In Android 8.1 e versioni successive, il sistema di build ha il supporto VNDK integrato. Quando il supporto VNDK è abilitato, il sistema di compilazione controlla le dipendenze tra i moduli, crea una variante specifica del fornitore per i moduli del fornitore e installa automaticamente tali moduli nelle directory designate.

Esempio di supporto per la creazione di 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 fornitore_disponibile:true e vndk.enabled:true

Figura 1. Supporto VNDK abilitato

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

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

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

Per ulteriori dettagli, vedere Definizione del modulo .

Configurazione del supporto per la compilazione

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

BOARD_VNDK_VERSION := current

Questa impostazione ha un effetto globale : quando definita in BoardConfig.mk , tutti i moduli vengono controllati. Poiché non esiste alcun meccanismo per inserire nella blacklist o nella whitelist un modulo offensivo, è necessario pulire 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 è abilitato, diversi percorsi di ricerca di intestazioni globali predefiniti vengono rimossi . Questi includono:

  • 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, è necessario specificare (esplicitamente) le dipendenze con header_libs , static_libs e/o shared_libs .

APICE VNDK

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

APICE VNDK

Figura 2. APICE VNDK

Definizione del modulo

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

Moduli del venditore

I moduli del fornitore sono file 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 della proprietà su true . Nei file Android.mk , i moduli del fornitore devono impostare LOCAL_VENDOR_MODULE o LOCAL_PROPRIETARY_MODULE su true .

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

  • un modulo senza vendor:true dipende da un modulo con vendor:true o
  • 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 il framework che i moduli del fornitore condividono la stessa e l'implementazione 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 ai moduli del fornitore. Per esempio:

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

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

  • Non è definito nella sezione che termina con _PRIVATE o _PLATFORM ,
  • Non ha il tag #platform-only e
  • Non ha tag #introduce* oppure 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à correlate a 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 dovrebbe essere trattata come un modulo framework e la variante del fornitore dovrebbe essere trattata come un modulo del fornitore. Se alcuni moduli del framework dipendono da questo modulo, viene creata la variante principale. 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 principale è sempre solo framework e inaccessibile ai moduli del fornitore.
  • La variante del fornitore è sempre inaccessibile ai moduli framework.
  • Tutte le dipendenze della variante del fornitore, specificate in header_libs , static_libs e/o shared_libs , devono essere una 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 core è 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 build gestisce le varianti del fornitore:

venditore_disponibile vndk
abilitato
vndk
support_stesso_processo
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 creazione)
true false Le varianti del fornitore sono VNDK . Le librerie condivise vengono installate su VNDK APEX.
true Le varianti del fornitore sono VNDK-SP . Le librerie condivise vengono installate su VNDK APEX.

false

false

false

Nessuna variante del fornitore. Questo modulo è SOLO FWK .

true Non valido (errore di creazione)
true false Le varianti del fornitore sono VNDK-Private . Le librerie condivise vengono installate su 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 su VNDK APEX. Questi 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 sovrascrivono le librerie condivise VNDK originali in fase di runtime.

Definizione delle estensioni VNDK

In Android 9 e versioni successive, Android.bp supporta nativamente le estensioni VNDK. Per creare un'estensione VNDK, definisci un altro modulo con un vendor:true e una proprietà 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 vendor:true , vndk.enabled:true ed extends definisce l'estensione VNDK:

  • La proprietà extends deve specificare un nome di libreria condivisa VNDK di base (o un nome di libreria condivisa VNDK-SP).
  • Le estensioni VNDK (o estensioni VNDK-SP) prendono il nome dai nomi dei moduli base da cui si estendono. Ad esempio, il binario di output di libvndk_ext è libvndk.so invece di libvndk_ext.so .
  • Le estensioni VNDK sono installate in /vendor/lib[64]/vndk .
  • Le estensioni VNDK-SP sono 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):

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 estensioni VNDK-SP) possono dipendere da librerie condivise di altri fornitori:

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

Utilizzo delle 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 dalle estensioni VNDK, tali 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. Per esempio:

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

Compilazione condizionale

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

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

Flag condizionali del compilatore

Per impostazione predefinita, il sistema di build Android definisce __ANDROID_VNDK__ per le varianti del fornitore e le estensioni VNDK. Puoi proteggere il codice con le guardie 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 possono essere specificati diversi cflags o cppflags . I cflags o cppflags specificati in target.vendor sono specifici della 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",
    ],
}

E questo è il listato del codice 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 , vndk_ext

Requisiti sui simboli esportati

Il controllo ABI VNDK 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 esempio /apex/com.android.vndk.v${VER}/lib[64]/libexample.so ) devono essere identici (non ai superset di) i simboli definiti nei dump ABI.
  • I simboli esportati dalle estensioni VNDK (ad esempio /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 soddisfano i requisiti di cui sopra, il controllo ABI VNDK genera errori di compilazione e interrompe la compilazione.

Esclusione di file di origine o librerie condivise dalle varianti del fornitore

Per escludere i file di origine dalla variante del fornitore, aggiungili alla proprietà exclude_srcs . Allo stesso modo, per garantire che le librerie condivise non siano collegate alla variante del fornitore, aggiungi tali librerie alla proprietà exclude_shared_libs . Per 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 exclude_srcs . Allo stesso modo, dipende solo dalla libreria condivisa libboth perché libfwk_only è esclusa dalla proprietà exclude_shared_libs .

Esporta intestazioni dalle estensioni VNDK

Un'estensione VNDK può aggiungere nuove classi o nuove funzioni a una libreria condivisa VNDK. Si suggerisce di mantenere tali dichiarazioni in intestazioni indipendenti ed evitare di modificare le intestazioni esistenti.

Ad esempio, viene creato un nuovo file di intestazione include-ext/example/ext/feature_name.h per l'estensione VNDK libexample_ext :

  • Android.bp
  • include-ext/esempio/ext/nome_funzione.h
  • include/esempio/esempio.h
  • src/esempio.c
  • src/ext/nome_funzione.c

Nel seguente Android.bp , le esportazioni libexample include solo , mentre le esportazioni libexample_ext includono sia include che include-ext . Ciò garantisce che feature_name.h non venga 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 header indipendenti, un'alternativa è aggiungere le protezioni #ifdef . 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 , è necessario modificare il file di intestazione esistente e aggiungere una 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_

Un cc_defaults denominato libexample2_ext_defaults è definito per gli utenti di 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",
    ],
}

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 sono installate implicitamente nel dispositivo.

Se BOARD_VNDK_VERSION è abilitato, i moduli con vendor_available o vndk.enabled ricevono un trattamento speciale. Se un modulo framework dipende da un modulo con vendor_available o vndk.enabled , la variante core è inclusa nel set di installazione transitiva. 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 esempio librerie condivise che possono essere aperte con dlopen() in runtime), dovresti specificare i nomi dei moduli in PRODUCT_PACKAGES per installare quei moduli esplicitamente.

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

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

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

PRODUCT_PACKAGES += libexample.vendor