HIDL em Java

No Android 8.0, o SO Android foi reprojetado para definir interfaces claras entre a plataforma Android independente de dispositivos e configurações o código-fonte é alterado. O Android já definiu muitas dessas interfaces na forma de HAL interfaces de rede, definidas como cabeçalhos C em hardware/libhardware. HIDL substituímos essas interfaces HAL por interfaces estáveis com controle de versões, que podem estar em Java (descrito abaixo) ou ser 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 uma resultado, o HIDL concentra-se na geração automática de código eficiente em C++. No entanto, As interfaces HIDL também precisam estar disponíveis para uso diretamente em Java, uma vez que subsistemas (como a Telefonia) têm interfaces HIDL do Java.

As páginas nesta seção descrevem o front-end do Java para interfaces HIDL, detalhar como criar, registrar e usar serviços, além de explicar como as HALs e as HALs os clientes 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, que está registrado como o nome do serviço default e um serviço adicional com o nome de serviço personalizado second_impl.

Adicionar bibliotecas

Será necessário adicionar dependências na biblioteca de stubs HIDL correspondente se em que você quer usá-lo. 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á está extraindo dependências dessas bibliotecas, também podem 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

Outras considerações para adicionar bibliotecas no Android 10

Se você tiver um app do sistema ou do fornecedor destinado ao Android 10 ou versões mais recentes, é possível incluir essas bibliotecas estaticamente. Você também pode usar (apenas) classes HIDL a partir de JARs personalizados instalados no dispositivo com APIs Java estáveis disponibilizadas usando o mecanismo uses-library já existente para apps do sistema. A última abordagem economiza espaço no dispositivo. Para mais detalhes, consulte Como implementar a biblioteca Java SDK. Para aplicativos mais antigos, o comportamento antigo é preservado.

A partir do Android 10, "superficial" versões dessas bibliotecas também estão disponíveis. Isso inclui a classe em questão, mas não quaisquer das classes dependentes. Por exemplo: android.hardware.foo-V1.0-java-shallow inclui classes no foo mas não inclui classes em android.hidl.base-V1.0-java, que contém a classe base de todos HIDL. Se você estiver criando uma biblioteca que já tem a biblioteca interface disponíveis como dependência, você pode 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 gerenciador e base HIDL também não estão mais disponíveis na inicialização para apps. Antes, elas às vezes eram usadas como APIs ocultas, devido à o classloader que prioriza o delegado do Android). Em vez disso, elas foram transferidas namespace com jarjar, e os apps que usam esses valores (necessariamente privados apps) precisam ter cópias separadas. módulos no caminho de classe de inicialização usando O HIDL deve usar as variantes superficiais dessas bibliotecas Java e adicionar jarjar_rules: ":framework-jarjar-rules" para o Android.bp para usar a versão dessas bibliotecas que existe no caminho de classe da inicialização.

Modificar sua fonte Java

Há apenas uma versão (@1.0) desse serviço, então este código recupera apenas essa versão. Consulte 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(…);

Prestação de serviço

O código do framework em Java pode precisar disponibilizar interfaces para receber chamadas de retorno das HALs.

Para a interface IFooCallback na versão 1.0 do android.hardware.foo, é possível implementar a interface Java seguindo estas etapas:

  1. Defina sua interface no HIDL.
  2. Abrir /tmp/android/hardware/foo/IFooCallback.java como de referência.
  3. Crie um novo módulo para a implementação do Java.
  4. Analise a classe abstrata android.hardware.foo.V1_0.IFooCallback.Stub e crie uma nova classe para estendê-la e implementar os métodos abstratos.

Ver 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 a arquivo /tmp/android/hardware/foo/1.0/IFooCallback.java, que encapsula a interface Java, o código de proxy e os stubs (tanto proxy como stubs estão em conformidade com a interface).

-Lmakefile gera as regras que executam esse comando no build tempo e permitem que você inclua android.hardware.foo-V1.0-java e um link de acordo com o arquivos adequados. Um script que faz isso automaticamente para um projeto cheio de interfaces podem ser encontradas em hardware/interfaces/update-makefiles.sh. Os caminhos neste exemplo são relativos; hardwares/interfaces podem ser um na sua árvore de código para que você possa desenvolver uma HAL antes publicá-lo.

Executar um serviço

A HAL fornece a interface IFoo, que precisa tornar para o framework pela interface IFooCallback. A A interface IFooCallback não está registrada pelo nome como detectável serviço Em vez disso, IFoo precisa conter um método como setFooCallback(IFooCallback x)

Para configurar o IFooCallback da versão 1.0 do pacote android.hardware.foo, adicionar android.hardware.foo-V1.0-java para 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 implementa a interface IFoo em todas é possível que, em um determinado dispositivo, o serviço forneça recursos adicionais implementados na extensão de interface IBetterFoo, da seguinte forma:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Chamar código ciente da interface estendida pode usar o Método Java castFrom() para transmitir com segurança a interface base para o 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.
}