Binder是一种Android实现的IPC,用于进程间通信。
通常Linux系统提供好几种进程间通信的方式,比如
1) Message Queue :把进程之间通信用的message保存到内核中或者从内核中读取的方式。
2) Shared Memory:进程间指定共享的内存,把需要传输的内容保存到相应的内存的方式
3) Socket:
Android中选择Binder为主要的IPC方式,因为Binder比其他的IPC方式有更加简洁快速,消耗内存更小等优点。
下面来看一下Framework层Java空间都是怎么用Binder实现进程间通信的。
Binder实际是一种C/S模式的工作方式,客户端通过Binde向服务端发出请求,服务端再通过Binder返回相应的内容给服务端。Binder的工作流程如下:
1)客户首先获得服务端的代理对象。所谓代理对象就是客户端建立一个服务端的”引用”,该代理对象具有服务端的功能,使其在客户端访问服务端的方法就像访问本地方法一样。
2)客户端通过调用服务器代理对象的方法,向服务器端发送请求
3)代理对象通过Binder驱动将用户请求发送给服务器端
4)服务器端处理客户端请求,并通过Binder驱动将处理结果返回给客户端
5)客户端收到服务器端的返回结果
这里说的服务端为:BBinder 服务端代理对象为:BpBinder
还需要说一下IBinder接口。这个接口是对跨进程对象的抽象,在C/C++和Java都有定义。IBinder定义了一套使用Binder机制来实现客户程序与服务器的通信协议。
一个对象只能在当前进程中被访问,如果希望它能被其他进程访问,就必须实现IBinder接口。IBinder接口可以指向本地对象,也可以指向远程对象。关键在与IBinder接口中的transact函数。如果IBinder指向服务端代理,那transact负责把请求发送给服务器;如果IBinder指向的是一个服务端,那么transact只负责提供服务。因此不管是服务端还是服务端代理对象,都必须实现该接口,这样才能进行Binder通信。
C/C++中BBinder和BpBinder都是继承了IBinder接口的类。
所以实现Binder就很简单,服务器端继承BBinder并实现onTransact函数,客户端继承BpBinder实现transact函数即可。
以MediaPlayerService为例,在Stagefright.cpp文件的main函数中有如下代码
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service =
interface_cast<IMediaPlayerService>(binder);
sp<IOMX> omx = service->getOMX();
这里getOMX函数是BpMediaPlayerService类中的函数,这个很容易看的出来。
定义如下:
virtual sp<IOMX> getOMX() {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
remote()->transact(GET_OMX, data, &reply); //调用tranact函数发送Binder请求
return interface_cast<IOMX>(reply.readStrongBinder());
}
上述的Binder请求会最终发给服务器端,也就是BnMediaPlayerService类的onTransact函数中
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
...
case GET_OMX: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IOMX> omx = getOMX();
reply->writeStrongBinder(omx->asBinder());
return NO_ERROR;
} break;
...
}
}
最终getOMX函数就是调用继承了BnMediaPlayerService类的MediaPlayerService类中的getOMX函数
sp<IOMX> MediaPlayerService::getOMX() {
Mutex::Autolock autoLock(mLock);
if (mOMX.get() == NULL) {
mOMX = new OMX;
}
return mOMX;
}
下面来看一下上述的过程是怎么通过Binder驱动来传递的,因为上面说的内容都没有涉及到打开,读写Binder驱动(/dev/binder)的内容。
要看service是怎么打开Binder驱动并实现,必须要从其初始化过程以及service的注册过程看起。
在系统开机的时候,init.rc里边有如下配置,负责启动mediaserver。
service media /system/bin/mediaserver
class main
user media
group system audio camera inet net_bt net_bt_admin net_bw_acct drmrpc sdcard_r shell mediadrm media_rw qcom_diag radio
ioprio rt 4
可以从Android.mk配置中找到,上面的service启动,入口函数是main_mediaserver.cpp文件中的main函数。
int main(int argc __unused, char** argv)
{
signal(SIGPIPE, SIG_IGN);
char value[PROPERTY_VALUE_MAX];
bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
pid_t childPid;
if (doLog && (childPid = fork()) != 0) {
//如果doLog为true,其父进程就会跑到这里,处理几个子进程的消息。这个不是重点,跳过!!
} else {
...
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
...
waitBeforeAdding(String16("media.player"));
MediaPlayerService::instantiate();
ALOGI("Add MediaPlayerService on mediaserver"); // SEC_PRODUCT_FEATURE_AUDIO_COMMON
...
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
}
来看一下上面几行代码的说明
1. sp<ProcessState> proc(ProcessState::self())
ProcessState没有初始化就初始化,已经初始化的话就把ProcessState的对象加一个sp。这里加sp的作用,
可以看Android中sp/wp的说明,这里就不再赘述。那ProcessState初始化都在干什么呢?
ProcessState::ProcessState()
: mDriverFD(open_driver()) //这里打开Binder驱动设备
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
//驱动设备的mmap!!!
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
2. sp<IServiceManager> sm = defaultServiceManager()
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
...
b = new BpBinder(handle);
//BpBinder为一个服务器代理客户端,handle(也就是mHandle)标识一个service。
//一个客户端在通过transact发送Binder消息给ServiceManager的时候会发送自己的handle。
//ServiceManager会根据这个handle来分发Binder消息给相应的服务端。
//handle为0是ServiceManager本身
//当然getService()找到相应的service不是通过handle,而是通过service名字
...
result = b;
}
BpBinder强制转换成IServiceManager??
3. MediaPlayerService::instantiate()
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService( //
String16("media.player"), new MediaPlayerService());
}
BpServiceManager::addService(){
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
//按理说应该是BnServiceManager::onTransact()函数接收!!!但其实是
//service_manager.c文件的函数接收处理
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
这里的remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply)按理说应该是传到
BnServiceManager::onTransact()函数来处理。但ServiceManager比较特殊。其实这个是传到
service_manager.c文件中去实现了
添加service的操作!!BnServiceManager为什么没有用呢??
4.ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool()
把相关的Server加到ServiceManger之后,Service会使用ProcessState::self()->startThreadPool()
启动一个线程(使用IPCThreadState::self()->joinThreadPool()),负责打开Binder驱动等待客户端发来消
息。下面的IPCThreadState::self()->joinThreadPool()本身也会打开一个Binder设备等待客户端消息。
看一下客户端发送Binder消息给对应的Service的流程以及Service接收到Binder消息之后的处理
1.在需要使用到Service完成功能的时候,需要按如下流程发送Binder消息
1) 需要从ServiceManager根据Service的名字,获取相应的Service(当然如果Service没有注册的话是获取不到
的)。
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
mOMX = service->getOMX();
2)打包数据只会通过remote()->transact发送数据
virtual sp<IOMX> getOMX() {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
remote()->transact(GET_OMX, data, &reply);
return interface_cast<IOMX>(reply.readStrongBinder());
}
2.具体看一下用来发送的am->transact()函数都在干什么
//am->transact()最终会调用到其父类的BpBinder::transact()函数
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
IPCThreadState::transact() {
IPCThreadState::writeTransactionData();
//负责数据的打包
/* //这里的cookie和handle负责找到指定的Service并调用相应的onTransact函数 //怎么通过cookie或者handle找到相应的onTranact函数呢???? tr.target.ptr = 0; tr.target.handle = handle; tr.code = code; tr.flags = binderFlags; tr.cookie = 0; tr.sender_pid = 0; tr.sender_euid = 0; */
IPCThreadState::waitForResponse();//talkWithDriver()发送Binder消息
}
3.以main_mediaserver.cpp文件为例,main函数最后会通过ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool()函数开启线程和打开Binder设备等待客户端发来消息
//来看一下调用流程
IPCThreadState::joinThreadPool()->IPCThreadState::getAndExecuteCommand() {
talkWithDriver();
executeCommand(cmd);
}
executeCommand()//这个函数如果发现是有Binder Transact会跑到下面部分
{
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
error = b->transact(tr.code, buffer, &reply, tr.flags);
}
}
//这里tr.target.pr其实就是tr.target.handle。这里b->transact()会调用到
//BBinder::transact()->onTransact()然后怎么调用到子类的onTransact()函数的?????
/*if(tr.target.ptr)为真的分支部分是最重要的。它从binder内核驱动中获取到一个地址并转换为BBinder类型的指针(该指针在执行IServiceManager::addService()函数时放入binder内核驱动)。记住,MediaPlayerService继承自BnMediaPlayerService,BnMediaPlayerService又继承自BBinder。该指针实际上与BnMediaPlayerService实例是同一个指针。于是接下来的transact()函数将调用到BnMediaPlayerService::onTransact()/
Service的注册以及获取Servcie,然后客户端发送请求给服务端的流程如下:
1) Service启动的时候通过IServiceManager的addService()把自己加到ServiceManager中
2) addService的service参数会在Binder Driver中变成handle变量
3) Binder Driver会根据名字来管理所有的service
4) IServiceManager可以通过getService()找到已经注册的Service的Interface handle
5) android.os.IBinder.INTERFACE_TRANSACTION code来找到Interface handle的实际名字
到此上面解释完了Framework层是怎么通过Binder实现IPC了!!
http://egloos.zum.com/windom/v/1865390
Java层的binder机制主要涉及到以下类:
服务层:IFooService;FooService; FooManager
其中,IFooService 接口定义服务所提供的方法,由.aidl文件实现;
FooService具体实现各个功能函数,提供具体服务;
FooManager用于注册和查找该服务;
中间层:IFooService.Stub;IFooService.Stub.Proxy
中间代码,用于实现框架封装,实际工作中由.aidl接口文件自动生成;
IPC层:Binder;BinderProxy;Parcel
BinderProxy为Binder对象在本地的代理,接收客户端传过来的数据,对其进行封装,调用JNI函数将数据发送至底层框架;
Binder接收从底层框架传过来的数据,解包,并传送至远程服务。
Parcel类对数据进行包封装。
int register_android_os_Binder(JNIEnv* env)
{
if (int_register_android_os_Binder(env) < 0)
return -1;
if (int_register_android_os_BinderInternal(env) < 0)
return -1;
if (int_register_android_os_BinderProxy(env) < 0)
return -1;
if (int_register_android_os_Parcel(env) < 0)
return -1;
return 0;
}
http://www.oss.kr/index.php?mid=oss_repository14&listStyle=list&page=5&document_srl=70352&sort_index=regdate&order_type=desc
#binder驱动
http://blog.csdn.net/woaieillen/article/details/8455797
待续。。