1. 程式人生 > >Activity的啟動流程分析

Activity的啟動流程分析

Activity是Android應用程式的四大元件之一,負責管理Android應用程式的使用者介面,一般一個應用程式中包含很多個Activity,他們可能執行在一個程序中,也可能執行在不同的程序中。

我們主要通過啟動在不同程序中的Activity,來分析Activity的啟動流程及AMS對Activity的管理邏輯。


有兩個應用程式App1和App2,在App1的Activity A中點選button 啟動 App2中的Activity B。

通過分析以上ActivityB的啟動過程來了解AMS對Activity的管理邏輯。

步驟1:Activity A告訴AMS服務準備啟動Activity B

步驟2:AMS服務處理並通知Activity A所在的程序pause Activity A,Activity A所在的程序處理完成之後,通知AMS服務Activity A已經完成pause工作。

步驟3:Activity B所在的程序沒有啟動,AMS服務首先啟動一個新的程序。新的程序啟動完成之後,通知AMS服務程序啟動完成。

步驟4:AMS服務通知新的程序來啟動Activity B,新的程序啟動Activity B完成之後,通知AMS服務Activity B啟動完成。

在分析Activity啟動流程之前我們先簡單介紹下應用程序和AMS服務通訊方法,AMS服務和應用程序間屬於不同的程序,兩者之間通訊肯定和Binder有關。我們知道系統的服務都是實現了Binder的服務端,應用程序要想和它通訊需要獲取它的代理端。

然而AMS服務是如何和應用程序通訊的呢?在建立一個新的應用程序之後,系統首先會啟動ActivityThread,ActivityThread是應用程序的主執行緒,在ActivityThread建立的時候會建立一個ApplicationThread的物件。這個ApplicationThread實現了一個Binder的服務端。新的程序建立完成之後通知AMS服務的之後同時把自己程序的ApplicationThread的代理端送給AMS服務。AMS服務中儲存了所有應用程序的ApplicationThread的代理物件。

所以AMS要想給應用程序傳送訊息,只需要得到目標應景程序的ApplicationThread的代理端物件即可。

由於Activity的啟動流程比較複雜,一步一步來分析,這樣比較容易理解。

第一步:準備啟動

1. Activity.startActivity

在activity A中點選button啟動activity B呼叫了 Activity的startActivity方法。

public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        ……
    }
在該方法中呼叫了activity的startActivityForResult方法來啟動Intent描述的Activity B,第二個引數-1表示不需要返回結果

2. Activity. startActivityForResult

public void startActivityForResult(
            String who, Intent intent, int requestCode, @Nullable Bundle options) {

        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, who,
                intent, requestCode, options);
       ……
    }

在這個方法中最終呼叫了Instrumentation的execStartActivity方法來啟動Activity。應用程式和系統之間的互動都集中交給Instrumentation來做,方便系統對這些活動的監視。

下面我們看下引數mMainThread.getApplicationThread(),mMainThread就是應用app1所在程序的主執行緒ActivityThread,getApplicationThread返回的是一個ActivityThread的內部類ApplicationThread,該類是一個Binder物件,實現了Binder的服務端,通過引數傳入到AMS服務中,AMS服務中則會儲存它的客戶端,這樣AMS就可以通過它和應用程序通訊了。

引數mToken是一個Binder代理物件,它指向了AMS中一個儲存的ActivityRecord資訊,mToken代表了Activity A,它通過引數傳遞給AMS後,AMS根據它就可以得到Activity A的資訊了。

3. Instrumentation. execStartActivity

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
       
        try {
            //intent做程序間傳輸的準備工作
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            //程序間傳輸,最終呼叫到AMS服務中
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        }
      ……
    }

該方法中通過ActivityManagerNative的getDefault方法來獲得AMS的代理物件,然後呼叫它的startActivity方法通過程序間傳輸呼叫到AMS服務startActivity方法,程序間的通訊此處不再詳細介紹。

 到此處為止,以上的操作都是在應用程式App1的程序中執行的。以下程式碼就進入了SystemServer程序的AMS服務中

