1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android的服务(Service)(二)Service的自动重启问题

Android的服务(Service)(二)Service的自动重启问题

时间:2023-10-31 01:58:14

相关推荐

Android的服务(Service)(二)Service的自动重启问题

继续上篇的分析,接下来是第二个问题”Service的自动重启问题“

(一)、Service的生命周期

(二)、Service的自动重启问题

这里要说服务的自动重启问题,这个问题其实很简单,只有两个关键的方法。代码如下:

这个方法在ActivityThread的一系列针对服务的handle方法中都有调用到ActivityManagerSerice的serviceDoneExecuting()方法,但是跟重启有关的只有handleServiceArgs(),因为只有在这里才有一个叫res的参数会起作用。

[java]view plaincopyprivatevoidhandleServiceArgs(ServiceArgsDatadata){ Services=mServices.get(data.token); if(s!=null){ try{ if(data.args!=null){ data.args.setExtrasClassLoader(s.getClassLoader()); } intres; if(!data.taskRemoved){ //就是回调了用户服务的onStartCommand生命周期,这个做应用的都知道了, //这里可以通过设置其返回值来控制自己的服务是否允许被重新启动,顺理成章的这个值就是res 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(RemoteExceptione){ //nothingtodo. } ensureJitEnabled(); } .................. } } 下面就是这个特性的关键代码,里面的注释已经写的很全了,关键其作用的就是stopIfKilled这个标志。

[java]view plaincopyvoidserviceDoneExecutingLocked(ServiceRecordr,inttype,intstartId,intres){ booleaninDestroying=mDestroyingServices.contains(r); if(r!=null){ if(type==1){ //Thisisacallfromaservicestart...takecareof //book-keeping. r.callStart=true; switch(res){ caseService.START_STICKY_COMPATIBILITY: caseService.START_STICKY:{ //Wearedonewiththeassociatedstartarguments. r.findDeliveredStart(startId,true); //Don'tstopifkilled. r.stopIfKilled=false; break; } caseService.START_NOT_STICKY:{ //Wearedonewiththeassociatedstartarguments. r.findDeliveredStart(startId,true); if(r.getLastStartId()==startId){ //Thereisnomorework,andthisservice //doesn'twanttohangaroundifkilled. r.stopIfKilled=true; } break; } caseService.START_REDELIVER_INTENT:{ //We'llkeepthisitemuntiltheyexplicitly //callstopforit,butkeeptrackofthefact //thatitwasdelivered. ServiceRecord.StartItemsi=r.findDeliveredStart(startId,false); if(si!=null){ si.deliveryCount=0; si.doneExecutingCount++; //Don'tstopifkilled. r.stopIfKilled=true; } break; } caseService.START_TASK_REMOVED_COMPLETE:{ //SpecialprocessingforonTaskRemoved().Don't //impactnormalonStartCommand()processing. r.findDeliveredStart(startId,true); break; } default: thrownewIllegalArgumentException( "Unknownservicestartresult:"+res); } if(res==Service.START_STICKY_COMPATIBILITY){ r.callStart=false; } } finallongorigId=Binder.clearCallingIdentity(); serviceDoneExecutingLocked(r,inDestroying,inDestroying); Binder.restoreCallingIdentity(origId); }else{ Slog.w(TAG,"Doneexecutingunknownservicefrompid" +Binder.getCallingPid()); } } 那么这个标志位又是在哪些情况下使得服务可以重启的呢?这种场景入口很多啊,比如系统清理进程等,总之就是APP Died的情况下,入口方法不列举了,最后都会执行到这来:

[java]view plaincopyfinalvoidkillServicesLocked(ProcessRecordapp,booleanallowRestart){ //Reportdisconnectedservices. if(false){ //XXXwearelettingtheclientlinktotheservicefor //deathnotifications. if(app.services.size()>0){ Iterator<ServiceRecord>it=app.services.iterator(); while(it.hasNext()){ ServiceRecordr=it.next(); for(intconni=r.connections.size()-1;conni>=0;conni--){ ArrayList<ConnectionRecord>cl=r.connections.valueAt(conni); for(inti=0;i<cl.size();i++){ ConnectionRecordc=cl.get(i); if(c.binding.client!=app){ try{ //c.conn.connected(r.className,null); }catch(Exceptione){ //todo:thisshouldbeasynchronous! Slog.w(TAG,"Exceptionthrowndisconnectedservce" +r.shortName +"fromapp"+app.processName,e); } } } } } } } //Firstclearappstatefromservices. for(inti=app.services.size()-1;i>=0;i--){ ServiceRecordsr=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,"killServicesremovedestroying"+sr); } finalintnumClients=sr.bindings.size(); for(intbindingi=numClients-1;bindingi>=0;bindingi--){ IntentBindRecordb=sr.bindings.valueAt(bindingi); if(DEBUG_SERVICE)Slog.v(TAG,"Killingbinding"+b +":shouldUnbind="+b.hasBound); b.binder=null; b.requested=b.received=b.hasBound=false; } } //Cleanupanyconnectionsthisapplicationhastootherservices. for(inti=app.connections.size()-1;i>=0;i--){ ConnectionRecordr=app.connections.valueAt(i); removeConnectionLocked(r,app,null); } app.connections.clear(); ServiceMapsmap=getServiceMap(app.userId); //Nowdoremainingservicecleanup. for(inti=app.services.size()-1;i>=0;i--){ ServiceRecordsr=app.services.valueAt(i); //Sanitycheck:iftheservicelistedfortheappisnotone //weactuallyaremaintaining,dropit. if(smap.mServicesByName.get(sr.name)!=sr){ ServiceRecordcur=smap.mServicesByName.get(sr.name); Slog.wtf(TAG,"Service"+sr+"inprocess"+app +"notsameasinmap:"+cur); app.services.removeAt(i); continue; } //Anyservicesrunningintheapplicationmayneedtobeplaced //backinthependinglist. //这里还是分很多种情况的 //允许重启时,如果当前服务所在进程crash超过两次,并且不是persistent的进程就结束不会重启了 if(allowRestart&&sr.crashCount>=2&&(sr.serviceInfo.applicationInfo.flags &ApplicationInfo.FLAG_PERSISTENT)==0){ Slog.w(TAG,"Servicecrashed"+sr.crashCount +"times,stopping:"+sr); EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH, sr.userId,sr.crashCount,sr.shortName,app.pid); bringDownServiceLocked(sr); }elseif(!allowRestart){ //不允许重启直接挂掉 bringDownServiceLocked(sr); }else{ // booleancanceled=scheduleServiceRestartLocked(sr,true); //Shouldtheserviceremainrunning?Notethatinthe //extremecaseofsomanyattemptstodeliveracommand //thatitfailedwealsowillstopithere. 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,noreasontorestart! bringDownServiceLocked(sr); } } } } } if(!allowRestart){ app.services.clear(); //Makesuretherearenomorerestartingservicesforthisprocess. for(inti=mRestartingServices.size()-1;i>=0;i--){ ServiceRecordr=mRestartingServices.get(i); if(r.processName.equals(app.processName)&& r.serviceInfo.applicationInfo.uid==app.info.uid){ mRestartingServices.remove(i); clearRestartingIfNeededLocked(r); } } for(inti=mPendingServices.size()-1;i>=0;i--){ ServiceRecordr=mPendingServices.get(i); if(r.processName.equals(app.processName)&& r.serviceInfo.applicationInfo.uid==app.info.uid){ mPendingServices.remove(i); } } } //Makesurewehavenomorerecordsonthestoppinglist. inti=mDestroyingServices.size(); while(i>0){ i--; ServiceRecordsr=mDestroyingServices.get(i); if(sr.app==app){ sr.forceClearTracker(); mDestroyingServices.remove(i); if(DEBUG_SERVICE)Slog.v(TAG,"killServicesremovedestroying"+sr); } } app.executingServices.clear(); }[java]view plaincopyprivatefinalbooleanscheduleServiceRestartLocked(ServiceRecordr, booleanallowCancel){ booleancanceled=false; ServiceMapsmap=getServiceMap(r.userId); if(smap.mServicesByName.get(r.name)!=r){ ServiceRecordcur=smap.mServicesByName.get(r.name); Slog.wtf(TAG,"Attemptingtoschedulerestartof"+r +"whenfoundinmap:"+cur); returnfalse; } finallongnow=SystemClock.uptimeMillis(); if((r.serviceInfo.applicationInfo.flags &ApplicationInfo.FLAG_PERSISTENT)==0){ longminDuration=SERVICE_RESTART_DURATION; longresetTime=SERVICE_RESET_RUN_DURATION; //Anydeliveredbutnotyetfinishedstartsshouldbeputback //onthependinglist. finalintN=r.deliveredStarts.size(); if(N>0){ for(inti=N-1;i>=0;i--){ ServiceRecord.StartItemsi=r.deliveredStarts.get(i); si.removeUriPermissionsLocked(); //注意了,这里的canceled如果为true还是需要结束服务的 //还要关注一下delivery的上限和doneExecuting的上限 if(si.intent==null){ //We'llgeneratethisagainifneeded. }elseif(!allowCancel||(si.deliveryCount<ServiceRecord.MAX_DELIVERY_COUNT &&si.doneExecutingCount<ServiceRecord.MAX_DONE_EXECUTING_COUNT)){ //重新在pendingStart中添加si,所以会在下次执行时重新带入intent进去 r.pendingStarts.add(0,si); longdur=SystemClock.uptimeMillis()-si.deliveredTime; dur*=2; if(minDuration<dur)minDuration=dur; if(resetTime<dur)resetTime=dur; }else{ Slog.w(TAG,"Cancelingstartitem"+si.intent+"inservice" +r.name); canceled=true; } } r.deliveredStarts.clear(); } r.totalRestartCount++; if(r.restartDelay==0){ r.restartCount++; r.restartDelay=minDuration; }else{ //Ifithasbeena"reasonablylongtime"sincetheservice //wasstarted,thenresetourrestartdurationbackto //thebeginning,sowedon'tinfinitelyincreasetheduration //onaservicethatjustoccasionallygetskilled(whichis //anormalcase,duetoprocessbeingkilledtoreclaimmemory). 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; //Makesurethatwedon'tenduprestartingabunchofservices //allatthesametime. booleanrepeat; do{ repeat=false; for(inti=mRestartingServices.size()-1;i>=0;i--){ ServiceRecordr2=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{ //Persistentprocessesareimmediatelyrestarted,sothereisno //reasontoholdofonrestartingtheirservices. 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); //最关键的操作在这里,忘ActivityManagerService的handler里面post一个重启的Runnable //这个东西前面启动过程创建ServiceRecord时有的,很简单就是一个ServiceRestarter,它里面保存了这个ServiceRecord本身 //重启的时候根据这个record就可以直接启动服务了 mAm.mHandler.postAtTime(r.restarter,r.nextRestartTime); r.nextRestartTime=SystemClock.uptimeMillis()+r.restartDelay; Slog.w(TAG,"Schedulingrestartofcrashedservice" +r.shortName+"in"+r.restartDelay+"ms"); EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART, r.userId,r.shortName,r.restartDelay); returncanceled; }[java]view plaincopyprivateclassServiceRestarterimplementsRunnable{ privateServiceRecordmService; voidsetService(ServiceRecordservice){ mService=service; } publicvoidrun(){ 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与其客户端的绑定如何实现,即跨进程调用问题。

原文地址:/hehui1860/article/details/41743549

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。