Venditore APEX

È possibile utilizzare il formato file APEX per creare pacchetti e installare moduli del sistema operativo Android di livello inferiore. Consente la creazione e l'installazione indipendente di componenti come servizi e librerie nativi, implementazioni HAL, firmware, file di configurazione, ecc.

Gli APEX del fornitore vengono installati automaticamente dal sistema di compilazione nella partizione /vendor e attivati ​​in fase di runtime da apexd proprio come gli APEX in altre partizioni.

Casi d'uso

Modularizzazione delle immagini dei fornitori

Gli APEX facilitano il raggruppamento e la modularizzazione naturali delle implementazioni delle funzionalità sulle immagini del fornitore.

Quando le immagini del fornitore vengono create come una combinazione di APEX di fornitori indipendenti, i produttori di dispositivi sono in grado di scegliere facilmente le implementazioni specifiche del fornitore desiderate sul proprio dispositivo. I produttori possono persino creare un nuovo fornitore APEX se nessuno degli APEX forniti soddisfa le loro esigenze o se dispongono di un nuovissimo hardware personalizzato.

Ad esempio, un OEM può scegliere di comporre il proprio dispositivo con l'implementazione Wi-Fi AOSP APEX, l'implementazione Bluetooth SoC APEX e un'implementazione di telefonia OEM personalizzata APEX.

Senza APEX del fornitore, un'implementazione con così tante dipendenze tra i componenti del fornitore richiede un attento coordinamento e monitoraggio. Raggruppando tutti i componenti (inclusi file di configurazione e librerie extra) in APEX con interfacce chiaramente definite in qualsiasi punto di comunicazione tra funzionalità, i diversi componenti diventano intercambiabili.

Iterazione dello sviluppatore

Gli APEX del fornitore aiutano gli sviluppatori a eseguire iterazioni più velocemente durante lo sviluppo dei moduli del fornitore raggruppando un'intera implementazione di funzionalità, come l'HAL Wi-Fi, all'interno di un APEX del fornitore. Gli sviluppatori possono quindi creare e spingere individualmente il fornitore APEX a testare le modifiche, invece di ricostruire l'intera immagine del fornitore.

Ciò semplifica e accelera il ciclo di iterazione degli sviluppatori per gli sviluppatori che lavorano principalmente in un'area di funzionalità e desiderano eseguire l'iterazione solo su quell'area di funzionalità.

Il naturale raggruppamento di un'area di funzionalità in un APEX semplifica inoltre il processo di creazione, inserimento e test delle modifiche per tale area di funzionalità. Ad esempio, la reinstallazione di APEX aggiorna automaticamente qualsiasi libreria in bundle o file di configurazione inclusi in APEX.

Raggruppare un'area di funzionalità in un APEX semplifica inoltre il debug o il ripristino quando si osserva un comportamento errato del dispositivo. Ad esempio, se la telefonia funziona male in una nuova build, gli sviluppatori potrebbero provare a installare un'implementazione di telefonia precedente APEX su un dispositivo (senza dover eseguire il flashing di una build completa) e verificare se viene ripristinato il buon comportamento.

Flusso di lavoro di esempio:

# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w

# Test the device.
... testing ...

# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...

# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...

Esempi

Nozioni di base

Consulta la pagina principale del formato file APEX per informazioni APEX generiche, inclusi requisiti del dispositivo, dettagli sul formato file e passaggi di installazione.

In Android.bp , l'impostazione della vendor: true rende un modulo APEX un fornitore APEX.

apex {
  ..
  vendor: true,
  ..
}

Binari e librerie condivise

Un APEX include dipendenze transitive all'interno del payload APEX a meno che non dispongano di interfacce stabili.

Le interfacce native stabili per le dipendenze APEX del fornitore includono cc_library con stubs , ndk_library o llndk_library . Queste dipendenze sono escluse dal pacchetto e le dipendenze vengono registrate nel manifest APEX. Il manifest viene elaborato da linkerconfig in modo che le dipendenze native esterne siano disponibili in fase di esecuzione.

A differenza degli APEX nella partizione /system , gli APEX del fornitore sono generalmente legati a una versione VNDK specifica. Le librerie VNDK garantiscono la stabilità ABI all'interno del rilascio, quindi possiamo considerare le librerie VNDK come stabili e ridurre la dimensione degli APEX del fornitore escludendoli dagli APEX utilizzando la proprietà use_vndk_as_stable .

