Android(二)Binder 进程间通讯

内容摘自:一篇文章了解 Android Binder 进程间通讯机制

什么是 Binder ?

Binder 是 Android 系统进程间通信(IPC)的一种方式。译文为 “粘合剂” ,它的作用也和粘合剂一样,将系统中各个组件(如四大件)粘合到了一起,是各个组件之间的桥梁。

Binder 架构

  • Binder 通信采用 C/S 架构。
  • Binder 在 framework 层进行了封装,通过 JNI 技术调用 Native 层的 Binder 架构
  • Binder 在 Native 层以 ioctl 的方式与 Binder 驱动通讯

Binder 机制

  1. 首先要注册服务端,服务端通过 ServiceManager 注册服务
    1. 向 Binder 驱动的全局链表 binder_procs 中插入服务端的信息
    2. 向 ServiceManager 的 svcinfo 列表中缓存一下注册的服务

      svcinfo 列表保存了所有已注册服务的信息

  2. 客户端获取服务,拿到服务的代理(也可以理解为引用)

    获取方式:通过 ServiceManager 从 svcinfo 列表中查询,返回服务端的代理

  3. 通过 BinderProxy 将客户端请求参数发送给 ServiceManager
  4. 通过共享内存的方式使用内核方法 copy_from_user() 将参数拷贝到内核空间
  5. 客户端进入等待状态,Binder 驱动向服务端的 todo 列表中添加一条事务,执行完成之后把执行结果通过 copy_to_user() 将内核的结果拷贝到用户空间
  6. 唤醒等待的客户端,把结果响应返回

Binder 驱动

先了解一些基本概念。

系统调用
用户空间访问内核空间的唯一方式就是系统调用

内核态/用户态
当一个进程(任务)执行系统调用而进入内核代码中执行时,就称进程处于内核运行态,简称内核态。此时处理器处于最高特权级(0级)的内核代码中运行。
当进程执行用户自己的代码时,称其处于用户运行态,简称用户态,此时处理器处于最低特权级(3级)的用户代码中运行

驱动
驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机和设备通信的特殊程序。相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作;

如上图:
  • 户空间中的 binder_open(),binder_mmap(),binder_ioctl()等方法通过 system call 来调用内核空间 Binder 驱动中的方法。
  • 内核空间与用户空间通过 copy_from_user(),copy_to_user() 这两个内核方法来完成用户空间与内核空间内存的数据传输。
  • Binder 驱动中有一个全局链表 binder_procs 保存服务端的进程信息

ServiceManager

通过 ServiceManager 可以与 Binder 驱动进行通讯。

ServiceManager的作用很简单:提供注册服务和查询服务的功能。

下图为 ServiceManager 启动的过程。

  • ServiceManager 分为 framework 层和 native 层,framework 层只是对 native 层进行了封装,方便调用。
  • 系统开机时,init 进程解析 init.rc 文件调用 service_manager.c 中的 main() 方法启动 ServiceManager 服务。
  • ServiceManager 启动步骤:
    1. 打开驱动创建全局链表 binder_procs
    2. 将自己当前进程信息保存到 binder_procs 链表
    3. 开启 loop 不断处理共享内存中的数据

通过 ServiceManager 注册服务

  1. 注册服务端:通过 ServiceManager 的 addService() 方法注册服务
  2. ServiceManager 向 Binder 驱动发送 BC_TRANSACTION 命令(binder client)并携带 ADD_SERVICE_TRANSACTION命令。同时,注册服务的线程进入等待状态,waitForResponse()
  3. Binder 驱动收到请求,向 ServiceManager 的 todo 队列里面添加一条事务:创建服务端进程 binder_node 信息并插入到 binder_procs 链表中
  4. 事务处理完,发送 BR_TRANSACTION 命令,ServiceManager 收到命令后向 svcinfo 列表添加已经注册的服务。
  5. 发送BR_REPLAY(binder replay)唤醒等待的线程,通知注册成功。

完整通信过程

  1. 通过 ServiceManager 获取到服务端的 BinderProxy 代理对象,通过调用 BinderProxy 将参数、方法标识(例如:TRANSACTION_test)传给 ServiceManager,同时客户端线程进入等待状态。
  2. ServiceManager 将用户空间的参数等请求数据复制到内核空间
  3. 向服务端插入一条执行执行方法的事务
  4. 事务执行完通知 ServiceManager 将执行结果从内核空间复制到用户空间,并唤醒等待的线程,响应结果,通讯结束。
posted @ 2021-03-05 15:25  张小凡I4CU  阅读(178)  评论(0编辑  收藏  举报