Server进程和Client进程获取ServiceManager的远程接口

来源:互联网 发布:判断平年和闰年的java 编辑:程序博客网 时间:2024/05/22 22:40

上篇博客《ServiceManager如何成为Binder进程通信的守护进程》已经详细讲述了ServiceManager是如何成为守护进程,然而其作为守护进程是如何为Server进程和Client进程提供服务的,也即Server进程和Client进程如何获得ServiceManager的远程接口(代理对象)的呢?此时ServiceManager必然是作为Server的,其与普通的Server进程是不一样的;对于普通的Server来说,Client如果想要获得Server的远程接口,必须通过ServiceManager远程接口提供的getService接口来获得,这本身就是一个Binder机制进行进程间通信的过程;然而对于ServiceManager这个Server来说,Client如果想得到ServiceManager远程接口,不必通过进程间通信机制来获得,因为ServiceManager远程接口是一个binder引用,它的句柄一定是0;

一、ServiceManager远程接口关系图


1)ServiceManager远程接口对象类型为BpServiceManager,它用来描述一个实现IServiceManager接口的Client组件。

2)IServiceManager接口定义4个成员函数getService,checkService,addService和listService;其中,getService和checkService是用来获取Service组件的代理对象的。addService用来注册Service组件的;listService用来获取注册在ServiceManager中的Service组件的列表。

3)对一般的Service组件来说,Client进程首先要通过Binder驱动程序来获取它的一个句柄值,然后通过这个句柄创建一个Binder代理对象,最后将这个Binder代理对象封装成一个实现特定接口的代理对象由于ServiceManager的句柄值为0,因此获取它的代理对象不需要跟Binder驱动程序进程交互。

4)通过函数defaultServiceManager来获得一个ServiceManager代理对象。

二、defaultServiceManager

函数实现位于frameworks/base/libs/binder/IServiceManager.cpp文件中:

sp<IServiceManager> defaultServiceManager(){//又是一个单例模式,Singleton    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;        {        AutoMutex _l(gDefaultServiceManagerLock);        if (gDefaultServiceManager == NULL) {//真正的gDefaultServiceManager在这里创建            gDefaultServiceManager = <span style="color:#ff0000;">interface_cast</span><IServiceManager>(                <span style="color:#ff0000;">ProcessState::self()</span>-><span style="color:#ff0000;">getContextObject(NULL))</span>;//从这里可以看到调用的ProcessState的getContextObject来创建,然后interface_cast<IServiceManager>利用BpBinder对象作为参数新建一个BpServiceManager对象        }    }        return gDefaultServiceManager;}

1)全局变量gDefaultServiceManager是一个类型为IServiceManager的强指针,指向进程内的一个BpServiceManager对象,即ServiceManager远程接口。
    2)全局变量gDefaultServiceManagerLock是一个互斥锁,保证一个进程中至多只有一个ServiceManager代理对象。
    3)重点:三次函数调用:1)调用ProcessState类的静态成员函数self获取进程内一个ProcessState对象;2)调用ProcessState对象的成员函数getContextObject创建一个Binder代理对象;3)调用模板函数interface_cast<IServiceManager>将Binder代理对象封装成ServiceManager代理对象。
2.1 ProcessState::self成员函数
位于frameworks/base/libs/binder/ProcessState.cpp文件中:

sp<ProcessState> ProcessState::self(){//gProcess是在Static.app中定义的全局变量//程序开始的时候。gProcess肯定为NULL    if (gProcess != NULL) return gProcess;        AutoMutex _l(gProcessMutex);//创建一个ProcessState对象,并赋给gProcess    if (gProcess == NULL) gProcess = new ProcessState;    return gProcess;}

  1)全局变量gProcess是一个类型为ProcessState的强指针,执行进程内一个ProcessState对象;
   2)gProcessMutex是一个互斥锁,用来保证进程内最多只有一个ProcessState对象。
      3)重点:通过ProcessState构造函数--->创建ProcessState对象