Nello snippet seguente, APEX conterrà sia il file binario ( my_service ) che le sue dipendenze non stabili (file *.so ). Non conterrà librerie VNDK, anche quando my_service è creato con librerie VNDK come libbase . Invece, in fase di runtime my_service utilizzerà libbase dalle librerie VNDK fornite dal sistema.

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

Nello snippet seguente, APEX conterrà la libreria condivisa my_standalone_lib e tutte le sue dipendenze non stabili (come descritto sopra).

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

Implementazioni HAL

Per definire un'implementazione HAL, fornire i file binari e le librerie corrispondenti all'interno di un fornitore APEX simile ai seguenti esempi:

Per incapsulare completamente l'implementazione HAL, APEX dovrebbe anche specificare eventuali frammenti VINTF e script di inizializzazione rilevanti.

Frammenti VINTF

I frammenti VINTF possono essere forniti da un fornitore APEX quando i frammenti si trovano in etc/vintf di APEX.

Utilizza la proprietà prebuilts per incorporare i frammenti VINTF nell'APEX.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

Script di inizializzazione

Gli APEX possono includere script di inizializzazione in due modi: (A) un file di testo predefinito all'interno del payload APEX o (B) uno script di inizializzazione regolare in /vendor/etc . È possibile impostarli entrambi per lo stesso APEX.

Script di inizializzazione in APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

Gli script di inizializzazione all'interno degli APEX possono avere solo definizioni service . Gli script di inizializzazione negli APEX del fornitore possono avere anche direttive on <property> .

Fare attenzione quando si utilizzano on direttive. Poiché gli script di inizializzazione negli APEX vengono analizzati ed eseguiti dopo l'attivazione degli APEX, alcuni eventi o proprietà non possono essere utilizzati. Utilizzare apex.all.ready=true per attivare le azioni il prima possibile.

Firmware

Esempio:

Incorpora il firmware in un APEX del fornitore con il tipo di modulo prebuilt_firmware , come segue.

prebuilt_firmware {
  name: "my.bin",
  src: "path_to_prebuilt_firmware",
  vendor: true,
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.bin"],  // installed inside APEX as /etc/firmware/my.bin
  ..
}

