0%

Service 源码分析

Android Service 简介

Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。

服务分三种类型:

  1. 前台服务:执行一些用户能注意到的操作,如播放音乐。前台服务必须显示通知。
  2. 后台服务:执行用户不会直接注意到的操作。
  3. 绑定服务:应用组件通过调用 bindService 绑定到服务。绑定服务提供客户端-服务器接口,以便组件与服务进行交互。绑定服务仅当应用组件绑定时才会启动,当全部绑定被取消时,服务会被销毁。

服务可以既是启动服务(通过 startService 启动)又是绑定服务(通过 bindService 启动),取决于是否实现 onStartCommand()onBind() 回调方法。

创建服务

如要创建服务,必须创建或使用 Service 类的子类。在实现中,必须实现一些处理服务生命周期的回调方法:

  • onStartCommand(): 当另一个组件通过 startService 请求启动服务时,系统会调用该方法。通过该方法调用的服务可以无限期运行。服务可以通过 stopSelf() 来自行停止运行。
  • onBind(): 当另一组件通过 bindService 与服务绑定时,系统会调用该方法。该方法必须返回一个 IBinder 接口,以供客户端与服务通信。
  • onCreate(): 首次创建服务时,系统会在调用 onStartCommand()onBind() 前调用此方法。如果服务已在运行,则不会调用此方法。
  • onDestroy(): 当不在使用服务并准备将其销毁时,系统会调用该方法。

创建服务后,还必须在应用清单文件中声明所有服务。

1
2
3
4
5
6
7
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>

绑定到服务

调用 bindService(Intent, ServiceConnection, int) 方法的组件必须实现 ServiceConnection 接口并将其传入 bindService。当应用组件调用 bindService 方法,系统将服务端 onBind 方法返回的 IBinder 对象传入 ServiceConnection.onServiceConnected(ComponentName, IBinder) 回调。客户端组件可通过此 IBinder 对象与客户端进行通信。

如果需要创建尚未处于活动状态的服务,则必须在 flag 参数中设置 BIND_AUTO_CREATE 标志,否则只能绑定到已经启动的服务。

服务生命周期

  1. 通过 startService 方法启动的服务:
    1. 除非通过 stopService 方法或服务自身调用 stopSelf 方法,将会无限期保持运行,即使进程被杀死也会重新启动;
    2. 如果运行过程中接收过 bindService 方法调用,必须等待所有设置 BIND_AUTO_CREATE 标志的客户端解绑,stopService 才会停止服务;
  2. 通过 bindService 方法启动的服务:
    1. 在所有 bindService 的客户端都调用 unbindService 解绑之后自动停止;
    2. 如果运行过程中接收过 startService 调用,必须调用 stopService 才会停止。

总结:startServicestopService 配对,bindServiceunbindService 配对,只有完成配对,服务才会停止运行,除非调用 stopService 时所有活跃绑定都没有设置 BIND_AUTO_CREATE。详细说明参照 Service 停止流程

PS:stopSelf 方法的限制与 stopService 相同。

源码分析

Service 启动流程

Service 启动流程

我们从 startService(Intent) 方法开始分析。这个方法的实现在 ContextImpl 类中:

1
2
3
4
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}

startForegroundService(Intent) 方法与之几乎相同,除了调用 startServiceCommon 的第二个参数 requireForegroundtrue

startServiceCommon 对 Intent 进行检查,之后调用 AMS 的 startService 方法;

AMS.startService 方法检查文件描述符泄漏和调用者之后,调用 ActiveServices.startServiceLocked 方法。

startServiceLocked

com.android.server.am.ActiveServices

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
final int userId, boolean allowBackgroundActivityStarts)
throws TransactionTooLargeException {
...
final boolean callerFg;
...... // 判断调用者是否在前台

ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}

ServiceRecord r = res.record;

if (!mAm.mUserController.exists(r.userId)) {...; return nulll;}

这一节做的事情有:

  1. 判断调用者是否在前台;
  2. 调用 retrieveServiceLocked 方法解析 service 这个 Intent,得到 ServiceLookupResult,从中取得 ServiceRecord;
  3. 处理这个服务记录的用户不存在的情况。
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
// If we're starting indirectly (e.g. from PendingIntent), figure out whether
// we're launching into an app in a background state. This keys off of the same
// idleness state tracking as e.g. O+ background service start policy.
final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid);

// If the app has strict background restrictions, we treat any bg service
// start analogously to the legacy-app forced-restrictions case, regardless
// of its target SDK version.
boolean forcedStandby = false;
if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
...
forcedStandby = true;
}

// If this is a direct-to-foreground start, make sure it is allowed as per the app op.
boolean forceSilentAbort = false;
if (fgRequired) {
final int mode = mAm.mAppOpsService.checkOperation(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
case AppOpsManager.MODE_DEFAULT:
// All okay.
break;
case AppOpsManager.MODE_IGNORED:
// Not allowed, fall back to normal start service, failing siliently
// if background check restricts that.
...
fgRequired = false;
forceSilentAbort = true;
break;
default:
return new ComponentName("!!", "foreground not allowed as per app op");
}
}

