Obsługa wersji interfejsu

HIDL wymaga, aby każdy interfejs napisany w HIDL miał wersję. Po HAL gdy zostaje opublikowany, pozostaje zablokowany i wszelkie dalsze zmiany nowej wersji interfejsu. Choć danego opublikowanego interfejsu nie można zmodyfikowany, można go rozszerzyć przez inny interfejs.

Struktura kodu HIDL

Kod HIDL jest zorganizowany w sposób zdefiniowany przez użytkownika typy, interfejsy i pakiety:

  • Typy zdefiniowane przez użytkownika (UDT). HIDL zapewnia dostęp do zestawu podstawowych typów danych, których można używać do tworzenia bardziej złożonych typów danych za pomocą struktury, związki i wyliczenia. Identyfikatory UDT są przekazywane do metod: i można je definiować na poziomie pakietu (wspólnym dla wszystkich z interfejsem użytkownika) lub lokalnie do interfejsu.
  • Interfejsy. Podstawowym elementem HIDL jest interfejs, składa się z deklaracji UDT i deklaracji metody. Interfejsy mogą również dziedziczyć z innego interfejsu.
  • Przesyłki. Porządkuje powiązane interfejsy HIDL i dane na których działają. Pakiet jest identyfikowany przez nazwę i wersję obejmuje następujące elementy:
    • Plik definicji typu danych o nazwie types.hal.
    • 0 lub więcej interfejsów, każdy w osobnym pliku .hal.

