As declarações de dados HIDL geram estruturas de dados no layout padrão do C++. Esses estruturas podem ser colocadas em qualquer lugar que pareça natural (na pilha, no arquivo ou escopo global ou na heap) e podem ser compostas da mesma maneira. Cliente chama o código de proxy HIDL passando em referências de constantes e tipos primitivos, enquanto o stub e o código proxy ocultam os detalhes da serialização.
Observação:em nenhum momento código escrito pelo desenvolvedor para serializar ou desserializar explicitamente as estruturas de dados.
A tabela abaixo mapeia primitivos HIDL para tipos de dados C++:
Tipo de HIDL | Tipo C++ | Cabeçalho/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 |
As seções abaixo descrevem os tipos de dados em mais detalhes.
enum
Um tipo enumerado no HIDL se torna um tipo enumerado em C++. Por exemplo:
enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 }; enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };
... passa a ser:
enum class Mode : uint8_t { WRITE = 1, READ = 2 }; enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };
No Android 10 e versões mais recentes, um tipo enumerado pode ser iterado.
acima do uso de ::android::hardware::hidl_enum_range
. Esta faixa
inclui cada enumerador na ordem em que aparece no código-fonte de HIDL, começando
desde o tipo enumerado pai até o último filho. Por exemplo, esse código itera
mais de WRITE
, READ
, NONE
e
COMPARE
nessa ordem. SpecialMode
informado acima:
template <typename T> using hidl_enum_range = ::android::hardware::hidl_enum_range<T> for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}
hidl_enum_range
também implementa iteradores reversos e pode ser
usada em contextos constexpr
. Se um valor aparecer em uma enumeração
várias vezes, o valor aparece no intervalo diversas vezes.
bitfield<T>
bitfield<T>
(em que T
é um tipo enumerado definido pelo usuário)
se torna o tipo subjacente desse tipo enumerado em C++. No exemplo acima,
bitfield<Mode>
se torna uint8_t
.
vec<T>
O modelo de classe hidl_vec<T>
faz parte de
libhidlbase
e podem ser usadas para transmitir um vetor de qualquer tipo HIDL com
um tamanho arbitrário. O contêiner de tamanho fixo comparável
hidl_array
: Um hidl_vec<T>
também pode ser
inicializado para apontar para um buffer de dados externo do tipo T
, usando
a função hidl_vec::setToExternal()
.
Além de emitir/inserir o struct adequadamente no
cabeçalho C++, o uso de vec<T>
gera alguma conveniência
funções para traduzir de/para std::vector
e T
nua
ponteiros. Se o vec<T>
for usado como um parâmetro, a função
que está sobrecarregado (são gerados dois protótipos) para aceitar e
transmitir o struct HIDL e um tipo std::vector<T>
para isso.
.
matriz
Matrizes constantes no hidl são representadas pela classe hidl_array
em libhidlbase
. Um hidl_array<T, S1, S2, …,
SN>
representa uma matriz n de tamanho fixo de dimensão.
T[S1][S2]…[SN]
.
string
A classe hidl_string
(parte de libhidlbase
) pode ser
usada para passar strings por interfaces HIDL e é definido em
/system/libhidl/base/include/hidl/HidlSupport.h
O primeiro armazenamento
local na classe é um ponteiro para o buffer de caracteres dela.
O hidl_string
sabe como converter de e para
std::string and char*
(string em estilo C) usando
operator=
, casts implícitos e função .c_str()
.
Os structs de string HIDL têm os construtores de cópia e atribuição apropriados
operadores para:
- Carregue a string HIDL de uma string
std::string
ou C. - Cria um novo
std::string
com base em uma string HIDL.
Além disso, as strings HIDL têm construtores de conversão. Portanto, as strings C
(char *
) e as strings C++ (std::string
) podem ser usadas em
métodos que usam uma string HIDL.
estrutura
Um struct
em HIDL pode conter apenas tipos de dados de tamanho fixo e nenhum
. As definições de struct HIDL são mapeadas diretamente para o layout padrão
struct
s em C++, garantindo que struct
s tenham uma
e um layout de memória consistente. Um struct pode incluir tipos de HIDL, incluindo
handle
, string
e vec<T>
, que
para separar buffers de comprimento variável.
identificador
AVISO: endereços de qualquer tipo (mesmo físicos endereços de dispositivo) nunca podem fazer parte de um identificador nativo. Ao passar informações entre processos é perigoso e os torna suscetíveis a ataques. Todos os valores transmitidos entre processos precisam ser validados antes de serem usados para procurar a memória alocada em um processo. Caso contrário, identificadores incorretos podem causar acesso ou corrupção de memória.
O tipo handle
é representado por hidl_handle
.
em C++, que é um wrapper simples em torno de um ponteiro para um
Objeto const native_handle_t
, que está presente no Android há
muito 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;
Por padrão, hidl_handle
não assume a propriedade
do ponteiro native_handle_t
que ele une. Ele existe apenas para proteger
armazene um ponteiro para um native_handle_t
para que ele possa ser usado em
processos de 32 e 64 bits.
Cenários em que hidl_handle
é o proprietário do arquivo incluído
os descritores incluem:
- Após uma chamada para o método
setTo(native_handle_t* handle, bool shouldOwn)
com o parâmetroshouldOwn
definido comotrue
- Quando o objeto
hidl_handle
é criado pela construção de cópia. de outro objetohidl_handle
- Quando o objeto
hidl_handle
é atribuído por cópia de outrohidl_handle
objeto
hidl_handle
oferece conversões implícitas e explícitas.
de/para objetos native_handle_t*
. O principal uso da
O tipo handle
em HIDL é transmitir descritores de arquivos pelo HIDL
do Google Cloud. Portanto, um único descritor de arquivo é representado por uma
native_handle_t
sem int
s e uma única
fd
Se o cliente e o servidor estiverem em um processo diferente, o RPC
implementação cuida automaticamente do descritor de arquivo para garantir
os dois processos podem operar no mesmo arquivo.
Embora um descritor de arquivo recebido em um hidl_handle
por um
ou processo é válido nesse processo, ele não persiste além do
função (ela é fechada quando a função retorna). Um processo que quer
reter o acesso persistente ao descritor de arquivo deverá dup()
o
descritores de arquivo incluídos ou copie todo o objeto hidl_handle
.
memória
O tipo memory
de HIDL é mapeado para a classe hidl_memory
em libhidlbase
, que representa a memória compartilhada não mapeada. Isso é
o objeto que precisa ser transmitido entre processos para compartilhar a memória no HIDL. Para
usar memória compartilhada:
- Consiga uma instância de
IAllocator
(atualmente, apenas a instância "ashmem" estiver disponível) e usá-lo para alocar memória compartilhada. IAllocator::allocate()
retorna umhidl_memory
. que pode ser transmitido pelo RPC HIDL e mapeado para um processo usando FunçãomapMemory
delibhidlmemory
.mapMemory
retorna uma referência a um Objetosp<IMemory>
que pode ser usado para acessar a memória. (IMemory
eIAllocator
são definidos nasandroid.hidl.memory@1.0
).
Uma instância de IAllocator
pode ser usada para alocar memória:
#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 }));
Mudanças reais na memória precisam ser feitas por uma IMemory
do objeto, seja no lado que criou mem
ou no lado que
recebe por 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();
interface
As interfaces podem ser transmitidas como objetos. A palavra interface pode ser usada
como açúcar sintático para o tipo android.hidl.base@1.0::IBase
.
Além disso, a interface atual e quaisquer interfaces importadas são definidas
como um tipo.
As variáveis que contêm interfaces precisam ser indicadores fortes:
sp<IName>
: Funções HIDL que usam parâmetros de interface
converter ponteiros brutos em ponteiros fortes, causando um comportamento não intuitivo
(o ponteiro pode ser apagado inesperadamente). Para evitar problemas, sempre armazene o HIDL
como um sp<>
.