I moduli prebuilt_firmware vengono installati nella directory <apex name>/etc/firmware di APEX. ueventd esegue la scansione delle directory /apex/*/etc/firmware per trovare i moduli firmware.

file_contexts di APEX dovrebbe etichettare correttamente tutte le voci del payload del firmware per garantire che questi file siano accessibili da ueventd in fase di runtime; in genere, l'etichetta vendor_file è sufficiente. Per esempio:

(/.*)? u:object_r:vendor_file:s0

Moduli del kernel

Incorpora i moduli del kernel in un APEX del fornitore come moduli precostruiti, come segue.

prebuilt_etc {
  name: "my.ko",
  src: "my.ko",
  vendor: true,
  sub_dir: "modules"
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.ko"],  // installed inside APEX as /etc/modules/my.ko
  ..
}

file_contexts di APEX dovrebbe etichettare correttamente tutte le voci del payload del modulo kernel. Per esempio:

/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0

I moduli del kernel devono essere installati esplicitamente. Il seguente script init di esempio nella partizione del fornitore mostra l'installazione tramite insmod :

my_init.rc :

on early-boot
  insmod /apex/myapex/etc/modules/my.ko
  ..

Sovrapposizioni di risorse runtime

Esempio:

Incorpora sovrapposizioni di risorse runtime in un APEX del fornitore utilizzando la proprietà rros .

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

Altri file di configurazione

Gli APEX del fornitore supportano vari altri file di configurazione generalmente presenti nella partizione del fornitore come precostruiti all'interno degli APEX del fornitore e altri vengono aggiunti.

Esempi:

Funzionalità di sviluppo aggiuntive

Selezione APEX all'avvio

Esempio:

Gli sviluppatori possono anche installare più versioni di APEX del fornitore che condividono lo stesso nome e chiave APEX, quindi scegliere quale versione attivare durante ogni avvio utilizzando sysprop persistenti. Per alcuni casi d'uso degli sviluppatori, questo potrebbe essere più semplice che installare una nuova copia di APEX utilizzando adb install .

Casi d'uso di esempio:

  • Installa 3 versioni del fornitore HAL Wi-Fi APEX: i team QA possono eseguire test manuali o automatizzati utilizzando una versione, quindi riavviare in un'altra versione ed eseguire nuovamente i test, quindi confrontare i risultati finali.
  • Installa 2 versioni della fotocamera HAL del fornitore APEX, attuale e sperimentale : i dogfooder possono utilizzare la versione sperimentale senza scaricare e installare un file aggiuntivo, in modo da poter facilmente tornare indietro.

Durante l'avvio, apexd cerca i sysprop che seguono un formato specifico per attivare la versione APEX corretta.

I formati previsti per la chiave della proprietà sono:

  • Bootconfig
    • Utilizzato per impostare il valore predefinito, in BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Sistema persistente
    • Utilizzato per modificare il valore predefinito, impostato su un dispositivo già avviato.
    • Sostituisce il valore bootconfig, se presente.
    • persist.vendor.apex.<apex name>

Il valore della proprietà dovrebbe essere il nome file dell'APEX che dovrebbe essere attivato.

// Default version.
apex {
  name: "com.oem.camera.hal.my_apex_default",
  vendor: true,
  ..
}

// Non-default version.
apex {
  name: "com.oem.camera.hal.my_apex_experimental",
  vendor: true,
  ..
}

La versione predefinita dovrebbe essere configurata anche utilizzando bootconfig in BoardConfig.mk :

# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
    androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default

Dopo aver avviato il dispositivo, modificare la versione attivata impostando il sysprop persistente:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

Se il dispositivo supporta l'aggiornamento di bootconfig dopo il flashing (ad esempio tramite comandi fastboot oem ), la modifica della proprietà bootconfig per APEX multiinstallato modifica anche la versione attivata all'avvio.

Per i dispositivi di riferimento virtuali basati su Cuttlefish , puoi utilizzare il comando --extra_bootconfig_args per impostare la proprietà bootconfig direttamente durante l'avvio. Per esempio:

launch_cvd --noresume \
  --extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";
,

È possibile utilizzare il formato file APEX per creare pacchetti e installare moduli del sistema operativo Android di livello inferiore. Consente la creazione e l'installazione indipendente di componenti come servizi e librerie nativi, implementazioni HAL, firmware, file di configurazione, ecc.

Gli APEX del fornitore vengono installati automaticamente dal sistema di compilazione nella partizione /vendor e attivati ​​in fase di runtime da apexd proprio come gli APEX in altre partizioni.

Casi d'uso

Modularizzazione delle immagini dei fornitori

Gli APEX facilitano il raggruppamento e la modularizzazione naturali delle implementazioni delle funzionalità sulle immagini del fornitore.

Quando le immagini del fornitore vengono create come una combinazione di APEX di fornitori indipendenti, i produttori di dispositivi sono in grado di scegliere facilmente le implementazioni specifiche del fornitore desiderate sul proprio dispositivo. I produttori possono persino creare un nuovo fornitore APEX se nessuno degli APEX forniti soddisfa le loro esigenze o se dispongono di un nuovissimo hardware personalizzato.

Ad esempio, un OEM può scegliere di comporre il proprio dispositivo con l'implementazione Wi-Fi AOSP APEX, l'implementazione Bluetooth SoC APEX e un'implementazione di telefonia OEM personalizzata APEX.

Senza APEX del fornitore, un'implementazione con così tante dipendenze tra i componenti del fornitore richiede un attento coordinamento e monitoraggio. Raggruppando tutti i componenti (inclusi file di configurazione e librerie extra) in APEX con interfacce chiaramente definite in qualsiasi punto di comunicazione tra funzionalità, i diversi componenti diventano intercambiabili.

Iterazione dello sviluppatore

Gli APEX del fornitore aiutano gli sviluppatori a eseguire iterazioni più velocemente durante lo sviluppo dei moduli del fornitore raggruppando un'intera implementazione di funzionalità, come l'HAL Wi-Fi, all'interno di un APEX del fornitore. Gli sviluppatori possono quindi creare e spingere individualmente il fornitore APEX a testare le modifiche, invece di ricostruire l'intera immagine del fornitore.

Ciò semplifica e accelera il ciclo di iterazione degli sviluppatori per gli sviluppatori che lavorano principalmente in un'area di funzionalità e desiderano eseguire l'iterazione solo su quell'area di funzionalità.

Il naturale raggruppamento di un'area di funzionalità in un APEX semplifica inoltre il processo di creazione, inserimento e test delle modifiche per tale area di funzionalità. Ad esempio, la reinstallazione di APEX aggiorna automaticamente qualsiasi libreria in bundle o file di configurazione inclusi in APEX.

Raggruppare un'area di funzionalità in un APEX semplifica inoltre il debug o il ripristino quando si osserva un comportamento errato del dispositivo. Ad esempio, se la telefonia funziona male in una nuova build, gli sviluppatori potrebbero provare a installare un'implementazione di telefonia precedente APEX su un dispositivo (senza dover eseguire il flashing di una build completa) e verificare se viene ripristinato il buon comportamento.

Flusso di lavoro di esempio:

# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w

# Test the device.
... testing ...

# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...

# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...

Esempi

Nozioni di base

Consulta la pagina principale del formato file APEX per informazioni APEX generiche, inclusi requisiti del dispositivo, dettagli sul formato file e passaggi di installazione.

In Android.bp , l'impostazione della vendor: true rende un modulo APEX un fornitore APEX.

apex {
  ..
  vendor: true,
  ..
}

Binari e librerie condivise

Un APEX include dipendenze transitive all'interno del payload APEX a meno che non dispongano di interfacce stabili.

Le interfacce native stabili per le dipendenze APEX del fornitore includono cc_library con stubs , ndk_library o llndk_library . Queste dipendenze sono escluse dal pacchetto e le dipendenze vengono registrate nel manifest APEX. Il manifest viene elaborato da linkerconfig in modo che le dipendenze native esterne siano disponibili in fase di esecuzione.

A differenza degli APEX nella partizione /system , gli APEX del fornitore sono generalmente legati a una versione VNDK specifica. Le librerie VNDK garantiscono la stabilità ABI all'interno del rilascio, quindi possiamo considerare le librerie VNDK come stabili e ridurre la dimensione degli APEX del fornitore escludendoli dagli APEX utilizzando la proprietà use_vndk_as_stable .

Nello snippet seguente, APEX conterrà sia il file binario ( my_service ) che le sue dipendenze non stabili (file *.so ). Non conterrà librerie VNDK, anche quando my_service è creato con librerie VNDK come libbase . Invece, in fase di runtime my_service utilizzerà libbase dalle librerie VNDK fornite dal sistema.

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

Nello snippet seguente, APEX conterrà la libreria condivisa my_standalone_lib e tutte le sue dipendenze non stabili (come descritto sopra).

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

Implementazioni HAL

Per definire un'implementazione HAL, fornire i file binari e le librerie corrispondenti all'interno di un fornitore APEX simile ai seguenti esempi:

Per incapsulare completamente l'implementazione HAL, APEX dovrebbe anche specificare eventuali frammenti VINTF e script di inizializzazione rilevanti.

Frammenti VINTF

I frammenti VINTF possono essere forniti da un fornitore APEX quando i frammenti si trovano in etc/vintf di APEX.

Utilizza la proprietà prebuilts per incorporare i frammenti VINTF nell'APEX.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

Script di inizializzazione

Gli APEX possono includere script di inizializzazione in due modi: (A) un file di testo predefinito all'interno del payload APEX o (B) uno script di inizializzazione regolare in /vendor/etc . È possibile impostarli entrambi per lo stesso APEX.

Script di inizializzazione in APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

Gli script di inizializzazione all'interno degli APEX possono avere solo definizioni service . Gli script di inizializzazione negli APEX del fornitore possono avere anche direttive on <property> .

Fare attenzione quando si utilizzano on direttive. Poiché gli script di inizializzazione negli APEX vengono analizzati ed eseguiti dopo l'attivazione degli APEX, alcuni eventi o proprietà non possono essere utilizzati. Utilizzare apex.all.ready=true per attivare le azioni il prima possibile.

Firmware

Esempio:

Incorpora il firmware in un APEX del fornitore con il tipo di modulo prebuilt_firmware , come segue.

prebuilt_firmware {
  name: "my.bin",
  src: "path_to_prebuilt_firmware",
  vendor: true,
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.bin"],  // installed inside APEX as /etc/firmware/my.bin
  ..
}

I moduli prebuilt_firmware vengono installati nella directory <apex name>/etc/firmware di APEX. ueventd esegue la scansione delle directory /apex/*/etc/firmware per trovare i moduli firmware.