Plik definicji typu danych types.hal zawiera tylko tabele UDT (wszystkie są przechowywane w jednym pliku. Reprezentacje w grupie docelowej we wszystkich interfejsach pakietu.

Filozofia wersjonowania

pakietu HIDL (np. android.hardware.nfc) po przejściu wersji opublikowanej (np. 1.0) nie można zmienić. jego nie można zmienić. Modyfikacje interfejsów w pakiecie lub dowolnych zmiany w jednostkach UDT mogą mieć miejsce tylko w innym pakiecie.

W HIDL obsługa wersji ma zastosowanie na poziomie pakietu, a nie na poziomie interfejsu. a wszystkie interfejsy i tabele UDT w pakiecie mają tę samą wersję. Przesyłka wersje są zgodne z semantyką obsługi wersji bez poziomu poprawki i komponentów metadanych kompilacji. W ciągu dla danego pakietu, wzrost wersji podrzędnej oznacza nową wersję pakiet jest zgodny wstecznie ze starym pakietem i dużym „wersja” oznacza, że nowa wersja pakietu zgodne wstecznie ze starym pakietem.

Pakiet może być powiązany z innym pakietem na kilka sposobów:

  • Wcale nie.
  • Rozszerzalność rozszerzania o zgodność wsteczną na poziomie pakietu. Ten ma miejsce w przypadku nowych uaktualnień wersji podrzędnej (następnej zwiększonej wersji) pakietu; nowy pakiet ma tę samą nazwę i wersję główną co stary pakiet, ale wyższej wersji podrzędnej. Pod względem funkcjonalnym nowy pakiet jest nadzbiorem starego pakietu pakiet, co oznacza:
    • W nowym pakiecie znajdują się interfejsy najwyższego poziomu pakietu nadrzędnego, chociaż interfejsy mogą mieć nowe metody: nowe lokalne tabele UDT ( rozszerzenia na poziomie interfejsu opisanego poniżej), a nowe tabele UDT w types.hal
    • Do nowego pakietu można też dodawać nowe interfejsy.
    • W nowym pakiecie znajdują się wszystkie typy danych z pakietu nadrzędnego mogą być obsługiwane za pomocą (prawdopodobnie ponownie zaimplementowanych) metod ze starego pakietu.
    • Można także dodawać nowe typy danych na potrzeby dowolnej z nowych metod za pomocą obecnych i nowych interfejsów.
  • Rozszerzalność wsteczna na poziomie interfejsu. Nowy Pakiet może także stanowić rozszerzenie pierwotnego pakietu, składając się z logicznie odrębnych elementów. interfejsów, które oferują tylko dodatkowe funkcje, a nie główną. W tym celu przydatne mogą być:
    • Interfejsy w nowym pakiecie muszą wrócić do typów danych starego pakietu SDK.
    • Interfejsy w nowym pakiecie mogą rozszerzać interfejsy jednego lub kilku starych przesyłek.
  • Zwiększyć zgodność pierwotnej wersji oprogramowania. To jest główną wersję pakietu i nie ma żadnej korelacji obu stron. W miarę możliwości może to być wyrażenie z użyciem kombinacji funkcji typy ze starszej wersji pakietu oraz dziedziczenie podzbioru ze starymi interfejsami.

Tworzenie struktury interfejsu

Jeśli interfejs jest dobrze uporządkowany, dodanie nowych rodzajów funkcji, nie są częścią oryginalnego projektu, powinny wymagać zmiany HIDL za pomocą prostego interfejsu online. Jeśli natomiast można lub oczekiwać zmiany po obu stronach interfejsu, który wprowadza nowe funkcje bez wprowadzania zmian sam interfejs nie ma struktury.

Treble obsługuje oddzielnie skompilowane komponenty dostawcy i systemu, w których vendor.img na urządzeniu, a system.img może być zebrane oddzielnie. Wszystkie interakcje między vendor.img a Metoda system.img musi być wprost i dokładnie zdefiniowana, aby można było będą działać przez wiele lat. Obejmuje to wiele interfejsów API, ale główny to mechanizm IPC używany przez HIDL do komunikacji międzyprocesowej Granica system.img/vendor.img.

Wymagania

Wszystkie dane przekazywane przez HIDL muszą być wyraźnie zdefiniowane. Aby zapewnić a klient może współpracować nawet po skompilowaniu oddzielnie lub opracowywane oddzielnie, dane muszą być zgodne z następującymi wymagania:

  • Można ją opisać bezpośrednio w HIDL (za pomocą wyliczeniowych elementów structs itp.) za pomocą nazwy semantyczne i ich znaczenie.
  • Może być zgodna z normą publiczną, np. ISO/IEC 7816.
  • Może być opisany standardem sprzętowym lub fizycznym układem sprzętu.
  • W razie potrzeby dane mogą być nieprzejrzyste (takie jak klucze publiczne, identyfikatory itp.).

Jeśli używane są nieprzezroczyste dane, muszą one być odczytywane tylko z jednej strony HIDL za pomocą prostego interfejsu online. Jeśli na przykład kod vendor.img przekazuje komponent na stronie system.img komunikat tekstowy lub vec<uint8_t> dane nie mogą zostać przeanalizowane przez samą system.img; może zostać zwrócona do vendor.img w celu interpretacji. Kiedy przekazując wartość z vendor.img do kodu dostawcy system.img lub na inne urządzenie, format danych i sposób ich przesyłania należy interpretować, musi być dokładnie opisany i nadal jest częścią .

Wskazówki

Musisz być w stanie napisać implementację lub klienta HAL używając wyłącznie z plikami .hal (tj. nie musisz sprawdzać pliku źródłowego Androida ani ). Zalecamy dokładne określenie wymaganego zachowania. Oświadczenia takie jak jako „implementacja może wybrać A lub B” zachęca wdrożenia do które są powiązane z klientami, z którymi zostały opracowane.

Układ kodu HIDL

HIDL obejmuje pakiety podstawowe i dostawcy.

Podstawowe interfejsy HIDL to te określone przez Google. pakiety, do których należą. zaczynają się od android.hardware. i są nazwane przez podsystem, potencjalnie z zagnieżdżonymi poziomami nazw. Na przykład pakiet NFC nazywa się android.hardware.nfc i pakiet z aparatem android.hardware.camera Ogólnie pakiet podstawowy ma nazwę android.hardware.[name1][name2]... Pakiety HIDL mają wersję oprócz nazwy. Na przykład: android.hardware.camera może być w wersji 3.4; to jest ważne, bo wersja pakietu wpływa na jego miejsce w drzewie źródłowym.

Wszystkie podstawowe pakiety znajdują się w kolumnie hardware/interfaces/ systemu kompilacji. Przesyłka android.hardware.[name1].[name2]... w wersji $m.$n jest poniżej hardware/interfaces/name1/name2/.../$m.$n/; przesyłka android.hardware.camera w wersji 3.4 jest w katalogu hardware/interfaces/camera/3.4/. Mapowanie jest zakodowane na stałe między prefiksem pakietu android.hardware. a ścieżką hardware/interfaces/.

Pakiety innego typu (dostawcy) to te wyprodukowane przez dostawcę SOC lub ODM. prefiks w przypadku pakietów innych niż podstawowe to vendor.$(VENDOR).hardware., gdzie $(VENDOR)nazwa dostawcy układów SOC lub OEM/ODM. Te dane są mapowane na ścieżkę vendor/$(VENDOR)/interfaces w drzewie (to mapowanie jest również zakodowanych na stałe).

Pełne i jednoznaczne nazwy typów zdefiniowane przez użytkownika

W HIDL każda funkcja UDT ma pełną i jednoznaczną nazwę, która składa się z nazwy UDT, nazwa pakietu, w którym zdefiniowano identyfikator UDT, oraz wersja pakietu. pełna i jednoznaczna nazwa jest używana tylko wtedy, gdy zadeklarowane są instancje typu a nie tam, gdzie zdefiniowany jest sam typ. Załóżmy na przykład, że pakiet android.hardware.nfc, w wersji 1.0 definiuje strukturę o nazwie NfcData. Na stronie deklaracji (niezależnie od tego, czy types.hal lub w deklaracji interfejsu), deklaracja po prostu stwierdza:

struct NfcData {
    vec<uint8_t> data;
};

Przy deklarowaniu wystąpienia tego typu (w strukturze danych lub jako parametru metody), użyj pełnej i jednoznacznej nazwy typu:

android.hardware.nfc@1.0::NfcData

Ogólna składnia to PACKAGE@VERSION::UDT, gdzie:

  • PACKAGE to rozdzielana kropkami nazwa pakietu HIDL (np. android.hardware.nfc).
  • VERSION to rozdzielana kropkami wersja główna.podrzędna format pakietu (np. 1.0).
  • UDT to rozdzielana kropkami nazwa HIDL UDT. Ponieważ HIDL obsługuje zagnieżdżone tabele UDT, a interfejsy HIDL mogą zawierać tabele UDT (typ zagnieżdżonej deklaracji), kropki są używane do uzyskiwania dostępu do nazw.

Jeśli na przykład poniższa zagnieżdżona deklaracja została zdefiniowana we wspólnym typ pliku w pakiecie android.hardware.example w wersji 1.0:

// types.hal
package android.hardware.example@1.0;
struct Foo {
    struct Bar {
        // …
    };
    Bar cheers;
};

Pełna nazwa elementu Bar to android.hardware.example@1.0::Foo.Bar Jeśli, oprócz tego, że jesteś w w powyższym pakiecie, deklaracja zagnieżdżona znajdowała się w interfejsie o nazwie IQuux:

// IQuux.hal
package android.hardware.example@1.0;
interface IQuux {
    struct Foo {
        struct Bar {
            // …
        };
        Bar cheers;
    };
    doSomething(Foo f) generates (Foo.Bar fb);
};

Pełna nazwa elementu Bar to android.hardware.example@1.0::IQuux.Foo.Bar

W obu przypadkach pole Bar może być określane tylko jako Bar w zakresie deklaracji zawartej w dokumencie Foo. Przy przesyłce lub poziomu interfejsu, należy odwołać się do Bar za pośrednictwem Foo: Foo.Bar zgodnie z deklaracją metody doSomething powyżej. Możesz też zadeklarować metodę bardziej szczegółowo jako:

// IQuux.hal
doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);

