文中的源代码版本为api23
Service启动流程
启动Service的方式有两种:startService
、bindService
startService
先祭上一张流程图看个大概
此图省略了一些进程间通信的细节,同时假设Service
进程已经启动
Context.startService
会经历以下调用链 Context.startService
-> ContextImpl.startService
-> ContextImpl.startServiceCommon
ContextImpl.startServiceCommon
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
//做一些校验,如Android L版本及以上不允许隐式Intent启动Service
validateServiceIntent(service);
service.prepareToLeaveProcess();
//调用AMS的startService
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
//一些异常判断
}
return cn;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
复制代码
该方法最核心的作用是将启动Service
的请求通过IPC
发送给了AMS
AMS
接收到请求之后会经历以下方法调用 ActivityManagerService.startService
-> ActiveService.startServiceLocked
ActiveService.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service,
String resolvedType,//mimetype
int callingPid, int callingUid, String callingPackage, int userId)
throws TransactionTooLargeException {
//...
//记录启动Service的进程是否处于前台
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
//...
}
callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
} else {
callerFg = true;
}
//根据Intent信息查找ServiceLookupResult
//ServiceLookupResult由ServiceRecord以及Service对应的permisson组成
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg);
//...
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
//保存请求数据,服务启动之后会遍历pendingStarts,取出StartItem
//拿里面的数据触发Service.onStartCommand
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
//ServiceMap与userId一一对应,保存服务信息
final ServiceMap smap = getServiceMap(r.userId);
//是否添加到服务启动列表中
//只有是后台进程发起调用,且目标进程未启动或者state>=PROCESS_STATE_SERVICE
//才为true
boolean addToStarting = false;
//延迟启动的判断
if (!callerFg//调用方处于后台,可能会延迟启动Service
&& r.app == null //ServiceRecord未被分配进程
&& mAm.mStartedUsers.get(r.userId) != null) {
//获取应用进程实例
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
//...
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
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;
//...
} else if (DEBUG_DELAYED_STARTS) {
//debug信息
}
} else if (DEBUG_DELAYED_STARTS) {
//debug信息
}
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
复制代码
ServiceMap
这个结构用于保存用户当前运行的服务信息,retrieveServiceLocked
方法逻辑就是通过Intent
从ServiceMap
中查找Service
,如果当前服务还未启动,那么会创建一个ServiceRecord
对象,保存在ServiceMap
中。 还有一个需要注意的点是后台服务以及延迟启动机制,所有的后台服务都会被添加至一个名为mStartingBackground
的列表中(添加逻辑在startServiceInnerLocked
方法中),如果当前后台服务超过阈值,那么服务将会被添加至延迟启动列表中。
ActiveService.startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
ServiceRecord r,
boolean callerFg,//服务启动者是否是前台进程
boolean addToStarting) //是否添加到后台服务列表中
throws TransactionTooLargeException {
//...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, 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() + BG_START_TIMEOUT;
//...
if (first) {
smap.rescheduleDelayedStarts();
}
} else if (callerFg) {
smap.ensureNotStartingBackground(r);
}
return r.name;
}
复制代码
该方法主要是调用了bringUpServiceLocked
来进行后续的服务启动功能,同时会判断addToStarting
值决定是否将服务添加至后台服务列表中。
ActiveService.bringUpServiceLocked
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags,
boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
//服务进程已经启动,且服务也已启动,分发onStartCommand事件
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
//...
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
//应用进程已经启动,调用realStartServiceLocked,返回
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
app = r.isolatedProc;
}
//启动服务进程
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
//进程启动需要时间,先将服务保存起来
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
//...
return null;
}
复制代码
这个方法根据服务进程的状态以及服务的状态产生了几个分支
- 如果服务进程已经启动,且服务也已经启动,那么调用
sendServiceArgsLocked
方法触发Service.onStartCommand
- 如果服务还未启动,且不是以
isotate
模式启动,那么调用ActivityManagerService.getProcessRecordLocked
查找是否有可用进程,如果有就调用realStartServiceLocked
启动服务 - 服务未启动,且服务的进程也没启动,那么调用
ActivityManagerService.startProcessLocked
启动进程,同时将服务保存至待启动列表中,等待进程启动完毕之后继续下面的流程。
sendServiceArgsLocked
这个方法在realStartServiceLocked
中也会被调用,我们到时候再分析。
关于进程启动,大家可以参考其他文章,这里不去展开讲。 进程启动之后,最终还是会进入到realStartServiceLocked
方法中,方法调用链如下 ActivityThread.main
-> ActivityThread.attach
-> ActivityManagerService.attachApplication
-> ActivityManagerService.attachApplicationLocked
-> ActiveService.attachApplicationLocked
-> ActiveService.realStartServiceLocked
下面我们就来分析一下ActiveService.realStartServiceLocked
ActiveService.realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
//...
boolean created = false;
try {
//...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
//...
} finally {
//...
}
//step2
requestServiceBindingsLocked(r, execInFg);
//...
//step3
sendServiceArgsLocked(r, execInFg, true);
//...
}
复制代码
这个方法我做了很多精简,我们只关注一些最核心的部分
- 跨进程调用
ApplicationThrad.scheduleCreateService
方法,最终会走到ActivityThread.handleCreateService
中,该方法通过反射创建一个Service
的实例,并调用其onCreate
方法,这部分的代码并不复杂,大家可以自行分析。 - 调用
requestServiceBindingsLocked
处理bindService
请求,我们放到bindService
启动流程去讲 - 调用
sendServiceArgsLocked
处理startService
请求
下面我们分析一下sendServiceArgsLocked
ActiveService.sendServiceArgsLocked
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
Exception caughtException = null;
ServiceRecord.StartItem si;
try {
si = r.pendingStarts.remove(0);
//...
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
//...
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (TransactionTooLargeException e) {
//...
} catch (RemoteException e) {
//...
} catch (Exception e) {
//...
}
//...
}
}
复制代码
还记得pendingStarts
么?在ActiveService.startServiceLocked
方法中,ActiveService
将启动服务的请求的信息保存在pendingStarts
中。 sendServiceArgsLocked
的逻辑非常简单,就是遍历pendingStarts
,将所有的start
请求发送出去。 发送的过程有涉及到了进程间通信,调用了ApplicationThrad.scheduleServiceArgs
方法,该方法最终会进入到ActivityThread.handleServiceArgs
中,触发Service.onStartCommand
。
至此,startService
的流程就结束了。
bindService
bindService
的大致流程如下
Context.bindService
会经历以下调用链 Context.bindService
-> ContextImpl.bindService
-> ContextImpl.bindServiceCommon
ContextImpl.bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
//bindService成功之后会回调给ServiceConnection一个binder对象
//用于后续的C/S通信,AMS直接通过IServiceConnection接口进行回调
//由于ServiceConnection不是aidl接口,因此需要进行一定的包装
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
//...
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
//...
}
return res != 0;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
复制代码
bindServiceCommon
的主要职责
- 调用
LoadedApk.getServiceDispatcher
是包装ServiceConnection
成一个IServiceConnection
对象,后续AMS
可以直接通过该对象发布客户端与服务端进行通信的Binder
对象。这个方法就不展开讲了。 - 跨进程调用
ActivityManagerService.bindService
方法继续服务启动流程
ActivityManagerService.bindService
会直接调用ActiveService.bindServiceLocked
ActiveService.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
//bind请求发起进程
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
//...
//请求发起进程是否处于前台
final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
//...
ServiceRecord s = res.record;
final long origId = Binder.clearCallingIdentity();
try {
//...
//下面这些操作是在AMS中建立起客户端和服务端的绑定关系
//主要是保存客户端的一些信息到ServiceRecord中
//保存服务端的一些信息到客户端(ActivityRecord、ProcessRecord)中
//retrieveAppBindingLocked方法执行完毕之后会在ServiceRecord的bindings
//字段中添加一条记录。bindings是Map类型,值类型为IntentBindRecord
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
//...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
//...
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
//conn就是客户端创建的IServiceConnection对象
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
//...
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
//...
} finally {
//...
}
return 1;
}
复制代码
该方法的核心有两点
- 调用
bringUpServiceLocked
启动服务 - 调用
IServiceConnection.connected
方法发布用于客户端与服务端进行通信的binder
对象
看似简单,但是如果将BIND_AUTO_CREATE
标志以及bringUpServiceLocked
方法内部逻辑分支,场景会变得稍微复杂一些。这里我对各个场景下Service.onBind
和ServiceConnection.onServiceConnected
的调用时机做一下简单分析
设置BIND_AUTO_CREATE
标志,服务未启动(包括进程未启动)
由于设置了BIND_AUTO_CREATE
标志,接下来就会进入到bringUpServiceLocked
中。该方法在分析startService
流程的时候我们分析过。如果进程已经启动则会进入到realStartServiceLocked
中,如果进程未启动,那么待进程启动之后通过进程间通信最终还是会走到realStartServiceLocked
方法中。 realStartServiceLocked
方法内会通过进程间通信,通知服务进程创建Service
实例,并调用onCreate方法
,之后会调用requestServiceBindingsLocked
方法处理bind
请求,这个方法之前特意留到这里进行分析。
ActiveService.requestServiceBindingsLocked
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
复制代码
该方法很简单,遍历ServiceRecord.bindings
的值,并挨个儿调用requestServiceBindingLocked
ActiveService.requestServiceBindingLocked
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
//...
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
//...
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
//...
} catch (TransactionTooLargeException e) {
//...
} catch (RemoteException e) {
//...
}
}
return true;
}
复制代码
requestServiceBindingLocked
也很简单,通过Binder
通信,调用ApplicationThread.scheduleBindService
方法,该方法在经过一些列调用之后,Service.onBind
就会被调用。
ServiceConnection.onServiceConnected
的回调则是在Service.onBind
方法被调用之后。 ActivityThread
在调完Service.onBind
之后,会回调AMS
,最终进入到ActiveService.publishServiceLocked
ActiveService.publishServiceLocked
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) {
//...
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
//...
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
//...
}
}
}
}
//...
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
复制代码
publishServiceLocked
调用了IServiceConnection.connected
,之后会经过进程间通信以及IServiceConnection
实现类的内部逻辑,最终调用ServiceConnection.onServiceConnected
方法。
case 2 : 设置BIND_AUTO_CREATE标志,服务已启动
此时bringUpServiceLocked
会马上返回,继续bindServiceLocked
的流程
ActiveService.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
//...
try {
//...
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
//conn就是客户端创建的IServiceConnection对象
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
//...
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
//...
} finally {
//...
}
return 1;
}
复制代码
这里要注意的有两个字段IntentBindRecord.requested
和IntentBindRecord.received
,它们会影响接下来的流程走向。
- IntentBindRecord.requested 是否已经发起了
Application.scheduleBindService
调用,通知服务进程回调Service.onBind
方法。 - IntentBindRecord.received 该字段如果为
true
,说明Service.onBind
方法已经被回调
而此时由于还没有调用ApplicationThread.scheduleBindService
,因此received
为false
,requested
也是false
,这时走requestServiceBindingLocked
方法。 后续的流程,则跟case 1
是一样的。
case 3 : 未设置BIND_AUTO_CREATE,服务已启动
如果未设置BIND_AUTO_CREATE,那么在bind
流程中是不会调用bringUpServiceLocked
启动服务的。而此时服务已经启动,那么可能是之前有调用过startService
启动过服务。 此时received
为false
,requested
也是false
,直接走requestServiceBindingLocked
,跟case 2
是一样的
case 4 : 未设置BIND_AUTO_CREATE,服务未启动
这种场景就需要等待服务启动了,服务启动的机制是下一次的startCommand
被调用或者带有BIND_AUTO_CREATE
标志的bindService
被调用。无论进程是否启动,最终都会走到realStartServiceLocked
,后续流程case 1
一样。
至此,bindService
的流程就分析完毕了。