AIDL 语言

AIDL 语言大致上基于 Java 语言。文件会指定接口协定以及此协定中使用的各种数据类型和常量。

软件包

每个 AIDL 文件都以一个可选软件包开头,该软件包与各个后端中的软件包名称相对应。软件包声明如下所示:

    package my.package;

与 Java 类似,AIDL 文件必须位于与其软件包匹配的文件夹结构中。包含软件包 my.package 的文件必须位于 my/package/ 文件夹中。

类型

在 AIDL 文件中,可以在许多位置指定类型。如需查看 AIDL 语言所支持类型的确切列表,请参阅 AIDL 后端类型

注释

AIDL 语言的多个部分均支持注解。如需查看注解列表以及可以应用它们的位置,请参阅 AIDL 注解

导入

如需使用其他接口中定义的类型,必须先在构建系统中添加依赖项。在 cc_*java_* Soong 模块中,.aidl 文件会直接在 Android 平台 build 中的 srcs 下使用,您可以使用 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。oneway 方法会异步调度,并且无法返回结果。从同一线程到同一 binder 的单向方法也会按顺序执行(但可能会在不同线程上执行)。如需查看有关如何设置线程的讨论,请参阅 AIDL 后端线程管理

Binder 允许通过 binder 接口共享多个接口和 binder 对象。AIDL 接口经常会在方法调用中使用回调,例如上例中的 ITeleportCallback。您可以在对同一方法的调用或对不同方法的调用之间重复使用回调对象。接口类型的另一个常见用途是用于从方法返回子接口或会话对象,例如前面示例中的 ITeleportSession。这种嵌套允许在 API 或根据运行时状态对不同的 API 进行封装。例如,会话可以代表特定资源的所有权。当接口多次传递或返回到其来源客户端或服务器时,它们始终会保持底层绑定对象的指针相等性。

方法可以有零个或多个参数。方法的参数可以是 inoutinout。如需查看有关这会如何影响参数类型的讨论,请参阅 AIDL 后端方向性

Parcelables

如需了解如何创建特定于后端的 Parcelable,请参阅 AIDL 后端自定义 Parcelable

Android 10 及更高版本支持直接使用 AIDL 进行 Parcelable 定义。这种类型的 Parcelable 称为结构化 Parcelable。如需详细了解结构化 AIDL 和稳定的 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 后端联合体

枚举

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 接口、Parcelable 和联合体还可以包含整数和字符串常量,例如:

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

常量表达式

您可以使用常量表达式指定 AIDL 常量、数组大小和枚举器。表达式可以使用括号来嵌套运算。常量表达式值可与整数或浮点值搭配使用。

truefalse 字面量表示布尔值。包含 . 但没有后缀的值(例如 3.8)会被视为双精度值。浮点值具有 f 后缀,例如 2.4f。以 lL 为后缀的整数值表示 64 位长的值。否则,整数值会获得 8 位(字节)、32 位(整型)和 64 位(长整型)之间的最小值保留有符号类型。因此,256 被视为 int,但 255 + 1 溢出为 byte 0。十六进制值(例如 0x3)首先被解析为 32 位到 64 位之间的最小值保留无符号类型,然后再重新解析为无符号值。因此,0xffffffffint 值为 -1。从 Android 13 开始,可以将后缀 u8 添加到常量中(例如 3u8),以表示 byte 值。此后缀非常重要,因此 0xffu8 * 3 计算解释为 -3(类型为 byte),而 0xff * 3 解释为 765(类型为 int)。

支持的运算符具有 C++ 和 Java 语义。按照优先级从低到高的顺序,二元运算符为 || && | ^ & == != < > <= >= << >> + - * / %,一元运算符为 + - ! ~