Pełne i jednoznaczne wartości wyliczenia

Jeśli UDT jest typem wyliczenia, każda wartość tego typu ma typ w pełni kwalifikowana nazwa zaczynająca się od pełnej i jednoznacznej nazwy typu wyliczenia, dwukropek, a po nim nazwa wartości wyliczeniowej. Przykład: zakładaj pakiet android.hardware.nfc, w wersji 1.0 określa typ wyliczenia NfcStatus:

enum NfcStatus {
    STATUS_OK,
    STATUS_FAILED
};

W przypadku atrybutu STATUS_OK pełna i jednoznaczna nazwa to:

android.hardware.nfc@1.0::NfcStatus:STATUS_OK

Ogólna składnia to PACKAGE@VERSION::UDT:VALUE, gdzie:

  • PACKAGE@VERSION::UDT to dokładnie tę samą pełną i jednoznaczną nazwę dla typu wyliczenia.
  • VALUE to nazwa wartości.

Reguły automatycznego wnioskowania

Nie musisz podawać pełnej i jednoznacznej nazwy UDT. Nazwa UDT może bezpiecznie pomijać następujące elementy:

  • Pakiet, np. @1.0::IFoo.Type
  • Zarówno pakiet, jak i wersja, np. IFoo.Type
.

HIDL próbuje uzupełnić nazwę przy użyciu reguł automatycznego zakłócania (dolna reguła oznacza wyższy priorytet).

