Activity 組件的啓動流程

Activity 組件的啓動過程

當我們在 Launcher 中點擊一個 app 時,發生了什麼?

1. 參與角色

  • Activity
  • Launcher
  • AMS
  • Instrumentation:監控應用程序和系統之間的交互操作
  • ActivityThread:ActivityThread 用來描述一個應用程序進程,系統每當啓動一個應用程序進程時,都會在該進程里加載一個 ActivityThread 實例,並且執行 main 方法,從而開啓主線程 looper 循環。並且每一個在該進程中啓動的 Activity 組件,都會保存這個 ActivityThread 實例在成員變量 mMainThread 中
  • ApplicationThread:看名字會很困惑以爲也是一個線程,實則不然,它是一個 Binder 本地對象,可與 AMS 進行 IPC 通信。(繼承 IApplicationThread.Stub)
  • ActivityStack:用來描述一個 Activity 組件堆棧
  • ResolveInfo:PMS.resolveIntent(),解析 intent 得到的一個信息
  • ProcessRecord:在 AMS 中,每一個應用程序進程都用 ProcessRecord 來描述,並且保存在 AMS 內部。
  • TaskRecord:任務棧的表現形式
  • ActivityRecord:AMS 中的一個 Binder 本地對象,每一個已經啓動的 Activity 組件在 AMS 中都有一個對應的 ActivityRecord 對象,用來維護對應的 Activity 組件的運行狀態和信息。通常 Activity 中的 mToken 成員變量會指向它,mToken 是一個 Binder 代理對象

2. 啓動流程

2.1 Launcher 發生的事

當我們在 Launcher 中點擊一個 app 圖標時,會調用 startActivitySafely 來啓動這個 app 的根 Activity。

void startActivitySafely(Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            startActivity(intent);
        } catch (ActivityNotFoundException e) {
            ......
        } catch (SecurityException e) {
            ......
        }
    }

因此參數 intent 所包含的信息有

action = "android.intent.action.MAIN"
category = "android.intent.category.LAUNCHER"
cmp = "com.yjnull.demo.activity.MainActivity"

Launcher 是怎麼獲得這些信息的呢?Launcher 在最開始啓動的過程中會向 PMS 查詢所有 Activity 名稱等於 “android.intent.action.MAIN”,並且 Category 等於 “android.intent.category.LAUNCHER” 的 Activity 組件。這樣當用戶點擊一個快捷圖標時,就可以拿到相應 Activity 組件的信息並啓動起來。

接着上述代碼講,調用父類的 startActivity(intent),即 Activity.startActivity(intent),這裏經過層層調用會走到 Activity.startActivityForResult(Intent intent, int requestCode) 這裏去。

public void startActivityForResult(Intent intent, int requestCode) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                ......
            }
        } else {
            ......
        }
    }

這裏通過方法名其實就可以知道,會把啓動 Activity 的操作委託給 Instrumentation 去做。所以 Instrumentation 是什麼鬼。。這裏有段代碼上的原文註釋:

Base class for implementing application instrumentation code. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml’s <instrumentation> tag.

大意就是它用來監控應用程序和系統之間的交互操作。因爲 Activity 的啓動最後需要通過 AMS 啓動,而 AMS 又是運行在系統進程 (system 進程) 的,所以算是和系統的交互操作,因此需要交給 Instrumentation 來執行。

execStartActivity 方法裏有幾個參數需要注意:

  • mMainThread.getApplicationThread():Launcher 組件所在的應用程序進程的 ApplicationThread 的 Binder 本地對象。爲了將它傳遞給 AMS,這樣 AMS 接下來就可以通過它來通知 Launcher 組件進入 Paused 狀態。
  • mToken:類型爲 IBinder,是一個 Binder 代理對象,指向 AMS 中一個類型爲 ActivityRecord 的 Binder 本地對象。將它傳遞給 AMS 的話,AMS 就可以通過它獲得 Launcher 組件的詳細信息了。

接下來我們走進 InstrumentationexecStartActivity 方法

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ......
        try {
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        null, 0, token, target != null ? target.mEmbeddedID : null,
                        requestCode, false, false);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }

這裏可以看到會通知 AMS 來將一個 Activity 組件啓動起來。當然中間還有一些過程,無非就是 ActivityManagerProxy 將一些參數進行封裝寫入到 Parcel 對象中,然後通過 mRemote 向 AMS 發送一個類型爲 START_ACTIVITY_TRANSACTION 的進程間通信請求。

2.2 AMS 中做的事

接着上述來,Launcher 通過 Instrumentation 發起了一個 START_ACTIVITY_TRANSACTION 的進程間通信,因此會回調到 AMS 中的 startActivity 方法中去,如下所示:

public final int startActivity(IApplicationThread caller,
            Intent intent, String resolvedType, Uri[] grantedUriPermissions,
            int grantedMode, IBinder resultTo,
            String resultWho, int requestCode, boolean onlyIfNeeded,
            boolean debug) {
        return mMainStack.startActivityMayWait(caller, intent, resolvedType,
                grantedUriPermissions, grantedMode, resultTo, resultWho,
                requestCode, onlyIfNeeded, debug, null, null);
    }

這裏可以看到將啓動操作委託給 mMainStack 了,mMainStack 是什麼呢?它是一個類型爲 ActivityStack 的成員變量,用來描述一個 Activity 組件堆棧。OK,那我們進到 ActivityStack 中的 startActivityMayWait 方法看看,這個方法挺長,所以分析就在註釋裏了:

Step 1 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/**
* caller: mMainThread.getApplicationThread(), Launcher 組件所在的應用程序進程ApplicationThread 的 Binder 本地對象。
* intent: 前面所構造的 Intent
* resolvedType: null
* grantedUriPermissions: null
* grantedMode: 0
* resultTo: Launcher Activity 中的 mToken,指向 AMS 中一個類型爲 ActivityRecord 的 Binder 本地對象
* resultWho: null
* requestCode: -1
* onlyIfNeeded: false
* debug: false
* outResult: null
* config: null
*/
final int startActivityMayWait(IApplicationThread caller,
            Intent intent, String resolvedType, Uri[] grantedUriPermissions,
            int grantedMode, IBinder resultTo,
            String resultWho, int requestCode, boolean onlyIfNeeded,
            boolean debug, WaitResult outResult, Configuration config) {
        ......
        // 省略部分代碼
        boolean componentSpecified = intent.getComponent() != null;
        
        // Don't modify the client's object!
        intent = new Intent(intent);

        // 這裏定義了一個 ActivityInfo 對象,目測是用來整合前面傳進來的 Intent 中所描述的信息
        ActivityInfo aInfo;
        try {
            // 這裏通過 PMS 去解析參數 intent 的內容,以便可以獲得即將啓動的 Activity 組件的更多信息
            ResolveInfo rInfo =
                AppGlobals.getPackageManager().resolveIntent(
                        intent, resolvedType,
                        PackageManager.MATCH_DEFAULT_ONLY
                        | ActivityManagerService.STOCK_PM_FLAGS);
            // 將上面解析出來的信息保存在 ActivityInfo 中
            aInfo = rInfo != null ? rInfo.activityInfo : null;
        } catch (RemoteException e) {
            aInfo = null;
        }

        ......

        synchronized (mService) {
            int callingPid;
            int callingUid;
            if (caller == null) {
                ......
            } else {
                callingPid = callingUid = -1;
            }
            ......
            
            int res = startActivityLocked(caller, intent, resolvedType,
                    grantedUriPermissions, grantedMode, aInfo,
                    resultTo, resultWho, requestCode, callingPid, callingUid,
                    onlyIfNeeded, componentSpecified);
            
            ......
            
            return res;
        }
    }

其實總結下來無非就是通過 PMS 將 Intent 中的參數解析出來,並獲取到即將啓動的 Activity 組件的更多信息,也就是 com.yjnull.demo.activity.MainActivity 的更多信息。

Step 2 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/**
* ...... 同上
* aInfo: 通過 PMS 去解析參數 intent 的內容,得到 ResolveInfo.activityInfo
* resultTo: Launcher Activity 中的 mToken,指向 AMS 中一個類型爲 ActivityRecord 的 Binder 本地對象
* resultWho: null
* requestCode: -1
* callingPid: -1
* callingUid: -1
* onlyIfNeeded: false
* componentSpecified: true
*/
final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType,
            Uri[] grantedUriPermissions,
            int grantedMode, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, boolean onlyIfNeeded,
            boolean componentSpecified) {
        int err = START_SUCCESS;

        ProcessRecord callerApp = null;
        if (caller != null) {
            // 這裏的 mService 指向 AMS,所獲得的 ProcessRecord 對象實際上指向了 Launcher 組件所在的應用程序進程信息。
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                ......
            }
        }
        
        ......
        // sourceRecord 用來描述 Launcher 組件的一個 ActivityRecord
        ActivityRecord sourceRecord = null;
        ......
        if (resultTo != null) {
            // 通過 resultTo 找到 Launcher 在 Activity 組件堆棧中的 index,這裏的 resultTo 就是前面在 Launcher 進程中 Instrumentation 傳遞的 mToken 參數。
            int index = indexOfTokenLocked(resultTo);
            ......
            if (index >= 0) {
                sourceRecord = (ActivityRecord)mHistory.get(index);
                ......
            }
        }

        ......
        // 這裏創建一個 ActivityRecord 用來描述即將啓動的 Activity 組件,即 MainActivity 組件,可以注意,前面我們說過 mToken 就是指向 ActivityRecord 的,所以可以關注這個 ActivityRecord 對象,看看它是怎麼傳遞給 Activity 類的成員變量
        // 這裏的幾個參數如下:AMS; ActivityStack; 描述 Launcher 的 ProcessRecord; Launcher 進程的 uid; intent; null; ActivityInfo 即將要啓動的 Activity 相關信息; AMS.mConfiguration; null; null; -1; true
        ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
                intent, resolvedType, aInfo, mService.mConfiguration,
                resultRecord, resultWho, requestCode, componentSpecified);

        ......
        return startActivityUncheckedLocked(r, sourceRecord,
                grantedUriPermissions, grantedMode, onlyIfNeeded, true);
    }

