外观
Agent 与系统服务怎样通过 Binder / AIDL 通信?
标准回答
Binder 是 Android 常用的进程间通信机制,AIDL 用来定义跨进程接口并生成代理和 Stub。我会把耗时操作设计成“提交任务、返回受理结果、异步通知进度”,避免让一次同步调用一直等到设备动作完成。
普通远程 AIDL 调用通常同步等待服务端返回,服务端会在 Binder 线程池处理请求,所以既不能在 UI 主线程做可能很慢的远程调用,也不能长期占用 Binder 线程做网络或推理。服务端应先校验调用者和参数,再把已授权任务交给合适的执行器。调用身份必须在 Binder 入口捕获和校验,不能切到工作线程后再假设还能读到原始调用者。
回调同样要考虑线程。远程回调到达客户端时不能直接操作 View,应切回主线程,并核对 taskId、当前页面生命周期和任务版本,防止旧结果覆盖新页面。共享任务状态可以通过串行执行器管理,或者使用明确的同步机制保护。
服务进程可能死亡。我会处理 RemoteException,结合绑定状态或死亡通知使旧代理失效,有限退避重连,并在重连后查询任务状态。有副作用的任务不会因为 Binder 断开就直接重发:断开只证明通信失败,不能证明动作没有执行。
关键机制
- 同步调用会等待;oneway 改变远程调用的等待方式,不证明工作已经完成。
- Binder 线程负责快速鉴权与转交;业务执行、主线程 UI 更新各自有清晰边界。
- 协议包含请求标识、状态查询、取消与结果;重连后先核对状态。
通俗例子
UI 提交“连接设备”后立即显示执行中。服务返回已受理并在工作线程连接;结果通过回调传回,UI 仅接收属于当前任务的事件。若中途服务重启,则进入重连与状态核对流程。
追问与回答
把接口全改成 oneway 就能解决卡顿吗?
不能。oneway 可以让远程调用不等待业务返回,但服务端仍可能排队、抢锁或耗时,也没有自动获得可靠完成通知。我会先区分短查询和长任务,长任务使用提交、回调和状态查询协议,再处理限流与工作线程。对同进程本地调用,oneway 也不会让方法自动变异步。
为什么持锁调用远程服务容易出问题?
远程调用时长不可控,而且对方可能再回调当前进程。如果当前线程拿着锁等待对方,而回调又要拿这把锁,就可能形成死锁。我会在锁内只做必要的状态读取或快照,在锁外执行 IPC,返回后再次核对状态版本;必须跨步骤保持一致时,用明确状态机代替长时间持锁。
易混淆点
本地 AIDL 调用仍在调用线程同步执行,oneway 对本地调用不产生同样的异步效果。Service 组件本身也不等于一条后台线程。
参考资料
内容来源
- Android 技术札记 · 原条目
system-ipc