Binder机制4---Framework层

来源:互联网 发布:璟璞网络瑾萱 编辑:程序博客网 时间:2024/05/17 02:27
[java] view plaincopy
  1. 5. Binder机制的Java接口  

通常,应用程序框架中基于Java语言的Binder接口是通过JNI来调用基于C/C++语言的Binder运行库来为Java应用程序提供进程间通信服务的。在应用程序中,Server被实现为Service的形式,并通过IServiceManager.addService接口来把这个Service添加到Service Manager中;Client也是通过IServiceManager.getService接口来获得Service接口,这样就可以使用这个Service提供的功能了。

这里,我们以XXXService代表XXX的Service服务为例,把整个交互的过程分为如下几个部分来分析:

  1. 初始化Framework层Binder框架
  2. C/S获得ServiceManager的Java远程接口过程
  3. XXXService的接口定义和启动过程,添加自己到SM中
  4. Client获得XXXService的Java远程接口过程
  5. Client通过Java远端接口使用XXXService提供的服务

5.1 Binder在framework层的初始化

在java层工作前,需建立与Native层的关系,建立这个关系的函数是 register_android_os_Binder(),位于frameworks\base\core\jni\目录的android_util_Binder.cpp文件内

初始化流程如下:

  1. 初始化Java  Binder类和Native层的关系:调用 int_register_android_os_Binder(env)
    1. 找到Java层的Binder
    2. 通过gBinderOffsets对象保存和Binder类相关的某些在JNI层中使用的信息
    3. 注册Binder类中native函数的实现
  2. 初始化Java  BinderInternal类和Native层的关系:调用 int_register_android_os_BinderInternal(env)
    1. 根据BinderInternal的全路径(com/android/internal/os/BinderInternal)找到代表该类的jclass对象
    2. 通过gBinderInternal静态对象,保存BinderInternal类的一些信息:如methodID和filedID
    3. 注册BinderInternal类中native函数的实现
  3. 初始化 Java  BinderProxy类和Native层的关系:调用 int_register_android_os_BinderProxy(env)
    1. 通过gWeakReferenceOffsets来和WeakReference类交互,包括:获取WeakReference类get函数的methodID
    2. 通过gErrorOffsets来和Error类交互
    3. 通过gBinderProxyOffsets来和BinderProxy类交互,包括:获取BinderProxy的一些信息
    4. 通过gClassOffsets来和Class类交互
    5. 注册BinderProxy native函数的实现
  4. 初始化Java  Parcel类和Native层的关系:调用 int_register_android_os_Parcel(env)

作用:初始化其实就是提前获取一些JNI层的使用信息,这样可以节省每次使用时获取这些信息的时间

5.2 Binder framework层构架总览


这里解释一下Java  Binder, Java  Internal, Java  Proxy,以及IBinder的关系:

  1. 系统定义了一个IBinder接口类以及DeathRecipient接口。IBinder接口类中定义了FLAG_ONEWAY标志,作用是实现非阻塞,只把请求发送到Binder驱动即可返回,不用等待服务端的结果。
  2. Binder类和BinderProxy类分别实现了IBinder接口。Binder类作为服务端Bn的代表;BinderProxy类作为客户端Bp的代表
  3. BinderInternal类仅供Binder架构使用,其内部有一个GcWatcher类,专门用于处理和Binder架构相关的垃圾回收
  4. Java层同样提供一个用于承载通信数据的Parcel类

5.3 C/S获得ServiceManager的Java远程接口过程

我们要获取的ServiceManager的Java远程接口是一个ServiceManagerProxy对象的IServiceManager接口,如上图。IServiceManager接口提供了getService()和addService()两个函数来管理Service。从serviceManagerProxy的构造函数中发现,它需要一个BinderProxy对象的IBinder接口作为参数;所以得先获得BinderProxy对象。

        再来看一下是通过什么路径来获取Service Manager的Java远程接口ServiceManagerProxy的。这个主角就是ServiceManager了,我们也先看一下ServiceManager是长什么样子的:


上图中,我们可以看到获取SM的Java远程接口ServiceManagerProxy的路径,是通过ServiceManager.getIServiceManager()来获取,而该函数又是通过ServiceManagerNative来获取。

我们先来分析getIServiceManager()

5.3.1 ServiceManager.getIServiceManager()

这个函数定义在frameworks/base/core/java/android/os/ServiceManager.java文件中,里面的核心代码:

  • sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());  
  • return sServiceManager;

