HIDL exige que chaque interface écrite en HIDL soit versionnée. Une fois qu'une interface HAL est publiée, elle est figée et toute modification ultérieure doit être apportée à une nouvelle version de cette interface. Bien qu'une interface publiée donnée ne puisse pas être modifiée, elle peut être étendue par une autre interface.
Structure du code HIDL
Le code HIDL est organisé en types, interfaces et packages définis par l'utilisateur:
- Types définis par l'utilisateur (UDT) HIDL fournit un accès à un ensemble de types de données primitifs qui peuvent être utilisés pour composer des types plus complexes via des structures, des unions et des énumérations. Les UDT sont transmises aux méthodes des interfaces et peuvent être définies au niveau d'un package (commun à toutes les interfaces) ou localement à une interface.
- Interfaces. En tant qu'élément de base de HIDL, une interface se compose de déclarations de types UDT et de méthodes. Les interfaces peuvent également hériter d'une autre interface.
- Packages Organise les interfaces HIDL associées et les types de données sur lesquels elles fonctionnent. Un package est identifié par un nom et une version, et comprend les éléments suivants :
- Fichier de définition de type de données appelé
types.hal
. - Une ou plusieurs interfaces, chacune dans son propre fichier
.hal
.
- Fichier de définition de type de données appelé
Le fichier de définition de type de données types.hal
ne contient que des UDT (tous les UDT au niveau du package sont conservés dans un seul fichier). Les représentations dans la langue cible sont disponibles pour toutes les interfaces du package.
Philosophie de gestion des versions
Une fois publié pour une version donnée (par exemple, 1.0
), un package HIDL (tel que android.hardware.nfc
) est immuable et ne peut pas être modifié. Les modifications apportées aux interfaces du package ou à ses UDT ne peuvent avoir lieu que dans un autre package.
Dans HIDL, la gestion des versions s'applique au niveau du package, et non au niveau de l'interface. Toutes les interfaces et les UDT d'un package partagent la même version. Les versions de paquets suivent le gestion sémantique des versions sans les composants de niveau de correctif et de métadonnées de compilation. Dans un package donné, une mise à niveau de la version mineure implique que la nouvelle version du package est rétrocompatible avec l'ancienne, tandis qu'une mise à niveau de la version majeure implique que la nouvelle version du package n'est pas rétrocompatible avec l'ancienne.
D'un point de vue conceptuel, un package peut être lié à un autre package de plusieurs manières:
- Pas du tout.
- Extensibilité rétrocompatible au niveau du package Cela se produit pour les nouvelles versions mineures (version incrémentée suivante) d'un package. Le nouveau package porte le même nom et la même version majeure que l'ancien, mais une version mineure supérieure. Fonctionnellement, le nouveau package est un sur-ensemble de l'ancien package, ce qui signifie :
- Les interfaces de premier niveau du package parent sont présentes dans le nouveau package, bien que les interfaces puissent comporter de nouvelles méthodes, de nouveaux UDT locaux d'interface (l'extension de niveau d'interface décrite ci-dessous) et de nouveaux UDT dans
types.hal
. - Vous pouvez également ajouter de nouvelles interfaces au nouveau package.
- Tous les types de données du package parent sont présents dans le nouveau package et peuvent être gérés par les méthodes (éventuellement réimplémentées) de l'ancien package.
- Vous pouvez également ajouter de nouveaux types de données à utiliser par de nouvelles méthodes d'interfaces existantes ou par de nouvelles interfaces.
- Les interfaces de premier niveau du package parent sont présentes dans le nouveau package, bien que les interfaces puissent comporter de nouvelles méthodes, de nouveaux UDT locaux d'interface (l'extension de niveau d'interface décrite ci-dessous) et de nouveaux UDT dans
- Extensibilité rétrocompatible au niveau de l'interface Le nouveau package peut également étendre le package d'origine en se composant d'interfaces distinctes sur le plan logique qui fournissent simplement des fonctionnalités supplémentaires, et non la fonctionnalité de base.
À cette fin, il peut être souhaitable de procéder comme suit :
- Les interfaces du nouveau package doivent faire appel aux types de données de l'ancien package.
- Les interfaces du nouveau package peuvent étendre les interfaces d'un ou de plusieurs anciens packages.
- Étendre l'incompatibilité ascendante d'origine Il s'agit d'une mise à niveau de la version majeure du package, et il n'est pas nécessaire qu'il y ait une corrélation entre les deux. Dans la mesure où il existe, il peut être exprimé avec une combinaison de types de l'ancienne version du package et l'héritage d'un sous-ensemble d'interfaces de l'ancien package.
Structuration de l'interface
Pour une interface bien structurée, l'ajout de nouveaux types de fonctionnalités qui ne font pas partie de la conception d'origine doit nécessiter une modification de l'interface HIDL. À l'inverse, si vous pouvez ou prévoyez d'apporter une modification des deux côtés de l'interface qui introduit une nouvelle fonctionnalité sans modifier l'interface elle-même, l'interface n'est pas structurée.
Treble est compatible avec les composants du fournisseur et du système compilés séparément, dans lesquels le vendor.img
sur un appareil et le system.img
peuvent être compilés séparément. Toutes les interactions entre vendor.img
et system.img
doivent être définies explicitement et de manière exhaustive afin qu'elles puissent continuer à fonctionner pendant de nombreuses années. Cela inclut de nombreuses surfaces d'API, mais une surface majeure est le mécanisme d'IPC utilisé par HIDL pour la communication inter-processus à la limite system.img
/vendor.img
.
Conditions requises
Toutes les données transmises via HIDL doivent être définies explicitement. Pour que l'implémentation et le client puissent continuer à travailler ensemble, même lorsqu'ils sont compilés ou développés séparément, les données doivent respecter les exigences suivantes:
- Peut être décrit directement en HIDL (à l'aide d'énumérations de structures, etc.) avec des noms et une signification sémantiques.
- Peut être décrit par une norme publique telle que la norme ISO/CEI 7816.
- Peut être décrit par une norme matérielle ou une disposition physique du matériel.
- Peut s'agir de données opaques (telles que des clés publiques, des ID, etc.) si nécessaire.
Si des données opaques sont utilisées, elles ne doivent être lues que par un seul côté de l'interface HIDL. Par exemple, si le code vendor.img
transmet à un composant du system.img
un message de chaîne ou des données vec<uint8_t>
, ces données ne peuvent pas être analysées par le system.img
lui-même. Elles ne peuvent être renvoyées à vendor.img
que pour être interprétées. Lorsque vous transmettez une valeur de vendor.img
au code du fournisseur sur system.img
ou à un autre appareil, le format des données et la manière dont elles doivent être interprétées doivent être décrits avec précision et font toujours partie de l'interface.
Consignes
Vous devriez pouvoir écrire une implémentation ou un client d'un HAL en utilisant uniquement les fichiers .hal (c'est-à-dire que vous ne devriez pas avoir besoin de consulter la source Android ni les normes publiques). Nous vous recommandons de spécifier le comportement exact requis. Des déclarations telles que "une implémentation peut faire A ou B" encouragent les implémentations à s'imbriquer avec les clients avec lesquels elles sont développées.
Mise en page du code HIDL
HIDL inclut les packages principaux et les packages de fournisseurs.
Les interfaces HIDL de base sont celles spécifiées par Google. Les packages auxquels ils appartiennent commencent par android.hardware.
et sont nommés par sous-système, avec des niveaux de dénomination imbriqués. Par exemple, le package NFC est nommé android.hardware.nfc
et le package de l'appareil photo est android.hardware.camera
. En général, un package principal porte le nom android.hardware.
[name1
].[name2
]…. Les packages HIDL comportent une version en plus de leur nom. Par exemple, le package android.hardware.camera
peut être en version 3.4
. Cela est important, car la version d'un package affecte son emplacement dans l'arborescence des sources.
Tous les packages principaux sont placés sous hardware/interfaces/
dans le système de compilation. Le package android.hardware.
[name1
].[name2
]… à la version $m.$n
se trouve sous hardware/interfaces/name1/name2/
…/$m.$n/
; le package android.hardware.camera
version 3.4
se trouve dans le répertoire hardware/interfaces/camera/3.4/.
. Un mappage encodé en dur existe entre le préfixe de package android.hardware.
et le chemin d'accès hardware/interfaces/
.
Les packages non principaux (fournisseur) sont ceux produits par le fournisseur de SoC ou l'ODM. Le préfixe des packages non principaux est vendor.$(VENDOR).hardware.
, où $(VENDOR)
fait référence à un fournisseur de SoC ou à un OEM/ODM. Cela correspond au chemin d'accès vendor/$(VENDOR)/interfaces
dans l'arborescence (ce mappage est également encodé en dur).
Noms de type défini par l'utilisateur complets
Dans HIDL, chaque UDT possède un nom complet qui comprend le nom de l'UDT, le nom du package dans lequel l'UDT est défini et la version du package. Le nom complet n'est utilisé que lorsque des instances du type sont déclarées, et non lorsque le type lui-même est défini. Par exemple, supposons que la version 1.0
du package android.hardware.nfc,
définisse une struct nommée NfcData
. Au site de la déclaration (que ce soit dans types.hal
ou dans la déclaration d'une interface), la déclaration indique simplement:
struct NfcData { vec<uint8_t> data; };
Lorsque vous déclarez une instance de ce type (que ce soit dans une structure de données ou en tant que paramètre de méthode), utilisez le nom de type complet:
android.hardware.nfc@1.0::NfcData
La syntaxe générale est PACKAGE@VERSION::UDT
, où:
PACKAGE
est le nom d'un package HIDL séparé par des points (par exemple,android.hardware.nfc
).VERSION
correspond au format de version majeure.version mineure du package, séparé par des points (par exemple,1.0
).UDT
est le nom d'un UDT HIDL séparé par des points. Comme HIDL est compatible avec les UDT imbriquées et que les interfaces HIDL peuvent contenir des UDT (un type de déclaration imbriquée), des points sont utilisés pour accéder aux noms.
Par exemple, si la déclaration imbriquée suivante a été définie dans le fichier de types communs du package android.hardware.example
version 1.0
:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
Le nom complet de Bar
est android.hardware.example@1.0::Foo.Bar
. Si, en plus d'être dans le package ci-dessus, la déclaration imbriquée se trouvait dans une interface appelée IQuux
:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
Le nom complet de Bar
est android.hardware.example@1.0::IQuux.Foo.Bar
.
Dans les deux cas, Bar
ne peut être désigné que par Bar
dans le champ d'application de la déclaration de Foo
. Au niveau du package ou de l'interface, vous devez faire référence à Bar
via Foo
:Foo.Bar
, comme dans la déclaration de la méthode doSomething
ci-dessus. Vous pouvez également déclarer la méthode de manière plus détaillée:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
Valeurs d'énumération complètes
Si un UDT est un type d'énumération, chaque valeur du type d'énumération possède un nom complet qui commence par le nom complet du type d'énumération, suivi d'un deux-points, puis du nom de la valeur d'énumération. Par exemple, supposons que la version 1.0
du package android.hardware.nfc,
définisse un type d'énumération NfcStatus
:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
Pour STATUS_OK
, le nom complet est le suivant:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
La syntaxe générale est PACKAGE@VERSION::UDT:VALUE
, où:
PACKAGE@VERSION::UDT
est le même nom complet que celui du type d'énumération.VALUE
correspond au nom de la valeur.
Règles d'inférence automatique
Vous n'avez pas besoin de spécifier un nom de type de données utilisateur complet. Un nom de type de données défini par l'utilisateur peut omettre les éléments suivants sans risque:
- Le package, par exemple
@1.0::IFoo.Type
- Le package et la version, par exemple
IFoo.Type
HIDL tente de compléter le nom à l'aide de règles d'auto-interférence (plus le numéro de règle est bas, plus la priorité est élevée).
Règle 1
Si aucun paquet et aucune version ne sont fournis, une recherche de nom locale est tentée. Exemple :
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
NfcErrorMessage
est recherché localement, et le typedef
situé au-dessus est trouvé. NfcData
est également recherché localement, mais comme il n'est pas défini localement, les règles 2 et 3 sont utilisées. @1.0::NfcStatus
fournit une version. La règle 1 ne s'applique donc pas.
Règle 2
Si la règle 1 échoue et qu'un composant du nom complet est manquant (package, version ou package et version), le composant est renseigné automatiquement avec les informations du package actuel. Le compilateur HIDL recherche ensuite dans le fichier actuel (et dans toutes les importations) le nom complet renseigné automatiquement.
En utilisant l'exemple ci-dessus, supposons que la déclaration de ExtendedNfcData
a été effectuée dans le même package (android.hardware.nfc
) à la même version (1.0
) que NfcData
, comme suit:
struct ExtendedNfcData { NfcData base; // … additional members };
Le compilateur HIDL renseigne le nom du package et le nom de la version du package actuel pour générer le nom de l'UDT complet android.hardware.nfc@1.0::NfcData
. Comme le nom existe dans le package actuel (en supposant qu'il est correctement importé), il est utilisé pour la déclaration.
Un nom du package actuel n'est importé que si l'une des conditions suivantes est remplie:
- Il est importé explicitement avec une instruction
import
. - Il est défini dans
types.hal
dans le package actuel.
La même procédure est suivie si NfcData
n'est qualifié que par le numéro de version:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
Règle 3
Si la règle 2 ne génère pas de correspondance (l'UDT n'est pas défini dans le package actuel), le compilateur HIDL recherche une correspondance dans tous les packages importés.
En vous basant sur l'exemple ci-dessus, supposons que ExtendedNfcData
soit déclaré dans la version 1.1
du package android.hardware.nfc
, que 1.1
importe 1.0
comme il se doit (voir la section Extensions au niveau du package) et que la définition ne spécifie que le nom de l'UDT:
struct ExtendedNfcData { NfcData base; // … additional members };
Le compilateur recherche une UDT nommée NfcData
et en trouve une dans android.hardware.nfc
à la version 1.0
, ce qui génère une UDT entièrement qualifiée de android.hardware.nfc@1.0::NfcData
. Si plusieurs correspondances sont trouvées pour un UDT partiellement qualifié donné, le compilateur HIDL génère une erreur.
Exemple
En appliquant la règle 2, un type importé défini dans le package actuel est privilégié par rapport à un type importé à partir d'un autre package:
// 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
est interpolé en tant queandroid.hardware.bar@1.0::S
et se trouve dansbar/1.0/types.hal
(cartypes.hal
est importé automatiquement).IFooCallback
est interpolé en tant queandroid.hardware.bar@1.0::IFooCallback
à l'aide de la règle 2, mais il ne peut pas être trouvé, carbar/1.0/IFooCallback.hal
n'est pas importé automatiquement (commetypes.hal
). Par conséquent, la règle 3 le résout àandroid.hardware.foo@1.0::IFooCallback
, qui est importé viaimport android.hardware.foo@1.0;
.
types.hal
Chaque package HIDL contient un fichier types.hal
contenant des UDT partagés entre toutes les interfaces participant à ce package. Les types HIDL sont toujours publics. Que l'UDT soit déclaré dans types.hal
ou dans une déclaration d'interface, ces types sont accessibles en dehors du champ d'application dans lequel ils sont définis. types.hal
n'est pas destiné à décrire l'API publique d'un package, mais plutôt à héberger les UDT utilisées par toutes les interfaces du package. En raison de la nature de HIDL, toutes les UDT font partie de l'interface.
types.hal
se compose de types de données définis par l'utilisateur et d'instructions import
.
Étant donné que types.hal
est mis à la disposition de chaque interface du package (il s'agit d'une importation implicite), ces instructions import
sont au niveau du package par définition. Les UDT dans types.hal
peuvent également intégrer les UDT et les interfaces ainsi importées.
Par exemple, pour 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;
Les éléments suivants sont importés:
android.hidl.base@1.0::IBase
(implicitement)android.hardware.foo@1.0::types
(implicitement)- Tout ce qui se trouve dans
android.hardware.bar@1.0
(y compris toutes les interfaces et sontypes.hal
) types.hal
à partir deandroid.hardware.baz@1.0::types
(les interfaces deandroid.hardware.baz@1.0
ne sont pas importées)IQux.hal
ettypes.hal
à partir deandroid.hardware.qux@1.0
Quuz
à partir deandroid.hardware.quuz@1.0
(en supposant queQuuz
soit défini danstypes.hal
, l'intégralité du fichiertypes.hal
est analysée, mais les types autres queQuuz
ne sont pas importés).
Gestion des versions au niveau de l'interface
Chaque interface d'un package se trouve dans son propre fichier. Le package auquel l'interface appartient est déclaré en haut de l'interface à l'aide de l'instruction package
. Après la déclaration du package, zéro ou plusieurs importations au niveau de l'interface (partielle ou complète) peuvent être listées. Exemple :
package android.hardware.nfc@1.0;
Dans HIDL, les interfaces peuvent hériter d'autres interfaces à l'aide du mot clé extends
. Pour qu'une interface étend une autre interface, elle doit y avoir accès via une instruction import
. Le nom de l'interface étendue (l'interface de base) suit les règles de qualification du nom de type expliquées ci-dessus. Une interface ne peut hériter que d'une seule interface. HIDL n'est pas compatible avec l'héritage multiple.
Les exemples de gestion des versions uprev ci-dessous utilisent le package suivant:
// 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); }
Règles Uprev
Pour définir un package package@major.minor
, A ou l'ensemble de B doit être vrai:
Règle A | "Is a start minor version": toutes les versions mineures précédentes, package@major.0 , package@major.1 , …, package@major.(minor-1) ne doivent pas être définies.
|
---|
Règle B | Toutes les affirmations suivantes sont vraies:
|
---|
En raison de la règle A:
- Le package peut commencer par n'importe quel numéro de version mineure (par exemple,
android.hardware.biometrics.fingerprint
commence à@2.1
). - L'exigence "
android.hardware.foo@1.0
n'est pas défini" signifie que le répertoirehardware/interfaces/foo/1.0
ne devrait même pas exister.
Toutefois, la règle A n'affecte pas un package portant le même nom, mais une version majeure différente (par exemple, android.hardware.camera.device
a défini à la fois @1.0
et @3.2
; @3.2
n'a pas besoin d'interagir avec @1.0
). Par conséquent, @3.2::IExtFoo
peut étendre @1.0::IFoo
.
Si le nom du package est différent, package@major.minor::IBar
peut étendre une interface avec un nom différent (par exemple, android.hardware.bar@1.0::IBar
peut étendre android.hardware.baz@2.2::IBaz
). Si une interface ne déclare pas explicitement un super-type avec le mot clé extend
, elle étend android.hidl.base@1.0::IBase
(à l'exception de IBase
).
B.2 et B.3 doivent être suivis en même temps. Par exemple, même si android.hardware.foo@1.1::IFoo
étend android.hardware.foo@1.0::IFoo
pour respecter la règle B.2, si un android.hardware.foo@1.1::IExtBar
étend android.hardware.foo@1.0::IBar
, il ne s'agit toujours pas d'une mise à niveau valide.
Interfaces Uprev
Pour mettre à niveau android.hardware.example@1.0
(défini ci-dessus) vers @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); }
Il s'agit d'un import
au niveau du package de la version 1.0
de android.hardware.example
dans types.hal
. Bien qu'aucun nouveau type défini par l'utilisateur ne soit ajouté dans la version 1.1
du package, les références aux types définis par l'utilisateur dans la version 1.0
sont toujours nécessaires, d'où l'importation au niveau du package dans types.hal
. (Le même effet aurait pu être obtenu avec une importation au niveau de l'interface dans IQuux.hal
.)
Dans extends @1.0::IQuux
, dans la déclaration de IQuux
, nous avons spécifié la version de IQuux
qui est héritée (une distinction est nécessaire, car IQuux
permet de déclarer une interface et d'en hériter). Comme les déclarations ne sont que des noms qui héritent de tous les attributs de package et de version au site de la déclaration, la démystification doit figurer dans le nom de l'interface de base. Nous aurions également pu utiliser le type de données défini par l'utilisateur complet, mais cela aurait été redondant.
La nouvelle interface IQuux
ne redeclare pas la méthode fromFooToBar()
qu'elle hérite de @1.0::IQuux
. Elle liste simplement la nouvelle méthode qu'elle ajoute fromBarToFoo()
. Dans HIDL, les méthodes héritées ne peuvent pas être déclarées à nouveau dans les interfaces enfants. Par conséquent, l'interface IQuux
ne peut pas déclarer explicitement la méthode fromFooToBar()
.
Conventions Uprev
Parfois, les noms d'interface doivent renommer l'interface étendue. Nous vous recommandons de donner aux extensions d'énumération, aux structures et aux unions le même nom que celui qu'elles étendent, sauf si elles sont suffisamment différentes pour justifier un nouveau nom. Exemples :
// 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 };
Si une méthode peut avoir un nouveau nom sémantique (par exemple, fooWithLocation
), c'est préférable. Sinon, il doit être nommé de manière similaire à ce qu'il étend. Par exemple, la méthode foo_1_1
dans @1.1::IFoo
peut remplacer la fonctionnalité de la méthode foo
dans @1.0::IFoo
s'il n'existe pas de meilleur nom alternatif.
Gestion des versions au niveau du package
La gestion des versions HIDL se produit au niveau du package. Une fois qu'un package est publié, il est immuable (son ensemble d'interfaces et de types UDT ne peut pas être modifié). Les packages peuvent se rapporter les uns aux autres de plusieurs manières, toutes exprimables via une combinaison d'héritage au niveau de l'interface et de création de types de données utilisateur par composition.
Toutefois, un type de relation est strictement défini et doit être appliqué : l'héritage rétrocompatible au niveau du package. Dans ce scénario, le package parent est celui dont le package enfant hérite. Les règles d'héritage rétrocompatibles au niveau du package sont les suivantes:
- Toutes les interfaces de niveau supérieur du package parent sont héritées des interfaces du package enfant.
- Vous pouvez également ajouter de nouvelles interfaces au nouveau package (aucune restriction concernant les relations avec d'autres interfaces dans d'autres packages).
- Vous pouvez également ajouter de nouveaux types de données à utiliser par de nouvelles méthodes d'interfaces existantes mises à jour ou par de nouvelles interfaces.
Ces règles peuvent être implémentées à l'aide de l'héritage au niveau de l'interface HIDL et de la composition UDT, mais nécessitent des connaissances au niveau méta pour savoir que ces relations constituent une extension de package rétrocompatible. Cette connaissance est déduite comme suit:
Si un package répond à cette exigence, hidl-gen
applique des règles de rétrocompatibilité.