Binder概述

Binder是一种Android实现的IPC,用于进程间通信。

通常Linux系统提供好几种进程间通信的方式,比如
1) Message Queue :把进程之间通信用的message保存到内核中或者从内核中读取的方式。

2) Shared Memory:进程间指定共享的内存,把需要传输的内容保存到相应的内存的方式

3) Socket:

Android中选择Binder为主要的IPC方式,因为Binder比其他的IPC方式有更加简洁快速,消耗内存更小等优点。

下面来看一下Framework层Java空间都是怎么用Binder实现进程间通信的。

Framework层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的实际名字

Android: Binder_第1张图片

到此上面解释完了Framework层是怎么通过Binder实现IPC了!!

http://egloos.zum.com/windom/v/1865390

Java Binder

Binder in java layer

Java层的binder机制主要涉及到以下类: 服务层:IFooService;FooService; FooManager其中,IFooService 接口定义服务所提供的方法,由.aidl文件实现;FooService具体实现各个功能函数,提供具体服务;FooManager用于注册和查找该服务;中间层:IFooService.Stub;IFooService.Stub.Proxy中间代码,用于实现框架封装,实际工作中由.aidl接口文件自动生成;IPC层:Binder;BinderProxy;ParcelBinderProxy为Binder对象在本地的代理,接收客户端传过来的数据,对其进行封装,调用JNI函数将数据发送至底层框架;Binder接收从底层框架传过来的数据,解包,并传送至远程服务。Parcel类对数据进行包封装。

Java 层 Binder 框架数据传递的实现

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

Linux Binder驱动

#binder驱动
http://blog.csdn.net/woaieillen/article/details/8455797

待续。。

更多相关文章

  1. Android访问WCF服务(上篇)-服务端开发
  2. fanfou(饭否) android客户端 代码学习1
  3. Android腾讯微薄客户端开发十四:首页menu菜单
  4. android mina 客户端无法接收信息的原因
  5. Android客户端自动更新代码
  6. android 客户端 smtp 协议发送数据
  7. Android 加载图片文件 函数
  8. 客户端性能测试
  9. 开源中国WP7客户端全面开源,包括iPhone客户端与Android

随机推荐

  1. 说说Android桌面(Launcher应用)背后的故
  2. android 软引用和lrucache的区别
  3. android适配器的简单使用
  4. android 2.2 通讯录
  5. Android Studio学习:简单控件:Button控件的
  6. 水平布局linerlayout
  7. android中任务栈的处理方式
  8. 动态的添加ImageView并居中显示
  9. Android Dialog中的EditText 弹出软键盘
  10. 【原创】Android 设置Dialog的长宽和位置