Android Framework-Binder驱动源码理解

291 阅读20分钟

内核基础概念理解

  • 为什么在内核状态下进程是互通的。 因为在内核眼里 进程都是我管理的,对于内核来说 ,所有的东西都他控制的。内核就是无敌的。进程对于内核来说就像个变量一样。所以想怎么搞就怎么搞。操作系统其实就是个程序。

  • 用户空间想访问内核空间咋办?

通过系统调用或者硬件中断,一般都是系统调用。

  • binder 驱动涉及到系统的调用有哪些?

    ioctlmmap

  • 常用方法的在Binder.c对应

open-->binder_open ioctl-->binder_ioctl mmap-->binder_mmap

方法源码分析

binder_open

    //android/binder.c static int binder_open(struct inode *nodp, struct file *filp)
    {
      //构建 binder_proc 进程
      struct binder_proc *proc;
      struct binder_device *binder_dev;
    ​
    ​
    ​
      proc = kzalloc(sizeof(*proc), GFP_KERNEL);
      if (proc == NULL)
        return -ENOMEM;
      spin_lock_init(&proc->inner_lock);
      spin_lock_init(&proc->outer_lock);
      get_task_struct(current->group_leader);
      proc->tsk = current->group_leader;
      mutex_init(&proc->files_lock);
      INIT_LIST_HEAD(&proc->todo);
      if (binder_supported_policy(current->policy)) {
        proc->default_priority.sched_policy = current->policy;
        proc->default_priority.prio = current->normal_prio;
      } else {
        proc->default_priority.sched_policy = SCHED_NORMAL;
        proc->default_priority.prio = NICE_TO_PRIO(0);
      }
    ​
      binder_dev = container_of(filp->private_data, struct binder_device,
              miscdev);
      proc->context = &binder_dev->context;
      //核心代码 
      binder_alloc_init(&proc->alloc);
    ​
      binder_stats_created(BINDER_STAT_PROC);
      //核心代码应用层的pid 也就是当前谁调用的binder 的应用的pid
      proc->pid = current->group_leader->pid;
      INIT_LIST_HEAD(&proc->delivered_death);
      INIT_LIST_HEAD(&proc->waiting_threads);
      //前面构建好的proc 赋值给了filpd的属性
      filp->private_data = proc;
    ​
      mutex_lock(&binder_procs_lock);
      //加入进程的列表
      hlist_add_head(&proc->proc_node, &binder_procs);
      mutex_unlock(&binder_procs_lock);
    ​
      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,
          (void *)(unsigned long)proc->pid,
          &binder_proc_fops);
      }
    ​
      return 0;
    }
    //总结 搞了个 进程对象 然后赋值过去了

mmap

    /** vm_area_struct 用于表示0~3G的空间中一段连续的虚拟地址空间,是给user space的process使用.
    vm_struct 是kernel space 除low memory中用于表示连续的虚拟地址空间,常用于vmalloc/vfree的操作
    简单理解为vm_area_struct 就是用户空间的虚拟内存描述结构体,vm_struct 是kernel中的虚拟内存描述结构体。
    所以这里大参数是用户空间传递来的虚拟内存结构体。
    这里binder_mmap除了判断限制了申请内存最大为4M,其他真正业务都是在binder_alloc_mmap_handler方法中,同时把proc的binder_alloc传递类进去,及用户空间的vm_area_struct 也传递了进去
    */
    ​
    ​
    static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
    {
      
      //前面 open 方法里 给filp->private_data = proc 这里就可以拿出来了
      int ret;
      struct binder_proc *proc = filp->private_data;
      const char *failure_string;
    ​
      if (proc->tsk != current->group_leader)
        return -EINVAL;
    ​
       //检查 用户空间虚拟地址end -start 是否大于4m
      if ((vma->vm_end - vma->vm_start) > SZ_4M)
        //如果大于4m 就限制到4m 一般情况是1M-8k
        vma->vm_end = vma->vm_start + SZ_4M;
    ​
    ​
    ​
      if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
        ret = -EPERM;
        failure_string = "bad vm_flags";
        goto err_bad_arg;
      }
      vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
      //设置了一个回调方法 没啥用
      vma->vm_ops = &binder_vm_ops;
        // 又赋值给了 wma的属性
      vma->vm_private_data = proc;
      //一个关键方法
      ret = binder_alloc_mmap_handler(&proc->alloc, vma);
      if (ret)
        return ret;
      mutex_lock(&proc->files_lock);
      proc->files = get_files_struct(current);
      mutex_unlock(&proc->files_lock);
      return 0;
    ​
    err_bad_arg:
      pr_err("binder_mmap: %d %lx-%lx %s failed %d\n",
             proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
      return ret;
    }
    //
    

总结 限制到4m 以内, 然后 赋值给wma 调用了 binder_alloc_mmap_handler

