android的binder驱动1

1332阅读 0评论2011-05-17 clzhana
分类:C/C++

androidbinder驱动1 - 简单的先写

module

init函数binder_init
1
create_singlethread_workqueue(“binder”)创建一个workqueue来做一些延迟工作。以前是静态创建的,2.2改为在init中创建。
2
proc文件系统中建立目录binderbinder/proc
3
注册binder驱动。
4
/proc/binder下建立几个proc文件state, stats, transactions, transaction_log, failed_transaction_log,这些个proc文件和/binder/proc/pid都可以读出binder相关的状态和统计信息,/binder/proc/pid是各个binder进程的信息,会在open函数中建立。这些个proc文件能帮助理解binder,可惜的是,有长度限制,最多只会打印一个内存页面那么多字节,对于node或者ref多的进程,信息就显示不全,比如system_serverbinder信息。具体每个文件的信息等把binder的数据结构写完了再加上。

exit函数,无,built-in的,不需要这个

module参数
1
参数可在/sys/module/binder/parameters下找到,可读可写。
2
debug_mask,调试标志位,参考enum BINDER_DEBUG_XXX,相应bit1能看到相应的调试信息,都是KERN_INFO级别。不过adb下是看不到printk的,得dmesg或者用串口看。这个参数的设置可以帮助理解binder驱动的工作流程。
3
proc_no_lock,查看proc文件时是否加binder全局锁,一般不加,查看proc一般也不需要得到最准确的信息,没必要锁着,影响binder工作。
4
stop_on_user_error,设置为0时,不起作用,设置为1时,如果某个进程调用binder时发生错误,则该进程sleep,以后别的进程再调用binderioctl也会sleep,此时你若往这个参数写入一个小于2的数,进程会被唤醒。设置为2以上的值,那悲剧了,ioctl直接睡觉。该参数默认为0

文件操作open - binder_open
1
创建binder_proc结构体用来记录调用进程的信息,并进行相关初始化工作。将该结构体指针记录到filp->private_data,这样以后别的文件操作都能得到当前进程的binder信息。
2
建立/proc/binder/pid文件,用于查询进程的binder信息。

文件操作mmap - binder_mmap
1
内核内存空间中分配最大4M的连续空间给进程,并关联到进程的用户空间。之所以要连续的,是为了方便的维护与用户空间地址的映射,内核地址只需要加上一个偏移量proc->user_buffer_offset就能得到用户地址了。
2
该空间用于transaction交互数据用。假设A是服务程序,B是客户程序,B发出请求后,驱动会把B传送的数据从B的用户空间拷贝到内核中分配给A进程的内存空间,然后通知A进程工作,由于内核空间的内存已经通过mmap映射到A的用户空间,驱动只需要给A进程一个指向内核空间的用户指针即可,A就能获得从B考过来的数据,于是节省了一次从驱动到A用户空间的数据拷贝。
3
由于该操作负责分配空间给进程,所以使用binder的进程必须调用一次,设定其用于transaction的总buffer空间,一般在open之后就会执行,否则无法进行transaction服务,会得到BR_FAILED_REPLY,如果空间不够用的时候,同样会得到这个BR
4
操作流程,get_vm_area获取内核空间的一段连续虚拟地址,kzalloc一段空间给proc->pages用于保存页表节点,binder_update_page_range调用alloc_page分配页面并用map_vm_area关联到内核的虚拟地址,同时用vm_insert_page把分配到的页面添加到进程的用户空间。注意,mmap的时候只分配了第一个页面,其余的页面在以后调用binder_alloc_buf的时候才分配,也算是一种page on demand吧。
5
这个操作还会保存进程的files_structbinder_struct中用于binderfd操作。
6
fd操作和buffer的操作写binder具体操作的时候再加上。

文件操作poll - binder_poll
1
检查是否有procthread的工作要做,有的话返回POLLIN
2
没有的话进行poll_wait
3
醒来之后再次检查,有工作要做的话返回POLLIN,否则返回0

文件操作unlocked_ioctl - binder_ioctl
1
进入时检查binder_stop_on_user_error(前面提到的模块参数stop_on_user_error),确定是否wait
2
binder_get_thread(proc),获取或者初始化当前线程在binder中的节点。binder_proc中有颗红黑树threads用结构体binder_thread记录了各个thread的信息,这是颗按pid排列的二叉查找树。比较重要的初始化,每个binder_threadlooperBINDER_LOOPER_STATE_NEED_RETURN标记被设置,这将使得任何一个线程的第一次ioctl一定回返回,而不会阻塞在read阶段。binder writeread操作的时候再详细说明。
3
各种binder ioctl操作。
4
清空线程looperBINDER_LOOPER_STATE_NEED_RETURN,没有这个标记之后,以后的ioctl就有可能阻塞在read阶段,写binder writeread操作的时候再详细说明。
5
返回前再次检查binder_stop_on_user_error(前面提到的模块参数stop_on_user_error),确定是否wait
6
以下是几个ioctl所做的事情,其中BINDER_WRITE_READ过于复杂,以后writeread操作时再写。
7
BINDER_SET_MAX_THREADS,设置进程的最大生成线程max_threads,具体操作BC_REGISTER_LOOPER时用到。
8
BINDER_SET_CONTEXT_MGR,设置当前进程为service manager,用全局变量记录下来。binder是一个服务和客户通讯的协议,客户为了能跟服务搭上线,需要有个地方能查找服务的实际所在,只有在获取服务的实际所在才能提出后面的各种要求,而为客户牵线的便是这个service manager进程,这个得等下binder框架层才能说的更清楚了。
9
BINDER_THREAD_EXIT,当前线程退出binder驱动,清理其在binder_get_thread中创建的节点,同时会给那些跟他transaction的线程发个BR_DEAD_REPLY表明自己挂了。
10
BINDER_VERSION,获取binder协议版本。

文件操作flush – binder_flush
1
调用binder_defer_work(proc, BINDER_DEFERED_FLUSH)flush的工作交给binder_init中创建的workqueue来延迟执行。
2
workqueue最终会执行binder_deferred_flush来进行flushflush函数会设置该进程的每个线程的looper标记的BINDER_LOOPER_STATE_NEED_RETURN位,前面提过,该标记会导致read操作立刻返回,当然,还需要唤醒那些已经睡觉的线程,不然光设置一个标记也没用。总之,这个操作就是让所有的线程不再睡觉,主要是针对那些等待read的线程。

文件操作release – binder_release
1
删除/binder/proc/pid
2
调用binder_defer_work(proc, BINDER_DEFERED_RELEASE)release的工作交给binder_init中创建的workqueue来延迟执行。
3
workqueue最终会执行binder_deferred_release来释放该进程在binder驱动中相关的内容,包括page, buffer, node, ref, thread, procnode的释放是将其先放到dead_node表中,并想那些注册过死亡通知的线程发出死亡通知,而dead_node需要等到该node所有的ref都删除时才会真的删

 

上一篇:C++/C经典教程(二)
下一篇:stagefright与opencore对比