HIDL

Język definicji interfejsu HAL lub HIDL jest językiem opisu interfejsu (IDL). do interfejsu między HAL swoich użytkowników. HIDL umożliwia określenie typów i wywołań metod zbieranych w interfejsów i pakietów. Ogólnie HIDL to system komunikacji między bazami kodu, które mogą być skompilowane niezależnie.

Protokół HIDL jest przeznaczony do komunikacji między procesami (IPC). Listy HAL utworzone przy użyciu HDL tzw. wiązań HAL, ponieważ mogą komunikować się z innymi warstwami architektury za pomocą wiązania wywołaniami w komunikacji międzyprocesowej (IPC). Powiązane poziomy HAL są uruchamiane w procesie innym niż klient który ich używa. Dla: które muszą być połączone z procesem, przekazywaniem jest także dostępny (nieobsługiwany w Javie).

HIDL określa struktury danych i podpisy metod uporządkowane w interfejsach (podobne do klasy) zbierane w pakiety. Składnia języka HIDL wygląda znajomo w językach C++ z innymi programistami w Javie słowa kluczowe. HIDL wykorzystuje również adnotacje w stylu Java.

Terminologia

W tej sekcji używane są następujące terminy związane z HIDL:

powiązane Wskazuje, że HIDL jest używany do zdalnych wywołań procedur między procesami. za pomocą mechanizmu podobnego do Binder. Zobacz też Przekazywanie.
wywołanie zwrotne, asynchroniczne interfejs obsługiwany przez użytkownika HAL przekazywany do HAL (przy użyciu metody HIDL), przez HAL w celu zwrócenia danych w dowolnym momencie.
wywołanie zwrotne, synchroniczne Zwraca do klienta dane z implementacji metody HIDL serwera. Nieużywane w przypadku metod, które zwracają nieważną lub pojedynczą wartość podstawową.
klient Proces, który wywołuje metody określonego interfejsu. platforma HAL lub platforma Androida może być klientem jednego interfejsu, a drugim serwerem. Zobacz też przekazywanie.
rozciąga się Wskazuje interfejs, który dodaje metody i/lub typy do innego interfejsu. Interfejs może stanowić rozszerzenie tylko jednego innego interfejsu. Przeznaczone dla osób nieletnich zwiększenie wersji w przypadku tej samej nazwy pakietu lub nowego pakietu (np. dostawcy ), aby bazować na starszym pakiecie.
generuje Wskazuje metodę interfejsu, która zwraca wartości klientowi. Aby zwrócić jedną lub więcej niż jedną wartość, synchroniczną funkcję wywołania zwrotnego .
interfejs Zbiór metod i typów. Przetłumaczone na zajęcia w C++ lub Java. Wszystkie metody w interfejsie są wywoływane w tym samym kierunku: proces klienta wywołuje metody zaimplementowane przez proces serwera.
w jedną stronę Po zastosowaniu do metody HIDL wskazuje, że metoda nie zwraca żadnych wartości i nie zostanie zablokowana.
paczka Zbiór interfejsów i typów danych współużytkujących daną wersję.
przekazywanie Tryb HIDL, w którym serwer jest biblioteką współdzieloną, dlopen przez klienta. W trybie przekazywania klient i serwer to ten sam proces, ale w osobnych bazach kodu. Służy tylko do przeniesienia starszych baz kodu do modelu HIDL. Zapoznaj się też z sekcją Powiązane.
serwer Proces implementujący metody interfejsu. Zobacz też przekazywanie.
transport infrastruktura HIDL, która służy do przenoszenia danych między serwerem a klientem.
Wersja Wersja pakietu. Składa się z 2 liczb całkowitych (dużej i małej). Nieletni przyrosty wersji mogą dodawać (ale nie zmieniać) typy i metody.

Projekt HIDL

Celem standardu HIDL jest zastąpienie platformy Androida bez konieczności odbudowywanie HAL. Listy HAL są tworzone przez dostawców lub twórców SOC i umieszczane partycja /vendor na urządzeniu, co samo w sobie daje dostęp do platformy Androida. partycji i zastąpić ją OTA bez konieczności ponownej kompilacji list HAL.