binder_alloc_mmap_handler

    //android/binder_alloc.c
    int binder_alloc_mmap_handler(struct binder_alloc *alloc,
                struct vm_area_struct *vma)
    {
      int ret;
      //内核中虚拟地址
      struct vm_struct *area;
      const char *failure_string;
      struct binder_buffer *buffer;
    ​
      mutex_lock(&binder_alloc_mmap_lock);
      if (alloc->buffer) {
        ret = -EBUSY;
        failure_string = "already mapped";
        goto err_already_mapped;
      }
      //构造内核虚拟地址  传入的大小 是用户空间内核的大小长度
      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;
      }
      //将用户allco 中的buffer 赋值为申请出来的空间地址
      alloc->buffer = area->addr;
      //用户空间和内核空间的偏移量 计算出来
      alloc->user_buffer_offset =
        vma->vm_start - (uintptr_t)alloc->buffer;
      mutex_unlock(&binder_alloc_mmap_lock);
    ​
    #ifdef CONFIG_CPU_CACHE_VIPT
      if (cache_is_vipt_aliasing()) {
        while (CACHE_COLOUR(
            (vma->vm_start ^ (uint32_t)alloc->buffer))) {
          pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n",
            alloc->pid, vma->vm_start, vma->vm_end,
            alloc->buffer);
          vma->vm_start += PAGE_SIZE;
        }
      }
    #endif
      //申请页数 就是对象的长度除以一页的大小 一般4096 一页
      alloc->pages = kzalloc(sizeof(alloc->pages[0]) *
               ((vma->vm_end - vma->vm_start) / PAGE_SIZE),
                 GFP_KERNEL);
      if (alloc->pages == NULL) {
        ret = -ENOMEM;
        failure_string = "alloc page array";
        goto err_alloc_pages_failed;
      }
      alloc->buffer_size = vma->vm_end - vma->vm_start;
      //申请了一个buffer 
      buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
      if (!buffer) {
        ret = -ENOMEM;
        failure_string = "alloc buffer struct";
        goto err_alloc_buf_struct_failed;
      }
     //装载内容 buffer的内容 指向alloc的buffer  这里的buffer 已经是内核里面的地址了
     
      buffer->data = alloc->buffer;
      list_add(&buffer->entry, &alloc->buffers);
      buffer->free = 1;
      binder_insert_free_buffer(alloc, buffer);
      //异步空间的地址大小 为申请的buffer的一半
      alloc->free_async_space = alloc->buffer_size / 2;
      barrier();
       //给用户空间属性 赋值回去
      alloc->vma = vma;
      alloc->vma_vm_mm = vma->vm_mm;
      /* Same as mmgrab() in later kernel versions */
      atomic_inc(&alloc->vma_vm_mm->mm_count);
    ​
      return 0;
    ​
    err_alloc_buf_struct_failed:
      kfree(alloc->pages);
      alloc->pages = NULL;
    err_alloc_pages_failed:
      mutex_lock(&binder_alloc_mmap_lock);
      vfree(alloc->buffer);
      alloc->buffer = NULL;
    err_get_vm_area_failed:
    err_already_mapped:
      mutex_unlock(&binder_alloc_mmap_lock);
      pr_err("%s: %d %lx-%lx %s failed %d\n", __func__,
             alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
      return ret;
    }
    ​
  

总结 申请了内核空间, 计算出来用户和内核空间之间的偏移量, 方便后面寻找, 只需要一个差额的计算就能找到对方地址,申请了页出来, 构建了buffer ,这里可以看出来不是每个都是1m-8k ,而是看你需要多少再去申请对应的页, 真正申请是在 binder_update_page_range 方法里

binder_update_page_range 申请真实物理内存地址

    //在这里 就相当于根据需要地址大小去申请对应的物理地址, 遍历了需要的页数 保证了申请成功,并把虚拟地址和真正的物理地址进行了映射。 然后根据之前算出来的偏差 把用户里面的虚拟地址和真实的物理地址也映射一起,这样用户和内核都映射到一块物理地址static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
                void *start, void *end)
    {
      void *page_addr;
      unsigned long user_page_addr;
      struct binder_lru_page *page;
      struct vm_area_struct *vma = NULL;
      struct mm_struct *mm = NULL;
      bool need_mm = false;
    ​
      。。省略
      //根据start和end区域大小,计算申请对应的内存页
      for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
        page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
        //判断这个物理页是否已经申请,如果没有申请则need_mm = true;就从这一页开始申请分配物理内存
        if (!page->page_ptr) {
          need_mm = true;
          break;
        }
      }
    ​
      /* Same as mmget_not_zero() in later kernel versions */
      if (need_mm && atomic_inc_not_zero(&alloc->vma_vm_mm->mm_users))
        mm = alloc->vma_vm_mm;
    ​
      if (mm) {
        down_write(&mm->mmap_sem);
        vma = alloc->vma;
      }
    //又一次遍历。。其实好像和上面的代码有点重复遍历,可以考虑是否可以优化这里减少遍历次数
      for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
      
        index = (page_addr - alloc->buffer) / PAGE_SIZE;
        page = &alloc->pages[index];
        //page->page_ptr不为null说明已经被使用,只能继续遍历
        if (page->page_ptr) {
           //lru优化。。。暂时不理会
          on_lru = list_lru_del(&binder_alloc_lru, &page->lru);
          continue;
        }
        //遍历到了没有被申请使用的,那就开始真正page内存页申请
        page->page_ptr = alloc_page(GFP_KERNEL |
                  __GFP_HIGHMEM |
                  __GFP_ZERO);
        。。省略
        page->alloc = alloc;
        //把内核虚拟地址page_addr与真实的页内存进行映射
        ret = map_kernel_range_noflush((unsigned long)page_addr,
                     PAGE_SIZE, PAGE_KERNEL,
                     &page->page_ptr);
        flush_cache_vmap((unsigned long)page_addr,
            (unsigned long)page_addr + PAGE_SIZE);
        //根据原来的内核和用户空间地址偏移,可以直接得出用户空间的虚拟地址
        user_page_addr =
          (uintptr_t)page_addr + alloc->user_buffer_offset;
      //  把用户空间虚拟地址user_page_addr与真实的页内存进行映射
        ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
      
    ​
        if (index + 1 > alloc->pages_high)
          alloc->pages_high = index + 1;
      }
      
      //。。省略
    }
   
    
  

