Anbieter APEX

Sie können das APEX-Dateiformat verwenden, um untergeordnete Android-Betriebssystemmodule zu packen und zu installieren. Es ermöglicht die unabhängige Erstellung und Installation von Komponenten wie nativen Diensten und Bibliotheken, HAL-Implementierungen, Firmware, Konfigurationsdateien usw.

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

Anwendungsfälle

Modularisierung von Anbieterbildern

APEXes ermöglichen eine natürliche Bündelung und Modularisierung von Feature-Implementierungen auf Anbieter-Images.

Wenn Anbieter-Images als Kombination unabhängig erstellter Anbieter-APEXes erstellt werden, können Gerätehersteller problemlos die spezifischen Anbieterimplementierungen auswählen, die sie auf ihrem Gerät benötigen. Hersteller können sogar einen neuen Anbieter-APEX erstellen, wenn keiner der bereitgestellten APEXs ihren Anforderungen entspricht oder sie über eine brandneue kundenspezifische Hardware verfügen.

Beispielsweise kann sich ein OEM dafür entscheiden, sein Gerät mit der AOSP-WLAN-Implementierung APEX, der SoC-Bluetooth-Implementierung APEX und einer benutzerdefinierten OEM-Telefonie-Implementierung APEX zusammenzustellen.

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

Entwickler-Iteration

Vendor APEXes helfen Entwicklern, bei der Entwicklung von Vendor-Modulen schneller zu iterieren, indem sie eine komplette Feature-Implementierung, wie das WLAN-HAL, in einem Vendor APEX bündeln. Entwickler können dann den APEX des Anbieters erstellen und einzeln pushen, um Änderungen zu testen, anstatt das gesamte Anbieter-Image neu erstellen zu müssen.

Dies vereinfacht und beschleunigt den Entwickler-Iterationszyklus für Entwickler, die hauptsächlich in einem Funktionsbereich arbeiten und nur in diesem Funktionsbereich iterieren möchten.

Die natürliche Bündelung eines Feature-Bereichs in einem APEX vereinfacht auch den Prozess des Erstellens, Pushens und Testens von Änderungen für diesen Feature-Bereich. Beispielsweise werden bei der Neuinstallation eines APEX automatisch alle gebündelten Bibliotheks- oder Konfigurationsdateien aktualisiert, die im APEX enthalten sind.

Durch die Bündelung 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önnten Entwickler versuchen, eine ältere Telefonie-Implementierung APEX auf einem Gerät zu installieren (ohne einen vollständigen Build flashen zu müssen) und prüfen, ob das gute Verhalten wiederhergestellt wird.

Beispiel-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

Grundlagen

Auf der Hauptseite zum APEX-Dateiformat finden Sie allgemeine APEX-Informationen, einschließlich Geräteanforderungen, Details zum Dateiformat und Installationsschritte.

In Android.bp wird durch Festlegen der Eigenschaft vendor: true ein APEX-Modul zu einem Vendor-APEX.

apex {
  ..
  vendor: true,
  ..
}

Binärdateien und gemeinsam genutzte Bibliotheken

Ein APEX umfasst transitive Abhängigkeiten innerhalb der APEX-Nutzlast, es sei denn, sie verfügen über stabile Schnittstellen.

Zu den stabilen nativen Schnittstellen für APEX-Abhängigkeiten von Anbietern gehören cc_library mit stubs , ndk_library oder llndk_library . Diese Abhängigkeiten sind von der Paketierung ausgeschlossen und Abhängigkeiten werden im APEX-Manifest aufgezeichnet. Das Manifest wird von linkerconfig verarbeitet, sodass die externen nativen Abhängigkeiten zur Laufzeit verfügbar sind.

Im Gegensatz zu APEXes in der /system Partition sind Hersteller-APEXes normalerweise an eine bestimmte VNDK-Version gebunden. VNDK-Bibliotheken garantieren ABI-Stabilität innerhalb der Version, sodass wir VNDK-Bibliotheken als stabil behandeln und die Größe der Anbieter-APEXes reduzieren können, indem wir sie mithilfe der Eigenschaft use_vndk_as_stable von den APEXes ausschließen.