如果其静态成员变量sServiceManager尚未创建,首先要通过BinderInternal.getContextObject()来获得一个BinderProxy对象,再调用ServiceManagerNative.asInterface()来创建对应的ServiceManagerProxy对象
接下来通过BinderInternal.getContextObject() 和ServiceManagerNative.asInterface()两个部分来分析。

5.3.1.1 BinderInternal.getContextObject()

BinderInternal.getContextObject()这个函数定义在frameworks/base/core/java/com/android/internal/os/BinderInternal.java文件中,调用了JNI层的android_os_BinderInternal_getContextObject()。android_os_BinderInternal_getContextObject()是一个JNI方法,在frameworks/base/core/jni/android_util_Binder.cpp文件中,核心代码为:

  • sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    • ProcessState::self()->getContextObject(NULL)返回一个BpBinder对象,handle值为0,代码即可以写成:
    • sp<IBinder> b = new BpBinder(0);
  • return javaObjectForIBinder(env, b);   把这个BpBinder对象转换成一个BinderProxy对象
    • 在该函数中,有两个变量gBinderOffsets和gBinderProxyOffsets:
    • gBinderOffsets变量是用来记录”ppt 2.”左下角第二个类图中的Binder类的相关信息的,它是在注册Binder类的JNI方法的int_register_android_os_Binder函数初始化的
      gBinderProxyOffsets是用来变量是用来记录”ppt 2.”右上角第一个图中的BinderProxy类的相关信息的,它是在注册BinderProxy类的JNI方法的int_register_android_os_BinderProxy函数初始化的
      核心代码:
      • object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);  创建了一个BinderProxy对象
      • env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());  把BpBinder对象和BinderProxy对象关联起来;BinderProxy.mObject成员记录了这个BpBinder对象的地址
      • 最后,把BinderProxy返回到android_os_BinderInternal_getContextObject函数,再返回到ServiceManager.getIServiceManager()中,我们就获得一个BinderProxy对象了
    • 在getIServiceManager()中的:sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
      相当于:sServiceManager = ServiceManagerNative.asInterface(new BinderProxy());

5.3.1.2 ServiceManagerNative.java::asInterface()

接下来调用asInterface(),定义在frameworks/base/core/java/android/os/ServiceManagerNative.java 文件中:

  • asInterface(IBinder obj):obj是一个BpProxy对象或者BinderProxy对象(取决于这个申请SM的Java层远程接口的对象是Client还是Server),构造一个和业务相关的Proxy对象。这里我们假设申请者是client,构造了ServiceManagerProxy对象

这样,在getIServiceManager()中:sServiceManager = ServiceManagerNative.asInterface(new BinderProxy()); 相当于:sServiceManager =new ServiceManagerProxy(new BinderProxy()); 

5.3.2 获得SM的Java远端接口整体流程

这样,申请者在Java层拥有了一个Service Manager远程接口ServiceManagerProxy,这个ServiceManagerProxy对象在JNI层有一个handle值为0的BpBinder对象与之通过gBinderProxyOffsets关联起来,整体流程如下:


5.4 Service启动过程

XXXService继承了IXXXService.Stub类,并通过本地方法实现了Stub类的业务函数,有了XXXService之后,我们就会把它的Server类SystemServer启动起来。

定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中,SystemServer对象是在系统启动时创建的,创建后会启动一个线程来创建XXXService,并把它添加到SM中去
在serverThread extends Thread中:ServiceManager.addService("XXX", new XXXService());

下面我们会进行new XXXService() 和 ServiceManager.addService()两部分的分析

5.4.1 new XXXService()


New XXXService()会调用XXXService类的构造函数,而XXXService类继承于IXXXService.Stub类(XXXNative),Stub类又继承于Binder类,因此会调用Binder类的构造函数,在这个构造函数里,又会调用init()来初始化这个Binder对象

init()只做了一件事,就是创建一个JavaBBinderHolder对象,然后把这个对象的地址保存在Binder类的mObject成员变量中

那么结果为:获得了一个新的实例XXXService();  且Java层的Binder对象把Native层的JavaBBinderHolder(就是BBinder)保存在变量mObject中

5.4.2 ServiceManager.addService()的实现

分析完了new XXXService(),再来看下ServiceManager.addService()的实现,核心代码:

  • getIServiceManager().addService(name, service);

