Interfejsy i pakiety

HIDL opiera się na interfejsach – typie abstrakcyjnym używanym w do definiowania zachowań. Każdy interfejs jest częścią pakietu.

Pakiety

Nazwy pakietów mogą mieć poziomy podrzędne, np. package.subpackage. katalog główny opublikowanych pakietów HIDL to hardware/interfaces lub vendor/vendorName (np. vendor/google w przypadku Pixela urządzenia). Nazwa pakietu tworzy co najmniej jeden podkatalog w katalogu głównym directory; wszystkie pliki definiujące pakiet znajdują się w tym samym katalogu. Przykład: Można znaleźć package android.hardware.example.extension.light@2.0 poniżej hardware/interfaces/example/extension/light/2.0.

W tej tabeli znajdziesz prefiksy pakietów i lokalizacje:

Prefiks pakietu Lokalizacja Typy interfejsów
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* platformy/ powiązane
android.system.* system/hardware/interfaces/* system/ pokrewne
android.hidl.* system/libhidl/transport/* mięśnie głębokie

Katalog pakietów zawiera pliki z rozszerzeniem .hal. Co musi zawierać instrukcję package zawierającą nazwę pakietu i wersji, do której należy plik. Plik types.hal (jeśli istnieje) nie definiuje interfejsu, lecz definiuje typy danych dostępne dla każdej który znajduje się w pakiecie.

Definicja interfejsu

Oprócz pliku types.hal każdy inny plik .hal określa 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 niejawnej deklaracji extends rozciąga się od android.hidl.base@1.0::IBase (podobne do java.lang.Object w Javie). Bezpośrednio za pomocą interfejsu IBase zaimportowane, deklaruje kilka zarezerwowanych metod, których nie można ponownie zadeklarowane w interfejsach zdefiniowanych przez użytkownika lub wykorzystane w inny sposób. Metody te uwzględnij:

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

Proces importowania

Instrukcja import to mechanizm HIDL uzyskujący dostęp do pakietu z interfejsów i typów w innym pakiecie. Instrukcja import dotyczy się dwóch podmiotów:

  • Importowana encja, którą może być pakiet lub interfejs
  • Zaimportowany element, którym może być pakiet lub interfejs

Importowany obiekt jest określany na podstawie lokalizacji Instrukcja import. Gdy instrukcja znajduje się w polu types.hal, to, co jest importowane, jest widoczne w całym pakiecie. jest to import na poziomie pakietu. Gdy instrukcja znajduje się w tagu elementem interfejsu jest sam interfejs, to jest na poziomie interfejsu.

Zaimportowany element jest określany na podstawie wartości występującej po fragmencie import słowa kluczowego. Wartość nie musi być w pełni kwalifikowaną nazwą; jeśli komponent to zostanie on automatycznie wypełniony informacjami z bieżącego pakietu. W przypadku w pełni kwalifikowanych wartości obsługiwane są następujące przypadki importu:

  • Importowanie całego pakietu. Jeśli wartością jest nazwa pakietu i (składnię opisaną poniżej), cały pakiet zostanie zaimportowany do importujący encję.
  • Importy częściowe. Jeśli wartość to:
    • Interfejs, types.hal i interfejs pakietu zaimportowane do elementu importu.
    • w przypadku jednostki UDT zdefiniowanej w types.hal, do niej zaimportowana jest tylko ta funkcja importowany element (inne typy w polu types.hal nie są importowane).
  • Importy tylko typów. Jeśli wartość korzysta ze składni częściowy import opisany powyżej, ale ze słowem kluczowym types nazwy interfejsu, tylko identyfikatory UDT w types.hal zaimportowanych pakietów.

Importowany element ma dostęp do kombinacji:

  • Wspólne identyfikatory UDT zaimportowanego pakietu zdefiniowane w tabeli types.hal;
  • Interfejsy importowanego pakietu (w przypadku importu całego pakietu) lub określone (do częściowego importu) do ich wywołania, uchwytów do nich lub dziedziczenia z nich.

Instrukcja importu korzysta ze składni w pełni kwalifikowanej nazwy typu-nazwa, aby zapewnić nazwa i wersja 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 w interfejsie

Interfejs może być rozszerzeniem wcześniej zdefiniowanego interfejsu. Istnieją trzy typy rozszerzeń:

  • Interfejs może dodać funkcje do innego, korzystając ze swojego interfejsu API bez zmian.
  • Pakiet może dodać funkcje do innego pakietu, wykorzystując swój interfejs API bez zmian.
  • Interfejs może importować typy z pakietu lub z określonego interfejsu.

Interfejs może stanowić rozszerzenie tylko jednego innego interfejsu (nie może być dziedziczeniem wielokrotnym). Każdy interfejs w pakiecie z numerem wersji podrzędnej innej niż 0 musi obejmować rozszerzenie w poprzedniej wersji pakietu. Jeśli na przykład interfejs użytkownika IBar w wersji 4.0 pakietu derivative na podstawie (rozszerza) interfejs IFoo w wersji 1.2 pakietu original oraz wersja 1.3 pakietu original to utworzono, IBar wersja 4.1 nie może rozszerzyć wersji 1.3 IFoo Zamiast tego musi być rozszerzenie IBar w wersji 4.1. IBar w wersji 4.0, która jest powiązana z IFoo w wersji 1.2. Przeglądarka IBar w wersji 5.0 może rozszerzyć IFoo wersję 1.3, jeśli pożądaną.

Rozszerzenia interfejsu nie sugerują zależności od biblioteki ani nie uwzględniają treści HAL w wygenerowanym kodzie – wystarczy, że zaimportują strukturę i metodę danych, na poziomie HIDL. Każda metoda w HAL musi być zaimplementowana w tym HAL.

Rozszerzenia dostawców

W niektórych przypadkach rozszerzenia dostawców są zaimplementowane jako podklasa klasy który reprezentuje podstawowy interfejs, który jest rozszerzany. Ten sam obiekt jest zarejestrowane pod podstawową nazwą i wersją HAL oraz pod Nazwa i wersja HAL (dostawcy).

Obsługa wersji

Pakiety mają różne wersje, a interfejsy – swoją wersję. Wersje są wyrażone za pomocą 2 liczb całkowitych: duża.mniejsza.

  • Wersje główne nie są zgodne wstecznie. Zwiększam numer wersji głównej resetuje numer wersji podrzędnej do 0.
  • Wersje Minor są zgodne wstecznie. Zwiększam liczba pomniejszona oznacza, że nowsza wersja jest w pełni zgodna wstecznie z poprzedniej wersji. Można dodawać nowe struktury danych i metody, ale nie możesz dodawać istniejących struktury danych lub podpisy metod mogą ulec zmianie.

Na urządzeniu może znajdować się wiele głównych i podrzędnych wersji HAL. jednocześnie. Należy jednak preferować wersję podrzędną zamiast wersji głównej. ponieważ kod klienta działa z interfejsem poprzedniej wersji podrzędnej działa również z późniejszymi wersjami podrzędnymi tego samego interfejsu. Więcej szczegółowe informacje na temat obsługi wersji i rozszerzeń dostawców można znaleźć w artykule Obsługa wersji HIDL.

Podsumowanie układu interfejsu

Z tej sekcji dowiesz się, jak zarządzać pakietem interfejsu HIDL (takim jak hardware/interfaces) i konsoliduje przedstawiane informacje w całej sekcji HIDL. Zanim zaczniesz czytać, zapoznaj się z Obsługa wersji HIDL, szyfrowanie z koncepcje hidl-gen, szczegóły pracy z grupą Ogólne informacje o HIDL oraz te definicje:

Termin Definicja
interfejs binarny aplikacji (ABI) Interfejs programowania aplikacji oraz wszelkie wymagane powiązania binarne.
pełna nazwa (fqName) Nazwa wyróżniająca typ hidl. Przykład: android.hardware.foo@1.0::IFoo
paczka Pakiet zawierający interfejs i typy HIDL. Przykład: android.hardware.foo@1.0
poziom 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, na którą mapuje się pakiet główny.

Więcej definicji znajdziesz w sekcji HIDL Terminologia.

Każdy plik można znaleźć z mapowania głównego pakietu, jego pełna i jednoznaczna nazwa

Poziomy główne pakietu są określone jako hidl-gen jako argument. -r android.hardware:hardware/interfaces Na przykład, jeśli plik przesyłka to vendor.awesome.foo@1.0::IFoo i hidl-gen zostanie wysłany -r vendor.awesome:some/device/independent/path/interfaces, plik interfejsu powinien znajdować się w $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal

W praktyce jest to zalecane w przypadku dostawcy lub OEM o nazwie awesome ich standardowe interfejsy zostały umieszczone w języku vendor.awesome. Po paczce została wybrana ścieżka, nie można jej zmieniać, ponieważ jest ona umieszczana w ABI do 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 mieć wartość równą $PATH_B dla spójnego katalogu interfejsu (powoduje to również interfejsy obsługi wersji ).

Element główny pakietu musi mieć plik obsługi wersji

Jeśli utworzysz ścieżkę pakietu, taką jak -r vendor.awesome:vendor/awesome/interfaces, także utwórz plik $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt, czyli powinien zawierać hasze interfejsów utworzonych przy użyciu opcji -Lhash w hidl-gen (to szczegółowo omówiono w Haszowanie z hidl-gen).

Interfejsy działają niezależnie od urządzenia lokalizacje

W praktyce zalecamy współdzielenie interfejsów między gałęziami. Ten pozwala na maksymalne ponowne wykorzystanie i testowanie kodu w różnych urządzeń i przypadków użycia.