Service啓動流程總結-start和stop service

回顧

Activity啓動系列總結:
Activity啓動流程總結-ActivityThread
Activity啓動流程總結-生命週期
Activity啓動流程總結-超時判定機制

在Activity啓動流程中對APP進程和ActivityManagerService的交互過程以及應用進程啓動初始化過程做了簡單總結。Service作爲四大組件之一,它的啓動過程大體相似。

概述

在開發中我們使用context.startService(intent)和context.stopService(intent)來啓動和停止Service,Service的啓動和停止也是由ActivityManagerService來進行調度,本文通過跟蹤源碼來看看它的啓動和停止過程。

源碼探究

文中源碼基於 Android 10.0

startService過程

當執行context.startService(intent),將開始Service的啓動過程:
[ContextImpl#startService]

public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}

public ComponentName startForegroundService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, true, mUser);
}

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        // ···
        // 請求AMS啓動Service
        ComponentName cn = ActivityManager.getService().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), requireForeground,
                        getOpPackageName(), user.getIdentifier());
        if (cn != null) {
            // 省略檢查異常部分 ···
        }
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

可以看到通過IActivityManager調用ActivityManagerService進行startService。

接下來從APP進程來到ActivityManagerService:
[ActivityManagerService#startService]

public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage, int userId)
        throws TransactionTooLargeException {
    enforceNotIsolatedCaller("startService");
    // Refuse possible leaked file descriptors
    // 省略參數異常檢查 ···
    synchronized(this) {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res;
        try {
            // mServices實例是ActiveServices
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

該方法中調用ActiveServices的startServiceLocked方法進一步處理。

ActiveServices的startServiceLocked方法中又調用了另一個重載方法:
[ActiveServices#startServiceLocked]

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage,
        final int userId, boolean allowBackgroundActivityStarts)
        throws TransactionTooLargeException {
    // 省略變量callerFg部分(用於標記調用方進程是否屬於前臺)···
    
    // 查找或新建可用ServiceRecord
    ServiceLookupResult res =
        retrieveServiceLocked(service, null, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false, false);
    // 省略對res結果檢查部分 ···
    
    ServiceRecord r = res.record;
    
    // 省略後臺啓動檢查和啓動權限檢查部分 ···
    
    // 創建startCommand參數添加到pendingStarts集合中保存
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
        service, neededGrants, callingUid));
    
    // 調用startServiceInnerLocked進一步處理
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;

這裏獲取一個ServiceRecord(被包裝在ServiceLookupResult中),ServiceRecord用於保存Service信息,一個ServiceRecord對應一個運行Service。然後調用startServiceInnerLocked方法進一步執行啓動流程。

retrieveServiceLocked方法中,首先獲取userId對應的ServiceMap緩存集合,根據ComponentName(顯式意圖)或IntentFilter(隱式意圖)查找ServiceRecord。不存在的話,則從PackageManagerService查找匹配的ServiceInfo,之後創建ServiceRecord並保存在集合中。在返回結果前還會判斷是否允許不同應用和不同userId間的調用和啓動權限檢查。

接下來進入startServiceInnerLocked方法:
[ActiveServices#startServiceInnerLocked]

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    // ···
    // 進一步執行啓動
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
    if (error != null) {
        return new ComponentName("!!", error);
    }
    
    // 省略添加後臺啓動服務集合和啓動前臺服務判斷部分 ···
    
    return r.name;
}

進入bringUpServiceLocked方法:
[ActiveServices#bringUpServiceLocked]

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    // 判斷目標Service是否已啓動,首次將要啓動時ServiceRecord中還未設置IApplicationThread
    if (r.app != null && r.app.thread != null) {
        // 調度應用進程觸發onStartCommand回調
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
    
    // 判斷目標Service是否等待重啓
    if (!whileRestarting && mRestartingServices.contains(r)) {
        // If waiting for a restart, then do nothing.
        return null;
    }
    
    // ···
    
    // 重置目標Service的延遲啓動標識 ···
    // 檢查目標Service的userId對應用戶是否已啓動 ···
    // ···
    
    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
    ProcessRecord app;

    if (!isolated) {
        // 查找對應進程的ProcessRecord
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                    + " app=" + app);
        // 通過ProcessRecord的的IApplicationThread判斷進程是否啓動
        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                // 進一步執行啓動
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
    } else {
        // 省略ISOLATED PROCESS SERVICE部分 ···
    }

    // Not running -- get it started, and enqueue this service record
    // to be executed when the app comes up.
    if (app == null && !permissionsReviewRequired) {
        // 省略啓動進程部分,會調用mAm.startProcessLocked方法 ···
    }
    
    // ···
    
    // 將ServiceRecord添加至待啓動集合緩存,等待進場啓動後再執行啓動流程
    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }
    
    // 省略延遲啓動但是Service又被要求停止,會調用stopServiceLocked方法 ···
    
    return null;
}

該方法中首先判斷目標Service是否已啓動,如果已經啓動則會調度onStartCommand回調。接着判斷目標Service所屬進程是否啓動,如果已經啓動則進一步執行Service啓動流程,否則將ServiceRecord添加到待啓動集合,等待目標進程啓動完成後再執行啓動流程。

PS:這裏通過ProcessRecord是否持有IApplicationThread來判斷目標Service和目標進程是否啓動。當目標Service啓動後,會爲對應ServiceRecord設置ProcessRecord和IApplicationThread。當目標進程啓動後,會爲對應ProcessRecord設置IApplicationThread。可參考《Activity啓動流程總結-ActivityThread》

接下來進入關鍵方法realStartServiceLocked:
[ActiveServices#realStartServiceLocked]

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    // ···
    // 這裏給ServiceRecord設置了ProcessRecord,便可通過ServiceRecord判斷目標Service是否已啓動
    r.setProcess(app);
    // ···
    // ProcessRecord的services集合保存對應進程中所有運行的Service信息
    final boolean newService = app.services.add(r);
    // 超時設置相關
    bumpServiceExecutingLocked(r, execInFg, "create");
    // ···
    
    boolean created = false;
    try {
        // 調度應用進程啓動Service
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                app.getReportedProcState());
        // 前臺Service前臺通知相關
        r.postNotification();
        created = true;
    } catch (DeadObjectException e) {
        Slog.w(TAG, "Application dead when creating service " + r);
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        if (!created) {
            // 省略Service啓動失敗異常處理部分 ···
        }
    }
    
    // ···
    // 省略bind Service相關流程部分 ···
    // ···
    
    // 發送參數到應用進程,將觸發onStartCommand回調
    sendServiceArgsLocked(r, execInFg, true);
    
    // ···
}