getIServiceManager()之前分析过,返回一个ServiceManagerProxy对象的IServiceManager接口,那么我们看ServiceManagerProxy.addService()的实现:

  1. 获得Parcel类型的data和reply
  2. data.writeStrongBinder(service)
  3.  调用mRemote.transact(ADD_SERVICE_TRANSACTION,data,reply,0);这里的mRemote就是BinderProxy对象,调用transact把封装好的请求数据发送出去

addService()最终会调用到Framework层的BinderProxy.transact();最后调用到Native层的BpBinder::transact()进入到Binder驱动,然后驱动唤醒SM响应这个ADD_SERVICE_TRANSACTION请求,把自己注册到SM中;

AMS在SM中注册服务流程图


XXXService注册服务的类图


5.5.1 Client获得XXXService的Java远程接口过程

Client是通过IServiceManager.getService()来获得XXXService的远程接口的;在client这边的onCreate()中调用IXXXService.Stub.asInterface(ServiceManager.getService(“XXX”)); 先看ServiceManager.getService(“XXX”)
ServiceManager.getService(“XXX”)。实际是调用了ServiceManagerProxy.getService(),这个函数通过mRemote.transact执行操作;和前面一样mRemote是一个BinderProxy对象。

然后调用IBinder binder = reply.readStrongBinder();作用是:调用JNI层的 android_os_Parcel_readStrongBinder(),其作用是把Java语言的Parcel对象转换成C++语言的Parcel对象parcel,并通过parcel->readStrongBinder函数来获得一个Binder引用的BpBinder对象

最后:

  • return javaObjectForIBinder(env, parcel->readStrongBinder());

javaObjectForIBinder()之前介绍过,会创建一个BinderProxy对象。相当于: return javaObjectForIBinder(env, new BpBinder(handle)); 返回给上层getService()的binder对象

那么     XXXService = IXXXService.Stub.asInterface(ServiceManager.getService("XXX")); 相当于:XXXService = IXXXService.Stub.asInterface(new BinderProxy())); 

5.5.2 IXXXService.Stub.asInterface()

这个函数的核心代码为:

[html] view plaincopy
  1. android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);    
  2.            if (((iin!=null)&&(iin instanceof android.os.IXXXService))) {    
  3.                 return ((android.os.IXXXService)iin);    
  4.             }    
  5.             return new android.os.IXXXService.Stub.Proxy(obj);    
  6.         }    

这里的obj是一个BinderProxy对象,它的queryLocalInterface返回null,于是调用下面语句获得XXXService的远程接口:    return new android.os.IXXXService.Stub.Proxy(obj); 

相当于:return new android.os.IXXXService.Stub.Proxy(new BinderProxy());

这样就获得了XXXService的远程接口了,实质上是实现了IXXXService接口的IXXXService.Stub.Proxy对象


获得XXXService的类图



client使用XXXService框架图



5.6 framework层总结

Native层和Java层的关键点:

  1. native层中,client会有一个BpBinder引用,Server会有一个BBinder引用来实现通信;
  2. Java层中,client会有一个BinderProxy对象,server会有一个JavaBBinder对象来负责通信,但实质的通信实现是基于native层,Native层又基于Binder驱动的

针对Java层C/S交互的5个步骤的总结:

  1. 初始化Java层Binder框架,是为了减少在以后通信过程中初始化的时间
  2. C/S获得ServiceManager的Java远程接口过程,实际上就是获得ServiceManagerProxy,为Java层提供C/S与SM通信的对象
  3.  XXXService的接口定义和启动过程,添加自己到SM中,实际上是为XXXService对象创建与SM通信的BinderProxy对象(就是步骤2),和创建为与client通信的JavaBBinder对象
  4. Client获得XXXService的Java远程接口过程,实际上是为client创建与SM通信的BinderProxy对象(就是步骤2),和创建与XXXService通信的BinderPorxy对象
  5. Client通过Java远端接口使用XXXService提供的服务,实际上是利用client的BinderProxy对象与XXXService的JavaBBinder对象通信,达到client使用服务的目的

虽然Binder机制的代码层层嵌套,逻辑复杂,但Binder机制的实质就是实现不同进程间的通信,通过SM来管理跨进程的服务;理解这一点,就可以理清Binder的核心:通信的实现最终都会由Binder的驱动实现,Native层和Java层的复杂构架,是出于2方面考虑:

  1. Native层的构架是为了提供统一的接口,并把业务层和逻辑层分开
  2. Java层的构架是为应用层提供统一的接口,把内部实现封装起来,隔开了底层实现和上层应用

原文:http://blog.csdn.net/bathinbreeze/article/details/8990719

0 0
原创粉丝点击