4. AMS.startActivity

public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }

該方法的引數中caller就是App1程序的ApplicationThread的binder物件,IBinder就是指向Activity A的ActivityRecord的Binder物件,緊接著這個方法就呼叫了startActivityAsUser方法

5. AMS. startActivityAsUser

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
       ……
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }

呼叫了activityStackSupervisor的startActivityMayWait方法,ActivityStackSupervisor是Activity排程的核心類,Activity的排程相關的工作都是在ActivityStackSuperVisor中處理,主要管理Task和Stack.它是在AMS啟動的時候建立的。

6. startActivityMayWait

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
            Bundle options, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
        ……
        //PMS服務根據intent查詢要啟動的Activity B的資訊,儲存到ActivityInfo中
        intent = new Intent(intent);
        ActivityInfo aInfo =
                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
            ……
            
            //決定當前活動的stack
ActivityContainer container = (ActivityContainer)iContainer;
            final ActivityStack stack;
            if (container == null || container.mStack.isOnHomeDisplay()) {
                stack = mFocusedStack;
            } else {
                stack = container.mStack;
            }


           ……
            //將PMS中查詢到的Activity B的資訊當做引數
            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);

          ……
    }

resolveActivity方法中最終是PMS服務根據Intent資訊去查詢即將要啟動的ActivityB的詳細資訊,

然後是查詢對應的ActivityStack,即將要啟動的Activity應該在放到哪個ActivityStack中,從引數傳遞過來的iContainer為null,所以要啟動的Activity應該在mFocusStack中來管理。mFocusStack指的是當前獲得焦點的ActivityStack。

Android中一般情況下有以下幾種ActivityStack

· Home Stack,這個是Launcher所在的Stack。 其實還有一些系統介面也執行在這個Stack上,例如近期任務.SystemUI等

· FullScreen Stack,全屏的Activity所在的Stack。 但其實在分屏模式下,Id為1的Stack只佔了半個螢幕。

· Freeform模式的Activity所在Stack

· Docked Stack 下文中我們將看到,在分屏模式下,螢幕有一半運行了一個固定的應用,這個就是這裡的Docked Stack

· Pinned Stack 這個是畫中畫Activity所在的Stack

第一個和第二個是較常用的Stack,後邊三個的Stack主要和多視窗模式有關。由此可見,大部分應用程式其實都是在同一個Stack中即FullScreenStack中。

然後呼叫startActivityLocked方法繼續啟動Activity.

7. startActivityLocked

final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            ActivityContainer container, TaskRecord inTask) {
       
	    //callerApp 代表呼叫方的應用程序,即App1的應用程序
        ProcessRecord callerApp = null;
        if (caller != null) {
		    //根據caller找到AMS中儲存的App1的processRecord物件
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
			    //得到App1應用程序的pid和應用的uid
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            }
			……
        }

        ……
		//即呼叫者的Activity元件
        ActivityRecord sourceRecord = null;
		//返回結果的Activity元件
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
		    //根據resultTo Binder物件得到其指向的ActivityRecord,即Activity A的ActivityRecord資訊
            sourceRecord = isInAnyStackLocked(resultTo);
            //一般情況下請求的Activity和要接收返回結果的Activity是同一個
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }

        final int launchFlags = intent.getFlags();

        ……
		
        //根據準備的資訊,建立一個即將啟動的ActivityRecord物件,即Activity B
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);

        ……
        //將剛建立的目標Activity的ActivityRecord作為引數,繼續呼叫startActivityUncheckedLocked方法來啟動
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);

        ……
        return err;
    }

StartActivityLocked方法主要作用是建立一個即將要啟動的Activity的ActivityRecord物件。

該方法中首先根據引數傳進來的代表Activity A的binder物件,來獲得Activity A的ActivityRecord資訊。然後獲取呼叫程序的pid和呼叫程式的uid。

根據這些資訊和ainfo建立一個ActivityRecord物件r,代表ActivityB。