// If this isn't a direct-to-foreground start, check our ability to kick off an
// arbitrary service
if (forcedStandby || (!r.startRequested && !fgRequired)) {
// Before going further -- if this app is not allowed to start services in the
// background, then at this point we aren't going to let it period.
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
...
if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {
// In this case we are silently disabling the app, to disrupt as
// little as possible existing apps.
return null;
}
if (forcedStandby) {
// This is an O+ app, but we might be here because the user has placed
// it under strict background restrictions. Don't punish the app if it's
// trying to do the right thing but we're denying it for that reason.
if (fgRequired) {
...
return null;
}
}
// This app knows it is in the new model where this operation is not
// allowed, so tell it what has happened.
UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}

// At this point we've applied allowed-to-start policy based on whether this was
// an ordinary startService() or a startForegroundService(). Now, only require that
// the app follow through on the startForegroundService() -> startForeground()
// contract if it actually targets O+.
if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
...
fgRequired = false;
}

NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);

// If permissions need a review before any of the app components can run,
// we do not start the service and launch a review activity if the calling app
// is in the foreground passing it a pending intent to start the service when
// review is completed.

// XXX This is not dealing with fgRequired!
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
callingUid, service, callerFg, userId)) {
return null;
}

进行一系列与后台启动限制相关的检查。TODO

1
2
3
4
5
6
7
...
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));

设置 ServiceRecord,新建 StartItem 加入到其 pendingStarts 列表。这个列表包含了准备发送给服务以执行其 onStartCommand 方法的的参数。

1
2
3
4
5
6
if (fgRequired) {
// We are now effectively running a foreground service.
...
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true);
}

如果要启动前台服务,调用 AppOpsService.startOperation 方法 TODO

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
    final ServiceMap smap = getServiceMapLocked(r.userId);
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.getCurProcState() > ActivityManager.PROCESS_STATE_RECEIVER) {
// If this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
// that are starting. This is to avoid process start spam when lots
// of applications are all handling things like connectivity broadcasts.
// We only do this for cached processes, because otherwise an application
// can have assumptions about calling startService() for a service to run
// in its own process, and for that process to not be killed before the
// service is started. This is especially the case for receivers, which
// may start a service in onReceive() to do some additional work and have
// initialized some global state as part of that.
...
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
...
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
...
addToStarting = true;
} else if (proc.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
...
} ...
} ...

if (allowBackgroundActivityStarts) {
r.whitelistBgActivityStartsOnServiceStart();
}

ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
  1. 如果服务对应进程没有启动,或者正在处理接收器,延迟启动服务,以避免大量服务同时启动:
    1. 如果已经设置延迟启动,直接返回;
    2. 如果正在后台启动的服务 smap.mStartingBackground 大于上限,将当前启动服务记录设为延迟启动,并加入延迟启动清单 smap.mDelayedStartList,最后返回;
  2. 没有延迟启动的,调用 startServiceInnerLocked 继续服务启动的流程。

startServiceInnerLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
if (error != null) {
return new ComponentName("!!", error);
}

if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
...
if (first) {
smap.rescheduleDelayedStartsLocked();
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r);
}

return r.name;
}

更新 ServiceRecord 的状态,调用 bringUpServiceLocked 拉起服务。

后台启动限制:TODO

bringUpServiceLocked

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
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);
return null;
}

if (!whileRestarting && mRestartingServices.contains(r)) {
// If waiting for a restart, then do nothing.
return null;
}
...
// We are now bringing the service up, so no longer in the
// restarting state.
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}

// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
...
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}

// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
String msg = ...;
...
bringDownServiceLocked(r);
return msg;
}

// Service is now being launched, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {...}
  1. 如果 r.app != null && r.app.thread != null,表明此 Service 已经启动过,调用 sendServiceArgsLocked 方法,这个方法会执行 Service.onStartCommand 方法,之后返回;
  2. 如果 !whileRestarting && mRestartingServices.contains(r),服务正在等待重启,直接返回;
  3. 如果之前在等待重启列表,移除之,并清除正在重启状态;
  4. 如果之前设置延迟启动状态,移除之;
  5. 确认 Service 所在用户已启动,否则销毁服务;
  6. 设置 Service 所在 App 不可被 PackageManager 停止;
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
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;

if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
...
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {...}

// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
}
if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
r.definingUid);
}
}
  1. 判断服务是不是独立进程,获取 ServiceRecord 的 processName 属性,也就是清单中的 android:process 属性;
  2. 如果不是独立进程,通过进程名和 UID 获取对应的 ProcessRecord,检查用来启动这个 Service 的进程是否已存在,如果存在,调用 realStartServiceLocked 启动这个 Service 组件并返回;
  3. 如果是独立进程,尝试从 ServiceRecord 的 isolatedProc 获取当前服务的 ProcessRecord;
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
    // Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, false, isolated, false)) == null) {
