Anbieter APEX

Sie können das APEX-Dateiformat verwenden, um Android-Betriebssystemmodule auf niedrigerer Ebene zu verpacken und zu installieren. Sie ermöglicht das unabhängige Erstellen und Installieren von Komponenten wie nativen Diensten und Bibliotheken, HAL-Implementierungen, Firmware und Konfigurationsdateien.

Vendor-APEX-Module werden vom Build-System automatisch in der Partition /vendor installiert und zur Laufzeit von apexd aktiviert, genau wie APEX-Module in anderen Partitionen.

Anwendungsfälle

Modularisierung von Anbieterbildern

APEX-Dateien ermöglichen eine natürliche Bündelung und Modularisierung von Funktionsimplementierungen in Anbieter-Images.

Wenn Anbieter-Images als Kombination aus unabhängig erstellten Anbieter-APEXes erstellt werden, können Gerätehersteller die gewünschten Anbieterimplementierungen für ihr Gerät einfach auswählen. Hersteller können sogar einen neuen Anbieter-APEX erstellen, wenn keiner der bereitgestellten APEXes ihren Anforderungen entspricht oder sie eine brandneue benutzerdefinierte Hardware haben.

Ein OEM kann beispielsweise sein Gerät mit dem AOSP-WLAN-APEX, dem SoC-Bluetooth-APEX und einem benutzerdefinierten OEM-Telefonie-APEX zusammenstellen.

Ohne Anbieter-APEXes erfordert eine Implementierung mit so vielen Abhängigkeiten zwischen Anbieterkomponenten eine sorgfältige Koordination und Nachverfolgung. Indem alle Komponenten (einschließlich Konfigurationsdateien und zusätzlichen Bibliotheken) in APEX-Dateien mit klar definierten Schnittstellen an jedem Punkt der funktionsübergreifenden Kommunikation verpackt werden, werden die verschiedenen Komponenten austauschbar.

Entwickleriteration

Mit Vendor-APEXes können Entwickler schneller Iterationen durchführen, wenn sie Vendormodule entwickeln, da eine gesamte Funktionsimplementierung, z. B. das WLAN-HAL, in einem Vendor-APEX gebündelt wird. Entwickler können dann den Anbieter-APEX erstellen und einzeln übertragen, um Änderungen zu testen, anstatt das gesamte Anbieter-Image neu zu erstellen.

Das vereinfacht und beschleunigt den Iterationszyklus für Entwickler, die hauptsächlich in einem Funktionsbereich arbeiten und nur diesen Funktionsbereich durchlaufen möchten.

Die natürliche Bündelung eines Funktionsbereichs in einem APEX vereinfacht auch das Erstellen, Pushen und Testen von Änderungen für diesen Funktionsbereich. Wenn Sie beispielsweise einen APEX neu installieren, werden alle darin enthaltenen gebündelten Bibliotheks- oder Konfigurationsdateien automatisch aktualisiert.

Durch das Bündeln eines Funktionsbereichs in einem APEX wird auch das Debuggen oder Zurücksetzen vereinfacht, wenn ein fehlerhaftes Geräteverhalten beobachtet wird. Wenn beispielsweise die Telefonie in einem neuen Build schlecht funktioniert, können Entwickler versuchen, einen älteren APEX für die Telefonie auf einem Gerät zu installieren (ohne einen vollständigen Build flashen zu müssen) und zu sehen, ob das Problem dadurch behoben wird.

Beispielworkflow:

# 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 das Attribut vendor: true festlegen, wird ein APEX-Modul zu einem Vendor-APEX.

apex {
  ..
  vendor: true,
  ..
}

Binärdateien und gemeinsam genutzte Bibliotheken

Ein APEX-Bundle enthält transitive Abhängigkeiten in der APEX-Nutzlast, sofern sie keine stabilen Schnittstellen haben.

