当前位置:   article > 正文

深入分析Android 9.0源代码——Service启动流程(startService方式)_mmaxstartingbackground

mmaxstartingbackground

引言

点击此处查看《深入分析Android 9.0源代码》系列的组织结构和相关说明。


1 应用进程发起启动请求

本章的调用流程如下图所示:

(Context) ContextWrapper ContextImpl [1] startService() [2] startService() [3] startServiceCommon() (Context) ContextWrapper ContextImpl

注:
(1)由于编辑器渲染的时序图不支持“无触发对象消息”(在标准的时序图中,这种消息的起点为实心圆形,表示流程的开始),此处用“(Context)”虚指触发流程的起始对象(而不是Android中的Context类)。
(2)对于时序图中形如“A—[#num] method()—>B”的消息(连线为实线),它的含义是控制流由先前的对象A(直接)转移到对象B,然后调用对象B的编号为#num的method()方法。


1.1 startService@ContextWrapper

Android系统为开发者提供了startService和bindService两种启动Service的方式,其中前者对应于Context类的startService()。由于Context类本身是一个抽象类,所以该方法实际上是在它的子类ContextWrapper中实现的。

// #1 {root}/core/java/ android.content.ContextWrapper (L663)
public ComponentName startService(Intent service) {
    return mBase.startService(service); // 调用#2
}
  • 1
  • 2
  • 3
  • 4

【L-03】return mBase.startService(service);
mBase是一个Context类型的成员变量,它的实际类型是ContextImpl。由此可见,Context抽象类提供了ContextWrapper和ContextImpl两个直接子类。其中ContextImpl是Context的功能实现类,它为Service等组件提供context这个重要概念的基础实现。但是,Android系统并不允许开发者直接使用ContextImpl类1,而是额外引入了一个ContextWrapper包装类(Activity、Service和Application类均直接或间接继承自该类),它负责将应用程序中与Context相关的方法调用转发给内部持有的ContextImpl引用。


1.2 startService@ContextImpl

startService()对系统进程的Service启动请求打印额外的调试信息2,然后调用startServiceCommon()处理启动请求。

// #2 {root}/core/java/ android.app.ContextImpl (L1530)
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser); // 调用#3
}
  • 1
  • 2
  • 3
  • 4
  • 5

【L-04】return startServiceCommon(…, false, …);
此处调用startServiceCommon()传入的第二个参数为false,表明默认情况下目标Service会以后台服务的方式进行启动。与前台服务相比,后台服务不会在下拉通知栏显示通知,同时优先级较低,当系统出现内存不足情况时容易被回收3


1.3 startServiceCommon@ContextImpl

startServiceCommon()首先对Intent的属性进行检查和准备,然后然后将Service的启动请求通过IPC(进程间通信)发送给系统服务ActivityManagerService(下文简称为AMS,它所属的system_server系统进程简称AMS进程)进行处理。由于AIDL实现的IPC默认是同步的,所以应用进程的当前线程将会挂起,直到AMS进程的startService()返回。需要特别注意的是,虽然该方法本身是同步调用,但是后续AMS处理Service的启动过程是异步的,也即AMS进程的startService()并不会一直阻塞直到Service启动完毕4。事实上,当应用进程调用的startServiceCommon()返回时,其返回值仅包含需要启动的Service的相关信息(如果该Service存在),此时AMS并不保证目标Service已经创建成功(如果需要)并且执行了onStartCommand()回调方法。