Projekt HIDL obejmuje następujące problemy:

  • Współdziałanie. Tworzenie niezawodnych, współdziałających interfejsów procesów, które można skompilować z użyciem różnych architektur, łańcuchów narzędzi i konfiguracje kompilacji. Interfejsy HIDL mają różne wersje i nie można ich zmieniać po ich opublikowaniu.
  • Skuteczność. HIDL próbuje zminimalizować liczbę kopii operacji. Dane zdefiniowane przez HIDL są przesyłane do kodu C++ w standardowym układzie C++ struktury danych, których można używać bez rozpakowywania. HIDL udostępnia również a ponieważ interfejsy RPC są z natury nieco wolne, HIDL obsługuje dwa sposoby przenoszenia danych bez użycia wywołania RPC: pamięć współdzielona oraz funkcja Fast Kolejka wiadomości (FMQ).
  • Intuicyjny. HIDL pozwala uniknąć poważnych problemów z własnością pamięci, używając tylko parametrów in na potrzeby RPC (patrz Android język definiowania interfejsu (AIDL)); wartości, których nie można wydajnie zwracane przez metody są zwracane przez funkcje wywołania zwrotnego. Brak przekazywania danych na HIDL w celu przeniesienia lub otrzymywanie danych od HIDL zmienia własność dane—własność zawsze pozostaje w funkcji wywołującego. Dane muszą: pozostają aktywne tylko przez czas trwania wywołanej funkcji i mogą zostać zniszczone; bezpośrednio po zwróceniu wywołanej funkcji.

Używanie trybu przekazywania

Aby zaktualizować urządzenia z wcześniejszą wersją Androida do Androida O, możesz: opakować zarówno konwencjonalne (jak i starsze) listy HAL, w nowy interfejs HIDL, który obsługuje HAL w trybach powiązania i tego samego procesu (przekazywania). To opakowanie jest są przejrzyste zarówno dla HAL, jak i platformy Androida.

Tryb przekazywania jest dostępny tylko w przypadku klientów i implementacji C++. Urządzenia z wcześniejszymi wersjami Androida nie mają interfejsów HAL napisanych w języku Java, Interfejsy HAL Java są z natury powiązane.

