https://blog.csdn.net/tkwxty/article/details/102824924

第一篇:Binder设计思想

https://blog.csdn.net/tkwxty/article/details/102824924

一、Binder架构解析

1.何为binder

Binder用最简单的话来概括说就是Android中的一种IPC进程间通信机制,虽然它是一种IPC通信机制,但是它又和Linux的传统的IPC机制管道,system V IPC,socket等有所不同(这个不同主要表现其实现原理和使用场景)。

2.binder模型


上图中涉及到Binder模型的4类角色:Binder驱动,ServiceManager(后续简称SMgr),Server和Client。其中Server,Client,SMgr运行于用户空间,驱动运行于内核空间。

  • Server
    分2部分,SystemServer进程和其它进程。
    1)SystemServer进程,所有的系统服务都是在这个进程中创建的。
    2)其它进程,任何对其它进程提供binder服务的进程。

  • Client
    一般指应用进程。Client 是相对于 ServiceManager 而言的,一个进程或者应用程序可能是提供服务的 Server,但对于 ServiceManager 来说它仍然是个 Client。

  • ServiceManager
    是单独的守护进程。
    ServiceManager 提供的 Binder 比较特殊,它没有名字也不需要注册。当一个进程使用 BINDERSETCONTEXT_MGR 命令将自己注册成 ServiceManager 时 Binder 驱动会自动为它创建 Binder 实体(这就是那只预先造好的那只鸡)。其次这个 Binder 实体的引用在所有 Client 中都固定为 0 而无需通过其它手段获得。也就是说,一个 Server 想要向 ServiceManager 注册自己的 Binder 就必须通过这个 0 号引用和 ServiceManager 的 Binder 通信。

3.Binder驱动存在的原因和意义

应用程序都运行在用户空间,每个应用程序都有它自己独立的内存空间;若不同的应用程序之间涉及到通信,需要通过内核进行中转,因为需要用到内核的copy_from_user()和copy_to_user()等函数。

4.为什么采用Binder机制,而不是其他的IPC通信方式

  • 第一. Binder能够很好的实现Client-Server架构

对于Android系统,Google想提供一套基于Client-Server的通信方式。
例如,将"电池信息/马达控制/wifi信息/多媒体服务"等等不同的服务都由不同的Server提供,当Client需要获取某Server的服务时,只需要Client向Server发送相应的请求,Server收到请求之后进行处理,处理完毕再将反馈内容发送给Client。

但是,目前Linux支持的"传统的管道/消息队列/共享内存/信号量/Socket等"IPC通信手段中,只有Socket是Client-Server的通信方式。但是,Socket主要用于网络间通信以及本机中进程间的低速通信,它的传输效率太低。

  • 第二. Binder的传输效率和可操作性很好

前面已经说了,Socket传输效率很低,已经被排除。而消息队列和管道又采用存储-转发方式,使用它们进行IPC通信时,需要经过2次内存拷贝!效率太低!

为什么消息队列和管道的数据传输需要经过2次内存拷贝呢? 首先,数据先从发送方的缓存区(即,Linux中的用户存储空间)拷贝到内核开辟的缓存区(即,Linux中的内核存储空间)中,是第1次拷贝。接着,再从内核缓存区拷贝到接收方的缓存区(也是Linux中的用户存储空间),这是第2次拷贝。
而采用Binder机制的话,则只需要经过1次内存拷贝即可! 即,从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,因此只需要1次拷贝即可。

至于共享内存呢,虽然使用它进行IPC通信时进行的内存拷贝次数是0。但是,共享内存操作复杂,也将它排除。
这里并不是说上面的其它进程间通信方式都是糟粕,只是在Binder通信上面使用内存映射是最合适的。在Android系统中Input系统的实现依然依赖着Socket,Android里面属性的实现使用的就是共享内存,Android Looper里面还使用着管道呢。

  • 第三. Binder机制的安全性很高

传统IPC没有任何安全措施,完全依赖上层协议来确保。传统IPC的接收方无法获得对方进程可靠的UID/PID(用户ID/进程ID),从而无法鉴别对方身份。而Binder机制则为每个进程分配了UID/PID来作为鉴别身份的标示,并且在Binder通信时会根据UID/PID进行有效性检测。在实际项目中可能一些敏感的服务,不希望被乱用就可以通过UID/PID鉴权的方式来防护。

