Interfaces e aplicativos Pacotes

O HIDL é construído em torno de interfaces, um tipo abstrato usado em linguagens orientadas a objetos para definir comportamentos. Cada interface faz parte de um pacote.

Pacotes

Os nomes dos pacotes podem ter subníveis como package.subpackage . O diretório raiz para pacotes HIDL publicados é hardware/interfaces ou vendor/vendorName (por exemplo, vendor/google para dispositivos Pixel). O nome do pacote forma um ou mais subdiretórios no diretório raiz; todos os arquivos que definem um pacote estão no mesmo diretório. Por exemplo, package android.hardware.example.extension.light@2.0 pode ser encontrado em hardware/interfaces/example/extension/light/2.0 .

A tabela a seguir lista prefixos e locais de pacotes:

Prefixo do pacote Localização Tipos de interface
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* estruturas/relacionadas
android.system.* system/hardware/interfaces/* sistema/relacionado
android.hidl.* system/libhidl/transport/* essencial

O diretório do pacote contém arquivos com extensão .hal . Cada arquivo deve conter uma declaração package nomeando o pacote e a versão da qual o arquivo faz parte. O arquivo types.hal , se presente, não define uma interface, mas define tipos de dados acessíveis a todas as interfaces do pacote.

Definição de interface

Além de types.hal , todos os outros arquivos .hal definem uma interface. Uma interface normalmente é definida da seguinte forma:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

Uma interface sem uma declaração extends explícita se estende implicitamente de android.hidl.base@1.0::IBase (semelhante a java.lang.Object em Java.) A interface IBase, importada implicitamente, declara vários métodos reservados que não devem e não podem ser redeclarados em interfaces definidas pelo usuário ou usadas de outra forma. Esses métodos incluem:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

Importando

A instrução import é um mecanismo HIDL para acessar interfaces e tipos de pacotes em outro pacote. Uma declaração import diz respeito a duas entidades:

  • A entidade importadora , que pode ser um pacote ou uma interface; e
  • A entidade import ed , que também pode ser um pacote ou uma interface.

A entidade importadora é determinada pela localização da declaração import . Quando a instrução está dentro do types.hal de um pacote, o que está sendo importado fica visível por todo o pacote; esta é uma importação em nível de pacote . Quando a instrução está dentro de um arquivo de interface, a entidade importadora é a própria interface; esta é uma importação em nível de interface .

A entidade importada é determinada pelo valor após a palavra-chave import . O valor não precisa ser um nome totalmente qualificado; se um componente for omitido, ele será automaticamente preenchido com informações do pacote atual. Para valores totalmente qualificados, há suporte para os seguintes casos de importação:

  • Importações de pacote inteiro . Se o valor for um nome de pacote e uma versão (sintaxe descrita abaixo), todo o pacote será importado para a entidade importadora.
  • Importações parciais . Se o valor for:
    • Uma interface, o types.hal do pacote e essa interface são importados para a entidade importadora.
    • Um UDT definido em types.hal , somente esse UDT é importado para a entidade importadora (outros tipos em types.hal não são importados).
  • Importações somente de tipos . Se o valor usar a sintaxe de uma importação parcial descrita acima, mas com a palavra-chave types em vez de um nome de interface, somente os UDTs em types.hal do pacote designado serão importados.

A entidade importadora obtém acesso a uma combinação de:

  • Os UDTs comuns do pacote importado definidos em types.hal ;
  • As interfaces do pacote importado (para uma importação de pacote inteiro) ou interface especificada (para uma importação parcial) para fins de invocá-los, passar identificadores para eles e/ou herdar deles.

A instrução import usa a sintaxe full-qualified-type-name para fornecer o nome e a versão do pacote ou interface que está sendo importada:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

Herança de interface

Uma interface pode ser uma extensão de uma interface previamente definida. As extensões podem ser de um dos três tipos a seguir:

  • Interface pode adicionar funcionalidade a outra, incorporando sua API inalterada.
  • O pacote pode adicionar funcionalidade a outro, incorporando sua API inalterada.
  • A interface pode importar tipos de um pacote ou de uma interface específica.

Uma interface pode estender apenas uma outra interface (sem herança múltipla). Cada interface em um pacote com um número de versão secundária diferente de zero deve estender uma interface na versão anterior do pacote. Por exemplo, se uma interface IBar na versão 4.0 do pacote derivative for baseada (estende) uma interface IFoo na versão 1.2 do pacote original e uma versão 1.3 do pacote original for criada, a versão 4.1 IBar não poderá estender a versão 1.3 do IFoo . Em vez disso, IBar versão 4.1 deve estender IBar versão 4.0, que está vinculado ao IFoo versão 1.2. A versão 5.0 IBar pode estender a versão 1.3 IFoo , se desejado.

As extensões de interface não implicam dependência de biblioteca ou inclusão cruzada de HAL no código gerado – elas simplesmente importam a estrutura de dados e as definições de método no nível HIDL. Cada método em um HAL deve ser implementado nesse HAL.

Extensões de fornecedor

Em alguns casos, as extensões do fornecedor serão implementadas como uma subclasse do objeto base que representa a interface principal que elas estendem. O mesmo objeto será registrado sob o nome e versão HAL base e sob o nome e versão HAL da extensão (fornecedor).

Versionamento

Os pacotes são versionados e as interfaces possuem a versão de seu pacote. As versões são expressas em dois números inteiros, major . menor .

  • As versões principais não são compatíveis com versões anteriores. Aumentar o número da versão principal redefine o número da versão secundária para 0.
  • Versões secundárias são compatíveis com versões anteriores. Aumentar o número menor indica que a versão mais recente é totalmente compatível com versões anteriores. Novas estruturas de dados e métodos podem ser adicionados, mas nenhuma estrutura de dados ou assinatura de método existente pode ser alterada.

Várias versões principais ou secundárias de um HAL podem estar presentes em um dispositivo simultaneamente. No entanto, uma versão secundária deve ser preferida a uma versão principal porque o código do cliente que funciona com uma interface de versão secundária anterior também funcionará com versões secundárias posteriores dessa mesma interface. Para obter mais detalhes sobre versionamento e extensões de fornecedores, consulte Versionamento HIDL .

Resumo do layout da interface

Esta seção resume como gerenciar um pacote de interface HIDL (como hardware/interfaces ) e consolida as informações apresentadas em toda a seção HIDL. Antes de ler, certifique-se de estar familiarizado com o Versionamento HIDL , os conceitos de hash em Hashing com hidl-gen , os detalhes de como trabalhar com HIDL em geral e as seguintes definições:

Prazo Definição
Interface Binária do Aplicativo (ABI) Interface de programação de aplicativos + quaisquer ligações binárias necessárias.
Nome totalmente qualificado (fqName) Nome para distinguir um tipo hidl. Exemplo: android.hardware.foo@1.0::IFoo .
Pacote Pacote contendo uma interface e tipos HIDL. Exemplo: android.hardware.foo@1.0 .
Raiz do pacote Pacote raiz que contém as interfaces HIDL. Exemplo: a interface HIDL android.hardware está no pacote root android.hardware.foo@1.0 .
Caminho raiz do pacote Local na árvore de origem do Android para onde a raiz do pacote é mapeada.

Para obter mais definições, consulte Terminologia HIDL.

Cada arquivo pode ser encontrado no mapeamento raiz do pacote e seu nome totalmente qualificado

As raízes do pacote são especificadas para hidl-gen como o argumento -r android.hardware:hardware/interfaces . Por exemplo, se o pacote for vendor.awesome.foo@1.0::IFoo e hidl-gen for enviado -r vendor.awesome:some/device/independent/path/interfaces , então o arquivo de interface deverá estar localizado em $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal .

Na prática, é recomendado que um fornecedor ou OEM chamado awesome coloque suas interfaces padrão em vendor.awesome . Após a seleção de um caminho de pacote, ele não deve ser alterado, pois isso está incluído na ABI da interface.

O mapeamento do caminho do pacote deve ser exclusivo

Por exemplo, se você tiver -rsome.package:$PATH_A e -rsome.package:$PATH_B , $PATH_A deve ser igual a $PATH_B para um diretório de interface consistente (isso também torna o versionamento de interfaces muito mais fácil).

A raiz do pacote deve ter um arquivo de controle de versão

Se você criar um caminho de pacote como -r vendor.awesome:vendor/awesome/interfaces , você também deve criar o arquivo $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt , que deve conter hashes de interfaces feitas usando o -Lhash opção em hidl-gen (isso é discutido extensivamente em Hashing com hidl-gen ).

As interfaces ficam em locais independentes do dispositivo

Na prática, é recomendado compartilhar interfaces entre filiais. Isso permite a reutilização máxima de código e o máximo teste de código em diferentes dispositivos e casos de uso.