基于 Android 7.1.1
源码分析 startService
的流程,本文为作者原创,转载请说明出处!
0 综述
我们在应用中经常会启动 Service
:
1 | startService(intent); |
这个方法最终会拉起 Service
的 onStartCommand
方法:1
2
3
4
5
public int onStartCommand(Intent intent, int flags, int startId) {
OppoLog.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
该方法有三个参数:
- Intent intent: 启动服务的
Intent
! - int flags: 启动时的额外参数,取值可以为
0
,START_FLAG_REDELIVERY
和START_FLAG_RETRY
! - int startId: 当前服务的唯一
ID
,和StopSelfResult(int startId)
配合使用!
1、下面我们来看看 onStartCommand
的 flag
参数:
- START_FLAG_REDELIVERY
- 取值:
x0001
- 解释:如果
Service
的onStartCommand
返回值是START_REDELIVER_INTENT
,当服务被杀掉,服务会重启,这时flag
会被传入这个值!
- 取值:
- START_FLAG_RETRY
- 取值:
0x0002
- 解释:当
onStartCommand
方法调用后一直没有返回时,会尝试重新去调用onStartCommand
方法,这时flag
会被传入这个值!
- 取值:
2、而 onStartCommand
有如下的返回值,这里先简单的介绍下:
- START_STICKY_COMPATIBILITY
- 取值:
0
- 取值:
- START_STICKY
- 取值:
1
- 说明:
- 如果
Service
进程启动后被杀掉了,服务被启动的状态会被保留并抛弃本次启动的Intent
,然后系统会尝试重新创建和启动一个新的服务实例! - 如果在重启期间,没有任何新的启动项
Intent
传递给Service
,那么会传递一个空的Intent
对象,所以在onStartCommand
方法中要做Intent
非空的判断!
- 如果
- 用途:
- 比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。
- 取值:
- START_NOT_STICKY
- 取值:
2
- 说明:
- 如果
Service
进程启动后被杀掉了,并且没有新的启动Intent
分发给服务,那么会移除服务被启动的状态,也不会重新创建服务,直到下一次显示地通过startService
启动服务! - 这种情况下,
onStartCommand
不会传入空的Intent
对象(因为在没有正在等待分发的 Intent 的情况下,该服务不会重启)!
- 如果
- 用途:
- 该模式比较适用于启动后需要做一些工作,但是在内存不够的情况下可以被停止,然后通过显示地再次启动去继续工作的情况!
- 一个简单的例子:从服务器获得数据的服务,通过设置一个
alarm
,间隔一定时间启动服务onStartCommand
,然后设置新的alarm
,如果服务进程被杀掉,那服务不会被触发,知道下一次alarm
触发!
- 取值:
- START_REDELIVER_INTENT
- 取值:
3
- 说明:
- 如果
Service
进程启动后被杀掉了,该Service
将会被重启,并且会将最后启动(startService
)分发过的Intent
再次通过onStartCommand
方法传递给Service
,该Intent
将会被保留用于下一次的重启分发,除非Service
调用stopSelf(int startId)
方法停止运行! - 这种情况下,
onStartCommand
也不会传入空的Intent
对象,因为服务只有在没有完成处理所有分发给它的Intent
的情况下或重启,一旦重启,就会将最后启动(startService
)分发过的Intent
再次通过onStartCommand
方法传递给服务!
- 如果
- 用途:
- 这个模式适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
- 取值:
- START_CONTINUATION_MASK 0xf
这里是 Android
文档中的对这些参数的做的简单说明,下面我们来分析 startService 的过程!
1 启动端进程
1.1 ContextWrapper.startService
1 |
|
ContextWrapper
提供了两个方法来启动 Service
,其中一个是隐藏方法:startServiceAsUser
!
mBase
是 ContextImpl
对象,继续看!
1.2 ContextImpl.startService
1 | class ContextImpl extends Context { |
ContextImpl
和 ContextWrapper
的具体关系,请看博文,这里我们不再详细说明!
mUser
表示的是当前的设备 user
!
最终,调用了 startServiceCommon
方法;
1.3 ContextImpl.startServiceCommon
1 | private ComponentName startServiceCommon(Intent service, UserHandle user) { |
validateServiceIntent
方法用用来校验启动用的 intent
是否安全:
1.3.1 ContextImpl.validateServiceIntent
1 | private void c(Intent service) { |
如果 intent
既没有设置 component
也没有设置 package
,那就要判断一下系统的版本了:
- 如果系统版本不低于
L
,那就要抛出异常,提示必须是显示启动; - 如果系统版本低于
L
,那只提示隐式启动不安全;
这里可以看出,Intent
必须要设置 component
或者 package
中的一个!
1.3.2 ContextImpl.getOpPackageName
通过 getOpPackageName
来获得启动者所在的包名:1
2
3
4
5/** @hide */
public String getOpPackageName() {
return mOpPackageName != null ? mOpPackageName : getBasePackageName();
}
这里的 mOpPackageName
是在创建 ContextImpl
的时候初始化的!
1.4 ActivityManagerP.startService
接着,通过 ActivityManagerP.startService
方法,启动服务!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeString(callingPackage);
data.writeInt(userId);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
通过 binder
进程间通信,进入系统进程,参数分析:
IApplicationThread caller
: 调用者进程的ApplicationThread
对象,实现了IApplicationThread
接口;Intent service
: 启动的intent
String resolvedType
: 这个intent
的MIME
类型;String callingPackage
: 启动者所属包名;int userId
: 设备用户id
;
2 系统进程
接下来,进入系统进程的 ActivityManagerService
中!
首先要进入 ActivityManagerN.onTransact
方法!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18case START_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
String callingPackage = data.readString();
int userId = data.readInt();
//【1】继续 startService!
ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
reply.writeNoException();
ComponentName.writeToParcel(cn, reply);
return true;
}
2.1 ActivityManagerS.startService
1 |
|
mServices
是 ActivityManagerService
的一个内部管理对象,用于管理所有的 Service
!
2.2 ActiveServices.startServiceLoced
参数和前面保持一致!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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
//【1】判断是否是前台调用!
final boolean callerFg;
if (caller != null) {
// 获得调用者进程的 ProcessRecord 对象!
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
//【2】检索要启动的服务的信息!
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
//【3】获得要启动的服务的数据对象:ServiceRecord!
ServiceRecord r = res.record;
// 如果服务所属的设备用户不存在,直接返回!
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
return null;
}
//【4】如果服务还没有被请求启动,要先判断服务是否允许在后台启动,如果不允许就直接返回!
if (!r.startRequested) {
final long token = Binder.clearCallingIdentity();
try {
final int allowed = mAm.checkAllowBackgroundLocked(
r.appInfo.uid, r.packageName, callingPid, true);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage);
return null;
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
//【5】如果启动者属于前台应用,并且启动服务组件是需要校验权限,就需要弹出权限校验界面!
// 只有权限校验成功,才会继续启动!
if (Build.PERMISSIONS_REVIEW_REQUIRED) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
callingUid, service, callerFg, userId)) {
return null;
}
}
//【6】取消服务重启的任务!
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
//【7】设置服务 ServiceRecord 的属性值;
r.lastActivity = SystemClock.uptimeMillis();
// 设置 startRequested 为 true,表示被请求启动!
r.startRequested = true;
// 设置 delayedStop 为 false;表示服务没有被延迟停止,只对后台服务有效!
r.delayedStop = false;
// 将本次启动需要的数据,包括 intent,封装成 StartItem,保存到 pendingStarts 列表中!
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
// 获得 userId 下的所有 Service 的 Map 集合!
final ServiceMap smap = getServiceMap(r.userId);
// 表示是否将服务添加到后台启动列表中;
boolean addToStarting = false;
//【8】对于后台启动的服务,需要做一些条件判断,看是延迟启动,还是立刻后台启动!
if (!callerFg && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
// 获得被启动的服务所在进程的 ProcessRecord 数据对象!
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
// 下面判断当前启动服务的进程状态来确定是否需要延时启动这个服务!
// 对于非前台的启动,尝试延迟启动服务!
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+ r + " in " + proc);
if (r.delayed) {
// 如果该服务已经延迟启动,说明他已经被加入到了 smap.mDelayedStartList 列表中等待启动,直接返回!
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
// 当同一时间正在后台启动的服务数超过了最大后台启动服务数,延迟启动!
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
// 就要将该服务加入 smap.mDelayedStartList 中;
smap.mDelayedStartList.add(r);
// 设置其 r.delayed 为 true!
r.delayed = true;
return r.name;
}
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
addToStarting = true;
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) { // 和 debug 相关,只是输出一些 log 信息!
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
.append(' ').append(proc.adjType);
String reason = proc.makeAdjReason();
if (reason != null) {
sb.append(' ');
sb.append(reason);
}
sb.append("): ");
sb.append(r.toString());
Slog.v(TAG_SERVICE, sb.toString());
}
} else if (DEBUG_DELAYED_STARTS) {
// 和 debug 相关,只是输出一些 log 信息!
if (callerFg) {
Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + "): " + r);
} else if (r.app != null) {
Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
} else {
Slog.v(TAG_SERVICE,
"Not potential delay (user " + r.userId + " not started): " + r);
}
}
//【9】进一步调用!
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
该方法的主要流程:
- 判断是前台启动,还是后台启动;
- 检索需要启动的服务的信息;
- 如果不满足启动条件就取消本次启动;
- 创建本次启动对应的启动项;
- 对于后台启动的服务,需要判读是否延迟启动;
- 进一步启动服务!
如何判断后台启动的服务是否需要延迟启动呢,依据如下:
这个地方会对进程的状态做一个判断:
- 如果是前台进程的调度,就直接进行启动;
- 如果是后台进程的调度,就要先判断一下,是否延迟执行;
对于如何判断进程是否是前台进程,还是后台进程,我会在另外一篇文章中说明!!
2.2.1 ActiveServices.unscheduleServiceRestartLocked
这里有一个方法,取消上一次的重启任务,参数传入:
- boolean force:传入 false!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid,
boolean force) {
if (!force && r.restartDelay == 0) {
return false;
}
//【1】将服务从重启列表中移除!
boolean removed = mRestartingServices.remove(r);
if (removed || callingUid != r.appInfo.uid) {
// 清空 restartCount,restartDelay,restartTime!
r.resetRestartCounter();
}
if (removed) {
// 让 restartTracker 对 ServiceRecord 重新监控!
clearRestartingIfNeededLocked(r);
}
//【2】移除重启任务!
mAm.mHandler.removeCallbacks(r.restarter);
return true;
}
这里有一个数据结构:r.restarter,他是在创建 ServiceRecord 时传入的,他是一个 ServiceRestarter 对象!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16private class ServiceRestarter implements Runnable {
private ServiceRecord mService;
void setService(ServiceRecord service) {
mService = service;
}
public void run() {
synchronized(mAm) {
//【1】执行重启操作!
performServiceRestartLocked(mService);
}
}
}
我们再去看看 performServiceRestartLocked 方法,是如何实现服务的重启的!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21final void performServiceRestartLocked(ServiceRecord r) {
//【1】mRestartingServices 没有当前服务,无法执行重启!
if (!mRestartingServices.contains(r)) {
return;
}
//【2】不需要重启服务!
if (!isServiceNeeded(r, false, false)) {
Slog.wtf(TAG, "Restarting service that is not needed: " + r);
return;
}
try {
//【3】再次拉起服务!!
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
} catch (TransactionTooLargeException e) {
// Ignore, it's been logged and nothing upstack cares.
}
}
用于执行重启操作,这里我们只是简单地看看!
2.3 ActiveServices.startServiceInnerLocked
接下来,进一步地启动服务,如果 addToStarting 为 true,表示该服务是后台启动的,需要将其添加到 mStartingBackground 集合中!
1 | ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, |
对于前台启动的方式:callerFg
为 true
,addToStarting
为 false
,就会执行 ensureNotStartingBackground
取消服务后台启动!
对于后台启动的方式:callerFg
为 false
,addToStarting
为 true
,就会将服务添加到 mStartingBackground
集合中!
2.3.1 ServiceMap.rescheduleDelayedStart
对于后台启动的方式,如果 mStartingBackground.size() == 0
,那就需要对延迟启动的调度做一次初始化,我们先来看看 rescheduleDelayedStarts
方法!
1 | void rescheduleDelayedStarts() { |
我们看到,对于延迟后台启动的服务,最后又会调用 startServiceInnerLocked
后台启动,然后,该服务会被添加到 mStartingBackground
列表中,表示正在启动,这个我们后面会分析到!
该方法的主要作用是:
- 移除
mStartingBackground
中已经启动超时的服务; - 如果后台启动的服务数小于最大允许后台启动的服务数,且
mDelayedStartList
中有延迟启动的服务,就立刻启动并移除mDelayedStartList
中的服务,然后将其添加到mStartingBackground
列表中! - 设置后台启动的超时处理!
- 发送那些等待后台服务启动的后台广播!
这里要简单的说一下 ServiceMap:
ServiceMap
是 Handler
的子类,其内部封装了指定设备用户所有的服务信息对象,还有后台启动的服务对象列表 mStartingBackground
,以及延迟后台启动的服务对象列表 mDelayedStartList
!
其本身是 Handler
,用于处理 MSG_BG_START_TIMEOUT
消息:1
2
3
4
5
6
7
8
9
10
11
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BG_START_TIMEOUT: {
synchronized (mAm) {
//【1】
rescheduleDelayedStarts();
}
} break;
}
}
ServiceMap
收到该消息后,会再次触发 rescheduleDelayedStart
方法,该内部又会发送 MSG_BG_START_TIMEOUT
消息,这样就会不断的循环发送 MSG_BG_START_TIMEOUT
消息,不断的处理 mDelayedStartList
和 mStartingBackground
列表,保证所有的后台延迟启动的服务能够即使启动,同时设置后台启动的超时处理!
2.3.2 ServiceMap.ensureNotStartingBackground
对于前台启动的方式,就需要更新 mStartingBackground
和 mDelayedStartList
集合中的元素了,尝试将当前的服务从这两个集合中删除,因为这里是前台启动,我们继续看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16void ensureNotStartingBackground(ServiceRecord r) {
//【1】从 mStartingBackground 中删除当前服务;
if (mStartingBackground.remove(r)) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"No longer background starting: " + r);
//【1.1】再次启动后台延迟服务的调度!
rescheduleDelayedStarts();
}
//【2】从 mDelayedStartList 中删除当前服务;
if (mDelayedStartList.remove(r)) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
}
}
首先是尝试从 mStartingBackground
中删除当前服务,如果删除成功,就要再次调用 rescheduleDelayedStarts
方法,尝试后台启动被延迟后台启动的服务,并再次发送 MSG_BG_START_TIMEOUT
消息!
2.3.3 阶段总结
对于立刻后台启动的服务 r
,启动时,都会被添加到 mStartingBackground
列表中,并且设置 r.startingBgTimeout
后台启动超时时间为 now + 15s
;每个后台启动的服务 r
,当其 r.startingBgTimeout
时间到了后,会从 mStartingBackground
列表中删除;
对于延迟后台启动的服务 r
,都会添加到 mDelayedStartList
列表中,并且设置 r.delayed
为 true
,每个延迟后台启动的服务的启动都依赖于一个条件:mStartingBackground.size() < mMaxStartingBackground
;
通过上面的分析,我们可以知道 rescheduleDelayedStarts
和 ensureNotStartingBackground
作用是什么了:
就是不断处理 mStartingBackground
中的服务,不断的根据 mStartingBackground
中服务的 r.startingBgTimeout
发送 MSG_BG_START_TIMEOUT
消息,不断的处理该消息,删除对应的服务,使得 mStartingBackground.size() < mMaxStartingBackground
,为 mDelayedStartList
中的服务腾出位置,保证这些延迟后台启动的服务能够后台启动!
2.4 ActiveServices.bringUpServiceLocked
下面我们来看看,系统进程是如何拉起 Serivce 的,传入参数分析:
- ServiceRecord r:服务的 ServiceRecord 对象;
- int intentFlags:启动服务的 intent 的 flag,通过 getFlags 获得;
- boolean execInFg:传入 callFg,表示本次启动是前台调用还是后台调用;
- boolean whileRestarting:表示是否是正在重启,传入 false;
- boolean permissionsReviewRequired:false;
1 | private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, |
我们来总结一下,这个方法的流程:
第一阶段:
- 如果服务所在的进程已经启动,就调用
sendServiceArgsLocked
,通过ApplicationThread
拉起onStartCommand
的方法,结束流程; - 如果服务所在的进程没有被启动,进入下面的流程:
第二阶段:
- 如果服务正在等待重启,不处理,结束流程;
- 否则,进入下面的流程:
第三阶段:
- 当前服务要被启动了,就从等待重启
mRestartingServices
中移除它; - 如果这个服务是被延迟启动(
delayed
的值为true
)的,就从mDelayedStartList
中移除它,并置其delayed
为false
; - 当前服务将要被启动,所以要设置其
package
的停止状态为false
; - 判断这个进程是否是隔离进程:
- 如果是非隔离进程,根据进程名和
uid
,获得其所在进程的ProcessRecord
对象,如果进程已经启动,就启动指定服务,结束流程; - 如果是隔离进程,获得服务之前所在的隔离进程的
ProcessRecord
对象;
- 如果是非隔离进程,根据进程名和
第四阶段:
- 根据获得的
ProcessRecord
对象,判断,如果之前服务所在进程没有启动,就需要先启动进程; - 将服务添加到
mPendingServices
中,表示正在启动该服务;
之前我们有说,我们假设要启动的服务所在的进程没有被启动,那么就要先启动目标进程,具体的启动过程,大家可以去看我的其他几篇博客:
Android 进程的创建和启动
这里我们直接用之前的结果,进入 AMS.attachApplicationLocked
方法!
2.5 ActivityManagerS.attachApplicationLocked
当应用进程启动后,会通过 Binder 通信,调用 AMS.attachApplicationLocked,我们去看看: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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
... ... ... ...
// 这里会回到应用进程中,创建 Applicaiton 对象,并调用其 onCreate 方法,这里我们先不说!
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
// 更新进程 LRU 队列!
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
// 每当 bind 操作失败,则重新启动进程, 此处有可能会导致进程无限重启。
startProcessLocked(app, "bind fail", processName);
return false;
}
// 将当前已经被启动的新进程的 ProcessRecord 从正在启动的进程集合 mPersistentStartingProcesses
// 和等待启动的进程集合 mProcessesOnHold 中移除!
mPersistentStartingProcesses.remove(app);
mProcessesOnHold.remove(app);
boolean badApp = false;
boolean didSomething = false;
... ... ... ...
if (!badApp) {
try {
// 检查是否有 sevvce 组件要在这个新进程中运行!
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
... ... ... ...
if (badApp) { // badApp 为 true,就杀掉这个进程
app.kill("error during init", true);
handleAppDiedLocked(app, false, true);
return false;
}
if (!didSomething) { // 检查后发现,没有任何组件要运行在新进程,更新 OomAdj 的值!
updateOomAdjLocked();
}
return true;
}
bindApplication
方法会回到应用进程中,创建 Applicaiton
对象,并调用其 onCreate
方法,这里我们不看!
这里会调用 ActiveServices
的 attachApplicationLocked
方法!
2.6 ActiveServices.attachApplicationLocked
当应用进程启动成功,并且 Application 对象已经创建,其 onCreate 方法已经调用后,就要启动指定的服务了!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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
//【1】启动该进程中所有的服务!
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
// 遍历 mPendingServices 集合中的所有服务,启动属于这个进程的所有服务!
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;
}
mPendingServices.remove(i);
i--;
// 将服务的包名,版本号以及 AMS 的进程状态对象保存到进程对象中!
proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
mAm.mProcessStats);
//【1】启动服务,这里又回到了之前的方法中!
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeeded(sr, false, false)) { // 如果已经不需要启动了,就取消启动!
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
throw e;
}
}
//【2】接着启动那些需要重启的服务,重启的服务都会保存到 mRestartingServices 服务中!
// 因为重启的时间可能还没有到,所以这里并不是立刻启动它们,而是启动了一个任务,交给了 AMS 的 MainHandler 去做!
if (mRestartingServices.size() > 0) {
ServiceRecord sr;
for (int i=0; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
// sr.restarter 是一个 ServiceRestarter 对象,是一个 Runnable,这里会执行重启!
mAm.mHandler.removeCallbacks(sr.restarter);
mAm.mHandler.post(sr.restarter);
}
}
return didSomething;
}
这里有一个方法 isServiceNeeded
是否需要启动服务:1
2
3
4
5
6
7
8
9
10
11
12
13
14private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
if (r.startRequested) {
return true;
}
if (!knowConn) {
hasConn = r.hasAutoCreateConnections();
}
if (hasConn) {
return true;
}
return false;
}
判断依据很简单:
r.startRequested
为true
,说明服务被请求启动,那么就需要;r.hasAutoCreateConnections
为true
;说明有应用已经和该服务建立了自动创建的连接,那么就需要;
我们发现无论进程是否已经被创建,最终都会调用 realStartServiceLocked
方法!
2.7 AS.realStartServiceLocked
通过调用 realStartServiceLocked 方法来启动进程中的指定服务: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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
// 设置服务的进程对象;
r.app = app;
// 设置服务的启动和活跃时间;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
// 将被启动服务的 ServiceRecord 对象添加到所属进程的 app.services 中!
final boolean newService = app.services.add(r);
//【1】针对 onCreate 方法,设置超时处理!
bumpServiceExecutingLocked(r, execInFg, "create");
// 更新 LruProcess 和 OomAdj!
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();
boolean created = false;
try {
if (LOG_SERVICE_START_STOP) { // log 相关!
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
}
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
// 将进程的状态更新为 ActivityManager.PROCESS_STATE_SERVICE!
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//【2】通过 binder 通信,拉起服务的 onCreate 方法!
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
// 如果服务通过 setForeground 方法设置了通知,就显示通知!
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app); // 如果在服务启动时,应用进程死了,调用 appDiedLocked 通知死亡仆告对象!
throw e;
} finally {
if (!created) { // 如果启动失败,并且不死一个被销毁的服务,那就尝试重启他!
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.services.remove(r);
r.app = null;
}
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
// 拉起 onBind 相关的方法,但是这里是不会触发的,因为 r.bindings 集合只有在 bindService 才会有元素!
// 但是,如果之前 bindService 的标志位设置的不是 Context.BIND_AUTO_CREATE,而是其他参数,那么其 r.bindings
// 是有元素的,这里才会调用服务的 onBind 方法,为之前的 bindService 返回代理对象!
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
// 如果服务被请求启动,但是其内部的启动项为 0,那就创建一个启动项,保证 Service 的 onStartCommand 可以被调用;
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
//【2】通过 binder 通信,拉起服务的 onStartCommand 方法!
sendServiceArgsLocked(r, execInFg, true);
// 如果是延迟启动的话,在这里将其移除!
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
这里要注意:
方法 requestServiceBindingsLocked
,一般是不会触发的,因为 r.bindings
集合只有在 bindService
的情况才会被添加元素!但是,如果之前 bindService
的标志位没有设置 Context.BIND_AUTO_CREATE
,而是其他标志位,那么其 r.bindings
是有元素的,这里就会调用服务的 onBind
方法,为之前的 bindService
返回代理对象!
2.7.1 AS.bumpServiceExecutingLocked
针对 onCreate
方法,设置超时处理,参数 fg
表示这个服务是前台执行,还是后台执行的!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
39
40
41
42
43
44private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
+ why + " of " + r + " in app " + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
+ why + " of " + r.shortName);
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) { // executeNesting 用来记录是否有超时处理操作!
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
// 对该服务进行内存监控处理!
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
// 将服务添加到 ProcessRecord 的 executingServices 集合中,表示服务正在执行某段代码!
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
// 如果正在执行指定函数的服务个数为 1,设置超时处理!
if (r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
scheduleServiceTimeoutLocked(r.app);
}
r.executeFg |= fg;
r.executeNesting++;
// 记录启动时间!
r.executingStart = now;
}
我们来看看超市处理的操作!
2.7.1.1 AS.scheduleServiceTimeoutLocked
1 | void scheduleServiceTimeoutLocked(ProcessRecord proc) { |
可以看到:
- 对于前台服务:超时时间是 20s
- 对于后台服务:超市时间是 200s
最后发送 SERVICE_TIMEOUT_MSG 消息到 AMS 的 MainHandler 中!
2.7.1.2 ActivityServiceS.MainHandler
1 | final class MainHandler extends Handler { |
接着进入 ActiveServices 中!
2.7.1.3 ActiveServices.serviceTimeout
1 | void serviceTimeout(ProcessRecord proc) { |
我们可以看到,判断启动服务是否超时:不断的给 AMS 的 MainHandler 发送 SERVICE_TIMEOUT_MSG 消息,不断的判断时间是否超时!
如果超时的话,会触发 AppErrors.appNotResponding 方法,这个我们以后再看!
2.7.2 ApplicationThreadP.scheduleCreateService
拉起其 onCreate 方法,参数说明:
- IBinder token:服务的 ServiceRecord 对象,实现了 IBinder 接口!
- erviceInfo info:服务的组件信息;
- CompatibilityInfo compatInfo:
- int processState:服务所在进程的状态;
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
27class ApplicationThreadProxy implements IApplicationThread {
public final void scheduleCreateService(IBinder token, ServiceInfo info,
CompatibilityInfo compatInfo, int processState) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
info.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
data.writeInt(processState);
try {
// 通过 binder 通信!
mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
} catch (TransactionTooLargeException e) {
Log.e("CREATE_SERVICE", "Binder failure starting service; service=" + info);
throw e;
}
data.recycle();
}
}
binder 通信,进入应用进程!
2.7.3 AS.sendServiceArgsLocked
拉起其 onStartCommand 方法:
参数传递:
- ServiceRecord r:被启动的服务的数据对象,它实现了 Binder 接口,可以跨进程传递;
- boolean execInFg:callFg,表示本次启动是前台调用还是后台调用;
- oomAdjusted:传入 false;
1 | private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg, |
可以看到,如果服务所在的进程已经被启动了,那就直接调用 sendServiceArgsLocked
方法,通过服务所属进程在系统进程中的 Binder
对象 ApplicationThreadProxy
,通过 Binder
间通信,调用应用进程的 ApplicationThread
的 scheduleServiceArgs
对象,拉起指定服务的 onStartCommand
方法;
2.7.3.1 ApplicationThreadP.scheduleServiceArgs
拉起 onStartCommand 方法,参数说明:
IBinder token
:服务的ServiceRecord
对象,实现了IBinder
接口!boolean taskRemoved
:启动项的taskRemoved
;int startId
:启动项的id
,用来表示本次启动的id
值!int flags
:Intent args
:启动项用的intent
,用来启动Service
!
1 | class ApplicationThreadProxy implements IApplicationThread { |
binder 通信,进入应用进程!
3 被启动者进程
在之前的进程启动分析中,当进程被拉起后,应用进程会创建进程的 ActivityThread
对象,用于托管进程的主线程,组件信息,ApplicationThread
对象等等的信息!
首先会进入 ApplicationThreadNative.onTransact
方法!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
39
40
41
42
43
44
45
46
47
48
49/** {@hide} */
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
// 拉起 onCreate 方法!
case SCHEDULE_CREATE_SERVICE_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data);
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
int processState = data.readInt();
// 继续来看!
scheduleCreateService(token, info, compatInfo, processState);
return true;
}
// 拉起 onStartCommand 方法!
case SCHEDULE_SERVICE_ARGS_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
boolean taskRemoved = data.readInt() != 0;
int startId = data.readInt();
int fl = data.readInt();
Intent args;
if (data.readInt() != 0) {
args = Intent.CREATOR.createFromParcel(data);
} else {
args = null;
}
// 继续来看!
scheduleServiceArgs(token, taskRemoved, startId, fl, args);
return true;
}
}
}
接下来,进入 binder 通信服务端 ApplicationThread!
3.1 ApplicationThread.scheduleCreateService
1 | private class ApplicationThread extends ApplicationThreadNative { |
可以看到,最后会调用 sendMessage 方法,将消息 H.CREATE_SERVICE 发送给进程的主线程!
3.2 ApplicationThread.scheduleServiceArgs
1 | private class ApplicationThread extends ApplicationThreadNative { |
可以看到,最后会调用 sendMessage 方法,将消息 H.SERVICE_ARGS 发送给进程的主线程!
3.3 ApplicationThread.H
1 | private class H extends Handler { |
这里省略了其他消息的处理!
最后分别调用:handleCreateService 和 handleServiceArgs 拉起指定的方法!
3.3.1 ApplicationThread.handleCreateService
1 | private void handleCreateService(CreateServiceData data) { |
接着,进入了 Service 的 onCreate 方法中:
3.3.1.1 service.onCreate
1 | public abstract class Service extends ContextWrapper implements ComponentCallbacks2 { |
注意这个 mToken, 它在系统进程对应着的是服务的 ServiceRecord 对象,之前在系统进程通过 ApplicationThreadP 传递对象的时候,会将 ServiceRecord 通过 binder 通信传递过来!
3.3.2 ApplicationThread.handleServiceArgs
1 | private void handleServiceArgs(ServiceArgsData data) { |
3.3.2.1 service.onStartCommand
1 | public int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) { |
最后进入了 Service 的 onStartCommand 方法!
3.4 ActivityManagerP.serviceDoneExecuting
当服务的指定方法被拉起后,会通知 AMS,拉起操作执行成功,代码如下:1
2
3
4
5
6
7// 通知 AMS,拉起 onCreate 操作完成;
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
// 通知 AMS,拉起 onStart 操作完成;
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
这里进入 ActivityManagerP:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public void serviceDoneExecuting(IBinder token, int type, int startId,
int res) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeInt(type);
data.writeInt(startId);
data.writeInt(res);
mRemote.transact(SERVICE_DONE_EXECUTING_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
}
这里再次进入系统进程,我们去看看发生了什么!!
4 系统进程
接下来,进入系统进程,处理反馈结果,首先要进入 ActivityManagerN.onTransact 方法!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15case SERVICE_DONE_EXECUTING_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
int type = data.readInt();
int startId = data.readInt();
int res = data.readInt();
// 进入 AMS!
serviceDoneExecuting(token, type, startId, res);
reply.writeNoException();
return true;
}
4.1 ActivityManagerS.serviceDoneExecuting
1 | public void serviceDoneExecuting(IBinder token, int type, int startId, int res) { |
继续看!
4.2 ActiveServices.serviceDoneExecutingLocked
- 对于拉起 onCreate 方法,type 的值为 SERVICE_DONE_EXECUTING_ANON;
- 对于拉起 onStartCommand 方法,type 的值为 SERVICE_DONE_EXECUTING_START;
1 | void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) { |
findDeliveredStart 方法用于从 ServiceRecord 的 deliveredStarts 集合中返回指定 id 的启动项,如果 remove 为 true,也要移除指定 id 的启动项!
1 | public StartItem findDeliveredStart(int id, boolean remove) { |
这里我们来看看 Service
的 onStartCommand
方法的返回值的处理总结:
- START_STICKY:
- START_STICKY_COMPATIBILITY:
- 删除本次启动的
startId
对应的启动项; - 设置服务的
stopIfKilled
为false
;
- 删除本次启动的
- START_NOT_STICKY:
- 删除本次启动的服务的
startId
对应的启动项; - 如果最后一次启动的启动项的
id
(lastStartId) 等于本次启动的启动项的id
;- 设置服务的
stopIfKilled
为true
;
- 设置服务的
- 删除本次启动的服务的
- START_REDELIVER_INTENT:
- 不删除本次启动的
startId
对应的启动项; - 如果本次启动的启动项不为 null;
- 设置启动项的
deliveryCount
为0
; - 设置启动项的
doneExecutingCount
加1
; - 设置服务的
stopIfKilled
为true
;
- 设置启动项的
- 不删除本次启动的
那么,如果服务被启动后,因为一些原因,所在的进程被杀掉了,那么系统会根据服务以上的属性对服务进行重启!
这里的 r.stopIfKilled
属性在 AS.killServicesLocked
的方法中会处理,用于判断服务在被 kill
掉后,是否被重启起!对于 Service
的重启,我会在另外一篇博文中分析,尽情期待!
4.3 ActiveServices.serviceDoneExecutingLocked
我们继续看,参数传递:
boolean inDestroying
:服务正在被销毁!boolean finishing
:服务正在完成!
因为这里是刚刚启动服务,所以传入均为 false;
1 | private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, |
这里会让 AMS 的 MainHandler 不再处理超时的消息!
5 总结
到这里,startService 的启动流程就分析完了,我们来回顾一下!!
6.1 数据结构总结
我们先来看看,在 start 流程中,会涉及到的一些重要的数据结构,以及他们之间的关系!
6.1.1 ProcessRecord
启动者和被启动者所在进程的信息对象;1
2
3
4
5int curProcState // 表示当前进程的状态,可以通过其来判断是否是前台进程调度,还是后台进调度
int setSchedGroup // 进程的最新状态
ArraySet<ServiceRecord> services // 运行在这个进程中的所有服务
ArraySet<ServiceRecord> executingServices // 当前正在执行某段代码逻辑的服务列表,比如正在拉起 onCreate 等
属性解释:
6.1.2 ActivieServices
用来保存和管理系统中所有活跃的 Service!1
2
3
4
5 SparseArray<ServiceMap> mServiceMap // 所有设备用户下的 Service 集合,key 为 userId,value 是 ServiceMap 类型的实例;
ArrayList<ServiceRecord> mRestartingServices // 因为 CRASH 需要重启的 ServiceRecord 集合!
ArrayList<ServiceRecord> mDestroyingServices // 进程被销毁的 ServiceRecord 集合!
ArrayList<ServiceRecord> mPendingServices // 所有正在启动的 ServiceRecord 集合
属性解释:
6.1.3 ServiceMap
是 Handler 的子类,用来保存制定 userId 目录下的所有 ServiceRecord!
1 | int mUserId: // 指定的 uid |
属性解释:
6.1.4 ServiceRecord
要启动的 Service 的数据对象!
1 | ServiceInfo serviceInfo // 该服务的解析信息,来自 PMS |
属性解释:
- r.pendingStarts:AS 会把启动相关的信息封装成一个 StartItem,保存到 pendingStarts 中!
- r.delayed:于后台启动的方式,如果 ServiceMap.mStartingBackground 的大小超过 mMaxStartingBackground 的话,会被置为 true,同时,将 ServiceRecord 添加到 ServiceMap.mDelayedStartList 中!
6.1.5 StartItem
这是一个启动项,封装一次 startService
的数据
1 | final ServiceRecord sr; // 要启动的服务 |
属性解释:
6.1.6 ServiceRestarter
这是 Runnable
对象,用于处理服务的重启!
1 | ServiceRecord mService // 对应的服务! |
属性解释:
6.1.7 CreateServiceData
ActivityThread
的内部类,用于封装拉起 onCreate
方法的数据:1
2
3
4IBinder token; // ServiceRecord 对象
ServiceInfo info;
CompatibilityInfo compatInfo;
Intent intent;
属性解释:
6.1.8 ServiceArgsData
ActivityThread
的内部类,用于封装拉起 onStartCommand
方法的数据:
1 | IBinder token; // ServiceRecord 对象 |
属性解释:
6.2 生命周期总结
startService 方法周期很简单:1
Serice.onCreate()(once) -> Service.onStartCommand()(more)
6.3 流程总结
下面是整个过程的 UML 序列图:
(我先填个坑,毕竟画图太累)
我们来看一下,这里面的一些细节:
- 如果多次调用
startService
,只有第一次会拉起服务的onCreate
方法,因为r.app
和r.app.thread
为null
,r.app
是在创建Serivce(onCreate)
时被赋值的,多次调用StartService
,会直接进入sendServiceArgsLocked
方法,拉起服务的onStartCommand
方法; onCreate
方法的startId
为0
,onStartCommand
方法的startId
从1
开始,一次递增!- 如果服务启动后,因为内存不足等情况,被杀掉了,那么系统会重启该服务,如果在重启之前,用户通过
startService
再次启动了服务,那么就会取消之前的重启任务!(r.restartDelay
是在设置服务重启任务时设置的,我们后面再看) onStartCommand
方法的返回值有多个,这些返回值会影响Serivce
的重启,请看Service reStart
流程处理的分析,这里就不再多说了!