Cada interface definida em um pacote HIDL tem a própria classe C++ gerada automaticamente dentro do namespace do pacote. Os clientes e servidores lidam com as interfaces maneiras diferentes:
- Os servidores implementam interfaces.
- Os clientes chamam métodos nas interfaces.
As interfaces podem ser registradas pelo nome pelo servidor ou transmitidas como parâmetros a métodos definidos por HIDL. Por exemplo, o código do framework pode disponibilizar para receber mensagens assíncronas da HAL e transmitir essa interface diretamente à HAL sem registrá-la.
Implementação do servidor
Um servidor que implementa a interface IFoo
precisa incluir o
Arquivo principal IFoo
que foi gerado automaticamente:
#include <android/hardware/samples/1.0/IFoo.h>
O cabeçalho é exportado automaticamente pela biblioteca compartilhada da
IFoo
para vincular. Exemplo de IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
Exemplo de esqueleto para uma implementação de servidor da interface IFoo:
// From the IFoo.h header using android::hardware::samples::V1_0::IFoo; class FooImpl : public IFoo { Return<void> someMethod(foo my_foo, someMethod_cb _cb) { vec<uint32_t> return_data; // Compute return_data _cb(return_data); return Void(); } ... };
Para disponibilizar a implementação de uma interface de servidor para um cliente, conseguem:
- Registre a implementação da interface com o
hwservicemanager
(mais detalhes abaixo),
e
OU
- Transmita a implementação da interface como um argumento de uma método de interface de usuário (para detalhes, consulte Assíncrono callbacks).
Ao registrar a implementação da interface, o
O processo hwservicemanager
monitora as interfaces HIDL registradas
em execução no dispositivo por nome e versão. Os servidores podem registrar uma interface HIDL
implementação por nome e os clientes podem solicitar implementações de serviço pelo nome.
e versão. Esse processo atende à interface HIDL
android.hidl.manager@1.0::IServiceManager
:
Cada arquivo de cabeçalho de interface HIDL gerado automaticamente (como IFoo.h
)
tem um método registerAsService()
que pode ser usado para registrar o
implementação de interface com o hwservicemanager
. O único
o argumento required é o nome das implementações de interface como clientes
use esse nome para extrair a interface do hwservicemanager
.
depois:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
O hwservicemanager
trata a combinação de
[package@version::interface, instance_name]
como exclusivos para ativar
interfaces diferentes (ou versões diferentes da mesma interface) para registrar
com nomes de instância idênticos e sem conflitos. Se você ligar
registerAsService()
usando exatamente a mesma versão do pacote, interface
e o nome da instância, o hwservicemanager
descarta a referência para o
serviço registrado anteriormente
e usa o novo.
Implementação do cliente
Assim como o servidor faz, um cliente precisa usar #include
em todas as interfaces
ele se refere a:
#include <android/hardware/samples/1.0/IFoo.h>
Um cliente pode conseguir uma interface de duas maneiras:
- Por
I<InterfaceName>::getService
(pelahwservicemanager
). - Com um método de interface
Cada arquivo de cabeçalho de interface gerado automaticamente tem um getService
estático.
que pode ser usado para recuperar uma instância de serviço do
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
Agora, o cliente tem uma interface IFoo
e pode chamar métodos para
como se fosse uma implementação de classe local. Na verdade, a implementação
pode ser executada no mesmo processo, em um processo diferente ou até mesmo em outro dispositivo
(com comunicação remota HAL). Como o cliente chamou getService
em uma
Objeto IFoo
incluído na versão 1.0
do pacote,
hwservicemanager
retorna uma implementação do servidor somente se esse
é compatível com clientes 1.0
. Na prática,
significa apenas implementações de servidor com a versão 1.n
(versão
x.(y+1)
de uma interface precisa estender (herdada de)
x.y
).
Além disso, o método castFrom
é fornecido para transmitir entre
interfaces diferentes. Esse método faz uma chamada IPC para o
para garantir que o tipo subjacente é igual ao que está sendo
solicitado. Se o tipo solicitado não estiver disponível, nullptr
será
retornados.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Callbacks assíncronos
Muitas implementações de HAL se comunicam com hardware assíncrono, o que significa eles precisam de uma forma assíncrona de notificar os clientes sobre novos eventos que o incidente. Uma interface HIDL pode ser usada como callback assíncrono porque o HIDL podem usar objetos de interface HIDL como parâmetros.
Exemplo de arquivo de interface IFooCallback.hal
:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
Exemplo de novo método em IFoo
que usa uma
Parâmetro IFooCallback
:
package android.hardware.samples@1.0; interface IFoo { struct Foo { int64_t someValue; handle myHandle; }; someMethod(Foo foo) generates (int32_t ret); anotherMethod() generates (vec<uint32_t>); registerCallback(IFooCallback callback); };
O cliente que usa a interface IFoo
é o
server da interface IFooCallback
; ele oferece
implementação de IFooCallback
:
class FooCallback : public IFooCallback { Return<void> sendEvent(uint32_t event_id) { // process the event from the HAL } Return<void> sendData(const hidl_vec<uint8_t>& data) { // process data from the HAL } };
Ele também pode simplesmente passar isso para uma instância existente do
Interface IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
O servidor que implementa o IFoo
recebe isso como uma
objeto sp<IFooCallback>
. Ele pode armazenar o callback e chamar
de volta ao cliente sempre que ele quiser usar essa interface.
Pessoas falecidas
Como as implementações de serviço podem ser executadas em um processo diferente,
que o processo que implementa uma interface morre enquanto o cliente permanece ativo.
Todas as chamadas em um objeto de interface hospedado em um processo que falhou falham
com um erro de transporte (isOK()
retorna false
). A única maneira de
se recuperar de uma falha é solicitar uma nova instância do serviço
chamando I<InterfaceName>::getService()
. Isso funciona apenas se
o processo que falhou reiniciou e registrou novamente os serviços com o
servicemanager
, o que geralmente é válido para implementações de HAL.
Em vez de lidar com isso de forma reativa, os clientes de uma interface
registrar um destinatário falecido para receber uma notificação quando um serviço for encerrado;
Para se registrar para receber essas notificações em uma interface IFoo
recuperada, uma
pode fazer o seguinte:
foo->linkToDeath(recipient, 1481 /* cookie */);
O parâmetro recipient
precisa ser uma implementação do
a interface android::hardware::hidl_death_recipient
fornecida pelo HIDL
que contém um único método serviceDied()
chamado
de um thread no conjunto de threads RPC quando o processo que hospeda a interface é encerrado:
class MyDeathRecipient : public android::hardware::hidl_death_recipient { virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) { // Deal with the fact that the service died } }
O parâmetro cookie
contém o cookie que foi transmitido com
linkToDeath()
, enquanto o parâmetro who
contém um
ponteiro fraco para o objeto que representa o serviço no cliente. Com o
chamada de exemplo fornecida acima, cookie
é igual a 1481 e who
igual a foo
.
Também é possível cancelar o registro de um destinatário falecido depois de registrá-lo:
foo->unlinkToDeath(recipient);