Servizi e trasferimento di dati

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:

  1. Crea sottoclasse della classe/interfaccia HIDL hidl_death_recipient (in C++ non in formato HIDL).
  2. Esegui l'override del metodo serviceDied().
  3. Crea un'istanza di un oggetto della sottoclasse hidl_death_recipient.
  4. Chiama il metodo linkToDeath() sul servizio da monitorare. passa nell'oggetto dell'interfaccia di IDeathRecipient. 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 o MQDescriptorUnsync. 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.
    di Gemini Advanced. Nessuno dei due tipi è consentito per l'underflow (lettura da una coda vuota non riuscita) e ogni tipo può avere un solo writer.

Per ulteriori dettagli su FMQ, consulta Coda di messaggi rapidi (FMQ).