1. Cilent从ServiceManger哪里获得BnMediaService的BnBinder引用就可以调用BnMediaPlayerService的方法了,BnMediaPlayerService是怎样响应客户端的请求的哪?

BnMediaService并不是直接接受Cilent发送过来的请求,而是使用IPCThreadState接受Cilent发送过来的请求,然后调用BBinder的transact函数,传入客户端发送过来的相关参数,由transact函数来调用BnMediaPlayerService类的onTransact函数来真正的处理Cilent请求的。也就是说Cilent的请求是经过了IPCThreadState的中转才调用BnMediaService的onTransact服务的。为什么要中转哪?因为这是跨进程的对象访问,并不是在进程内的直接访问,要让跨进程的对象访问像自己内部对象访问一样,必须经过底层驱动的一个转换过程,也就是说在IPCTheadState线程里完成了和底层Binder的通信。

3.通常客户端如何和服务器端通信的流程?

LayoutInflater layoutInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//1.通常情况下是客户端要和服务器端通信就是调用ServieManager远程接口提供的getService接口来实现的。这样就获得了服务器端的跨进程引用
View view =layoutInflater.inflate(R.layout.activity_second, null);
//2.客户端直接调用服务引用的方法
//3.服务器端的IPCTHreadState线程接受到客户端的请求后会调用BBinder的transat函数,传入客户端的请求,然后由transact函数自动调用服务器端的onTransact函数为什么这里调用IPCThreadState而不是直接在Service里调用,因为Service端是多线程的,也就是服务器端可以有几个至几十个客户端,而用线程正好可以给每个客户端请求开启一个IPCTheadState线程)
//4.服务器端在onTransate函数里执行对外开发的服务方法,返回执行结果。

4.通常的C/S的通信流程是从客户端有ServiceManger的远程接口开始的,正式因为客户端一开始就有ServiceManger的远程接口,所以才能调用getService 接口,才有后面的流程,那么客户端如何获得ServiceManger的远程接口的哪?

//1.客户端直接调用defaultServiceManager就可以获得ServiceManger的引用ServiceManager

5.ServiceManager有很多父类和实现了很多接口,最终ServiceManger有一个很重要的成员变量mRemote他的类型是IBinder*,实现类就是BpBinder。ServiceManger服务的对外监听客户端请求的线程IPCThreadState有一个成员变量mProcess,这个mProcess的类型就是ProcessState。一个进程里只有一个PoocessState,当客户端调用defaultServiceManger的时候就是在请求BpBinder。

/****过程如下:1.客户端(可能是MediaServiceManager也可能是一个自定义普通的Service,无论这个对象是Service Cilent 还是ServiceManger在这个时候相对于ServiceManger这个Linux init函数最先加载的进程都是客户端)调用defaultServiceManger,那么ServiceMnager就会启动一个IPCThreadState线程,然后会同过ProcessState打开/dev/binder设备2.返回一个句柄值为0的binder引用****/

6.Android和Binder驱动通信都是在ProcessState里完成的,因为只有ProcessState打开了/dev/binder文件,分析ProcessState的构造函数

