HIDL richiede che ogni interfaccia scritta in HIDL sia sottoposta al controllo delle versioni. Dopo un HAL a riga di comando è pubblicata, è bloccata ed eventuali altre modifiche devono essere apportate nuova versione dell'interfaccia. Una determinata interfaccia pubblicata modificato, può essere esteso tramite un'altra interfaccia.
Struttura del codice HIDL
Il codice HIDL è organizzato in termini definiti dall'utente di tipi, interfacce e pacchetti:
- Tipi definiti dall'utente. L'architettura HIDL fornisce accesso a una serie tipi di dati primitivi che possono essere utilizzati per comporre tipi più complessi tramite strutture, unioni ed enumerazioni. Gli UDT vengono passati ai metodi interfacce e può essere definito a livello di pacchetto (comune a tutti interfacce) o localmente a un'interfaccia.
- Interfacce. Come componente di base dell'architettura HIDL, un'interfaccia è composto da dichiarazioni UDT e di metodo. Le interfacce possono ereditare anche un'altra interfaccia.
- Pacchetti. Organizza le interfacce HIDL correlate e i dati
tipi su cui operano. Un pacchetto è identificato da un nome e da una versione e
include:
- File di definizione del tipo di dati denominato
types.hal
. - Zero o più interfacce, ciascuna nel proprio file
.hal
.
- File di definizione del tipo di dati denominato
Il file di definizione del tipo di dati types.hal
contiene solo funzioni definite dall'utente (tutte
gli UDT a livello di pacchetto vengono conservati in un unico file). Rappresentazioni nel target
sono disponibili per tutte le interfacce del pacchetto.
Filosofia del controllo delle versioni
Un pacchetto HIDL (ad esempio android.hardware.nfc
), dopo essere stato
pubblicato per una determinata versione (ad esempio 1.0
), è immutabile; questo elemento
non possono essere modificate. Modifiche alle interfacce nel pacchetto o a qualsiasi
le modifiche agli UDT possono avvenire solo in un altro pacchetto.
In HIDL, il controllo delle versioni si applica a livello di pacchetto, non a livello di interfaccia. e tutte le interfacce e le UDT di un pacchetto condividono la stessa versione. Pacco le versioni seguono la semantica controllo delle versioni senza i componenti a livello di patch e build-metadata. All'interno di un oggetto dato pacchetto, un bump di versione secondaria implica che la nuova versione è compatibile con le versioni precedenti del pacchetto e con un versione implica che la nuova versione del pacchetto compatibile con le versioni precedenti del pacchetto.
Concettualmente, un pacchetto può essere correlato a un altro in uno dei seguenti modi:
- Assolutamente no.
- Estensibilità compatibile con le versioni precedenti a livello di pacchetto. Questo
si verifica per i nuovi uprev della versione secondaria (la prossima revisione incrementata) di un pacchetto;
il nuovo pacchetto ha lo stesso nome e la stessa versione principale del vecchio pacchetto, ma una
una versione secondaria superiore. A livello di funzionalità, il nuovo pacchetto è un soprainsieme del vecchio
pacchetto, cioè:
- Le interfacce di primo livello del pacchetto principale sono presenti nel nuovo pacchetto,
sebbene le interfacce possano avere nuovi metodi, nuovi UDT locali dell'interfaccia (il
a livello di interfaccia descritta di seguito) e nuovi UDT in
types.hal
. - Puoi anche aggiungere nuove interfacce al nuovo pacchetto.
- Tutti i tipi di dati del pacchetto principale sono presenti nel nuovo pacchetto e può essere gestito con i metodi (possibilmente reimplementati) del pacchetto precedente.
- È possibile aggiungere nuovi tipi di dati anche per l'utilizzo con entrambi i nuovi metodi di aumento delle entrate interfacce esistenti o di nuove interfacce.
- Le interfacce di primo livello del pacchetto principale sono presenti nel nuovo pacchetto,
sebbene le interfacce possano avere nuovi metodi, nuovi UDT locali dell'interfaccia (il
a livello di interfaccia descritta di seguito) e nuovi UDT in
- Estensibilità compatibile con le versioni precedenti a livello di interfaccia. Il nuovo
può anche estendere il pacchetto originale consistendo in pacchetti logicamente separati
che forniscono semplicemente funzionalità aggiuntive e non quella principale.
A questo scopo, potrebbe essere opportuno quanto segue:
- Le interfacce nel nuovo pacchetto devono fare ricorso ai tipi di dati del vecchio pacchetto pacchetto.
- Le interfacce nei nuovi pacchetti possono estendere le interfacce di una o più vecchie pacchetti.
- Estendi l'incompatibilità con le versioni precedenti dell'originale. Si tratta di un l'uprev della versione principale del pacchetto e non c'è alcuna correlazione tra i due. In alcuni casi, può essere espressa con una combinazione tipi dalla versione precedente del pacchetto ed ereditarietà di un sottoinsieme le interfacce più vecchie del pacchetto.
Struttura dell'interfaccia
Per un'interfaccia ben strutturata, l'aggiunta di nuovi tipi di funzionalità che che non fanno parte del design originale, dovrebbero essere necessarie una modifica del a riga di comando. Al contrario, se puoi o aspettarti di apportare una modifica a entrambi i lati che introduce nuove funzionalità senza modificare l'interfaccia l'interfaccia non è strutturata.
Treble supporta componenti del fornitore e di sistema compilati separatamente, in cui
vendor.img
su un dispositivo e system.img
può essere
da compilare separatamente. Tutte le interazioni tra vendor.img
e
Il campo system.img
deve essere definito in modo esplicito ed esaustivo in modo che possa
continuano a funzionare per molti anni. Ciò include molte piattaforme API, ma una delle principali
è il meccanismo IPC utilizzato da HIDL per la comunicazione tra processi
Confine system.img
/vendor.img
.
Requisiti
Tutti i dati trasmessi attraverso l'HIDL devono essere definiti esplicitamente. Per garantire che di implementazione e il client possono continuare a lavorare insieme anche separatamente o in modo indipendente, i dati devono rispettare le seguenti requisiti:
- Può essere descritto direttamente in HIDL (utilizzando enum struct e così via) con nomi e significati semantici.
- Può essere descritto da uno standard pubblico come ISO/IEC 7816.
- Può essere descritto da uno standard hardware o da un layout fisico dell'hardware.
- I dati possono essere opachi (come chiavi pubbliche, ID e così via), se necessario.
Se vengono utilizzati dati opachi, devono essere letti solo da un lato dell'HIDL
a riga di comando. Ad esempio, se il codice vendor.img
fornisce un componente nella
system.img
un messaggio di stringa o vec<uint8_t>
dati, tali dati non possono essere analizzati dal system.img
stesso; può
deve essere restituito solo a vendor.img
per l'interpretazione. Quando
passando un valore pari a vendor.img
al codice del fornitore
system.img
o a un altro dispositivo, il formato dei dati e come
deve essere interpretato, deve essere descritto esattamente e fa ancora parte del
a riga di comando.
Linee guida
Dovresti essere in grado di scrivere un'implementazione o un client di un HAL utilizzando solo i file .hal (ad esempio, non è necessario consultare il codice sorgente Android o standard). Ti consigliamo di specificare il comportamento richiesto esatto. Dichiarazioni quali "Un'implementazione può fare A o B" incoraggiare le implementazioni a diventare intrecciati con i clienti con cui sono sviluppati.
Layout codice HIDL
HIDL include pacchetti di base e del fornitore.
Le interfacce HIDL principali sono quelle specificate da Google. I pacchetti a cui appartengono
inizino con android.hardware.
e sono denominati in base al sottosistema,
potenzialmente con livelli di denominazione nidificati. Ad esempio, il pacchetto NFC è denominato
android.hardware.nfc
e la confezione della fotocamera è
android.hardware.camera
. In generale, un pacchetto principale ha il nome
android.hardware.
[name1
].[name2
]...
Oltre al nome, i pacchetti HIDL hanno una versione. Ad esempio, il pacchetto
android.hardware.camera
potrebbe essere alla versione 3.4
; questo è
è importante, in quanto la versione di un pacchetto influisce sul suo posizionamento nell'albero di origine.
Tutti i pacchetti principali si trovano sotto hardware/interfaces/
nella
di un sistema di compilazione. Il pacchetto
android.hardware.
[name1
].[name2
]...
alla versione $m.$n
è inferiore a
hardware/interfaces/name1/name2/
.../$m.$n/
; pacco
La versione 3.4
di android.hardware.camera
si trova nella directory
hardware/interfaces/camera/3.4/.
Esiste una mappatura hard-coded
tra il prefisso del pacchetto android.hardware.
e il percorso
hardware/interfaces/
.
I pacchetti non principali (fornitore) sono quelli prodotti dal fornitore SoC o ODM. La
il prefisso per i pacchetti non principali è vendor.$(VENDOR).hardware.
dove
$(VENDOR)
Si riferisce a un fornitore di SoC o a un OEM/ODM. Questo viene mappato al percorso
vendor/$(VENDOR)/interfaces
nell'albero (questa mappatura è anche
hardcoded).
Nomi di tipo definiti dall'utente completi
Nelle HIDL, ogni UDT ha un nome completo composto dal nome della stessa,
il nome del pacchetto in cui è definita la funzione definita dall'utente e la versione del pacchetto. La
il nome completo viene utilizzato solo quando vengono dichiarate istanze del tipo
non dove viene definito il tipo stesso. Ad esempio, supponi pacchetto
La versione 1.0
di android.hardware.nfc,
definisce uno struct
denominato NfcData
. Sul sito della dichiarazione (sia
types.hal
o all'interno della dichiarazione di un'interfaccia), la dichiarazione
afferma semplicemente:
struct NfcData { vec<uint8_t> data; };
Quando dichiari un'istanza di questo tipo (all'interno di una struttura di dati o come parametro del metodo), utilizza il nome completo del tipo:
android.hardware.nfc@1.0::NfcData
La sintassi generale è
PACKAGE@VERSION::UDT
, dove:
PACKAGE
è il nome separato da punti di un pacchetto HIDL (ad es.android.hardware.nfc
).VERSION
è la versione main.minor separata da punti formato del pacchetto (ad es.1.0
).UDT
è il nome separato da un punto di una funzione HIDL UDT. Poiché HIDL supporta gli UDT nidificati e le interfacce HIDL possono contenere UDT (un tipo dichiarazione nidificata), i punti vengono utilizzati per accedere ai nomi.
Ad esempio, se la seguente dichiarazione nidificata è stata definita nel
file di tipi nel pacchetto android.hardware.example
versione
1.0
:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
Il nome completo di Bar
è
android.hardware.example@1.0::Foo.Bar
. Se, oltre a essere nel
al pacchetto precedente, la dichiarazione nidificata era in un'interfaccia
IQuux
:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
Il nome completo di Bar
è
android.hardware.example@1.0::IQuux.Foo.Bar
.
In entrambi i casi, Bar
può essere definito solo come Bar
nell'ambito della dichiarazione di Foo
. Al pacco o
a livello di interfaccia, devi fare riferimento a Bar
tramite Foo
:
Foo.Bar
, come nella dichiarazione del metodo doSomething
in alto. In alternativa, potresti dichiarare il metodo in modo più dettagliato come:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
Valori di enumerazione completi
Se una funzione UDT è di tipo enum, ogni valore del tipo enum ha un
nome completo che inizia con il nome completo del tipo enum,
seguito dai due punti e dal nome del valore enum. Ad esempio:
presupponi pacchetto android.hardware.nfc,
versione 1.0
definisce un tipo di enum NfcStatus
:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
Quando si fa riferimento a STATUS_OK
, il nome completo è:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
La sintassi generale è
PACKAGE@VERSION::UDT:VALUE
,
dove:
PACKAGE@VERSION::UDT
è il esattamente lo stesso nome completo per il tipo di enum.VALUE
è il nome del valore.
Regole di inferenza automatica
Non è necessario specificare un nome UDT completo. Un nome UDT può omettere in sicurezza quanto segue:
- Il pacchetto, ad esempio
@1.0::IFoo.Type
- Sia pacchetto che versione, ad es.
IFoo.Type
HIDL tenta di completare il nome utilizzando regole di interferenza automatica (regola inferiore rappresenta una priorità più alta).
Regola 1
Se non vengono forniti alcun pacchetto e versione, si cerca di eseguire una ricerca del nome locale. Esempio:
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
La ricerca di NfcErrorMessage
viene eseguita a livello locale, mentre typedef
sopra. NfcData
viene cercato a livello locale, ma così com'è
non definiti localmente, vengono utilizzate le regole 2 e 3. @1.0::NfcStatus
fornisce una versione, pertanto la regola 1 non si applica.
Regola 2
Se la regola 1 non riesce e manca un componente del nome completo
(pacchetto, versione o pacchetto e versione), il componente viene compilato automaticamente
le informazioni del pacchetto corrente. Il compilatore HIDL cerca quindi
il file corrente (e tutte le importazioni) per trovare il nome completo compilato automaticamente.
Utilizzando l'esempio precedente, presupponi la dichiarazione ExtendedNfcData
.
è stata effettuata nello stesso pacchetto (android.hardware.nfc
) con
(1.0
) come NfcData
, come segue:
struct ExtendedNfcData { NfcData base; // … additional members };
Il compilatore HIDL compila il nome del pacchetto e il nome della versione
pacchetto attuale per produrre il nome UDT completo
android.hardware.nfc@1.0::NfcData
. Poiché il nome esiste nel
pacchetto corrente (se importato correttamente), viene utilizzato per
dichiarazione.
Un nome nel pacchetto corrente viene importato solo se uno dei seguenti è vero:
- Viene importata in modo esplicito con un'istruzione
import
. - È definito in
types.hal
nel pacchetto attuale
La stessa procedura viene seguita se NfcData
è stato qualificato solo
il numero della versione:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
Regola 3
Se la regola 2 non produce una corrispondenza (la funzione UDT non è definita nella
), il compilatore HIDL cerca una corrispondenza all'interno di tutti i pacchetti importati.
Utilizzando l'esempio precedente, supponiamo che ExtendedNfcData
sia dichiarato in
versione 1.1
del pacchetto android.hardware.nfc
,
1.1
importa 1.0
come dovrebbe (vedi
estensioni a livello di pacchetto) e la definizione
specifica solo il nome dell'UDT:
struct ExtendedNfcData { NfcData base; // … additional members };
Il compilatore cerca qualsiasi UDT denominato NfcData
e ne trova uno in
android.hardware.nfc
alla versione 1.0
, con conseguente
UDT completo di android.hardware.nfc@1.0::NfcData
. Se
viene trovata una corrispondenza per un determinato UDT parzialmente qualificato, il compilatore HIDL
genera un errore.
Esempio
Utilizzando la regola 2, un tipo importato definito nel pacchetto corrente è preferito rispetto a un tipo importato da un altro pacchetto:
// hardware/interfaces/foo/1.0/types.hal package android.hardware.foo@1.0; struct S {}; // hardware/interfaces/foo/1.0/IFooCallback.hal package android.hardware.foo@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/types.hal package android.hardware.bar@1.0; typedef string S; // hardware/interfaces/bar/1.0/IFooCallback.hal package android.hardware.bar@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/IBar.hal package android.hardware.bar@1.0; import android.hardware.foo@1.0; interface IBar { baz1(S s); // android.hardware.bar@1.0::S baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback };
S
viene interpolato comeandroid.hardware.bar@1.0::S
e si trova inbar/1.0/types.hal
(perchétypes.hal
viene automaticamente importati).IFooCallback
viene interpolato comeandroid.hardware.bar@1.0::IFooCallback
utilizza la regola 2, ma impossibile trovare perchébar/1.0/IFooCallback.hal
non è importato automaticamente (come ètypes.hal
). Pertanto, la regola 3 lo risolveandroid.hardware.foo@1.0::IFooCallback
, che è stata importata tramiteimport android.hardware.foo@1.0;
).
type.hal
Ogni pacchetto HIDL contiene un file types.hal
contenente gli UDT
condivisi tra tutte le interfacce
che fanno parte del pacchetto. Tipi HIDL
sono sempre pubblici; a prescindere dalla dichiarazione di una funzione
types.hal
o all'interno di una dichiarazione dell'interfaccia, questi tipi sono
accessibili al di fuori dell'ambito in cui sono definite. types.hal
non ha lo scopo di descrivere l'API pubblica di un pacchetto, ma piuttosto di ospitare UDT
utilizzata da tutte le interfacce all'interno del pacchetto. A causa della natura delle regole HIDL, tutti gli UDT
fanno parte dell'interfaccia.
types.hal
è composto da UDT e istruzioni import
.
Poiché types.hal
è disponibile per ogni interfaccia del
(è un'importazione implicita), queste istruzioni import
vengono
a livello di pacchetto per definizione. Gli UDT in types.hal
possono anche incorporare
gli UDT e le interfacce così importati.
Ad esempio, per IFoo.hal
:
package android.hardware.foo@1.0; // whole package import import android.hardware.bar@1.0; // types only import import android.hardware.baz@1.0::types; // partial imports import android.hardware.qux@1.0::IQux.Quux; // partial imports import android.hardware.quuz@1.0::Quuz;
Vengono importati i seguenti dati:
android.hidl.base@1.0::IBase
(implicitamente)android.hardware.foo@1.0::types
(implicitamente)- Tutto in
android.hardware.bar@1.0
(inclusi tutti e relativetypes.hal
) types.hal
daandroid.hardware.baz@1.0::types
(le interfacce inandroid.hardware.baz@1.0
non vengono importate)IQux.hal
etypes.hal
daandroid.hardware.qux@1.0
Quuz
daandroid.hardware.quuz@1.0
(supponendoQuuz
è definito intypes.hal
, l'interotypes.hal
file viene analizzato, ma tipi diversi daQuuz
non vengono importate).
Controllo delle versioni a livello di interfaccia
Ogni interfaccia all'interno di un pacchetto risiede in un proprio file. Il pacchetto
a cui appartiene l'interfaccia è dichiarata nella parte superiore dell'interfaccia utilizzando
package
. Dopo la dichiarazione relativa al pacchetto, zero o più valori
a livello di interfaccia (il pacchetto completo o parziale). Ad esempio:
package android.hardware.nfc@1.0;
Nelle interfacce HIDL, le interfacce possono ereditare da altre interfacce utilizzando
extends
parola chiave. Affinché un'interfaccia estenda un'altra interfaccia,
devono avervi accesso tramite un'istruzione import
. Il nome del
dell'interfaccia utente estesa (l'interfaccia di base) segue le regole di type-name
sulla qualifica descritta sopra. Un'interfaccia può ereditare una sola interfaccia;
HIDL non supporta l'ereditarietà multipla.
Gli esempi di controllo delle versioni uprev riportati di seguito utilizzano il seguente pacchetto:
// types.hal package android.hardware.example@1.0 struct Foo { struct Bar { vec<uint32_t> val; }; }; // IQuux.hal package android.hardware.example@1.0 interface IQuux { fromFooToBar(Foo f) generates (Foo.Bar b); }
Regole di uprev
Per definire un pacchetto package@major.minor
, uno o tutti i componenti B
deve essere vero:
Regola A | "Is a start minor version" (È una versione secondaria iniziale): tutte le versioni secondarie precedenti,
package@major.0 , package@major.1 , ...,
Non è necessario definire package@major.(minor-1) .
|
---|
Regola B | Tutte le seguenti condizioni sono vere:
|
---|
A causa della regola A:
- Il pacchetto può iniziare con qualsiasi numero di versione secondario (ad esempio,
android.hardware.biometrics.fingerprint
inizia alle ore@2.1
. - Il requisito "
android.hardware.foo@1.0
non è definito" significa la directoryhardware/interfaces/foo/1.0
non dovrebbe nemmeno esistere.
Tuttavia, la regola A non ha effetto su un pacchetto con lo stesso nome di pacchetto, ma su un
versione principale diversa (ad esempio,
android.hardware.camera.device
ha sia @1.0
che
@3.2
definito; @3.2
non deve interagire con
@1.0
. Pertanto, @3.2::IExtFoo
può estendere
@1.0::IFoo
.
Se il nome del pacchetto è diverso,
package@major.minor::IBar
può estendersi da un'interfaccia con un
un nome diverso (ad esempio, android.hardware.bar@1.0::IBar
può
estendi android.hardware.baz@2.2::IBaz
). Se un'interfaccia non
dichiarare esplicitamente un super tipo con la parola chiave extend
,
si estende android.hidl.base@1.0::IBase
(tranne IBase
).
I punti B.2 e B.3 devono essere seguiti contemporaneamente. Ad esempio, anche se
android.hardware.foo@1.1::IFoo
si estende
android.hardware.foo@1.0::IFoo
per superare la regola B.2, se
Si estende android.hardware.foo@1.1::IExtBar
android.hardware.foo@1.0::IBar
, questo valore non è ancora valido.
Interfacce Uprev
Per aumentare le entrate di android.hardware.example@1.0
(definita sopra) a
@1.1
:
// types.hal package android.hardware.example@1.1; import android.hardware.example@1.0; // IQuux.hal package android.hardware.example@1.1 interface IQuux extends @1.0::IQuux { fromBarToFoo(Foo.Bar b) generates (Foo f); }
Questo è un import
a livello di pacchetto della versione 1.0
di
android.hardware.example
a types.hal
. Anche se non esistono nuovi
Le funzioni UDT vengono aggiunte nella versione 1.1
del pacchetto, mentre i riferimenti alle funzioni definite dall'utente vengono aggiunti
è ancora necessaria la versione 1.0
, di conseguenza l'importazione a livello di pacchetto
a types.hal
. (Lo stesso effetto si sarebbe potuto ottenere con una
importazione a livello di interfaccia in IQuux.hal
.)
In extends @1.0::IQuux
, nella dichiarazione di
IQuux
, abbiamo specificato la versione di IQuux
attualmente
ereditati (è necessaria la disambiguazione perché IQuux
è utilizzato
dichiarare un'interfaccia ed ereditare da un'interfaccia). Poiché le dichiarazioni sono
semplicemente i nomi che ereditano tutti gli attributi di pacchetto e versione sul sito
la disambiguazione deve essere indicata nel nome dell'interfaccia di base; noi
avrebbe potuto utilizzare anche l'UDT completo, ma sarebbe stato così
ridondante.
La nuova interfaccia IQuux
non richiede una nuova dichiarazione del metodo
fromFooToBar()
che eredita da @1.0::IQuux
; perché
indica il nuovo metodo aggiunto fromBarToFoo()
. In HIDL, ereditato
metodi non possono essere dichiarati nuovamente nelle interfacce figlio,
l'interfaccia IQuux
non può dichiarare fromFooToBar()
in modo esplicito.
Convenzioni di uprev
A volte i nomi di interfaccia devono rinominare l'interfaccia di estensione. I nostri suggerimenti che le estensioni, gli struct e le unioni enum hanno lo stesso nome di ciò che estendono a meno che non siano sufficientemente diversi da giustificare un nuovo nome. Esempi:
// in parent hal file enum Brightness : uint32_t { NONE, WHITE }; // in child hal file extending the existing set with additional similar values enum Brightness : @1.0::Brightness { AUTOMATIC }; // extending the existing set with values that require a new, more descriptive name: enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };
Se un metodo può avere un nuovo nome semantico (ad esempio
fooWithLocation
), allora è preferibile. In caso contrario,
in modo simile a quello che sta estendendo. Ad esempio, il metodo
foo_1_1
in @1.1::IFoo
può sostituire la funzionalità
del metodo foo
in @1.0::IFoo
se non esiste un
un nome alternativo.
Controllo delle versioni a livello di pacchetto
Il controllo delle versioni HIDL avviene a livello di pacchetto. dopo la pubblicazione di un pacchetto, è immutabile (il suo insieme di interfacce e UDT non può essere modificato). I pacchetti possono si relazionano tra loro in vari modi, che possono essere espressi mediante combinazione di ereditarietà a livello di interfaccia e creazione di funzioni definite dall'utente per composizione.
Tuttavia, un tipo di relazione è rigorosamente definito e deve essere applicato in modo forzato: Ereditarietà compatibile con le versioni precedenti a livello di pacchetto. In questo scenario, parent rappresenta il pacchetto ereditato da e Il pacchetto child è quello che estende il pacchetto principale. A livello di pacchetto le regole di ereditarietà compatibili con le versioni precedenti sono le seguenti:
- Tutte le interfacce di primo livello del pacchetto principale vengono ereditate dalle interfacce nel pacchetto secondario.
- È inoltre possibile aggiungere nuove interfacce al nuovo pacchetto (senza limitazioni su relazioni con altre interfacce di altri pacchetti).
- È possibile aggiungere nuovi tipi di dati anche per l'utilizzo con entrambi i nuovi metodi di aumento delle entrate interfacce esistenti o di nuove interfacce.
Queste regole possono essere implementate utilizzando l'ereditarietà a livello di interfaccia HIDL e le funzioni UDT composizione, ma sono necessarie conoscenze di meta-livello per conoscere queste relazioni rappresentano un'estensione del pacchetto compatibile con le versioni precedenti. Queste conoscenze vengono dedotte come segue:
Se un pacchetto soddisfa questo requisito, hidl-gen
applica
di compatibilità con le versioni precedenti.