язык AIDL

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

Упаковка

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

    package my.package;

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

Типы

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

Аннотации

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

Импорт

Чтобы использовать типы, определенные в других интерфейсах, необходимо сначала добавить зависимости в систему сборки. В модулях cc_* и java_* Soong, где файлы .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 .

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

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

Посылки

Описание того, как создавать отдельные объекты для серверной части, можно найти в AIDL .

Android 10 и более поздних версий поддерживают определения пакетов непосредственно в AIDL. Этот тип посылок называется структурированным. Дополнительную информацию о том, как структурированный и стабильный 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 Backend Unions .

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

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

    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 , считаются двойными значениями. Значения с плавающей запятой имеют суффикс f , например 2.4f . Целочисленное значение с суффиксом l или L указывает на 64-битное длинное значение. В противном случае целочисленные значения получают наименьший сохраняющий значение знаковый тип между 8-битным (байт), 32-битным (int) и 64-битным (длинным). Таким образом, 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. Бинарные операторы в порядке от низшего к высшему приоритету имеют вид || && | ^ & == != < > <= >= << >> + - * / % . Унарные операторы + - ! ~ .