Binder机制4---Framework层

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层的关系,建立这个关系的函数是 android_util_Binder.cpp::register_android_os_Binder(),流程如下:

  1. 初始化Java Binder类和Native层的关系:调用 int_register_android_os_Binder(env)

  2. 找到Java层的Binder

  3. 通过gBinderOffsets对象保存和Binder类相关的某些在JNI层中使用的信息

  4. 注册Binder类中native函数的实现

  5. 初始化Java BinderInternal类和Native层的关系:调用 int_register_android_os_BinderInternal(env)

  6. 根据BinderInternal的全路径(com/android/internal/os/BinderInternal)找到代表该类的jclass对象

  7. 通过gBinderInternal静态对象,保存BinderInternal类的一些信息:如methodID和filedID

  8. 注册BinderInternal类中native函数的实现

  9. 初始化 Java BinderProxy类和Native层的关系:调用 int_register_android_os_BinderProxy(env)

  10. 通过gWeakReferenceOffsets来和WeakReference类交互,包括:获取WeakReference类get函数的methodID

  11. 通过gErrorOffsets来和Error类交互

  12. 通过gBinderProxyOffsets来和BinderProxy类交互,包括:获取BinderProxy的一些信息

  13. 通过gClassOffsets来和Class类交互

  14. 注册BinderProxy native函数的实现

  15. 初始化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对象。

上图中,我们可以看到获取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 b = ProcessState::self()->getContextObject(NULL);

  • ProcessState::self()->getContextObject(NULL)返回一个BpBinder对象,handle值为0,代码即可以写成:

  • sp b = new BpBinder(0);

  • return javaObjectForIBinder(env, b);   把这个BpBinder对象转换成一个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对象了

  • 在该函数中,有两个变量gBinderOffsets和gBinderProxyOffsets:

  • gBinderOffsets变量是用来记录”ppt 2.”左下角第二个类图中的Binder类的相关信息的,它是在注册Binder类的JNI方法的int_register_android_os_Binder函数初始化的
    gBinderProxyOffsets是用来变量是用来记录”ppt 2.”右上角第一个图中的BinderProxy类的相关信息的,它是在注册BinderProxy类的JNI方法的 int_register_android_os_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()

这个函数的核心代码为:

android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
           if (((iin!=null)&&(iin instanceof android.os.IXXXService))) {  
                return ((android.os.IXXXService)iin);  
            }  
            return new android.os.IXXXService.Stub.Proxy(obj);  
        }

这里的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层的构架是为应用层提供统一的接口,把内部实现封装起来,隔开了底层实现和上层应用