file_contexts di APEX dovrebbe etichettare correttamente tutte le voci del payload del firmware per garantire che questi file siano accessibili da ueventd in fase di runtime; in genere, l'etichetta vendor_file è sufficiente. Per esempio:

(/.*)? u:object_r:vendor_file:s0

Moduli del kernel

Incorpora i moduli del kernel in un APEX del fornitore come moduli precostruiti, come segue.

prebuilt_etc {
  name: "my.ko",
  src: "my.ko",
  vendor: true,
  sub_dir: "modules"
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.ko"],  // installed inside APEX as /etc/modules/my.ko
  ..
}

file_contexts di APEX dovrebbe etichettare correttamente tutte le voci del payload del modulo kernel. Per esempio:

/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0

I moduli del kernel devono essere installati esplicitamente. Il seguente script init di esempio nella partizione del fornitore mostra l'installazione tramite insmod :

my_init.rc :

on early-boot
  insmod /apex/myapex/etc/modules/my.ko
  ..

Sovrapposizioni di risorse runtime

Esempio:

Incorpora sovrapposizioni di risorse runtime in un APEX del fornitore utilizzando la proprietà rros .

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

Altri file di configurazione

Gli APEX del fornitore supportano vari altri file di configurazione generalmente presenti nella partizione del fornitore come precostruiti all'interno degli APEX del fornitore e altri vengono aggiunti.

