Dostawca APEX

Możesz użyć formatu pliku APEX do spakowania i zainstalowania modułów systemu operacyjnego Android niższego poziomu. Umożliwia niezależne budowanie i instalację komponentów, takich jak natywne usługi i biblioteki, implementacje HAL, oprogramowanie sprzętowe, pliki konfiguracyjne itp.

Moduły APEX dostawcy są automatycznie instalowane przez system kompilacji na partycji /vendor i aktywowane w czasie wykonywania przez apexd , podobnie jak APEXy w innych partycjach.

Przypadków użycia

Modularyzacja obrazów dostawców

APEXy ułatwiają naturalne łączenie i modularyzację implementacji funkcji na obrazach dostawców.

Gdy obrazy dostawców są tworzone jako kombinacja niezależnie zbudowanych plików APEX dostawców, producenci urządzeń mogą łatwo wybierać konkretne implementacje dostawców, które chcą zastosować na swoim urządzeniu. Producenci mogą nawet stworzyć nowy dostawca APEX, jeśli żaden z dostarczonych APEXów nie odpowiada ich potrzebom lub mają zupełnie nowy, niestandardowy sprzęt.

Na przykład producent OEM może zdecydować się na skomponowanie swojego urządzenia z implementacją Wi-Fi AOSP APEX, implementacją Bluetooth SoC APEX i niestandardową implementacją telefonii OEM APEX.

Bez aplikacji APEX dostawcy implementacja z tak wieloma zależnościami między komponentami dostawcy wymaga starannej koordynacji i śledzenia. Dzięki opakowaniu wszystkich komponentów (w tym plików konfiguracyjnych i dodatkowych bibliotek) w pliki APEX z jasno zdefiniowanymi interfejsami w dowolnym punkcie komunikacji między funkcjami, różne komponenty stają się wymienne.

Iteracja deweloperska

APEX dostawcy pomagają programistom szybciej iterować podczas opracowywania modułów dostawcy, łącząc całą implementację funkcji, taką jak Wi-Fi HAL, w APEX dostawcy. Programiści mogą następnie zbudować i indywidualnie wypchnąć APEX dostawcy w celu przetestowania zmian, zamiast odbudowywać cały obraz dostawcy.

Upraszcza to i przyspiesza cykl iteracji programisty w przypadku programistów, którzy pracują głównie w jednym obszarze funkcji i chcą iterować tylko w tym obszarze funkcji.

Naturalne połączenie obszaru funkcji w APEX upraszcza również proces tworzenia, wypychania i testowania zmian dla tego obszaru funkcji. Na przykład ponowna instalacja APEX automatycznie aktualizuje wszystkie dołączone biblioteki lub pliki konfiguracyjne, które zawiera APEX.

Łączenie obszaru funkcji w plik APEX upraszcza także debugowanie lub przywracanie ustawień w przypadku zaobserwowania nieprawidłowego zachowania urządzenia. Na przykład, jeśli telefonia działa słabo w nowej wersji, programiści mogą spróbować zainstalować starszą implementację telefonii APEX na urządzeniu (bez konieczności flashowania pełnej wersji) i sprawdzić, czy przywrócone zostanie dobre działanie.

Przykładowy przepływ pracy:

# 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 ...

Przykłady

Podstawy

Zobacz główną stronę formatu pliku APEX , aby uzyskać ogólne informacje dotyczące APEX, w tym wymagania dotyczące urządzenia, szczegóły dotyczące formatu pliku i kroki instalacji.

W Android.bp ustawienie właściwości vendor: true powoduje, że moduł APEX staje się punktem APEX dostawcy.

apex {
  ..
  vendor: true,
  ..
}

Pliki binarne i biblioteki współdzielone

APEX zawiera zależności przechodnie wewnątrz ładunku APEX, chyba że mają stabilne interfejsy.

Stabilne natywne interfejsy dla zależności APEX dostawcy obejmują cc_library z stubs , ndk_library lub llndk_library . Zależności te są wykluczone z pakowania i są rejestrowane w manifeście APEX. Manifest jest przetwarzany przez linkerconfig , dzięki czemu zewnętrzne zależności natywne są dostępne w czasie wykonywania.

