Google si impegna a promuovere l'equità razziale per le comunità nere. Vedi come.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

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 e i suoi utenti. Consente di specificare tipi e chiamate di metodi, raccolti in interfacce e pacchetti. Più in generale, HIDL è un sistema di comunicazione tra codebase che può essere compilato in modo indipendente.

HIDL è destinato all'uso per la comunicazione tra processi (IPC). La comunicazione tra processi viene definita Binderized . Per le librerie che devono essere collegate a un processo, è disponibile anche una modalità passthrough (non supportata in Java).

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

Design HIDL

L'obiettivo di HIDL è che il framework può essere sostituito senza dover ricostruire gli HAL. Gli HAL verranno creati da fornitori o produttori di social media e inseriti in una partizione /vendor sul dispositivo, consentendo al framework, nella propria partizione, di essere sostituito con un OTA senza ricompilare gli HAL.

Il design HIDL bilancia le seguenti preoccupazioni:

  • Interoperabilità . Crea interfacce interoperabili in modo affidabile tra processi che possono essere compilati con varie architetture, toolchain e configurazioni di build. Le interfacce HIDL hanno la versione e non possono essere modificate dopo la loro pubblicazione.
  • Efficienza . HIDL tenta di ridurre al minimo il numero di operazioni di copia. I dati definiti da HIDL vengono consegnati al codice C ++ nelle strutture di dati di layout standard C ++ che possono essere utilizzate senza decomprimere. HIDL fornisce anche interfacce di memoria condivisa e, poiché gli RPC sono intrinsecamente un po 'lenti, HIDL supporta due modi per trasferire i dati senza utilizzare una chiamata RPC: memoria condivisa e Fast Message Queue (FMQ).
  • Intuitivo . HIDL evita i problemi spinosi della proprietà della memoria usando solo in parametri per RPC (vedi Android Interface Definition Language (AIDL) ); i valori che non possono essere restituiti in modo efficiente dai metodi vengono restituiti tramite le 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 su Android O, è possibile racchiudere gli HAL convenzionali (e legacy) in una nuova interfaccia HIDL che serve l'HAL in modalità binderized e 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 vincolati.

Quando viene compilato un file .hal , hidl-gen produce un file di intestazione passthrough extra BsFoo.h oltre alle intestazioni utilizzate per la comunicazione del raccoglitore; questa intestazione definisce le funzioni da dlopen . 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 oneway eseguiti nel proprio thread in quanto non sono destinati ad attendere che HAL li elabori (ciò significa che qualsiasi HAL che utilizza metodi oneway in modalità passthrough deve essere thread-safe).

Dato un IFoo.hal , BsFoo.h racchiude i metodi generati da HIDL per fornire funzionalità aggiuntive (come l'esecuzione di transazioni a senso oneway in un altro thread). Questo file è simile a BpFoo.h , tuttavia invece di trasferire chiamate IPC utilizzando il raccoglitore, le funzioni desiderate vengono invocate direttamente. Le future implementazioni di HAL potrebbero fornire molteplici implementazioni, come FooFast HAL e FooAccurate HAL. In tali casi, verrà creato un file per ogni implementazione aggiuntiva (ad esempio, PTFooFast.cpp e PTFooAccurate.cpp ).

Raccoglitore di HAL passanti

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

  • abcd@MN::IFoo-impl . Contiene l'implementazione dell'HAL ed espone la funzione IFoo* HIDL_FETCH_IFoo(const char* name) . Sui dispositivi legacy, questo pacchetto viene dlopen e l'implementazione viene istanziata utilizzando HIDL_FETCH_IFoo . È possibile generare il codice di base usando hidl-gen e -Lc++-impl -Landroidbp-impl e -Landroidbp-impl .
  • abcd@MN::IFoo-service . Apre l'HAL passthrough e si registra come un servizio binderized, consentendo di utilizzare la stessa implementazione HAL sia passthrough che binderized.

Dato il tipo IFoo , puoi chiamare sp<IFoo> IFoo::getService(string name, bool getStub) per accedere a un'istanza di IFoo . Se getStub è true, getService tenta di aprire l'HAL solo in modalità passthrough. Se getStub è falso, getService tenta di trovare un servizio vincolante; in caso contrario, prova a trovare il servizio passthrough. Il parametro getStub non deve mai essere utilizzato, tranne in defaultPassthroughServiceImplementation . (I dispositivi che si avviano con Android O sono dispositivi completamente vincolati, pertanto non è possibile aprire un servizio in modalità passthrough.)

Grammatica HIDL

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

Nota: per dettagli sullo stile del codice HIDL, consultare la Guida allo stile di codice .

  • /** */ 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 a fine riga. A parte // , le nuove righe sono le stesse di qualsiasi altro spazio bianco.
  • Nella grammatica di esempio seguente, il testo da // alla fine della riga non fa parte della grammatica ma è invece un commento sulla grammatica.
  • [empty] significa che il termine può essere vuoto.
  • ? seguire un letterale o un termine significa che è facoltativo.
  • ... indica una sequenza contenente zero o più elementi con punteggiatura separata come indicato. Non ci sono argomenti variadici in HIDL.
  • Le virgole separano gli elementi di sequenza.
  • I punti e virgola terminano ogni elemento, incluso l'ultimo elemento.
  • MAIUSCOLO non è un terminale.
  • italics è una famiglia di token come integer o identifier (regole di analisi C standard).
  • constexpr è un'espressione costante in stile C (come 1 + 1 e 1L << 3 ).
  • import_name è un nome di pacchetto o interfaccia, qualificato come descritto in HIDL Versioning .
  • Le words minuscole 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

Terminologia

Questa sezione utilizza i seguenti termini relativi a HIDL:

binderized Indica che HIDL viene utilizzato per chiamate di procedura remote tra processi, implementate su un meccanismo simile a Binder. Vedi anche passthrough .
callback, 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.
callback, sincrono Restituisce i dati dall'implementazione del metodo HIDL di un server al client. Non utilizzato per metodi che restituiscono void o un singolo valore di base.
cliente Processo che chiama i 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 passthrough .
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 con lo stesso nome di pacchetto o per un nuovo pacchetto (ad es. Un'estensione del fornitore) per 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 richiamata sincrona.
interfaccia Raccolta di metodi e tipi. Tradotto in una classe in C ++ o Java. Tutti i metodi in un'interfaccia sono chiamati nella stessa direzione: un processo client richiama i metodi implementati da un processo server.
senso unico Se applicato a un metodo HIDL, indica che il metodo non restituisce valori e non si blocca.
pacchetto Raccolta di interfacce e tipi di dati che condividono una versione.
passthrough Modalità di HIDL in cui il server è una libreria condivisa, dlopen dal client. In modalità passthrough, client e server sono lo stesso processo ma basi di codice separate. Utilizzato solo per portare basi di codice legacy nel modello HIDL. Vedi anche Binderized .
server Processo che implementa i 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, maggiore e minore. Incrementi di versione minori possono aggiungere (ma non modificare) tipi e metodi.