這裏會先後兩次調度應用進程,應用側會先後往應用主進程消息隊列添加兩條任務消息,AMS側繼續往下執行它的其餘邏輯,下面需要到應用側看創建Service的過程。

在看create Service流程前,先看看sendServiceArgsLocked方法:
[ActiveServices#sendServiceArgsLocked]

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    // pendingStarts保存待派發執行startCommand的命令參數
    final int N = r.pendingStarts.size();
    if (N == 0) {
        return;
    }

    ArrayList<ServiceStartArgs> args = new ArrayList<>();
    
    while (r.pendingStarts.size() > 0) {
        // 封裝參數保存在args中 ···
    }

    // ParceledListSlice用於跨IPC傳輸大量Parcelable對象,可拆分爲多個binder_transact事務傳輸。
    ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
    slice.setInlineCountLimit(4);
    Exception caughtException = null;
    try {
        // 調度應用進程執行onStartCommand回調
        r.app.thread.scheduleServiceArgs(r, slice);
    } catch (TransactionTooLargeException e) {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large for " + args.size()
                + " args, first: " + args.get(0).args);
        Slog.w(TAG, "Failed delivering service starts", e);
        caughtException = e;
    } catch (RemoteException e) {
        // Remote process gone...  we'll let the normal cleanup take care of this.
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
        Slog.w(TAG, "Failed delivering service starts", e);
        caughtException = e;
    } catch (Exception e) {
        Slog.w(TAG, "Unexpected exception", e);
        caughtException = e;
    }
    
    if (caughtException != null) {
        // Keep nesting count correct
        // 省略異常處理部分 ···
    }
}

