Binder概述:

Binder是一种进程间通信机制,基于开源的OpenBinder实现,从字面上解释Binder有粘合剂的意思,顾名思义就是粘合不同的进程,使之实现通信。

Binder与传统的IPC(Inner-Process Communication)之间的区别

Binder

共享内存

Socket

性能

需要拷贝一次

无需拷贝

需要拷贝两次

特点

基于C/S架构易用性高

控制复杂,易用性差

基于C/S架构,作为一款通用接口,其传输效率低,开销大

安全性

为每个app分配UID同时支持实名和匿名

依赖上层协议访问接入点是开放的不安全

依赖上层协议访问接入点是开发的不安全

性能

Socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区,再从内核缓存去拷贝到接收方缓存区,至少需要拷贝两次。共享内存虽然无需拷贝,但控制复杂,难以使用,多进程访问同一块内存,加入某一个进程在使用过程中出现了问题,不释放内存而引发死锁。Binder仅需一次数据拷贝,性能上仅次于共享内存。

稳定性

Binder基于C/S架构,客户端有什么需求直接丢给服务端去完成,架构清晰、职责明确又相互独立,自然稳定性更好。共享内存控制复杂,多个进程同时访问资源时,只能有一个进程使用资源,其他进程处于等锁状态。从稳定性的角度讲,Binder机制优于内存共享。

安全性

传统的IPC没有任何安全措施,完全依赖上层协议来确保。首先传统的IPC接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),从而无法验证对方身份。Android为每个安装好的App分配了自己的UID,故进程UID是鉴别进程身份的重要标志。传统的 IPC 只能由用户在数据包中填入 UID/PID,但这样不可靠,容易被恶意程序利用。其次传统的IPC访问接入点是开放的,只要知道这些接入点的程序就可以和对端建立连接。同时Binder支持实名Binder和匿名Binder,安全性高。

Binder跨进程通信原理

Binder IPC机制中涉及到内存映射mmap()(memory map)实现,mmap是操作系统中一种内存映射方法,简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。
内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。

Binder跨进程通信简图

Android Binder为什么进行一次数据拷贝而不是2次或者0次 binder一次拷贝原理_共享内存

Binder系统服务调用图

Android Binder为什么进行一次数据拷贝而不是2次或者0次 binder一次拷贝原理_内核空间_02

  • 系统服务调用需要进行6次进程通信:
  • 1.客户端从ServiceManager拿到AMS服务,client与ServiceManager通信;
  • 2.调用AMS.bindService(),client与AMS通信;
  • 3.AMS 调用scheduleBindService与server通信;
  • 4.server从ServiceManager拿到AMS 代理对象;server与ServiceManager通信;
  • 5.调用AMS.publishService(),Server与AMS通信;
  • 6.调用c.conn.connected(r.name, service),AMS与Client通信;

各java类职责描述

  • IBinder:IBinder是一个接口,代表了一种跨进程通信的能力。实现了这个接口就可以跨进程传输。
  • IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)
  • Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象。BinderProxy 类是 Binder 类的一个内部类,它代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。
  • Stub : AIDL 的时候,编译工具会给我们生成一个名为 Stub 的静态内部类;这个类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;Stub 是一个抽象类,具体的 IInterface 的相关实现需要开发者自己实现。
  • Proxy:代理类,它是Stub的静态内部类,当远程调用时,client想要调用server的服务需要通过Binder代理来完成,client无法直接拿到server的对象

使用AIDL进行进程间通信

  • 1.声明一个IAddtionInterface.aidl接口,写入抽象方法,即该服务有什么功能;
  • 2.创建Person类,实现序列化,只有实现了序列化的类才可以传输;
  • 3.rebuild project,android studio帮助生成一个IAddtionInterface.java类;
  • 4.创建服务,实现IAddationInterface.stub抽象方法
  • 5.创建客户端:通过ServiceConnection方法,获取到binder对象,调用服务