Cette section décrit les types de données HIDL. Pour en savoir plus sur l'implémentation, consultez HIDL C++ (pour C++ implémentations) ou HIDL Java (pour les implémentations Java).
Les similitudes avec C++ sont les suivantes:
structs
utilise la syntaxe C++.unions
est compatible avec la syntaxe C++ par défaut. Les deux doivent être nommés. les structs et les unions anonymes ne sont pas pris en charge.- Les typesdefs sont autorisés en HIDL (comme en C++).
- Les commentaires de style C++ sont autorisés et sont copiés dans le fichier d'en-tête généré.
Les similitudes avec Java sont les suivantes:
- Pour chaque fichier, HIDL définit un espace de noms de style Java qui doit commencer par
android.hardware.
L'espace de noms C++ généré est::android::hardware::…
- Toutes les définitions du fichier sont contenues dans un fichier
Wrapper
interface
. - Les déclarations de tableau HIDL suivent le style Java, et non le style C++. Exemple :
struct Point { int32_t x; int32_t y; }; Point[3] triangle; // sized array
- Les commentaires sont similaires au format Javadoc.
Représentation des données
Un élément struct
ou union
composé des éléments suivants :
Mise en page standard
(un sous-ensemble des exigences des types de données standards)
mise en page dans le code C++ généré, appliquée avec des attributs d'alignement explicites
struct
et union
membres.
Types HIDL primitifs, ainsi que enum
et bitfield
(qui dérivent toujours de types primitifs), mappés aux types C++ standards
comme std::uint32_t
,
cstdint
Java n'étant pas compatible avec les types non signés, les types HIDL non signés sont mappés sur le type Java signé correspondant. Les objets Structs correspondent aux classes Java. Les tableaux sont mappés à des tableaux Java. Les unions ne sont pas acceptées actuellement en Java. Les chaînes sont stockées en interne au format UTF8. Java prend en charge uniquement des chaînes UTF16, les valeurs de chaîne envoyées vers ou depuis une implémentation Java sont traduits et peuvent être différents lors d'une nouvelle traduction, car les jeux de caractères cartographiée de manière fluide.
Les données reçues via IPC en C++ sont marquées const
et sont dans
en lecture seule qui ne persiste que pendant la durée de l'appel de fonction. Données
reçu via IPC en Java a déjà été copié dans des objets Java, il peut donc
être conservées sans copie supplémentaire (et peuvent être modifiées).
Annotations
Des annotations de style Java peuvent être ajoutées aux déclarations de type. Les annotations sont analysés par le backend de la suite de tests fournisseurs (VTS) du compilateur HIDL, mais aucune des ces annotations analysées sont réellement compréhensibles par le compilateur HIDL. À la place, les annotations VTS analysées sont gérées par le compilateur VTS (VTSC).
Les annotations utilisent la syntaxe Java: @annotation
ou
@annotation(value)
ou @annotation(id=value, id=value…)
où "valeur" peut être une expression constante, une chaîne ou une liste de valeurs
dans {}
, tout comme en Java. Plusieurs annotations du même nom
peuvent être associés au même élément.
Transférer les déclarations
Avec HIDL, les structs peuvent ne pas être déclarés avant, ce qui rend les données définies par l'utilisateur les types de données auto-références impossibles (par exemple, vous ne pouvez pas décrire une liste liée ou un arbre dans HIDL). La plupart des HAL existants (antérieures à Android 8.x) utilisent de manière limitée les déclarations avant, qui peuvent être supprimées en réorganisant la structure des données .
Cette restriction permet de copier des structures de données par valeur à l'aide d'un simple
au lieu de garder une trace des valeurs du pointeur pouvant apparaître plusieurs
dans une structure de données auto-référence. Si les mêmes données sont
transmises deux fois,
par exemple avec deux paramètres de méthode, ou vec<T>
, qui pointent vers
les mêmes données, deux copies distinctes sont faites et livrées.
Déclarations imbriquées
HIDL accepte les déclarations imbriquées à autant de niveaux que vous le souhaitez (avec un l'exception indiquée ci-dessous). Exemple :
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 } …
La seule exception est que les types d'interface ne peuvent être intégrés
vec<T>
et un seul niveau de profondeur (pas
vec<vec<IFoo>>
).
Syntaxe du pointeur brut
Le langage HIDL n'utilise pas * et n'est pas compatible avec le toute la flexibilité des pointeurs bruts C/C++. Pour plus de détails sur l’encapsulation de HIDL les pointeurs et les tableaux/vecteurs, voir vec<T> modèle.
Interfaces
Le mot clé interface
a deux utilisations.
- Elle ouvre la définition d'une interface dans un fichier .hal.
- Il peut être utilisé en tant que type spécial dans les champs struct/union, les paramètres de méthode,
et des retours. Il est considéré comme une interface générale et un synonyme de
android.hidl.base@1.0::IBase
Par exemple, IServiceManager
possède la méthode suivante:
get(string fqName, string name) generates (interface service);
La méthode promet de rechercher une interface par son nom. Il est également
identique au remplacement de l'interface par android.hidl.base@1.0::IBase
.
Les interfaces ne peuvent être transmises que de deux manières: en tant que paramètres de niveau supérieur ou en tant que
membres d'un vec<IMyInterface>
. Ils ne peuvent pas être membres
les vecteurs, structs, tableaux ou unions imbriqués.
MQDescriptorSync et MQDescriptorUnsync
Types MQDescriptorSync
et MQDescriptorUnsync
transmettre des descripteurs FMQ synchronisés ou non synchronisés
via une interface HIDL. Pour en savoir plus, consultez
HIDL C++ (les FMQ ne sont pas
compatibles avec Java).
type de mémoire
Le type memory
est utilisé pour représenter la mémoire partagée non mappée dans
HIDL. Il n'est compatible qu'avec C++. Une valeur de ce type peut être utilisée
côté récepteur pour initialiser un objet IMemory
, mappant la mémoire.
et de le rendre utilisable. Pour en savoir plus, consultez
HIDL C++
Avertissement:Données structurées placées dans des fichiers partagés
"mémoire" DOIT être un type dont le format ne change jamais pendant la durée de vie du
version d'interface en transmettant memory
. Sinon, les HAL risquent
de problèmes de compatibilité fatals.
type de pointeur
Le type pointer
est réservé à un usage interne HIDL.
champ de bits<T> modèle de type
bitfield<T>
, où T
est
énumération définie par l'utilisateur suggère que la valeur est un opérateur OU au niveau du bit de la
Valeurs d'énumération définies dans T
. Dans le code généré,
bitfield<T>
apparaît comme le type sous-jacent de T. Exemple :
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);
Le compilateur gère les options de type de la même manière que uint8_t
.
Pourquoi ne pas utiliser
(u)int8_t
/(u)int16_t
/(u)int32_t
/(u)int64_t
?
L'utilisation de bitfield
fournit des informations HAL supplémentaires au lecteur,
qui sait maintenant que setFlags
accepte une valeur OR (OU) bit à bit de cet élément (c'est-à-dire
sait que l'appel de setFlags
avec 16 n'est pas valide). Sans
bitfield
, ces informations ne sont transmises que via la documentation. Dans
En outre, le VTS peut vérifier si la valeur des indicateurs est un OR au niveau du bit de l'indicateur.
Poignées de type primitif
AVERTISSEMENT:Toute adresse (même physique, quelle qu'elle soit) adresses de l'appareil) ne doit jamais faire partie d'un identifiant natif. Transmission à les informations entre les processus est dangereux et les rend vulnérables aux attaques. Toutes les valeurs transmises entre les processus doivent être validées avant d'être utilisées pour rechercher la mémoire allouée dans un processus. Sinon, des poignées de mauvaise qualité un accès à la mémoire ou une corruption de la mémoire.
La sémantique HIDL est une copie par valeur, ce qui implique que les paramètres sont copiés.
Toute grande quantité de données ou données qui doivent être partagées entre les processus
(par exemple, une barrière de synchronisation), sont gérés en transmettant les descripteurs de fichier
aux objets persistants: ashmem
pour la mémoire partagée, des fichiers réels ou
tout autre élément pouvant se cacher
derrière un descripteur de fichier. Le lecteur de liaison
duplique le descripteur de fichier
dans l'autre processus.
poignée_native
Android est compatible avec native_handle_t
, un concept d'identifiant général
défini dans 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;
Un handle natif est un ensemble
d'ents et de descripteurs de fichier transmis
en fonction de leur valeur. Un seul descripteur de fichier peut être stocké
dans un handle natif avec
sans entier et un seul
descripteur de fichier. Transmettre des identifiants à l'aide d'identifiants natifs
encapsulé avec le type primitif handle
garantit que le trafic natif
les poignées sont
directement inclus dans HIDL.
Comme native_handle_t
a une taille variable, il ne peut pas être inclus
directement dans un struct. Un champ de handle génère un pointeur vers un élément
a alloué native_handle_t
.
Dans les versions antérieures d'Android, les identifiants natifs étaient créés à l'aide de la même
fonctions présentes dans
libcutils
Dans Android 8.0 et versions ultérieures, ces fonctions sont désormais copiées dans le
Espace de noms android::hardware::hidl
ou déplacé vers le NDK. HIDL
le code généré automatiquement sérialise et désérialise ces fonctions automatiquement,
sans impliquer le code écrit par l'utilisateur.
Gérer la propriété des descripteurs de fichiers
Lorsque vous appelez une méthode d'interface HIDL qui transmet (ou renvoie) un
Un objet hidl_handle
(niveau supérieur ou faisant partie d'un type composé)
la propriété des descripteurs de fichier qu'il contient est la suivante:
- L'appelant transmettant un objet
hidl_handle
en tant que conserve la propriété des descripteurs de fichier contenus dansnative_handle_t
il encapsule. l'appelant doit fermer ce fichier quand vous en avez fini avec eux. - Le processus renvoyant un
hidl_handle
(en le transmettant dans une fonction_cb
) conserve la propriété du descripteurs de fichier contenus dans lenative_handle_t
encapsulés par object; le processus doit fermer ces descripteurs de fichier une fois qu'il en a terminé avec eux. - Un transport qui reçoit une
hidl_handle
possède propriété des descripteurs de fichier dansnative_handle_t
encapsulés par l'objet. le récepteur peut utiliser ces descripteurs de fichier tels quels le rappel de transaction, mais vous devez cloner le handle natif pour utiliser le fichier au-delà du rappel. Le transport appelle automatiquementclose()
pour les descripteurs de fichier lorsque la transaction est terminée.
HIDL ne prend pas en charge les poignées en Java (car Java n'est pas compatible avec les handle au niveau toutes).
Tableaux dimensionnés
Pour les tableaux dimensionnés dans les structs HIDL, leurs éléments peuvent être de n'importe quel type Peut contenir:
struct foo { uint32_t[3] x; // array is contained in foo };
Strings
Les chaînes apparaissent différemment en C++ et en Java, mais le transport sous-jacent est une structure C++. Pour en savoir plus, consultez Types de données C++ HIDL ou Types de données Java HIDL.
Remarque:La transmission d'une chaîne vers ou depuis Java via un L'interface HIDL (y compris Java vers Java) génère des conversions de jeux de caractères. qui peut ne pas conserver l'encodage d'origine.
vec<T> modèle de type
Le modèle vec<T>
représente un tampon de taille variable
contenant des instances de T
.
T
peut être:
- Types primitifs (par exemple, uint32_t)
- Strings
- Énumérations définies par l'utilisateur
- Structures définies par l'utilisateur
- Interfaces, ou mot clé
interface
(vec<IFoo>
etvec<interface>
sont acceptés) uniquement en tant que paramètre de niveau supérieur) - Identifiants
- champ de bits<U>
- vec<U>, où U figure dans cette liste, sauf pour l'interface (par exemple,
vec<vec<IFoo>>
n'est pas accepté) - U[] (tableau dimensionné de U), où U figure dans cette liste, à l'exception de l'interface
Types définis par l'utilisateur
Cette section décrit les types définis par l'utilisateur.
Énumération
HIDL n'est pas compatible avec les énumérations anonymes. Sinon, les énumérations dans HIDL sont similaires vers C++11:
enum name : type { enumerator , enumerator = constexpr , … }
Une énumération de base est définie en fonction de l'un des types d'entiers dans HIDL. Si non valeur est spécifiée pour le premier énumérateur d'une énumération basée sur un entier la valeur par défaut est 0. Si aucune valeur n'est spécifiée pour un énumérateur ultérieur, la valeur par défaut est la valeur précédente, plus un. Exemple :
// RED == 0 // BLUE == 4 (GREEN + 1) enum Color : uint32_t { RED, GREEN = 3, BLUE }
Une énumération peut également hériter d'une énumération déjà définie. Si aucune valeur n'est
spécifié pour le premier énumérateur d'une énumération enfant (dans ce cas,
FullSpectrumColor
), la valeur par défaut du dernier
énumérateur de l'énumération parente plus un. Exemple :
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
Avertissement:L'héritage des énumérations fonctionne dans l'ordre inverse. de la plupart des autres types d'héritage. Vous ne pouvez pas utiliser de valeur d'énumération enfant valeur d'énumération parent. En effet, une énumération enfant inclut plus de valeurs que parent. Cependant, une valeur d'énumération parente peut être utilisée en toute sécurité comme valeur d'énumération enfant. car les valeurs d'énumération enfants sont, par définition, un sur-ensemble de valeurs d'énumération parentes. Gardez cela à l'esprit lors de la conception d'interfaces, car cela signifie que les types faisant référence à les énumérations parentes ne peuvent pas faire référence aux énumérations enfants dans les itérations ultérieures de votre de commande.
Les valeurs des énumérations sont appelées par la syntaxe deux-points (et non par la syntaxe à point,
types imbriqués). La syntaxe est Type:VALUE_NAME
. Pas besoin de préciser
type si la valeur est référencée dans le même type d'énumération ou les mêmes types enfants. Exemple :
enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 }; enum Color : Grayscale { RED = WHITE + 1 }; enum Unrelated : uint32_t { FOO = Color:RED + 1 };
À partir d'Android 10, les énumérations ont un
Attribut len
pouvant être utilisé dans des expressions constantes.
MyEnum::len
est le nombre total d'entrées dans cette énumération.
Ce nombre est différent du nombre total de valeurs, qui peut être inférieur lorsque
sont en double.
Structure
HIDL n'est pas compatible avec les structs anonymes. Sinon, les structs en HIDL sont très semblable à C.
HIDL n'est pas compatible avec les structures de données de longueur variable contenues entièrement dans
un struct. Cela inclut le tableau de longueur
indéfinie qui est parfois utilisé comme
le dernier champ d'un struct en C/C++ (parfois vu avec une taille de
[0]
). HIDL vec<T>
représente la taille dynamique
des tableaux avec les données stockées dans un tampon distinct ; ces instances sont représentées
par une instance de vec<T>
dans struct
.
De même, string
peut être contenu dans un struct
.
(les tampons associés sont distincts). Dans le C++ généré, les instances de HIDL
type de handle sont représentés via un pointeur vers le handle natif réel en tant que
les instances du type de données sous-jacent ont une longueur variable.
Union
HIDL n'est pas compatible avec les unions anonymes. Sinon, les unions sont semblables à C.
Les unions ne peuvent pas contenir de types de correction (tels que des pointeurs, des descripteurs de fichier, des liaisons
des objets). Ils n'ont pas besoin de champs spéciaux
ni de types associés et sont
est simplement copié à l'aide de memcpy()
ou équivalent. Il se peut qu'une union ne soit pas
contiennent (ou contiennent à l'aide d'autres structures de données) tout ce qui nécessite de définir
Décalages de liaison (c'est-à-dire les références de poignée ou d'interface de liaison). Exemple :
union UnionType { uint32_t a; // vec<uint32_t> r; // Error: can't contain a vec<T> uint8_t b;1 }; fun8(UnionType info); // Legal
Les unions peuvent également être déclarées à l'intérieur des objets STRUCT. Exemple :
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 }