生活随笔
收集整理的這篇文章主要介紹了
Android的服务(Service)(二)Service的自动重启问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
繼續上篇的分析,接下來是第二個問題”Service的自動重啟問題“
(一)、Service的生命周期
(二)、Service的自動重啟問題
??? 這里要說服務的自動重啟問題,這個問題其實很簡單,只有兩個關鍵的方法。代碼如下:
??? 這個方法在ActivityThread的一系列針對服務的handle方法中都有調用到ActivityManagerSerice的serviceDoneExecuting()方法,但是跟重啟有關的只有handleServiceArgs(),因為只有在這里才有一個叫res的參數會起作用。
[java]?view plaincopy
private?void?handleServiceArgs(ServiceArgsData?data)?{?? ????Service?s?=?mServices.get(data.token);?? ????if?(s?!=?null)?{?? ????????try?{?? ????????????if?(data.args?!=?null)?{?? ????????????????data.args.setExtrasClassLoader(s.getClassLoader());?? ????????????}?? ????????????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;?? ????????????}?? ????????????...............?? ????????????try?{?? ?????????????????? ????????????????ActivityManagerNative.getDefault().serviceDoneExecuting(?? ????????????????????????data.token,?1,?data.startId,?res);?? ????????????}?catch?(RemoteException?e)?{?? ?????????????????? ????????????}?? ????????????ensureJitEnabled();?? ????????}?? ????????..................?? ????}?? }?? ??? 下面就是這個特性的關鍵代碼,里面的注釋已經寫的很全了,關鍵其作用的就是stopIfKilled這個標志。
[java]?view plaincopy
void?serviceDoneExecutingLocked(ServiceRecord?r,?int?type,?int?startId,?int?res)?{?? ????boolean?inDestroying?=?mDestroyingServices.contains(r);?? ????if?(r?!=?null)?{?? ????????if?(type?==?1)?{?? ?????????????? ?????????????? ????????????r.callStart?=?true;?? ????????????switch?(res)?{?? ????????????????case?Service.START_STICKY_COMPATIBILITY:?? ????????????????case?Service.START_STICKY:?{?? ?????????????????????? ????????????????????r.findDeliveredStart(startId,?true);?? ?????????????????????? ????????????????????r.stopIfKilled?=?false;?? ????????????????????break;?? ????????????????}?? ????????????????case?Service.START_NOT_STICKY:?{?? ?????????????????????? ????????????????????r.findDeliveredStart(startId,?true);?? ????????????????????if?(r.getLastStartId()?==?startId)?{?? ?????????????????????????? ?????????????????????????? ????????????????????????r.stopIfKilled?=?true;?? ????????????????????}?? ????????????????????break;?? ????????????????}?? ????????????????case?Service.START_REDELIVER_INTENT:?{?? ?????????????????????? ?????????????????????? ?????????????????????? ????????????????????ServiceRecord.StartItem?si?=?r.findDeliveredStart(startId,?false);?? ????????????????????if?(si?!=?null)?{?? ????????????????????????si.deliveryCount?=?0;?? ????????????????????????si.doneExecutingCount++;?? ?????????????????????????? ????????????????????????r.stopIfKilled?=?true;?? ????????????????????}?? ????????????????????break;?? ????????????????}?? ????????????????case?Service.START_TASK_REMOVED_COMPLETE:?{?? ?????????????????????? ?????????????????????? ????????????????????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());?? ????}?? }?? ??? 那么這個標志位又是在哪些情況下使得服務可以重啟的呢?這種場景入口很多啊,比如系統清理進程等,總之就是APP Died的情況下,入口方法不列舉了,最后都會執行到這來:
[java]?view plaincopy
final?void?killServicesLocked(ProcessRecord?app,?boolean?allowRestart)?{?? ?????? ????if?(false)?{?? ?????????? ?????????? ????????if?(app.services.size()?>?0)?{?? ????????????Iterator<ServiceRecord>?it?=?app.services.iterator();?? ????????????while?(it.hasNext())?{?? ????????????????ServiceRecord?r?=?it.next();?? ????????????????for?(int?conni=r.connections.size()-1;?conni>=0;?conni--)?{?? ????????????????????ArrayList<ConnectionRecord>?cl?=?r.connections.valueAt(conni);?? ????????????????????for?(int?i=0;?i<cl.size();?i++)?{?? ????????????????????????ConnectionRecord?c?=?cl.get(i);?? ????????????????????????if?(c.binding.client?!=?app)?{?? ????????????????????????????try?{?? ?????????????????????????????????? ????????????????????????????}?catch?(Exception?e)?{?? ?????????????????????????????????? ????????????????????????????????Slog.w(TAG,?"Exception?thrown?disconnected?servce?"?? ??????????????????????????????????????+?r.shortName?? ??????????????????????????????????????+?"?from?app?"?+?app.processName,?e);?? ????????????????????????????}?? ????????????????????????}?? ????????????????????}?? ????????????????}?? ????????????}?? ????????}?? ????}?? ?? ?????? ????for?(int?i=app.services.size()-1;?i>=0;?i--)?{?? ????????ServiceRecord?sr?=?app.services.valueAt(i);?? ????????synchronized?(sr.stats.getBatteryStats())?{?? ????????????sr.stats.stopLaunchedLocked();?? ????????}?? ????????if?(sr.app?!=?null)?{?? ????????????sr.app.services.remove(sr);?? ????????}?? ????????sr.app?=?null;?? ????????sr.isolatedProc?=?null;?? ????????sr.executeNesting?=?0;?? ????????sr.forceClearTracker();?? ????????if?(mDestroyingServices.remove(sr))?{?? ????????????if?(DEBUG_SERVICE)?Slog.v(TAG,?"killServices?remove?destroying?"?+?sr);?? ????????}?? ?? ????????final?int?numClients?=?sr.bindings.size();?? ????????for?(int?bindingi=numClients-1;?bindingi>=0;?bindingi--)?{?? ????????????IntentBindRecord?b?=?sr.bindings.valueAt(bindingi);?? ????????????if?(DEBUG_SERVICE)?Slog.v(TAG,?"Killing?binding?"?+?b?? ????????????????????+?":?shouldUnbind="?+?b.hasBound);?? ????????????b.binder?=?null;?? ????????????b.requested?=?b.received?=?b.hasBound?=?false;?? ????????}?? ????}?? ?? ?????? ????for?(int?i=app.connections.size()-1;?i>=0;?i--)?{?? ????????ConnectionRecord?r?=?app.connections.valueAt(i);?? ????????removeConnectionLocked(r,?app,?null);?? ????}?? ????app.connections.clear();?? ?? ????ServiceMap?smap?=?getServiceMap(app.userId);?? ?? ?????? ????for?(int?i=app.services.size()-1;?i>=0;?i--)?{?? ????????ServiceRecord?sr?=?app.services.valueAt(i);?? ?????????? ?????????? ????????if?(smap.mServicesByName.get(sr.name)?!=?sr)?{?? ????????????ServiceRecord?cur?=?smap.mServicesByName.get(sr.name);?? ????????????Slog.wtf(TAG,?"Service?"?+?sr?+?"?in?process?"?+?app?? ????????????????????+?"?not?same?as?in?map:?"?+?cur);?? ????????????app.services.removeAt(i);?? ????????????continue;?? ????????}?? ?? ?????????? ?????????? ?????????? ?????????? ????????if?(allowRestart?&&?sr.crashCount?>=?2?&&?(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)?{?? ?????????????? ????????????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())?{?? ?????????????????????????? ????????????????????????bringDownServiceLocked(sr);?? ????????????????????}?? ????????????????}?? ????????????}?? ????????}?? ????}?? ?? ????if?(!allowRestart)?{?? ????????app.services.clear();?? ?? ?????????? ????????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);?? ????????????}?? ????????}?? ????}?? ?? ?????? ????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,?"killServices?remove?destroying?"?+?sr);?? ????????}?? ????}?? ?? ????app.executingServices.clear();?? }????? [java]?view plaincopy
private?final?boolean?scheduleServiceRestartLocked(ServiceRecord?r,?? ????????boolean?allowCancel)?{?? ????boolean?canceled?=?false;?? ?? ????ServiceMap?smap?=?getServiceMap(r.userId);?? ????if?(smap.mServicesByName.get(r.name)?!=?r)?{?? ????????ServiceRecord?cur?=?smap.mServicesByName.get(r.name);?? ????????Slog.wtf(TAG,?"Attempting?to?schedule?restart?of?"?+?r?? ????????????????+?"?when?found?in?map:?"?+?cur);?? ????????return?false;?? ????}?? ?? ????final?long?now?=?SystemClock.uptimeMillis();?? ?? ????if?((r.serviceInfo.applicationInfo.flags?? ????????????&ApplicationInfo.FLAG_PERSISTENT)?==?0)?{?? ????????long?minDuration?=?SERVICE_RESTART_DURATION;?? ????????long?resetTime?=?SERVICE_RESET_RUN_DURATION;?? ?? ?????????? ?????????? ????????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)?{?? ?????????????????????? ????????????????}?else?if?(!allowCancel?||?(si.deliveryCount?<?ServiceRecord.MAX_DELIVERY_COUNT?? ????????????????????????&&?si.doneExecutingCount?<?ServiceRecord.MAX_DONE_EXECUTING_COUNT))?{?? ?????????????????????? ????????????????????r.pendingStarts.add(0,?si);?? ????????????????????long?dur?=?SystemClock.uptimeMillis()?-?si.deliveredTime;?? ????????????????????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();?? ????????}?? ?? ????????r.totalRestartCount++;?? ????????if?(r.restartDelay?==?0)?{?? ????????????r.restartCount++;?? ????????????r.restartDelay?=?minDuration;?? ????????}?else?{?? ?????????????? ?????????????? ?????????????? ?????????????? ?????????????? ????????????if?(now?>?(r.restartTime+resetTime))?{?? ????????????????r.restartCount?=?1;?? ????????????????r.restartDelay?=?minDuration;?? ????????????}?else?{?? ????????????????r.restartDelay?*=?SERVICE_RESTART_DURATION_FACTOR;?? ????????????????if?(r.restartDelay?<?minDuration)?{?? ????????????????????r.restartDelay?=?minDuration;?? ????????????????}?? ????????????}?? ????????}?? ?? ????????r.nextRestartTime?=?now?+?r.restartDelay;?? ?? ?????????? ?????????? ????????boolean?repeat;?? ????????do?{?? ????????????repeat?=?false;?? ????????????for?(int?i=mRestartingServices.size()-1;?i>=0;?i--)?{?? ????????????????ServiceRecord?r2?=?mRestartingServices.get(i);?? ????????????????if?(r2?!=?r?&&?r.nextRestartTime?? ????????????????????????>=?(r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)?? ????????????????????????&&?r.nextRestartTime?? ????????????????????????<?(r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN))?{?? ????????????????????r.nextRestartTime?=?r2.nextRestartTime?+?SERVICE_MIN_RESTART_TIME_BETWEEN;?? ????????????????????r.restartDelay?=?r.nextRestartTime?-?now;?? ????????????????????repeat?=?true;?? ????????????????????break;?? ????????????????}?? ????????????}?? ????????}?while?(repeat);?? ?? ????}?else?{?? ?????????? ?????????? ????????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);?? ????}?? ?? ????r.cancelNotification();?? ?? ????mAm.mHandler.removeCallbacks(r.restarter);?? ?????? ?????? ?????? ????mAm.mHandler.postAtTime(r.restarter,?r.nextRestartTime);?? ????r.nextRestartTime?=?SystemClock.uptimeMillis()?+?r.restartDelay;?? ????Slog.w(TAG,?"Scheduling?restart?of?crashed?service?"?? ????????????+?r.shortName?+?"?in?"?+?r.restartDelay?+?"ms");?? ????EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,?? ????????????r.userId,?r.shortName,?r.restartDelay);?? ?? ????return?canceled;?? }?? [java]?view plaincopy
private?class?ServiceRestarter?implements?Runnable?{?? ????private?ServiceRecord?mService;?? ?? ????void?setService(ServiceRecord?service)?{?? ????????mService?=?service;?? ????}?? ?? ????public?void?run()?{?? ????????synchronized(mAm)?{?? ?????????????? ????????????performServiceRestartLocked(mService);?? ????????}?? ????}?? }?? ??? 整個這個過程中,有好幾個參數控制著是否需要重啟,也定了很多參數的上限等等,這里單獨列出來解釋一下。
??? ServiceRecord.crashCount、ServiceRecord.StartItem.deliveryCount、ServiceRecord.StartItem.doneExecutingCount
??? crashCount顧名思義啊,就是crash的次數,這個在handleAppCrashLocked()中自增的,很明顯每crash一次就會自增,沒什么好說的
??? deliveryCount也很好理解,他是屬于StartItem的,所以表示的是啟動信息,是執行onStartCommand方法的次數,也就是外部startService的次數
??? doneExecutingCount跟deliveryCount還很有關聯,類似的也是說的這個服務執行的次數,那么它們有什么區別呢?
??? 還有兩個標志位Service.START_FLAG_RETRY、Service.START_FLAG_REDELIVERY要一起看。這個在ActivesService.sendServiceArgsLocked()中可以看到。意思就是說這個服務是直接重啟還是重新發送發送請求。
??? 它們還是互斥的,這點在serviceDoneExecutingLocked()方法的START_REDELIVER_INTENT分支處理中可以得到結論,總的來說就是說onStartCommand返回START_STICKY是允許重啟,而START_REDELIVER_INTENT會重新將上次的intent請求發送出去,服務中會重新接收到這個。
最后將在下篇論第三個問題
(三)、Service與其客戶端的綁定如何實現,即跨進程調用問題。
原文地址:http://blog.csdn.net/hehui1860/article/details/41743549
總結
以上是生活随笔為你收集整理的Android的服务(Service)(二)Service的自动重启问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。