浅析 Binder 机制

几个概念

  1. 进程隔离

    进程隔离,不同进程之间,不共享内存。而操作系统是多进程的,因此需要 IPC。

  2. 进程空间划分

    Kernel 是操作系统的核心,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。因此把 Kernel 和上层的应用程序隔离,分为内核空间和用户空间。

进程隔离

Android 利用了 Linux 的动态可加载内核模块机制,使 Binder 驱动运行在内核空间,负责各个用户进程通信。

Binder 机制

Binder 通信模型:C/S 模型

通信过程:

  1. Server 向 ServiceManager 也是通过发送 Binder 消息注册。ServiceManager 是比较特殊的服务,所有应用都能直接使用,因为ServiceManager对于Client端来说Handle句柄是固定的,都是0,所以ServiceManager服务并不需要查询,可以直接使用。
  2. client 通过 ServiceManager 获得一个 server 的 Binder 实体的代理,对 server 进行调用。代理接口中定义的方法与 server 中定义的方法时一一对应的。
  3. client 调用某个代理接口中的方法时,代理接口的方法会将 client 传递的参数打包成 Parcel 对象。client 线程挂起。
  4. 代理接口将 Parcel 发送给内核中的 binder 驱动。驱动通过一系列调用,将请求派发给 server 的 Binder 本地对象的 onTransact 方法。
  5. onTransact 方法解包 Parcel 对象,处理并将结果返回给 binder 驱动,驱动唤醒 client 线程,并将结果返回。

Android APP进程都是由Zygote进程孵化出来的。常见场景:点击桌面icon启动APP,或者startActivity启动一个新进程里面的Activity,最终都会由AMS去调用Process.start()方法去向Zygote进程发送请求,让Zygote去fork一个新进程,Zygote收到请求后会调用Zygote.forkAndSpecialize()来fork出新进程,之后会通过RuntimeInit.nativeZygoteInit来初始化Andriod APP运行需要的一些环境,而binder线程就是在这个时候新建启动的。

IPC 是一个概念,Binder 是一种 IPC 的具体实现;AIDL 是 Binder 机制向外提供的接口,目的就是为了方便对 Binder 的使用;

Android 系统匿名共享内存 Ashmem,其作用之一即通过 Binder 进程间通信机制来实现进程间的内存共享。

Client 进程只不过是持有了 Server端的代理;代理对象协助驱动完成了跨进程通信。

对 Server 来说,Binder 就是 Binder 本地对象,对 Client 来说, Binder 是 Binder 本地对象的代理。在Android开机启动过程中,Android会初始化系统的各种Service,并将这些Service向ServiceManager注册。

我们所持有的Binder引用(即服务端的类引用)并不是实际真实的远程Binder对象,我们的引用在Binder驱动里还要做一次映射。客户端要调用远程对象函数时,只需把数据写入到Parcel,在调用所持有的Binder引用的transact()函数,transact函数执行过程中会把参数、标识符(标记远程对象及其函数)等数据放入到Client的共享内存,Binder驱动从Client的共享内存中读取数据,根据这些数据找到对应的远程进程的共享内存,把数据拷贝到远程进程的共享内存中,并通知远程进程执行onTransact()函数。远程进程Binder对象执行完成后,将结果写入自己的共享内存中,Binder驱动再将远程进程的共享内存数据拷贝到客户端的共享内存,并唤醒客户端线程。

整个的调用过程是一个同步过程,在server处理的时候,client会block住。因此client调用过程不应在主线程。

区别于传统的 IPC 的两次拷贝, Binder 机制使用内存映射。

Binder IPC 机制中涉及到的内存映射通过 mmap() 来实现,mmap() 是操作系统中一种内存映射的方法。内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。
只需要一次拷贝(用户内核到服务内核的拷贝)内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。两个空间各自的修改能直接反映在映射的内存区域,从而被对方空间及时感知。

实现过程

Client 连接 Server 时,需要创建一个 ServiceConnection 作为入参,ServiceConnection 的回调方法 onServiceConnected 中会通过 asInterface(IBinder binder) 拿到 IBinder 对象,如果 Client 和 Server 在同一个进出,binder 就是 Binder 本地对象,否则是一个代理对象。

参考

写给 Android 应用工程师的 Binder 原理剖析

简单理解Binder机制的原理

https://blog.csdn.net/china0851/article/details/87945740

Binder系列5—注册服务(addService)

听说你Binder机制学的不错,来解决下这几个问题(一)

写给 Android 应用工程师的 Binder 原理剖析