這樣就獲取了呼叫者的Activity A的元件資訊,和即將要啟動的目標Activity B的資訊。分別儲存在sourceRecord和r中

最後呼叫startActivityUncheckedLocked方法來繼續啟動Activity B

8. startActivityUncheckedLocked

final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
		
        //根據flag獲取相應的啟動模式,我們程式碼中沒有設定啟動模式,所以預設應該是標準模式,這三個變數都應該是false		
	    final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
		……
		//即將要啟動activity的 task
		ActivityStack targetStack;
		……
		//是否新建一個Task
		boolean newTask = false;
		……
		//獲取Activity A的Task,然後賦值給B,即兩個Activity位於同一個Task中
		 else if (sourceRecord != null) {
//獲取Activity A所在的Task
            final TaskRecord sourceTask = sourceRecord.task;
            //將A所在的ActivityStack作為B啟動的Stack
            targetStack = sourceTask.stack;
            targetStack.moveToFront("sourceStackToFront");
            //獲取ActivityStack中的 top Task是不是和當前的Task一致,如果不一致則將當前的Task移動到ActivityStack的頂端
            final TaskRecord topTask = targetStack.topTask();
            if (topTask != sourceTask) {
                targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
                        r.appTimeTracker, "sourceTaskToFront");
            }			
		……
		//將當前Activity Stack mLastPausedActivity設定為null
		targetStack.mLastPausedActivity = null;
		//呼叫startActivityLocked方法
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);

這個方法中主要處理的工作就是Activity四種啟動模式的處理。根據Intent中的flag標誌來決定不同的啟動模式,然後根據不同的啟動模式來決定Activity在Task中的位置。這個方法比較複雜,我們只關注了和我們邏輯相關的程式碼。關於啟動模式的處理就不在詳細分析。

由於我們沒有設定Activity B 的啟動模式,即Activity B預設是標準的啟動模式。Activity A和Activity B應該放在同一個Task中。

在前面我們也已經分析過了,一般情況下所有的應用程式的Activity都是位於同一個ActivityStack中的。此處程式碼中也可以分析出把ActivityA所在的ActivityStack直接當成啟動Activity B的Activity Stack.

我們通過一幅圖來了解下Task和ActivityStack的關係。



Task和Stack的關係

Android系統中的每一個Activity都位於一個Task中。一個Task可以包含多個Activity,同一個Activity也可 能有多個例項。 在AndroidManifest.xml中,我們可以通過 android:launchMode 來控制Activity在Task中的例項。

另外,在startActivity的時候,我們也可以通過 setFlag 來控制啟動的Activity在Task中的例項。

Task管理的意義還在於近期任務列表以及Back棧。 當你通過多工鍵(有些裝置上是長按Home鍵,有些裝置上是專門提供的多工鍵)調出多工時,其實就是從ActivityManagerService獲取了最近啟動的Task列表。

其實在ActivityManagerService與WindowManagerService內部管理中,在Task之外,還有一層容器, 這個容器應用開發者和使用者可能都不會感覺到或者用到,但它卻非常重要,那就是Stack,Android系統中的多視窗管理,就是建立在Stack的資料結構上的 。 一個Stack中包含了多個Task,一個Task中包含了多個Activity(Window)

最後呼叫獲取的ActivityTask的startActivityLocked來繼續啟動

9. ActivityStack . startActivityLocked

final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
			//獲取要啟動的Task物件
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
		
		 TaskRecord task = null;
        if (!newTask) {
            //遍歷AMS中所有的Task,找到目標task,然後將即將要啟動的Activity加入到Task的棧頂
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // All activities in task are finishing.
                    continue;
                }
                if (task == r.task) {
                    
                    if (!startIt) {
                        task.addActivityToTop(r);
                        r.putInHistory();
                        ……
		//傳入的resume位 true,然後呼叫	resumeTopActivitiesLocked方法繼續啟動Activity			
        if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        }

該方法主要作用是變數所有Task,找到目標task然後將即將要啟動的Activity的ActivityRecord加入到棧頂

10. ActivityStackSuperVisor. resumeTopActivitiesLocked

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        
        //如果目標task是front Stack呼叫resumeTopActivityLocked
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
        //然後遍歷找到時frontStack 的task執行resumeTopActivityLocked
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ……
                }
                if (isFrontStack(stack)) {
                    stack.resumeTopActivityLocked(null);
                }
    ……

