1、客户端 通过驱动发送 BC_TRANSACTION 命令到驱动内核代表用户空间执行的内核thread,通过binder_thread_write 获取客户端命令、数据等,组织好binder_transaction 唤醒目标thread;目标thread 执行binder_thread_read发送数据到用户空间,客户端对应内核thread 执行binder_thread_read 进入睡眠等待。
2、服务端内核thread 唤醒继续执行 binder_thread_read,通过进一步组织binder_transaction ,对应BR_TRANSACTION 命令码,并通过驱动将数据发送到服务端用户线程,用户线程执行命令码。
3、服务端用户线程执行完,返回结果,并通过驱动发送BC_REPLY 到内核,内核服务端thread 通过binder_thread_write获取BC_REPLAY,并根据2、 binder_transaction 信息获取要应答的内核线程,发送work唤醒客户端内核线程继续执行binder_thread_read,发送BR_REPLY 返回结果到用户空间。
ADD_SERVICE 和 GET_SERVICE 、BnService.fun
GET_SERVICE
1、getServiceManager
IPCProcessState 里面有一个映射表格:handle ->Bpbinder ,这个时候serviceManager 对应的handler 是0 ,如果发起端进程是第一次binder 调用,那映射表格里面是查询不到0 对应的Bpbinder对象,就会创建一个Bpbinder(0) ,并加入映射表格,接下来需要ping 下serviceManager,ping 通了说明servieManager 已经注册了,那ping 的过程就是一次binder 通信,命令码是 BINDER_PING.由于serviceManager 对应的BBinder 地址保存在binder_context 上下文里面,因此可以根据handle=0 直接拿到BBinder 也就是binder_node ,这个时候发起端binder_proc 里面会根据BBinbder 地址(或者handle=0)查询是否创建了binder_ref ,没有就创建,这样就拿到了ServiceManager 对应的binder_ref。
binder_proc 里面有保存映射表:
handler ->binder_ref
binder_node ->binder_ref
ping 通了后,就根据BpBiner(0) 构建BpServiceManager 。
2、BpServiceManager.getService(service_name)
2.1、BpBinder_transact->IPCThreadState->transact 将信息发送到驱动:
BC_TRANSACTION binder 协议命令码 + service_name + BINDER_WRITE_READ IOCTL 命令码 + handle =0
2.2、talkwithdriver 通过ioctl 发送给到驱动,发起端进入waitforrespond 阻塞
到了驱动里面根据ioctl 命令码执行binder_thread_write
2.3、根据binder_proc 查询或者创建一个空闲的binder_thread 用于这次通信
2.4、读取用户空间信息,根据handler =0 找到目标服务servicemanager 对应的binder_ref , 根据binder_ref 拿到binder_node ,根据binder_node 拿到binder_proc ,这样就拿到了 servicemanager常驻内核进程,由于serviceManager 没有binder线程也就是只有一个主 线程,不然需要根据binder_proc 查询或者创建一个binder_thread 用于这次通信。
2.5、serviceManager 所在的binder_proc 获取binder_alloc 分配binder_buffer ,将用户空间的 信息 service_name 复制到binder_buffer
2.6 、创建填充binder_transtraction t 数据结构,用于驱动进程(线程)共享传递数据及返回 (应答),这里保存 from pid:tid to pid:tid ,binder_buffer ,binder_node 等,将 binder_thread->transaction_stack 摘下来赋值给到 t->parent ,再将 t 赋值 binder_thread->transaction_stack = t ,这样就保存了事务栈
2.7、往serviceManager binder_proc(binder_thread)->todo 等待队列里面添加 binder_transaction 类型的binder_work,这样就唤醒了serviceManager binder_proc(binder_thread);往自己的binder_thread->todo 队列添加 binder_transaction_complete 类型binder_work。这样就执行servicemanager ,而发起 端就会很快执行完binder_transaction_complete 进入binder_thread_read 函数挂起
2.8、serviceManager binder_proc(binder_thread)->todo 执行根据work 类型执行不同的代 码,拿到binder_transaction t 这个共享数据结构,往里面填充 to pid:tid ,及其它信 息,保存 t 到 binder_thread->transaction_stack ,同上面。
2.9、向serviceManager 用户进程发送BR_TRANSACTION 命令码 + GET_SERVICE + SERVICE_NAME + handle(或者binder_buffer 里面)
2.10、serviceManager 用户进程talk_with_driver 拿到对应的数据信息,由于handle = 0,IPCProcessState里面保存了BBinder 地址,直接转换成BBinder,执行BBinder- >transact->Ontransact -> get_service , servicemanager 里面保存了一个 映射 表 serivice_name->handle,这样就拿到了handle,应答给到驱动,命令码 BC_REPLY.
2.11、驱动执行binder_thread_write 获取BC_REPLY,执行对应的命令代码,这个时候根据 binder_thread->transaction_stack 拿到应道的对端 from pid:tid ,从而就可以拿到应答 的binder_proc
2.12、根据应答的binder_proc 可以确定应答的不是serivice_name 对应的服务,从而就在应 答的binder_proc 中创建对serivice_name 对应的binder_node 的引用binder_ref ,同时 会分配一个handle(单调递增),这样就拿到了服务。
2.13、 应答的binder_proc的binder_alloc 分配一个binder_buffer ,将应答信息(返回值)填 充
2.15、还原binder_thread->transaction_stack
2.16、跟2.7 跟好一个反的添加 binder_work ,唤醒发前端执行,向用户空间发送 BR_REPLY 从而waitforrespond 解除阻塞,获取返回值,根据2.12、 handle 构建 Bpbinder(handle),再构建BpXXXService(Bpbinder(handle))
3、BpServiceManager.addService(service_name,BnXXXService)
3.1、BC_TRANSACTION binder 协议命令码 + service_name + binder扁平对象(包括BBinder 地址,应用地址) + BINDER_WRITE_READ IOCTL 命令码
3.2、同ADD_SERVICE ,唯一不同的是,由于驱动传递的是binder 对象而不是handle ,所以这里就会在binder_proc 驱动端查询是否存在对应BnXXXService 地址对应的binder_node ,没有就会创建,binder_node 包括了BBinder 地址等。目标服务serviceManager 对应的binder_proc ,查询是否有BnXXXService 对应的binder_node 的引用binder_ref ,没有就创建binder_ref 并分配一个handle (单调地址)
3.3、其它跟上面一样,这个时候发送给到serviceManager 用户空间是 service_name + handle ,构建 service_name ->hanlde 映射表。
4、BpXXXService.fun
同上,唯一不同的是,这个service 跟 servicemanager 有些差异,没有保存其bbinder 到驱动binder_context ,并且IPCProcessState 里面不像servicemanager ,也没有保存bbinder 地址。
从而驱动里面需要根据service->handle 查询binder_ref ,根据binder_ref 查询到binder_node ,根据binder_node 查询到 binder_proc 及BBinder 地址,从而会将BBinder 地址 发送到service用户空间,从而 转换成 BBinder ->transact->OnTransact ->BnService.fun 执行对应函数。