Binder是怎么跨进程传输的?——源码分析(三)

Binder是怎么跨进程传输的?

  • Parcel的writeStrongBinder和readStrongBinder
  • Binder在Parcel中存储原理,flat_binder_object
  • 说清楚binder_node, binder_ref
  • 目标进程根据binder_ref的handle创建BpBinder
  • 由BpBinder再往上到BinderProxy到业务层的Proxy

这篇文章还是看源码:

1、定义AIDL的接口(目的发布binder)

Binder是怎么跨进程传输的?——源码分析(三)_第1张图片

2、根据对应的AIDL接口生成的类,把数据写到Parcel中,调用transact一层一层发给驱动,通过WriteStrongBinder,把binder对象写到Parcel中,然后调用

Binder是怎么跨进程传输的?——源码分析(三)_第2张图片

3、服务端onTransact回调

Binder是怎么跨进程传输的?——源码分析(三)_第3张图片


接下来分析一下上面 第二条:客户端是怎么传递Binder对象过去的

1、把java传过来的Parcel写到native的Parcel中

Binder是怎么跨进程传输的?——源码分析(三)_第4张图片

2、通过Java层的binder找到natice层的binder

PS: Binder可能是实体:我的理解,在同一个进程的时候传进来的是当前的stub对象
如果代理对象,就是在不同的进程,传过来的是客户端的代理对象
Binder是怎么跨进程传输的?——源码分析(三)_第5张图片

3、native层writeStrongBinder 如何写到native层的Parcel的,如下:

Binder是怎么跨进程传输的?——源码分析(三)_第6张图片

flat_binder_object在Parcel中的储存方式,我们把flat_binder_object存在mObjects中,另一个进程就是根据偏移量取出来

Binder是怎么跨进程传输的?——源码分析(三)_第7张图片
上面总结:
根据java层的Parcel,找出对应的native层的binder,然后把binder封装成flat_binder_object对象,存在mObjects中,最终写在了native的Parcel中整体流程。


到了Binder驱动层怎么处理的?

binder_node = 服务进程引用
binder_ref = 对应客户端的引用,但指向的都是binder_node
binder驱动会为每个客户端的引用维护一个handle,存在binder_ref中。
总结就是把binder的代理对象handle写在flat_binder_object中
Binder是怎么跨进程传输的?——源码分析(三)_第8张图片


服务端怎么读出来的?

1、在java层parcel中读取数据,到native层读取

Binder是怎么跨进程传输的?——源码分析(三)_第9张图片

跨进程传递binder,传的是binder实体对象,但是到了binder层会转成binder的代理对象

Binder是怎么跨进程传输的?——源码分析(三)_第10张图片

根据handle值返回对应的BpBinder对象

Binder是怎么跨进程传输的?——源码分析(三)_第11张图片

根据native层的binder对象返回对应java层的binder对象

Binder是怎么跨进程传输的?——源码分析(三)_第12张图片

总结:

Binder对象跨进程的传输:

整体的流程:
1、在客户端中,通过parcel方法writeStrongBinder,把binder写进java层的Parcel中
2、然后调动用trasact把parcel一层一层传给binder驱动,然后在返回服务端
3、服务端在onTransact中接收数据,通过parcel的方法readStrongBinder读出来binder

PS:ServerManager中的addServer方法会传递binder实体注册在SM中。后面文章我会在出一个它的源码

客户端流程:
分析writeStrongBinder流程:
1、调用native的方法有两个参数:
参数1:native层对应的parcel指针,也就是通过它找到对应的native层的Parcel数据,
参数2:Binder对象,这个binder对象可能是Binder实体,也可能是代理对象

解释一下为什么是binder实体,后者是代理对象
Binder实体:同一个进程asInterface获取的是本地的binder Stub
代理对象: 也可能是代理对象,说明是两个进程asInterface获取的是客户端代理对象

2、调用native层nativewriteStrongBinder
a、根据传过来的指针找到native层对应的parcel对象
b、通过java层的binder对象找到native层的binder对象
c、然后调用writeStrongBinder把native的binder写到parcel中

  • 1、创建一个flat_binder_object 然后把binder赋值到里面
  • 2、然后把flat_binder_object写在Parcel中
  • 3、Parcel中有一个mObjects数组,用来保存flat_binder_object在缓冲区的偏移

以上是在Binder驱动之前操作,然后我们看下到了Binder驱动怎么处理的呢?

3、到达驱动之后先取出对应的flat_binder_object,然后取出来对应的Binder对象,

  • a、判断驱动里面有没有binder实体对象的binder_node,没有就创建一个
  • b、查找目标进程有没有binder引用对象,没有就创建一个 --binder_ref
  • c、然后把客户端对应的handle值赋值给flat_binder_object。所以handle就是binder代理对象

总结:binder驱动会把binder实体转成代理对象handle

binder_node = 服务进程引用
binder_ref = 对应客户端的引用,但指向的都是binder_node
binder驱动会为每个客户端的引用维护一个handle,存在binder_ref中。

服务端接收流程:
1、在readStrongBinder中,调用nativeReadStrongBinder。
2、根据java层传下来的引用找到native层对应的Parcel,然后在里面读取binder。readStrongBinder
3、在Parcel中读出flat_binder_object,然后取出type

  • type == BINDER_TYPE_BINDER : 同一个进程,cookie是binder实体对象
  • ype == BINDER_TYPE_HANDLE : 不同进程,传过来的是handle值,代理对象,根据handle值返回一个Bpbinder(handle是一个索引,在数组中查看,没有查到就new一个BpBinder)

4、跟好友native binder对象返回对应java层的binder对象
如果native的binder对象是实体就返回java层的javaBBinder
如果是代理对象就new一个dialing对象,而且binderProxy对象会保存一个native层的binder对象指针

你可能感兴趣的:(framework)