Android的IPC机制-Binder

主要问题:

进程间通信是什么?

Linux下进程之间如何通信?

Android中进程间通信采用什么方式?

Android为什么要引入Binder机制?

Binder机制包括哪些部分?

Binder的工作原理是什么?

如何实现Binder驱动?

如何使用Binder机制来完成进程间通信?

Android的多媒体服务MediaService如何工作?

如何实现自己的核心服务?

 

在Linux系统中,是以进程为单位分配和管理资源的,出于保护机制,一个进程不能直接访问另一个进程的资源,也就是说,进程之间相互封闭。但是在一个复杂的应用系统中,通过常会使用多个相关的进程来共同完成一项任务,因此要求进程之间必须能够互相通信,从而共享资源和信息。所有操作系统内核必须提供进程间的通信机制。在linux中,进程间的通信机制有很多种,例如可以采用管道、消息队列、信号、共享内存、socket等方式。但是,在Android终端上几乎看不到这些IPC通信方式,取而代之的是Binder的方式。Android同时为Java环境 和C/C++环境提供了Binder机制。本章主要介绍C/C++环境下的Binder机制,主要包括Binder驱动的实现、运作原理、IPC机制的实现、接口等。

 

3.1Binder概述

应用程序虽然是以独立的进程来运行,但相互之间还是需要通信,比如,在多进程的环境下,应用程序和后台服务通常会运行在不同的进程中,有着独立的地址空间,但是因为需要相互协作,彼此间又必须进程通信和数据共享,这就需要进程通信来完成。Linux系统中,进程间通信的方式有socket、named pipe、message queue、signal、share memory等;Java系统中的进程间通信反射也有socket、named price等。所以Android可以选择的进程间通信的方式也有很多,但是它主要包括以下几种方式:

1.编制Linux Kernel IPC接口

2.标准D-BUS接口

3.Binder接口

 

3.1.1为什么选择Binder

在上面这些可供选择的方式中,Android使用得最多也最被认可的还是Binder机制。为什么会选择Binder来作为进程之间的通信机制呢?因为Binder更加简洁。和快速,消耗的内存资源更小吗?不错,这些也正是Binder的优点。

1.用驱动程序来推进进程间的通信。

2.通过共享内存来提高性能。

3.为进程请求分配每个进程的线程池

4.针对系统中的对象引入了引用计数和跨进程的对象引用映射。

5.进程间同步调用

 

3.1.2初识Binder

Binder是通过Linux的Binder Driver来实现的,Binder操作类似于线程迁移,两个进程间通信看起来就像是一个进程进入另一个进程去执行代码,然后带着结果返回。Binder的用户空间为每一个进程维护着一个可用的线程池。线程池用于处理到来的IPC以及执行进程的本地消息,Binder通信是同步的而不是异步的。同时,Binder机制是基于OpenBindr来实现的,是一个OpenBinder的Linux实现,Android 系统的运行都将依赖Binder驱动。

Binder通信也是基于Service与Client的,所有需要IBinder通信的进程都必须创建一个IBinder接口。系统有一个名为Service Manager的守护进程管理者系统中的各个服务,它负责监听是否有其他程序向其发送请求,如果有请求就响应,如果没有则继续监听等待。每个都要在Service Manager中注册,而请求服务的客户端则向Service Manager请求服务。在Android虚拟机启动前,系统会先启动Service Manager进程,Service Manager就会打开Binder驱动,并通知Binder kernel驱动程序,这个进程将作为System Service Manager就会打开Binder驱动,并通知Binder Kernel驱动程序,这个进程将作为System Service Manger,然后该进程将进入一个序号,等待处理来自其他进程的数据。

因此,我们也可以将Binder的实现大致分为:Binder驱动、Service、Manger、Service、Client这几个部分,下面将分别对这几个部分基础详细分析。

3.2Binder驱动的原理和实现

通过上一节的介绍,大家应该对Binder有了基本的认识了,任何上层应用程序接口和用户操作都需要底层硬件设备驱动的支持,并为其提供各种操作接口。本节首先从Binder的驱动实现入手,分析其原理和它提供给用层使用的接口。

3.2.1Binder驱动的原理

为了完成进程间通信,Binder采用了AIDL来描述进程间的接口。在实际的实现中,Binder是作为一个特殊的字符设备而存在的,设备节点为/dev/binder。

