HIDL

Il linguaggio di definizione dell'interfaccia HAL o HIDL (pronunciato "hide-l") è un linguaggio di descrizione dell'interfaccia (IDL) per specificare l'interfaccia tra un HAL ei suoi utenti. Consente di specificare tipi e chiamate di metodo, raccolte in interfacce e pacchetti. Più in generale, HIDL è un sistema per la comunicazione tra codebase che può essere compilato in modo indipendente. A partire da Android 10, HIDL è deprecato e Android sta migrando per utilizzare AIDL ovunque.

HIDL è concepito per essere utilizzato per la comunicazione tra processi (IPC). La comunicazione tra i processi si riferisce a come Binderized . Per le librerie che devono essere collegati a un processo, una modalità passthrough è disponibile anche (non supportato in Java).

HIDL specifica le strutture di dati e le firme dei metodi, organizzate in interfacce (simili a una classe) che vengono raccolte in pacchetti. La sintassi di HIDL sembrerà familiare ai programmatori C++ e Java, sebbene con un diverso insieme di parole chiave. HIDL utilizza anche annotazioni in stile Java.

Design HIDL

L'obiettivo di HIDL è che il framework possa essere sostituito senza dover ricostruire gli HAL. HAL saranno costruiti da fornitori o produttori di SOC e messo in un /vendor partizione sul dispositivo, consentendo il quadro, nella sua partizione, per essere sostituito con un OTA senza ricompilare i HAL.

Il design HIDL bilancia le seguenti preoccupazioni:

  • Interoperabilità. Crea interfacce interoperabili affidabili tra i processi che possono essere compilati con varie architetture, toolchain e configurazioni di build. Le interfacce HIDL sono dotate di versione e non possono essere modificate dopo la pubblicazione.
  • Efficienza. HIDL tenta di ridurre al minimo il numero di operazioni di copia. I dati definiti da HIDL vengono consegnati al codice C++ in strutture dati di layout standard C++ che possono essere utilizzate senza scompattare. HIDL fornisce anche interfacce di memoria condivisa e, poiché gli RPC sono intrinsecamente alquanto lenti, HIDL supporta due modi per trasferire i dati senza utilizzare una chiamata RPC: memoria condivisa e Fast Message Queue (FMQ).
  • Intuitivo. HIDL evita spinoso questioni di proprietà della memoria utilizzando solo in parametri per RPC (vedi Interfaccia Android Definition Language (AIDL) ); i valori che non possono essere restituiti in modo efficiente dai metodi vengono restituiti tramite funzioni di callback. Né il passaggio di dati in HIDL per il trasferimento né la ricezione di dati da HIDL modificano la proprietà dei dati: la proprietà rimane sempre con la funzione chiamante. I dati devono persistere solo per la durata della funzione chiamata e possono essere distrutti immediatamente dopo il ritorno della funzione chiamata.

Utilizzo della modalità passthrough

Per aggiornare i dispositivi che eseguono versioni precedenti di Android ad Android O, puoi avvolgere sia gli HAL convenzionali (e legacy) in una nuova interfaccia HIDL che serve l'HAL in modalità binderizzata e con lo stesso processo (passthrough). Questo wrapping è trasparente sia per l'HAL che per il framework Android.

La modalità passthrough è disponibile solo per client e implementazioni C++. I dispositivi che eseguono versioni precedenti di Android non hanno HAL scritti in Java, quindi gli HAL Java sono intrinsecamente binderizzati.

Quando un .hal file viene compilato, hidl-gen produce un extra passthrough file di intestazione BsFoo.h in aggiunta alle intestazioni utilizzati per la comunicazione legante; Questo definisce intestazione funzioni da dlopen ed. Poiché gli HAL passthrough vengono eseguiti nello stesso processo in cui vengono chiamati, nella maggior parte dei casi i metodi passthrough vengono richiamati dalla chiamata di funzione diretta (stesso thread). oneway metodi eseguite nel proprio filo in quanto non sono destinati ad aspettare l'HAL elaborarli (Si intende qualsiasi HAL che usi oneway metodi in modalità passthrough devono essere thread-safe).

Dato un IFoo.hal , BsFoo.h avvolge i metodi HIDL generati per fornire funzionalità aggiuntive (come la realizzazione oneway operazioni eseguite in un altro thread). Questo file è simile a BpFoo.h , tuttavia, invece di trasmettere chiamate IPC utilizzando legante, le funzioni desiderate sono direttamente invocati. Implementazioni future di HAL possono fornire più implementazioni, come FooFast HAL e FooAccurate HAL. In questi casi, un file per ogni applicazione aggiuntiva sarebbe creata (ad esempio, PTFooFast.cpp e PTFooAccurate.cpp ).

HAL passanti leganti

È possibile associare implementazioni HAL che supportano la modalità passthrough. Dato un HAL un'interfaccia abcd@MN::IFoo , vengono creati due pacchetti:

  • abcd@MN::IFoo-impl . Contiene l'attuazione del HAL ed espone funzionano IFoo* HIDL_FETCH_IFoo(const char* name) . Sui dispositivi legacy, questo pacchetto è dlopen Ed e l'implementazione viene creata un'istanza utilizzando HIDL_FETCH_IFoo . È possibile generare il codice di base utilizzando hidl-gen e -Lc++-impl e -Landroidbp-impl .
  • abcd@MN::IFoo-service . Apre l'HAL passthrough e si registra come servizio associato, consentendo l'utilizzo della stessa implementazione HAL sia come passthrough che come binder.

