Android Binder进程间通信机制

本文深入剖析Android Binder进程间通信机制,包括服务端与客户端的实现、内存映射、Binder驱动控制协议以及C++层的Binder Framework。阐述了Binder初始化、与驱动通信的细节,如打开设备、内存映射、设置最大线程数,以及如何通过ioctl调用与Binder驱动交互。同时介绍了ServiceManager作为Binder服务管理的角色,展示了如何启动SM、注册服务和查询服务。通过对Binder通信协议的解读,揭示了数据在C/S间的高效传输方式。
摘要由CSDN通过智能技术生成

}

return 0;

}

在Binder驱动中,通过binder_procs集合记录了所有使用Binder的进程。每个初次打开Binder设备的进程都会创建一个binder_proc结构体对象,用来描述使用Binder的进程,然后被添加到这个列表中的。

3.3 内存映射——binder_mmap


在打开Binder设备之后,上层进程就要通过mmap进行内存映射。mmap的作用有如下两个:

  • 申请一块内存空间,用来接收Binder通信过程中的数据

  • 对这块内存进行地址映射,以便将来访问

mmap在内核对应的就是binder_mmap()函数:在这个函数中,会申请一块物理内存,然后将用户空间和内核空间虚拟地址同时对应到这块物理内存上。在这之后,当有Client要发送数据给Server的时候,只需一次copy_from_user动作,将Client发送过来的数据拷贝到Server端的内核空间指定的内存地址即可(从而实现前文说的Binder通信机制只需要一次内存拷贝的效果),由于这个内存地址在服务端已经同时映射到用户空间,因此无需再做一次复制,Server即可直接访问,整个过程如下图所示: mmap_and_transaction.png

这幅图的说明如下:

  1. Server在启动之后,调用对/dev/binder设备调用mmap;

  2. 内核中的binder_mmap函数进行对应的处理:申请一块物理内存,然后在用户空间和内核空间同时进行映射

  3. Client通过BINDER_WRITE_READ命令发送请求,这个请求将先到驱动中,同时需要将数据从Client进程的用户空间拷贝到内核空间;

  4. 驱动通过BR_TRANSACTION通知Server有人发出请求,Server进行处理。由于这块内存也在用户空间进行了映射,因此Server进程的代码可以直接访问。

3.4 Binder驱动控制协议——binder_ioctl


binder_ioctl()实现了上层应用进程与Binder驱动之间的交互命令,可以说承载了Binder驱动的大部分业务,也是我们学习的重中之重。下面表格中列出binder_ioctl支持的命令:

| 命令 | 说明 |

| — | — |

| BINDER_WRITE_READ | 读写操作,可以用此命令向Binder读取或写入数据 |

| BINDER_SET_MAX_THREADS | 设置支持的最大线程数。因为客户端可以并发向服务器端发送请求,如果Binder驱动发现当前线程数已经超过设定值,就会告知Binder Server停止启动新的线程 |

| BINDER_SET_CONTEXT_MGR | Service Manager专用,将自己设置为“Binder大管家”。系统中只能有一个SM存在 |

| BINDER_THREAD_EXIT | 通知Binder线程退出。每个线程退出时都应该告知Binder驱动、才能释放相关资源;否则会造成内存泄漏 |

| BINDER_VERSION | 获取Binder版本号 |

其中BINDER_WRITE_READ这个命令是重点,又分为若干子命令,如下表所示:

| 命令 | 说明 |

| — | — |

| BC_TRANSACTION | Binder事务,即:Client对于Server的请求 |

| BC_REPLY | 事务的应答,即:Server对于Client的回复 |

| BC_ENTER_LOOPER | 通知驱动主线程ready |

| BC_REGISTER_LOOPER | 通知驱动子线程ready |

| BR_REPLY | 通知进程收到Binder请求的回复(Client) |

| BR_TRANSACTION_COMPLETE | 驱动对于接受请求的确认回复 |

| BR_TRANSACTION | 通知进程收到一次Binder请求(Server端) |

| BR_DEAD_BINDER | 发送死亡通知 |

| BR_SPAWN_LOOPER | 通知Binder进程创建一个新的线程 |

