Service做为四大组件之一,在平时的开发中使用的频率仅次于Activity。可是,咱们生成一个Service时,通常是不会重写它的onStartCommand方法的。 究竟这个方法的返回值有什么意义,Android系统为何要给咱们提供这样的一个方法呢?下面咱们仍是从源码中寻找答案。bash
在以前【源码解析】Service的工做过程 的文章中咱们分析过了Service的工做过程,知道Service的建立会走到ActiveService的realStartServiceLocked方法,咱们就从该方法入手:app
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...省略
boolean created = false;
try {
...省略
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
...省略
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
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);
...省略
}
复制代码
该方法经过app.thread.scheduleCreateService(app.thread是ActivityThread对象)建立了Service,而后调用了ActiveService的sendServiceArgsLocked方法,代码以下:less
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<>();
...省略
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
...省略
} catch (RemoteException e) {
...省略
} catch (Exception e) {
...省略
}
...省略
}
复制代码
sendServiceArgsLocked方法最终调用了r.app.thread.scheduleServiceArgs方法,也就是ActivityThread的scheduleServiceArgs方法,代码以下:oop
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList();
for (int i = 0; i < list.size(); i++) {
ServiceStartArgs ssa = list.get(i);
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = ssa.taskRemoved;
s.startId = ssa.startId;
s.flags = ssa.flags;
s.args = ssa.args;
sendMessage(H.SERVICE_ARGS, s);
}
}
复制代码
scheduleServiceArgs方法经过消息发送机制,发送一个标志位为H.SERVICE_ARGS的消息给到ActivityThread的内部类H处理,ActivityThread内部类H对于H.SERVICE_ARGS的处理逻辑是:源码分析
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
复制代码
在handleMessage中对于SERVICE_ARGS的状况,调用了handleServiceArgs方法,handleServiceArgs的代码以下:post
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) {
throw e.rethrowFromSystemServer();
}
ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
复制代码
在上面的方法中显式的调用了Service的onStartCommand方法,获得一个整型返回值res,而咱们本文须要分析的就是这个返回值。能够看到这个返回值res最终是做为了ActivityManager.getService().serviceDoneExecuting方法的参数,而ActivityManager.getService()就是ActivityManagerService对象,其中的serviceDoneExecuting方法以下所示:ui
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
复制代码
在serviceDoneExecuting方法中又调用了ActiveServices的serviceDoneExecutingLocked方法,以下所示:this
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
// This is a call from a service start... take care of
// book-keeping.
r.callStart = true;
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
// Don't stop if killed. r.stopIfKilled = false; break; } case Service.START_NOT_STICKY: { // We are done with the associated start arguments. r.findDeliveredStart(startId, true); if (r.getLastStartId() == startId) { // There is no more work, and this service // doesn't want to hang around if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
// We'll keep this item until they explicitly // call stop for it, but keep track of the fact // that it was delivered. ServiceRecord.StartItem si = r.findDeliveredStart(startId, false); if (si != null) { si.deliveryCount = 0; si.doneExecutingCount++; // Don't stop if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_TASK_REMOVED_COMPLETE: {
// Special processing for onTaskRemoved(). Don't // impact normal onStartCommand() processing. r.findDeliveredStart(startId, true); break; } default: throw new IllegalArgumentException( "Unknown service start result: " + res); } if (res == Service.START_STICKY_COMPATIBILITY) { r.callStart = false; } } ...省略 final long origId = Binder.clearCallingIdentity(); serviceDoneExecutingLocked(r, inDestroying, inDestroying); Binder.restoreCallingIdentity(origId); } else { Slog.w(TAG, "Done executing unknown service from pid " + Binder.getCallingPid()); } } 复制代码
在serviceDoneExecutingLocked方法中,对于参数res的值作了不一样的处理:spa
其功能和START_STICKY同样,是START_STICKY的兼容版本,可是不保证onStartCommand方法会被调用。3d
在Service启动后,若是该Service被系统杀死了,系统会从新建立该Service,onStartCommand方法会被调用,可是传给Service的intent为null。这种模式适合在用Service播放在后台播放音乐的场景。
在Service启动后,若是该Service被系统杀死了,系统不会从新建立该Service。除非开发者明确地使用startService的方式启动该Service。这种模式适用在使用Service存储一些数据的操做,在系统杀死Service时,操做中止也能够接受的场景。
在Service启动后,若是该Service被系统杀死了,系统会从新建立该Service,onStartCommand方法会调用,而且将上次的Intent经过onStartCommand方法传递进来。除非开发者明确使用stopSelf方法中止该Service,不然其不会中止。
在对参数res的值作了不一样的处理后,调用了serviceDoneExecutingLocked方法,全局搜索了一下ServiceRecord的stopIfKilled值的引用,只有ActiveService的killServicesLocked方法对其进行了引用,代码以下:
final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
...省略
for (int i=app.services.size()-1; i>=0; i--) {
ServiceRecord sr = app.services.valueAt(i);
// Unless the process is persistent, this process record is going away,
// so make sure the service is cleaned out of it.
if (!app.persistent) {
app.services.removeAt(i);
}
// Sanity check: if the service listed for the app is not one
// we actually are maintaining, just let it drop.
final ServiceRecord curRec = smap.mServicesByName.get(sr.name);
if (curRec != sr) {
if (curRec != null) {
Slog.wtf(TAG, "Service " + sr + " in process " + app
+ " not same as in map: " + curRec);
}
continue;
}
// Any services running in the application may need to be placed
// back in the pending list.
if (allowRestart && sr.crashCount >= mAm.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY
&& (sr.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0) {
Slog.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
sr.userId, sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr);
} else if (!allowRestart
|| !mAm.mUserController.isUserRunningLocked(sr.userId, 0)) {
bringDownServiceLocked(sr);
} else {
boolean canceled = scheduleServiceRestartLocked(sr, true);
// Should the service remain running? Note that in the
// extreme case of so many attempts to deliver a command
// that it failed we also will stop it here.
if (sr.startRequested && (sr.stopIfKilled || canceled)) {
if (sr.pendingStarts.size() == 0) {
sr.startRequested = false;
if (sr.tracker != null) {
sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
if (!sr.hasAutoCreateConnections()) {
// Whoops, no reason to restart!
bringDownServiceLocked(sr);
}
}
}
}
}
if (!allowRestart) {
app.services.clear();
// Make sure there are no more restarting services for this process.
for (int i=mRestartingServices.size()-1; i>=0; i--) {
ServiceRecord r = mRestartingServices.get(i);
if (r.processName.equals(app.processName) &&
r.serviceInfo.applicationInfo.uid == app.info.uid) {
mRestartingServices.remove(i);
clearRestartingIfNeededLocked(r);
}
}
for (int i=mPendingServices.size()-1; i>=0; i--) {
ServiceRecord r = mPendingServices.get(i);
if (r.processName.equals(app.processName) &&
r.serviceInfo.applicationInfo.uid == app.info.uid) {
mPendingServices.remove(i);
}
}
}
// Make sure we have no more records on the stopping list.
int i = mDestroyingServices.size();
while (i > 0) {
i--;
ServiceRecord sr = mDestroyingServices.get(i);
if (sr.app == app) {
sr.forceClearTracker();
mDestroyingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
}
app.executingServices.clear();
}
复制代码
killServicesLocked方法对于ServiceRecord的stopIfKilled的逻辑看不懂,和Service中的注释对不上。后面有时间继续研究,若是有小伙伴知道的话,也请赐教,万分感谢!
本文从源码的角度并结合源码注释解析了Service的onStartCommand的返回值,分析了不一样的返回值对Service的重建有不一样的效果。 针对该结论,写了一个小Demo进行验证。文章传送门:【Demo验证】Service的onStartCommand返回值