赞
踩
点击此处查看《深入分析Android 9.0源代码》系列的组织结构和相关说明。
本章的调用流程如下图所示:
注:
(1)由于编辑器渲染的时序图不支持“无触发对象消息”(在标准的时序图中,这种消息的起点为实心圆形,表示流程的开始),此处用“(Context)”虚指触发流程的起始对象(而不是Android中的Context类)。
(2)对于时序图中形如“A—[#num] method()—>B”的消息(连线为实线),它的含义是控制流由先前的对象A(直接)转移到对象B,然后调用对象B的编号为#num的method()方法。
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
}
【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引用。
startService()
对系统进程的Service启动请求打印额外的调试信息2,然后调用startServiceCommon()
处理启动请求。
// #2 {root}/core/java/ android.app.ContextImpl (L1530)
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser); // 调用#3
}
【L-04】return startServiceCommon(…, false, …);
此处调用startServiceCommon()
传入的第二个参数为false,表明默认情况下目标Service会以后台服务的方式进行启动。与前台服务相比,后台服务不会在下拉通知栏显示通知,同时优先级较低,当系统出现内存不足情况时容易被回收3。
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;
}
【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类型的成员变量mPackage
和mClass
,分别表示组件(此处为Service)对应的应用包名和组件类名7。
【L-10】if (cn != null) { … }
当由于权限、安全性等问题导致Service无法正常启动时,返回值cn
的成员变量mPackage
会被设置为"!"、“?”等特殊值,此时应用进程会进行处理并抛出对应的异常。
本章的调用流程如下图所示:
注:由于编辑器限制对象文本的最大长度,时序图中对于名称较长的类使用方括号(“[]”)和缩写来表示。上图中[AMS]=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; } }
【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。
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; }
【L-06】ServiceLookupResult res = retrieveServiceLocked(…);
retrieveServiceLocked()
根据Intent查询并返回一个ServiceLookupResult对象,其中封装了目标Service对应的ServiceRecord。该方法首先尝试从ServiceMap中获取ServiceRecord缓存对象,而ServiceMap又是ActiveServices类的内部类,它为每个用户分别维护了mServicesByName
和mServicesByIntent
两个值类型为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
列表的容量限制,一定可以立即启动。
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;
}
【L-05】r.callStart = false;
callStart
是ServiceRecord类的一个boolean类型的成员变量,该值为true表示(先前运行的)Service由于内存不足被杀死后进行自动重启(一个典型的实例是Service的onStartCommand()
返回START_STICKY
)22。在本文分析的执行流程中,目标Service是通过startService方式进行“全新启动”而非自动重启,所以此处该值被设置为false。
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; }
【L-05】if (r.app != null && r.app.thread != null) { … }
r.app
和r.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) { … }
app
和app.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的后续启动流程。
本章的调用流程如下图所示:
注:
(1)由于本章对时序图中的方法介绍均参见本系列的《Activity启动流程》的第4章,所以方法编号前加上“R”表示引用自其它文章,而非本文固有的自然编号。
(2)[AMS]=ActivityManagerService。
(3)同名的重载方法调用会直接合并,其对应的方法编号也使用[#num1-#num2]的形式进行合并。
该方法的详细介绍参见本系列的《Activity启动流程》的4.2节。
该方法的详细介绍参见本系列的《Activity启动流程》的4.3节,注意与Activity启动流程唯一不同之处是hostingType
被赋值为“service”(参见上文2.4节)而不是“activity”。
该方法的详细介绍参见本系列的《Activity启动流程》的4.4节。
该方法的详细介绍参见本系列的《Activity启动流程》的4.5节。
该方法的详细介绍参见本系列的《Activity启动流程》的4.6节。
该方法的详细介绍参见本系列的《Activity启动流程》的4.7节。
本章的调用流程如下图所示:
注:
(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()对于理解执行流程具有重要意义,所以这两个方法被标注在时序图中。由于下文并没有具体对这两个方法进行分析,所以它们的方法编号为“-”。
该方法的详细介绍参见本系列的《Activity启动流程》的5.1节。
该方法的详细介绍参见本系列的《Activity启动流程》的5.2节。
该方法的详细介绍参见本系列的《Activity启动流程》的5.3节。
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 ... } ... }
【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的后续启动流程。
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 ... } } ... }
上文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
...
}
【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.startRequested
、r.callStart
和r.pendingStarts
的详细分析依次参见上文的2.2节、2.3节和2.2节。此处if语句的判断条件表示“通过startService方式启动的Service需要自动重启,并且没有为其传入新的启动参数”,该条件满足时将构造一个缺省的StartItem作为启动参数并添加到对应的pendingStarts
中,以确保最终一定会回调它的onStartCommand()
28 (具体原因将在下文4.11节中进行分析)。在本文分析的执行流程中,目标Service是通过startService方式进行“全新启动”而非自动重启,所以这个if语句的判断条件事实上并不会满足。
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
}
该方法的详细介绍参见本系列的《Activity启动流程》的3.6节。
根据消息的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;
...
}
...
}
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); ... }
【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对象的成员变量mThread
和mToken
。
【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代理对象会作为键保存在mServices
中35,从而维护同一个Service对象在AMS进程与应用进程之间的映射关系。
上文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 ... }
【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代理对象,主动通知应用进程对启动参数进行处理。
scheduleServiceArgs()
获取AMS进程通过IPC传输的启动参数,对其进行重新封装,然后利用Handler发送SERVICE_ARGS
消息。与上文4.8~4.9节类似,该消息最终由mH
的handleMessage()
进行处理。
// #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
}
}
根据消息的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;
...
}
...
}
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);
...
}
}
调用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(),从而完成启动流程。
Android中ContextImpl源码分析(二).
https://blog.csdn.net/dongxianfei/article/details/54632423 ↩︎
Android服务之startService源码分析.
https://blog.csdn.net/zhangyongfeiyong/article/details/51910578 ↩︎
Android Service生命周期,本地服务远程服务,前台服务后台服务,启动方式,与IntentService区别全面解析.
https://blog.csdn.net/qq_30993595/article/details/78452064 ↩︎
Android6.0之App的Service组件运行机制之StartService.
https://www.jianshu.com/p/fffef3f278b6 ↩︎
service的隐式启动和显示启动.
https://blog.csdn.net/cpcpcp123/article/details/52741237 ↩︎
Service流程笔记.
https://www.jianshu.com/p/ef19ae5929cf ↩︎
Android ComponentName的用法.
https://blog.csdn.net/u012532559/article/details/52766348 ↩︎
Android源码的Binder权限控制.
https://blog.csdn.net/bbmcdull/article/details/52046690 ↩︎
android IPC通信中的UID和PID识别.
https://blog.csdn.net/windskier/article/details/6921672 ↩︎
一图解惑之Android管理Service数据结构.
https://www.jianshu.com/p/1c0e908046fb ↩︎
Android 进阶 - Activity服务启动分析.
https://blog.csdn.net/szzhaom/article/details/23452939 ↩︎
Android源码的Binder权限控制.
https://blog.csdn.net/bbmcdull/article/details/52046690 ↩︎
Android 8.0 Service源码分析:启动流程及后台限制详解.
https://blog.csdn.net/zwjemperor/article/details/82949913 ↩︎
Android Service演义(android 5.1).
https://blog.csdn.net/thinkinwm/article/details/52399177 ↩︎
Android Gems — AMS的Service生命周期管理.
http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎
四大组件之ServiceRecord.
http://gityuan.com/2017/05/25/service_record/ ↩︎
Android Service重启恢复(Service进程重启)原理解析.
https://blog.csdn.net/happylishang/article/details/81776217 ↩︎
Android Gems — AMS的Service生命周期管理.
http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎
Android系统源码分析–Service启动流程.
https://www.meiwen.com.cn/subject/mzcwlftx.html ↩︎
Android系统中的进程管理:进程的优先级.
https://blog.csdn.net/omnispace/article/details/73320950 ↩︎
Android Gems — AMS的Service生命周期管理.
http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎
Android Service重启恢复(Service进程重启)原理解析.
https://cloud.tencent.com/developer/article/1199550 ↩︎
Android Gems — AMS的Service生命周期管理.
http://www.zhimengzhe.com/Androidkaifa/160730.html ↩︎
Android Service演义(android 5.1).
https://blog.csdn.net/thinkinwm/article/details/52399177 ↩︎
关于Android Service真正的完全详解,你需要知道的一切.
https://blog.csdn.net/javazejian/article/details/52709857 ↩︎
AMS (2): AMS 如何进程管理?.
https://blog.csdn.net/ccjhdopc/article/details/52795711 ↩︎
Android 8.0 Service源码分析:启动流程及后台限制详解.
https://blog.csdn.net/zwjemperor/article/details/82949913 ↩︎
Service的自动重启问题.
https://www.jianshu.com/p/1c995328c293 ↩︎
Service启动过程分析.
https://www.cnblogs.com/cr330326/p/6394071.html ↩︎
Android 插件化原理解析——插件加载机制.
https://blog.csdn.net/huangkun125/article/details/52184116 ↩︎
深入理解Android中的Context(三).
https://baijiahao.baidu.com/s?id=1584558620597480755 ↩︎
Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析.
https://blog.csdn.net/luoshengyang/article/details/8201936 ↩︎
深入理解Activity启动流程(三)–Activity启动的详细流程2.
https://blog.csdn.net/chen381051010/article/details/56844788 ↩︎
ActvitityThread中的performLaunchActivity(ActivityClientRecord r, Intent customIntent)解析.
https://blog.csdn.net/a284266978/article/details/53782453 ↩︎
Android6.0之App的Service组件运行机制介绍.
https://www.jianshu.com/p/1a5105eab7cb ↩︎
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。