這個方法的主要作用就是找到frontStack然後呼叫它的resumeTopActivityLocked方法。

由於我們的ActivityA啟動ActivityB都是位於同一個Task,所以當前Task就是frontStack,所以直接呼叫ActicityStack的resumeTopActivityLocked方法。resumeTopActivityLocked方法則直接有呼叫了resumeTopActivityInnerLocked方法

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
 
        ……
        //找到棧頂第一個不是出於finishing狀態的ActicityRecord
        final ActivityRecord next = topRunningActivityLocked(null);
		……
		//呼叫startPausingLocked方法來暫停上一個Activity
		 if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }

只看這個方法中的關鍵部分。首先呼叫topRunningActivityLocked方法來找到當前棧頂不是出於fininshing狀態的ActicityRecord。我們剛才把即將要啟動的ActicityRecord r加入到了當前Task的棧頂,所以這個next就是即將要啟動的Acticity BActicityRecord

mResumedActivity不是Null的時候就呼叫startPausingLocked方法來暫停上一個ActivityActivityStack有三個成員變數,mResumedActivity表示這個棧中處於啟用狀態的Activity。這個棧中處於啟用狀態的Acticity就是Acticity A了。mLastPausedActivity表示上一次被暫停的ActivitymLastPausingActivity即當前棧中正在被暫停的Activity.

mResumedActivity表示Activity A不是Null,所以呼叫startPasingLocked來暫停Activity A

Activity啟動流程的第一部分就到此為止。總結下這部分做的主要工作 

1. 呼叫ActivitystartActivity方法來啟動目標Activity

2. 呼叫Instrumentation的方法execStartActivity方法,方便Instrumentation對互動進行監測

3. 以上部分是在App1的程序中執行,之後會通過程序間通訊呼叫到AMS服務中呼叫AMSstartActivity方法。此時進入SystemServer程序。

4. 然後由AMS中管理Acticity核心排程的類ActivityStackSupervisor的方法startActivityMayWait來處理。該方法中主要是根據IntentPMS中查詢目標Activity的資訊

5. ActivityStackSuperVisorstartActivityLocked方法主要是在AMS中找呼叫程序的processRecord資訊,呼叫ActivityActivityRecord資訊,目標Activity還沒有啟動,所以需要先建立一個目標ActivityActivityRecord資訊。

6. ActivityStackSuperVisorStartActivityUncheckedLocked方法主要來處理啟動模式相關的邏輯,根據不同的啟動模式,找到相應的對的Task,然後又相應的Task進行處理

7. ActivityStack將目標Activity加入到對應的Task頂部

8. 呼叫ActivityStackSuperVisorresumeTopActivityLocked方法找到處於前臺的Stack,然後呼叫它的resumeTopActivityLocked方法啟用目標Activity.

9. 當前的Stack的棧開始Pasuing呼叫的Activity


以上幾個步驟完成了AMS對呼叫Activity及目標Activity的資訊收集處理,根據啟動模式來決定將目標Activity方法那個棧中,然後目標棧開始講當前處於啟用狀態的Activity Pause掉給目標Activity騰地方。

接著看第二部分,如何呼叫Activity 的由Resume變為Pause的過程


第二步:暫停Activity A