Reguła 1

Jeśli nie podano pakietu ani wersji, zostanie podjęta próba wyszukiwania nazwy lokalnej. Przykład:

interface Nfc {
    typedef string NfcErrorMessage;
    send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m);
};

Wyszukiwanie NfcErrorMessage jest wyszukiwane lokalnie, a typedef powyżej wyników. Wyszukiwanie „NfcData” też jest przeprowadzane lokalnie, ale w rzeczywistości niezdefiniowane lokalnie, używane są reguły 2 i 3. @1.0::NfcStatus podaje wersję, więc reguła 1 nie jest stosowana.

Reguła 2

Jeśli reguła 1 zakończy się niepowodzeniem i brakuje komponentu pełnej nazwy (pakiet, wersja lub pakiet i wersja) komponent jest automatycznie uzupełniany wartością informacje z bieżącego pakietu. Kompilator HIDL wyszukuje następnie bieżącego pliku (i wszystkich importów), aby znaleźć automatycznie wypełnioną, pełną i jednoznaczną nazwę. W przykładzie powyżej załóżmy, że deklaracja funkcji ExtendedNfcData zostało wysłane w tym samym pakiecie (android.hardware.nfc) w tym samym (1.0) jako NfcData w następujący sposób:

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

Kompilator HIDL wypełnia nazwę pakietu i wersji z bieżący pakiet do wygenerowania w pełni kwalifikowanej nazwy UDT android.hardware.nfc@1.0::NfcData Nazwa znajduje się w (zakładając, że został prawidłowo zaimportowany), jest używany przez tej deklaracji.

Nazwa w bieżącym pakiecie zostanie zaimportowana tylko wtedy, gdy zostanie true (prawda):

  • Jest importowany bezpośrednio za pomocą instrukcji import.
  • Jest zdefiniowane w types.hal w bieżącym pakiecie

Ta sama procedura jest stosowana, jeśli kategoria NfcData została zakwalifikowana tylko przez Numer wersji:

struct ExtendedNfcData {
    // autofill the current package name (android.hardware.nfc)
    @1.0::NfcData base;
    // … additional members
};

Reguła 3

Jeśli reguła 2 nie zwróci dopasowania (numer UDT nie jest zdefiniowany w bieżącej pakiet), kompilator HIDL skanuje wszystkie zaimportowane pakiety pod kątem dopasowania. W powyższym przykładzie załóżmy, że ExtendedNfcData jest zadeklarowany w wersja 1.1 pakietu android.hardware.nfc, 1.1 importuje 1.0 poprawnie (zobacz Rozszerzenia na poziomie pakietu) i definicja określa tylko nazwę UDT:

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

Kompilator wyszukuje wszystkie tabele UDT o nazwie NfcData i znajduje jedną w android.hardware.nfc w wersji 1.0, co daje błąd w pełni kwalifikowana wartość UDT wynosząca android.hardware.nfc@1.0::NfcData. Jeśli więcej dla danego częściowo kwalifikowanego UDT, kompilator HIDL powoduje zgłoszenie błędu.

