Langage AIDL

Le langage AIDL est vaguement basé sur le langage Java. Les fichiers spécifient un contrat d'interface, ainsi que divers types de données et constantes utilisés dans ce contrat.

Package

Chaque fichier AIDL commence par un package facultatif qui correspond aux noms de package dans différents backends. Une déclaration de package se présente comme suit:

    package my.package;

Comme pour Java, les fichiers AIDL doivent se trouver dans une structure de dossiers correspondant à leur package. Les fichiers avec le package my.package doivent se trouver dans le dossier my/package/.

Types

Dans les fichiers AIDL, les types peuvent être spécifiés à de nombreux endroits. Pour obtenir la liste exacte des types compatibles avec le langage AIDL, consultez la section Types de backends AIDL.

Annotations

Plusieurs parties du langage AIDL acceptent les annotations. Pour obtenir la liste des annotations et les emplacements où elles peuvent être appliquées, consultez la section Annotations AIDL.

Importations

Pour utiliser les types définis dans d'autres interfaces, vous devez d'abord ajouter des dépendances dans le système de compilation. Dans les modules Soong cc_* et java_*, où les fichiers .aidl sont utilisés directement sous srcs dans les builds de la plate-forme Android, vous pouvez ajouter des répertoires à l'aide du champ aidl: { include_dirs: ... }. Pour les importations à l'aide de aidl_interface, consultez cette page.

Une importation se présente comme suit:

    import some.package.Foo;  // explicit import

Lorsque vous importez un type dans le même package, vous pouvez omettre le package. Toutefois, l'omission du package peut entraîner des erreurs d'importation ambiguës lorsque les types sont spécifiés sans package et placés dans l'espace de noms global (en général, tous les types doivent être associés à un espace de noms):

    import Foo;  // same as my.package.Foo

Définir des types

Les fichiers AIDL définissent généralement des types utilisés comme interface.

Interfaces

Voici un exemple d'interface AIDL:

    interface ITeleport {
        // Location defined elsewhere
        void teleport(Location baz, float speed);
        String getName();

        // ITeleportCallback defined elsewhere
        void methodWithCallback(ITeleportCallback callback);

        // ITeleportSession defined elsewhere
        ITeleportSession getASubInterface();
    }

Une interface définit un objet avec une série de méthodes. Les méthodes peuvent être oneway (oneway void doFoo()) ou synchrones. Si une interface est définie sur oneway (oneway interface ITeleport {...}), toutes les méthodes qu'elle contient sont implicitement oneway. Les méthodes à sens unique sont envoyées de manière asynchrone et ne peuvent pas renvoyer de résultat. Les méthodes unidirectionnelles du même thread au même liaison s'exécutent également en série (bien que potentiellement sur des threads différents). Pour savoir comment configurer des threads, consultez la section Gestion des threads des backends AIDL.

Le liaisonneur permet de partager de nombreuses interfaces et objets de liaison via des interfaces de liaison. Les interfaces AIDL utilisent fréquemment des rappels dans les appels de méthode, comme avec ITeleportCallback dans l'exemple précédent. Vous pouvez réutiliser des objets de rappel entre les appels à la même méthode ou à différentes méthodes. Une autre utilisation courante des types d'interfaces consiste à renvoyer des sous-interfaces ou des objets de session à partir de méthodes, comme avec ITeleportSession dans l'exemple précédent. Cette imbrication permet d'encapsuler différentes API au niveau de l'API ou en fonction de l'état d'exécution. Par exemple, une session peut représenter la propriété d'une ressource particulière. Lorsque des interfaces sont transmises plusieurs fois ou renvoyées au client ou au serveur d'où elles proviennent, elles préservent toujours l'égalité des pointeurs de l'objet de liaison sous-jacent.

Les méthodes peuvent avoir zéro ou plusieurs arguments. Les arguments des méthodes peuvent être in, out ou inout. Pour en savoir plus sur l'impact de ce changement sur les types d'arguments, consultez la section Orientation des backends AIDL.

Éléments Parcelables

Pour savoir comment créer des parcelables spécifiques au backend, consultez Parcelables personnalisés de backend AIDL.

Android 10 et les versions ultérieures sont compatibles avec les définitions parcelables directement dans AIDL. Ce type de parcelable est appelé "parcelable structuré". Pour en savoir plus sur la relation entre AIDL structuré et stable dans le compilateur AIDL et notre système de compilation, consultez la section AIDL structuré et stable.

Exemple :

    package my.package;

    import my.package.Boo;

    parcelable Baz {
        @utf8InCpp String name = "baz";
        Boo boo;
    }

Unions

Android 12 et versions ultérieures sont compatibles avec les déclarations d'union taguée. Exemple :

    package my.package;

    import my.package.FooSettings;
    import my.package.BarSettings;

    union Settings {
        FooSettings fooSettings;
        BarSettings barSettings;
        @utf8InCpp String str;
        int number;
    }

Pour en savoir plus sur les backend, consultez la section Unions de backend AIDL.

Énumérations

Android 11 et versions ultérieures sont compatibles avec les déclarations d'énumérations. Exemple :

    package my.package;

    enum Boo {
        A = 1 * 4,
        B = 3,
    }

Déclarations de type imbriquées

Android 13 et versions ultérieures sont compatibles avec les déclarations de types imbriqués. Exemple :

    package my.package;

    import my.package.Baz;

    interface IFoo {
        void doFoo(Baz.Nested nested);  // defined in my/package/Baz.aidl
        void doBar(Bar bar);            // defined below

        parcelable Bar { ... }          // nested type definition
    }

Constantes

Les interfaces, les éléments parcellables et les unions AIDL personnalisées peuvent également contenir des constantes d'entiers et de chaînes, par exemple:

    const @utf8InCpp String HAPPY = ":)";
    const String SAD = ":(";
    const byte BYTE_ME = 1;
    const int ANSWER = 6 * 7;

Expressions constantes

Les constantes AIDL, les tailles de tableaux et les énumérateurs peuvent être spécifiés à l'aide d'expressions constantes. Les expressions peuvent utiliser des parenthèses pour imbriquer des opérations. Les valeurs d'expression constantes peuvent être utilisées avec des valeurs entières ou à virgule flottante.

Les littéraux true et false représentent des valeurs booléennes. Les valeurs contenant un ., mais sans suffixe, telles que 3.8, sont considérées comme des valeurs doubles. Les valeurs à virgule flottante sont associées au suffixe f, par exemple 2.4f. Une valeur entière avec le suffixe l ou L indique une valeur de 64 bits. Sinon, les valeurs intégrales obtiennent le plus petit type signé préservant la valeur entre 8 bits (octet), 32 bits (int) et 64 bits (long). 256 est donc considéré comme une int, mais 255 + 1 déborde pour être le 0 byte. Les valeurs hexadécimales, telles que 0x3, sont d'abord interprétées comme le plus petit type non signé préservant la valeur entre 32 bits et 64 bits, puis réinterprétées en tant que valeurs non signées. 0xffffffff a donc la valeur int -1. À partir d'Android 13, le suffixe u8 peut être ajouté aux constantes, telles que 3u8, pour représenter une valeur byte. Ce suffixe est important pour qu'un calcul, tel que 0xffu8 * 3, soit interprété comme -3 avec le type byte, tandis que 0xff * 3 est 765 avec le type int.

Les opérateurs compatibles ont une sémantique C++ et Java. Dans l'ordre de priorité de la plus faible à la plus élevée, les opérateurs binaires sont || && | ^ & == != < > <= >= << >> + - * / %. Les opérateurs unaires sont + - ! ~.