Im folgenden Snippet enthält APEX sowohl die Binärdatei ( my_service ) als auch ihre nicht stabilen Abhängigkeiten ( *.so Dateien). Es enthält keine VNDK-Bibliotheken, selbst wenn my_service mit VNDK-Bibliotheken wie libbase erstellt wird. Stattdessen verwendet my_service zur Laufzeit libbase aus vom System bereitgestellten VNDK-Bibliotheken.

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

Im folgenden Snippet enthält APEX die gemeinsam genutzte Bibliothek my_standalone_lib und alle ihre nicht stabilen Abhängigkeiten (wie oben beschrieben).

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

HAL-Implementierungen

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

Um die HAL-Implementierung vollständig zu kapseln, sollte der APEX auch alle relevanten VINTF-Fragmente und Init-Skripte angeben.

VINTF-Fragmente

VINTF-Fragmente können von einem Anbieter-APEX bereitgestellt werden, wenn sich Fragmente in etc/vintf des APEX befinden.

Verwenden Sie die prebuilts Eigenschaft, um die VINTF-Fragmente in APEX einzubetten.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

Init-Skripte

APEXes können Init-Skripte auf zwei Arten enthalten: (A) eine vorgefertigte Textdatei innerhalb der APEX-Nutzlast oder (B) ein reguläres Init-Skript in /vendor/etc . Sie können beide für denselben APEX festlegen.

Init-Skript in APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

Init-Skripte innerhalb von APEXes können nur service haben. Init-Skripte in Vendor APEXes können auch on <property> -Anweisungen haben.

Seien Sie vorsichtig, wenn Sie on Anweisungen verwenden. Da Init-Skripte in APEXes nach der Aktivierung von APEXes analysiert 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.

Firmware

Beispiel:

