摘要:抱歉,此文暂时作废,不会使用的删除功能。我会在后面重新整理后再继续写下去。是内部的一个机制,通过设备驱动的协助能够起到进程间通讯的的作用。这个应该是个全局表,统计所有结构。实际上是保存在打开的设备文件的结构中。目前还未涉及到其他操作,只是。
抱歉,此文暂时作废,不会使用segmentfault的删除功能。我会在后面重新整理后再继续写下去。
继续上篇的文,这篇打算进入到android的内核世界,真正接触到binder。
binder是android内部的一个机制,通过设备驱动的协助能够起到进程间通讯的(ipc)的作用。那么binder的设备驱动的源码在/drivers/staging/android/binder.c这个路径下。
先看下定义:
3632static const struct file_operations binder_fops = { 3633 .owner = THIS_MODULE, 3634 .poll = binder_poll, 3635 .unlocked_ioctl = binder_ioctl, 3636 .compat_ioctl = binder_ioctl, 3637 .mmap = binder_mmap, 3638 .open = binder_open, 3639 .flush = binder_flush, 3640 .release = binder_release, 3641};
这里说明了设备的各项操作对应的函数。
设备驱动是在系统刚开始的时候就初始化好的,初始化的过程看binder_init,不是重点,因此不在这里累述。这个初始化的过程如果进入的以及怎么发展的,有机会再其他文中叙述吧。
上文的servicemanager的main函数中首先就是open设备,因此先从open开始:
2941static int binder_open(struct inode *nodp, struct file *filp) 2942{ 2943 struct binder_proc *proc; 2944 2945 binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d ", 2946 current->group_leader->pid, current->pid); 2947 2948 proc = kzalloc(sizeof(*proc), GFP_KERNEL); 2949 if (proc == NULL) 2950 return -ENOMEM; 2951 get_task_struct(current); 2952 proc->tsk = current; 2953 INIT_LIST_HEAD(&proc->todo); 2954 init_waitqueue_head(&proc->wait); 2955 proc->default_priority = task_nice(current); 2956 2957 binder_lock(__func__); 2958 2959 binder_stats_created(BINDER_STAT_PROC); 2960 hlist_add_head(&proc->proc_node, &binder_procs); 2961 proc->pid = current->group_leader->pid; 2962 INIT_LIST_HEAD(&proc->delivered_death); 2963 filp->private_data = proc; 2964 2965 binder_unlock(__func__); 2966 2967 if (binder_debugfs_dir_entry_proc) { 2968 char strbuf[11]; 2969 2970 snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); 2971 proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, 2972 binder_debugfs_dir_entry_proc, proc, &binder_proc_fops); 2973 } 2974 2975 return 0; 2976}
1.创建binder_proc结构;
2.各种维护性的链表及结构的添加;
3.存储proc到私有数据内;
先说下,内核开空间都是使用kzalloc与应用层的malloc类似。
这里用到一个current结构,是linux的一个指针,指向当前正在运行的进程结构task_struct,这里还是先不深究,大体意思了解不影响后续即可。后面就是INIT_LIST_HEAD(&proc->todo);初始化链表头,这个链表是怎么回事儿呢?先看下proc的结构吧:
292struct binder_proc { 293 struct hlist_node proc_node; 294 struct rb_root threads; 295 struct rb_root nodes; 296 struct rb_root refs_by_desc; 297 struct rb_root refs_by_node; 298 int pid; 299 struct vm_area_struct *vma; 300 struct mm_struct *vma_vm_mm; 301 struct task_struct *tsk; 302 struct files_struct *files; 303 struct hlist_node deferred_work_node; 304 int deferred_work; 305 void *buffer; 306 ptrdiff_t user_buffer_offset; 307 308 struct list_head buffers; 309 struct rb_root free_buffers; 310 struct rb_root allocated_buffers; 311 size_t free_async_space; 312 313 struct page **pages; 314 size_t buffer_size; 315 uint32_t buffer_free; 316 struct list_head todo; 317 wait_queue_head_t wait; 318 struct binder_stats stats; 319 struct list_head delivered_death; 320 int max_threads; 321 int requested_threads; 322 int requested_threads_started; 323 int ready_threads; 324 long default_priority; 325 struct dentry *debugfs_entry; 326};
这个结构的写法很c很linux,可以看到可能会有很多个proc结构被贯穿成为一个链表统一管理,那么结合之前的内容猜测,binder_proc结构可以支持多个每个对应一个进程,然后通过链表来维护,那么进一步思考,本身binder就是为了支持跨进程通讯的,那么这些通讯之间的binder衔接就是在这个链表结构中维护。
下面,init_waitqueue_head(&proc->wait);初始化linux的等待队列。又是个宏,内容如下:
71#define init_waitqueue_head(q) 72 do { 73 static struct lock_class_key __key; 74 75 __init_waitqueue_head((q), #q, &__key); 76 } while (0) 77 78#ifdef CONFIG_LOCKDEP 79# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) 80 ({ init_waitqueue_head(&name); name; }) 81# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) 82 wait_queue_head_t name = __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) 83#else 84# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name) 85#endif 86
带入的参数是proc结构中的一个成员wait,感觉这里也是个队列(链表),用来维护等待处理的binder_proc结构。那么大胆猜测下,系统利用这个来建立等待通讯处理的binder进程队列,可在这基础上进行各种策略调配来管理binder通讯的过程,不能放着驱动自我的承载力来决定(可能带来稳定性隐患)。
再往后看,proc->default_priority = task_nice(current); 记录当前进程的优先级。看吧,之前的策略这里就会体现。
然后hlist_add_head(&proc->proc_node, &binder_procs);又一个,真linux真c,不得不说:看系统源码就必须习惯各种链表的这种方式,其实很好,不用额外维护什么东西,这种原始的方式其实有时候是最适合的,所以说,机制不是多复杂就牛逼的,而是看是否符合当前的体系当前的场景。这个应该是个全局hash表,统计所有binder_proc结构。
借用一张网络上的图说明下proc结构:
最后保存这个proc倒private_data里,这个私有数据中。然后完了。
再回顾一下吧,每次打开设备就创建一个binder_proc结构,并将当前进程的信息保存在这里,然后将其挂接在系统的各个链表或红黑树或hash表中,为了便于日后的策略和维护。之后再将这个proc结构保留到私有数据中。实际上是保存在打开的设备文件的结构中。目前还未涉及到其他操作,只是binder_open。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/65002.html
摘要:以版本源码为例。源码位于下打开驱动设备,将自己作为的管理者,进入循环,作为等待的请求位于首先,建立一个结构体,然后剩下的就是给这个结构体的成员赋值。同属于这一层,因此我们看看具体内容刚才从驱动设备读取的的前位取出来作为进行判断处理。 前一阵子在忙项目,没什么更新,这次开始写点android源码内部的东西分析下。以6.0.1_r10版本android源码为例。servicemanager...
摘要:也同时可以看到责任链的应用,一个请求从上到下会经过很多层,每层都只处理和自己相关的部分,如果没有则交由下层继续传递,如果有直接返回。因此虽然看着费劲点,但是在此还是要对搞操作系统的以及研究操作系统的人们给予敬意。 承接上篇,serviceManager是怎么被调用的呢?如何为app提供服务支持?怎么衔接的?。这次我打算从最上层开始逐步把脉络屡清楚。首先,我们在写app的时候需要使用Au...
摘要:的构造传递进入的就是。如果状态是,直接返回。到底是否正确呢看代码先创建一个对象,这个对象是个存储读写内容的对象。然后终于进入了内核驱动的部分。 承接上文,从getService开始,要开始走binder的通讯机制了。首先是上文的java层 /frameworks/base/core/java/android/os/ServiceManagerNative.java: 118 pu...
阅读 2339·2021-10-14 09:42
阅读 1110·2021-09-22 15:09
阅读 3499·2021-09-09 09:33
阅读 2968·2021-09-07 09:59
阅读 3608·2021-09-03 10:34
阅读 3502·2021-07-26 22:01
阅读 2797·2019-08-30 13:06
阅读 1145·2019-08-30 10:48