La lingua di definizione dell'interfaccia HAL, o HIDL, è una lingua di descrizione dell'interfaccia (IDL, Interface Description Language) che consente di specificare l'interfaccia tra un HAL e e i relativi utenti. HIDL consente di specificare tipi e chiamate di metodi, raccolti in interfacce e pacchetti. Più in generale, HIDL è un sistema di comunicazione tra codebase che possono essere compilati in modo indipendente.
HIDL è destinato a essere utilizzato per la comunicazione tra processi (IPC). Gli HAL creati con HDL chiamati HAL binderizzati in quanto possono comunicare con altri strati di architettura utilizzando binder tramite le chiamate IPC (Inter-Process Communication). Gli HAL Binderizzati vengono eseguiti in un processo separato dal client che li utilizza. Per librerie che devono essere collegate a un processo, un passthrough (non supportata in Java).
HIDL specifica le strutture di dati e le firme dei metodi, organizzate in interfacce (simile a una classe) raccolti in pacchetti. La sintassi delle HIDL è familiare a C++ e programmatori Java, ma con un set diverso parole chiave. HIDL utilizza anche annotazioni in stile Java.
Terminologia
Questa sezione utilizza i seguenti termini correlati all'HIDL:
legato | Indica che HIDL viene utilizzato per chiamate di procedure remote tra i processi, implementato in un meccanismo simile a Binder. Vedi anche passthrough. |
---|---|
il callback, il callback | Interfaccia pubblicata da un utente HAL, passata all'HAL (utilizzando un metodo HIDL) e chiamato dall'HAL per restituire i dati in qualsiasi momento. |
callback, sincrono | Restituisce i dati dall'implementazione del metodo HIDL di un server al client. Non utilizzato per i metodi che restituiscono un valore vuoto o un singolo valore primitivo. |
client | Processo che chiama metodi di una particolare interfaccia. Un framework HAL o Android un processo può essere un client di un'interfaccia e un server di un'altra. Vedi anche passthrough. |
si estende | Indica un'interfaccia che aggiunge metodi e/o tipi a un'altra interfaccia. Un'interfaccia può estendere solo un'altra interfaccia. Possono essere utilizzati per un minorenne incremento della versione nello stesso nome di pacchetto o per un nuovo pacchetto (ad es. per creare su un pacchetto meno recente. |
genera | Indica un metodo di interfaccia che restituisce valori al client. Da restituire un valore non primitivo, o più di un valore, una funzione di callback sincrona viene generata automaticamente. |
interfaccia | Raccolta di metodi e tipi. Tradotto in una classe in C++ o Java. Tutti in un'interfaccia vengono chiamati nella stessa direzione: un processo client richiama metodi implementati da un processo server. |
solo andata | Quando applicato a un metodo HIDL, indica che il metodo non restituisce valori e non viene bloccato. |
Pacco | Raccolta di interfacce e tipi di dati che condividono una versione. |
passthrough | Modalità HIDL in cui il server è una libreria condivisa, dlopen
dal cliente. In modalità passthrough, client e server sono lo stesso processo, ma
codebase separati. Utilizzato solo per inserire codebase legacy nel modello HIDL.
Vedi anche Binderized. |
server | Processo che implementa metodi di un'interfaccia. Vedi anche passthrough. |
trasporto | Infrastruttura HIDL che sposta i dati tra il server e il client. |
versione | Versione di un pacchetto. Composto da due numeri interi, maggiori e minori. Minorenne gli incrementi di versione possono aggiungere (ma non modificare) tipi e metodi. |
Design HIDL
L'obiettivo dell'HIDL è che il framework Android possa essere sostituito senza dover
ricreare gli HAL. Gli HAL vengono costruiti da fornitori o produttori dei SOC e inseriti in
partizione /vendor
sul dispositivo, attivando il framework Android autonomamente
da sostituire con una OTA senza ricompilare gli HAL.
Il design HIDL bilancia i seguenti aspetti:
- Interoperabilità. Crea interfacce interoperabili in modo affidabile tra i processi che possono essere compilati con varie architetture, toolchain, e configurazioni di build. Le interfacce HIDL sono soggette al controllo delle versioni e non possono essere modificate dopo la loro pubblicazione.
- Efficienza. L'HIDL cerca di ridurre al minimo il numero di copie operazioni. I dati definiti tramite HIDL vengono inviati al codice C++ nel layout standard C++ strutture di dati utilizzabili senza decompressione. HIDL fornisce inoltre servizi interfacce di memoria e, poiché le RPC sono intrinsecamente lente, HIDL supporta per trasferire i dati senza utilizzare una chiamata RPC: la memoria condivisa e Coda di messaggi (FMQ).
- Intuitive. HIDL evita i problemi spinosi di proprietà della memoria
utilizzando solo i parametri
in
per RPC (vedi Android Interface Definition Language (AIDL); che non possono essere efficienti da metodi vengono restituiti tramite funzioni di callback. Nessuno dei dati trasmessi alle HIDL per il trasferimento o la ricezione di dati dalla HIDL cambia la proprietà dei la proprietà rimane sempre con la funzione chiamante. I dati devono rimangono attive solo per la durata della funzione chiamata e possono essere eliminate subito dopo il ritorno della funzione chiamata.
Usa la modalità passthrough
Per aggiornare ad Android O i dispositivi con versioni precedenti di Android, puoi: raggruppano gli HAL convenzionali (e legacy) in una nuova interfaccia HIDL che gestisce HAL in modalità binderizzata e nello stesso processo (passthrough). Questo wrapping è sia per l'HAL che per il framework Android.
La modalità passthrough è disponibile solo per i client e le implementazioni C++. I dispositivi con versioni precedenti di Android non dispongono di HAL scritti in Java, quindi Gli HAL Java sono binderizzati intrinsecamente.
File di intestazione passthrough
Quando viene compilato un file .hal
, hidl-gen
genera un
file di intestazione passthrough aggiuntivo BsFoo.h
oltre alle intestazioni
utilizzati per le comunicazioni con binder; questa intestazione definisce le funzioni
dlopen
ed. Poiché gli HAL passthrough vengono eseguiti nello stesso processo in cui
vengono chiamati, nella maggior parte dei casi i metodi passthrough sono richiamati
chiamata di funzione (stesso thread). oneway
metodo eseguito nel proprio thread
non è prevista l'attesa che l'HAL li elabori (ciò significa che qualsiasi
che utilizza metodi oneway
in modalità passthrough deve essere sicura per thread).
Data un'istruzione IFoo.hal
, BsFoo.h
racchiude il codice generato dall'HIDL
metodi per fornire funzionalità aggiuntive (ad esempio, rendere oneway
transazioni eseguite in un altro thread). Questo file è simile a
BpFoo.h
, tuttavia, invece di passare le chiamate IPC tramite binder, la classe
le funzioni desiderate vengono richiamate direttamente. Implementazioni future degli HAL
può fornire molteplici implementazioni, come FooFast HAL e un
HAL impreciso. In questi casi, un file per ogni implementazione aggiuntiva
essere creati (ad es. PTFooFast.cpp
e
PTFooAccurate.cpp
).
Associazione degli HAL passthrough
Puoi vincolare le implementazioni HAL che supportano la modalità passthrough. Data un
Interfaccia HAL a.b.c.d@M.N::IFoo
, vengono creati due pacchetti:
a.b.c.d@M.N::IFoo-impl
. Contiene l'implementazione dell'HAL ed espone la funzioneIFoo* HIDL_FETCH_IFoo(const char* name)
. Attivato dispositivi precedenti, questo pacchetto èdlopen
ed e l'implementazione è creata conHIDL_FETCH_IFoo
. Puoi generare il codice di base utilizzandohidl-gen
,-Lc++-impl
e-Landroidbp-impl
.a.b.c.d@M.N::IFoo-service
. Apre l'HAL passthrough e si registra come servizio binderizzato, consentendo la stessa implementazione dell'HAL da utilizzare sia come passthrough che come binderizzati.
Dato il tipo IFoo
, puoi chiamare sp<IFoo>
IFoo::getService(string name, bool getStub)
per ottenere l'accesso a un'istanza
di IFoo
. Se getStub
è vero, getService
tenta di aprire l'HAL solo in modalità passthrough. Se getStub
è
falso, getService
tenta di trovare un servizio associato; se questo
un errore, prova a trovare il servizio passthrough. getStub
non deve mai essere usato, se non in
defaultPassthroughServiceImplementation
. (Dispositivi avviati con
Gli Android O sono dispositivi completamente vincolati, quindi l'apertura di un servizio in modalità passthrough
non è consentito).
Grammatica HIDL
Per progettazione, il linguaggio HIDL è simile al linguaggio C (ma non utilizza il linguaggio C
preprocessore). Tutta la punteggiatura non descritta di seguito (tranne l'uso evidente
di =
e |
) fa parte della grammatica.
Nota:per informazioni dettagliate sullo stile del codice HIDL, consulta le Guida di stile del codice.
/** */
indica un commento alla documentazione. Possono essere applicati solo per le dichiarazioni di valore di tipo, metodo, campo ed enum./* */
indica un commento su più righe.//
indica un commento alla fine della riga. A parte//
, i ritorni a capo sono uguali a tutti gli altri spazi vuoti.- Nell'esempio grammaticale riportato di seguito, il testo da
//
alla fine della riga non fa parte della grammatica, ma è un commento alla grammatica. [empty]
significa che il termine potrebbe essere vuoto.?
dopo un valore letterale o termine significa che è facoltativo....
indica una sequenza contenente zero o più elementi con separando la punteggiatura come indicato. Non ci sono argomenti variadi in HIDL.- Le virgole separano gli elementi di sequenza.
- I punti e virgola terminano ogni elemento, incluso l'ultimo.
- MAIUSCOLO è un non terminale.
italics
è una famiglia di token comeinteger
oidentifier
(standard C di analisi).constexpr
è un'espressione costante di stile C (ad esempio1 + 1
e1L << 3
).import_name
è un nome di pacchetto o interfaccia, qualificato come descritto in HIDL Controllo delle versioni.words
minuscolo sono token 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