深入理解四大組件(三)Service 的啟動(dòng)過程

概述

Service 的啟動(dòng)過程和根 Activity 啟動(dòng)過程有部分相似的知識(shí)點(diǎn),Service 的啟動(dòng)過程將分為兩個(gè)部分來(lái)進(jìn)行講解,分別是 ContextImpl 到 ActivityManageService 的調(diào)用過程和 ActivityThread 啟動(dòng) Service。

1. ContextImpl 到 AMS 的調(diào)用過程

ContextImpl 到 AMS 的調(diào)用過程很簡(jiǎn)短,如圖所示:

ContextImpl 到 AMS 的調(diào)用過程

要啟動(dòng)Service,我們會(huì)調(diào)用 startService 方法,它在 ContextWrapper 中實(shí)現(xiàn),代碼如下所示:
frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {
    Context mBase;
...
  @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
...    
}

在 startService 方法中會(huì)調(diào)用 mBase 的 startService 方法,Context 類型的 mBase 對(duì)象具體指的是什么呢?通過學(xué)習(xí)根 Activity 啟動(dòng)過程我們知道,ActivityThead 啟動(dòng) Activity 時(shí)會(huì)調(diào)用如下代碼創(chuàng)建 Activity 的上下文環(huán)境:
frameworks/base/core/java/android/app/ActivityThread.java

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);  //1
         ...
                }
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
                ...
        }
        return activity;
}

在注釋 1 處創(chuàng)建上下文對(duì)象 appContext,并傳入 Activity 的 attach 方法中,將 Activity 與上下文對(duì)象 appContext 關(guān)聯(lián)起來(lái),這個(gè)上下文對(duì)象 appContext 的具體類型是什么?我們接著查看 createBaseContextForActivity 方法,代碼如下所示:
frameworks/base/core/java/android/app/ActivityThread.java

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
...

    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, r.token, displayId, r.overrideConfig);
    appContext.setOuterContext(activity);
    Context baseContext = appContext;
    ...
    return baseContext;
}

上下文對(duì)象 appContext 的具體類型就是 ContextImpl,在 Activity 的 attach 方法中將 ContextImpl 賦值給 ContextWrapper 的成員變量 mBase,因此,上面提出的問題就得到了解答,mBase 具體指向的就是 ContextImpl。那么,緊接著來(lái)查看 ContextImpl 的 startService 方法,代碼如下所示:
frameworks/base/core/java/android/app/ContextImpl.java

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, mUser);
}
 private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            /**
            * 1
            */
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), getOpPackageName(), user.getIdentifier());
      ...
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在 startService 方法中會(huì)返回 startServiceCommon 方法,在 startServiceCommon 方法中會(huì)在注釋 1 處調(diào)用 AMS 的代理 IActivityManager 的 startService 方法,最終調(diào)用的是 AMS 的 startService 方法。

2. ActivityThread 啟動(dòng) Service

ActivityThread 啟動(dòng) Service 的時(shí)序圖如圖所示:

ActivityThread 啟動(dòng) Service 的時(shí)序圖

接下來(lái)我們來(lái)查看 AMS 的 startService 方法,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, String callingPackage, int userId)
        throws TransactionTooLargeException {
 ...
    synchronized(this) {
 ...
        ComponentName res = mServices.startServiceLocked(caller, service,
                resolvedType, callingPid, callingUid, callingPackage, userId);  //1
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

注釋 1 處調(diào)用 mServices 的 startServiceLocked 方法,mServices 的類型是 ActiveServices,ActiveServices 的 startServiceLocked 方法代碼如下所示:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
     ···
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);  //1
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
        ServiceRecord r = res.record;  //2
···
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);  //3
        return cmp;  
    }

注釋 1 處的 retrieveServiceLocked 方法會(huì)查找是否有與參數(shù) service 對(duì)應(yīng)的 ServiceRecord,如果沒有找到,就會(huì)調(diào)用 PackageManagerService 去獲取參數(shù) service 對(duì)應(yīng)的 Service 信息,并封裝到 ServiceRecord 中,最后將 ServiceRecord 封裝為 ServiceLookupResult 返回。其中 ServiceRecord 用于描述一個(gè) Service,和此前講過的 ActivityRecord 類似,在注釋 2 處通過注釋 1 處返回的 ServiceLookupResult 得到參數(shù) service 對(duì)應(yīng)的 ServiceRecord,并傳入到注釋 3 處的 startServiceInnerLocked 方法中。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, String callingPackage, final int userId)
            throws TransactionTooLargeException {
      ...
        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }

   ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
 
     ...
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
     ...
        return r.name;
    }

startServiceLocked 方法的末尾 return 了 startServiceInnerLocked 方法,而 startServiceInnerLocked 方法中又調(diào)用了 bringUpServiceLocked 方法,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

  private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
...
  final String procName = r.processName;  //1
  ProcessRecord app;
  if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);  //2
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {  //3
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode,
                    mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);  //4
                    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 (app == null && !permissionsReviewRequired) {  //5
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {  //6
              ...
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }
 ...     
  return null;
}

