深入 Android 系统 Binder-1- 导读与简介
第二个问题,我们自己写的服务什么时候启动的呢?
从常理来讲,我们的服务要在进程启动的时候就要开始监听外界的消息了,不然万一错过消息怎么办。
Binder也是这样做的:
对于
服务进程来说会在
进程启动时执行joinThreadPool这个函数会进入
while循环读取binder驱动的数据对于
客户进程来说在发送远程调用时,会执行
transact函数时这个函数在发送完调用数据给
binder驱动后,会继续读取,查看返回数据
servicemanager 怎么没占多少篇幅呢?
首先这不是一个问题,哈哈哈哈!
servicemanager是Android用来管理注册的Binder服务的,我们的getService大概率是找的它。(还没没看源码,不要轻信)servicemanager并没有按照 Android 定义的模板来,自己实现了一个简易版本的servicemanager在 Android 系统启动时就启动了,这部分在init.rc中配置没有
servicemanager不影响我们认识学习binder整体流程和结构有了
servicemanager,可以加深我们对binder的理解
binder导读部分对一些知识点的描述比较简单。细节还是看正文
书本中源码是
Android 5.0,但是binder这部分从9.0上看也没有太大变化,只是增加了一些log打印这代码强悍的生命力不正是我们追求的么,哈哈哈
本来还想在导读中说一下
一次拷贝的事情,算了,留在正文吧
binder的学习比时间晚了两周。。。。。
好在真滴可以学到不少东西,下面是正文,谨慎阅读
=======================================================================
Binder是 Android 特有的一种进程间通信方式。Android Binder的前身是OpenBinder,最早由Dianne Hackborn开发并用于PalmOS上,后来Dianne Hackborn加入了OpenBinder的基础上开发了Android Binder
Binder和传统的IPC机制相比,融合了远程过程调用(RPC)的概念,而且这种远程调用不是传统的面向过程的远程调用,而是一种面向对象的远程调用。
从 Unix 发展而来的IPC机制,只能提供比较原始的进程间通信手段,通信的双方必须处理线程同步、内存管理等复杂问题,不但工作量大,而且容易出错。
除了Socket、匿名管道以外,传统的IPC,例如命名管道、信号量、消息队列等已经从 Android 中去掉了。
和其他IPC相比,Socket是一种比较成熟的通信手段,同步控制也很容易实现。Socket用于网络通信非常合适,但是用于进程间通信,效率就不太高了。
Android 在架构上一直希望模糊进程的概念,取而代之以
组件的概念。应用不需要关系组件的存放位置、运行在哪个进程、生命周期等问题。随时随地,只要拥有Binder对象,就能使用组件功能。Binder就像一张网,将整个系统的组件,跨越进程和线程,组织在了一起。
Binder很强大也很复杂。但我们在使用时却是一件很轻松的事情,不需要考虑线程同步、内存分配等问题。这些复杂的事情都在Binder框架中完成了。
正因为如此,Android 系统的服务都是利用Binder构建的。Android 系统服务有几十种之多,这是任何一个其它嵌入式平台所不具备的。
Android 在进程间传递数据使用的是共享内存的方式,这样数据只需要复制一次就能从一个进程到达另一个进程(一般的 IPC 都需要两步,从用户进程复制到内核,再从内核复制到服务进程),大大提高了数据传输效率。
在安全性方面 Android 也做了考虑,Binder调用时会传递进程的euid到服务端,因此,服务端可以通过检查调用进程的权限来决定是否允许其使用所调用的服务。
大家可以阅读下知乎大神的 为什么 Android 要采用 Binder 作为 IPC 机制? 来加深下了解,文章有惊喜
为了理解方便,把Binder相关的对象进行如下定义:
Binder实体对象:Binder实体对象就是Binder服务的提供者。一个提供Binder服务的类必须继承BBinder类。因此,有时为了强调对象的类型,也用BBinder对象来代替Binder 实体对象。Binder引用对象:Binder引用对象是Binder实体对象在客户进程的代表,每个引用对象的类型都是BpBinder类。同样可以用名称BpBinder对象来代替Binder引用对象。Binder代理对象:Binder代理对象也称为Binder接口对象,它主要为客户端的上层应用提供接口服务,从IInterface类派生,它实现了Binder服务的函数接口,当然只是一个转调的空壳。通过Binder代理对象应用能像使用本地对象一样使用远端的Binder实体对象提供的服务。IBinder对象:BBinder和BpBinder类都是从IBinder对象继承而来的。在很多场合,不需要刻意地去区分Binder实体对象和Binder引用对象,这是刻意使用IBinder对象来统一称呼它们。
Binder接口对象主要和应用程序打交道,将Binder接口对象和Binder引用对象分开的好处就是Binder接口对象可以有很多实例,但是它们包含的是同一个Binder引用对象这样方便了用户层的使用。
关系图如下:
应用完全可以抛开Binder接口对象直接使用Binder引用对象,但是这样开发的程序兼容性不好。也正是因为在客户端将Binder引用对象和Binder接口对象分离,Android 才能用一套架构来同时为Java层和Native层提供Binder服务。隔离后Binder底层不需要关心上层的实现细节,只需要和Binder实体对象和Binder引用对象进行交互。
Binder通信的参与者由 4 部分组成:
Binder驱动:Binder的核心,实现各种Binder的底层操作。ServiceManager:提供Binder 实体对象的名称到Binder 引用对象的转换服务服务端:Binder服务的提供者客户端:Binder服务的使用者
关系图如下:
Binder 驱动的简单解释:
Binder 驱动属于Binder架构的核心,通过文件系统内的标准接口,如open、ioctl、mmap等,向用户层提供服务。应用层和
Binder 驱动之间的数据通过ioctl接口来完成,并没有使用read和write系统调用。使用ioctl的好处就是一次系统调用就可以完成用户系统和驱动之间的双向数据交换,不但简化了控制逻辑,也提高了传输效率。Binder 驱动的主要功能就是提供Binder通信的通道,维护Binder对象的引用计数,转换传输中的Binder实体对象和Binder引用对象以及管理数据缓存区。
ServiceManager的简单解释:
ServiceManager是一个守护进程,它的作用是提供Binder服务的查询功能,返回被查询服务的引用。对于一个
Binder服务,通常会有一个唯一的字符串标识,只要它向ServiceManager注册了这个标识,应用就可以通过标识来获得Binder服务的引用对象。ServiceManager是一个独立的进程,对于其他想要获得Binder服务的进程来说,首要任务是获得ServiceManager。ServiceManager也是通过 Binder 框架来提供服务的,感觉遇到了鸡生蛋蛋生鸡的情况为了保证其他进程能获得
ServiceManager,Android 默认注册绑定了ServiceManager:Binder引用对象的核心数据是一个Binder实体对象的引用号,它是在驱动内部分配的一个值。Binder框架硬性规定了0代表ServiceManager。这样用户进程使用参数0可以直接构造出ServiceManager的Binder引用对象。为什么查找
Binder服务功能不直接放到Binder驱动中完成呢?是 Android 的安全管理要求,不容许任意进程都能注册
Binder服务,虽然任意进程都能创建Binder服务,但只有root进程或system进程才可以不受限制地向ServiceManager注册服务。ServiceManager中有一张表,里面规定了能够注册服务的进程的用户 ID,以及能够注册的服务名称。
Binder服务可以分成两种:实名服务和匿名服务。除实名服务能够通过ServiceManager查询到外,它们从开发到使用没有任何其他区别。
对于普通应用开发的Binder服务,都是匿名服务。对于匿名服务无法通过ServiceManager获取,那么客户端通过什么方式才能获得Binder引用对象呢?
首先,
匿名Binder服务的传输必须基于已经建立好的 Binder 通信连接,也就是基于实名注册的BinderServer将匿名Binder对象写入Parcel,接着通过ioctl和binder驱动通信,bidner驱动会对传入的对象进行检查。如果发现传入的
type是binder,则会在当前进程(Server对应的proc)查找是否有这个节点如果没有,就用传入的
匿名Binder对象在用户空间的指针和cookie(通常是BBinder本身)构造一个新的节点,接着得到匿名Binder对象的引用,存放在transaction_data中等待Client去获取。Client得到这个匿名Binder的引用,通过这个引用向位于Server中的实体发送请求。
匿名 Binder 这部分暂时收集到的资料就是这些,等学习完后面的再来补充吧
Android 组件
Service包含了一种启动 Java 匿名 Binder 服务的方法,我们来简单看下
首先,需要应用调用
bindService方法发出一个IntentFramework根据Intent找到对应的组件Service并启动它,此时组件Service中匿名Binder服务也将同时创建出来。随后,
Framework会把服务的IBinder对象通过ConnectivityManager的回调方法onServiceConnected()传回到应用这样应用就得到了
匿名Binder服务的引用对象
在这里 Android 的Framework用Intent代替了Binder服务的名称来查找对应的服务,同时也承担了ServiceManager的工作,解析Intent并传回服务的引用对象。如图:
Android 的Framework并没有使用新的技术来传递Binder对象,因为Framework中担任这个角色的ActivityManagerService本身就是一个Binder服务,最终还是通过Binder框架在服务端和客户端之间传递了IBinder对象。
从代码实现上划分,Binde 设计的类可以分为 4 个层次,如图:
最上层是位于
Framework中的各种 Binder 服务类和他们的接口类。这一层的类非常多,例如:ActivityManagerService、WindowManagerService、PackageManagerService等,它们为应用程序提供了各种各样的服务。第二层是用于给最上层的
服务类和接口类的开发提供基础,如 IBinder、BBinder、BpBinder 等。第三层是和
Binder驱动交互的IPCThreadState和ProcessState类最底层是
Binder驱动。











评论