這一段首先是通過 resultTo 參數,在 Activity 堆棧中拿到 Launcher 這個 Activity 的相關信息並保存在 sourceRecod 中,然後創建一個新的 ActivityRecord 用來描述即將要啓動的 Activity 的相關信息,並保存在變量 r 中。 接着調用 startActivityUncheckedLocked 函數進行下一步操作。

Step 3 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/**
* r: 上面新建的 ActivityRecord,用來描述即將要啓動的 Activity 組件
* sourceRecord: 用來描述 Launcher 組件的一個 ActivityRecord
* grantedUriPermissions: null
* grantedMode: 0
* onlyIfNeeded: false
* doResume: true
*/
final int startActivityUncheckedLocked(ActivityRecord r,
            ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
            int grantedMode, boolean onlyIfNeeded, boolean doResume) {
        final Intent intent = r.intent;
        final int callingUid = r.launchedFromUid;
        // 首先獲得 intent 的標誌位
        int launchFlags = intent.getFlags();
        
        // mUserLeaving = true
        mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
        ......
        // notTop = null
        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
                != 0 ? r : null;

        // 這裏 onlyIfNeeded 爲 false,所以不看裏面的內容
        if (onlyIfNeeded) {
            ......
        }

        if (sourceRecord == null) {
            // 原文註釋以及 Slog 打印的內容說的很清楚了,這正好是當我們以 ApplicationContext 啓動一個 Activity 的情況,這種情況下,launchFlags 必須設置 FLAG_ACTIVITY_NEW_TASK
            // This activity is not being started from another...  in this
            // case we -always- start a new task.
            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
                      + intent);
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            }
        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
            // 如果 Launcher 的啓動模式是 SINGLE_INSTANCE,那麼我們要啓動的 Activity 必須得在一個新的 task 中去啓動。
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
            // The activity being started is a single instance...  it always
            // gets launched into its own task.
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }	

        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            ......
        }
  
        // 由於我們將要啓動的 MainActivity 沒有配置 launchMode 屬性,所以這裏的 r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
        boolean addingToTask = false;
        if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
            // r.resultTo 就是上面構造函數中的 resultRecord,可知是爲 null 的,表示 Launcher 不需要等這個即將要啓動的 MainActivity 的執行結果
            if (r.resultTo == null) {
                // 這裏 r.launchMode 是不等於 SINGLE_INSTANCE 的,所以通過 findTaskLocked 來查找是否有 Task 可以用來執行這個將要啓動的 Activity 組件。我們的場景是在 Launcher 中第一次啓動一個 app,因此這裏返回的 null,即 taskTop == null,因此需要創建一個新的 task 來啓動 Activity
                ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                        ? findTaskLocked(intent, r.info)
                        : findActivityLocked(intent, r.info);
                if (taskTop != null) {
                    ......
                }
            }
        }

        if (r.packageName != null) {
            // 當前在堆棧頂端的 Activity 是否就是即將要啓動的 Activity,因爲有些情況下,如果即將要啓動的 Activity 就在堆棧的頂端,那麼就不會重新啓動這個 Activity 的另一個實例了。我們的場景下,當前處在堆棧頂端的 Activity 是 Launcher,因此不繼續往下看
            ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);	
            if (top != null && r.resultTo == null) {
                if (top.realActivity.equals(r.realActivity)) {
                    ......
                }
            }

        } else {
            ......
        }

        boolean newTask = false;

        // 首先 addingToTask 在我們的場景下,現在是 false
        // 執行到這裏,其實就是要在一個新的 Task 裏面來啓動這個 Activity 了。
        if (r.resultTo == null && !addingToTask
                && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            // todo: should do better management of integers.
            mService.mCurTask++;
            if (mService.mCurTask <= 0) {
                mService.mCurTask = 1;
            }
            // 新建一個 TaskRecord 
            r.task = new TaskRecord(mService.mCurTask, r.info, intent,
                    (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
            ......
            newTask = true;
            if (mMainStack) {
                // 並且添加到 AMS 中
                mService.addRecentTaskLocked(r.task);
            }
        } else if (sourceRecord != null) {
            ......
        } else {
            ......
        }

        if (grantedUriPermissions != null && callingUid > 0) {
            ......
        }
        
        ......
        startActivityLocked(r, newTask, doResume);
        return START_SUCCESS;
    }

這一段主要是結合 Launcher 的 launchMode 以及將要啓動的 MainActivity 的 launchMode 來判斷是否需要在一個新的 Task 中啓動這個 MainActivity,如果需要就 new 一個新的 TaskRecord,保存在 r.task 中,並添加到 AMS中,然後進入 startActivityLocked(r, newTask, doResume) 進一步處理。

總結這一段就是判斷你的 LaunchMode,然後決定要不要新建 Task。

Step 4 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/**
* r: 上面的 ActivityRecord,現在 r.task 有值了
* newTask: true
* doResume: true
*/
private final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume) {
        // mHistory 是一個 ArrayList ,存放着 ActivityRecord
        final int NH = mHistory.size();

        int addPos = -1;
        
        if (!newTask) {
            ......
        }

        // 這裏 NH 肯定大於 0,因爲 Launcher 已經跑起來了。
        if (addPos < 0) {
            addPos = NH;
        }
        
        if (addPos < NH) {
            ......
        }
        
        // Slot the activity into the history stack and proceed
        mHistory.add(addPos, r);
        r.inHistory = true;
        r.frontOfTask = newTask;
        r.task.numActivities++;
        if (NH > 0) {
            // We want to show the starting preview window if we are
            // switching to a new task, or the next activity's process is
            // not currently running.
            // 這一段是當切換新任務時,要做一些任務切換的界面操作,主要是操作 AMS 中的 WindowManager
            ......
        } else {
            // If this is the first activity, don't do any fancy animations,
            // because there is nothing for it to animate on top of.
            ......
        }
        ......
        if (doResume) {
            resumeTopActivityLocked(null);
        }
    }

