AndroidBinder进程间通信系统
Posted fesng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AndroidBinder进程间通信系统相关的知识,希望对你有一定的参考价值。
目录
前言及知识准备
Service组件结构
Clinet组件结构
与Binder驱动程序交互
总结
Binder进程间通信实例
问题
本次
主要介绍android平台下Binder进程间通信库。所谓通信库,就是Adroid在应用程序框架层中将各种Binder驱动操作封装成一个Binder库,应用程序可以方便地调用库中提供的接口进行通信。这次将介绍Binder库的结构以及相关知识。 ##
在Binder库中,service组件用模板类BnInterface来描述,称之为一个Binder本地对象,对应在Binder驱动程序中的Binder实体对象;
client组件使用模板类BpInterface来描述,称之为一个Binder代理对象,对应在Binder驱动程序中的Binder引用对象
在使用Binder通信库进行开发service组件和client组件时,首先是要定义一个service组件接口,然后必须实现一个Binder本地对象类和Binder代理对象类,他们分别继承自模板类BnInterface和BpInterface。
例如首先定义服务接口IKeyService,然后定义一个Binder本地对象类BnKeyService和一个Binder代理对象类BpKeyService。分别继承各自的模板类。
模板类BnInterface源码定义如下
参数INTERFACE是一个由进程自定义的组件接口。
模板类继承了Bbinder类,它为本地对象提供了抽象的进程间通信接口。如下
BBinder 定义如下
上图只列出了两个重要的成员函数:
transact:当client使用的Binder代理对象通过Binder驱动向service使用的Binder本地对象发出通信请求时,Binder驱动程序会调用此函数。
onTransact:用来处理业务的分发以及进程间的通信请求。这种处理并不在这里实现,而是在其子类Binder本地对象类的子类,service组件类中实现的。
Binder本地对象类重写了父类BBinder中的onTransact函数,并且将这种操作分发到自己的子类,service组件类来处理。
可以注意到,BBinder类继承自IBinder类,IBinder类继承自RefBase类
继承了RefBase类的子类都可以使用强指针和弱指针来时维持生命周期,就是说,Binder本地对象通过引用计数来维护生命周期。
Binder机制所使用的引用机制比较复杂,功能就是当有进程使用此对象时,便会增加相应的引用计数,当使用完毕,便会减少相应的计数,当计数减少至0,则对该对象进行释放和销毁。用来防止忘记销毁,或是提早销毁而导致的程序崩溃。
至此,service组件的结构分析告一段落,接下来看client组件。
Client组件使用的BpInterface定义如下:
使用比较简单,继承了BpRefBase类,此类为Binder代理对象提供了抽象的进程间通信接口。源码如下:
BpRefBase定义如下
此类继承了RefBase类,同理,Binder代理对象也可以通过引用计数维护生命周期。
BpRefBase类中有一个重要的成员变量mRemote,它指向了一个BpBinder对象,可通过成员函数remote来获取。
BpBinder实现了BpRefBase类中的进程间通信接口
定义如右图
成员变量mHandle是一个整数,也是用来表示client组件的句柄值,通过成员函数handle获取。
每一个client组件在Biinder驱动程序中都有一个对应的Binder引用对象,而每一个Binder引用对象都有一个句柄值。Client组件就是通过句柄值mHandle,与Binder驱动中的Binder引用对象建立对应关系的。
至此,client组件结构也介绍完毕。
但是无论是service组件还是client组件,前面的定义都是在各自的组件内定义,通信时还是需要与Binder驱动交互的,在代码内部就表示为BBinder类或者是BpBinder类,通过与IPCThreadState类进行交互来完成的。
IPCThreadState类定义如下:
IPCThreadState定义如下
其中比较重要的函数self,功能介绍如下:
每个使用Binder进程间通信机制的进程都有一个Binder线程池,用来处理通信请求。池中的每一个Binder线程都存在一个IPCThreadState对象。函数self就是用来获取IPCThreadState对象的。
成员函数transact用于和Binder驱动交互,在函数内部,使用talkwithdriver函数完成交互操作。一方面向Binder驱动发送通信请求,一方面接受来自Binder驱动的通信请求
IPCThreadState类中一个重要的成员变量mProcess,指向一个ProcessState对象,负责初始化Binder设备,即打开设备文件,并且将这个设备映射到进程的地址空间。
ProcessState对象
定义如右图
成员函数self用来获取进程中的ProcessState对象,
打开Binder设备之后用成员变量mDriverFD保存其描述符。
完成设备文件的映射,
即分配完内存缓冲区
后,地址保存在变量
nVMStart内。
Service组件原理图如下,以keyService为例
client组件原理图如下,以KeyService为例
上图中:
IKeyService为Service组件和client组件都要实现的接口;
BnKeyService为Service组件要继承的Binder本地对象类;
BpKeyService为client组件要继承的Binder本地代理类。
KeyService为一个Service组件。
Binder通信库中的service组件和client组件虽然结构都很复杂,但是其主要目标就是按照各自的功能,完成对于一个共同的服务接口的不同实现。Service组件通过服务接口来提供服务,client组件通过服务接口对于服务进行访问。
在组件中,各自完成了与Binder驱动程序的交互。
此次使用基于应用程序框架层提供的Binder库开发一个Binder进程应用实例。包含一个Server进程和Client进程。
Server进程实现了一个service组件,功能是对一个虚拟硬件设备freg的寄存器val进行管理,并且向Client进程提供访问服务。
为了简化操作,将虚拟硬件设备的寄存器简化为一个整数型变量。
1. Android源代码的编译命令有哪些?mmm指令作用是什么?
答:编译命令有:
①m:编译所有的模块
②mm:编译当前目录下的模块,当前目录下要有Android.mk文件
②mmm:编译指定路径下的模块,指定路径下下要有Android.mk文件
1. adb logcat FregTest:i *:s是什么意思?logcat命令如何使用?
答:①:这是一条过滤指令。表示只显示标签为FregTest的日志,且日志的优先级要为info(信息)以上。
②adb logcat 命令格式 :
adb logcat [选项] [过滤项]
选项记录如下:
-- "-s"选项 : 设置输出日志的标签, 只显示该标签的日志;
--"-f"选项 : 将日志输出到文件, 默认输出到标准输出流中, -f 参数执行不成功;
--"-r"选项 : 按照每千字节输出日志, 需要 -f 参数, 不过这个命令没有执行成功;
--"-n"选项 : 设置日志输出的最大数目, 需要 -r 参数, 这个执行 感觉 跟 adb logcat 效果一样;
--"-v"选项 : 设置日志的输出格式, 注意只能设置一项;
--"-c"选项 : 清空所有的日志缓存信息;
--"-d"选项 : 将缓存的日志输出到屏幕上, 并且不会阻塞;
--"-t"选项 : 输出最近的几行日志, 输出完退出, 不阻塞;
--"-g"选项 : 查看日志缓冲区信息;
--"-b"选项 : 加载一个日志缓冲区, 默认是 main, 下面详解;
--"-B"选项 : 以二进制形式输出日志;
过滤项为
-- V : Verbose (明细);
-- D : Debug (调试);
-- I : Info (信息);
-- W : Warn (警告);
-- E : Error (错误);
-- F: Fatal (严重错误);
-- S : Silent(Super all output) (最高的优先级, 可能不会记载东西);
3.Android源代码根本目录下/external目录用处?
答:/external目录主要存放的是一些开源的模组,包括蓝牙、AES加密、google应用库、防火墙等等,只要是由其他开发者完成的模块,都存放在这个目录下。
4. 为什么编译之后的文件存放在目录
答:Android在编译完成之后在根目录下生成一个out目录。
/out/target表示在目标机(ARM)上运行的内容。
../Product含义是此时编译的是针对产品的内容
../Generic目录是表示选定的产品还可生成其他目录,
../system目录是存放主要的文件系统的
../bin用来存放文件系统的二进制文件
以上是关于AndroidBinder进程间通信系统的主要内容,如果未能解决你的问题,请参考以下文章