You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
5.2 KiB
85 lines
5.2 KiB
---
|
|
Binder 进程间通信库
|
|
---
|
|
|
|
Android 系统在应用程序框架层中将各种 Binder 驱动程序操作封装成了一个 Binder 库,这样进程就可以以方便的调用 Binder 库提供的接口来实现进程间通信。
|
|
|
|
在 Binder 库中,Service 组件和 Client 组件分别使用模版类 BnInterface 和 BpInterface 来描述,其中,前者称为 Binder 本地对象,后者称为 Binder 代理对象。Binder 库中的 Binder 本地对象和 Binder 代理对象分别对应于 Binder 驱动程序中的 Binder 实体对象和 Binder 引用对象。
|
|
|
|
模板类 BnInterface 继承了 BBinder 类,后者为 Binder 本地对象提供了抽象的进程间通信接口,它的定义如下:
|
|
|
|
```c++
|
|
class BBinder : public IBinder
|
|
{
|
|
public:
|
|
virtual status_t transact(...);
|
|
protected:
|
|
virtual status_t onTransact(...);
|
|
}
|
|
```
|
|
|
|
BBinder 类有两个重要的成员函数 transact 和 onTransact。当一个 Binder 代理对象通过 Binder 驱动程序向一个 Binder 本地对象发出一个进程间通信请求时,Binder 驱动程序就会调用该 Binder 本地对象的成员函数 transact 来处理该请求。成员函数 onTransact 是由 BBinder 的子类,即 Binder 本地对象类来实现的,它负责分发与业务相关的进程间通信请求。事实上,与业务相关的进程间通信请求是由 Binder 本地对象类的子类,即 Service 组件类来负责处理的。
|
|
|
|
模版类 BpInterface 继承了 BpRefBase 类,后者为 Binder 代理对象提供了抽象的进程间通信接口,它的定义如下所示:
|
|
|
|
```c++
|
|
class BpRefBase: public virtual RefBase
|
|
{
|
|
inline IBinder* remote() { return mRemote; }
|
|
|
|
private:
|
|
IBinder* const mRemote;
|
|
}
|
|
```
|
|
|
|
BpRefBase 类有一个重要的成员变量 mRemote,它指向一个 BpBinder 对象,可以通过成员函数 remote 来获取。BpBinder 类实现了 BpRefBase 类的进程间通信接口,它的定义如下所示:
|
|
|
|
```c++
|
|
class BpBinder: public IBinder
|
|
{
|
|
public:
|
|
BpBinder(int32_t handle);
|
|
transact(...);
|
|
private:
|
|
const int32_t mHandle;
|
|
}
|
|
```
|
|
|
|
BpBinder 类的成员变量 mHandle 是一个整数,它表示一个 Client 组件的句柄值,在前面介绍结构体 binder_ref 时提到,每一个 Client 组件在 Binder 驱动程序中都对应有一个 Binder 引用对象,而每一个 Binder 引用对象都有一个句柄值。其中,Client 组件就是通过这个句柄值来和 Binder 驱动程序中的 Binder 引用对象建立对应关系的。
|
|
|
|
BpBinder 类的成员函数 transact 用来向运行在 Server 进程中的 Service 组件发送进程间通信请求,这是通过 Binder 驱动程序间接实现的。BpBinder 类的成员函数 transact 会把 BpBinder 类的成员变量 mHandle,以及进程间通信数据发送给 Binder 驱动程序,这样 Binder 驱动程序就能够根据这个句柄值来找到对应的 Binder 引用对象,继而找到对应的 Binder 实体对象,最后就可以将进程间通信数据发送给对应的 Service 组件了。
|
|
|
|
无论是 BBinder 类,还是 BpBinder 类,它们都是通过 IPCThreadState 类来和 Binder 驱动程序交互的。IPCThreadState 类的定义如下所示:
|
|
|
|
```c++
|
|
class IPCThreadState
|
|
{
|
|
public:
|
|
static IPCThreadState* self();
|
|
status_t transact(...);
|
|
private:
|
|
status_t talkWithDriver();
|
|
const sp<ProcessState> mProcess;
|
|
}
|
|
```
|
|
|
|
在前面介绍结构体 binder_proc 时提到,每一个使用了 Binder 进程间通信机制的进程都有一个 Binder 线程池,用来处理进程间通信请求。对于每一个 Binder 线程来说,它的内部都有一个 IPCThreadState 对象,我们可以通过 IPCThreadState 类的静态成员函数 self 来获取,并且调用它的成员函数 transact 来和 Binder 驱动程序交互。在 transact 函数内部,与 Binder 驱动程序的交互操作又是通过调用成员函数 talkWithDriver 来实现的,它一方面负责向 Binder 驱动程序发送进程间通信请求,另一方面又负责接收来自 Binder 驱动程序的进程间通信请求。
|
|
|
|
IPCThreadState 类有一个成员变量 mProcess,它指向一个 ProcessState 对象。对于每一个使用了 Binder 进程间通信机制的进程来说,它的内部都有一个 ProcessState 对象,它负责初始化 Binder 设备,即打开设备文件 /dev/binder,以及将设备文件 /dev/binder 映射到进程的地址空间。由于这个 ProcessState 对象在进程范围内是唯一的,因此,Binder 线程池中的每一个线程都可以通过它来和 Binder 驱动程序建立连接。
|
|
|
|
ProcessState 类的定义如下所示:
|
|
|
|
```c++
|
|
class ProcessState: public virtual RefBase
|
|
{
|
|
public:
|
|
static sp<ProcessState> self();
|
|
private:
|
|
int mDriverFD;
|
|
void* mVMStart;
|
|
}
|
|
```
|
|
|
|
进程中的 ProcessState 对象可以通过 ProcessState 类的静态成员函数 self 来获取。第一次调用 self 时,Binder 库就会为进程创建一个 ProcessState 对象,并且调用函数 open 来打开设备文件 /dev/binder,接着又调用函数 mmap 将它映射到进程的地址空间,即请求 Binder 驱动程序为进程分配内核缓冲区。设备文件 /dev/binder 映射到进程的地址空间后,得到的内核缓冲区的用户地址就保在其成员变量 mVMStart 中。
|
|
|
|
至此,Binder 库的基础知识就介绍完了。 |