引言
Android服务框架由本地服务框架(Native Service Framework)和Java服务框架(Java Service Framework)两部分组成。前面我们通过Binder机制,详细地分析了本地服务框架的服务注册、获取及使用过程。这篇Blog中我们将分析Java服务框架的架构与实现过程。
Java服务框架是一系列类的集合,这些类用于支持开发Java系统服务,这些服务运行在基于Java的应用程序框架中。Java服务框架实际上是在本地服务框架的基础上实现的,它通过JNI来使用本地服务框架中的功能,示意图如下:
借助JNI,Java层的用户不仅可以使用由Java语言编写的服务,还可以使用由C++语言编写的本地服务。
1.Java服务框架的层次结构
跟本地服务框架类似,Java服务框架也是分为三层:服务层、RPC层、IPC层。层次结构示意图如下
服务层
与本地服务框架不同,Java服务框架中的服务层需要实现FooManager类,原因是SDK包中并不包含ServiceManager类(实际上源码中是存在这个类的,但是它被标记为@hide,所以不会被编译进SDK中),应用程序无法使用ServiceManager类来注册或检索系统服务。
因此,为了让应用程序开发者能够使用系统服务,系统服务开发者就需要将包装类包含到SDK中。例如,为了让应用程序开发者能够使用FooService,系统服务开发者就要编写FooManager包装类,添加使用ServiceManager获取FooService的功能,并将其编入SDK中。之后,应用程序开发者就可以通过包含在SDK中的FooManager类来使用FooService系统服务了。如下图所示:
RPC层
Java服务框架使用Android平台中的AIDL语言与编译器自动生成服务代理和服务Stub.在Android系统中进程之间不能共享内存,为了使其他应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用的方式来实现,并使用AIDL来公开服务的接口。
IPC层
为了支持Binder IPC,本地服务框架提供了BpBinder与BBinder两个类,Java服务框架则提供了BinderProxy与Binder两个类。
实际上,Java服务框架是通过JNI使用本地服务框架的Binder IPC,即BinderProxy与Binder通过JNI使用本地服务框架的BpBinder与BBinder类的功能。示意图如下:
由上图可知,用户调用服务时,首先是BinderProxy的transact()方法使用JNI本地函数调用BpBinder的transact()函数,而后通过Binder IPC调用BBinder的transact()函数。之后BBinder会调用transact()函数,从而引起JavaBBinder对象的回调:onTransact(),而在该方法中会通过JNI调用Binder中的execTransact()方法,在execTransact()中会调用Stub的服务方法,从而最终调用服务。
2.实现过程
完整的Java系统服务实现包含注册、获取、调用这3个阶段。下面就按这3个阶段对Java系统服务框架进行分析。为了便于说明,此处以AlarmManagerService为例进行讲解。
2.1 Java系统服务注册
在ServiceManager类中,注册服务的代码如下:
|
|
其中name为服务名称,而service则为服务对象,如AlarmManagerService对象,记住这个很重要,后面会用到的。
然后看getIServiceManager()方法:
|
|
首先分析BinderInternal.getContextObject()方法,其声明如下:
|
|
显然,这是一个native方法,它对应的本地函数是什么呢?在/frameworks/base/core/jni/android_util_Binder.cpp中有如下映射数组:
|
|
显然,该native方法对应的本地函数为android_os_BinderInternal_getContextObject(),该函数的定义如下:
|
|
ProcessState::self()->getContextObject()方法在分析本地服务注册的博客中讲解过,它会返回一个BpBinder对象,而且该BpBinder对象的handle值为0;
然后进入javaObjectForIBinder()方法:
|
|
首先,前面说过val其实是对应一个handle值为0的BpBinder对象,而BpBinder并没有重写IBinder的checkSubclass()方法,故返回false,从而此处不新建JavaBBinder对象;
又由于第一次请求时BpBinder的findObject()返回值为NULL,故此处会通过env->NewObject()方法新建BinderProxy对象,并且将BpBinder对象保存到BinderProxy对象中的mObject中,记住这个很重要,后面会再提到。
再回到BinderInternal中的native IBinder getContextObject()方法中,显然它返回的是一个BinderProxy(BinderProxy继承于IBinder)对象。
然后回到getIServiceManager()方法中,如下所示:
|
|
显然,此时ServiceManagerNative.asInterface(BinderInternal.getContextObject());等价于ServiceManagerNative.asInterface(new BinderProxy());下面进入ServiceManagerNative.asInterface()方法:
|
|
即将之前新建的BinderProxy对象保存在mRemote中,记住这个很重要,后面还会用到mRemote.
所以getIServiceManager().addService(name,service);其实调用ServiceManagerProxy中的addService()方法,代码如下:
|
|
- 该方法中首先是将RPC数据写入到data中,接口描述符和服务名称都很好理解,关键是data.writeStringBinder(service);注意service是AlarmManagerService对象。
Parcel类的writeStrongBinder()方法如下:
|
|
显然,它是一个native方法,类似地,在/frameworks/base/core/jni/android_util_Binder.cpp中可以找到它对应的本地函数是android_os_Parcel_writeStrongBinder(),其代码如下(注意传入的参数clazz是Java中的Parcel类对象,object则是AlarmManagerService对象):
|
|
其中parcelForJavaObject()的目的是将Parcel(Java类)中的mObject转化为Parcel(C++)指针。
在分析Parcel(C++)类的writeStrongBinder()方法之前,我们先分析ibinderForJavaObject()方法,注意此处传入的参数obj是AlarmManagerService对象:
|
|
由于AlarmManagerService继承于IAlarmManager.Stub,而IAlarmManager.Stub继承于Binder,而gBinderOffsets.mClass对应的正是Binder类,故env->IsInstanceOf(obj,gBinderOffsets.mClass)这个判断成立,从而会新建JavaBBinderHolder类,其构造函数如下:
|
|
显然,AlarmManagerService对象被赋值给了JavaBBinderHolder中的mObject成员;
之后返回jbh->get(evn),而JavaBBinder的get()方法如下:
|
|
显然这里采用了懒加载的方式,在第一次使用时新建了JavaBBinder对象,注意前面说到的mObject,它实际上对应AlarmManagerService对象。
而JavaBBinder的构造函数如下:
|
|
这里的binder其实是JavaBBinder对象,而JavaBBinder继承于BBinder,它重写了localBinder()方法,返回this,所以这里执行的是如下代码:
|
|
所以flat_binder_object对象obj的成员type为BINDER_TYPE_BINDER,成员binder则为JavaBBinder对象的弱引用,成员cookie则保存着JavaBBinder对象,特别注意cookie成员,后面还会提到。
之后Parcel方法的调用与单纯的本地系统服务一致,不再赘述。
===============================================================================================================================
再回到addService()方法中:
|
|
mRemote在之前已经说过,它是一个BinderProxy对象,所以mRemote.transact()实际上调用的是BinderProxy的transact()方法,代码如下:
|
|
显然,这是一个native方法,它对应的本地函数也可以在/frameworks/base/core/jni/android_util_Binder.cpp中找到,对应的函数是android_os_BinderProxy_transact(),如下所示,注意传入的参数obj为BinderProxy对象,code为ADD_SERVICE_TRANSACTION,dataObj为上面的Parcel对象data的本地引用(其中data中含有IServiceManager接口描述符,服务名称以及AlarmManagerService对象),replyObj则为Parcel对象的本地引用:
|
|
前面的代码都是将Java中的Parcel对象转化为C++中的Parcel对象,之后获取BinderProxy中的mObject成员,前面说过,mObject成员保存的是BpBinder对象,所以这里IBinder*target其实指向的是BpBinder对象。从而target->transact()其实调用的是BpBinder的transact()方法,该方法的代码如下:
|
|
然后进入IPCThreadState的transact()方法,其主要代码如下:
|
|
显然,这里主要就是将IPC数据写入binder_transaction_data对象中,并且将cmd(此处值为BC_TRANSACTION)写入到mOut中.
再回到IPCThreadState::transact()方法中,之后执行waitForResponse()方法中,其代码如下:
|
|
在博客本地服务的注册过程这篇博客中,我们提到了talkWithDriver()的作用,就是将保存在mOut中的Binder IPC数据传递给Binder Driver,并将来自Binder Driver的Binder IPC数据保存在mIn中,同时会新建binder_node.
在talkWithDriver()中新建完binder_node之后,Binder IPC协议就变成BR_REPLY,所以此时tr中包含的数据就是BR_REPLY和binder_transaction_data对象,之后通过调用ipcSetDataReference()方法将注册AlarmManagerService的结果存入到Parcel对象reply中,至此,添加服务的过程就完成了。
2.2 Java系统服务获取
当Context对象(如Activity)调用getSystemService(Context.ALARM_SERVICE)方法时,实际调用的是ContextImpl中的getSystemService()方法,该方法如下:
|
|
由于传入的参数为Context.ALARM_SERVICE,进入getAlarmManager()方法中:
|
|
首先分析ServiceManager.getService()这个方法:
|
|
如果是第一次请求该服务,则没有缓存,从而调用getIServiceManager().getService()方法。
在上面的服务注册过程中分析了getIServiceManager()其实返回的是ServiceManagerProxy对象,并且该ServiceManagerProxy对象中的mRemote保存着BinderProxy对象。
再回到ServiceManager.getService()方法中,可知getIServiceManager().getService()其实调用的是ServiceManagerProxy的getService()方法,该方法的代码如下:
|
|
这个方法里,重点是mRemote.transact(GET_SERVICE_TRANSACTION,data,reply,0);这个语句,前面说过,mRemote是一个BinderProxy对象,所以这里其实调用的是BinderProxy的transact()方法,代码如下:
|
|
显然,这是一个native方法,它对应的本地函数也可以在/frameworks/base/core/jni/android_util_Binder.cpp中找到,对应的函数是android_os_BinderProxy_transact(),如下所示:
|
|
前面的代码都是将Java中的Parcel对象转化为C++中的Parcel对象,之后获取BinderProxy中的mObject成员,前面说过,mObject成员保存的是BpBinder对象,所以这里IBinder*target其实指向的是BpBinder对象。从而target->transact()其实调用的是BpBinder的transact()方法,之后就和本地服务框架中的获取服务过程一样了,最后是将返回的数据放在reply中。
返回到getService()方法中,下面要调用的是reply.readStrongBinder();该方法的定义如下:
|
|
显然,该方法是一个native方法,它对应的是android_os_Parcel_readStrongBinder()函数:
|
|
在获取本地服务的博客中我们分析过,readStrongBinder()实际上返回的是一个持有相应服务handle值的BpBinder对象(注意,这个BpBinder对象和前面的BpBinder对象不同,前面的BpBinder持有的handle值为0,而此处为AlarmManagerService注册的handle值).
而javaObjectForIBinder()函数在前面已经分析过,它会生成一个BinderProxy对象,并且将刚刚生成的BpBinder对象保存在BinderProxy中的mObject中.
这样,getService()方法就分析完了,最终结果是返回BinderProxy对象,并且该对象中的mObject保存着对应于AlarmManagerService的BpBinder对象.
下面再回到getAlarmManager()中:
|
|
下面分析IAlarmManager.Stub.asInterface()方法:
|
|
前面说过,这个obj其实是BinderProxy对象,前面说过,BinderProxy的queryLocalInterface()始终返回null,所以这里会新建IAlarmManager.Stub.Proxy对象,其构造方法如下:
|
|
即将BinderProxy对象保存在Proxy中的mRemote成员中,记住这个,后面会用到。
再回到getAlarmManager()方法中,可见service其实是一个IAlarmManager.Stub.Proxy对象。下面一句很简单,就是新建AlarmManager对象,其构造方法如下:
|
|
可见,将前面新建的IAlarmManager.Stub.Proxy对象保存在AlarmManager中的mService对象中。
到这里,我们就成功获取到了AlarmManager对象,并且AlarmManager对象中的mService保存着IAlarmManager.Stub.Proxy对象,而Proxy对象中保存着BinderProxy对象,BinderProxy对象中保存着持有AlarmManagerService的handle值的BpBinder(C++)对象.
由于BpBinder持有了AlarmManagerService的handle值,所以到这里就相当于获取到了我们需要的闹钟服务。
2.3 Java系统服务调用
获取到服务后,返回AlarmManager对象,调用闹钟服务的过程示意图如下所示:
获取了AlarmManager对象之后,比如调用setTime()方法,代码如下:
|
|
前面说过,mService其实是IAlarmManager.Stub.Proxy对象,所以mService.setTime(millis);其实是调用IAlarmManager.Stub.Proxy的setTime()方法,代码如下所示:
|
|
前面说过,保存在Proxy对象中的mRemote中保存的是BinderProxy对象,而BinderProxy的transact()是个native方法,它对应的本地函数为android_os_BinderProxy_transact(),注意传入的参数obj为BinderProxy对象的本地引用,code为Stub.TRANSACTION_setTime,dataObj为保存Binder IPC数据的Parcel对象,replyObj则用于存放返回结果:
|
|
显然,这里会调用BpBinder对象的transact()方法,需要注意的是这个BpBinder对象是持有AlarmManagerService的handle值的BpBinder,而不是handle值为0的BpBinder.
之后仍然是调用IPCThreadState::transact()方法,writeTransactionData()也都差别不大,但是注意handle,code值不一样,其中handle为AlarmManagerService对应的handle值,code则为Stub.TRANSACTION_setTime.
然后调用waitForResponse()方法,客户端进程进入等待状态。
而Service Server进程则被唤醒,开始执行命令,下面是IPCThreadState::executeCommand()方法的主要代码:
|
|
这里先将tr.cookie转化为BBinder指针.前面已经说过,与单纯的本地服务不同,tr.cookie中存放的不是类似MediaPlayerService对象指针,而是JavaBBinder对象指针,而之前分析过BBinder的transact()中会调用onTransact()方法,JavaBBinder又重写了onTransact()方法,因而此处调用的是JavaBBinder中的onTransact()方法,其代码主要如下:
|
|
前面说过,JavaBBinder对象中mObject成员是AlarmManagerService对象,因而这里调用的是AlarmManagerService对象的execTransact()方法(因为AlarmManagerService继承于IAlarmManager.Stub,而IAlarmManager.Stub又继承于Binder,Binder中定义了execTransact()方法),代码如下:
|
|
显然,这里会调用Stub中的onTransact()方法,代码如下:
|
|