Android 跨进程通信-(六)几句话描述Binder机制

目录

前言

二 概念汇总

1.为什么要引入多进程

2.Android中常见的跨进程通信(IPC)的方式

3.什么是Binder

4.ServiceManager进程

5. Client进程

6.Server进程

7.Binder机制中的一次拷贝原理


前言

Android 跨进程通信-(一)Binder概念引入

Android 跨进程通信-(二)Binder机制之ServiceManager

Android 跨进程通信-(三)Binder机制之Client

Android 跨进程通信-(四)Binder机制之Server

Android 跨进程通信-(五)Binder机制之一次拷贝的原理

经过前面五篇文章的总结,对Binder机制有了自己的一点认知,前面主要是从源码的角度来分析,这次主要简单的汇总下几个概念性的东西。

二 概念汇总

1.为什么要引入多进程

第一点:Android系统为每个APP会分配固定大小的内存。如果一个APP需要更多的内存空间,要么就可以引入多进程,让某些模块运行在另外的进程中,获取更大的内存;

第二点:由于每个APP运行在不同的进程中,若共享APP中的某些数据的时候,例如通讯录等。

2.Android中常见的跨进程通信(IPC)的方式

Bundle:常用于四大组件之间的通信,实现了Parcelable接口;

ContentProvider:存储和获取数据,不同APP之间共享数据;

文件共享:常用于无并发,交换数据实时性不高;

Messenger:在不同进程通过Message传输,只支持Bundle支持的数据类型,不支持RPC(远程过程调用:Client调用Server的方法);低并发的一对多的串行通信(串行的方式接收Client发出的消息);最底层基于AIDL;

AIDL:一对多并发通信(Server支持同时处理大量消息),支持RPC;

Socket:网络数据交换

3.什么是Binder

在Linux系统中,会将虚拟空间分为用户空间和内核空间。系统每启动一个APP,就会给APP在用户空间创建一个进程;由于Android系统对每个APP是有内存限制,如果想给该APP申请更大的内存,同样也可以在该APP中额外创建一个进程来运行其他模块。

由于进程间是不能互相访问的,只能通过内核空间进行中转,而Binder机制就是Android系统中的一种跨进程通信的方式。

Binder机制需要四部分组成:Server、Client、ServiceManager以及Binder驱动。前三个运行在用户空间,Binder驱动运行在内核空间。Server、Client、ServiceManager之间进行数据通信,都需要通过Binder驱动进行中转。

相对于Linux其他IPC方式来说,Binder机制只需要拷贝一次数据,并且在用Binder驱动传递数据的时候,分配和传输数据一样大的内存,节省了内存和时间。(因为Linux系统的其他IPC因为不知道传输数据的大小,所以目标进程为了能够有足够的空间来存放数据,通常会分配尽可能大的空间;或者有的IPC通过先解析消息头的信息来获取消息体的大小,例如Socket,浪费空间或时间)。

4.ServiceManager进程

用来管理Service的注册和查询。将字符串转换层对应的Binder引用。该进程为系统启动的时候,有init进程创建出来的。在ServiceManager进程创建的过程中,会执行两步操作:

第一步:通过binder_open()打开“/dev/binder”设备文件,获取一个文件描述符,才可以与Binder驱动进行交互;

第二步:通过mmap将该设备文件映射到用户空间的虚拟内存,同时系统调用到内核,也在内核空间分配虚拟内存,同时申请一块物理内存,同时映射到用户空间对应的虚拟内存和内核空间对应的虚拟内存中;

第三步:通过ioctl发送指令,告诉Binder驱动,该进程为ServiceManager进程;

第四步:通过binder_loop(),开启一个循环,时刻等待Binder驱动发送过来的消息;

第五步:当接收Binder驱动发送的消息时,通过binder_parse()解析和处理消息。

详细的内容可参见Android 跨进程通信-(二)Binder机制之ServiceManager

5. Client进程

通常APP进程会作为Client进程。

当Android系统启动的时候,启动的第一个用户进程为init进程,init进程fork出Zygote进程,Android的其他进程都是有Zygote进程fork出来的。

一个进程要经历创建、初始化以及加载功能。那么Zygote进程有init进程创建出来的,在完成初始化加载功能的时候,会创建一个Socket通信的ZygoteServer,用来接收AMS发出创建进程的请求;同时fork出system_server进程,完成system_server进程初始化、功能加载:system_server进程主要就是启动一些系统Service,如AMS、PMS、WMS等。

