Skip to content

Stub与Proxy代码生成

追踪 AIDL Java backend 从 AST 到 Stub、Proxy、transaction code 和 Parcel 代码的真实生成路径。

基于android-17.0.0_r1
AndroidAIDLStubProxy编译器

Stub与Proxy代码生成 ​

AIDL Java backend 先加载并校验文档,再计算输出路径,最后由 Java generator 和 CodeWriter 生成文件;Stub/Proxy 只是 backend 输出,不是 parser 阶段直接拼接的模板。

本文承接 AIDL编译器原理、Stub与Proxy代码分析 和 AIDL语法详解。本文聚焦 generator owner、输出路径、Java AST 和生成约束,不展开每个 Parcel 类型的全部模板。

1. 生成入口 ​

1.1 Java分支 ​

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

cpp
if (lang == Options::Language::JAVA) {
    if (defined_type->AsUnstructuredParcelable() != nullptr) {
        success = true;
        if (!options.OutputDir().empty()) {
            io_delegate.GetCodeWriter(output_file_name)->Close();
        }
    } else {
        java::GenerateJava(output_file_name, options,
                           typenames, *defined_type,
                           io_delegate);
        success = true;
    }
}

Java backend 对 structured interface/parcelable 生成代码;legacy unstructured parcelable 可能只产生空输出文件,不应把成功等同于有 Java class 内容。

1.2 输出路径 ​

GetOutputFilePath 根据 package、定义类型和 output dir 计算目标文件;dependency file 记录输入和 import。输出路径、依赖文件和 writer 失败属于生成阶段错误,不是 grammar 错误。

2. Java生成器 ​

2.1 GenerateJava ​

源码文件:system/tools/aidl/generate_java.cpp

cpp
namespace android::aidl::java {
bool GenerateJava(const std::string& output_file,
                  const Options& options,
                  AidlTypenames* typenames,
                  const AidlDefinedType& defined_type,
                  const IoDelegate& io_delegate) {
    CodeWriterPtr writer =
            io_delegate.GetCodeWriter(output_file);
    if (!writer) return false;
    CodeGeneratorContext context(
            options, typenames, defined_type, writer);
    return context.Generate();
}
}

generator 接收已解析的 AidlDefinedType,不重新读取 grammar。CodeGeneratorContext 负责 Java 类型映射、接口/parcelable 分支、注解和输出写入。

2.2 Java AST ​

源码文件:system/tools/aidl/ast_java.cpp

Java AST 把 AIDL 节点转换成 Java package、type、method、field 和 annotation 表达。它是生成器中间结构,既不是原始 grammar AST,也不是最终文本。

3. Stub输出 ​

3.1 类型职责 ​

生成 Stub 通常继承 Binder 并实现接口,提供 DESCRIPTOR、asInterface、asBinder 和 onTransact。编译器根据 interface members 产生 transaction constants 和方法分支。

3.2 解包顺序 ​

真实 IServiceCallback:

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

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

Stub 生成的 onTransact 必须按声明顺序检查 token,再读取 String 和 IBinder,最后调用 onRegistration。参数顺序是 schema 的直接消费者。

3.3 标准分支 ​

Stub 对 INTERFACE_TRANSACTION 返回 descriptor;业务 code 执行解包和方法调用;oneway 不写 reply。unknown code 由生成基类或父类处理,具体结果取决于 generator 版本和接口基类。

4. Proxy输出 ​

4.1 发送顺序 ​

生成 Proxy 保存远程 IBinder。以 IServiceCallback 为例,业务方法需要 obtain Parcel、写 token、写 name、写 Binder、调用 transact 并 finally recycle data。oneway 的 reply 为 null,flags 包含 FLAG_ONEWAY。

4.2 异常策略 ​

同步方法通常 readException;oneway 没有同步异常 Parcel。生成器根据 method oneway 属性选择 flags 和 reply 代码。

5. CodeWriter ​

源码文件:system/tools/aidl/code_writer.cpp

CodeWriter 负责打开目标、写文本、写依赖文件并报告 IO 错误。它不决定 transaction code,也不检查 Parcelable 类型是否可跨 backend;这些职责在 semantic validation 和 generator context。

生成输出是编译输入,不是运行时证明:Java 编译、ServiceManager 注册、权限和线程池仍需后续阶段。

6. 测试边界 ​

6.1 Golden输出 ​

源码文件:system/tools/aidl/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/ITestService.java

golden output 将生成 Java 文件与预期文本比较,覆盖 Stub/Proxy、Parcelable、enum、数组和异常路径的稳定输出。它证明 generator 输出变化可被发现,不代表所有 backend 共用相同代码。

6.2 Generator测试 ​

源码文件:system/tools/aidl/ast_java_unittest.cpp

测试 Java AST 类型、命名和注解映射;code_writer_unittest.cpp 覆盖 writer 输出/错误。它们分别验证中间结构和文件写入,不替代端到端 aidl 命令。

bash
rg -n "GenerateJava|CodeGeneratorContext|Java"   system/tools/aidl/generate_java.cpp   system/tools/aidl/aidl.cpp   system/tools/aidl/ast_java.cpp
rg -n "CodeWriter|GetCodeWriter|dependency"   system/tools/aidl/code_writer.cpp
rg -n "ITestService|golden_output|Java"   system/tools/aidl/tests system/tools/aidl/*unittest.cpp

排查生成 Stub/Proxy 异常时,先确认输入 AST/semantic validation,再看 Java AST 映射、输出路径和 CodeWriter,最后检查 transaction code、Parcel 顺序和 oneway flags。