Każdy interfejs zdefiniowany w pakiecie HIDL ma własną, automatycznie generowaną klasę C++ w przestrzeni nazw pakietu. Klienty i serwery obsługują interfejsy w różne sposoby:
- Serwery implementują interfejsy.
- Metody wywołań klientów w interfejsach.
Interfejsy mogą być rejestrowane przez serwer według nazwy lub przekazywane jako do metod określonych przez HIDL. Na przykład kod platformy może obsługiwać do odbierania komunikatów asynchronicznych z HAL i przekazywania tego interfejsu bezpośrednio do HAL bez jego rejestrowania.
Implementacja serwera
Serwer implementujący interfejs IFoo
musi zawierać element
Automatycznie wygenerowany plik nagłówka IFoo
:
#include <android/hardware/samples/1.0/IFoo.h>
Nagłówek jest automatycznie eksportowany przez zasoby wspólne
IFoo
interfejs, do którego ma być nadany link. Przykładowy element IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
Przykładowy szkielet implementacji interfejsu IFoo na serwerze:
// From the IFoo.h header using android::hardware::samples::V1_0::IFoo; class FooImpl : public IFoo { Return<void> someMethod(foo my_foo, someMethod_cb _cb) { vec<uint32_t> return_data; // Compute return_data _cb(return_data); return Void(); } ... };
Aby udostępnić klientowi implementację interfejsu serwera, mogą:
- Zarejestruj implementację interfejsu w
hwservicemanager
(szczegóły poniżej),
LUB
- Przekaż implementację interfejsu jako argument interfejs (szczegóły znajdziesz w sekcji Asynchroniczna, ).
Przy rejestrowaniu implementacji interfejsu funkcja
Proces hwservicemanager
śledzi zarejestrowane interfejsy HIDL
działające na urządzeniu według nazwy i wersji. Serwery mogą zarejestrować interfejs HIDL
wdrożenie według nazwy, a klienci mogą prosić o implementacje usług po nazwie
i jej wersji. Ten proces służy do obsługi interfejsu HIDL
android.hidl.manager@1.0::IServiceManager
Każdy automatycznie wygenerowany plik nagłówka interfejsu HIDL (np. IFoo.h
)
ma metodę registerAsService()
, której można użyć do zarejestrowania
implementacji interfejsu za pomocą interfejsu hwservicemanager
. Jedyna
wymagany argument to nazwa implementacji interfejsu jako klientów
użyj tej nazwy do pobrania interfejsu z hwservicemanager
później:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
hwservicemanager
traktuje połączenie tych parametrów:
[package@version::interface, instance_name]
jako unikalną wartość, którą można włączyć
za pomocą różnych interfejsów (lub różnych wersji tego samego interfejsu) w celu rejestracji
z identycznymi nazwami instancji bez konfliktów. Jeśli dzwonisz
registerAsService()
z dokładnie taką samą wersją pakietu, interfejsem
i nazwy instancji, hwservicemanager
usuwa odwołanie do funkcji
wcześniej zarejestrowanej usługi i nowej.
Implementacja u klienta
Podobnie jak serwer, klient musi #include
każdy interfejs.
Dotyczy to:
#include <android/hardware/samples/1.0/IFoo.h>
Klient może uzyskać dostęp do interfejsu na dwa sposoby:
- Przez:
I<InterfaceName>::getService
(przez:hwservicemanager
). - Za pomocą interfejsu
Każdy automatycznie wygenerowany plik nagłówka interfejsu zawiera statyczny plik getService
której można użyć do pobrania instancji usługi z
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
Teraz klient ma interfejs IFoo
i może wywoływać metody
tak jakby była to implementacja klas lokalnych. W rzeczywistości wdrożenie
mogą funkcjonować w ramach tego samego procesu, innego procesu, a nawet na innym urządzeniu.
(z działaniem zdalnym HAL). Ponieważ klient zadzwonił do firmy getService
IFoo
obiekt z wersji 1.0
pakietu,
hwservicemanager
zwraca implementację serwera tylko wtedy, gdy to
implementacja jest zgodna z klientami 1.0
. W praktyce
oznacza tylko implementacje serwera z wersją 1.n
(wersja
x.(y+1)
interfejsu musi stanowić rozszerzenie (dziedziczenie z)
x.y
).
Dodatkowo podana jest metoda castFrom
do rzutowania między
przy użyciu różnych interfejsów. Ta metoda polega na wywołaniu IPC do pilota
i upewnij się, że bazowy typ jest taki sam jak typ
poproszono o dostęp. Jeśli żądany typ jest niedostępny, nullptr
jest
.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Asynchroniczne wywołania zwrotne
Wiele istniejących implementacji HAL komunikuje się ze sprzętem asynchronicznym, co oznacza, że potrzebują asynchronicznego sposobu powiadamiania klientów o nowych zdarzeniach, . Interfejs HIDL może być używany jako asynchroniczne wywołanie zwrotne, ponieważ HIDL funkcje interfejsu mogą przyjmować jako parametry obiekty interfejsu HIDL.
Przykładowy plik interfejsu IFooCallback.hal
:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
Przykładowa nowa metoda w IFoo
, która wymaga
Parametr IFooCallback
:
package android.hardware.samples@1.0; interface IFoo { struct Foo { int64_t someValue; handle myHandle; }; someMethod(Foo foo) generates (int32_t ret); anotherMethod() generates (vec<uint32_t>); registerCallback(IFooCallback callback); };
Klient korzystający z interfejsu IFoo
jest
serwer interfejsu IFooCallback
; zapewnia
implementacja IFooCallback
:
class FooCallback : public IFooCallback { Return<void> sendEvent(uint32_t event_id) { // process the event from the HAL } Return<void> sendData(const hidl_vec<uint8_t>& data) { // process data from the HAL } };
Może również po prostu przesłać ją nad istniejącą instancją
Interfejs IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
Serwer implementujący interfejs IFoo
odbiera to jako plik
sp<IFooCallback>
obiekt. Może zapisać wywołanie zwrotne i wywołać
z powrotem do klienta za każdym razem, gdy zechce użyć danego interfejsu.
Adresaci śmierci
Implementacje usług mogą działać w ramach innego procesu, więc może się zdarzyć,
że proces wdrażania interfejsu wygasa, gdy klient przeżyje.
Wszystkie wywołania obiektu interfejsu hostowanego w procesie, które zakończyły się, kończą się niepowodzeniem
z błędem transportu (isOK()
zwraca false
). Jedynym sposobem na
w przypadku takiej awarii polega na zażądaniu nowej instancji usługi przez
Wywołuję: I<InterfaceName>::getService()
. Ta funkcja działa tylko wtedy, gdy
proces, który uległ awarii, uruchomił się ponownie i ponownie zarejestrował usługi przy użyciu
servicemanager
(zwykle dotyczy to implementacji HAL).
Zamiast reagować na to, klienci interfejsu mogą również
zarejestrować odbiorcę śmierci, aby otrzymywać powiadomienia o umowie usługi.
Aby zarejestrować takie powiadomienia w pobranym interfejsie IFoo
,
Klient może wykonać te czynności:
foo->linkToDeath(recipient, 1481 /* cookie */);
Parametr recipient
musi być implementacją funkcji
Interfejs android::hardware::hidl_death_recipient
udostępniany przez HIDL,
który zawiera pojedynczą metodę serviceDied()
o nazwie
z wątku w puli wątków RPC, gdy proces hostujący interfejs się kończy:
class MyDeathRecipient : public android::hardware::hidl_death_recipient { virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) { // Deal with the fact that the service died } }
Parametr cookie
zawiera plik cookie, który został przekazany z
linkToDeath()
, a parametr who
zawiera
słaby wskaźnik do obiektu reprezentującego usługę w kliencie. Za pomocą
przykładowe wywołanie podane powyżej, cookie
równa się 1481 i who
wynosi foo
.
Możesz też wyrejestrować odbiorcę zgonu po jego zarejestrowaniu:
foo->unlinkToDeath(recipient);