现在的位置: 首页 > 综合 > 正文

Binder机制之ProcessState

2013年11月05日 ⁄ 综合 ⁄ 共 6746字 ⁄ 字号 评论关闭
一、前言
如果一个进程要使用Binder机制,那么他的进程中必须要创建一个ProcessState对象来负责管理Service的代理对象。ProcessState的作用是维护当前进程中所有Service代理(BpBinder对象)。一个客户端进程可能需要多个Service的服务,这样可能会创建多个Service代理(BpBinder对象),客户端进程中的ProcessState对象将会负责维护这些Service代理。Android中每个进程只有一个ProcessState。因此,我们一般都是通过ProcessState::self()来引用当前进程的ProcessState实例。
ProcessState源码位置在framework\base\libs\binder\ProcessState.cpp中。
二、ProcessState::self()
Android中每个进程只有一个ProcessState。因此,我们一般都是通过ProcessState::self()来引用当前进程的ProcessState实例。

sp<ProcessState> ProcessState::self()
{
    if (gProcess != NULL) return gProcess;//在一个进程中,第一次进来肯定不走这儿
    AutoMutex _l(gProcessMutex);//锁保护
    if (gProcess == NULL) gProcess = new ProcessState;//创建一个ProcessState对象
  return gProcess;//这里返回ProcessState指针。
}

ProcessState::self()代码中返回的是指针,但是函数本身要求返回的是sp<ProcessState>
sp,究竟是smart pointer还是strong pointer呢?其实不用太关注这个,就把它当做一个普通的指针看待,即sp<IServiceManager>相当于IServiceManager*吧。sp是google搞出来的为了方便C/C++程序员管理指针的分配和释放的一套方法,类似JAVA的什么WeakReference之类的。以后的分析中,sp<XXX>就看成是XXX*就可以了。
我们通常在一个进程中首次调用ProcessState::self()来创建一个ProcessState时,一般采用如下的形式
sp<ProcessState> proc(ProcessState::self());
这样在进程结束时,系统会自动释放ProcessState对象所占用的内存。关于此可以参照framework/base/media/mediaserver/main_mediaserver.cpp文件中的main函数。
构造函数ProcessState::ProcessState()
来看看ProcessState构造函数,这个构造函数看来很重要。
ProcessState::ProcessState()
    : mDriverFD(open_driver())//Android很多代码都是这么写的,稍不留神就没看见这里调用了一个很重要的函数
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // XXX Ideally, there should be a specific define for whether we
        // have mmap (or whether we could possibly have the kernel module
        // availabla).
#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
    }
    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

open_driver()就是打开/dev/binder这个设备,详细请见后文。
mVMStart= mmap(0,BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,mDriverFD,
0);
这句话的大概意思是:
将mDriverFD这个文件从0开始的所有内容映射到大小为BIDNER_VM_SIZ内存区域中,并把该内存的地址返回给mVMStart
这样内存的memcpy等操作就相当于write/read(fd)了。
BINDER_VM_SIZE的定义如下:
#defineBINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
BINDER_VM_SIZE的实际值为1M-8k
关于的mmap更多内容请参考《Linux内存映射(mmap)
四、open_driver()
open_driver()就是打开/dev/binder这个设备,这个是android在内核中搞的一个专门用于完成
进程间通讯而设置的一个虚拟的设备。BTW,说白了就是内核的提供的一个机制,这个和我们用socket加NET_LINK方式和内核通讯是一个道理。该函数的定义也位于framework\base\libs\binder\ProcessState.cpp

static int open_driver()
{
    int fd = open("/dev/binder", O_RDWR);
    if (fd >= 0) {
        fcntl(fd, F_SETFD, FD_CLOEXEC);
        int vers;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
            LOGE("Binder driver protocol does not match user space protocol!");
            close(fd);
            fd = -1;
        }
        size_t maxThreads = 15;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result == -1) {
            LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
    }
    return fd;
}

open("/dev/binder", O_RDWR)表面上看是打开binder这个文件,其实是打开binder驱动这个设备。
关于此的更多内容请参考《Linux内存映射(mmap)
另外注意:

        size_t maxThreads = 15;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);

这句话实际通过ioctl方式告诉Binder驱动,这个fd支持最大线程数是15个。

关于ioctl函数的更多内容请参考《ioctl函数简介
五、getStrongProxyForHandle

getStrongProxyForHandle(int32_t handle)用于把一个handle翻译成一个BpBinder 。

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    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)) {
            b = new BpBinder(handle); 
            e->binder = b;
            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;
}

 getStrongProxyForHandle函数的作用是根据一个binder句柄(Binder驱动为每个Service维护的一个Binder句柄,客户端可以通过句柄来和Service通讯)创建对应的Service代理对象BpBinder

 lookupHandleLocked函数首先去查看当前进程维护的Service代理对象的列表,该待创建Service代理对象是否已经在当前进程中被创建,如果已经创建过了,则直接返回其引用就可以了。否则将会在Service代理对象的列表增加相应的位置(注意系统为了减少分配开销,可能会多分配一些空间,策略是“以空间换时间”),保存将要创建的代理对象。
    后面代码就好理解了,如果Service代理对象BpBinder已经创建过了且当前弱引用数大于0(该值是通过attemptIncWeak返回),直接引用就行了。否则,则需要创建一个新的Service代理对象。
六、getWeakProxyForHandle
getWeakProxyForHandle函数和getStrongProxyForHandle(int32_t handle)相似,也是用于把一个handle翻译成一个BpBinder 。

wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) { wp<IBinder> result; AutoMutex _l(mLock); 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. The // attemptIncWeak() is safe because we know the BpBinder destructor will always // call expungeHandle(), which acquires the same lock we are holding now. // We need to do this because there is a race condition between someone // releasing a reference on this BpBinder, and a new reference on its handle // arriving from the driver. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { b = new BpBinder(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); } else { result = b; e->refs->decWeak(this); } } return result; }

getWeakProxyForHandle函数和getStrongProxyForHandle函数的作用相似,也是根据一个binder句柄(Binder驱动为每个Service维护的一个Binder句柄,客户端可以通过句柄来和Service通讯)创建对应的Service代理对象BpBinde 当前进程首先调用lookupHandleLocked函数去查看当前进程维护的Service代理对象的列表,该待创建Service代理对象是否已经在当前进程中创建,如果已经创建过了,则直接返回其引用就可以了。否则将会在Service代理对象的列表增加相应的位置(注意系统为了减少分配开销,可能会多分配一些空间,策略是“以空间换时间”),保存将要创建的代理对象。具体代码请参考lookupHandleLocked的源码。
后面代码就好理解了,如果Service代理对象已经创建过了且当前弱引用数大于0(该值是通过attemptIncWeak返回),直接引用就行了。否则,则需要创建一个新的Service代理对象。
lookupHandleLocked
lookupHandleLocked(int32_t handle)主要是在一个列表中查找是否有所对应的handle_entry,如果有则返回该handle_entry;如果没有则创建一个handle_entry,然后把它插入到列表中,并返回该handle_entry

ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
    const size_t N=mHandleToObject.size();
    if (N <= (size_t)handle) {
        handle_entry e;
        e.binder = NULL;
        e.refs = NULL;
        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
        if (err < NO_ERROR) return NULL;
    }
    return &mHandleToObject.editItemAt(handle);
}

结束!

抱歉!评论已关闭.