andriod binder-ServiceManager守护进程

来源:互联网 发布:php将数组转换成字符串 编辑:程序博客网 时间:2024/04/28 15:09

ServiceManager是一个守护进程。它的main()函数源码如下:

frameworks/native/cmds/servicemanager/service_manager.c

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)) {        ALOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;     }       svcmgr_handle = svcmgr;    binder_loop(bs, svcmgr_handler);    return 0;}

/frameworks/native/cmds/servicemanager/binder.c

struct binder_state *binder_open(unsigned mapsize){    struct binder_state *bs;    bs = malloc(sizeof(*bs));    ...    bs->fd = open("/dev/binder", O_RDWR);    ...    bs->mapsize = mapsize;    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);     ...    return bs;}

这里写图片描述

kernel/drivers/staging/android/binder.c

static int binder_open(struct inode *nodp, struct file *filp){    struct binder_proc *proc;    binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",           current->group_leader->pid, current->pid);    // 为proc分配内存    proc = kzalloc(sizeof(*proc), GFP_KERNEL);    if (proc == NULL)      return -ENOMEM;    get_task_struct(current);    // 将proc->tsk指向当前线程    proc->tsk = current;    // 初始化proc的待处理事务列表    INIT_LIST_HEAD(&proc->todo);    // 初始化proc的等待队列    init_waitqueue_head(&proc->wait);    // 设置proc的进程优先级为当前线程的优先级    proc->default_priority = task_nice(current);    binder_lock(__func__);    binder_stats_created(BINDER_STAT_PROC);    // 将该进程上下文信息proc保存到"全局哈希表binder_procs"中    hlist_add_head(&proc->proc_node, &binder_procs);    // 设置进程id    proc->pid = current->group_leader->pid;    INIT_LIST_HEAD(&proc->delivered_death);    // 将proc添加到私有数据中。    // 这样,mmap(),ioctl()等函数都可以通过私有数据获取到proc,即该进程的上下文信息    filp->private_data = proc;    binder_unlock(__func__);    if (binder_debugfs_dir_entry_proc) {      char strbuf[11];      snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);      proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,          binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);    }    return 0;}

创建binder_proc对象,并把当前进程等信息保存到binder_proc对象,该对象管理IPC所需的各种信息并拥有其他结构体的根结构体;再把binder_proc对象保存到文件指针filp,以及把binder_proc加入到全局链表binder_procs。

这里写图片描述

kernel/drivers/staging/android/binder.c

//vm_area_struct则是描述进程虚拟地址信息的结构体。//vm_struct是描述内核虚拟地址信息的结构体。static int binder_mmap(struct file *filp, struct vm_area_struct *vma){    int ret;    struct vm_struct *area; //内核虚拟空间    struct binder_proc *proc = filp->private_data;    const char *failure_string;    struct binder_buffer *buffer;    if (proc->tsk != current)        return -EINVAL;    if ((vma->vm_end - vma->vm_start) > SZ_4M)        vma->vm_end = vma->vm_start + SZ_4M;  //保证映射内存大小不超过4M    mutex_lock(&binder_mmap_lock);  //同步锁    //采用IOREMAP方式,分配一个连续的内核虚拟空间,与进程虚拟空间大小一致    area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);    if (area == NULL) {        ret = -ENOMEM;        failure_string = "get_vm_area";        goto err_get_vm_area_failed;    }    proc->buffer = area->addr; //指向内核虚拟空间的地址    //地址偏移量 = 用户虚拟地址空间 - 内核虚拟地址空间    proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;    mutex_unlock(&binder_mmap_lock); //释放锁    ...    //分配物理页的指针数组,数组大小为vma的等效page个数;    proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);    if (proc->pages == NULL) {        ret = -ENOMEM;        failure_string = "alloc page array";        goto err_alloc_pages_failed;    }    // 内核虚拟空间的内存大小 = 进程虚拟地址区域(用户空间)的内存大小    proc->buffer_size = vma->vm_end - vma->vm_start;    vma->vm_ops = &binder_vm_ops;    vma->vm_private_data = proc;    //分配物理页面,同时映射到内核空间和进程空间,先分配1个物理页    if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {        ret = -ENOMEM;        failure_string = "alloc small buf";        goto err_alloc_small_buf_failed;    }    buffer = proc->buffer; //binder_buffer对象 指向proc的buffer地址    INIT_LIST_HEAD(&proc->buffers); //创建进程的buffers链表头    list_add(&buffer->entry, &proc->buffers); //将binder_buffer地址 加入到所属进程的buffers队列    buffer->free = 1;    //将空闲buffer放入proc->free_buffers中    binder_insert_free_buffer(proc, buffer);    //异步可用空间大小为buffer总大小的一半。    proc->free_async_space = proc->buffer_size / 2;    barrier();    proc->files = get_files_struct(current);    proc->vma = vma;    proc->vma_vm_mm = vma->vm_mm;    return 0;    ...// 错误flags跳转处,free释放内存之类的操作    return ret;}
static int binder_update_page_range(struct binder_proc *proc, int allocate,            void *start, void *end,            struct vm_area_struct *vma){  void *page_addr;  unsigned long user_page_addr;  struct page **page;  struct mm_struct *mm; // 内存结构体  if (vma)        mm = NULL; //binder_mmap过程vma不为空,其他情况都为空    else        mm = get_task_mm(proc->tsk); //获取mm结构体  if (mm) {    down_write(&mm->mmap_sem); //获取mm_struct的写信号量    vma = proc->vma;  }  //此处allocate为1,代表分配过程。如果为0则代表释放过程  if (allocate == 0)    goto free_range;  for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {    int ret;    page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];    //分配一个page的物理内存    *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);    //物理空间映射到虚拟内核空间    ret = map_kernel_range_noflush((unsigned long)page_addr,          PAGE_SIZE, PAGE_KERNEL, page);    flush_cache_vmap((unsigned long)page_addr, (unsigned long)page_addr + PAGE_SIZE);    user_page_addr = (uintptr_t)page_addr + proc->user_buffer_offset;    //物理空间映射到虚拟进程空间    ret = vm_insert_page(vma, user_page_addr, page[0]);  }  if (mm) {    up_write(&mm->mmap_sem); //释放内存的写信号量    mmput(mm); //减少mm->mm_users计数  }  return 0;free_range:  ... //释放内存的流程  return -ENOMEM;}

这里写图片描述

binder_update_page_range主要完成工作:分配物理空间,将物理空间映射到内核空间,将物理空间映射到进程空间

在Binder通信机制中,mmap()会将Server进程的虚拟地址和内核虚拟地址映射到同一个物理页面。那么当Client进程向Server进程发送请求时,只需要将Client的数据拷贝到内核空间即可!由于Server进程的地址和内核空间映射到同一个物理页面,因此,Client中的数据拷贝到内核空间时,也就相当于拷贝到了Server进程中。因此,Binder通信机制中,数据传输时,只需要1次内存拷贝!

http://qiangbo.space/2017-01-15/AndroidAnatomy_Binder_Driver/
http://wangkuiwu.github.io/2014/09/03/Binder-ServiceManager-Daemon/
http://gityuan.com/2015/11/01/binder-driver/

原创粉丝点击