// #3 {root}/core/java/ android.app.ContextImpl (L1557)
private ComponentName startServiceCommon(Intent service, boolean requireForeground, 
        UserHandle user) {
    ...
    validateServiceIntent(service);
    service.prepareToLeaveProcess(this);
    ComponentName cn = ActivityManager.getService().startService(mMainThread.getApplicationThread(), 
            service, service.resolveTypeIfNeeded(getContentResolver()), requireForeground, 
            getOpPackageName(), user.getIdentifier()); // IPC调用#4
    if (cn != null) { ... }
    return cn;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

【L-05】validateServiceIntent(service);
validateServiceIntent()对参数Intent进行合法性检查,确保其中与Service启动的相关属性值不为null。此外,Android 5.0后强制要求Service必须通过显式Intent启动5,否则会直接抛出异常。

【L-06】service.prepareToLeaveProcess(this);
prepareToLeaveProcess()对Intent的属性进行离开应用进程前的准备工作。在StrictMode下,该方法还会进行跨进程安全性的检查,此时不允许使用scheme为“file://”的URI进行数据传输,而必须使用FileProvider作为替代6

【L-07】ComponentName cn = ActivityManager.getService().startService(…);
ActivityManager.getService()获取AMS的Binder代理对象,然后通过AIDL调用AMS的startService()。对AMS和IPC更详细的介绍参见本系列的《Activity启动流程》的1.3节。该方法的返回类型为ComponentName,它内部有两个String类型的成员变量mPackagemClass,分别表示组件(此处为Service)对应的应用包名和组件类名7

【L-10】if (cn != null) { … }
当由于权限、安全性等问题导致Service无法正常启动时,返回值cn的成员变量mPackage会被设置为"!"、“?”等特殊值,此时应用进程会进行处理并抛出对应的异常。


2 AMS处理启动请求

本章的调用流程如下图所示:

ComtextImpl [AMS] ActiveServices [4] startService() [5] startServiceLocked() [6] startServiceInnerLocked [7] bringUpServiceLocked ComtextImpl [AMS] ActiveServices

注:由于编辑器限制对象文本的最大长度,时序图中对于名称较长的类使用方括号(“[]”)和缩写来表示。上图中[AMS]=ActivityManagerService。


2.1 startService@ActivityManagerService

startService()获取客户端进程的callingPid与callingUid,然后将它们连同其它参数传递给ActiveServices对象的startServiceLocked()进行处理。

// #4 {root}/services/core/java com.android.server.am.ActivityManagerService (L20342)
public ComponentName startService(IApplicationThread caller, Intent service, 
        String resolvedType, boolean requireForeground, String callingPackage, 
        int userId) throws TransactionTooLargeException {
    ...
    synchronized (this) {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res;
        try {
            res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, 
                    callingUid, requireForeground, callingPackage, userId); // 调用#5
        }
        finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

【L-09】final long origId = Binder.clearCallingIdentity();
Binder.clearCallingIdentity()将远程调用端的PID和UID的初始值暂存于返回值origId中,然后将其替换为当前进程的PID和UID8。因为包括AMS在内的众多系统服务都运行在同一个system_server进程中,所以当AMS通过AIDL接口调用其它系统服务时,实质上只是一个同进程的本地方法调用。在这种情况下,Binder驱动不再(像跨进程调用一样)提供调用方进程的PID和UID,故此处需要显式地设置当前进程的PID和UID9

【L-12】res = mServices.startServiceLocked(…);
mServices是一个ActiveServices类型的成员变量,它的主要职责是辅助AMS管理应用服务10(与系统服务相对11)。

【L-16】Binder.restoreCallingIdentity(origId);
Binder.restoreCallingIdentity()利用origId恢复远程调用端的UID和PID的原始值,通常它与先前提到的Binder.clearCallingIdentity()总是成对出现12


2.2 startServiceLocked@ActiveServices

startServiceInnerLocked()首先尝试获取目标Service对应的SerivceRecord缓存对象(如果不存在则创建一个新的SerivceRecord),然后检查启动权限的合法性13,最后判断Service能够立即启动还是需要延迟启动。

// #5 {root}/services/core/java com.android.server.am.ActiveServices (L389)
ComponentName startServiceLocked(IApplicationThread caller, Intent service, 
        String resolvedType, int callingPid, int callingUid, boolean fgRequired, 
        String callingPackage, final int userId) throws TransactionTooLargeException {
    ...
    ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, 
            callingPid, callingUid, userId, true, callerFg, false, false);
    ...
    ServiceRecord r = res.record;
    ...
    r.startRequested = true;
    ...
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants, callingUid));
    ...
    boolean addToStarting = false;
    if (!callerFg && !fgRequired && r.app == null && 
            mAm.mUserController.hasStartedUserState(r.userId)) {
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
        if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
            ...
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            addToStarting = true;
        }
        else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
            addToStarting = true;
        }
        ...
    }
    ...
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); // 调用#6
    return cmp;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

【L-06】ServiceLookupResult res = retrieveServiceLocked(…);
retrieveServiceLocked()根据Intent查询并返回一个ServiceLookupResult对象,其中封装了目标Service对应的ServiceRecord。该方法首先尝试从ServiceMap中获取ServiceRecord缓存对象,而ServiceMap又是ActiveServices类的内部类,它为每个用户分别维护了mServicesByNamemServicesByIntent两个值类型为ServiceRecord的ArrayMap14。如果不存在缓存对象,该方法将调用PackageManagerService的resolveService()解析Intent并获得对应的ResolveInfo对象,然后利用它创建一个新的ServiceRecord对象15

【L-11】r.startRequested = true;
startRequested是ServiceRecord类的一个boolean类型的成员变量,该值为true表示Service是通过startService方式(而不是bindService方式)启动的16

【L-13】r.pendingStarts.add(new ServiceRecord.StartItem(…));
pendingStarts是ServiceRecord类的一个ArrayList<StartItem>类型的成员变量,它保存着所有尚未处理的Service启动参数,这些参数最终会在回调Service的onStartCommand()时传递给应用进程进行处理17