String msg = ...;
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}

if (r.fgRequired) {
mAm.tempWhitelistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
}

if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}

if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);
}
}

return null;
}
  1. 如果用来启动服务的进程没有启动,调用 AMS.startProcessLocked 来启动该进程,如果启动失败则销毁服务,如果是独立进程的服务,将启动的 ProcessRecord 保存到 ServiceRecord 的 isolatedProc 成员;
  2. 如果是前台服务,加入进程到 tempWhitelist;
  3. 加入 ServiceRecord 到 mPendingServices 列表;
  4. 如果是延迟停止的服务,这里直接停止?TODO

总结下来,这个方法最主要做了三件事:

  1. 如果 Service 已经启动过,执行 Service.onStartCommand 方法;
  2. 如果此 Service 未启动,但所属进程已启动,则调用 realStartServiceLocked 进入真正启动 Service 的流程;
  3. 如果 Service 所属进程尚未启动,则先启动进程,如 app 进程启动失败则销毁此 Service ;如启动成功,则加入 mPendingServices 列表,待 App 进程启动结束后再启动 Service。此过程参见 attachApplicationLocked

realStartServiceLocked

如果 Service 所属进程已存在,启动 Service 组件。这个方法在 bindService 时也可能调用。

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
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
r.setProcess(app);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);

boolean created = false;
try {
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
mAm.appDiedLocked(app);
throw e;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);

// Cleanup.
if (newService) {
app.services.remove(r);
r.setProcess(null);
}

// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
  1. 向 ProcessRecord 添加这条 ServiceRecord;
  2. 调整 LruProcess 列表,调整进程 OomAdj,更新 ProcessRecord 中的进程状态;
  3. 调用 ActivityThread.ApplicationThread.scheduleCreateService 在目标线程初始化服务实例;
  4. 调用 ServiceReocord.postNotification(),如果是前台服务,发布通知;
  5. 如果服务拉起失败,做好清理,按情况尝试重启服务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (r.whitelistManager) {
app.whitelistManager = true;
}

requestServiceBindingsLocked(r, execInFg);

updateServiceClientActivitiesLocked(app, null, true);

if (newService && created) {
app.addBoundClientUidsOfNewService(r);
}

// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
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);
  1. 调用 requestServiceBindingsLocked,准备调用 onBind 方法;
  2. 调用 sendServiceArgsLocked,准备调用 onStartCommand 方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
    if (r.delayed) {
getServiceMapLocked(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) {
stopServiceLocked(r);
}
}
}

后台启动限制:
9. 如果之前设置了延迟启动,取消设置;
10. 如果之前设置延迟停止,调用 stopServiceLocked 停止。

ActivityThread.handleCreateService

正如 ApplicationThread 的其他 schedule 方法,scheduleCreateService 将收到的传入参数打包到 CreateServiceData 对象,向 ActivityThread 的 Handler 发送 CREATE_SERVICE 消息,Handler 收到消息后调用 handleCreateService 方法。

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
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();

LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {...}

try {
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);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {...}
} catch (Exception e) {...}
}
  1. 通过反射实例化了需要的 Service 对象;
  2. 创建用于 Service 的 ContextImpl 对象,获取 Application 对象,调用 Service.attach 方法进行绑定;
  3. 调用 Service.onCreate() 方法;
  4. 记录服务到 mServices 成员;
  5. 最后调用 AMS.serviceDoneExecuting 方法。

sendServiceArgsLocked

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
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);
if (si.intent == null && N > 1) {
// If somehow we got a dummy null intent in the middle,
// then skip it. DO NOT skip a null intent when it is
// the only one in the list -- this is to support the
// onStartCommand(null) case.
continue;
}
......
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
scheduleServiceForegroundTransitionTimeoutLocked(r);
} else {
r.fgRequired = false;
}
}
int flags = 0;
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
}

ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (...) {...}

if (caughtException != null) {
// Keep nesting count correct
final boolean inDestroying = mDestroyingServices.contains(r);
for (int i = 0; i < args.size(); i++) {
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
}
if (caughtException instanceof TransactionTooLargeException) {
throw (TransactionTooLargeException)caughtException;
}
}
}
  1. 遍历 ServiceRecord 的 pendingStarts 列表,取出其中需要使用的 StartItem:
    1. 调用 bumpServiceExecutingLocked 标记开始启动服务过程;
    2. 将其中的 Intent 保存到 args 列表,最后保存到 slice 中,
  2. 将 ServiceRecord 与之前生成的 slice 传入 ApplicationThread.scheduleServiceArgs 方法;
  3. 如果上一步捕获到异常,对 args 列表中的每个对象,调用 serviceDoneExecutingLocked 方法,保持计数正确(?TODO)

