zoukankan      html  css  js  c++  java
  • Binder理解

    native takepicture -> camera -> ICamera: class bpbinder: transact -> BpBinder: transact -> IPCThread: transact->IPCThread:writeTransactionData 写到mout中,之后会waitForResponse()

    IPCThread : joinThreadPool 为一个无限循环线程,循环中不断调用 getandExecuteCommand(),

    getandExecuteCommand() ->talkWithDriver():会从mIn中读取数据,并将mOut中的数据通过ioctl写入共享内存。

    getandExecuteCommand() -> executeCommand():从mIn中读取命令及数据,若为transact:reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);

    调用BBinder的transact()->BnCamera:BnInterface -> onTransact()

    再调用到hal层的实现

    从AMP.startService是如何通过Binder一步步调用进入到system_server进程的AMS.startService. 整个过程涉及Java framework, native, kernel driver各个层面知识:

    从通信流程角度来看整个过程:binder_ipc_process

    图解:

    1. 发起端线程向Binder Driver发起binder ioctl请求后, 便采用环不断talkWithDriver,此时该线程处于阻塞状态, 直到收到如下BR_XXX命令才会结束该过程.
      • BR_TRANSACTION_COMPLETE: oneway模式下,收到该命令则退出
      • BR_REPLY: 非oneway模式下,收到该命令才退出;
      • BR_DEAD_REPLY: 目标进程/线程/binder实体为空, 以及释放正在等待reply的binder thread或者binder buffer;
      • BR_FAILED_REPLY: 情况较多,比如非法handle, 错误事务栈, security, 内存不足, buffer不足, 数据拷贝失败, 节点创建失败, 各种不匹配等问题
      • BR_ACQUIRE_RESULT: 目前未使用的协议;
    2. 左图中waitForResponse收到BR_TRANSACTION_COMPLETE,则直接退出循环, 则没有机会执行executeCommand()方法, 故将其颜色画为灰色. 除以上5种BR_XXX命令, 当收到其他BR命令,则都会执行executeCommand过程.
    3. 目标Binder线程创建后, 便进入joinThreadPool()方法, 采用循环不断地循环执行getAndExecuteCommand()方法, 当bwr的读写buffer都没有数据时,则阻塞在binder_thread_read的wait_event过程. 另外,正常情况下binder线程一旦创建则不会退出.

    6.2 通信协议

    从通信协议的角度来看这个过程:

    binder_transaction

    • Binder客户端或者服务端向Binder Driver发送的命令都是以BC_开头,例如本文的BC_TRANSACTIONBC_REPLY, 所有Binder Driver向Binder客户端或者服务端发送的命令则都是以BR_开头, 例如本文中的BR_TRANSACTIONBR_REPLY.
    • 只有当BC_TRANSACTION或者BC_REPLY时, 才调用binder_transaction()来处理事务. 并且都会回应调用者一个BINDER_WORK_TRANSACTION_COMPLETE事务, 经过binder_thread_read()会转变成BR_TRANSACTION_COMPLETE.
    • startService过程便是一个非oneway的过程, 那么oneway的通信过程如下所述.

    6.3 说一说oneway

    上图是非oneway通信过程的协议图, 下图则是对于oneway场景下的通信协议图:

    binder_transaction_oneway

    当收到BR_TRANSACTION_COMPLETE则程序返回,有人可能觉得好奇,为何oneway怎么还要等待回应消息? 我举个例子,你就明白了.

    你(app进程)要给远方的家人(system_server进程)邮寄一封信(transaction), 你需要通过邮寄员(Binder Driver)来完成.整个过程如下:

    1. 你把信交给邮寄员(BC_TRANSACTION);
    2. 邮寄员收到信后, 填一张单子给你作为一份回执(BR_TRANSACTION_COMPLETE). 这样你才放心知道邮递员已确定接收信, 否则就这样走了,信到底有没有交到邮递员手里都不知道,这样的通信实在太让人不省心, 长时间收不到远方家人的回信, 无法得知是在路的中途信件丢失呢,还是压根就没有交到邮递员的手里. 所以说oneway也得知道信是投递状态是否成功.
    3. 邮递员利用交通工具(Binder Driver),将信交给了你的家人(BR_TRANSACTION);

    当你收到回执(BR_TRANSACTION_COMPLETE)时心里也不期待家人回信, 那么这便是一次oneway的通信过程.

    如果你希望家人回信, 那便是非oneway的过程,在上述步骤2后并不是直接返回,而是继续等待着收到家人的回信, 经历前3个步骤之后继续执行:

    1. 家人收到信后, 立马写了个回信交给邮递员BC_REPLY;
    2. 同样,邮递员要写一个回执(BR_TRANSACTION_COMPLETE)给你家人;
    3. 邮递员再次利用交通工具(Binder Driver), 将回信成功交到你的手上(BR_REPLY)

    这便是一次完成的非oneway通信过程.

    oneway与非oneway: 都是需要等待Binder Driver的回应消息BR_TRANSACTION_COMPLETE. 主要区别在于oneway的通信收到BR_TRANSACTION_COMPLETE则返回,而不会再等待BR_REPLY消息的到来. 另外,oneway的binder IPC则接收端无法获取对方的pid.

    总结

    1. Binder概述

    1. 从IPC角度来说:Binder是Android中的一种跨进程通信方式,该通信方式在linux中没有,是Android独有;
    2. 从Android Driver层:Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder;
    3. 从Android Native层:Binder是创建Service Manager以及BpBinder/BBinder模型,搭建与binder驱动的桥梁;
    4. 从Android Framework层:Binder是各种Manager(ActivityManager、WindowManager等)和相应xxxManagerService的桥梁;
    5. 从Android APP层:Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的 Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

    2. Binder架构

    binder_arch

    Binder在整个Android系统中有这举足轻重的地位,在Native层有一套完整的binder通信的C/S架构(图中的蓝色),Bpinder作为客户端,BBinder作为服务端。基于naive层的Binder框架,Java也有一套镜像功能的binder C/S架构,通过JNI技术,与native层的binder对应,Java层的binder功能最终都是交给native的binder来完成。从kernel到native,jni,framework层的架构所涉及的所有有关类和方法见Binder类图

    3. Binder进程与线程

    binder_proc_relation

    对于底层Binder驱动,通过binder_procs链表记录所有创建的binder_proc结构体,binder驱动层的每一个binder_proc结构体都与用户空间的一个用于binder通信的进程一一对应,且每个进程有且只有一个ProcessState对象,这是通过单例模式来保证的。在每个进程中可以有很多个线程,每个线程对应一个IPCThreadState对象,IPCThreadState对象也是单例模式,即一个线程对应一个IPCThreadState对象,在Binder驱动层也有与之相对应的结构,那就是Binder_thread结构体。在binder_proc结构体中通过成员变量rb_root threads,来记录当前进程内所有的binder_thread。

    Binder线程池:每个Server进程在启动时会创建一个binder线程池,并向其中注册一个Binder线程;之后Server进程也可以向binder线程池注册新的线程,或者Binder驱动在探测到没有空闲binder线程时会主动向Server进程注册新的的binder线程。对于一个Server进程有一个最大Binder线程数限制,默认为16个binder线程,例如Android的system_server进程就存在16个线程。对于所有Client端进程的binder请求都是交由Server端进程的binder线程来处理的。

    4. Binder传输过程

    Binder IPC机制,就是指在进程间传输数据(binder_transaction_data),一次数据的传输,称为事务(binder_transaction)。对于多个不同进程向同一个进程发送事务时,这个同一个进程或线程的事务需要串行执行,在Binder驱动中为binder_proc和binder_thread都有todo队列。

    也就是说对于进程间的通信,就是发送端把binder_transaction节点,插入到目标进程或其子线程的todo队列中,等目标进程或线程不断循环地从todo队列中取出数据并进行相应的操作。

    binder_transaction

    在Binder驱动层,每个接收端进程都有一个todo队列,用于保存发送端进程发送过来的binder请求,这类请求可以由接收端进程的任意一个空闲的binder线程处理;接收端进程存在一个或多个binder线程,在每个binder线程里都有一个todo队列,也是用于保存发送端进程发送过来的binder请求,这类请求只能由当前binder线程来处理。binder线程在空闲时进入可中断的休眠状态,当自己的todo队列或所属进程的todo队列有新的请求到来时便会唤醒,如果是由所需进程唤醒的,那么进程会让其中一个线程处理响应的请求,其他线程再次进入休眠状态。

    5. Binder路由

    先来看看Native Binder IPC的两个重量级对象:BpBinder(客户端)和BBinder(服务端)都是Android中Binder通信相关的代表,它们都从IBinder类中派生而来,关系图如下:

    Binder关系图

    • IBinder有一个重要方法queryLocalInterface, 默认返回值为NULL;
      • BBinder/BpBinder都没有实现,默认返回NULL;BnInterface重写该方法;
      • BinderProxy(Java)默认返回NULL;Binder(Java)重写该方法;
    • IInterface有一个重要方法asBinder;
    • IInterface子类(服务端)会有一个方法asInterface;

    Native层通过宏IMPLEMENT_META_INTERFACE来完成asInterface实现和descriptor的赋值过程;

    对于Java层跟Native一样,也有完全对应的一套对象和方法:

    • 例如ActivityManagerNative, 通过实现asInterface方法,以及其通过其构造函数 调用attachInterface(),完成descriptor的赋值过程。
    • 再如AIDL全自动生成asInterface和descriptor赋值过程。

    同一个进程,请求binder服务,不需要创建binder_ref,BpBinder等这些对象,但是是否需要经过binder call,取决于descriptor是否设置。 这就涉及到Java服务Native使用,或许Native服务在Java层使用,需要格外注意。

    binder的路由原理:BpBinder发送端,根据handler,在当前binder_proc中,找到相应的binder_ref,由binder_ref再找到目标binder_node实体,由目标binder_node再找到目标进程binder_proc。简单地方式是直接把binder_transaction节点插入到binder_proc的todo队列中,完成传输过程。

    对于binder驱动来说应尽可能地把binder_transaction节点插入到目标进程的某个线程的todo队列,效率更高。当binder驱动可以找到合适的线程,就会把binder_transaction节点插入到相应线程的todo队列中,如果找不到合适的线程,就把节点之间插入binder_proc的todo队列。

    转自:http://gityuan.com/2016/09/04/binder-start-service/

  • 相关阅读:
    我还在生产玩 JDK7,JDK 15 却要来了!|新特性尝鲜
    Memcached双主模型之repcached
    Redis服务之Redis5集群相关命令说明
    Redis服务之集群节点管理
    Redis服务之Redis Cluster
    Redis服务之高可用组件sentinel
    Redis服务之常用数据类型
    Redis服务之常用配置(三)
    Redis服务之常用配置(二)
    Redis服务之常用配置(一)
  • 原文地址:https://www.cnblogs.com/zl1991/p/6093222.html
Copyright © 2011-2022 走看看