Jimmy Chen

A Programmer

(原创)Android中的Service和Binder关系

  因为C/C++层binder服务的使用过程和Java层的服务使用过程有所不同,所以这里分C/C++和Java两个层次看一下。

C/C++层

  经过前面的文章,对一些Binder会用到的类、组件有了认识,所以在这篇博客中要是有遇到前面已经讲过的类,大部分会跳过。如果要讲解Android中各个Service和Binder的关系,那么最好的办法还是找一个具体的Service进行讲解,所以这里还是找MediaServer进行讲解吧,毕竟部分已经有人讲解过,自己再重新分析一遍代码,应该能理解更多。

1. MediaServer的入口函数

  MediaServer作为一个C程序,其入口函数当然是main函数了。这里只选择部分需要讲解的代码,其余的大家可以自行查看源码

1.1 defaultServiceManager

可以看到,defaultServiceManager中会缓存缓存创建的IServiceManager对象,如果gDefaultServiceManager没有创建过,就会调用ProcessState的getContextObject方法创建BpBinder对象,然后通过interface_cast将创建的BpBinder对象包装成一个IServiceManager,先讲到这里,下面继续看这些过程的代码。

1.2 getContextObject

getContextObject在此调用getStrongProxyForHandle方法,然后调用到lookupHandleLocked,lookupHandleLocked对根据索引查找对应的资源,如果lookupHandleLocked没有发现有对应的资源项,就会新创建一个handle_entry对象,然后加入进去。接下来在defaultServiceManager中返回result,result就是新建的BpBinder(0)了。之前说过,BpBinder是客户端拿来和服务端BBinder通信用的,这里我们要和服务端ServiceManager进行通信,所以当然是需要获得ServiceManager的BpBinder对象了。

  回到defaultServiceManager中,下面的语句:

就可以简化成

接下来分析interface_cast为何物?

1.3 interface_cast

interface_case是一个函数模板,这里直接将IServiceManager代入到INTERFACE中,可以得到如下代码:

所以这里是调用IServiceManager的asInterface方法,传入的obj=new BpBinder(0);

1.4 asInterface

  这里要讲asInterface,其实这个知识点在之前的博客就有讲到,这个asInterface方法比较特殊,它是通过DECLARE_META_INTERFACE(INTERFACE)宏来定义这个方法, 然后在通过IMPLEMENT_META_INTERFACE(INTERFACE, NAME)这个宏实现这个方法的。asInterface的定义如下:

将IServiceManager代入,简化后的代码:

  所以这里最后返回intr=new BpServiceManager(Bpbinder(0))。

1.5 BpServiceManager

  这里的BpServiceManager是从BpInterface类模板中继承而来的,而BpInterface类又是从IServiceManager和BpRefBae这两个类中继承而来。

因为BpBinder(0)才是和ServiceManager通信的关键实例,所以需要看一下这个BpBinder保存在什么地方。

所以,这里可以看到,BpBinder(0)这个实例对象最后是保存到了BpRefBase的mRemote类变量中,这个变量会在之后与BBinder进行交互的过程中使用的。

2. MediaPleyerService注册

  在MediaServer中,MediaPlayerService是通过MediaPlayerService::instantiate进行注册的,下面看看instantiate函数。

一样,上面的代码首先通过defaultServiceManager获取一个IServiceManager对象,然后调用IServiceManager对象的addService函数,将MediaPlayerService对象注册进去。

2.1 addService

  addService的工作是将数据写到一个Parcel中。然后调用remote()函数返回一个BpBinder对象,调用BpBinder的transact函数与Binder进行交互。根据上一节的只是,这里的remote()返回的应该就是BpBinder(0)这个对象了,不信的大家可以跟踪一下代码。

  到了BpBinder还没有完,根据之前博客的知识BpBinder的transact函数其实也是没有和binder进行交互的,交互的工作最后会转交给IPCThreadState对象。最后IPCThreadState中的talkWithDriver函数会调用ioctl,传入BINDER_WRITE_READ命令,实现和Binder驱动的交互,下面我们直接Binder驱动的内容,中间的调用过程,大家可以查看博主的另外两篇博客。

3. Binder驱动部分

  上面讲到IPCThreadState的talkWithDriver会通过ioctl调用到binder_ioctl函数,传入的指令是BINDER_WRITE_READ,在之前的《Linux中的binder驱动》一文有分析到BINDER_WRITE_READ后面调用的函数是binder_ioctl_write_read

3.1 binder_thread_write

  这个函数很长,但是我们只需要看BC_TRANSACTION分支的代码。

3.2 binder_transaction

  这Binder驱动分析部分有点难看懂,目前也是没办法全部看懂,留待后续再继续深入。