5.Binder中各角色之间关系

  • Binder实体
    Binder实体,是各个Server以及ServiceManager在内核中的存在形式。
    Binder实体实际上是内核中binder_node结构体的对象,它的作用是在内核中保存Server和ServiceManager的信息(例如,Binder实体中保存了Server对象在用户空间的地址)。简言之,Binder实体是Server在Binder驱动中的存在形式,内核通过Binder实体可以找到用户空间的Server对象。

  • Binder引用
    说到Binder实体,就不得不说"Binder引用"。所谓Binder引用,实际上是内核中binder_ref结构体的对象,它的作用是在表示"Binder实体"的引用。换句话说,每一个Binder引用都是某一个Binder实体的引用,通过Binder引用可以在内核中找到它对应的Binder实体。
    如果将Server看作是Binder实体的话,那么Client就好比Binder引用。Client要和Server通信,它就是通过保存一个Server对象的Binder引用,再通过该Binder引用在内核中找到对应的Binder实体,进而找到Server对象,然后将通信内容发送给Server对象。

Binder实体和Binder引用都是内核(即,Binder驱动)中的数据结构。每一个Server在内核中就表现为一个Binder实体,而每一个Client则表现为一个Binder引用。这样,每个Binder引用都对应一个Binder实体,而每个Binder实体则可以多个Binder引用。

  • 远程服务 (**)

二、Binder设计解析

1.Binder设计

1-1)内核空间的Binder设计

  • 重要结构体

内核空间的Binder设计涉及到3个非常重要的结构体:binder_proc,binder_node和binder_ref。由于本文的重点是介绍Binder机制的理论知识,因此,在这里我并不打算展开这3个结构体对它们进行详细介绍。当然,后面会再撰文对这些类进行详细说明。这里只需要了解个大概即可。

binder_proc是描述进程上下文信息的,每一个用户空间的进程都对应一个binder_proc结构体。
binder_node是Binder实体对应的结构体,它是Server在Binder驱动中的体现。
binder_ref是Binder引用对应的结构体,它是Client在Binder驱动中的体现。

binder_proc包含binder实体与binder引用红黑树

1-2)用户空间的Binder设计

2.Binder通信

2-1)Binder通信模型

2-2)Binder通信数据结构

第二篇:Binder数据结构

https://blog.csdn.net/tkwxty/article/details/102843741

一、内核空间的Binder数据结构

高通android10内核数据结构基本都定义在kernel/drivers/android/binder.c

1.binder_proc

Binder驱动的文件节点是"/dev/binder",每当一个程序打开该文件节点时;Binder驱动中都会新建一个binder_proc对象来保存该进程的上下文信息。

2.binder_thread

binder_thread是内核层描述Binder线程的结构体,在用户层与其相对应的是IPCThreadState。binder_proc是描述进程的,而binder_thread是描述进程中的线程。从上面对binder_proc结构体的描述我们可以知道binder_proc可以同时包含多个binder_thread,即一对多的关系。

1) proc,它是binder_proc(进程上下文信息)结构体对象。目的是保存该线程所属的Binder进程。
2)rb_node,它是红黑树节点。通过将rb_node binder关联到所属进程红黑树proc->threads中,从而将该线程添加到进程的threads红黑树中进行管理。

3.binder_node

binder_node是内核层描述Binder实体的结构体,用户层与之相对应的是具体的Binder Server。

1)rb_node和dead_node属于一个union。如果该Binder实体还在使用,则通过rb_node将该节点链接到proc->nodes红黑树中;否则,则将该Binder实体通过dead_node链接到全局哈希表binder_dead_nodes中。
2)proc,它是binder_proc(进程上下文信息)结构体对象。目的是保存该Binder实体的进程。
3)refs,它是该Binder实体的所有引用所组成的链表。

4.binder_ref

binder_ref是内核层描述Binder引用的结构体,用户层与之相对应的是某个具体服务的远程代理BpBinder或者BinderProxy。

5.binder_buffer

binder_buffer是描述Binder进程所管理的每段内存的结构体。

6.flat_binder_object

flat_binder_object是用来描述Binder信息的结构体。它也属于内核空间和用户空间的通信结构体。
总体来说,在用户空间,flat_binder_object是描述该Binder实体在用户空间的存在形式;而在内核空间中,flat_binder_object则描述该Binder实体在内核中的存在形式。

7.binder_write_read

binder_write_read是用来描述Binder在驱动层和用户层进行数据读写交互的的结构体。

8.binder_transaction_data

binder_transaction_data使用来描述Binder事务交互的数据结构体。它也属于内核空间和用户空间的通信结构体。

9.binder_transaction

binder_transaction用来描述进程间通信过程,这个过程又称为一个事务,进程通信事务。

二、用户空间的Binder数据结构

1.ServiceManager守护进程中的数据结构

1-1.binder_state

binder_state定义在frameworks/native/cmds/servicemanager/binder.c中,它是ServiceManager调用binder_open后用来描述打开的"/dev/binder"的信息结构体。

1-2.binder_io

binder_io定义在frameworks/native/cmds/servicemanager/binder.h中,它是ServiceManager中与binder_transaction_data对应的结构体。

1-3.svcinfo

