Interfacce e funzionalità Pacchetti

HIDL è costruito attorno alle interfacce, un tipo astratto utilizzato nei linguaggi orientati agli oggetti per definire i comportamenti. Ogni interfaccia fa parte di un pacchetto.

Pacchetti

I nomi dei pacchetti possono avere sottolivelli come package.subpackage . La directory principale per i pacchetti HIDL pubblicati è hardware/interfaces o vendor/vendorName (ad esempio vendor/google per i dispositivi Pixel). Il nome del pacchetto forma una o più sottodirectory nella directory root; tutti i file che definiscono un pacchetto si trovano nella stessa directory. Ad esempio, package android.hardware.example.extension.light@2.0 può essere trovato in hardware/interfaces/example/extension/light/2.0 .

La tabella seguente elenca i prefissi e le posizioni dei pacchetti:

Prefisso del pacchetto Posizione Tipi di interfaccia
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* quadri/correlati
android.system.* system/hardware/interfaces/* sistema/relativo
android.hidl.* system/libhidl/transport/* nucleo

La directory del pacchetto contiene file con estensione .hal . Ogni file deve contenere un'istruzione package che nomina il pacchetto e la versione di cui fa parte il file. Il file types.hal , se presente, non definisce un'interfaccia ma definisce invece i tipi di dati accessibili a ogni interfaccia nel pacchetto.

Definizione dell'interfaccia

A parte types.hal , ogni altro file .hal definisce un'interfaccia. Un'interfaccia è generalmente definita come segue:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

Un'interfaccia senza una dichiarazione extends esplicita si estende implicitamente da android.hidl.base@1.0::IBase (simile a java.lang.Object in Java.) L'interfaccia IBase, importata implicitamente, dichiara diversi metodi riservati che non dovrebbero e non possono essere dichiarati nuovamente in interfacce definite dall'utente o utilizzate in altro modo. Questi metodi includono:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

Importazione

L'istruzione import è un meccanismo HIDL per accedere alle interfacce e ai tipi del pacchetto in un altro pacchetto. Una dichiarazione import riguarda due entità:

  • L'entità importatrice , che può essere un pacchetto o un'interfaccia; E
  • L' entità importata, che può essere anch'essa un pacchetto o un'interfaccia.

L'entità importatrice è determinata dall'ubicazione della dichiarazione import . Quando l'istruzione si trova all'interno del types.hal di un pacchetto, ciò che viene importato è visibile dall'intero pacchetto; questa è un'importazione a livello di pacchetto . Quando l'istruzione si trova all'interno di un file di interfaccia, l'entità importante è l'interfaccia stessa; questa è un'importazione a livello di interfaccia .

L'entità importata è determinata dal valore dopo la parola chiave import . Non è necessario che il valore sia un nome completo; se un componente viene omesso, viene automaticamente riempito con le informazioni del pacchetto corrente. Per i valori completi, sono supportati i seguenti casi di importazione:

  • Importazioni di pacchetti interi . Se il valore è il nome di un pacchetto e una versione (sintassi descritta di seguito), l'intero pacchetto viene importato nell'entità di importazione.
  • Importazioni parziali . Se il valore è:
    • Un'interfaccia, il types.hal del pacchetto e quell'interfaccia vengono importati nell'entità di importazione.
    • Un UDT definito in types.hal , quindi solo quell'UDT viene importato nell'entità importatrice (gli altri tipi in types.hal non vengono importati).
  • Importazioni di soli tipi . Se il valore utilizza la sintassi di un'importazione parziale descritta sopra, ma con la parola chiave types invece del nome dell'interfaccia, vengono importati solo gli UDT in types.hal del pacchetto designato.

L'entità importatrice ottiene l'accesso a una combinazione di:

  • Gli UDT comuni del pacchetto importato definiti in types.hal ;
  • Le interfacce del pacchetto importato (per un'importazione dell'intero pacchetto) o l'interfaccia specificata (per un'importazione parziale) allo scopo di richiamarle, passare loro gli handle e/o ereditare da essi.

L'istruzione import utilizza la sintassi del nome del tipo completo per fornire il nome e la versione del pacchetto o dell'interfaccia da importare:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

Eredità dell'interfaccia

Un'interfaccia può essere un'estensione di un'interfaccia definita in precedenza. Le estensioni possono essere di tre tipi:

  • L'interfaccia può aggiungere funzionalità ad un'altra, incorporando la sua API invariata.
  • Il pacchetto può aggiungere funzionalità a un altro, incorporando la sua API invariata.
  • L'interfaccia può importare tipi da un pacchetto o da un'interfaccia specifica.

Un'interfaccia può estendere solo un'altra interfaccia (nessuna ereditarietà multipla). Ciascuna interfaccia in un pacchetto con un numero di versione secondaria diverso da zero deve estendere un'interfaccia nella versione precedente del pacchetto. Ad esempio, se un'interfaccia IBar nella versione 4.0 del pacchetto derivative è basata su (estende) un'interfaccia IFoo nella versione 1.2 del pacchetto original e viene creata una versione 1.3 del pacchetto original , IBar versione 4.1 non può estendere la versione 1.3 di IFoo . Invece, IBar versione 4.1 deve estendere IBar versione 4.0, che è legata a IFoo versione 1.2. Se lo si desidera, la versione 5.0 IBar potrebbe estendere la versione 1.3 di IFoo .

Le estensioni dell'interfaccia non implicano dipendenza dalla libreria o inclusione tra HAL nel codice generato: importano semplicemente la struttura dei dati e le definizioni dei metodi a livello HIDL. Ogni metodo in un HAL deve essere implementato in quell'HAL.

Estensioni del fornitore

In alcuni casi, le estensioni del fornitore verranno implementate come sottoclasse dell'oggetto base che rappresenta l'interfaccia principale che estendono. Lo stesso oggetto verrà registrato con il nome e la versione HAL di base e con il nome e la versione HAL dell'estensione (fornitore).

Controllo delle versioni

I pacchetti hanno una versione e le interfacce hanno la versione del loro pacchetto. Le versioni sono espresse in due numeri interi, major . minore .

  • Le versioni principali non sono compatibili con le versioni precedenti. L'incremento del numero della versione principale reimposta il numero della versione secondaria su 0.
  • Le versioni minori sono retrocompatibili. L'incremento del numero minore indica che la versione più recente è completamente compatibile con la versione precedente. È possibile aggiungere nuove strutture dati e metodi, ma non è possibile modificare le strutture dati esistenti o le firme dei metodi.

Su un dispositivo possono essere presenti contemporaneamente più versioni principali o secondarie di un HAL. Tuttavia, una versione minore dovrebbe essere preferita rispetto a una versione maggiore perché il codice client che funziona con un'interfaccia di versione minore precedente funzionerà anche con le versioni minori successive della stessa interfaccia. Per ulteriori dettagli sul controllo delle versioni e sulle estensioni del fornitore, vedere Controllo delle versioni HIDL .

Riepilogo del layout dell'interfaccia

Questa sezione riassume come gestire un pacchetto di interfacce HIDL (come hardware/interfaces ) e consolida le informazioni presentate nella sezione HIDL. Prima di leggere, assicurati di avere familiarità con il controllo delle versioni HIDL , i concetti di hashing in Hashing con hidl-gen , i dettagli su come lavorare con HIDL in generale e le seguenti definizioni:

Termine Definizione
Interfaccia binaria dell'applicazione (ABI) Interfaccia di programmazione dell'applicazione + eventuali collegamenti binari richiesti.
Nome completo (fqName) Nome per distinguere un tipo hidl. Esempio: android.hardware.foo@1.0::IFoo .
Pacchetto Pacchetto contenente un'interfaccia e tipi HIDL. Esempio: android.hardware.foo@1.0 .
Radice del pacchetto Pacchetto root che contiene le interfacce HIDL. Esempio: l'interfaccia HIDL android.hardware si trova nel pacchetto root android.hardware.foo@1.0 .
Percorso radice del pacchetto Posizione nell'albero dei sorgenti Android a cui viene mappata la radice del pacchetto.

Per ulteriori definizioni, vedere Terminologia HIDL.

Ogni file può essere trovato dalla mappatura root del pacchetto e dal suo nome completo

Le radici del pacchetto vengono specificate in hidl-gen come argomento -r android.hardware:hardware/interfaces . Ad esempio, se il pacchetto è vendor.awesome.foo@1.0::IFoo e hidl-gen viene inviato -r vendor.awesome:some/device/independent/path/interfaces , il file di interfaccia dovrebbe trovarsi in $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal .

In pratica, si consiglia a un fornitore o OEM denominato awesome di inserire le proprie interfacce standard in vendor.awesome . Dopo che è stato selezionato il percorso di un pacchetto, non deve essere modificato poiché è integrato nell'ABI dell'interfaccia.

La mappatura del percorso del pacchetto deve essere univoca

Ad esempio, se hai -rsome.package:$PATH_A e -rsome.package:$PATH_B , $PATH_A deve essere uguale a $PATH_B per una directory di interfaccia coerente (questo rende anche molto più semplice il controllo delle versioni delle interfacce ).

La radice del pacchetto deve avere un file di controllo delle versioni

Se crei un percorso del pacchetto come -r vendor.awesome:vendor/awesome/interfaces , dovresti creare anche il file $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt , che dovrebbe contenere hash delle interfacce realizzate utilizzando -Lhash opzione in hidl-gen (questo è ampiamente discusso in Hashing con hidl-gen ).

Le interfacce vanno in posizioni indipendenti dal dispositivo

In pratica si consiglia di condividere le interfacce tra le filiali. Ciò consente il massimo riutilizzo del codice e il massimo test del codice su diversi dispositivi e casi d'uso.