這一段主要是將 ActivityRecord 添加到 mHistory 中,並做一些界面切換的操作,然後調用 resumeTopActivityLocked 進一步操作

Step 5 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/*
* prev: null
*/
final boolean resumeTopActivityLocked(ActivityRecord prev) {
        // Find the first activity that is not finishing.
        // 這邊獲取到的 next 就是要啓動的 MainActivity 了
        ActivityRecord next = topRunningActivityLocked(null);

        // Remember how we'll process this pause/resume situation, and ensure
        // that the state is reset however we wind up proceeding.
        // 這裏的 mUserLeaving 在上面的分析中得出是 true
        final boolean userLeaving = mUserLeaving;
        mUserLeaving = false;

        if (next == null) {
            ......
        }

        next.delayedResume = false;
        
        // mResumedActivity 這裏是 Launcher
        // 這段主要是查看當前要啓動的 Activity 是否就是當前處於 Resume 狀態的 Activity,如果是的話就什麼都不用做,直接返回了
        if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            mService.mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            return false;
        }

        // 這裏是處理休眠狀態時的情況,mLastPausedActivity 保存堆棧頂端的 Activity
        if ((mService.mSleeping || mService.mShuttingDown)
                && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            mService.mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            return false;
        }
        ......
          
        // 在我們的情景中,上面兩個情況肯定都不滿足,因此執行到這裏
        // We need to start pausing the current activity so the top one
        // can be resumed...
        if (mResumedActivity != null) {
            if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
            startPausingLocked(userLeaving, false);
            return true;
        }

        ......
        }

        return true;
    }

這一段主要做的事情是將當前處於 Resume 狀態的 Activity 推入 Paused 狀態去。這個過程也反映了當啓動一個新的 Activity 時,舊 Activity 是先進入 Paused 狀態,新 Activity 才 create 的。

到這裏可以分個小階段,因爲我們要啓動的 Activity 的信息保存下來了,Task 也建立起來了。接下來還是轉場給 Launcher 這個應用程序進程了,得讓它進入 Paused 狀態。


2.3 回到 Launcher 讓它 Pause

