Les déclarations de données HIDL génèrent des structures de données de mise en page standard C++. Ces les structures peuvent être placées n’importe où qui vous semble naturel (sur la pile, dans un fichier ou un champ d'application global ou sur le tas de mémoire) et peuvent être composés de la même manière. Client le code appelle le code proxy HIDL en transmettant des références const et des types primitifs, tandis que le bouchon et le code de proxy masquent les détails de la sérialisation.
Remarque:Le code n'est jamais écrit par le développeur. nécessaires pour sérialiser ou désérialiser explicitement les structures de données.
Le tableau ci-dessous met en correspondance les primitives HIDL et les types de données C++:
Type HIDL | Type C++ | En-tête/Bibliothèque |
---|---|---|
enum |
enum class |
|
uint8_t..uint64_t |
uint8_t..uint64_t |
<stdint.h> |
int8_t..int64_t |
int8_t..int64_t |
<stdint.h> |
float |
float |
|
double |
double |
|
vec<T> |
hidl_vec<T> |
libhidlbase |
T[S1][S2]...[SN] |
T[S1][S2]...[SN] |
|
string |
hidl_string |
libhidlbase |
handle |
hidl_handle |
libhidlbase |
safe_union |
(custom) struct |
|
struct |
struct |
|
union |
union |
|
fmq_sync |
MQDescriptorSync |
libhidlbase |
fmq_unsync |
MQDescriptorUnsync |
libhidlbase |
Les sections ci-dessous décrivent les types de données plus en détail.
enum
Une énumération dans HIDL devient une énumération en C++. Par exemple:
enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 }; enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };
... devient:
enum class Mode : uint8_t { WRITE = 1, READ = 2 }; enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };
À partir d'Android 10, une énumération peut être itérée.
que d'utiliser ::android::hardware::hidl_enum_range
. Cette plage
inclut chaque énumérateur dans l'ordre dans lequel il apparaît dans le code source HIDL, en commençant
de l'énumération parent
jusqu'au dernier enfant. Par exemple, ce code itère
sur WRITE
, READ
, NONE
et
COMPARE
dans cet ordre. Donnée SpecialMode
ci-dessus:
template <typename T> using hidl_enum_range = ::android::hardware::hidl_enum_range<T> for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}
hidl_enum_range
implémente également des itérateurs inversés et peut être
utilisé dans les contextes constexpr
. Si une valeur apparaît dans une énumération
plusieurs fois, la valeur apparaît plusieurs fois dans la plage.
champ de bits<T>
bitfield<T>
(où T
est une énumération définie par l'utilisateur)
devient le type sous-jacent de cette énumération en C++. Dans l'exemple ci-dessus,
bitfield<Mode>
devient uint8_t
.
vec<T>
Le modèle de classe hidl_vec<T>
fait partie de
libhidlbase
et permet de transmettre un vecteur de n'importe quel type HIDL avec
une taille arbitraire. Le conteneur de taille fixe comparable
hidl_array
Un hidl_vec<T>
peut également être
initialisé pour pointer vers un tampon de données externe de type T
, en utilisant
la fonction hidl_vec::setToExternal()
.
En plus d'émettre/d'insérer le struct de manière appropriée dans le
en-tête C++, l'utilisation de vec<T>
est pratique
Fonctions de traduction vers/depuis std::vector
et T
simple
ces pointeurs. Si vec<T>
est utilisé en tant que paramètre, la fonction
son utilisation est surchargée (deux prototypes
sont générés) pour accepter et
transmettez à la fois le struct HIDL et un type std::vector<T>
pour cette
.
tableau
Les tableaux constants dans Hidl sont représentés par la classe hidl_array
dans libhidlbase
. Un élément hidl_array<T, S1, S2, …,
SN>
représente un tableau de taille fixe à N dimensions
T[S1][S2]…[SN]
string
La classe hidl_string
(partie de libhidlbase
) peut être
utilisé pour transmettre des chaînes via des interfaces HIDL et est défini dans
/system/libhidl/base/include/hidl/HidlSupport.h
Le premier espace de stockage
"location" dans la classe pointe vers son tampon de caractères.
hidl_string
sait comment effectuer une conversion vers et depuis
std::string and char*
(chaîne de style C) avec
operator=
, conversions implicites et fonction .c_str()
.
Les structures de chaîne HIDL ont les constructeurs de copie appropriés et l'affectation
pour:
- Chargez la chaîne HIDL à partir d'une chaîne
std::string
ou C. - Créez un
std::string
à partir d'une chaîne HIDL.
De plus, les chaînes HIDL ont des constructeurs de conversion, de sorte que les chaînes C
(char *
) et des chaînes C++ (std::string
) peuvent être utilisées sur
qui acceptent une chaîne HIDL.
structure
Un struct
en HIDL ne peut contenir que des types de données de taille fixe et aucun
fonctions. Les définitions de structure HIDL sont mappées directement à la mise en page standard
les struct
en C++, ce qui garantit que les struct
ont un
une mise en page cohérente
de la mémoire. Un struct peut inclure des types HIDL, y compris
handle
, string
et vec<T>
, qui
pour séparer des tampons de longueur variable.
poignée
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 au cours d'un processus. Sinon, des poignées de mauvaise qualité peuvent un accès à la mémoire ou une corruption de la mémoire.
Le type handle
est représenté par l'élément hidl_handle
en C++, qui est un simple wrapper autour d'un pointeur vers
Objet const native_handle_t
(présent sur Android depuis
depuis longtemps).
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;
Par défaut, hidl_handle
n'est pas propriétaire
du pointeur native_handle_t
qu'il encapsule. Il sert simplement à
stocker un pointeur vers un élément native_handle_t
de sorte qu'il puisse être utilisé dans
les processus 32 et 64 bits.
Scénarios dans lesquels hidl_handle
est propriétaire du fichier inclus
descripteurs incluent:
- Après un appel à la méthode
setTo(native_handle_t* handle, bool shouldOwn)
avec le paramètreshouldOwn
défini surtrue
- Lorsque l'objet
hidl_handle
est créé par construction d'une copie à partir d'un autre objethidl_handle
- Lorsque l'objet
hidl_handle
est copié à partir d'un autrehidl_handle
objet
hidl_handle
fournit des conversions implicites et explicites
vers/depuis des objets native_handle_t*
. La principale fonction
Le type handle
en HIDL est de transmettre les descripteurs de fichier via HIDL
de commande. Un seul descripteur de fichier est donc représenté par un
native_handle_t
sans int
s et un seul
fd
Si le client et le serveur vivent dans un processus différent, la méthode RPC
s'occupe automatiquement du descripteur de fichier pour garantir
les deux processus peuvent
fonctionner sur le même fichier.
Même si un descripteur de fichier reçu dans un hidl_handle
par un
processus est valide dans ce processus, il ne persiste pas au-delà de la réception
(elle est fermée lorsque la fonction est renvoyée). Un processus
qui veut
conserver un accès persistant au descripteur de fichier doit dup()
descripteurs de fichier inclus, ou copiez l'intégralité de l'objet hidl_handle
.
mémoire
Le type memory
HIDL est mappé à la classe hidl_memory
.
dans libhidlbase
, qui représente la mémoire partagée non mappée. C'est
l'objet qui doit être transmis entre les processus
pour partager la mémoire en HIDL. À
utiliser la mémoire partagée:
- Récupérez une instance de
IAllocator
(actuellement, seule l'instance "ashmem" est disponible) et utilisez-la pour allouer de la mémoire partagée. IAllocator::allocate()
renvoie unhidl_memory
. objet pouvant être transmis via HIDL RPC et être mappé dans un processus à l'aide de la fonctionmapMemory
delibhidlmemory
.mapMemory
renvoie une référence à un Objetsp<IMemory>
permettant d'accéder à la mémoire. (IMemory
etIAllocator
sont définis dansandroid.hidl.memory@1.0
).
Une instance de IAllocator
peut être utilisée pour allouer de la mémoire:
#include <android/hidl/allocator/1.0/IAllocator.h> #include <android/hidl/memory/1.0/IMemory.h> #include <hidlmemory/mapping.h> using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hardware::hidl_memory; .... sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem"); ashmemAllocator->allocate(2048, [&](bool success, const hidl_memory& mem) { if (!success) { /* error */ } // now you can use the hidl_memory object 'mem' or pass it around }));
Les modifications réelles apportées à la mémoire doivent être effectuées via un IMemory
soit du côté qui a créé mem
, soit du côté qui
le reçoit via HIDL RPC.
// Same includes as above sp<IMemory> memory = mapMemory(mem); void* data = memory->getPointer(); memory->update(); // update memory however you wish after calling update and before calling commit data[0] = 42; memory->commit(); // … memory->update(); // the same memory can be updated multiple times // … memory->commit();
interface
Les interfaces peuvent être transmises en tant qu'objets. Le mot interface peut être utilisé
en tant que sucre syntaxique pour le type android.hidl.base@1.0::IBase
;
En outre, l'interface actuelle et toutes les interfaces importées sont définies
en tant que type.
Les variables contenant des interfaces doivent constituer des pointeurs forts:
sp<IName>
Fonctions HIDL qui acceptent des paramètres d'interface
convertir les pointeurs bruts en pointeurs forts, ce qui entraîne un comportement non intuitif
(le pointeur peut être effacé de manière inattendue). Pour éviter les problèmes, stockez toujours HIDL
interfaces en tant que sp<>
.