一次典型binder 同步通讯

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  执行对应函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值