Das Containerformat Android Pony EXpress (APEX) wurde in Android 10 eingeführt und wird bei der Installation von Systemmodulen der unteren Ebene verwendet. Dieses Format erleichtert das Aktualisieren von Systemkomponenten, die nicht in das Standard-Android-Anwendungsmodell passen. Beispiele für Komponenten sind native Dienste und Bibliotheken, Hardwareabstraktionsschichten (HALs), die Laufzeit (ART) und Klassenbibliotheken.
Der Begriff „APEX“ kann sich auch auf eine APEX-Datei beziehen.
Hintergrund
Android unterstützt zwar Updates von Modulen, die dem Standard-App-Modell entsprechen (z. B. Dienste, Aktivitäten), über Paketinstallations-Apps wie die Google Play Store App. Die Verwendung eines ähnlichen Modells für Betriebssystemkomponenten auf niedrigerer Ebene hat jedoch folgende Nachteile:
- APK-basierte Module können nicht zu Beginn der Bootreihenfolge verwendet werden. Der Paketmanager ist das zentrale Repository für Informationen zu Apps und kann nur über den Aktivitätsmanager gestartet werden, der in einer späteren Phase des Bootvorgangs bereit ist.
- Das APK-Format (insbesondere das Manifest) ist für Android-Apps konzipiert und Systemmodule eignen sich nicht immer gut dafür.
Design
In diesem Abschnitt wird das allgemeine Design des APEX-Dateiformats und des APEX-Managers beschrieben, einem Dienst zur Verwaltung von APEX-Dateien.
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
Das 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 und an 4-KB-Grenzen gespeichert werden.
Eine APEX-Datei enthält vier Dateien:
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. Dies ist ein ApexManifest
-Protokoll-Buffer im JSON-Format.
Die AndroidManifest.xml
-Datei ermöglicht es der APEX-Datei, APK-bezogene Tools und Infrastrukturen wie ADB, PackageManager und Paketinstallations-Apps (z. B. Play Store) zu verwenden. Für die APEX-Datei kann beispielsweise ein vorhandenes Tool wie aapt
verwendet werden, um grundlegende Metadaten aus der Datei zu prüfen. Die Datei enthält den Paketnamen und Versionsinformationen. Diese Informationen sind in der Regel auch in apex_manifest.json
verfügbar.
Für neuen Code und Systeme, die mit APEX zu tun haben, wird apex_manifest.json
anstelle von AndroidManifest.xml
empfohlen. AndroidManifest.xml
kann zusätzliche Informationen zum Targeting enthalten, die von den vorhandenen Tools zum App-Veröffentlichen 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 bereitgestellt. Insbesondere werden der Hash-Baum und der Metadatenblock mit der libavb
-Bibliothek erstellt. Die Dateisystemnutzlast wird nicht geparst, 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, mit dem das Dateisystem-Image signiert wird. Dieser Schlüssel sorgt dafür, dass die heruntergeladene APEX-Datei zur Laufzeit mit derselben Entität signiert wird, die dieselbe APEX-Datei in den integrierten Partitionen signiert.
APEX-Benennungsrichtlinien
Beachten Sie die folgenden Benennungsrichtlinien, um Namenskonflikte zwischen neuen APEX-Objekten bei der Weiterentwicklung der Plattform zu vermeiden:
com.android.*
- Reserviert für AOSP-APEXes. Nicht eindeutig für ein Unternehmen oder Gerät.
com.<companyname>.*
- Für ein Unternehmen reserviert. Wird möglicherweise von mehreren Geräten dieses Unternehmens verwendet.
com.<companyname>.<devicename>.*
- Reserviert für APEX-Dateien, die nur für ein bestimmtes Gerät (oder eine bestimmte Teilmenge von Geräten) gelten.
APEX-Manager
Der APEX-Manager (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 schon früh in der Boot-Sequenz bereit. APEX-Dateien sind normalerweise unter /system/apex
auf dem Gerät vorinstalliert. Der APEX-Manager verwendet diese Pakete standardmäßig, wenn keine Updates verfügbar sind.
Bei der Aktualisierungssequenz eines APEX-Objekts wird die Klasse „PackageManager“ verwendet. Sie sieht so aus:
- Eine APEX-Datei wird über eine Paketinstallations-App, ADB oder eine andere Quelle heruntergeladen.
- Der Paketmanager startet den Installationsvorgang. Wenn der Paketmanager erkennt, dass es sich um eine APEX-Datei handelt, übergibt er die Kontrolle an den APEX-Manager.
- Der APEX-Manager überprüft die APEX-Datei.
- Wenn die APEX-Datei überprüft wurde, wird die interne Datenbank des APEX-Managers so aktualisiert, dass die APEX-Datei beim nächsten Start aktiviert wird.
- Der Installanfragende erhält eine Nachricht, wenn die Paketüberprüfung erfolgreich war.
- Damit die Installation fortgesetzt werden kann, muss das System neu gestartet werden.
Beim nächsten Start wird der APEX-Manager gestartet, die interne Datenbank gelesen und für jede aufgeführte APEX-Datei Folgendes ausgeführt:
- Prüft die APEX-Datei.
- Erstellt ein Loopback-Gerät aus der APEX-Datei.
- Erstellt ein Blockgerät des Gerätemappers über dem Loopback-Gerät.
- Hiermit wird das Blockgerät des Gerätemappers auf einem eindeutigen Pfad bereitgestellt (z. B.
/apex/name@ver
).
Wenn alle in der internen Datenbank aufgeführten APEX-Dateien bereitgestellt sind, stellt der APEX-Manager einen Binder-Dienst für andere Systemkomponenten bereit, um Informationen zu den installierten APEX-Dateien abzufragen. So können die anderen Systemkomponenten beispielsweise die Liste der auf dem Gerät installierten APEX-Dateien oder den genauen Pfad abfragen, unter dem ein bestimmtes APEX bereitgestellt wird, damit auf die Dateien zugegriffen werden kann.
APEX-Dateien sind APK-Dateien
APEX-Dateien sind gültige APK-Dateien, da sie signierte ZIP-Archive (mit dem APK-Signaturschema) mit einer AndroidManifest.xml
-Datei sind. So können APEX-Dateien die Infrastruktur für APK-Dateien verwenden, z. B. eine Paketinstallations-App, das Signaturdienstprogramm und den Paketmanager.
Die AndroidManifest.xml
-Datei in einer APEX-Datei ist minimal und besteht aus dem Paket name
, versionCode
und optional targetSdkVersion
, minSdkVersion
und maxSdkVersion
für ein detailliertes Targeting. Anhand dieser Informationen können APEX-Dateien über bestehende Kanäle wie Paketinstallations-Apps und ADB bereitgestellt werden.
Unterstützte Dateitypen
Das APEX-Format unterstützt die folgenden Dateitypen:
- Native freigegebene Bibliotheken
- Native ausführbare Dateien
- JAR-Dateien
- Datendateien
- Konfigurationsdateien
Das bedeutet nicht, dass APEX alle diese Dateitypen aktualisieren kann. Ob ein Dateityp aktualisiert werden kann, hängt von der Plattform und der Stabilität der Definitionen der Schnittstellen für die Dateitypen ab.
Signaturoptionen
APEX-Dateien werden auf zwei Arten signiert. Zuerst wird die Datei apex_payload.img
(insbesondere der vbmeta-Descriptor, der an apex_payload.img
angehängt ist) mit einem Schlüssel signiert.
Anschließend wird die gesamte APEX mit dem APK-Signaturschema Version 3 signiert. Dabei werden zwei verschiedene Schlüssel verwendet.
Auf Geräteseite wird ein öffentlicher Schlüssel installiert, der dem privaten Schlüssel entspricht, der zum Signieren des vbmeta-Deskriptors verwendet wurde. Der APEX-Manager verwendet den öffentlichen Schlüssel, um APEX-Anwendungen zu überprüfen, die zur Installation angefordert werden. Jede APEX-Datei muss mit unterschiedlichen Schlüsseln signiert sein. Dies wird sowohl zur Build- als auch zur Laufzeit erzwungen.
APEX in integrierten Partitionen
APEX-Dateien können sich in vorinstallierten Partitionen wie /system
befinden. Die Partition ist bereits über dm-verity, sodass die APEX-Dateien direkt über das Loopback-Gerät bereitgestellt werden.
Wenn sich eine APEX-Datei in einer integrierten Partition befindet, kann sie aktualisiert werden, indem Sie ein APEX-Paket mit demselben Paketnamen und einem Versionscode angeben, der mindestens der Version entspricht. Die neue APEX-Datei wird in /data
gespeichert und ähnlich wie bei APKs wird die Version, die sich bereits in der integrierten Partition befindet, von der neu installierten Version überschattet. Im Gegensatz zu APKs wird die neu installierte Version der APEX-Datei jedoch erst nach dem Neustart aktiviert.
Kernelanforderungen
Für die Unterstützung von APEX-Mainline-Modulen auf einem Android-Gerät sind die folgenden Linux-Kernelfunktionen erforderlich: der Loopback-Treiber und dm-verity. Der Loopback-Treiber bindet das Dateisystem-Image in einem APEX-Modul an 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 Kernelversionen
APEX-Mainline-Module werden auf Geräten mit Kernelversion 4.4 oder höher unterstützt. Neue Geräte, die mit Android 10 oder höher auf den Markt gebracht werden, müssen die Kernelversion 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 Android Common Tree enthalten. Verwenden Sie die neueste Version des Android Common Tree, um die Patches für die APEX-Unterstützung zu erhalten.
Kernelversion 4.4
Diese Version wird nur für Geräte unterstützt, die von Android 9 auf Android 10 umgestellt werden und APEX-Module unterstützen sollen. Um die erforderlichen Patches zu erhalten, wird ein Downmerge aus dem android-4.4
-Branch dringend empfohlen. Im Folgenden finden Sie eine Liste der erforderlichen einzelnen Patches für die Kernelversion 4.4.
- UPSTREAM: loop: ioctl zum Ändern der logischen Blockgröße hinzufügen (4.4)
- BACKPORT: block/loop: set hw_sectors (4.4)
- UPSTREAM: loop: LOOP_SET_BLOCK_SIZE in compat ioctl hinzufügen (4.4)
- ANDROID: mnt: Fehler bei next_descendent beheben (4.4)
- ANDROID: mnt: remount sollte an untergeordnete Slaves weitergegeben werden (4.4)
- ANDROID: mnt: Remount korrekt weitergeben (4.4)
- Rücknahme von „ANDROID: dm verity: add minimum prefetch size“ (4.4)
- UPSTREAM: loop: Caches löschen, wenn Offset oder Blockgröße geändert werden (4.4)
Kernel-Versionen 4.9/4.14/4.19
Wenn Sie die erforderlichen Patches für die Kernelversionen 4.9, 4.14 und 4.19 benötigen, führen Sie einen Downmerge aus dem android-common
-Branch aus.
Erforderliche Kernelkonfigurationsoptionen
In der folgenden Liste sind die grundlegenden Konfigurationsanforderungen für die Unterstützung von APEX-Modulen aufgeführt, die in Android 10 eingeführt wurden. Die Elemente mit einem Sternchen (*) sind bestehende 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
Damit APEX unterstützt wird, müssen die Kernel-Befehlszeilenparameter die folgenden Anforderungen erfüllen:
loop.max_loop
darf NICHT festgelegt seinloop.max_part
muss kleiner oder gleich 8 sein
APEX erstellen
In diesem Abschnitt wird beschrieben, wie Sie eine APEX-Datei mit dem Android-Build-System erstellen.
Das folgende Beispiel zeigt Android.bp
für eine 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 |
---|---|
Geteilte Fotogalerien | /lib und /lib64 (/lib/arm für übersetzte ARM-Code in x86) |
Ausführbare Dateien | /bin |
Java-Bibliotheken | /javalib |
Vorkonfigurierte Systeme | /etc |
Transitive Abhängigkeiten
APEX-Dateien enthalten automatisch transitive Abhängigkeiten von nativen freigegebenen Bibliotheken oder ausführbaren Dateien. Wenn libFoo
beispielsweise von libBar
abhängt, werden die beiden Bibliotheken eingeschlossen, wenn nur libFoo
in der native_shared_libs
-Property aufgeführt ist.
Mehrere ABIs verarbeiten
Installieren Sie die native_shared_libs
-Eigenschaft sowohl für die primäre als auch für die sekundäre Binärschnittstelle (Application Binary Interface, ABI) des Geräts. Wenn eine APEX-Anwendung auf Geräte mit einem einzelnen ABI ausgerichtet ist (d. h. nur 32-Bit oder nur 64-Bit), werden nur Bibliotheken mit dem entsprechenden ABI installiert.
Installieren Sie die Property binaries
nur für die primäre ABI des Geräts, wie unten beschrieben:
- Wenn das Gerät nur 32 Bit unterstützt, wird nur die 32-Bit-Variante des Binärprogramms installiert.
- Wenn das Gerät nur 64-Bit unterstützt, wird nur die 64-Bit-Variante des Binärprogramms installiert.
Wenn Sie die ABIs der nativen Bibliotheken und Binärdateien genau steuern möchten, verwenden Sie die multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]
-Eigenschaften.
first
: Muss mit der primären ABI des Geräts übereinstimmen. Dies ist die Standardeinstellung für Binärdateien.lib32
: Entspricht dem 32-Bit-ABI des Geräts, sofern unterstützt.lib64
: Entspricht dem 64-Bit-ABI des unterstützten Geräts.prefer32
: Entspricht dem 32-Bit-ABI des Geräts, sofern unterstützt. Wenn das 32-Bit-ABI nicht unterstützt wird, entspricht es dem 64-Bit-ABI.both
: Entspricht beiden ABIs. Das ist die Standardeinstellung fürnative_shared_libraries
.
Die Attribute java
, libraries
und prebuilts
sind ABI-unabhängig.
Dieses Beispiel bezieht sich auf 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-Signatur
Signieren Sie jede APEX-Datei mit einem anderen Schlüssel. Wenn ein neuer Schlüssel erforderlich ist, erstellen Sie ein Schlüsselpaar aus öffentlichem und privatem Schlüssel und erstellen Sie ein apex_key
-Modul. Verwenden Sie die Property key
, um die APEX-Datei mit dem Schlüssel zu signieren. Der öffentliche Schlüssel wird automatisch mit dem Namen avb_pubkey
in 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, mit dem eine APEX-Datei signiert wurde, ist in der APEX-Datei selbst enthalten. Bei der Laufzeit prüft apexd
die APEX mit einem öffentlichen Schlüssel mit derselben ID auf dem Gerät.
APEX-Signatur
Signieren Sie APEX-Dateien auf die gleiche Weise wie APKs. Signieren Sie APEX-Dateien zweimal: einmal für das Mini-Dateisystem (apex_payload.img
-Datei) und einmal für die gesamte Datei.
Wenn Sie eine APEX-Datei auf Dateiebene signieren möchten, können Sie das Attribut certificate
auf eine der folgenden drei Arten festlegen:
- Nicht festgelegt: Wenn kein Wert festgelegt ist, wird die APEX mit dem Zertifikat unter
PRODUCT_DEFAULT_DEV_CERTIFICATE
signiert. Wenn kein Flag festgelegt ist, lautet der Standardpfadbuild/target/product/security/testkey
. <name>
: Die APEX-Datei ist mit dem<name>
-Zertifikat im selben Verzeichnis wiePRODUCT_DEFAULT_DEV_CERTIFICATE
signiert.:<name>
: Die APEX ist mit dem Zertifikat signiert, das vom Soong-Modul namens<name>
definiert ist. Das Zertifikatsmodul kann so 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)
}
APEX installieren
Verwenden Sie ADB, um eine APEX-Datei zu installieren.
adb install apex_file_name
adb reboot
Wenn supportsRebootlessUpdate
in apex_manifest.json
auf true
gesetzt ist und die aktuell installierte APEX nicht verwendet wird (z. B. alle darin enthaltenen Dienste beendet wurden), kann eine neue APEX ohne Neustart mit dem Flag --force-non-staged
installiert werden.
adb install --force-non-staged apex_file_name
APEX verwenden
Nach dem Neustart wird APEX im Verzeichnis /apex/<apex_name>@<version>
bereitgestellt. Es können mehrere Versionen derselben APEX gleichzeitig bereitgestellt werden.
Derjenige der Bereitstellungspfade, der der neuesten Version entspricht, wird unter /apex/<apex_name>
bereitgestellt.
Clients können den über Bindung bereitgestellten Pfad verwenden, um Dateien aus APEX zu lesen oder auszuführen.
APEX-Objekte werden in der Regel so verwendet:
- Ein OEM oder ODM lädt beim Versand des Geräts eine APEX unter
/system/apex
vor. - Der Zugriff auf Dateien im APEX erfolgt über den Pfad
/apex/<apex_name>/
. - Wenn eine aktualisierte Version des APEX in
/data/apex
installiert wird, verweist der Pfad nach dem Neustart auf das neue APEX.
Dienst mit einer APEX-Anwendung aktualisieren
So aktualisieren Sie einen Dienst mithilfe einer APEX-Domain:
Markieren Sie den Dienst in der Systempartition als aktualisierbar. Fügen Sie der Dienstdefinition die Option
updatable
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 die Optionoverride
, 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
Dienstdefinitionen können nur in der .rc
-Datei einer APEX-Anwendung definiert werden. Aktionstrigger werden in APEX-Klassen nicht unterstützt.
Wenn ein als aktualisierbar gekennzeichneter Dienst gestartet wird, bevor die APEX-Objekte aktiviert wurden, wird der Start verzögert, bis die APEX-Objekte aktiviert wurden.
System für APEX-Updates konfigurieren
Legen Sie die folgende Systemeigenschaft auf true
fest, um APEX-Dateiupdates zu unterstützen.
<device.mk>:
PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true
BoardConfig.mk:
TARGET_FLATTEN_APEX := false
oder einfach
<device.mk>:
$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
Abgeflachte APEX-Datei
Bei älteren Geräten ist es manchmal unmöglich oder nicht möglich, den alten Kernel so zu aktualisieren, dass er APEX vollständig unterstützt. Möglicherweise wurde der Kernel beispielsweise ohne CONFIG_BLK_DEV_LOOP=Y
erstellt, was für das Bereitstellen des Dateisystem-Images in einem APEX-Image erforderlich ist.
Flattened APEX ist eine speziell entwickelte APEX-Datei, die auf Geräten mit einem alten Kernel aktiviert werden kann. Dateien in einer flachen APEX-Datei werden direkt in einem Verzeichnis unter der integrierten Partition installiert. Beispiel: lib/libFoo.so
in einer abgeflachen APEX-my.apex
-Datei wird in /system/apex/my.apex/lib/libFoo.so
installiert.
Beim Aktivieren einer flachen APEX-Datei wird das Loop-Gerät nicht verwendet. Das gesamte Verzeichnis /system/apex/my.apex
wird direkt mit /apex/name@ver
verbunden.
Abgeflachte APEX-Objekte können nicht durch Herunterladen aktualisierter Versionen der APEX-Objekte aus dem Netzwerk aktualisiert werden, da die heruntergeladenen APEX-Objekte nicht abgeflacht werden können. Zusammengeführte APEX-Dokumente können nur über eine reguläre OTA-Datei aktualisiert werden.
Die flache APEX-Konfiguration ist die Standardkonfiguration. Das bedeutet, dass alle APEX-Dateien standardmäßig flach sind, es sei denn, Sie konfigurieren Ihr Gerät explizit so, dass nicht flache APEX-Dateien erstellt werden, um APEX-Updates zu unterstützen (wie oben beschrieben).
Die Kombination von abgeflachenen und nicht abgeflachenen APEX-Objekten auf einem Gerät wird NICHT unterstützt. APEX-Objekte in einem Gerät müssen entweder alle nicht abgeflattet oder alle abgeflattet sein.
Das ist besonders wichtig, wenn Sie vorsignierte APEX-Prebuilts für Projekte wie Mainline bereitstellen. APEX-Objekte, die nicht vorab signiert wurden (d. h. aus der Quelle erstellt wurden), sollten auch nicht flachgelegt und mit den richtigen Schlüsseln signiert werden. Das Gerät sollte von updatable_apex.mk
erben, wie unter Dienst mit einem APEX aktualisieren erläutert.
Komprimierte APEX-Dateien
Android 12 und höher bieten die APEX-Komprimierung, um die Speicherbelastung durch aktualisierbare APEX-Pakete zu reduzieren. Nachdem ein Update für eine APEX installiert wurde, belegt die vorinstallierte Version zwar nicht mehr den Speicherplatz, nimmt aber weiterhin denselben Speicherplatz in Anspruch. Dieser belegte Speicherplatz ist weiterhin nicht verfügbar.
Die APEX-Komprimierung minimiert diese Speicherauswirkungen, indem eine stark komprimierte Gruppe von APEX-Dateien auf nur lesbaren Partitionen (z. B. der /system
-Partition) verwendet wird. Android 12 und höher verwenden den DEFLATE-Zip-Komprimierungsalgorithmus.
Die Komprimierung bietet keine Optimierung für Folgendes:
Bootstrap-APEXes, die sehr früh in der Bootreihenfolge bereitgestellt werden müssen.
Nicht aktualisierbare APEX-Dateien Die Komprimierung ist nur dann von Vorteil, wenn auf der
/data
-Partition eine aktualisierte Version eines APEX installiert ist. Eine vollständige Liste der aktualisierbaren APEX-Objekte finden Sie auf der Seite Modulare Systemkomponenten.APEX-Objekte mit dynamischen freigegebenen Bibliotheken Da
apexd
immer beide Versionen solcher APEX-Dateien (vorinstalliert und aktualisiert) aktiviert, bringt eine Komprimierung keinen Mehrwert.
Komprimiertes APEX-Dateiformat
Das 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 andere nicht komprimierte Dateien enthält.
Eine APEX-Datei besteht aus vier Dateien:
original_apex
: entpackt mit Komprimierungsstufe 9. Dies ist die ursprüngliche, nicht komprimierte APEX-Datei.apex_manifest.pb
: nur gespeichertAndroidManifest.xml
: nur gespeichertapex_pubkey
: nur gespeichert
Die Dateien apex_manifest.pb
, AndroidManifest.xml
und apex_pubkey
sind Kopien der entsprechenden Dateien in original_apex
.
Komprimierte APEX-Datei erstellen
Komprimierte APEX-Dateien können mit dem apex_compression_tool.py
-Tool unter system/apex/tools
erstellt werden.
Im Build-System sind mehrere Parameter für die APEX-Komprimierung verfügbar.
In Android.bp
wird die Komprimierbarkeit einer APEX-Datei über das Attribut compressible
gesteuert:
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
compressible: true,
}
Mit einem PRODUCT_COMPRESSED_APEX
-Produktflag wird festgelegt, ob ein aus der Quelle erstelltes System-Image komprimierte APEX-Dateien enthalten muss.
Bei lokalen Tests können Sie APEX-Dateien bei der Erstellung erzwingen, indem Sie OVERRIDE_PRODUCT_COMPRESSED_APEX=
auf true
setzen.
Komprimierte APEX-Dateien, die vom Build-System generiert werden, haben die Endung .capex
.
Die Erweiterung erleichtert die Unterscheidung zwischen komprimierten und nicht komprimierten Versionen einer APEX-Datei.
Unterstützte Komprimierungsalgorithmen
Android 12 unterstützt nur die Deflate-Zip-Komprimierung.
Komprimierte APEX-Datei beim Starten aktivieren
Bevor eine komprimierte APEX-Datei aktiviert werden kann, wird die darin enthaltene original_apex
-Datei im Verzeichnis /data/apex/decompressed
dekomprimiert. Die resultierende dekomprimierte APEX-Datei ist mit dem Verzeichnis /data/apex/active
hart verknüpft.
Das folgende Beispiel veranschaulicht den oben beschriebenen Prozess.
Betrachten Sie /system/apex/com.android.foo.capex
als komprimierte APEX-Datei, die aktiviert wird, mit dem 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 prüfen, ob das richtige SELinux-Label vorhanden ist.- Es werden Überprüfungen an
/data/apex/decompressed/com.android.foo@37.apex
durchgeführt, um seine Gültigkeit zu bestätigen:apexd
prüft den in/data/apex/decompressed/com.android.foo@37.apex
enthaltenen öffentlichen Schlüssel, um sicherzustellen, dass er mit dem in/system/apex/com.android.foo.capex
enthaltenen übereinstimmt. - Die Datei
/data/apex/decompressed/com.android.foo@37.apex
ist über einen Hardlink mit dem Verzeichnis/data/apex/active/com.android.foo@37.apex
verknüpft. - Die reguläre Aktivierungslogik für nicht komprimierte APEX-Dateien wird auf
/data/apex/active/com.android.foo@37.apex
ausgeführt.
Interaktion mit OTA
Komprimierte APEX-Dateien haben Auswirkungen auf die OTA-Bereitstellung und -Anwendung. Da ein Over-the-air-Update eine komprimierte APEX-Datei mit einer höheren Versionsebene als die auf dem Gerät aktive Version enthalten kann, muss vor dem Neustart eines Geräts ein bestimmter freier Speicherplatz reserviert werden, um ein Over-the-air-Update anzuwenden.
Zur Unterstützung des OTA-Systems stellt apexd
die folgenden beiden Binder APIs bereit:
calculateSizeForCompressedApex
: Berechnet die Größe, die zum Dekomprimieren von APEX-Dateien in einem OTA-Paket erforderlich ist. So lässt sich prüfen, ob auf einem Gerät genügend Speicherplatz vorhanden ist, bevor ein Over-the-air-Update heruntergeladen wird.reserveSpaceForCompressedApex
: Reserviert Speicherplatz auf dem Laufwerk für die zukünftige Verwendung durchapexd
zum Dekomprimieren komprimierter APEX-Dateien im OTA-Paket.
Bei einem A/B-OTA-Update versucht apexd
im Rahmen des OTA-Vorgangs nach der Installation, die Dekomprimierung im Hintergrund durchzuführen. Wenn die Dekomprimierung fehlschlägt, führt apexd
die Dekomprimierung während des Bootens aus, um das OTA-Update anzuwenden.
Bei der Entwicklung von APEX in Betracht gezogene Alternativen
Im Folgenden finden Sie einige Optionen, die beim Entwerfen des APEX-Dateiformats von AOSP berücksichtigt wurden, und warum sie entweder aufgenommen oder ausgeschlossen wurden.
Regelmäßige 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 erfolgt nur, wenn Pakete installiert werden.
Angreifer können die Integrität der installierten Pakete unbemerkt schädigen. Dies ist eine Regression für Android, bei der alle Systemkomponenten in schreibgeschützten Dateisystemen gespeichert wurden, deren Integrität bei jeder E/A durch dm-verity geschützt ist. Jegliche Manipulation von Systemkomponenten muss entweder verboten oder nachweisbar sein, damit das Gerät bei einer Manipulation nicht gestartet werden kann.
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. Dort sind Änderungen an den Dateien auch nach dem Bereitstellen der Partitionen nicht zulässig. Um für die Dateien dasselbe Sicherheitsniveau zu bieten, werden alle Dateien in einem APEX in einem Dateisystem-Image gespeichert, das mit einem Hash-Baum und einem vbmeta-Beschreibungselement gekoppelt ist. Ohne dm-verity ist eine APEX-Datei in der /data
-Partition anfällig für unbeabsichtigte Änderungen, die nach der Überprüfung und Installation vorgenommen werden.
Tatsächlich ist die /data
-Partition auch durch Verschlüsselungsschichten wie dm-crypt geschützt. Dies bietet zwar einen gewissen Schutz vor Manipulation, sein Hauptzweck besteht jedoch in der Wahrung der Privatsphäre, nicht der Integrität. Wenn ein Angreifer Zugriff auf die /data
-Partition erhält, kann es keinen weiteren Schutz geben. Dies ist im Vergleich dazu, dass sich alle Systemkomponenten in der /system
-Partition befinden, ein Rückschritt.
Der Hash-Baum in einer APEX-Datei bietet zusammen mit dm-verity denselben Inhaltsschutz.
Pfade von /system zu /apex weiterleiten
Auf Dateien von Systemkomponenten, die in einer APEX-Datei verpackt sind, kann über neue Pfade wie /apex/<name>/lib/libfoo.so
zugegriffen werden. Wenn die Dateien Teil der Partition /system
waren, war über Pfade wie /system/lib/libfoo.so
auf sie zuzugreifen. Ein Client einer APEX-Datei (andere APEX-Dateien oder die Plattform) muss die neuen Pfade verwenden. Möglicherweise müssen Sie aufgrund der Pfadänderung vorhandenen Code aktualisieren.
Eine Möglichkeit, die Pfadänderung zu vermeiden, besteht darin, den Dateiinhalt in einer APEX-Datei auf die /system
-Partition zu überlagern. Das Android-Team hat sich jedoch entschieden, keine Dateien auf die /system
-Partition zu überlagern, da dies die Leistung beeinträchtigen könnte, wenn die Anzahl der überlagerten Dateien (möglicherweise sogar übereinander gestapelt) zunimmt.
Eine weitere Möglichkeit bestand darin, Funktionen für den Dateizugriff wie open
, stat
und readlink
zu manipulieren, sodass Pfade, die mit /system
beginnen, zu den entsprechenden Pfaden unter /apex
weitergeleitet wurden. Das Android-Team hat diese Option verworfen, da es nicht möglich ist, alle Funktionen zu ändern, die Pfade akzeptieren.
Einige Apps verknüpfen Bionic beispielsweise statisch, wodurch die Funktionen implementiert werden.
In diesen Fällen werden diese Apps nicht weitergeleitet.