ApplicationThread.scheduleServiceArgs 遍历传入的 args 列表,向 ActivityThread 的 Handler 发送 SERVICE_ARGS 消息以及从 ServiceStartArgs 构建的 ServiceArgsData。Handler 接到消息后会调用 handleServiceArgs 方法处理。

ActivityThread.handleServiceArgs

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
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}

QueuedWork.waitToFinish();

try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {...}
} catch (Exception e) {...}
}
}
  1. 根据 data.token,也就是 ServiceRecord 对象从 mServices 获取对应的 Service 对象,这里的 Service 对象是在 handleCreateService 方法中创建并存入的;
  2. 如果没有设定 taskRemoved 标志,就执行 Service.onStartCommand 方法,否则执行 Service.onTaskRemoved 方法;
  3. 等待 QueuedWork 队列完成,调用 AMS.serviceDoneExecuting,这个方法调用 ActiveServices.serviceDoneExecutingLocked 方法。

bumpServiceExecutingLocked

处理服务启动超时,调用 scheduleServiceTimeoutLocked。TODO

serviceDoneExecutingLocked

有两个形参列表不同的重载方法:

  1. (ServiceRecord, int, int, int): 根据情况设置 ServiceRecord 和 StartItem 的一些信息;
  2. (ServiceRecord, boolean, boolean): 负责在停止服务后清除剩余的记录。

TODO

Service 绑定流程

Service 绑定流程

应用组件绑定服务从 bindService 方法开始,这个方法调用 bindServiceCommon

bindServiceCommon

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
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {...}
if (handler != null && executor != null) {...}
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
}
} else {...}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
...
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
if (res < 0) {...}
return res != 0;
} catch (RemoteException e) {...}
}
  1. 调用 LoadedApk.getServiceDispatcher 获取实现了 IServiceConnection 接口的 Binder 对象,也就是 ServiceDispatcher.InnerConnection,这个方法进一步调用 getServiceDispatcherCommon
  2. 调用 AMS 的 bindIsolatedService 方法,这个方法进一步调用 ActiveServices.bindServiceLocked 方法。

LoadedApk.getServiceDispatcher

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
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler, Executor executor, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
if (executor != null) {
sd = new ServiceDispatcher(c, context, executor, flags);
} else {
sd = new ServiceDispatcher(c, context, handler, flags);
}
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler, executor);
}
return sd.getIServiceConnection();
}
}

每个 Service 组件与 Activity 组件的绑定在 LoadedApk 类的 mService 都对应一个 ServiceDispatcher 对象。

1
2
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();
  1. 如果找到已有的 ServiceDispatcher,就返回其 InnerConnection;
  2. 如果没有,就新建一个,保存到 mService 中,返回其 InnerConnection;

bindServiceLocked

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
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {throw new SecurityException(...);}

ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
if (token != null) {
activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
if (activity == null) { return 0; }
}
...... // 权限检查
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
...

ServiceLookupResult res =
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
  1. 获取调用者对应的 ProcessRecord 和 ActivityServiceConnectionsHolder<ConnectionRecord>;
  2. 检查调用者是否在前台(callerFg),是否绑定了外部服务(isBindExternal);
  3. 获取对应的 ServiceLookupResult,取出其中的 ServiceRecord;
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
... // 如有必要,显示申请权限对话框
final long origId = Binder.clearCallingIdentity();

try {
......
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage);

IBinder binder = connection.asBinder();
s.addConnection(binder, c);
b.connections.add(c);
if (activity != null) {
activity.addConnection(c);
}
b.client.connections.add(c);
c.startAssociationIfNeeded();
...
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);

if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
  1. 获取或初始化相关变量:
    1. 调用 ServiceRecord.retrieveAppBindingLocked 方法获取 AppBindRecord;
    2. 新建 ConnectionRecord 存入连接相关信息;
    3. 从 IServiceConnection 获取对应的 IBinder 对象;
  2. 记录连接:
    1. 在 ServiceRecord 记录;
    2. 在 AppBindRecord 以及对应客户端的 ProcessRecord 中记录;
    3. mServiceConnections 列表中记录;
  3. 如果调用 bindService 方法时设置了 BIND_AUTO_CREATE 标志,表示如果绑定服务尚未运行,则进行创建,调用 bringUpServiceLocked 启动服务,如果启动失败(返回值不为 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
        if (s.app != null) {
...
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app,
(callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities())
|| (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
&& (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
b.client);
mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
}

if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {...}

// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}

getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

} finally {
Binder.restoreCallingIdentity(origId);
}

return 1;
}
  1. 更新 LruProcess 和进程 OomAdj;
  2. 如果服务已经在运行,调用 ServiceDispatcher.InnerConnection.connected 方法,最终调用 ServiceDispatcher.doConnected 方法。还记得我们在bindService调用方获取或新建了一个 ServiceDispatcher 对象,返回了其实现了 IServiceConnection 接口的成员。因此这个方法实现位于 LoadedApk.ServiceDispatcher.InnerConnection,实际上调用 LoadedApk.ServiceDispatcher.doConnected 方法。这个方法实际上是处理调用者在 ServiceConnection 中实现的回调,在这里是 onServiceConnected 回调;
  3. 否则,调用 requestServiceBindingLocked 方法,最后一个参数 rebind 表明是重新绑定还是首次绑定。