Betten Sie die Firmware wie folgt in ein APEX eines Anbieters mit dem Modultyp prebuilt_firmware ein.

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 durchsucht die Verzeichnisse /apex/*/etc/firmware nach Firmware-Modulen.

Die file_contexts des APEX sollten alle Firmware-Nutzdateneinträge ordnungsgemäß kennzeichnen, um sicherzustellen, dass ueventd zur Laufzeit auf diese Dateien zugreifen kann. Normalerweise ist die Bezeichnung vendor_file ausreichend. Zum Beispiel:

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

Kernelmodule

Betten Sie Kernelmodule wie folgt als vorgefertigte Module in ein APEX eines Anbieters 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 des APEX sollten alle Nutzlasteinträge des Kernelmoduls ordnungsgemäß kennzeichnen. Zum Beispiel:

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

Kernelmodule müssen explizit installiert werden. Das folgende Beispiel-Init-Skript in der Vendor-Partition zeigt die Installation über insmod :

my_init.rc :

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

Laufzeitressourcen-Overlays

Beispiel:

Betten Sie Laufzeitressourcen-Overlays mithilfe der rros Eigenschaft in einen APEX eines Anbieters 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 normalerweise auf der Anbieterpartition als vorgefertigte Dateien in Anbieter-APEXes zu finden sind, und weitere werden hinzugefügt.

Beispiele:

Zusätzliche Entwicklungsfunktionen

APEX-Auswahl beim Booten

Beispiel:

Entwickler können auch mehrere Versionen von APEX-Anbietern installieren, die denselben APEX-Namen und Schlüssel haben, 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 von APEX mit adb install .

Beispielhafte Anwendungsfälle:

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

Während des Startvorgangs sucht apexd nach Sysprops, die einem bestimmten Format folgen, um die richtige APEX-Version zu aktivieren.

Die erwarteten Formate für den Eigenschaftsschlüssel sind:

  • Bootconfig
    • Wird verwendet, um den Standardwert in BoardConfig.mk festzulegen.
    • androidboot.vendor.apex.<apex name>
  • Persistentes Sysprop
    • Wird verwendet, um den Standardwert zu ändern, der auf einem bereits gestarteten Gerät festgelegt wird.
    • Ü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.

// 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 die Aktualisierung der Bootconfig nach dem Flashen unterstützt (z. B. über fastboot oem -Befehle), ändert sich durch Ändern der Bootconfig-Eigenschaft für das mehrfach installierte APEX auch die beim Booten aktivierte Version.

Für virtuelle Referenzgeräte, die auf Cuttlefish basieren, können Sie den Befehl --extra_bootconfig_args verwenden, um die bootconfig-Eigenschaft direkt beim Start festzulegen. Zum Beispiel:

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

Sie können das APEX-Dateiformat verwenden, um untergeordnete Android-Betriebssystemmodule zu packen und zu installieren. Es ermöglicht die unabhängige Erstellung und Installation von Komponenten wie nativen Diensten und Bibliotheken, HAL-Implementierungen, Firmware, Konfigurationsdateien usw.

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

Anwendungsfälle

Modularisierung von Anbieterbildern

APEXes ermöglichen eine natürliche Bündelung und Modularisierung von Feature-Implementierungen auf Anbieter-Images.

Wenn Anbieter-Images als Kombination unabhängig erstellter Anbieter-APEXes erstellt werden, können Gerätehersteller problemlos die spezifischen Anbieterimplementierungen auswählen, die sie auf ihrem Gerät benötigen. Hersteller können sogar einen neuen Anbieter-APEX erstellen, wenn keiner der bereitgestellten APEXs ihren Anforderungen entspricht oder sie über eine brandneue kundenspezifische Hardware verfügen.

Beispielsweise kann sich ein OEM dafür entscheiden, sein Gerät mit der AOSP-WLAN-Implementierung APEX, der SoC-Bluetooth-Implementierung APEX und einer benutzerdefinierten OEM-Telefonie-Implementierung APEX zusammenzustellen.

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

Entwickler-Iteration

Vendor APEXes helfen Entwicklern, bei der Entwicklung von Vendor-Modulen schneller zu iterieren, indem sie eine komplette Feature-Implementierung, wie das WLAN-HAL, in einem Vendor APEX bündeln. Entwickler können dann den APEX des Anbieters erstellen und einzeln pushen, um Änderungen zu testen, anstatt das gesamte Anbieter-Image neu erstellen zu müssen.

Dies vereinfacht und beschleunigt den Entwickler-Iterationszyklus für Entwickler, die hauptsächlich in einem Funktionsbereich arbeiten und nur in diesem Funktionsbereich iterieren möchten.

Die natürliche Bündelung eines Feature-Bereichs in einem APEX vereinfacht auch den Prozess des Erstellens, Pushens und Testens von Änderungen für diesen Feature-Bereich. Beispielsweise werden bei der Neuinstallation eines APEX automatisch alle gebündelten Bibliotheks- oder Konfigurationsdateien aktualisiert, die im APEX enthalten sind.

Durch die Bündelung 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önnten Entwickler versuchen, eine ältere Telefonie-Implementierung APEX auf einem Gerät zu installieren (ohne einen vollständigen Build flashen zu müssen) und prüfen, ob das gute Verhalten wiederhergestellt wird.

Beispiel-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

Grundlagen

Auf der Hauptseite zum APEX-Dateiformat finden Sie allgemeine APEX-Informationen, einschließlich Geräteanforderungen, Details zum Dateiformat und Installationsschritte.

In Android.bp wird durch Festlegen der Eigenschaft vendor: true ein APEX-Modul zu einem Vendor-APEX.

apex {
  ..
  vendor: true,
  ..
}

Binärdateien und gemeinsam genutzte Bibliotheken

Ein APEX umfasst transitive Abhängigkeiten innerhalb der APEX-Nutzlast, es sei denn, sie verfügen über stabile Schnittstellen.

Zu den stabilen nativen Schnittstellen für APEX-Abhängigkeiten von Anbietern gehören cc_library mit stubs , ndk_library oder llndk_library . Diese Abhängigkeiten sind von der Paketierung ausgeschlossen und Abhängigkeiten werden im APEX-Manifest aufgezeichnet. Das Manifest wird von linkerconfig verarbeitet, sodass die externen nativen Abhängigkeiten zur Laufzeit verfügbar sind.

Im Gegensatz zu APEXes in der /system Partition sind Hersteller-APEXes normalerweise an eine bestimmte VNDK-Version gebunden. VNDK-Bibliotheken garantieren ABI-Stabilität innerhalb der Version, sodass wir VNDK-Bibliotheken als stabil behandeln und die Größe der Anbieter-APEXes reduzieren können, indem wir sie mithilfe der Eigenschaft use_vndk_as_stable von den APEXes ausschließen.

Im folgenden Snippet enthält APEX sowohl die Binärdatei ( my_service ) als auch ihre nicht stabilen Abhängigkeiten ( *.so Dateien). Es enthält keine VNDK-Bibliotheken, selbst wenn my_service mit VNDK-Bibliotheken wie libbase erstellt wird. Stattdessen verwendet my_service zur Laufzeit libbase aus vom System bereitgestellten VNDK-Bibliotheken.

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

Im folgenden Snippet enthält APEX die gemeinsam genutzte Bibliothek my_standalone_lib und alle ihre nicht stabilen Abhängigkeiten (wie oben beschrieben).

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

HAL-Implementierungen

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

Um die HAL-Implementierung vollständig zu kapseln, sollte der APEX auch alle relevanten VINTF-Fragmente und Init-Skripte angeben.

VINTF-Fragmente

VINTF-Fragmente können von einem Anbieter-APEX bereitgestellt werden, wenn sich Fragmente in etc/vintf des APEX befinden.

Verwenden Sie die prebuilts Eigenschaft, um die VINTF-Fragmente in APEX einzubetten.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

Init-Skripte

APEXes können Init-Skripte auf zwei Arten enthalten: (A) eine vorgefertigte Textdatei innerhalb der APEX-Nutzlast oder (B) ein reguläres Init-Skript in /vendor/etc . Sie können beide für denselben APEX festlegen.

Init-Skript in APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

Init-Skripte innerhalb von APEXes können nur service haben. Init-Skripte in Vendor APEXes können auch on <property> -Anweisungen haben.

Seien Sie vorsichtig, wenn Sie on Anweisungen verwenden. Da Init-Skripte in APEXes nach der Aktivierung von APEXes analysiert 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.

Firmware

Beispiel:

Betten Sie die Firmware wie folgt in ein APEX eines Anbieters mit dem Modultyp prebuilt_firmware ein.

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 durchsucht die Verzeichnisse /apex/*/etc/firmware nach Firmware-Modulen.

