AIDL-Sprache

Die AIDL-Sprache basiert lose auf der Java-Sprache. In Dateien wird ein Schnittstellenvertrag sowie verschiedene Datentypen und Konstanten angegeben, die in diesem Vertrag verwendet werden.

Paket

Jede AIDL-Datei beginnt mit einem optionalen Paket, das den Paketnamen in verschiedenen Backends entspricht. Eine Paketdeklaration sieht so aus:

    package my.package;

Ähnlich wie bei Java müssen sich AIDL-Dateien in einer Ordnerstruktur befinden, die ihrem Paket entspricht. Dateien mit dem Paket my.package müssen sich im Ordner my/package/ befinden.

Typen

In AIDL-Dateien gibt es viele Stellen, an denen Typen angegeben werden können. Eine genaue Liste der in der AIDL-Sprache unterstützten Typen finden Sie unter AIDL-Backend-Typen.

Anmerkungen

Mehrere Teile der AIDL-Sprache unterstützen Anmerkungen. Eine Liste der Annotationen und der Stellen, an denen sie angewendet werden können, finden Sie unter AIDL-Annotationen.

Importe

Wenn Sie in anderen Schnittstellen definierte Typen verwenden möchten, müssen Sie zuerst Abhängigkeiten im Build-System hinzufügen. In cc_*- und java_*-Soong-Modulen, in denen .aidl-Dateien direkt unter srcs in Android-Plattform-Builds verwendet werden, können Sie Verzeichnisse mit dem Feld aidl: { include_dirs: ... } hinzufügen. Informationen zum Importieren mit aidl_interface finden Sie hier.

Ein Import sieht so aus:

    import some.package.Foo;  // explicit import

Beim Importieren eines Typs im selben Paket kann das Paket weggelassen werden. Wenn Sie das Paket weglassen, kann dies jedoch zu mehrdeutigen Importfehlern führen, wenn Typen ohne Paket angegeben und im globalen Namespace platziert werden (im Allgemeinen sollten alle Typen mit einem Namespace versehen werden):

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

Typen definieren

In AIDL-Dateien werden in der Regel Typen definiert, die als Schnittstelle verwendet werden.

Schnittstellen

Hier ist ein Beispiel für eine AIDL-Schnittstelle:

    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();
    }

Eine Schnittstelle definiert ein Objekt mit einer Reihe von Methoden. Methoden können entweder oneway (oneway void doFoo()) oder synchron sein. Wenn eine Schnittstelle als oneway (oneway interface ITeleport {...}) definiert ist, sind alle Methoden darin implizit oneway. Oneway-Methoden werden asynchron gesendet und können kein Ergebnis zurückgeben. Unidirektionale Methoden vom selben Thread zum selben Binder werden ebenfalls seriell ausgeführt (möglicherweise in verschiedenen Threads). Eine Anleitung zum Einrichten von Threads finden Sie unter Threadverwaltung für AIDL-Back-Ends.

Mit Binder können viele Schnittstellen und Binder-Objekte über Binder-Schnittstellen freigegeben werden. AIDL-Schnittstellen verwenden häufig Callbacks als Teil von Methodenaufrufen, wie z. B. ITeleportCallback im vorherigen Beispiel. Sie können Callback-Objekte zwischen Aufrufen derselben Methode oder Aufrufen verschiedener Methoden wiederverwenden. Eine weitere häufige Verwendung von Schnittstellentypen ist das Zurückgeben von Unterschnittstellen oder Sitzungsobjekten aus Methoden, wie im vorherigen Beispiel mit ITeleportSession. Durch diese Schachtelung können verschiedene APIs entweder auf API- oder auf Laufzeitstatusbasis gekapselt werden. Eine Sitzung kann beispielsweise den Besitz einer bestimmten Ressource darstellen. Wenn Schnittstellen mehrmals übergeben oder an den Client oder Server zurückgegeben werden, von dem sie stammen, behalten sie immer die Zeigergleichheit des zugrunde liegenden Binder-Objekts bei.

Methoden können null oder mehr Argumente haben. Argumente für Methoden können in, out oder inout sein. Eine Erläuterung dazu, wie sich dies auf Argumenttypen auswirkt, finden Sie unter AIDL-Back-Ends – Richtung.

Parcelables

Eine Beschreibung zum Erstellen von backend-spezifischen Parcelables finden Sie unter Benutzerdefinierte AIDL-Backend-Parcelables.

Unter Android 10 und höher werden Parcelable-Definitionen direkt in AIDL unterstützt. Diese Art von Parcelable wird als strukturiertes Parcelable bezeichnet. Weitere Informationen dazu, wie sich strukturierte und stabile AIDL im AIDL-Compiler und unserem Build-System zueinander verhalten, finden Sie unter Strukturiertes und stabiles AIDL.

Beispiel:

    package my.package;

    import my.package.Boo;

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

Gewerkschaften

Android 12 und höher unterstützen Deklarationen für getaggte Unions. Beispiel:

    package my.package;

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

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

Weitere backend-spezifische Informationen finden Sie unter AIDL Backends Unions.

Aufzählungen

In Android 11 und höher werden Enum-Deklarationen unterstützt. Beispiel:

    package my.package;

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

Verschachtelte Typdeklarationen

In Android 13 und höher werden verschachtelte Typdeklarationen unterstützt. Beispiel:

    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
    }

Konstanten

Benutzerdefinierte AIDL-Schnittstellen, Parcelables und Unions können auch Integer- und Stringkonstanten enthalten, z. B.:

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

Konstante Ausdrücke

AIDL-Konstanten, Arraygrößen und Enumeratoren können mit konstanten Ausdrücken angegeben werden. In Ausdrücken können Klammern verwendet werden, um Vorgänge zu verschachteln. Konstante Ausdruckswerte können mit Ganzzahl- oder Gleitkommawerten verwendet werden.

Die Literale true und false stellen boolesche Werte dar. Werte mit einem ., aber ohne Suffix, z. B. 3.8, werden als Double-Werte betrachtet. Gleitkommazahlen haben das Suffix f, z. B. 2.4f. Ein ganzzahliger Wert mit dem Suffix l oder L gibt einen 64-Bit-Long-Wert an. Andernfalls erhalten Integralwerte den kleinsten wertbewahrenden Typ mit Vorzeichen zwischen 8 Bit (Byte), 32 Bit (Int) und 64 Bit (Long). 256 wird also als int betrachtet, aber 255 + 1 läuft über und wird zum byte 0. Hexadezimalwerte wie 0x3 werden zuerst als kleinster wertbewahrender vorzeichenloser Typ zwischen 32 Bit und 64 Bit interpretiert und dann als vorzeichenlose Werte neu interpretiert. 0xffffffff hat also den Wert int -1. Ab Android 13 kann das Suffix u8 Konstanten wie 3u8 hinzugefügt werden, um einen byte-Wert darzustellen. Dieses Suffix ist wichtig, damit eine Berechnung wie 0xffu8 * 3 als -3 mit dem Typ byte interpretiert wird, während 0xff * 3 als 765 mit dem Typ int interpretiert wird.

Unterstützte Operatoren haben C++- und Java-Semantik. Binäre Operatoren sind in aufsteigender Priorität || && | ^ & == != < > <= >= << >> + - * / %. Unäre Operatoren sind + - ! ~.