【L-16】boolean addToStarting = false;
addToStarting是一个boolean类型的局部变量,该值为true表示目标Service可以作为后台服务立即启动,并且它对应的ServiceRecord将被添加到ServiceMap对象的mStartingBackground列表中18。此处它的值被初始化为false,后续的执行流程将根据目标Service是否为后台服务以及是否需要延迟启动来对其进行赋值。

【L-17】if (!callerFg && !fgRequired && r.app == null && … ) { … }
此处if语句的判断条件依次表示“caller app不是前台应用”、“目标Service不是前台服务”、“目标Service处于未运行状态”、“发起请求的用户已经启动”19。当以上条件均满足时,后续代码进入if分支并判断目标Service是否需要延迟启动;否则,将调用startServiceInnerLocked()立即启动目标Service。

【L-20】if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) { … }
当目标Service所属的进程尚未创建,或者已创建但优先级较低时(即proc.curProcState的值大于常量10,注意它的取值越小反而表示进程优先级越高20),会进入if分支判断是否要延迟启动目标Service。

【L-22】if (smap.mStartingBackground.size() >= mMaxStartingBackground) { … }
当ServiceMap对象的mStartingBackground列表的容量已达上限时,表明系统目前正在忙于处理其它后台Service的启动请求。此时目标Service的启动将被添加到ServiceMap的mDelayedStartList列表中并标记为延迟启动,然后方法会直接返回,而不是立即调用startServiceInnerLocked()执行后续启动流程21

【L-29】else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) { … }
当目标Service所属的进程已经创建且优先级较高时(即proc.curProcState的值大于或等于常量9),目标Service的启动不受mStartingBackground列表的容量限制,一定可以立即启动。


2.3 startServiceInnerLocked@ActiveServices

startServiceLocked()调用bringUpServiceLocked()“拉起”目标Service,如果启动失败则会抛出对应的异常。

// #6 {root}/services/core/java com.android.server.am.ActiveServices (L660)
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, 
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ...
    r.callStart = false;
    ...
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); // 调用#7
    if (error != null) 
        return new ComponentName("!!", error);
    ...
    return r.name;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

【L-05】r.callStart = false;
callStart是ServiceRecord类的一个boolean类型的成员变量,该值为true表示(先前运行的)Service由于内存不足被杀死后进行自动重启(一个典型的实例是Service的onStartCommand()返回START_STICKY22。在本文分析的执行流程中,目标Service是通过startService方式进行“全新启动”而非自动重启,所以此处该值被设置为false。


2.4 bringUpServiceLocked@ActiveServices

bringUpServiceLocked()“拉起”目标Service,它根据其所属的进程是否已经创建执行相应的后续流程,并且在执行成功时返回null(反之则返回错误消息)。如果目标Service所属的进程尚未创建,则需要额外通过AMS的startProcessLocked()创建对应的进程;如果目标Service尚未创建但所属的进程已经存在,则需要额外通过realStartServiceLocked()执行Service的create流程;如果目标Service已经创建,则可以直接通过sendServiceArgsLocked()回调目标Service的onStartCommand()23。为了更加全面地展示Service的启动流程,本文假定对应的进程尚未创建。

// #7 {root}/services/core/java com.android.server.am.ActiveServices (L2287)
private String bringUpServiceLocked(ServiceRecord r, 
        int intentFlags, boolean execInFg, boolean whileRestarting, 
        boolean permissionsReviewRequired) throws TransactionTooLargeException {
    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false); // 调用#14
        return null;
    }
    ...
    final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    String hostingType = "service";
    ProcessRecord app;
    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (app != null && app.thread != null) {
            ...
            realStartServiceLocked(r, app, execInFg); // 调用#10
            return null;
            ...
        }
    }
    ...
    if (app == null && !permissionsReviewRequired) {
        if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, hostingType, 
                r.name, false, isolated, false)) == null) { // 调用#R39
            ...
            bringDownServiceLocked(r);
            return msg;
        }
        ...
    }
    ...
    if (!mPendingServices.contains(r)) 
        mPendingServices.add(r);
    ...
    return null;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

【L-05】if (r.app != null && r.app.thread != null) { … }
r.appr.app.thread分别是ProcessRecord和IApplicationThread类型的对象,当这两者不为null时表示目标Service此前已经执行过创建和初始化的流程。此时后续调用的sendServiceArgsLocked()会将ServiceRecord(它本身是AMS进程的Binder实体类24)和相关的启动参数通过IPC传递给应用进程,并最终回调目标Service的onStartCommand()对启动参数进行解析和处理。本文假定目标Service对应的进程尚未创建,也即不满足if语句的判断条件。

