Interfacce

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:

  1. Registra l'implementazione dell'interfaccia con hwservicemanager (vedi i dettagli di seguito),

    OPPURE

  2. 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 (tramite hwservicemanager)
  • 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);