Binder机制-ProcessState过程

在Android系统中,只要进程涉及到Binder通信过程都需要存在的一条语句,也是在Android Framework经常出现的一条语句。

sp<ProcessState> proc(ProcessState::self());

ProcessState::self()函数是ProcessState类中的一个静态函数(static),属于这个类,不属于某个具体对象。

class ProcessState : public virtual RefBase
{
public:
    static  sp<ProcessState>    self();
...
}

其函数体如下:

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState("/dev/binder");
    return gProcess;
}

gProcess是一个全局变量。

sp<ProcessState> gProcess;

这种实现模式的目的就是设计模式中所说明的单例模式,不懂的可以去查一下什么叫做单例模式。其实现的目的就是在一个进程中,只会唯一存在一个这样的变量gProcess,且内部语句也只会执行一次,即实例化一次ProcessState。

gProcess = new ProcessState("/dev/binder");

继续往下看看其构造函数做了些什么,

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))
...
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
...
{
    if (mDriverFD >= 0) {
        // 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);
      ...
    }
...
}

此构造函数中,存在非常重要的两条语句,第一条是

mDriverFD(open_driver(driver))

用于打开设备驱动,并把设备驱动的fd保存在mDriverFD中,函数体如下:

static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);  
    if (fd >= 0) {
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        ...
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        ...
    }
    ...
    return fd;
}

fd = open(driver, O_RDWR | O_CLOEXEC) //以读写方式打开传入的设备文件
status_t result = ioctl(fd, BINDER_VERSION, &vers);//获取binder驱动版本信息
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//DEFAULT_MAX_BINDER_THREADS = 15,设置Binder驱动的最大现成数量为15
然而,第二条语句就是

 mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

用于映射内核空间的一段地址到用户空间,并把返回的首地址保存在mVMStart中,mmap()系统调用使得进程与内核之间实现内存共享。文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作,最终形成的内核映射过程如下图:
这里写图片描述
mmap()系统调用形式如下:

void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset )

mmap的作用是映射文件描述符fd指定文件的 [offset, offset + len]区域至调用进程的[addr, addr + len]的内存区域,具体参数解析如下:
addr:指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。
len:是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
prot :参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可执行), PROT_NONE(不可访问)。
flags:由以下几个常值指定:MAP_SHARED(与其它所有映射这个对象的进程共享映射空间,通过share文件的page cache做到的,所以不会立即更新) , MAP_PRIVATE(建立一个写入时拷贝的私有映射,其实就是当你修改了文件之后,会copy一个新的page出来,所以自然就无法跟其他进程共享你的修改了) , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
fd:为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)。
offset:参数一般设为0,表示从文件头开始映射。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值