requestServiceBindingLocked

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
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
throw e;
} catch (RemoteException e) { /* 同上 */ return false; }
}
return true;
}
  1. 如果服务所在进程还没有运行,直接返回;
  2. 检查是否已经为 IntentBindRecord 对象 i 对应的应用进程请求过 Binder 本地对象,如果还没有则 i.quested = false,参数 rebind 表示是否需要将 Service 组件重新绑定到 IntentBindRecord 对象 i
  3. 如果满足条件判断,调用 ApplicationThread.scheduleBindService 方法进行绑定,该方法会调用 ActivityThread.handleBindService 方法;
  4. 如果出现异常,销毁服务。

ActivityThread.handleBindService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {...}
} catch (Exception e) {...}
}
}
  1. 如果是首次绑定,调用 onBind 方法,调用 AMS.publishService 发布服务,此方法调用 ActiveServices.publishServiceLocked 方法;
  2. 否则,调用 onRebind 方法,调用 AMS.serviceDoneExecuting 通知操作已完成。

publishServiceLocked

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
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) { continue; }
try {
c.conn.connected(r.name, service, false);
} catch (Exception e) {...}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
  1. 设置 IntentBindRecord,将 binder 赋值为 Service.onBind 返回的 Binder 对象,将 requested 设置为 true,表示已调用 onBind
  2. 遍历 ServiceRecord 中的连接记录,调用其成员 IServiceConnection connconnected 方法。
  3. 调用 ServiceDoneExecutingLocked 方法结束。

LoadedApk.ServiceDispatcher.connected

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}

private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {...}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
...
}
  1. 如果 ServiceDispatcher 是用 Executor 初始化,调用 Executor 的 execute 方法执行 RunConnection.run() 方法,这一方法最终执行 doConnected 方法;
  2. 如果是用 ActivityThread 的 Handler 初始化,调用 Handler 的 post 方法执行该方法;
  3. 如果以上两种情况都不是,直接执行 doConnected 方法。

LoadedApk.ServiceDispatcher.doConnected

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;

synchronized (this) {
if (mForgotten) {
// We unbound before receiving the connection; ignore
// any connection received.
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
return;
}
  1. 如果收到连接请求前已经 unbind,就不作处理直接返回;
  2. mActiveConnections 获取组件目前活跃的连接。如果这个组件已经持有当前服务的连接,直接返回;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    if (service != null) {
// A new service is being connected... set it all up.
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
// This service was dead before we got it... just
// don't do anything with it.
mActiveConnections.remove(name);
return;
}

} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}

if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
  1. 处理新连接:
    1. 创建新 ConnectionInfo,存入要连接的服务和死亡回调信息;
    2. 服务调用 linkToDeath 注册死亡回调;
    3. 将新的 ConnectionInfo 存入 mActiveConnections
    4. 如果发生异常,远程对象已死,则移除之前添加的 ConnectionInfo;
    5. 如果之前持有旧连接,注销旧连接的服务的死亡回调;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    // If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
}
  1. 处理 ServiceConnection 回调:
    1. 如果组件之前绑定其他服务,调用 onServiceDisconnected 回调;
    2. 如果是 bringDownService 方法调用的,dead = true,调用 onBindingDied 回调;
    3. 如果有新服务连接上,调用 onServiceConnected 回调;
    4. 否则,调用 onNullBinding 回调。

Service 解绑流程

Service 解绑流程

应用组件调用 Context.unbindService 方法解除与 Service 的绑定。

1
2
3
4
5
6
7
8
9
10
public void unbindService(ServiceConnection conn) {
if (conn == null) {...}
if (mPackageInfo != null) {
IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
getOuterContext(), conn);
try {
ActivityManager.getService().unbindService(sd);
} catch (RemoteException e) {...}
} else {...}
}

AMS.unbindService 调用 ActiveServices.unbindServiceLocked 方法。

ActiveServices.unbindServiceLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) { return false; }

final long origId = Binder.clearCallingIdentity();
try {
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r) {
clist.remove(0);
}
... // 调整 LruProcess
}
mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
} finally {
Binder.restoreCallingIdentity(origId);
}

return true;
}

主要工作是从 mServiceConnections 中找到对应的连接记录列表,对列表中的每一个连接调用 removeConnectionLocked 方法。

ActiveServices.removeConnectionLocked

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
void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
ActivityServiceConnectionsHolder skipAct) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
s.removeConnection(binder);
}
}
b.connections.remove(c);
c.stopAssociation();
if (c.activity != null && c.activity != skipAct) {
c.activity.removeConnection(c);
}
if (b.client != skipApp) {
b.client.connections.remove(c);
......
}
clist = mServiceConnections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}

mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid,
s.appInfo.longVersionCode, s.instanceName, s.processName);

if (b.connections.size() == 0) {
b.intent.apps.remove(b.client);
}

if (!c.serviceDead) {
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
bumpServiceExecutingLocked(s, false, "unbind");
... // 调整 LruProcess 和 OomAdj,又来一遍?
b.intent.hasBound = false;
// Assume the client doesn't want to know about a rebind;
// we will deal with that later if it asks for one.
b.intent.doRebind = false;
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
serviceProcessGoneLocked(s);
}
}

// If unbound while waiting to start, remove the pending service
mPendingServices.remove(s);

if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
......
bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
}
}
}
  1. 移除连接记录 ConnectionRecord:
    1. 获取 ServiceRecord 中的连接列表,从该列表中移除;
    2. 从 AppBindRecord 中移除连接记录;
    3. mServiceConnections 中移除连接记录;
    4. 如果 AppBindRecord 中记录为空了,从 b.intent.apps 中移除客户端;
  2. 如果服务还存在,调用 ApplicationThread.scheduleUnbindServie,该方法通过 Handler 调用 ActivityThread.handleUnbindService 方法;
  3. mPendingServices 中移除 ServiceRecord;
  4. 调用 bringDownServiceIfNeededLocked 方法,如果服务不再被需要,就关闭服务。

ActivityThread.handleUnbindService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
ActivityManager.getService().unbindFinished(
data.token, data.intent, doRebind);
} else {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {...}
} catch (Exception e) {...}
}
}
  1. 调用 Service.onUnbind 方法,返回值表示是否需要在新的客户端绑定到该服务时调用 onRebind 方法;
  2. 如果需要,调用 AMS.unbindFinished 方法,进一步调用 ActiveServices.unbindFinishedLocked 方法;
  3. 否则,调用 AMS.serviceDoneExecuting 方法;

ActiveServices.unbindFinishedLocked

这个方法没有用到 doRebind 参数,因为 ActivityThread 只会在 doRebind = true 时调用这个方法,因此这个方法实际上做的事情总是要求服务调用 onRebind 方法。

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
void unbindFinishedLocked(ServiceRecord r, Intent intent, boolean doRebind) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);

boolean inDestroying = mDestroyingServices.contains(r);
if (b != null) {
if (b.apps.size() > 0 && !inDestroying) {
// Applications have already bound since the last
// unbind, so just rebind right here.
boolean inFg = false;
for (int i=b.apps.size()-1; i>=0; i--) {
ProcessRecord client = b.apps.valueAt(i).client;
if (client != null && client.setSchedGroup
!= ProcessList.SCHED_GROUP_BACKGROUND) {
inFg = true;
break;
}
}
try {
requestServiceBindingLocked(r, b, inFg, true);
} catch (TransactionTooLargeException e) {
// Don't pass this back to ActivityThread, it's unrelated.
}
} else {
// Note to tell the service the next time there is
// a new client.
b.doRebind = true;
}
}

serviceDoneExecutingLocked(r, inDestroying, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
  1. 从 ServiceRecord 中获取相应的 IntentBindRecord,获取绑定和应用的当前状态;
  2. 如果应用在上次解绑之后已经重新绑定,就直接调用 requestServiceBindingLocked 方法,最后一个参数 rebind = true
  3. 否则,令 IntentBindRecord 的 doRebind = true,以通知服务有新的客户端时调用 onRebind 方法;

AMS.stopAssociationLocked

TODO

Service 停止流程

服务停止的方式

应用组件可以通过两种方式停止服务:

  1. stopService
  2. unbindService

此外,服务自身可以调用 stopSelf 停止自身。

这三种方式最终都会调用 bringDownServiceIfNeededLocked 方法。然而这种方法并不保证停止服务:服务启动完成,并且没有自动创建服务的连接(见 hasAutoCreateConnection)时,才会调用 bringDownServiceLocked 真正停止服务。

调用 stopService 停止服务

stopService -> ContextImpl.stopServiceCommon -> AMS.stopService -> ActiveServices.stopServiceLocked(IApplicationThread, Intent, String, int) -> stopServiceLocked(ServiceRecord) -> bringDownServiceIfNeededLocked

Service 停止流程

调用 unbindService 解绑最后一个客户端

unbindService -> unbindServiceLocked -> bringDownServiceIfNeededLocked

服务调用 stopSelf 停止

stopSelf -> AMS.stopServiceToken -> ActiveServices.stopServiceTokenLocked -> bringDownServiceIfNeededLocked

bringDownServiceIfNeededLocked

1
2
3
4
5
6
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
if (isServiceNeededLocked(r, knowConn, hasConn)) { return; }
if (mPendingServices.contains(r)) { return; }
bringDownServiceLocked(r);
}

isServiceNeededLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
private final boolean isServiceNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
// Are we still explicitly being asked to run?
if (r.startRequested) { return true; }

