浅析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通信机制。在实际架构设计中,可以根据业务场景灵活选择和组合这三种模式。

相关推荐
用户092 小时前
深入了解 Android 16KB内存页面
android·kotlin
火车叼位3 小时前
Android Studio与命令行Gradle表现不一致问题分析
android
前行的小黑炭5 小时前
【Android】 Context使用不当,存在内存泄漏,语言不生效等等
android·kotlin·app
前行的小黑炭6 小时前
【Android】CoordinatorLayout详解;实现一个交互动画的效果(上滑隐藏,下滑出现);附例子
android·kotlin·app
用户20187928316718 小时前
Android黑夜白天模式切换原理分析
android
芦半山18 小时前
「幽灵调用」背后的真相:一个隐藏多年的Android原生Bug
android
卡尔特斯19 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
ace望世界19 小时前
安卓的ViewModel
android
ace望世界19 小时前
kotlin的委托
android