//

传输数据的基本流程 数据的写入,aidl 实际调用的是BPBinder. 然后调用的IPCThreadState 里面的transact()

    //native/libs/binder/IPCThreadState.cpp
    ​
    status_t IPCThreadState::transact(int32_t handle,
                                      uint32_t code, const Parcel& data,
                                      Parcel* reply, uint32_t flags)
    {
       
    ​
        status_t err;
    ​
        flags |= TF_ACCEPT_FDS;
    ​
       
         //数据写入
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
        //一般不报错
        if (err != NO_ERROR) {
            if (reply) reply->setError(err);
            return (mLastError = err);
        }
    ​
        if ((flags & TF_ONE_WAY) == 0) {
            //省略。。
    ​
       
            if (reply) {
              //等待响应
                err = waitForResponse(reply);
            } else {
                Parcel fakeReply;
                err = waitForResponse(&fakeReply);
            }
            #if 0
            if (code == 4) { // relayout
                ALOGI("<<<<<< RETURNING transaction 4");
            } else {
                ALOGI("<<<<<< RETURNING transaction %d", code);
            }
            #endif
    ​
            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                    << handle << ": ";
                if (reply) alog << indent << *reply << dedent << endl;
                else alog << "(none requested)" << endl;
            }
        } else {
            err = waitForResponse(nullptr, nullptr);
        }
    ​
        return err;
    }


    // transact 里面会调用 writeTransactionData
    status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
        int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
    {
        binder_transaction_data tr;//用户空间和内核空间 共用的结构体
    ​
        tr.target.ptr = 0; 
        tr.target.handle = handle;//很关键
        tr.code = code; //就是aidl 里面掉的方法code 从0开始那个
        tr.flags = binderFlags;
        tr.cookie = 0;
        tr.sender_pid = 0;
        tr.sender_euid = 0;
    ​
        const status_t err = data.errorCheck();
        if (err == NO_ERROR) {
           //从data 里面取出数据  那边也用这个结构体 里面存的是指针地址
            tr.data_size = data.ipcDataSize();
            tr.data.ptr.buffer = data.ipcData();
            tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
            tr.data.ptr.offsets = data.ipcObjects();
        } else if (statusBuffer) {
            tr.flags |= TF_STATUS_CODE;
            *statusBuffer = err;
            tr.data_size = sizeof(status_t);
            tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
            tr.offsets_size = 0;
            tr.data.ptr.offsets = 0;
        } else {
            return (mLastError = err);
        }
       //数据拼装完成   mOut 是个 Parcel  相当于数据写进进去
        mOut.writeInt32(cmd);
        mOut.write(&tr, sizeof(tr));
    ​
        return NO_ERROR;
    }
    // binder 里面对buffer 只拷贝一次因为这个比较大 ,其他的结构体的其他属性 还是拷贝两次的

        //等待结果

    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    {
        uint32_t cmd;
        int32_t err;
    ​
        while (1) {
           // 进入talkWithDriver()
            if ((err=talkWithDriver()) < NO_ERROR) break;
            err = mIn.errorCheck();
            if (err < NO_ERROR) break;
            if (mIn.dataAvail() == 0) continue;
    ​
            cmd = (uint32_t)mIn.readInt32();
    ​
          
    ​
            switch (cmd) {
            case BR_ONEWAY_SPAM_SUSPECT:
               
                CallStack::logStack("oneway spamming", CallStack::getCurrent().get(),
                        ANDROID_LOG_ERROR);
                [[fallthrough]];
            case BR_TRANSACTION_COMPLETE:
                if (!reply && !acquireResult) goto finish;
                break;
    ​
            case BR_DEAD_REPLY:
                err = DEAD_OBJECT;
                goto finish;
    ​
            case BR_FAILED_REPLY:
                err = FAILED_TRANSACTION;
                goto finish;
    ​
            case BR_FROZEN_REPLY:
                err = FAILED_TRANSACTION;
                goto finish;
    ​
            case BR_ACQUIRE_RESULT:
                {
                 
                    const int32_t result = mIn.readInt32();
                    if (!acquireResult) continue;
                    *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
                }
                goto finish;
    ​
            case BR_REPLY:
                {
                    binder_transaction_data tr;
                    err = mIn.read(&tr, sizeof(tr));
                   
                    if (err != NO_ERROR) goto finish;
    ​
                    if (reply) {
                        if ((tr.flags & TF_STATUS_CODE) == 0) {
                            reply->ipcSetDataReference(
                                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                                tr.data_size,
                                reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                                tr.offsets_size/sizeof(binder_size_t),
                                freeBuffer);
                        } else {
                            err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                            freeBuffer(nullptr,
                                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                                tr.data_size,
                                reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                                tr.offsets_size/sizeof(binder_size_t));
                        }
                    } else {
                        freeBuffer(nullptr,
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t));
                        continue;
                    }
                }
                goto finish;
    ​
            default:
                err = executeCommand(cmd);
                if (err != NO_ERROR) goto finish;
                break;
            }
        }
    ​
    finish:
        if (err != NO_ERROR) {
            if (acquireResult) *acquireResult = err;
            if (reply) reply->setError(err);
            mLastError = err;
        }
    ​
        return err;
    }



    status_t IPCThreadState::talkWithDriver(bool doReceive)
    {
        if (mProcess->mDriverFD < 0) {
            return -EBADF;
        }
    ​
       //读写结构体
        binder_write_read bwr;
    ​
       
        const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    ​
       
        const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    ​
       //获取传入的大小
        bwr.write_size = outAvail;
       //从out里面把数据取出来
        bwr.write_buffer = (uintptr_t)mOut.data();
    ​
      
        if (doReceive && needRead) {
            bwr.read_size = mIn.dataCapacity();
            bwr.read_buffer = (uintptr_t)mIn.data();
        } else {
          //先走write 所以read 就是0
            bwr.read_size = 0;
            bwr.read_buffer = 0;
        }
    ​
     
    ​
      //无读无写就错误了
        if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
    ​
        bwr.write_consumed = 0;
        bwr.read_consumed = 0;
        status_t err;
       
    #if defined(__ANDROID__)
        //  bwr 组装好  调用 ioctl   将组好的 结构体 传入进去了
            if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                err = NO_ERROR;
            else
                err = -errno;
    #else
            err = INVALID_OPERATION;
    #endif
            if (mProcess->mDriverFD < 0) {
                err = -EBADF;
            }
           
        } while (err == -EINTR);
    ​
      
    ​
        if (err >= NO_ERROR) {
            if (bwr.write_consumed > 0) {
                if (bwr.write_consumed < mOut.dataSize())
                    
                else {
                    mOut.setDataSize(0);
                    processPostWriteDerefs();
                }
            }
            if (bwr.read_consumed > 0) {
                mIn.setDataSize(bwr.read_consumed);
                mIn.setDataPosition(0);
            }
            
            return NO_ERROR;
        }
    ​
        return err;
    }
   
    //总结 弄了个结构体 给 ioctl了 会调用 binder_ioctl
    

binder_ioctl


    static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
      //这里cmd 是上面传的 BINDER_WRITE_READ
      int ret;
      struct binder_proc *proc = filp->private_data;
      struct binder_thread *thread;
      unsigned int size = _IOC_SIZE(cmd);
      void __user *ubuf = (void __user *)arg;
    ​
    ​
    ​
      binder_selftest_alloc(&proc->alloc);
    ​
      trace_binder_ioctl(cmd, arg);
    ​
      ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
      if (ret)
        goto err_unlocked;
    //进程里 获取thread 
      thread = binder_get_thread(proc);
      if (thread == NULL) {
        ret = -ENOMEM;
        goto err;
      }
    ​
      switch (cmd) {
      case BINDER_WRITE_READ:
          //走这
        ret = binder_ioctl_write_read(filp, cmd, arg, thread);
        if (ret)
          goto err;
        break;
      case BINDER_SET_MAX_THREADS: {
        int max_threads;
    ​
        if (copy_from_user(&max_threads, ubuf,
               sizeof(max_threads))) {
          ret = -EINVAL;
          goto err;
        }
        binder_inner_proc_lock(proc);
        proc->max_threads = max_threads;
        binder_inner_proc_unlock(proc);
        break;
      }
      case BINDER_SET_CONTEXT_MGR:
        ret = binder_ioctl_set_ctx_mgr(filp);
        if (ret)
          goto err;
        break;
      case BINDER_THREAD_EXIT:
        
        binder_thread_release(proc, thread);
        thread = NULL;
        break;
      case BINDER_VERSION: {
        struct binder_version __user *ver = ubuf;
    ​
        if (size != sizeof(struct binder_version)) {
          ret = -EINVAL;
          goto err;
        }
        if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
               &ver->protocol_version)) {
          ret = -EINVAL;
          goto err;
        }
        break;
      }
      case BINDER_GET_NODE_INFO_FOR_REF: {
        struct binder_node_info_for_ref info;
    ​
        if (copy_from_user(&info, ubuf, sizeof(info))) {
          ret = -EFAULT;
          goto err;
        }
    ​
        ret = binder_ioctl_get_node_info_for_ref(proc, &info);
        if (ret < 0)
          goto err;
    ​
        if (copy_to_user(ubuf, &info, sizeof(info))) {
          ret = -EFAULT;
          goto err;
        }
    ​
        break;
      }
      case BINDER_GET_NODE_DEBUG_INFO: {
        struct binder_node_debug_info info;
    ​
        if (copy_from_user(&info, ubuf, sizeof(info))) {
          ret = -EFAULT;
          goto err;
        }
    ​
        ret = binder_ioctl_get_node_debug_info(proc, &info);
        if (ret < 0)
          goto err;
    ​
        if (copy_to_user(ubuf, &info, sizeof(info))) {
          ret = -EFAULT;
          goto err;
        }
        break;
      }
      default:
        ret = -EINVAL;
        goto err;
      }
      ret = 0;
    err:
      if (thread)
        thread->looper_need_return = false;
      wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    ​
    err_unlocked:
      trace_binder_ioctl_done(ret);
      return ret;
    }
    ​


    
    static int binder_ioctl_write_read(struct file *filp,
            unsigned int cmd, unsigned long arg,
            struct binder_thread *thread)
    {
      int ret = 0;
      struct binder_proc *proc = filp->private_data;
      unsigned int size = _IOC_SIZE(cmd);
      //来自于用户端 所以是user
      void __user *ubuf = (void __user *)arg;
      //内核空间的地址
      struct binder_write_read bwr;
    ​
      //肯定等于 所以不进去
      if (size != sizeof(struct binder_write_read)) {
        ret = -EINVAL;
        goto out;
      }
      //走 这 将用户空间的 地址里的东西 copy内核结构体里面去
      if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
      }
    ​
    ​
      if (bwr.write_size > 0) {//有数据肯定大于0  走 binder_thread_write
        ret = binder_thread_write(proc, thread,
                bwr.write_buffer,
                bwr.write_size,
                &bwr.write_consumed);//这里 write_consumed 是0
        trace_binder_write_done(ret);
        if (ret < 0) {
          bwr.read_consumed = 0;
          if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
            ret = -EFAULT;
          goto out;
        }
      }
      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);
        binder_inner_proc_lock(proc);
        if (!binder_worklist_empty_ilocked(&proc->todo))
          binder_wakeup_proc_ilocked(proc);
        binder_inner_proc_unlock(proc);
        if (ret < 0) {
          if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
            ret = -EFAULT;
          goto out;
        }
      }
      
      if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
      }
    out:
      return ret;
    }


    static int binder_thread_write(struct binder_proc *proc,
          struct binder_thread *thread,
          binder_uintptr_t binder_buffer, size_t size,
          binder_size_t *consumed){ // consumed 0   size 是buffer 长度
      
     
      uint32_t cmd;
      struct binder_context *context = proc->context;
      //又转成user
      void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
      void __user *ptr = buffer + *consumed;
      void __user *end = buffer + size;
      
      
      
      while (ptr < end && thread->return_error.cmd == BR_OK) {
        int ret;
    //IPCThreadState::transact {   err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);}
        //这里所以是 BC_TRANSACTION
        if (get_user(cmd, (uint32_t __user *)ptr))
          return -EFAULT;
        ptr += sizeof(uint32_t);
        trace_binder_command(cmd);
        if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
          atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);
          atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);
          atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);
        }
        switch (cmd) {
        
    ​
        //省略。。。
          
        
      
            
            //走这里
        case BC_TRANSACTION:
        case BC_REPLY: {
          struct binder_transaction_data tr;
           //将用户空间的数据 拷贝到内核空间变量里了
          if (copy_from_user(&tr, ptr, sizeof(tr)))
            return -EFAULT;
          ptr += sizeof(tr);//做偏移
          //调用binder_transaction   第三个参数 是false
        
          binder_transaction(proc, thread, &tr,
                 cmd == BC_REPLY, 0);
          break;
        }
    ​
      
        
    ​
        //省略。。。default:
          pr_err("%d:%d unknown command %d\n",
                 proc->pid, thread->pid, cmd);
          return -EINVAL;
        }
        *consumed = ptr - buffer;
      }
      return 0;
      
      
    }


//调用到binder_transaction
    static void binder_transaction(struct binder_proc *proc,
                 struct binder_thread *thread,
                 struct binder_transaction_data *tr, int reply,
                 binder_size_t extra_buffers_size){
      //reply 为false 是0  最后 extra_buffers_size 为0   tr是关键
      //省略
      if(reply){
        //省略
      } else{
        if (tr->target.handle) {//之前构造的handle 是0 则为SM
          //ProcessState::getContextObject Sm构造的时候 自己是0
          //可以  看 BpBinder.cpp 中的  BpBinder::create
          //这里代码可以看ProcessState::getContextObject 有一个基础的调用过程
          //最后构建了 一个 binder_transaction_data 里面加入的handle 就是0 正好对应binder.c 里面的基础流程
          
          struct binder_ref *ref;
    ​
          //加锁
          binder_proc_lock(proc);
          //看该方法
          ref = binder_get_ref_olocked(proc, tr->target.handle,
                     true);
          if (ref) {//找到对方进程的binder node  这玩意相当于 binder 实现
            //因为你可能一对多 在binder_open 里面
            // 调用 加入进去的hlist_add_head(&proc->proc_node, &binder_procs);
            //一般情况下是1对1  正常来说 target_node=ref->node->proc;
            // tagget_node 相当于 内核里面对应的那块 proc 相当于具体哪个进程的
            //
            target_node = binder_get_node_refs_for_txn(
                ref->node, &target_proc,
                &return_error);
          } else {
            binder_user_error("%d:%d got transaction to invalid handle\n",
                  proc->pid, thread->pid);
            return_error = BR_FAILED_REPLY;
          }
          binder_proc_unlock(proc);
        } 
        
        //省略
        if (target_thread)
        e->to_thread = target_thread->pid;
      e->to_proc = target_proc->pid;
    ​
       //申请内存  struct binder_transaction *t; 结构体
      t = kzalloc(sizeof(*t), GFP_KERNEL);
        
        //省略
         //给t 的from 赋值
        if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
        else
        t->from = NULL;
        //赋值。。。
      t->sender_euid = task_euid(proc->tsk);
      t->to_proc = target_proc;
      t->to_thread = target_thread;
      t->code = tr->code;
      t->flags = tr->flags;
      if (!(t->flags & TF_ONE_WAY) &&
          binder_supported_policy(current->policy)) {
      
        t->priority.sched_policy = current->policy;
        t->priority.prio = current->normal_prio;
      } else {
      
        t->priority = target_proc->default_priority;
        
        trace_binder_transaction(reply, t, target_node);
    // buffer   参数 分别是申请内存的相关  offsets_size 感觉没啥用  extra_buffers_size默认为0 
        //这个buffer 其实是在目标对象的内存空间申请的 
      t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
        tr->offsets_size, extra_buffers_size,
        !reply && (t->flags & TF_ONE_WAY));
        
        //省略
        //把data buffer 拷贝 datasize的长度到 t的buffer里面 这里是ipcdata
        if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
             tr->data.ptr.buffer, tr->data_size)) {
        binder_user_error("%d:%d got transaction with invalid data ptr\n",
            proc->pid, thread->pid);
        return_error = BR_FAILED_REPLY;
        return_error_param = -EFAULT;
        return_error_line = __LINE__;
        goto err_copy_data_failed;
      }
        //copy 
      if (copy_from_user(offp, (const void __user *)(uintptr_t)
             tr->data.ptr.offsets, tr->offsets_size)) {
        binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
            proc->pid, thread->pid);
        return_error = BR_FAILED_REPLY;
        return_error_param = -EFAULT;
        return_error_line = __LINE__;
        goto err_copy_data_failed;
      }
        //省略
        
        for (; offp < off_end; offp++) {
        struct binder_object_header *hdr;
         
    ​
        //省略
          //将t的buffer中data 转回了 binder_object_header
          //可能将binder 转为handle类型 因为需要在对应的进程里面进行查询 添加
        hdr = (struct binder_object_header *)(t->buffer->data + *offp);
        off_min = *offp + object_size;
        switch (hdr->type) {// 获取类型
        case BINDER_TYPE_BINDER://可以理解为就是这个类型
        case BINDER_TYPE_WEAK_BINDER: {
          struct flat_binder_object *fp;
    ​
          fp = to_flat_binder_object(hdr);
          ret = binder_translate_binder(fp, t, thread);
          if (ret < 0) {
            return_error = BR_FAILED_REPLY;
            return_error_param = ret;
            return_error_line = __LINE__;
            goto err_translate_failed;
          }
        } break;
            
        case BINDER_TYPE_HANDLE:
        case BINDER_TYPE_WEAK_HANDLE: {
          struct flat_binder_object *fp;
          struct binder_ref_data rdata;
          int ret;
    ​
          fp = to_flat_binder_object(hdr);
          ret = binder_dec_ref_for_handle(proc, fp->handle,
            hdr->type == BINDER_TYPE_HANDLE, &rdata);
    ​
          if (ret) {
            pr_err("transaction release %d bad handle %d, ret = %d\n",
             debug_id, fp->handle, ret);
            break;
          }
          binder_debug(BINDER_DEBUG_TRANSACTION,
                 "        ref %d desc %d\n",
                 rdata.debug_id, rdata.desc);
        } break;
        
        //省略
            //赋值为 数据传输完成
        tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
            //t的状态切换为工作
      t->work.type = BINDER_WORK_TRANSACTION;
            
            
      if (reply) {
        binder_enqueue_thread_work(thread, tcomplete);
        binder_inner_proc_lock(target_proc);
        if (target_thread->is_dead) {
          binder_inner_proc_unlock(target_proc);
          goto err_dead_proc_or_thread;
        }
        BUG_ON(t->buffer->async_transaction != 0);
        binder_pop_transaction_ilocked(target_thread, in_reply_to);
        binder_enqueue_thread_work_ilocked(target_thread, &t->work);
        binder_inner_proc_unlock(target_proc);
        wake_up_interruptible_sync(&target_thread->wait);
        binder_restore_priority(current, in_reply_to->saved_priority);
        binder_free_transaction(in_reply_to);
      } else if (!(t->flags & TF_ONE_WAY)) {
        //不是回复 走这
      
        binder_inner_proc_lock(proc);
        
        binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete);
        //跟T走 1 需要回复
        t->need_reply = 1;
        //现在还是null
        t->from_parent = thread->transaction_stack;
        //把transaction_stack 赋值为t
        thread->transaction_stack = t;
        binder_inner_proc_unlock(proc);
          //任务放进todo 队列 唤醒了线程 准备干活
        if (!binder_proc_transaction(t, target_proc, target_thread)) {
          binder_inner_proc_lock(proc);
          binder_pop_transaction_ilocked(thread, t);
          binder_inner_proc_unlock(proc);
          goto err_dead_proc_or_thread;
        }
      } else {
      //省略
      }
      //省略
      smp_wmb();
      WRITE_ONCE(e->debug_id_done, t_debug_id);
      return;
    ​
      
      }
        
      }
      
    }



    static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc,
                 u32 desc, bool need_strong_ref)
    {
      struct rb_node *n = proc->refs_by_desc.rb_node;
      struct binder_ref *ref;
      //相当于红黑树 遍历出来对应的ref
      while (n) {
        ref = rb_entry(n, struct binder_ref, rb_node_desc);
    ​
        if (desc < ref->data.desc) {
          n = n->rb_left;
        } else if (desc > ref->data.desc) {
          n = n->rb_right;
        } else if (need_strong_ref && !ref->data.strong) {
      
          return NULL;
        } else {
          return ref;
        }
      }
      return NULL;
    }


    struct binder_ref {
      
      struct binder_ref_data data;
      struct rb_node rb_node_desc;
      struct rb_node rb_node_node;
      struct hlist_node node_entry;
      struct binder_proc *proc;
      struct binder_node *node;
      struct binder_ref_death *death;
    };

    static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset)
    {
      /* Check if we can read a header first */
      struct binder_object_header *hdr;
      size_t object_size = 0;
    ​
      if (offset > buffer->data_size - sizeof(*hdr) ||
          buffer->data_size < sizeof(*hdr) ||
          !IS_ALIGNED(offset, sizeof(u32)))
        return 0;
    ​
      /* Ok, now see if we can read a complete object. */
      hdr = (struct binder_object_header *)(buffer->data + offset);
      switch (hdr->type) {
      case BINDER_TYPE_BINDER://binder 类型
      case BINDER_TYPE_WEAK_BINDER:
      case BINDER_TYPE_HANDLE:
      case BINDER_TYPE_WEAK_HANDLE:
        object_size = sizeof(struct flat_binder_object);
        break;
      case BINDER_TYPE_FD:
        object_size = sizeof(struct binder_fd_object);
        break;
      case BINDER_TYPE_PTR:
        object_size = sizeof(struct binder_buffer_object);
        break;
      case BINDER_TYPE_FDA:
        object_size = sizeof(struct binder_fd_array_object);
        break;
      default:
        return 0;
      }
      if (offset <= buffer->data_size - object_size &&
          buffer->data_size >= object_size)
        return object_size;
      else
        return 0;
    }

大家常说的Binder只有一次拷贝,这个怎么简单理解呢。就是A进程, 其实在构建对象的时候,自己也不知自己需要跨进程。不可能这会直接往共享内存干。 他会在自己的堆栈空间里,找一块放这些数据。

然后 需要跨进程的时候,内核空间开一块 物理内存 给他俩进程共享,把数据拷贝到这块共享内存 就是一次拷贝。

但是 其实 Parcel 中的 mData 中的对象才会一次拷贝,因为比较大。 结构体里面的其他数据是不会的。因为很小。还是需要 先搞到内核, 然后内核再拷到对方那去。

还有数据的偏移问题,Parcel 数据都在mData 里面 ,但是 比如被包装为flat_binder_object

这种,只能记录在mObject 里。 然后读的时候 就先算 在mObject 之前需要偏移多少,然后挨个读。 mObject里面要知道 第一个对象 开始和结束,第二个开始结束。

mData mObject 这玩意数据量大,只拷贝一次,像一般的基础类型,其实是不会节省。


    static bool binder_proc_transaction(struct binder_transaction *t,
                struct binder_proc *proc,
                struct binder_thread *thread)
    {
      struct binder_node *node = t->buffer->target_node;
      struct binder_priority node_prio;
      bool oneway = !!(t->flags & TF_ONE_WAY);
      bool pending_async = false;
    ​
      BUG_ON(!node);
      binder_node_lock(node);
      node_prio.prio = node->min_priority;
      node_prio.sched_policy = node->sched_policy;
    ​
      if (oneway) {
        BUG_ON(thread);
        if (node->has_async_transaction) {
          pending_async = true;
        } else {
          node->has_async_transaction = 1;
        }
      }
    ​
      binder_inner_proc_lock(proc);
    ​
      //没死
      if (proc->is_dead || (thread && thread->is_dead)) {
        binder_inner_proc_unlock(proc);
        binder_node_unlock(node);
        return false;
      }
    //现在thread是null
      if (!thread && !pending_async)
        //从等待的处理线程里找一个出来
        thread = binder_select_thread_ilocked(proc);
    ​
      if (thread) {
        //提高线程优先级 让他干活 加入到队列里
        binder_transaction_priority(thread->task, t, node_prio,
                  node->inherit_rt);
        binder_enqueue_thread_work_ilocked(thread, &t->work);
      } else if (!pending_async) {
        binder_enqueue_work_ilocked(&t->work, &proc->todo);
      } else {
        binder_enqueue_work_ilocked(&t->work, &node->async_todo);
      }
    ​
      if (!pending_async)
        //唤醒线程干活
        binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);
    ​
      binder_inner_proc_unlock(proc);
      binder_node_unlock(node);
    ​
      return true;
    }