ProcessState::ProcessState()    : mDriverFD(open_driver()) //open_driver打开Binder设备    , mVMStart(MAP_FAILED)//内存映射的起始地址    , mManagesContexts(false)    , mBinderContextCheckFunc(NULL)    , mBinderContextUserData(NULL)    , mThreadPoolStarted(false)    , mThreadPoolSeq(1){    if (mDriverFD >= 0) {#if !defined(HAVE_WIN32_IPC)        // mmap the binder, providing a chunk of virtual address space to receive transactions.        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);        if (mVMStart == MAP_FAILED) {            // *sigh*            LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");            close(mDriverFD);            mDriverFD = -1;        }#else        mDriverFD = -1;#endif    }    if (mDriverFD < 0) {        // Need to run without the driver, starting our own thread pool.    }}
在ProcessState构造函数中:
1)首先调用open_driver打开设备/dev/binder,并且将得到的文件描述符保证在成员变量mDriverFD中。
        2)调用mmap函数把设备文件/dev/binder映射到进程的地址空间,映射的地址空间大小为  BINDER_VM_SIZE:请求Binder驱动程序为进程分配内核缓冲区。
2.2 调用getContextObject创建一个Binder代理对象
位于frameworks/base/libs/binder/ProcessState.cpp文件中:
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller){/*caller的值为0,而且该函数返回的是一个IBinder。supportsProcesses()是查看设备是否支持打开设备来判断它是否支持process**/    if (supportsProcesses()) {//真实的设备肯定支持,所以会调用下面的函数来得到IBinder        return getStrongProxyForHandle(0);    } else {        return getContextObject(String16("default"), caller);    }}
1)先通过supportsProcesses来检查系统是否支持Binder进程间通信机制;
    2)然后调用getStrongProxyForHandler来创建一个Binder代理对象

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle){    sp<IBinder> result;    AutoMutex _l(mLock);/*根据索引查找对应的资源,如果lookupHandleLocked没有发现对应的资源,则会创建一个新的项并返回*/    handle_entry* e = lookupHandleLocked(handle);    if (e != NULL) {        // We need to create a new BpBinder if there isn't currently one, OR we        // are unable to acquire a weak reference on this current one.  See comment        // in getWeakProxyForHandle() for more info about this.        IBinder* b = e->binder;        if (b == NULL || !e->refs->attemptIncWeak(this)) {//对于新创建的资源项,它的binder为空,此时handle值为0.            <span style="color:#ff0000;">b = new BpBinder(handle); //创建一个BpBinder</span>            e->binder = b;//填充entry的内容            if (b) e->refs = b->getWeakRefs();            result = b;        } else {            // This little bit of nastyness is to allow us to add a primary            // reference to the remote proxy when this team doesn't have one            // but another team is sending the handle to us.            result.force_set(b);            e->refs->decWeak(this);        }    }    return result;//返回BpBinder(handler),handle值为0
2.3 调用模板函数interface_cast<IServiceManager>将Binder代理对象封装为ServiceManager代理对象
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){    return INTERFACE::asInterface(obj);}
这只是一个模板方法,所以defaultServiceManager中的interface_cast<IServiceManager>可等价于:
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj){    return IServiceManager::asInterface(obj);}
三、Server和Client进程拿到ServiceManager远程接口后,如何使用?
1) 对于Server进程,调用IServiceManager::addService这个接口来和Binder驱动进行交互,即BpServiceManager::addService。然后BpServiceManager::addService通过调用其基类BpRefBase的成员函数remote获取原先创建的BpBinder实例;接着调用BpBinder::transact成员函数。在transact函数中,又会调用IPCThreadState::transact成员函数与Binder驱动程序进行交互。原因是IPCThreadState的成员变量mProcess是ProcessState类型,其可以打开Binder设备。
2)对于Client进程,调用IServiceManager::getService接口来和Binder驱动进行交互。后续步骤跟Server进程一样。












0 0