做过Android开发的同学可能有些体会,入门初期,工作内容主要是实现各式各样的UI界面,以及实现应用的业务逻辑。在这个阶段,我们会逐渐熟悉View系统,逐渐学会实现各种各样的界面以及动画效果。再往后,当我们想更深入的学习android系统,比如学习android四大组件的启动过程、AMS、PMS等等时,都会遇到一个叫做Binder的东西。结合笔者的经验,Binder可以说是深入理解Android系统的重要基础。binder作为android系统进程间通信的机制,贯穿在方方面面。我们平时使用最多的startActivity、startService都是通过binder机制与AMS所在进程进行通信。本文主要对Binder机制的体系结构作简要介绍,相信读者看完后,会对binder有一个总体上的理解与把握。

注:笔者初学binder时,曾经看过一些binder介绍的文章,并且过早的纠结于一些文章中的binder代码细节,感觉非常吃力。本文仅从宏观上对binder机制进行介绍。相信读者先理解了binder的总体结构后,再去深入细节,学习效果会更好。

Binder是什么、能做什么?

Binder是android系统里面的进程间通信机制。androd系统中,不同的app运行在不同的进程中,同一个app的不同组件也可能运行在不同的进程中(androidManifest文件中android:process)。当一个进程想为其它进程提供服务时,就需要通过进程间通信的方式来提供服务。打个比方:我们有一个APP1,里面有个service组件可以提供计算器的服务。当另外一个APP2也想使用APP1里面的service的计算器的服务时,由于不同的APP运行在不同的进程中,所以,APP2是无法直接使用APP1里面的service。由于跨越了进程,只能通过进程间通信机制来完成。

再说的形象点,APP1所在进程有一个对象object1,其中有一个方法method1。 APP2所在的另外一个进程,想使用object1的method1方法。binder可能帮助我们在APP2所在进程拿到一个object1对象的引用,使我们能够像调用本地对象一样,通过object1.method1()直接调用。利用binder,我们可以突破进程的限制,将对象传给其它进程,让其它进程方便调用对象的方法。

为什么用Binder?

理解了binder是什么、能做什么后,大家可能会有疑问:android系统基于Linux,linux本身具有很多的进程间通信方式可供选择,为什么android不使用linux自带的一个进程间通信方式,而新创造了一个binder?是重复造轮子吗?

Linux自带的进程间通信方式有:文件、signal、socket、Pipe、共享内存...,  为什么使用Binder?笔者总结原因有两大方面:

1 历史原因。Binder最早并不是为Android系统而设计的,最开始有一个OpenBinder的东西,用在一个叫做Palm Cobaltw的为内核操作系统上。后来,Palm Cobaltw移植到了Linux系统上,OpenBinder也跟着移植了过来。Google在组建Android开发团队的时候,聘请了一位叫做Dianne Hackborn的工程师,而他就是OpenBinder的核心人员。后面在做android进程间通信时,发现binder很合适,就理所当然的在android系统上使用了Binder。

2 binder自身的一些特点和优势。Binder实现进程间通信时,在安全性和效率方面,都很合适用在android系统中。关于这点,先有个印象即可。

Binder有哪些组成部分?

一个Binder系统由四部分组成:Binder客户端、Binder服务端、Binder驱动、服务登记查询模块

Binder客户端:想要使用服务的进程

Binder服务端:实际提供服务的进程

Binder驱动:我们在客户端先通过Binder拿到一个服务端进程中的一个对象的引用,通过这个引用,直接调用对象的方法获取结果。在这个引用对象执行方法时,它是先将方法调用的请求传给binder驱动;然后binder驱动再将请求传给服务端进程;服务端进程收到请求后,调用服务端“真正”的对象来执行所调用的方法;得出结果后,将结果发给binder驱动;binder驱动再将结果发给我们的客户端;最终,我们在客户端进程的调用就有了返回值。Binder驱动,相当于一个中转者的角色。通过这个中转者的帮忙,我们就可以调用其它进程中的对象。

服务登记查询模块:我们调用其它进程里面的对象时,首先要获取这个对象。这个对象其实代表了另外一个进程能给我们提供什么样的服务(再直接一点,就是:对象中有哪些方法可以让客户端进程调用)。首先服务端进程要在某个地方注册登记一下,告诉系统我有个对象可以公开给其它进程来提供服务。当客户端进程需要这个服务时,就去这个登记的地方通过查询来找到这个对象。

Binder各部分是如何工作的?

下面从客户端进程的角度来看看binder的工作机制

作为客户端进程,仅仅是想使用服务端进程提供的服务而已:
 
但是由于进程的隔离性,Client所在的ProcessA是不能读写Service所在的ProcessB中的内容,但系统内核可以,而Binder驱动就是运行在内核态。Binder驱动帮我们中转请求即可:
 