該方法中進行封裝批量StartCommand參數,然後調度應用進程執行scheduleServiceArgs方法。

接下來在應用側將會先後執行Service的create和start兩個消息任務。

onCreate階段

app.thread.scheduleCreateService將執行應用進程ActivityThread的scheduleCreateService方法,該方法中會發生H.CREATE_SERVICE消息至主線程,將執行handleCreateService方法

[ActivityThread#handleCreateService]

private void handleCreateService(CreateServiceData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    // 移除請求GC的消息
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        // 通過反射實例化目標Service
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
    } catch (Exception e) {
        // 省略異常處理 ···
    }

    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

        // 創建上下文ContextImpl
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        // context持有service實例
        context.setOuterContext(service);

        // 獲取應用進程Application實例
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        // service中保存傳入的參數,會調用attachBaseContext方法使mBase持有ContextImpl
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        // 調用Service的onCreate生命週期回調方法
        service.onCreate();
        // 以token爲key,添加service實例至集合緩存(token是AMS傳來的ServiceRecord客戶端代理,ServiceRecord繼承自Binder)
        mServices.put(data.token, service);
        try {
            // 通知AMS創建完成
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        // 省略異常處理 ···
    }
}

首先通過反射創建目標Service,之後創建ContextImpl並使ContextImpl和Service互相持有對方引用,獲取應用Application實例並使Service持有其引用。接着便調用onCreate生命週期回調方法。最後再通知AMS創建完成。

再來到ActivityManagerService,在它的serviceDoneExecuting方法中又調用了ActiveServices的serviceDoneExecutingLocked方法:
[ActiveServices#serviceDoneExecutingLocked]

void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
    // mDestroyingServices保存執行銷燬的Service
    boolean inDestroying = mDestroyingServices.contains(r);
    if (r != null) {
        // 判斷type類型。
        // 剛create時是SERVICE_DONE_EXECUTING_ANON,startCommand時是SERVICE_DONE_EXECUTING_START,stop時是SERVICE_DONE_EXECUTING_STOP。
        if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
            // 設置ServiceRecord相關參數,主要設置stopIfKilled(異常殺死是否不能夠重啓) ···
        } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
            // ···
        }
        final long origId = Binder.clearCallingIdentity();
        // 更新ServiceRecord中的狀態,移除超時消息
        serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        Binder.restoreCallingIdentity(origId);
    } else {
        Slog.w(TAG, "Done executing unknown service from pid "
                + Binder.getCallingPid());
    }

該方法主要是處理ServiceRecord中的參數和狀態更新設置,以及移除超時消息。

onStartCommand階段

app.thread.scheduleServiceArgs將會執行ActivityThread的scheduleServiceArgs方法:
[ActivityThread#scheduleServiceArgs]

public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
    List<ServiceStartArgs> list = args.getList();

    for (int i = 0; i < list.size(); i++) {
        // 依次取出參數,發送到主線程執行
        ServiceStartArgs ssa = list.get(i);
        ServiceArgsData s = new ServiceArgsData();
        s.token = token;
        s.taskRemoved = ssa.taskRemoved;
        s.startId = ssa.startId;
        s.flags = ssa.flags;
        s.args = ssa.args;

        sendMessage(H.SERVICE_ARGS, s);
    }
}

