язык AIDL

Язык AIDL в некоторой степени основан на языке Java. Файлы определяют контракт интерфейса, а также различные типы данных и константы, используемые в этом контракте.

Упаковка

Каждый файл AIDL начинается с необязательного пакета, соответствующего именам пакетов в различных бэкендах. Объявление пакета выглядит следующим образом:

    package my.package;

Как и в случае с Java, файлы AIDL должны находиться в папке, соответствующей их пакету. Файлы с пакетом my.package должны находиться в папке my/package/ .

Типы

В файлах AIDL существует множество мест, где можно указать типы. Полный список типов, поддерживаемых языком AIDL, см. в разделе «Типы бэкендов AIDL» .

Аннотации

Некоторые части языка AIDL поддерживают аннотации. Список аннотаций и области их применения см. в разделе «Аннотации AIDL» .

Импорт

Чтобы использовать типы, определённые в других интерфейсах, необходимо сначала добавить зависимости в систему сборки. В модулях Soong cc_* и java_* , где файлы .aidl используются непосредственно в srcs в сборках платформы Android, можно добавить каталоги с помощью поля aidl: { include_dirs: ... } . Сведения об импорте с помощью aidl_interface см. здесь .

Импорт выглядит так:

    import some.package.Foo;  // explicit import

При импорте типа в том же пакете пакет можно не указывать. Однако это может привести к неоднозначным ошибкам импорта, если типы указаны без пакета и помещены в глобальное пространство имён (как правило, все типы должны быть включены в пространство имён):

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

Определить типы

Файлы AIDL обычно определяют типы, которые используются в качестве интерфейса.

Интерфейсы

Вот пример интерфейса 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();
    }

Интерфейс определяет объект с набором методов. Методы могут быть oneway ( oneway void doFoo() ) или синхронными. Если интерфейс определён как oneway ( oneway interface ITeleport {...} ), то все методы в нём неявно являются oneway . Односторонние методы выполняются асинхронно и не могут возвращать результат. Односторонние методы из одного потока в один и тот же связующий компонент также выполняются последовательно (хотя, возможно, в разных потоках). Подробнее о настройке потоков см. в разделе Управление потоками бэкендов AIDL .

Связыватель позволяет совместно использовать множество интерфейсов и объектов связывателя через интерфейсы связывателя. Интерфейсы AIDL часто используют обратные вызовы как часть вызовов методов, например, ITeleportCallback в предыдущем примере. Вы можете повторно использовать объекты обратных вызовов между вызовами одного и того же метода или вызовами разных методов. Другое распространённое применение типов интерфейсов — возврат подинтерфейсов или объектов сеанса из методов, например, ITeleportSession в предыдущем примере. Такая вложенность позволяет инкапсулировать различные API либо на уровне API, либо на основе состояния времени выполнения. Например, сеанс может представлять владение определённым ресурсом. Когда интерфейсы передаются несколько раз или возвращаются клиенту или серверу, с которого они были получены, они всегда сохраняют равенство указателей базового объекта связывателя.

Методы могут иметь ноль или более аргументов. Аргументы методов могут быть in , out или inout . Подробнее о том, как это влияет на типы аргументов, см. в разделе «Направленность бэкендов AIDL» .

Посылки

Описание того, как создавать специфичные для бэкенда parcelables, см. в статье AIDL backends custom parcelables .

Android 10 и более поздние версии поддерживают определения Parcelable непосредственно в AIDL. Этот тип Parcelable называется структурированным Parcelable. Подробнее о соотношении структурированного и стабильного AIDL в компиляторе AIDL и нашей системе сборки см. в разделе «Сравнение структурированного и стабильного AIDL» .

Например:

    package my.package;

    import my.package.Boo;

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

Профсоюзы

Android 12 и более поздние версии поддерживают маркированные декларации профсоюзов. Например:

    package my.package;

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

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

Подробную информацию о бэкендах см. в разделе Объединения бэкендов AIDL .

Перечисления

Android 11 и более поздние версии поддерживают объявления enum. Например:

    package my.package;

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

Вложенные объявления типов

Android 13 и более поздние версии поддерживают вложенные объявления типов. Например:

    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
    }

Константы

Пользовательские интерфейсы AIDL, парцелляты и объединения также могут содержать целочисленные и строковые константы, например:

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

Постоянные выражения

Константы AIDL, размеры массивов и перечислители можно указывать с помощью константных выражений. Выражения могут использовать скобки для вложения операций. Значения константных выражений можно использовать с целыми и плавающими числами.

Литералы true и false представляют логические значения. Значения с точкой ( . но без суффикса, например, 3.8 , считаются значениями типа double. Значения с плавающей точкой (float) имеют суффикс f , например, 2.4f . Целочисленное значение с суффиксом l или L указывает на 64-битное значение типа long. В противном случае целочисленные значения получают наименьший сохраняющий значение знаковый тип из 8-битных (byte), 32-битных (int) и 64-битных (long). Так, 256 считается int , но 255 + 1 переполняется, становясь byte 0 Шестнадцатеричные значения, такие как 0x3 , сначала интерпретируются как наименьший сохраняющий значение беззнаковый тип из 32-битных и 64-битных, а затем переинтерпретируются как беззнаковые значения. Так, 0xffffffff имеет значение int -1 . Начиная с Android 13, к константам, например, 3u8 , можно добавлять суффикс u8 для представления byte значения. Этот суффикс важен, поскольку вычисление, например, 0xffu8 * 3 , интерпретируется как -3 с типом byte , тогда как 0xff * 3 — как 765 с типом int .

Поддерживаемые операторы имеют семантику C++ и Java. В порядке от низшего к высшему приоритету бинарные операторы: || && | ^ & == != < > <= >= << >> + - * / % . Унарные операторы: + - ! ~ .