Binder机制:拷贝一次,通过open, mmap, ioctl在dev/binder上实现的。

Client, Service, Service Manager三者之间的通信都是基于上面机制。

Service死亡接收通知:Service组件所在的进程可能会意外崩溃,Client在它所引用的Service组件死亡时获得通知。

Binder中的红黑树:在Binder驱动程序中,宿主进程通过一个binder_proc结构体来描述。宿主进程使用一个红黑树来维护它内部所有的Binder实体对象。

内核缓冲区:结构体binder_buffer用来描述一个内核缓冲区,是用来在进程间传输数据的。每个使用Binder进程间通信机制的进程在Binder驱动程序中都有一个内核缓冲区列表,用来保存Binder驱动为它所分配的内核缓冲区。

 

Binder 设备底层工作机制

Binder 驱动程序在目标设备上创建了一个Binder设备文件/dev/binder,这个设备文件的操作方法有:binder_open, binder_mmap, binder_ioctl

  1. Binder设备文件打开过程
    在目标设备上的/proc/binder/proc目录下创建一个以进程ID为名称的只读文件,并且以函数binder_read_proc_proc作为它的文件内容读取函数。通过读取文件/proc/binder/proc/<PID>的内容,我们就可以获得进程PID的Binder线程池,Binder实体对象,Binder引用对象,以及内核缓冲区等信息。
  2. Binder设备文件的内存映射过程
    一个使用Binder进程间通信机制的进程只有将Binder设备文件映射到自己的地址空间,Binder驱动程序才能够为它分配内核缓冲区,以便可以用来传输进程间数据。

    Android Binder机制学习笔记-LMLPHP

    Binder驱动程序为进程分配的内核缓冲区即为一系列物理页面,它们分别被映射到进程的用户地址空间和内核空间。当Binder驱动程序需要将一块数据传输给一个进程时,它就可以先把这块数据保存在为该进程所分配的一块内核缓冲区中,然后再把这块内核缓冲区的用户空间地址告诉进程,最后进程就可以访问到里面的数据了。好处:不需要将数据从内核空间拷贝到用户空间,提高了数据传输效率。

 

Binder 进程间通信库

 

Android 系统在应用程序框架层中将各种Binder驱动程序操作封装成一个Binder库。Service组件和Client组件分别使用BnInterface和BpInterface来描述(n代表native, p代表proxy),分别对应于Binder驱动程序中的Binder实体对象和Binder引用对象。

 

// 书中P188有一个应用实例帮助理解通信机制

Binder 对象引用计数技术:

Android Binder机制学习笔记-LMLPHP

Client 进程和Server进程的一次通信过程涉及四种类型对象:

Binder驱动中的Binder实体对象binder_node和Binder引用对象binder_ref,以及位于Binder库中的Binder本地对象BBinder和Binder代理对象BpBinder。

 

交互过程:

  1. 运行在Client进程中的Binder代理对象通过Binder驱动程序向运行在Server进程中的Binder本地对象发出一个进程间通信请求,Binder驱动程序就根据Client进程传递过来的Binder代理对象的句柄值找到对应的Binder引用对象。
  2. Binder驱动程序根据前面找到的Binder引用对象找到对应的Binder实体对象,并且创建一个事务binder_transaction来描述进程间通信过程。
  3. Binder驱动根据前面找到的实体对象来找到运行在Server进程中的Binder本地对象,并且将Client进程传递过来的通信数据发送给它处理。
  4. Binder本地对象处理完成Client进程的通信请求之后,就将通信结果返回给Binder驱动程序,Binder驱动程序接着就找到前面所创建的一个事务。
  5. Binder驱动程序根据前面找到的事务的相关属性找到发出通信的Client进程,并且通知Client进程将通信结果返回给对应的Binder代理对象处理。

 

 

Service Manager的启动过程

 

SM 是Binder进程间通信机制上下文管理者,同时负责管理系统中的Service组件,并且向Client组件提供获取Service代理对象的服务。

 

SM 运行在独立的进程中,因此,Service组件和Client组件也需要通过进程间通信机制来和它交互。

 

SM 是由init进程负责启动的,init进程是在系统启动时启动的,因此,SM 也是在启动时启动的。启动步骤:一,调用函数binder_open打开设备文件/dev/binder,以及将它映射到本进程的地址空间;二,调用函数binder_become_context_manager将自己注册为Binder进程间通信机制的上下文管理者;三,调用函数binder_loop来循环等待和处理Client进程的通信请求

 

 

Service Manager代理对象的获取过程

 

Service 组件在启动时,需要将自己注册到SM中,而Client组件在使用Service组件提供的服务之前,也需要通过SM来获得Service组件的代理对象。SM本身也是一个Service组件,但它的获取过程与其它的Service代理对象的获取有所不同。

Android Binder机制学习笔记-LMLPHP

对于一般的Service组件来说,Client进程首先要通过Binder驱动程序来获得它的一个句柄值,然后才可以根据这个句柄创建一个Binder代理对象,最后将这个Binder代理对象封装成一个实现了特定接口的代理对象。由于SM的句柄值恒为0,因此,获取它的一个代理对象的过程就省去了与Binder驱动程序交互的过程。

 

有了SM代理对象之后,Service组件就可以在启动时使用它的成员函数addService将自己注册到SM中,而Client组件就可以使用它的成员函数getService来获得一个指定名称的Service组件的代理对象。

 

Android系统在应用程序框架层的Binder库中提供了一个函数defaultServiceManager来获得一个SM代理对象。

 

 

Binder进程间通信机制的Java接口

 

Android 系统在应用程序框架层中提供了Binder进程间通信机制的Java接口,它们通过JNI方法来调用Binder库的C/C++接口,从而提供了执行Binder进程间通信的能力。

 

  1. SM的Java代理对象的获取过程
    在Java层中,SM的Java代理对象类型是ServiceManagerProxy,它实现了IServiceManager接口。
     SM的Java代理对象内部有一个成员变量mRemote,它的类型为IBinder,实际上指向的是一个BinderProxy对象,BinderProxy用来描述一个Java服务代理对象,实现了IBinder接口,BinderProxy内部有一个类型为int的成员变量mObject,它指向C++层中的一个Binder代理对象。这样就可以将一个Java服务代理对象和C++层中的一个Binder代理对象关联起来,即可通过C++层中的Binder代理对象来实现Java服务代理对象的功能。
  2. 在Java 层中,SM的Java代理对象是由SM类来负责创建的。 

    Android Binder机制学习笔记-LMLPHP  
    Android Binder机制学习笔记-LMLPHP

    Android Binder机制学习笔记-LMLPHP

asInterface将句柄值为0的Java服务代理对象封装成一个SM的Java代理对象。 getIServiceManager将获得的ServiceManager的Java 代理对象保存在静态成员变量中,最后将它的IServiceManager接口返回给调用者。

 

 

Java服务接口的定义和解析

 

定义服务接口:在实现Java服务之前,首先定义服务接口。Android使用AIDL来定义服务接口。

 

在编译文件“服务接口.aidl”时,编译系统会生成一个中间文件“服务接口.java”。它包含一个Java接口,一个Java抽象类,和一个Java类。(例如,IFregService, IFregService.Stub, IFregService.Stub.Proxy)。Stub和Proxy都实现了IFregService接口,其中Stub类用来描述一个Java服务,而Proxy类用来描述一个Java服务代理对象

 

步骤:

  1. Java 服务接口定义
  2. Java 服务启动
  3. Java 服务代理对象获取
  4. Java 服务对象调用

 

10-05 18:56