当Zygote进程接收到AMS创建APP进程的时候,维护的循环中就会通过Zygote进程fork出一个进程,完成APP进程的初始化、功能加载:主要加载了APP的入口类ActivityThread,通过维护的循环消息机制来完成对Activity、Broadcast、Service等操作。

APP进程需要通过Binder驱动与其他进程通信,同样需要获取“/dev/binder”设备文件的描述符,并且在用户空间分配虚拟内存,在内核空间对应分配虚拟内存,同时申请一块物理内存,完成映射。区别于ServiceManager进程,该APP进程会设置Binder驱动的最大连接数,默认的为15个,只会创建binder主线程,其他的线程有Binder驱动来控制创建。

6.Server进程

在APP中都是通过AMS来启动Service,在启动Service之前会判断该Service的进程是否和APP的进程一致,如果跟APP的进程一致,则直接通过ActivityThread中维护的消息队列来启动该Service;如果不在APP的进程中,则会通过AMS的startProcessLocked(),最终将进程的信息写入到与Zygote进程的socket通道中,Zygote进程收到消息之后,同样会通过Zygote进程fork出一个进程,并完成该进程的初始化、功能加载,同样也是加载了一个ActivityThread类。

只不过bindService在创建完进程之后,还会发送通过ActivityThread的消息机制完成Service的bind过程。

7.Binder机制中的一次拷贝原理

进程之间使用Binder驱动来进行通信,需要首先获取一个dev/binder设备文件的文件描述符,才可以与Binder驱动交互。Binder驱动会为每个进程创建一个binder_proc的结构体,然后将该结构体放到全局的hash队列binder_procs中,只要遍历该队列,就知道当前有多少进程在使用Binder通信。

其次还需要利用mmap内存映射,可以将/dev/binder设备文件映射到用户空间的虚拟内存中。系统在为该文件内存映射的时候,不仅在用户空间分配虚拟内存,并且还会在内核空间分配虚拟内存,并且Kernel还会申请一块物理内存同时映射到用户空间对应的虚拟内存和在内核空间对应的虚拟内存;这样如果将数据拷贝到用户空间,都是相当于拷贝到内核空间,反之亦然。

在将数据从发送进程传递到目标进程的时候:

(1)首先将数据从发送进程的用户空间对应的虚拟内存拷贝到内核空间对应的虚拟内存中;

(2)然后使用Binder驱动传递数据的时候,Binder驱动会为该数据从目标进程在内核空间对应的虚拟内存开始分配虚拟内存,那么当把数据从发送进程对应的虚拟内存拷贝到Binder驱动的虚拟内存的时候,其实就相当于直接拷贝到目标进程在内核空间对应的虚拟内存中。

(3)由于前面创建目标进程的时候,由于进程在用户空间分配的虚拟内存和在内核空间对应的虚拟内存存在映射关系,实际上上面的过程就是直接拷贝到了目标进程在用户空间分配的虚拟内存中。

(4)目标进程将数据从内核空间对应的虚拟内存拷贝到用户空间对应的虚拟内存

这样就完成了Binder机制中的一次拷贝,我觉得所谓的Binder机制的一次拷贝,指的是用Binder驱动传递数据的时候只需要拷贝一次数据。

具体详细逻辑可参见Android 跨进程通信-(五)Binder机制之一次拷贝的原理

扩展几个小问题:

  • 1.为什么ServiceManager进程仅仅为128k的内存,而其他进程为1M-8k?

ServiceManager进程仅仅与Server进程和Client进程进行通信,仅仅是用来做一些注册、查找服务这些简单的事务,数据传输量不大,不需要分配太大的虚拟内存;

而其他Client进程和Service进程之间需要传递一些业务相关的数据。在使用Binder传递数据,必须实现Parcelable或Seri

  • 2.其他进程传递的数据能达到1M-8k吗?

不能。因为所有的进程都会共享进程在用户空间分配的内存空间,而Binder驱动中最多可支持15个Binder链接。所以传递数据不可能达到1M-8k

上一篇:干了5年Android开发还没掌握binder机制?震撼来袭免费下载!


下一篇:字节跳动上千道精选面试题还不刷起来!论程序员成长的正确姿势