Mit dem APEX-Dateiformat können Sie Android-Betriebssystemmodule niedrigerer Ebene verpacken und installieren. Es ermöglicht das unabhängige Erstellen und Installieren von Komponenten wie nativen Diensten und Bibliotheken, HAL-Implementierungen, Firmware, Konfigurationsdateien usw.
Anbieter-APEXes werden vom Build-System automatisch in der /vendor
-Partition installiert und von apexd
zur Laufzeit aktiviert, genau wie APEXes in anderen Partitionen.
Anwendungsfälle
Modularisierung von Anbieterbildern
APEX-Dateien ermöglichen eine natürliche Bündelung und Modularisierung von Funktionsimplementierungen auf Anbieter-Images.
Wenn Anbieter-Images als Kombination unabhängig erstellter Anbieter-APEXes erstellt werden, können Gerätehersteller die gewünschten Anbieterimplementierungen auf ihrem Gerät ganz einfach auswählen. Hersteller können sogar eine neue Anbieter-APEX erstellen, wenn keine der bereitgestellten APEXes ihren Anforderungen entspricht oder sie eine brandneue benutzerdefinierte Hardware haben.
Ein OEM kann beispielsweise sein Gerät mit der AOSP-WLAN-Implementierung APEX, der SoC-Bluetooth-Implementierung APEX und einer benutzerdefinierten OEM-Telefonieimplementierung APEX zusammenstellen.
Ohne Anbieter-APEXes erfordert eine Implementierung mit so vielen Abhängigkeiten zwischen Anbieterkomponenten eine sorgfältige Koordination und Überwachung. Wenn Sie alle Komponenten (einschließlich Konfigurationsdateien und zusätzlicher Bibliotheken) in APEX-Objekte mit klar definierten Schnittstellen an jeder Stelle der funktionsübergreifenden Kommunikation einbetten, werden die verschiedenen Komponenten austauschbar.
Entwickleriteration
Anbieter-APEX-Objekte helfen Entwicklern, beim Entwickeln von Anbietermodulen schneller zu iterieren, indem eine vollständige Funktionsimplementierung wie die WLAN-HAL in einem Anbieter-APEX-Objekt gebündelt wird. Entwickler können dann die APEX-Datei des Anbieters erstellen und einzeln per Push übertragen, um Änderungen zu testen, anstatt das gesamte Anbieter-Image neu zu erstellen.
Dies vereinfacht und beschleunigt den Iterationszyklus für Entwickler, die hauptsächlich in einem bestimmten Funktionsbereich arbeiten und nur diesen Bereich iterieren möchten.
Durch die natürliche Bündelung eines Feature-Bereichs in einem APEX-Objekt wird auch der Prozess zum Erstellen, Pushen und Testen von Änderungen für diesen Feature-Bereich vereinfacht. Wenn Sie beispielsweise eine APEX-Anwendung neu installieren, werden automatisch alle Bibliotheken oder Konfigurationsdateien aktualisiert, die in der APEX-Anwendung enthalten sind.
Wenn Sie einen Funktionsbereich in einem APEX-Objekt bündeln, wird auch das Debuggen oder Zurücksetzen vereinfacht, wenn ein schlechtes Geräteverhalten festgestellt wird. Wenn die Telefonie in einem neuen Build beispielsweise schlecht funktioniert, können Entwickler versuchen, eine ältere APEX-Telefonieimplementierung auf einem Gerät zu installieren (ohne einen vollständigen Build zu flashen) und zu prüfen, ob das Problem dadurch behoben wird.
Beispiel für einen Workflow:
# 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 ...
Beispiele
Grundlegende Informationen
Auf der Hauptseite APEX-Dateiformat finden Sie allgemeine Informationen zu APEX, einschließlich Geräteanforderungen, Details zum Dateiformat und Installationsschritten.
Wenn Sie in Android.bp
die Eigenschaft vendor: true
festlegen, wird ein APEX-Modul zu einem Anbieter-APEX.
apex {
..
vendor: true,
..
}
Binärdateien und freigegebene Bibliotheken
Ein APEX-Bundle enthält transitive Abhängigkeiten in der APEX-Nutzlast, es sei denn, sie haben stabile Schnittstellen.
Zu den stabilen nativen Schnittstellen für APEX-Abhängigkeiten von Anbietern gehören cc_library
mit stubs
und LLNDK-Bibliotheken. Diese Abhängigkeiten werden nicht verpackt und im APEX-Manifest erfasst. Das Manifest wird von linkerconfig
verarbeitet, damit die externen nativen Abhängigkeiten zur Laufzeit verfügbar sind.
Im folgenden Snippet enthält die APEX-Datei sowohl die Binärdatei (my_service
) als auch die nicht stabilen Abhängigkeiten (*.so
-Dateien).
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
Im folgenden Snippet enthält die APEX-Datei die freigegebene Bibliothek my_standalone_lib
und alle nicht stabilen Abhängigkeiten (wie oben beschrieben).
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
APEX verkleinern
APEX kann größer werden, da nicht stabile Abhängigkeiten gebündelt werden. Wir empfehlen die Verwendung statischer Verknüpfungen. Gängige Bibliotheken wie libc++.so
und libbase.so
können statisch mit HAL-Binärdateien verknüpft werden. Eine weitere Option ist die Abhängigkeit von einer anderen Komponente, um eine stabile Benutzeroberfläche bereitzustellen. Die Abhängigkeit wird nicht in der APEX-Anwendung gebündelt.
HAL-Implementierungen
Wenn Sie eine HAL-Implementierung definieren möchten, stellen Sie die entsprechenden Binärdateien und Bibliotheken in einem Anbieter-APEX bereit, ähnlich wie in den folgenden Beispielen:
Um die HAL-Implementierung vollständig zu kapseln, sollte die APEX auch alle relevanten VINTF-Fragmente und Init-Scripts angeben.
VINTF-Fragmente
VINTF-Fragmente können von einem Anbieter-APEX ausgeliefert werden, wenn sich die Fragmente in etc/vintf
des APEX befinden.
Verwende die Property prebuilts
, um die VINTF-Fragmente in die APEX einzubetten.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
Abfrage-APIs
Wenn VINTF-Fragmente zu APEX hinzugefügt werden, verwende libbinder_ndk
APIs, um die Zuordnungen von HAL-Schnittstellen und APEX-Namen abzurufen.
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:true
Wenn die HAL-Instanz in APEX definiert ist.AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
: holt den APEX-Namen ab, der die HAL-Instanz definiert.AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
: Mit dieser Option wird eine Passthrough-HAL geöffnet.
Init-Scripts
APEX-Dateien können auf zwei Arten Init-Scripts enthalten: (A) eine vorgefertigte Textdatei in der APEX-Nutzlast oder (B) ein reguläres Init-Script in /vendor/etc
. Sie können beide für dieselbe APEX festlegen.
Init-Script in APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
Init-Scripts in Anbieter-APEXes können service
-Definitionen und on <property or event>
-Anweisungen enthalten.
Achten Sie darauf, dass eine service
-Definition auf ein Binärprogramm im selben APEX verweist.
com.android.foo
APEX kann beispielsweise einen Dienst mit dem Namen foo-service
definieren.
on foo-service /apex/com.android.foo/bin/foo
...
Seien Sie vorsichtig, wenn Sie on
-Anweisungen verwenden. Da Init-Scripts in APEX-Objekten nach der Aktivierung von APEX-Objekten geparst und ausgeführt werden, können einige Ereignisse oder Properties nicht verwendet werden. Verwenden Sie apex.all.ready=true
, um Aktionen so früh wie möglich auszuführen.
on init
kann für Bootstrap-APEXes verwendet werden, on early-init
jedoch nicht.
Firmware
Beispiel:
Befolgen Sie die folgenden Schritte, um die Firmware in einem Anbieter-APEX mit dem Modultyp prebuilt_firmware
einzubetten.
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
-Module werden im Verzeichnis <apex name>/etc/firmware
der APEX installiert. ueventd
scannt /apex/*/etc/firmware
-Verzeichnisse, um Firmwaremodule zu finden.
Die file_contexts
der APEX muss alle Firmware-Nutzlasteinträge korrekt labeln, damit diese Dateien zur Laufzeit von ueventd
zugänglich sind. Normalerweise ist das Label vendor_file
ausreichend. Beispiel:
(/.*)? u:object_r:vendor_file:s0
Kernelmodule
So betten Sie Kernelmodule als vorkonfigurierte Module in eine Anbieter-APEX ein:
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
..
}
Die file_contexts
der APEX sollte alle Kernel-Modul-Nutzlasteinträge korrekt kennzeichnen. Beispiel:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
Kernelmodule müssen explizit installiert werden. Das folgende Beispiel für ein Init-Script in der Anbieterpartition zeigt die Installation über insmod
:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
Overlays für Laufzeitressourcen
Beispiel:
Mit der Property rros
können Sie Laufzeitressourcen-Overlays in eine APEX-Anzeigenfläche eines Anbieters einbetten.
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
Andere Konfigurationsdateien
Anbieter-APEXes unterstützen verschiedene andere Konfigurationsdateien, die sich in der Regel als Prebuilts in Anbieter-APEXes auf der Anbieterpartition befinden. Es werden ständig weitere hinzugefügt.
Beispiele:
- XML-Dateien für die Funktionserklärung
- Sensoren enthalten XMLs als Vorabversionen in einem Sensor HAL-Anbieter-APEX
- Eingabekonfigurationsdateien
- Touchscreen-Konfigurationen als Vorabversionen in einer APEX-Anwendung des Anbieters, die nur für die Konfiguration vorgesehen ist
Bootstrap-Anbieter-APEXes
Einige HAL-Dienste wie keymint
sollten verfügbar sein, bevor APEXes aktiviert werden. Diese HALs legen in der Regel early_hal
in ihrer Dienstdefinition im Init-Script fest. Ein weiteres Beispiel ist die animation
-Klasse, die in der Regel früher als das post-fs-data
-Ereignis gestartet wird. Wenn ein solcher HAL-Dienst in einem Anbieter-APEX-Paket enthalten ist, muss der Apex "vendorBootstrap": true
im APEX-Manifest sein, damit er früher aktiviert werden kann. Bootstrap-APEX-Objekte können nur über den vorkonfigurierten Speicherort wie /vendor/apex
aktiviert werden, nicht über /data/apex
.
Systemeigenschaften
Das Framework liest die folgenden Systemeigenschaften, um Anbieter-APEXes zu unterstützen:
input_device.config_file.apex=<apex name>
: Wenn diese Option festgelegt ist, werden die Eingabekonfigurationsdateien (*.idc
,*.kl
und*.kcm
) im/etc/usr
-Verzeichnis der APEX gesucht.ro.vulkan.apex=<apex name>
– wenn festgelegt, wird der Vulkan-Treiber aus dem APEX geladen. Da der Vulkan-Treiber von frühen HALs verwendet wird, müssen Sie APEX als Bootstrap APEX festlegen und diesen Linker-Namespace sichtbar konfigurieren.
Legen Sie die Systemeigenschaften in init-Scripts mit dem Befehl setprop
fest.
Zusätzliche Entwicklungsfunktionen
APEX-Auswahl beim Starten
Beispiel:
Entwickler können auch mehrere Versionen von Anbieter-APEXes mit demselben APEX-Namen und demselben Schlüssel installieren und dann mithilfe persistenter Sysprops auswählen, welche Version bei jedem Start aktiviert wird. Für bestimmte Anwendungsfälle von Entwicklern ist dies möglicherweise einfacher als die Installation einer neuen Kopie der APEX-Anwendung mit adb install
.
Beispiele für Anwendungsfälle:
- Drei Versionen des Wifi HAL-Anbieters APEX installieren:QA-Teams können manuelle oder automatisierte Tests mit einer Version ausführen, dann neu starten, um eine andere Version zu verwenden, die Tests noch einmal ausführen und die endgültigen Ergebnisse vergleichen.
- Zwei Versionen des HAL-Anbieters APEX für die Kamera installieren, eine aktuelle und eine experimentelle: Dogfooder können die experimentelle Version verwenden, ohne eine zusätzliche Datei herunterzuladen und zu installieren. So können sie ganz einfach wieder zur vorherigen Version wechseln.
Beim Starten sucht apexd
nach Sysprops in einem bestimmten Format, um die richtige APEX-Version zu aktivieren.
Die erwarteten Formate für den Property-Schlüssel sind:
- Bootconfig
- Wird verwendet, um den Standardwert in
BoardConfig.mk
festzulegen. androidboot.vendor.apex.<apex name>
- Wird verwendet, um den Standardwert in
- Persistent sysprop
- Wird verwendet, um den Standardwert zu ändern, der auf einem bereits gestarteten Gerät festgelegt wurde.
- Überschreibt den Wert „bootconfig“, falls vorhanden.
persist.vendor.apex.<apex name>
Der Wert der Property sollte der Dateiname der APEX-Anwendung sein, die aktiviert werden soll.
// 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,
..
}
Die Standardversion sollte auch mit „bootconfig“ in BoardConfig.mk
konfiguriert werden:
# 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
Ändern Sie nach dem Starten des Geräts die aktivierte Version, indem Sie das persistente Sysprop festlegen:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
Wenn das Gerät das Aktualisieren von bootconfig nach dem Flashen unterstützt (z. B. über fastboot
oem
-Befehle), ändert sich durch Ändern der bootconfig-Eigenschaft für die mehrfach installierte APEX auch die beim Starten aktivierte Version.
Bei virtuellen Referenzgeräten auf Basis von Cuttlefish können Sie die Bootconfig-Eigenschaft direkt beim Starten mit dem Befehl --extra_bootconfig_args
festlegen. Beispiel:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";