No Android 8.0, o sistema operacional Android foi reprojetado 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 versionadas, que podem estar em Java (descritas abaixo) ou ser interfaces HIDL do lado do cliente e do servidor em C++ .
As interfaces HIDL destinam-se a ser usadas principalmente a partir de código nativo e, como resultado, o HIDL está 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 um cliente
Este é um exemplo de 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 personalizado second_impl
.
Adicionando bibliotecas
Você precisa adicionar dependências na biblioteca 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á extraindo dependências dessas bibliotecas, também pode usar a ligaçã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 (apenas) classes HIDL de JARs customizados 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, versões “superficiais” dessas bibliotecas também estão disponíveis. 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 estiver criando uma biblioteca que já tenha as classes base da interface preferencial disponíveis como dependência, você 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 base e gerenciadoras HIDL também não estão mais disponíveis no caminho de classe de inicialização para aplicativos (anteriormente, elas às vezes 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 os usam (necessariamente aplicativos privados) devem ter suas próprias cópias separadas. Os 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
Existe apenas uma versão ( @1.0
) deste serviço, portanto este 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(…);
Fornecendo um serviço
O código da 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, em seguida, 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 do proxy e os stubs (ambos proxy e stubs estão em conformidade com a interface).
-Lmakefile
gera as regras que executam este comando no momento da compilação e permite 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 por meio da interface IFooCallback
. A interface IFooCallback
não está registrada pelo nome como um serviço detectável; em vez disso, IFoo
deve conter um método como setFooCallback(IFooCallback x)
.
Para configurar 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 dispositivo específico o serviço forneça recursos adicionais implementados na extensão de interface IBetterFoo
, como segue:
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 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. }