andriod binder-ServiceManager守护进程

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/

欢迎关注微信公众号:DroidMind
精品内容独家发布平台


呈现与博客不一样的技术干货

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值