Android 8 zmienia architekturę systemu operacyjnego Android, definiując interfejsy między
platformę Androida niezależnie od urządzenia, a także kod związany z określonym urządzeniem i dostawcą.
Android ma już wiele takich interfejsów w postaci interfejsów HAL,
zdefiniowane jako nagłówki C w komponencie hardware/libhardware
. HIDL zastępuje te ustawienia
Interfejsy HAL ze stabilnymi, wersjonowanymi interfejsami, które mogą być zarówno
interfejsów HIDL po stronie serwera w języku C++ (opisane poniżej) lub
Java.
Strony w tej sekcji opisują implementacje interfejsów HIDL w języku C++,
w tym szczegóły o plikach wygenerowanych automatycznie na podstawie HIDL .hal
przez kompilatora hidl-gen
, sposób ich spakowania oraz
jak zintegrować te pliki z kodem C++, który z nich korzysta.
Implementacje klient-serwer
Interfejsy HIDL mają implementacje klienta i serwera:
- Klient interfejsu HIDL to kod, który korzysta z metody za pomocą metod jego wywoływania.
- Serwer to implementacja interfejsu HIDL, odbiera połączenia od klientów i zwraca wyniki (w razie potrzeby).
Podczas przechodzenia z libhardware
HAL na HAL HIDL
staje się serwerem, a proces wywołujący wartość HAL zmienia się w
do klienta. Implementacje domyślne mogą obsługiwać zarówno przekazywanie, jak i powiązania
HAL, które mogą się z czasem zmieniać:
Rysunek 1. Postęp w rozwoju starszych wersji HAL.
Tworzenie klienta HAL
Zacznij od dodania bibliotek HAL do pliku Makefile:
- Marka:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
- Utwór:
shared_libs: [ …, android.hardware.nfc@1.0 ]
Następnie dołącz pliki nagłówka HAL:
#include <android/hardware/nfc/1.0/IFoo.h> … // in code: sp<IFoo> client = IFoo::getService(); client->doThing();
Tworzenie serwera HAL
Aby utworzyć implementację HAL, musisz mieć pliki .hal
reprezentujące Twoją HAL i wygenerowane dla niej przez kod
-Lmakefile
lub -Landroidbp
w aplikacji hidl-gen
(./hardware/interfaces/update-makefiles.sh
robi to w przypadku zasobów wewnętrznych
plików HAL). Podczas przenoszenia kont HAL z
libhardware
, możesz z łatwością wykonać wiele tych czynności, korzystając z c2hal.
Aby utworzyć pliki niezbędne do implementacji HAL:
PACKAGE=android.hardware.nfc@1.0 LOC=hardware/interfaces/nfc/1.0/default/ m -j hidl-gen hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE
Aby HAL działał w trybie przekazywania, musisz mieć
funkcja HIDL_FETCH_IModuleName
korzystająca z funkcji
/(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so
gdzie OPTIONAL_IDENTIFIER to ciąg znaków identyfikujący przekazywanie
implementacji. Wymagania trybu przekazywania są automatycznie spełnione przez
tych poleceń, które również tworzą android.hardware.nfc@1.0-impl
ale można użyć dowolnego rozszerzenia. Przykład:
android.hardware.nfc@1.0-impl-foo
używa -foo
do:
się wyróżniać.
Jeśli HAL jest wersją podrzędną lub rozszerzeniem innej
HAL, do nazwania tego pliku binarnego należy używać podstawowej struktury HAL. Przykład:
Implementacje „android.hardware.graphics.mapper@2.1
” powinny
być w pliku binarnym o nazwie
android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER)
Zwykle wartość OPTIONAL_IDENTIFIER w tym miejscu zawiera rzeczywistą wartość HAL
wersji. Klienty wersji 2.0 mogą pobrać plik binarny w taki sposób,
a klienci 2.1 mogą ją skonfigurować.
Następnie wypełnij wycinki z funkcjami i skonfiguruj demona. Przykład kod demona (obsługujący przekazywanie):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
połączenia
dlopen()
dla podanej biblioteki -impl
i udostępnia ją jako
w powiązanej usłudze. Przykładowy kod demona (na potrzeby czystej usługi powiązanej):
int main(int /* argc */, char* /* argv */ []) { // This function must be called before you join to ensure the proper // number of threads are created. The threadpool never exceeds // size one because of this call. ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); sp<INfc> nfc = new Nfc(); const status_t status = nfc->registerAsService(); if (status != ::android::OK) { return 1; // or handle error } // Adds this thread to the threadpool, resulting in one total // thread in the threadpool. We could also do other things, but // would have to specify 'false' to willJoin in configureRpcThreadpool. ::android::hardware::joinRpcThreadpool(); return 1; // joinRpcThreadpool should never return }
Ten demon zwykle mieszka w regionie $PACKAGE + "-service-suffix"
(dla
np. android.hardware.nfc@1.0-service
), ale może być gdziekolwiek.
Polityka separacyjna konkretnej
klasa HAL to atrybut hal_<module>
(na przykład
hal_nfc)
Ten atrybut należy zastosować do demona, który uruchamia
konkretną HAL (jeśli ten sam proces obsługuje wiele HAL, wiele atrybutów
).