ProcessState::ProcessState()    : mDriverFD(open_driver())//打开/dev/binder文件,并把设备文件描述符保存在mDriverFD成员变量中//打开文件设备的时候会使用BINDER_VERSION和BINDER_SET_MAX_THREADS命令和Binder驱动程序交互,前者用来获得驱动程序的版本号,后者告诉驱动Server端最多可以打开的线程的数量。和驱动交互本身就是和内核态的程序交互,发送命令获得返回值。
 , mVMStart(MAP_FAILED)    , mManagesContexts(false)    , mBinderContextCheckFunc(NULL)    , mBinderContextUserData(NULL)    , mThreadPoolStarted(false)    , mThreadPoolSeq(1){    if (mDriverFD >= 0) {        // XXX Ideally, there should be a specific define for whether we        // have mmap (or whether we could possibly have the kernel module        // availabla).#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.    }}

7.Sever创建一个Binder实体,为其取一个字符形式可读易记的名字,将这个Binder连同名字以数据包的形式通过Binder驱动发送给SMGr,通知SMgr注册一个叫张三的Binder,它位于某个Server中,驱动为这个穿过进程边界的Binder创建位于内核中的实体节点以及SMgr对实体的引用,将名字及新建的引用传递给Smgr。SMgr接收到数据包后,从中取出名字和引用填写到一张查找表中。Server创建一个BInder实体后,就会通过AddService向ServiceManger注册,注册的时候因为是在进程间的通讯,所以必然要通过内核,内核就根据BInder实体的Parcel信息在内核中创建了一个实体,和引用,发送给ServerManger,这样当客户端向服务器发送请求的时候直接把数据发送到内核,内核经过ServerManger的唯一确定后,直接在内核中完成对Service方法的调用,因为无论是IPCThreadState还是ProcessState都是C++实现的在内核中完成的功能。java端只是实现了Binder会拥有哪些功能,而这个用java写成的功能会是被C++的代码接收请求和管理的。

package com.example.servicedemo3;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;public class ServiceDemo extends Service {        @Override    public int onStartCommand(Intent intent, int flags, int startId) {        // TODO Auto-generated method stub        Log.d("Start COmmand","Startcommad 调用");        return super.onStartCommand(intent, flags, startId);    }        @Override    public IBinder onBind(Intent intent) {        // TODO Auto-generated method stub        return new MyBlinder();            }        class MyBlinder extends Binder{                public void checkWifi(){                        System.out.println("----------------------------");            System.out.println("------------CheckWIfi----------------");            Log.d("CHeckWIFT","Service------------------");                                }            }}

8.当一个进程使用BINDER_SET_CONTEXT_MGR命令将自己注册成Servermanger的时候,BInder驱动就会自动的在驱动中创建一个ServerManger的实体(而一般的服务是在addServer的时候才会在驱动中创建实体),也就是说系统启动后,那些角色为ServerManager的进程当调用BINDER_SET_CONTEXT_MGR命令后,驱动就自动在BInder驱动里创建BpBinder,系统有多少ServiceManger,驱动就一一对应有多少BpBInder。他们的关系是平等。而当有Service向某个ServerManger注册BInder的时候其实注册的就是BBinder。驱动在自己的内存空间里维护着BpBinder和BBinder的一对多关系,这样当客户端需要调用某个服务的时候就会先取得BpBInder,当调用getService的时候就是由驱动在自己的内存中从BpBinder这个节点开始搜索对象名字的BBinder,如果查到就直接执行BBinder里的方法。因为客户端事实上是只有BpBinder的引用,所以就是这个过程中,首先把客户端的数据拷贝到内核中,当查询到指定的BBinder后,就可以直接执行了,而不必拷贝到别的地方。BInder驱动内部的结构如图所示:

参考阅读:Android深入浅出之Binder机制

Android进程间通信(IPC)机制Binder简要介绍和学习计划

Android Binder设计与实现 – 设计篇

更多相关文章

  1. 如何在Android(安卓)NDK中调用第三方库文件(.so)
  2. android 简易通讯录查询
  3. 倒计时功能CountDownTimer PK Handler
  4. Android自动生成启动Activity的特定按钮
  5. 记录targetSdkVersion升级以后Android遇到的一些问题
  6. Android(安卓)继承ViewGroup必须重写onMeasure方法和onLayout方
  7. Android之启动应用源码分析
  8. Android之Service相关
  9. 关于overridePendingTransition效果在1.6版本中会出现VerifyErro

随机推荐

  1. 基于android的远程视频监控系统(已开放源
  2. Android拨号器的实现
  3. 谷歌宣布Android设备累计激活量突破10亿
  4. 如何搭建android的开发环境 虚拟机和ubun
  5. [置顶] 一步一步学android OpenGL ES2.0
  6. Android Market正式更名Google Play Stor
  7. Android通讯-Socket(TCP/IP)
  8. 曼妙琳珑心 Android 面试题(2)
  9. 【转】Android下实现wap和net自适应
  10. android 监听edittext addTextChangedLis