W odróżnieniu od plików APEX w partycji /system , pliki APEX dostawcy są zazwyczaj powiązane z konkretną wersją VNDK. Biblioteki VNDK gwarantują stabilność ABI w wydaniu, więc możemy traktować biblioteki VNDK jako stabilne i zmniejszyć rozmiar APEX-ów dostawcy, wykluczając je z APEXów za pomocą właściwości use_vndk_as_stable .

W poniższym fragmencie plik APEX będzie zawierał zarówno zależności binarne ( my_service ), jak i jego niestabilne zależności ( pliki *.so ). Nie będzie zawierać bibliotek VNDK, nawet jeśli my_service jest zbudowany z bibliotek VNDK, takich jak libbase . Zamiast tego w czasie wykonywania my_service użyje libbase z bibliotek VNDK dostarczonych przez system.

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

W poniższym fragmencie APEX będzie zawierał bibliotekę współdzieloną my_standalone_lib i wszystkie jej niestabilne zależności (jak opisano powyżej).

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

Implementacje HAL-a

Aby zdefiniować implementację HAL, podaj odpowiednie pliki binarne i biblioteki wewnątrz pliku APEX dostawcy, podobnie jak w poniższych przykładach:

Aby w pełni enkapsulować implementację HAL, APEX powinien również określać wszelkie istotne fragmenty VINTF i skrypty inicjujące.

fragmenty VINTF

Fragmenty VINTF mogą być udostępniane przez dostawcę APEX, jeśli fragmenty znajdują się w etc/vintf APEX.

Użyj właściwości prebuilts , aby osadzić fragmenty VINTF w pliku APEX.

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

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

Skrypty inicjujące

APEXy mogą zawierać skrypty init na dwa sposoby: (A) wstępnie zbudowany plik tekstowy w ładunku APEX lub (B) zwykły skrypt init w /vendor/etc . Możesz ustawić oba dla tego samego APEX.

Skrypt inicjujący w APEX:

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

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

Skrypty inicjujące w APEXach mogą mieć tylko definicje service . Skrypty inicjujące w APEXach dostawców mogą również zawierać dyrektywy on <property> .

Zachowaj ostrożność podczas używania dyrektyw on . Ponieważ skrypty init w APEXach są analizowane i wykonywane po aktywowaniu APEXów, nie można użyć niektórych zdarzeń lub właściwości. Użyj apex.all.ready=true aby rozpocząć akcje tak wcześnie, jak to możliwe.

Oprogramowanie sprzętowe

Przykład:

Osadź oprogramowanie sprzętowe w urządzeniu APEX dostawcy z typem modułu prebuilt_firmware w następujący sposób.

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
  ..
}

