12 Binder原理-Kemel层

作者: 凤邪摩羯 | 来源:发表于2021-03-01 10:14 被阅读0次
    • 根据Android系统的分层,Binder机制主要分为以下几个部分:
    image.png
    • Binder机制涉及到的类


      image.png

    Binder驱动

    image.png

    1 binder_init

    • kernel/drivers/staging/android/binder.c
    // 4290 设备驱动入口函数
    device_initcall(binder_init);
    
    // 4213
    static int init binder_init(void)
    
    // 4220 创建名为binder的单线程的工作队列
    binder_deferred_workqueue = create_singlethread_workqueue("binder");
    
    // 4269
    ret = init_binder_device(device_name);
    
    
    • kernel/drivers/staging/android/binder.c
    // 4186
    static int init init_binder_device(const char *name)
    {
    int ret;
    struct binder_device *binder_device;
    
    // 4191 为binder设备分配内存
    binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
    
    // 4195 初始化设备
    binder_device->miscdev.fops = &binder_fops; // 设备的文件操作结构,这是
    file_operations结构
    binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; //   次设备号 动态分配
    binder_device->miscdev.name = name; // 设备名,"binder"
    
    binder_device->context.binder_context_mgr_uid = INVALID_UID; binder_device->context.name = name;
    
    // 4202 misc驱动注册
    ret = misc_register(&binder_device->miscdev);
    
    // 4208 将hlist节点添加到binder_devices为表头的设备链表
    hlist_add_head(&binder_device->hlist, &binder_devices);
    
    return ret;
    }
    
    

    2 binder_open

    • kernel/drivers/staging/android/binder.c
    // 3454
    
    static int binder_open(struct inode *nodp, struct file *filp)
    
    // 3462 为binder_proc结构体在kernel分配内存空间
    
    proc = kzalloc(sizeof(*proc), GFP_KERNEL);
    
    // 3465 将当前线程的task保存到binder进程的tsk get_task_struct(current);
    
    proc->tsk = current;
    
    INIT_LIST_HEAD(&proc->todo); // 初始化todo列表
    
    init_waitqueue_head(&proc->wait); // 初始化wait队列
    
    proc->default_priority = task_nice(current); // 将当前进程的nice值转换为进程优先级
    
    // 3474 同步锁,因为binder支持多线程访问
    
    binder_lock(func);
    
    binder_stats_created(BINDER_STAT_PROC);  //  binder_proc对象创建数加1 hlist_add_head(&proc->proc_node,  &binder_procs);  // 将proc_node节点添加到
    
    binder_procs的队列头部
    proc->pid = current->group_leader->pid; // 进 程 pid INIT_LIST_HEAD(&proc->delivered_death);  // 初始化已分发的死亡通知列表
    
    filp->private_data = proc; // 将这个binder_proc与filp关联起来,这样下次通过filp就能找到这个proc了
    binder_unlock( func ); // 释放同步锁
    

    3 binder_mmap

    • kernel/drivers/staging/android/binder.c
    
    // 3355
    static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
    
    // 3366 保证映射内存大小不超过4M
    if ((vma->vm_end - vma->vm_start) > SZ_4M) vma->vm_end = vma->vm_start + SZ_4M;
    
    // 3382 同步锁,保证一次只有一个进程分配内存,保证多进程间的并发访问
    mutex_lock(&binder_mmap_lock);
    // 是否已经做过映射,执行过则进入if,goto跳转,释放同步锁后结束binder_mmap方法
    if (proc->buffer) {
    goto err_already_mapped;
    }
    // 采用 VM_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指针指向这块内核的虚拟内存
    proc->buffer = area->addr;
    // 计算出用户空间和内核空间的地址偏移量。地址偏移量 = 用户虚拟内存地址 - 内核虚拟内存地址proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; mutex_unlock(&binder_mmap_lock); // 释放锁
    
    // 3407 分配物理页的指针数组,数组大小为vma的等效page个数
    proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
    
    // 3418 分配物理页面,同时映射到内核空间和进程空间,先分配1个物理页。
    if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
    ...
    }
    
    • kernel/drivers/staging/android/binder.c
    
    // 576
    static int binder_update_page_range(struct binder_proc *proc, int allocate,
    void *start, void *end,
    struct vm_area_struct *vma)
    // 609 allocate为1,代表分配内存过程。如果为0则代表释放内存过程
    if (allocate == 0)
    goto free_range;
    // 624 分配一个page的物理内存
    *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
    // 630 物理空间映射到虚拟内核空间
    ret = map_kernel_range_noflush((unsigned long)page_addr,
    PAGE_SIZE, PAGE_KERNEL, page);
    // 641 物理空间映射到虚拟进程空间
    ret = vm_insert_page(vma, user_page_addr, page[0]);
    
    • kernel/drivers/staging/android/binder.c
    
    // 3355
    static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
    // 3425
    list_add(&buffer->entry, &proc->buffers);// 将buffer连入buffers链表中
    buffer->free = 1; // 此内存可用
    binder_insert_free_buffer(proc, buffer);// 将buffer插入 proc->free_buffers 链表中
    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;
    

    3.1 binder_insert_free_buffer

    • kernel/drivers/staging/android/binder.c
    // 494
    static void binder_insert_free_buffer(struct binder_proc *proc,
    struct binder_buffer *new_buffer)
    
    // 511
    while (*p) {
    parent = *p;
    buffer = rb_entry(parent, struct binder_buffer, rb_node);
    
    // 计算得出空闲内存的大小
    buffer_size = binder_buffer_size(proc, buffer);
    
    if (new_buffer_size < buffer_size) p = &parent->rb_left;
    else
    p = &parent->rb_right;
    }
    rb_link_node(&new_buffer->rb_node, parent, p);
    // 将 buffer插入 proc->free_buffers 链表中
    rb_insert_color(&new_buffer->rb_node, &proc->free_buffers);
    
    

    4 binder_ioctl

    • kernel/drivers/staging/android/binder.c
    // 3241
    static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    // 3254 进入休眠状态,直到中断唤醒
    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error
    < 2);
    
    // 3259 根据当前进程的pid,从binder_proc中查找binder_thread,
    //  如果当前线程已经加入到proc的线程队列则直接返回,
    //  如果不存在则创建binder_thread,并将当前线程添加到当前的proc thread = binder_get_thread(proc);
    
    // 3265 进行binder的读写操作
    switch (cmd) {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread); if (ret)
          ...
    }
    

    4.1 binder_ioctl_write_read

    • kernel/drivers/staging/android/binder.c
    // 3136
    static int binder_ioctl_write_read(struct file *filp,
    unsigned int cmd, unsigned long arg, struct binder_thread *thread)
    
    // 3150 把用户空间数据ubuf拷贝到bwr
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    
    // 3160
    if (bwr.write_size > 0) { // 当写缓存中有数据,则执行binder写操作
    ret = binder_thread_write(proc, thread,
    bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
    }
    if (bwr.read_size > 0) { // 当读缓存中有数据,则执行binder读操作
    ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size,
    &bwr.read_consumed,
    filp->f_flags & O_NONBLOCK);
    // 进程todo队列不为空,则唤醒该队列中的线程
    if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait);
    }
    
    // 3192 把内核空间数据bwr拷贝到ubuf
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
    ...
    }
    

    相关文章

      网友评论

        本文标题:12 Binder原理-Kemel层

        本文链接:https://www.haomeiwen.com/subject/tnyiaktx.html