Anbieter APEX

Mit dem APEX-Dateiformat können Sie untergeordnete Android-Betriebssystemmodule 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 wie APEXes in anderen Partitionen von apexd zur Laufzeit aktiviert.

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 entwickelter APEX-Anbieter erstellt werden, können Gerätehersteller ganz einfach die gewünschten Anbieterimplementierungen auf ihrem Gerät 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. Durch das Einbinden aller Komponenten (einschließlich Konfigurationsdateien und zusätzlichen Bibliotheken) in APEXes mit klar definierten Schnittstellen an jedem Punkt der funktionsübergreifenden Kommunikation sind die verschiedenen Komponenten austauschbar.

Entwickleriteration

Mit Anbieter-APEX können Entwickler bei der Entwicklung von Anbietermodulen schneller iterieren. Dazu wird eine vollständige Funktionsimplementierung wie WLAN-HAL in einem Anbieter-APEX bündelt. 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 Entwickleriterationszyklus für Entwickler, die hauptsächlich in einem Funktionsbereich arbeiten und nur diesen Funktionsbereich 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 enthält transitive Abhängigkeiten innerhalb der APEX-Nutzlast, sofern sie keine stabile Schnittstellen haben.

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 von der Paketerstellung ausgeschlossen und im APEX-Manifest aufgezeichnet. 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 im APEX 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 bei der Verwendung von on-Anweisungen. Da Initialisierungsskripte in APEXes nach der Aktivierung von APEX geparst und ausgeführt werden, können einige Ereignisse oder Attribute nicht verwendet werden. Verwende apex.all.ready=true, um Aktionen so früh wie möglich auszulösen. 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 reicht das Label vendor_file aus. 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
  ..

Laufzeit-Ressourcen-Overlays

Beispiel:

Betten Sie Overlays für Laufzeitressourcen mithilfe des Attributs rros in einen Anbieter-APEX ein.

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:

Bootstrap-Anbieter-APEXes

Einige HAL-Dienste wie keymint sollten verfügbar sein, bevor APEXes aktiviert werden. Diese HALs legen normalerweise early_hal in ihrer Dienstdefinition im Init-Skript fest. Ein weiteres Beispiel ist die animation-Klasse, die in der Regel früher als das post-fs-data-Ereignis gestartet wird. Wenn ein solch früher HAL-Dienst in Anbieter-APEX gepackt ist, erstellen Sie den Apex-"vendorBootstrap": true im zugehörigen APEX-Manifest, 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-Anwendung 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 Entwickleranwendungsfälle kann dies einfacher sein, als eine neue Kopie des APEX mit adb install zu installieren.

Beispiele für Anwendungsfälle:

  • Drei Versionen des WLAN-HAL-Anbieters APEX installieren: QA-Teams können manuelle oder automatisierte Tests mit einer Version durchführen, dann mit einer anderen Version neu starten, die Tests noch einmal ausführen und dann die Endergebnisse vergleichen.
  • Zwei Versionen des Kamera-HAL-Anbieters APEX (aktuell und experimentell) installieren: Dogfooder können die experimentelle Version verwenden, ohne eine zusätzliche Datei herunterzuladen und zu installieren, sodass sie problemlos wieder zurückwechseln können.

Beim Starten sucht apexd nach Sysprops in einem bestimmten Format, um die richtige APEX-Version zu aktivieren.

Für den Attributschlüssel werden folgende Formate erwartet:

  • Bootconfig
    • Wird verwendet, um den Standardwert in BoardConfig.mk festzulegen.
    • androidboot.vendor.apex.<apex name>
  • Persistent sysprop
    • Wird zum Ändern des Standardwerts auf einem bereits gestarteten Gerät verwendet.
    • Ü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 Booten 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.

Für virtuelle Referenzgeräte, die auf Cuttlefish basieren, können Sie mit dem Befehl --extra_bootconfig_args das Attribut bootconfig direkt beim Start festlegen. Beispiel:

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