1. 程式人生 > >Android之Service自啟動流程

Android之Service自啟動流程

 當Service被異常銷燬後,預設都會自動重啟,但Service的自動重啟是如何實現的尼?下面就來梳理一下Service的自動重啟流程。
 無論Service是啟動還是繫結成功,都會呼叫ActiveServicesserviceDoneExecutingLocked方法,來看一下這個方法的實現。

    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後會呼叫ActiveServiceskillServicesLocked方法,來看看這個方法的實現。

    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程序重啟)原理解析