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

versioning

HIDL richiede che ogni interfaccia scritta in HIDL sia versionata. Dopo la pubblicazione di un'interfaccia HAL, questa viene bloccata e ogni ulteriore modifica deve essere apportata a una nuova versione di tale interfaccia. Sebbene una determinata interfaccia pubblicata non possa essere modificata, può essere estesa da un'altra interfaccia.

Struttura del codice HIDL

Il codice HIDL è organizzato in tipi, interfacce e pacchetti definiti dall'utente:

  • Tipi definiti dall'utente (UDT) . HIDL fornisce l'accesso a una serie di tipi di dati primitivi che possono essere utilizzati per comporre tipi più complessi tramite strutture, sindacati ed enumerazioni. Gli UDT vengono passati ai metodi di interfaccia e possono essere definiti a livello di un pacchetto (comune a tutte le interfacce) o localmente a un'interfaccia.
  • Interfacce . Come blocco base di HIDL, un'interfaccia è costituita da dichiarazioni UDT e metodo. Le interfacce possono anche ereditare da un'altra interfaccia.
  • Pacchetti . Organizza le interfacce HIDL correlate e i tipi di dati su cui operano. Un pacchetto è identificato da un nome e una versione e include quanto segue:
    • File di definizione del tipo di dati chiamato types.hal .
    • Zero o più interfacce, ognuna nel proprio file .hal .

Il file di definizione del tipo di dati types.hal contiene solo UDT (tutti gli UDT a livello di pacchetto sono conservati in un singolo file). Le rappresentazioni nella lingua di destinazione sono disponibili per tutte le interfacce nel pacchetto.

Filosofia del versioning

Un pacchetto HIDL (come android.hardware.nfc ), dopo essere stato pubblicato per una data versione (come 1.0 ), è immutabile; non può essere modificato. Le modifiche alle interfacce nel pacchetto o eventuali modifiche ai suoi 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 UDT in un pacchetto condividono la stessa versione. Le versioni del pacchetto seguono il controllo delle versioni semantico senza il livello di patch e i componenti build-metadata. All'interno di un determinato pacchetto, un bump della versione minore implica che la nuova versione del pacchetto è retrocompatibile con il vecchio pacchetto e un bump della versione principale implica che la nuova versione del pacchetto non è retrocompatibile con il vecchio pacchetto.