moduły prebuilt_firmware są instalowane w katalogu <apex name>/etc/firmware w APEX. ueventd skanuje katalogi /apex/*/etc/firmware w celu znalezienia modułów oprogramowania sprzętowego.

file_contexts APEX powinien odpowiednio oznaczyć wszelkie wpisy ładunku oprogramowania sprzętowego, aby zapewnić, że pliki te będą dostępne dla ueventd w czasie wykonywania; zazwyczaj wystarczająca jest etykieta vendor_file . Na przykład:

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

Moduły jądra

Osadź moduły jądra w APEX dostawcy jako gotowe moduły w następujący sposób.

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
  ..
}

file_contexts APEX powinien poprawnie oznaczać wszelkie wpisy ładunku modułu jądra. Na przykład:

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

Moduły jądra muszą być zainstalowane jawnie. Poniższy przykładowy skrypt init na partycji dostawcy przedstawia instalację poprzez insmod :

my_init.rc :

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

Nakładki zasobów środowiska wykonawczego

Przykład:

Osadź nakładki zasobów środowiska wykonawczego w APEX dostawcy, używając właściwości rros .

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

Inne pliki konfiguracyjne

Moduły APEX dostawców obsługują różne inne pliki konfiguracyjne, zwykle znajdujące się na partycji dostawcy, jako gotowe pliki w plikach APEX dostawców, a kolejne są dodawane.

Przykłady:

Dodatkowe funkcje rozwojowe

Wybór APEX podczas uruchamiania

Przykład:

Programiści mogą także zainstalować wiele wersji APEX-ów dostawcy, które mają tę samą nazwę i klucz APEX, a następnie wybrać, która wersja ma być aktywowana podczas każdego uruchomienia, korzystając z trwałych sysprops. W niektórych przypadkach użycia przez programistów może to być prostsze niż zainstalowanie nowej kopii APEX za pomocą adb install .

Przykładowe przypadki użycia:

  • Zainstaluj 3 wersje APEX, dostawcy Wi-Fi HAL: zespoły ds. kontroli jakości mogą przeprowadzić ręczne lub automatyczne testy przy użyciu jednej wersji, następnie uruchomić ponownie komputer w innej wersji i ponownie uruchomić testy, a następnie porównać ostateczne wyniki.
  • Zainstaluj 2 wersje kamery HAL, dostawcy APEX, aktualną i eksperymentalną : testerzy mogą korzystać z wersji eksperymentalnej bez pobierania i instalowania dodatkowego pliku, dzięki czemu mogą łatwo wymieniać.

Podczas uruchamiania apexd szuka sysprops w określonym formacie, aby aktywować odpowiednią wersję APEX.

Oczekiwane formaty klucza właściwości to:

  • Konfiguracja rozruchowa
    • Służy do ustawiania wartości domyślnej w BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Trwałe sysprop
    • Służy do zmiany wartości domyślnej, ustawionej na już uruchomionym urządzeniu.
    • Zastępuje wartość bootconfig, jeśli jest obecna.
    • persist.vendor.apex.<apex name>

Wartością właściwości powinna być nazwa pliku APEX, który ma zostać aktywowany.

// 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,
  ..
}

Domyślną wersję należy również skonfigurować za pomocą bootconfig w BoardConfig.mk :

# 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

Po uruchomieniu urządzenia zmień aktywowaną wersję, ustawiając trwały sysprop:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

Jeśli urządzenie obsługuje aktualizację bootconfig po flashowaniu (na przykład za pomocą poleceń fastboot oem ), wówczas zmiana właściwości bootconfig dla wieloinstalowanego APEX zmienia również wersję aktywowaną podczas uruchamiania.

W przypadku wirtualnych urządzeń referencyjnych opartych na mątwie można użyć polecenia --extra_bootconfig_args , aby ustawić właściwość bootconfig bezpośrednio podczas uruchamiania. Na przykład:

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

Możesz użyć formatu pliku APEX do spakowania i zainstalowania modułów systemu operacyjnego Android niższego poziomu. Umożliwia niezależne budowanie i instalację komponentów, takich jak natywne usługi i biblioteki, implementacje HAL, oprogramowanie sprzętowe, pliki konfiguracyjne itp.

Moduły APEX dostawcy są automatycznie instalowane przez system kompilacji na partycji /vendor i aktywowane w czasie wykonywania przez apexd , podobnie jak APEXy w innych partycjach.

Przypadków użycia

Modularyzacja obrazów dostawców

APEXy ułatwiają naturalne łączenie i modularyzację implementacji funkcji na obrazach dostawców.

Kiedy obrazy dostawców są tworzone jako kombinacja niezależnie zbudowanych APEX-ów dostawców, producenci urządzeń mogą łatwo wybierać konkretne implementacje dostawców, które chcą mieć na swoim urządzeniu. Producenci mogą nawet stworzyć nowy dostawca APEX, jeśli żaden z dostarczonych APEXów nie odpowiada ich potrzebom lub mają zupełnie nowy, niestandardowy sprzęt.

Na przykład producent OEM może zdecydować się na skomponowanie swojego urządzenia z implementacją Wi-Fi AOSP APEX, implementacją Bluetooth SoC APEX i niestandardową implementacją telefonii OEM APEX.

Bez aplikacji APEX dostawcy implementacja z tak wieloma zależnościami między komponentami dostawcy wymaga starannej koordynacji i śledzenia. Dzięki opakowaniu wszystkich komponentów (w tym plików konfiguracyjnych i dodatkowych bibliotek) w pliki APEX z jasno zdefiniowanymi interfejsami w dowolnym punkcie komunikacji między funkcjami, różne komponenty stają się wymienne.

Iteracja deweloperska

APEX dostawcy pomagają programistom szybciej iterować podczas opracowywania modułów dostawcy, łącząc całą implementację funkcji, taką jak Wi-Fi HAL, w APEX dostawcy. Programiści mogą następnie zbudować i indywidualnie wypchnąć APEX dostawcy w celu przetestowania zmian, zamiast odbudowywać cały obraz dostawcy.

Upraszcza to i przyspiesza cykl iteracji programisty w przypadku programistów, którzy pracują głównie w jednym obszarze funkcji i chcą iterować tylko w tym obszarze funkcji.

Naturalne połączenie obszaru funkcji w APEX upraszcza również proces tworzenia, wypychania i testowania zmian dla tego obszaru funkcji. Na przykład ponowna instalacja APEX automatycznie aktualizuje wszystkie dołączone biblioteki lub pliki konfiguracyjne, które zawiera APEX.

Łączenie obszaru funkcji w plik APEX upraszcza także debugowanie lub przywracanie ustawień w przypadku zaobserwowania nieprawidłowego zachowania urządzenia. Na przykład, jeśli telefonia działa słabo w nowej wersji, programiści mogą spróbować zainstalować starszą implementację telefonii APEX na urządzeniu (bez konieczności flashowania pełnej wersji) i sprawdzić, czy przywrócone zostanie dobre działanie.

Przykładowy przepływ pracy:

# 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 ...

Przykłady

Podstawy

Zobacz główną stronę formatu pliku APEX , aby uzyskać ogólne informacje dotyczące APEX, w tym wymagania dotyczące urządzenia, szczegóły dotyczące formatu pliku i kroki instalacji.

W Android.bp ustawienie właściwości vendor: true powoduje, że moduł APEX staje się punktem APEX dostawcy.

apex {
  ..
  vendor: true,
  ..
}

Pliki binarne i biblioteki współdzielone

APEX zawiera zależności przechodnie wewnątrz ładunku APEX, chyba że mają stabilne interfejsy.

Stabilne natywne interfejsy dla zależności APEX dostawcy obejmują cc_library z stubs , ndk_library lub llndk_library . Zależności te są wykluczone z pakowania i są rejestrowane w manifeście APEX. Manifest jest przetwarzany przez linkerconfig , dzięki czemu zewnętrzne zależności natywne są dostępne w czasie wykonywania.

W odróżnieniu od plików APEX w partycji /system , pliki APEX dostawcy są zazwyczaj powiązane z konkretną wersją VNDK. Biblioteki VNDK gwarantują stabilność ABI w wydaniu, więc możemy traktować biblioteki VNDK jako stabilne i zmniejszyć rozmiar APEX-ów dostawcy, wykluczając je z APEXów za pomocą właściwości use_vndk_as_stable .

W poniższym fragmencie plik APEX będzie zawierał zarówno zależności binarne ( my_service ), jak i jego niestabilne zależności ( pliki *.so ). Nie będzie zawierać bibliotek VNDK, nawet jeśli my_service jest zbudowany z bibliotek VNDK, takich jak libbase . Zamiast tego w czasie wykonywania my_service użyje libbase z bibliotek VNDK dostarczonych przez system.

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

W poniższym fragmencie APEX będzie zawierał bibliotekę współdzieloną my_standalone_lib i wszystkie jej niestabilne zależności (jak opisano powyżej).

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

Implementacje HAL-a

Aby zdefiniować implementację HAL, podaj odpowiednie pliki binarne i biblioteki wewnątrz pliku APEX dostawcy, podobnie jak w poniższych przykładach:

Aby w pełni enkapsulować implementację HAL, APEX powinien również określać wszelkie istotne fragmenty VINTF i skrypty inicjujące.

fragmenty VINTF

Fragmenty VINTF mogą być udostępniane przez dostawcę APEX, jeśli fragmenty znajdują się w etc/vintf APEX.

Użyj właściwości prebuilts , aby osadzić fragmenty VINTF w pliku APEX.

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

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

Skrypty inicjujące

APEXy mogą zawierać skrypty init na dwa sposoby: (A) wstępnie zbudowany plik tekstowy w ładunku APEX lub (B) zwykły skrypt init w /vendor/etc . Możesz ustawić oba dla tego samego APEX.

Skrypt inicjujący w APEX:

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

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

Skrypty inicjujące w APEXach mogą mieć tylko definicje service . Skrypty inicjujące w APEXach dostawców mogą również zawierać dyrektywy on <property> .

Zachowaj ostrożność podczas używania dyrektyw on . Ponieważ skrypty init w APEXach są analizowane i wykonywane po aktywowaniu APEXów, nie można użyć niektórych zdarzeń lub właściwości. Użyj apex.all.ready=true aby rozpocząć akcje tak wcześnie, jak to możliwe.

Oprogramowanie sprzętowe

Przykład:

Osadź oprogramowanie sprzętowe w urządzeniu APEX dostawcy z typem modułu prebuilt_firmware w następujący sposób.

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
  ..
}

moduły prebuilt_firmware są instalowane w katalogu <apex name>/etc/firmware w APEX. ueventd skanuje katalogi /apex/*/etc/firmware w celu znalezienia modułów oprogramowania sprzętowego.

