by Nefarius@newsmth.net
有些事情是结束不了了,不过这个文章还是可以结束的。如果没记错的话,还剩fd和death notify没写了。赶紧写完睡觉。
fd是通过offsets数据里的类型BINDER_TYPE_FD传递的,driver会根据src的fd,在target proc中找一个空闲的fd,然后install上,都是file的一些基本操作。懂的人一看就明白,不懂的人要想真明白的话还是先看看kernel里关于file的部分。而我,属于不明白的,所以这部分就不详细写了,因为binder驱动里关于file的操作其实真的不多。不过跨进程传fd很重要,没有它就没有ashmem, pmem, IMemory, ImemoryHeap等等等等,结果会很悲剧的。
而death相关的涉及到以下几个BC/BR:
BC_REQUEST_DEATH_NOTIFICATION,
BC_CLEAR_DEATH_NOTIFICATION,
BC_DEAD_BINDER_DONE
BR_DEAD_BINDER
BR_CLEAR_DEATH_NOTIFICATION_DONE
BC_REQUEST和BC_CLEAR是相反的命令,一个要求死亡通知,一个是移除死亡通知。死亡通知是记录在binder_ref的death字段,death指向结构体:
by Nefarius@newsmth.net
终于可以写引用计数了,赶紧填完这个坑。
列一下驱动里涉及到binder引用计数的BC和BR:
1. BC_INCREFS, BC_ACQUIRE, BC_RELEASE, BC_DECREFS, 进程主动要驱动增加/减少计数。
2. BR_AQCUIRE, BR_INCREFS, BC_AQCUIRE_DONE, BC_INCREFS_DONE,驱动要进程增加引用计数以及进程完事之后回复驱动。
3. BR_RELEASE/BR_DECREFS, 驱动要进程减少引用计数。
4. BR/BC_ATTEMPT_ACQUIRE, BR/BC_ACQUIRE_RESULT, 这四个没实现。
写之前简单介绍一下binder驱动和binder库的对应关系。一个进程里如果是自己的指针或者说是类,在驱动里叫做binder_node,在binder库里对应于BBinder,如果是别的进程的指针或者说是类映射到自己的空间里,驱动里叫做binder_ref,在binder库中对应于BpBinder。而android本身又搞了一套RefBase/sp
by Nefarius@newsmth.net
上回说的transaction里还有个没提到的,就是binder_buffer以及BC_FREE_BUFFER。
稍微回顾一下binder里的数据相关结构体。
ioctl BINDER_WRITE_READ使用的是binder_write_read,里面的write_buffer/read_buffer都是用户空间的地址,这里面可以存放多个BC/BR,而每种BC/BR的附带数据都是固定大小的。在这里面,BC_TRANSACTION/BR_TRANSACTION/BC_REPLY/BR_REPLY将携带附加的transaction参数,结构为binder_transaction_data。
binder_transaction_data里面的data.ptr包含buffer/offsets两个指针,分别指向存放普通数据以及跨进程数据(binder/fd)的用户空间地址。
最近很无聊,决定把以前的坑填完。先把这个binder驱动的写完吧,其他的坑慢慢填。
已经写过三篇了,binder驱动的基本东西,binder驱动的数据结构,binder驱动的进程线程。前面几篇文章每次提到一个writerread,后面必然跟了一句“以后再写”,这次真的不能以后再写了,现在就写。
BINDER_WRITE_READ是binder里最重要的ioctl,通过它,用户程序可以发命令(BC_开头)给驱动,也可以从驱动读出回复(BR_开头)。这些BC/BR大概可以分为四类,一类是线程池相关的,上一篇已经写过了,各种LOOPER的BC和BR,一类是引用计数相关的,一类是死亡通知相关的,这两类看来还得以后再写,还有一类就是transaction相关的,包括BC_TRANSACTION, BC_REPLY, BC_FREE_BUFFER, BR_TRANSACTION, BR_REPLY, BR_DEAD_REPLY, BR_TRANSACTION_COMPLETE, BR_FAILED_REPLY,对于上层应用的使用者来说,这个是最重要的,这个也是binder实际目的所在——不同进程之间的通讯。这篇主要写这个ioctl以及重要的transaction。
本来想接着写引用计数的,不过这些与上层(binder库)的沟通又牵涉BC,BR以及ioctl(BINDER_WRITE_READ),而这些又跟进程,线程,线程池息息相关,所以还得写写进程相关的东西。
首先说一下进程,即linux进程。驱动会使用上篇提到的binder_proc记录进程信息。每个要使用binder驱动的进程都会在使用驱动前open binder驱动(废话…),驱动在open的时候会创建该结构体,初始化一些信息,并把该结构体的指针记录到文件结构体的private_data,以后的驱动操作就能通过文件结构体获取该进程信息。binder_proc如下:
struct binder_proc {
struct hlist_node proc_node;
struct rb_root threads;
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
int pid;
struct vm_area_struct *vma;
struct task_struct *tsk;
struct files_struct *files;
我发现得先写一下binder的基本结构,不然很多函数写不清楚,所以决定先写这篇。在这之前,先得简单介绍一下binder是什么。简单的说,binder就是个跨进程的指针。
现代操作系统里,一个进程的地址空间是确定的,地址是没有二义性的,进程里的一个指针就对应一个内存地址,不可能同时对应到多个地址,给定一个指针,就能获得想要的东西。但跨进程的情况下,事情就完全不一样了,不同进程的线性地址空间都是一样的,一个进程里的指针放到另一个进程里,就是完全不同的东西了。要实现跨进程的指针,就必须通过操作系统层,只有在系统底层才能将一个进程里的地址映射到另一个进程里的地址,这也就是binder驱动所做的事情。跨进程的指针(以下直接记为binder)有两种存在方式,一是在本地进程里的存在,一是在远程进程里的存在,驱动所做的其实就是实现这两种存在方式的转换。当进程A要使用一个活在进程B里的binder时,驱动根据这个binder在进程A中的表示,找到这个binder的本地进程表示,获取其所在进程和实际指针,然后让它来完成进程A的需求。
by Nefarius@newsmth.net
module
init函数binder_init
1. create_singlethread_workqueue(“binder”)创建一个workqueue来做一些延迟工作。以前是静态创建的,2.2改为在init中创建。
2. proc文件系统中建立目录binder和binder/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_server的binder信息。具体每个文件的信息等把binder的数据结构写完了再加上。
exit函数,无,built-in的,不需要这个
module参数
1. 参数可在/sys/module/binder/parameters下找到,可读可写。
水木一个帖子,很有意思,哈哈
发信人: Bumblebee (大黄蜂), 信区: CPlusPlus
标 题: 今天的一道笔试题,不会做~
发信站: 水木社区 (Tue Sep 7 20:23:20 2010), 站内
用12个字符以下的可编译的代码实现控制台输出一个'A',可能吗?
论述题。
不会做。
居然有解。。。太发指了。
考虑一个目录a,兄弟目录b,父目录c,爷爷目录d,都是绝对路径。bcd有所有权限,a没有写权限。
cd c
以下哪个命令可以执行?为啥。假设各个fuck都不存在。
A. mv a b/fuck
B. mv a c/fuck
C. mv a d/fuck