Skip to content

oneway异步接口

追踪 AIDL oneway 从 AST 校验、Java/CPP flags 到 Binder 异步队列和测试边界。

基于android-17.0.0_r1
AndroidAIDLoneway异步事务

oneway异步接口 ​

AIDL oneway 是接口/方法级协议:编译器要求返回 void 且没有 out/inout 参数,Java/CPP generator 发送 FLAG_ONEWAY 并省略 reply,Binder 驱动按同一 node 的异步队列串行交付。调用返回只说明提交没有立即失败,不代表远端方法已经执行完成。

本文承接 in-out-inout语义、Stub与Proxy代码生成 和 oneway异步事务队列。本文串联编译期与运行期,不重复驱动 buffer 算法。

1. AST与校验 ​

1.1 Oneway状态 ​

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

cpp
AidlMethod::AidlMethod(..., bool oneway, ...)
    : oneway_(oneway),
      oneway_annotation_(oneway) {}

AidlInterface::AidlInterface(..., bool oneway, ...) {
    for (auto& method : GetMethods()) {
        method->ApplyInterfaceOneway(oneway);
    }
}

interface 级 oneway 会应用到所有方法;方法级 oneway 只标记单个 AidlMethod。AST 保留 oneway 信息供 validation 和 generator 消费。

1.2 返回值限制 ​

cpp
if (IsOneway() &&
        GetType().GetName() != "void") {
    AIDL_ERROR(this)
        << "oneway method cannot return a value";
    return false;
}

oneway 没有同步 reply,所以返回类型必须 void。该限制在 semantic validation,不是运行时丢弃返回值。

1.3 参数限制 ​

cpp
if (IsOneway() && arg->IsOut()) {
    AIDL_ERROR(this)
        << "oneway method cannot have out parameters";
    return false;
}

inout 包含 OUT 位,同样被拒绝。允许的参数只能沿请求方向传递。

2. Java生成 ​

2.1 Proxy ​

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

cpp
if (oneway) {
    flags.push_back(
        "android.os.IBinder.FLAG_ONEWAY");
}
out << "mRemote.transact(..., "
    << (oneway ? "null" : "_reply")
    << ", flags);";

oneway 不创建 reply Parcel,不调用 readException,也不读取返回值/out 参数;finally 只 recycle data。

2.2 Stub ​

cpp
if (!oneway) {
    reply.writeNoException();
}
realCall();

Stub 仍在 Binder 线程执行真实方法,只是不写同步 reply。Java 实现抛异常时发送方无法通过 readException 接收,异常只能在服务端日志/observer 中观察。

3. CPP生成 ​

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

cpp
if (method.IsOneway()) {
    flags.push_back(
        "::android::IBinder::FLAG_ONEWAY");
}
remote()->transact(code, data,
        method.IsOneway() ? nullptr : &reply,
        flags);

CPP backend 与 Java backend 使用同一协议 flag,但类型、Parcel API 和 status 表达不同。oneway 语义来自 AIDL AST,不是某个语言独占能力。

4. 运行时语义 ​

4.1 跨进程返回 ​

Java IBinder 文档说明 oneway 跨进程调用立即返回,不等待 callee。驱动仍可能在提交阶段返回 DEAD_OBJECT、FAILED_TRANSACTION、FROZEN 等错误;没有业务 reply 不等于没有 transport error。

4.2 同node顺序 ​

同一 IBinder/node 上多个 oneway 按发送顺序一次分发一个,前一个完成后才推进下一个。不同 Binder 对象、不同 node 或同步/oneway 混合不保证相同全局顺序。

4.3 本地调用 ​

如果调用目标是同进程 Java Binder,Binder.transact() 直接调用 onTransact();FLAG_ONEWAY 不会创建驱动异步队列,方法可能同步执行并返回 false。接口设计不能用本地测试推断跨进程时序。

5. 冻结与失败 ​

冻结目标进程时,同步事务返回错误,oneway 可在驱动中缓存并在解冻后交付;缓存内容可能过时。oneway buffer、spam detection 和 async quota 仍会限制大量异步调用。

服务端 RuntimeException 不会返回给 oneway 客户端;客户端只能通过独立 callback、状态查询或日志建立完成/失败闭环。

6. 测试边界 ​

源码文件:frameworks/native/libs/binder/tests/binderLibTest.cpp

NopTransactionOneway 发送 TF_ONE_WAY 并断言 NO_ERROR。测试服务对 oneway 返回 UNKNOWN_ERROR,但客户端仍只观察提交结果,证明服务端业务 status 不通过 reply 返回。

同步 NopTransaction 用相同 code 但等待 reply,形成对照。测试不证明所有异步调用都低延迟,也不覆盖不同 node 的全局排序。

bash
rg -n "IsOneway|cannot return|cannot have out"   system/tools/aidl/aidl_language.cpp
rg -n "FLAG_ONEWAY|oneway|_reply"   system/tools/aidl/generate_java_binder.cpp   system/tools/aidl/generate_cpp.cpp
rg -n "NopTransactionOneway|TF_ONE_WAY"   frameworks/native/libs/binder/tests/binderLibTest.cpp

排查 oneway 事件丢失时,先区分编译器是否真的生成 FLAG_ONEWAY,再查 transport 提交、冻结/配额、node async 队列和服务端日志;如果业务需要完成结果,应设计独立 callback 或状态协议。