【L-10】final boolean isolated = …;
isolated是一个boolean类型的局部变量,它对应于Manifest中Service的android:isolatedProcess属性,该值为true意味着Service会在一个特殊的进程下运行,该进程将与系统其它进程分开并且没有自己的权限25。为了更加全面地展示Service的启动流程,本文假定该值为false。

【L-15】app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
mAm是一个ActivityManagerService类型的成员变量,它的getProcessRecordLocked()在当前运行的进程列表中(通过进程名称和UID)查找目标Service所属的进程是否已经存在26,并且返回值将被保存在局部变量app中。

【L-16】if (app != null && app.thread != null) { … }
appapp.thread同样也分别是ProcessRecord和IApplicationThread类型的对象,当这两者不为null时表示目标Service所属的进程已经存在,此时会调用realStartServiceLocked()(它首先通过IPC回调Service的onCreate()完成创建流程,接着调用刚才提到的sendServiceArgsLocked()),然后返回null。本文假定目标Service对应的进程尚未创建,也即不满足if语句的判断条件。

【L-25】if ((app = mAm.startProcessLocked(…)) == null) { … }
此处调用AMS的startProcessLocked()创建一个新的进程,如果创建失败将执行if分支并返回错误消息msg。本文假定进程创建成功,从而后续不会执行if分支。

【L-34】if (!mPendingServices.contains(r)) { … }
mPendingServices是一个ArrayList<ServiceRecord>类型的成员变量,当Service所属的进程不存在时,会将对应的ServiceRecord保存在这个列表中。当进程创建完成后会调用attachApplicationLocked(),该方法将遍历mPendingServices并调用realStartServiceLocked()执行目标Service的后续启动流程。


3 创建Service所属的新进程

本章的调用流程如下图所示:

ActiveServices [AMS] Process ZygoteProcess [R39-R43] startProcessLocked() [R44] startProcess() [R45] start() [R46] start() [R47] startViaZygote() [R48] zygoteSendArgsAndGetResult() ActiveServices [AMS] Process ZygoteProcess

