Puoi utilizzare il formato di file APEX per creare pacchetti e installare moduli del sistema operativo Android di livello inferiore. Consente la creazione e l'installazione indipendenti di componenti come servizi e librerie nativi, implementazioni HAL, firmware, file di configurazione e così via.
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à nelle immagini del fornitore.
Quando le immagini del fornitore vengono create come combinazione di APEX del fornitore creati in modo indipendente, i produttori di dispositivi possono scegliere facilmente le implementazioni specifiche del fornitore che vogliono sul proprio dispositivo. I produttori possono persino creare un nuovo APEX fornitore se nessuno degli APEX forniti soddisfa le loro esigenze o se hanno un hardware personalizzato nuovo di zecca.
Ad esempio, un OEM può scegliere di comporre il proprio dispositivo con l'APEX di implementazione Wi-Fi AOSP, l'APEX di implementazione Bluetooth del SoC e un APEX di implementazione di telefonia OEM personalizzato.
Senza gli APEX dei fornitori, un'implementazione con così tante dipendenze tra i componenti dei fornitori richiede un coordinamento e un monitoraggio attenti. Se tutti i componenti (inclusi i file di configurazione e le librerie aggiuntive) vengono inclusi in APEX con interfacce chiaramente definite in qualsiasi punto della comunicazione tra funzionalità, i diversi componenti diventano intercambiabili.
Iterazione dello sviluppatore
Gli APEX dei fornitori aiutano gli sviluppatori a eseguire iterazioni più rapidamente durante lo sviluppo dei moduli dei fornitori raggruppando un'intera implementazione di funzionalità, come l'HAL Wi-Fi, all'interno di un APEX del fornitore. Gli sviluppatori possono quindi creare e inviare singolarmente l'APEX del fornitore per testare le modifiche, anziché ricompilare l'intera immagine del fornitore.
Ciò semplifica e accelera il ciclo di iterazione degli sviluppatori che lavorano principalmente in un'area di funzionalità e vogliono eseguire l'iterazione solo in quell'area.
Il raggruppamento naturale di un'area di funzionalità in un APEX semplifica anche il processo di creazione, push e test delle modifiche per quell'area di funzionalità. Ad esempio, la reinstallazione di un APEX aggiorna automaticamente qualsiasi libreria o file di configurazione in bundle incluso nell'APEX.
Il raggruppamento di un'area di funzionalità in un APEX semplifica anche il debug o il ripristino quando si osserva un comportamento anomalo del dispositivo. Ad esempio, se la telefonia funziona male in una nuova build, gli sviluppatori potrebbero provare a installare un APEX di implementazione della telefonia precedente su un dispositivo (senza dover eseguire il flash di una build completa) e verificare se il comportamento corretto viene ripristinato.
Workflow 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 Formato file APEX per informazioni generiche su APEX, inclusi requisiti del dispositivo, dettagli del formato file e passaggi di installazione.
In Android.bp
, l'impostazione della proprietà vendor: true
rende un modulo APEX un
APEX fornitore.
apex {
..
vendor: true,
..
}
Binari e librerie condivise
Un APEX include le dipendenze transitive all'interno del payload APEX, a meno che non abbiano interfacce stabili.
Le interfacce native stabili per le dipendenze APEX del fornitore includono cc_library
con
stubs
e le librerie LLNDK. Queste dipendenze vengono escluse
dal packaging e vengono registrate nel manifest APEX. Il manifest viene
elaborato da linkerconfig
in modo che le dipendenze native esterne siano
disponibili in fase di runtime.
Nello snippet seguente, l'APEX contiene sia il binario (my_service
) sia le relative dipendenze non stabili (file *.so
).
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
Nel seguente snippet, l'APEX contiene la libreria condivisa
my_standalone_lib
e le relative dipendenze non stabili (come descritto sopra).
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
Riduci le dimensioni di APEX
APEX potrebbe aumentare di dimensioni perché include dipendenze non stabili. Ti consigliamo di utilizzare il collegamento statico. Librerie comuni come libc++.so
e libbase.so
possono essere
collegate staticamente ai file binari HAL. Un'altra opzione è creare una dipendenza per fornire un'interfaccia stabile. La dipendenza non verrà inclusa nell'APEX.
Implementazioni HAL
Per definire un'implementazione HAL, fornisci i binari e le librerie corrispondenti all'interno di un APEX fornitore simile ai seguenti esempi:
Per incapsulare completamente l'implementazione HAL, l'APEX deve specificare anche eventuali frammenti VINTF e script init pertinenti.
Frammenti VINTF
I frammenti VINTF possono essere pubblicati da un APEX fornitore quando si trovano in
etc/vintf
dell'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",
}
API di query
Quando i frammenti VINTF vengono aggiunti ad APEX, utilizza le API libbinder_ndk
per ottenere
i mapping delle interfacce HAL e dei nomi APEX.
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:true
se l'istanza HAL è definita in APEX.AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
: recupera il nome APEX che definisce l'istanza HAL.AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
: utilizza questo comando per aprire un HAL passthrough.
Script di inizializzazione
Gli APEX possono includere script di inizializzazione in due modi: (A) un file di testo precompilato all'interno del
payload APEX o (B) uno script di inizializzazione normale in /vendor/etc
. Puoi impostare 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 negli APEX dei fornitori possono avere definizioni service
e
istruzioni on <property or event>
.
Assicurati che una definizione service
punti a un binario nello stesso APEX.
Ad esempio, com.android.foo
APEX può definire un servizio denominato foo-service
.
on foo-service /apex/com.android.foo/bin/foo
...
Fai attenzione quando utilizzi le direttive on
. Poiché gli script di inizializzazione negli APEX vengono analizzati ed eseguiti dopo l'attivazione degli APEX, non è possibile utilizzare alcuni eventi o proprietà. Utilizza apex.all.ready=true
per attivare le azioni il prima possibile.
Gli APEX di bootstrap possono utilizzare on init
, ma non
on early-init
.
Firmware
Esempio:
Incorpora il firmware in un APEX 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
..
}
prebuilt_firmware
moduli sono installati nella directory <apex name>/etc/firmware
dell'APEX. ueventd
esegue la scansione delle directory /apex/*/etc/firmware
per
trovare i moduli firmware.
Il file_contexts
dell'APEX deve etichettare correttamente tutte le voci del payload del firmware
per garantire che questi file siano accessibili a ueventd
in fase di runtime; in genere, l'etichetta vendor_file
è sufficiente. Ad esempio:
(/.*)? u:object_r:vendor_file:s0
Moduli del kernel
Incorpora i moduli del kernel in un APEX fornitore come moduli precompilati, 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
..
}
Il file_contexts
dell'APEX deve etichettare correttamente tutte le voci del payload del modulo kernel. Ad esempio:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
I moduli kernel devono essere installati in modo esplicito. 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
..
Overlay delle risorse di runtime
Esempio:
Incorpora overlay delle risorse di 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 in genere presenti nella partizione del fornitore come precompilati all'interno degli APEX del fornitore e ne vengono aggiunti altri.
Esempi:
- File XML di dichiarazione delle funzionalità
- XML delle funzionalità dei sensori come prebuilt in un APEX del fornitore HAL dei sensori
- File di configurazione di input
- Configurazioni del touchscreen come precompilati in un APEX fornitore solo di configurazione
Bootstrap Vendor APEXes
Alcuni servizi HAL come keymint
devono essere disponibili prima dell'attivazione degli APEX. Questi HAL di solito impostano early_hal
nella definizione del servizio nello
script di inizializzazione. Un altro esempio è la classe animation
, che in genere inizia
prima dell'evento post-fs-data
. Quando un servizio HAL iniziale di questo tipo viene incluso in un APEX fornitore, crea l'APEX "vendorBootstrap": true
nel relativo manifest APEX in modo che possa essere attivato prima. Tieni presente che gli APEX di bootstrap possono essere
attivati solo dalla posizione predefinita come /vendor/apex
, non da
/data/apex
.
Proprietà di sistema
Queste sono le proprietà di sistema che il framework legge per supportare gli APEX del fornitore:
input_device.config_file.apex=<apex name>
: se impostato, i file di configurazione di input (*.idc
,*.kl
e*.kcm
) vengono cercati nella directory/etc/usr
dell'APEX.ro.vulkan.apex=<apex name>
: se impostato, il driver Vulkan viene caricato da APEX. Poiché il driver Vulkan viene utilizzato dalle prime HAL, crea l'APEX Bootstrap APEX e configura lo spazio dei nomi del linker in modo che sia visibile.
Imposta le proprietà di sistema negli script di inizializzazione utilizzando il comando setprop
.
Funzionalità aggiuntive
Selezione di APEX all'avvio
Esempio:
I file APEX del fornitore possono essere attivati facoltativamente durante l'avvio.
Se specifichi un nome file utilizzando la proprietà di sistema
ro.vendor.apex.<apex name>
, solo l'APEX corrispondente al nome file viene
attivato per il <apex name>
specifico.
L'APEX con <apex name>
viene ignorato (non attivato) se questa proprietà di sistema
è impostata su none
. Puoi utilizzare questa funzionalità per installare più copie di
un APEX con lo stesso nome. Se esistono più versioni dello stesso
APEX, devono condividere la stessa chiave.
Esempi di casi d'uso:
- Installa tre versioni dell'APEX del fornitore HAL Wi-Fi:i team QA possono eseguire test manuali o automatizzati utilizzando una versione, riavviare un'altra versione ed eseguire nuovamente i test, quindi confrontare i risultati finali.
- Installa due versioni dell'APEX del fornitore HAL della fotocamera, attuale e sperimentale: i dogfooder possono utilizzare la versione sperimentale senza scaricare e installare un file aggiuntivo, in modo da poter tornare facilmente alla versione precedente.
Durante l'avvio, apexd
cerca 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>
- Utilizzato per impostare il valore predefinito in
- Persistent sysprop
- Utilizzato per modificare il valore predefinito, impostato su un dispositivo già avviato.
- Se presente, sovrascrive il valore bootconfig.
persist.vendor.apex.<apex name>
Il valore della proprietà deve essere il nome file dell'APEX da
attivare o none
per disattivarlo.
// 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 deve 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 l'avvio del dispositivo, modifica la versione attivata impostando la 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 i comandi fastboot
oem
), la modifica della proprietà bootconfig per l'APEX multi-installato
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. Ad esempio:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";