file_contexts APEX powinien odpowiednio oznaczyć wszelkie wpisy ładunku oprogramowania sprzętowego, aby zapewnić, że pliki te będą dostępne dla ueventd w czasie wykonywania; zazwyczaj wystarczająca jest etykieta vendor_file . Na przykład:

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

Moduły jądra

Osadź moduły jądra w APEX dostawcy jako gotowe moduły w następujący sposób.

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
  ..
}

file_contexts APEX powinien poprawnie oznaczać wszelkie wpisy ładunku modułu jądra. Na przykład:

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

Moduły jądra muszą być zainstalowane jawnie. Poniższy przykładowy skrypt init na partycji dostawcy przedstawia instalację poprzez insmod :

my_init.rc :

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

Nakładki zasobów środowiska wykonawczego

Przykład:

Osadź nakładki zasobów środowiska wykonawczego w APEX dostawcy, używając właściwości rros .

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

Inne pliki konfiguracyjne

Moduły APEX dostawców obsługują różne inne pliki konfiguracyjne, zwykle znajdujące się na partycji dostawcy, jako gotowe pliki w plikach APEX dostawców, a kolejne są dodawane.

Przykłady:

Dodatkowe funkcje rozwojowe

Wybór APEX podczas uruchamiania

Przykład:

Programiści mogą także zainstalować wiele wersji APEX-ów dostawcy, które mają tę samą nazwę i klucz APEX, a następnie wybrać, która wersja ma być aktywowana podczas każdego uruchomienia, korzystając z trwałych sysprops. W niektórych przypadkach użycia przez programistów może to być prostsze niż zainstalowanie nowej kopii APEX za pomocą adb install .

