Android Binder 通信原理图文详解

目录
  • 前言
  • 1. Binder的作用
  • 2. 进程与Binder驱动如何通信
  • 3. ServiceManager进程的作用
    • Binder Client、Binder Server、ServiceManager关系
    • ServiceManager注册进Binder
  • 4. 进程添加服务到ServiceManager的流程
    • 其它进程找到SM
    • 添加服务到ServiceManager
    • BBinder作用
  • 5. 进程从ServiceManager获取服务的流程
    • 其它进程找到SM
    • 从ServiceManager获取服务
    • handle转换为Binder对象
  • 6. Binder服务端数据接收
  • 7. Binder 通信全流程图

前言

Binder机制可谓是Android 知识体系里的重中之重,作为偏底层的基础组件,平时我们很少关注它,而它却是无处不在,也是Android 面试易考察的点之一。网上很多文章,要么知识点比较陈旧,要么源码贴一堆,要么没有成体系地分析,导致读者一知半解,似是而非。
本篇将从流程上将Binder通信过一遍,尽量多用图展示。
通过本篇文章,你将了解到:

Binder的作用

进程与Binder驱动如何通信

ServiceManager进程的作用

进程添加服务到ServiceManager的流程

进程从ServiceManager获取服务的流程

Binder服务端数据接收

Binder 通信全流程图

1. Binder的作用

先看Linux下进程地址映射关系:

我们知道,对象调用本身就是地址空间的访问。

如上,进程之间各自访问各自的内存地址,它们之间无法直接访问对方的地址,也就是说微信不能直接调用支付宝提供的接口。而内核具有访问其它进程地址空间的权限,因此微信可以将消息发送给内核,让内核帮忙转发给支付宝,这种方式叫做:存储/转发方式。

由此衍生的几种IPC(进程间通信)如:管道、消息队列、socket等,而Android 上采用了新的机制:

Binder,相比传统的方式,Binder只需要一次数据拷贝,并且Binder更安全。

Binder机制是Android 里用来做IPC的主要方式。

2. 进程与Binder驱动如何通信

既然得要内核进行消息中转,那么Binder驱动得运行在内核空间,而事实上也确实如此,Binder驱动加载后在内核空间运行,进程只需要和Binder驱动取得联系,通过Binder驱动联系另一个进程,那么一次消息的传送过程就可以实现了。

内核提供提供一系列的系统调用接口给用户进程使用,当用户进程想要访问内核时,只需要调用对应的接口,此时代码就会从用户空间切换到内核空间执行。

常见的系统调用函数如:open/read/write/ioctl/close/mmap/fork 等。

与Binder驱动通信分两步:

打开Binder驱动:open("/dev/binder", O_RDWR | O_CLOEXEC)

通过ioctl 与Binder驱动进行数据通信:ioctl(mDriverFD, BINDER_WRITE_READ, &bwr)
bwr 为读写数据结构

3. ServiceManager进程的作用

Binder Client、Binder Server、ServiceManager关系

为方便起见,ServiceManager简称SM。

Binder 设计为C/S架构,C为Client(客户端),S为Server(服务端),Server端提供接口(服务)给Client端使用,而这个服务是以Binder引用的形式提供的。

由之前的知识可知,C和S是不同的进程,那么C如何拿到S的Binder引用呢?

你可能会说,当然是SM了,S先将Binder引用存放在SM里,当C需要的时候向SM查询即可。

这么看似乎讲得通了,那问题又来了,SM也是一个单独的进程,那S、C如何与SM进行通信呢?这就陷入了先有鸡还是先有蛋的死循环了。

实际上C、S、SM之间都是依靠Binder通信,只是SM作为特殊的Binder(handle=0)提前放入了Binder驱动里,当C、S想要获取SM的Binder引用,只需要获取handle=0的Binder即可。

这么说没有太直观的印象,我们一步步剖析。

ServiceManager注册进Binder

SM 注册进Binder驱动后就会等待来自Binder驱动的消息,这里列出了两个最常见的处理消息的Case:

其它进程添加服务到SM里

其它进程向SM查询服务

SM里维护着一个链表,链表的元素是结构体:

主要记录的是name和handle字段。
当SM收到添加服务的指令后,从Binder驱动里取出handle和name,并构造结构体插入到链表。
当SM收到查询服务的指令后,从Binder驱动里取出name,并找到链表里相同的name,找到后取出handle,最后写入到Binder驱动。

4. 进程添加服务到ServiceManager的流程

其它进程找到SM

现在SM已经翘首以盼其它进程的请求了,接着来看看如何添加一个服务到SM里。
以Java层添加服务为例,我们选择振动服务作为切入点分析。

在system_server 进程里构造振动服务(VibratorService继承自Binder),并添加到SM里。

可以看出,分两步:

先找到ServiceManager

往ServiceManager里添加服务

getIServiceManager()继续往下:

BinderInternal.getContextObject() 是native方法,后续流程较多,我们用图表示。

寻找ServiceManager的过程涉及到Java层和Native层,主要的重点在Native层查找 ServiceManager对应的BpBinder对象,没有找到的话则创建新的并存入缓存里以备下次直接获取。

ProcessState里维护了一个单例,每个进程只有一个ProcessState对象,创建ProcessState时候就会去打开Binder驱动,同时会设置Binder线程池里线程个数等其它参数

Native层构造BpBinder(handle=0表示该BpBinder是ServiceManager在客户端的引用),再构造BinderProxyNativeData持有BpBinder。

构造BinderProxy对象并持有BinderProxyNativeData,也就是间接持有BpBinder

最后构造了ServiceManagerProxy对象,它实现了IServiceManager接口,它的成员变量mRemote指向了BinderProxy

可以看出,获取ServiceManager的过程并不是真正去获取ServiceManager的Binder对象,而是获取它在当前进程的代理:BpBinder

添加服务到ServiceManager

既然找到了SM的Binder代理,接下来看看如何使用它给SM添加服务。

    #ServiceManagerNative.ServiceManagerProxy
    public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
            throws RemoteException {
        //构造Parcel
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        //写入Binder
        data.writeStrongBinder(service);
        data.writeInt(allowIsolated ? 1 : 0);
        data.writeInt(dumpPriority);
        //通过BinderProxy发送
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }

其中IPCThreadState与线程相关,不同的线程会维护一个单例。

由此可见,最终还是通过BpBinder发送消息,进而发送到Binder驱动。

此时驱动收到的信息包括不限于:

服务的名字

ServiceManager的handle

BBinder对象指针

驱动建立服务handle和BBinder对象指针的映射关系,并将服务的名字和服务的handle传递给ServiceManager(通过ServiceManager handle查找)。

ServiceManager拿到消息后建立映射关系,等待其它进程的请求。

至此,进程添加服务到ServiceManager过程已经分析完毕,用图表示如下:

BBinder作用

Java层传递的是Binder对象,如何与Native的BBinder关联起来呢?
重点在:

Parcel.writeStrongBinder(Binder)

也即是说Server端的Java Binder对象在Native层的代表是BBinder。
Binder驱动记录了BBinder的地址,当有消息过来时通过找到BBinder对象进而找到Java层的Binder对象,最终调用Binder.onTransact()。

5. 进程从ServiceManager获取服务的流程

其它进程找到SM

振动服务添加完成后,某些进程想要获取振动服务进行振动,比如微信收到消息后需要振动用以提示用户。
接着来看看如何获取振动服务。

    private void vibrate() {
        //获取振动服务
        Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
        //开始振动
        vibrator.vibrate(1000);
    }

与添加服务类似,想要获取服务先要找到SM,找SM的过程上边分析过了,此处不再细说。

