Skip to content

AIDL语法详解

根据 Android 17 AIDL parser grammar,解释 package/import、interface、parcelable、enum、oneway、参数方向和常量。

基于android-17.0.0_r1
AndroidAIDL语法Java框架源码阅读

AIDL语法详解 ​

AIDL 语法不是“Java 接口加几种类型”。Android 17 的 parser grammar 将文档拆成 package、import、interface/parcelable/enum/union 声明,再把方法参数方向、oneway、常量和注解交给 AST/类型检查。语法选择会继续影响 Stub/Proxy、Parcel 读写和不同 backend 的生成约束。

本文面向已经读过 Stub与Proxy代码分析、Java-Parcel序列化 和 BnInterface与BpInterface模板 的读者。本文以 Android 17 parser grammar 和真实 AIDL 样本为事实来源,不展开编译器代码生成模板。

1. 文档结构 ​

1.1 package与import ​

源码文件:system/tools/aidl/aidl_language_y.yy

java
document
 : optional_package imports decls
 ;

optional_package
 : PACKAGE qualified_name ';'
 ;

import
 : IMPORT qualified_name ';'
 ;

一个文档最多一个 package 前置,再接 import 和声明列表。qualified name 由 identifier 与点组成;import 路径参与类型解析,不是 Java import 的运行时行为。

1.2 声明种类 ​

java
unannotated_decl
 : parcelable_decl
 | interface_decl
 | enum_decl
 | union_decl
 ;

Android 17 parser 明确区分 interface、parcelable、enum 和 union。声明进入 AST 后,类型检查和 backend 再决定哪些目标语言/稳定性组合可生成。

2. Interface语法 ​

2.1 普通与oneway ​

源码文件:system/tools/aidl/aidl_language_y.yy

java
interface_decl
 : INTERFACE qualified_name '{' interface_members '}'
 | ONEWAY INTERFACE qualified_name '{' interface_members '}'
 ;

oneway 是 interface 级语法,生成的方法默认采用异步事务约束;它不是 Java 方法返回类型,也不能只在调用方 flags 中临时添加来改变接口契约。

2.2 真实样本 ​

源码文件:frameworks/native/libs/binder/aidl/android/os/IServiceCallback.aidl

java
package android.os;

oneway interface IServiceCallback {
    void onRegistration(@utf8InCpp String name, IBinder binder);
}

样本只有一个 oneway 方法,参数包含 annotated String 与 IBinder。生成 Stub 会接收并解包,Proxy 会以 FLAG_ONEWAY 发出。

2.3 方法成员 ​

parser 将 interface members 解析为 method、constant 或嵌套声明。方法的返回类型、名字、参数列表和注解进入 AidlMethod AST;重复 name、非法类型和 backend 限制在后续检查阶段报告,不由 lexer 单独决定。

3. 参数语法 ​

3.1 方向 ​

源码文件:system/tools/aidl/aidl_language_y.yy

java
%token IN "in"
%token INOUT "inout"
%token OUT "out"

参数方向是语法 token,不是普通类型修饰。in 表示发送方输入,out/inout 需要生成代码在 reply 或回写路径处理,实际可用方向还受 backend 与稳定 AIDL 约束。

3.2 类型与数组 ​

AIDL type grammar 支持基本类型、命名类型、数组和泛型 type arguments;parser 先构造 AidlTypeSpecifier,类型名解析/可用性检查在 AidlTypenames 和 semantic validation 中完成。不能从 parser 接受 identifier 推断所有语言都能生成该类型。

3.3 注解参数 ​

真实样本的 @utf8InCpp String 是参数注解,影响 C++ backend 的字符串表示;Java backend 仍以 Java String 作为接口参数。注解是 AST metadata,不应当被误读成运行时 Parcel 字段。

4. 数据声明 ​

4.1 Parcelable ​

java
parcelable_decl
 : PARCELABLE qualified_name optional_type_params
   optional_unstructured_headers ';'
 | PARCELABLE qualified_name optional_type_params
   '{' parcelable_members '}'
 ;

unstructured parcelable 只声明类型名,structured parcelable 在大括号内声明字段/常量/嵌套声明。两者的生成与稳定性能力不同,不能只看关键字 parcelable。

4.2 Enum ​

java
enum_decl
 : ENUM qualified_name enum_decl_body
 ;

enum_decl_body
 : '{' enumerators '}'
 | '{' enumerators ',' '}'
 ;

枚举项可显式赋值或使用默认值。常量表达式支持整数/浮点/布尔等 grammar,语义检查负责类型和重复值约束。

4.3 Union ​

union 与 structured parcelable 共用部分成员声明路径,但生成的数据布局和读取策略不同。它不是 Java sealed class 的直接语法别名,必须查看目标 backend 支持。

5. 常量与注解 ​

5.1 常量表达式 ​

parser grammar 定义逻辑、位运算、比较、移位、算术和一元运算优先级;常量先构造表达式 AST,再由 semantic phase Evaluate/CheckValid。源码中出现合法 token 不等于常量一定符合目标类型范围。

5.2 目标语言注解 ​

AIDL parser token 包含 annotation、cpp_header、ndk_header、rust_type 等扩展入口。它们为 backend 提供额外 metadata;Java、NDK、Rust 的可接受注解集合不同,不能把某个 backend 的注解写成通用 AIDL 语义。

6. 错误边界 ​

parser 对未知字符、缺失分号、括号不闭合和声明结构错误报告语法错误;类型不存在、重复声明、方向不支持和 backend 能力不足属于后续语义/代码生成错误。排查时先区分 parser error、AST validation error 和 backend error。

7. 测试与验证 ​

源码文件:system/tools/aidl/tests/aidl_parser_fuzzer.cpp

fuzzer 将任意输入送入 parser,目标是发现崩溃和解析状态错误,不证明任意语法都应该被接受。

bash
rg -n "optional_package|imports|interface_decl|parcelable_decl|enum_decl|union_decl"   system/tools/aidl/aidl_language_y.yy
rg -n "direction|INOUT|OUT|method_decl|parameter"   system/tools/aidl/aidl_language_y.yy
rg -n "oneway interface|@utf8InCpp|interface IServiceCallback"   frameworks/native/libs/binder/aidl/android/os/IServiceCallback.aidl

阅读一个 AIDL 文件时,先标出 package/import,再识别声明种类,然后判断 interface 是否 oneway、每个参数方向和注解,最后再追 semantic validation/backend 约束;不要把 parser 接受等同于生成和运行都成功。