(注:上面部分摘自:http://gityuan.com/2015/11/14/binder-add-service)

Java层

  Java层中的binder和native层的binder在命名上尽量保持了一致,且Java层的binder依托于Native层的binder,事实上Java层的binder最后还是会通过JNI调用到native层的binder API,所以要理解Java层的binder调用,需要先对native层的binder有个基本的认识。

1. Java层binder框架初始化

  既然Java层的Binder是通过JNI调用native层的binder,那么当然需要完成相应JNI方法的注册了。记得在Zygote启动一文中有提到如下的代码:

  这里的startReg(env)中就有注册Java层Binder需要的函数。startReg函数内会调用register_jni_process方法将gRegJNI数组中设计的函数都调用一遍。binder相关的注册函数是:

register_android_os_Binder函数在android_util_Binder.cpp文件内,执行的操作如下:

1.1 int_register_android_os_Binder

其中FindClassOrDie等方法都是对原来的JNI方法进行包装的,这里只看一下FindClassOrDie方法的实现

所以:

  • FindClassOrDie(env,kBinderPathName)等价于env->FindClass(kBinderPathName)
  • MakeGlobalRefOrDie等价于env->MakeGlobalRef()
  • GetMethodIDOrDie等价于env->GetMethodIDOrDie
  • GetFieldIDOrDie等价于env->GetFieldID()
  • RegisterMethodsOrDie这个特殊点,这个等价于Android::registerNativeMethods()

  上面将一些常用的Binder成员字段和方法缓存到gBinderOffsets变量中,在之后直接使用以提高效率,最后通过RegisterMathodsOrDie方法将Java层的binder和相应的native函数绑定

1.2 int_register_android_os_BinderInternal

  类似的,首先将BinderInternal类中一些常用字段和方法ID缓存到gBinderInternalOffsets中,然后调用RegisterMethodsOrDie方法将BinderInternal类中的方法和Native层的方法绑定。gBinderInternalMethods中包含的函数如下:

1.3 int_register_android_os_BinderProxy

  again,同样的方式缓存类中的字段和方法ID到gClassOffsets中,然后调用RegisterMethodsOrDie方法将BinderProxy类中的方法和Native层的方法绑定。其中gBinderProxyMethods包含的方法如下:

2.ServiceManager中的addService

2.1 getIServiceManager方法

单例模式,调用ServiceManagerNative.asInterface方法将BinderInternal.getContextObject返回的对象转换为所需的IServiceManager对象。下面看看BinderInternal中额getContextObject方法,从上一节中可以留意到,getContextObject是一个native方法,对应native层的android_os_BinderInternal_getContextObject方法。

2.2 getContextObject方法

对应于android_util_Binder.cpp中的android_os_BinderInternal_getContextObject方法。

  明显,这里调用ProcessState中的getContextObject方法,传进去的NULL即0,本篇前面C/C++层中讲到过这个方法,最后会返回一个BpBinder(0)对象,然后将BpBinder(0)作为参数传给javaObjecForIBinder,这个主要是将C/C++层的BpBinder对象转换为Java层的BinderProxy对象。

2.3 javaObjectForIBinder方法

所以所以这里是根据C/C++层的BpBinder对象,创建出Java层使用的BinderProxy对象,并且将BpBinder对象保存到BinderProxy.mObject成员变量中。所以

调用的返回值层次大概是这样的

3. ServiceManagerNative.asInterface

  根据上面的分析,传给asInterface的参数是一个BinderProxy对象。

上面的代码将基本的BinderProxy对象包装成一个ServiceManagerProxy对象。下面看看ServiceManagerProxy的构造函数。

3.1 ServiceManagerProxy构造函数

  ServiceManagerProxy的构造函数将传入的BinderProxy对象保存到mRemote成员变量中,按照前面的分析,这个BinderProxy实际就是BpBinder(0)。不过这里是Java层,当然不能直接使用了。接下来就看ServiceManagerProxy的addservice函数了。

4 ServiceManagerProxy.addService

  上面的调用和C/C++层有点类似啊,将数据写入到Parcel中。

4.1 writeStrongBinder

  搞事情,Java层总是什么都不做,然后就调用到Native去了。对应的代码在android_os_Parcel.cpp文件中,在上面有注册JNI函数时和Java层函数名字的对应关系,这里找到nativeWriteStrongBinder对应的JNI函数时android_os_Parcel_writeSringBinder

4.2 ibinderForJavaObject

4.3 JavaBBInderHolder.get()

  JavaBBinderHolder中有一个成员变量mBInder,保存创建的JavaBBinder对象。

4.4 JavaBBinder构造函数

  JavaBBinder类是继承了BBinder类的。

  所以parcel->writeStrongBinder(ibinderForJavaObject(env, object)),最后会转变成parcel->writeStrongBinder(new JavaBBinder(env, obj))。下面接着分析C/C++层中Parcel的writeStringBinder方法

4.5 writeStrongBinder

  将Binder对象扁平化,这里按照Binder对象是远程对象还是本地对象进行区分,如果是本地binder对象,这将Binder对象的实体指针记录在cookie中,否则就记录在handle中。

4.6 BinderProxy.transact

接下来我们回到addservice中,分析其中的mRemote.transact函数。之前就有分析到,mRemote其实就是一个BinderProxy对象。

  上面的代码最后也是调用到BpBinder的transact函数,之后的流程就和C/C++的流程一样了,大家可以按照C/C++层的流程接下去分析。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注