Dato il tipo di IFoo , è possibile chiamare sp<IFoo> IFoo::getService(string name, bool getStub) per ottenere l'accesso a un'istanza di IFoo . Se getStub è vero, getService tentativi di aprire l'HAL solo in modalità passthrough. Se getStub è falso, getService tentativi di trovare un servizio binderized; se fallisce, prova a trovare il servizio passthrough. Il getStub parametro dovrebbe mai essere usato se non in defaultPassthroughServiceImplementation . (I dispositivi che si avviano con Android O sono dispositivi completamente binderizzati, quindi l'apertura di un servizio in modalità passthrough non è consentita.)

grammatica HIDL

In base alla progettazione, il linguaggio HIDL è simile al C (ma non utilizza il preprocessore C). Tutti punteggiatura non descritta di seguito (a parte l'ovvio uso di = e | ) fa parte della grammatica.

Nota: Per i dettagli su stile del codice HIDL, consultare la Guida Codice di stile .

  • /** */ indica un commento di documentazione. Questi possono essere applicati solo a dichiarazioni di tipo, metodo, campo ed enum.
  • /* */ Indica un commento su più righe.
  • // indica un commento alla fine della riga. Oltre a // , nuove righe sono le stesse di qualsiasi altro spazio bianco.
  • Nell'esempio di grammatica di seguito, il testo da // alla fine della linea non è parte della grammatica, ma è invece un commento alla grammatica.
  • [empty] significa che il termine può essere vuota.
  • ? dopo un letterale o un termine significa che è facoltativo.
  • ... indica sequenza contenente zero o più articoli di separare punteggiatura come indicato. Non ci sono argomenti variadici in HIDL.
  • Elementi di sequenza separati da virgole.
  • Il punto e virgola termina ogni elemento, compreso l'ultimo elemento.
  • MAIUSCOLE è un non terminale.
  • italics è una famiglia di token come integer o identifier (regole standard C parsing).
  • constexpr è una costante espressione stile C (ad esempio 1 + 1 e 1L << 3 ).
  • import_name è un nome di pacchetto o interfaccia, qualificato come descritto HIDL delle versioni .
  • Minuscole words sono segni letterali.

Esempio:

ROOT =
    PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... }  // not for types.hal
  | PACKAGE IMPORTS ITEM ITEM...  // only for types.hal; no method definitions

ITEM =
    ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
  |  safe_union identifier { UFIELD; UFIELD; ...};
  |  struct identifier { SFIELD; SFIELD; ...};  // Note - no forward declarations
  |  union identifier { UFIELD; UFIELD; ...};
  |  enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar
  |  typedef TYPE identifier;

VERSION = integer.integer;

PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;

PREAMBLE = interface identifier EXTENDS

EXTENDS = <empty> | extends import_name  // must be interface, not package

GENERATES = generates (FIELD, FIELD ...)

// allows the Binder interface to be used as a type
// (similar to typedef'ing the final identifier)
IMPORTS =
   [empty]
  |  IMPORTS import import_name;

TYPE =
  uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t |
 float | double | bool | string
|  identifier  // must be defined as a typedef, struct, union, enum or import
               // including those defined later in the file
|  memory
|  pointer
|  vec<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]

FIELD =
   TYPE identifier

UFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...};
  |  struct identifier { FIELD; FIELD; ...};
  |  union identifier { FIELD; FIELD; ...};
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SIZE =  // Must be greater than zero
     constexpr

ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION

ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)

ANNO_ENTRY =
     identifier=VALUE

VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations

ENUM_ENTRY =
     identifier
  |  identifier = constexpr

Terminologia

Questa sezione utilizza i seguenti termini relativi a HIDL:

legante Indica che HIDL viene utilizzato per chiamate di procedure remote tra processi, implementato su un meccanismo simile a Binder. Vedi anche passante.
richiamata, asincrono Interfaccia servita da un utente HAL, passata all'HAL (tramite un metodo HIDL) e chiamata dall'HAL per restituire i dati in qualsiasi momento.
richiamata, sincrono Restituisce i dati dall'implementazione del metodo HIDL di un server al client. Non utilizzato per i metodi che restituiscono void o un singolo valore primitivo.
cliente Processo che chiama metodi di una particolare interfaccia. Un processo HAL o framework può essere un client di un'interfaccia e un server di un'altra. Vedi anche passante.
si estende Indica un'interfaccia che aggiunge metodi e/o tipi a un'altra interfaccia. Un'interfaccia può estendere solo un'altra interfaccia. Può essere utilizzato per un incremento di versione minore nello stesso nome del pacchetto o per un nuovo pacchetto (ad es. un'estensione del fornitore) da costruire su un pacchetto precedente.
genera Indica un metodo di interfaccia che restituisce valori al client. Per restituire un valore non primitivo o più di un valore, viene generata una funzione di callback sincrona.
interfaccia Raccolta di metodi e tipi. Tradotto in una classe in C++ o Java. Tutti i metodi in un'interfaccia vengono chiamati nella stessa direzione: un processo client richiama metodi implementati da un processo server.
senso unico Quando applicato a un metodo HIDL, indica che il metodo non restituisce alcun valore e non si blocca.
pacchetto Raccolta di interfacce e tipi di dati che condividono una versione.
passante Modalità di HIDL in cui il server è una libreria condivisa, dlopen ndr dal cliente. In modalità passthrough, client e server sono lo stesso processo ma codebase separate. Utilizzato solo per portare codebase legacy nel modello HIDL. Vedi anche Binderized.
server Processo che implementa i metodi di un'interfaccia. Vedi anche passante.
trasporto Infrastruttura HIDL che sposta i dati tra il server e il client.
versione Versione di un pacchetto. Consiste di due numeri interi, maggiore e minore. Incrementi di versione minori possono aggiungere (ma non modificare) tipi e metodi.