12. ActivityStack.startPausingLocked

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        //mResumeActivity代表當前啟用的Activity,即Activity A
	ActivityRecord prev = mResumedActivity;
	……
        //當前處於啟用狀態mResumedActivity 的設定為null
   	mResumedActivity = null;
        //即將要處於pasuing狀態的Activity 就是Activity A
        mPausingActivity = prev;
        mLastPausedActivity = prev;
	……
        //將Activity A的狀態設定為PAUSING
        prev.state = ActivityState.PAUSING;
        //找到當前的棧頂的topActivity就是 Activity B 
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
         //呼叫程序不為null,且呼叫程序的ApplicationThread不為null
	 if (prev.app != null && prev.app.thread != null) {
            try {
               ……
                通過呼叫程序的ApplicationThread通知呼叫程序schedulePauseActivity方法
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);

首先得到要Pause的Activity prev,就是mResumeActivity,代表當前處於啟用狀態的Activity A,然後把mResumeActivity設定為null,因為Activity A馬上要為pause狀態了,而Activity B還沒有啟動,所以此時沒有啟用狀態的Activity。

把mPausingActivity設定為Activity B,表示處於Pausing狀態的Activity. 同時prev.state = ActivityState.PAUSING,把Activity A的狀態設定為PAUSING。

Prev是Activity A的ActivityRecord 物件,prev.app代表的是Activity A所在程序的ProcessRecord,prev.app.thread就是Activity A 所在程序的ApplicationThread,我們在前面說過,ApplicationThread是一個Binder物件,服務端在應用程序中,AMS服務中這持有每個程序的Binder客戶端,這樣AMS就可以嚮應用程序傳送訊息了。

程序間通訊Binder機制此處不解釋

此方法最後會通過程序間通訊呼叫Activity A所在程序的schedulePauseActivity方法,繼續Activity Pause的過程。

13. ApplicationThread. schedulePauseActivity

public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
                    configChanges);
        }

應用程序的ApplicationThread是ActivityThread的一個內部類,引數token是一個Binder型別的物件,指向了AMS中與Activity A對應的一個ActivityRecord。當前要進入pause狀態,傳進來的finished位false。

此方法傳送了一個PAUSE_ACTIVITY的Message給Handler,接著看Handler的handleMessage方法 

14. H.handleMessage

ase PAUSE_ACTIVITY:

            ……

            handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,

                            (msg.arg1&2) != 0);

呼叫handlePauseActivity方法來處理


