Android之Service自啟動流程
阿新 • • 發佈:2019-01-09
當Service被異常銷燬後,預設都會自動重啟,但Service的自動重啟是如何實現的尼?下面就來梳理一下Service的自動重啟流程。
無論Service是啟動還是繫結成功,都會呼叫ActiveServices
的serviceDoneExecutingLocked
方法,來看一下這個方法的實現。
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.
//預設呼叫Service的startCommand這個方法
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.
//被異常kill掉,允許重啟該Service
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.
//被異常kill掉,不允許重啟該Service
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.
//被異常kill掉,不允許重啟。但後面會依靠deliveredStarts觸發重啟
r.C= 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) {
//當startCommand返回START_STICKY_COMPATIBILITY時則不允許呼叫startCommand方法
r.callStart = false;
}
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
...
}
...
} else {
...
}
}
當Service啟動或繫結成功後就會給當前Service給stopIfKilled
這個標誌位賦值,該標誌位決定當Service被異常kill掉後是否需要重啟。
Service被意外kill後會呼叫ActiveServices
的killServicesLocked
方法,來看看這個方法的實現。
final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
...
ServiceMap smap = getServiceMapLocked(app.userId);
// Now do remaining service cleanup.
for (int i=app.services.size()-1; i>=0; i--) {
//拿到Service的資訊
ServiceRecord sr = app.services.valueAt(i);
...
// Any services running in the application may need to be placed
// back in the pending list.
//如果連續兩次重啟失敗就不再重啟Service
if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0) {
...
//不允許重啟
bringDownServiceLocked(sr);
} else if (!allowRestart//不允許重啟
|| !mAm.mUserController.isUserRunningLocked(sr.userId, 0)) {
//不允許重啟
bringDownServiceLocked(sr);
} else {
//嘗試重啟
boolean canceled = scheduleServiceRestartLocked(sr, true);
//在多次嘗試傳送失敗的命令的極端情況下,也會在這裡停止它。
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);
}
}
}
}
}
//做一些清理操作
...
}
從上面程式碼可以看出,嘗試重啟的具體實現是在scheduleServiceRestartLocked
這個方法裡,來看看它的實現。
private final boolean scheduleServiceRestartLocked(ServiceRecord r, boolean allowCancel) {
boolean canceled = false;
...
final long now = SystemClock.uptimeMillis();
if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0) {
long minDuration = mAm.mConstants.SERVICE_RESTART_DURATION;
long resetTime = mAm.mConstants.SERVICE_RESET_RUN_DURATION;
// Any delivered but not yet finished starts should be put back
// on the pending list.
final int N = r.deliveredStarts.size();
if (N > 0) {
for (int i=N-1; i>=0; i--) {
ServiceRecord.StartItem si = r.deliveredStarts.get(i);
si.removeUriPermissionsLocked();
if (si.intent == null) {
// We'll generate this again if needed.
} else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
&& si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
//重啟的時候,deliveredStarts被pendingStarts替換掉了,這樣就能拿到Intent的值
// 也就說,這個時候START_REDELIVER_INTENT由死轉生
r.pendingStarts.add(0, si);
long dur = SystemClock.uptimeMillis() - si.deliveredTime;
//將重啟間隔時間拉大,被kill掉次數越多,重啟所需要時間越長
dur *= 2;
if (minDuration < dur) minDuration = dur;
if (resetTime < dur) resetTime = dur;
} else {
Slog.w(TAG, "Canceling start item " + si.intent + " in service "
+ r.name);
canceled = true;
}
}
r.deliveredStarts.clear();
}
//重啟次數加1
r.totalRestartCount++;
if (r.restartDelay == 0) {
r.restartCount++;
r.restartDelay = minDuration;
} else {
// If it has been a "reasonably long time" since the service
// was started, then reset our restart duration back to
// the beginning, so we don't infinitely increase the duration
// on a service that just occasionally gets killed (which is
// a normal case, due to process being killed to reclaim memory).
if (now > (r.restartTime+resetTime)) {
r.restartCount = 1;
r.restartDelay = minDuration;
} else {
r.restartDelay *= mAm.mConstants.SERVICE_RESTART_DURATION_FACTOR;
if (r.restartDelay < minDuration) {
r.restartDelay = minDuration;
}
}
}
r.nextRestartTime = now + r.restartDelay;
//兩個Service啟動至少間隔10秒,這裡的意義其實不是很大,主要是為了Service啟動失敗的情況,如果啟動成功,其他要啟動的Service會被一併直接重新喚起
boolean repeat;
do {
repeat = false;
final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
for (int i=mRestartingServices.size()-1; i>=0; i--) {
ServiceRecord r2 = mRestartingServices.get(i);
if (r2 != r && r.nextRestartTime >= (r2.nextRestartTime-restartTimeBetween)
&& r.nextRestartTime < (r2.nextRestartTime+restartTimeBetween)) {
r.nextRestartTime = r2.nextRestartTime + restartTimeBetween;
r.restartDelay = r.nextRestartTime - now;
repeat = true;
break;
}
}
} while (repeat);
} else {
// Persistent processes are immediately restarted, so there is no
// reason to hold of on restarting their services.
r.totalRestartCount++;
r.restartCount = 0;
r.restartDelay = 0;
r.nextRestartTime = now;
}
if (!mRestartingServices.contains(r)) {
r.createdFromFg = false;
mRestartingServices.add(r);
r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
}
cancelForegroundNotificationLocked(r);
mAm.mHandler.removeCallbacks(r.restarter);
//執行Service重啟操作,這裡的restarter就是一個ServiceRestarter物件,在ServiceRecord建立時新增進去的
mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
...
return canceled;
}
private class ServiceRestarter implements Runnable {
private ServiceRecord mService;
void setService(ServiceRecord service) {
mService = service;
}
public void run() {
synchronized(mAm) {
//開始重啟
performServiceRestartLocked(mService);
}
}
}
final void performServiceRestartLocked(ServiceRecord r) {
...
try {
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
} catch (TransactionTooLargeException e) {
...
}
}
最後就在ServiceRestarter
執行重新建立Service操作,在run
方法裡呼叫了performServiceRestartLocked
來進行重啟,而performServiceRestartLocked
裡直接呼叫了bringUpServiceLocked
這個方法,這個就是重新建立Service的方法,關於這個方法的詳細實現可以去閱讀Android原始碼之Service啟動流程這篇文章。
Android的服務(Service)(二)Service的自動重啟問題
Android Service重啟恢復(Service程序重啟)原理解析