No Android 8.0, o sistema operacional Android foi reprojetado para definir interfaces claras entre a plataforma Android independente de 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ão, que podem estar em Java (descrito abaixo) ou ser interfaces HIDL do lado do cliente e do servidor em C++ .
As interfaces HIDL devem ser usadas principalmente a partir de código nativo e, como resultado, o HIDL é focado na geração automática de código eficiente em C++. No entanto, as interfaces HIDL também devem estar disponíveis para uso diretamente do Java, pois alguns subsistemas Android (como Telefonia) possuem interfaces Java HIDL.
As páginas nesta seção descrevem o frontend 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.
Ser cliente
Este é um exemplo de um cliente para uma interface IFoo
no pacote android.hardware.foo@1.0
que está registrado como nome de serviço default
e um serviço adicional com o nome de serviço customizado second_impl
.
Adicionando bibliotecas
Você precisa adicionar dependências na biblioteca de stub HIDL correspondente se quiser usá-la. Normalmente, esta é 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ê sabe que já está recebendo dependências dessas bibliotecas, também pode 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 aplicativo de sistema ou fornecedor direcionado ao Android 10 ou superior, poderá incluir essas bibliotecas estaticamente. Você também pode usar (somente) classes HIDL de JARs personalizados instalados no dispositivo com APIs Java estáveis disponibilizadas usando o mecanismo uses-library
existente para aplicativos do sistema. A última abordagem economiza espaço no dispositivo. Para obter mais detalhes, consulte Implementando a Biblioteca Java SDK . Para aplicativos mais antigos, o comportamento antigo é preservado.
A partir do Android 10, também estão disponíveis versões "rasas" dessas bibliotecas. Isso inclui a classe em questão, mas não inclui 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 todos os HIDL interfaces. Se você estiver criando uma biblioteca que já tenha as classes base da interface preferencial disponíveis como dependência, poderá usar 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 gerenciador HIDL também não estão mais disponíveis no caminho de classe de inicialização para aplicativos (anteriormente, às vezes elas eram usadas como API oculta, devido ao carregador de classe delegado primeiro do Android). Em vez disso, eles foram movidos para um novo namespace com jarjar
e os aplicativos que usam esses (necessariamente aplicativos priv) devem ter suas próprias cópias separadas. Módulos no caminho de classe de inicialização usando HIDL devem usar as variantes superficiais dessas bibliotecas Java e adicionar jarjar_rules: ":framework-jarjar-rules"
ao seu Android.bp
para usar a versão dessas bibliotecas que existe no caminho de classe de inicialização.
Modificando sua fonte Java
Há apenas uma versão ( @1.0
) desse serviço, portanto, esse código recupera apenas essa versão. Consulte as extensões de interface para saber como lidar com 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(…);
Prestando um serviço
O código de estrutura em Java pode precisar servir interfaces para receber retornos de chamada assíncronos de HALs.
Para a interface IFooCallback
na versão 1.0 do pacote android.hardware.foo
, você pode implementar sua interface em Java usando as seguintes 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 escreva uma nova classe para estendê-la e implementar os métodos abstratos.
Visualizando arquivos gerados automaticamente
Para visualizar 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 proxy e os stubs (ambos proxy e stubs estão em conformidade com a interface).
-Lmakefile
gera as regras que executam esse comando em tempo de compilação e permitem incluir android.hardware.foo-V1.0-java
e vincular aos 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; hardware/interfaces pode ser um diretório temporário em sua árvore de código para permitir que você desenvolva um HAL antes de publicá-lo.
Executando um serviço
O HAL fornece a interface IFoo
, que deve fazer retornos de chamada assíncronos para a estrutura pela interface IFooCallback
. A interface IFooCallback
não é registrada pelo nome como um serviço detectável; em vez disso, o IFoo
deve conter um método como setFooCallback(IFooCallback x)
.
Para configurar o IFooCallback
da 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 determinado dispositivo o serviço forneça recursos adicionais implementados na extensão de interface IBetterFoo
, conforme a seguir:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
Chamar o código ciente da interface estendida pode usar o método Java castFrom()
para converter com segurança a interface base para a 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. }