注:
(1)由于本章对时序图中的方法介绍均参见本系列的《Activity启动流程》的第4章,所以方法编号前加上“R”表示引用自其它文章,而非本文固有的自然编号。
(2)[AMS]=ActivityManagerService。
(3)同名的重载方法调用会直接合并,其对应的方法编号也使用[#num1-#num2]的形式进行合并。


3.1 startProcessLocked@ActivityManagerService

该方法的详细介绍参见本系列的《Activity启动流程》的4.2节


3.2 startProcess@ActivityManagerService

该方法的详细介绍参见本系列的《Activity启动流程》的4.3节,注意与Activity启动流程唯一不同之处是hostingType被赋值为“service”(参见上文2.4节)而不是“activity”。


3.3 start@Process

该方法的详细介绍参见本系列的《Activity启动流程》的4.4节


3.4 start@ZygoteProcess

该方法的详细介绍参见本系列的《Activity启动流程》的4.5节


3.5 startViaZygote@ZygoteProcess

该方法的详细介绍参见本系列的《Activity启动流程》的4.6节


3.6 zygoteSendArgsAndGetResult@ZygoteProcess

该方法的详细介绍参见本系列的《Activity启动流程》的4.7节


4 应用进程启动Service

本章的调用流程如下图所示:

(VM) ActivityThread [AMS] ActiveServices [R49] main() [R50] attach() [R51] attachApplication() [R52] attachApplicationLocked() [9] attachApplicationLocked() [10] realStartServiceLocked() (VM) ActivityThread [AMS] ActiveServices


ActiveServices ApplicationThread ActivityThread H Service [11] scheduleCreateService() [R25-R28] sendMessage() [12] handleMessage() [13] handleCreateService() [-] onCreate() ActiveServices ApplicationThread ActivityThread H Service


ActiveServices ApplicationThread ActivityThread H Service [14] sendServiceArgsLocked() [15] scheduleServiceArgs() [R25-R28] sendMessage() [16] handleMessage() [17] handleServiceArgs() [-] onStartCommand() ActiveServices ApplicationThread ActivityThread H Service

注:
(1)为了排版美观,此处将整个流程拆分为三个时序图进行绘制,分别展示ActivityThread的初始化和绑定流程、Service的create流程、Service的startCommand流程。
(2)新进程的底层创建过程由虚拟机负责调度,此处第一幅时序图中用“(VM)”虚指触发流程的起始对象。
(3)[AMS]=ActivityManagerService。
(4)对于时序图中形如“A---[#num] method()--->B”的消息(连线为虚线),它的含义是控制流由先前的对象A(经过一些略去的中间流程后)最终转移到对象B,然后调用对象B的编号为#num的method()方法。
(5)由于本章对流程图中的部分方法介绍参见本系列的《Activity启动流程》的第3章(R25-R28)和第5章(R49-R52),所以方法编号前加上“R”表示引用自其它文章,而非本文固有的自然编号。
(6)onCreate()和onStartCommand()对于理解执行流程具有重要意义,所以这两个方法被标注在时序图中。由于下文并没有具体对这两个方法进行分析,所以它们的方法编号为“-”。


4.1 main@ActivityThread

该方法的详细介绍参见本系列的《Activity启动流程》的5.1节


4.2 attach@ActivityThread

该方法的详细介绍参见本系列的《Activity启动流程》的5.2节


4.3 attachApplication@ActivityManagerService

该方法的详细介绍参见本系列的《Activity启动流程》的5.3节


4.4 attachApplicationLocked@ActivityManagerService

attachApplicationLocked()的流程相对复杂,主要包括对Application进行一系列的合法性校验和参数配置、调用thread.bindApplication()通知应用进程执行Application的初始化流程、调用mServices.attachApplicationLocked()启动属于当前进程的Service。

// #8 {root}/services/core/java com.android.server.am.ActivityManagerService (L7572)
private final boolean attachApplicationLocked(IApplicationThread thread, int pid,
        int callingUid, long startSeq) {
    ProcessRecord app;
    ...
    if (app.isolatedEntryPoint != null) {
        ...
    }
    else if (app.instr != null) {
        thread.bindApplication(processName, appInfo, providers, app.instr.mClass, 
                profilerInfo, app.instr.mArguments, app.instr.mWatcher, 
                app.instr.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, 
                enableTrackAllocation, isRestrictedBackupMode || !normalMode, 
                app.persistent, new Configuration(getGlobalConfiguration()), 
                app.compat, getCommonServicesLocked(app.isolated), 
                mCoreSettingsObserver.getCoreSettingsLocked(), 
                buildSerial, isAutofillCompatEnabled);
    }
    else {
        thread.bindApplication(processName, appInfo, providers, null, 
                profilerInfo, null, null, null, testMode, mBinderTransactionTrackingEnabled, 
                enableTrackAllocation, isRestrictedBackupMode || !normalMode, 
                app.persistent, new Configuration(getGlobalConfiguration()), 
                app.compat, getCommonServicesLocked(app.isolated), 
                mCoreSettingsObserver.getCoreSettingsLocked(), 
                buildSerial, isAutofillCompatEnabled);
    }
    ...
    if (!badApp) {
        ...
        didSomething |= mServices.attachApplicationLocked(app, processName); // 调用#9
        ...
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

【L-06】if (app.isolatedEntryPoint != null) { … }
该语句的详细介绍参见本系列的《Activity启动流程》的5.4节的【L-06】。

【L-10】thread.bindApplication(…);
该语句的详细介绍参见本系列的《Activity启动流程》的5.4节的【L-10】。

【L-31】didSomething |= mServices.attachApplicationLocked(app, processName);
上文2.4节中提到,当Service所属的进程不存在时,会将对应的ServiceRecord保存在mPendingServices中,以等待进程创建完毕。此处的attachApplicationLocked()会遍历这个列表,并恢复执行属于当前进程的Service的后续启动流程。


4.5 attachApplicationLocked@ActiveServices

attachApplicationLocked()遍历mPendingServices中的每一项ServiceRecord,当对应的进程恰好是目标Service所属的进程时,则调用realStartServiceLocked()执行Service的create流程。

// #9 {root}/services/core/java com.android.server.am.ActiveServices (L3065)
boolean attachApplicationLocked(ProcessRecord proc, String processName) throws RemoteException {
    ...
    if (mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        ...
        for (int i = 0; i < mPendingServices.size(); i++) {
            sr = mPendingServices.get(i);
            if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid 
                    || !processName.equals(sr.processName))) 
                continue;
            ...
            realStartServiceLocked(sr, proc, sr.createdFromFg); // 调用#10
            ...
        }
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18


4.6 realStartServiceLocked@ActiveServices

上文2.4节中已经简要介绍过realStartServiceLocked(),它首先通过IPC调用scheduleCreateService()执行Service的create的流程,然后通过sendServiceArgsLocked()(内部实现也是IPC调用)回调目标Service的onStartCommand()

// #10 {root}/services/core/java com.android.server.am.ActiveServices (L2433)
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, 
        boolean execInFg) throws RemoteException {
    ...
    app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(
            r.serviceInfo.applicationInfo), app.repProcState); // IPC调用#11
    ...
    requestServiceBindingsLocked(r, execInFg);
    ...
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) 
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), 
                null, null, 0));
    sendServiceArgsLocked(r, execInFg, true); // 调用#14
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

【L-05】app.thread.scheduleCreateService(…);
app.thread是ProcessRecord类的一个IApplicationThread类型的成员变量。与本系列的《Activity启动流程》的3.3节类似,此处AMS同样作为客户端,通过IApplicationThread接口的Binder代理对象,主动通知应用进程执行Service的create流程。

