Das Containerformat Android Pony EXpress (APEX) wurde in Android 10 eingeführt und wird im Installationsablauf für untergeordnete Systemmodule verwendet. Dieses Format erleichtert die Aktualisierung von Systemkomponenten, die nicht in das standardmäßige Android-Anwendungsmodell passen. Einige Beispielkomponenten sind native Dienste und Bibliotheken, Hardwareabstraktionsschichten ( HALs ), Laufzeit ( ART ) und Klassenbibliotheken.
Der Begriff „APEX“ kann sich auch auf eine APEX-Datei beziehen.
Hintergrund
Obwohl Android Updates von Modulen unterstützt, die in das Standard-App-Modell (z. B. Dienste, Aktivitäten) über Paketinstallations-Apps (z. B. die Google Play Store-App) passen, hat die Verwendung eines ähnlichen Modells für untergeordnete Betriebssystemkomponenten die folgenden Nachteile:
- APK-basierte Module können nicht früh in der Startsequenz verwendet werden. Der Paketmanager ist die zentrale Ablage für Informationen über Apps und kann nur aus dem Aktivitätsmanager gestartet werden, der in einem späteren Stadium des Bootvorgangs bereitsteht.
- Das APK-Format (insbesondere das Manifest) ist für Android-Apps konzipiert, und Systemmodule passen nicht immer gut.
Entwurf
Dieser Abschnitt beschreibt das High-Level-Design des APEX-Dateiformats und des APEX-Managers, eines Dienstes, der APEX-Dateien verwaltet.
Weitere Informationen dazu, warum dieses Design für APEX ausgewählt wurde, finden Sie unter Bei der Entwicklung von APEX berücksichtigte Alternativen .
APEX-Format
Dies ist das Format einer APEX-Datei.
Abbildung 1. APEX-Dateiformat
Auf der obersten Ebene ist eine APEX-Datei eine ZIP-Datei, in der Dateien unkomprimiert gespeichert werden und sich an 4-KB-Grenzen befinden.
Die vier Dateien in einer APEX-Datei sind:
-
apex_manifest.json
-
AndroidManifest.xml
-
apex_payload.img
-
apex_pubkey
Die Datei apex_manifest.json
enthält den Paketnamen und die Version, die eine APEX-Datei identifizieren.
Die Datei AndroidManifest.xml
“ ermöglicht der APEX-Datei die Verwendung von APK-bezogenen Tools und Infrastrukturen wie ADB, PackageManager und Paketinstallationsprogramm-Apps (z. B. Play Store). Beispielsweise kann die APEX-Datei ein vorhandenes Tool wie aapt
, um grundlegende Metadaten aus der Datei zu untersuchen. Die Datei enthält Paketnamen und Versionsinformationen. Diese Informationen sind im Allgemeinen auch in apex_manifest.json
verfügbar.
apex_manifest.json
wird gegenüber AndroidManifest.xml
für neuen Code und Systeme empfohlen, die sich mit APEX befassen. AndroidManifest.xml
enthält möglicherweise zusätzliche Targeting-Informationen, die von den vorhandenen App-Veröffentlichungstools verwendet werden können.
apex_payload.img
ist ein ext4-Dateisystem-Image, das von dm-verity unterstützt wird. Das Image wird zur Laufzeit über ein Loopback-Gerät gemountet. Insbesondere werden der Hash-Baum und der Metadatenblock mit der libavb
Bibliothek erstellt. Die Nutzlast des Dateisystems wird nicht analysiert (da das Image an Ort und Stelle bereitgestellt werden sollte). Reguläre Dateien sind in der Datei apex_payload.img
enthalten.
apex_pubkey
ist der öffentliche Schlüssel, der zum Signieren des Dateisystem-Image verwendet wird. Zur Laufzeit stellt dieser Schlüssel sicher, dass das heruntergeladene APEX mit derselben Entität signiert wird, die dasselbe APEX in den integrierten Partitionen signiert.
APEX-Namensrichtlinien
Verwenden Sie die folgenden Benennungsrichtlinien, um Namenskonflikte zwischen neuen APEXs zu vermeiden, wenn die Plattform voranschreitet:
-
com.android.*
- Reserviert für AOSP-APEX. Nicht einzigartig für ein Unternehmen oder Gerät.
-
com.<companyname>.*
- Reserviert für ein Unternehmen. Wird möglicherweise von mehreren Geräten dieses Unternehmens verwendet.
-
com.<companyname>.<devicename>.*
- Reserviert für APEXs, die nur für ein bestimmtes Gerät (oder eine Teilmenge von Geräten) gelten.
APEX-Manager
Der APEX-Manager (oder apexd
) ist ein eigenständiger nativer Prozess, der für die Überprüfung, Installation und Deinstallation von APEX-Dateien verantwortlich ist. Dieser Prozess wird gestartet und ist früh in der Startsequenz bereit. APEX-Dateien sind normalerweise auf dem Gerät unter /system/apex
vorinstalliert. Der APEX-Manager verwendet standardmäßig diese Pakete, wenn keine Updates verfügbar sind.
Die Aktualisierungssequenz eines APEX verwendet die PackageManager-Klasse und ist wie folgt.
- Eine APEX-Datei wird über eine Paketinstallations-App, ADB oder eine andere Quelle heruntergeladen.
- Der Paketmanager startet den Installationsvorgang. Beim Erkennen, dass die Datei ein APEX ist, überträgt der Paketmanager die Kontrolle an den APEX-Manager.
- Der APEX-Manager überprüft die APEX-Datei.
- Wenn die APEX-Datei überprüft wird, wird die interne Datenbank des APEX-Managers aktualisiert, um widerzuspiegeln, dass die APEX-Datei beim nächsten Start aktiviert wird.
- Der Installations-Anforderer erhält nach erfolgreicher Paketüberprüfung eine Rundsendung.
- Um die Installation fortzusetzen, muss das System neu gestartet werden.
Beim nächsten Start startet der APEX-Manager, liest die interne Datenbank und führt für jede aufgeführte APEX-Datei Folgendes aus:
- Überprüft die APEX-Datei.
- Erstellt ein Loopback-Gerät aus der APEX-Datei.
- Erstellt ein Device-Mapper-Blockgerät auf dem Loopback-Gerät.
- Stellt das Device-Mapper-Blockgerät auf einem eindeutigen Pfad bereit (z. B.
/apex/ name @ ver
).
Wenn alle in der internen Datenbank aufgelisteten APEX-Dateien gemountet sind, stellt der APEX-Manager einen Bindedienst für andere Systemkomponenten bereit, um Informationen über die installierten APEX-Dateien abzufragen. Beispielsweise können die anderen Systemkomponenten die Liste der auf dem Gerät installierten APEX-Dateien abfragen oder den genauen Pfad abfragen, an dem ein bestimmtes APEX gemountet ist, damit auf die Dateien zugegriffen werden kann.
APEX-Dateien sind APK-Dateien
APEX-Dateien sind gültige APK-Dateien, da es sich um signierte ZIP-Archive (unter Verwendung des APK-Signaturschemas) handelt, die eine AndroidManifest.xml
-Datei enthalten. Dadurch können APEX-Dateien die Infrastruktur für APK-Dateien verwenden, z. B. eine Paketinstallations-App, das Signaturdienstprogramm und den Paketmanager.
Die Datei AndroidManifest.xml
in einer APEX-Datei ist minimal und besteht aus dem name
, versionCode
und optional targetSdkVersion
, minSdkVersion
und maxSdkVersion
für eine feinkörnige Ausrichtung. Diese Informationen ermöglichen die Bereitstellung von APEX-Dateien über vorhandene Kanäle wie Paketinstallations-Apps und ADB.
Unterstützte Dateitypen
Das APEX-Format unterstützt diese Dateitypen:
- Native gemeinsam genutzte Bibliotheken
- Native ausführbare Dateien
- JAR-Dateien
- Datei
- Konfigurationsdateien
Dies bedeutet nicht, dass APEX alle diese Dateitypen aktualisieren kann. Ob ein Dateityp aktualisiert werden kann, hängt von der Plattform ab und davon, wie stabil die Definitionen der Schnittstellen für die Dateitypen sind.
Unterzeichnung
APEX-Dateien werden auf zwei Arten signiert. Zuerst wird die apex_payload.img
(insbesondere der an apex_payload.img angehängte apex_payload.img
-Deskriptor) mit einem Schlüssel signiert. Anschließend wird das gesamte APEX mit dem APK-Signaturschema v3 signiert. Dabei werden zwei unterschiedliche Schlüssel verwendet.
Auf der Geräteseite wird ein öffentlicher Schlüssel installiert, der dem privaten Schlüssel entspricht, der zum Signieren des vbmeta-Deskriptors verwendet wird. Der APEX-Manager verwendet den öffentlichen Schlüssel, um APEXs zu überprüfen, deren Installation angefordert wird. Jeder APEX muss mit unterschiedlichen Schlüsseln signiert werden und wird sowohl zur Erstellungszeit als auch zur Laufzeit erzwungen.
APEX in integrierten Partitionen
APEX-Dateien können sich in integrierten Partitionen wie /system
. Die Partition ist bereits über dm-verity, sodass die APEX-Dateien direkt über das Loopback-Gerät gemountet werden.
Wenn ein APEX in einer integrierten Partition vorhanden ist, kann das APEX aktualisiert werden, indem ein APEX-Paket mit demselben Paketnamen und einem Versionscode größer oder gleich bereitgestellt wird. Das neue APEX wird in /data
gespeichert und ähnlich wie bei APKs spiegelt die neu installierte Version die Version, die bereits in der integrierten Partition vorhanden ist. Aber im Gegensatz zu APKs wird die neu installierte Version des APEX erst nach einem Neustart aktiviert.
Kernel-Anforderungen
Um APEX Mainline-Module auf einem Android-Gerät zu unterstützen, sind die folgenden Linux-Kernel-Features erforderlich: der Loopback-Treiber und dm-verity. Der Loopback-Treiber stellt das Dateisystem-Image in einem APEX-Modul bereit und dm-verity überprüft das APEX-Modul.
Die Leistung des Loopback-Treibers und von dm-verity ist wichtig, um bei der Verwendung von APEX-Modulen eine gute Systemleistung zu erzielen.
Unterstützte Kernel-Versionen
APEX Mainline-Module werden auf Geräten mit Kernel-Version 4.4 oder höher unterstützt. Neue Geräte, die mit Android 10 oder höher gestartet werden, müssen die Kernel-Version 4.9 oder höher verwenden, um APEX-Module zu unterstützen.
Erforderliche Kernel-Patches
Die erforderlichen Kernel-Patches zur Unterstützung von APEX-Modulen sind im allgemeinen Android-Baum enthalten. Um die Patches zur Unterstützung von APEX zu erhalten, verwenden Sie die neueste Version des Android Common Tree.
Kernel-Version 4.4
Diese Version wird nur für Geräte unterstützt, die von Android 9 auf Android 10 aktualisiert wurden und APEX-Module unterstützen möchten. Um die erforderlichen Patches zu erhalten, wird ein Down-Merge vom android-4.4
Zweig dringend empfohlen. Im Folgenden finden Sie eine Liste der erforderlichen individuellen Patches für die Kernel-Version 4.4.
- UPSTREAM: Schleife: ioctl zum Ändern der logischen Blockgröße hinzufügen ( 4.4 )
- BACKPORT: Block/Schleife: setze hw_sectors ( 4.4 )
- UPSTREAM: Schleife: LOOP_SET_BLOCK_SIZE in Compat ioctl hinzufügen ( 4.4 )
- ANDROID: mnt: Fix next_descendent ( 4.4 )
- ANDROID: mnt: Remount sollte an Slaves von Slaves weitergegeben werden ( 4.4 )
- ANDROID: mnt: Remount korrekt propagieren ( 4.4 )
- Zurücksetzen von „ANDROID: dm verity: minimale Prefetch-Größe hinzufügen“ ( 4.4 )
- UPSTREAM: Schleife: Caches löschen, wenn Offset oder Blockgröße geändert werden ( 4.4 )
Kernel-Versionen 4.9/4.14/4.19
Um die erforderlichen Patches für die Kernel-Versionen 4.9/4.14/4.19 zu erhalten, führen Sie eine Downmerge vom android-common
Zweig durch.
Erforderliche Kernel-Konfigurationsoptionen
Die folgende Liste zeigt die grundlegenden Konfigurationsanforderungen für die Unterstützung von APEX-Modulen, die in Android 10 eingeführt wurden. Die Elemente mit einem Sternchen (*) sind vorhandene Anforderungen von Android 9 und niedriger.
(*) 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
Anforderungen an Kernel-Befehlszeilenparameter
Stellen Sie zur Unterstützung von APEX sicher, dass die Kernel-Befehlszeilenparameter die folgenden Anforderungen erfüllen:
-
loop.max_loop
darf NICHT gesetzt sein -
loop.max_part
muss <= 8 sein
Aufbau eines APEX
In diesem Abschnitt wird beschrieben, wie Sie ein APEX mit dem Android-Buildsystem erstellen. Das Folgende ist ein Beispiel für Android.bp
für ein APEX mit dem Namen 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",
}
apex_manifest.json
Beispiel:
{
"name": "com.android.example.apex",
"version": 1
}
file_contexts
Beispiel:
(/.*)? u:object_r:system_file:s0
/sub(/.*)? u:object_r:sub_file:s0
/sub/file3 u:object_r:file3_file:s0
Dateitypen und Speicherorte in APEX
Dateityp | Standort in APEX |
---|---|
Gemeinsam genutzte Bibliotheken | /lib und /lib64 ( /lib/arm für übersetzten arm in x86) |
Ausführbare Dateien | /bin |
Java-Bibliotheken | /javalib |
Vorgefertigt | /etc |
Transitive Abhängigkeiten
APEX-Dateien enthalten automatisch transitive Abhängigkeiten von nativen gemeinsam genutzten Bibliotheken oder ausführbaren Dateien. Wenn beispielsweise libFoo von libFoo
abhängt, werden die beiden libBar
eingeschlossen, wenn nur libFoo
in der Eigenschaft native_shared_libs
aufgeführt ist.
Umgang mit mehreren ABIs
Installieren Sie die Eigenschaft native_shared_libs
für die primären und sekundären binären Anwendungsschnittstellen (ABIs) des Geräts. Wenn ein APEX auf Geräte mit einer einzelnen ABI abzielt (d. h. nur 32 Bit oder nur 64 Bit), werden nur Bibliotheken mit der entsprechenden ABI installiert.
Installieren Sie die binaries
Eigenschaft nur für die primäre ABI des Geräts, wie unten beschrieben:
- Wenn das Gerät nur 32-Bit ist, wird nur die 32-Bit-Variante der Binärdatei installiert.
- Wenn das Gerät nur 64-Bit ist, wird nur die 64-Bit-Variante der Binärdatei installiert.
Um eine feinkörnige Kontrolle über die ABIs der nativen Bibliotheken und Binärdateien hinzuzufügen, verwenden Sie die multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]
.
-
first
: Entspricht dem primären ABI des Geräts. Dies ist die Standardeinstellung für Binärdateien. -
lib32
: Stimmt mit der 32-Bit-ABI des Geräts überein, falls unterstützt. -
lib64
: Entspricht der 64-Bit-ABI des unterstützten Geräts. -
prefer32
: Stimmt mit der 32-Bit-ABI des Geräts überein, falls unterstützt. Wenn die 32-Bit-ABI nicht unterstützt wird, stimmt sie mit der 64-Bit-ABI überein. -
both
: Entspricht beiden ABIs. Dies ist die Standardeinstellung fürnative_shared_libraries
.
Die Eigenschaften java
, libraries
und prebuilts
sind ABI-agnostisch.
Dieses Beispiel gilt für ein Gerät, das 32/64 unterstützt und 32 nicht bevorzugt:
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
},
},
}
vbmeta signieren
Signieren Sie jeden APEX mit unterschiedlichen Schlüsseln. Wenn ein neuer Schlüssel erforderlich ist, erstellen Sie ein öffentlich-privates Schlüsselpaar und ein apex_key
-Modul. Verwenden Sie die key
, um das APEX mit dem Schlüssel zu signieren. Der öffentliche Schlüssel wird automatisch mit dem Namen avb_pubkey
in das APEX aufgenommen.
# 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", }
Im obigen Beispiel wird der Name des öffentlichen Schlüssels ( foo
) zur ID des Schlüssels. Die ID des Schlüssels, der zum Signieren eines APEX verwendet wird, wird in das APEX geschrieben. Zur Laufzeit verifiziert apexd
den APEX mithilfe eines öffentlichen Schlüssels mit derselben ID im Gerät.
ZIP-Signatur
Signieren Sie APEXs genauso wie APKs. Signieren Sie APEXs zweimal; einmal für das Mini-Dateisystem (Datei apex_payload.img
) und einmal für die gesamte Datei.
Um ein APEX auf Dateiebene zu signieren, legen Sie die certificate
auf eine der folgenden drei Arten fest:
- Nicht festgelegt: Wenn kein Wert festgelegt ist, wird das APEX mit dem Zertifikat signiert, das sich unter
PRODUCT_DEFAULT_DEV_CERTIFICATE
. Wenn kein Flag gesetzt ist, lautet der Pfad standardmäßigbuild/target/product/security/testkey
. -
<name>
: Das APEX ist mit dem<name>
-Zertifikat im selben Verzeichnis wiePRODUCT_DEFAULT_DEV_CERTIFICATE
. -
:<name>
: Das APEX wird mit dem Zertifikat signiert, das durch das Soong-Modul mit dem Namen<name>
definiert wird. Das Zertifikatsmodul kann wie folgt definiert werden.
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)
}
Installieren eines APEX
Um ein APEX zu installieren, verwenden Sie ADB.
adb install apex_file_name
adb reboot
Verwenden eines APEX
Nach dem Neustart wird das APEX im /apex/<apex_name>@<version>
. Mehrere Versionen desselben APEX können gleichzeitig montiert werden. Unter den Bereitstellungspfaden wird derjenige, der der neuesten Version entspricht, unter /apex/<apex_name>
Bind-Mount bereitgestellt.
Clients können den Bind-Mounted-Pfad verwenden, um Dateien von APEX zu lesen oder auszuführen.
APEXs werden typischerweise wie folgt verwendet:
- Ein OEM oder ODM lädt ein APEX vorab unter
/system/apex
, wenn das Gerät ausgeliefert wird. - Auf Dateien im APEX wird über den Pfad
/apex/<apex_name>/
. - Wenn eine aktualisierte Version des APEX in
/data/apex
installiert ist, zeigt der Pfad nach dem Neustart auf das neue APEX.
Aktualisieren eines Dienstes mit einem APEX
So aktualisieren Sie einen Dienst mit einem APEX:
Markieren Sie den Dienst in der Systempartition als aktualisierbar. Fügen Sie die Option
updatable
zur Dienstdefinition hinzu./system/etc/init/myservice.rc: service myservice /system/bin/myservice class core user system ... updatable
Erstellen Sie eine neue
.rc
-Datei für den aktualisierten Dienst. Verwenden Sie dieoverride
, um den vorhandenen Dienst neu zu definieren./apex/my.apex/etc/init.rc: service myservice /apex/my.apex/bin/myservice class core user system ... override
Service-Definitionen können nur in der .rc
-Datei eines APEX definiert werden. Aktionsauslöser werden in APEXes nicht unterstützt.
Wenn ein als aktualisierbar gekennzeichneter Dienst gestartet wird, bevor die APEXs aktiviert sind, wird der Start verzögert, bis die Aktivierung der APEXs abgeschlossen ist.
Konfigurieren des Systems zur Unterstützung von APEX-Updates
Setzen Sie die folgende Systemeigenschaft auf „ true
“, um APEX-Dateiaktualisierungen zu unterstützen.
<device.mk>:
PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true
BoardConfig.mk:
TARGET_FLATTEN_APEX := false
oder nur
<device.mk>:
$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
Abgeflachte Spitze
Bei älteren Geräten ist es manchmal unmöglich oder unmöglich, den alten Kernel zu aktualisieren, um APEX vollständig zu unterstützen. Beispielsweise könnte der Kernel ohne CONFIG_BLK_DEV_LOOP=Y
worden sein, was für das Mounten des Dateisystem-Images in einem APEX entscheidend ist.
Flattened APEX ist ein speziell entwickeltes APEX, das auf Geräten mit einem Legacy-Kernel aktiviert werden kann. Dateien in einem abgeflachten APEX werden direkt in einem Verzeichnis unter der integrierten Partition installiert. Beispielsweise wird lib/libFoo.so
in einem abgeflachten APEX my.apex
in /system/apex/my.apex/lib/libFoo.so
installiert.
Das Aktivieren eines abgeflachten APEX betrifft nicht das Loop-Gerät. Das gesamte Verzeichnis /system/apex/my.apex
ist direkt an /apex/name@ver
gebunden.
Abgeflachte APEX-Dateien können nicht aktualisiert werden, indem aktualisierte Versionen der APEX-Dateien aus dem Netzwerk heruntergeladen werden, da die heruntergeladenen APEX-Dateien nicht abgeflacht werden können. Abgeflachte APEXs können nur über ein reguläres OTA aktualisiert werden.
Abgeflachtes APEX ist die Standardkonfiguration. Das bedeutet, dass alle APEXs standardmäßig abgeflacht sind, es sei denn, Sie konfigurieren Ihr Gerät explizit so, dass nicht abgeflachte APEXs erstellt werden, um APEX-Updates zu unterstützen (wie oben erläutert).
Das Mischen von abgeflachten und nicht abgeflachten APEXs in einem Gerät wird NICHT unterstützt. APEXs in einem Gerät müssen entweder alle nicht abgeflacht oder alle abgeflacht sein. Dies ist besonders wichtig, wenn Sie vorsignierte APEX-Prebuilds für Projekte wie Mainline versenden. APEXs, die nicht vorsigniert sind (d. h. aus der Quelle erstellt wurden), sollten ebenfalls nicht abgeflacht und mit den richtigen Schlüsseln signiert werden. Das Gerät sollte von updatable_apex.mk
erben, wie in Aktualisieren eines Dienstes mit einem APEX erläutert.
Komprimierte APEXs
Android 12 und höher verfügen über die APEX-Komprimierung, um die Speicherbelastung durch aktualisierbare APEX-Pakete zu reduzieren. Nachdem ein Update auf ein APEX installiert wurde, belegt es, obwohl seine vorinstallierte Version nicht mehr verwendet wird, immer noch die gleiche Menge an Speicherplatz. Dieser besetzte Platz bleibt nicht verfügbar.
Die APEX-Komprimierung minimiert diese Auswirkungen auf den Speicher, indem ein stark komprimierter Satz von APEX-Dateien auf schreibgeschützten Partitionen (z. B. der /system
Partition) verwendet wird. Android 12 und höher verwenden einen DEFLATE-Zip-Komprimierungsalgorithmus.
Die Komprimierung bietet keine Optimierung für Folgendes:
Bootstrap-APEXs, die sehr früh in der Startsequenz gemountet werden müssen.
Nicht aktualisierbare APEXs. Die Komprimierung ist nur dann von Vorteil, wenn eine aktualisierte Version eines APEX auf der
/data
Partition installiert ist. Eine vollständige Liste der aktualisierbaren APEX-Modelle finden Sie auf der Seite „Modulare Systemkomponenten “.Dynamische gemeinsam genutzte Bibliotheken APEXes. Da
apexd
immer beide Versionen solcher APEXs (vorinstalliert und aktualisiert) aktiviert, bringt das Komprimieren keinen Mehrwert.
Komprimiertes APEX-Dateiformat
Dies ist das Format einer komprimierten APEX-Datei.
Abbildung 2. Komprimiertes APEX-Dateiformat
Auf der obersten Ebene ist eine komprimierte APEX-Datei eine ZIP-Datei, die die ursprüngliche Apex-Datei in deflatierter Form mit einer Komprimierungsstufe von 9 und mit anderen unkomprimiert gespeicherten Dateien enthält.
Vier Dateien umfassen eine APEX-Datei:
-
original_apex
: deflationiert mit Komprimierungsstufe 9 Dies ist die ursprüngliche, unkomprimierte APEX-Datei . -
apex_manifest.pb
: nur gespeichert -
AndroidManifest.xml
: nur gespeichert -
apex_pubkey
: nur gespeichert
Die apex_manifest.pb
, AndroidManifest.xml
und apex_pubkey
sind Kopien ihrer entsprechenden Dateien in original_apex
.
Komprimiertes APEX erstellen
Komprimiertes APEX kann mit dem Tool apex_compression_tool.py
erstellt werden, das sich unter system/apex/tools
befindet.
Im Build-System sind mehrere Parameter im Zusammenhang mit der APEX-Komprimierung verfügbar.
Ob eine APEX-Datei komprimierbar ist, wird in Android.bp
durch die Eigenschaft compressible
gesteuert:
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
compressible: true,
}
Ein PRODUCT_COMPRESSED_APEX
Produktflag steuert, ob ein aus der Quelle erstelltes Systemabbild komprimierte APEX-Dateien enthalten muss.
Für lokale Experimente können Sie einen Build zwingen, APEXs zu komprimieren, indem OVERRIDE_PRODUCT_COMPRESSED_APEX=
auf true
setzen.
Komprimierte APEX-Dateien, die vom Build-System generiert werden, haben die Erweiterung .capex
. Die Erweiterung erleichtert die Unterscheidung zwischen komprimierten und unkomprimierten Versionen einer APEX-Datei.
Unterstützte Komprimierungsalgorithmen
Android 12 unterstützt nur die Deflate-Zip-Komprimierung.
Aktivieren einer komprimierten APEX-Datei während des Bootens
Bevor ein komprimiertes APEX aktiviert werden kann, wird die darin enthaltene Datei original_apex
in das Verzeichnis /data/apex/decompressed
. Die resultierende dekomprimierte APEX-Datei ist fest mit dem Verzeichnis /data/apex/active
verknüpft.
Betrachten Sie das folgende Beispiel als Veranschaulichung des oben beschriebenen Prozesses.
Betrachten Sie /system/apex/com.android.foo.capex
als aktiviertes komprimiertes APEX mit Versionscode 37.
- Die Datei
original_apex
in/system/apex/com.android.foo.capex
wird in/data/apex/decompressed/com.android.foo@37.apex
dekomprimiert. -
restorecon /data/apex/decompressed/com.android.foo@37.apex
wird ausgeführt, um zu überprüfen, ob es ein korrektes SELinux-Label hat. - Verifizierungsprüfungen werden auf
/data/apex/decompressed/com.android.foo@37.apex
durchgeführt, um seine Gültigkeit sicherzustellen:apexd
überprüft den öffentlichen Schlüssel, der in/data/apex/decompressed/com.android.foo@37.apex
gebündelt ist Stellen Sie sicher, dass es mit dem in/system/apex/com.android.foo.capex
gebündelten identisch ist. - Die Datei
/data/apex/decompressed/com.android.foo@37.apex
ist fest mit dem Verzeichnis/data/apex/active/com.android.foo@37.apex
verknüpft. - Die reguläre Aktivierungslogik für unkomprimierte APEX-Dateien wird auf
/data/apex/active/com.android.foo@37.apex
.
Interaktion mit OTA
Komprimierte APEX-Dateien haben Auswirkungen auf die OTA-Bereitstellung und -Anwendung. Da ein OTA-Update möglicherweise eine komprimierte APEX-Datei mit einer höheren Versionsebene als der auf einem Gerät aktiven enthält, muss eine bestimmte Menge an freiem Speicherplatz reserviert werden, bevor ein Gerät neu gestartet wird, um ein OTA-Update anzuwenden.
Zur Unterstützung des OTA-Systems stellt apexd
diese beiden Binder-APIs zur Verfügung:
-
calculateSizeForCompressedApex
– berechnet die Größe, die zum Dekomprimieren von APEX-Dateien in einem OTA-Paket erforderlich ist. Dies kann verwendet werden, um zu überprüfen, ob ein Gerät über genügend Speicherplatz verfügt, bevor ein OTA heruntergeladen wird. -
reserveSpaceForCompressedApex
– reserviert Speicherplatz auf der Festplatte für die zukünftige Verwendung durchapexd
zum Dekomprimieren komprimierter APEX-Dateien innerhalb des OTA-Pakets.
Im Falle eines A/B-OTA-Updates versucht apexd
die Dekomprimierung im Hintergrund als Teil der OTA-Routine nach der Installation. Wenn die Dekomprimierung fehlschlägt, führt apexd
die Dekomprimierung während des Bootvorgangs durch, der das OTA-Update anwendet.
Bei der Entwicklung von APEX berücksichtigte Alternativen
Hier sind einige Optionen, die AOSP beim Entwerfen des APEX-Dateiformats berücksichtigt hat, und warum sie entweder eingeschlossen oder ausgeschlossen wurden.
Reguläre Paketverwaltungssysteme
Linux-Distributionen haben Paketverwaltungssysteme wie dpkg
und rpm
, die leistungsstark, ausgereift und robust sind. Sie wurden jedoch nicht für APEX übernommen, da sie die Pakete nach der Installation nicht schützen können. Die Überprüfung wird nur durchgeführt, wenn Pakete installiert werden. Angreifer können unbemerkt die Integrität der installierten Pakete knacken. Dies ist eine Regression für Android, bei der alle Systemkomponenten in schreibgeschützten Dateisystemen gespeichert wurden, deren Integrität von dm-verity für jede E/A geschützt wird. Jede Manipulation an Systemkomponenten muss entweder verboten oder erkennbar sein, damit das Gerät den Start verweigern kann, wenn es kompromittiert wird.
dm-crypt für Integrität
Die Dateien in einem APEX-Container stammen aus integrierten Partitionen (z. B. der /system
Partition), die durch dm-verity geschützt sind, wobei jede Änderung an den Dateien auch nach dem Mounten der Partitionen verboten ist. Um den Dateien dieselbe Sicherheitsebene zu bieten, werden alle Dateien in einem APEX in einem Dateisystem-Image gespeichert, das mit einem Hash-Baum und einem vbmeta-Deskriptor gekoppelt ist. Ohne dm-verity ist ein APEX in der /data
Partition anfällig für unbeabsichtigte Änderungen, die vorgenommen werden, nachdem es überprüft und installiert wurde.
Tatsächlich ist die /data
Partition auch durch Verschlüsselungsschichten wie dm-crypt geschützt. Obwohl dies ein gewisses Maß an Schutz vor Manipulationen bietet, ist sein Hauptzweck der Datenschutz, nicht die Integrität. Wenn ein Angreifer Zugriff auf die /data
Partition erhält, kann es keinen weiteren Schutz geben, und dies ist wiederum ein Rückschritt im Vergleich zu jeder Systemkomponente, die sich in der /system
Partition befindet. Der Hash-Baum in einer APEX-Datei bietet zusammen mit dm-verity das gleiche Maß an Inhaltsschutz.
Pfade von /system nach /apex umleiten
In einem APEX gepackte Systemkomponentendateien sind über neue Pfade wie /apex/<name>/lib/libfoo.so
zugänglich. Als die Dateien Teil der Partition /system
waren, waren sie über Pfade wie /system/lib/libfoo.so
zugänglich. Ein Client einer APEX-Datei (andere APEX-Dateien oder die Plattform) muss die neuen Pfade verwenden. Aufgrund der Pfadänderung müssen Sie möglicherweise vorhandenen Code aktualisieren.
Obwohl eine Möglichkeit, die Pfadänderung zu vermeiden, darin besteht, den Dateiinhalt in einer APEX-Datei auf der /system
Partition zu überlagern, entschied sich das Android-Team, keine Dateien auf der /system
Partition zu überlagern, da dies die Leistung beeinträchtigen könnte, da die Anzahl der überlagerten Dateien ( evtl. sogar hintereinander gestapelt) erhöht.
Eine andere Möglichkeit bestand darin, Dateizugriffsfunktionen wie open
, stat
und readlink
zu kapern, sodass Pfade, die mit /system
beginnen, auf ihre entsprechenden Pfade unter /apex
umgeleitet wurden. Das Android-Team hat diese Option verworfen, da es unmöglich ist, alle Funktionen zu ändern, die Pfade akzeptieren. Beispielsweise binden einige Apps Bionic statisch ein, das die Funktionen implementiert. In solchen Fällen werden diese Apps nicht umgeleitet.