有了Binder驱动后,对于Client端和Service端,需要额外专门与Binder驱动打交道,为了帮Client和Service端屏蔽掉与Binder驱动打交道这件很low的工作,我们可以分别为Client和Service设计一个代理,让他们只与代理打交道即可,将与Binder驱动打交道的任务放在代理里面:
读者可能要问,如果要自己实现Client端和Service端,通过上面的方式,虽然逻辑上独立出来了两个代理(客户端代理的Proxy、服务端的代理Stub),这两个代理还不是要自己实现?如果还是要自己实现,那分出来又有实际的意义?
AndroidSDK为我们提供了一个AIDL工具。我们只要新建一个AIDL文件,像创建普通interface一样(略有不同)在里面定义接口方法。定义好之后,androidSDK会根据aidl里面的接口定义,自动为我们生成一个java文件,其中就包括客户端代理Proxy和服务端代理Stub,并且自动生成了与Binder驱动通信的代码,是不是很爽。上面的图片中,之所以将客户端代理叫做Proxy,服务端代理叫做Stub,就是因为aidl自动生成的代理中,两个代理的类名就是Proxy和Stub。我们在做的实际工作就只有真正的服务功能逻辑了。
 
再更近一步的想想,对于客户端而言,更理想的状态是,客户端完全不用知道调用的对象是一个本地对象,还是一个服务端进程中的对象。按照上面的图片,客户端显然知道自己调用的是远程对象,所以通过一个Proxy来调。我们在开发android应用程序的过程中,都会用到一些系统提供的XXXManager(ActivityManager、PackageManager、WifiManager、PowerManager等等),而这些manager所要实现的目的之一,正是帮Client屏蔽掉Binder的实现细节。有了这些Manager,Client在使用时,首先通过getServiceManager(xxx)获取一个manager对象,后面就直接调用manager中封装好的服务方法即可。这样以来,manager内部实际上还是通过客户端代理,通过binder驱动来跟运行在另外一个进程中的xxxService来通信,但对于Client来说,完全不用知道。如下图:
对于一些系统服务,ActivityManager、PackagerManager等等,不光为Client屏幕了Binder相关细节,还可以对真正的服务端对象提供的服务API进行过滤和控制,可以只为Client暴露一个服务API的子集。
 
最后一个疑问:到上面的图片所讲的内容为止,前提条件是Client先获取到了一个Proxy或者Manager,然后才完成后面的进程间通信。那到底Client是如何获取到Manager或者Proxy呢?
首先以一些系统服务为例:
前面提到,Binder机制的四个组成部分中,有一个是“服务登记查询模块”,对应上图中的Context Manager,在Android系统中运行时的进程名为:servicemanager。在所有服务进程中,servicemanager第一个启动,原因也不难理解,如果其它服务进程先于servicemanager启动,到哪里去注册?
 
如上图所示,假设Service所在的进程ProcessB在servicemanager进程启动后启动,ProcessB需要向servicemanager注册。“注册”这个动作,本质也是要跨进程通信,从ProcessB到servicemanager,这时,Service成为了本次跨进程通信的客户端,ContextManager成为了服务端。客户端到服务端的通信,按前面讲到的内容,需要一个Proxy或者Manager。这个Proxy或者Manager从哪里获取呢?问题好像陷入了循环死锁?因为ContextManager的特殊地位,读者可以理解为系统对它有点特殊待遇,Service可以从一个全局固定的地方直接去拿Proxy或者Manager,而不用像Client那样通过查询来获取Proxy/Manager。拿到了客户端代理,具体注册的通信过程如上文所讲,不再重复。到这里为止,Service就成功注册到了ContextManager中。
 
客户端Client初始化Manager时,manager也像刚才的Service,直接从某个固定的地方拿到ContextManager的代理,通过代理,去查询ContextManager,获取一个“提供所要服务的代理对象”。manager有了这个对象,Client就可以通过manager来使用服务了,调用逻辑如图:
 
当自己来实现Client和Service时,Client如何获取Proxy代理对象?
先讲一下实现方式:一般我们会在App中通过Service组件的方式来创建一个服务。其它App通过BindService的方式连接到Service,通过onServiceConnected回调就能获取Proxy代理对象。具体实现可参考:http://blog.csdn.net/singwhatiwanna/article/details/17041691
 

总结

本文简要介绍了Binder跨进程通信机制的逻辑,希望能帮助初学Binder的同学快速入门,提交学习效率。文中使用的图片以及讲解思路,来自于这个文档:

http://events.linuxfoundation.org/images/stories/slides/abs2013_gargentas.pdf,加进去一些笔者自己的思考和总结。一些地方如果有错误,欢迎指正交流。

另外推荐一篇binder入门的文章:http://weishu.me/2016/01/12/binder-index-for-newer/