【L-08】requestServiceBindingsLocked(r, execInFg);
requestServiceBindingsLocked()处理Service的绑定过程,它最终会回调Service的onBind()。事实上以startService方式启动Service时,原本并不需要处理绑定过程。但是上文2.4节中提到,当Service对应的进程尚未创建时,会将对应的ServiceRecord对象暂时保存在mPendingServices中。如果在进程创建的过程中,恰好又以bindService方式提交了其它启动请求,那么自然就需要额外处理Service的绑定过程27。受篇幅限制,此处不再继续深入解析与之相关的绑定流程。

【L-10】if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) { … }
r.startRequestedr.callStartr.pendingStarts的详细分析依次参见上文的2.2节2.3节2.2节。此处if语句的判断条件表示“通过startService方式启动的Service需要自动重启,并且没有为其传入新的启动参数”,该条件满足时将构造一个缺省的StartItem作为启动参数并添加到对应的pendingStarts中,以确保最终一定会回调它的onStartCommand()28 (具体原因将在下文4.11节中进行分析)。在本文分析的执行流程中,目标Service是通过startService方式进行“全新启动”而非自动重启,所以这个if语句的判断条件事实上并不会满足。


4.7 scheduleCreateService@ApplicationThread

scheduleCreateService()更新应用进程的状态,然后通过Handler发送CREATE_SERVICE消息,执行目标Service的create流程。

