HIDL

Język definicji interfejsu HAL lub HIDL (wymawiane "ukryj-l") to język opisu interfejsu (IDL) określający interfejs między warstwą HAL a jej użytkownikami. Pozwala na określenie typów i wywołań metod, zebranych w interfejsy i pakiety. Mówiąc szerzej, HIDL to system do komunikacji między bazami kodu, które mogą być kompilowane niezależnie. Począwszy od Androida 10, HIDL jest przestarzały, a Android jest migrowany, aby używać AIDL wszędzie.

HIDL jest przeznaczony do użytku w komunikacji między procesami (IPC). Komunikacja pomiędzy procesami jest określany jako Binderized . Dla bibliotek, które muszą być łączony z procesie, tryb passthrough jest również dostępny (nie jest obsługiwana w Javie).

HIDL określa struktury danych i sygnatury metod, zorganizowane w interfejsy (podobnie jak klasa), które są gromadzone w pakiety. Składnia HIDL będzie wyglądać znajomo programistom C++ i Java, choć z innym zestawem słów kluczowych. HIDL używa również adnotacji w stylu Java.

Projekt HIDL

Celem HIDL jest umożliwienie zastąpienia struktury bez konieczności przebudowywania warstw HAL. HAL zostanie zbudowany przez dostawców lub producentów SOC i umieścić w /vendor partycji na urządzeniu, dzięki czemu ramy, w osobnej partycji, które mają być zastąpione przez OTA bez rekompilacji HALS.

Projekt HIDL równoważy następujące problemy:

  • Interoperacyjność. Twórz niezawodnie interoperacyjne interfejsy między procesami, które można kompilować z różnymi architekturami, łańcuchami narzędzi i konfiguracjami kompilacji. Interfejsy HIDL są wersjonowane i nie można ich zmienić po opublikowaniu.
  • Efektywność. HIDL próbuje zminimalizować liczbę operacji kopiowania. Dane zdefiniowane w HIDL są dostarczane do kodu C++ w standardowych strukturach danych układu C++, których można używać bez rozpakowywania. HIDL zapewnia również interfejsy pamięci współdzielonej, a ponieważ RPC są z natury nieco powolne, HIDL obsługuje dwa sposoby przesyłania danych bez użycia wywołania RPC: pamięć współdzielona i szybka kolejka wiadomości (FMQ).
  • Intuicyjne. HIDL unika drażliwy kwestie własności pamięci przy użyciu tylko in parametrach dla RPC (patrz Interfejs Android Definition Language (AIDL) ); wartości, których nie można skutecznie zwrócić z metod, są zwracane za pośrednictwem funkcji wywołania zwrotnego. Ani przekazywanie danych do HIDL w celu przesłania, ani odbierania danych z HIDL nie zmienia własności danych — własność zawsze pozostaje w funkcji wywołującej. Dane muszą być utrwalane tylko przez czas trwania wywołanej funkcji i mogą zostać zniszczone natychmiast po powrocie wywołanej funkcji.

Korzystanie z trybu przekazywania

Aby zaktualizować urządzenia z wcześniejszymi wersjami systemu Android do systemu Android O, można opakować zarówno konwencjonalne (i starsze) warstwy HAL w nowy interfejs HIDL, który obsługuje warstwy HAL w trybie powiązania i tego samego procesu (przekazującego). To zawijanie jest przezroczyste zarówno dla warstwy HAL, jak i platformy Android.

Tryb przekazywania jest dostępny tylko dla klientów i implementacji języka C++. Urządzenia z wcześniejszymi wersjami systemu Android nie mają warstw HAL napisanych w języku Java, więc warstwy HAL języka Java są z natury zbindowane.

Kiedy .hal plik jest skompilowany, hidl-gen produkuje dodatkowego połączenia Przez pliku nagłówka BsFoo.h oprócz nagłówków wykorzystywanych do komunikacji spoiwa; Określa funkcje header być dlopen ed. Ponieważ przekazujące warstwy HAL działają w tym samym procesie, w którym są wywoływane, w większości przypadków metody przekazujące są wywoływane przez bezpośrednie wywołanie funkcji (ten sam wątek). oneway metody prowadzony we własnym wątku, ponieważ nie mają czekać na HAL je przetwarzać (oznacza to, że używa żadnych HAL oneway metod w tryb przekazywania musi być bezpieczny wątku).

Biorąc pod uwagę IFoo.hal , BsFoo.h owija metody HIDL generowane w celu zapewnienia dodatkowych funkcji (takich jak uczynienie oneway transakcje prowadzone w innym wątku). Plik ten jest podobny do BpFoo.h jednak zamiast przekazywania połączeń IPC z wykorzystaniem spoiwa, pożądane funkcje są bezpośrednio powoływać. Przyszłe implementacje HAL może dostarczyć wielu implementacji, jak FooFast HAL i FooAccurate Hal. W takich przypadkach plik dla każdego dodatkowego realizacji byłyby tworzone (np PTFooFast.cpp i PTFooAccurate.cpp ).

Wiążące przepuszczające warstwy HAL