Die file_contexts des APEX sollten alle Firmware-Nutzdateneinträge ordnungsgemäß kennzeichnen, um sicherzustellen, dass ueventd zur Laufzeit auf diese Dateien zugreifen kann. Normalerweise ist die Bezeichnung vendor_file ausreichend. Zum Beispiel:

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

Kernel-Module

Betten Sie Kernelmodule wie folgt als vorgefertigte Module in ein APEX eines Anbieters 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 des APEX sollten alle Nutzlasteinträge des Kernelmoduls ordnungsgemäß kennzeichnen. Zum Beispiel:

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

Kernelmodule müssen explizit installiert werden. Das folgende Beispiel-Init-Skript in der Vendor-Partition zeigt die Installation über insmod :

my_init.rc :

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

Laufzeitressourcen-Overlays

Beispiel:

Betten Sie Laufzeitressourcen-Overlays mithilfe der rros Eigenschaft in einen APEX eines Anbieters 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 normalerweise auf der Anbieterpartition als vorgefertigte Dateien in Anbieter-APEXes zu finden sind, und weitere werden hinzugefügt.

Beispiele:

Zusätzliche Entwicklungsfunktionen

APEX-Auswahl beim Booten

Beispiel:

Entwickler können auch mehrere Versionen von APEX-Anbietern installieren, die denselben APEX-Namen und Schlüssel haben, 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 von APEX mit adb install .

Beispielhafte Anwendungsfälle:

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

Während des Startvorgangs sucht apexd nach Sysprops, die einem bestimmten Format folgen, um die richtige APEX-Version zu aktivieren.

Die erwarteten Formate für den Eigenschaftsschlüssel sind:

  • Bootconfig
    • Wird verwendet, um den Standardwert in BoardConfig.mk festzulegen.
    • androidboot.vendor.apex.<apex name>
  • Persistentes Sysprop
    • Wird verwendet, um den Standardwert zu ändern, der auf einem bereits gestarteten Gerät festgelegt wird.
    • Ü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.

// 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 die Aktualisierung der Bootconfig nach dem Flashen unterstützt (z. B. über fastboot oem -Befehle), ändert sich durch Ändern der Bootconfig-Eigenschaft für das mehrfach installierte APEX auch die beim Booten aktivierte Version.

Für virtuelle Referenzgeräte, die auf Cuttlefish basieren, können Sie den Befehl --extra_bootconfig_args verwenden, um die bootconfig-Eigenschaft direkt beim Start festzulegen. Zum Beispiel:

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

