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 wtypes.hal
nie są importowane).
- Interfejs,
- 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 wtypes.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.