Binder - 內(nèi)核驅(qū)動(dòng)層源碼淺析

binder驅(qū)動(dòng).png

在線(xiàn)內(nèi)核層代碼:http://androidxref.com/kernel_3.18/xref/

1.binder_init

驅(qū)動(dòng)啟動(dòng)時(shí)會(huì)先調(diào)用驅(qū)動(dòng)的binder_init():主要負(fù)責(zé)注冊(cè)misc設(shè)備,通過(guò)調(diào)用misc_register來(lái)實(shí)現(xiàn)

//資源路徑: /drivers/staging/android/binder.c
static int __init binder_init(void)
{
  int ret;
  //創(chuàng)建名為binder的單線(xiàn)程工作隊(duì)列
  binder_deferred_workqueue = create_singlethread_workqueue("binder");
  //...
  //注冊(cè)misc設(shè)備
  ret = misc_register(&binder_miscdev);
  return ret
}
static struct miscdevice binder_miscdev = {
  //次設(shè)備號(hào) 動(dòng)態(tài)分配
  .minor = MISC_DYNAMIC_MINOR,
  //設(shè)備名 binder
  .name = "binder",
  //設(shè)備的文件操作結(jié)構(gòu),file_operations結(jié)構(gòu)
  .fops = &binder_fops
};
//Native層調(diào)用驅(qū)動(dòng)層需要通過(guò)系統(tǒng)調(diào)用(syscall),下面是Native層與驅(qū)動(dòng)層的映射關(guān)系
static const struct file_operations binder_fops = {
  .owner = THIS_MODULE,
  .poll = binder_poll,
  .unlocked_ioctl = binder_ioctl,
  .compat_ioctl = binder_ioctl,
  //如Native層調(diào)用mmap會(huì)調(diào)到驅(qū)動(dòng)層的binder_mmap
  .mmap = binder_mmap,
  .open = binder_open,
  .flush = binder_flush,
  .release = binder_release,
};
2.binder_open

打開(kāi)驅(qū)動(dòng)會(huì)調(diào)用binder_open():創(chuàng)建binder_proc對(duì)象,并把當(dāng)前進(jìn)程等信息保存到binder_proc對(duì)象,再將binder_proc對(duì)象保存到文件指針filp,以及把binder_proc添加到全局鏈表binder_procs中。

//資源路徑:/drivers/staging/android/binder.c
static int binder_open(struct inode *nodp, struct file *filp)
{
  //當(dāng)前binder進(jìn)程結(jié)構(gòu)體
  struct binder_proc *proc;
  //為binder_proc結(jié)構(gòu)體在內(nèi)核申請(qǐng)內(nèi)存空間
  proc = kzalloc(sizeof(*proc), GFP_KERNEL);
  //current代表當(dāng)前線(xiàn)程
  get_task_struct(current);
  //將當(dāng)前線(xiàn)程的task保存到binder進(jìn)程的tsk
  proc->tsk = current;
  //初始化todo列表
  INIT_LIST_HEAD(&proc->todo);
  //初始化wait隊(duì)列
  init_waitqueue_head(&proc->wait);
  //將當(dāng)前進(jìn)程的nice值轉(zhuǎn)換為進(jìn)程優(yōu)先級(jí)
  proc->default_priority = task_nice(current);
  
  //同步鎖,因?yàn)閎inder支持多線(xiàn)程訪(fǎng)問(wèn)
  binder_lock(__func__);

  //binder_proc對(duì)象創(chuàng)建數(shù)加1
  binder_stats_created(BINDER_STAT_PROC);
  //將pro_node節(jié)點(diǎn)添加到binder_procs的隊(duì)列頭部
  hlist_add_head(&proc->proc_node, &binder_procs);
  //記錄當(dāng)前進(jìn)程的pid
  proc->pid = current->group_leader->pid;
  //初始化已分發(fā)的死亡通知列表
  INIT_LIST_HEAD(&proc->delivered_death);
  //將binder_proc存放在filp的private_data域,以便在之后的mmap、ioctl中獲取
  filp->private_data = proc;

  //釋放同步鎖
  binder_unlock(__func__);
  
  return 0;
}
3.binder_mmap

1.通過(guò)用戶(hù)空間的虛擬內(nèi)存大小,分配一塊內(nèi)核的虛擬內(nèi)存
2.分配一塊物理內(nèi)存(4KB)
3.把這塊物理內(nèi)存分別映射到用戶(hù)空間的虛擬內(nèi)存和內(nèi)核的虛擬內(nèi)存