Concettualmente, un pacchetto può riguardare un altro pacchetto in uno dei diversi modi:

  • Niente affatto .
  • Estensibilità retrocompatibile a livello di pacchetto . Ciò si verifica per i nuovi uprevs di versione minore (prossima revisione incrementata) di un pacchetto; il nuovo pacchetto ha lo stesso nome e la versione principale del pacchetto precedente, ma una versione secondaria superiore. Funzionalmente, il nuovo pacchetto è un superset del vecchio pacchetto, che significa:
    • Le interfacce di livello superiore del pacchetto padre sono presenti nel nuovo pacchetto, sebbene le interfacce possano avere nuovi metodi, nuovi UDT locali (l'estensione a livello di interfaccia descritta di seguito) e nuovi UDT in types.hal .
    • Nuove interfacce possono anche essere aggiunte al nuovo pacchetto.
    • Tutti i tipi di dati del pacchetto padre sono presenti nel nuovo pacchetto e possono essere gestiti con i metodi (eventualmente reimplementati) del pacchetto precedente.
    • Nuovi tipi di dati possono anche essere aggiunti per essere utilizzati da nuovi metodi di interfacce esistenti aggiornate o da nuove interfacce.
  • Estensibilità retrocompatibile a livello di interfaccia . Il nuovo pacchetto può anche estendere il pacchetto originale consistendo in interfacce logicamente separate che forniscono semplicemente funzionalità aggiuntive e non quella principale. A tal fine, può essere desiderabile quanto segue:
    • Le interfacce nel nuovo pacchetto devono ricorrere ai tipi di dati del vecchio pacchetto.
    • Le interfacce nel nuovo pacchetto possono estendere le interfacce di uno o più pacchetti precedenti.
  • Estendere l'incompatibilità all'indietro originale . Questa è una versione principale del pacchetto e non c'è bisogno di alcuna correlazione tra i due. Nella misura in cui esiste, può essere espresso con una combinazione di tipi dalla versione precedente del pacchetto e l'ereditarietà di un sottoinsieme di interfacce vecchio pacchetto.

Interfacce strutturanti

Per un'interfaccia ben strutturata, l'aggiunta di nuovi tipi di funzionalità che non fanno parte del progetto originale dovrebbe richiedere una modifica all'interfaccia HIDL. Al contrario, se è possibile o si prevede di apportare una modifica su entrambi i lati dell'interfaccia che introduce nuove funzionalità senza modificare l'interfaccia stessa, l'interfaccia non è strutturata.

Gli alti supportano i componenti compilati separatamente del fornitore e del sistema in cui è possibile compilare separatamente vendor.img su un dispositivo e system.img . Tutte le interazioni tra vendor.img e system.img devono essere esplicitamente e accuratamente definite in modo da poter continuare a funzionare per molti anni. Ciò include molte superfici API, ma una superficie maggiore è il meccanismo IPC che HIDL utilizza per la comunicazione tra vendor.img limite system.img / vendor.img .

Requisiti

Tutti i dati passati attraverso HIDL devono essere definiti in modo esplicito. Per garantire che un'implementazione e un client possano continuare a lavorare insieme anche se compilati separatamente o sviluppati in modo indipendente, i dati devono rispettare i seguenti requisiti:

  • Può essere descritto direttamente in HIDL (usando enum di strutture, ecc.) Con nomi e significato semantici.
  • Può essere descritto da uno standard pubblico come ISO / IEC 7816.
  • Può essere descritto da uno standard hardware o layout fisico dell'hardware.
  • Possono essere dati opachi (come chiavi pubbliche, ID, ecc.) Se necessario.

Se si utilizzano dati opachi, devono essere letti solo da un lato dell'interfaccia HIDL. Ad esempio, se il codice vendor.img fornisce a un componente sul system.img un messaggio stringa o dati vec<uint8_t> , tali dati non possono essere analizzati dal system.img stesso; può essere restituito a vendor.img per interpretarlo. Quando si passa un valore da vendor.img al codice fornitore su system.img o su un altro dispositivo, il formato dei dati e il modo in cui devono essere interpretati devono essere esattamente descritti e fanno ancora parte dell'interfaccia .

Linee guida

Dovresti essere in grado di scrivere un'implementazione o un client di un HAL usando solo i file .hal (cioè non dovresti guardare l'origine Android o gli standard pubblici). Si consiglia di specificare il comportamento esatto richiesto. Dichiarazioni come "un'implementazione può fare A o B" incoraggiano le implementazioni a intrecciarsi con i clienti con cui sono sviluppate.

Layout del codice HIDL

HIDL include pacchetti core e di fornitori.

Le interfacce HIDL principali sono quelle specificate da Google. I pacchetti a cui appartengono iniziano con android.hardware. e sono nominati dal sottosistema, potenzialmente con livelli di denominazione nidificati. Ad esempio, il pacchetto NFC è denominato android.hardware.nfc e il pacchetto fotocamera è android.hardware.camera . In generale, un pacchetto principale ha il nome android.hardware. [ name1 ]. [ name2 ]…. I pacchetti HIDL hanno una versione oltre al loro nome. Ad esempio, il pacchetto android.hardware.camera potrebbe essere alla versione 3.4 ; questo è importante, poiché la versione di un pacchetto influenza il suo posizionamento nell'albero dei sorgenti.

