本节讲述BpBinder调用BBinder的过程,我们以client使用server提供的服务源码来分析。假设server向serviceManager注册了Goodbye服务(binder初始化有说),client获取了Goodbye服务。
client应用程序调用代理类对象方法BpGoodbyeService::saygoodbye_to("android")
Parcel对象提供了很多方法去封装数据到缓冲区,或者读取缓冲区的数据,注意在Parcel缓冲区写入字符串会先写入字符串的长度。
data的缓冲区是这样分布的:
封装好数据后调用remote()->transact()。前面我们说过remote()返回的是binder引用对象Bpbinder,所以remote()->transact()就会调用到BpBinder的transact()函数。
BpBinder::transact()会调用binder线程对象transact函数,注意参数它增加了一个mHandle参数,也就是binder引用对象的handle值。这里它对binder实体对象BBinder的引用编号为1(handle=1)。
IPCThreadState::transact()会有两个步骤
1、writeTransactionData()封装数据
2、waitForResponse()发送数据并等待回复
1、writeTransactionData()
继续封装参数的数据到线程缓冲区,注意参数data和线程缓冲区mout都是Parcel对象。
mOut的缓冲区是这样分布的:
2、waitForResponse()
waitForResponse会在死循环通过talkWithDriver向驱动发送数据,并在talkWithDriver里面阻塞,直到有数据返回,然后通过case-by-case解释读到的cmd。要注意很多返回的cmd处理只是简单的break处理,然后循环talkWithDriver再向驱动发送数据,阻塞等待驱动返回的数据,直到解释goto
finish的命令才结束死循环。
再看talkWithDriver把线程缓冲区mout的数据封装成binder_write_read 结构体发送到驱动
它最终会通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)发送数据到驱动,这个线程阻塞到这里。直到驱动返回,返回数据的就在bwr.read_buffer缓冲区,bwr.read_consumed是返回数据的长度。可以看到它把数据放到reply缓冲区,reply依然是Parcel对象。
总结为图:
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
client进入内核空间,调用到binder驱动的binder_ioctl。cmd为BINDER_WRITE_READ,参数bwr.write_size 和 bwr.read_size都大于0,所有依次调用
1、binder_thread_write()
2、binder_thread_read()
1 binder_thread_write()
binder_transaction
其实server就是在binder_thread_read上wait_event_interruptible_exclusive上睡眠了,binder_transaction把它唤醒了,继续执行。我们先忽略client的binder_thread_read,直接看看server的binder_thread_read。
binder_thread_read()
client在用户空间把binder_transaction_data传给client内核空间,client内核空间在binder_transaction函数里面把binder_transaction_data整理成一个事务binder_transaction结构体,并通过链表链入到server内核空间的proc->todo事务队列,并唤醒server内核空间的proc->wait等待队列。server会继续在binder_thread_read函数wait_event_interruptible_exclusive上唤醒并继续执行。server把proc->todo链表中的事务binder_transaction取出来,并重新组织binder_transaction_data传递给server的用户空间。要注意,client用户空间结构体binder_transaction_data.target.handle为Bpbinder的handle值,到了server的内核空间binder_thread_read,server把binder_transaction_data.target.cookie附上值,cookie值正是BBinder在server用户空间中的地址。
待续。。。