其中BC_TRANSACTION和BC_REPLAY是最关键的两个命令,Binder机制中Client与Server交互基本靠它们完成。

单独看上面的协议可能很难理解,这里我们以一次Binder请求过程来详细看一下Binder协议是如何通信的,就比较好理解了。 binder_request_sequence.png

这幅图的说明如下:

  • Binder是C/S架构的,通信过程牵涉到:Client,Server以及Binder驱动三个角色

  • Client对于Server的请求以及Server对于Client回复都需要通过Binder驱动来中转数据

  • BC_XXX命令是进程发送给驱动的命令

  • BR_XXX命令是驱动发送给进程的命令

  • 整个通信过程由Binder驱动控制

4 Binder Framework C++层

=====================================================================================

Binder Framework的C++部分:主要功能是实现向下与Binder驱动的对接交互,并封装复杂的内部实现,对外提供使用接口。头文件定义位于:/frameworks/native/include/binder/,实现位于这个路径:/frameworks/native/libs/binder/ 。Binder库最终会编译成一个动态链接库libbinder.so,供其他进程链接使用。为了便于说明,下文中我们将Binder Framework 的C++部分称为libbinder。

4.1 主要类结构


先用一张类图描述libbinder中的主要类结构之间的关系:

对照上面这张libbinder的设计类图,我们来理一下各个核心类的功能与职责:

  • 基类
  1. IBinder:Binder对象的基类,这个类描述了所有在Binder上传递的对象,它既是Binder服务端对象BBinder的父类,也是Binder客户端对象BpBinder的父类;主要定义的方法有:a.transact ———进行一次Binder操作;b.queryLocalInterface——尝试获取本地Binder对象;c.getInterfaceDescriptor ——获取Binder的服务接口唯一的描述;d.isBinderAlive——查询Binder服务是否还活着等;

  2. IInterfaceBinder服务接口的基类,Binder服务通常需要同时提供客户端接口和服务端接口。每个Binder服务都是为了某个功能而实现的,因此其本身会定义一套接口集来描述自己提供的所有功能。而Binder服务既有自身实现服务的类,也要有给客户端进程调用的类。为了便于开发,这两中类里面的服务接口应当是一致的。因此为了实现方便,本地实现类和远程接口类需要有一个公共的描述服务接口的基类(即上图中的IXXXService)来继承。而这个基类通常是IInterface的子类。

  • 客户端类
  1. BpBinder :BpBinder的实例代表了客户端Binder,这个类的对象将被客户端调用。这个类最重要就是提供了transact方法,这个方法会将客户端调用的参数封装好通过IPCThreadState逻辑封装后发送给Binder驱动。

  2. BpInterface:客户端接口的基类,远程接口是供客户端调用的接口集。BpInterface是个模板类,它们在继承自INTERFACE的基础上还继承了BpRefBase,通过这个类的remote方法可以获取到指向服务实现方的句柄。

  • 服务端类
  1. BBinder:BBinder的实例代表了服务端Binder,它描述了服务的提供方,所有Binder服务的实现者都要继承这个类(的子类),在继承类中,最重要的就是实现onTransact方法,因为这个方法是所有请求的入口。因此,这个方法是和BpBinder中的transact方法对应的,这个方法同样也有一个uint32_t code参数(统一在IBinder中定义),在这个方法的实现中,由服务提供者通过code对请求的接口进行区分,然后调用具体实现服务的方法。

  2. BnInterface:服务端接口的基类,是需要服务端服务中真正实现的接口集。BnInterface是个模板类,它们在继承自INTERFACE(Binder服务接口的基类,继承自IInterface)的基础上还继承了BBinder,由此可以通过复写onTransact方法来提供实现

  • 与驱动通信的类
  1. ProcessState : 代表使用Binder的进程。在讲解Binder驱动的时候我们就提到:任何使用Binder机制的进程都必须要对/dev/binder设备进行open以及mmap之后才能使用,这部分逻辑是所有使用Binder机制进程共同的。对于这种共同逻辑的封装便是Framework层的职责之一。libbinder中,ProcessState类封装了这个逻辑,从而负责进程Binder的初始化

  2. <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值