Przykładowe przypadki użycia:

  • Zainstaluj 3 wersje APEX, dostawcy Wi-Fi HAL: zespoły ds. kontroli jakości mogą przeprowadzić ręczne lub automatyczne testy przy użyciu jednej wersji, następnie uruchomić ponownie komputer w innej wersji i ponownie uruchomić testy, a następnie porównać ostateczne wyniki.
  • Zainstaluj 2 wersje kamery HAL, dostawcy APEX, aktualną i eksperymentalną : testerzy mogą korzystać z wersji eksperymentalnej bez pobierania i instalowania dodatkowego pliku, dzięki czemu mogą łatwo wymieniać.

Podczas uruchamiania apexd szuka sysprops w określonym formacie, aby aktywować odpowiednią wersję APEX.

Oczekiwane formaty klucza właściwości to:

  • Konfiguracja rozruchowa
    • Służy do ustawiania wartości domyślnej w BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Trwałe sysprop
    • Służy do zmiany wartości domyślnej, ustawionej na już uruchomionym urządzeniu.
    • Zastępuje wartość bootconfig, jeśli jest obecna.
    • persist.vendor.apex.<apex name>

Wartością właściwości powinna być nazwa pliku APEX, który ma zostać aktywowany.

// 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,
  ..
}

Domyślną wersję należy również skonfigurować za pomocą bootconfig w BoardConfig.mk :