在其驱动实现过程中,主要是通过binder_ioctl函数与用户空间的进程交换数据。BINDER_WRITE_READ用来读写数据,数据包中有一个cmd域用于区分不同的请求。binder_thread_write函数用于发送请或者返回结果,而binder_thread_read函数则用于读取结果。

在binder_thread_write函数中调用binder_transaction函数来转发请求并返回结果。当收到请求时,binder_transaction函数会通过对象的handle找到对象所在的进程,如果handle为空,就认为对象是context_mgr,把请求发给context_mgr所在的进程。请求中所有的Binder对象全部放到RB树中,最后把请求放到目标进程队列中,等待目标进程读取。数据的解析工作放在binder_parse()中实现;关于如何生成context_mgr,内核中提供了BINDER_SET_CONTEXT_MGR命令来完成此项功能。

 

3.2.2Binder驱动的实现

上面我们已经对Binder驱动的原理进行了分析,在开始分析驱动的实现之前,我们还是通过一个例子来说明Binder在实际应用中应该如何运用,以及它能帮我们解决什么样的问题。举个例子:

A进程如果要使用B进程的服务,B进程首先要注册此服务,A进程通过Binder获取该服务的handle,通过这个handle,A进程就可以使用该服务了。之外,你可以把handle理解成地址。A进程使用B进程的服务还意味者二者遵循相同的协议,这个协议反映在代码上就是二者要实现IBinder接口。

1.“对象”与“引用”

Binder不仅是Android系统中的一个完整的IPC机制,它也可以被当作Android系统的一种RPC机制,因为Binder的功能就是在本地“执行”其他进程的功能。因此,进程在通过Binder获取将要调用的进程服务时,可以是一个本地对象,也可以是一个远程服务的“引用”。

Binder不仅可以与本地进程通信,还可以与远程进程通信。这里的本地进程就是我们所说的本地对象,而远程进程则是我们所说的远程服务的一个“引用”

Binder的实质就是要把对象从一个进程映射到另一个进程中,而不管这个对象是本地的还是远程的。如果是本地对象,更好理解;如果是远程对象,就按照我们上面所讲的来理解,即将远程对象“引用”从一个进程映射到另一个进程中,于是当使用这个远程对象时,实际上就是使用远程对象在本地的一个“引用”,类似于把这个远程对象当作一个本地对象在使用。这也是Binder和其他IPC机制不同的地方。

这个本地“对象”与远程 对象的“引用”有什么不同呢?本地“对象”表示本地进程的地址空间的一个地址,而远程对象引用则是一个抽象的32位句柄。它们之间是互斥的:所有的进程本地对象都是本地的一个地址,所有的远程进程的对象的“引用”都是一个句柄。对于发送者来说,不管是“对象”还是引用,他都会认为被发送的Binder对象是一个远程对象的句柄。但是,当Binder对象的数据被发送到远程端接收进程时,远程接收进程则会任务该Binder对象是一个本地对象地址。

2.binder_work

这个是最简单也是最基础的结构体binder_work

struct binder_work{

struct list_head entry;

enum{

}

}

 

其中entry被定义为list_head,用来实现一个双向链表,存储所有binder_work的队列;此外,还包含一个enum类型的type,binder_work的类型,后文会对这些类型进行详细分解。

 

3.Binder的类型

Binder的类型是使用定义在在binder.h头文件中的一个enum来表示,从代码上看却是3个不同的大类,它们分别是:本地对象(BINDER_TYPE_BINDER、BINDER_TYPE_BINDER)、远程对象(BINDER_TYPE_HANDLE、BINDER_TYPE_WEAK_HANDLE)、文件(BINDER_TYPE_FD)如果传递的是文件类型,其实还是会将文件映射到句柄上,根据此fd找到对应的文件,然后在目标进程中分配一个fd,最后把这个fd赋值给返回的句柄。

4.Binder对象

我们把进程之间的传递的数据称之为Binder对象,他在对应源码中使用flat_binder_object结构题表示。

struct flat_binder_object{

unsigned long type;

unsigned long flags;

union{

void binder;

signed long handle;

}

void *cookie;

};

该结构体中的type字段描述的是Binder的类型,传输的数据是一个复用数据联合体。对于Binder类型,数据就是一个Binder本地对象;HANDLE类型

posted @ 2021-12-13 18:10  周千  阅读(252)  评论(0编辑  收藏  举报