O idioma de definição da interface HAL, ou HIDL, é um idioma de descrição da interface (IDL) para especificar a interface entre uma HAL e e seus usuários. O HIDL permite especificar tipos e chamadas de método, coletados em interfaces e pacotes do Google Cloud. Mais amplamente, HIDL é um sistema de comunicação entre bases de código que podem ser compiladas de forma independente.
O HIDL é usado para comunicação entre processos (IPC). As HALs criadas com HDL são chamadas de HALs binderizadas porque podem se comunicar com outras camadas de arquitetura chamadas de comunicação entre processos (IPC). HALs Binderized são executadas em um processo separado do cliente que os utiliza. Para bibliotecas que devem ser vinculadas a um processo, um passthrough mode também está disponível (não compatível com Java).
O HIDL especifica estruturas de dados e assinaturas de método, organizadas em interfaces (semelhante a uma classe) que são coletadas em pacotes. A sintaxe do HIDL é familiar para C++ e programadores de Java, mas com um conjunto diferente de palavras-chave. O HIDL também usa anotações no estilo Java.
Terminologia
Esta seção usa os seguintes termos relacionados ao HIDL:
vinculado | Indica que o HIDL está sendo usado para chamadas de procedimento remoto entre processos por um mecanismo do tipo Binder. Consulte também passthrough. |
---|---|
callback, assíncrono | Interface disponibilizada por um usuário da HAL, transmitida para a HAL (usando um método HIDL) chamados pela HAL para retornar dados a qualquer momento. |
callback, síncrono | Retorna dados da implementação do método HIDL de um servidor ao cliente. Não utilizado para métodos que retornam nulo ou um único valor primitivo. |
cliente | Processo que chama métodos de uma interface específica. Uma HAL ou framework do Android pode ser cliente de uma interface e servidor de outra. Consulte também passthrough. |
estende | Indica uma interface que adiciona métodos e/ou tipos a outra interface. Uma interface só pode estender uma outra interface. Pode ser usado para menores incremento de versão no mesmo nome de pacote ou para um novo pacote (por exemplo, um ) para criar a partir de um pacote mais antigo. |
gera | Indica um método de interface que retorna valores para o cliente. De volta um valor não primitivo, ou mais de um valor, uma função de callback síncrona é gerado. |
interface | Coleção de métodos e tipos. Traduzido para uma classe em C++ ou Java. Todos em uma interface são chamados na mesma direção: um processo cliente invoca métodos implementados por um processo de servidor. |
viagem de ida | Quando aplicado a um método HIDL, indica que o método não retorna valores e que não seja bloqueada. |
pacote | Conjunto de interfaces e tipos de dados que compartilham uma versão. |
passagem | Modo de HIDL em que o servidor é uma biblioteca compartilhada, dlopen
pelo cliente. No modo de passagem, cliente e servidor são o mesmo processo, mas
bases de código separadas. Usado apenas para trazer bases de código legadas para o modelo HIDL.
Consulte também Binderized. |
servidor | Processo que implementa métodos de uma interface. Consulte também passthrough. |
transporte | Infraestrutura HIDL que move dados entre o servidor e o cliente. |
versão | Versão de um pacote. Consiste em dois números inteiros, maior e menor. Menor incrementos de versão podem adicionar (mas não alterar) tipos e métodos. |
Design de HIDL
O objetivo do HIDL é que o framework do Android possa ser substituído sem ter que
reconstrua as HALs. As HALs são construídas por fornecedores ou fabricantes de SOC e colocadas em
/vendor
no dispositivo, ativando o framework do Android por conta própria.
para ser substituída por uma OTA sem recompilar as HALs.
O design de HIDL equilibra as seguintes preocupações:
- Interoperabilidade. Crie interfaces interoperáveis e confiáveis entre processos que podem ser compilados com várias arquiteturas, conjuntos de ferramentas e configurações de build. As interfaces HIDL têm controle de versão e não podem ser alteradas após a publicação.
- Eficiência. o HIDL tenta minimizar o número de cópias as operações. Os dados definidos pelo HIDL são entregues ao código C++ no layout padrão C++ estruturas de dados que podem ser usadas sem descompactar. O HIDL também oferece conteúdo interfaces de memória e, como RPCs são inerentemente lentas, o HIDL suporta duas maneiras de transferir dados sem usar uma chamada RPC: memória compartilhada e um de mensagens (FMQ, na sigla em inglês).
- Intuitivo. O HIDL evita problemas complicados de propriedade de memória ao
usando apenas parâmetros
in
para RPC (consulte No Android Linguagem de definição de interface (AIDL) valores que não podem ser retornados de métodos são retornados por funções de callback. Nenhuma transmissão de dados ao HIDL para transferência ou recebimento de dados do HIDL altera a propriedade do dados: a propriedade sempre permanece com a função de chamada. Os dados precisam persistem apenas durante a função chamada e podem ser destruídos imediatamente após o retorno da função chamada.
Usar o modo de passagem
Para atualizar dispositivos que executam versões anteriores do Android para o Android O, você pode unem as HALs convencionais (e legadas) em uma nova interface HIDL que atende HAL nos modos de vinculação e de mesmo processo (passagem). Esse encapsulamento é transparentes tanto para a HAL quanto para o framework do Android.
O modo de passagem está disponível apenas para clientes e implementações do C++. Dispositivos com versões anteriores do Android não têm HALs escritas em Java. Portanto, As HALs do Java são encadeadas inerentemente.
Arquivos de cabeçalho de passagem
Quando um arquivo .hal
é compilado, hidl-gen
produz uma
arquivo de cabeçalho de passagem extra BsFoo.h
além dos cabeçalhos
usados para comunicação do binder; esse cabeçalho define as funções a serem
dlopen
. À medida que as HALs de passagem são executadas no mesmo processo,
são chamados. Na maioria dos casos, os métodos de passagem são invocados
chamada de função (mesma linha de execução). Os métodos oneway
são executados na própria linha de execução
pois não devem esperar o processamento pela HAL (isso significa que
que usam métodos oneway
no modo de passagem precisam ser thread-safe).
Dado um IFoo.hal
, BsFoo.h
une os elementos gerados por HIDL
métodos para fornecer recursos adicionais (como tornar oneway
transações executadas em outra linha de execução). Esse arquivo é semelhante a
BpFoo.h
, no entanto, em vez de transmitir a IPC de chamadas usando um binder, a
que as funções desejadas sejam invocadas diretamente. Futuras implementações de HALs
pode fornecer várias implementações, como FooFast HAL e um
HAL precisa. Nesses casos, um arquivo para cada implementação adicional
ser criado (por exemplo, PTFooFast.cpp
e
PTFooAccurate.cpp
).
Binder HALs de passagem
É possível vincular implementações de HAL com suporte ao modo de passagem. Considerando
interface HAL a.b.c.d@M.N::IFoo
, dois pacotes são criados:
a.b.c.d@M.N::IFoo-impl
: Contém a implementação da HAL e expõe a funçãoIFoo* HIDL_FETCH_IFoo(const char* name)
. Ativado dispositivos legados, este pacote temdlopen
, e a implementação é instanciado usandoHIDL_FETCH_IFoo
. É possível gerar o código base usandohidl-gen
,-Lc++-impl
e-Landroidbp-impl
a.b.c.d@M.N::IFoo-service
: Abre a HAL de passagem e registra a si mesmo como um serviço vinculado, permitindo a mesma implementação de HAL para ser usado como passthrough e de vinculação.
Com o tipo IFoo
, é possível chamar sp<IFoo>
IFoo::getService(string name, bool getStub)
para ter acesso a uma instância
de IFoo
. Se getStub
for verdadeiro, getService
tenta abrir a HAL somente no modo de passagem. Se getStub
for
false, getService
tenta encontrar um serviço vinculado; se isso
falhar, ele tenta encontrar o serviço de passagem. O getStub
nunca deve ser usado, exceto em
defaultPassthroughServiceImplementation
. (Dispositivos lançados com
Android O são dispositivos totalmente vinculados. Portanto, abrir um serviço no modo de passagem
não é permitida.
Gramática HIDL
Por padrão, a linguagem HIDL é semelhante ao C (mas não usa o C
(pré-processador). Todas as pontuações não descritas abaixo (exceto o uso óbvio
de =
e |
) faz parte da gramática.
Observação:para mais detalhes sobre o estilo de código HIDL, consulte o Guia de estilo de código.
/** */
indica um comentário da documentação. Elas podem ser aplicadas somente para declarações de tipo, método, campo e enumeração./* */
indica um comentário de várias linhas.//
indica um comentário no fim da linha. Além de//
, as novas linhas são iguais a qualquer outro espaço em branco.- No exemplo de gramática abaixo, o texto de
//
no final da não faz parte da gramática, mas sim um comentário sobre a gramática. [empty]
significa que o termo pode estar vazio.?
depois de um literal ou termo significa que ele é opcional....
indica sequência que contém zero ou mais itens com separando pontuação conforme indicado. Não há argumentos variados no HIDL.- Os elementos de sequência são separados por vírgulas.
- Os pontos e vírgulas terminam cada elemento, incluindo o último.
- MAIÚSCULAS é um não terminal.
italics
é uma família de tokens comointeger
ouidentifier
(padrão C e análise de regras).constexpr
é uma expressão constante de estilo C (como1 + 1
e1L << 3
).import_name
é um nome de pacote ou interface qualificado conforme descrito no HIDL Controle de versão.words
em minúsculas são tokens literais.
Exemplo:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr