android 4.1 Binder驱动笔记

1. __init binder_init(void)

(1)创建binder_deferred_workqueue工作队列。

(2)注册binder驱动。misc_register(&binder_miscdev);

2. __init binder_open(struct inode *nodp, struct file *filp)

(1)每次调用binder_open,驱动都会申请一个binder_proc对象并初始化(部分全局数据操作需要binder_lock锁)。

struct binder_proc {
 struct hlist_node proc_node;-------------------->本proc_node将会链接到binder_procs这个全局链表中。
 struct rb_root threads;  -------------------->在ioctrl调用中,会将属于本进程的所有线程链入这颗红黑树。
 struct rb_root nodes;
 struct rb_root refs_by_desc;
 struct rb_root refs_by_node;
 int pid;          -------------------->current->group_leader->pid;
 struct vm_area_struct *vma;
 struct mm_struct *vma_vm_mm;
 struct task_struct *tsk;  -------------------->指向调用binder_open的当前进程。
 struct files_struct *files;
 struct hlist_node deferred_work_node;
 int deferred_work;
 void *buffer;-------------------->mmap操作后,指向内存映射后的虚拟地址(内核空间使用)。
 ptrdiff_t user_buffer_offset;---------------->mmap操作后,内核使用的虚拟地址和用户空间虚拟地址偏差。

 struct list_head buffers;-------------------->mmap后,将映射的内存页面链接起来。详细结构体为binder_buffer。
 struct rb_root free_buffers; -------------------->mmap后,空闲页面通过红黑树链接起来。详细结构体为binder_buffer。
 struct rb_root allocated_buffers; -------------------->正在使用的页面数据,链入该红黑树。详细结构体为binder_buffer。
 size_t free_async_space;-------------------->mmap操作后为proc->buffer_size / 2

 struct page **pages;---------------->mmap操作后,保存内核页面物理地址。
 size_t buffer_size; -------------------->mmap操作后,指示实际已映射的空间大小。
 uint32_t buffer_free;
 struct list_head todo;  -------------------->指向进程工作队列(binder事物处理)。
 wait_queue_head_t wait;-------------------->初始化等待队列。
 struct binder_stats stats;
 struct list_head delivered_death;--->初始化本队列。binder die后,会通过这个链表通知客户端本binder已经死了。
 int max_threads;
 int requested_threads;
 int requested_threads_started;
 int ready_threads;
 long default_priority;  -------------------->调用open的进程nice值(优先级号)。
 struct dentry *debugfs_entry;
};

(2)binder_stats.obj_created[BINDER_STAT_PROC]++; //用于统计binder proc创建的数目。

(3)binder_procs:当前创建的binder_proc对象会链接到这里。

(4)filp->private_data:保存当前创建的binder_proc,供其他binder驱动调用使用。

 

 3. static int binder_mmap(struct file *filp, struct vm_area_struct *vma)

(1):客户端部分:使用api:void *mmap(void *start, size_t length, int prot, int flags,   int fd, off_t offset);来调用。

I.   start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。

II.  length:映射区的长度。

III. prot:期望的内存保护标志,不能与文件的打开模式冲突。

IV.flags:指定映射对象的类型,映射选项和映射页是否可以共享。

V.fd:有效的文件描述符。

VI.offset:被映射对象内容的起点。

(2):驱动部分:

1- 通过传入的filp,获取filp->private_data数据,拿到open_binder时创建的binder_proc对象指针。

2- 内存映射控制在4M以内。

3- vm_struct *area; area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); 申请内核使用的一片虚拟内存空间。需要获取binder_mmap_lock锁。

4- proc->buffer = area->addr;  proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;

5- proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);申请page结构体队列空间(后来会申请物理页面)。

6- vma->vm_ops = &binder_vm_ops;  vma->vm_private_data = proc; //proc对象存入vma->vm_privae_data。

7- mm_struct结构描述了一个进程的整个虚拟地址空间。vm_struct结构来表示vmalloc使用的线性地址.

8- map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr);//内核虚拟地址空间和物理空间关联起来。

9- user_page_addr = (uintptr_t)page_addr + proc->user_buffer_offset;//由于open_binder时,算出了应用空间虚拟地址与内核虚拟地址的偏移量。因此,给定一个内核地址虚拟地址,可以快速计算出用户虚拟地址。

10- ret = vm_insert_page(vma, user_page_addr, page[0]); //将物理页面与用户的虚拟地址空间关联起来。

 

4. static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

(1)binder_ioctl调用先从filp中获取binder_proc变量。并在使用这个文件句柄的binder_proc对象中,查找是否存在本pid的binder_thread对象,没有就创建一个,并链入filp对应的binder_proc中。这样每个open_binder中获得的文件句柄会包含一个binder_proc,使用该文件句柄的每个进程会有一个对应的binder_thread,并链入binder_proc。

struct binder_thread {
  struct binder_proc *proc;-------------------->指向所属的binder_proc对象。
  struct rb_node rb_node; -------------------->链入binder_proc中的threads红黑树所用的节点对象。
  int pid;-------------------->当前线程的pid
  int looper; --------------->指示当前线程状态,初始状态为:BIDER_LOOPER_STATE_NEED_RETURN
  struct binder_transaction *transaction_stack; -------------------->保存本线程将要处理的事务列表
  struct list_head todo; ---------------->保存线程的数据列表。
  uint32_t return_error; /* Write failed, return error code in read buf */
  uint32_t return_error2; /* Write failed, return error code in read */
   /* buffer. Used when sending a reply to a dead process that */
   /* we are also waiting on */
  wait_queue_head_t wait;-------------------->用于将本线程加入某个等待队列用。
  struct binder_stats stats;-------------------->线程统计信息。
};

(2)case BINDER_WRITE_READ:最重要的binder操作ioctl操作码。

struct binder_write_read {
 signed long write_size; /* bytes to write */
 signed long write_consumed; /* bytes consumed by driver */
 unsigned long write_buffer;
 signed long read_size; /* bytes to read */
 signed long read_consumed; /* bytes consumed by driver */
 unsigned long read_buffer;
};

如果write_size>0,表示有数据写。则开始执行一次binder命令操作。

 I

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值