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

http://blog.csdn.net/hehui1860/article/details/41743549


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

(一)、Service的生命周期

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

    这里要说服务的自动重启问题,这个问题其实很简单,只有两个关键的方法。代码如下:
    这个方法在ActivityThread的一系列针对服务的handle方法中都有调用到ActivityManagerSerice的serviceDoneExecuting()方法,但是跟重启有关的只有handleServiceArgs(),因为只有在这里才有一个叫res的参数会起作用。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private void handleServiceArgs(ServiceArgsData data) {  
  2.     Service s = mServices.get(data.token);  
  3.     if (s != null) {  
  4.         try {  
  5.             if (data.args != null) {  
  6.                 data.args.setExtrasClassLoader(s.getClassLoader());  
  7.             }  
  8.             int res;  
  9.             if (!data.taskRemoved) {  
  10.                 //就是回调了用户服务的onStartCommand生命周期,这个做应用的都知道了,  
  11.   
  12.                 //这里可以通过设置其返回值来控制自己的服务是否允许被重新启动,顺理成章的这个值就是res  
  13.                 res = s.onStartCommand(data.args, data.flags, data.startId);  
  14.             } else {  
  15.                 s.onTaskRemoved(data.args);  
  16.                 res = Service.START_TASK_REMOVED_COMPLETE;  
  17.             }  
  18.             ...............  
  19.             try {  
  20.                 //看看系统用这个值都干了一些什么导致有这个特性  
  21.                 ActivityManagerNative.getDefault().serviceDoneExecuting(  
  22.                         data.token, 1, data.startId, res);  
  23.             } catch (RemoteException e) {  
  24.                 // nothing to do.  
  25.             }  
  26.             ensureJitEnabled();  
  27.         }  
  28.         ..................  
  29.     }  
  30. }  
    下面就是这个特性的关键代码,里面的注释已经写的很全了,关键其作用的就是stopIfKilled这个标志。
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {  
  2.     boolean inDestroying = mDestroyingServices.contains(r);  
  3.     if (r != null) {  
  4.         if (type == 1) {  
  5.             // This is a call from a service start...  take care of  
  6.             // book-keeping.  
  7.             r.callStart = true;  
  8.             switch (res) {  
  9.                 case Service.START_STICKY_COMPATIBILITY:  
  10.                 case Service.START_STICKY: {  
  11.                     // We are done with the associated start arguments.  
  12.                     r.findDeliveredStart(startId, true);  
  13.                     // Don't stop if killed.  
  14.                     r.stopIfKilled = false;  
  15.                     break;  
  16.                 }  
  17.                 case Service.START_NOT_STICKY: {  
  18.                     // We are done with the associated start arguments.  
  19.                     r.findDeliveredStart(startId, true);  
  20.                     if (r.getLastStartId() == startId) {  
  21.                         // There is no more work, and this service  
  22.                         // doesn't want to hang around if killed.  
  23.                         r.stopIfKilled = true;  
  24.                     }  
  25.                     break;  
  26.                 }  
  27.                 case Service.START_REDELIVER_INTENT: {  
  28.                     // We'll keep this item until they explicitly  
  29.                     // call stop for it, but keep track of the fact  
  30.                     // that it was delivered.  
  31.                     ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);  
  32.                     if (si != null) {  
  33.                         si.deliveryCount = 0;  
  34.                         si.doneExecutingCount++;  
  35.                         // Don't stop if killed.  
  36.                         r.stopIfKilled = true;  
  37.                     }  
  38.                     break;  
  39.                 }  
  40.                 case Service.START_TASK_REMOVED_COMPLETE: {  
  41.                     // Special processing for onTaskRemoved().  Don't  
  42.                     // impact normal onStartCommand() processing.  
  43.                     r.findDeliveredStart(startId, true);  
  44.                     break;  
  45.                 }  
  46.                 default:  
  47.                     throw new IllegalArgumentException(  
  48.                             "Unknown service start result: " + res);  
  49.             }  
  50.             if (res == Service.START_STICKY_COMPATIBILITY) {  
  51.                 r.callStart = false;  
  52.             }  
  53.         }  
  54.         final long origId = Binder.clearCallingIdentity();  
  55.         serviceDoneExecutingLocked(r, inDestroying, inDestroying);  
  56.         Binder.restoreCallingIdentity(origId);  
  57.     } else {  
  58.         Slog.w(TAG, "Done executing unknown service from pid "  
  59.                 + Binder.getCallingPid());  
  60.     }  
  61. }  
    那么这个标志位又是在哪些情况下使得服务可以重启的呢?这种场景入口很多啊,比如系统清理进程等,总之就是APP Died的情况下,入口方法不列举了,最后都会执行到这来:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. final void killServicesLocked(ProcessRecord app, boolean allowRestart) {  
  2.     // Report disconnected services.  
  3.     if (false) {  
  4.         // XXX we are letting the client link to the service for  
  5.         // death notifications.  
  6.         if (app.services.size() > 0) {  
  7.             Iterator<ServiceRecord> it = app.services.iterator();  
  8.             while (it.hasNext()) {  
  9.                 ServiceRecord r = it.next();  
  10.                 for (int conni=r.connections.size()-1; conni>=0; conni--) {  
  11.                     ArrayList<ConnectionRecord> cl = r.connections.valueAt(conni);  
  12.                     for (int i=0; i<cl.size(); i++) {  
  13.                         ConnectionRecord c = cl.get(i);  
  14.                         if (c.binding.client != app) {  
  15.                             try {  
  16.                                 //c.conn.connected(r.className, null);  
  17.                             } catch (Exception e) {  
  18.                                 // todo: this should be asynchronous!  
  19.                                 Slog.w(TAG, "Exception thrown disconnected servce "  
  20.                                       + r.shortName  
  21.                                       + " from app " + app.processName, e);  
  22.                             }  
  23.                         }  
  24.                     }  
  25.                 }  
  26.             }  
  27.         }  
  28.     }  
  29.   
  30.     // First clear app state from services.  
  31.     for (int i=app.services.size()-1; i>=0; i--) {  
  32.         ServiceRecord sr = app.services.valueAt(i);  
  33.         synchronized (sr.stats.getBatteryStats()) {  
  34.             sr.stats.stopLaunchedLocked();  
  35.         }  
  36.         if (sr.app != null) {  
  37.             sr.app.services.remove(sr);  
  38.         }  
  39.         sr.app = null;  
  40.         sr.isolatedProc = null;  
  41.         sr.executeNesting = 0;  
  42.         sr.forceClearTracker();  
  43.         if (mDestroyingServices.remove(sr)) {  
  44.             if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);  
  45.         }  
  46.   
  47.         final int numClients = sr.bindings.size();  
  48.         for (int bindingi=numClients-1; bindingi>=0; bindingi--) {  
  49.             IntentBindRecord b = sr.bindings.valueAt(bindingi);  
  50.             if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b  
  51.                     + ": shouldUnbind=" + b.hasBound);  
  52.             b.binder = null;  
  53.             b.requested = b.received = b.hasBound = false;  
  54.         }  
  55.     }  
  56.   
  57.     // Clean up any connections this application has to other services.  
  58.     for (int i=app.connections.size()-1; i>=0; i--) {  
  59.         ConnectionRecord r = app.connections.valueAt(i);  
  60.         removeConnectionLocked(r, app, null);  
  61.     }  
  62.     app.connections.clear();  
  63.   
  64.     ServiceMap smap = getServiceMap(app.userId);  
  65.   
  66.     // Now do remaining service cleanup.  
  67.     for (int i=app.services.size()-1; i>=0; i--) {  
  68.         ServiceRecord sr = app.services.valueAt(i);  
  69.         // Sanity check: if the service listed for the app is not one  
  70.         // we actually are maintaining, drop it.  
  71.         if (smap.mServicesByName.get(sr.name) != sr) {  
  72.             ServiceRecord cur = smap.mServicesByName.get(sr.name);  
  73.             Slog.wtf(TAG, "Service " + sr + " in process " + app  
  74.                     + " not same as in map: " + cur);  
  75.             app.services.removeAt(i);  
  76.             continue;  
  77.         }  
  78.   
  79.         // Any services running in the application may need to be placed  
  80.         // back in the pending list.  
  81.         // 这里还是分很多种情况的  
  82.         // 允许重启时,如果当前服务所在进程crash超过两次,并且不是persistent的进程就结束不会重启了  
  83.         if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags  
  84.                 &ApplicationInfo.FLAG_PERSISTENT) == 0) {  
  85.             Slog.w(TAG, "Service crashed " + sr.crashCount  
  86.                     + " times, stopping: " + sr);  
  87.             EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,  
  88.                     sr.userId, sr.crashCount, sr.shortName, app.pid);  
  89.             bringDownServiceLocked(sr);  
  90.         } else if (!allowRestart) {  
  91.             // 不允许重启直接挂掉  
  92.             bringDownServiceLocked(sr);  
  93.         } else {  
  94.             //  
  95.             boolean canceled = scheduleServiceRestartLocked(sr, true);  
  96.   
  97.             // Should the service remain running?  Note that in the  
  98.             // extreme case of so many attempts to deliver a command  
  99.             // that it failed we also will stop it here.  
  100.             if (sr.startRequested && (sr.stopIfKilled || canceled)) {  
  101.                 if (sr.pendingStarts.size() == 0) {  
  102.                     sr.startRequested = false;  
  103.                     if (sr.tracker != null) {  
  104.                         sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),  
  105.                                 SystemClock.uptimeMillis());  
  106.                     }  
  107.                     if (!sr.hasAutoCreateConnections()) {  
  108.                         // Whoops, no reason to restart!  
  109.                         bringDownServiceLocked(sr);  
  110.                     }  
  111.                 }  
  112.             }  
  113.         }  
  114.     }  
  115.   
  116.     if (!allowRestart) {  
  117.         app.services.clear();  
  118.   
  119.         // Make sure there are no more restarting services for this process.  
  120.         for (int i=mRestartingServices.size()-1; i>=0; i--) {  
  121.             ServiceRecord r = mRestartingServices.get(i);  
  122.             if (r.processName.equals(app.processName) &&  
  123.                     r.serviceInfo.applicationInfo.uid == app.info.uid) {  
  124.                 mRestartingServices.remove(i);  
  125.                 clearRestartingIfNeededLocked(r);  
  126.             }  
  127.         }  
  128.         for (int i=mPendingServices.size()-1; i>=0; i--) {  
  129.             ServiceRecord r = mPendingServices.get(i);  
  130.             if (r.processName.equals(app.processName) &&  
  131.                     r.serviceInfo.applicationInfo.uid == app.info.uid) {  
  132.                 mPendingServices.remove(i);  
  133.             }  
  134.         }  
  135.     }  
  136.   
  137.     // Make sure we have no more records on the stopping list.  
  138.     int i = mDestroyingServices.size();  
  139.     while (i > 0) {  
  140.         i--;  
  141.         ServiceRecord sr = mDestroyingServices.get(i);  
  142.         if (sr.app == app) {  
  143.             sr.forceClearTracker();  
  144.             mDestroyingServices.remove(i);  
  145.             if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);  
  146.         }  
  147.     }  
  148.   
  149.     app.executingServices.clear();  
  150. }     
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final boolean scheduleServiceRestartLocked(ServiceRecord r,  
  2.         boolean allowCancel) {  
  3.     boolean canceled = false;  
  4.   
  5.     ServiceMap smap = getServiceMap(r.userId);  
  6.     if (smap.mServicesByName.get(r.name) != r) {  
  7.         ServiceRecord cur = smap.mServicesByName.get(r.name);  
  8.         Slog.wtf(TAG, "Attempting to schedule restart of " + r  
  9.                 + " when found in map: " + cur);  
  10.         return false;  
  11.     }  
  12.   
  13.     final long now = SystemClock.uptimeMillis();  
  14.   
  15.     if ((r.serviceInfo.applicationInfo.flags  
  16.             &ApplicationInfo.FLAG_PERSISTENT) == 0) {  
  17.         long minDuration = SERVICE_RESTART_DURATION;  
  18.         long resetTime = SERVICE_RESET_RUN_DURATION;  
  19.   
  20.         // Any delivered but not yet finished starts should be put back  
  21.         // on the pending list.  
  22.         final int N = r.deliveredStarts.size();  
  23.         if (N > 0) {  
  24.             for (int i=N-1; i>=0; i--) {  
  25.                 ServiceRecord.StartItem si = r.deliveredStarts.get(i);  
  26.                 si.removeUriPermissionsLocked();  
  27.                 //注意了,这里的canceled如果为true还是需要结束服务的  
  28.                 //还要关注一下delivery的上限和doneExecuting的上限  
  29.                 if (si.intent == null) {  
  30.                     // We'll generate this again if needed.  
  31.                 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT  
  32.                         && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {  
  33.                     //重新在pendingStart中添加si,所以会在下次执行时重新带入intent进去  
  34.                     r.pendingStarts.add(0, si);  
  35.                     long dur = SystemClock.uptimeMillis() - si.deliveredTime;  
  36.                     dur *= 2;  
  37.                     if (minDuration < dur) minDuration = dur;  
  38.                     if (resetTime < dur) resetTime = dur;  
  39.                 } else {  
  40.                     Slog.w(TAG, "Canceling start item " + si.intent + " in service "  
  41.                             + r.name);  
  42.                     canceled = true;  
  43.                 }  
  44.             }  
  45.             r.deliveredStarts.clear();  
  46.         }  
  47.   
  48.         r.totalRestartCount++;  
  49.         if (r.restartDelay == 0) {  
  50.             r.restartCount++;  
  51.             r.restartDelay = minDuration;  
  52.         } else {  
  53.             // If it has been a "reasonably long time" since the service  
  54.             // was started, then reset our restart duration back to  
  55.             // the beginning, so we don't infinitely increase the duration  
  56.             // on a service that just occasionally gets killed (which is  
  57.             // a normal case, due to process being killed to reclaim memory).  
  58.             if (now > (r.restartTime+resetTime)) {  
  59.                 r.restartCount = 1;  
  60.                 r.restartDelay = minDuration;  
  61.             } else {  
  62.                 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;  
  63.                 if (r.restartDelay < minDuration) {  
  64.                     r.restartDelay = minDuration;  
  65.                 }  
  66.             }  
  67.         }  
  68.   
  69.         r.nextRestartTime = now + r.restartDelay;  
  70.   
  71.         // Make sure that we don't end up restarting a bunch of services  
  72.         // all at the same time.  
  73.         boolean repeat;  
  74.         do {  
  75.             repeat = false;  
  76.             for (int i=mRestartingServices.size()-1; i>=0; i--) {  
  77.                 ServiceRecord r2 = mRestartingServices.get(i);  
  78.                 if (r2 != r && r.nextRestartTime  
  79.                         >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)  
  80.                         && r.nextRestartTime  
  81.                         < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {  
  82.                     r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;  
  83.                     r.restartDelay = r.nextRestartTime - now;  
  84.                     repeat = true;  
  85.                     break;  
  86.                 }  
  87.             }  
  88.         } while (repeat);  
  89.   
  90.     } else {  
  91.         // Persistent processes are immediately restarted, so there is no  
  92.         // reason to hold of on restarting their services.  
  93.         r.totalRestartCount++;  
  94.         r.restartCount = 0;  
  95.         r.restartDelay = 0;  
  96.         r.nextRestartTime = now;  
  97.     }  
  98.   
  99.     if (!mRestartingServices.contains(r)) {  
  100.         r.createdFromFg = false;  
  101.         mRestartingServices.add(r);  
  102.         r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);  
  103.     }  
  104.   
  105.     r.cancelNotification();  
  106.   
  107.     mAm.mHandler.removeCallbacks(r.restarter);  
  108.     // 最关键的操作在这里,忘ActivityManagerService的handler里面post一个重启的Runnable  
  109.     // 这个东西前面启动过程创建ServiceRecord时有的,很简单就是一个ServiceRestarter,它里面保存了这个ServiceRecord本身  
  110.     // 重启的时候根据这个record就可以直接启动服务了  
  111.     mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);  
  112.     r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;  
  113.     Slog.w(TAG, "Scheduling restart of crashed service "  
  114.             + r.shortName + " in " + r.restartDelay + "ms");  
  115.     EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,  
  116.             r.userId, r.shortName, r.restartDelay);  
  117.   
  118.     return canceled;  
  119. }  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class ServiceRestarter implements Runnable {  
  2.     private ServiceRecord mService;  
  3.   
  4.     void setService(ServiceRecord service) {  
  5.         mService = service;  
  6.     }  
  7.   
  8.     public void run() {  
  9.         synchronized(mAm) {  
  10.             //后面的事情就顺利成章了。  
  11.             performServiceRestartLocked(mService);  
  12.         }  
  13.     }  
  14. }  
    整个这个过程中,有好几个参数控制着是否需要重启,也定了很多参数的上限等等,这里单独列出来解释一下。
    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与其客户端的绑定如何实现,即跨进程调用问题。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值