Step 6 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/*
* userLeaving: true
* uiSleeping: false
*/
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
        if (mPausingActivity != null) {
            ......
        }
        // 這裏的 prev 是 Launcher Activity
        ActivityRecord prev = mResumedActivity;
        if (prev == null) {
            ......
        }
        ......
        mResumedActivity = null;
        // 這個賦值在下面 2.4 小節有用
        mPausingActivity = prev;
        mLastPausedActivity = prev;
        prev.state = ActivityState.PAUSING;
        prev.task.touchActiveTime();

        mService.updateCpuStats();
        
        if (prev.app != null && prev.app.thread != null) {
            ......
            try {
                ......
                // 這裏其實就是通過 Launcher 進程中的 ApplicationThread 來通知 Launcher 進入 Paused 狀態。其中參數 prev.finishing 代表當前 Activity 是否正在等待結束的 Activity 列表中,由於 Launcher 正在運行,所以這裏爲 false
                prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving, prev.configChangeFlags);
                ......
            } catch (Exception e) {
                ......
            }
        } else {
            ......
        }
        ......
    }

這裏其實就是通過 ApplicationThread 發起一個 IPC,通知 Launcher 進程進入 paused 狀態。

Step 7 frameworks/base/core/java/android/app/ApplicationThreadNative.java

public final void schedulePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeStrongBinder(token);
        data.writeInt(finished ? 1 : 0);
        data.writeInt(userLeaving ? 1 :0);
        data.writeInt(configChanges);
        mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }

沒啥說的,通過 Binder 進入到 ApplicationThread.schedulePauseActivity 方法。

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

/*
* token: Launcher 的 ActivityRecord。
* finished: false
* userLeaving: true
* configChanges: 暫不關心
!!! 到這裏是否可以猜測 mToken 是怎麼賦值的了,前面我們知道給將要啓動的 MainActivity 新建了一個 ActivityRecord 並且存在了 mHistory 中,想必接下來在給那個將要啓動的 MainActivity 發送 Create 消息時,會把這個 ActivityRecord 帶過來,這樣 mToken 就給賦值了 !!!
*/
public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges) {
            queueOrSendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? 1 : 0),
                    configChanges);
        }

這裏無非就是通過 Handler 將消息發送出去了,最後是由 H.handleMessage 來處理這個消息。H 收到 Paused 消息後,會交給 handlePauseActivity 來處理。

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

private final void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            if (userLeaving) {
                // 我們前面知道 userLeaving 是爲 true 的。
                // 執行這個方法會回調 Activity 的 onUserLeaveHint 通知 Activity,用戶要離開它了
                performUserLeavingActivity(r);
            }

            r.activity.mConfigChangeFlags |= configChanges;
            // 回調 Activity 的生命週期,進入 onPause()
            Bundle state = performPauseActivity(token, finished, true);
            
            ......
            
            // 告訴 AMS 我們已經進入 Paused 了
            try {
                ActivityManagerNative.getDefault().activityPaused(token, state);
            } catch (RemoteException ex) {
            }
        }
    }

這裏又可以告一段落了,Launcher 已經進入 onPause 了,並且去通知 AMS,AMS 接到這個通知就可以繼續完成未完成的事情了,即啓動 MainActivity。


2.4 Launcher 通知 AMS 我暫停好了,你繼續做你接下來要做的事吧

Step 10 frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

/*
* token: 是 Launcher 的 ActivityRecord
*/
public final void activityPaused(IBinder token, Bundle icicle) {
        // Refuse possible leaked file descriptors
        if (icicle != null && icicle.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Bundle");
        }

        final long origId = Binder.clearCallingIdentity();
        mMainStack.activityPaused(token, icicle, false);
        Binder.restoreCallingIdentity(origId);
    }

這裏可以看到再次進入到 ActivityStack 類中,去執行 activityPaused 函數。

Step 11 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/*
* token: 是 Launcher 的 ActivityRecord
* icicle: 不關心
* timeout: false
*/
final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
        ......
        ActivityRecord r = null;

        synchronized (mService) {
            // 這裏拿到的是 Launcher 在 mHistory 列表中的 index
            int index = indexOfTokenLocked(token);
            if (index >= 0) {
                // 拿到 Launcher 的 ActivityRecord
                r = (ActivityRecord)mHistory.get(index);
                if (!timeout) {
                    r.icicle = icicle;
                    r.haveState = true;
                }
                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                // 在前面的 2.3 小節中,我們讓 Launcher 進入 Paused 狀態時,把 Launcher 賦值給了 mPausingActivity,因此下面這個判斷是相等的
                if (mPausingActivity == r) {
                    r.state = ActivityState.PAUSED;
                    completePauseLocked();
                } else {
                    ......
                }
            }
        }
    }

