前言
Binder 做为 Android 中外围机制,对于了解 Android 零碎是必不可少的,对于 binder 的文章也有很多,然而每次看总感觉看的不是很懂,到底什么才是 binder 机制?为什么要应用 binder 机制?binder 机制又是怎么运行的呢?这些问题只是理解 binder 机制是不够的,须要从 Android 的整体零碎登程来剖析,在我找了很多材料后,真正的弄懂了 binder 机制,置信看完这篇文章大家也能够弄懂 binder 机制。
1、Binder 是什么?
要了解 binder,先要晓得 IPC,Inter-process communication , 也就是过程中互相通信,Binder 是 Android 提供的一套过程间互相通信框架。用来多过程间发送音讯,同步和共享内存。已有的过程间通信形式有一下几种:
1、Files 文件系统(包含内存映射)2、Sockets 3、Pipes 管道 4、共享内存 5、Intents, ContentProviders, Messenger 6、Binder
Android 零碎中的 Binder 框架图如下:
拿 Activity 举例从上图能够看进去:Activity 是由 ActivityManager 来管制的,而 ActivityManager 其实是通过 Binder 获取 ActivityManagerService 服务来管制 Activity 的,并且 ActivityManager 是 Android 零碎 FrameWork 层的,和利用中的 activity 不是同一个过程。
重点:
1、Binder 是 Android 提供的一套过程间通信框架。
2、零碎服务 ActivityManagerService,LocationManagerService,等都是在独自过程中的,应用 binder 和利用进行通信。
2、Android 零碎框架
如上图,Android 零碎分成三层。最上层是 application 应用层,第二层是 Framework 层,第三层是 native 层。由下图可知几点:
1、Android 中的应用层和零碎服务层不在同一个过程,零碎服务在独自的过程中。
2、Android 中不同利用属于不同的过程中。
Android 利用和零碎 services 运行在不同过程中是为了平安,稳固,以及内存治理的起因,然而利用和零碎服务须要通信和分享数据。
长处
安全性:每个过程都独自运行的,能够保障应用层对系统层的隔离。
稳定性:如果某个过程解体了不会导致其余过程解体。
内存调配:如果某个过程以及不须要了能够从内存中移除,并且回收相应的内存。
3、Binder 通信
client 申请 service 服务,比如说 Activity 申请 Activity ManagerService 服务,因为 Activity 和 ActivityManagerService 是在两个不同的过程中的,那么下图是一个很直观的申请过程。
然而留神,一个过程是不能间接间接操作另一个过程的,比如说读取另一个过程的数据,或者往另一个过程的内存空间写数据,过程之间的通信要通过内核过程才能够,因而这里就要应用到过程通信工具 Binder 了如下图:
Binder driver 通过 /dev/binder /dev/binder 提供了 open, release release, poll poll, mmap mmap, flush flush, and ioctl 等操作的接口 api。这样过程 A 和过程 B 就能够通过内核过程进行通信了。过程中大部分的通信都是通过 ioctl(binderFd, BINDER\_WRITE\_READ, &bwd)来进行的。bwd 的定义如下:
struct binder_write_read {
signed long write_size;/* bytes to write */
signed long write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
signed long read_size; /* bytes to read */
signed long read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
然而 下面还有个问题就是 client 和 service 要间接和 binder driver 打交道,然而实际上 client 和 service 并不想晓得 binder 相干协定,所以进一步 client 通过增加 proxy 代理,service 通过增加 stub 来进一步解决与 binder 的交互。
这样的益处是 client 和 service 都能够不必间接去和 binder 打交道。下面的图如同曾经很欠缺了,然而 Android 零碎更进一步封装,不让 client 晓得 Binder 的存在,Android 零碎提供了 Manager 来治理 client。如下图:
这样 client 只须要交给 manager 来治理就好了,基本就不必关怀过程通信相干的事,对于 manager 其实是很相熟的,比如说 activity 的就是由 ActivityManager 来管制的,ActivityManager 是通过 Binder 获取 ActivityManagerService 来管制 activity 的。这样就不必咱们本人来应用 Binder 来 ActivityManagerService 通信了。
更进一步,client 是如何具体获取到哪个 service 的呢?如下图所示:
在 service 和 binder 之间还有一个 contextManager,也就是 serviceManager,每一个 service 要先往 serviceManager 外面进行注册,注册实现之后由 serviceManager 对立治理。在 Android studio 中能够通过 adb 指定打印出以后曾经注册过 serviceManager 的 service。
$ adb shell service list
Found 71 services: 0 sip:
[android.net.sip.ISipService] 1 phone: [com.android.internal.telephony.ITelephony] … 20 location: [android.location.ILocationManager] …
55 activity: [android.app.IActivityManager]
56 package: [android.content.pm.IPackageManager] …
67 SurfaceFlinger: [android.ui.ISurfaceComposer]
68 media.camera: [android.hardware.ICameraService]
69 media.player: [android.media.IMediaPlayerService]
70 media.audio_flinger: [android.media.IAudioFlinger]
下图是一次更加残缺的 client 和 service 的通信流程:
4、Binder 框架
在看 Binder 框架之前,先来看一下,从 client 发出请求 service 的残缺的流程。
获取服务过程:
第一步 :client 要申请服务,比如说在 activity 中调用context.getSystemService()
办法,这个时候 serviceManager
就会应用 getService(name)
,而后就会调用到 native 层中的ServiceManagerNative
类中的 getService(name)
办法。
第二步 :ServiceManagerNative 会通过 Binder 发送一条 SVG\_MGR\_GET\_SERVICE 的指令,而后通过 svcmgr\_handler() 调用 do\_find\_service()办法去 svc\_list 中查找到相干的 service。
第三步:查找到相应的服务后就会通过 Binder 将服务传给 ServiceManagerNative,而后传给 serviceManager,最初 client 就能够应用了。
留神: 服务切实 svclist 中保留的,svclist 是一个链表,因而客户端调用的服务必须要先注册到 svclist 中。
注册服务过程:
第一步: service 通过调用 serviceManager 中的 addService 办法,而后调用 ServiceManagerNative
类中的 addservice(name)
办法。
第二步: ServiceManagerNative
会通过 Binder 发送一条 SVG\_MGR\_ADD\_SERVICE 的指令,而后通过 svcmgr\_handler()调用 do\_add\_service()办法往 svc\_list 中增加相应的 service。
重点:所有的服务都要先注册到 svc\_list 中能力被 client 调用到。svc\_list 以 linkedlist 的模式保留这些服务。
Binder 结构设计 要理解 binder 的结构设计,就要理解 Android 的体系结构,Android 是分成 application 层,framework 层 native 层,以及内核层,Binder 设计在每一层上都有不同的形象。如下图:
由上图可知 Binder 的整体设计总共有四层:
1、Java 层 AIDL。
2、Framework 层,Android.os.Binder。
framework 层中最重要的数据结构是 transaction,有一下几个默认的:
3、Native 层: libBinder.cpp
在 native 层次要是 libBinder
4、内核层 内核层的通信都是通过 ioctl 来进行的,client 关上一个 ioctl, 进入到轮询队列,始终阻塞直到工夫到或者有音讯。
5、Binder 中应用的设计模式
1、代理模式(Proxy Pattern) 在 Android 中 client 不是间接去和 binder 打交道,client 间接和 Manager 交互,而 manager 和 managerProxy 交互,也就是说 client 是通过 managerProxy 去和 binder 进行交互的。同时 service 也不是间接和 binder 交互,而是通过 stub 去和 binder 交互。如下图。
2、Bridge Pattern 如下图,应用层也就是 Java 层要应用 MediaPlayer, 就要调用 native 层中的 MediaPlayer.cpp,然而 MediaPlay.java 不是间接去跟 JNI 打交道,而是通过与 MediaPlayerSevice 通信,从而通过 Binder 返回的。
6、Binder 与内存映射 mmap
Binder IPC 是基于内存映射(mmap)来实现的,然而 mmap() 通常是用在有物理介质的文件系统上的。
比方过程中的用户区域是不能间接和物理设施打交道的,如果想要把磁盘上的数据读取到过程的用户区域,须要两次拷贝(磁盘 –> 内核空间 –> 用户空间);通常在这种场景下 mmap() 就能发挥作用,通过在物理介质和用户空间之间建设映射,缩小数据的拷贝次数,用内存读写取代 I / O 读写,进步文件读取效率。
而 Binder 并不存在物理介质,因而 Binder 驱动应用 mmap() 并不是为了在物理介质和用户空间之间建设映射,而是用来在内核空间创立数据接管的缓存空间。
一次残缺的 Binder IPC 通信过程通常是这样:
首先 Binder 驱动在内核空间创立一个数据接管缓存区;接着在内核空间开拓一块内核缓存区,建设内核缓存区和内核中数据接管缓存区之间的映射关系,以及内核中数据接管缓存区和接管过程用户空间地址的映射关系;发送方过程通过零碎调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,因为内核缓存区和接管过程的用户空间存在内存映射,因而也就相当于把数据发送到了接管过程的用户空间,这样便实现了一次过程间的通信。如下图:
相干视频举荐:
【安卓面试合集】Binder 过程间通信机制 -01
本文转自 https://juejin.cn/post/6844904115777044488,如有侵权,请分割删除。