# 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

Po uruchomieniu urządzenia zmień aktywowaną wersję, ustawiając trwały sysprop:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

Jeśli urządzenie obsługuje aktualizację bootconfig po flashowaniu (na przykład za pomocą poleceń fastboot oem ), wówczas zmiana właściwości bootconfig dla wieloinstalowanego APEX zmienia również wersję aktywowaną podczas uruchamiania.

W przypadku wirtualnych urządzeń referencyjnych opartych na mątwie można użyć polecenia --extra_bootconfig_args , aby ustawić właściwość bootconfig bezpośrednio podczas uruchamiania. Na przykład:

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

Możesz użyć formatu pliku APEX do spakowania i zainstalowania modułów systemu operacyjnego Android niższego poziomu. Umożliwia niezależne budowanie i instalację komponentów, takich jak natywne usługi i biblioteki, implementacje HAL, oprogramowanie sprzętowe, pliki konfiguracyjne itp.

Moduły APEX dostawcy są automatycznie instalowane przez system kompilacji na partycji /vendor i aktywowane w czasie wykonywania przez apexd , podobnie jak APEXy w innych partycjach.

Przypadków użycia

Modularyzacja obrazów dostawców

APEXy ułatwiają naturalne łączenie i modularyzację implementacji funkcji na obrazach dostawców.

Kiedy obrazy dostawców są tworzone jako kombinacja niezależnie zbudowanych APEX-ów dostawców, producenci urządzeń mogą łatwo wybierać konkretne implementacje dostawców, które chcą mieć na swoim urządzeniu. Producenci mogą nawet stworzyć nowy dostawca APEX, jeśli żaden z dostarczonych APEXów nie odpowiada ich potrzebom lub mają zupełnie nowy, niestandardowy sprzęt.

Na przykład producent OEM może zdecydować się na skomponowanie swojego urządzenia z implementacją Wi-Fi AOSP APEX, implementacją Bluetooth SoC APEX i niestandardową implementacją telefonii OEM APEX.

Bez aplikacji APEX dostawcy implementacja z tak wieloma zależnościami między komponentami dostawcy wymaga starannej koordynacji i śledzenia. Dzięki opakowaniu wszystkich komponentów (w tym plików konfiguracyjnych i dodatkowych bibliotek) w pliki APEX z jasno zdefiniowanymi interfejsami w dowolnym punkcie komunikacji między funkcjami, różne komponenty stają się wymienne.

Iteracja deweloperska

APEX dostawcy pomagają programistom szybciej iterować podczas opracowywania modułów dostawcy, łącząc całą implementację funkcji, taką jak Wi-Fi HAL, w APEX dostawcy. Programiści mogą następnie zbudować i indywidualnie wypchnąć APEX dostawcy w celu przetestowania zmian, zamiast odbudowywać cały obraz dostawcy.

Upraszcza to i przyspiesza cykl iteracji programisty w przypadku programistów, którzy pracują głównie w jednym obszarze funkcji i chcą iterować tylko w tym obszarze funkcji.

Naturalne połączenie obszaru funkcji w APEX upraszcza również proces tworzenia, wypychania i testowania zmian dla tego obszaru funkcji. Na przykład ponowna instalacja APEX automatycznie aktualizuje wszystkie dołączone biblioteki lub pliki konfiguracyjne, które zawiera APEX.