Tutti i pacchetti principali sono collocati sotto hardware/interfaces/ nel sistema di compilazione. Il pacchetto android.hardware. [ name1 ]. [ name2 ]… alla versione $m.$n è in hardware/interfaces/name1/name2/ /$m.$n/ hardware/interfaces/name1/name2/ /$m.$n/ hardware/interfaces/name1/name2//$m.$n/ ; pacchetto android.hardware.camera versione 3.4 è nella directory hardware/interfaces/camera/3.4/. Esiste un mapping hardcoded tra il prefisso del pacchetto android.hardware. e il percorso hardware/interfaces/ .

I pacchetti non core (fornitore) sono quelli prodotti dal fornitore SoC o ODM. Il prefisso per i pacchetti non core è il vendor.$(VENDOR).hardware. dove $(VENDOR) riferisce a un fornitore di SoC o OEM / ODM. Questo si associa al percorso vendor/$(VENDOR)/interfaces nella struttura (anche questa mappatura è codificata).

Nomi di tipo definito dall'utente completamente qualificati

In HIDL, ogni UDT ha un nome completo che comprende il nome UDT, il nome del pacchetto in cui è definito l'UDT e la versione del pacchetto. Il nome completo viene utilizzato solo quando vengono dichiarate istanze del tipo e non dove viene definito il tipo stesso. Ad esempio, supponiamo che il pacchetto android.hardware.nfc, versione 1.0 definisca una struttura chiamata NfcData . Nel sito della dichiarazione (sia in types.hal o all'interno di una dichiarazione di interfaccia), la dichiarazione afferma semplicemente:

struct NfcData {
    vec<uint8_t> data;
};

Quando si dichiara un'istanza di questo tipo (all'interno di una struttura di dati o come parametro di metodo), utilizzare il nome di tipo completo:

android.hardware.nfc@1.0::NfcData

La sintassi generale è PACKAGE @ VERSION :: UDT , dove:

  • PACKAGE è il nome separata da punti di un pacchetto HIDL (ad esempio, android.hardware.nfc ).
  • VERSION è il formato della versione major.minor separato da punti del pacchetto (ad es. 1.0 ).
  • UDT è il nome separato da punti di un UDT HIDL. Poiché HIDL supporta UDT nidificati e le interfacce HIDL possono contenere UDT (un tipo di dichiarazione nidificata), i punti vengono utilizzati per accedere ai nomi.

Ad esempio, se la seguente dichiarazione nidificata è stata definita nel file dei tipi comuni 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 per Bar è android.hardware.example@1.0::Foo.Bar . Se, oltre ad essere nel pacchetto sopra, la dichiarazione nidificata si trovava in un'interfaccia chiamata 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 per Bar è android.hardware.example@1.0::IQuux.Foo.Bar .

In entrambi i casi, Bar può essere definito Bar solo nell'ambito della dichiarazione di Foo . A livello di pacchetto o interfaccia, è necessario fare riferimento a Bar tramite Foo : Foo.Bar , come nella dichiarazione del metodo doSomething sopra. In alternativa, è possibile 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 un UDT è un tipo enum, ogni valore del tipo enum ha un nome completo che inizia con il nome completo del tipo enum, seguito da due punti, quindi dal nome del valore enum. Ad esempio, supponiamo che il pacchetto android.hardware.nfc, versione 1.0 definisca un tipo 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 è esattamente lo stesso nome completo per il tipo enum.
  • VALUE è il nome del valore.

Regole di inferenza automatica

Non è necessario specificare un nome UDT completo. Un nome UDT può tranquillamente omettere quanto segue:

  • Il pacchetto, ad es. @1.0::IFoo.Type
  • Sia pacchetto che versione, ad es. IFoo.Type

HIDL tenta di completare il nome utilizzando le regole di interferenza automatica (un numero di regola inferiore indica una priorità più elevata).

Regola 1

Se non viene fornito alcun pacchetto e versione, viene tentata una ricerca del nome locale. Esempio:

