Annotations en AIDL

AIDL prend en charge les annotations qui donnent au compilateur AIDL des informations supplémentaires sur l'élément annoté, ce qui affecte également le code stub généré.

La syntaxe est similaire à celle de Java :

@AnnotationName(argument1=value, argument2=value) AidlEntity

Ici, AnnotationName est le nom de l'annotation et AidlEntity est une entité AIDL comme interface Foo , void method() ou int arg . Une annotation est attachée à l'entité qui la suit.

Certaines annotations peuvent avoir des arguments définis entre parenthèses, comme indiqué ci-dessus. Les annotations qui n'ont pas d'argument n'ont pas besoin de parenthèses. Par exemple:

@AnnotationName AidlEntity

Ces annotations ne sont pas les mêmes que les annotations Java, même si elles se ressemblent beaucoup. Les utilisateurs ne peuvent pas définir d'annotations AIDL personnalisées ; les annotations sont toutes prédéfinies. Certaines annotations n'affectent qu'un certain backend et ne sont pas opérationnelles dans d'autres backends. Ils ont différentes restrictions auxquelles ils peuvent être attachés.

Vous trouverez ci-dessous la liste des annotations AIDL prédéfinies :

Annotations Ajouté dans la version Android
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage dix
Hide 11
Backing 11
NdkOnlyStableParcelable 14
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

nullable

nullable déclare que la valeur de l'entité annotée ne peut pas être fournie.

Cette annotation ne peut être attachée qu'aux types de retour de méthode, aux paramètres de méthode et aux champs parcellaires.

interface IFoo {
    // method return types
    @nullable Data method();

    // method parameters
    void method2(in @nullable Data d);
}

parcelable Data {
    // parcelable fields
    @nullable Data d;
}

Les annotations ne peuvent pas être attachées à des types primitifs. Ce qui suit est une erreur.

void method(in @nullable int a); // int is a primitive type

Cette annotation n'est pas opérationnelle pour le backend Java. En effet, en Java, tous les types non primitifs sont transmis par référence, qui peut être null .

Dans le backend CPP, @nullable T correspond à std::unique_ptr<T> dans Android 11 ou version antérieure, et à std::optional<T> dans Android 12 ou version ultérieure.

Dans le backend NDK, @nullable T correspond toujours à std::optional<T> .

Pour un type L de type liste tel que T[] ou List<T> , @nullable L correspond à std::optional<std::vector<std::optional<T>>> (ou std::unique_ptr<std::vector<std::unique_ptr<T>>> dans le cas du backend CPP pour Android 11 ou version antérieure).

Il existe une exception à ce mappage. Lorsque T est IBinder ou une interface AIDL, @nullable n'est pas opérationnel. En d'autres termes, @nullable IBinder et IBinder correspondent également à android::sp<IBinder> , qui est déjà nullable car il s'agit d'un pointeur fort (les lectures CPP appliquent toujours la nullité, mais le type est toujours android::sp<IBinder> ).

À partir d'Android 13, @nullable(heap=true) peut être utilisé pour les champs parcellaires afin de modéliser les types récursifs. @nullable(heap=true) ne peut pas être utilisé avec des paramètres de méthode ou des types de retour. Lorsqu'il est annoté avec, le champ est mappé à une référence std::unique_ptr<T> allouée au tas dans les backends CPP/NDK. @nullable(heap=true) n'est pas opérationnel dans le backend Java.

utf8InCpp

utf8InCpp déclare qu'une String est représentée au format UTF8 pour le backend CPP. Comme son nom l'indique, l'annotation n'est pas opérationnelle pour les autres backends. Plus précisément, String est toujours UTF16 dans le backend Java et UTF8 dans le backend NDK.

Cette annotation peut être attachée partout où le type String peut être utilisé, y compris les valeurs de retour, les paramètres, les déclarations constantes et les champs parcellaires.

Pour le backend CPP, @utf8InCpp String dans AIDL correspond à std::string , tandis que String sans l'annotation correspond à android::String16 où UTF16 est utilisé.

Notez que l'existence de l'annotation utf8InCpp ne change pas la façon dont les chaînes sont transmises sur le fil. Les chaînes sont toujours transmises au format UTF16 sur le fil. Une chaîne annotée utf8InCpp est convertie en UTF16 avant d'être transmise. Lorsqu'une chaîne est reçue, elle est convertie d'UTF16 en UTF8 si elle a été annotée comme utf8InCpp .

VintfStabilité

VintfStability déclare qu'un type défini par l'utilisateur (interface, parcelable et enum) peut être utilisé dans les domaines du système et du fournisseur. Voir AIDL pour les HAL pour en savoir plus sur l'interopérabilité système-fournisseur.

L'annotation ne modifie pas la signature du type, mais lorsqu'elle est définie, l'instance du type est marquée comme stable afin qu'elle puisse voyager à travers les processus du fournisseur et du système.

L'annotation ne peut être attachée qu'aux déclarations de type définies par l'utilisateur, comme indiqué ci-dessous :

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Lorsqu'un type est annoté avec VintfStability , tout autre type référencé dans le type doit également être annoté en tant que tel. Dans l'exemple ci-dessous, Data et IBar doivent tous deux être annotés avec VintfStability .

@VintfStability
interface IFoo {
    void doSomething(in IBar b); // references IBar
    void doAnother(in Data d); // references Data
}

@VintfStability // required
interface IBar {...}

@VintfStability // required
parcelable Data {...}

De plus, les fichiers AIDL définissant les types annotés avec VintfStability ne peuvent être construits qu'en utilisant le type de module aidl_interface Soong, avec la propriété stability définie sur "vintf" .

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