這一段主要是判斷 mPausingActivity 是否等於 token 代表的 Activity,如果是相等就代表完成了 Pause,進入 completePauseLocked 方法。

Step 12 frameworks/base/services/java/com/android/server/am/ActivityStack.java

private final void completePauseLocked() {
        // 代表 Launcher
        ActivityRecord prev = mPausingActivity;
        ......
        
        if (prev != null) {
            ......
            // 這邊把 mPausingActivity 置空,因爲已經不需要了
            mPausingActivity = null;
        }

        if (!mService.mSleeping && !mService.mShuttingDown) {
            resumeTopActivityLocked(prev);
        } else {
            ......
        }
        
        ......
    }

這裏 AMS 肯定還沒有在睡眠也沒有 shutdown,因此進入 resumeTopActivityLocked(prev)

Step 13 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/*
* prev: Launcher Activity
*/
final boolean resumeTopActivityLocked(ActivityRecord prev) {
        // 這邊獲取到的 next 就是要啓動的 MainActivity 了
        ActivityRecord next = topRunningActivityLocked(null);

        // 這裏的 mUserLeaving 在上面的分析中得出是 true
        final boolean userLeaving = mUserLeaving;
        mUserLeaving = false;
  
        ......
          
        next.delayedResume = false;
        
        // mResumedActivity 這裏是 null,因爲之前最後一個 Resumed 狀態的 Activity 是 Launcher,現在它已經處於 Paused 狀態了。
        if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
            ......
            return false;
        }

        // 這裏是處理休眠狀態時的情況,這裏 mLastPausedActivity 是 Launcher
        if ((mService.mSleeping || mService.mShuttingDown)
                && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
            ......
            return false;
        }
        ......
          
        // 在 Step 5 的時候,這裏是滿足情況的,會去執行 startPausingLocked,但是現在不滿足了,mResumedActivity 已經爲 null 了
        if (mResumedActivity != null) {
            ......
            startPausingLocked(userLeaving, false);
            return true;
        }
        ......
          
        // next 是將要啓動的 MainActivity,前面我們只是爲它創建了 ActivityRecord,然後就讓 Launcher 去 Pause 了,因此這裏的 app 域還是爲 null 的。也很容易理解,我們還沒啓動起來呢,怎麼可能不爲 null
        if (next.app != null && next.app.thread != null) {
            ......
        } else {
            ......
            // 調用這個去啓動 Activity
            startSpecificActivityLocked(next, true, true);
        }
  
        return true;
    }

這裏在 Step 5 的時候分析過,那個時候 prev 是爲 null 的,現在有值了,是 Launcher Activity,所以會走不同的邏輯了。

Step 14 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/*
* r: 要啓動的 MainActivity 的 ActivityRecord
* andResume: true
* checkConfig: true
*/
private final void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // 這裏我們的是第一次啓動應用程序的 Activity,所以取到的 app 爲 null
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid);
        
        ......
        
        if (app != null && app.thread != null) {
            try {
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                .......
            }
        }

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

Step 15 frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

/*
* processName: com.yjnull.demo
* info: null
* knownToBeDead: true
* intentFlags: 0
* hostingType: "activity"
* hostingName: ComponentName 對象
* allowWhileBooting: false
*/
final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
        // 這裏再次檢查 process+uid 命名的進程是否存在,取到的 app 還是等於 null
        ProcessRecord app = getProcessRecordLocked(processName, info.uid);
        ......
          
        // 這裏的 hostingNameStr = com.yjnull.demo/.activity.MainActivity
        String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;
        
        ......
        
        if (app == null) {
            // 創建一個 processRecord
            app = newProcessRecordLocked(null, info, processName);
            // mProcessNames 是一個 ProcessMap<ProcessRecord> 類型的變量
            mProcessNames.put(processName, info.uid, app);
        } else {
            // If this is a new package in the process, add the package to the list
            app.addPackage(info.packageName);
        }

        ......
        // 這裏應該是去真正創建一個新的進程了
        startProcessLocked(app, hostingType, hostingNameStr);
        return (app.pid != 0) ? app : null;
}

// --- 接着看 startProcessLocked 方法 ---------------------------------------------