15. ActivityThread.handPauseActivity

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            
            //呼叫Activity A的onPause方法
            performPauseActivity(token, finished, r.isPreHoneycomb());

            //等待pause狀態的資料寫入完成.
            if (r.isPreHoneycomb()) {
                QueuedWork.waitToFinish();
            }

             ……
                try {
                    //程序間通訊,呼叫AMS的ActivityPause方法
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {

在ActivityThread中的mActivities集合中儲存了當前程序中的所有的Activity,每個Activity都用一個ActivityClientRecord表示,集合中以binder為key來儲存,同樣AMS服務中的所有Activity也是在一個集合中儲存,在AMS服務中的每一個Activity用ActivityRecord來表示,同樣key值也是Binder物件,我們知道Binder物件是可以程序間傳遞的,所以使用binder來做key值,可以使應用程序的ActivityClientRecord和AMS中的ActivityRecord一一對應起來。

此方法中首先根據AMS中傳遞過了的binder物件來獲取應用程序中的ActivityClientRecord物件,由於引數token指向的是AMS中的代表Activity A的ActivityRecord,所以此處獲取的就是Activity A的ActivityClientRecord.

然後呼叫preformPauseActivity方法,這個方法中會呼叫Activity A的onSaveInstance方法,然後呼叫Activity A的onPause方法。

因為onSaveInstance方法會儲存當前的Activity資訊,要寫入磁碟進行IO操作,所以QueuedWork.waitToFinish()方法用來等待儲存操作完成。

最後,又是程序間通訊,呼叫AMS的activityPaused方法,此處離開了Activity A的程序,進入了AMS的 SystemServer程序。

16. AMS.activityPaused

public final void activityPaused(IBinder token) {
            //獲或Activity 所在的ActivityStack
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                //呼叫目標ActivityStack的activityPauseLocked方法
                stack.activityPausedLocked(token, false);
            }
        }

Token代表的是Activity A ,此處根據token找到Activity A所在的ActivityStack,然後由目標Stack來處理activityPause邏輯

17. ActivityStack.activityPauseLocked

final void activityPausedLocked(IBinder token, boolean timeout) {
        //根據token獲取Activity A的ActivityRecord物件
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            //移除pause超時訊息
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
               //呼叫completePauseLocked方法繼續執行pause邏輯
                completePauseLocked(true);
            } 
	……

Token代表的是Activity的binder物件,根據token可以獲得Activity A的資訊ActivityRecord,移除Pause超時訊息,當執行完pause邏輯的ActivityRecord和我們執行pause邏輯前的activityRecord一樣的時候,即是同一個Activity,就可以呼叫completePauseLocked方法來完成Activity A Pause最後的邏輯了。

18. ActivityStack. completePauseLocked

if (resumeNext) {
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();
            if (!mService.isSleepingOrShuttingDown()) {
                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
            } 
			……
        }

resumeNext就是completePauseLocked傳進來的引數,為true。呼叫mStackSupervisor的getFocusedStack()方法來獲取正在處理的ActivityStack. mService.isSleepingOrShuttingDown,判斷AMS服務是否處於正常啟用狀態,然後呼叫mStackSupervisor的resumeTopActivitiesLocked繼續處理。

19. ActivityStackSuperVisor. resumeTopActivitiesLocked

這個步驟我們在第10步驟的時候處理過,此處和第10步邏輯一致,如果當前的ActivityStack是frontStack,直接呼叫ActivityStack的resumeTopActivityLocked。

ActivityStack的resumeTopActivityLocked方法則直接有呼叫了ActivityStack的resumeTopActivityInnerLocked方法。

20. ActivityStack. resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
   ……
		//找到棧頂的Activity,此時棧頂的acitvity就是即將要啟動的Activity B
		final ActivityRecord next = topRunningActivityLocked(null);
		……
		
		//我們知道,在前面Activity A變為pause狀態的時候,我們就把mResumeActivity 置為了Null
		if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }
		……
		//即將要啟動的Activity處於一個新的程序,目前還沒有啟動
		if (next.app != null && next.app.thread != null) {
			……
		}else{
			……
			//來啟動目標Activity
			mStackSupervisor.startSpecificActivityLocked(next, true, true);
		}

在第11步的時候,已經走過這個方法的邏輯,那個時候呼叫這個方法來啟用目標Activity的時候,判斷mResumeActivity不為空,說明當前有一個處於正在啟用狀態的Activity,需要先將原先的Activity變為pause狀態。

Activity A變為Pause狀態後,再次走到這個方法來啟用目標Activity,此時mResumeActivity已經為空,所以不需要再執行pause的邏輯。

然後判斷目標Activity next的程序appApplicationThread是否為空,因為Activity A 所在的程序還沒有建立,所以兩個都為空,直接執行mStackSupervisor的startSpecificActivityLocked來啟動新的Activity

第三步:啟動新程序

21. ActivityStackSuperVisor. startSpecificActivityLocked

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //獲取目標Activity的程序ProcessRecord
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        ……
        //,由於目標Activity所在程序還沒有建立,所以為空
        if (app != null && app.thread != null) {
           ……

        }
        //
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

該方法比較簡單,根據目標ActivityProcessName來查詢對應的ProcessRecord.根據processRecord中的程序appApplicationThread來判斷,如果這兩個變數不為空,說明目標Activity的程序和執行環境已經具備,直接啟動Activity就可以,我們知道目前目標Activity的程序還沒有啟動,所以需要呼叫AMS先啟動一個目標Activity的程序。