Przykład

Przy użyciu reguły 2 zaimportowany typ zdefiniowany w bieżącym pakiecie jest faworyzowany zaimportowany typ z innego pakietu:

// hardware/interfaces/foo/1.0/types.hal
package android.hardware.foo@1.0;
struct S {};

// hardware/interfaces/foo/1.0/IFooCallback.hal
package android.hardware.foo@1.0;
interface IFooCallback {};

// hardware/interfaces/bar/1.0/types.hal
package android.hardware.bar@1.0;
typedef string S;

// hardware/interfaces/bar/1.0/IFooCallback.hal
package android.hardware.bar@1.0;
interface IFooCallback {};

// hardware/interfaces/bar/1.0/IBar.hal
package android.hardware.bar@1.0;
import android.hardware.foo@1.0;
interface IBar {
    baz1(S s); // android.hardware.bar@1.0::S
    baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback
};
  • S jest interpolowany jako android.hardware.bar@1.0::S i znajduje się w bar/1.0/types.hal (ponieważ types.hal jest automatycznie zaimportowane).
  • IFooCallback jest interpolowany jako android.hardware.bar@1.0::IFooCallback korzysta z reguły 2, ale nie można znaleźć, ponieważ bar/1.0/IFooCallback.hal nie został zaimportowany automatycznie (tak jak types.hal). Tym samym reguła 3 powoduje, że android.hardware.foo@1.0::IFooCallback, która jest importowana przez import android.hardware.foo@1.0;).

type.hal

Każdy pakiet HIDL zawiera plik types.hal zawierający numery UDT które są współdzielone przez wszystkie interfejsy w tym pakiecie. Typy HIDL są zawsze publiczne, niezależnie od tego, czy funkcja UDT jest zadeklarowana w types.hal lub w deklaracji interfejsu te typy są dostępne poza zakresem, w którym zostały zdefiniowane. types.hal nie służy do opisania publicznego interfejsu API pakietu, ale do hostowania tabel UDT używane we wszystkich interfejsach w pakiecie. Ze względu na charakter HIDL wszystkie UDT są częścią interfejsu.

types.hal składa się z tabel UDT i instrukcji import. Ponieważ usługa types.hal jest dostępna dla każdego interfejsu pakiet (jest to import niejawny), te instrukcje import są na poziomie pakietu według definicji. Identyfikatory UDT w języku types.hal mogą też zawierać Importowane w ten sposób tabele UDT i interfejsy.

Przykład dla IFoo.hal:

package android.hardware.foo@1.0;
// whole package import
import android.hardware.bar@1.0;
// types only import
import android.hardware.baz@1.0::types;
// partial imports
import android.hardware.qux@1.0::IQux.Quux;
// partial imports
import android.hardware.quuz@1.0::Quuz;

Importowane są następujące elementy:

  • android.hidl.base@1.0::IBase (domyślnie)
  • android.hardware.foo@1.0::types (domyślnie)
  • Wszystko w kategorii android.hardware.bar@1.0 (w tym wszystkie interfejsów API i ich types.hal)
  • types.hal z: android.hardware.baz@1.0::types (interfejsy w android.hardware.baz@1.0 nie są importowane)
  • IQux.hal i types.hal od android.hardware.qux@1.0
  • Quuz z android.hardware.quuz@1.0 (przy założeniu Quuz jest zdefiniowany w types.hal, cała Przeanalizowano types.hal plik, ale typy innych niż Quuz nie są importowane).

Obsługa wersji na poziomie interfejsu

Każdy interfejs w pakiecie znajduje się w osobnym pliku. Pakiet interfejs jest zadeklarowany w górnej części interfejsu za pomocą Instrukcja package. Po deklaracji dotyczącej pakietu – zero lub więcej importu na poziomie interfejsu (częściowy lub całego pakietu). Na przykład:

package android.hardware.nfc@1.0;