Łączenie obszaru funkcji w plik APEX upraszcza także debugowanie lub przywracanie ustawień w przypadku zaobserwowania nieprawidłowego zachowania urządzenia. Na przykład, jeśli telefonia działa słabo w nowej wersji, programiści mogą spróbować zainstalować starszą implementację telefonii APEX na urządzeniu (bez konieczności flashowania pełnej wersji) i sprawdzić, czy przywrócone zostanie dobre działanie.

Przykładowy przepływ pracy:

# 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 ...

Przykłady

Podstawy

Zobacz główną stronę formatu pliku APEX , aby uzyskać ogólne informacje dotyczące APEX, w tym wymagania dotyczące urządzenia, szczegóły dotyczące formatu pliku i kroki instalacji.

W Android.bp ustawienie właściwości vendor: true powoduje, że moduł APEX staje się punktem APEX dostawcy.

apex {
  ..
  vendor: true,
  ..
}

Pliki binarne i biblioteki współdzielone

APEX zawiera zależności przechodnie wewnątrz ładunku APEX, chyba że mają stabilne interfejsy.

Stabilne natywne interfejsy dla zależności APEX dostawcy obejmują cc_library z stubs , ndk_library lub llndk_library . Zależności te są wykluczone z pakowania i są rejestrowane w manifeście APEX. Manifest jest przetwarzany przez linkerconfig , dzięki czemu zewnętrzne zależności natywne są dostępne w czasie wykonywania.

W odróżnieniu od plików APEX w partycji /system , pliki APEX dostawcy są zazwyczaj powiązane z konkretną wersją VNDK. Biblioteki VNDK gwarantują stabilność ABI w wydaniu, więc możemy traktować biblioteki VNDK jako stabilne i zmniejszyć rozmiar APEX-ów dostawcy, wykluczając je z APEXów za pomocą właściwości use_vndk_as_stable .

W poniższym fragmencie plik APEX będzie zawierał zarówno zależności binarne ( my_service ), jak i jego niestabilne zależności ( pliki *.so ). Nie będzie zawierać bibliotek VNDK, nawet jeśli my_service jest zbudowany z bibliotek VNDK, takich jak libbase . Zamiast tego w czasie wykonywania my_service użyje libbase z bibliotek VNDK dostarczonych przez system.

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

W poniższym fragmencie APEX będzie zawierał bibliotekę współdzieloną my_standalone_lib i wszystkie jej niestabilne zależności (jak opisano powyżej).

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

Implementacje HAL-a

Aby zdefiniować implementację HAL, podaj odpowiednie pliki binarne i biblioteki wewnątrz pliku APEX dostawcy, podobnie jak w poniższych przykładach:

Aby w pełni enkapsulować implementację HAL, APEX powinien również określać wszelkie istotne fragmenty VINTF i skrypty inicjujące.

fragmenty VINTF

Fragmenty VINTF mogą być udostępniane przez dostawcę APEX, jeśli fragmenty znajdują się w etc/vintf APEX.

Użyj właściwości prebuilts , aby osadzić fragmenty VINTF w pliku APEX.

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

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

Skrypty inicjujące

APEXy mogą zawierać skrypty init na dwa sposoby: (A) wstępnie zbudowany plik tekstowy w ładunku APEX lub (B) zwykły skrypt init w /vendor/etc . Możesz ustawić oba dla tego samego APEX.

Skrypt inicjujący w APEX:

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

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

Skrypty inicjujące w APEXach mogą mieć tylko definicje service . Skrypty inicjujące w APEXach dostawców mogą również zawierać dyrektywy on <property> .

Zachowaj ostrożność podczas używania dyrektyw on . Ponieważ skrypty init w APEXach są analizowane i wykonywane po aktywowaniu APEXów, nie można użyć niektórych zdarzeń lub właściwości. Użyj apex.all.ready=true aby rozpocząć akcje tak wcześnie, jak to możliwe.

Oprogramowanie sprzętowe

Przykład:

