浅析Binder通信的三种调用方式

首先,我们达成一个共识:Binder调用本质上是客户端(Client)向服务端(Server)发送一个事务(Transaction),并可能等待回复(Reply)的过程。 驱动(Binder Driver)是这个过程的核心中转站和协调者。


1. 同步调用 (Synchronous Call)

这是最常用、最基础的调用方式。客户端线程会发起调用,然后被阻塞,直到服务端处理完毕并返回结果后,该线程才会被唤醒并继续执行。

核心特征: 调用方(客户端)线程阻塞,等待被调用方(服务端)返回结果。

时序图:

过程解析:

  1. 客户端调用 transact() 方法,传入必要的参数(如:事务码、数据Parcel、标志位0-表示同步)。
  2. transact() 方法内部会通过系统调用(ioctl)向Binder驱动发送 BC_TRANSACTION 命令。
  3. Binder驱动将请求放入服务端线程的待处理事务队列中,并唤醒一个空闲的服务端线程(或线程池中的线程)。
  4. 被唤醒的服务端线程从驱动中读取到 BR_TRANSACTION 命令,并解析出数据。
  5. 服务端线程调用服务端Stub的 onTransact() 方法。onTransact() 根据事务码解码参数并调用对应的目标方法(如:getUserInfo())。
  6. 服务端方法执行完毕,将结果返回给 onTransact()
  7. onTransact() 方法通过系统调用向Binder驱动发送 BC_REPLY 命令,携带结果Parcel。
  8. Binder驱动将回复结果与之前阻塞的客户端线程关联起来,向其发送 BR_REPLY 命令,并唤醒该线程。
  9. 客户端线程被唤醒,从 transact() 调用中返回,并获取到回复数据Parcel。
  10. 客户端线程继续执行后续代码。

2. 异步调用 (Asynchronous Call / Oneway)

也称为"单向调用"。客户端发起调用后立即返回,不会阻塞 等待服务端处理。它不关心调用是否成功,也不获取任何返回结果。在 transact() 中需要指定 FLAG_ONEWAY 标志。

核心特征: 调用方(客户端)线程立即返回,不等待不阻塞。被调用方(服务端)异步处理。

时序图:

过程解析:

  1. 客户端调用 transact() 方法,并指定标志位为 FLAG_ONEWAY
  2. 后续步骤与同步调用类似,客户端向驱动发送 BC_TRANSACTION
  3. 关键区别: Binder驱动看到 FLAG_ONEWAY 标志后,会立即让客户端的 ioctl 系统调用返回,而不会 阻塞客户端线程。客户端 transact() 方法立即返回。
  4. 驱动仍然会将事务发送给服务端,服务端线程也会像同步调用一样被唤醒、处理 onTransact()
  5. 因为客户端不需要回复,所以服务端处理完后也不会 发送 BC_REPLY

注意: 异步调用只保证请求被发出,不保证请求被及时处理。如果服务端的事务队列积压,请求可能会延迟处理。


3. 回调式异步调用 (Callback-based Asynchronous Call)

这是一种更高级的模式,它结合了上述两种方式。常用于"请求-响应"模型,其中响应需要很长时间(如:网络请求、大文件计算)。

核心思想:

  1. 客户端发起一个同步调用,但服务端收到后立即返回一个空的或临时的回复,解除客户端的阻塞。
  2. 同时,服务端持有客户端传入的一个回调接口(ICallback) 的Binder代理对象。
  3. 服务端在另一个线程中处理耗时任务。
  4. 当服务端处理完成后,再通过持有的回调接口反向调用客户端的方法来传递最终结果。

这实际上是两个Binder调用:

  • 调用1:Client → Server (同步,但立刻返回)
  • 调用2:Server → Client (通过Callback,可以是同步或异步)

时序图:

过程解析:

  1. 初始调用: 客户端同步调用服务端,但在参数中传递一个实现了 ICallback 接口的Binder对象。
  2. 立即回复: 服务端的 onTransact() 方法收到请求后,立即(在处理耗时任务之前)返回一个空的回复,而不是等待任务完成。这使得客户端线程被迅速唤醒。
  3. 异步执行: 服务端将耗时任务提交到自己的后台线程(WorkerThread)中执行。
  4. 回调通知: 当后台任务执行完毕后,服务端通过第一步中客户端传过来的 ICallback 接口的代理对象,发起一个从服务端到客户端的Binder调用。
  5. 处理结果: 客户端的 ICallback 实现类中的方法被调用,在这里处理最终的结果。

技术关键点:

  • 回调接口 ICallback 本身必须是一个AIDL接口,这样它才能被跨进程传递。服务端拿到的是它的 Proxy 对象。
  • 这种方式完美解决了在UI主线程中同步调用耗时服务会导致应用无响应(ANR)的问题。

总结与对比

特性 同步调用 异步调用 (Oneway) 回调式异步调用
客户端阻塞 (初始调用迅速返回)
获取结果 直接通过返回值 无法获取 通过回调接口间接获取
服务端保证 强保证,客户端知道是否成功 弱保证,请求可能延迟处理 强保证,最终结果或错误可通过回调返回
实现复杂度 高(需定义回调接口,处理双向通信)
典型场景 获取即时信息,如:getVersion() 触发一个动作,不关心结果,如:notifySomething() 发起耗时任务,如:downloadFile(ICallback)
Binder标志 0 FLAG_ONEWAY 初始调用:0,回调调用:0FLAG_ONEWAY

希望这份详细的解析和时序图能帮助您和您的团队更深刻地理解Binder通信机制。在实际架构设计中,可以根据业务场景灵活选择和组合这三种模式。

相关推荐
kobe_OKOK_32 分钟前
Django `models.Field` 所有常见配置参数的完整清单与说明表
android
前行的小黑炭2 小时前
Android Compose :初步了解一下生命周期,对比原生android
android·kotlin·app
湖南人爱科技有限公司3 小时前
RaPhp和Python某音最新bd-ticket-guard-client-data加密算法解析(视频评论)
android·python·php·音视频·爬山算法·raphp
守城小轩7 小时前
Chromium 138 编译指南 - Android 篇:从Linux版切换到Android版(六)
android·chrome·指纹浏览器·浏览器开发·超级浏览器
守城小轩7 小时前
Chromium 138 编译指南 - Android 篇:环境搭建与准备(一)
android·chrome·指纹浏览器·浏览器开发
消失的旧时光-19437 小时前
Kotlin when 用法完整分享
android·开发语言·kotlin
顾林海9 小时前
Android编译插桩黑科技:ReDex带你给App"瘦个身,提个速"
android·面试·性能优化
maki07710 小时前
VR大空间资料 04 —— VRAF使用体验和源码分析
android·vr·虚幻·源码分析
消失的旧时光-194312 小时前
Kotlin 判空写法对比与最佳实践
android·java·kotlin