Android Binder机制介绍的更多相关文章

  1. android binder机制之——(创建binder服务)

      Binder机制编程 前面的几篇文章具体介绍了android中binder机制的方方面面,相信你对binder机制已经有了较深刻的理解.俗话说得好"学以致用",以下我们就通过在 ...

  2. 【转】Android - Binder机制

    以下几篇文章是分析binder机制里讲得还算清楚的 目录 1. Android - Binder机制 - ServiceManager 2. Android - Binder机制 - 普通servic ...

  3. Android Binder机制彻底梳理二

    根据AIDL了解整体调用流程[重点分析AIDL流程]: 在上一次https://www.cnblogs.com/webor2006/p/11741743.html中我们已经对Android Binde ...

  4. Android Binder机制简单了解

    Binder -- 一种进程间通信(IPC)机制, 基于OpenBinder来实现 毫无疑问, 老罗的文章是不得不看的 Android进程间通信(IPC)机制Binder简要介绍和学习计划 浅谈Ser ...

  5. ANDROID BINDER机制浅析

    Binder是Android上一种IPC机制,重要且较难理解.由于Linux上标准IPC在灵活和可靠性存在一定不足,Google基于OpenBinder的设计和构想实现了Binder. 本文只简单介绍 ...

  6. Android Binder机制(一) Binder的设计和框架

    这是关于Android中Binder机制的一系列纯技术贴.花了一个多礼拜的时间,才终于将其整理完毕.行文于此,以做记录:也是将自己所得与大家分享.和以往一样,介绍Binder时,先讲解框架,然后再从设 ...

  7. Android Binder机制彻底梳理一

    Binder架构图: 先来瞅一下它的整体架构图: 其中粉红部分是上层的Binder,而蓝色的则是下层的Binder,很显然上层的是依赖于下层的. 什么是Binder[有个大概了解]? 这里从几个层面来 ...

  8. 理解 Android Binder 机制(一):驱动篇

    Binder的实现是比较复杂的,想要完全弄明白是怎么一回事,并不是一件容易的事情. 这里面牵涉到好几个层次,每一层都有一些模块和机制需要理解.这部分内容预计会分为三篇文章来讲解.本文是第一篇,首先会对 ...

  9. 浅谈android binder机制

    binder机制 是谷歌优化在android上更适合终端的IPC(多进程通信方式),满足系统对通信方式,传输性能和安全性的要求. 特性: 1. 用驱动程序来推进进程间的通信.2. 通过共享内存来提高性 ...

随机推荐

  1. 【EmguCV视频教程】VS2017+EmguCV3.4(C# OpenCV)高清入门视频教程

    视频采用VS2017 + EmguCV3.4版本录制,内容类似本人的Python和C++版本,如果需要的朋友可加我咨询,视频共40讲,从按照到读取显示图片,图形预处理,边缘检测,形态学,角点检测,轮廓 ...

  2. CMMS系统中的物联监测

    有条件的设备物联后,可时实查看设备运行状态,如发现异常,可提前干预.

  3. Kruskal算法求最小生成树 笔记与思路整理

    整理一下前一段时间的最小生成树的算法.(其实是刚弄明白 Kruskal其实算是一种贪心算法.先将边按权值排序,每次选一条没选过的权值最小边加入树,若加入后成环就跳过. 先贴张图做个示例. (可视化均来 ...

  4. MIT线性代数:6.列向量和零空间

  5. 使用position设置经典的网站前端结构

    能脱离文档流的设置: float:left/right position:absolute; 绝对定位 position:fixed; 固定定位 //搞清楚position的属性值的意思就容易明白 使 ...

  6. [考试反思]1023csp-s模拟测试84:精妙

    一套很奇怪的题.单调性+神仙dp/搜索+随机化. 但是说实在的,思路都很不错. 考场上显然乱搞没什么好说的. 虽说T2剪枝打错变量名掉了20分... T1:Smooth 暴力各有不同,最暴力的想法就是 ...

  7. [考试反思]0828NOIP模拟测试32:沉底

    ,,190,180,170,170... 倒数第6,75. 啊...再这么下去要失去理想了... 开学翘课停课以来的第一场考试,就考成这鬼模样. 本来还可以凭借那几次高分苟在公共卷总分的第2,这一场直 ...

  8. 爬虫学习--常用的正则表达式 Day3

    在做爬虫经常遇到需要用正则校验数据时候,往往是在网上去找很久,结果找来的还是不很符合要求.所以我最近把开发中常用的一些正则表达式整理了一下,给自己留个底,也给朋友们做个参考. 一.校验数字的表达式 1 ...

  9. Vue基础系列(四)——Vue中的指令(上)

    写在前面的话: 文章是个人学习过程中的总结,为方便以后回头在学习. 文章中会参考官方文档和其他的一些文章,示例均为亲自编写和实践,若有写的不对的地方欢迎大家和我一起交流. VUE基础系列目录 < ...

  10. java中的线程安全

    在Java中,线程的安全实际上指的是内存的安全,这是由操作系统决定的. 目前主流的操作系统都是多任务的,即多个进程同时运行.为了保证安全,每个进程只能访问分配给自己的内存空间,而不能访问别的.分配给别 ...