注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

Binder机制之ProcessState  

2012-05-01 22:32:55|  分类: 深入研究 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、前言
如果一个进程要使用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的定义如下:
#define BINDER_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);
}

结束!
  评论这张
 
阅读(2398)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017