Sie können das APEX-Dateiformat verwenden, um untergeordnete Android-Betriebssystemmodule zu packen und zu installieren. Es ermöglicht die unabhängige Erstellung und Installation von Komponenten wie nativen Diensten und Bibliotheken, HAL-Implementierungen, Firmware, Konfigurationsdateien usw.

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

Anwendungsfälle

Modularisierung von Anbieterbildern

APEXes ermöglichen eine natürliche Bündelung und Modularisierung von Feature-Implementierungen auf Anbieter-Images.

Wenn Anbieter-Images als Kombination unabhängig erstellter Anbieter-APEXes erstellt werden, können Gerätehersteller problemlos die spezifischen Anbieterimplementierungen auswählen, die sie auf ihrem Gerät benötigen. Hersteller können sogar einen neuen Anbieter-APEX erstellen, wenn keiner der bereitgestellten APEXs ihren Anforderungen entspricht oder sie über eine brandneue kundenspezifische Hardware verfügen.

Beispielsweise kann sich ein OEM dafür entscheiden, sein Gerät mit der AOSP-WLAN-Implementierung APEX, der SoC-Bluetooth-Implementierung APEX und einer benutzerdefinierten OEM-Telefonie-Implementierung APEX zusammenzustellen.

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

Entwickler-Iteration

Vendor APEXes helfen Entwicklern, bei der Entwicklung von Vendor-Modulen schneller zu iterieren, indem sie eine komplette Feature-Implementierung, wie das WLAN-HAL, in einem Vendor APEX bündeln. Entwickler können dann den APEX des Anbieters erstellen und einzeln pushen, um Änderungen zu testen, anstatt das gesamte Anbieter-Image neu erstellen zu müssen.

Dies vereinfacht und beschleunigt den Entwickler-Iterationszyklus für Entwickler, die hauptsächlich in einem Funktionsbereich arbeiten und nur in diesem Funktionsbereich iterieren möchten.

Die natürliche Bündelung eines Feature-Bereichs in einem APEX vereinfacht auch den Prozess des Erstellens, Pushens und Testens von Änderungen für diesen Feature-Bereich. Beispielsweise werden bei der Neuinstallation eines APEX automatisch alle gebündelten Bibliotheks- oder Konfigurationsdateien aktualisiert, die im APEX enthalten sind.

Durch die Bündelung 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önnten Entwickler versuchen, eine ältere Telefonie-Implementierung APEX auf einem Gerät zu installieren (ohne einen vollständigen Build flashen zu müssen) und prüfen, ob das gute Verhalten wiederhergestellt wird.

Beispiel-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

Grundlagen

Auf der Hauptseite zum APEX-Dateiformat finden Sie allgemeine APEX-Informationen, einschließlich Geräteanforderungen, Details zum Dateiformat und Installationsschritte.

In Android.bp wird durch Festlegen der Eigenschaft vendor: true ein APEX-Modul zu einem Vendor-APEX.

apex {
  ..
  vendor: true,
  ..
}

Binärdateien und gemeinsam genutzte Bibliotheken

Ein APEX umfasst transitive Abhängigkeiten innerhalb der APEX-Nutzlast, es sei denn, sie verfügen über stabile Schnittstellen.

Zu den stabilen nativen Schnittstellen für APEX-Abhängigkeiten von Anbietern gehören cc_library mit stubs , ndk_library oder llndk_library . Diese Abhängigkeiten sind von der Paketierung ausgeschlossen und Abhängigkeiten werden im APEX-Manifest aufgezeichnet. Das Manifest wird von linkerconfig verarbeitet, sodass die externen nativen Abhängigkeiten zur Laufzeit verfügbar sind.

Im Gegensatz zu APEXes in der /system Partition sind Hersteller-APEXes normalerweise an eine bestimmte VNDK-Version gebunden. VNDK-Bibliotheken garantieren ABI-Stabilität innerhalb der Version, sodass wir VNDK-Bibliotheken als stabil behandeln und die Größe der Anbieter-APEXes reduzieren können, indem wir sie mithilfe der Eigenschaft use_vndk_as_stable von den APEXes ausschließen.

