HIDL è basato su interfacce, un tipo astratto utilizzato nei linguaggi object-oriented 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 principale. Tutti i file che definiscono un pacchetto si trovano nella stessa directory. Ad esempio,
package android.hardware.example.extension.light@2.0
potrebbe 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/* |
frameworks/ correlati |
android.system.* |
system/hardware/interfaces/* |
correlati al sistema |
android.hidl.* |
system/libhidl/transport/* |
nucleo |
La directory del pacchetto contiene file con estensione .hal
. Ogni
file deve contenere un'istruzione package
che indichi il pacchetto e la
versione di cui fa parte il file. Il file types.hal
, se presente, non
definisce un'interfaccia, ma definisce i tipi di dati accessibili a ogni
interfaccia del pacchetto.
Definizione dell'interfaccia
A parte types.hal
, ogni altro file .hal
definisce
un'interfaccia. Un'interfaccia è in genere 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 devono e non possono essere dichiarati di nuovo nelle interfacce definite dall'utente o utilizzati in altro modo. Questi metodi includono:
ping
interfaceChain
interfaceDescriptor
notifySyspropsChanged
linkToDeath
unlinkToDeath
setHALInstrumentation
getDebugInfo
debug
getHashChain
Procedura di importazione
L'istruzione import
è il meccanismo HIDL per accedere alle interfacce e ai tipi di pacchetti in un altro pacchetto. Un'istruzione import
riguarda due entità:
- L'entità di importazione, che può essere un pacchetto o un'interfaccia
- L'entità importata, che può essere un pacchetto o un'interfaccia
L'entità di importazione è determinata dalla posizione dell'istruzione import
. Quando l'istruzione si trova all'interno di un types.hal
del pacchetto, gli elementi importati sono visibili all'intero pacchetto. Si tratta di un'importazione a livello di pacchetto. Quando l'istruzione si trova all'interno di un
file di interfaccia, l'entità di importazione è l'interfaccia stessa; si tratta di un'importazione
a livello di interfaccia.
L'entità importata è determinata dal valore dopo la parola chiave import
. Il valore non deve essere un nome completo. Se un componente viene omesso, viene compilato automaticamente con le informazioni del pacchetto corrente.
Per i valori completamente qualificati, sono supportati i seguenti casi di importazione:
- Importazioni di pacchetti completi. Se il valore è un nome del pacchetto e una versione (la 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 l'interfaccia vengono importati nell'entità di importazione. - Un UDT definito in
types.hal
, quindi solo questo UDT viene importato nell'entità di importazione (gli altri tipi intypes.hal
non vengono importati).
- Un'interfaccia, il
- Importazioni solo di tipi. Se il valore utilizza la sintassi di un'importazione parziale descritta sopra, ma con la parola chiave
types
anziché un nome di interfaccia, vengono importati solo gli UDT intypes.hal
del pacchetto designato.
L'entità che esegue l'importazione ottiene l'accesso a una combinazione di:
- Le UDT comuni del pacchetto importato definite in
types.hal
. - Le interfacce del pacchetto importato (per un'importazione dell'intero pacchetto) o l'interfaccia specificata (per un'importazione parziale) ai fini della loro chiamata, del passaggio di handle e/o dell'eredità.
L'istruzione di importazione utilizza la sintassi del nome completo del tipo 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 uno dei seguenti tre tipi:
- L'interfaccia può aggiungere funzionalità a un'altra, incorporando la sua API immutata.
- Un pacchetto può aggiungere funzionalità a un altro, incorporando la relativa API senza modifiche.
- L'interfaccia può importare tipi da un pacchetto o da un'interfaccia specifica.
Un'interfaccia può estendere solo un'altra interfaccia (non è ammessa l'eredità multipla).
Ogni 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
si basa su (estende) un'interfaccia IFoo
nella versione 1.2 del pacchetto original
e viene creata una versione 1.3 del pacchetto original
, la versione 4.1 di IBar
non può estendere la versione 1.3 di IFoo
. La versione 4.1 di IBar
deve invece estendere la versione 4.0 di IBar
, che è legata alla versione 1.2 di IFoo
.
Se lo si desidera, la versione 5.0 di IBar
può estendere la versione 1.3 di IFoo
.
Le estensioni dell'interfaccia non implicano dipendenza dalle librerie o inclusione di più HAL nel codice generato: importano semplicemente le definizioni di metodo e struttura di dati a livello di HIDL. Ogni metodo in un HAL deve essere implementato in quell'HAL.
Estensioni del fornitore
In alcuni casi, le estensioni del fornitore vengono implementate come sottoclasse dell'oggetto base che rappresenta l'interfaccia di base che estendono. Lo stesso oggetto viene registrato con il nome e la versione HAL di base e con il nome e la versione HAL dell'estensione (del fornitore).
Controllo delle versioni
I pacchetti sono versionati e le interfacce hanno la versione del pacchetto. Le versioni sono espresse in due numeri interi, major.minor.
- 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 secondarie sono compatibili con le versioni precedenti. L'incremento del numero secondario indica che la versione più recente è completamente compatibile con la versione precedente. È possibile aggiungere nuove strutture di dati e metodi, ma non è possibile modificare le strutture di dati o le firme dei metodi esistenti.
Su un dispositivo possono essere presenti contemporaneamente più versioni principali o secondarie di un HAL. Tuttavia, è preferibile una versione secondaria a una maggiore perché il codice client che funziona con un'interfaccia della versione secondaria precedente funziona anche con le versioni secondarie successive della stessa interfaccia. Per maggiori dettagli sul controllo delle versioni e sulle estensioni del fornitore, consulta Controllo delle versioni HIDL.
Riepilogo del layout dell'interfaccia
Questa sezione riassume come gestire un pacchetto di interfaccia HIDL (ad esempio
hardware/interfaces
) e consolida le informazioni presentate
nella sezione HIDL. Prima di leggere, assicurati di conoscere i concetti di versionamento HIDL, hashing con hidl-gen, i dettagli del lavoro con HIDL in generale e le seguenti definizioni:
Termine | Definizione |
---|---|
Application Binary Interface (ABI) | Interfaccia di programmazione di un'applicazione, oltre a eventuali collegamenti binari richiesti. |
nome completo (fqName) | Nome per distinguere un tipo HIDL. Esempio:
android.hardware.foo@1.0::IFoo . |
Pacco | Pacchetto contenente un'interfaccia e tipi HIDL. Esempio:
android.hardware.foo@1.0 . |
package root | Pacchetto principale che contiene le interfacce HIDL. Esempio: l'interfaccia HIDL
android.hardware si trova nella directory principale del pacchetto
android.hardware.foo@1.0 . |
percorso principale del pacchetto | Posizione nella struttura della sorgente di Android a cui corrisponde la radice di un pacchetto. |
Per altre definizioni, consulta la terminologia HIDL.
Ogni file può essere trovato dalla mappatura della radice del pacchetto e dal suo nome completo
Le radici dei pacchetti vengono specificate per 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 deve trovarsi in $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal
.
In pratica, è consigliabile che un fornitore o un OEM denominato awesome
inserisca le proprie interfacce standard in vendor.awesome
. Una volta selezionato un percorso del pacchetto, non deve essere modificato in quanto è 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 dell'interfaccia coerente (inoltre, questo semplifica molto anche le
interfacce di gestione delle versioni).
La directory principale del pacchetto deve avere un file di controllo delle versioni
Se crei un percorso del pacchetto come
-r vendor.awesome:vendor/awesome/interfaces
, devi anche
creare il file
$ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt
, che deve contenere gli hash delle interfacce creati utilizzando l'opzione -Lhash
in
hidl-gen
(questo argomento è trattato ampiamente in
Hashing con
hidl-gen).
Le interfacce si trovano in posizioni indipendenti dal dispositivo
In pratica, consigliamo di condividere le interfacce tra i reparti. Ciò consente il riutilizzo e il test massimo del codice su diversi dispositivi e casi d'uso.