Możesz powiązać implementacje warstwy HAL, które obsługują tryb tranzytowy. Biorąc pod uwagę HAL interfejsu abcd@MN::IFoo dwa pakiety zostały utworzone:

  • abcd@MN::IFoo-impl . Zawiera realizację HAL i naraża funkcjonować IFoo* HIDL_FETCH_IFoo(const char* name) . Na urządzeniach starszego typu, ten pakiet jest dlopen ed i realizacja jest tworzony przy użyciu HIDL_FETCH_IFoo . Można wygenerować kod bazowy przy użyciu hidl-gen i -Lc++-impl i -Landroidbp-impl .
  • abcd@MN::IFoo-service . Otwiera przekazującą warstwę HAL i rejestruje się jako usługa zbindowana, umożliwiając używanie tej samej implementacji warstwy HAL zarówno jako przekazującej, jak i zbinderyzowanej.

Biorąc pod uwagę rodzaj IFoo można wywołać sp<IFoo> IFoo::getService(string name, bool getStub) , aby uzyskać dostęp do instancji IFoo . Jeśli getStub jest prawdą, getService próby otwarcia HAL tylko w tryb przekazywania. Jeśli getStub jest fałszywa, getService próby znalezienia binderized usługi; jeśli to się nie powiedzie, próbuje znaleźć usługę przekazywania. getStub parametr nie powinien być stosowany z wyjątkiem defaultPassthroughServiceImplementation . (Urządzenia uruchamiane z Androidem O są urządzeniami w pełni powiązanymi, więc otwieranie usługi w trybie przekazującym jest niedozwolone).

Gramatyka HIDL

Z założenia język HIDL jest podobny do C (ale nie używa preprocesora C). Wszystkie znaki interpunkcyjne nie opisano poniżej (oprócz oczywistego wykorzystania = i | ) jest częścią gramatyki.

Uwaga: Aby uzyskać szczegółowe informacje na kodzie HIDL stylu, zobacz kodu styl Guide .

  • /** */ wskazuje komentarz dokumentacji. Można je zastosować tylko do deklaracji typu, metody, pola i wartości wyliczenia.
  • /* */ Wskazuje wielowierszowego komentarza.
  • // wskazuje komentarz do końca linii. Oprócz // , znaki nowej linii są takie same jak każdy inny spacji.
  • Na przykład gramatyki poniżej tekst z // na końcu linii nie jest częścią gramatyki, lecz zamiast komentarz na gramatyce.
  • [empty] oznacza, że może ono być puste.
  • ? następujące po literze lub terminie oznacza, że ​​jest to opcjonalne.
  • ... wskazuje ciąg zawierający zero lub więcej elementów z oddzielania znaków interpunkcyjnych jak wskazano. W HIDL nie ma argumentów variadic.
  • Przecinki oddzielają elementy sekwencji.
  • Średniki kończą każdy element, łącznie z ostatnim elementem.
  • WIELKIE LITERY to nieterminal.
  • italics jest wyrazem rodzin, takich jak integer lub identifier (zasady Standard C analizowania).
  • constexpr jest stałą wyrażenie C (na przykład na 1 + 1 i 1L << 3 ).
  • import_name to nazwa pakietu lub interfejs, kwalifikacje, jak opisano w HIDL Versioning .
  • Małe words są dosłowne tokeny.

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

Terminologia

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

spoiwo Wskazuje, że HIDL jest używany do zdalnych wywołań procedur między procesami, zaimplementowanych przez mechanizm podobny do Bindera. Zobacz także passthrough.
wywołanie zwrotne, asynchroniczne Interfejs obsługiwany przez użytkownika warstwy HAL, przekazywany do warstwy HAL (za pomocą metody HIDL) i wywoływany przez warstwę HAL w celu zwrócenia danych w dowolnym momencie.
wywołanie zwrotne, synchroniczne Zwraca dane z implementacji metody HIDL serwera do klienta. Nieużywany w przypadku metod, które zwracają void lub pojedynczą wartość pierwotną.
klient Proces, który wywołuje metody określonego interfejsu. Proces HAL lub framework może być klientem jednego interfejsu i serwerem innego. Zobacz także passthrough.
rozciąga się Wskazuje interfejs, który dodaje metody i/lub typy do innego interfejsu. Interfejs może rozszerzać tylko jeden inny interfejs. Może być użyty do zwiększenia mniejszej wersji w tej samej nazwie pakietu lub do zbudowania nowego pakietu (np. rozszerzenia dostawcy) na starszym pakiecie.
generuje Wskazuje metodę interfejsu, która zwraca wartości do klienta. Aby zwrócić jedną wartość niepierwotną lub więcej niż jedną, generowana jest synchroniczna funkcja wywołania zwrotnego.
berło Zbiór metod i typów. Przetłumaczone na klasę w C++ lub Javie. Wszystkie metody w interfejsie są wywoływane w tym samym kierunku: proces klienta wywołuje metody implementowane przez proces serwera.
jednokierunkowa W przypadku zastosowania do metody HIDL wskazuje, że metoda nie zwraca żadnych wartości i nie blokuje.
pakiet Zbiór interfejsów i typów danych udostępniających wersję.
Przejść przez Tryb HIDL w którym serwer jest wspólna biblioteka, dlopen ed przez klienta. W trybie tranzytowym klient i serwer to ten sam proces, ale oddzielne bazy kodu. Używany tylko do przeniesienia starszych baz kodu do modelu HIDL. Zobacz także Binderized.
serwer Proces implementujący metody interfejsu. Zobacz także passthrough.
transport Infrastruktura HIDL, która przenosi dane między serwerem a klientem.
wersja Wersja pakietu. Składa się z dwóch liczb całkowitych, major i minor. Przyrosty wersji drugorzędnych mogą dodawać (ale nie zmieniać) typy i metody.