/*
* app: 上面新創建的 ProcessRecord
* hostingType: "activity"
* hostingNameStr: "com.yjnull.demo/.activity.MainActivity"
*/
private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
        ......
        
        try {
            int uid = app.info.uid;
            int[] gids = null;
            try {
                gids = mContext.getPackageManager().getPackageGids(
                        app.info.packageName);
            } catch (PackageManager.NameNotFoundException e) {
                Slog.w(TAG, "Unable to retrieve gids", e);
            }
            ......
            int debugFlags = 0;
            ......
            // 這裏主要是通過 Process.start 來創建一個新的進程,新的進程會導入 android.app.ActivityThread 類,並執行它的 main 函數
            int pid = Process.start("android.app.ActivityThread",
                    mSimpleProcessManagement ? app.processName : null, uid, uid,
                    gids, debugFlags, null);
            ......
            if (pid == 0 || pid == MY_PID) {
                // Processes are being emulated with threads.
                app.pid = MY_PID;
                app.removed = false;
                mStartingProcesses.add(app);
            } else if (pid > 0) {
                app.pid = pid;
                app.removed = false;
                synchronized (mPidsSelfLocked) {
                    this.mPidsSelfLocked.put(pid, app);
                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                    msg.obj = app;
                    mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
                }
            } else {
                app.pid = 0;
                ......
            }
        } catch (RuntimeException e) {
            ......
        }
    }

2.5 創建新進程去了

創建新進程的主要過程:

  • 把一些參數拼接好,通過 socket 發出去。ZygoteInit 類在 runSelectLoopMode 函數會一直偵聽是否有請求,當偵聽到有請求來臨時,會交給 ZygoteConnection 的 runOnce 函數去處理。這裏面會通過 Zygote.forkAndSpecialize 真正創建進程。

  • Zygote.forkAndSpecialize 創建一個進程後,會有兩個返回值,一個是在當前進程中返回的,一個是在新創建的進程中返回的。在當前進程中返回的是新創建進程的 pid,而在新創建進程中返回的是 0。 當 pid 不等於 0 時,會調用 handleParentProc ,這裏面會通過 mSocketOutStream.writeInt(pid); 將 pid 發送回去。這樣上面所講的 AMS 去啓動一個新進程的流程就結束了,AMS 拿到了 pid,並賦給了 ProcessRecord。然鵝,新進程開始繼續運行了呢。

  • 創建好新進程後,肯定還需要一些處理,前面我們有拼接過一些參數,那些參數裏有一個 --runtime-init ,因此新進程通過這個參數就知道要去初始化運行時庫,於是繼續執行 RuntimeInit.zygoteInit 進一步處理。這裏面主要做了兩件事,一個 zygoteInitNative(),一個 invokeStaticMain()。前者是執行 Binder 驅動程序初始化相關的工作。後者就是執行進程的入口函數,在這個場景下就是 android.app.ActivityThread 的 main 函數。

  • 這樣新進程就進入到 ActivityThread 的 main 函數了,在 main 裏面,我們會創建一個 ActivityThread 實例,然後調用它的 attach 函數,接着就通過 Looper 進入消息循環了,直到最後進程退出。

在創建新進程這裏我們好像斷流程了。 AMS 在拿到 pid 後就結束了。

爲什麼會覺得斷流程了,因爲 MainActivity 還是沒啓動起來。但是仔細想想,我們運行 MainActivity 的進程已經啓動起來了,並且調用了 attach 函數,那麼我們新的流程就從 attach 開始分析。

2.6 新進程調用 ActivityThread.attach(),向 AMS 發送消息,在 AMS 中繼續處理

函數 attach 最終會調用 AMS 的 attachApplication 函數,傳入的參數是 mAppThread。

Step 16 frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

/*
* thread: 新進程的 ApplicationThread
* pid: 新進程的 Binder.getCallingPid()
*/
private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        // Find the application record that is being attached...  either via
        // the pid if we are running in multiple processes, or just pull the
        // next app record if we are emulating process with anonymous threads.
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                // 前面在 Step15 創建一個新進程獲得 pid 時,將 ProcessRecord put 進 mPidsSelfLocked 了。這裏通過 pid 取出來
                app = mPidsSelfLocked.get(pid);
            }
        } else if (mStartingProcesses.size() > 0) {
            ......
        } else {
            ......
        }

        if (app == null) {
            ......
            return false;
        }

        ......

        String processName = app.processName;
        try {
            thread.asBinder().linkToDeath(new AppDeathRecipient(
                    app, pid, thread), 0);
        } catch (RemoteException e) {
            ......
            return false;
        }

        ......
        // 主要進行一些初始化,把 thread 設置爲 ApplicationThread 是關鍵,這樣,AMS 就可以通過這個 thread 與新創建的應用程序進程通信了
        app.thread = thread;
        app.curAdj = app.setAdj = -100;
        app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
        app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
        app.forcingToForeground = null;
        app.foregroundServices = false;
        app.debugging = false;

        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
        ......

        boolean badApp = false;
        boolean didSomething = false;

        // See if the top visible activity is waiting to run in this process...
        // 這裏取棧頂的 ActivityRecord,其實就是對應的 MainActivity
        ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
        if (hr != null && normalMode) {
            if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
                    && processName.equals(hr.processName)) {
                try {
                    if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
                        didSomething = true;
                    }
                } catch (Exception e) {
                    ......
                    badApp = true;
                }
            } else {
                ......
            }
        }

        ......

        return true;
    }