interface Nfc {
    typedef string NfcErrorMessage;
    send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m);
};

NfcErrorMessage viene cercato localmente e viene trovato il typedef sopra di esso. NfcData viene cercato localmente, ma poiché non è definito localmente, vengono utilizzate le regole 2 e 3. @1.0::NfcStatus fornisce una versione, quindi la regola 1 non si applica.

Regola 2

Se la regola 1 non riesce e manca un componente con il nome completo (pacchetto, versione o pacchetto e versione), il componente viene compilato automaticamente con le informazioni dal pacchetto corrente. Il compilatore HIDL cerca quindi il file corrente (e tutte le importazioni) per trovare il nome completo compilato automaticamente. Usando l'esempio sopra, supponiamo che la dichiarazione di ExtendedNfcData stata fatta nello stesso pacchetto ( android.hardware.nfc ) alla stessa versione ( 1.0 ) di NfcData , come segue:

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

Il compilatore HIDL compila il nome del pacchetto e il nome della versione dal pacchetto corrente per produrre il nome UDT completo android.hardware.nfc@1.0::NfcData . Poiché il nome esiste nel pacchetto corrente (supponendo che sia importato correttamente), viene utilizzato per la dichiarazione.

Un nome nel pacchetto corrente viene importato solo se è vera una delle seguenti condizioni:

  • Viene importato esplicitamente con una dichiarazione di import .
  • È definito in types.hal nel pacchetto corrente

Lo stesso processo viene seguito se NfcData era qualificato solo dal numero di versione:

struct ExtendedNfcData {
    // autofill the current package name (android.hardware.nfc)
    @1.0::NfcData base;
    // … additional members
};

Regola 3

Se la regola 2 non riesce a produrre una corrispondenza (l'UDT non è definito nel pacchetto corrente), il compilatore HIDL cerca una corrispondenza all'interno di tutti i pacchetti importati. Utilizzando l'esempio precedente, si supponga che ExtendedNfcData sia dichiarato nella versione 1.1 del pacchetto android.hardware.nfc , 1.1 importa 1.0 come dovrebbe (vedere Estensioni a livello di pacchetto ) e la definizione specifica solo il nome UDT:

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

Il compilatore cerca qualsiasi UDT chiamato NfcData e ne trova uno in android.hardware.nfc alla versione 1.0 , risultante in un UDT completo di android.hardware.nfc@1.0::NfcData . Se viene trovata più di 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 viene 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 è interpolato come android.hardware.bar@1.0::S e si trova in bar/1.0/types.hal (perché types.hal viene importato automaticamente).
  • IFooCallback è interpolato come android.hardware.bar@1.0::IFooCallback usando la regola 2, ma non può essere trovato perché bar/1.0/IFooCallback.hal non viene importato automaticamente (come types.hal è types.hal ). Pertanto, la regola 3 lo risolve in android.hardware.foo@1.0::IFooCallback invece, che viene importato tramite import android.hardware.foo@1.0; ).

types.hal

Ogni pacchetto HIDL contiene un file types.hal contenente UDT condivisi tra tutte le interfacce che partecipano a quel pacchetto. I tipi HIDL sono sempre pubblici; indipendentemente dal fatto che un UDT sia dichiarato in types.hal o all'interno di una dichiarazione di interfaccia, questi tipi sono accessibili al di fuori dell'ambito in cui sono definiti. types.hal non ha lo scopo di descrivere l'API pubblica di un pacchetto, ma piuttosto di ospitare gli UDT utilizzati da tutte le interfacce all'interno del pacchetto. A causa della natura di HIDL, tutti gli UDT fanno parte dell'interfaccia.