Po skompilowaniu pliku .hal hidl-gen generuje dodatkowy przekazujący plik nagłówka BsFoo.h oprócz nagłówków używane do komunikacji z powiązanymi podmiotami; ten nagłówek definiuje funkcje dlopened. Przekazujące HAL działają w tym samym procesie, w którym W większości przypadków metody przekazywania są wywoływane przez metody bezpośrednie wywołanie funkcji (ten sam wątek). oneway metoda działa w osobnym wątku ponieważ nie muszą czekać, aż HAL je przetworzy (oznacza to, że wszystkie HAL który korzysta z metod oneway w trybie przekazywania, musi być bezpiecznym wątkiem.

Biorąc pod uwagę wartość IFoo.hal, BsFoo.h opakowuje wygenerowane przez HIDL metod udostępniania dodatkowych funkcji (takich jak tworzenie oneway transakcji wykonanych w innym wątku). Ten plik jest podobny do pliku BpFoo.h, jednak zamiast przekazywania wywołań IPC za pomocą bindera funkcja wymagane funkcje są wywoływane bezpośrednio. Kolejne implementacje HAL mogą zapewniać wiele implementacji, takich jak FooFast HAL, Precyzyjne HAL. W takich przypadkach plik z każdą dodatkową implementacją byłby (np. PTFooFast.cpp i PTFooAccurate.cpp).

Powiązanie przekazujących HAL

Możesz powiązać implementacje HAL, które obsługują tryb przekazywania. Jeśli Interfejs HAL a.b.c.d@M.N::IFoo, tworzone są 2 pakiety:

  • a.b.c.d@M.N::IFoo-impl Zawiera implementację HAL i ujawnia funkcję IFoo* HIDL_FETCH_IFoo(const char* name). Wł. starszych urządzeń, ten pakiet jest dlopenedytowany, a implementacja jest utworzono za pomocą HIDL_FETCH_IFoo. Możesz wygenerować kod podstawowy za pomocą: hidl-gen, -Lc++-impl i -Landroidbp-impl
  • a.b.c.d@M.N::IFoo-service Otwiera przekazywanie HAL i rejestruje się jako usługę powiązaną, umożliwiając tę samą implementację HAL do wykorzystania zarówno jako przekazu, jak i powiązania.

Typ IFoo umożliwia wywołanie metody sp<IFoo> IFoo::getService(string name, bool getStub), aby uzyskać dostęp do instancji z IFoo. Jeśli getStub ma wartość prawda, getService próbuje otworzyć zawartość HAL tylko w trybie przekazywania. Jeśli getStub to false, getService próbuje znaleźć usługę powiązaną; jeśli a następnie próbuje znaleźć usługę przekazywania. getStub z wyjątkiem defaultPassthroughServiceImplementation (Urządzenia uruchamiane z Android O to urządzenia w pełni powiązane, więc otwarcie usługi w trybie przekazywania jest niedozwolone).

Gramatyka HIDL

Z założenia język HIDL jest podobny do języka C (ale nie używa (preprocesor). wszelkie znaki interpunkcyjne nieopisane poniżej (z wyjątkiem oczywistego zastosowania) = i |) jest częścią gramatyki.

Uwaga: szczegółowe informacje o stylu kodu HIDL znajdziesz w Przewodnik po stylach kodu.

  • /** */ oznacza komentarz do dokumentacji. Można je stosować tylko na deklaracje typu, metody, pól i wartości wyliczeniowych.
  • /* */ oznacza komentarz wielowierszowy.
  • // oznacza komentarz na końcu wiersza. Oprócz //, znaki nowego wiersza są takie same jak wszystkie inne odstępy.
  • W przykładowej gramatyce poniżej tekst od // do końca wiersz nie jest częścią gramatyki, ale jest komentarzem na jej temat.
  • [empty] oznacza, że hasło może być puste.
  • ? po literału lub pojęciu oznacza, że element jest opcjonalny.
  • ... oznacza sekwencję zawierającą 0 lub więcej elementów z argumentem rozdzielając znaki interpunkcyjne zgodnie ze wskazówkami. W HIDL nie ma żadnych argumentów zmiennych.
  • Elementy sekwencji są rozdzielane przecinkami.
  • Średniki kończą każdy element, w tym ostatni.
  • WIELKIE LITERY to nieterminal.
  • italics to rodzina tokenów, taka jak integer lub identifier (standardowy C reguły analizy składniowej).
  • constexpr to wyrażenie stałe stylu C (np. 1 + 1 i 1L << 3).
  • import_name to kwalifikowana nazwa pakietu lub interfejsu zgodnie z opisem w HIDL Obsługa wersji.
  • Małe litery words to tokeny dosłowne.

Przykład:

ROOT =
    PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... }  // not for types.hal
  | PACKAGE IMPORTS ITEM ITEM...  // only for types.hal; no method definitions

ITEM =
    ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
  |  safe_union identifier { UFIELD; UFIELD; ...};
  |  struct identifier { SFIELD; SFIELD; ...};  // Note - no forward declarations
  |  union identifier { UFIELD; UFIELD; ...};
  |  enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar
  |  typedef TYPE identifier;

VERSION = integer.integer;

PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;

PREAMBLE = interface identifier EXTENDS

EXTENDS = <empty> | extends import_name  // must be interface, not package

GENERATES = generates (FIELD, FIELD ...)

// allows the Binder interface to be used as a type
// (similar to typedef'ing the final identifier)
IMPORTS =
   [empty]
  |  IMPORTS import import_name;

TYPE =
  uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t |
 float | double | bool | string
|  identifier  // must be defined as a typedef, struct, union, enum or import
               // including those defined later in the file
|  memory
|  pointer
|  vec<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]

FIELD =
   TYPE identifier

UFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...};
  |  struct identifier { FIELD; FIELD; ...};
  |  union identifier { FIELD; FIELD; ...};
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SIZE =  // Must be greater than zero
     constexpr

ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION

ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)

ANNO_ENTRY =
     identifier=VALUE

VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations

ENUM_ENTRY =
     identifier
  |  identifier = constexpr