W tej sekcji opisano typy danych HIDL. Szczegóły implementacji znajdziesz w artykule HIDL C++ (dla C++) wdrożenia) lub HIDL Java (w implementacjach Java).
Podobieństwa do języka C++ to między innymi:
structs
używa składni C++.unions
obsługuje składnię C++ domyślnie. Oba typy muszą być nazwane. anonimowe struktury i sumy nie są obsługiwane.- Obiekty Typedefs są dozwolone w HIDL (tak jak w C++).
- Komentarze w stylu C++ są dozwolone – są kopiowane do wygenerowanego pliku nagłówka.
Podobieństwa do Javy to między innymi:
- Dla każdego pliku HIDL definiuje przestrzeń nazw w stylu Java, która musi zaczynać się od
android.hardware.
Wygenerowana przestrzeń nazw C++ to::android::hardware::…
- Wszystkie definicje pliku są zawarte w kodzie Java
Kod
interface
. - Deklaracje tablicy HIDL są zgodne ze stylem Java, a nie C++. Przykład:
struct Point { int32_t x; int32_t y; }; Point[3] triangle; // sized array
- Komentarze są podobne do formatu javadoc.
Przedstawienie danych
struct
lub union
, złożone z:
Układ standardowy
(podzbiór wymagań dotyczących zwykłych typów danych) ma spójną pamięć
układ w wygenerowanym kodzie C++, wymuszany z włączonymi jawnymi atrybutami wyrównywania
struct
i union
członków.
Proste typy HIDL oraz enum
i bitfield
typy (które zawsze wywodzą się z typów podstawowych) są mapowane na standardowe typy C++.
na przykład std::uint32_t
z
cstdint.
Ponieważ Java nie obsługuje typów niepodpisanych, niepodpisane typy HIDL są mapowane na odpowiedniego podpisanego typu Java. Obiekty Structs są mapowane na klasy Java; tablice są mapowane na tablice Java; związki nie są obecnie obsługiwane w Javie. Ciągi tekstowe są przechowywane wewnętrznie jako UTF8. Ponieważ Java obsługuje tylko ciągi UTF16, wartości ciągów znaków wysyłane do lub z implementacji Java są przetłumaczone i po ponownym tłumaczeniu mogą różnić się od siebie, zawsze płynnie tworzyć mapę.
Dane odebrane przez IPC w C++ są oznaczone etykietą const
i znajdują się w
pamięć tylko do odczytu, która pozostaje dostępna tylko przez czas wywołania funkcji. Dane
Odebrane przez IPC w Javie zostały już skopiowane do obiektów Java, więc można
mogą być przechowywane bez dodatkowego kopiowania (i mogą być modyfikowane).
Adnotacje
Do deklaracji typów można dodawać adnotacje w stylu Java. Adnotacje analizowane przez backend Vendor Test Suite (VTS) kompilatora HIDL, ale żadne takie przeanalizowane adnotacje są odczytywane przez kompilator HIDL. Zamiast tego: przeanalizowane adnotacje VTS są obsługiwane przez narzędzie VTS Compiler (VTSC).
Adnotacje używają składni Java: @annotation
lub
@annotation(value)
lub @annotation(id=value, id=value…)
gdzie wartość może być wyrażeniem stałym, ciągiem znaków lub listą wartości
wewnątrz {}
, tak samo jak w Javie. Wiele adnotacji o tej samej nazwie
które można dołączyć do tego samego elementu.
Prześlij deklaracje
W HIDL mogą nie być zadeklarowane struktury do przekazywania dalej, przez co są zdefiniowane Niemożliwe typy danych odnoszące się do siebie (np. nie możesz opisać połączonej listy lub drzewo w HIDL). Większość istniejących kont HAL (starszych niż 8.x) w ograniczonym zakresie deklaracje, które można usunąć, zmieniając strukturę danych deklaracje.
To ograniczenie umożliwia kopiowanie struktur danych według wartości za pomocą prostego
głęboka kopia, a nie śledzenie wartości wskaźników, które mogą występować
w autoreferencyjnej strukturze danych. Jeśli te same dane zostaną przekazane dwukrotnie,
np. z 2 parametrami metody lub vec<T>
wskazującymi na
tych samych danych, tworzy się i dostarcza dwie oddzielne kopie.
Zagnieżdżone deklaracje
HIDL obsługuje zagnieżdżone deklaracje na dowolnej liczbie poziomów (w jednej wyjątkiem opisanym poniżej). Na przykład:
interface IFoo { uint32_t[3][4][5][6] multidimArray; vec<vec<vec<int8_t>>> multidimVector; vec<bool[4]> arrayVec; struct foo { struct bar { uint32_t val; }; bar b; } struct baz { foo f; foo.bar fb; // HIDL uses dots to access nested type names } …
Wyjątkiem jest to, że typy interfejsów można umieszczać tylko w
vec<T>
i tylko jeden poziom głębokości (brak
vec<vec<IFoo>>
).
Składnia nieprzetworzonych wskaźników
Język HIDL nie zawiera symbolu * i nie obsługuje zapewnia pełną swobodę wskazówek w języku C/C++. Szczegółowe informacje o uwzględnianiu HIDL wskaźniki oraz tablice/wektory, patrz vec<T> .
Interfejsy
Słowo kluczowe interface
ma 2 zastosowania.
- Otwiera definicję interfejsu w pliku .hal.
- Można jej używać jako specjalnego typu w polach struktury/łączności, parametrach metody
i powrót. Jest on postrzegany jako ogólny interfejs i synonim
android.hidl.base@1.0::IBase
Na przykład IServiceManager
udostępnia tę metodę:
get(string fqName, string name) generates (interface service);
Metoda obiecuje wyszukiwanie jakiegoś interfejsu według nazwy. Jest także
interfejs jest identyczny z interfejsem android.hidl.base@1.0::IBase
.
Interfejsy mogą być przekazywane tylko na 2 sposoby: jako parametry najwyższego poziomu lub jako
członków grupy vec<IMyInterface>
. Nie mogą być członkami:
zagnieżdżone obiekty vecs, strukturalne, tablice lub sumy.
MQDescriptorSync i MQDescriptorUnsync
Typy MQDescriptorSync
i MQDescriptorUnsync
przekazują zsynchronizowane lub niezsynchronizowane deskryptory Szybkich wiadomości (FMQ).
za pomocą interfejsu HIDL. Więcej informacji:
HIDL C++ (kody FMQ nie są
obsługiwane w Javie).
typ pamięci
Typ memory
jest używany do reprezentowania niezmapowanej pamięci współdzielonej w:
HIDL. Jest on obsługiwany tylko w języku C++. Tego typu wartości można użyć w funkcji
koniec odbierający, aby zainicjować obiekt IMemory
, mapować pamięć
i zapewnianiu użyteczności. Więcej informacji:
HIDL w C++.
Ostrzeżenie: uporządkowane dane umieszczone w udostępnionych danych
musi być typem, którego format nigdy się nie zmienia przez cały czas istnienia
wersję interfejsu z komunikatem memory
. W przeciwnym razie właściciele HAL mogą mieć problemy
krytyczne problemy ze zgodnością.
typ wskaźnika
Typ pointer
jest przeznaczony tylko do użytku wewnętrznego HIDL.
bitfield<T> typ szablonu
bitfield<T>
, w którym T
to
wyliczenie zdefiniowane przez użytkownika sugeruje, że wartość jest bitem LUB argumentu
wartości wyliczeniowe zdefiniowane w funkcji T
. W wygenerowanym kodzie
bitfield<T>
jest typowym typem T. Dla:
przykład:
enum Flag : uint8_t { HAS_FOO = 1 << 0, HAS_BAR = 1 << 1, HAS_BAZ = 1 << 2 }; typedef bitfield<Flag> Flags; setFlags(Flags flags) generates (bool success);
Kompilator obsługuje typ „Flagi” tak samo jak uint8_t
.
Dlaczego nie stosować
(u)int16_t
.(u)int8_t
.(u)int32_t
/(u)int64_t
?
Użycie bitfield
dostarcza czytelnikom dodatkowych informacji HAL,
który teraz wie, że setFlags
przyjmuje wartość bitową LUB flagę (tzn.
wie, że nawiązanie połączenia setFlags
z numerem 16 jest nieprawidłowe). Bez
bitfield
, te informacje są przekazywane tylko w ramach dokumentacji. W
VTS może natomiast sprawdzić, czy wartość flag jest rozbita na bity LUB flagę.
Uchwyty typów podstawowych
OSTRZEŻENIE: wszelkiego rodzaju adresy (nawet fizyczne adresów urządzeń) nigdy nie mogą być częścią natywnego nicka. Zaliczono informacje między procesami są niebezpieczne i narażają je na atak. Wszelkie wartości przekazywane między procesami muszą zostać zweryfikowane, zanim zostaną użyte do ich użycia sprawdzać przydzieloną pamięć w ramach procesu. W przeciwnym razie nieprawidłowe nicki mogą powodować dostępu do pamięci lub jej uszkodzenia.
Semantyka HIDL to kopiowanie według wartości, co oznacza, że parametry są kopiowane.
Wszelkie duże porcje danych lub dane, które muszą być współdzielone przez procesy.
(takich jak ogrodzenie synchronizacji) są obsługiwane przez deskryptory plików wskazujące
do obiektów trwałych: ashmem
w przypadku pamięci współdzielonej, rzeczywistych plików lub
wszystko, co można ukryć za deskryptorem pliku. Sterownik
duplikuje deskryptor pliku do drugiego procesu.
uchwyt_natywny
Android obsługuje native_handle_t
– ogólny nick
zdefiniowane w: libcutils
.
typedef struct native_handle { int version; /* sizeof(native_handle_t) */ int numFds; /* number of file-descriptors at &data[0] */ int numInts; /* number of ints at &data[numFds] */ int data[0]; /* numFds + numInts ints */ } native_handle_t;
Uchwyt natywny to zbiór int i deskryptorów plików, który jest przekazywany
wokół wartości. Deskryptor jednego pliku można przechowywać w natywnym nicku z
bez int i deskryptora pojedynczego pliku. Uchwyty przekazywania za pomocą uchwytów natywnych
umieszczony w elemencie podstawowym handle
zapewnia
uchwyty są bezpośrednio uwzględnione w HIDL.
Nie można użyć elementu native_handle_t
, ponieważ ma zmienny rozmiar
bezpośrednio w elemencie struct. Pole uchwytu generuje wskaźnik do oddzielnego
przydzielonych native_handle_t
.
We wcześniejszych wersjach Androida natywne nicki były tworzone przy użyciu tego samego
funkcje obecne w
libcutils.
W Androidzie 8.0 i nowszych funkcje te są teraz kopiowane do
Przestrzeń nazw android::hardware::hidl
lub przeniesiona do NDK. HIDL
automatycznie wygenerowany kod zserializuje i deserializuje te funkcje automatycznie,
bez udziału kodu napisanego przez użytkownika.
Nick i własność deskryptora pliku
Gdy wywołujesz metodę interfejsu HIDL, która przekazuje (lub zwraca)
hidl_handle
obiekt (najwyższego poziomu lub część typu złożonego),
własność zawartych w nim deskryptorów plików jest następująca:
- Wywołujący przekazuje obiekt
hidl_handle
jako zachowuje prawo własności do deskryptorów plików zawartych wnative_handle_t
zawija, rozmówca musi zamknąć ten plik deskryptory. - Proces zwracający
hidl_handle
(przekazując go do funkcji_cb
) zachowuje prawo własności do obiektu deskryptory plików zawarte w elemencienative_handle_t
opakowanym przez komponent obiektu; proces musi zamknąć te deskryptory plików, gdy je skończy. - Transport, do którego przypisano
hidl_handle
, ma własność deskryptorów plików w obrębienative_handle_t
opakowany przez obiekt; odbiorca może używać tych deskryptorów plików wywołanie zwrotne transakcji, ale trzeba skopiować uchwyt natywny, aby użyć pliku deskryptory poza wywołaniem zwrotnym. Transport automatycznie nawiąże połączenieclose()
dla deskryptorów plików po zakończeniu transakcji.
HIDL nie obsługuje nicków w Javie (ponieważ Java nie obsługuje nicków wszystkie).
Tablice o określonym rozmiarze
W przypadku tablic o określonych rozmiarach w strukturach HIDL ich elementy mogą mieć dowolny typ struktury mogą zawierać:
struct foo { uint32_t[3] x; // array is contained in foo };
Strings
Ciągi znaków w C++ i Javie wyglądają inaczej, ale bazowy system transportowy typ pamięci masowej jest strukturą C++. Więcej informacji: Typy danych HIDL w C++ lub Typy danych Java HIDL.
Uwaga: przekazywanie ciągu znaków do lub z Javy Interfejs HIDL (w tym Java na Java) powoduje konwersję zestawu znaków które mogą nie zachować oryginalnego kodowania.
vec<T> typ szablonu
Szablon vec<T>
reprezentuje bufor o zmiennym rozmiarze
zawierający wystąpienia T
.
T
może być jednym z tych elementów:
- Typy podstawowe (np. uint32_t)
- Strings
- Wyliczenia zdefiniowane przez użytkownika
- Jednostki struct zdefiniowane przez użytkownika
- Interfejsy lub słowo kluczowe
interface
(vec<IFoo>
,vec<interface>
są obsługiwane tylko jako parametr najwyższego poziomu) - Nicki
- pole bitowe<U>
- vec<U>, gdzie na liście znajduje się U, z wyjątkiem interfejsu (np.
vec<vec<IFoo>>
nie jest obsługiwany) - U[] (rozmiar tablicy U), gdzie U znajduje się na liście, oprócz interfejsu
Typy zdefiniowane przez użytkownika
W tej sekcji opisano typy zdefiniowane przez użytkownika.
Wyliczenie
HIDL nie obsługuje anonimowych wyliczeniowych. W przeciwnym razie wyliczenia w HIDL są podobne. do C++11:
enum name : type { enumerator , enumerator = constexpr , … }
Wyliczenie bazowe jest zdefiniowane w postaci jednego z typów liczb całkowitych w HIDL. Jeśli nie wartość jest określona dla pierwszego elementu wyliczającego wyliczenie na podstawie liczby całkowitej type, wartość domyślna to 0. Jeśli nie zostanie określona żadna wartość dla późniejszego modułu wyliczającego, domyślnie zostanie użyta poprzednia wartość plus jeden. Na przykład:
// RED == 0 // BLUE == 4 (GREEN + 1) enum Color : uint32_t { RED, GREEN = 3, BLUE }
Wyliczenie może również dziedziczyć z wcześniej zdefiniowanego wyliczenia. Jeśli żadna wartość nie jest
określony dla pierwszego wyliczającego wyliczenia podrzędnego (w tym przypadku
FullSpectrumColor
), domyślnie przyjmuje się wartość ostatniego parametru
wyliczający wyliczenie nadrzędnej plus jeden. Na przykład:
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
Ostrzeżenie: dziedziczenie wyliczenia działa wstecz z większości innych typów dziedziczenia. Wartości wyliczeniowej nie można użyć jako wartość wyliczenia nadrzędnego. Dzieje się tak, ponieważ wyliczenie podrzędne zawiera więcej wartości niż elementu nadrzędnego. Wartości wyliczenia nadrzędnej można jednak bezpiecznie używać jako wartości wyliczeniowej podrzędnej ponieważ wartości wyliczenia podrzędne są z definicji nadzbiorem wartości wyliczeniowych nadrzędnych. Pamiętaj o tym przy projektowaniu interfejsów, ponieważ oznacza to typy odnoszące się do wyliczenia nadrzędne nie mogą odnosić się do wyliczeń podrzędnych w późniejszych iteracjach argumentu za pomocą prostego interfejsu online.
Wartości wyliczenia są odwoływane za pomocą składni dwukropka (a nie w składni kropek, jak
zagnieżdżonych typów). Składnia to Type:VALUE_NAME
. Nie trzeba podawać
type, jeśli do wartości odwołuje się ten sam typ wyliczenia lub typy podrzędne. Przykład:
enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 }; enum Color : Grayscale { RED = WHITE + 1 }; enum Unrelated : uint32_t { FOO = Color:RED + 1 };
Począwszy od Androida 10 wyliczenia mają
Atrybut len
, którego można używać w wyrażeniach stałych.
MyEnum::len
to łączna liczba wpisów w tym wyliczeniu.
Ta wartość różni się od łącznej liczby wartości, która może być mniejsza,
wartości są zduplikowane.
Struktura
HIDL nie obsługuje anonimowych elementów struct. W przeciwnym razie struktura w HIDL jest bardzo podobnie jak C.
HIDL nie obsługuje struktur danych o zmiennej długości, które są w całości zawarte w
struct. Obejmuje to macierz o nieokreślonej długości, która jest czasami używana jako
ostatnie pole struktury w C/C++ (czasami wyświetlane w formacie o rozmiarze
[0]
). HIDL vec<T>
reprezentuje rozmiar dynamiczny
tablice z danymi przechowywanymi w osobnym buforze; takie instancje są reprezentowane
z wystąpieniem vec<T>
w tabeli struct
.
Podobnie pole string
może znajdować się w elemencie struct
(powiązane bufory są oddzielne). Instancje HIDL w wygenerowanym języku C++
są reprezentowane przez wskaźnik do rzeczywistego uchwytu natywnego jako
instancji typu danych bazowego mają zmienną długość.
Union
HIDL nie obsługuje sum anonimowych. W przeciwnym razie sumy są podobne do C.
Łączniki nie mogą zawierać typów poprawek (takich jak wskaźniki, deskryptory plików, spoiwo)
obiekty). Nie wymagają pól specjalnych ani powiązanych typów.
po prostu za pomocą funkcji memcpy()
lub jej odpowiednika. Związek nie musi bezpośrednio
zawierają (lub zawierają inne struktury danych) wszystko, co wymaga ustawienia
przesunięcia (tzn. uchwytów lub odwołań do interfejsu segregatora). Na przykład:
union UnionType { uint32_t a; // vec<uint32_t> r; // Error: can't contain a vec<T> uint8_t b;1 }; fun8(UnionType info); // Legal
Związki można też deklarować w elementach struct. Na przykład:
struct MyStruct { union MyUnion { uint32_t a; uint8_t b; }; // declares type but not member union MyUnion2 { uint32_t a; uint8_t b; } data; // declares type but not member }