在注釋 1 處得到 ServiceRecord 的 processName 的值賦值給 procName ,其中 processName 用來(lái)描述 Service 想要在哪個(gè)進(jìn)程運(yùn)行,默認(rèn)是當(dāng)前進(jìn)程,我們也可以在 AndroidManifes 配置文件中設(shè)置 android:process 屬性來(lái)新開啟一個(gè)進(jìn)程運(yùn)行 Service。注釋 2 處將 procName 和 Service 的 uid 傳入到 AMS 的 getProcessRecordLocked 方法中,來(lái)查詢是否存在一個(gè)與 Service 對(duì)應(yīng)的 ProcessRecord 類型的對(duì)象 app,ProcessRecord 主要用來(lái)記錄運(yùn)行的應(yīng)用程序進(jìn)程的信息。注釋 5 處判斷 Service 對(duì)應(yīng)的 app 為 null 則說明用來(lái)運(yùn)行 Service 的應(yīng)用程序進(jìn)程不存在,則調(diào)用注釋 6 處的 AMS 的 startProcessLocked 方法來(lái)創(chuàng)建對(duì)應(yīng)的應(yīng)用程序進(jìn)程。注釋 3 處判斷如果用來(lái)運(yùn)行 Service 的應(yīng)用程序進(jìn)程存在,則調(diào)用注釋 4 處的 realStartServiceLocked 方法來(lái)啟動(dòng) Service:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
   ...
    try {
       ...
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        r.postNotification();
        created = true;
    } catch (DeadObjectException e) {
      ...
    } 
    ...
}

在 realStartServiceLocked 方法中調(diào)用了 app.thread 的 scheduleCreateService 方法。其中 app.thread 是 IApplicationThread 類型的,它的實(shí)現(xiàn)是 ActivityThread 的內(nèi)部類 ApplicationThread。ApplicationThread 的 scheduleCreateService 方法如下所示:
frameworks/base/core/java/android/app/ActivityThread.java

public final void scheduleCreateService(IBinder token,
         ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
     updateProcessState(processState, false);
     CreateServiceData s = new CreateServiceData();
     s.token = token;
     s.info = info;
     s.compatInfo = compatInfo;
     sendMessage(H.CREATE_SERVICE, s);
 }

首先將要啟動(dòng)的信息封裝成 CreateServiceData 對(duì)象并傳給 sendMessage 方法,sendMessage 方法向 H 發(fā)送 CREATE_SERVICE 消息,sendMessage 方法有多個(gè)重載方法,最終調(diào)用的 sendMessage 方法如下所示:
frameworks/base/core/java/android/app/ActivityThread.java

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

這里 mH 指的是 H,它是 ActivityThread 的內(nèi)部類并繼承自 Handler,是應(yīng)用程序進(jìn)程中主線程的消息管理類。我們接著查看 H 的handleMessage 方法:
frameworks/base/core/java/android/app/ActivityThread.java

private class H extends Handler {
      public static final int LAUNCH_ACTIVITY = 100;
      public static final int PAUSE_ACTIVITY = 101;
...
public void handleMessage(Message msg) {
          if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
          switch (msg.what) {
          ···
                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
            ...
}

handleMessage 方法根據(jù)消息類型為 CREATE_SERVICE,會(huì)調(diào)用 handleCreateService 方法:
frameworks/base/core/java/android/app/ActivityThread.java

    private void handleCreateService(CreateServiceData data) {
        unscheduleGcIdler();
        //獲取要啟動(dòng) Service 的應(yīng)用程序的 LoadedApk
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);  //1
        Service service = null;
        try {
            //獲取類加載器
            java.lang.ClassLoader cl = packageInfo.getClassLoader();  //2
            //創(chuàng)建 Service 實(shí)例
            service = (Service) cl.loadClass(data.info.name).newInstance();  //3
        } catch (Exception e) {
             ···
        }
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            //創(chuàng)建 Service 的上下文環(huán)境 ContextImpl 對(duì)象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);  //4
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //初始化 Service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());  //5
            service.onCreate();  //6
            mServices.put(data.token, service);  //7
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            ···
        }
    }

在注釋 1 處獲取要啟動(dòng) Service 的應(yīng)用程序的 LoadedApk,LoadedApk 是一個(gè) APK 文件的描述類。在注釋 2 處通過調(diào)用 LoadedApk 的 getClassLoader 方法來(lái)獲取類加載器。接著在注釋 3 處根據(jù) CreateServiceData 對(duì)象中儲(chǔ)存的 Service 信息,創(chuàng)建 Service 實(shí)例。在注釋 4 處創(chuàng)建 Service 的上下文環(huán)境 ContextImpl 對(duì)象。在注釋 5 處通過 Service 的 attach 方法來(lái)初始化 Service。在注釋 6 處調(diào)用 Service 的 onCreate 方法,這樣 Service 就啟動(dòng)了。在注釋 7 處啟動(dòng)的 Service 加入到 ActivityThread 的成員變量 mServices 中,其中 mServices 是 ArrayMap 類型。

Service 的啟動(dòng)過程就講到這里,接下來(lái)我們學(xué)習(xí) Service 的綁定過程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容