W HIDL interfejsy mogą dziedziczyć z innych interfejsów za pomocą extends słowo kluczowe. Rozszerzenie innego interfejsu musi mieć do niego dostęp za pomocą instrukcji import. Nazwa rozszerzany interfejs (interfejs podstawowy) jest zgodny z regułami dla typu nazwa powyższej kwalifikacji. interfejs może dziedziczyć tylko z jednego interfejsu; HIDL nie obsługuje dziedziczenia wielokrotnego.

W poniższych przykładach obsługi wersji plików uprev używany jest ten pakiet:

// types.hal
package android.hardware.example@1.0
struct Foo {
    struct Bar {
        vec<uint32_t> val;
    };
};

// IQuux.hal
package android.hardware.example@1.0
interface IQuux {
    fromFooToBar(Foo f) generates (Foo.Bar b);
}

Reguły podwyższenia standardu

Aby zdefiniować pakiet package@major.minor, może to być pakiet A lub całość B. musi mieć wartość prawda:

Reguła A „Jest początkową wersją podrzędną”: wszystkie poprzednie wersje podrzędne, package@major.0, package@major.1, ..., Nie można zdefiniować wartości package@major.(minor-1).
LUB
Reguła B

Wszystkie te stwierdzenia są prawdziwe:

  1. „Poprzednia wersja podrzędna jest prawidłowa”: package@major.(minor-1) musi być zdefiniowana i zgodna z tą samą regułą A (żadne z package@major.0 do package@major.(minor-2) są zdefiniowane) lub reguła B (jeśli jest to podwyżka z @major.(minor-2));

    I

  2. „Odziedzicz co najmniej jeden interfejs o tej samej nazwie”: istnieje interfejs package@major.minor::IFoo, który obejmuje package@major.(minor-1)::IFoo (jeśli poprzedni pakiet ma interfejs);

    I

  3. „Brak dziedziczonego interfejsu o innej nazwie”: nie może istnieć package@major.minor::IBar rozciąga się package@major.(minor-1)::IBaz, gdzie IBar i IBaz to 2 różne nazwy. Jeśli istnieje interfejs z funkcją ta sama nazwa, package@major.minor::IBar musi być rozszerzeniem package@major.(minor-k)::IBar, tak aby nie było żadnego paska IBar z elementem mniejsze k.

Ze względu na regułę A:

  • Pakiet może zaczynać się od dowolnego numeru wersji podrzędnej (na przykład android.hardware.biometrics.fingerprint – ceny zaczynają się o @2.1).
  • Niezdefiniowane wymaganie „android.hardware.foo@1.0” oznacza katalog hardware/interfaces/foo/1.0 w ogóle nie powinien istnieć.

Reguła A nie wpływa jednak na pakiet o tej samej nazwie, ale inną główną wersję (na przykład android.hardware.camera.device zawiera zarówno @1.0, jak i Zdefiniowano @3.2; @3.2 nie musi wchodzić w interakcję z: @1.0). Dlatego @3.2::IExtFoo może przedłużyć @1.0::IFoo

Jeśli nazwa pakietu jest inna, package@major.minor::IBar może rozszerzyć się z interfejsu z inną nazwę (na przykład android.hardware.bar@1.0::IBar może przedłużenie android.hardware.baz@2.2::IBaz). Jeśli interfejs nie jednoznacznie zadeklarować supertyp ze słowem kluczowym extend, obejmuje android.hidl.base@1.0::IBase (z wyjątkiem IBase) ).

B.2 i B.3 muszą być stosowane jednocześnie. Na przykład, nawet jeśli android.hardware.foo@1.1::IFoo – rozszerzenia android.hardware.foo@1.0::IFoo, aby przekazać regułę B.2, jeśli android.hardware.foo@1.1::IExtBar – rozszerzenia android.hardware.foo@1.0::IBar, to nadal nie jest prawidłowy wzrost przychodów.

Interfejsy Uprev

Aby zwiększyć przychody android.hardware.example@1.0 (zdefiniowane powyżej) do @1.1:

// types.hal
package android.hardware.example@1.1;
import android.hardware.example@1.0;

// IQuux.hal
package android.hardware.example@1.1
interface IQuux extends @1.0::IQuux {
    fromBarToFoo(Foo.Bar b) generates (Foo f);
}

