好久没写过博客了,也没怎么研究过源码,偶尔看到别人的博客都是系列研究,自愧不如啊,所以也下下来android源码开始看了,参考网上的讲解,结合源码。希望这样记录下自己的阅读历程,也不枉虚度时光了。
先从android的Binder驱动说起吧,以前也不懂Linux驱动,有说错的地方敬请谅解,欢迎指正。
一、驱动注册就不详细说了binder_init
1、初始化工作队列binder_deferred_workqueue = create_singlethread_workqueue("binder");
2、注册设备misc_register(&binder_device->miscdev);
3、注册到内核的函数
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
自己的一些理解:binder_deferred_workqueue用于延时任务,以后再详细说,其它的都好理解,虽然机制不了解,但是不影响后续分析,不再深入研究。
二、然后就是打开binder的操作binder_open
1、分配binder_proc结构体,设置相关属性,记录当前进程的binder相关的信息
2、其它一些统计信息binder_stats_created(BINDER_STAT_PROC);记录open的个数。
自己的一些理解:binder_dev = container_of(filp->private_data, struct binder_device,miscdev);这句一开始没有理解,没看到给filp->private_data赋值,怎么就得到了binder_dev呢,原来在misc.c中misc_open中file->private_data = c;进行了赋值然后调用file->f_op->open(inode,file);的,因此file->private_data通misc_register(&binder_device->miscdev);指向&binder_device->miscdev,而container_of通过结构体成员的地址获取结构体的地址因此获取的是misc_register时传入的&binder_device。
三、binder_ioctl,这个函数比较复杂,主要实现也是在这里,先简单说下自己迷惑的地方。
1、总的流程,binder_ioctl处理数据分两种一种类似BINDER_SET_MAX_THREADS等,直接操作数据结构,直接返回这种比较简单,还有一种需要传递到相应的进程或线程处理。
2、先看读取操作最终在binder_thread_read中处理
调用 binder_wait_for_work等待
for (;;) {
prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE);
if (binder_has_work_ilocked(thread, do_proc_work))
break;
if (do_proc_work)
list_add(&thread->waiting_thread_node,
&proc->waiting_threads);
binder_inner_proc_unlock(proc);
schedule();
binder_inner_proc_lock(proc);
list_del_init(&thread->waiting_thread_node);
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
}
finish_wait(&thread->wait, &wait);
等待thread->wait,和线程相关,等待唤醒,binder_has_work_ilocked判断等待条件 => return !binder_worklist_empty_ilocked(&thread->todo) ||
thread->looper_need_return ||
(do_proc_work &&
!binder_worklist_empty_ilocked(&thread->proc->todo)); todo队列不为空或者looper_need_return需要返回,或者do_proc_work。
然后就是进行数据处理了,以后再详细分析,主要根据transaction_stack查找相对应的线程。
3、写操作对于进程间操作也是写入相应的todo队列,后面再进行详细的分析。
就先大概写一下吧,整体还是比较复杂的,说的比较简略,以后再接着写。