ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### 为什么要使用 Binder 机制 Android 会为每个进程分配独立的虚拟内存空间,每个进程的虚拟地址空间是互相隔离的,如果进程间要进行互相通信,就要使用 Android 提供的 Binder 机制来进行通信。 ### 进程间通信的方式 1. 使用 Intent 来进行进程间通信,比如在调用百度地图的时候,使用 Intent ,用startActivity 来启动百度地图的指定页面 2. 使用共享文件的方式,比如 A 、 B 进程要进行通信,那么A 进程可以把要通信的内容通过序列化的方式写入到本地文件,然后 B 进程再通过读取本地文件的方式获取A 要传递的内容 3. 使用 Messager 或者AIDL(Android Interface Define Language,事实上 Messager 也是通过 AIDL 实现的,只是 Android 为我们进行了进行了简单的封装),AIDL 的底层也是通过 Binder 来完成进程间通信的。 4. 使用 ContentProvider 进行进程间通信,作为四大组件,底层使用的也是 Binder 来完成进程间通信的 5. 使用 Socket,Socket 可以实现计算机网络中的两个进程间通信,当然也可以用于进程间通信服务端监听指定的端口,客户端链接指定的端口,成功建立链接以后,拿到 socket 对象客户端就可以向服务端发送消息,或者接受服务端传来的消息。 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190509173817.png) ### 什么是 Binder Binder 是 Android 为我们提供的 IPC(Inner Process Commnuication进程间通信)的一种方式,Android 中的 Activity 、Service、Broadcast、ContentProvider 都是运行在不同的进程中,Binder 是他们之间进行通信的桥梁。 ### Binder 运行的原理 首先要定义要传输的对象,并进行序列化,反序列化,然后在相同包名下定义 AIDL 接口、要传输的对象,然后定义好了以后,再 makeProject ,生成对应的类,然后再创建一个 Service 写服务端的代码,然后再客户端使用 bindService 方法进行连接,再 ServiceConnection 的回调方法中拿到服务端的接口对象,之后就可以往服务端发送消息。 1. AIDL 接口,是一个 interface, 2. Sub 类,是 Binder 的实现类,服务端通过 Sub 类来提供服务 3. Proxy 类,服务端的本地代理,客户端通过这个类调用服务端提供的方法。只有处于不同进程间通信的时候才会调用到,一个进程内不会使用这个类,直接使用 Sub 类就可以完成通信 4. asInterface() 客户端调用,用来将 IBinder 对象转换为客户端需要的服务端的 AIDL 接口类型的对象。如果客户端和服务端处于同一个进程则返回 Sub ,不同进程返回 Sub.Proxy对象 5. asBinder()根据当前调用情况返回代理Proxy的Binder对象 6. onTransact() 运行在服务端的 Binder 线程池中,当客户端发起跨进程请求以后,请求会通过这个方法来处理 7. transact() 运行在客户端,当客户端发起远程请求以后将当前线程挂起,之后调用服务端的 onTransact知 直到请求返回,当前线程才继续执行。 > 当多个模块需要 AID 来进行 IPC 的时候,此时需要创建多个 AIDL 文件,那么相应的 Service 就会有很多,必然会出现系统资源耗费严重,解决办法是创建 Binder 连接池,即将每个业务模块的 Binder 请求统一转发到一个远程 Service 中去执行,从而避免重复建立 Service。原理大概是: > 每个业务模块创建自己的AIDL接口并实现此接口,然后向服务端提供自己的唯一标识和其对应的Binder对象。服务端只需要一个Service并提供一个queryBinder接口,它会根据业务模块的特征来返回相应的Binder对象,不同的业务模块拿到所需的Binder对象后就可以进行远程方法的调用了。 ### 为什么使用 Binder #### 1. 效率高 传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高,传统的 IPC 使用消息队列、Socket和管道,数据先从发送方的用户空间缓存区拷贝到内核空间开辟的缓存区,然后再从内核缓存区拷贝到接收方的用户空间缓存区,一共拷贝两次。 共享内存的方式不用拷贝,效率很高,但是实现的复杂度很高 。 而 Binder 只用拷贝一次 ,使用Binder 的话,进程 A、B通讯,只用拷贝数据到内核缓存区,内核缓存区和B 的缓存区是映射到同一块物理地址的,节省了一次拷贝的过程。 下面描述 Binder 传输过程(A进程向B进程传递数据) 1. 首先 Binder 驱动在内核空间开辟一块 **数据接收内存缓存区** 2. 接着在内核空间开辟一块 **内核缓存区**,建立**内核缓存区**和**数据接收缓存区**的映射关系,以及内核中的**数据接收缓存区**和**B用户空间 缓存区**的映射关系。 3. **发送方进程 A 使用 copyfromuser(),将数据拷贝到内核缓存区,由于内核缓存区和数据接收缓存区有映射关系,数据接收缓存区和B进程的用户空间缓存区有映射关系,因此也就相当于把数据从 A 进程传递到了 B 进程。** ![传输示意图](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200303171705.png) #### 2.稳定性好 上面说到共享内存的性能优于Binder,那为什么不采用共享内存呢,因为共享内存需要处理并发同步问题,容易出现死锁和资源竞争,稳定性较差。Socket虽然是基于C/S架构的,但是它主要是用于网络间的通信且传输效率较低。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。 #### 3. 安全性 传统的 Linux IPC 的接收方无法获得对方进程可靠的 UID/PID,从而无法鉴别对方的身份,而Binder 机制为每个进程分配了 UID/PID,并且在 Binder 通信过程中会根据 UID/PID进行有效的身份验证。 [参考1](https://blog.csdn.net/freekiteyu/article/details/70082302) [Binder系列文章](http://gityuan.com/2015/10/31/binder-prepare/) [红茶一杯话Binder](https://my.oschina.net/youranhongcha/blog/149575) [Android进程间通信(IPC)机制Binder简要介绍和学习计划](https://blog.csdn.net/luoshengyang/article/details/6618363) [写给 Android 应用工程师的 Binder 原理剖析](https://juejin.im/post/5acccf845188255c3201100f) [关于Binder,作为应用开发者你需要知道的全部](https://www.jianshu.com/p/062a6e4f5cbe) [巧用Android多进程,微信,微博等主流App都在用](https://cjw-blog.net/2017/02/26/AIDL/)