失眠必读系列——Binder知识点记录

220 阅读5分钟

Linux传统IPC

进程隔离

进程与进程间内存不共享,数据交互需要IPC

进程空间

进程空间分为:

  • 用户空间(User Space)
  • 内核空间(Kernel Space)

现代操作系统采用虚拟内存,比如32位系统,其寻址空间是2的32次方,即4GB(对于操作系统而言,一个地址=1byte)

摘自网络:虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。

以Linux而言,将最高的 1GB 字节供内核使用;较低的 3GB 字节供各进程使用(图片来自网络,侵删)

image.png

进程调用

系统调用是用户空间访问内核空间的唯一方式,即内核可控,提升了系统安全性和稳定性。 Linux中有两级保护机制:

  • 0级,处理器执行内核代码(内核态)
  • 3级,处理器执行用户代码(用户态)

系统调用主要通过如下两个函数来实现:

  • copy_from_user() //将数据从用户空间拷贝到内核空间
  • copy_to_user() //将数据从内核空间拷贝到用户空间

(图片来自网络,侵删) image.png

  • 数据存放用户空间的内存缓存中,通过系统调用,进入内核态
  • 内核程序在内核空间开辟内核缓存区,调用copy_from_user() ,将数据拷贝到内核空间的缓存
  • 接收方相反,调用 copy_to_user()

缺点:

  • 二次拷贝,效率低
  • 接收方不知道数据大小,要么开辟尽可能大空间,要么事先去获取数据大小

Binder IPC

Binder驱动

Linux 的动态内核可加载模块(Loadable Kernel Module,LKM)的机制导致Android 系统可以通过动态添加一个内核模块运行在内核空间,用户进程之间通过这个内核模块作为桥梁来实现通信。这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder 驱动(Binder Dirver)。

(图片来自网络,侵删) image.png

内存映射mmap

Binder IPC机制中涉及到的内存映射通过 mmap() (memory map)来实现,即将用户空间的一块内存区域映射到内核空间。映射后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。正是因为mmap的一次拷贝,才会比传统Linux的IPC效率高

内核中的binder_mmap函数:申请一块物理内存A,然后在Server端的用户空间B和内核空间C同时进行映射。
物理A映射内核空间C
物理A映射用户空间B
相当于B和C相互映射

实现原理

  • Binder驱动在内核空间创建数据接收缓存区;
  • 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及数据接收缓存区和接收方进程的用户空间的映射关系;
  • 发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核缓存区,因为有这层映射关系,因此相当于把数据发送到了接收方的进程的用户空间,即A与B映射,B与C映射,对A进行写入数据,则C也能收到数据

通信过程

(图片来自网络,侵删) Avdroid Applcatlon.jpg

Server 班程.jpg

  • 1.SM进程使用 BINDER_SET_CONTEXT_MGR 命令通过 Binder 驱动将自己注册成为服务管家;可以参考我之前写的ServiceManager启动流程
  • 2.Server端(比如SystemServer)通过Binder驱动向ServiceManager注册Binder(即服务),Binder驱动为Binder创建结点以及引用,然后将引用+名字发给ServiceManager,写入一张查找表(这里可能有个疑问,服务注册过程其实也是跨进程,如何拿到SM的?其实在【ServiceManager启动流程】文章已经说明,服务管家SM的引用可以在Binder驱动中直接拿到,引用为0,不管是Client端还是Service端)
  • 3.Client通过名字就能在ServiceManager中找到对应的引用(不过返回的是代理对象objectProxy,方法名+参数都一样)
//AMS/PMS/WMS都是实体Binder:
ActivityManagerService extends IActivityManager.Stub
PackageManagerService extends IPackageManager.Stub
WindowManagerService extends IWindowManager.Stub
abstract class Stub extends android.os.Binder

Binder驱动类似路由器,负责转发消息,ServiceManager类似DNS,通过字符串名字找到对应的代理对象返回给Client

不同角度定义Binder

  • 1.进程间通信角度,Binder是一种进程间的通信方式(在Binder驱动的帮助下,代理对象和实体对象相互转换,从而可以发送数据返回结果)
  • 2.Server进程角度,Binder是实体对象(比如AMS/WMS/PMS,他们都是继续Binder)
  • 3.Client进程角度,Binder是Binder实体的代理对象(Binder驱动根据名字返回对应的代理对象,代理对象调用同名方法,传入相同的参数,然后Binder驱动找到对应的Binder实体,调用真正的方法,最后返回想要的结果)

借助AIDL手动编码实现Binder IPC

可以参考个人练习项目AndroidTest

结尾

失眠必读系列未完待续,有任何错误,虚心讨教,欢迎指正...


参考资料:

zhuanlan.zhihu.com/p/430557625
blog.csdn.net/Hfengxiang/…
blog.csdn.net/mcryeasy/ar…
www.cnblogs.com/huxiao-tee/…