To jest import na poziomie pakietu w wersji 1.0 android.hardware.example w: types.hal. Nie ma tu nowych Identyfikatory UDT są dodawane w wersji 1.1 pakietu, a odwołania do tabel UDT w wersja 1.0 jest nadal potrzebna, dlatego import na poziomie pakietu w aplikacji types.hal. (Ten sam efekt można było uzyskać, stosując tag importowanie na poziomie interfejsu w IQuux.hal).

W extends @1.0::IQuux w deklaracji IQuux określiliśmy wersję IQuux, która jest dziedziczone (dokonanie wyboru jest możliwe, ponieważ tag IQuux jest używany do zadeklarować interfejs i odziedziczyć z interfejsu). Ponieważ deklaracje po prostu nazwy, które dziedziczą wszystkie atrybuty pakietu i wersji w witrynie należy dokonać wyboru w nazwie interfejsu podstawowego. my mogłoby również użyć w pełni kwalifikowanej funkcji UDT, ale to nadmiarowe.

Nowy interfejs IQuux nie ponownie deklaruje metody fromFooToBar() dziedziczy z zasad @1.0::IQuux; po prostu wyświetla nową metodę dodawania fromBarToFoo(). W przypadku HIDL dziedziczona nie można ponownie zadeklarować metod w interfejsach podrzędnych, interfejs IQuux nie może zadeklarować fromFooToBar() bezpośrednio.

Konwencje Uprev

Czasami nazwa interfejsu musi zmienić nazwę interfejsu rozszerzającego. Zalecamy że rozszerzenia wyliczeniowe, struktury i sumy mają taką samą nazwę jak to, co rozszerzają chyba że są one wystarczająco różne, aby uzasadnić nową nazwę. Przykłady:

// in parent hal file
enum Brightness : uint32_t { NONE, WHITE };

// in child hal file extending the existing set with additional similar values
enum Brightness : @1.0::Brightness { AUTOMATIC };

// extending the existing set with values that require a new, more descriptive name:
enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };

Jeśli metoda może mieć nową nazwę semantyczną (np. fooWithLocation), jest to preferowane ustawienie. W przeciwnym razie należy nazwane podobnie do rozszerzenia. Na przykład metoda Komponent foo_1_1 w pliku @1.1::IFoo może zastąpić tę funkcję metody foo w @1.0::IFoo, jeśli nie ma lepszej nazwę alternatywną.

Obsługa wersji na poziomie pakietu

Obsługa wersji HIDL odbywa się na poziomie pakietu. po opublikowaniu pakietu jest niezmienny (jego zestawu interfejsów ani identyfikatorów UDT nie można zmienić). Pakiety mogą są ze sobą powiązane na kilka sposobów, z których każdy da się wyrazić połączenie dziedziczenia na poziomie interfejsu i tworzenia identyfikatorów UDT według kompozycji.

Jeden rodzaj relacji jest jednak ściśle zdefiniowany i musi być egzekwowany: Dziedziczenie zgodne wstecznie na poziomie pakietu. W tym scenariuszu Pakiet nadrzędny to pakiet, z którego jest dziedziczony, a tag pakiet child, który rozszerza pakiet nadrzędny. Na poziomie pakietu reguły dziedziczenia zgodnego wstecznie są następujące:

  1. Wszystkie interfejsy najwyższego poziomu pakietu nadrzędnego są dziedziczone przez interfejsy w pakietu podrzędnego.
  2. Można również dodać nowy pakiet (bez ograniczeń relacje z innymi interfejsami w innych pakietach).
  3. Można także dodawać nowe typy danych na potrzeby dowolnej z nowych metod za pomocą obecnych i nowych interfejsów.

Reguły te można wdrożyć za pomocą dziedziczenia HIDL na poziomie interfejsu i funkcji UDT ale aby zrozumieć te zależności, wymagana jest wiedza metapoziomowa. tworzą kompatybilne wstecznie rozszerzenie pakietu. Wiedza ta jest wnioskowana w następujący sposób:

Jeśli pakiet spełnia to wymaganie, hidl-gen wymusza reguł zgodności wstecznej.