types.hal costituito da UDT e dichiarazioni di import . Poiché types.hal è reso disponibile per ogni interfaccia del pacchetto (è un'importazione implicita), queste dichiarazioni di import sono a livello di pacchetto per definizione. Gli UDT in types.hal possono anche incorporare UDT e interfacce così importate.

Ad esempio, per un 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;

Sono importati:

  • android.hidl.base@1.0::IBase (implicitamente)
  • android.hardware.foo@1.0::types (implicitamente)
  • Tutto in android.hardware.bar@1.0 (comprese tutte le interfacce e i suoi types.hal )
  • types.hal da android.hardware.baz@1.0::types (le interfacce in android.hardware.baz@1.0 non vengono importate)
  • IQux.hal e types.hal da android.hardware.qux@1.0
  • Quuz da android.hardware.quuz@1.0 (supponendo che Quuz sia definito in types.hal , viene analizzato l'intero file types.hal , ma i tipi diversi da Quuz non vengono importati).

Controllo delle versioni a livello di interfaccia

Ogni interfaccia all'interno di un pacchetto risiede nel proprio file. Il pacchetto a cui appartiene l'interfaccia è dichiarato nella parte superiore dell'interfaccia usando l'istruzione del package . A seguito della dichiarazione del pacchetto, è possibile elencare zero o più importazioni a livello di interfaccia (pacchetto parziale o intero). Per esempio:

package android.hardware.nfc@1.0;

In HIDL, le interfacce possono ereditare da altre interfacce usando la parola chiave extends . Affinché un'interfaccia possa estendere un'altra interfaccia, deve avere accesso ad essa tramite un'istruzione di import . Il nome dell'interfaccia che viene estesa (l'interfaccia di base) segue le regole per la qualificazione del tipo di nome spiegate sopra. Un'interfaccia può ereditare solo da una interfaccia; HIDL non supporta l'ereditarietà multipla.

Gli esempi di versione uprev 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 Uprev

Per definire un pacchetto package@major.minor , A o tutta B devono essere veri:

Regola A "È una versione secondaria iniziale": non devono essere definite tutte le precedenti versioni package@major.0 , package@major.1 , package@major.(minor-1) package@major.1 ,…, package@major.(minor-1) .
O
Regola B

È vero quanto segue:

  1. "La versione secondaria precedente è valida": package@major.(minor-1) deve essere definito e seguire la stessa regola A (nessuna di package@major.0 fino a package@major.(minor-2) è definita) o regola B (se è un uprev da @major.(minor-2) );

    E

  2. "Eredita almeno un'interfaccia con lo stesso nome": esiste un'interfaccia package@major.minor::IFoo che estende il package@major.(minor-1)::IFoo (se il pacchetto precedente ha un'interfaccia);

    E

  3. "Nessuna interfaccia ereditata con un nome diverso": Non deve esistere package@major.minor::IBar che estende il package@major.(minor-1)::IBaz , dove IBar e IBaz sono due nomi diversi. Se esiste un'interfaccia con lo stesso nome, package@major.minor::IBar deve estendere package@major.(minor-k)::IBar tale che non esiste IBar con un k più piccolo.

A causa della regola A:

  • Il pacchetto può iniziare con qualsiasi numero di versione minore (ad esempio android.hardware.biometrics.fingerprint inizia a @2.1 .)
  • Il requisito " android.hardware.foo@1.0 non è definito" significa che la directory hardware/interfaces/foo/1.0 non dovrebbe nemmeno esistere.

Tuttavia, la regola A non influisce su un pacchetto con lo stesso nome di pacchetto ma con una versione principale diversa (ad esempio, android.hardware.camera.device ha definito sia @1.0 che @3.2 ; @3.2 non deve interagire con @1.0 .) Quindi, @3.2::IExtFoo può estendere @1.0::IFoo .

A condizione che il nome del pacchetto sia diverso, package@major.minor::IBar può estendersi da un'interfaccia con un nome diverso (ad esempio android.hardware.bar@1.0::IBar può estendere android.hardware.baz@2.2::IBaz ). Se un'interfaccia non dichiara esplicitamente un tipo di super-con l' extend parola chiave, si estenderà android.hidl.base@1.0::IBase (tranne IBase stesso).

B.2 e B.3 devono essere seguiti contemporaneamente. Ad esempio, anche se android.hardware.foo@1.1::IFoo estende android.hardware.foo@1.0::IFoo per passare la regola B.2, se un android.hardware.foo@1.1::IExtBar estende android.hardware.foo@1.0::IBar , questo non è ancora un uprev valido.

Interfacce ascendenti

Per aggiornare android.hardware.example@1.0 (definito 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);
}

Questa è import livello di pacchetto della versione 1.0 di android.hardware.example in types.hal . Sebbene non siano stati aggiunti nuovi UDT nella versione 1.1 del pacchetto, sono ancora necessari riferimenti agli UDT nella versione 1.0 , quindi l'importazione a livello di pacchetto in types.hal . (Lo stesso effetto avrebbe potuto essere ottenuto con un'importazione a livello di interfaccia in IQuux.hal .)

