zoukankan      html  css  js  c++  java
  • Binder机制1---Binder原理介绍

    1.Binder通信机制介绍

    这篇文章会先对照Binder机制与Linux的通信机制的区别,了解为什么Android会另起炉灶,採用Binder。接着,会依据Binder的机制,去理解什么是Service Manager,在C/S模型中扮演什么角色。最后,会从一次完整的通信活动中,去理解Binder通信的过程。

    1.1 Android与Linux通信机制的比較

    尽管Android继承使用Linux的内核,但Linux与Android的通信机制不同。

    在Linux中使用的IPC通信机制例如以下:

    1. 传统IPC:无名pipe, signal, trace, 有名管道
    2. AT&T Unix 系统V:共享内存,信号灯,消息队列
    3. BSD Unix:Socket

    而在Android中,并没有使用这些,取而代之的是Binder机制。Binder机制是採用OpenBinder演化而来,在Android中使用它的原因例如以下:

    1. 採用C/S的通信模式。而在linux通信机制中,眼下仅仅有socket支持C/S的通信模式,但socket有其劣势,详细參看第二条。
    2. 有更好的传输性能。对照于Linux的通信机制,
      • socket:是一个通用接口,导致其传输效率低,开销大;
      • 管道和消息队列:由于採用存储转发方式,所以至少须要拷贝2次数据,效率低;
      • 共享内存:尽管在传输时没有拷贝数据,但其控制机制复杂(比方跨进程通信时,需获取对方进程的pid,得多种机制协同操作)。
    3. 安全性更高。Linux的IPC机制在本身的实现中,并没有安全措施,得依赖上层协议来进行安全控制。而Binder机制的UID/PID是由Binder机制本身在内核空间加入身份标识,安全性高;而且Binder能够建立私有通道,这是linux的通信机制所无法实现的(Linux訪问的接入点是开放的)。

    综上所述,Android採用Binder机制是有道理的。既然Binder机制这么多长处,那么我们接下来看看它是如何通过C/S模型来实现的。

    1.2 BinderService服务中的作用

    在android中,有非常多Service都是通过binder来通信的,比方MediaServer旗下包括了众多service:

    •     AudioFlinger 音频核心服务
    •     AudioPolicyService:音频策略相关的重要服务
    •     MediaPlayerService:多媒体系统中的重要服务
    •     CameraService:有关摄像/照相的重要服务

    Binder在C/S中的流程例如以下:


    1. Server注冊服务。Server作为众多Service的拥有者,当它想向Client提供服务时,得先去Service Manager(以后缩写成SM)那儿注冊自己的服务。Server能够向SM注冊一个或多个服务。
    2. Client申请服务。Client作为Service的使用者,当它想使用服务时,得向SM申请自己所须要的服务。Client能够申请一个或多个服务。
    3. 当Client申请服务成功后,Client就能够使用服务了。
    SM一方面管理Server所提供的服务,同一时候又响应Client的请求并为之分配对应的服务。扮演的角色相当于月老,两边牵线。这样的通信方式的优点是:一方面,service和Client请求便于管理,还有一方面在应用程序开发时,仅仅需为Client建立到Server的连接,就可花非常少时间和精力去实现Server对应功能。那么,Binder与这个通信模式有什么关系呢?!事实上,3者的通信方式就是Binder机制(比如:Server向SM注冊服务,使用Binder通信;Client申请请求,用的是Binder通讯)

    1.3 Binder通信机制流程(总体框架)


    上图即是Binder的通信模型。我们能够发现:

    1. Client和Server是存在于用户空间
    2. Client与Server通信的实现,是由Binder驱动在内核空间实现
    3. SM作为守护进程,处理client请求,管理全部服务项。

    为了方便理解,我们能够把SM理解成DNSserver; 那么Binder Driver 就相当于路由的功能。这里就涉及到Client和Server是怎样通信的问题。以下对1.2中提到的3个流程进行说明。

    1.3.1 Server向SM注冊服务


    1. 首先,XXXServer(XXX代表某个)在自己的进程中向Binder驱动申请创建一个XXXService的Binder的实体,
    2. Binder驱动为这个XXXService创建位于内核中的Binder实体节点以及Binder的引用,注意,是将名字和新建的引用打包传递给SM(实体没有传给SM),通知SM注冊一个名叫XXX的Service。
    3. SM收到数据包后,从中取出XXXService名字和引用,填入一张查找表中。
    4. 此时,假设有Client向SM发送申请服务XXXService的请求,那么SM就能够在查找表中找到该Service的Binder引用,并把Binder引用(XXXBpBinder)返回给Client。

    在进一步了解Binder通信机制之前,我们先弄清几个概念。

    1. 引用和实体。这里,对于一个用于通信的实体(能够理解成具有真实空间的Object),能够有多个该实体的引用(没有真实空间,能够理解成实体的一个链接,操作引用就会操作相应链接上的实体)。假设一个进程持有某个实体,其它进程也想操作该实体,最高效的做法是去获得该实体的引用,再去操作这个引用。
    2. 有些资料把实体称为本地对象,引用成为远程对象。能够这么理解:引用是从本地进程发送给其它进程来操作实体之用,所以有本地和远程对象之名。

    1.3.2 一个问题-怎样获得SM的远程接口

    假设你足够细心,会发现这里有一个问题:

    Sm和Server都是进程,Server向SM注冊Binder须要进程间通信,当前实现的是进程间通信却又用到进程间通信。这就好比鸡生蛋、蛋生鸡,但至少得先有当中之中的一个。

    巧妙的Binder解决思路:

    针对Binder的通信机制,Server端拥有的是Binder的实体;Client端拥有的是Binder的引用。
    假设把SM看作Server端,让它在Binder驱动一执行起来时就有自己的Binder实体(代码中设置ServiceManager的Binder其handle值恒为0)。这个Binder实体没有名字也不须要注冊,全部的client都觉得handle值为0的binder引用是用来与SM通信的(代码中是这么实现的),那么这个问题就攻克了。那么,Client和Server中这么达成协议了(handle值为0的引用是专门与SM通信之用的),还不行,还须要让SM有handle值为0的实体才算大功告成。怎么实现的呢?!当一个进程调用Binder驱动时,使用BINDER_SET_CONTEXT_MGR命令(在驱动的binder_ioctl中)将自己注冊成SM时,Binder驱动会自己主动为它创建Binder实体。这个Binder的引用对全部的Client都为0。


    1.3.3 Client从SM获得Service的远程接口


    Server向SM注冊了Binder实体及其名字后,Client就能够通过Service的名字在SM的查找表中获得该Binder的引用了(BpBinder)。Client也利用保留的handle值为0的引用向SM请求訪问某个Service:我申请訪问XXXService的引用。SM就会从请求数据包中获得XXXService的名字,在查找表中找到该名字相应的条目,取出Binder的引用打包回复给client。之后,Client就能够利用XXXService的引用使用XXXService的服务了。
    假设有很多其它的Client请求该Service,系统中就会有很多其它的Client获得这个引用。

    1.3.4 建立C/S通路后

    首先要理清一个概念:client拥有自己Binder的实体,以及Server的Binder的引用;Server拥有自己Binder的实体,以及Client的Binder的引用。我们也能够从接收方和发送方的方式来理解:

    • 从client向Server发数据:Client为发送方,拥有Binder的实体;Server为接收方,拥有Binder的引用
    • 从server向client发数据:Server为发送方,拥有Binder的实体;client为接收方,拥有Binder的引用。

    也就是说,我们在建立了C/S通路后,无需考虑谁是Client谁是Server,仅仅要理清谁是发送方谁是接收方,就能知道Binder的实体和引用在哪边。


    建立CS通路后的流程:(当接收方获得Binder的实体,发送方获得Binder的引用后)

    1. 发送方会通过Binder实体请求发送操作。
    2. Binder驱动会处理这个操作请求,把发送方的数据放入写缓存(binder_write_read.write_buffer) (对于接收方为读缓冲区),并把read_size(接收方读数据)置为数据大小(对于详细的实现后面会介绍);
    3. 接收方之前一直在堵塞状态中,当写缓存中有数据,则会读取数据,运行命令操作
    4. 接收方运行完后,会把返回结果相同用binder_transaction_data结构体封装,写入写缓冲区(对于发送方,为读缓冲区)

    1.3.5 匿名Binder

    之前在介绍Android使用Binder机制的长处中,提到Binder能够建立点对点的私有通道,匿名Binder就是这样的方式。在Binder通信中,并非全部用来通信的Binder实体都须要注冊给SM广而告之的,Server能够通过已建立的实体Binder连接将创建的Binder实体传给Client。而这个Binder没有向SM注冊名字。这样Server与Client的通信就有非常高的隐私性和安全性。

    这样,整个Binder的通信流程就介绍完成了,可是对于详细的代码实现(比方binder_transaction_data是什么?binder_write_read.write_buffer又是什么?详细的驱动和逻辑实现又是怎么样?),在后面章节中会一一介绍。

    几点疑问:
    1. 是谁,怎么样成为SM守护进程,handle为0的binder实体什么时候创建?
    2.  binder引用和实体是怎样创建的?在驱动中怎样实现的通信?
    3. 在SM中,binder实体是如何转换成为引用的?
    4. Server是怎样注冊服务,Client是怎样获取服务的?

    读完兴许文章就会知道答案了!

  • 相关阅读:
    Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.
    DHCP "No subnet declaration for xxx (no IPv4 addresses)" 报错
    Centos安装前端开发常用软件
    kubernetes学习笔记之十:RBAC(二)
    k8s学习笔记之StorageClass+NFS
    k8s学习笔记之ConfigMap和Secret
    k8s笔记之chartmuseum搭建
    K8S集群集成harbor(1.9.3)服务并配置HTTPS
    Docker镜像仓库Harbor1.7.0搭建及配置
    Nginx自建SSL证书部署HTTPS网站
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4331526.html
Copyright © 2011-2022 走看看