//資源路徑:/drivers/staging/android/binder.c
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
  int ret;
  //內(nèi)核的虛擬內(nèi)存
  struct vm_struct *area;
  //從filp中取binder_proc(binder_open方法中保存的)
  struct binder_proc *proc = filp->private_data;
    //保證映射內(nèi)存大小不超過(guò)4M
  if ((vma->vm_end - vma->vm_start) > SZ_4M)
    vma->vm_end = vma->vm_start + SZ_4M;
  
  //同步鎖,保證一次只有一個(gè)進(jìn)程分配內(nèi)存
  mutex_lock(&binder_mmap_lock);
  //判斷是否映射過(guò)
  if (proc->buffer) {       
    ret = -EBUSY;
    failure_string = "already mapped";
    goto err_already_mapped;
  }
    //采用VM_IOREMAP方式,分配一個(gè)連續(xù)的內(nèi)核虛擬內(nèi)存,與進(jìn)程虛擬內(nèi)存大小一致
  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指針指向這塊內(nèi)核的虛擬內(nèi)存
  proc->buffer = area->addr;
  //計(jì)算用戶(hù)空間和內(nèi)核空間的地址偏移量
  proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
    //釋放同步鎖
  mutex_unlock(&binder_mmap_lock);
  //分配物理頁(yè)的指針數(shù)組,大小為vma的等效page個(gè)數(shù)
  proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
  
  //分配物理頁(yè)面,同時(shí)映射到內(nèi)核空間和進(jìn)程空間,先分配1個(gè)物理頁(yè)(4KB),真正數(shù)據(jù)傳輸?shù)臅r(shí)候再添加,免得內(nèi)存浪費(fèi)。
  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;
  }
  //binder_buffer對(duì)象指向proc的buffer地址 
  buffer = proc->buffer;
  //創(chuàng)建進(jìn)程的buffers鏈表頭
  INIT_LIST_HEAD(&proc->buffers);
  //將binder_buffer地址加入所屬進(jìn)程的buffers隊(duì)列
  list_add(&buffer->entry, &proc->buffers);
  //上面通過(guò)binder_update_page_range已經(jīng)做了映射,此內(nèi)存可用
  buffer->free = 1;
  //將空閑的buffer放入proc->free_buffers鏈表中
  binder_insert_free_buffer(proc, buffer);
  //異步傳輸?shù)目捎每臻e空間大小為buffer總大小的一半
  proc->free_async_space = proc->buffer_size / 2;
  //...
  return 0;
}


static int binder_update_page_range(struct binder_proc *proc, int                       allocate,void *start, void *end,struct vm_area_struct *vma)
{
  //上面allocate為1,代表分配內(nèi)存。如果是1表示釋放內(nèi)存
  if (allocate == 0)
        goto free_range;
  for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
        int ret;
    //①分配一個(gè)page的物理內(nèi)存
    *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
    //②內(nèi)核空間的虛擬內(nèi)存映射到物理空間
    ret = map_vm_area(&tmp_area, PAGE_KERNEL, page);
    //用戶(hù)空間地址=內(nèi)核空間地址+偏移量
    user_page_addr =(uintptr_t)page_addr + proc->user_buffer_offset;
    //③用戶(hù)空間的虛擬內(nèi)存映射到物理內(nèi)存
    ret = vm_insert_page(vma, user_page_addr, page[0]);
  }
}
4.binder_ioctl

binder_ioctl承載了Binder數(shù)據(jù)傳輸部分的主要業(yè)務(wù),有兩個(gè)核心方法 binder_thread_write 和 binder_thread_read

//資源路徑:/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  //進(jìn)入休眠狀態(tài),直到中斷喚醒
  ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
  binder_lock(__func__);
  //獲取binder_thread
  thread = binder_get_thread(proc);
  //
  switch (cmd) {
    //binder讀寫(xiě)操作
    case BINDER_WRITE_READ:
      ret = binder_ioctl_write_read(filp, cmd, arg, thread);
      if (ret)
        goto err;
      break;
      //...
  }
}


static int binder_ioctl_write_read(struct file *filp,
                                   unsigned int cmd, unsigned long arg,
                                   struct binder_thread *thread)
{
  int ret=0
  //把用戶(hù)空間數(shù)據(jù)ubuf拷貝到bwr
  if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    ret = -EFAULT;
    goto out;
  }
  //當(dāng)寫(xiě)緩存中有數(shù)據(jù),則執(zhí)行binder寫(xiě)操作
  if (bwr.write_size > 0) {
    ret = binder_thread_write(proc, thread,
                              bwr.write_buffer,
                              bwr.write_size,
                              &bwr.write_consumed);
    trace_binder_write_done(ret);
    if (ret < 0) {
      bwr.read_consumed = 0;
      if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
        ret = -EFAULT;
      goto out;
    }
  }
  //當(dāng)讀緩存中有數(shù)據(jù),則執(zhí)行binder讀操作
  if (bwr.read_size > 0) {
    ret = binder_thread_read(proc, thread, bwr.read_buffer,
                             bwr.read_size,
                             &bwr.read_consumed,
                             filp->f_flags & O_NONBLOCK);
    trace_binder_read_done(ret);
    if (!list_empty(&proc->todo))
      //喚醒等待狀態(tài)的線(xiàn)程
      wake_up_interruptible(&proc->wait);
    //讀失敗,再將bwr數(shù)據(jù)寫(xiě)回用戶(hù)空間,并返回
    if (ret < 0) {
      if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
        ret = -EFAULT;
      goto out;
    }
  }
  //將內(nèi)核數(shù)據(jù)bwr拷貝到用戶(hù)空間ubuf
  if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
    ret = -EFAULT;
    goto out;
  }
  out:
  return ret;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容