service的啓動過程

疫情似乎仍然沒有好轉的跡象,鄰居被查出來感染上了病毒,搞得人心惶惶的。待在家裏啥也做不了,就好好學習吧。
今天看了下service的啓動過程,然後將其捋一捋加深印象。

1.service的啓動流程

如下圖所示爲service的啓動流程
在這裏插入圖片描述
我們可以看到,我們調用的startService是ContextImpl的startService方法,然後會遠程調用AMS,AMS再調用ActiveServices類的方法去啓動一個service。
這裏我們重點看下bringUpServiceLocked方法。
在註釋1處,如果service已經啓動了,那麼就只會調用sendServiceArgsLocked方法,然後直接返回,這個方法會觸發service的onStartCommand方法,所以當一個service被start兩次,onCreate只會執行一次,而onStartCommand卻會執行兩次,原因就在這裏。
在註釋2處,如果service沒啓動,但是進程已經啓動了,那麼就會執行realStartServiceLocked方法,這個方法就會真正的啓動一個service,並執行service的周期函數。
在註釋3處,如果進程沒有啓動,那麼就會調用AMS的mAm.startProcessLocked方法去啓動進程。
在註釋4處,將serviceRecord添加到penddingServices裏面。如果當前進程沒有啓動,那麼這個serviceRecord就會添加到penddingServices列表裏面,當進程啓動之後,就會去處理這個列表。

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        //1.service已經啓動
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
       ......
        if (!isolated) {
            //2.service沒啓動,進程已經啓動
            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.shortName, e);
                }
            }
        } else {
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }
        if (app == null && !permissionsReviewRequired) {
            //3.進程沒啓動,調用startProcessLocked啓動進程
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) {
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": process is bad";
                Slog.w(TAG, msg);
                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }

       ......
       //4.將ServiceRecord添加到mPendingServices裏面
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
        ......
    }

我們再來看下進程啓動的大致流程,看看這個pendingService是什麼時候被處理的。
如下圖所示爲應用的一個大致的啓動流程,AMS通過socket向Zygote進程發出啓動進程的請求,Zygote便會fork處一個應用進程,應用進程創建成功之後,便會向AMS發起binder調用,最終會執行attachApplication方法,將應用的binder對象註冊到AMS裏面,就是告訴AMS應用進程已經創建好了。
接着AMS就會調用bindApplication方法,嚮應用端發起binder調用,去通知應用進程做初始化。
在這裏插入圖片描述
我們來看下attachApplication的實現。
從註釋2中,我們可以看出最終調用了ActiveServices的attachApplicationLocked方法,而在這個方法裏面處理了pendingServices。

//ActivityManagerService
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        ......
        //1.調用attachApplicationLocked
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        ......
    }
}

//ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread,
         int pid, int callingUid, long startSeq) {
      ......
      //2.調用ActiveServices的attachApplicationLocked方法
      mServices.attachApplicationLocked(app, processName);
      ......
}

//ActiveServices
boolean attachApplicationLocked(ProcessRecord proc, String processName)
         throws RemoteException {
     boolean didSomething = false;
     //2.處理pendingServices
     if (mPendingServices.size() > 0) {
         ServiceRecord sr = null;
         try {
             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(sr, proc, sr.createdFromFg);
                 didSomething = true;
                 if (!isServiceNeededLocked(sr, false, false)) {
                     bringDownServiceLocked(sr);
                 }
             }
         } catch (RemoteException e) {
             Slog.w(TAG, "Exception in new application when starting service "
                     + sr.shortName, e);
             throw e;
         }
     }
     ......
 }

其實service的啓動流程也不復雜,下圖是service的啓動過程,可以幫助理解
在這裏插入圖片描述

發佈了131 篇原創文章 · 獲贊 21 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章