Android-Binder系列1

Binder [ˈbaɪndə®] 宏观理论详解

hi,大家好,我是爱吃香蕉的猴子,今天开始 我要聊聊binder的那些事,现在已经有很多大佬写Binder的文章,我也是借鉴他们的文章,然后加上自己的琢磨,写一个系列的binder文章.


在Binder之前,有什么跨进程通信方式?

  • 管道:由内核管理的一个缓冲区,管道的一端连接一个进程输入,另一端连接进程输出, 缓冲区不需要很大,被设计成环形的数据结构。
    • 特点: 在创建一个管道时,缓存区大小比较受限制,并不适合Android的大量的进程通信。
  • 内存共享: 就是不相关的两个进程同时访问一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据一种非常有效的方式,不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中。
    • 特点: 无需要复制,自然速度快。缺点:不安全,如果android采用这种方式,则会产生安全隐患。
  • socket: 两次拷贝,效率比较低。

在上面进程间通信方式,都不太适合Android.这才有了Binder,那么Binder通信有什么特点:

  • 性能: 只需要一次拷贝,其余的管道、socket都是两次拷贝,则效率比较高
  • 稳定性: Binder是基于C/S的架构,是指客户端(Client)和服务端(Server)组成的架构,Client端有什么需求,直接发送给Server端去完成,架构清晰明朗,Server端与Client端相对独立,稳定性较好;相比内存共享则没有客户端和服务端的区别,存在安全的隐患。
  • 安全性: Binder给每个进程分配一个UID,故进程的UID是鉴别进程身份的重要标志,Android系统中对外只暴露Client端,Client端将任务发送给Server端,Server端会根据权限控制策略,判断UID/PID是否满足访问权限,目前权限控制很多时候是通过弹出权限询问对话框,让用户选择是否运行。

现在应该了解了为什么android选择了Binder,下面就分析一下Binder;
Binder [ˈbaɪndə®]详解

  • 中文讲是粘合剂,就是可以粘合两个不同的进程
  • Binder是一种Android中实现跨进程通信(IPC)的方式(一种架构设计)
  • Binder是一种虚拟的物理设备驱动, 连接Service进程、Client进程、Service Manager进程(Binder驱动)
  • Binder是一个类,实现了IBinder接口,将Binder架构以代码的形式具体实现在Android中.

基础概念

  • 用户空间: 数据不能共享(不可共享空间)
  • 内核空间: 数据可以共享(可共享空间)
  • 交互:
    • copy_from_user(): 用户空间的数据拷贝到内核空间
    • copy_to_user(): 将内核空间的数据拷贝到用户空间
  • 内存映射[盗图]
    在这里插入图片描述
  • 进程1 、进程2 和共享对象存在映射关系, 当进程1写入数据时, 进程1虚拟内存区域将数据映射到共享对象,从而也会映射到进程2的虚拟内存区域。
  • 代码:
/**
  * 函数原型
  */
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
/**
  * 具体使用(用户进程调用mmap())
  * 下述代码即常见了一片大小 = MAP_SIZE的接收缓存区 & 关联到共享对象中(即建立映射)
  */
  mmap(NULL, MAP_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
/**
  * 内部原理
  * 步骤1:创建虚拟内存区域
  * 步骤2:实现地址映射关系,即:进程的虚拟地址空间 ->> 共享对象
  * 注: 
  *    a. 此时,该虚拟地址并没有任何数据关联到文件中,仅仅只是建立映射关系
  *    b. 当其中1个进程对虚拟内存写入数据时,则真正实现了数据的可见
  */
  • 图解client server sm的流程:

在这里插入图片描述

  • Server端:
    • path:frameworks\native\cmds\servicemanager\binder.c
    • open 驱动 # open("/dev/binder", O_RDWR);
    • 注册服务(向servicemanager发送服务名)
    • while() {1.读驱动 2. 解析数据 3. 根据code 调用具体函数}
    • 流程: Server进程向Binder驱动发起服务注册请求 --> Binder驱动将注册的请求发给SM–>SM进程添加给进程。
  • service_manager:
    • frameworks\native\cmds\servicemanager\service_manager.c
    • open 驱动 # binder_open(128*1024);
    • 告诉驱动,它是“servicemanager” # binder_become_context_manager
    • while() { 1. 读取驱动获取数据 2. 解析数据 3. 注册服务到链表 和 返回server进程的handle} # binder_loop(bs, svcmgr_handler);
  • Client端:
    • path: frameworks\native\cmds\servicemanager\bctest.c
    • open驱动 # bs = binder_open(128*1024);
    • 获取服务: 1. 向servicemanager查询服务 2. 获取一个handler
    • 向handle发送数据
    • 流程:Client端向Binder驱动发起获取服务的请求(传递服务的Name)–> Binder驱动将请求发给SM进程–> SM找到对应的服务–> 返回给client(通过binder驱动)

Binder驱动图解【盗图】


  • 注解: binder驱动创建一块 接收缓存区,实现地址映射关系(SM进程里的Server信息找到对应的Server进程,实现内核缓冲区和Server进程用户空间地址 同时映射到一个 接收缓存区)。
  • 流程:Client进程通过系统调用copy_from_user() 发送数据到内核空间中的缓存区–> binder驱动通知Server进程执行解包–>Server端收到Binder驱动通知后,Server进程从线程中取出线程,进行解包 & 调用目标方法,---->将最终的执行结果写入到自己的共享内存中 -->执行结果写入存在映射的用户空间的内存区域中—>Binder驱动通知Client进程获得返回结果–>client进程通过系统调用copy_to_user(), 从内核缓冲区接收Server进程返回的数据。
  • 优点: 每次单向通信数据拷贝次数少、用户空间 & 内核空间 可直接通过共享对象直接交互。

到这里基本把binder的基础写完了,后面会从代码中分析,client端调用了什么函数,server端调用了什么函数,下面是自己学习参考的大神的文章,有不理解的地方,可以看他们的详细分析。

借鉴的教程-图文讲解
借鉴的教程-跨进程方式对比分析

                                                    Code的搬运工

猜你喜欢

转载自blog.csdn.net/qq_20608169/article/details/112131293