svcinfo定义在frameworks/native/cmds/servicemanager/service_manager.c中。它是ServiceManager守护进程的私有结构体。
svcinfo是保存"注册到ServiceManager中的服务"的相关信息的结构体。它是一个单链表,在ServiceManager守护进程中的svclist是保存注册到ServiceManager中的服务的链表,它就是struct info类型。svcinfo中的next是指向下一个服务的节点,而ptr是该服务在Binder驱动中Binder引用的描述。name则是服务的名称。

2.c++层的数据结构

2-1.Parcel

Parcel是描述Binder在用户层服务代理端和服务端进行通信的信息的结构体。
Parcel定义在frameworks/native/include/binder/Parcel.h中。

第三篇:Binder接口和类

https://blog.csdn.net/tkwxty/article/details/102970008

1.Java层次的Binder接口和类

  • IBinder接口
    Android要求所有的Binder实体都必须实现IBinder接口,其文件在Android源码的路径是frameworks/base/core/java/android/os/IBinder.java

  • IInterface接口
    IInterface接口比较简单,其源码路径为仅仅单单定义了一个方法,不管是服务端还是客户端都需要实现该接口

  • BinderProxy类
    BinderProxy是IBinder的子类,客户端进程持有关联的服务的的BinderProxy对象从而完成相关的远程服务调用,其底层相对应的C++层的BpBinder。

  • Binder类
    Binder也是IBinder的子类,Java层提供服务的Server进程持有一个Binder对象从而完成跨进程间通信。

类与接口关系图:


在实际开发使用中,我们并不需要编写上图的XXXXNative、XXXXProxy,它们会由ADT根据我们编写的aidl脚本自动生成。就研究跨进程通信而言,其实质内容基本上都在C++层次,Java层次只是一个壳而已。

2.C++层次的相关接口和类

  • RefBase类
    它定义在system/core/include/utils/RefBase.h

  • BpRefBase类
    它定义在frameworks/native/include/binder/Binder.h中。BpRefBase继承于RefBase,它有一个IBinder*类型的成员mRemote,同时提供了获取该mRemote的方法。实际上,该mRemote就是BpBinder对象。

  • IInterface类
    定义在frameworks/native/include/binder/IInterface.h中。和RefBase类似,它也是一个公共父类,IInterface中声明了asBinder()方法,用于获取对象的IBinder对象。

  • BpInterface和BnInterface
    (1).BpInterface:它定义在frameworks/native/include/binder/IInterface.h中。实际上,BpInterface是一个模板类,同时继承了BpRefBase和INTERFACE,这里的INTERFACE是模板。
    (2).BnInterface:它定义在frameworks/native/include/binder/IInterface.h中。和BpInterface类似,BnInterface也是一个模板类,它同时继承了BBinder和INTERFACE。

java层与c++层的binder是如何关联的

3.ProcessState

它定义在frameworks/native/libs/binder/ProcessState.cpp中,在每个进程中,会有一个全局的ProcessState对象。这个很容易理解,ProcessState的字面意思不就是“进程状态”吗,ProcessState的实例是采用单例模式实现的。

它拥有两个非常重要的成员:mDriverFD和mHandleToObject。

  • mDriverFD
    我们知道,Binder内核被设计成一个驱动程序,所以ProcessState里专门搞了个mDriverFD域,来记录binder驱动对应的句柄值,以便随时和binder驱动通信。ProcessState对象采用了典型的单例模式,在一个应用进程中,只会有唯一的一个ProcessState对象,它将被进程中的多个线程共用,因此每个进程里的线程其实是共用所打开的那个驱动句柄(mDriverFD)的

  • mHandleToObject

4.IPCThreadState

它定义在frameworks/native/libs/binder/IPCThreadState.cpp中中。IPCThreadState的实例也是采用单例模式实现的,它是正在与Binder驱动进行交互的类,和Binder内核层的binder_thread相对应。

总结:

对于一个Server而言,它都会存在一个"远程BpBinder对象"和"本地BBinder对象"。
(01) 远程BpBinder对象的作用:是和Binder驱动进行交互。具体的方式是,当Client端要向Binder发起事务请求时,会调用BpBinder的transact()接口,而该接口会调用到IPCThreadState::transact()接口,通过IPCThreadState类来和Binder驱动交互。此外,该BpBinder在Binder驱动中的Binder引用的描述会被保存到ProcessState的mHandleToObject矢量缓冲数组中。
(02) 本地BBinder对象的作用:是Server响应Client请求的类。当Client有请求发送给Server时,都会调用到BBinder的onTransact()函数,而每个Server都会覆盖onTransact()函数。这样,每个Server就可以在onTransact()中根据自己的情况对请求进行处理。

第四篇:Parcel详解之基本数据的读写

https://blog.csdn.net/tkwxty/article/details/107916160

Parcel框架图:

分类: Binder

0 条评论

发表回复

您的电子邮箱地址不会被公开。