版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux系统中,是以进程为单位分配和管理资源的。出于保护机制,一个进程不能直接IPCpipequeue(signalmemoryAndroid同时为Java环境和C/C++环境提供了Binder机制。本章主要介绍C/C++环境下的BinderBinder驱动的实现、运作原理、IPC机制的实现、接口等,所以本章可能会涉Linux系统中,socket、namedpipe、messagequeue、signal、sharememory等;Java系统socket、namedpipeAndroid可以选择的进程间通信的方式LinuxKernelIPCBinder在上面这些可供选择的方式中,AndroidBinder机制。为什BinderBinder更加简洁和快速,消耗的内存资通信可能会增加进程的开销,而且有进程过载和安全等方面的风险,Binder正好能解决和避免这些问题。Binder主要能提供以下一些功能:Binder是通过Linux的BinderDriver来实现的,Binder操作类似于线程迁移(thread行的结果返回。Binder的用户空间为每一个进程着一个可用的线程池,线程池用于处理到OpenBinderOpenBinderLinux实现,Android系统的运行都将依赖Binder驱动。Binder通信也是基于Service与 的,所有需要IBinder通信的进程都必须创建一个IBinder接口。系统中有一个名为ServiceManager的守护进程管理着系统中的各个服务,它负务都要在ServiceManager中,而请求服务的客户端则向ServiceManager请求服务。在驱动,并通知BinderKernel驱动程序,这个进程将作为SystemServiceManager,然后该进程Binder驱动、ServiceManager、Service、 在其驱动的实现过程中,主要通过binder_ioctl函数与用户空间的进程交换数据。BINDER_WRITE_READ用来读写数据,数据包中有一个cmd域用于区分不同的请求。关于OpenBinder信息,可以参考 关于OpenBinderbinder_thread_writebinder_transaction函数来转发请求并返回结果。当收到请求到一个RB树中,最后把请求放到目标进程的队列中,等待目标进程。数据的解析工作放MGR命令来完成此项功能。下面我们就来看看Binder驱动究竟是如何实现的。循相同的协议,这个协议反映在代码上就是二者要实现IBinder接口。BinderAndroidIPCAndroid系统的一种RPC(过程调用)机制,因为Binder的功能就是在本地“执行”其他进程的功能。因以与本地进程通信,还可以与进程通信;这里的本地进程就是我们所说的本地对象,而远程进程则是我们所说的服务的一个“”。这也就是Binder与其他IPC机制不同的地方。址空间的一个地址,而对象的“”则是一个抽象的32位句柄。它们之间是互斥的:binder3-1binder_workstructbinder_workstructlist_headentry;enum{BINDER_WORK_TRANSACTION=1, }大家就会觉得它更像是一个用来表示状态的enum。3-2Binder#defineB_PACK_CHARS(c1,c2,c3,c4)((((c1)<<24))|(((c2)<<16))|(((c3)<<8))|#defineB_TYPE_LARGE0x85enum{ =B_PACK_CHARS('s','b','*',B_TYPE_LARGE), =B_PACK_CHARS('w','b','*',B_TYPE_LARGE), =B_PACK_CHARS('s','h','*',B_TYPE_LARGE), =B_PACK_CHARS('w','h','*',B_TYPE_LARGE), =B_PACK_CHARS('f','d','*',B_TYPE_LARGE),从上面的代码可以看出,Binder53个不同的IT_E_BIE(BINERTYE_FD(BINDER_YPE_FDBinder对象(BinderObject),它在对应源码中使用flat_binder_object结构体(位于binderh文件中)来表示,其定义如代码3-3所示。 3-3flat_binder_object定struct{unsignedlong unsignedlong union{ signedlonghandle; 该结构体中的type字段描述的是Binder的类型,传输的数据是一个复用数据联合体。对本地Binder对象和handle句柄比较难以理解,这里我们再次举例说明:假如A有个对象O,对于A来说,O就是一个本地的Binder对象;如果B想A的O对象,对于B来说, 字段中。flags字段表示传输方式,比如同步和异步等,其值同样使用一个enum来表示,定义如代码3-4所示。3-4transaction_flagsenum{TF_ONE_WAY=0x01, =0x04, =0x08,TF_ACCEPT_FDS=0x10,hndeT_CET_Sflat_binder_objectBinder对象所传递的实际内容,因为如代码3-5所示。 3-5binder_transaction_data定struct{union void*ptr;} unsignedintcode;unsignedintflags; union{structconstvoid constvoid }uint8_t}根据此handle,Binder驱动可以找到应该由哪个进程处理此,并且把此的任务分发给ioctlBINDER_WRITE_READ操作,即正在等待一个请”,handle和ptr之间的翻译(解析)关系正是Binder驱动需要的(在binder_transaction函数 字段表示target对象所附加的额外数据;code是一个命令,它描述了请求Binder对象执行的操作;flags字段描述了传输的方式与flat_binder_object中的flagsoffsets_size表示数据的偏移量字节数;最后一个union数据data表示真正的数据,其中ptr表当Beriner就要的的任务放在读缓冲(bindr_ie_ad)里,返回给这个服务线程,该服务线程则会执行idr_rnaio_daideridr_ierd)(线程ERWIERD#defineBINDER_WRITE_READ_IOWR('b',1,struct该命令是ioctl函数中的一个操作,从上面的宏中可以看出,其所对应的参数是binder_write_read结构体,该结构体正好就是我们所说的读写缓冲区,将用它来发送的任务信息和接收返回的结果信息,其定义如代码3-6所示。 3-6binder_write_read定struct{signedlongwrite_size;signedlong unsignedlongwrite_buffer;signedlong signedlong unsignedlongread_buffer;上面的代码中分别指定了读缓冲区和写缓冲区,对于写操作,write_buffer包含了一系列请Binder命令;对于读(返回结果)操作,read_buffer包含了一系列线程执行后填3-7BINDER_WRITE_READ BC_TRANSACTION=_IOW('c',0,structbinder_transaction_data),BC_REPLY=_IOW('c',1,structbinder_transaction_data),BC_ACQUIRE_RESULT=_IOW('c',2,int), _BUFFER=_IOW('c',3,int),BC_INCREFS=_IOW('c',4,int),BC_ACQUIRE=_IOW('c',5,int),BC_RELEASE=_IOW('c',6,int),BC_DECREFS=_IOW('c',7,BC_INCREFS_DONE=_IOW('c',8,structbinder_ptr_ BC_ACQUIRE_DONE=_IOW('c',9,structbinder_ptr_ BC_ATTEMPT_ACQUIRE=_IOW('c',10,structbinder_pri_desc),BC_REGISTER_LOOPER=_IO('c',11),BC_ENTER_LOOPER=_IO('c',12),BC_EXIT_LOOPER=_IO('c',13),BC_REQUEST_DEATH_NOTIFICATION=_IOW('c',14,structbinder_ptr_ BC_CLEAR_DEATH_NOTIFICATION=_IOW('c',15,structbinder_ptr_ BC_DEAD_BINDER_DONE=_IOW('c',16,void*),enum{BR_ERROR=_IOR('r',0,BR_OK=_IO('r',BR_TRANSACTION=_IOR('r',2,structbinder_transaction_data),BR_REPLY=_IOR('r',3,structbinder_transaction_data),BR_ACQUIRE_RESULT=_IOR('r',4,int),BR_DEAD_REPLY=_IO('r',PLETE=_IO('r',BR_INCREFS=_IOR('r',7,structbinder_ptr_),BR_ACQUIRE=_IOR('r',8,structbinder_ptr_),BR_RELEASE=_IOR('r',9,structbinder_ptr_),BR_DECREFS=_IOR('r',10,structbinder_ptr_),BR_ATTEMPT_ACQUIRE=_IOR('r',11,structbinder_pri_ptr_ BR_NOOP=_IO('r',12),BR_SPAWN_LOOPER=_IO('r',13),BR_FINISHED=_IO('r',14),BR_DEAD_BINDER=_IOR('r',15,void*),BR_CLEAR_DEATH_NOTIFICATION_DONE=_IOR('r',16,void*),BR_FAILED_REPLY=_IO('r',17),其数据参数都是binder_transaction_data结构体;前者用于翻译和解析将要被处理的数据,后者则是处理完成之后对返回“结果数据”的操作命令。我们稍后在分析binder_ioctl的Binder状态信息等,定义如代码3-8所示。 3-8binder_proc定structbinder_procstructhlist_nodestructrb_rootthreads;structrb_rootnodes;structrb_rootrefs_by_desc;structrb_rootintstructvm_area_struct*vma;structtask_struct*tsk;structfiles_struct*files;structhlist_nodedeferred_work_node;intdeferred_work;voidptrdiff_tstructlist_headbuffers;structrb_root structrb_rootallocated_buffers; structpage**pages;size_tbuffer_size;uint32_tbuffer_ structlist_headtodo;structbinder_statsstats;structlist_headdelivered_death;intintintrequested_threads_started;intready_threads;long析。其中proc_node字段用于实现双向链表,threads则用于所有的线程信息。紧接着我们就需要分析Binder节点和Binder线程的具体定义了。3-9binder_nodestruct{intstructbinder_workwork;union{structrb_noderb_node;structhlist_nodedead_node;structbinder_proc*proc;structhlist_headrefs;intinternal_strong_refs;intlocal_weak_refs;intlocal_strong_refs;voiduser*ptr; user* unsignedhas_strong_ref:1;unsignedpending_strong_ref:1;unsignedhas_weak_ref:1;unsignedpending_weak_ref:1;unsignedhas_async_transaction:1;unsignedaccept_fds:1;intmin_priority:8;structlist_headasync_todo;我们已经知道,binder_thread结构体用于每一个单独的线程的信息,其定义如代码清单3-10所示。 3-10binder_thread定structbinder_threadstructbinder_proc*proc;structrb_noderb_node;intpid;intstructbinder_transaction*transaction_stack;structlist_headtodo;uint32_treturn_error;uint32_treturn_error2;wait_queue_head_twait;structbinder_statsstats;其中,procBinder进程(binder_proc指针;rb_node是一binder_transaction,稍候我们会进行详细的分析;todo用于创建一个双向链表;return_errorreturn_error2为返回的错误信息代码;wait是一个等待队列头;stats用于表示Binder状态信息,其定义如代码3-11所示。3-11binder_statsstructbinder_statsintbr[_IOC_NR(BR_FAILED_REPLY)+intbc[_IOC_NR(BC_DEAD_BINDER_DONE)+intobj_created[BINDER_STAT_COUNT];int其中,br用来BINDER_WRITE_READ的写操作命令协议(BinderDriverReturnProtocolbcrotocol;obj_ceated就需要同时调用该成员来增加相应的对象计数,而obj_deleted好相反。3-12BinderlooperenumBINDER_LOOPER_STATE_REGISTERED=0x01,BINDER_LOOPER_STATE_ENTERED=0x02,BINDER_LOOPER_STATE_EXITED=0x04,BINDER_LOOPER_STATE_INVALID=0x08,BINDER_LOOPER_STATE_WAITING=0x10,BINDER_LOOPER_STATE_NEED_RETURN=0x20单3-13所示。 3-13binder_transaction定struct{intdebug_id;//调试相关structbinder_workwork;structbinder_thread*from;structbinder_transaction*from_parent;structbinder_proc*to_proc;structbinder_thread*to_thread;structbinder_transaction*to_parent;unsignedneed_reply:1;structbinder_buffer*buffer;unsignedintcode;unsignedintflags;longpriority;longsaved_priority; workbinder_work;fromto_threadbinder_thread对象,用于表示接收和要发送的进程信息,另外还包括了接收和发送进程信息的父节点from_parent和to_thread;to_procbinder_proc类型的结构体。其中还包括flags、need_reply、优先级的缓冲区信息,其定义如代码3-14所示。3-14binder_bufferstructbinder_buffer{structlist_headentry;structrb_noderb_node; :1;unsignedallow_user_ :1;unsignedasync_transaction:1;unsigneddebug_id:29;structbinder_transaction*transaction;structbinder_node*target_node;size_tdata_size;size_toffsets_size;uint8_tdata[0];该结构体主要用来Binder的相关信息,entry同样用于构建一个双向链表;rb_node为一个树节点;transaction表示上面我们刚刚说到的binder_transaction,用于中转请求和返回结果;target_node是一个目标节点;data_size表示数据的大小;offsets_size是一个偏移量;binder.c中找到该初始化函数,具体实现如代码3-15所示。3-15binder_initstatic init{intif//Misc设ret=binder_read_proc_state,NULL);binder_read_proc_stats,NULL);binder_read_proc_transactions,NULL);binder_read_proc_transaction_log,&binder_transaction_log);create_proc_read_entry("failed_transaction_log",S_IRUGO,binder_proc_dir_entry_root,binder_read_proc_transaction_log,}return}AndroidBinderdevice_initcall,这与上一章提到的设备驱动的接口函数是module_initmodule_exitmodule_initmodule_exit是为了同时兼容支持静态编译的驱动模块(buildin)和动态编译的驱动模块(module,但是Binder选择使用device_initcall的目的就是不让Binder驱动支持动态编译,而且需要在内核(Kernel)做镜像。initcall用于进行初始化的函数;如果你的确需要将Binder驱动修改为动态的内核模块,可以直接将device_initcall修改为module_init,但了增加module_exit的驱动卸proc_i_tr_ot/rieecet/cie函数中调用handle_device_event(&uevent)函数执行其中uevent-netlink在"/dev/" 最后,调用create_proc_read_entry创建以下只读proc文件:表3-1 代码3-16所示。 3-16binder_miscdev的实staticstructmiscdevicebinder_miscdev=.minor=.name=.fops=Binder10minor被设置为动态获得设备号MISC_DYNAMIC_MINOR;.namefile_operations结构体,定义如代码3-17所示。 3-17file_operations的定staticstructfile_operationsbinder_fops=.owner=.poll=.unlocked_ioctl=.mmap=.open=.flush=.release=操作设备文件(/dev/binder)binder_fopsfile_operations结构体一样,及其内的所有线程都可以打开一个Binder设备,其打开过程的实现如代码3-18所示。3-18binder_openstaticintbinder_open(structinode*nodp,structfile{structbinder_procif(binder_debug_mask&printk(KERN_INFO"binder_open:%d:%d\n",current->group_leader->pid,proc=kzalloc(sizeof(*proc),GFP_KERNEL);if(proc==NULL)return-//增加计proc->tsk=//初始化binder_proc队列proc->default_priority=task_nice(current);proc->pid=current->group_leader->pid;filp->private_data=proc;if{charsnprintf(strbuf,sizeof(strbuf),"%u",proc->pid);remove_proc_entry(strbuf,binder_proc_dir_entry_proc);create_proc_read_entry(strbuf,S_IRUGO,binder_proc_dir_entry_proc,binder_read_proc_proc,proc);}return}nice值(通过task_nice得到当前进程的nice值。BINDER_STAT_PROChlist_add_headbinder_proc对象添加到全局的binder_proc哈希表中,这样一来,任何一个进程就都可以到其他进程的binder_proc对象了。把当前进程(或线程)pid(pidid)procpid字段,可建的binder_proc对象指针赋值给filp的private_data对象并保存起来。binderproc中创建只读文件/proc/binder/proc/$pidbinderproc对赋值给该pid字段的。另外,在创建该文件时,同样也指定了操作该文件的函数接口为binder_read_proc_procbinder_procproc,对于该接口的实现,后binder_releasebinder_openBinder驱动退出时,需要使用它来释放在打开以及其他操作过程中分配的空间并清理相关的数据信息,其实现如代码3-193-19binder_releasestaticintbinder_release(structinode*nodp,structfile{structbinder_proc*proc=filp->private_data;if(binder_proc_dir_entry_proc){char}binder_defer_work(proc,BINDER_DEFERRED_RELEASE);return0;}这样就能得到在open过程中创建的以pid命名的用来输出当前binderproc对象的状态的只读文remove_proc_entrybinder_defer_work函数和其参数BINDER_DEFERRED_RELEASEbinder_proc对象的数据和分配的空间。你可能会和flush等操作比较复杂,而且也没有必要在系统调用里完成它,因此最好的方法是延迟执行这个任务,所以这里选择使用workqueue(deferred)来提高系统的响应速度和性能。BINDER_DEFERRED_RELEASE参数位于一个enum中,如代码3-20所示。3-20BINDER_DEFERRED_RELEASEenumBINDER_DEFERRED_PUT_FILES=0x01,BINDER_DEFERRED_FLUSH=0x02,BINDER_DEFERRED_RELEASE=码3-21所示。3-21binder_flushstaticintbinder_flush(structfile*filp,fl_owner_t{structbinder_proc*proc=filp->private_data;binder_defer_work(proc,BINDER_DEFERRED_FLUSH);return0;}从而完成该flush操作,但是最终的处理还是交给了binder_defer_work函数。(POLLIN用poll_wait函数来实现的:具体实现如代码3-22所示。3-22binder_poll{structbinder_proc*proc=filp->private_data;structbinder_thread*thread=NULL;intthread=wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo)&&thread->return_error==BR_OK;if(wait_for_proc_work)if(binder_has_proc_work(proc,thread))returnPOLLIN;if(binder_has_proc_work(proc,thread))returnPOLLIN;else{//thread_workif(binder_has_thread_work(thread))returnPOLLIN;poll_wait(filp,&thread->wait,wait);if(binder_has_thread_work(thread))return}return}首先需要取得当前进程/线程的信息,由于所有的线程信息都在binder_proc结构体的threadsbinder_get_thread(proc)来找到当前进程/线程的相关信息,稍后会详细分析查找原理。proc_work和thread_work方式如代码3-23所示。3-23proc_workthread_work{return!list_empty(&proc->todo)||(thread->looper&}{return!list_empty(&thread->todo)||thread->return_error!=BR_OK||(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN);}的等待方式,最后通过调用poll_wait函数来实现poll操作。3-24binder_get_threadstaticstructbinder_thread*binder_get_thread(structbinder_proc{structbinder_thread*thread=NULL;structrb_node*parent=NULL;structrb_node**p=&proc-while(*p)parent=thread=rb_entry(parent,structbinder_thread,if(current->pid<thread->pid)p=&(*p)->rb_left;elseif(current->pid>thread->pid)p=&(*p)->rb_right;}
if(*p==NULL)thread=kzalloc(sizeof(*thread),GFP_KERNEL);if(thread==NULL)returnthread->proc=proc;thread->pid=current-rb_link_node(&thread->rb_node,parent,p);rb_insert_color(&thread->rb_node,&proc->threads);thread->looper|=BINDER_LOOPER_STATE_NEED_RETURN;thread->return_error=BR_OK;thread->return_error2=}return}pidpid是否相同,如果找到了,mmap(memorymap)用于把设备内存映射到用户进程地址空间中,这样就可以像操作用户内存那样操作设备内存。Binder设备对内存映射是有限制的,比如,Binder设备最大能映射vmallockmalloc等内核内都会返回错误,具体实现如代码3-25所示。3-25binder_mmapstaticintbinder_mmap(structfile*filp,structvm_area_struct{intstructvm_structstructbinder_proc*proc=filp->private_data;constchar*failure_string;structbinder_bufferif((vma->vm_end-vma->vm_start)>SZ_4M)vma->vm_end=vma->vm_start+SZ_4M;if(binder_debug_mask&BINDER_DEBUG_OPEN_CLOSE)"binder_mmap:%d%lx-%lx(%ldK)vma%lxpagep%lx\n",proc->pid,vma->vm_start,vma->vm_end,(vma->vm_end-vma->vm_start)/SZ_1K,vma->vm_flags,(unsignedlong)pgprot_val(vma->vm_page_prot));if(vma->vm_flags&{ret=-failure_string="badvm_flags";gotoerr_bad_arg;}vma->vm_flags=(vma->vm_flags|VM_DONTCOPY)&{ret=-failure_string="alreadymapped";gotoerr_already_mapped;}area=get_vm_area(vma->vm_end-vma->vm_start,VM_IOREMAP);if(area==NULL){ret=-failure_string="get_vm_area";gotoerr_get_vm_area_failed;}proc->buffer=area-proc->user_buffer_offset=vma->vm_start-(uintptr_t)proc->buffer;#ifdefCONFIG_CPU_CACHE_VIPTwhile(CACHE_COLOUR((vma->vm_start^(uint32_t)proc-{printk(KERN_INFO"binder_mmap:%d%lx-%lxmaps%pbadalignment\n",proc->pid,vma->vm_start,vma->vm_end,proc->buffer);vma->vm_start+=PAGE_SIZE;}}/PAGE_SIZE),if(proc->pages=={ret=-failure_string="allocpagearray";gotoerr_alloc_pages_failed;}proc->buffer_size=vma->vm_end-vma->vm_start;vma->vm_ops=&binder_vm_ops;vma->vm_private_data=if(binder_update_page_range(proc,1,proc->buffer,proc->buffer+PAGE_SIZE,vma)){ret=-failure_string="allocsmallbuf";gotoerr_alloc_small_buf_failed;}buffer=proc->buffer;list_add(&buffer->entry,&proc->buffers); =1; _buffer(proc, _async_space=proc->buffer_size/2;proc->files=get_files_struct(current);proc->vma=vma;return0; proc->pages=NULL; proc->buffer=printk(KERN_ERR"binder_mmap:%d%lx-%lx%sfailed%d\n",proc->pid,vma->vm_start,vma->vm_end,failure_string,ret);return}护这个结构的。VMA的作用是管理进程地址空间中不同区域的数据结构。该函数首先对内存get_vm_area从系统中申请可用的虚拟内存空间(注意:不是物理内存空间),即在内核中申请并保留一块连续的内核虚拟内存空间区域;接着,将配Binder的数据结构binder_proc的pages成员,它主要用来保存指向申请的物理页的指binder_update_page_range来实现的。binder_update_page_range的实现主要是一些内核操 将buffer插入到进程信息的buffer列表中。6)通过binder_insert__buffer函数把此进程的buffer插入到进程信息中。这里我们再来看一下vm_operations_struct操作的定义,如代码3-26所示。3-26binder_vm_opsstaticstructvm_operations_structbinder_vm_ops=.open=.close=里使用的参数则是BINDER_DEFERRED_PUT_FILES。3-27Binderioctl#defineBINDER_WRITE_READ _IOWR('b',1,structbinder_write_read)#defineBINDER_SET_IDLE_TIMEOUT _IOW('b',3,int64_t)#defineBINDER_SET_MAX_THREADS _IOW('b',5,size_t)#defineBINDER_SET_IDLE_PRIORITY_IOW('b',6,int)#defineBINDER_SET_CONTEXT_MGR _IOW('b',7,int)#defineBINDER_THREAD_EXIT _IOW('b',8,int)#define _IOWR('b',9,struct有被实现;BINDER_WRITE_READ是所有Binder的基础,即读写操作;BINDER_SET_MAX_THREADS用于设置最大线程数目;BINDER_SET_CONTEXT_MGR则被Serviceioctl面的驱动分析中我们已经提到过,这里将对其进行更深入的分析。ioctlI/OI/O通道进行管理,就ioctlioctlI/O通道。ioctlI/O通道的控制,但那就太复杂了。例如,我们可以write的时候检查一下是否有特殊约定的数据流通过,如果有,那么后面就在后面附加控制命令(socket编程中常常这样做。但是,如果这样做,就会导致代码预料的事情发生。所以,在Linux内核中这样定义一个命令码,如表3-2所示。3-2 8 8 2 8~14这样一来,一个命令就变成了一个整数形式令码。但是,命令码非常不直观,所以Linux内核中提供了一些宏,这些宏可以根据便于理解的字符串生成命令码,或者是从命令码正如上面所述,每个命令都被定义成一个_IOW宏,关于_IOW宏的定义大家可以在“bionic\libc\kernel\common\asm-generic\Ioctl.h”中找到,如代码3-28所示。3-28_IOW 8 //大小(size)字段的字位宽度,14bits 2 #define_IOC_NRMASK((1_IOC_NRBITS)-1)//序数字段的掩码,0x000000FF#define_IOC_TYPEMASK((1_IOC_TYPEBITS)-1)类型字段的掩码,0x000000FF#define_IOC_SIZEMASK((1_IOC_SIZEBITS)-1)大小字段的掩码,0x00003FFF#define_IOC_DIRMASK((1_IOC_DIRBITS)-1)//方向字段的掩码,0x (_IOC_NRSHIFT+_IOC_NRBITS) (_IOC_TYPESHIFT+_IOC_TYPEBITS) //大小字段的位移,16 (_IOC_SIZESHIFT+_IOC_SIZEBITS) #define_IOC_NONE0U//#define_IOC_WRITE 1U //向设备中写入数据,驱动程序必须从用户空间读入数据#define_IOC_READ #define_IOC(dir,type,nr,size)\(((dir)<<_IOC_DIRSHIFT)|((type)<<_IOC_TYPESHIFT)|\ <<_IOC_NRSHIFT)|\((size)<<_IOC_SIZESHIFT))#define #define #define #define_IOWR(type,nr,size)#define (((nr)>>_IOC_DIRSHIFT)define (((nr)>>_IOC_TYPESHIFT)define (((nr)>>_IOC_NRSHIFT)define (((nr)>>_IOC_SIZESHIFT)&3-29BINDER_VERSIONif(size!=sizeof(struct{ret=-goto}if(put_user(BINDER_CURRENT_PROTOCOL_VERSION,&((structbinder_version*)ubuf)->protocol_version)){ret=-goto}3-30BINDER_SET_MAX_THREADS{ret=-goto}anage(ontx_grbinder_context_mgr_nodeBinder上下文管理进程/线程才有权限重新设置这个对象。该命令的实现如代码3-31所示:3-31BINDER_SET_CONTEXT_MGRif(binder_context_mgr_node!=NULL)printk(KERN_ERR"binder:BINDER_SET_CONTEXT_MGRalreadyset\n");ret=-EBUSY;goto}if(binder_context_mgr_uid!=-1)if(binder_context_mgr_uid!=current->cred-{printk(KERN_ERR"binder:BINDER_SET_""CONTEXT_MGRbaduid%d!=%d\n",ret=-goto}elsebinder_context_mgr_node=binder_new_node(proc,NULL,NULL);if(binder_context_mgr_node==NULL){ret=-goto}binder_context_mgr_node->has_strong_ref=从上面的代码中可以看出,首先检测binder_context_mgr_node是否为NULL,然后检测binder_context_mgr_uiduid(这里主要检euidbinder_new_node函数创建一个binder_node节点,并对该binder_node节点执行初始化操作。下面我们分析如何创建这个binder_node节点,其具体实现如代码3-32所示。3-32binder_new_nodestaticstructbinder_node*binder_new_node(structbinder_proc*proc,voiduser*ptr,voiduser* {structrb_node**p=&proc->nodes.rb_node;structrb_node*parent=NULL;structbinder_nodewhile(*p){parent=node=rb_entry(parent,structbinder_node,if(ptr<node-p=&(*p)->rb_left;elseif(ptr>node->ptr)p=&(*p)-}
returnnode=kzalloc(sizeof(*node),GFP_KERNEL);if(node==NULL)returnNULL;rb_link_node(&node->rb_node,parent,p);rb_insert_color(&node->rb_node,&proc->nodes);node->debug_id=++binder_last_id;node->proc=proc;node->ptr= =node->work.type=if(binder_debug_mask&BINDER_DEBUG_INTERNAL_REFS)printk(KERN_INFO"binder:%d:%dnode%du%pc%pcreated\n",proc->pid,current->pid,node->debug_id,node->ptr,node-> return}binder_proc的成员node是binder_node的根节点,这是一棵树(一种平衡二叉树。是一个内联函数,它用于将新节点插入到树中的指定父节点下。rb_insert_color则是把已经插入到树中的节点调整并融合到树中。最后,执行数据初始化和初始化该节点的链表头,其中node->proc保存着binder_proc对象指针。现如代码3-33所示。3-33BINDER_WRITE_READstructbinder_write_readif(size!=sizeof(struct{ret=-goto}if(copy_from_user(&bwr,ubuf,{ret=-goto}if(binder_debug_mask&printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);if(bwr.write_size>0)ret=binder_thread_write(proc,thread,(void user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);if(ret<0)bwr.read_consumed=if(copy_to_user(ubuf,&bwr,sizeof(bwr)))ret=-EFAULT;goto}}if(bwr.read_size>0)ret=binder_thread_read(proc,thread,(void user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);if(!list_empty(&proc->todo))if(ret<0)if(copy_to_user(ubuf,&bwr,sizeof(bwr)))ret=-EFAULT;goto}}if(binder_debug_mask&printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);if(copy_to_user(ubuf,&bwr,{ret=-goto}该部分的实现很简单,首先检查其数据是否完整,然后从用户空间数据到binder_write_readwrite_sizebwrread_size来判断需要执行的操作。当然,最终的操作会通过inder_thread_write和binder_thread_read函数来实现。稍候分析ioctlwait_event_interruptible函然后添加到等待队列binder_user_error_w
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 感染科抗生素使用指南
- 设备租赁合同协议书模板
- 2026年成人高考计算机信息管理(本科)计算机应用基础真题单套试卷
- 2026年成人高考法学专业(宪法)真题单套试卷
- 2026年9月卫生专业技术资格(士)临床医学基础真题单套试卷
- 证劵投资题库及答案
- 招标采购从业题库及答案
- 中考语文现代文阅读真题分类汇编(冲刺刷题)
- 久任活动策划方案(3篇)
- 内墙泡沫施工方案(3篇)
- 2026年水泥行业转型金融标准试点进展与项目申报指南
- 春季驾驶员安全教育培训
- 2026春人音版小学音乐二年级下册(新教材)每课教学反思(附目录)
- 2026绍兴市政务服务办下属中心招聘政务服务专员4人考试参考试题及答案解析
- 2026年全国“两会”学习试题测试卷(含答案)
- 2026年北京招警心理测试题及答案
- 万豪酒店礼仪规范
- 道路运输成本考核制度
- 2026年成都文职辅警笔试题库及1套参考答案
- 江苏苏州市2025-2026学年高二上学期期末考试英语试题(含答案)
- 广州市财政投资信息化项目(运行维护类)方案编写指南
评论
0/150
提交评论