// #11 {root}/core/java/ android.app.ActivityThread$ApplicationThread (L805)
public final void scheduleCreateService(IBinder token, ServiceInfo info, 
        CompatibilityInfo compatInfo, int processState) {
    updateProcessState(processState, false);
    CreateServiceData s = new CreateServiceData();
    s.token = token;
    s.info = info;
    s.compatInfo = compatInfo;
    sendMessage(H.CREATE_SERVICE, s); // 调用#R25
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10


4.8 sendMessage@ActivityThread

该方法的详细介绍参见本系列的《Activity启动流程》的3.6节


4.9 handleMessage@H

根据消息的what值的不同,H类的handleMessage()可以处理多达四十余种不同的消息。由于上文4.7节中caller方法scheduleCreateService()发送的消息的what值为ActivityThread.H.CREATE_SERVICE,所以此处只展示该消息的处理流程。

// #12 {root}/core/java/ android.app.ActivityThread$H (L1644)
public void handleMessage(Message msg) {
    switch (msg.what) {
        ...
        case CREATE_SERVICE:
            ...
            handleCreateService((CreateServiceData)msg.obj); // 调用#13
            ...
            break;
        ...
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13


4.10 handleCreateService@ActivityThread

handleCreateService()的主要流程包括通过类加载器创建创建Service的实例、(在必要的情况下)尝试创建Application对象、创建并初始化Service对应的Context对象、调用Service的onCreate()、更新mServices以维护Service在AMS进程与应用进程之间的映射关系29。至此为止,需要启动的Service的create流程终于分析完毕。

// #13 {root}/core/java/ android.app.ActivityThread (L3503)
private void handleCreateService(CreateServiceData data) {
    LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
    Service service = null;
    ...
    java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent);
    ...
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
    context.setOuterContext(service);
    Application app = packageInfo.makeApplication(false, mInstrumentation);
    service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
    service.onCreate();
    mServices.put(data.token, service);
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

【L-03】LoadedApk packageInfo = getPackageInfoNoCheck(…);
getPackageInfoNoCheck()的返回值类型为LoadedApk,它是APK文件在内存中的表示,通过它可以获取APK文件中包含的代码和资源文件30

【L-09】ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
此处调用静态方法ContextImpl.createAppContext()创建ContextImpl实例31。上文1.1节中提到过,ContextImpl类继承自Context抽象类,它为Service等组件提供context这个重要概念的基础实现。

【L-10】context.setOuterContext(service);
setOuterContext()将ContextImpl类的mOuterContext成员变量设置为Service对象,从而使得ContextImpl能够将特定的操作转发给它所关联的Service进行处理32

【L-11】Application app = packageInfo.makeApplication(false, mInstrumentation);
makeApplication()检查进程的Application对象是否存在,如果不存在则尝试执行对应的创建流程。由于上文4.4节中调用的thread.bindApplication()已经完成了Application的初始化流程33,所以此处并不需要重复执行创建流程。

【L-12】service.attach(…);
attach()完成了Service对象的大部分成员变量的初始化流程34,也就是说,此处传入的部分参数的引用会被Service所持有。例如,第二个参数this和第四个参数data.token分别用于初始化Service对象的成员变量mThreadmToken

【L-14】mServices.put(data.token, service);
mServices是ActivityThread类的一个ArrayMap<IBinder, Service>类型的成员变量(注意不要与上文2.1节中ActivityManagerService类的ActiveServices类型的同名变量混淆),它的键是AMS进程的ServiceRecord在应用进程中的Binder代理对象,它的值是应用进程的Service对象。当AMS请求应用进程运行一个Service时,会将ServiceRecord通过IPC传递给应用进程,然后它对应的Binder代理对象会作为键保存在mServices35,从而维护同一个Service对象在AMS进程与应用进程之间的映射关系。


4.11 sendServiceArgsLocked@ActiveServices

上文4.6节中提到,当Service的create流程执行完毕后,接下来会调用sendServiceArgsLocked()。该方法对Service的启动参数进行检查和封装,然后通过IPC调用应用进程的scheduleServiceArgs()对启动参数进行处理。

// #14 {root}/services/core/java com.android.server.am.ActiveServices (L2528)
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg, 
        boolean oomAdjusted) throws TransactionTooLargeException {
    final int N = r.pendingStarts.size();
    if (N == 0) 
        return;
    ...
    ArrayList<ServiceStartArgs> args = new ArrayList<>();
    ...
    while (r.pendingStarts.size() > 0) {
        ServiceRecord.StartItem si = r.pendingStarts.remove(0);
        ...
        args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
    }
    ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
    ...
    r.app.thread.scheduleServiceArgs(r, slice); // IPC调用#15
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

【L-05】if (N == 0) { … }
此处检查启动参数列表r.pendingStarts的长度,如果该值为0,表示没有启动参数需要处理,此时方法会直接返回。上文2.2节中caller方法startServiceLocked()已经为目标Service创建并添加了一个StartItem对象,所以此处一定会执行后续的流程并最终回调Service的onStartCommand()。同理,上文4.6节中caller方法realStartServiceLocked()之所以需要为自动重启且未传入启动参数的Service构造一个缺省的StartItem对象,也是为了确保能最终回调onStartCommand()

【L-15】ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
ParceledListSlice类是Android系统提供的一个利用IPC传输Parcelable对象列表的工具类,当列表中元素的数量足够多时,会自动将其拆分为多个transaction依次处理。

【L-17】r.app.thread.scheduleServiceArgs(r, slice);
与上文4.6节类似,此处通过IApplicationThread接口的Binder代理对象,主动通知应用进程对启动参数进行处理。


4.12 scheduleServiceArgs@ApplicationThread

scheduleServiceArgs()获取AMS进程通过IPC传输的启动参数,对其进行重新封装,然后利用Handler发送SERVICE_ARGS消息。与上文4.8~4.9节类似,该消息最终由mHhandleMessage()进行处理。

// #15 {root}/core/java/ android.app.ActivityThread$ApplicationThread (L838)
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
    List<ServiceStartArgs> list = args.getList();
    for (int i = 0; i < list.size(); i++) {
        ServiceStartArgs ssa = list.get(i);
        ServiceArgsData s = new ServiceArgsData();
        s.token = token;
        s.taskRemoved = ssa.taskRemoved;
        s.startId = ssa.startId;
        s.flags = ssa.flags;
        s.args = ssa.args;
        sendMessage(H.SERVICE_ARGS, s); // 最终调用#16
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14


4.13 handleMessage@H

根据消息的what值的不同,H类的handleMessage()可以处理多达四十余种不同的消息。由于上文4.12节中caller方法scheduleServiceArgs()发送的消息的what值为ActivityThread.H.SERVICE_ARGS,所以此处只展示该消息的处理流程。

// #16 {root}/core/java/ android.app.ActivityThread$H (L1644)
public void handleMessage(Message msg) {
    switch (msg.what) {
        ...
        case SERVICE_ARGS:
            ...
            handleServiceArgs((ServiceArgsData)msg.obj); // 调用#17
            ...
            break;
        ...
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13


4.14 handleServiceArgs@ActivityThread

handleServiceArgs()调用Service的onStartCommand(),至此为止Service的整个启动流程全部分析完毕。

// #17 {root}/core/java/ android.app.ActivityThread (L3657)
private void handleServiceArgs(ServiceArgsData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        ...
        if (!data.taskRemoved) 
            res = s.onStartCommand(data.args, data.flags, data.startId);
        ...
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10


总结

调用Context.startService()启动一个Service的执行流程简要总结如下:
(1)应用进程向AMS发送Service启动请求。
(2)AMS进行一系列准备工作,主要包括合法性检查和判断是否延迟启动。
(3)AMS判断目标Service所属的进程是否已经存在。若进程尚未创建,则请求Zygote创建一个新进程,然后在其主线程中调用ActivityThread.main()完成进程的初始化。
(4)AMS判断Service是否已经创建。若Service尚未创建,则执行相应的创建流程并最终回调onCreate()。
(5)AMS将Service的启动参数发送给应用进程。
(6)Service所属的目标进程接收并解析启动参数,然后调用onStartCommand(),从而完成启动流程。


参考文献


  1. Android中ContextImpl源码分析(二).
    https://blog.csdn.net/dongxianfei/article/details/54632423 ↩︎

  2. Android服务之startService源码分析.
    https://blog.csdn.net/zhangyongfeiyong/article/details/51910578 ↩︎

  3. Android Service生命周期,本地服务远程服务,前台服务后台服务,启动方式,与IntentService区别全面解析.
    https://blog.csdn.net/qq_30993595/article/details/78452064 ↩︎

  4. Android6.0之App的Service组件运行机制之StartService.
    https://www.jianshu.com/p/fffef3f278b6 ↩︎

  5. service的隐式启动和显示启动.
    https://blog.csdn.net/cpcpcp123/article/details/52741237 ↩︎

  6. Service流程笔记.
    https://www.jianshu.com/p/ef19ae5929cf ↩︎

  7. Android ComponentName的用法.
    https://blog.csdn.net/u012532559/article/details/52766348 ↩︎

  8. Android源码的Binder权限控制.
    https://blog.csdn.net/bbmcdull/article/details/52046690 ↩︎

  9. android IPC通信中的UID和PID识别.
    https://blog.csdn.net/windskier/article/details/6921672 ↩︎

  10. 一图解惑之Android管理Service数据结构.
    https://www.jianshu.com/p/1c0e908046fb ↩︎

  11. Android 进阶 - Activity服务启动分析.
    https://blog.csdn.net/szzhaom/article/details/23452939 ↩︎

  12. Android源码的Binder权限控制.
    https://blog.csdn.net/bbmcdull/article/details/52046690 ↩︎

  13. Android 8.0 Service源码分析:启动流程及后台限制详解.
    https://blog.csdn.net/zwjemperor/article/details/82949913 ↩︎

  14. Android Service演义(android 5.1).
    https://blog.csdn.net/thinkinwm/article/details/52399177 ↩︎

  15. Android Gems — AMS的Service生命周期管理.
    http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎

  16. 四大组件之ServiceRecord.
    http://gityuan.com/2017/05/25/service_record/ ↩︎

  17. Android Service重启恢复(Service进程重启)原理解析.
    https://blog.csdn.net/happylishang/article/details/81776217 ↩︎

  18. Android Gems — AMS的Service生命周期管理.
    http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎

  19. Android系统源码分析–Service启动流程.
    https://www.meiwen.com.cn/subject/mzcwlftx.html ↩︎

  20. Android系统中的进程管理:进程的优先级.
    https://blog.csdn.net/omnispace/article/details/73320950 ↩︎

  21. Android Gems — AMS的Service生命周期管理.
    http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎

  22. Android Service重启恢复(Service进程重启)原理解析.
    https://cloud.tencent.com/developer/article/1199550 ↩︎

  23. Android Gems — AMS的Service生命周期管理.
    http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎

  24. Android Service演义(android 5.1).
    https://blog.csdn.net/thinkinwm/article/details/52399177 ↩︎

  25. 关于Android Service真正的完全详解,你需要知道的一切.
    https://blog.csdn.net/javazejian/article/details/52709857 ↩︎

  26. AMS (2): AMS 如何进程管理?.
    https://blog.csdn.net/ccjhdopc/article/details/52795711 ↩︎

  27. Android 8.0 Service源码分析:启动流程及后台限制详解.
    https://blog.csdn.net/zwjemperor/article/details/82949913 ↩︎

  28. Service的自动重启问题.
    https://www.jianshu.com/p/1c995328c293 ↩︎

  29. Service启动过程分析.
    https://www.cnblogs.com/cr330326/p/6394071.html ↩︎

  30. Android 插件化原理解析——插件加载机制.
    https://blog.csdn.net/huangkun125/article/details/52184116 ↩︎

  31. 深入理解Android中的Context(三).
    https://baijiahao.baidu.com/s?id=1584558620597480755 ↩︎

  32. Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析.
    https://blog.csdn.net/luoshengyang/article/details/8201936 ↩︎

  33. 深入理解Activity启动流程(三)–Activity启动的详细流程2.
    https://blog.csdn.net/chen381051010/article/details/56844788 ↩︎

  34. ActvitityThread中的performLaunchActivity(ActivityClientRecord r, Intent customIntent)解析.
    https://blog.csdn.net/a284266978/article/details/53782453 ↩︎

  35. Android6.0之App的Service组件运行机制介绍.
    https://www.jianshu.com/p/1a5105eab7cb ↩︎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/273025
推荐阅读
相关标签
  

闽ICP备14008679号