Las declaraciones de datos HIDL generan estructuras de datos de diseño estándar C++. Estos Las estructuras se pueden colocar en cualquier lugar que se sienta natural (en la pila, en el archivo o alcance global o en el montón) y se pueden componer de la misma manera. Cliente el código llama al código proxy HIDL pasando referencias constantes y tipos primitivos, mientras que el código stub y proxy oculta los detalles de la serialización.
Nota: En ningún momento se encuentra código escrito por el desarrollador. necesarias para serializar o deserializar explícitamente las estructuras de datos.
En la siguiente tabla, se asignan primitivas de HIDL a tipos de datos C++:
Tipo de HIDL | Tipo de C++ | Encabezado/biblioteca |
---|---|---|
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 |
En las siguientes secciones, se describen los tipos de datos en más detalle.
enum
Una enumeración en HIDL se convierte en una enumeración en C++. Por ejemplo:
enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 }; enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };
... se convierte en:
enum class Mode : uint8_t { WRITE = 1, READ = 2 }; enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };
A partir de Android 10, se puede iterar una enumeración
por encima del uso de ::android::hardware::hidl_enum_range
. Este rango
incluye a cada enumerador en el orden en que aparece en el código fuente HIDL, a partir de
desde la enumeración principal hasta la secundaria. Por ejemplo, este código itera
sobre WRITE
, READ
, NONE
y
COMPARE
en ese orden. Dado SpecialMode
anterior:
template <typename T> using hidl_enum_range = ::android::hardware::hidl_enum_range<T> for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}
hidl_enum_range
también implementa iteradores inversos y puede
usado en contextos constexpr
. Si aparece un valor en una enumeración
varias veces, el valor aparece en el rango varias veces.
campo de bits<T>
bitfield<T>
(donde T
es una enumeración definida por el usuario)
se convierte en el tipo subyacente de esa enumeración en C++. En el ejemplo anterior,
bitfield<Mode>
se convierte en uint8_t
.
VEC<T>
La plantilla de la clase hidl_vec<T>
forma parte de
libhidlbase
y se puede usar para pasar un vector de cualquier tipo HIDL con
un tamaño arbitrario. El contenedor de tamaño fijo comparable
hidl_array
. Un hidl_vec<T>
también puede ser
inicializada para apuntar a un búfer de datos externo de tipo T
, con
la función hidl_vec::setToExternal()
.
Además de emitir o insertar el struct de forma adecuada en los
encabezado C++, el uso de vec<T>
genera algunos beneficios.
funciones para traducir desde y hacia std::vector
y T
vacío
de seguridad. Si se usa vec<T>
como parámetro, la función
está sobrecargado (se generan dos prototipos) para aceptar y
pasar el struct HIDL y un tipo std::vector<T>
para eso
parámetro.
matriz
Los arrays constantes en hidl se representan con la clase hidl_array
en libhidlbase
. Una hidl_array<T, S1, S2, …,
SN>
representa un array de tamaño fijo de N dimensiones.
T[S1][S2]…[SN]
string
La clase hidl_string
(parte de libhidlbase
) puede ser
que se usa para pasar cadenas a través de interfaces HIDL y se define en
/system/libhidl/base/include/hidl/HidlSupport.h
El primer almacenamiento
la ubicación en la clase es un puntero a su búfer de caracteres.
hidl_string
sabe cómo convertir y viceversa.
std::string and char*
(cadena de estilo C) con
operator=
, conversiones implícitas y función .c_str()
.
Las estructuras de cadena de HIDL tienen los constructores de copia y la asignación adecuados
operadores para lo siguiente:
- Carga la cadena HIDL desde una cadena
std::string
o C. - Crea un
std::string
nuevo a partir de una cadena HIDL.
Además, las cadenas HIDL tienen constructores de conversión, por lo que las cadenas C
(char *
) y las cadenas C++ (std::string
) se pueden usar en
que toman una cadena HIDL.
estructura
Una struct
en HIDL solo puede contener tipos de datos de tamaño fijo y no
funciones. Las definiciones de la estructura HIDL se asignan directamente al diseño estándar
struct
en C++, lo que garantiza que los struct
tengan un
un diseño de memoria coherente. Una struct puede incluir tipos de HIDL, como
handle
, string
y vec<T>
, que
apuntan a búferes de longitud variable separados.
identificador
ADVERTENCIA: Direcciones de cualquier tipo (incluso físicas del dispositivo) nunca deben ser parte de un identificador nativo. Pasando por alto esto información entre procesos es peligrosa y los hace susceptibles de sufrir ataques. Todos los valores que se pasen entre procesos se deben validar antes de usarlos para buscar la memoria asignada dentro de un proceso. De lo contrario, los identificadores incorrectos pueden causar el acceso a la memoria o los daños en la memoria.
El tipo handle
se representa con hidl_handle
.
en C++, que es un wrapper sencillo alrededor de un puntero hacia una
const native_handle_t
(esto está presente en Android durante
mucho tiempo).
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;
De forma predeterminada, hidl_handle
no asume la propiedad.
del puntero native_handle_t
que une. Simplemente existe para proteger
almacenar un puntero para un elemento native_handle_t
, de modo que pueda usarse en
en procesos de 32 y 64 bits.
Situaciones en las que hidl_handle
posee su archivo adjunto
los descriptores incluyen:
- Luego de una llamada al método
setTo(native_handle_t* handle, bool shouldOwn)
con el parámetroshouldOwn
configurado comotrue
- Cuando se crea el objeto
hidl_handle
mediante construcción de copia de otro objetohidl_handle
- Cuando el objeto
hidl_handle
se asigna por copia desde otrohidl_handle
objeto
hidl_handle
proporciona conversiones implícitas y explícitas
desde y hacia native_handle_t*
objetos. El uso principal del
El tipo handle
en HIDL consiste en pasar los descriptores de archivos a través del HIDL
interfaces. Por lo tanto, un solo descriptor de archivo está representado por un
native_handle_t
sin int
y un solo
fd
Si el cliente y el servidor se encuentran en un proceso diferente, la RPC
implementación se encarga automáticamente del descriptor de archivo para garantizar
ambos procesos pueden operar en el mismo archivo.
Aunque un descriptor de archivos recibido en un hidl_handle
por un
proceso es válido en ese proceso, no persiste más allá de la recepción
(se cierra cuando la función muestra un resultado). Un proceso en el que se intenta
retener el acceso persistente al descriptor de archivo debe dup()
el
descriptores de archivos delimitados o copiar el objeto hidl_handle
completo.
memoria
El tipo memory
de HIDL se asigna a la clase hidl_memory
en libhidlbase
, que representa la memoria compartida sin asignar. Este es
el objeto que se debe pasar entre procesos para compartir memoria en HIDL. Para
usar memoria compartida:
- Obtén una instancia de
IAllocator
(por el momento, la única instancia “ashmem” está disponible) y lo usa para asignar memoria compartida. IAllocator::allocate()
muestra unhidl_memory
. que se puede pasar a través de la RPC de HIDL y asignarse a un proceso mediante FunciónmapMemory
delibhidlmemory
.mapMemory
devuelve una referencia a un Es el objetosp<IMemory>
que se puede usar para acceder a la memoria. (IMemory
yIAllocator
se definen enandroid.hidl.memory@1.0
).
Se puede usar una instancia de IAllocator
para asignar 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 }));
Los cambios reales en la memoria deben realizarse mediante un IMemory
.
objeto, ya sea en el lado que creó mem
o en el lado que
los recibe a través de RPC HIDL.
// 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();
interfaz
Las interfaces se pueden pasar como objetos. Puedes usar la palabra interfaz.
como sintaxis edulcorada para el tipo android.hidl.base@1.0::IBase
;
además, se definen la interfaz actual y cualquier interfaz importada
como un tipo.
Las variables que contienen interfaces deben ser punteros fuertes:
sp<IName>
. Funciones HIDL que toman parámetros de interfaz
Convierten punteros sin procesar en punteros fuertes, lo que provoca un comportamiento no intuitivo
(el puntero se puede borrar de forma inesperada). Para evitar problemas, almacena siempre el HIDL
interfaces como un sp<>
.