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 兼容性校验。

稳定 AIDL 的核心约束:接口必须标注 @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 向后兼容的核心:旧服务端不认识新方法,新客户端必须优雅降级;新服务端遇到旧客户端,则只暴露旧方法即可。

AIDL 版本化接口与向后兼容机制 旧客户端 v1 只认识 process() 调用 getInterfaceVersion() 按版本降级调用 新客户端 v2 认识 process() + setConfig() 先查版本再调用新方法 旧服务端则跳过新方法 服务端 v2 实现 process() + setConfig() getInterfaceVersion() 返回 2 未实现方法返回错误码 兼容性判断路径 调用 getInterfaceVersion() 获取服务端版本号 版本 >= 2 ? 是则调用 setConfig() 否则降级 仅调用旧方法

四、迁移场景与常见误区

在 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 代理/桩
常见误区:把 AIDL 接口当成普通 Java 接口随意修改方法顺序;忘记给自定义类型加 @VintfStability;在 oneway 方法中使用 out 参数;迁移后未重新冻结接口就发布。这些都会导致跨进程调用失败或 VINTF 校验不通过。
复盘建议:迁移前先梳理 HIDL 接口的调用方与被调用方,明确哪些方法需要版本协商;迁移后编写“旧客户端 + 新服务端”和“新客户端 + 旧服务端”两组兼容性测试,确保降级路径可用。

总结来说,AIDL 的核心是“契约先行、编译生成、稳定冻结、追加演进”。掌握 .aidl 语法、稳定 AIDL 的 @VintfStability 约束,以及基于 getInterfaceVersion() 的能力协商机制,才能在 HIDL 迁移中既保证功能对齐,又保证跨版本、跨分区的长期兼容。