几种ipc方式
Android基于Linux系统,在Linux中进程空间被划分为用于空间和内核空间
- 用户空间:用户间的数据不共享
- 内核空间:属于共享空间
用户空间和内核空间的交互需要通过系统调用
- copy_from_user():将用户空间的数据拷贝到内核空间
- copy_to_user():将内核空间的数据拷贝到用户空间
进行了2次copy。
binder
通信机制 模型 基于 Client - Server 模式 。其核心原理:内存映射。 参考 操作系统:图文详解 内存映射
对比 Linux (Android基于Linux)上的其他进程通信方式(管道、消息队列、共享内存、
信号量、Socket),Binder 机制的优点有:
- 高效,只需要一次数据拷贝
- 安全,给每个进程分配了 UID/PID 进行身份校验
Linux 系统中,进程与进程间内存是不共享的。两个进程就像两个平行的世界,A 进程没法直接访问 B 进程的数据,这就是进程隔离的通俗解释。
内核空间(Kernel)是系统内核运行的空间,用户空间(User Space)是用户程序运行的空间,每个进程运行在独立的用户空间。为了保证安全性,它们之间是隔离的。
内存映射通过 mmap() 来实现,mmap() 是操作系统中一种内存映射的方法。内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。
映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。
ServiceManager、Binder Client、Binder Server处于不同的进程,他们三个都在用户空间,而Binder驱动在内核空间。Server进程向ServiceManager注册一个映射关系表,Client进程想要和Server进程通信,首先向ServiceManager查询地址,ServiceManager收到查询的请求之后,返回查询结果给Client。
Binder 驱动在内核空间创建数据接收缓存区和内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系。发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
跨进程传递大图片
当我们使用Intent跨进程传输数据的时候,数据量要是太大,会抛出TransactionTooLargeException的异常,这个异常表示两个Client的进行交互式,事物占用的内存过大,该异常发生的一些情况和解决方法:
- 发送/返回的数据量过大,跨进程通信的过程中,发送数据和接收数据都是通过Buffer承载的,要是占用的内存过大,那么预留给对方的内存就有可能不足,当内存不足的时候,发送/返回数据申请不到足够的内存,就会抛这个异常;
- BInder缓存申请不到足够的内存缓存空间,应用在启动Binder机制的时候,会穿件1M的缓存空间作为BInder通信的内存空间,所有的Binder公用这1M的内存,要是某个Binder服务占用的内存空间较大,导致其他的Binder无法申请到足够的内存空间,就会抛出这个异常;
- 对于单个Binder调用数据传输量过大的问题,建议的解决方案是将数据打散分批发送。
通过Intent来跨进程传递一个Bitmap,当mBitmap占用的内存过大的时候,就会抛出TRansactionTooLargeException的异常。
而以下方式则不会
1 | Bundle bundle = new Bundle(); |
如上面的代码,我们通过Intent传递一个Binder对象,接收端在收到Binder对象之后,通过调用BInder对象的getBitmap方法,同样可以获得传输的Bitmap,却不会造成异常。
当我们调用putParcelable传递Bitmap(Bitmap是实现了Parcelable接口的,可以进行序列化的)的时候,系统自动将allowFds设为false,禁止使用文件描述符,bitmap的传输不能利用共享内存的方式,只能将Bitmap拷贝Binder的缓存区,导致缓存区超限,需要申请的内存大于了Binder初始化的1M内存空间的限制,这样就会抛出
当我们使用putBinder的方式传递Bitmap的时候,系统是会将allowFds设置为true,运行带fd描述字符的,当传递数据的时候,首先会判断当前数据是否小于16K,小于16KB的时候会直接使用Binder的缓存空间,而当大于16KB的时候,则开辟一个ashmem,映射出一块内存,该数据会保存到ashmem中,在Intent中之写入一个fd的文件描述符,这样即使传输的数据再大,Intent中传输的也只是该资源的文件描述符。而ashmem就是利用了共享内存,在发送端和接收端之间映射同一块内存,无需多次拷贝,提高了数据传输的性能。
优秀文章: