AMS分析「 Activity啓動流程 」

Activity是Android應用程序的四大組件之一,負責管理Android應用程序的用戶界面,一般一個應用程序中包含很多個Activity,他們可能運行在一個進程中,也可能運行在不同的進程中。

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

Activity啓動.png

有兩個應用程序App1和App2,在App1的Activity A中點擊button 啓動 App2中的Activity B。
通過分析以上ActivityB的啓動過程來了解AMS對Activity的管理邏輯。

 

image.png

步驟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

1:Home Stack,這個是Launcher所在的Stack。 其實還有一些系統界面也運行在這個Stack上,例如近期任務.SystemUI等
2:FullScreen Stack,全屏的Activity所在的Stack。 但其實在分屏模式下,Id爲1的Stack只佔了半個屏幕。
3:Freeform模式的Activity所在Stack
4:Docked Stack 下文中我們將看到,在分屏模式下,屏幕有一半運行了一個固定的應用,這個就是這裏的Docked Stack
5: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


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) {
            //遍歷當前stack中所有的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) {
        
        //如果目標stack是front Stack, 則調用resumeTopActivityLocked
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
        //否則遍歷找到frontStack,執行resumeTopActivityLocked
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ……
                }
                if (isFrontStack(stack)) {
                    stack.resumeTopActivityLocked(null);
                }
    ……

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

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

11. ActivityStack. 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 B的ActicityRecord

當mResumedActivity不是Null的時候就調用startPausingLocked方法來暫停上一個Activity。ActivityStack有三個成員變量,mResumedActivity表示這個棧中處於激活狀態的Activity。這個棧中處於激活狀態的Acticity就是Acticity A了。mLastPausedActivity表示上一次被暫停的Activity,mLastPausingActivity即當前棧中正在被暫停的Activity.

mResumedActivity表示Activity A不是Null,所以調用startPasingLocked來暫停Activity A。

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

  1. 調用Activity的startActivity方法來啓動目標Activity
  2. 調用Instrumentation的方法execStartActivity方法,方便Instrumentation對交互進行監測
  3. 以上部分是在App1的進程中執行,之後會通過進程間通信調用到AMS服務中調用AMS的startActivity方法。此時進入SystemServer進程。
  4. 然後由AMS中管理Acticity核心調度的類ActivityStackSupervisor的方法startActivityMayWait來處理。該方法中主要是根據Intent從PMS中查詢目標Activity的信息
  5. ActivityStackSuperVisor的startActivityLocked方法主要是在AMS中找調用進程的processRecord信息,調用Activity的ActivityRecord信息,目標Activity還沒有啓動,所以需要先創建一個目標Activity的ActivityRecord信息。
  6. ActivityStackSuperVisor的StartActivityUncheckedLocked方法主要來處理啓動模式相關的邏輯,根據不同的啓動模式,找到相應的對的Task,然後又相應的Task進行處理
  7. ActivityStack將目標Activity加入到對應的Task頂部
  8. 調用ActivityStackSuperVisor的resumeTopActivityLocked方法找到處於前臺的Stack,然後調用它的resumeTopActivityLocked方法激活目標Activity.
  9. 當前的Stack的棧開始Pasuing調用的Activity

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的進程app和ApplicationThread是否爲空,因爲Activity A 所在的進程還沒有創建,所以兩個都爲空,直接執行mStackSupervisor的startSpecificActivityLocked來啓動新的Activity。

 

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);
    }

該方法比較簡單,根據目標Activity的ProcessName來查找對應的ProcessRecord.根據processRecord中的進程app和ApplicationThread來判斷,如果這兩個變量不爲空,說明目標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對象,然後把目標activity的Compoment轉化成一個字符串,方便傳輸。最後調用另一個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實例,反射調用ActivityThread的main方法。這樣ActivityThread主線程就在新的進程中啓動起來了。

接着看ActivityThread的main方法,此時已經在新的進程中執行了。我們來看ActivityThread的main方法。

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啓動第三部分

第四步:啓動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所在的應用程序也就啓動起來了。

 

image.png

Activity整體啓動流程時序圖如下:

Activity啓動流程.jpg


 

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