// Is someone still bound to us keeping us running?
if (!knowConn) {
hasConn = r.hasAutoCreateConnections();
}
if (hasConn) { return true; }

return false;
}

调用 stopServiceLocked(ServiceRecord) 方法时会将 startRequested 标志设为 false,因此调用 stopService实际检查的只有是否还有活跃的绑定。

ServiceRecord.hasAutoCreateConnection

1
2
3
4
5
6
7
8
9
10
11
12
13
public boolean hasAutoCreateConnections() {
// XXX should probably keep a count of the number of auto-create
// connections directly in the service.
for (int conni=connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
for (int i=0; i<cr.size(); i++) {
if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
return true;
}
}
}
return false;
}

遍历保存的连接列表,当有在 bindService 时设置了 BIND_AUTO_CREATE 标志的活跃连接,就返回 true。因此只有所有设置了 BIND_AUTO_CREATE 标志的客户端调用了 unbindService 时,服务才会停止。

bringDownServiceLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final void bringDownServiceLocked(ServiceRecord r) {
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> c = connections.valueAt(conni);
for (int i=0; i<c.size(); i++) {
ConnectionRecord cr = c.get(i);
// There is still a connection to the service that is
// being brought down. Mark it as dead.
cr.serviceDead = true;
cr.stopAssociation();
try {
cr.conn.connected(r.name, null, true);
} catch (Exception e) {...}
}
}
  1. 对所有活跃绑定,调用 ServiceDispatcher.InnerDispatcher.connected 以发送 onBindingDied 回调;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Tell the service that it has been unbound.
if (r.app != null && r.app.thread != null) {
boolean needOomAdj = false;
for (int i = r.bindings.size() - 1; i >= 0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (ibr.hasBound) {
try {
bumpServiceExecutingLocked(r, false, "bring down unbind");
needOomAdj = true;
ibr.hasBound = false;
ibr.requested = false;
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) { serviceProcessGoneLocked(r); }
}
}
if (needOomAdj) {
mAm.updateOomAdjLocked(r.app, true,
OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
}
}

  1. 如果有活跃绑定,更新 IntentBindRecord 状态,调用 ApplicationThread.scheduleUnbindService 安排解绑,调整 OomAdj;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Check to see if the service had been started as foreground, but being
// brought down before actually showing a notification. That is not allowed.
if (r.fgRequired) {
r.fgRequired = false;
r.fgWaiting = false;
...
mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
msg.obj = r.app;
msg.getData().putCharSequence(
ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
mAm.mHandler.sendMessage(msg);
}
}

TODO

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
final ServiceMap smap = getServiceMapLocked(r.userId);
ServiceRecord found = smap.mServicesByInstanceName.remove(r.instanceName);

// Note when this method is called by bringUpServiceLocked(), the service is not found
// in mServicesByInstanceName and found will be null.
if (found != null && found != r) { throw new IllegalStateException(...); }
smap.mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r, 0, true);

// Also make sure it is not on the pending list.
for (int i=mPendingServices.size()-1; i>=0; i--) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
}
}

cancelForegroundNotificationLocked(r);
if (r.isForeground) {
decActiveForegroundAppLocked(smap, r);
...
mAm.mAppOpsService.finishOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
}

r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;

// Clear start entries.
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
smap.mDelayedStartList.remove(r);
  1. 从 ServiceMap 中移除服务记录;
  2. 调用 unscheduleServiceRestartLocked 取消重启服务的安排;
  3. mPendingServices 中移除记录;
  4. 如果是前台服务,取消前台通知;
  5. 清除在 ServiceRecord.pendingStarts 队列中的参数;
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

if (r.app != null) {
...
r.app.services.remove(r);
r.app.updateBoundClientUids();
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
mAm.updateOomAdjLocked(r.app, true,
OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
r.app.thread.scheduleStopService(r);
} catch (Exception e) { serviceProcessGoneLocked(r); }
} else {...} else {...}

if (r.bindings.size() > 0) {
r.bindings.clear();
}
...
}
  1. 移除 ProcessRecord 中的记录;
  2. 加入 mDestroyingServices 列表;
  3. 调用 ApplicationThread.scheduleStopService 停止服务,跟之前类似,这个方法调用 ActivityThread.handleStopService 方法;

