Le dichiarazioni dei dati HIDL generano strutture di dati con layout standard C++. Questi di sistema possono essere posizionate in qualsiasi punto ti sembri naturale (sulla pila, su un file in un ambito globale o sull'heap) e possono essere create nello stesso modo. Cliente chiama codice proxy HIDL che passa in riferimenti const e tipi primitivi, mentre il codice stub e proxy nasconde i dettagli della serializzazione.
Nota: in nessun momento viene creato codice scritto dallo sviluppatore. necessari per serializzare o deserializzare in modo esplicito le strutture di dati.
La tabella seguente mappa le primitive HIDL ai tipi di dati C++:
Tipo HIDL | Tipo C++ | Intestazione/libreria |
---|---|---|
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 |
Le sezioni seguenti descrivono in maggiore dettaglio i tipi di dati.
enum
Un'enumerazione in HIDL diventa enum in C++. Ad esempio:
enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 }; enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };
... diventa:
enum class Mode : uint8_t { WRITE = 1, READ = 2 }; enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };
A partire da Android 10, è possibile ripetere un'enumerazione
rispetto all'uso di ::android::hardware::hidl_enum_range
. Questo intervallo
include ogni enumeratore nell'ordine in cui appare nel codice sorgente HIDL, a partire da
dall'enumerazione padre all'ultimo figlio. Ad esempio, questo codice esegue l'iterazione
più di WRITE
, READ
, NONE
e
COMPARE
in quell'ordine. Dati di SpecialMode
sopra:
template <typename T> using hidl_enum_range = ::android::hardware::hidl_enum_range<T> for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}
hidl_enum_range
implementa anche iteratori inversi e può essere
utilizzata in constexpr
contesti. Se un valore appare in un'enumerazione
più volte, il valore appare nell'intervallo più volte.
bitfield<T>
bitfield<T>
(dove T
è un enum definito dall'utente)
diventa il tipo sottostante di quell'enumerazione in C++. Nell'esempio precedente,
bitfield<Mode>
diventa uint8_t
.
vec<T>
Il modello del corso hidl_vec<T>
fa parte di
libhidlbase
e può essere utilizzato per passare un vettore di qualsiasi tipo HIDL con
una dimensione arbitraria. Il container comparabile a dimensione fissa
hidl_array
. Un hidl_vec<T>
può anche essere
inizializzato in modo da puntare a un buffer di dati esterno di tipo T
, utilizzando
la funzione hidl_vec::setToExternal()
.
Oltre a emettere/inserire correttamente lo struct nel codice
Intestazione C++, l'uso di vec<T>
genera una certa praticità
funzioni per la traduzione da/verso std::vector
e T
semplice
i cursori. Se vec<T>
viene utilizzato come parametro, la funzione
il suo utilizzo è sovraccarico (vengono generati due prototipi) per accettare e
passare sia lo struct HIDL sia un tipo std::vector<T>
per quello
.
array
Gli array costanti in hidl sono rappresentati dalla classe hidl_array
nel mese di libhidlbase
. Un hidl_array<T, S1, S2, …,
SN>
rappresenta un array di dimensioni fisse N dimensionale
T[S1][S2]…[SN]
.
string
La classe hidl_string
(parte di libhidlbase
) può essere
utilizzato per passare stringhe su interfacce HIDL ed è definito in
/system/libhidl/base/include/hidl/HidlSupport.h
. Il primo spazio di archiviazione
nella classe è un puntatore al suo buffer di caratteri.
hidl_string
sa come effettuare conversioni da e verso
std::string and char*
(stringa di tipo C) utilizzando
operator=
, trasmissioni implicite e funzione .c_str()
.
Gli struct stringa HIDL hanno i costruttori e le assegnazioni di copia appropriati
operatori per:
- Carica la stringa HIDL da una stringa
std::string
o C. - Crea un nuovo
std::string
da una stringa HIDL.
Inoltre, le stringhe HIDL hanno costruttori di conversione, quindi le stringhe C.
(char *
) e le stringhe C++ (std::string
) possono essere utilizzate
che accettano una stringa HIDL.
struct
Un elemento struct
in HIDL può contenere solo tipi di dati a dimensione fissa e nessun tipo
funzioni. Le definizioni degli struct HIDL vengono mappate direttamente al layout standard
struct
in C++, per fare in modo che struct
abbia un
un layout di memoria coerente. Uno struct può includere tipi HIDL, inclusi
handle
, string
e vec<T>
, che
punto per separare i buffer a lunghezza variabile.
handle
ATTENZIONE: indirizzi di qualsiasi tipo (anche fisico) indirizzi del dispositivo) non devono mai far parte di un handle nativo. Superato le informazioni tra i processi sono pericolose e suscettibili di attacchi. Tutti i valori passati tra i processi devono essere convalidati prima di essere utilizzati per cercare memoria allocata all'interno di un processo. In caso contrario, gli handle non validi possono causare errori l'accesso alla memoria o il danneggiamento della memoria.
Il tipo handle
è rappresentato dal valore hidl_handle
struttura in C++, che è un semplice wrapper attorno a un puntatore a
const native_handle_t
oggetto (disponibile in Android per
molto tempo).
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;
Per impostazione predefinita, hidl_handle
non acquisisce la proprietà
del puntatore native_handle_t
che avvolge. Esiste solo per proteggere
un puntatore a native_handle_t
in modo che possa essere utilizzato
sia a 32 che a 64 bit.
Scenari in cui hidl_handle
possiede il file incluso
i descrittori includono:
- A seguito di una chiamata al metodo
setTo(native_handle_t* handle, bool shouldOwn)
con il parametroshouldOwn
impostato sutrue
- Quando l'oggetto
hidl_handle
viene creato con una copia da un altro oggettohidl_handle
- Quando l'oggetto
hidl_handle
viene copiato da un altro oggettohidl_handle
oggetto
hidl_handle
fornisce conversioni sia implicite che esplicite
da/verso native_handle_t*
oggetti. L'utilizzo principale
Il tipo handle
in HIDL prevede il trasferimento dei descrittori dei file tramite HIDL
interfacce. Un descrittore di file singolo è quindi rappresentato da un
native_handle_t
senza int
e un singolo
fd
. Se il client e il server risiedono in un processo diverso, l'RPC
l'implementazione si occupa automaticamente del descrittore del file per garantire
entrambi i processi possono operare sullo stesso file.
Anche se un descrittore di file ricevuto in un elemento hidl_handle
da un
processo è valido durante questo processo, non persiste oltre il destinatario
(è chiusa quando restituisce la funzione). Un processo che vuole
mantenga l'accesso permanente al descrittore del file deve dup()
descrittori di file racchiusi o copia l'intero oggetto hidl_handle
.
ricordo
Il tipo HIDL memory
viene mappato alla classe hidl_memory
in libhidlbase
, che rappresenta la memoria condivisa non mappata. Questo è
l'oggetto che deve essere passato tra i processi per condividere la memoria in HIDL. A
usa memoria condivisa:
- Ottieni un'istanza di
IAllocator
(al momento solo l'istanza "ashmem" è disponibile) e utilizzarla per allocare la memoria condivisa. IAllocator::allocate()
restituisce unhidl_memory
che può essere passato attraverso HIDL RPC e mappato in un processo utilizzando FunzionemapMemory
dilibhidlmemory
.mapMemory
restituisce un riferimento a un Oggettosp<IMemory>
che può essere utilizzato per accedere alla memoria. (IMemory
eIAllocator
sono definiti inandroid.hidl.memory@1.0
.
È possibile utilizzare un'istanza di IAllocator
per allocare la memoria:
#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 }));
Le modifiche effettive alla memoria devono essere apportate tramite un IMemory
sia sul lato che ha creato mem
sia sul lato
la riceve tramite 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();
interfaccia
Le interfacce possono essere passate come oggetti. Si può usare la parola interface
come zucchero sintattico per il tipo android.hidl.base@1.0::IBase
;
Inoltre, vengono definite l'interfaccia corrente e le eventuali interfacce importate
come tipo.
Le variabili che contengono le interfacce dovrebbero essere puntatori efficaci:
sp<IName>
. Funzioni HIDL che accettano i parametri dell'interfaccia
convertire i puntatori non elaborati in puntatori forti, con un comportamento non intuitivo
(il puntatore può essere cancellato in modo imprevisto). Per evitare problemi, memorizza sempre i dati HIDL
si interfaccia come sp<>
.