2021-11-17 AIDL
AIDL 概览
Android 接口定义语言 (AIDL) 是一款可供用户用来抽象化 IPC 的工具。以在 .aidl
文件中指定的接口为例,各种构建系统都会使用 aidl
二进制文件构造 C++ 或 Java 绑定,以便跨进程使用该接口(无论其运行时环境或位数如何)。
AIDL 可以在 Android 中的任何进程之间使用:在平台组件之间使用或在应用之间使用均可。但是,AIDL 绝不能用作应用的 API。例如,可以使用 AIDL 在平台中实现 SDK API,但 SDK API Surface 绝不能直接包含 AIDL API。在 APEX(从 Android 10 开始)或 HAL(从 Android 11 开始)等单独更新的平台组件之间使用 AIDL 时,必须使用称为稳定的 AIDL的版本控制系统。
示例
以下是一个 AIDL 接口示例:
package my.package;
import my.package.Baz; // defined elsewhere
interface IFoo {
void doFoo(Baz baz); // synchronous method
oneway void doFoo(int a); // async method
}
Android 10 及更高版本支持 parcelable 声明。例如:
package my.package;
import my.package.Boo;
parcelable Baz {
@utf8InCpp String name = "baz";
Boo boo;
}
Android 11 及更高版本支持枚举声明。例如:
package my.package;
enum Boo {
A = 1 * 4,
B = 3,
}
Android 12 及更高版本支持联合声明。例如:
package my.package;
import my.package.FooSettings;
import my.package.BarSettings;
union Settings {
FooSettings fooSettings;
BarSettings barSettings;
@utf8InCpp String str;
int number;
}
Android T(AOSP 实验版)及更高版本支持嵌套类型声明。 例如:
package my.package;
import my.package.Baz;
interface IFoo {
void doFoo(Baz.Nested nested); // defined my/package/Baz.aidl
void doBar(Bar bar); // defined below
parcelable Bar { ... } // union/enum types can be nested, while
// an interface can't.
}
服务器进程注册接口并提供对它的调用,客户端进程则调用这些接口。在许多情况下,进程既是客户端又是服务器,因为它可能会引用多个接口。如需详细了解可供您用来使用这些接口的各种运行时环境,请参阅 AIDL 后端。这些类型声明与给定语言中的类声明完全相同,但可以跨进程工作。
工作原理
AIDL 使用 Binder 内核驱动程序进行调用。当您发出调用时,系统会将方法标识符和所有对象打包到某个缓冲区中,然后将其复制到某个远程进程,该进程中有一个 Binder 线程正在等待读取数据。Binder 线程收到某个事务的数据后,该线程会在本地进程中查找原生桩对象,然后此类会解压缩数据并调用本地接口对象。此本地接口对象正是服务器进程所创建和注册的对象。当在同一进程和同一后端中进行调用时,不存在代理对象,因此直接调用即可,无需执行任何打包或解压缩操作。
与设备上的服务互动
Android 具有一些命令,可供您用来与设备上的服务互动。请尝试输入:
adb shell dumpsys --help # listing and dumping services
adb shell service --help # sending commands to services for testing