Update Binder.md

master
Omooo 5 years ago
parent 78e91f9d4c
commit edc12eb07b
  1. 57
      blogs/Android/口水话/Binder.md

@ -4,15 +4,62 @@ Binder 系列口水话
#### 面试题 #### 面试题
谈谈你对 Binder 的理解? 1. 谈谈你对 Binder 的理解?
2. 一次完整的 IPC 通信流程是怎样的?
3. Binder 对象跨进程传递的原理是怎么样的?
4. Framework 中其他的 IPC 通信方式
#### 大纲 #### 谈谈你对 Binder 的理解?
1. binder 是干嘛的? Binder 是 Android 中一种高效、方便、安全的进程间通信方式。高效是指 Binder 只需要一次数据拷贝,把一块物理内存同时映射到内核和目标进程的用户空间。方便是指用起来简单直接,Client 端使用 Service 端的提供的服务只需要传 Service 的一个描述符即可,就可以获取到 Service 提供的服务接口。安全是指 Binder 验证调用方可靠的身份信息,这个身份信息不能是调用方自己填写的,显然不可靠的,而可靠的身份信息应该是 IPC 机制本身在内核态中添加。
2. binder 存在的意义是什么?
3. binder 的架构原理是怎样的?
Binder 通信模型由四方参与,分别是 Binder 驱动层、Client 端、Service 端和 ServiceManager。
Client 端表示应用程序进程,Service 端表示系统服务,它可能运行在 SystemService 进程,比如 AMS、PKMS等,也可能是运行在一个单独的进程中,比如 SurfaceFlinger。ServiceManager 是 Binder 进程间通信方式的上下文管理者,它提供 Service 端的服务注册和 Client 端的服务获取功能。它们之间是不能直接通信的,需要借助于 Binder 驱动层进行交互。
这就需要它们首先通过 binder_open 打开 binder 驱动,然后根据返回的 fd 进行内存映射,分配缓冲区,最后启动 binder 线程,启动 binder 线程一方面是把这个这些线程注册到 binder 驱动,另一方面是这个线程要进入 binder_loop 循环,不断的去跟 binder 驱动进程交互。
接下来就可以开始 binder 通信了,我们从 ServiceManager 说起。
ServiceManger 的 main 函数首先调用 binder_open 打开 binder 驱动,然后调用 binder_become_context_manager 注册为 binder 的大管家,也就是告诉 Binder 驱动 Service 的注册和获取都是通过我来做的,最后进入 binder_loop 循环。binder_loop 首先通过 BC_ENTER_LOOPER 命令协议把当前线程注册为 binder 线程,也就是 ServiceManager 的主线程,然后在一个 for 死循环中不断去读 binder 驱动发送来的请求去处理,也就调用 ioctl。
有了 ServiceManager 之后,Service 系统服务就可以向 ServiceManager 进行注册了。也 ServiceFlinger 为例,在它的入口函数 main 函数中,首先也需要启动 binder 机制,也就是上所说的那三步,然后就是初始化 ServiceFlinger,最后就是注册服务。注册服务首先需要拿到 ServiceManager 的 Binder 代理对象,也就是通过 defaultServiceManager 方法,真正获取 ServiceManager 代理对象的是通过 getStrongProxyForHandle(0),也就是查的是句柄值为 0 的 binder 引用,也就是 ServiceManager。如果没查到就说明可能 ServiceManager 还没来得及注册,这个时候 sleep(1) 等等就行了。然后就是调用 addService 来进行注册了。addService 就会把 name 和 binder 对象都写到 Parcel 中,然后就是调用 transact 发送一个 ADD_SERVICE_TRANSACTION 的请求。实际上是调用 IPCThreadState 的 transact 函数,第一个参数是 mHandle 值,也就是说底层在和 binder 驱动进行交互的时候是不区分 BpBinder 还是 BBinder,它只认一个 handle 值。
Binder 驱动就会把这个请求交给 Binder 实体对象去处理,也就是是在 ServiceManager 的 onTransact 函数中处理 ADD_SERVICE_TRANSACTION 请求,也就是根据 handle 值封装一个 BinderProxy 对象,至此,Service 的注册就完成了。
至于 Client 获取服务,其实和这个差不多,也就是拿到服务的 BinderProxy 对象即可。
在回答的时候,最后可以画一下图:
![](https://i.loli.net/2020/03/27/REqCWzQSnokHKFw.png)
![](https://i.loli.net/2020/03/28/1qUCWh5B7vSVzAe.png)
上面已经说清楚了 Binder 通信模型的大致流程,下面可以再说一下一次完整的 IPC 通信流程是怎么样的。
#### 一次完整的 IPC 通信流程是怎样的?
首先是从应用层的 Proxy 的 transact 函数开始,传递到 Java 层的 BinderProxy,最后到 Native 层的 BpBinder 的 transact。在 BpBinder 的 transact 实际上是调用 IPCThreadState 的 transact 函数,在它的第一个参数是 handle 值,Binder 驱动就会根据这个 handle 找到 Binder 引用对象,继而找到 Binder 实体对象。在这个函数中,做了两件事件,一件是调用 writeTransactionData 向 Binder 驱动发出一个 BC_TRANSACTION 的命令协议,把所需参数写到 mOut 中,第二件是 waitForResponse 等待回复,在它里面才会真正的和 Binder 驱动进行交互,也就是调用 talkWithDriver,然后接收到的响应执行相应的处理。这时候 Client 接收到的是 BR_TRANSACTION_COMPLETE,表示 Binder 驱动已经接收到了 Client 的请求了。在这里面还有一个 cmd 为 BR_REPLY 的返回协议,表示 Binder 驱动已经把响应返回给 Client 端了。在 talkWithDriver 中,是通过系统调用 ioctl 来和 Binder 驱动进行交互的,传递一个 BINDER_WRITE_READ 的命令并且携带一个 binder_write_read 数据结构体。在 Binder 驱动层就会根据 write_size/read_size 处理该 BINDER_WRITE_READ 命令。
到这里,已经讲完了 Client 端如何和 Binder 驱动进行交互的了,下面就讲 Service 端是如何和 Binder 驱动进行交互的。
Service 端首先会开启一个 Binder 线程来处理进程间通信消息,也就是通过 new Thread 然后把该线程 joinThreadPool 注册到 Binder 驱动。注册呢也就是通过 BC_ECTER_LOOPER 命令协议来做的,接下来就是在 do while 死循环中调用 getAndExecuteCommand。它里面做的就是不断从驱动读取请求,也就是 talkWithDriver,然后再处理请求 executeCommand。在 executeCommand 中,就会根据 BR_TRANSACTION 来调用 BBinder Binder 实体对象的 onTransact 函数来进行处理,然后在发送一个 BC_REPLY 把响应结构返回给 Binder 驱动。Binder 驱动在接收到 BC_REPLY 之后就会向 Service 发送一个 BR_TRANSACTION_COMPLETE 协议表示 Binder 驱动已经收到了,在此同时呢,也会向 Client 端发送一个 BR_REPLY把响应回写给 Client 端。
需要注意的是,上面的 onTransact 函数就是 Service 端 AIDL 生成的 Stub 类的 onTransact 函数,这时一次完整的 IPC 通信流程就完成了。
最后可画一张图即可:
![](https://i.loli.net/2020/03/28/1ZbMj2fUiX8BGc7.png)
#### Binder 对象跨进程传递的原理是怎么样的?
有以下五点:
1. Parcel 的 writeStrongBinder 和 readStrongBinder
2. Binder 在 Parcel 中存储原理,flat_binder_objet
3. 说清楚 binder_node,binder_ref
4. 目标进程根据 binder_ref 的 handle 创建 BpBinder
5. 由 BpBinder 再往上到 BinderProxy 到业务层的 Proxy
#### Framework IPC 方式汇总 #### Framework IPC 方式汇总

Loading…
Cancel
Save