Im folgenden Snippet enthält APEX sowohl die Binärdatei ( my_service ) als auch ihre nicht stabilen Abhängigkeiten ( *.so Dateien). Es enthält keine VNDK-Bibliotheken, selbst wenn my_service mit VNDK-Bibliotheken wie libbase erstellt wird. Stattdessen verwendet my_service zur Laufzeit libbase aus vom System bereitgestellten VNDK-Bibliotheken.

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

Im folgenden Snippet enthält APEX die gemeinsam genutzte Bibliothek my_standalone_lib und alle ihre nicht stabilen Abhängigkeiten (wie oben beschrieben).

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

HAL-Implementierungen

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

Um die HAL-Implementierung vollständig zu kapseln, sollte der APEX auch alle relevanten VINTF-Fragmente und Init-Skripte angeben.

VINTF-Fragmente

VINTF-Fragmente können von einem Anbieter-APEX bereitgestellt werden, wenn sich Fragmente in etc/vintf des APEX befinden.

Verwenden Sie die prebuilts Eigenschaft, um die VINTF-Fragmente in APEX einzubetten.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

Init-Skripte

APEXes können Init-Skripte auf zwei Arten enthalten: (A) eine vorgefertigte Textdatei innerhalb der APEX-Nutzlast oder (B) ein reguläres Init-Skript in /vendor/etc . Sie können beide für denselben APEX festlegen.

Init-Skript in APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

Init-Skripte innerhalb von APEXes können nur service haben. Init-Skripte in Vendor APEXes können auch on <property> -Anweisungen haben.

Seien Sie vorsichtig, wenn Sie on Anweisungen verwenden. Da Init-Skripte in APEXes nach der Aktivierung von APEXes analysiert 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.

Firmware

Beispiel:

Betten Sie die Firmware wie folgt in ein APEX eines Anbieters mit dem Modultyp prebuilt_firmware ein.

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 durchsucht die Verzeichnisse /apex/*/etc/firmware nach Firmware-Modulen.

Die file_contexts des APEX sollten alle Firmware-Nutzdateneinträge ordnungsgemäß kennzeichnen, um sicherzustellen, dass ueventd zur Laufzeit auf diese Dateien zugreifen kann. Normalerweise ist die Bezeichnung vendor_file ausreichend. Zum Beispiel:

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

Kernel-Module

Betten Sie Kernelmodule wie folgt als vorgefertigte Module in ein APEX eines Anbieters 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 des APEX sollten alle Nutzlasteinträge des Kernelmoduls ordnungsgemäß kennzeichnen. Zum Beispiel:

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

Kernelmodule müssen explizit installiert werden. Das folgende Beispiel-Init-Skript in der Vendor-Partition zeigt die Installation über insmod :

my_init.rc :

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

Laufzeitressourcen-Overlays

Beispiel:

Betten Sie Laufzeitressourcen-Overlays mithilfe der rros Eigenschaft in einen APEX eines Anbieters 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 normalerweise auf der Anbieterpartition als vorgefertigte Dateien in Anbieter-APEXes zu finden sind, und weitere werden hinzugefügt.

Beispiele:

Zusätzliche Entwicklungsfunktionen

APEX-Auswahl beim Booten

Beispiel:

Entwickler können auch mehrere Versionen von APEX-Anbietern installieren, die denselben APEX-Namen und Schlüssel haben, 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 von APEX mit adb install .

Beispielhafte Anwendungsfälle:

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

Während des Startvorgangs sucht apexd nach Sysprops, die einem bestimmten Format folgen, um die richtige APEX-Version zu aktivieren.

Die erwarteten Formate für den Eigenschaftsschlüssel sind:

  • Bootconfig
    • Wird verwendet, um den Standardwert in BoardConfig.mk festzulegen.
    • androidboot.vendor.apex.<apex name>
  • Persistentes Sysprop
    • Wird verwendet, um den Standardwert zu ändern, der auf einem bereits gestarteten Gerät festgelegt wird.
    • Ü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.

// 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 die Aktualisierung der Bootconfig nach dem Flashen unterstützt (z. B. über fastboot oem -Befehle), ändert sich durch Ändern der Bootconfig-Eigenschaft für das mehrfach installierte APEX auch die beim Booten aktivierte Version.

Für virtuelle Referenzgeräte, die auf Cuttlefish basieren, können Sie den Befehl --extra_bootconfig_args verwenden, um die bootconfig-Eigenschaft direkt beim Start festzulegen. Zum Beispiel:

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