Il formato contenitore Android Pony EXpress (APEX) è stato introdotto in Android 10 ed è utilizzato nel flusso di installazione per i moduli di sistema di livello inferiore. Questo formato facilita gli aggiornamenti dei componenti di sistema che non rientrano nel modello di applicazione Android standard. Alcuni componenti di esempio sono servizi e librerie nativi, livelli di astrazione hardware ( HAL ), runtime ( ART ) e librerie di classi.
Il termine "APEX" può anche riferirsi a un file APEX.
Sfondo
Sebbene Android supporti gli aggiornamenti dei moduli che rientrano nel modello di app standard (ad esempio, servizi, attività) tramite app di installazione dei pacchetti (come l'app Google Play Store), l'utilizzo di un modello simile per i componenti del sistema operativo di livello inferiore presenta i seguenti svantaggi:
- I moduli basati su APK non possono essere utilizzati all'inizio della sequenza di avvio. Il gestore pacchetti è il repository centrale delle informazioni sulle app e può essere avviato solo dal gestore attività, che diventa pronto in una fase successiva della procedura di avvio.
- Il formato APK (in particolare il manifest) è progettato per le app Android e i moduli di sistema non sono sempre adatti.
Progetto
Questa sezione descrive la progettazione di alto livello del formato di file APEX e del gestore APEX, che è un servizio che gestisce i file APEX.
Per ulteriori informazioni sul motivo per cui è stato scelto questo progetto per APEX, vedere Alternative considerate durante lo sviluppo di APEX .
Formato APEX
Questo è il formato di un file APEX.
Figura 1. Formato file APEX
Al livello superiore, un file APEX è un file zip in cui i file vengono archiviati non compressi e si trovano a limiti di 4 KB.
I quattro file in un file APEX sono:
-
apex_manifest.json
-
AndroidManifest.xml
-
apex_payload.img
-
apex_pubkey
Il file apex_manifest.json
contiene il nome e la versione del pacchetto, che identificano un file APEX. Questo è un buffer di protocollo ApexManifest
in formato JSON.
Il file AndroidManifest.xml
consente al file APEX di utilizzare gli strumenti e l'infrastruttura relativi all'APK come ADB, PackageManager e le app di installazione dei pacchetti (come Play Store). Ad esempio, il file APEX può utilizzare uno strumento esistente come aapt
per ispezionare i metadati di base dal file. Il file contiene il nome del pacchetto e le informazioni sulla versione. Queste informazioni sono generalmente disponibili anche in apex_manifest.json
.
apex_manifest.json
è consigliato su AndroidManifest.xml
per il nuovo codice e i sistemi che gestiscono APEX. AndroidManifest.xml
potrebbe contenere ulteriori informazioni sul targeting che possono essere utilizzate dagli strumenti di pubblicazione delle app esistenti.
apex_payload.img
è un'immagine del file system ext4 supportata da dm-verity. L'immagine viene montata in fase di esecuzione tramite un dispositivo di loopback. In particolare, l'albero hash e il blocco di metadati vengono creati utilizzando la libreria libavb
. Il payload del file system non viene analizzato (perché l'immagine dovrebbe essere montabile sul posto). I file normali sono inclusi nel file apex_payload.img
.
apex_pubkey
è la chiave pubblica utilizzata per firmare l'immagine del file system. In fase di esecuzione, questa chiave garantisce che l'APEX scaricato sia firmato con la stessa entità che firma lo stesso APEX nelle partizioni integrate.
Linee guida per la denominazione APEX
Per evitare conflitti di denominazione tra i nuovi APEX man mano che la piattaforma avanza, utilizza le seguenti linee guida per la denominazione:
-
com.android.*
- Riservato agli APEX AOSP. Non univoco per qualsiasi azienda o dispositivo.
-
com.<companyname>.*
- Riservato a un'azienda. Potenzialmente utilizzato da più dispositivi di quella società.
-
com.<companyname>.<devicename>.*
- Riservato agli APEX univoci per un dispositivo specifico (o sottoinsieme di dispositivi).
Responsabile APEX
Il gestore APEX (o apexd
) è un processo nativo autonomo responsabile della verifica, installazione e disinstallazione dei file APEX. Questo processo viene avviato ed è pronto all'inizio della sequenza di avvio. I file APEX sono normalmente preinstallati sul dispositivo in /system/apex
. Per impostazione predefinita, il gestore APEX utilizza questi pacchetti se non sono disponibili aggiornamenti.
La sequenza di aggiornamento di un APEX utilizza la classe PackageManager ed è la seguente.
- Un file APEX viene scaricato tramite un'app di installazione del pacchetto, ADB o un'altra fonte.
- Il gestore pacchetti avvia la procedura di installazione. Dopo aver riconosciuto che il file è un APEX, il gestore pacchetti trasferisce il controllo al gestore APEX.
- Il gestore APEX verifica il file APEX.
- Se il file APEX viene verificato, il database interno del gestore APEX viene aggiornato per indicare che il file APEX viene attivato all'avvio successivo.
- Il richiedente dell'installazione riceve una trasmissione dopo che la verifica del pacchetto è andata a buon fine.
- Per continuare l'installazione, il sistema deve essere riavviato.
Al successivo avvio, il gestore APEX si avvia, legge il database interno ed esegue le seguenti operazioni per ciascun file APEX elencato:
- Verifica il file APEX.
- Crea un dispositivo di loopback dal file APEX.
- Crea un dispositivo a blocchi del mapper del dispositivo sopra il dispositivo di loopback.
- Monta il dispositivo a blocchi del mapper di dispositivi su un percorso univoco (ad esempio,
/apex/ name @ ver
).
Quando vengono montati tutti i file APEX elencati nel database interno, il gestore APEX fornisce un servizio raccoglitore per altri componenti di sistema per richiedere informazioni sui file APEX installati. Ad esempio, gli altri componenti del sistema possono interrogare l'elenco dei file APEX installati nel dispositivo o interrogare il percorso esatto in cui è montato un APEX specifico, in modo da poter accedere ai file.
I file APEX sono file APK
I file APEX sono file APK validi perché sono archivi zip firmati (utilizzando lo schema di firma APK) contenenti un file AndroidManifest.xml
. Ciò consente ai file APEX di utilizzare l'infrastruttura per i file APK, come un'app di installazione dei pacchetti, l'utilità di firma e il gestore dei pacchetti.
Il file AndroidManifest.xml
all'interno di un file APEX è minimo e comprende il name
del pacchetto , versionCode
e targetSdkVersion
, minSdkVersion
e maxSdkVersion
facoltativi per il targeting granulare. Queste informazioni consentono la consegna dei file APEX tramite canali esistenti come le app di installazione dei pacchetti e ADB.
Tipi di file supportati
Il formato APEX supporta questi tipi di file:
- Librerie condivise native
- Eseguibili nativi
- file JAR
- File di dati
- File di configurazione
Ciò non significa che APEX può aggiornare tutti questi tipi di file. La possibilità di aggiornare un tipo di file dipende dalla piattaforma e dalla stabilità delle definizioni delle interfacce per i tipi di file.
Opzioni di firma
I file APEX sono firmati in due modi. Innanzitutto, il file apex_payload.img
(in particolare, il descrittore vbmeta aggiunto a apex_payload.img
) è firmato con una chiave. Quindi, l'intero APEX viene firmato utilizzando lo schema di firma APK v3 . In questo processo vengono utilizzate due chiavi diverse.
Lato dispositivo, viene installata una chiave pubblica corrispondente alla chiave privata utilizzata per firmare il descrittore vbmeta. Il gestore APEX utilizza la chiave pubblica per verificare gli APEX di cui è richiesta l'installazione. Ogni APEX deve essere firmato con chiavi diverse e viene applicato sia in fase di compilazione che in fase di esecuzione.
APEX nelle partizioni integrate
I file APEX possono trovarsi in partizioni integrate come /system
. La partizione è già su dm-verity, quindi i file APEX vengono montati direttamente sul dispositivo di loopback.
Se un APEX è presente in una partizione incorporata, l'APEX può essere aggiornato fornendo un pacchetto APEX con lo stesso nome pacchetto e un codice versione maggiore o uguale a. Il nuovo APEX è archiviato in /data
e, analogamente agli APK, la versione appena installata oscura la versione già presente nella partizione integrata. Ma a differenza degli APK, la versione appena installata di APEX viene attivata solo dopo il riavvio.
Requisiti del kernel
Per supportare i moduli della linea principale APEX su un dispositivo Android, sono necessarie le seguenti funzionalità del kernel Linux: il driver di loopback e dm-verity. Il driver di loopback monta l'immagine del file system in un modulo APEX e dm-verity verifica il modulo APEX.
Le prestazioni del driver di loopback e di dm-verity sono importanti per ottenere buone prestazioni del sistema quando si utilizzano i moduli APEX.
Versioni del kernel supportate
I moduli della linea principale APEX sono supportati sui dispositivi che utilizzano le versioni del kernel 4.4 o successive. I nuovi dispositivi avviati con Android 10 o versioni successive devono utilizzare la versione 4.9 o successiva del kernel per supportare i moduli APEX.
Patch del kernel richieste
Le patch del kernel richieste per il supporto dei moduli APEX sono incluse nell'albero comune di Android. Per fare in modo che le patch supportino APEX, utilizzare l'ultima versione dell'albero comune di Android.
Kernel versione 4.4
Questa versione è supportata solo per i dispositivi aggiornati da Android 9 ad Android 10 e che desiderano supportare i moduli APEX. Per ottenere le patch richieste, si consiglia vivamente di effettuare un down-merge dal ramo android-4.4
. Di seguito è riportato un elenco delle singole patch richieste per la versione 4.4 del kernel.
- UPSTREAM: ciclo: aggiungi ioctl per modificare la dimensione del blocco logico ( 4.4 )
- BACKPORT: blocco/loop: set hw_sectors ( 4.4 )
- UPSTREAM: loop: Aggiungi LOOP_SET_BLOCK_SIZE in compat ioctl ( 4.4 )
- ANDROID: mnt: Fix next_descendent ( 4.4 )
- ANDROID: mnt: remount dovrebbe propagarsi agli schiavi degli schiavi ( 4.4 )
- ANDROID: mnt: propaga correttamente il rimontaggio ( 4.4 )
- Ripristina "ANDROID: dm verity: aggiungi dimensioni minime di prelettura" ( 4.4 )
- UPSTREAM: loop: elimina le cache se vengono modificati offset o block_size ( 4.4 )
Versioni del kernel 4.9/4.14/4.19
Per ottenere le patch richieste per le versioni del kernel 4.9/4.14/4.19, eseguire il down-merge dal ramo android-common
.
Opzioni di configurazione del kernel richieste
L'elenco seguente mostra i requisiti di configurazione di base per il supporto dei moduli APEX introdotti in Android 10. Gli elementi con un asterisco (*) sono requisiti esistenti da Android 9 e versioni precedenti.
(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support
Requisiti dei parametri della riga di comando del kernel
Per supportare APEX, assicurati che i parametri della riga di comando del kernel soddisfino i seguenti requisiti:
-
loop.max_loop
NON deve essere impostato -
loop.max_part
deve essere <= 8
Costruisci un APEX
Questa sezione descrive come creare un APEX utilizzando il sistema di compilazione Android. Di seguito è riportato un esempio di Android.bp
per un APEX denominato apex.test
.
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
// libc.so and libcutils.so are included in the apex
native_shared_libs: ["libc", "libcutils"],
binaries: ["vold"],
java_libs: ["core-all"],
prebuilts: ["my_prebuilt"],
compile_multilib: "both",
key: "apex.test.key",
certificate: "platform",
}
esempio apex_manifest.json
:
{
"name": "com.android.example.apex",
"version": 1
}
esempio file_contexts
:
(/.*)? u:object_r:system_file:s0
/sub(/.*)? u:object_r:sub_file:s0
/sub/file3 u:object_r:file3_file:s0
Tipi di file e posizioni in APEX
Tipo di file | Posizione in APEX |
---|---|
Librerie condivise | /lib e /lib64 ( /lib/arm per braccio tradotto in x86) |
Eseguibili | /bin |
Librerie Java | /javalib |
Precostruiti | /etc |
Dipendenze transitive
I file APEX includono automaticamente dipendenze transitive di librerie condivise native o eseguibili. Ad esempio, se libFoo
dipende da libBar
, le due librerie sono incluse quando solo libFoo
è elencato nella proprietà native_shared_libs
.
Gestisci più ABI
Installa la proprietà native_shared_libs
per le interfacce binarie dell'applicazione (ABI) primarie e secondarie del dispositivo. Se un APEX è destinato a dispositivi con un singolo ABI (ovvero solo a 32 bit o solo a 64 bit), vengono installate solo le librerie con l'ABI corrispondente.
Installa la proprietà binaries
solo per l'ABI principale del dispositivo come descritto di seguito:
- Se il dispositivo è solo a 32 bit, viene installata solo la variante a 32 bit del binario.
- Se il dispositivo è solo a 64 bit, viene installata solo la variante a 64 bit del file binario.
Per aggiungere un controllo granulare sugli ABI delle librerie e dei binari nativi, utilizzare le proprietà multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]
.
-
first
: corrisponde all'ABI principale del dispositivo. Questa è l'impostazione predefinita per i file binari. -
lib32
: corrisponde all'ABI a 32 bit del dispositivo, se supportato. -
lib64
: corrisponde all'ABI a 64 bit del dispositivo, supportato. -
prefer32
: corrisponde all'ABI a 32 bit del dispositivo, se supportato. Se l'ABI a 32 bit non è supportato, corrisponde all'ABI a 64 bit. -
both
: corrisponde a entrambi gli ABI. Questa è l'impostazione predefinita pernative_shared_libraries
.
Le proprietà java
, libraries
e prebuilts
sono indipendenti dall'ABI.
Questo esempio è per un dispositivo che supporta 32/64 e non preferisce 32:
apex {
// other properties are omitted
native_shared_libs: ["libFoo"], // installed for 32 and 64
binaries: ["exec1"], // installed for 64, but not for 32
multilib: {
first: {
native_shared_libs: ["libBar"], // installed for 64, but not for 32
binaries: ["exec2"], // same as binaries without multilib.first
},
both: {
native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
binaries: ["exec3"], // installed for 32 and 64
},
prefer32: {
native_shared_libs: ["libX"], // installed for 32, but not for 64
},
lib64: {
native_shared_libs: ["libY"], // installed for 64, but not for 32
},
},
}
firma vbmeta
Firma ogni APEX con chiavi diverse. Quando è richiesta una nuova chiave, crea una coppia di chiavi pubblica-privata e crea un modulo apex_key
. Utilizzare la proprietà key
per firmare l'APEX utilizzando la chiave. La chiave pubblica viene inclusa automaticamente nell'APEX con il nome avb_pubkey
.
# create an rsa key pairopenssl genrsa -out foo.pem 4096
# extract the public key from the key pairavbtool extract_public_key --key foo.pem --output foo.avbpubkey
# in Android.bpapex_key { name: "apex.test.key", public_key: "foo.avbpubkey", private_key: "foo.pem", }
Nell'esempio precedente, il nome della chiave pubblica ( foo
) diventa l'ID della chiave. L'ID della chiave utilizzata per firmare un APEX è scritto nell'APEX. In fase di esecuzione, apexd
verifica l'APEX utilizzando una chiave pubblica con lo stesso ID nel dispositivo.
Firma APEX
Firma gli APEX nello stesso modo in cui firmi gli APK. Firma APEX due volte; una volta per il mini file system ( apex_payload.img
file) e una volta per l'intero file.
Per firmare un APEX a livello di file, imposta la proprietà certificate
in uno di questi tre modi:
- Non impostato: se non è impostato alcun valore, l'APEX viene firmato con il certificato che si trova in
PRODUCT_DEFAULT_DEV_CERTIFICATE
. Se non è impostato alcun flag, il percorso predefinito èbuild/target/product/security/testkey
. -
<name>
: l'APEX è firmato con il certificato<name>
nella stessa directory diPRODUCT_DEFAULT_DEV_CERTIFICATE
. -
:<name>
: APEX è firmato con il certificato definito dal modulo Soong denominato<name>
. Il modulo del certificato può essere definito come segue.
android_app_certificate {
name: "my_key_name",
certificate: "dir/cert",
// this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}
Installa un APEX
Per installare un APEX, utilizzare ADB.
adb install apex_file_name
adb reboot
Se supportsRebootlessUpdate
è impostato su true
in apex_manifest.json
e l'APEX attualmente installato non è utilizzato (ad esempio, tutti i servizi in esso contenuti sono stati arrestati), è possibile installare un nuovo APEX senza riavviare con il flag --force-non-staged
.
adb install --force-non-staged apex_file_name
Usa un APEX
Dopo il riavvio, l'APEX viene montato nella directory /apex/<apex_name>@<version>
. È possibile montare contemporaneamente più versioni dello stesso APEX. Tra i percorsi di montaggio, quello che corrisponde alla versione più recente è montato su bind in /apex/<apex_name>
.
I client possono utilizzare il percorso montato su bind per leggere o eseguire file da APEX.
Gli APEX vengono generalmente utilizzati come segue:
- Un OEM o un ODM precarica un APEX in
/system/apex
quando il dispositivo viene spedito. - È possibile accedere ai file nell'APEX tramite il percorso
/apex/<apex_name>/
. - Quando una versione aggiornata di APEX viene installata in
/data/apex
, il percorso punta al nuovo APEX dopo il riavvio.
Aggiorna un servizio con un APEX
Per aggiornare un servizio utilizzando un APEX:
Contrassegna il servizio nella partizione di sistema come aggiornabile. Aggiungere l'opzione
updatable
alla definizione del servizio./system/etc/init/myservice.rc: service myservice /system/bin/myservice class core user system ... updatable
Crea un nuovo file
.rc
per il servizio aggiornato. Utilizzare l'opzioneoverride
per ridefinire il servizio esistente./apex/my.apex/etc/init.rc: service myservice /apex/my.apex/bin/myservice class core user system ... override
Le definizioni dei servizi possono essere definite solo nel file .rc
di un APEX. I trigger di azione non sono supportati negli APEX.
Se un servizio contrassegnato come aggiornabile viene avviato prima dell'attivazione degli APEX, l'avvio viene ritardato fino al completamento dell'attivazione degli APEX.
Configurare il sistema per supportare gli aggiornamenti APEX
Impostare la seguente proprietà di sistema su true
per supportare gli aggiornamenti dei file APEX.
<device.mk>:
PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true
BoardConfig.mk:
TARGET_FLATTEN_APEX := false
o semplicemente
<device.mk>:
$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
APEX appiattito
Per i dispositivi legacy, a volte è impossibile o irrealizzabile aggiornare il vecchio kernel per supportare completamente APEX. Ad esempio, il kernel potrebbe essere stato compilato senza CONFIG_BLK_DEV_LOOP=Y
, che è fondamentale per montare l'immagine del file system all'interno di un APEX.
L'APEX appiattito è un APEX appositamente creato che può essere attivato su dispositivi con un kernel legacy. I file in un APEX appiattito vengono installati direttamente in una directory sotto la partizione incorporata. Ad esempio, lib/libFoo.so
in un APEX appiattito my.apex
viene installato in /system/apex/my.apex/lib/libFoo.so
.
L'attivazione di un APEX appiattito non coinvolge il dispositivo loop. L'intera directory /system/apex/my.apex
è direttamente montata tramite bind su /apex/name@ver
.
Gli APEX appiattiti non possono essere aggiornati scaricando le versioni aggiornate degli APEX dalla rete perché gli APEX scaricati non possono essere appiattiti. Gli APEX appiattiti possono essere aggiornati solo tramite un normale OTA.
L'APEX appiattito è la configurazione predefinita. Ciò significa che tutti gli APEX sono appiattiti per impostazione predefinita, a meno che non si configuri esplicitamente il dispositivo per creare APEX non appiattiti per supportare gli aggiornamenti APEX (come spiegato sopra).
La combinazione di APEX appiattiti e non appiattiti in un dispositivo NON è supportata. Gli APEX in un dispositivo devono essere tutti non appiattiti o tutti appiattiti. Questo è particolarmente importante quando si spediscono APEX pre-firmati per progetti come Mainline. Anche gli APEX che non sono prefirmati (ovvero creati dall'origine) devono essere non appiattiti e firmati con le chiavi appropriate. Il dispositivo dovrebbe ereditare da updatable_apex.mk
come spiegato in Aggiornamento di un servizio con un APEX .
APEX compressi
Android 12 e versioni successive presentano la compressione APEX per ridurre l'impatto sull'archiviazione dei pacchetti APEX aggiornabili. Dopo l'installazione di un aggiornamento di un APEX, anche se la sua versione preinstallata non viene più utilizzata, occupa comunque la stessa quantità di spazio. Quello spazio occupato rimane non disponibile.
La compressione APEX riduce al minimo questo impatto sull'archiviazione utilizzando un set altamente compresso di file APEX su partizioni di sola lettura (come la partizione /system
). Android 12 e versioni successive utilizzano un algoritmo di compressione zip DEFLATE.
La compressione non fornisce l'ottimizzazione a quanto segue:
APEX Bootstrap che devono essere montati molto presto nella sequenza di avvio.
APEX non aggiornabili. La compressione è vantaggiosa solo se nella partizione
/data
è installata una versione aggiornata di un APEX. Un elenco completo degli APEX aggiornabili è disponibile nella pagina Componenti del sistema modulare .APEX delle librerie condivise dinamiche. Poiché
apexd
attiva sempre entrambe le versioni di tali APEX (preinstallate e aggiornate), la loro compressione non aggiunge valore.
Formato di file APEX compresso
Questo è il formato di un file APEX compresso.
Figura 2. Formato di file APEX compresso
Al livello superiore, un file APEX compresso è un file zip contenente il file apex originale in forma sgonfia con un livello di compressione di 9 e con altri file archiviati non compressi.
Quattro file comprendono un file APEX:
-
original_apex
: sgonfiato con livello di compressione 9 Questo è il file APEX originale non compresso . -
apex_manifest.pb
: memorizzato solo -
AndroidManifest.xml
: solo memorizzato -
apex_pubkey
: memorizzato solo
I apex_manifest.pb
, AndroidManifest.xml
e apex_pubkey
sono copie dei file corrispondenti in original_apex
.
Crea APEX compresso
L'APEX compresso può essere creato utilizzando lo strumento apex_compression_tool.py
disponibile in system/apex/tools
.
Diversi parametri relativi alla compressione APEX sono disponibili nel sistema di compilazione.
In Android.bp
se un file APEX è comprimibile è controllato dalla proprietà compressible
:
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
compressible: true,
}
Un flag di prodotto PRODUCT_COMPRESSED_APEX
controlla se un'immagine di sistema creata dall'origine deve contenere file APEX compressi.
Per la sperimentazione locale puoi forzare una build a comprimere gli APEX impostando OVERRIDE_PRODUCT_COMPRESSED_APEX=
su true
.
I file APEX compressi generati dal sistema di compilazione hanno l'estensione .capex
. L'estensione semplifica la distinzione tra versioni compresse e non compresse di un file APEX.
Algoritmi di compressione supportati
Android 12 supporta solo la compressione deflate-zip.
Attiva un file APEX compresso durante l'avvio
Prima che un APEX compresso possa essere attivato, il file original_apex
al suo interno viene decompresso nella directory /data/apex/decompressed
. Il file APEX decompresso risultante è collegato alla directory /data/apex/active
.
Si consideri l'esempio seguente come illustrazione del processo sopra descritto.
Considera /system/apex/com.android.foo.capex
come APEX compresso in fase di attivazione, con versionCode 37.
- Il file
original_apex
all'interno di/system/apex/com.android.foo.capex
viene decompresso in/data/apex/decompressed/com.android.foo@37.apex
. -
restorecon /data/apex/decompressed/com.android.foo@37.apex
viene eseguito per verificare che abbia un'etichetta SELinux corretta. - I controlli di verifica vengono eseguiti su
/data/apex/decompressed/com.android.foo@37.apex
per assicurarne la validità:apexd
controlla la chiave pubblica inclusa in/data/apex/decompressed/com.android.foo@37.apex
per verificare che sia uguale a quello in bundle in/system/apex/com.android.foo.capex
. - Il file
/data/apex/decompressed/com.android.foo@37.apex
è collegato alla directory/data/apex/active/com.android.foo@37.apex
. - La normale logica di attivazione per i file APEX non compressi viene eseguita su
/data/apex/active/com.android.foo@37.apex
.
Interazione con OTA
I file APEX compressi hanno implicazioni sulla consegna e sull'applicazione OTA. Poiché un aggiornamento OTA potrebbe contenere un file APEX compresso con un livello di versione superiore a quello attivo su un dispositivo, è necessario riservare una certa quantità di spazio libero prima che un dispositivo venga riavviato per applicare un aggiornamento OTA.
Per supportare il sistema OTA, apexd
espone queste due API del raccoglitore:
-
calculateSizeForCompressedApex
: calcola la dimensione richiesta per decomprimere i file APEX in un pacchetto OTA. Questo può essere utilizzato per verificare che un dispositivo disponga di spazio sufficiente prima che venga scaricato un OTA. -
reserveSpaceForCompressedApex
- riserva spazio sul disco per uso futuro da parte diapexd
per decomprimere i file APEX compressi all'interno del pacchetto OTA.
Nel caso di un aggiornamento OTA A/B, apexd
tenta la decompressione in background come parte della routine OTA post-installazione. Se la decompressione fallisce, apexd
esegue la decompressione durante l'avvio che applica l'aggiornamento OTA.
Alternative considerate durante lo sviluppo di APEX
Ecco alcune opzioni che AOSP ha preso in considerazione durante la progettazione del formato file APEX e il motivo per cui sono state incluse o escluse.
Regolari sistemi di gestione dei pacchetti
Le distribuzioni Linux hanno sistemi di gestione dei pacchetti come dpkg
e rpm
, che sono potenti, maturi e robusti. Tuttavia, non sono stati adottati per APEX perché non possono proteggere i pacchetti dopo l'installazione. La verifica viene eseguita solo durante l'installazione dei pacchetti. Gli aggressori possono violare l'integrità dei pacchetti installati, senza essere notati. Questa è una regressione per Android in cui tutti i componenti di sistema sono stati archiviati in file system di sola lettura la cui integrità è protetta da dm-verity per ogni I/O. Qualsiasi manomissione ai componenti del sistema deve essere proibita o essere rilevabile in modo che il dispositivo possa rifiutarsi di avviarsi se compromesso.
dm-crypt per l'integrità
I file in un contenitore APEX provengono da partizioni integrate (ad esempio, la partizione /system
) protette da dm-verity, dove qualsiasi modifica ai file è proibita anche dopo che le partizioni sono state montate. Per fornire lo stesso livello di sicurezza ai file, tutti i file in un APEX vengono archiviati in un'immagine del file system abbinata a un albero hash e un descrittore vbmeta. Senza dm-verity, un APEX nella partizione /data
è vulnerabile a modifiche indesiderate apportate dopo che è stato verificato e installato.
Infatti, anche la partizione /data
è protetta da livelli di crittografia come dm-crypt. Sebbene ciò fornisca un certo livello di protezione contro la manomissione, il suo scopo principale è la privacy, non l'integrità. Quando un utente malintenzionato ottiene l'accesso alla partizione /data
, non può esserci ulteriore protezione e anche questa è una regressione rispetto a ogni componente di sistema che si trova nella partizione /system
. L'albero hash all'interno di un file APEX insieme a dm-verity fornisce lo stesso livello di protezione dei contenuti.
Reindirizza i percorsi da /system a /apex
I file dei componenti di sistema inclusi in un APEX sono accessibili tramite nuovi percorsi come /apex/<name>/lib/libfoo.so
. Quando i file facevano parte della partizione /system
, erano accessibili tramite percorsi come /system/lib/libfoo.so
. Un client di un file APEX (altri file APEX o la piattaforma) deve utilizzare i nuovi percorsi. Potrebbe essere necessario aggiornare il codice esistente in seguito alla modifica del percorso.
Sebbene un modo per evitare la modifica del percorso sia sovrapporre il contenuto del file in un file APEX sulla partizione /system
, il team di Android ha deciso di non sovrapporre i file sulla partizione /system
perché ciò potrebbe influire sulle prestazioni in quanto il numero di file viene sovrapposto ( possibilmente anche impilati uno dopo l'altro) aumentati.
Un'altra opzione era dirottare le funzioni di accesso ai file come open
, stat
e readlink
, in modo che i percorsi che iniziano con /system
fossero reindirizzati ai percorsi corrispondenti in /apex
. Il team di Android ha scartato questa opzione perché non è possibile modificare tutte le funzioni che accettano percorsi. Ad esempio, alcune app collegano staticamente Bionic, che ne implementa le funzioni. In tali casi, tali app non vengono reindirizzate.