纪伯伦说:“你没法同时拥有青春和关于青春的知识;由于青春忙于生计,没有余暇去求知;而知识忙于寻求自我,没法享受生活。”android
跑去图书馆自习了一天,看了一天Binder,效率仍是蛮高的。特别推荐,同时想在之后每篇博文写几句文艺或者鸡汤或者高逼格的话,提升各种姿式水平吧。回到正题,讲讲Binder,我将从为何要有Binder,Binder的底层实现,而后经过一个客户端调用服务进程的整个过程来进一步阐述其做用。git
进程间通讯,嗯?而后你就想知道这些??进程间通讯为何要借助一个中间件,直接不能够吗?
来看下Linux内核空间和用户空间,再慢慢的谈谈为何?这里要先从Linux下的内存空间划分来说起了。github
Linux中,给每一个用户进程的空间是4个G,内核一个G,固然这是虚拟的内存,也就是不足的地方是借助于硬盘来实现虚拟,对于用户进程,用户进程空间是不能够共享的,可是对于内核空间彼此之间是能够共享的,用户空间不能够共享,所以两个进程之间进行通讯就会有问题了,因此在通讯上要借助于内核空间来进行通讯。引出来内核了,经过内核进行通讯,具体如何进行呢?若是让你来设计你会怎么设计呢?
跟每个进程划分一块区域,而后每一个进程对其内存进行loop,有消息后做出反馈将内容发送至对方的内存中,而后。。。感受优雅吗?可是对于中间部分怎么寻找,如何定位,内存不多是事先划分好,动态划分了,进程间如何知道彼此的内存中的地址,这是一个问题,中间的数据如何进行传递,等等问题。算法
再考虑一个问题,什么样的进程间须要通讯,不难发现,须要进行通讯的进程通常是可见或不可见进程和服务进程之间进行的通讯,因此咱们须要去找服务进程,而后和它通讯,先看一个例子,当咱们在手机中经过进度条调节手机音量的时候。函数
如今你能够对Binder有一个这样的认识,经过它能够进行进程间通讯,固然Binder是Android在基于Linux上进行一个IPC的新方式,虽为新方式,也不过是在基于共享内存上进行了更进一步的封装和优化,并且其不只仅是进行IPC,还能够RPC,即为远程调用,在进程A中能够像调用本身的函数同样,调用进程B的函数。oop
既然是借助于内核空间的一块内存,既然要进行通讯,彼此之间有数据交流,有哪些数据呢?要找到该进程,而后要让该进程知道本身调用的方法,而后还要将结果传递回来,
IPC数据
Handle即为所要寻找的服务的编号,RPC数据,即为咱们在调用函数的时候所要传递的参数,RPC代码即为咱们的调用代码,Binder协议,也就是咱们在和内存进行交互的时候,告知其咱们是要接收仍是要发送,而后内核空间给对于Binder管理的这块区域起了个什么名字呢?Binder Driver,经过其对Binder进行管理。如今咱们对于进程间通讯有了更进一步的理解。Binder Driver的生成则是在init进程中建立。
如今咱们要更深刻一步来了解这个过程的具体细节了,由于本篇主要是对这个机制进行一个概述,因此不许备经过代码细节来对该过程进行一个细节化的描述。只讲述整个流程。优化
前面提到了,进程间的通讯通常是在和服务进程进行通讯,如今个人一个进程和某个服务进程进行通讯,那么我给出服务名便可,而后系统如何根据这个服务名找到服务,而后调用服务的相关方法,而后再将结果返回呢?来看看Android中是如何实现的。
回顾上一篇文章中讲述的Android启动流程中,讲到的一个Context Manager进程,这个进程在全部的Service启动以前启动,而后全部的服务进程须要向其进行注册,那么又牵扯到一个问题,既然Context Manager也是一个进程,其它进程向其进行注册时候不是也须要进程间通讯了,先从Context Manager来看。spa
Context Manager和其它的Android服务不一样,采用C语言编写,为了方便和Binder进行紧密衔接,Context Manager,首先打开Binder Driver,而后在内存中建立一块内存,用来接收一写IPC数据,在内存中建立一个Binder节点,将本身置为0号节点,而后对本身的内存区域进行轮询,当接收到数据的时候,对其中的数据进行解析,而后根据相应的协议执行相应的操做。Context Manager的主要做用是服务注册和服务检索。它给每个服务分配了一个称为Handle的编号。这个过程讲的比较粗了。设计
Context Manager在mediaserver和system_server以前运行,每当有service server来注册服务的时候,Context Manager会把服务的名称和该服务在Binder Driver 中分配的Binder节点编号注册到自身服务目录中。Service程序以IPC应答数据的形式结束Context Manager服务目录中的服务名称,而后输出咱们所看到的一系列的服务。server
调用binder_open函数,引发open和mmap的调用,调用open打开Binder Driver,而调用mmap则生成结束IPC数据的Buffer,系统给予其128k的大小用来接收IPC数据。其具体代码实现,则是经过一个结构体来记录,而后存放了该块内存的引用。
Context Manager在访问Binder Driver,将自身的Binder节点设置为0号节点。
调用loop函数,来轮询检测Binder,接收IPC数据,当出现IPC数据后,调用binder_parse,来解析IPC数据。
由于Context Manager的两个主要做用是服务的检索和服务的注册,因此接收到的IPC数据也就是用来作这两件事情的。
服务检索:经过RPC数据中传递的服务名称,从do_find_service()函数自身的服务列表中获取带有指定名称的服务编号,然后经过bio_put_ref()函数来生成binder_object结构体,该结构体被包含到IPC引导数据的RPC数据中,而后调用binder_send_reply()函数,将数据传递给Binder Driver.
服务注册:当解析出为服务注册的时候,调用do_add_service()函数,将IPC数据的RPC数据包含的服务名称和Binder节点编号注册到自身的服务目录中,而后调用binder_send_reply,将IPC应答数据传递给Binder Driver。
咱们对于服务的注册和检索,又有了更进一步的了解了,如今咱们要更深刻一些。跟具体一些。
当Service Server向Context Manager注册自身的服务时,Binder Driver会进行Binder Addressing。Binder Driver会首先找到Handle值为0的Binder节点,Handle值为0的Binder节点为Context Manager,而后Binder Driver会生成一个Binder节点,用来表示前来注册的服务,接下来生成Binder引用数据,以便Context Manager识别所生成的Binder节点,并将其关联起来,根据生成顺序,引用数据会被编号,而后将编号插入到IPC数据,传递给Context Manager,Context Manager会根据服务名称将Binder节点进行关联,这样咱们服务注册过程便完成了。
首先是Handle值为0的IPC数据通过Binder Driver传递至Context Manager,Context Manager根据服务编号查找对应的引用数据,而后在服务客户端生成引用数据,并将其和ConText Manager的引用数据所指向的Binder节点链接起来,链接后的Binder节点和Service Server自身服务的Binder节点相对应,Binder Driver将根据生成顺序为引用数据编号,并传递给服务客户端,服务端将引用数据编号保存到Handle中,把与服务相关的RPC代码,RPC函数包含进IPC数据中,发送给Service Sever。而后Service server在和其进行数据交互。
经过上述两个步骤咱们实现了本地客户端经过Binder对于服务的调用。经过上述,你对Binder会有了一个初步的了解和大致上对整个过程有了一个面貌。接下来将写一篇关于android 生成apk过程和apk安装过程。
本人如今每日一道算法题的Github地址。
https://github.com/Jensenczx/CodeEveryday附带OJ地址和本人的代码