socket通信原理_Framework 深入探索之Binder进程通信

4142546e85c56801748c652893e06677.png

进程通信无论在Android应用层中使用,还是在AndroidFramework中都是常见的方式。

Binder中在四大组件启动中都使用到了,socket:这里socket是本地通信,在向AMS发送startActivity请求,应用组件没有启动,AMS通过socket向Zygote发送创建应用进程请求。 我们首先说一下什么是Binder相关的知识点

Binder

下面分为四部分来讨论一下Binder,具体的Binder用法在之前的文章中以及做了具体的操作,文章可以看看这个https://www.ztzyif.top/index.php/2019/07/17/binder-%e8%bf%9b%e7%a8%8b%e9%80%9a%e4%bf%a1/

binder做什么

  1. 用来通信,分为客户端与服务端,可以在同一个进程,也可以不再同一个进程,客户端可以发起远程函数调用或者传数据,远程调用进程边界模糊,无需关注在哪个进程
  2. 远程调用,首先将参数序列化存入到buffer ,在通过Linux跨进程通信传入到服务端,在反序列化参数,调用函数,返回结果给客户端;跨进程要快,性能好,方便,Linux只提供底层,真正调用复杂,需要搭建一个框架,安全性

binder存在意义

  1. binder跑在驱动层,自己发明的一套机制,没有用到Linux跨进程通信
  2. 只有系统服务binder才可以注册到ServiceManager中,应用服务binder无法注册进ServiceManager中

binder架构原理怎么样

ClientProxy中进行分发请求给java层的BinderProxy,它再把请求分发给Native层的BpBinder,通过IPC的transact分发将请求发送到binder驱动中,转发到server,在server binder线程的onTransact中继续分发请求,到native层的BBinder,分发到Java的Binder中,最后分发到应用层的Stub

进程启动binder机制

  1. 打开binder驱动
  2. 内存映射,分配缓冲区
  3. 启动binder线程

Binder 对象传递原理

binder传递方式

先通过PracelwriteStrongBinder,写入到Pracel中,目标进程再通过Pracel的readStrongBinder读出来

binder传递过程中怎么存储的

通过flat_binder_object进程存储,在缓冲区中存储,Pracel中有数组保存flat_binder_object偏移,到目标进程通过偏移进行还原flat_binder_objectPracel中取出来flat_binder_object,根据binder对象进行创建数据结构,比如为实体对象创建binder_node,binder_ref,以binder引用进行传递

IPC 过程通信协议

我们在来说一下IPC整个通信的过程 Client向Server发起IPC调用:首先Client向Binder驱动发送一个BC_TRANSACTION指令,然后Binder驱动回复一个BC_TRANSACTION_COMPLET指令,Binder驱动再向Server端发送一个BR_TRANSACTION指令,Server端处理完请求回复一个BC_REPLAY指令,Binder驱动收到指令会发送一个BR_TRANSACTION_COMPLETE指令,最后Binder驱动将返回结果通过发送一个BR_REPLAY指令给Client端,Client发送请求在等待Binder驱动进行返回值得时候处于休眠状态,Server端是binder线程,在没处理请求都是处于休眠状态,等待binder端发送来的请求

Linux 常用的跨进程通信方式

谈到IPC进程通信,说一下Android framework中进程通信,比如Linux的常用跨进程通信

管道

  • 半双工,单向,要么读,要么写,如果要既能读又可以写,就需要两个描述符。提供pipe(fds)api
  • 一般是在父子进程之间使用是无名管道,有名管道,需要两个进程都知道管道名字,才可以使用
  • Android 4.0版本的 java层中 Looper用到了管道,创建管道,对应写与读描述符

本地Socket通信

  • 全双工,既可以读也可以写
  • 两个进程之间无需存在亲缘关系,只要公开创建的路径,就可以通信
  • 在AMS中,通过socket通信通知Zygote进程,进入Loop循坏,当有新的请求,去处理,参数列表通过AMS进行跨进程发送,在子进程进行执行ActivityThread.main()函数

共享内存

  • 很快,无需多次拷贝
  • 进程之间无需存在亲缘关系,只需要拿到文件描述符,它可以跨进程传递,在Android中图像显示中用到了共享内存

信号

  • 单向,发出去后怎么处理是别人的事
  • 只能带个信号,不能带别的参数
  • 知道进程pid就可以发信号,也可以一次给一群进程发信号
  • 需要权限,比如root,或者进程描述符相同,在杀死进程中用到了信号

跨进程传递大图片

跨进程传递大图片,如果图片不进行处理,则会触发TransactionTooLargeException异常 那它的触发原因以及底层机制是什么

TransactionTooLargeException的触发原因和底层机制

TransactionTooLargeException异常 事务大巨大,客户端向服务发送调用,一直到调用结束称为事务 - 发出去的或者返回的数据流太大 - 跨进程需要Buffer,发送数据需要Buffer,等到数据结束,才释放Buffer,发数据占用空间,留给接受数据空间就小 - Binder缓存用于该进程所以正在进行中的Binder事务 - Binder事务共享1M空间,不要同时跑很多事务,尤其大数据量事务 - 大数据量打碎分批发,或按需发

跨进程传大图片方案

那如何解决这个异常问题 1. 给图片保存到固定的地方,通过文件路径传递,再另一个进程根据路径进行读取,但是耗时,传key给对方,图片写到文件,路径传到另一个进程,再读出来 2. 通过IPC方式转发图片数据 - Binder - Socket、管道 - 共享内存 - 性能,减少拷贝次数 - 内存泄漏,资源及时关闭

intent传图与binder传图对比

  • intent传图,但是容易抛异常,因为intent带Bitmap,Bitmap直接考到Pracel的缓冲区,没有用到ashmem机制,Pracel是否允许带描述符机制没有打开
Bundle b = new Bundle();
b.putParcelable("bitmap",mBitmap);
intent.putExtras(b);
  • binder调用传图,底层ashmem机制
Bundle b = new Bundle();
b.putBinder("binder",new IRemoteCaller.Stub(){
public Bitmap getBitmap(){return mBitmap}})
intent.putExtras(b);

如果跨进程传输不是图片

  1. 使用ContentProvider
  2. 或者MemoryFile

这两个底层都采用了共享内存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值