转帖:Lotus Notes安装和使用的常见问题
2011-04-03 14:17
344 查看
IPC框架分析 Binder,Service,Service manager
我首先从宏观的角度观察Binder,Service,ServiceManager,并阐述
各自的概念。从
Linux
的概念空间中,
Android
的设计每个
Activity
都是一个独立的进程,每个
Service
也都是一个独立的进程,
Activity,Service
之间要交换数据属于
IPC
。
Binder
就是为了
Activity通讯而设计的一个轻量级的
IPC
框架。
在代码分析中,我发现
Android
中只是把
Binder
理解成进程间通讯的实现,有点狭隘,而是应该站在公共对象请求代理这个高度来理解
Binder
,
Service
的概念,这样我们就会看到不一样的格局,从这个高度来理解设计意图,我们才会对
Android
中的一些天才想法感到惊奇。从
Android
的外特性概念空间中,我们看不到进程的概念,而是
Activity
,
Service
,
AIDL
,
INTENT
。一般的如果我作为设计者,在我们的根深蒂固的想法中,这些都是如下的
C/S
架构,客户端和服务端直接通过
Binder
交互数据,打开
Binder
写入数据,通过
Binder
读取数据,通讯就可以完成了。
该注意到
Android
的概念中,
Binder
是一个很低层的概念,上面一层根本都看不到
Binder
,而是
Activity
跟一个
Service
的对象直接通过方法调用,获取服务。
这个就是
Android
提供给我们的外特性:在
Android
中,要完成某个操作,所需要做的就是请求某个有能力的服务对象去完成动作,而无需知道这个通讯是怎样工作的,以及服务在哪里。所以
Andoid
的
IPC
在本质上属于对象请求代理架构,
Android
的设计者用
CORBA
的概念将自己包装了一下,实现了一个微型的轻量级
CORBA
架构,这就是
Andoid
的
IPC
设计的意图所在,它并不是仅仅解决通讯,而是给出了一个架构,一种设计理念,这就是
Android
的闪光的地方。
Android
的
Binder
更多考虑了数据交换的便捷,并且只是解决本机的进程间的通讯,所以不像
CORBA
那样复杂,所以叫做轻量级。
所以要理解
Android
的
IPC
架构,就需要了解
CORBA
的架构。而
CORBA
的架构在本质上可以使用下面图来表示:
在服务端,多了一个代理器,更为抽象一点我们可以下图来表示。
分析和
CORBA
的大体理论架构,我给出下面的
Android
的对象代理结构。
在结构图中,我们可以较为清楚的把握
Android
的IPC包含了如下的概念:
设备上下文什(
ContextObject
)
设备上下文包含关于客服端,环境或者请求中没有作为参数传递个操作的上下文信息,应用程序开发者用
ContextObject
接口上定义的操作来创建和操作上下文。
Android
代理:这个是指代理对象
BinderLinux
内核提供的
Binder
通讯机制
Android
的外特性空间是不需要知道服务在那里,只要通过代理对象完成请求,但是我们要探究
Android
是如何实现这个架构,首先要问的是在
Client
端要完成云服务端的通讯,首先应该知道服务在哪里?我们首先来看看
ServiceManger
管理了那些数据。
ServiceManager
提供了
addservice,checkservice
两个重要的方法,并且维护了一个服务列表记录登记的服务名称和句柄。
Servicemanager service
使用
0
来标识自己。并且在初始化的时候,通过
binder
设备使用
BINDER_SET_CONTEXT_MGRioctl
将自己变成了
CONTEXT_MGR。Svclist
中存储了服务的名字和
Handle
,这个
Handle
作为
Client
端发起请求时的目标地址。服务通过
add_service
方法将自己的名字和
Binder
标识
handle
登记在
svclist
中。而服务请求者,通过
check_service
方法,通过服务名字在
servicelist
中获取到
service
相关联的
Binder
的标识
handle,
通过这个
Handle
作为请求包的目标地址发起请求。
我们理解了Service Manager的工作就是登记功能,现在再回到IPC上,客服端如何建立连接的?我们首先回到通讯的本质:
IPC
。从一般的概念来讲,
Android
设计者在
Linux
内核中设计了一个叫做
Binder
的设备文件,专门用来进行
Android
的数据交换。所有从数据流来看
Java
对象从
Java
的
VM
空间进入到
C++
空间进行了一次转换,并利用
C++
空间的函数将转换过的对象通过
driver/binder
设备传递到服务进程,从而完成进程间的
IPC
。这个过程可以用下图来表示。
这里数据流有几层转换过程。
(1)从
JVM
空间传到
c++
空间,这个是靠
JNI
使用
ENV
来完成对象的映射过程。
(2)从
c++
空间传入内核
Binder
设备,使用
ProcessState
类完成工作。
(3)Service
从内核中
Binder
设备读取数据。
Android设计者需要利用面向对象的技术设计一个框架来屏蔽掉这个过程。要让上层概念空间中没有这些细节。Android设计者是怎样做的呢?我们通过
c++
空间代码分析,看到有如下空间概念包装
(ProcessState@(ProcessState.cpp)
在ProcessState类中包含了通讯细节,利用open_binder打开Linux设备dev/binder,通过ioctrl建立的基本的通讯
框架。利用上层传递下来的servicehandle来确定请求发送到那个Service。通过分析我终于明白了
Bnbinder
,
BpBinder
的命名含义,
Bn-
代表
Native
,而
Bp
代表
Proxy
。一旦理解到这个层次,ProcessState就容易弄明白了。
下面我们看
JVM
概念空间中对这些概念的包装。
为了通篇理解设备上下文,我们需要将
AndroidVM
概念空间中的设备上下文和
C++
空间总的设备上下文连接起来进行研究。
为了在上层使用统一的接口,在
JVM
层面有两个东西。在
Android
中,为了简化管理框架,引入了
ServiceManger
这个服务。所有的服务都是从
ServiceManager
开始的,只用通过
ServiceManager
获取到某个特定的服务标识构建代理
IBinder
。在
Android
的设计中利用
ServiceManager
是默认的
Handle
为
0
,只要设置请求包的目标句柄为
0
,就是发给
ServiceManager
这个
Service
的。在做服务请求时,
Android
建立一个新的
ServiceManagerProxy
。
ServiceManagerProxy
使用
ContexObject
作为
Binder
和
ServiceManagerService
(服务端)进行通讯。
我们看到
Android
代码一般的获取
Service
建立本地代理的用法如下:
IXXXmIxxx=IXXXInterface.Stub.asInterface(ServiceManager.getService("xxx"));
例如:使用输入法服务:
IInputMethodManagermImm=
IInputMethodManager.Stub.asInterface(ServiceManager.getService("input_method"));
这些服务代理获取过程分解如下:
(1)通过调用
GetContextObject
调用获取设备上下对象。注意在
AndroidJVM
概念空间的
ContextObject
只是
与
ServiceMangerService
通讯的代理
Binder
有对应关系。这个跟
c++
概念空间的
GetContextObject
意义是不一样的。
注意看看关键的代码
BinderInternal.getContextObject
()
@BinderInteral.java
NATIVEJNI:getContextObject() @android_util_Binder.cpp
Android_util_getConextObject@android_util_Binder.cpp
ProcessState::self()->getCotextObject(0)@processState.cpp
getStrongProxyForHandle(0)@
NEWBpBinder(0)
注意ProcessState::self()->getCotextObject(0)@processtate.cpp
,就是该函数在进程空间建立
了
ProcessState
对象,打开了
Binder
设备
dev/binder,
并且传递了参数
0
,这个
0
代表了与
ServiceManager
这个服务绑定。
(2)通过调用
ServiceManager.asInterface
(
ContextObject
)建立一个代理
ServiceManger
。
mRemote=ContextObject(Binder)
这样就建立起来
ServiceManagerProxy
通讯框架。
(3)
客户端通过调用
ServiceManager
的
getService
的方法建立一个相关的代理
Binder
。
ServiceMangerProxy.remote.transact(GET_SERVICE)
IBinder=ret.ReadStrongBinder()
-》这个就是JVM空间的代理Binder
JNINavite:android_os_Parcel_readStrongBinder()@android_util_binder.cpp
Parcel->readStrongBinder() @pacel.cpp
unflatten_binder @pacel.cpp
getStrongProxyForHandle(flat_handle)
NEWBpBinder(flat_handle)-》这个就是底层c++空间新建的代理Binder。
整个建立过程可以使用如下的示意图来表示:
Activity为了建立一个IPC,需要建立两个连接:访问Servicemanager Service的连接,IXXX具体XXX
Service的代理对象与XXXService的连接。这两个连接对应c++空间ProcessState中BpBinder。对IXXX的操作最后就
是对BpBinder的操作。由于我们在写一个Service时,在一个Package中写了Service Native部分和Service
Proxy部分,而Native和Proxy都实现相同的接口:IXXX
Interface,但是一个在服务端,一个在客服端。客户端调用的方式是使用remote->transact方法向Service发出请求,而
在服务端的OnTransact中则是处理这些请求。所以在Android
Client空间就看到这个效果:只需要调用代理对象方法就达到了对远程服务的调用目的,实际上这个调用路径好长好长。
我们其实还一部分没有研究,就是同一个进程之间的对象传递与远程传递是区别的。同一个进程间专递服务地和对象,就没有代理
BpBinder
产生,而只是对象的直接应用了。应用程序并不知道数据是在同一进程间传递还是不同进程间传递,这个只有内核中的
Binder
知道,所以内核
Binder
驱动可以将
Binder
对象数据类型从
BINDER_TYPE_BINDER
修改为
BINDER_TYPE_HANDLE
或者
BINDER_TYPE_WEAK_HANDLE作为
引用传递。
相关文章推荐
- Linux 使用rpm方式安装最新mysql(5.7.16)步骤以及常见问题解决
- Linux 使用rpm方式安装最新mysql(5.7.16)步骤以及常见问题解决
- Sniffer Portable 4.9安装/启动/使用等过程常见问题、故障诊断
- jdmail邮件系统安装和使用中的常见问题汇总
- iOSCocoaPods的安装使用和常见问题
- CloudStack 安装及使用过程中常见问题汇总
- Cocoapod安装使用和常见问题
- BugFree 安装和使用常见问题汇总
- 对于CocoaPods的简单理解,实践安装使用过程和常见问题
- 工作总结-CocoaPods的安装使用和常见问题
- Android Studio安装使用教程\环境搭建\常见问题汇总
- PCL使用常见问题 及安装pcl1.8.0 vs2013 及linux下
- CocoaPods的安装使用和常见问题
- aspjpeg组件安装、使用常见问题
- CocoaPods的安装使用和常见问题
- CocoaPods的安装使用和常见问题
- charles抓包的安装,使用说明以及常见问题解决(windows)
- Ubuntu 初步使用经验(虚拟机安装、命令行简单操作、常见问题)
- linux运维笔记----使用yum安装常见问题小结
- Win7系统64位环境下使用Apache——Apache2.2安装及常见问题解决