在上一节中,我们分析了binder服务的注册过程,该小节讲解服务的获取过程。在这之前,我们来回顾一下上一小节的内容,下面是个简单的框图:
用户态:
1.构造数据:name("hello"),flat_binder_node(包含:type【代表其为实体】,
binder【与进程相关,即随便传递,可以为函数指针,也可以为一个数值】,cookie)
2.调用ioctl发送数据
内核态:
3.根据handle=0,找到目的进程service_manager,把数据放入到service_manager的tudo
(目的进程通过mmap空间)链表中。
4.构造结构体(在binder驱动中,会每一个进程创建一个binder_proc,每个进程的
binder_proc中存在一个红黑树nodes,每添加一个服务,都会为该红黑树添加一
binder_node(如“hello”)个节点,然后会给目的进程创建一个binder_ref节点)
a.binder_node:
b.binder_ref:
5.唤醒service_manager
service_manager进程
用户态:
6.调用ADD_SERVICE函数,在svclist链表中创建一项,该项代表一个服务。包含了name=“hello”,handlr=1(由驱动上传)
内核态:
同样,其也存在binder结构体,其中包含了两个红黑树成员(refs_by_dosc,refs_by_node),当驱动传入binder_node,他可以很快找到对应的
binder_ref结构体,也可以根据一个整数找到binder_ref结构体。binder_ref中存在成员dosc,与node。dosc
其实际就是handle(一个整数,当我们传入hello是,其为1,代表我们test_sevcer进程的第一个服务)。其中node指向test_sevcer进程binder_proc结构体中nodes的binder_node(引用)。
服务的获取过程(流程简介)
以上就是我们对上小节知识点的总结,现在我们开始讲解服务的获取过程,将会涉及到tet_client进程。在讲解tet_client进程时,我们也依照前面的方法,把其分为用户态,以及内核态。 首先tet_client运行,其中点1.2.3…代表执行的顺序。
tet_client运行 用户态1.构造数据
.name="hello"
2.通过ioctl发送数据给service_manager,即handle=0,然后进入内核态
13.用户态得到handle=1,此时的handle代表是service的服务,不是service_manager进程。到此,就能发送数据给test_server进程了。
内核态
3.根据handle=0找到service_manager,把数据放入service_manager的todo链表。
4.唤醒service_manager进程
tet_client运行到这里之后,service_manager被唤醒,则service_manager继续向下运行
service_manager运行从第5处接着上面的第4处,即唤醒是在内核
用户态6.取出数据,得到"hello"
7.在svclist链表中根据字符串"hello"得到"hello"对应的handle = 1
8.使用ioctl发送给驱动
内核态
5.返回数据
9.在refs_by_desc树中,根据handle=1找到binder_ref,进而找到hello服务的binder_node。
binder_node中肯定存在.proc=test_server,这样就知道给那个进程发送数据了。
10.为test_client创建binder_ref(在test_client的binder_proc结构体中,也存在两个红黑树:refs_by_dosc,refs_by_node),把创建的binder_ref挂载在红黑树上面。其binder_ref.desc=1,
表示在红黑树上的第一个结构体。其指向的为test_server驱动层的binder_node节点。
11.把数据放入到test_client的tudo链表,唤醒test_client,
为了直观的分析上述过程,下面是一个关系框图: 在tet_client获得server的handel之后,他就可以把数据直接放入到server的todo(mmap空间)链表中,实现通信了。