Ogni interfaccia definita in un pacchetto HIDL ha una propria classe C++ generata automaticamente nello spazio dei nomi del pacchetto. Clienti e server gestiscono le interfacce in vari modi:
- I server implementano le interfacce.
- Metodi di chiamata dei client sulle interfacce.
Le interfacce possono essere registrate dal server per nome o trasmesse come ai metodi definiti HIDL. Ad esempio, il codice del framework può gestire per ricevere messaggi asincroni dall'HAL e trasmetterla direttamente all'HAL senza registrarlo.
Implementazione del server
Un server che implementa l'interfaccia IFoo
deve includere il campo
IFoo
file di intestazione generato automaticamente:
#include <android/hardware/samples/1.0/IFoo.h>
L'intestazione viene esportata automaticamente dalla libreria condivisa del
Interfaccia IFoo
a cui collegarti. Esempio IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
Scheletro di esempio per l'implementazione su server dell'interfaccia 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(); } ... };
Per rendere disponibile l'implementazione di un'interfaccia server a un client, è in grado di:
- Registra l'implementazione dell'interfaccia con
hwservicemanager
(vedi i dettagli di seguito),
OPPURE
- Passa l'implementazione dell'interfaccia come argomento di un (per i dettagli, consulta Asynchronous callback).
Quando registri l'implementazione dell'interfaccia,
Il processo hwservicemanager
tiene traccia delle interfacce HIDL registrate
in esecuzione sul dispositivo per nome e versione. I server possono registrare un'interfaccia HIDL
implementazione per nome e i clienti possono richiedere implementazioni del servizio per nome
e la versione. Questo processo gestisce l'interfaccia HIDL.
android.hidl.manager@1.0::IServiceManager
.
Ogni file di intestazione HIDL generato automaticamente (ad esempio IFoo.h
)
ha un metodo registerAsService()
che può essere usato per registrare
dell'interfaccia utente con hwservicemanager
. L'unico
l'argomento richiesto è il nome delle implementazioni dell'interfaccia come client
usa questo nome per recuperare l'interfaccia da hwservicemanager
più tardi:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
Il hwservicemanager
tratta la combinazione di
[package@version::interface, instance_name]
come univoco da attivare
interfacce diverse (o versioni diverse della stessa interfaccia) per registrare
con nomi di istanze identici senza conflitti. Se chiami
registerAsService()
con la stessa versione del pacchetto, interfaccia
e il nome dell'istanza, hwservicemanager
elimina il suo riferimento
registrato in precedenza e utilizza quello nuovo.
Implementazione client
Così come fa il server, un client deve #include
ogni interfaccia
si riferisce a:
#include <android/hardware/samples/1.0/IFoo.h>
Un client può ottenere un'interfaccia in due modi:
- Tramite
I<InterfaceName>::getService
(tramitehwservicemanager
) - Tramite un metodo di interfaccia
Ogni file di intestazione dell'interfaccia generato automaticamente ha un elemento getService
statico
che può essere utilizzato per recuperare un'istanza di servizio
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
Ora il client ha un'interfaccia IFoo
e può richiamare metodi
come se si trattasse di un'implementazione
di classe locale. In realtà, l'implementazione
può essere eseguita nello stesso processo, in un altro processo o anche su un altro dispositivo
(con comunicazione remota dell'HAL). Perché il cliente ha chiamato getService
su una
Oggetto IFoo
incluso dalla versione 1.0
del pacchetto,
hwservicemanager
restituisce un'implementazione del server solo se
è compatibile con i client 1.0
. In pratica, questo
indica solo le implementazioni del server con versione 1.n
(versione
La proprietà x.(y+1)
di un'interfaccia deve estendersi (ereditare da)
x.y
).
Viene inoltre fornito il metodo castFrom
per trasmettere
interfacce diverse. Questo metodo funziona effettuando una chiamata IPC al telecomando
per assicurarsi che il tipo sottostante sia identico a quello creato
richiesto. Se il tipo richiesto non è disponibile, nullptr
è
restituito.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Callback asincroni
Molte implementazioni HAL esistenti comunicano con l'hardware asincrono, hanno bisogno di un metodo asincrono per informare i clienti dei nuovi eventi si è verificato un errore. Un'interfaccia HIDL può essere utilizzata come callback asincrono poiché HIDL possono assumere come parametri gli oggetti dell'interfaccia HIDL.
File di interfaccia di esempio IFooCallback.hal
:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
Esempio di nuovo metodo in IFoo
che utilizza un
Parametro 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); };
Il client che utilizza l'interfaccia IFoo
è il
server dell'interfaccia IFooCallback
; fornisce un
implementazione di 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 } };
Può anche semplicemente trasmetterlo a un'istanza esistente
Interfaccia IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
Il server che implementa IFoo
riceve questo messaggio come
Oggetto sp<IFooCallback>
. Può memorizzare il callback e chiamare
al client ogni volta che vuole usare questa interfaccia.
Destinatari del decesso
Poiché le implementazioni dei servizi possono essere eseguite in un processo diverso, può verificarsi
il processo di implementazione di un'interfaccia scompare mentre il client rimane attivo.
Le chiamate su un oggetto di interfaccia ospitato in un processo terminato hanno esito negativo
con un errore di trasporto (isOK()
restituisce false
). L'unico modo per
il ripristino da un errore di questo tipo consiste nel richiedere una nuova istanza del servizio
chiamata I<InterfaceName>::getService()
. Funziona solo se
il processo che si è arrestato in modo anomalo è stato riavviato e ha registrato nuovamente i suoi servizi con
servicemanager
(che in genere è vero per le implementazioni HAL).
Invece di affrontare questo problema in modo reattivo, i client di un'interfaccia possono anche
Registrare un destinatario della morte per ricevere una notifica quando un servizio muore.
Per registrarti per ricevere queste notifiche sull'interfaccia IFoo
recuperata, è necessario un
Il client può:
foo->linkToDeath(recipient, 1481 /* cookie */);
Il parametro recipient
deve essere un'implementazione del metodo
android::hardware::hidl_death_recipient
fornita da HIDL,
che contiene un singolo metodo serviceDied()
chiamato
da un thread nel pool di thread RPC quando il processo che ospita l'interfaccia muore:
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 } }
Il parametro cookie
contiene il cookie che è stato trasmesso con
linkToDeath()
, mentre il parametro who
contiene un parametro
puntatore debole all'oggetto che rappresenta il servizio nel client. Con
chiamata di esempio sopra indicata, cookie
è uguale a 1481 e who
è uguale a foo
.
È anche possibile annullare la registrazione di un destinatario del decesso dopo averlo registrato:
foo->unlinkToDeath(recipient);