Questa pagina descrive come registrare e individuare i servizi e come inviarli
a un servizio chiamando i metodi definiti nelle interfacce in .hal
.
Registra servizi
È possibile registrare i server di interfaccia HIDL (oggetti che implementano l'interfaccia) come servizi con nome. Il nome registrato non deve essere necessariamente correlato all'interfaccia o il nome del pacchetto. Se non viene specificato alcun nome, viene visualizzato il nome "default" ; questo dovrebbe da utilizzare per HAL che non devono registrare due implementazioni dello stesso a riga di comando. Ad esempio, la chiamata C++ per la registrazione al servizio definita in è la seguente:
status_t status = myFoo->registerAsService(); status_t anotherStatus = anotherFoo->registerAsService("another_foo_service"); // if needed
La versione di un'interfaccia HIDL è inclusa nell'interfaccia stessa. È
automaticamente associati alla registrazione del servizio e possono essere recuperati tramite
chiamata al metodo (android::hardware::IInterface::getInterfaceVersion()
)
su tutte le interfacce HIDL. Gli oggetti server non devono essere registrati e possono essere passati
tramite parametri del metodo HIDL a un altro processo che effettua chiamate al metodo HIDL
al server.
Scopri i servizi
Le richieste per codice client vengono effettuate per una determinata interfaccia in base al nome e
della versione, chiamando getService
sulla classe HAL desiderata:
// C++ sp<V1_1::IFooService> service = V1_1::IFooService::getService(); sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service"); // Java V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */); V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);
Ogni versione di un'interfaccia HIDL viene trattata come un'interfaccia separata. Pertanto,
IFooService
versione 1.1 e IFooService
versione 2.2
possono essere registrati come "foo_service" e
getService("foo_service")
su entrambe le interfacce consente la registrazione
per quella interfaccia. Questo è il motivo per cui, nella maggior parte dei casi, non è necessario specificare
da fornire per la registrazione o il rilevamento (che significa nome "predefinito").
Anche il Vendor Interface Object ha un ruolo nel metodo di trasporto
l'interfaccia restituita. Per un'interfaccia IFoo
nel pacchetto
android.hardware.foo@1.0
, l'interfaccia restituita da
IFoo::getService
utilizza sempre il metodo di trasporto dichiarato per
android.hardware.foo
nel manifest del dispositivo, se esiste la voce.
Se il metodo di trasporto non è disponibile, viene restituito nullptr.
In alcuni casi, potrebbe essere necessario continuare immediatamente anche senza
scaricare il servizio. Ciò può accadere, ad esempio, quando un client vuole
gestire le notifiche di servizio direttamente o in un programma di diagnostica (ad esempio,
atrace
) che deve recuperare tutti gli hwservices e recuperarli. Nella
in questo caso, vengono fornite API aggiuntive, ad esempio tryGetService
in C++ o
getService("instance-name", false)
in Java. L'API legacy
Anche getService
fornito in Java deve essere utilizzato con il servizio
notifiche. L'uso di questa API non evita la condizione di gara in cui un server
si registra dopo che il client la richiede con una di queste API senza nuovi tentativi.
Notifiche di decesso in servizio
I clienti che vogliono ricevere una notifica quando un servizio muore possono morire inviate dal framework. Per ricevere le notifiche, il cliente devono:
- Crea sottoclasse della classe/interfaccia HIDL
hidl_death_recipient
(in C++ non in formato HIDL). - Esegui l'override del metodo
serviceDied()
. - Crea un'istanza di un oggetto della sottoclasse
hidl_death_recipient
. - Chiama il metodo
linkToDeath()
sul servizio da monitorare. passa nell'oggetto dell'interfaccia diIDeathRecipient
. Tieni presente che non acquisisce la proprietà del destinatario del decesso o del proxy su cui .
Un esempio di pseudocodice (C++ e Java sono simili):
class IMyDeathReceiver : hidl_death_recipient { virtual void serviceDied(uint64_t cookie, wp<IBase>& service) override { log("RIP service %d!", cookie); // Cookie should be 42 } }; .... IMyDeathReceiver deathReceiver = new IMyDeathReceiver(); m_importantService->linkToDeath(deathReceiver, 42);
Lo stesso destinatario del decesso può essere registrato su più servizi diversi.
Trasferimento dati
I dati possono essere inviati a un servizio richiamando i metodi definiti nelle interfacce in
.hal
file. Esistono due tipi di metodi:
- I metodi di blocco attendono che il server generi un o il risultato finale.
- I metodi monodirezionali inviano i dati in una sola direzione e non bloccare. Se la quantità di dati in corso nelle chiamate RPC supera l'implementazione limiti, le chiamate potrebbero bloccare o restituire un'indicazione di errore (il comportamento non ancora determinato).
Un metodo che non restituisce un valore, ma non è dichiarato come
oneway
sta ancora bloccando.
Tutti i metodi dichiarati in un'interfaccia HIDL vengono chiamati in un'unica direzione, direttamente dall'HAL o dall'HAL. L'interfaccia non specifica quale in cui viene chiamato. Architetture che necessitano di chiamate l'HAL deve fornire due (o più) interfacce nel pacchetto HAL e fornire nell'interfaccia appropriata per ogni processo. Le parole cliente e server vengono utilizzati in relazione alla direzione di chiamata dell'interfaccia Ad esempio, l'HAL può essere un server di un'interfaccia e un client di un'altra a riga di comando).
Callback
La parola callback si riferisce a due diversi concetti, distinti per callback sincrono e callback asincrono.
I callback sincrono vengono utilizzati in alcuni metodi HIDL che restituiscono e i dati di Google Cloud. Un metodo HIDL che restituisce più di un valore (o un solo valore di tipo non primitivo) restituisce i risultati tramite una funzione di callback. Se solo uno viene restituito ed è un tipo primitivo; non viene utilizzato un callback e viene restituito dal metodo. Il server implementa i metodi HIDL e il client implementa i callback.
I callback asincroni consentono al server di un'interfaccia HIDL di
ricevere chiamate. Ciò viene fatto passando un'istanza di una seconda interfaccia
attraverso la prima interfaccia. Il client della prima interfaccia deve agire come
del secondo server. Il server della prima interfaccia può richiamare metodi sul
secondo oggetto dell'interfaccia. Ad esempio, un'implementazione HAL può inviare informazioni
in modo asincrono al processo che lo utilizza richiamando i metodi su una
o l'oggetto interfaccia creato e pubblicato da quel processo. Metodi nelle interfacce utilizzate
per il callback asincrono potrebbe bloccarlo (e restituire valori al chiamante).
o oneway
. Ad esempio, consulta "Callback asincroni" nel
HIDL C++.
Per semplificare la proprietà della memoria, le chiamate ai metodi e i callback
in
e non supportano out
o
Parametri inout
.
Limiti per transazione
Non sono imposti limiti per transazione alla quantità di dati inviati con l'HIDL
e i callback. Tuttavia, le chiamate che superano i 4 kB per transazione
considerati eccessivi. Come vedi, riprogettare l'interfaccia HIDL in questione
è consigliato. Un'altra limitazione sono le risorse disponibili per l'HIDL
per gestire più transazioni simultanee. Più di uno
transazioni possono essere in corso contemporaneamente a causa di più thread o
processi l'invio di chiamate a un processo o più chiamate oneway
che
non vengono gestite rapidamente dal processo di ricezione. Lo spazio totale massimo
per impostazione predefinita è di 1 MB.
In un'interfaccia ben progettata, il superamento di questi limiti delle risorse non dovrebbe accadono; In caso affermativo, la chiamata che li ha superati può bloccarsi le risorse diventano disponibili o segnalano un errore di trasporto. Ogni occorrenza il superamento dei limiti per transazione o l'overflow delle risorse di implementazione HIDL vengono registrate le transazioni in corso aggregate per facilitare il debug.
Implementazioni dei metodi
HIDL genera file di intestazione che dichiarano i tipi, i metodi e nella lingua di destinazione (C++ o Java). Il prototipo di un sistema HIDL e callback è uguale per il codice client e server. HIDL fornisce le implementazioni proxy dei metodi sul lato chiamante, che organizzano i dati per il trasporto IPC, e lo stub il codice lato destinatario che passa i dati alle implementazioni da parte degli sviluppatori i metodi.
Il chiamante di una funzione (metodo HIDL o callback) è proprietario dei dati strutture passate alla funzione e ne conserva la proprietà dopo la chiamata; nel in tutti i casi il destinatario non ha bisogno di liberare o rilasciare lo spazio di archiviazione.
- In C++, i dati potrebbero essere di sola lettura (i tentativi di scrittura possono causare un errore segmentazione) e sono validi per tutta la durata della chiamata. Il cliente può copiare i dati per propagarli oltre la chiamata.
- In Java, il codice riceve una copia locale dei dati (un normale oggetto Java), che potrebbe conservare e modificare o consentire il garbage collection.
Trasferimento di dati non RPC
HIDL ha due modi per trasferire i dati senza utilizzare una chiamata RPC: e una coda di messaggi rapida (FMQ), entrambe supportate solo in C++.
- Ricordo condiviso. Il tipo HIDL integrato
memory
viene utilizzato per passare un oggetto che rappresenta la memoria condivisa che è stata allocata. Può essere utilizzato in un processo di ricezione per mappare la memoria condivisa. - Coda di messaggi rapidi (FMQ). HIDL fornisce un messaggio basato su modello
un tipo di coda che implementa il passaggio dei messaggi senza attesa. Non usa il kernel
o scheduler in modalità passthrough o binderizzata (la comunicazione tra dispositivi
queste proprietà). Di solito, l'HAL imposta la sua fine della coda,
creando un oggetto che può essere passato attraverso RPC mediante un parametro
Tipo HIDL
MQDescriptorSync
oMQDescriptorUnsync
. Questo può essere utilizzato dal processo di ricezione per impostare l'altra estremità della coda.- Le code di sincronizzazione non possono superare l'overflow e possono averne solo una Reader.
- Le code non sincronizzate possono superare l'overflow e possono avere molti lettori, ognuno dei quali deve leggere i dati nel tempo o perderli.
Per ulteriori dettagli su FMQ, consulta Coda di messaggi rapidi (FMQ).