Android深入四大組件(二)Service的啟動過程

來源:互聯網
上載者:User

標籤:span   restart   log   default   alt   remote   instance   ota   rem   

相關文章
Android深入理解四大組件系列

前言

此前我用較長的篇幅來介紹Android應用程式的啟動過程(根Activity的啟動過程),這一篇我們接著來分析Service的啟動過程。建議閱讀此篇文章前,請先閱讀Android深入四大組件(一)應用程式啟動過程(前篇)和Android深入四大組件(一)應用程式啟動過程(後篇)這兩篇文章。

1.ContextImpl到ActivityManageService的調用過程

要啟動Service,我們會調用startService方法,它的實現在ContextWrapper中,代碼如下所示。
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方法中會調用mBase的startService方法,Context類型的mBase對象具體指的是什麼呢?在Android深入四大組件(一)應用程式啟動過程(後篇)這篇文章中我們講過ActivityThread啟動Activity時會調用如下代碼建立Activity的上下文環境。
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處建立內容物件appContext ,並傳入Activity的attach方法中,將Activity與內容物件appContext 關聯起來,這個內容物件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;}

這裡可以得出結論,內容物件appContext 的具體類型就是ContextImpl 。Activity的attach方法中將ContextImpl賦值給ContextWrapper的成員變數mBase中,因此,mBase具體指向就是ContextImpl 。
那麼,我們緊接著來查看ContextImpl的startService方法,代碼如下所示。
frameworks/base/core/java/android/app/ContextImpl.java.java

Overridepublic 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方法中會return startServiceCommon方法,在startServiceCommon方法中會在注釋1處調用ActivityManageService(AMS)的代理對象ActivityManagerProxy(AMP)的startService方法,最終會調用AMS的startService方法。至於注釋1處的代碼為何會調用AMS的startService方法,在Android深入四大組件(一)應用程式啟動過程(前篇)這篇文章中已經講過,這裡不再贅述。
ContextImpl到ActivityManageService的調用過程如下面的時序圖所示。

2.ActivityThread啟動Service

我們接著來查看AMS的startService方法。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

Overridepublic 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處調用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, 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方法中又調用了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;            }        } ...     }

在注釋1處得到ServiceRecord的processName的值賦值給procName ,其中ServiceRecord用來描述Service的android:process屬性。注釋2處將procName和Service的uid傳入到AMS的getProcessRecordLocked方法中,來查詢是否存在一個與Service對應的ProcessRecord類型的對象app,ProcessRecord主要用來記錄啟動並執行應用程式進程的資訊。注釋5處判斷Service對應的app為null則說明用來運行Service的應用程式進程不存在,則調用注釋5處的AMS的startProcessLocked方法來建立對應的應用程式進程。關於建立應用程式進程請查看Android應用程式進程啟動過程(前篇) 和Android應用程式進程啟動過程(後篇)這兩篇文章。注釋3處判斷如果用來運行Service的應用程式進程存在,則調用注釋4處的realStartServiceLocked方法:

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方法中調用了app.thread的scheduleCreateService方法。其中app.thread是IApplicationThread類型的,它的實現是ActivityThread的內部類ApplicationThread,其中ApplicationThread繼承了ApplicationThreadNative,而ApplicationThreadNative繼承了Binder並實現了IApplicationThread介面。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);    }

首先將要啟動的資訊封裝成CreateServiceData 對象並傳給sendMessage方法,sendMessage方法向H發送CREATE_SERVICE訊息,H是ActivityThread的內部類並繼承Handler。這個過程和應用程式的啟動過程(根Activity啟動過程)是類似的。我們接著查看H的handleMessage方法。
frameworks/base/core/java/android/app/ActivityThread.java

  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方法根據訊息類型,調用了handleCreateService方法:

frameworks/base/core/java/android/app/ActivityThread.java

 private void handleCreateService(CreateServiceData data) {        unscheduleGcIdler();        LoadedApk packageInfo = getPackageInfoNoCheck(                data.info.applicationInfo, data.compatInfo);//1        Service service = null;        try {            java.lang.ClassLoader cl = packageInfo.getClassLoader();//2            service = (Service) cl.loadClass(data.info.name).newInstance();//3        } catch (Exception e) {           ...            }        }        try {            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//4            context.setOuterContext(service);            Application app = packageInfo.makeApplication(false, mInstrumentation);            service.attach(context, this, data.info.name, data.token, app,                    ActivityManagerNative.getDefault());//5            service.onCreate();//6            mServices.put(data.token, service);//7         ...        } catch (Exception e) {            ...        }    }

注釋1處擷取要啟動Service的應用程式的LoadedApk,LoadedApk是一個APK檔案的描述類。注釋2處通過調用LoadedApk的getClassLoader方法來擷取類載入器。接著在注釋3處根據CreateServiceData對象中儲存的Service資訊,將Service載入到記憶體中。注釋4處建立Service的上下文環境ContextImpl對象。注釋5處通過Service的attach方法來初始化Service。注釋6處調用Service的onCreate方法,這樣Service就啟動了。在注釋7處將啟動的Service加入到ActivityThread的成員變數mServices中,其中mServices是ArrayMap類型。
最後給出這一節的時序圖。

歡迎關注我的公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。

Android深入四大組件(二)Service的啟動過程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.