這一段實際是通過 pid 找到之前創建的 ProcessRecord,然後初始化一些值,主要是把 ApplicationThread 設置進去。最後交給 realStartActivityLocked 進一步處理。

Step 17 frameworks/base/services/java/com/android/server/am/ActivityStack.java

/**
* r: MainActivity 代表的 ActivityRecord
* app: 新創建的進程,即 MainActivity 將要運行在的進程
* andResume: true
* checkConfig: true
*/
final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
        ......

        r.app = app;
        ......

        int idx = app.activities.indexOf(r);
        if (idx < 0) {
            app.activities.add(r);
        }
        ......

        try {
            ......
            List<ResultInfo> results = null;
            List<Intent> newIntents = null;
            if (andResume) {
                results = r.results;
                newIntents = r.newIntents;
            }
            ......
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
                    System.identityHashCode(r),
                    r.info, r.icicle, results, newIntents, !andResume,
                    mService.isNextTransitionForward());
            
            ......
            
        } catch (RemoteException e) {
            ......
        }

        ......
        
        return true;
    }

這裏最後把啓動 MainActivity 的任務交給了應用程序進程的 ApplicationThread 中去了。

到這裏我們想想,前面創建了一個新進程後,新進程已經進入了 looper 消息循環,一直在等待消息來處理,此時這個新進程還沒有任何 Activity 啓動起來。但是 AMS 已經有了 MainActivity 的記錄 ActivityRecord,也有了這個新進程的記錄 ProcessRecord。因此 AMS 通過 ApplicationThread 向新進程發了一個 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 的消息通信。所以後面我們就轉場到 新進程 中去分析。

2.7 回到新進程中處理 啓動 Activity 的請求

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

/**
* intent: 就是最初的 intent
* token: MainActivity 在 AMS 中的表現形式 [ActivityRecord]
* ident: System.identityHashCode(r)
* info: ActivityRecord.info
* state: ActivityRecord.icicle
* pendingResults: ActivityRecord.results
* pendingNewIntents: ActivityRecord.newIntents
* notResumed: false
* isForwar: mService.isNextTransitionForward()
*/
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
            ActivityClientRecord r = new ActivityClientRecord();
    			  // 到這裏我們應該知道 mToken 是怎麼來的了
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.activityInfo = info;
            r.state = state;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
        }

將要啓動的 Activity 組件的信息封裝成一個 ActivityClientRecord 對象。然後往主線程的消息隊列 H 發送一個 LAUNCH_ACTIVITY 的消息。

H 收到這個消息,會分發給 handleLaunchActivity 處理。

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

/**
* r: MainActivity 組件信息
* customIntent: null
*/
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        // 執行啓動 Activity
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            // 處理 resume
            handleResumeActivity(r.token, false, r.isForward);

            ......
        } else {
            ......
        }
    }


// --- 啓動 Activity ------------------------------------------
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        
        ......
        // 首先獲得要啓動 Activity 的包名和類名
        ComponentName component = r.intent.getComponent();
        ......

        Activity activity = null;
        try {
            // 終於生成了我們需要的 MainActivity 實例
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ......
        } catch (Exception e) {
            ......
        }

        try {
            // 這裏會根據 Manifest 文件中解析出來的 ApplicationInfo 去生成 Application。並且完成 Application 的 attach 、onCreate 生命週期
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            ......

            if (activity != null) {
                // 創建 ContextImpl,這就是我們平常熟悉的 Context 了
                ContextImpl appContext = new ContextImpl();
                appContext.init(r.packageInfo, r.token, this);
                appContext.setOuterContext(activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mConfiguration);
                ......
                // 初始化 Activity 對象
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstance,
                        r.lastNonConfigurationChildInstances, config);

                ......
                // ok, 終於回調到 onCreate 了
                mInstrumentation.callActivityOnCreate(activity, r.state);
                ......
            }
            ......

            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            ......

        } catch (Exception e) {
            ......
        }

        return activity;
    }

無 f**k 說

問題

  1. mToken 是怎麼初始化的。

參考

Android 系統源代碼情景分析(第三版)
老羅的博客

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