Android进阶解密
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.2 Service的启动过程

Service的启动过程和根Activity启动过程有部分相似的知识点,另外Service启动过程涉及上下文Context的知识点,这里只关注流程而不会详细介绍Context,关于上下文Context 会在第5章进行介绍。Service的启动过程将分为两个部分来进行讲解,分别是ContextImpl到ActivityManageService的调用过程和ActivityThread启动Service。

4.2.1 ContextImpl到AMS的调用过程

ContextImpl到AMS的调用过程很简短,如图4-7所示。

图4-7 ContextImpl到AMS的调用过程

要启动Service,我们会调用startService方法,它在ContextWrapper中实现,代码如下所示:

在startService方法中会调用mBase的startService方法,Context类型的mBase对象具体指的是什么呢?在4.1.3节中我们讲过,ActivityThread启动Activity时会调用如下代码创建Activity的上下文环境:

在注释1处创建上下文对象appContext,并传入Activity的attach方法中,将Activity与上下文对象appContext关联起来,这个上下文对象appContext的具体类型是什么?我们接着查看createBaseContextForActivity方法,代码如下所示:

上下文对象appContext的具体类型就是ContextImpl,在Activity的attach方法中将ContextImpl赋值给ContextWrapper的成员变量mBase,因此,上面提出的问题就得到了解答,mBase具体指向的就是ContextImpl。那么,紧接着来查看ContextImpl的startService方法,代码如下所示:

在startService方法中会返回startServiceCommon方法,在startServiceCommon方法中会在注释1处调用AMS的代理IActivityManager的startService方法,最终调用的是AMS的startService方法,这一过程已经在4.1.1节讲过了,这里不再赘述。

4.2.2 ActivityThread启动Service

ActivityThread启动Service的时序图如图4-8所示。

图4-8 ActivityThread启动Service的时序图

接着我们来查看AMS的startService方法,如下所示:

注释1处调用mServices的startServiceLocked方法,mServices的类型是ActiveServices,ActiveServices的startServiceLocked方法代码如下所示:

注释1处的retrieveServiceLocked方法会查找是否有与参数service对应的ServiceRecord,如果没有找到,就会调用PackageManagerService去获取参数service对应的Service信息,并封装到ServiceRecord中,最后将ServiceRecord封装为ServiceLookupResult返回。其中ServiceRecord用于描述一个Service,和此前讲过的ActivityRecord类似。在注释2处通过注释1处返回的ServiceLookupResult得到参数service对应的ServiceRecord,并传入到注释3处的startServiceInnerLocked方法中。

在startServiceInnerLocked方法中又调用了bringUpServiceLocked方法,如下所示:

在注释1处得到ServiceRecord 的processName值并赋给procName,其中processName用来描述Service想要在哪个进程中运行,默认是当前进程,我们也可以在AndroidManifest文件中设置android:process 属性来新开启一个进程运行Service。在注释2处将procName和Service的uid传入到AMS的getProcessRecordLocked 方法中,查询是否存在一个与Service对应的ProcessRecord类型的对象app,ProcessRecord主要用来描述运行的应用程序进程的信息。在注释5处判断Service对应的app为null则说明用来运行Service的应用程序进程不存在,则调用注释6处的AMS的startProcessLocked方法来创建对应的应用程序进程,关于创建应用程序进程请查看第3章的内容,这里只讨论没有设置android:process属性,即应用程序进程存在的情况。在注释3处判断如果用来运行Service的应用程序进程存在,则调用注释4处的realStartServiceLocked方法来启动Service:

在realStartServiceLocked方法中调用了app.thread的scheduleCreateService方法。其中app.thread是IApplicationThread 类型的,它的实现是ActivityThread的内部类ApplicationThread。ApplicationThread的scheduleCreateService方法如下所示:

scheduleLaunchActivity方法将启动Service的参数封装成ActivityClientRecord,sendMessage方法向H类发送类型为CREATE_SERVICE的消息,并将ActivityClientRecord传递过去,这个过程和4.1.3节ActivityThread启动Activity的过程是类似的。sendMessage方法有多个重载方法,最终调用的sendMessage方法如下所示:

这里mH指的是H,它是ActivityThread的内部类并继承自Handler,是应用程序进程中主线程的消息管理类。我们接着查看H的handleMessage方法:

handleMessage 方法根据消息类型为CREATE_SERVICE,会调用handleCreateService方法:

在注释1处获取要启动Service的应用程序的LoadedApk,LoadedApk是一个APK文件的描述类。在注释2处通过调用LoadedApk的getClassLoader方法来获取类加载器。接着在注释3处根据CreateServiceData对象中存储的Service信息,创建Service实例。在注释4处创建Service的上下文环境ContextImpl对象。在注释5处通过Service的attach方法来初始化Service。在注释6处调用Service的onCreate方法,这样Service就启动了。在注释7处将启动的Service加入到ActivityThread的成员变量mServices中,其中mServices是ArrayMap类型。Service的启动过程就讲到这里,接下来我们学习Service的绑定过程。