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相关推荐

  1. 【Android】Binder的理解

    1.Binder是什么? 对于android而言,是跨进程传输的通道,是封装好的java类,可以直接继承和使用. 从组成.模型来讲,我认为是连接Server层.Client层.ServerManage ...

  2. WSUS 重置引导指南(WSUS Reset Guide Line) WSUS针对性获取上级补丁数据

    WSUS 重置引导指南 && WSUS针对性获取上级补丁数据 WSUS Reset Guide Line for Production/Infrastructure Servers 更 ...

  3. Binder—获取服务

    Binder-获取服务 获取服务 一.BC_TRANSACTION binder_ioctl 二.BR_TRANSACTION 三.BC_REPLY 四.BR_REPLY 五.Client 收到服务句 ...

  4. Java 获取当前时间之后的第一个周几,java获取当前日期的下一个周几

    Java 获取当前时间之后的第一个周几,java获取当前日期的下一个周几 //获得入参的日期 Calendar cd = Calendar.getInstance(); cd.setTime(date ...

  5. 淘宝获取单笔订单信息服务端调用API及流程

    淘宝获取单笔交易接口(文档地址):https://open.taobao.com/api.htm?docId=54&docType=2 调用接口所需依赖(文档地址):https://devel ...

  6. 使用ajax不刷新页面获取、操作数据

    在使用jsp或html时,利用ajax达到不刷新页面就可以获取.操作数据. 首先上代码 (html+js) 在此处需要引入jquery插件 <!-- 这是页面部分 html--> < ...

  7. Go 学习笔记(79)— Go 标准库 net(获取本机IP地址)

    1. 获取本机 IP 地址 package mainimport ("fmt""net" )// 获取本机网卡IP func getLocalIP() (ipv ...

  8. Go 学习笔记(59)— Go 第三方库之 etcd/clientv3 封装为方法使用(建立连接、设置key-value、获取key-value、获取带前缀的key-value)

    1. 示例 1 package main import ("context""fmt""go.etcd.io/etcd/clientv3"& ...

  9. Redis 笔记(06)— set 类型(向集合添加元素、获取集合元素个数、判断集合中是否包含某个元素、删除给定元素、返回集合中所有元素、计算集合的交集、并集、差集)

    Redis 的 set 集合内部的键值对是无序的唯一的.它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL .当集合中最后一个元素移除之后,数据结构自动删除,内存被回收. ...

最新文章

  1. noip2016普及组 魔法阵vijos2012
  2. java-信息安全(十)-数字签名算法DSA
  3. 作业三--简单四则运算
  4. 宁夏计算机专科大学排名,2019年民办学校排行榜_科普2019年宁夏专科学校排名及2019宁夏民办高校排...
  5. css3实践之图片轮播(Transform,Transition和Animation)
  6. SP2010开发和VS2010专家食谱--第三章节--高级工作流(2)--为沙盒解决方案创建自定义活动...
  7. 675. Cut Off Trees for Golf Event
  8. 征稿 | ​第 9 届国际语义技术联合会议征稿(截稿日 9 月 8 号)
  9. 重命名myclipse中web项目名称的过程
  10. 四个DBHelper实现
  11. python爬取音乐_Python现学现用xpath爬取豆瓣音乐
  12. php josnp_浅析php中jsonp的跨域实例
  13. Bailian3255 十进制到六进制【进制】
  14. 用拉普拉斯变换求零状态响应_什么是UPS?为什么用UPS?关于UPS电源的知识都在这里!...
  15. 在线客服代码:在线QQ客服、在线旺旺客服
  16. PyQt:1个文件选择对话框实现既可以选择文件,也可以选择文件夹
  17. 苏州真不能成为一线城市?
  18. R语言 多元方差分析|单因素方差分析
  19. android root是什么意思啊,root是什么意思?安卓手机怎么root
  20. 如何选择适合你的兴趣爱好(二十二),羽毛球

热门文章

  1. 服务器硬件电路设计书籍,家庭网关硬件接口电路设计大全——电路精选(3)...
  2. java 滑动窗口_【Java】 剑指offer(59-1) 滑动窗口的最大值
  3. oracle 关联出现重复数据,ORACLE 分页查询出现重复记录的解决办法
  4. 14.QueuedConnection和BlockingQueuedConnection连接方式源码分析
  5. Marketing learning-2
  6. # 小猪的Python学习之旅 —— 17.Python数据分析:我主良缘交友了解下
  7. 浅谈Linux的内存管理机制
  8. Java 获取并计算程序执行时间
  9. Net设计模式实例之桥接模式( Bridge Pattern)(2)
  10. 如何使用Salt 的各种状态值