这里仅仅梳理了主要的流程信息,方便大家查找。详细流程请参考:https://blog.csdn.net/tkwxty/category_9437770.html
1、servicesmanager进程binder进入等待
1.1 服务端进程:
//service_manager.c main();
open("/dev/binder", O_RDWR | O_CLOEXEC);
ioctl(bs->fd, BINDER_VERSION, &vers)
mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
binder_become_context_manager(struct binder_state *bs)
ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); //驱动层 将全局变量binder_context_mgr_uid binder_context_mgr_node 赋值,创建binder_thread
binder_loop(bs, svcmgr_handler)
//循环调用,先设置BC_ENTER_LOOPER,告诉Kernel binder驱动,我(ServiceManager进程)要进入消息循环状态了,请做好相关准备
//然后再从kernel读取消息反馈
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
1.2 进入驱动:
//bwr.write_size=0,而bwr.read_size不为0。
binder_ioctl()
binder_thread_read()
// 由于目前没有事务,servicemanger进程进入等待中
// 阻塞式的读取,则阻塞等待事务的发生。
wait_event_freezable_exclusive()
由此servicesmanager阻塞在main()–>binder_loop()–>binder_ioctl()–>binder_thread_read()–>wait_event_freezable_exclusive()
2、MediaPlayerService请求addService流程。
2.1 客户端侧:
remote->transact() -->
BpBinder::transact() -->
IPCThreadState::transact -->
IPCThreadState::writeTransactionData() 数据打包为 binder_transaction_data-->
IPCThreadState::waitForResponse //等待数据的返回-->
IPCThreadState::talkWithDriver() 数据打包为binder_write_read --》
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)发送数据 --》
2.2 ioctl进入驱动侧:
binder_ioctl() 将binder_write_read从“用户空间”拷贝到“内核空间”--》
binder_thread_write() 将binder_transaction_data 从“用户空间”拷贝到“内核空间”--》
//分配事务给服务端侧
//分配待完成工作给客服端侧
//通过binder_alloc_buf,在service内核空间开辟内存t->buffer,内存和用户空间存在映射。
//<mark>将"用户空间的数据"拷贝到内核中binder_alloc_buf开辟的地址,将binder对象copy到内核中</mark>
//解析flat_binder_object 修改type BINDER_TYPE_BINDER为BINDER_TYPE_BINDER
//唤醒目标进程wake_up_interruptible
binder_transaction()
binder_thread_read() 将 BR_NOOP 、 BINDER_WORK_TRANSACTION_COMPLETE拷贝到用户空间,意味着"Binder驱动已经将请求的内容都处理完毕了"
2.3 ioctl完毕 重回客户端侧:
IPCThreadState::talkWithDriver() 释放mOut的内存,将bwr.read_consumed数据赋值给mIn.准备读取返回。——》
IPCThreadState::waitForResponse //mIn中的数据就是Binder驱动返回的"BR_NOOP和BR_TRANSACTION_COMPLETE两个指令",BR_NOOP不执行任何操作,重新开始while循环,执行talkWithDriver()。-->
IPCThreadState::talkWithDriver() 由于 bwr.write_size和bwr.read_size都为0,因此直接返回NO_ERROR。再次返回waitForResp-->
IPCThreadState::waitForResponse 读取到BR_TRANSACTION_COMPLETE--》
IPCThreadState::talkWithDriver() binder线程进入等待请求的状态。--》
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)发送数据 --》
2.4 ioctl进入驱动侧:
此时bwr.write_size=0,因此只读不写,不会执行binder_thread_write()。而此时bwr.read_size>0,因此会调用binder_thread_read()进行读取动作。
(1) 此时,bwr.read_consumed=0,意味着*consumed=0。因此,还是会先将BR_NOOP写入到bwr.read_buffer中。
(2) 此时,当前线程的事务栈和待处理事务队列都是空,因此wait_for_proc_work=true。
(3) 在调用binder_set_nice()设置当前线程的优先级之后,就会调用wait_event_interruptible()。而此时binder_has_proc_work()为false,因此当前线程会进入中断等待状态。当Service Manager处理完MediaPlayerService的请求之后,就会将其唤醒。
由此客户端暂时等待servicemanger的处理。等待在流程图的第5步
三、servicemanager获取到请求
3.1 驱动侧
当前 servicemanager阻塞在binder_thread_read()–>wait_event_freezable_exclusive(),客户端唤醒servicemanager,我们从binder_thread_read()开始分析
//从&thread->todo取出待完成的工作binder_transaction。
//将binder_transaction 数据提取为binder_transaction_data
//将cmd指令和binder_transaction_data 复制到用户空间。binder_transaction_data包含了传输的数据指针地址。
//删除已处理的事务
//修改*consumed的值,即bwr.read_consumed的值,表示待读取内容的大小。
binder_thread_read()
//执行copy_to_user()将bwr拷贝到用户空间
binder_ioctl()
此时ServiceManager进程已经从驱动层返回回来,进入用户空间中执行,即回到binder_loop()中,那么我们继续分析binder_loop()。
3.2 回到ServiceManager进程
//ioct返回数据
binder_loop()
//将数据转换为binder_transaction_data
//进行解析
//将binder_transaction_data转换为私有对象binder_io,msg和reply
binder_parse()
//根据msg获取service name和 flat_binder_object 要添加的binder代理对象flat_binder_object ->handle,而该handle在Binder驱动中被赋值为"MediaPlayerService对应的Binder引用的描述,即binder_ref->desc"。根据该引用描述,可以在Binder驱动中找到MediaPlayerService对应的Binder实体以及MediaPlayerService对应的进程上下文信息,进而可以给MediaPlayerService发送消息。
svcmgr_handler()
//创建svcinfo 注册到svclist
//svcinfo包含了MediaPlayerService的name和binder handle等信息
do_add_service()
//0表示不写数据到reply
bio_put_uint32(reply, 0);
//组装数据BC_FREE_BUFFER和BC_REPLY BC_REPLY是告诉Binder驱动,这是回复,这里回复的内容是null
binder_send_reply()
//将上面组装的数据告诉驱动。
binder_write()
ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
3.3 在回驱动侧
此时bwr.write_size>0,而bwr.read_size=0
binder_ioctl()
//BC_FREE_BUFFER 释放分配的数据内存
//BC_REPLY 继续执行binder_transaction()
//在收到BC_REPLY之后,得知ServiceManager已经处理完addService请求
binder_thread_write()
//从MediaPlayerService线程的事务栈中删除该事务。
//BINDER_WORK_TRANSACTION添加到MediaPlayerService 待处理事务队列target_list中。目的是告诉MediaPlayerService,它已经处理完了addService请求。
//BINDER_WORK_TRANSACTION_COMPLETE 添加到Service Manager 的待处理事务队列thread->todo中
//wake_up_interruptible()唤醒MediaPlayerService进程。
binder_transaction()
//将数据拷贝到用户空间
binder_ioctl()
3.4 再回servicemanger
返回到binder_loop()会再次开始循环
并通过binder_ioctl()调用到binder_thread_read()时
处理事务BINDER_WORK_TRANSACTION_COMPLETE
便取出该事务进行执行,执行完毕之后,将该事务从Service Manager的待处理事务队列中删除,并反馈cmd=BR_TRANSACTION_COMPLETE信息给ServiceManager守护进程。
serviceManager守护进程收到Binder驱动的反馈后,解析出BR_TRANSACTION_COMPLETE,该指令什么也不做;它的目的是让ServiceManager知道,此次addService的反馈已经顺利完成!
于是,ServiceManager继续它的循环;当它再次调用ioctl(),进而进入到Binder驱动中读取请求时;由于此时的待处理事务队列为空,因此,ServiceManager会再次进入中断等待状态,等待Client的请求。
四、MediaPlayerService 处理数据反馈第10步
MediaPlayerService在发送addService请求之后,会阻塞在Binder驱动wait_event_interruptible_exclusive等待被唤醒
4.1 驱动侧
//取出事务BINDER_WORK_TRANSACTION
//将binder_transaction_data copy到用户空间,
//共反馈了两个指令到用户空间,BR_NOOP和BR_REPLY。
binder_thread_read()
4.2 MediaPlayerService重回用户空间
IPCThreadState::waitForResponse
//解析BR_REPLY
//取出数据binder_transaction_data
waitForResponse()
//重新初始化Parcel的数据和对象。
//ServiceManager返回的是空,就是告诉它addService已经成功处理完毕!
Parcel->ipcSetDataReference()
MediaPlayerService 初始化完成。addService的整个流程也算告一段落了
int main(int argc __unused, char **argv __unused)
{
...
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
...
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
...
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}