22. AMS. startProcessLocked

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            ……) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
		 if (!isolated) {
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
			
			 String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;
		
		……
		startProcessLocked(
            app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);

得到一個processRecord物件,然後把目標activityCompoment轉化成一個字串,方便傳輸。最後呼叫另一個startProcessLocked方法來繼續處理新程序的啟動。

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
			
			int uid = app.uid;
            int[] gids = null;
			……
			 //從PMS服務中查詢目標應用對應的許可權組
			 final IPackageManager pm = AppGlobals.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
					……
					gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
			 ……
			 app.gids = gids;
			 
			 ……
			  if (entryPoint == null) entryPoint = "android.app.ActivityThread";
			 呼叫Process的靜態方法啟動一個新的程序 
			 Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);

這個方法做的主要工作就是呼叫Process的靜態方法啟動一個新的程序,啟動新的程序的過程大概是,Zygote程序會fork一個新的子程序出來,子程序建立完成之後,classLoader載入ActivityThread類並建立一個ActivityThread例項,反射呼叫ActivityThreadmain方法。這樣ActivityThread主執行緒就在新的程序中啟動起來了。

接著看ActivityThreadmain方法,此時已經在新的程序中執行了。我們來看ActivityThreadmain方法。

23. ActivityThread.main

public static void main(String[] args) {
       
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        
        Looper.loop();
}

這個方法主要工作就是呼叫Looper.prepareMainLooper建立一個訊息迴圈佇列,然後呼叫Looper.loop進入訊息迴圈,當前執行緒進入訊息迴圈中,使當前執行緒成為新程序的主執行緒,然後建立一個ActivityThread物件,呼叫Attach方法。

24. ActivityThread.attach

final ApplicationThread mAppThread = new ApplicationThread();

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ……
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
            ……
        } else {
		} 

在AMS服務啟動的時候,初始系統程序的執行環境的時候,那時候傳入的引數system為true,表示是系統程序,而這次是普通的應用程序,所以引數system為false。ActivityManagerNative.getDefault()方法獲取AMS的代理,呼叫attachApplication方法傳送一個程序間通訊的請求,將建立的ApplicationThread物件傳遞給AMS服務。

ApplicationThread是一個ActivityThread本地binder物件,Binder的服務端在ActivityThread中,將Binder物件傳遞給AMS服務,則AMS服務中儲存它的代理,AMS就獲得了與新程序通訊的方式。

此前的程式碼實在新建的程序中,即應用App2所在的程序,然後通過程序間通訊,下面的程式碼再次進入AMS服務中。

25. AMS.attachApplication

          ApplicationInfo appInfo = app.instrumentationInfo != null
                    ? app.instrumentationInfo : app.info;
					
            //程序間呼叫:呼叫新程序的bindApplication方法
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
         ……
		 
        if (normalMode) {
            try {
			    //呼叫ActivityStackSupervisor的方法來啟動新的Activity
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            }
		……
    }

attachApplication方法獲得呼叫程序的ID之後,直接呼叫attachApplicationLocked方法繼續執行。

attachApplicationLocked方法主要工作

首先根據程序ID,從mPidsSelfLocked中查詢對應程序的ProcessRecord,這個ProcessRecord就是新程序的物件,只不過它之前沒有指向任何程序,因為新的程序還沒有建立。現在新程序已經建立完成,所以需要將它指向新的程序。

從PMS服務中查詢新程序相關的ContentProvider的資訊,然後通過程序間通訊請求,呼叫thread的bindApplication方法。這個thread就是新程序的ApplicationThread的代理端Binder物件,通過它最終呼叫到新程序中ActivityThread的handleBindApplication方法。來進一步處理新程序的執行環境的初始化。主要是新程序Application的初始化,Instrumentation的初始化和安裝相關的ContentProvider.。

交給ActivityStackSupervisor來繼續處理attchApplication邏輯。

26. ActivityStackSuperVisor. attachApplicationLocked

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        //遍歷所有的stack,找到處於前臺的ActivityStack
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFrontStack(stack)) {
                    continue;
                }
				//找到處於棧頂的ActivityRecord
                ActivityRecord hr = stack.topRunningActivityLocked(null);
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
						    //呼叫realstartActivityLocked方法來啟動目標Activity
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                          ……
            }
        }

