No Android 8.0, o SO Android foi reestruturado para definir interfaces claras
entre a plataforma Android independente do dispositivo e o código específico do dispositivo e do fornecedor. O Android já definiu muitas dessas interfaces na forma de interfaces
HAL, definidas como cabeçalhos C em hardware/libhardware
. O HIDL
substituiu essas interfaces HAL por interfaces estáveis e com versões, que podem
estar em Java (descrito abaixo) ou ser interfaces HIDL do lado do cliente e do servidor
em C++.
As interfaces HIDL são usadas principalmente em código nativo e, como resultado, o foco delas é a geração automática de código eficiente em C++. No entanto, as interfaces HIDL também precisam estar disponíveis para uso diretamente do Java, já que alguns subsistemas do Android (como a telefonia) têm interfaces HIDL Java.
As páginas desta seção descrevem o front-end Java para interfaces HIDL, detalham como criar, registrar e usar serviços e explicam como HALs e clientes HAL escritos em Java interagem com o sistema HIDL RPC.
Exemplo de cliente
Este é um exemplo de cliente para uma interface IFoo
no pacote
android.hardware.foo@1.0
registrado como nome de serviço
default
e um serviço adicional com o nome de serviço personalizado
second_impl
.
Adicionar bibliotecas
É necessário adicionar dependências à biblioteca de stub HIDL correspondente se você quiser usá-la. Normalmente, essa é uma biblioteca estática:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Se você já estiver extraindo dependências dessas bibliotecas, também poderá usar a vinculação compartilhada:
// in Android.bp libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Considerações adicionais para adicionar bibliotecas no Android 10
Se você tiver um app de sistema ou fornecedor direcionado ao Android 10 ou mais recente,
é possível incluir essas bibliotecas de forma estática. Também é possível usar apenas classes HIDL
de JARs personalizados instalados no dispositivo com APIs Java estáveis disponibilizadas
usando o mecanismo uses-library
atual para apps do sistema. A
segunda abordagem economiza espaço no dispositivo. Para mais detalhes, consulte Como implementar a biblioteca Java SDK. Para
apps mais antigos, o comportamento antigo é preservado.
A partir do Android 10, versões "superficiais" dessas bibliotecas
também estão disponíveis. Elas incluem a classe em questão, mas não incluem nenhuma
das classes dependentes. Por exemplo,
android.hardware.foo-V1.0-java-shallow
inclui classes no pacote
foo, mas não inclui classes em
android.hidl.base-V1.0-java
, que contém a classe base de todas
as interfaces HIDL. Se você estiver criando uma biblioteca que já tem as classes básicas
da interface preferida disponíveis como uma dependência, use o seguinte:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java-shallow", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow
As bibliotecas de base e de gerenciamento de HIDL também não estão mais disponíveis no bootclasspath
de apps. Antes, elas eram usadas como API oculta devido ao
carregador de classes de delegação do Android. Em vez disso, elas foram movidas para um novo
namespace com jarjar
, e os apps que as usam (necessariamente apps
privados) precisam ter as próprias cópias separadas. Os módulos no caminho de classe de inicialização que usam
HIDL precisam usar as variantes rasas dessas bibliotecas Java e adicionar
jarjar_rules: ":framework-jarjar-rules"
ao
Android.bp
para usar a versão dessas bibliotecas que existe
no caminho de classe de inicialização.
Modificar a origem Java
Há apenas uma versão (@1.0
) desse serviço, portanto, esse código
recupera apenas essa versão. Consulte
Extensões de interface
para saber como processar várias versões diferentes do serviço.
import android.hardware.foo.V1_0.IFoo; ... // retry to wait until the service starts up if it is in the manifest IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available IFoo anotherServer = IFoo.getService("second_impl", true /* retry */); server.doSomething(…);
Oferecer um serviço
O código do framework em Java pode precisar fornecer interfaces para receber callbacks assíncronos de HALs.
Para a interface IFooCallback
na versão 1.0 do
pacote android.hardware.foo
, é possível implementar sua interface em
Java seguindo estas etapas:
- Defina sua interface em HIDL.
- Abra
/tmp/android/hardware/foo/IFooCallback.java
como referência. - Crie um novo módulo para sua implementação Java.
- Examine a classe abstrata
android.hardware.foo.V1_0.IFooCallback.Stub
e crie uma nova classe para estender e implementar os métodos abstratos.
Conferir arquivos gerados automaticamente
Para conferir os arquivos gerados automaticamente, execute:
hidl-gen -o /tmp -Ljava \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0
Esses comandos geram o diretório
/tmp/android/hardware/foo/1.0
. Para o arquivo
hardware/interfaces/foo/1.0/IFooCallback.hal
, isso gera o
arquivo /tmp/android/hardware/foo/1.0/IFooCallback.java
, que
encapsula a interface Java, o código do proxy e os stubs (o proxy e
os stubs estão em conformidade com a interface).
O -Lmakefile
gera as regras que executam esse comando no momento
do build e permite que você inclua
android.hardware.foo-V1.0-java
e estabeleça links com os
arquivos apropriados. Um script que faz isso automaticamente para um projeto cheio de
interfaces pode ser encontrado em hardware/interfaces/update-makefiles.sh
.
Os caminhos neste exemplo são relativos. O hardware/interfaces pode ser um diretório temporário
na árvore de código para que você possa desenvolver um HAL antes de
publicá-lo.
Executar um serviço
A HAL fornece a interface IFoo
, que precisa fazer callbacks
assíncronos para a estrutura pela interface IFooCallback
. A
interface IFooCallback
não é registrada por nome como um serviço
detectável. Em vez disso, IFoo
precisa conter um método, como
setFooCallback(IFooCallback x)
.
Para configurar o IFooCallback
na versão 1.0 do
pacote android.hardware.foo
, adicione
android.hardware.foo-V1.0-java
a Android.mk
. O código
para executar o serviço é:
import android.hardware.foo.V1_0.IFoo; import android.hardware.foo.V1_0.IFooCallback.Stub; .... class FooCallback extends IFooCallback.Stub { // implement methods } .... // Get the service from which you will be receiving callbacks. // This also starts the threadpool for your callback service. IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available .... // This must be a persistent instance variable, not local, // to avoid premature garbage collection. FooCallback mFooCallback = new FooCallback(); .... // Do this once to create the callback service and tell the "foo-bar" service server.setFooCallback(mFooCallback);
Extensões de interface
Supondo que um determinado serviço implemente a interface IFoo
em todos
os dispositivos, é possível que em um dispositivo específico o serviço forneça
mais recursos implementados na extensão de interface
IBetterFoo
, conforme abaixo:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
A chamada de código ciente da interface estendida pode usar o
método Java castFrom()
para converter com segurança a interface de base na
interface estendida:
IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available IBetterFoo extendedService = IBetterFoo.castFrom(baseService); if (extendedService != null) { // The service implements the extended interface. } else { // The service implements only the base interface. }