获取ServerManager
ServiceManager的远程接口(代理对象)的呢?此时ServiceManager必然是作为Server的,其与普通的Server进程是不一样的;对于普通的Server来说,Client如果想要获得Server的远程接口,必须通过ServiceManager远程接口提供的getService接口来获得,这本身就是一个Binder机制进行进程间通信的过程;然而对于ServiceManager这个Server来说,Client如果想得到ServiceManager远程接口,不必通过进程间通信机制来获得,因为ServiceManager远程接口是一个binder引用,它的句柄一定是0;
一、ServiceManager远程接口关系图
1)ServiceManager远程接口对象类型为BpServiceManager,它用来描述一个实现IServiceManager接口的Client组件。
2)IServiceManager接口定义4个成员函数getService,checkService,addService和listService;其中,getService和checkService是用来获取Service组件的代理对象的。addService用来注册Service组件的;listService用来获取注册在ServiceManager中的Service组件的列表。
3)**对一般的Service组件来说,Client进程首先要通过Binder驱动程序来获取它的一个句柄值,然后通过这个句柄创建一个Binder代理对象,最后将这个Binder代理对象封装成一个实现特定接口的代理对象。**由于ServiceManager的句柄值为0,因此获取它的代理对象不需要跟Binder驱动程序进程交互。
4)通过函数defaultServiceManager来获得一个ServiceManager代理对象。
二、defaultServiceManager
函数实现位于frameworks/base/libs/binder/IServiceManager.cpp文件中:
sp<IServiceManager> defaultServiceManager(){ //又是一个单例模式,Singleton if (gDefaultServiceManager != NULL) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); if (gDefaultServiceManager == NULL) { //真正的gDefaultServiceManager在这里创建 gDefaultServiceManager = <span style="color:#ff0000;">interface_cast</span><IServiceManager>( <span style="color:#ff0000;">ProcessState::self()</span>-><span style="color:#ff0000;">getContextObject(NULL))</span>; //从这里可以看到调用的ProcessState的getContextObject来创建,然后interface_cast<IServiceManager>利用BpBinder对象作为参数新建一个BpServiceManager对象 } } return gDefaultServiceManager;}
1)全局变量gDefaultServiceManager是一个类型为IServiceManager的强指针,指向进程内的一个BpServiceManager对象,即ServiceManager远程接口。
2)全局变量gDefaultServiceManagerLock是一个互斥锁,保证一个进程中至多只有一个ServiceManager代理对象。
3)重点:三次函数调用: 1)调用ProcessState类的静态成员函数self获取进程内一个ProcessState对象;2)调用ProcessState对象的成员函数getContextObject创建一个Binder代理对象;3)调用模板函数interface_cast将Binder代理对象封装成ServiceManager代理对象。
2.1 ProcessState::self成员函数
位于frameworks/base/libs/binder/ProcessState.cpp文件中:
sp<ProcessState> ProcessState::self(){ //gProcess是在Static.app中定义的全局变量 //程序开始的时候。gProcess肯定为NULL if (gProcess != NULL) return gProcess; AutoMutex _l(gProcessMutex); //创建一个ProcessState对象,并赋给gProcess if (gProcess == NULL) gProcess = new ProcessState; return gProcess;}
1)全局变量gProcess是一个类型为ProcessState的强指针,执行进程内一个ProcessState对象;
2)gProcessMutex是一个互斥锁,用来保证进程内最多只有一个ProcessState对象。
3)重点:通过ProcessState构造函数—> 创建ProcessState对象
ProcessState::ProcessState() : mDriverFD(open_driver()) //open_driver打开Binder设备 , mVMStart(MAP_FAILED) //内存映射的起始地址 , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1){ if (mDriverFD >= 0) {#if !defined(HAVE_WIN32_IPC) // mmap the binder, providing a chunk of virtual address space to receive transactions. mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { // *sigh* LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); close(mDriverFD); mDriverFD = -1; }#else mDriverFD = -1;#endif } if (mDriverFD < 0) { // Need to run without the driver, starting our own thread pool. }}
在ProcessState构造函数中:
1)首先调用open_driver打开设备/dev/binder,并且将得到的文件描述符保证在成员变量mDriverFD中。
2)调用mmap函数把设备文件/dev/binder映射到进程的地址空间,映射的地址空间大小为 BINDER_VM_SIZE:请求Binder驱动程序为进程分配内核缓冲区。
2.2 调用getContextObject创建一个Binder代理对象
位于frameworks/base/libs/binder/ProcessState.cpp文件中:
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller){ /* caller的值为0,而且该函数返回的是一个IBinder。 supportsProcesses()是查看设备是否支持打开设备来判断它是否支持process **/ if (supportsProcesses()) { //真实的设备肯定支持,所以会调用下面的函数来得到IBinder return getStrongProxyForHandle(0); } else { return getContextObject(String16("default"), caller); }}
1)先通过supportsProcesses来检查系统是否支持Binder进程间通信机制;
2)然后调用getStrongProxyForHandler来创建一个Binder代理对象
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle){ sp<IBinder> result; AutoMutex _l(mLock); /* 根据索引查找对应的资源,如果lookupHandleLocked没有发现对应的资源,则会创建一个新的项并返回 */ handle_entry* e = lookupHandleLocked(handle); if (e != NULL) { // We need to create a new BpBinder if there isn't currently one, OR we // are unable to acquire a weak reference on this current one. See comment // in getWeakProxyForHandle() for more info about this. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { //对于新创建的资源项,它的binder为空,此时handle值为0. <span style="color:#ff0000;">b = new BpBinder(handle); //创建一个BpBinder</span> e->binder = b; //填充entry的内容 if (b) e->refs = b->getWeakRefs(); result = b; } else { // This little bit of nastyness is to allow us to add a primary // reference to the remote proxy when this team doesn't have one // but another team is sending the handle to us. result.force_set(b); e->refs->decWeak(this); } } return result; //返回BpBinder(handler),handle值为0
2.3 调用模板函数interface_cast将Binder代理对象封装为ServiceManager代理对象
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){ return INTERFACE::asInterface(obj);}
这只是一个模板方法,所以defaultServiceManager中的interface_cast可等价于:
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj){ return IServiceManager::asInterface(obj);}
三、Server和Client进程拿到ServiceManager远程接口后,如何使用?
1) 对于Server进程,调用IServiceManager::addService这个接口来和Binder驱动进行交互,即BpServiceManager::addService。然后BpServiceManager::addService通过调用其基类BpRefBase的成员函数remote获取原先创建的BpBinder实例;接着调用BpBinder::transact成员函数。在transact函数中,又会调用IPCThreadState::transact成员函数与Binder驱动程序进行交互。原因是IPCThreadState的成员变量mProcess是ProcessState类型,其可以打开Binder设备。
2)对于Client进程,调用IServiceManager::getService接口来和Binder驱动进行交互。后续步骤跟Server进程一样。
获取ServerManager相关推荐
- 【Android】Binder的理解
1.Binder是什么? 对于android而言,是跨进程传输的通道,是封装好的java类,可以直接继承和使用. 从组成.模型来讲,我认为是连接Server层.Client层.ServerManage ...
- WSUS 重置引导指南(WSUS Reset Guide Line) WSUS针对性获取上级补丁数据
WSUS 重置引导指南 && WSUS针对性获取上级补丁数据 WSUS Reset Guide Line for Production/Infrastructure Servers 更 ...
- Binder—获取服务
Binder-获取服务 获取服务 一.BC_TRANSACTION binder_ioctl 二.BR_TRANSACTION 三.BC_REPLY 四.BR_REPLY 五.Client 收到服务句 ...
- Java 获取当前时间之后的第一个周几,java获取当前日期的下一个周几
Java 获取当前时间之后的第一个周几,java获取当前日期的下一个周几 //获得入参的日期 Calendar cd = Calendar.getInstance(); cd.setTime(date ...
- 淘宝获取单笔订单信息服务端调用API及流程
淘宝获取单笔交易接口(文档地址):https://open.taobao.com/api.htm?docId=54&docType=2 调用接口所需依赖(文档地址):https://devel ...
- 使用ajax不刷新页面获取、操作数据
在使用jsp或html时,利用ajax达到不刷新页面就可以获取.操作数据. 首先上代码 (html+js) 在此处需要引入jquery插件 <!-- 这是页面部分 html--> < ...
- Go 学习笔记(79)— Go 标准库 net(获取本机IP地址)
1. 获取本机 IP 地址 package mainimport ("fmt""net" )// 获取本机网卡IP func getLocalIP() (ipv ...
- Go 学习笔记(59)— Go 第三方库之 etcd/clientv3 封装为方法使用(建立连接、设置key-value、获取key-value、获取带前缀的key-value)
1. 示例 1 package main import ("context""fmt""go.etcd.io/etcd/clientv3"& ...
- Redis 笔记(06)— set 类型(向集合添加元素、获取集合元素个数、判断集合中是否包含某个元素、删除给定元素、返回集合中所有元素、计算集合的交集、并集、差集)
Redis 的 set 集合内部的键值对是无序的唯一的.它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL .当集合中最后一个元素移除之后,数据结构自动删除,内存被回收. ...
最新文章
- noip2016普及组 魔法阵vijos2012
- java-信息安全(十)-数字签名算法DSA
- 作业三--简单四则运算
- 宁夏计算机专科大学排名,2019年民办学校排行榜_科普2019年宁夏专科学校排名及2019宁夏民办高校排...
- css3实践之图片轮播(Transform,Transition和Animation)
- SP2010开发和VS2010专家食谱--第三章节--高级工作流(2)--为沙盒解决方案创建自定义活动...
- 675. Cut Off Trees for Golf Event
- 征稿 | ​第 9 届国际语义技术联合会议征稿(截稿日 9 月 8 号)
- 重命名myclipse中web项目名称的过程
- 四个DBHelper实现
- python爬取音乐_Python现学现用xpath爬取豆瓣音乐
- php josnp_浅析php中jsonp的跨域实例
- Bailian3255 十进制到六进制【进制】
- 用拉普拉斯变换求零状态响应_什么是UPS?为什么用UPS?关于UPS电源的知识都在这里!...
- 在线客服代码:在线QQ客服、在线旺旺客服
- PyQt:1个文件选择对话框实现既可以选择文件,也可以选择文件夹
- 苏州真不能成为一线城市?
- R语言 多元方差分析|单因素方差分析
- android root是什么意思啊,root是什么意思?安卓手机怎么root
- 如何选择适合你的兴趣爱好(二十二),羽毛球
热门文章
- 服务器硬件电路设计书籍,家庭网关硬件接口电路设计大全——电路精选(3)...
- java 滑动窗口_【Java】 剑指offer(59-1) 滑动窗口的最大值
- oracle 关联出现重复数据,ORACLE 分页查询出现重复记录的解决办法
- 14.QueuedConnection和BlockingQueuedConnection连接方式源码分析
- Marketing learning-2
- # 小猪的Python学习之旅 —— 17.Python数据分析:我主良缘交友了解下
- 浅谈Linux的内存管理机制
- Java 获取并计算程序执行时间
- Net设计模式实例之桥接模式( Bridge Pattern)(2)
- 如何使用Salt 的各种状态值