Interfejsy & Pakiety

Język HIDL opiera się na interfejsach, typie abstrakcyjnym używanym w językach obiektowych do definiowania zachowań. Każdy interfejs jest częścią pakietu.

Pakiety

Nazwy pakietów mogą mieć podpoziomy, takie jak package.subpackage . Katalog główny opublikowanych pakietów HIDL to hardware/interfaces lub vendor/vendorName (np. vendor/google dla urządzeń Pixel). Nazwa pakietu tworzy jeden lub więcej podkatalogów w katalogu głównym; wszystkie pliki definiujące pakiet znajdują się w tym samym katalogu. Na przykład package android.hardware.example.extension.light@2.0 można znaleźć w hardware/interfaces/example/extension/light/2.0 .

Poniższa tabela zawiera prefiksy i lokalizacje pakietów:

Prefiks pakietu Lokalizacja Typy interfejsów
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* frameworki/powiązane
android.system.* system/hardware/interfaces/* system/powiązane
android.hidl.* system/libhidl/transport/* rdzeń

Katalog pakietu zawiera pliki z rozszerzeniem .hal . Każdy plik musi zawierać instrukcję package zawierającą nazwę pakietu i wersję, której częścią jest plik. Plik types.hal , jeśli istnieje, nie definiuje interfejsu, ale zamiast tego definiuje typy danych dostępne dla każdego interfejsu w pakiecie.

Definicja interfejsu

Poza types.hal , co drugi plik .hal definiuje interfejs. Interfejs jest zwykle definiowany w następujący sposób:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

Interfejs bez jawnej deklaracji extends domyślnie rozciąga się od android.hidl.base@1.0::IBase (podobnie jak java.lang.Object w Javie). Interfejs IBase, niejawnie zaimportowany, deklaruje kilka zarezerwowanych metod, których nie należy i nie można ponownie deklarować w interfejsach zdefiniowanych przez użytkownika lub używanych w inny sposób. Metody te obejmują:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

Importowanie

Instrukcja import to mechanizm HIDL umożliwiający dostęp do interfejsów i typów pakietów w innym pakiecie. Oświadczenie import dotyczy dwóch podmiotów:

  • Jednostka importująca , która może być pakietem lub interfejsem; I
  • Importowana jednostka, która również może być pakietem lub interfejsem.

Podmiot importujący jest określany na podstawie lokalizacji wyciągu import . Gdy instrukcja znajduje się w types.hal pakietu, to, co jest importowane, jest widoczne w całym pakiecie; jest to import na poziomie pakietu . Gdy instrukcja znajduje się w pliku interfejsu, jednostką importującą jest sam interfejs; jest to import na poziomie interfejsu .

Importowana jednostka jest określana na podstawie wartości znajdującej się po słowie kluczowym import . Wartość nie musi być w pełni kwalifikowaną nazwą; jeżeli jakiś komponent zostanie pominięty, zostanie on automatycznie uzupełniony informacjami z aktualnego pakietu. W przypadku wartości w pełni kwalifikowanych obsługiwane są następujące przypadki importu:

  • Import całych paczek . Jeżeli wartością jest nazwa pakietu i jego wersja (składnia opisana poniżej), to do podmiotu importującego importowany jest cały pakiet.
  • Częściowy import . Jeśli wartość wynosi:
    • Interfejs, types.hal pakietu i ten interfejs są importowane do jednostki importującej.
    • UDT zdefiniowany w types.hal , wtedy tylko ten UDT jest importowany do jednostki importującej (inne typy w types.hal nie są importowane).
  • Import tylko typów . Jeśli wartość wykorzystuje składnię częściowego importu opisaną powyżej, ale ze słowami kluczowymi types zamiast nazwy interfejsu, importowane są tylko UDT w types.hal wyznaczonego pakietu.

Podmiot importujący uzyskuje dostęp do kombinacji:

  • Typowe UDT zaimportowanego pakietu zdefiniowane w types.hal ;
  • Interfejsy zaimportowanego pakietu (w przypadku importu całego pakietu) lub określony interfejs (w przypadku importu częściowego) w celu ich wywoływania, przekazywania do nich uchwytów i/lub dziedziczenia z nich.

Instrukcja import używa składni w pełni kwalifikowanej nazwy typu w celu podania nazwy i wersji importowanego pakietu lub interfejsu:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

Dziedziczenie interfejsu

Interfejs może być rozszerzeniem wcześniej zdefiniowanego interfejsu. Rozszerzenia mogą należeć do jednego z trzech następujących typów:

  • Interfejs może dodawać funkcjonalność do innego, włączając jego API w niezmienionej formie.
  • Pakiet może dodawać funkcjonalność do innego, włączając jego API w niezmienionej formie.
  • Interfejs może importować typy z pakietu lub z określonego interfejsu.

Interfejs może rozszerzać tylko jeden inny interfejs (bez wielokrotnego dziedziczenia). Każdy interfejs w pakiecie z niezerowym numerem wersji pomocniczej musi rozszerzać interfejs z poprzedniej wersji pakietu. Na przykład, jeśli interfejs IBar w wersji 4.0 derivative pakietu jest oparty (rozszerza) interfejs IFoo w wersji 1.2 original pakietu i utworzona jest wersja 1.3 original pakietu, IBar w wersji 4.1 nie może rozszerzać wersji 1.3 IFoo . Zamiast tego wersja IBar 4.1 musi rozszerzać wersję IBar 4.0, która jest powiązana z wersją IFoo 1.2. W razie potrzeby wersja IBar 5.0 może rozszerzyć wersję IFoo 1.3.

Rozszerzenia interfejsu nie implikują zależności od bibliotek ani włączenia różnych HAL do wygenerowanego kodu — po prostu importują strukturę danych i definicje metod na poziomie HIDL. Każda metoda w warstwie HAL musi być zaimplementowana w tej warstwie HAL.

Rozszerzenia dostawcy

W niektórych przypadkach rozszerzenia dostawców zostaną zaimplementowane jako podklasa obiektu podstawowego, który reprezentuje podstawowy interfejs, który rozszerzają. Ten sam obiekt zostanie zarejestrowany pod podstawową nazwą i wersją HAL oraz pod nazwą i wersją HAL rozszerzenia (dostawcy).

Wersjonowanie

Pakiety są wersjonowane, a interfejsy mają wersję swojego pakietu. Wersje są wyrażone w dwóch liczbach całkowitych, major . drobny .

  • Wersje główne nie są kompatybilne wstecz. Zwiększanie numeru wersji głównej resetuje numer wersji pomocniczej na 0.
  • Wersje mniejsze są kompatybilne wstecz. Zwiększanie mniejszej liczby oznacza, że ​​nowsza wersja jest w pełni kompatybilna wstecz z wersją poprzednią. Można dodawać nowe struktury danych i metody, ale nie można zmieniać istniejących struktur danych ani sygnatur metod.

Na urządzeniu może znajdować się jednocześnie wiele głównych lub pomocniczych wersji warstwy HAL. Jednak wersja pomocnicza powinna być preferowana w stosunku do wersji głównej, ponieważ kod klienta współpracujący z interfejsem poprzedniej wersji pomocniczej będzie również działał z późniejszymi wersjami pomocniczymi tego samego interfejsu. Aby uzyskać więcej informacji na temat wersjonowania i rozszerzeń dostawców, zobacz Wersjonowanie HIDL .

Podsumowanie układu interfejsu

Ta sekcja podsumowuje sposób zarządzania pakietem interfejsu HIDL (takim jak hardware/interfaces ) i konsoliduje informacje przedstawione w całej sekcji HIDL. Przed przeczytaniem upewnij się, że znasz wersjonowanie HIDL , koncepcje mieszania w Hashing z hidl-gen , ogólne szczegóły pracy z HIDL oraz następujące definicje:

Termin Definicja
Interfejs binarny aplikacji (ABI) Interfejs programowania aplikacji + wymagane wszelkie powiązania binarne.
Pełna nazwa (fqName) Nazwa służąca do rozróżnienia typu hidl. Przykład: android.hardware.foo@1.0::IFoo .
Pakiet Pakiet zawierający interfejs i typy HIDL. Przykład: android.hardware.foo@1.0 .
Katalog główny pakietu Pakiet główny zawierający interfejsy HIDL. Przykład: interfejs HIDL android.hardware znajduje się w katalogu głównym pakietu android.hardware.foo@1.0 .
Ścieżka główna pakietu Lokalizacja w drzewie źródłowym Androida, do której mapowany jest katalog główny pakietu.

Aby uzyskać więcej definicji, zobacz Terminologia HIDL.

Każdy plik można znaleźć na podstawie mapowania katalogu głównego pakietu i jego pełnej nazwy

Katalog główny pakietów jest określony dla hidl-gen jako argument -r android.hardware:hardware/interfaces . Na przykład, jeśli pakiet to vendor.awesome.foo@1.0::IFoo i wysłano hidl-gen -r vendor.awesome:some/device/independent/path/interfaces , to plik interfejsu powinien znajdować się w $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal .

W praktyce zaleca się, aby dostawca lub producent OEM o nazwie awesome umieścił swoje standardowe interfejsy w vendor.awesome . Po wybraniu ścieżki pakietu nie można jej zmieniać, ponieważ jest ona zapisana w ABI interfejsu.

Mapowanie ścieżki pakietu powinno być unikalne

Na przykład, jeśli masz -rsome.package:$PATH_A i -rsome.package:$PATH_B , $PATH_A musi być równe $PATH_B , aby zapewnić spójny katalog interfejsu (to także znacznie ułatwia wersjonowanie interfejsów ).

Katalog główny pakietu musi zawierać plik wersji

Jeśli utworzysz ścieżkę pakietu, taką jak -r vendor.awesome:vendor/awesome/interfaces , powinieneś także utworzyć plik $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt , który powinien zawierać skróty interfejsów utworzone przy użyciu opcji -Lhash opcja w hidl-gen (jest to szczegółowo omówione w Hashing z hidl-gen ).

Interfejsy znajdują się w lokalizacjach niezależnych od urządzenia

W praktyce zaleca się współdzielenie interfejsów pomiędzy oddziałami. Pozwala to na maksymalne ponowne wykorzystanie kodu i maksymalne testowanie kodu na różnych urządzeniach i przypadkach użycia.