天天看点

android中binder的初始化

binder是android独有的一种IPC机制,它是在/system/bin/servicemanager进程(可以用ps看到)中完成初始化的,它的父进程是init. 

1. 代码: 

     frameworks\base\cmds\servicemanager\,这个目录下,有service_manager.c,binder.c。

(1) 在service_manager.c中,有main函数,代码如下:

int main(int argc, char **argv)

{

    struct binder_state *bs;

    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {

        LOGE("cannot become context manager (%s)\n", strerror(errno));

        return -1;

    }

    svcmgr_handle = svcmgr;

    binder_loop(bs, svcmgr_handler);

    return 0;

}

(2) binder_open:  位于binder.c中,binder_open函数实现如下: 

struct binder_state *binder_open(unsigned mapsize)

{

    struct binder_state *bs;

    bs = malloc(sizeof(*bs));

    if (!bs) {

        errno = ENOMEM;

        return 0;

    }

    bs->fd = open("/dev/binder", O_RDWR);

    if (bs->fd < 0) {

        fprintf(stderr,"binder: cannot open device (%s)\n",

                strerror(errno));

        goto fail_open;

    }

    bs->mapsize = mapsize;

    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);

    if (bs->mapped == MAP_FAILED) {

        fprintf(stderr,"binder: cannot map device (%s)\n",

                strerror(errno));

        goto fail_map;

    }

    return bs;

fail_map:

    close(bs->fd);

fail_open:

    free(bs);

    return 0;

}

2. 说明:

   (1) 在frameworks\base\cmds\servicemanager目录下的Android.mk中,指定生成的模块为servicemanager:

         LOCAL_MODULE := servicemanager //

   (2) dev/binder会映射到一块内存虚拟空间中,通过mmap系统调用来实现。

   (3) binder.c中还提供了一系列函数,用于支持binder的访问。

   (4) binder通信机制的实现中,是用ioctl的方式与内核进行交互的。

   (5) binder的初始化一定是在jvm的初始化之前,因为jvm初始化一直到上层的system_server的过程中,会有启动很多的service,这些service都会去用到binder。

    (6) servicemanager这个进程的权限是system,这个通过ps也能看出来,它是在init.rc中指定的。

3. 补充:

  mmap的使用:

    #include <sys/mman.h>  

 (1)   void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)。  

    描述: 把文件或者设备映射到内存。这个函数在调用进程的虚拟地址空间中创建一块映射区域。

    参数说明:

        addr: 指定映射区域的首地址, 如果addr是NULL,那么由内核来选择一个地址来创建映射的区域,否则创建的时候会尽可能地使用addr的地址。在linux系统中,创建映射的时候应该是在下一个页面的边界创建,addr是NULL的时候,程序的可移植性最好。

        length:指定映射区域的长度。

        offset:指定从文件的哪个偏移位置开始映射,offset必须是页面大小的整数倍页面的大小可以由sysconf(_SC_PAGE_SIZE)来返回。

        flags指定区域在不同进程之间的共享方式,以及区域是否同步到相应的文件等等。

        fd: 文件描述符.在binder中,指的就是:bs->fd = open("/dev/binder", O_RDWR)。

    返回值: 这个函数返回新创建的页面的地址。成功的时候这个函数返回0。   失败的时候,返回-1。

  (2)  int munmap(void *addr, size_t length); 

    作用: munmap  取消address指定地址范围的映射。以后再引用取消的映射的时候就会导致非法内存的访问。这里address应该是页面的整数倍。 成功的时候这个函数返回0。   失败的时候,返回-1.。

继续阅读