此方法的主要工作就是遍歷並找到目標stack,然後拿到這個ActivityStack棧頂的ActivityRecord,這就是目標Activity,是我們之前放到棧頂的。得到要啟動的Activity資訊之後,做了這麼多的準備工作,終於要真正來啟動新的Activity了。

第四步:啟動Activity B

27. ActivityStackSuperVisor. realStartActivityLocked

 final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
			……
			//將新程序的資訊儲存到ActivityRecord的app變數中
			r.app = app;
			
			//獲取目標Task
			final TaskRecord task = r.task;
			
			//找到Task對用的Stack
			final ActivityStack stack = task.stack;
			
			//跨程序呼叫,通知目標程序來啟動Activity
			app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

這個方法中首先將ActivityRecord的app物件指向了新的程序,這樣ActivityRecord就和新的程序關聯了起來。

然後通過目標程序ApplicationThread代理Binder物件發起程序間通訊請求,呼叫目標程序的scheduleLaunchActivity方法來啟動新的Activity.

此處程式碼通過跨程序呼叫再次進入到了目標程序中。

28. ApplicationThread. scheduleLaunchActivity

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig,…… ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);
			//根據程序間傳遞的訊息,初始化ActivityClientRecord
            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
			……
			//傳送訊息,最終有Handler來處理
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

呼叫到ActivityThread內部的ApplicationThread中,該ApplicationThread實現了ApplicationThreadNative,這樣就實現了程序間通訊的Binder服務端。Binder程序間通訊不在詳細解釋

最終傳送訊息,有Handler的HandMessage來處理。在handleMessage中又呼叫了ActivityThread的handleLaunchActivity來處理。

29. ActivityThread.handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

	//呼叫performLaunchActivity方法來啟動Activity
	  Activity a = performLaunchActivity(r, customIntent);
	//Activity啟動完成後,呼叫handlResumeActivity來使Activity進入resume啟用狀態
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
……

首先呼叫performLaunchActivity來建立一個Activity物件,並呼叫Activity的onCreate方法完成Activity啟動,隨後呼叫handleResumeActivity方法,啟用Activity,時Activity計入resume狀態。

30. ActivityThread.performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
     ActivityInfo aInfo = r.activityInfo;
	//獲取Activity的packageInfo資訊
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
	//獲取Activity的Component資訊
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

	呼叫Instrumentation類來建立一個根據Activity的資訊Activity物件
        Activity activity = null;
	java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);

	 //建立完成後,呼叫Activity的attach方法來初始化Activity
	 if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                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);

	……
	//呼叫Activity的onCreate方法
  	mInstrumentation.callActivityOnCreate(activity, r.state);

	……
	//執行Activity的onStart方法
	if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
	……
	//呼叫Activity的onRestoreInstancestate方法
	if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
	……
	//呼叫Activity的onPostCreate方法
	 mInstrumentation.callActivityOnPostCreate(activity, r.state);

         ……
	//把建立的對應的ActivityClientRecord以binder為鍵值,儲存到mActivities中
	 mActivities.put(r.token, r);

在新的程序中,根據AMS傳遞過來的資訊建立了一個ActivityClientRecord物件,該物件和AMS服務中的一個ActivityRecord對應。

在這個方法中,根據目標Activity B的ActivityClientRecord,最終呼叫Instrumentation類來建立一個Acitivity,建立過程就是ClassLoader載入對應的Activity類,用反射方法建立一個物件。

建立完新的Activity物件後,即Activity B的物件,然後呼叫它的onCreate方法,這樣Activity B的onCreate物件就會被呼叫,以便載入自己定義的使用者介面,以及其他的初始化方法。

onCreate方法呼叫完成之後,然後依次呼叫Activity的onStart,onRestoreInstanceState,onPostCreate方法等。這個就是Activity生命週期執行的邏輯。

到此為止,ActivityB就啟動完成了,它啟動起來之後,意味著ActivityB所在的應用程式也就啟動起來了。