Binder学习总结

该文章参考了
jeanboydev(https://blog.csdn.net/freekiteyu/article/details/70082302)博主的文章,如有侵权请通知删除
什么是Binder
Binder是Android系统中进程间通讯(IPC)的一种方式,也是Android系统中最重要的特性之一。Android中的四大组件Activity,Service,Broadcast,ContentProvider,不同的App等都运行在不同的进程中,它是这些进程间通讯的桥梁。正如其名“粘合剂”一样,它把系统中各个组件粘合到了一起,是各个组件的桥梁。
下图是一张Binder架构图
在这里插入图片描述

  1. Binder 通信采用 C/S 架构,从组件视角来说,包含 Client、 Server、 ServiceManager 以及 Binder 驱动,其中 ServiceManager 用于管理系统中的各种服务。
  2. Binder 在 framework 层进行了封装,通过 JNI 技术调用 Native(C/C++)层的 Binder 架构。
  3. Binder 在 Native 层以 ioctl 的方式与 Binder 驱动通讯。

下图是Binder机制图
在这里插入图片描述

  1. 首先需要注册服务端,只有注册了服务端,客户端才有通讯的目标,服务端通过 ServiceManager 注册服务,注册的过程就是向 Binder 驱动的全局链表 binder_procs 中插入服务端的信息(binder_proc 结构体,每个 binder_proc 结构体中都有 todo 任务队列),然后向 ServiceManager 的 svcinfo 列表中缓存一下注册的服务。
    2.有了服务端,客户端就可以跟服务端通讯了,通讯之前需要先获取到服务,拿到服务的代理,也可以理解为引用。比如下面的代码:
    //获取WindowManager服务引用 WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);

    获取服务端的方式就是通过 ServiceManager 向 svcinfo 列表中查询一下返回服务端的代理,svcinfo 列表就是所有已注册服务的通讯录,保存了所有注册的服务信息。.
    3.有了服务端的引用我们就可以向服务端发送请求了,通过 BinderProxy 将我们的请求参数发送给 ServiceManager,通过共享内存的方式使用内核方法 copy_from_user() 将我们的参数先拷贝到内核空间,这时我们的客户端进入等待状态,然后 Binder 驱动向服务端的 todo 队列里面插入一条事务,执行完之后把执行结果通过 copy_to_user() 将内核的结果拷贝到用户空间(这里只是执行了拷贝命令,并没有拷贝数据,binder只进行一次拷贝),唤醒等待的客户端并把结果响应回来,这样就完成了一次通讯。
    Binder驱动
    在这里插入图片描述

用户空间/内核空间
Kernel space 是 Linux 内核的运行空间,User space 是用户程序的运行空间。 为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。
Kernel space 可以执行任意命令,调用系统的一切资源; User space 只能执行简单的运算,不能直接调用系统资源,必须通过系统接口(又称 system call),才能向内核发出指令。

用户空间访问内核空间的唯一方式就是系统调用;尽管于内核中 添加传统的Linux通讯机制(Socket、管道)支持都是可以进行通讯,但是Binder不属于Linux内核,所以在Android系统中,Binder使用的是Binder驱动进行通讯的。
驱动就是操作硬件的接口,为了支持Binder通信过程,Binder 使用了一种“硬件”,因此这个模块被称之为驱动。
ServiceManager
其次说一下 从机制图上来看相当重要的ServiceManager。
Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务(查询服务、注册服务)。

item注册服务(addService):Server进程要先注册Service到ServiceManager。该过程:Server是客户端,ServiceManager是服务端。
获取服务(getService):Client进程使用某个Service前,须先向ServiceManager中获取相应的Service。该过程:Client是客户端,ServiceManager是服务端。
使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:client是客户端,server是服务端。

在这里插入图片描述

  1. ServiceManager 分为 framework 层和 native 层,framework 层只是对 native
    层进行了封装方便调用,图上展示的是 native 层的 ServiceManager 启动过程。
  2. ServiceManager 的启动是系统在开机时,init 进程解析 init.rc 文件调用 service_manager.c中的 main() 方法入口启动的。 native 层有一个 binder.c 封装了一些与 Binder 驱动交互的方法。
  3. ServiceManager 的启动分为三步,首先打开驱动创建全局链表 binder_procs,然后将自己当前进程信息保存到binder_procs 链表,最后开启 loop 不断的处理共享内存中的数据,并处理 BR_xxx 命令(ioctl 的命令,BR可以理解为 binder reply 驱动处理完的响应)。
    总结
    在这里插入图片描述
    上图是完整的一次通讯图。
    简单介绍一下,在framework层的AIDL就是一个简单的同学本地服务端,假设已经完成了注册流程,首先我们通过ServiceManager获取服务端的BinderProxy对象,通过调用 BinderProxy 将参数,方法标识(例如:TRANSACTION_test,AIDL中自动生成)传给 ServiceManager,同时客户端线程进入等待状态。ServiceManager 将用户空间的参数等请求数据复制到内核空间,并向服务端插入一条执行执行方法的事务。事务执行完通知 ServiceManager 将执行结果从内核空间复制到用户空间,并唤醒等待的线程,响应结果,通讯结束。
    这次学习Binder比较粗糙,相信在之后的多次接触进程通讯后,查看源码后会再次进行总结。这里挂几个关于binder的传送门:
    Gityuan(http://gityuan.com/2015/10/31/binder-prepare/) (基于 Android 6.0)
    Weishu(http://weishu.me/2016/01/12/binder-index-for-newer/)
    老罗(https://blog.csdn.net/luoshengyang/article/details/6618363)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值