H.SERVICE_ARGS消息將會執行handleServiceArgs方法:
[ActivityThread#handleServiceArgs]

private void handleServiceArgs(ServiceArgsData data) {
    // 取出create階段創建並緩存的Service實例
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            if (data.args != null) {
                // 給Intent設置ClassLoader
                data.args.setExtrasClassLoader(s.getClassLoader());
                data.args.prepareToEnterProcess();
            }
            int res;
            if (!data.taskRemoved) {
                // 觸發Service的onStartCommand生命週期回調
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            // 這裏會阻塞當前線程,直到QueuedWork中的Runnable執行完畢。(SharedPreference會用到)
            QueuedWork.waitToFinish();

            try {
                // 通知AMS執行完成
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

這裏取出緩存的Service實例,然後便調用其onStartCommand生命週期回調方法。最後也會通知AMS進行狀態更新操作。

到這裏,Service的啓動流程便完成,先後經過了onCreate和onStartCommand生命週期回調。

Service超時機制

在Service啓動過程中,AMS會進行超時機制相關設置,包括設置超時時間、觸發超時處理、移除超時處理。

設置超時

回到ActiveServices#realStartServiceLocked方法中,在調度應用進程創建Service前,會先執行bumpServiceExecutingLocked方法,在該方法中會調用scheduleServiceTimeoutLocked方法進行超時監聽的設置。

[ActiveServices#scheduleServiceTimeoutLocked]

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }
    // 獲取SERVICE_TIMEOUT_MSG消息
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    // 發送延遲消息
    mAm.mHandler.sendMessageDelayed(msg,
            proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}

該方法中發送一個延遲消息SERVICE_TIMEOUT_MSG,當20s(啓動前臺服務)或200s(啓動後臺服務)後仍沒有執行完,則會觸發超時處理。

移除超時

當應用進程側完成Service啓動後,便會調用AMS側的ActiveServices#serviceDoneExecutingLocked方法,其中會進行超時消息的移除:
[ActiveServices#serviceDoneExecutingLocked]

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
        boolean finishing) {
    // ···
    // 移除SERVICE_TIMEOUT_MSG消息
    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
    // ···
}
觸發超時

若在規定時間內,應用側沒有及時完成啓動流程和通知AMS,則會觸發超時邏輯,將會執行ActiveServices的serviceTimeout方法。

[ActiveServices#serviceTimeout]

void serviceTimeout(ProcessRecord proc) {
    // ···
    if (anrMessage != null) {
        // dump ANR信息和觸發ANR彈窗
        proc.appNotResponding(null, null, null, null, false, anrMessage);
    }
}

當觸發超時後,將會觸發ANR。

當目標Service進程未啓動時

在前面的ActiveServices#bringUpServiceLocked方法中,會首先判斷若目標Service進程尚未已經啓動,則會先啓動應用進程,然後將ServiceRecord保存在mPendingServices集合中

當應用進程啓動後,會調用ActivityManagerService的attachApplicationLocked方法,在該方法中會執行待啓動的Service。
[ActivityManagerService#attachApplicationLocked]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // ···
    // thread.bindApplication
    // ···
    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            // 啓動等待對應進程啓動的Service
            didSomething |= mServices.attachApplicationLocked(app, processName);
            checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }
    // ···
}

調用了ActiveServices的attachApplicationLocked方法:
[ActiveServices#attachApplicationLocked]

boolean attachApplicationLocked(ProcessRecord proc, String processName)
        throws RemoteException {
    boolean didSomething = false;
    // Collect any services that are waiting for this process to come up.
    if (mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            // 遍歷待啓動ServiceRecord
            for (int i=0; i<mPendingServices.size(); i++) {
                sr = mPendingServices.get(i);
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                    continue;
                }

                mPendingServices.remove(i);
                i--;
                proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
                        mAm.mProcessStats);
                // 執行realStartServiceLocked進行啓動流程
                realStartServiceLocked(sr, proc, sr.createdFromFg);
                didSomething = true;
                if (!isServiceNeededLocked(sr, false, false)) {
                    // We were waiting for this service to start, but it is actually no
                    // longer needed.  This could happen because bringDownServiceIfNeeded
                    // won't bring down a service that is pending...  so now the pending
                    // is done, so let's drop it.
                    bringDownServiceLocked(sr);
                }
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception in new application when starting service "
                    + sr.shortInstanceName, e);
            throw e;
        }
    }
    // Also, if there are any services that are waiting to restart and
    // would run in this process, now is a good time to start them.  It would
    // be weird to bring up the process but arbitrarily not let the services
    // run at this point just because their restart time hasn't come up.
    if (mRestartingServices.size() > 0) {
        // 省略待重啓Service部分 ···
    }
    return didSomething;
}

可以看到,當應用進程啓動完成通知AMS後,會再進行Service啓動流程。

stopService過程

停止Service通過調用context.stopService方法:
[ContextImpl#stopService]

public boolean stopService(Intent service) {
    warnIfCallingFromSystemProcess();
    return stopServiceCommon(service, mUser);
}

private boolean stopServiceCommon(Intent service, UserHandle user) {
    try {
        // ···
        // 請求AMS執行stopService調度
        int res = ActivityManager.getService().stopService(
            mMainThread.getApplicationThread(), service,
            service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
        // ···
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

和startService一樣,也是調用ActivityManagerService的方法,在stopService中又會調用ActiveServices的stopServiceLocked方法:
[ActiveServices#stopServiceLocked]

int stopServiceLocked(IApplicationThread caller, Intent service,
        String resolvedType, int userId) {
    // ···
    // If this service is active, make sure it is stopped.
    ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, null,
            Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false);
    if (r != null) {
        if (r.record != null) {
            final long origId = Binder.clearCallingIdentity();
            try {
                stopServiceLocked(r.record);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return 1;
        }
        return -1;
    }

    return 0;
}

首先查找目標ServiceRecord,然後調用stopServiceLocked方法。

stopServiceLocked方法最終會調用bringDownServiceLocked方法:
[ActiveServices#bringDownServiceLocked]

private final void bringDownServiceLocked(ServiceRecord r) {
    // ···
    
    if (r.app != null) {
        if (r.app.thread != null) {
            try {
                // ···
                r.app.thread.scheduleStopService(r);
            } catch (Exception e) {
                // ···
            }
        } else {
            // ···
        }
    } else {
        // ···
    }
    
    // ···
}

調度應用進程執行stop操作。

scheduleStopService將發送H.STOP_SERVICE消息,最終將執行handleStopService方法:
[ActivityThread#handleStopService]

private void handleStopService(IBinder token) {
    // 獲取緩存的Service實例
    Service s = mServices.remove(token);
    if (s != null) {
        try {
            if (localLOGV) Slog.v(TAG, "Destroying service " + s);
            // 執行onDestroy回調
            s.onDestroy();
            s.detachAndCleanUp();
            Context context = s.getBaseContext();
            if (context instanceof ContextImpl) {
                final String who = s.getClassName();
                ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
            }

            QueuedWork.waitToFinish();

            try {
                // 通知AMS
                ActivityManager.getService().serviceDoneExecuting(
                        token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            // ···
        }
    } else {
        Slog.i(TAG, "handleStopService: token=" + token + " not found.");
    }
    //Slog.i(TAG, "Running services: " + mServices);
}

應用側stopService就是從mServices集合中移除Service實例,並執行它的onDestroy生命週期回調方法,最後通知AMS。

總結

Service的啓動和停止都是通過發請求給ActivityManagerService,由AMS來進行調度分發。AMS側通過ServiceRecord記錄運行Service的信息,應用側通過mServices集合保存反射創建的Service實例。AMS發送啓動或停止指令到應用側後,由應用側對Service實例執行對應的生命週期回調。

下面用時序圖總結這兩個流程。
啓動流程:

啓動service

停止流程:

停止service

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章