从ServiceManager获取服务

    #ServiceManagerNative.ServiceManagerProxy
    public IBinder getService(String name) throws RemoteException {
        //构造Parcel
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        //写入名字
        data.writeString(name);
        //通过BinderProxy发送
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

由此可见,最终还是通过BpBinder发送消息,进而发送到Binder驱动。
此时驱动收到的信息包括不限于:

服务的名字

ServiceManager的handle

Binder驱动收到消息后,找到SM,并将服务的名字传给SM,SM从自己维护的链表里找到服务名相同的节点,最终取出该服务的handle,发送给Binder驱动。

用图表示如下:

对比添加服务流程和获取服务流程,两者前半部分都很相似,都是先拿到SM的BpBinder引用,然后写入驱动,最后由SM进程处理。只是对于获取服务流程来说,还需要将查询的结果(handle)写入驱动返回给调用方(对应图上红色部分)。

到这,大家可能会有疑惑了:"handle是整形值,而微信获取的振动服务是一个Binder对象,这两者是怎么结合起来的呢?"

handle转换为Binder对象

handle表示的即是Binder服务端在客户端的索引句柄,只要客户端拿到了handle,它就能通过Binder驱动调用到服务端。

        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();

再回过头看看获取服务的代码,当微信进程将查询命令发给Binder驱动后就等待驱动回复的结果,SM查询到结果后将handle写入驱动,而后微信进程从驱动将结果读出并将结果存入reply字段。
最后通过reply拿到Binder引用,也就是说重点在reply.readStrongBinder()方法。
直接看图:

如上,通过驱动返回的handle构造BpBinder,最终封装为Java层的BinderProxy。

至此,获取服务流程就结束了,用图展示简化的流程

6. Binder服务端数据接收

微信进程拿到振动服务(在system_server进程里)的Binder(BinderProxy)后,就可以调用振动方法了,而后指令发送给驱动,驱动通过振动服务的handle找到对应的服务BBinder指针,从而调用服务的接收方法。
微信进程发送指令给Binder驱动前面已经分析过,重点来看看system_server进程是如何接收并处理指令的。

system_server进程启动的时候就会开启Binder线程池,并等待驱动数据到来。
当system_server进程添加振动服务到SM时,会将Java层的Binder转为Native层的BBinder,并将BBinder对象指针写入Binder驱动。
当微信进程调用system_server接口时:

微信进程调用BpBinder.transact()将handle和数据写入Binder驱动

Binder驱动根据handle找到system_server进程

system_server进程从驱动拿到数据,并取出BBinder指针,最终调用到system_server进程Java层的Binder.onTransact()

如此一来,微信成功调用了振动服务,也就是说一次Client到Server端的通信就完成了。

7. Binder 通信全流程图

纵观Binder机制设计,最核心的点是handle。

通过handle构造Client端的BpBinder(Native层),与此对应的是Java层的BinderProxy

通过handle,驱动找到Server端进程,进而调用BBinder(Native层),与此对应的是Java层的Binder

通过handle的一系列中转,Client.transact()成功调用了Server.onTransact(),一次Binder通信就过程就完成了

最后,用一张图总结Binder机制的全过程:

以上就是整个Binder机制的梳理过程,此间省略了Binder驱动里的映射逻辑,可以将Binder驱动当做一个黑盒,而更重要的是Binder客户端和服务端是如何进行映射的。
Binder流程比较绕,尤其是IPCThreadStsate作为客户端的发送和服务端的数据接收的实体,需要区分不同的场景。
当然,jni基础知识必不可少。

本文基于Android 10

以上就是Android Binder 通信原理图文详解的详细内容,更多关于Android Binder 通信原理的资料请关注我们其它相关文章!

(0)

相关推荐

  • 浅谈Android IPC机制之Binder的工作机制

    进程和线程的关系 按照操作系统中的描述,线程是CPU调度的最小单位,同时线程也是一种有限的系统资源.而进程一般是指一个执行单元,在pc端或者移动端上是指一个程序或者一个应用.一个进程中可以包含一个或者是多个线程.所以他们的关系应该是包含和被包含的关系. 跨进程的种类 在Android中跨进程通信的方式有很多种,Bundle,文件共享,AIDL,Messenger,ContentProvider,Socket,这些都能实现进程间之间的通信,当然,虽然都能够实现进程间通信,但是他们之间的实现原理或者

  • Android Binder进程间通信工具AIDL使用示例深入分析

    目录 前言 AIDL AIDL示例 客户端 运行日志 AIDL通信过程分析 bindService流程分析 前言 众所周知,Android进程间通信采用的是Binder机制.Binder是Android系统 独有的进程间通信方式,它是采用mmp函数将进程的用户空间与内核空间的一块内存区域进行映射,免去了一次数据拷贝,相比Linux上的传统IPC具有高效.安全的优点.本文结合AIDL与bindService函数,在Android体系的应用层和Framework层,对Binder通信进行深入剖析,以

  • Android中Binder IPC机制介绍

    目录 前言 一.Binder是什么? 二.为什么要使用Binder 三.IPC机制原理 传统IPC机制如何实现跨进程通信 Binder IPC机制原理 小结 前言 记得刚开始做Andorid那会,面试时最怕被问到Binder,就感觉战战兢兢不知道从什么地方说起,导致后来一直有一种恐惧感.当然现在没有这种感觉了,但是这块知识点一直模模糊糊的,最近在学Andorid framework课程,借此机会简单总结下其中Binder相关知识点. 一.Binder是什么? Binder是Android中一种进

  • Android中关于Binder常见面试问题小结

    目录 1.简单介绍下binder 2.Binder的定向制导,如何找到目标Binder,唤起进程或者线程? 3.Binder中的红黑树,为什么会有两棵binder_ref红黑树 4.Binder一次拷贝原理 5.Binder传输数据的大小限制? 6.系统服务与bindService等启动的服务的区别 7.Binder多线程 8.Android APP进程天生支持Binder通信的原理是什么? 9.同一个线程的请求必定是顺序执行,即使是异步请求(oneway) 1.简单介绍下binder bind

  • Android 图文详解Binder进程通信底层原理

    之前了解到进程与多进程,涉及多进程不可避免的遇到了进程间通信,说到进程间通信,Binder 成了一道绕不过的坎.接下来咱们逐一了解.

  • Android中的binder机制详解

    前言 Binder做为Android中核心机制,对于理解Android系统是必不可少的,关于binder的文章也有很多,但是每次看总感觉看的不是很懂,到底什么才是binder机制?为什么要使用binder机制?binder机制又是怎样运行的呢?这些问题只是了解binder机制是不够的,需要从Android的整体系统出发来分析,在我找了很多资料后,真正的弄懂了binder机制,相信看完这篇文章大家也可以弄懂binder机制. 1.Binder是什么? 要理解binder,先要知道IPC,Inter

  • Android10 Binder原理概述深入解析

    目录 IPC工具介绍 Pipe Sign message queue shared memory Socket AIDL HIDL IPC工具介绍 Binder作为Android 众多的IPC通讯手段之一,在Framework的数据传输中起到极为关键的作用.为什么Google需要重新创造Binder这么一个IPC工具,使用linux默认提供的Pipe.Socket.共享内存.信号.消息队列等IPC工具不行吗? 答案是 这些传统的linux IPC工具有一部分android也在使用,只是在某些场合

  • Android Binder的原理与使用

    前言 Binder是安卓中实现IPC(进程间通信的)常用手段,四大组件之间的跨进程通信也是利用Binder实现的,Binder是学习四大组件工作原理的的一个重要基础. 好多文章都会深入C代码去介绍Binder的工作流程,没点水平真的难以理解,本文不会太深入底层去剖析原理,尽可能较为简单的让大家了解Binder是怎么工作的. Binder的使用 在介绍Binder原理之前,我们先来看看在安卓中怎么使用Binder来进程间通信. 在使用之前我们先来介绍Binder的几个方法: public fina

  • Android Binder 通信原理图文详解

    目录 前言 1. Binder的作用 2. 进程与Binder驱动如何通信 3. ServiceManager进程的作用 Binder Client.Binder Server.ServiceManager关系 ServiceManager注册进Binder 4. 进程添加服务到ServiceManager的流程 其它进程找到SM 添加服务到ServiceManager BBinder作用 5. 进程从ServiceManager获取服务的流程 其它进程找到SM 从ServiceManager获

  • vue内置组件transition简单原理图文详解(小结)

    基本概念 Vue 在插入.更新或者移除 DOM 时,提供多种不同方式的应用过渡效果 在 CSS 过渡和动画中自动应用 class 可以配合使用第三方 CSS 动画库,如 Animate.css 在过渡钩子函数中使用 JavaScript 直接操作 DOM 可以配合使用第三方 JavaScript 动画库,如 Velocity.js 简单用法 用 v-if/v-show 控制显示隐藏,使用transition 组件控制其变化过程 一个页面子组件 router-view 的消失隐藏,使用transi

  • Java LinkedList的实现原理图文详解

    一.概述 先来看看源码中的这一段注释,我们先尝试从中提取一些信息: Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations, and permits all elements (including null).All of the operations perform as could be expected for a doubly-l

  • 图文详解Android属性动画

    Android中的动画分为视图动画(View Animation).属性动画(Property Animation)以及Drawable动画.从Android 3.0(API Level 11)开始,Android开始支持属性动画,本文主要讲解如何使用属性动画.关于视图动画可以参见博文<Android四大视图动画图文详解>. 一.概述 视图动画局限比较大,如下所述: 1.视图动画只能使用在View上面. 2.视图动画并没有真正改变View相应的属性值,这导致了UI效果与实际View状态存在差异

  • Android Studio 中运行 groovy 程序的方法图文详解

    Groovy简介 Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python.Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码.由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库. Groovy 是 用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言.使用该种语言不必编写过多的代码,同时又具有闭包和动态语

  • Android线程间通信 Handler使用详解

    目录 前言 01.定义 02.使用 第一步.创建 第二步.发送消息 第一种是 post(Runnable) 第二种是 sendMessage(Message) 第三步.处理消息 03.结语 前言 Handler,可谓是面试题中的一个霸主了.在我<面试回忆录>中,几乎没有哪家公司,在面试的时候是不问这个问题的.简单一点,问问使用流程,内存泄漏等问题.复杂一点,纠其源码细节和底层 epoll 机制来盘你.所以其重要性,不言而喻了吧. 那么今天让我们来揭开 Handler 的神秘面纱.为了读者轻松易

  • Android USB转串口通信开发实例详解

     Android USB转串口通信开发实例详解 好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设进行通信,一直忙到最近,才慢慢闲下来,趁着这个周末不忙,记录下usb转串口通信开发的基本流程. 我们开发使用的是usb主机模式,即:安卓平板作为主机,usb外设作为从机进行数据通信.整个开发流程可以总结为以下几点: 1.发现设备 UsbManager usbManager = (UsbManager) context.getSystem

  • 初学者Android studio安装图文详解

    学习过java基础,最近趁着大量课余时间想学习Android开发.百度很多资料Android studio,由Google开发的开发工具,那就不需要再多说.对于初学者的我来说,一定足够用了.此文主要介绍自己下载.安装.第一次使用遇到的问题. 开发环境 物理机:Windows8.1专业版 Android Studio 2.3.3.0 下载来源:Android Studio中文社区http://www.android-studio.org/(建议安装带有Android sdk的安装包) 下载好后按照

  • 两分钟让你彻底明白Android Activity生命周期的详解(图文介绍)

    大家好,今天给大家详解一下Android中Activity的生命周期,我在前面也曾经讲过这方面的内容,但是像网上大多数文章一样,基本都是翻译Android API,过于笼统,相信大家看了,会有一点点的帮助 ,但是还不能完全吃透,所以我今天特意在重新总结一下.首先看一下Android api中所提供的Activity生命周期图(不明白的,可以看完整篇文章,在回头看一下这个图,你会明白的): Activity其实是继承了ApplicationContext这个类,我们可以重写以下方法,如下代码: 复

随机推荐