Stabile native Schnittstellen für APEX-Abhängigkeiten von Anbietern umfassen cc_library mit stubs und LLNDK-Bibliotheken. Diese Abhängigkeiten werden nicht in das Paket aufgenommen und im APEX-Manifest aufgezeichnet. Das Manifest wird von linkerconfig verarbeitet, sodass die externen nativen Abhängigkeiten zur Laufzeit verfügbar sind.

Im folgenden Snippet enthält das APEX 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 der APEX die freigegebene Bibliothekmy_standalone_libund alle ihre nicht stabilen Abhängigkeiten (wie oben beschrieben).

apex {
  ..
  vendor: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

APEX verkleinern

APEX-Pakete können größer werden, da sie nicht stabile Abhängigkeiten enthalten. Wir empfehlen die Verwendung von statischem Linking. Häufig verwendete Bibliotheken wie libc++.so und libbase.so können statisch mit HAL-Binärdateien verknüpft werden. Eine Abhängigkeit zu schaffen, um eine stabile Schnittstelle bereitzustellen, kann eine weitere Option sein. Die Abhängigkeit wird nicht im APEX gebündelt.

HAL-Implementierungen

Um eine HAL-Implementierung zu definieren, stellen Sie die entsprechenden Binärdateien und Bibliotheken in einem Vendor-APEX bereit, ähnlich den folgenden Beispielen:

Um die HAL-Implementierung vollständig zu kapseln, sollten im APEX auch alle relevanten VINTF-Fragmente und Init-Skripts angegeben werden.

VINTF-Fragmente

VINTF-Fragmente können über einen Anbieter-APEX bereitgestellt werden, wenn sie sich im etc/vintf des APEX befinden.

Verwenden Sie das Attribut prebuilts, um die VINTF-Fragmente in den 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, verwenden Sie 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", ...): Ruft den APEX-Namen ab, der die HAL-Instanz definiert.
  • AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...): Damit wird ein Passthrough-HAL geöffnet.

Init-Scripts

APEX-Dateien können auf zwei Arten Initialisierungsskripts enthalten: (A) eine vorgefertigte Textdatei in der APEX-Nutzlast oder (B) ein reguläres Initialisierungsskript in /vendor/etc. Sie können beide für denselben 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. Beispielsweise kann in com.android.foo APEX ein Dienst mit dem Namen foo-service definiert werden.

on foo-service /apex/com.android.foo/bin/foo
  ...

Seien Sie vorsichtig, wenn Sie on-Anweisungen verwenden. Da Init-Scripts in APEX-Modulen nach der Aktivierung von APEX-Modulen geparst und ausgeführt werden, können einige Ereignisse oder Eigenschaften nicht verwendet werden. Verwenden Sie apex.all.ready=true, um Aktionen so früh wie möglich auszulösen. Bootstrap-APEXs können on init, aber nicht on early-init verwenden.

Firmware

Beispiel:

Betten Sie die Firmware mit dem Modultyp prebuilt_firmware in einen Anbieter-APEX ein, wie unten beschrieben.

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 des APEX installiert. ueventd scannt /apex/*/etc/firmware-Verzeichnisse, um Firmwaremodule zu finden.

Im file_contexts des APEX müssen alle Firmware-Payload-Einträge richtig gekennzeichnet sein, damit ueventd zur Laufzeit auf diese Dateien zugreifen kann. In der Regel reicht das Label vendor_file aus. Beispiel:

(/.*)? u:object_r:vendor_file:s0

Kernelmodule

Betten Sie Kernelmodule als vorkompilierte Module in einen Vendor-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
  ..
}

Im file_contexts des APEX müssen alle Nutzlast-Einträge für Kernel-Module richtig gekennzeichnet sein. Beispiel:

/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0

Kernelmodule müssen explizit installiert werden. Das folgende Beispiel für ein Initialisierungsskript in der Anbieterpartition zeigt die Installation über insmod:

my_init.rc:

on early-boot
  insmod /apex/myapex/etc/modules/my.ko
  ..

Laufzeit-Ressourcen-Overlays

Beispiel:

Betten Sie Laufzeit-Ressourcen-Overlays in einen Anbieter-APEX ein, indem Sie das Attribut rros verwenden.

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-APEXs unterstützen verschiedene andere Konfigurationsdateien, die sich in der Regel als Prebuilts in Anbieter-APEXs auf der Anbieterpartition befinden. Es werden immer mehr hinzugefügt.

Beispiele:

Anbieter-APEXes booten

Einige HAL-Dienste wie keymint sollten verfügbar sein, bevor APEX-Module aktiviert werden. In diesen HALs wird early_hal normalerweise in der Dienstdefinition im Init-Script festgelegt. Ein weiteres Beispiel ist die Klasse animation, die in der Regel früher als das Ereignis post-fs-data gestartet wird. Wenn ein solcher früher HAL-Dienst in einem Anbieter-APEX verpackt ist, machen Sie den APEX "vendorBootstrap": true in seinem APEX-Manifest, damit er früher aktiviert werden kann. Bootstrap-APEX-Module können nur über den vordefinierten Speicherort wie /vendor/apex und nicht über /data/apex aktiviert werden.

Systemattribute

Dies sind die Systemeigenschaften, die das Framework zum Unterstützen von Anbieter-APEXs liest:

  • input_device.config_file.apex=<apex name>: Wenn diese Option festgelegt ist, werden die Eingabekonfigurationsdateien (*.idc, *.kl und *.kcm) im Verzeichnis /etc/usr des 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, erstellen Sie den APEX Bootstrap APEX und konfigurieren Sie diesen Linker-Namespace so, dass er sichtbar ist.

Legen Sie die Systemattribute in Init-Skripts mit dem Befehl setprop fest.

Zusätzliche Funktionen

APEX-Auswahl beim Booten

Beispiel:

Vendor-APEXes können optional während des Bootvorgangs aktiviert werden. Wenn Sie einen Dateinamen mit der Systemeigenschaft ro.vendor.apex.<apex name> angeben, wird nur der APEX, der dem Dateinamen entspricht, für die jeweilige <apex name> aktiviert. Der APEX mit <apex name> wird ignoriert (nicht aktiviert), wenn diese Systemeigenschaft auf none gesetzt ist. Mit dieser Funktion können Sie mehrere Kopien eines APEX mit demselben Namen installieren. Wenn es mehrere Versionen desselben APEX gibt, sollten sie denselben Schlüssel verwenden.

Beispiele für Anwendungsfälle:

  • Drei Versionen des WLAN-HAL-Anbieter-APEX installieren:QA-Teams können manuelle oder automatisierte Tests mit einer Version ausführen, dann in eine andere Version neu starten und die Tests noch einmal ausführen und schließlich die Ergebnisse vergleichen.
  • Installieren Sie zwei Versionen des Kamera-HAL-Anbieter-APEX, current und experimental:Dogfooder können die experimentelle Version verwenden, ohne eine zusätzliche Datei herunterladen und installieren zu müssen, sodass sie problemlos zur aktuellen Version zurückkehren können.

Beim Booten sucht apexd nach System-Properties 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>
  • Persistent sysprop
    • Wird verwendet, um den Standardwert zu ändern, der auf einem bereits gebooteten Gerät festgelegt ist.
    • Überschreibt den Bootconfig-Wert, falls vorhanden.
    • persist.vendor.apex.<apex name>

Der Wert der Eigenschaft sollte der Dateiname des APEX sein, der aktiviert werden soll, oder none, um den APEX zu deaktivieren.

// 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 Booten des Geräts die aktivierte Version, indem Sie die persistente System-Property 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 der Bootkonfiguration nach dem Flashen unterstützt (z. B. über fastboot oem-Befehle), wird durch Ändern der Bootkonfigurationseigenschaft für die mehrfach installierten APEX-Dateien auch die beim Booten aktivierte Version geändert.

Bei virtuellen Referenzgeräten, die auf Cuttlefish basieren, können Sie die Bootconfig-Eigenschaft mit dem Befehl --extra_bootconfig_args direkt beim Starten festlegen. Beispiel:

launch_cvd --noresume \
  --extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";