Na tej stronie dowiesz się, jak zarejestrować i wykryć usługi oraz jak je wysyłać
do usługi za pomocą metod wywołań zdefiniowanych w interfejsach w interfejsie .hal
.
.
Zarejestruj usługi
Rejestrować serwery interfejsu HIDL (obiekty implementujące interfejs) jako usługi nazwane. Zarejestrowana nazwa nie musi być związana z interfejsem ani nazwę pakietu. Jeśli nie podasz nazwy, zostanie użyta nazwa „default” jest używany; to powinno w przypadku HAL, które nie wymagają rejestrowania dwóch implementacji tej samej za pomocą prostego interfejsu online. Na przykład wywołanie rejestracji usługi w języku C++ zdefiniowane w każdym z nich interfejs jest:
status_t status = myFoo->registerAsService(); status_t anotherStatus = anotherFoo->registerAsService("another_foo_service"); // if needed
Wersja interfejsu HIDL jest dołączona do samego interfejsu. Jest
automatycznie powiązane z rejestracją usługi i można je pobrać za pomocą
wywołanie metody (android::hardware::IInterface::getInterfaceVersion()
)
w każdym interfejsie HIDL. Obiekty serwera nie muszą być rejestrowane i można je przekazywać
za pomocą parametrów metody HIDL do innego procesu, który wywołuje metodę HIDL
do serwera.
Odkryj usługi
Żądania wysyłane przez kod klienta są przesyłane dla danego interfejsu według nazwy i
z wywołaniem getService
z odpowiednią klasą HAL:
// C++ sp<V1_1::IFooService> service = V1_1::IFooService::getService(); sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service"); // Java V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */); V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);
Każda wersja interfejsu HIDL jest traktowana jako oddzielny interfejs. W związku z tym:
IFooService
w wersji 1.1 i IFooService
w wersji 2.2
mogą być zarejestrowane jako „foo_service” oraz
getService("foo_service")
w dowolnym interfejsie powoduje zarejestrowanie wartości
dla danego interfejsu. Dlatego w większości przypadków nie trzeba podawać parametru
przeznaczone do rejestracji lub wykrywania (nazwa „default”).
Obiekt interfejsu dostawcy odgrywa też rolę w metodzie przesyłania
interfejsu. Dla interfejsu IFoo
w pakiecie
android.hardware.foo@1.0
, interfejs zwrócony przez
IFoo::getService
zawsze używa metody transportu zadeklarowanej dla
android.hardware.foo
w manifeście urządzenia, jeśli taka pozycja istnieje;
a jeśli metoda transportu nie jest dostępna, zwracana jest wartość nullptr.
W niektórych przypadkach konieczne może być natychmiastowe kontynuowanie pracy, nawet jeśli
korzystanie z usługi. Może się tak zdarzyć np. wtedy, gdy klient chce
zarządzać powiadomieniami o usłudze lub programami diagnostycznymi (np.
atrace
), który musi pobrać wszystkie hwservices i je pobrać. W
w tym przypadku udostępnione są dodatkowe interfejsy API, takie jak tryGetService
w C++, lub
getService("instance-name", false)
w Javie. Starsza wersja interfejsu API
Pole getService
podane w Javie musi być też używane z usługą
powiadomienia. Użycie tego interfejsu API nie eliminuje sytuacji wyścigu, w której serwer
rejestruje się po otrzymaniu żądania od klienta za pomocą jednego z tych interfejsów API bez konieczności ponownego wykonywania czynności.
Powiadomienia o wyłączeniu usługi
Klienci, którzy chcą otrzymywać powiadomienia o zamknięciu usługi, mogą otrzymać śmierć powiadomień dostarczanych przez platformę. Aby otrzymywać powiadomienia, musi:
- Podklasa klasa/interfejs HIDL
hidl_death_recipient
(w C++ kodu, a nie HIDL). - Zastąp jej metodę
serviceDied()
. - Utwórz instancję podklasy
hidl_death_recipient
. - Wywołaj w usłudze metodę
linkToDeath()
, aby ją monitorować. przez przekazywanie obiektu interfejsuIDeathRecipient
. Pamiętaj, że to nie przejmuje własności osoby zmarłej ani pośrednika, na którego .
Przykład pseudokodu (C++ i Java są podobne):
class IMyDeathReceiver : hidl_death_recipient { virtual void serviceDied(uint64_t cookie, wp<IBase>& service) override { log("RIP service %d!", cookie); // Cookie should be 42 } }; .... IMyDeathReceiver deathReceiver = new IMyDeathReceiver(); m_importantService->linkToDeath(deathReceiver, 42);
Ten sam obdarowany zgon może być zarejestrowany w wielu różnych usługach.
Przenoszenie danych
Dane mogą być wysyłane do usługi przez wywołania metod zdefiniowanych w interfejsach w
.hal
. Dostępne są 2 rodzaje metod:
- Metody blokowania czekają, aż serwer wygeneruje błąd wynik.
- Metody jednokierunkowe wysyłają dane tylko w jednym kierunku i nie blokować. Jeśli ilość przesyłanych danych w wywołaniach RPC przekracza implementację połączenia mogą zablokować lub zwrócić komunikat o błędzie (działanie jeszcze nie określono).
Metoda, która nie zwraca wartości, ale nie jest zadeklarowana jako
Użytkownik oneway
nadal blokuje dostęp.
Wszystkie metody zadeklarowane w interfejsie HIDL są wywoływane w jednym kierunku, z interfejsu HAL lub HAL. Interfejs nie określa, które w kierunku jej wywołania. Architektury, z których pochodzą wywołania HAL powinien zawierać co najmniej dwa interfejsy w pakiecie HAL i obsługiwać odpowiedni interfejs do każdego procesu. Wyrazy client i server są używane zgodnie z kierunkiem wywołania interfejsu. (HAL może być serwerem jednego interfejsu, a klientem innego – ).
Wywołania zwrotne
Słowo wywołanie zwrotne odnosi się do 2 różnych koncepcji, różniących się: synchroniczne wywołanie zwrotne i asynchroniczne wywołanie zwrotne.
Synchroniczne wywołania zwrotne są używane w niektórych metodach HIDL, które zwracają i skalowalnych danych. Metoda HIDL, która zwraca więcej niż jedną wartość (lub zwraca jedną wartość nietypu podstawowego) zwraca wyniki za pomocą funkcji wywołania zwrotnego. Jeśli tylko jeden jest zwracana i jest to typ podstawowy, wywołanie zwrotne nie jest używane, a . Serwer wdraża metody HIDL i klient implementuje wywołania zwrotne.
Asynchroniczne wywołania zwrotne umożliwiają serwerowi interfejsu HIDL
nawiązywanie połączeń telefonicznych. Jest to możliwe dzięki przekazaniu wystąpienia drugiego interfejsu
za pomocą pierwszego interfejsu. Klient pierwszego interfejsu musi pełnić funkcję
serwera drugiego. Serwer pierwszego interfejsu może wywoływać metody na
drugiego obiektu interfejsu. Na przykład implementacja HAL może wysyłać informacje
asynchronicznie do procesu, który go używa, wywołując metody na
który zostaje utworzony i obsługiwany przez ten proces. Metody używane w interfejsach
dla asynchronicznego wywołania zwrotnego może być blokowane (i może zwracać wartości do elementu wywołującego)
lub oneway
. Przykład znajdziesz w sekcji „Asynchroniczne wywołania zwrotne” cale
HIDL w C++.
Aby uprościć własność pamięci, wywołania metod i wywołania zwrotne uwzględniają tylko
Parametr in
, który nie obsługuje out
ani
inout
parametry.
Limity na jedną transakcję
Limity na transakcję nie są narzucane na ilość danych wysyłanych przez HIDL
metod i wywołań zwrotnych. Jednak wywołania przekraczające 4 KB na transakcję są
uznanych za nadmierne. W takim przypadku należy zmienić architekturę danego interfejsu HIDL.
. Kolejnym ograniczeniem są zasoby dostępne dla HIDL
do obsługi wielu transakcji jednocześnie. Wiele
transakcje mogą być przetwarzane jednocześnie z powodu wielu wątków lub
przetwarza wysyłanie połączeń do procesu lub wielu wywołań oneway
, które
nie są szybko obsługiwane przez proces odbierania. Maksymalna całkowita ilość miejsca
ten rozmiar jest domyślnie dostępny w przypadku wszystkich jednoczesnych transakcji.
W dobrze zaprojektowanym interfejsie przekroczenie tych ograniczeń zasobów nie powinno wystąpieniu; Jeśli tak, połączenie, które je przekroczyło, może zostać zablokowane do stają się dostępne lub sygnalizują błąd transportu. Każde wystąpienie przekroczenie limitów na transakcję lub przepełnienie zasobów wdrożenia HIDL przez zagregowane transakcje w trakcie lotów są logowane w celu ułatwienia debugowania.
Implementacje metod
HIDL generuje pliki nagłówka z deklaracją niezbędnych typów, metod wywołania zwrotne w języku docelowym (C++ lub Java). Prototyp modelu zdefiniowanego przez HIDL są takie same zarówno dla kodu klienta, jak i serwera. HIDL udostępnia implementacje proxy w sekcji po stronie rozmówcy, które porządkują dane transportu IPC, oraz stub po stronie wywołującego kod, który przekazuje dane do implementacji programistycznych metod weryfikacji danych.
Wywołujący funkcję (metoda HIDL lub wywołanie zwrotne) ma własność danych struktury przekazywane do funkcji i zachowują własność po wywołaniu; cale we wszystkich przypadkach rozmówca nie musi zwolnić ani zwolnić miejsca na dane.
- W języku C++ dane mogą być tylko do odczytu (próba zapisu w nim może spowodować błąd podziału na segmenty) i są ważne przez cały czas trwania połączenia. Klient może przeprowadzić głęboką kopię danych, aby rozpowszechnić je poza wywołaniem.
- W Javie kod otrzymuje lokalną kopię danych (zwykły obiekt Java), które może przechowywać i modyfikować lub umożliwiać usuwanie do kosza.
Przenoszenie danych bez RPC
HIDL może przekazywać dane bez użycia wywołania RPC na 2 sposoby: udostępnione i szybkiej kolejki wiadomości (FMQ), obsługiwane tylko w języku C++.
- Udostępnione wspomnienie. Wbudowany typ HIDL
memory
jest używany do przekazywania obiektu reprezentującego przydzieloną pamięć współdzieloną. Może być używana w procesie odbierania do mapowania pamięci współdzielonej. - Szybka kolejka wiadomości (FMQ). HIDL dostarcza szablonowy komunikat
typu kolejki, który obsługuje przekazywanie wiadomości bez oczekiwania. Nie używa jądra systemu
lub algorytmu szeregowania w trybie przekazywania lub powiązania (komunikacja między urządzeniami
mają te właściwości). Zwykle HAL ustawia koniec kolejki,
tworząc obiekt, który może być przekazywany przez RPC za pomocą parametru wbudowanego
Typ HIDL
MQDescriptorSync
lubMQDescriptorUnsync
. Ten proces odbierający może użyć do skonfigurowania drugiego końca kolejki.- Kolejki synchronizacji nie mogą się przepełniać i mogą mieć tylko jedną .
- Kolejki niezsynchronizowane mogą się przepełnić i mogą mieć wielu czytelników. każdy z nich musi odczytać dane w odpowiednim czasie lub je utracić.
Więcej informacji na temat FMQ: Szybka kolejka wiadomości (FMQ).