In extends @1.0::IQuux nella dichiarazione di IQuux , abbiamo specificato la versione di IQuux che viene ereditata (è richiesta IQuux perché IQuux viene utilizzato per dichiarare un'interfaccia ed ereditare da un'interfaccia). Dato che le dichiarazioni sono semplicemente nomi che ereditano tutti gli attributi di pacchetto e versione nel sito della dichiarazione, la disambiguazione deve essere nel nome dell'interfaccia di base; avremmo potuto usare anche l'UDT completo, ma sarebbe stato ridondante.

La nuova interfaccia IQuux non dichiara nuovamente il metodo da fromFooToBar() che eredita da @1.0::IQuux ; elenca semplicemente il nuovo metodo che aggiunge fromBarToFoo() . In HIDL, i metodi ereditati potrebbero non essere dichiarati di nuovo nelle interfacce figlio, quindi l'interfaccia IQuux non può dichiarare esplicitamente il metodo fromFooToBar() .

Convenzioni Uprev

A volte i nomi delle interfacce devono rinominare l'interfaccia di estensione. Raccomandiamo che le estensioni, le strutture e i sindacati enum abbiano 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 ), questo è preferito. Altrimenti, dovrebbe essere chiamato in modo simile a quello che si 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 nome alternativo migliore.

Controllo delle versioni a livello di pacchetto

Il versioning HIDL si verifica a livello di pacchetto; dopo che un pacchetto è stato pubblicato, è immutabile (il suo set di interfacce e UDT non possono essere modificati). I pacchetti possono relazionarsi tra loro in diversi modi, tutti esprimibili tramite una combinazione di ereditarietà a livello di interfaccia e costruzione di UDT per composizione.

Tuttavia, un tipo di relazione è strettamente definito e deve essere applicato: ereditarietà retrocompatibile a livello di pacchetto . In questo scenario, il pacchetto padre è il pacchetto da cui viene ereditato e il pacchetto figlio è quello che estende il padre. Le regole di ereditarietà retrocompatibili a livello di pacchetto sono le seguenti:

  1. Tutte le interfacce di livello superiore del pacchetto padre sono ereditate da interfacce nel pacchetto figlio.
  2. Nuove interfacce possono anche essere aggiunte al nuovo pacchetto (nessuna restrizione sulle relazioni con altre interfacce in altri pacchetti).
  3. Nuovi tipi di dati possono anche essere aggiunti per essere utilizzati da nuovi metodi di interfacce esistenti aggiornate o da nuove interfacce.

Queste regole possono essere implementate usando l'ereditarietà HIDL a livello di interfaccia e la composizione UDT, ma richiedono conoscenze a livello meta per sapere che queste relazioni costituiscono un'estensione del pacchetto compatibile con le versioni precedenti. Questa conoscenza è dedotta come segue:

Se un pacchetto soddisfa questo requisito, hidl-gen applica regole di retrocompatibilità.