Binder跨进程通讯实例

 

图解:

  1. 发起端线程向Binder Driver发起binder ioctl请求后, 便采用环不断talkWithDriver,此时该线程处于阻塞状态, 直到收到如下BR_XXX命令才会结束该过程.
    • BR_TRANSACTION_COMPLETE: oneway模式下,收到该命令则退出
    • BR_REPLY: 非oneway模式下,收到该命令才退出;
    • BR_DEAD_REPLY: 目标进程/线程/binder实体为空, 以及释放正在等待reply的binder thread或者binder buffer;
    • BR_FAILED_REPLY: 情况较多,比如非法handle, 错误事务栈, security, 内存不足, buffer不足, 数据拷贝失败, 节点创建失败, 各种不匹配等问题
    • BR_ACQUIRE_RESULT: 目前未使用的协议;
  2. 左图中waitForResponse收到BR_TRANSACTION_COMPLETE,则直接退出循环, 则没有机会执行executeCommand()方法, 故将其颜色画为灰色. 除以上5种BR_XXX命令, 当收到其他BR命令,则都会执行executeCommand过程.
  3. 目标Binder线程创建后, 便进入joinThreadPool()方法, 采用循环不断地循环执行getAndExecuteCommand()方法, 当bwr的读写buffer都没有数据时,则阻塞在binder_thread_read的wait_event过程. 另外,正常情况下binder线程一旦创建则不会退出.

 

  • Binder客户端或者服务端向Binder Driver发送的命令都是以BC_开头,例如本文的BC_TRANSACTIONBC_REPLY, 所有Binder Driver向Binder客户端或者服务端发送的命令则都是以BR_开头, 例如本文中的BR_TRANSACTIONBR_REPLY.
  • 只有当BC_TRANSACTION或者BC_REPLY时, 才调用binder_transaction()来处理事务. 并且都会回应调用者一个BINDER_WORK_TRANSACTION_COMPLETE事务, 经过binder_thread_read()会转变成BR_TRANSACTION_COMPLETE.
  • startService过程便是一个非oneway的过程, 那么oneway的通信过程如下所述.

 

当收到BR_TRANSACTION_COMPLETE则程序返回,有人可能觉得好奇,为何oneway怎么还要等待回应消息? 我举个例子,你就明白了.

你(app进程)要给远方的家人(system_server进程)邮寄一封信(transaction), 你需要通过邮寄员(Binder Driver)来完成.整个过程如下:

  1. 你把信交给邮寄员(BC_TRANSACTION);
  2. 邮寄员收到信后, 填一张单子给你作为一份回执(BR_TRANSACTION_COMPLETE). 这样你才放心知道邮递员已确定接收信, 否则就这样走了,信到底有没有交到邮递员手里都不知道,这样的通信实在太让人不省心, 长时间收不到远方家人的回信, 无法得知是在路的中途信件丢失呢,还是压根就没有交到邮递员的手里. 所以说oneway也得知道信是投递状态是否成功.
  3. 邮递员利用交通工具(Binder Driver),将信交给了你的家人(BR_TRANSACTION);

当你收到回执(BR_TRANSACTION_COMPLETE)时心里也不期待家人回信, 那么这便是一次oneway的通信过程.

如果你希望家人回信, 那便是非oneway的过程,在上述步骤2后并不是直接返回,而是继续等待着收到家人的回信, 经历前3个步骤之后继续执行:

  1. 家人收到信后, 立马写了个回信交给邮递员BC_REPLY;
  2. 同样,邮递员要写一个回执(BR_TRANSACTION_COMPLETE)给你家人;
  3. 邮递员再次利用交通工具(Binder Driver), 将回信成功交到你的手上(BR_REPLY)

这便是一次完成的非oneway通信过程.

oneway与非oneway: 都是需要等待Binder Driver的回应消息BR_TRANSACTION_COMPLETE. 主要区别在于oneway的通信收到BR_TRANSACTION_COMPLETE则返回,而不会再等待BR_REPLY消息的到来. 另外,oneway的binder IPC则接收端无法获取对方的pid.

  • BC_TRANSACTION + BC_REPLY = BR_TRANSACTION_COMPLETE + BR_DEAD_REPLY + BR_FAILED_REPLY
  • Binder线程只有当本线程的thread->todo队列为空,并且thread->transaction_stack也为空,才会去处理当前进程的事务, 否则会继续处理或等待当前线程的todo队列事务。换句话说,就是只有当前线程的事务;
  • binder_thread_write: 添加成员到todo队列;
  • binder_thread_read: 消耗todo队列;
  • 对于处于空闲可用的,或者Ready的binder线程是指停在binder_thread_read()的wait_event地方的Binder线程;
  • 每一次BR_TRANSACTION或者BR_REPLY结束之后都会调用freeBuffer().
  • ProcessState.mHandleToObject记录着handle与对应的BpBinder信息。

整个过程copy once便是指binder_transaction()过程把binder_transaction_data->data拷贝到目标进程的buffer。

 

  • [2.1]AMP.startService:组装flat_binder_object对象等组成的Parcel data;
  • [2.9]IPC.writeTransactionData:组装BC_TRANSACTION和binder_transaction_data结构体,写入mOut;
  • [2.11]IPC.talkWithDriver: 组装BINDER_WRITE_READ和binder_write_read结构体,通过ioctl传输到驱动层。

进入驱动后

  • [3.3]binder_thread_write: 处理binder_write_read.write_buffer数据
  • [3.4]binder_transaction: 处理write_buffer.binder_transaction_data数据;
    • 创建binder_transaction结构体,记录事务通信的线程来源以及事务链条等相关信息;
    • 分配binder_buffer结构体,拷贝当前线程binder_transaction_data的data数据到binder_buffer->data;
  • [3.5]binder_thread_read: 处理binder_transaction结构体数据
    • 组装cmd=BR_TRANSACTION和binder_transaction_data结构体,写入binder_write_read.read_buffer数据

回到用户空间

  • [4.3]IPC.executeCommand:处理BR_TRANSACTION命令, 将binder_transaction_data数据解析成BBinder.transact()所需的参数
  • [4.7] AMN.onTransact: 层层回调,进入该方法,反序列化数据后,调用startService()方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值