Usługi i przesyłanie danych

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:

  1. Podklasa klasa/interfejs HIDL hidl_death_recipient (w C++ kodu, a nie HIDL).
  2. Zastąp jej metodę serviceDied().
  3. Utwórz instancję podklasy hidl_death_recipient.
  4. Wywołaj w usłudze metodę linkToDeath(), aby ją monitorować. przez przekazywanie obiektu interfejsu IDeathRecipient. 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 lub MQDescriptorUnsync. 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ć.
    . Żaden z typów nie może być niedomiarowy (odczyt z pustej kolejki kończy się niepowodzeniem) i każdy typ może mieć tylko jednego zapisującego.

Więcej informacji na temat FMQ: Szybka kolejka wiadomości (FMQ).