AIDL-Sprache

Die AIDL-Sprache basiert lose auf der Java-Sprache. In den Dateien werden ein Interface-Vertrag und 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 Back-Ends entspricht. Eine Paketdeklaration sieht so aus:

    package my.package;

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

Typen

In AIDL-Dateien können an vielen Stellen Typen angegeben werden. Eine genaue Liste der Typen, die in der AIDL-Sprache unterstützt werden, finden Sie unter AIDL-Back-End-Typen.

Anmerkungen

Mehrere Teile der AIDL-Sprache unterstützen Anmerkungen. Eine Liste der Anmerkungen und ihrer Verwendungsmöglichkeiten finden Sie unter AIDL-Anmerkungen.

Importe

Wenn Sie Typen verwenden möchten, die in anderen Schnittstellen definiert sind, müssen Sie zuerst Abhängigkeiten im Build-System hinzufügen. In cc_*- und java_*-Soong-Modulen, in denen .aidl-Dateien in Android-Plattform-Builds direkt unter srcs verwendet werden, können Sie mit dem Feld aidl: { include_dirs: ... } Verzeichnisse hinzufügen. Informationen zu Importen 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. Das Auslassen des Pakets kann jedoch zu mehrdeutigen Importfehlern führen, wenn Typen ohne Paket angegeben und in den globalen Namespace eingefügt werden. Im Allgemeinen sollten alle Typen einen Namensraum haben:

    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 eine Beispiel-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. Einwegmethoden werden asynchron gesendet und können kein Ergebnis zurückgeben. Einwegmethoden vom selben Thread in denselben Binder werden auch nacheinander ausgeführt (möglicherweise auf verschiedenen Threads). Weitere Informationen zum Einrichten von Threads finden Sie unter Thread-Management für AIDL-Back-Ends.

Binder ermöglicht die Freigabe vieler Schnittstellen und Binder-Objekte über Binder-Schnittstellen. In AIDL-Schnittstellen werden häufig Callbacks als Teil von Methodenaufrufen verwendet, z. B. ITeleportCallback im vorherigen Beispiel. Sie können Rückrufobjekte zwischen Aufrufen derselben Methode oder Aufrufen verschiedener Methoden wiederverwenden. Schnittstellentypen werden auch häufig verwendet, um Subschnittstellen oder Sitzungsobjekte mit Methoden wie ITeleportSession im vorherigen Beispiel zurückzugeben. Durch dieses Verschachtelungsmuster können verschiedene APIs entweder auf API-Ebene oder basierend auf dem Laufzeitstatus gekapselt werden. Eine Sitzung kann beispielsweise die Inhaberschaft einer bestimmten Ressource darstellen. Wenn Schnittstellen mehrmals übergeben oder an den Client oder Server zurückgegeben werden, von dem sie gekommen sind, bewahren sie immer die Zeigergleichheit des zugrunde liegenden Binderobjekts auf.

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 Richtung von AIDL-Back-Ends.

Parcelables

Eine Beschreibung zum Erstellen backendspezifischer Parcelables finden Sie unter Benutzerdefinierte Parcelables für AIDL-Backends.

Android 10 und höher unterstützen Parcelable-Definitionen direkt in AIDL. Diese Art von Parzelle wird als strukturierte Parzelle bezeichnet. Weitere Informationen dazu, wie sich strukturierte und stabile AIDL im AIDL-Compiler und in unserem Build-System unterscheiden, 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 getaggte Union-Deklarationen. Beispiel:

    package my.package;

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

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

Backendspezifische Details finden Sie unter AIDL-Backend-Unions.

Aufzählungen

Android 11 und höher unterstützen enum-Deklarationen. Beispiel:

    package my.package;

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

Verschachtelte Typdeklarationen

Android 13 und höher unterstützen verschachtelte Typdeklarationen. 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 Unionen können auch Ganzzahl- 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 mithilfe von 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.

true- und false-Literale stellen boolesche Werte dar. Werte mit ., aber ohne Suffix, z. B. 3.8, gelten als doppelte Werte. Gleitkommawerte haben das Suffix f, z. B. 2.4f. Ein ganzzahliger Wert mit dem Suffix l oder L gibt einen 64 Bit langen Wert an. Andernfalls wird für Ganzzahlwerte der kleinste Werttyp mit Vorzeichen zwischen 8-Bit (Byte), 32-Bit (int) und 64-Bit (long) verwendet. 256 wird also als int betrachtet, aber 255 + 1 überschreitet den Grenzwert und wird zum byte 0. Hexadezimalwerte wie 0x3 werden zuerst als kleinster werterhaltender 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 anzugeben. Dieses Suffix ist wichtig, damit eine Berechnung wie 0xffu8 * 3 als -3 vom Typ byte interpretiert wird, während 0xff * 3 765 vom Typ int ist.

Die unterstützten Operatoren haben C++- und Java-Semantik. Die binären Operatoren haben folgende Priorität: || && | ^ & == != < > <= >= << >> + - * / %. Unäre Operatoren sind + - ! ~.