ActivityThread.handleStopService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void handleStopService(IBinder token) {
Service s = mServices.remove(token);
if (s != null) {
try {
s.onDestroy();
s.detachAndCleanUp();
Context context = s.getBaseContext();
if (context instanceof ContextImpl) {
final String who = s.getClassName();
((ContextImpl) context).scheduleFinalCleanup(who, "Service");
}

QueuedWork.waitToFinish();

try {
ActivityManager.getService().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {...}
} catch (Exception e) {...}
} else {...}
}
  1. 移除服务在 mServices 中的引用;
  2. 调用 Service.onDestroy 回调;
  3. 调用 Service.detachAndCleanUp ,令 mToken = null 以移除其引用;
  4. 调用 ContextImpl.scheduleFinalCleanup,最终调用 LoadedApk.removeContextRegistration,清除其对应 Context 注册的 BroadcastReceiver。
  5. 调用 AMS.serviceDoneExecuting 回调,清除剩余的服务记录。

Service 被杀重新启动的流程

Service 重启流程

应用被杀的回调

在 ContentProvider 源码分析中提到过,在 AMS.attachApplicationLocked 方法中,添加了 ActivityThread 对象的死亡回调,调用了 appDiedLocked 方法,这样 AMS 就可以在进程死亡时完成善后工作。

对于 Service 被杀后重新启动这一过程,相关的调用过程为:
appDiedLocked -> handleAppDiedLocked -> cleanUpApplicationRecordLocked -> ActiveServices.killServicesLocked

killServicesLocked

  1. 遍历 ProcessRecord 中的 services 列表,判断其中的服务是否需要重启,如果需要则调用 scheduleServiceRestartLocked 安排启动服务,否则调用 bringDownServiceLocked 将其清理干净;
  2. 如果设置传入形参 allowRestart = false,从 ProcessRecord,mRestartingServicesmPendingServices 中清除相应记录;
  3. mDestroyingServices 清除这个进程待销毁的服务记录;

AMS 发起重启服务

scheduleServiceRestartLocked

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
private final boolean scheduleServiceRestartLocked(ServiceRecord r, boolean allowCancel) {
boolean canceled = false;

if (mAm.mAtmInternal.isShuttingDown()) { return false; }

ServiceMap smap = getServiceMapLocked(r.userId);
if (smap.mServicesByInstanceName.get(r.instanceName) != r) { return false; }

final long now = SystemClock.uptimeMillis();

if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0) {
// Any delivered but not yet finished starts should be put back
// on the pending list.
......

...... // 设置 ServiceRecord 与重启服务相关变量,为服务启动加上延迟,防止大量服务同时启动

// Make sure that we don't end up restarting a bunch of services
// all at the same time.

} else {
// Persistent processes are immediately restarted, so there is no
// reason to hold of on restarting their services.
...
}

if (!mRestartingServices.contains(r)) {
r.createdFromFg = false;
mRestartingServices.add(r);
r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
}

cancelForegroundNotificationLocked(r);

mAm.mHandler.removeCallbacks(r.restarter);
mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;

return canceled;
}
  1. 排除系统关机和服务已存在的情形;
  2. 将已送达但未完成的 StartItem 放回 mPendingStarts 列表;
  3. 为服务启动加上延迟,防止扎堆启动;
  4. 将记录加入 mRestartingServices 列表;
  5. 将 ServiceRecord 的 restarter 成员 post 到 AMS 的 Handler,这是个实现了 Runnable 接口的 ServiceRestarter 对象,调用 performServiceRestartLocked 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
private class ServiceRestarter implements Runnable {
private ServiceRecord mService;

void setService(ServiceRecord service) {
mService = service;
}

public void run() {
synchronized(mAm) {
performServiceRestartLocked(mService);
}
}
}

performServiceRestartLocked 方法调用 bringUpServiceLocked 启动服务。

应用(重新)启动时带起服务

attachApplicationLocked

应用启动后,AMS.attachApplicationLocked 调用 ActiveServices.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
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
// Collect any services that are waiting for this process to come up.
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
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--;
proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
// We were waiting for this service to start, but it is actually no
// longer needed. This could happen because bringDownServiceIfNeeded
// won't bring down a service that is pending... so now the pending
// is done, so let's drop it.
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) { throw e; }
}

遍历 mPendingServices 列表,找到进程名与当前启动进程名相同的 ServiceRecord,调用 realStartServiceLocked 启动该服务。如果判断当前启动服务不再需要,调用 bringDownServiceLocked 关闭之。

Q: mPendingServices 采用 ArrayList 存储是否影响查找效率?

Q: 为什么不前置判断,直接不启动不需要的服务?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    // Also, if there are any services that are waiting to restart and
// would run in this process, now is a good time to start them. It would
// be weird to bring up the process but arbitrarily not let the services
// run at this point just because their restart time hasn't come up.
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;
}
mAm.mHandler.removeCallbacks(sr.restarter);
mAm.mHandler.post(sr.restarter);
}
}
return didSomething;
}

遍历 mRestartingServices 列表,移除 AMS 的 Handler 中延时重启服务的消息,再重新添加立即启动服务的消息。

TODO

  1. 后台启动限制的梳理
  2. 数据结构的梳理
  3. 流程图

参考文献

  1. 服务概览 | Android 开发者, https://developer.android.com/guide/components/services?hl=zh-cn
  2. Android系统源码分析–Service启动流程, http://codemx.cn/2018/04/24/AndroidOS010-Service/

源代码

1
2
3
4
5
6
7
8
9
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
frameworks/base/services/core/java/com/android/server/am/ConnectionRecord.java
frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/app/LoadedApk.java