#### binder的读取

    //binder_wakeup_thread_ilocked()-->唤醒等待的线程//native/libs/binder/IPCThreadState.cpp 
    //会一直等待
    void IPCThreadState::joinThreadPool(bool isMain)
      -->getAndExecuteCommand()
         -->talkWithDriver()
    {
         if (doReceive && needRead) {
           //这次走read
            bwr.read_size = mIn.dataCapacity();
            bwr.read_buffer = (uintptr_t)mIn.data();
        } else {
            bwr.read_size = 0;
            bwr.read_buffer = 0;
        }
      #if defined(__ANDROID__)
      //走ioctl
            if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                err = NO_ERROR;
      
    }
    ​
    //--------------------ioctrl 代码开始------------------------------   
    --->Binder.c /binder_ioctl(){
      case BINDER_WRITE_READ:
        ret = binder_ioctl_write_read(filp, cmd, arg, thread);
        if (ret)
          goto err;
        break;
    }
      -->binder_ioctl_write_read() {
        //省略
        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);
        binder_inner_proc_lock(proc);
        if (!binder_worklist_empty_ilocked(&proc->todo))
          binder_wakeup_proc_ilocked(proc);
        binder_inner_proc_unlock(proc);
        if (ret < 0) {
          if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
            ret = -EFAULT;
          goto out;
        }
      }
      }
    --> binder_thread_read(){
      //省略 等待别人唤醒
      ret = binder_wait_for_work(thread, wait_for_proc_work);
      
      //looper 被重置掉 可以走下面代码
      thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
      //省略
        switch (w->type) {
        
            whilie(1){
    struct binder_transaction *t = NULL;
           /省略   
        case BINDER_WORK_TRANSACTION: {
          //加锁
          binder_inner_proc_unlock(proc);
          //算出t 的启点 其实t就是传过来的数据的相关内容
          t = container_of(w, struct binder_transaction, work);
          
            //省略
          //把t的相关都拿出来 拷贝到这个进程空间里面
          if (t->buffer->target_node) {
          struct binder_node *target_node = t->buffer->target_node;
          struct binder_priority node_prio;
    ​
          tr.target.ptr = target_node->ptr;
          tr.cookie =  target_node->cookie;
          node_prio.sched_policy = target_node->sched_policy;
          node_prio.prio = target_node->min_priority;
          binder_transaction_priority(current, t, node_prio,
                    target_node->inherit_rt);
          cmd = BR_TRANSACTION;
        }
          //继续赋值用户端传递的数据
       tr.code = t->code;
        tr.flags = t->flags;
        tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
            t_from = binder_get_txn_from(t);
          //数据长度
            tr.data_size = t->buffer->data_size;
          //偏移
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.offsets = tr.data.ptr.buffer +
              ALIGN(t->buffer->data_size,
                  sizeof(void *));
          //
          if (put_user(cmd, (uint32_t __user *)ptr)) {
          if (t_from)
            binder_thread_dec_tmpref(t_from);
    ​
          binder_cleanup_transaction(t, "put_user failed",
                   BR_FAILED_REPLY);
    ​
          return -EFAULT;
        }
          //做偏移
        ptr += sizeof(uint32_t);
          //内核里面的东西拷贝到ptr里
        if (copy_to_user(ptr, &tr, sizeof(tr))) {
          if (t_from)
            binder_thread_dec_tmpref(t_from);
    ​
          binder_cleanup_transaction(t, "copy_to_user failed",
                   BR_FAILED_REPLY);
    ​
          return -EFAULT;
        }
          //省略
      }
    }
    // --------------------ioctrl 代码结束------------------------------    
         
           //继续走 getAndExecuteCommand 后面的代码
            
    result = executeCommand(cmd);
            {
               case BR_TRANSACTION_SEC_CTX:
        case BR_TRANSACTION:
              
              {
                //省略 
                 result = mIn.read(&tr, sizeof(tr));
                 tr_secctx.secctx = 0;
             buffer.ipcSetDataReference(
                    reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                    tr.data_size,
                    reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                    tr.offsets_size/sizeof(binder_size_t), freeBuffer);
                 //省略  执行到bbinder
                  error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                                &reply, tr.flags);
                
              }
              
            }        
        // 就是一读一写  通知线程等待和唤醒    ioctrl 才是开始进入内核状态