Esempi:

Funzionalità di sviluppo aggiuntive

Selezione APEX all'avvio

Esempio:

Gli sviluppatori possono anche installare più versioni di APEX del fornitore che condividono lo stesso nome e chiave APEX, quindi scegliere quale versione attivare durante ogni avvio utilizzando sysprop persistenti. Per alcuni casi d'uso degli sviluppatori, questo potrebbe essere più semplice che installare una nuova copia di APEX utilizzando adb install .

Casi d'uso di esempio:

  • Installa 3 versioni del fornitore HAL Wi-Fi APEX: i team QA possono eseguire test manuali o automatizzati utilizzando una versione, quindi riavviare in un'altra versione ed eseguire nuovamente i test, quindi confrontare i risultati finali.
  • Installa 2 versioni della fotocamera HAL del fornitore APEX, attuale e sperimentale : i dogfooder possono utilizzare la versione sperimentale senza scaricare e installare un file aggiuntivo, in modo da poter facilmente tornare indietro.

Durante l'avvio, apexd cerca i sysprop che seguono un formato specifico per attivare la versione APEX corretta.

I formati previsti per la chiave della proprietà sono:

  • Bootconfig
    • Utilizzato per impostare il valore predefinito, in BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Sistema persistente
    • Utilizzato per modificare il valore predefinito, impostato su un dispositivo già avviato.
    • Sostituisce il valore bootconfig, se presente.
    • persist.vendor.apex.<apex name>

Il valore della proprietà dovrebbe essere il nome file dell'APEX che dovrebbe essere attivato.

// Default version.
apex {
  name: "com.oem.camera.hal.my_apex_default",
  vendor: true,
  ..
}

// Non-default version.
apex {
  name: "com.oem.camera.hal.my_apex_experimental",
  vendor: true,
  ..
}

La versione predefinita dovrebbe essere configurata anche utilizzando bootconfig in BoardConfig.mk :

# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
    androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default

Dopo aver avviato il dispositivo, modificare la versione attivata impostando il sysprop persistente:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

Se il dispositivo supporta l'aggiornamento di bootconfig dopo il flashing (ad esempio tramite comandi fastboot oem ), la modifica della proprietà bootconfig per APEX multiinstallato modifica anche la versione attivata all'avvio.

Per i dispositivi di riferimento virtuali basati su Cuttlefish , puoi utilizzare il comando --extra_bootconfig_args per impostare la proprietà bootconfig direttamente durante l'avvio. Per esempio:

launch_cvd --noresume \
  --extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";