Utilisation d'application non prise en charge

L'annotation UnsupportedAppUsage indique que le type AIDL annoté fait partie de l'interface non SDK qui a été accessible pour les applications héritées. Consultez Restrictions sur les interfaces non SDK pour plus d’informations sur les API masquées.

L'annotation UnsupportedAppUsage n'affecte pas le comportement du code généré. L'annotation annote uniquement la classe Java générée avec l'annotation Java du même nom.

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

Il s'agit d'une opération interdite pour les backends non Java.

Support

L'annotation Backing spécifie le type de stockage d'un type d'énumération AIDL.

@Backing(type="int")
enum Color { RED, BLUE, }

Dans le backend CPP, ce qui précède émet une classe enum C++ de type int32_t .

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

Si l'annotation est omise, le type est supposé être byte , qui correspond à int8_t pour le backend CPP.

L'argument type ne peut être défini que sur les types intégraux suivants :

  • byte (largeur 8 bits)
  • int (largeur 32 bits)
  • long (largeur 64 bits)

NdkOnlyStableParcelable

NdkOnlyStableParcelable marque une déclaration parcelable (et non une définition) comme stable afin qu'elle puisse être référencée à partir d'autres types AIDL stables. C'est comme JavaOnlyStableParcelable , mais NdkOnlyStableParcelable marque une déclaration parcelable comme stable pour le backend NDK plutôt que pour Java.

Pour utiliser ce colisable : * Vous devez spécifier ndk_header . * Vous devez disposer d'une bibliothèque NDK spécifiant le parcellaire et la bibliothèque doit être compilée dans la bibliothèque. Par exemple, dans le système de build principal sur un module cc_* , utilisez static_libs ou shared_libs . Pour aidl_interface , ajoutez la bibliothèque sous additional_shared_libraries dans Android.bp .

JavaOnlyStableParcelable

JavaOnlyStableParcelable marque une déclaration parcelable (et non une définition) comme stable afin qu'elle puisse être référencée à partir d'autres types AIDL stables.

AIDL stable nécessite que tous les types définis par l'utilisateur soient stables. Pour les parcelles, être stable nécessite que ses champs soient explicitement décrits dans le fichier source AIDL.

parcelable Data { // Data is a structured parcelable.
    int x;
    int y;
}

parcelable AnotherData { // AnotherData is also a structured parcelable
    Data d; // OK, because Data is a structured parcelable
}

Si le colisable n'était pas structuré (ou simplement déclaré), alors il ne peut pas être référencé.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable vous permet de remplacer la vérification lorsque le colisable auquel vous faites référence est déjà disponible en toute sécurité dans le cadre du SDK Android.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDériver

JavaDerive génère automatiquement des méthodes pour les types parcellaires dans le backend Java.

@JavaDerive(equals = true, toString = true)
parcelable Data {
  int number;
  String str;
}

L'annotation nécessite des paramètres supplémentaires pour contrôler ce qu'il faut générer. Les paramètres pris en charge sont :

  • equals=true génère les méthodes equals et hashCode .
  • toString=true génère la méthode toString qui imprime le nom du type et des champs. Par exemple : Data{number: 42, str: foo}

JavaPar défaut

JavaDefault , ajouté à Android 13, contrôle si la prise en charge de la gestion des versions d'implémentation par défaut est générée (pour setDefaultImpl ). Ce support n'est plus généré par défaut afin de gagner de la place.

JavaPassthrough

JavaPassthrough permet à l'API Java générée d'être annotée avec une annotation Java arbitraire.

Les annotations suivantes dans AIDL

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

devenir

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

dans le code Java généré.

La valeur du paramètre annotation est directement émise. Le compilateur AIDL ne examine pas la valeur du paramètre. S'il y a une erreur de syntaxe au niveau Java, elle ne sera pas détectée par le compilateur AIDL mais par le compilateur Java.

Cette annotation peut être attachée à n’importe quelle entité AIDL. Cette annotation est interdite aux backends non Java.

Taille fixe

FixedSize marque un parcellaire structuré comme étant de taille fixe. Une fois marqué, le colisable ne pourra pas recevoir de nouveaux champs ajoutés. Tous les champs du parcelleable doivent également être des types de taille fixe, y compris les types primitifs, les énumérations, les tableaux de taille fixe et les autres parcelles marquées de FixedSize .

Cela ne fournit aucune garantie sur différents bits et ne doit pas être invoqué pour une communication à bits mixtes.

Descripteur

Descriptor spécifie de force le descripteur d'interface d'une interface.

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

Le descripteur de l'interface ci-dessus est android.bar.IWorld . Si l'annotation Descriptor est manquante, le descripteur serait android.foo.IHello .

Ceci est utile pour renommer une interface déjà publiée. Rendre le descripteur de l'interface renommée identique au descripteur de l'interface avant le changement de nom permet aux deux interfaces de communiquer entre elles.

@hide dans les commentaires

Le compilateur AIDL reconnaît @hide dans les commentaires et le transmet à la sortie Java pour que Metalava puisse le récupérer. Ce commentaire garantit que le système de build Android sait que les API AIDL ne sont pas des API SDK.

@obsolète dans les commentaires

Le compilateur AIDL reconnaît @deprecated dans les commentaires comme une balise permettant d'identifier une entité AIDL qui ne doit plus être utilisée.

interface IFoo {
  /** @deprecated use bar() instead */
  void foo();
  void bar();
}

Chaque backend marque les entités obsolètes avec une annotation/un attribut spécifique au backend afin que le code client soit averti s'il fait référence aux entités obsolètes. Par exemple, l'annotation @Deprecated et la balise @deprecated sont attachées au code généré par Java.