文中的源代码版本为api23java
启动Service的方式有两种:startService
、bindService
api
先祭上一张流程图看个大概app
Service
进程已经启动
Context.startService
会经历如下调用链 Context.startService
-> ContextImpl.startService
-> ContextImpl.startServiceCommon
post
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
ui
AMS
接收到请求以后会经历如下方法调用 ActivityManagerService.startService
-> ActiveService.startServiceLocked
spa
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
方法中),若是当先后台服务超过阈值,那么服务将会被添加至延迟启动列表中。debug
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
值决定是否将服务添加至后台服务列表中。rest
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;
}
复制代码
这个方法根据服务进程的状态以及服务的状态产生了几个分支code
sendServiceArgsLocked
方法触发Service.onStartCommand
isotate
模式启动,那么调用ActivityManagerService.getProcessRecordLocked
查找是否有可用进程,若是有就调用realStartServiceLocked
启动服务ActivityManagerService.startProcessLocked
启动进程,同时将服务保存至待启动列表中,等待进程启动完毕以后继续下面的流程。sendServiceArgsLocked
这个方法在realStartServiceLocked
中也会被调用,咱们到时候再分析。cdn
关于进程启动,你们能够参考其余文章,这里不去展开讲。 进程启动以后,最终仍是会进入到realStartServiceLocked
方法中,方法调用链以下 ActivityThread.main
-> ActivityThread.attach
-> ActivityManagerService.attachApplication
-> ActivityManagerService.attachApplicationLocked
-> ActiveService.attachApplicationLocked
-> 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
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
的大体流程以下
Context.bindService
会经历如下调用链 Context.bindService
-> ContextImpl.bindService
-> 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
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
请求,这个方法以前特地留到这里进行分析。
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
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
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
方法。
此时bringUpServiceLocked
会立刻返回,继续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
,它们会影响接下来的流程走向。
Application.scheduleBindService
调用,通知服务进程回调Service.onBind
方法。true
,说明Service.onBind
方法已经被回调而此时因为尚未调用ApplicationThread.scheduleBindService
,所以received
为false
,requested
也是false
,这时走requestServiceBindingLocked
方法。 后续的流程,则跟case 1
是同样的。
若是未设置BIND_AUTO_CREATE,那么在bind
流程中是不会调用bringUpServiceLocked
启动服务的。而此时服务已经启动,那么多是以前有调用过startService
启动过服务。 此时received
为false
,requested
也是false
,直接走requestServiceBindingLocked
,跟case 2
是同样的
这种场景就须要等待服务启动了,服务启动的机制是下一次的startCommand
被调用或者带有BIND_AUTO_CREATE
标志的bindService
被调用。不管进程是否启动,最终都会走到realStartServiceLocked
,后续流程case 1
同样。
至此,bindService
的流程就分析完毕了。