天天看点

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

通过前面的学习我们知道,binder通信涉及搭配两个进程,A,B:

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

A发送一个BC_TRANSACTION消息给驱动,驱动把其转化为BR_TRANSACTIONB转发给B。

B接收到一个类型为BR_TRANSACTIONB的数据,然后发送一个BC_REPLY的消息给驱动,驱动把其转化为BR_REPLY,然后回复给A进程。

简单概述

在前面的分析中,我们没有详细的分析,驱动程序中,如何查找到消息的目的进程。该小节我们进行详细的分析。主要解决以下两个问题即可:

1.发给谁?handle只表明了进程,是发送给进程,还是发送给线程?

2.回复给谁?回复的时候没有了handle表明目的进程,必定在某个地方记录了发送者(即后面要讲解的transaction_stack)

在获取服务的时候,我们获得的handle代表一个进程,但是需要发送的目标可能是某个线程。

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

如test_client要发送数据给test_sever。

test_sever中存在多个线程(binder_thread),其在binder驱动中,对应一个binder_proc结构体,并且还有一个todo链表。但是binder_thread中也存在一个todo链表。那么问题来了,发送数据的时候,我们是把数据放入binder_proc的todo链表还是放入binder_thread的todo链表呢?

一般来说,test_client会把数据放入到binder_proc的todo链表中,唤醒等待于binder_proc.wait的空闲线程。但是也有特殊情况,对于双向传输,则放在binder_thread.todo中,然后唤醒该线程。那怎么分辨是否为双向传输呢?其也是通过该小节要讲解的transaction_stack机制来判断。

下面我们进行情景分析。

情景分析

下面是一个test_client与test_server执行的流程图:

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

test_client发送一个BC_TRANSACTION,test_server接收到一个BR_TRANSACTION。test_server处理完成之后发送BC_REPLY给test_client,test_client接收到一个BR_REPLY。

根据这四个过程,我们看看transaction_stack是如何其作用的,前面分析过,binder_ioctl最终会调用到binder_transaction()函数,

static void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply,binder_size_t extra_buffers_size)
	if (reply) {
		......
	} else {
		struct binder_ref *ref;
		/*根据tr->target.handle获得一个struct binder_ref *ref*/
		ref = binder_get_ref_olocked(proc, tr->target.handle,true);
		/*根据ref获得struct binder_node *target_node,即目的节点*/
		target_node = binder_get_node_refs_for_txn(ref->node, &target_proc,&return_error);
		......
		......
           

下面是一个详细的框图,我们围绕该框图进行讲解:

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

BC_TRANSACTION过程

1.在一看是的时候,test_client与test_server是非双向传输的,所以数据将放在test_server的binder_proc.todo的链表中,唤醒test_server.binder_proc.wait上等待到得线程

static void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply,binder_size_t extra_buffers_size)
	/*发送之后还想得到回复*/
	} else if (!(t->flags & TF_ONE_WAY)) {
		/*一个链表的操作,入栈。t中包含了甚多信息,如发送给谁,从哪里开始发送等等*/
		t->from_parent = thread->transaction_stack;
	/*进程在没有创建线线程的时候,也存在一个主线程*/
	binder_enqueue_work(proc, tcomplete, &thread->todo);
           

2.test_client中的binder_thread存在.transaction_stack指向一个传输结构。

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

BC_TRANSACTION过程

test_server接收到BR_TRANSACTION之后:

05.Binder系统:第6课第7节_Binder系统_驱动情景分析_transaction_stack机制_REPLY

继续阅读