Cada interfaz definida en un paquete HIDL tiene su propia clase C++ generada automáticamente. dentro del espacio de nombres de su paquete. Los clientes y los servidores trabajan con las interfaces maneras diferentes:
- Los servidores implementan interfaces.
- Los clientes llaman a métodos en las interfaces.
El servidor puede registrar las interfaces por nombre o pasarlas como parámetros a los métodos definidos por HIDL. Por ejemplo, el código del framework puede entregar para recibir mensajes asíncronos de la HAL y pasar esa interfaz directamente al HAL sin registrarlo.
Implementación del servidor
Un servidor que implemente la interfaz IFoo
debe incluir el
Archivo de encabezado IFoo
que se generó automáticamente:
#include <android/hardware/samples/1.0/IFoo.h>
El encabezado se exporta automáticamente a través de la biblioteca compartida de la
IFoo
para vincular. Ejemplo IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
Ejemplo de esquema de una implementación de servidor de la interfaz de 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 que la implementación de una interfaz de servidor esté disponible para un cliente, puedes puede hacer lo siguiente:
- Registra la implementación de la interfaz con el
hwservicemanager
(consulta los detalles a continuación)
O
- Pasar la implementación de la interfaz como un argumento de un de interfaz de usuario (para detalles, consulta Acerca del devoluciones de llamada).
Cuando registres la implementación de la interfaz, el
El proceso hwservicemanager
realiza un seguimiento de las interfaces HIDL registradas.
que se ejecuta en el dispositivo por nombre y versión. Los servidores pueden registrar una interfaz HIDL
implementación por su nombre, y los clientes pueden solicitar implementaciones de servicios por su nombre
y la versión. Este proceso entrega la interfaz HIDL
android.hidl.manager@1.0::IServiceManager
Cada archivo de encabezado de interfaz HIDL generado automáticamente (como IFoo.h
)
tiene un método registerAsService()
que se puede usar para registrar el
la implementación de la interfaz con el hwservicemanager
. El único
El argumento required es el nombre de las implementaciones de la interfaz como clientes.
usar este nombre para recuperar la interfaz desde el archivo hwservicemanager
más adelante:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
hwservicemanager
trata la combinación de
[package@version::interface, instance_name]
como único para habilitar
diferentes interfaces (o diferentes versiones de la misma interfaz) para registrar
con nombres de instancia idénticos sin conflictos. Si llamas
registerAsService()
con exactamente la misma versión de paquete, interfaz
y el nombre de la instancia, hwservicemanager
descarta su referencia al
servicio registrado previamente y usa el nuevo.
Implementación del cliente
Al igual que el servidor, un cliente debe usar #include
en todas las interfaces.
se refiere a:
#include <android/hardware/samples/1.0/IFoo.h>
Un cliente puede obtener una interfaz de dos maneras:
- A través de
I<InterfaceName>::getService
(mediante lahwservicemanager
) - A través de un método de interfaz
Cada archivo de encabezado de interfaz generado automáticamente tiene un elemento getService
estático.
que se puede usar para recuperar una instancia de servicio de la
hwservicemanager
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
Ahora el cliente tiene una interfaz IFoo
y puede llamar a métodos para
como si fuera una implementación de clase local. En realidad, la implementación
pueden ejecutarse en el mismo proceso, en un proceso diferente o incluso en otro dispositivo
(con el modo remoto HAL). Como el cliente llamó a getService
en un
Se incluyó un objeto IFoo
en la versión 1.0
del paquete.
hwservicemanager
devuelve una implementación de servidor solo si esa
es compatible con clientes de 1.0
. En la práctica, esto
se refiere únicamente a implementaciones de servidor con la versión 1.n
(versión
Se debe extender el x.(y+1)
de una interfaz (heredar de)
x.y
).
Además, se proporciona el método castFrom
para convertir
con diferentes interfaces. Este método funciona haciendo una llamada IPC al control remoto
para asegurarse de que el tipo subyacente sea el mismo que el que se envía
solicitado. Si el tipo solicitado no está disponible, entonces nullptr
es
que se devuelven.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Devoluciones de llamada asíncronas
Muchas implementaciones de HAL existentes se comunican con hardware asíncrono, lo que significa necesitan una forma asíncrona de notificar a los clientes sobre eventos nuevos que tienen para determinar si se produjo un error. Una interfaz HIDL se puede usar como una devolución de llamada asíncrona porque este protocolo pueden tomar objetos de la interfaz HIDL como parámetros.
Ejemplo de archivo de interfaz IFooCallback.hal
:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
Ejemplo de método nuevo en IFoo
que toma un elemento
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); };
El cliente que usa la interfaz IFoo
es el
server de la interfaz IFooCallback
proporciona un
implementación 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 } };
También puede simplemente pasar eso por una instancia existente de la
Interfaz IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
El servidor que implementa IFoo
recibe esto como un
sp<IFooCallback>
. Puede almacenar la devolución de llamada y llamar
de vuelta al cliente cada vez que quiera usar esta interfaz.
Destinatarios de muertes
Dado que las implementaciones de servicios pueden ejecutarse en un proceso diferente, también puede suceder
que el proceso que implementa una interfaz termina mientras el cliente permanece activo.
Todas las llamadas realizadas en un objeto de la interfaz alojado en un proceso finalizado fallará.
con un error de transporte (isOK()
muestra false
). La única forma de
recuperarse de una falla es solicitar una nueva instancia del servicio
llamando a I<InterfaceName>::getService()
. Esto funciona solo si
el proceso que falló se reinició y volvió a registrar sus servicios con el
servicemanager
(que suele ser verdadero para las implementaciones de HAL).
En lugar de lidiar con esto de manera reactiva, los clientes de una interfaz también pueden
registrar un destinatario de la muerte para recibir una notificación cuando se cierre un servicio
Si deseas registrarte para recibir esas notificaciones en una interfaz IFoo
recuperada, se aplica un
puede hacer lo siguiente:
foo->linkToDeath(recipient, 1481 /* cookie */);
El parámetro recipient
debe ser una implementación del
Interfaz de android::hardware::hidl_death_recipient
proporcionada por HIDL
que contiene un solo método serviceDied()
llamado
de un subproceso en el grupo de subprocesos de RPC cuando el proceso que aloja la interfaz deja de estar disponible:
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 } }
El parámetro cookie
contiene la cookie que se pasó con
linkToDeath()
, mientras que el parámetro who
contiene un
un puntero débil al objeto que representa el servicio en el cliente. Con la
llamada de ejemplo anterior, cookie
es igual a 1481 y who
es igual a foo
.
También es posible cancelar el registro del destinatario de la muerte después de registrarlo:
foo->unlinkToDeath(recipient);