Osadź oprogramowanie sprzętowe w urządzeniu APEX dostawcy z typem modułu prebuilt_firmware w następujący sposób.

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
  ..
}

moduły prebuilt_firmware są instalowane w katalogu <apex name>/etc/firmware w APEX. ueventd skanuje katalogi /apex/*/etc/firmware w celu znalezienia modułów oprogramowania sprzętowego.

file_contexts APEX powinien odpowiednio oznaczyć wszelkie wpisy ładunku oprogramowania sprzętowego, aby zapewnić, że pliki te będą dostępne dla ueventd w czasie wykonywania; zazwyczaj wystarczająca jest etykieta vendor_file . Na przykład:

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

Moduły jądra

Osadź moduły jądra w APEX dostawcy jako gotowe moduły w następujący sposób.

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
  ..
}

file_contexts APEX powinien poprawnie oznaczać wszelkie wpisy ładunku modułu jądra. Na przykład:

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

Moduły jądra muszą być zainstalowane jawnie. Poniższy przykładowy skrypt init na partycji dostawcy przedstawia instalację poprzez insmod :

my_init.rc :

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

Nakładki zasobów środowiska wykonawczego

Przykład:

Osadź nakładki zasobów środowiska wykonawczego w APEX dostawcy, używając właściwości rros .

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

Inne pliki konfiguracyjne

Moduły APEX dostawców obsługują różne inne pliki konfiguracyjne, zwykle znajdujące się na partycji dostawcy, jako gotowe pliki w plikach APEX dostawców, a kolejne są dodawane.

Przykłady:

Dodatkowe funkcje rozwojowe

Wybór APEX podczas uruchamiania

Przykład:

Programiści mogą także zainstalować wiele wersji APEX-ów dostawcy, które mają tę samą nazwę i klucz APEX, a następnie wybrać, która wersja ma być aktywowana podczas każdego uruchomienia, korzystając z trwałych sysprops. W niektórych przypadkach użycia przez programistów może to być prostsze niż zainstalowanie nowej kopii APEX za pomocą adb install .

Przykładowe przypadki użycia:

  • Zainstaluj 3 wersje APEX, dostawcy Wi-Fi HAL: zespoły ds. kontroli jakości mogą przeprowadzić ręczne lub automatyczne testy przy użyciu jednej wersji, następnie uruchomić ponownie komputer w innej wersji i ponownie uruchomić testy, a następnie porównać ostateczne wyniki.
  • Zainstaluj 2 wersje kamery HAL, dostawcy APEX, aktualną i eksperymentalną : testerzy mogą korzystać z wersji eksperymentalnej bez pobierania i instalowania dodatkowego pliku, dzięki czemu mogą łatwo wymieniać.

Podczas uruchamiania apexd szuka sysprops w określonym formacie, aby aktywować odpowiednią wersję APEX.

Oczekiwane formaty klucza właściwości to:

  • Konfiguracja rozruchowa
    • Służy do ustawiania wartości domyślnej w BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Trwałe sysprop
    • Służy do zmiany wartości domyślnej, ustawionej na już uruchomionym urządzeniu.
    • Zastępuje wartość bootconfig, jeśli jest obecna.
    • persist.vendor.apex.<apex name>

Wartością właściwości powinna być nazwa pliku APEX, który ma zostać aktywowany.

// 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,
  ..
}

Domyślną wersję należy również skonfigurować za pomocą bootconfig w BoardConfig.mk :

# 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

Po uruchomieniu urządzenia zmień aktywowaną wersję, ustawiając trwały sysprop:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

Jeśli urządzenie obsługuje aktualizację bootconfig po flashowaniu (na przykład za pomocą poleceń fastboot oem ), wówczas zmiana właściwości bootconfig dla wieloinstalowanego APEX zmienia również wersję aktywowaną podczas uruchamiania.

W przypadku wirtualnych urządzeń referencyjnych opartych na mątwie można użyć polecenia --extra_bootconfig_args , aby ustawić właściwość bootconfig bezpośrednio podczas uruchamiania. Na przykład:

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