4. AIDL核心概念
从 HIDL 迁移到 AIDL,第一步不是急着改代码,而是先建立对 AIDL 接口模型的正确认知。AIDL(Android Interface Definition Language)本质上是一套“跨进程契约描述语言”:开发者用 .aidl 文件声明接口方法、参数类型和方向,编译期由 aidl 工具生成 Binder 代理与桩代码,运行时通过 Binder 驱动完成跨进程调用。理解接口定义、文件语法、稳定 AIDL 与版本化机制,是后续迁移工程能否平滑落地的关键。
一、AIDL 接口定义与文件语法
AIDL 接口以 interface 关键字声明,方法参数需显式标注方向:in(调用方传入)、out(被调用方回填)、inout(双向)。基本类型默认按值传递,自定义类型必须实现 Parcelable 并在同包或导入路径下声明。接口文件通常放在 aidl/ 源码目录,包名与 Java 包名一致。
// IFoo.aidl
package vendor.demo.foo;
import vendor.demo.foo.Result;
interface IFoo {
int getVersion();
Result process(in byte[] input, out int status);
void registerCallback(IFooCallback cb);
}
编译后生成 IFoo.Stub(服务端实现基类)与 IFoo.Proxy(客户端代理)。服务端继承 Stub 并实现方法,客户端通过 IFoo.Stub.asInterface(binder) 获取代理。需要注意的是,AIDL 方法默认同步阻塞,若需异步可声明 oneway,但 oneway 方法不能有返回值与 out 参数。
二、稳定 AIDL(Stable AIDL)
普通 AIDL 的接口布局由编译期决定,一旦发布后修改方法顺序或类型,就会破坏已有客户端的调用约定。稳定 AIDL 通过 @VintfStability 注解和 --stability 编译选项,把接口的 ABI 固定下来,使其可以跨 Android 版本、跨分区(system/vendor/product)稳定通信,并支持 VINTF 兼容性校验。
@VintfStability;所有自定义类型也需稳定;方法参数与返回值类型必须可稳定序列化;接口一旦发布,只能追加方法,不能修改或删除已有方法签名。
在 Android 11 及以上,HAL 接口推荐使用稳定 AIDL 替代 HIDL。迁移时,原本 HIDL 的 @1.0 接口通常对应一个稳定 AIDL 接口,并通过 @VintfStability 保证 vendor 与 framework 之间的兼容性。
三、版本化接口与向后兼容机制
AIDL 的版本化不是靠文件名中的版本号,而是靠“接口冻结 + 追加式演进”。稳定 AIDL 接口在发布后会被冻结(frozen),后续版本只能新增方法,且新方法必须放在接口末尾。旧客户端调用新服务端时,未实现的新方法会返回 UNKNOWN_TRANSACTION,因此服务端需要提供默认实现或版本查询方法。
// 版本化接口示例
interface IFoo {
const int VERSION = 2;
int getInterfaceVersion();
Result process(in byte[] input, out int status);
// 新增方法必须追加在末尾
void setConfig(in Config cfg);
}
客户端应先调用 getInterfaceVersion() 判断服务端能力,再决定是否调用新方法。这种“能力协商”模式是 AIDL 向后兼容的核心:旧服务端不认识新方法,新客户端必须优雅降级;新服务端遇到旧客户端,则只暴露旧方法即可。
四、迁移场景与常见误区
在 HIDL 到 AIDL 的迁移中,最常见的场景是把 HIDL 的 @1.0::IFoo 映射为稳定 AIDL 的 IFoo,并把 HIDL 的 generates、callback 等语义转换为 AIDL 的 oneway、in/out 参数。迁移后必须重新冻结接口,不能沿用 HIDL 的版本号语义。
| 对比项 | HIDL | 稳定 AIDL |
|---|---|---|
| 接口描述 | .hal 文件,含版本号 | .aidl 文件,@VintfStability |
| 版本演进 | 主版本 + 次版本,可多版本共存 | 冻结后追加方法,单接口版本号 |
| 兼容性校验 | VINTF 矩阵 | VINTF + 稳定 AIDL 冻结校验 |
| 调用方式 | hwbinder + passthrough | binder + Binder 代理/桩 |
@VintfStability;在 oneway 方法中使用 out 参数;迁移后未重新冻结接口就发布。这些都会导致跨进程调用失败或 VINTF 校验不通过。
总结来说,AIDL 的核心是“契约先行、编译生成、稳定冻结、追加演进”。掌握 .aidl 语法、稳定 AIDL 的 @VintfStability 约束,以及基于 getInterfaceVersion() 的能力协商机制,才能在 HIDL 迁移中既保证功能对齐,又保证跨版本、跨分区的长期兼容。