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 o nazwie
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.
- 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
- 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 jakoandroid.hardware.bar@1.0::S
i znajduje się wbar/1.0/types.hal
(ponieważtypes.hal
jest automatycznie zaimportowane).IFooCallback
jest interpolowany jakoandroid.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 jaktypes.hal
). Tym samym reguła 3 powoduje, żeandroid.hardware.foo@1.0::IFooCallback
, która jest importowana przezimport 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 ichtypes.hal
) types.hal
z:android.hardware.baz@1.0::types
(interfejsy wandroid.hardware.baz@1.0
nie są importowane)IQux.hal
itypes.hal
odandroid.hardware.qux@1.0
Quuz
zandroid.hardware.quuz@1.0
(przy założeniuQuuz
jest zdefiniowany wtypes.hal
, cała Przeanalizowanotypes.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) .
|
---|
Reguła B | Wszystkie te stwierdzenia są prawdziwe:
|
---|
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 kataloghardware/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:
- Wszystkie interfejsy najwyższego poziomu pakietu nadrzędnego są dziedziczone przez interfejsy w pakietu podrzędnego.
- Można również dodać nowy pakiet (bez ograniczeń relacje z innymi interfejsami w innych pakietach).
- 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.