Android 8.0 原始碼分析 (四) Activity 啟動

DevYK發表於2019-10-29

前言

我們熟知一般 Android 工程師都是在應用層上開發,不會涉及系統原始碼,但是如果你想往底層發展,或者深入外掛化、Framework 系統層等開發工作,如果不瞭解 Android 原始碼可是不行的,那麼接下來我基於自己的理解跟學習來記錄跟 Android 開發息息相關的原始碼分析,大概從 Android 中的 SystemServer 啟動、四大元件啟動、AMS、PMS 等幾個維度來介紹,下面是我的計劃,當然在未來也有可能改變。

還沒有關注的小夥伴,可以先關注一波,系列文章會持續更新。

Android 8.0 原始碼分析 (一) SystemServer 程式啟動

Android 8.0 原始碼分析 (二) Launcher 啟動

Android 8.0 原始碼分析 (三) 應用程式程式建立到應用程式啟動的過程

Android 8.0 原始碼分析 (四) Activity 啟動

Android 8.0 原始碼分析 (五) Service 啟動

Android 8.0 原始碼分析 (六) BroadcastReceiver 啟動

Android 8.0 原始碼分析 (七) ContentProvider 啟動

Android 8.0 原始碼分析 (八) ActivityManagerService

Android 8.0 原始碼分析 (九) WindowManager

Android 8.0 原始碼分析 (十) WindowManagerService 的視窗管理

介紹

前面 3 篇文章分別分析了系統程式、系統桌面 Launcher 程式、應用程式程式的啟動過程,那麼接下來點選系統桌面圖示就該進入到應用程式程式的根 Activity 了,這篇文章就給大家帶來 Android 中四大元件之一的 Activity 啟動分析,還沒有看過我之前的原始碼分析可以先去了解下,因為前面講解的內容相當於基礎或者相當於四大元件啟動的鋪墊。

應用程式根 Activity 啟動過程

Activity 啟動過程分為 2 種,一種是應用程式根 Activity 的啟動也就是在 XML 佈局中有該配置的屬性,

<action android:name="android.intent.action.MAIN"/>
複製程式碼

第二種就是我們程式中呼叫 startActivity 啟動。不過這 2 種在最後原始碼中的呼叫幾乎一樣,可以這樣說只要理解了第一種,那麼第二種理解起來就輕鬆多了。下面我們先來分析第一種。

Launcher 請求 AMS 過程

Android 8.0 原始碼分析 (二) Launcher 啟動 這一節中,我們知道 Launcher 啟動後會將已經安裝應用安裝應用程式的快捷圖示顯示到桌面上,這些應用圖示就是啟動應用程式根 Activity 入口,當我們點選某個應用的快捷圖示的時候,就會通過 Launcher 請求 AMS 來啟動該應用程式。 Launcher 請求 AMS 的時序圖如下:

KfEHMV.png

當我們點選應用圖示的時候,就會呼叫 Launcher 的 startActivitySafely 函式,如下所示:

//Launcher.java
    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
            return false;
        }
        /**
         * 1. 為啟動應用的 Activity 新增一個新的任務棧
         */
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (v != null) {
            intent.setSourceBounds(getViewBounds(v));
        }
        try {
            if (Utilities.ATLEAST_MARSHMALLOW
                    && (item instanceof ShortcutInfo)
                    && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                     || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                    && !((ShortcutInfo) item).isPromise()) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // Could be launching some bookkeeping activity
                /**
                 * 2. 執行 Activity 的 startActivity 函式
                 */
                startActivity(intent, optsBundle);
            } else {
                LauncherAppsCompat.getInstance(this).startActivityForProfile(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
            }
            return true;
        } catch (ActivityNotFoundException|SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
        }
        return false;
    }
複製程式碼

註釋 1 處為將要啟動的 Activity 新增 Flag 為 Intent.FLAG_ACTIVITY_NEW_TASK 模式,代表啟動的 Activity 將在新的任務棧中啟動,註釋 2 處呼叫 Activity 內部的函式 startActivity,詳細程式碼如下:

//Activity.java
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        /**
         * 判斷是否有傳參行為
         */
        if (options != null) {
            /**
             * 1. 呼叫 Activity startActivityForResult 函式,將引數傳遞下去
             */
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }
複製程式碼

在 Activity startActivity 函式中最終會呼叫 startActivityForResult 函式,第二個引數 -1 代表 Activity 不需要知道結果,第三個引數就是啟動設定進去的引數 Bundle,接著我們看註釋 1 處呼叫的原始碼

//Activity.java
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        /**
         * 1. mParent 代表 Activity 的父類
         */
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);

            /**
             * Instrumentation:主要用來監控應用程式和系統的互動
             *
             * 2. 呼叫 Instrumentation 的 execStartActivity 函式。
             *
             */
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                /**
                 * 3. 內部給 Activity onActivityResult 回撥
                 */
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
          ...
        } else {
            ...
        }
    }
複製程式碼

註釋 1 處的 mParent 代表的是 Activity 的型別,表示當前 Activity 的父類。因為目前根 Activity 還沒有建立出來,因此判斷成立執行註釋 2 Instrumentation 的 execStartActivity 函式,註釋 3 就是如果是以 startActivityForResult 函式啟動的 Activity 那麼就會回撥給 Activity結果。我們看註釋 2 的原始碼實現,如下:

//Instrumentation.java
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
      	//1. 拿到 IAPPlicationThead 這個類可以說是是啟動 Activity 的關鍵
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ....
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            /**
             * 2. 拿到 AMS 代理物件 IActivityManager 呼叫 startActivity 函式
             */
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
複製程式碼

首先拿到 IApplicationThead . aidl 程式間通訊方式,然後拿到 AMS 代理物件 IActivityManager .aidl ,呼叫 aidl 中的 startActivity 函式最後在 AMS 中執行。我們來看下 ActivityManager.getService() 實現,程式碼如下:

//ActivityManager.java
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                  	//1. 拿到 AMS 的引用
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                  	//2. 
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
複製程式碼

getService 函式呼叫 IActivityManagerSingleton 的 get 函式 ,IActivityManagerSingleton 是一個 Singleton 類。最後會直接回撥到 AMS 中的 startActivity 函式。

AMS 到 ApplicationThread 的呼叫過程

Launcher 請求 AMS 後,程式碼邏輯就已經執行到了 AMS 也就是系統 SystemServer 程式中了,接著 AMS 到 ApplicationThread 的呼叫流程,時序圖如下:

KfMa4S.png

上一小節我們知道,在 Instrumentation 類中最後會通過獲取 AMS 代理類 IActivityManager ,然後呼叫 startActivity 利用 aidl 程式間通訊,最後會執行 AMS 中的 startActivity 函式,程式碼如下:

//AMS.java

    /**
     * Instrumentation startActivity 傳遞過來的
     * @param caller
     * @param callingPackage
     * @param intent
     * @param resolvedType
     * @param resultTo
     * @param resultWho
     * @param requestCode
     * @param startFlags
     * @param profilerInfo
     * @param bOptions
     * @return
     */
    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        /**
         * 呼叫內部 startActivityAsUser 函式
         */
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }


    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        /**
         * 1. 判斷呼叫者程式是否被隔離
         */
        enforceNotIsolatedCaller("startActivity");
        /**
         * 2. 檢查呼叫者許可權
         */
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        /**
         * 3. 呼叫 ActivityStarter 的 startActivityMayWait 函式,啟動的理由
         */
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }
複製程式碼

在 AMS 的 startActivity 函式中呼叫內部的 startActivityAsUser 函式,在該函式中我們主要做了 3 個步驟

  1. 判斷呼叫者程式是否被隔離
  2. 檢查呼叫者許可權
  3. 呼叫 ActivityStarter 的 startActivityMayWait 函式,啟動 Activity 的理由

startActivityMayWait 函式中需要注意倒數第二個引數 TaskRecord,代表啟動的 Activity 任務棧,最後一個是啟動的理由

註釋 3 程式碼如下:

//ActivityStarter.java
    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 globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {

...
            /**
             * ActivityStarter 是載入 Activity 控制類,會蒐集所有的邏輯來決定如果將 Intent 和 Flags 轉換為 Activity ,並將Activity 和 Task 以及 Stack 相關聯。
             */
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);


...
}
複製程式碼

ActivityStarter 是 7.0 中新加入的類,它是載入 Activity 的控制類,會收集所有的邏輯來決定如果將 Intent 和 Flag 轉為 Activity ,並將 Activity 和 Task 以及 Stack 相關聯。

繼續看內部 startActivityLocked 呼叫,程式碼如下:

//ActivityStarter.java
    int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask, String reason) {

        /**
         * 1. 判斷啟動的理由不為空
         */
        if (TextUtils.isEmpty(reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord[0] = null;

        /**
         * 2. 繼續呼叫當前類裡面的 startActivity 函式
         */
        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                container, inTask);

        if (outActivity != null) {
            // mLastStartActivityRecord[0] is set in the call to startActivity above.
            outActivity[0] = mLastStartActivityRecord[0];
        }
        return mLastStartActivityResult;
    }
複製程式碼

判斷啟動的理由,然後繼續呼叫 startActivity 函式,程式碼如下:

//ActivityStarter.java

    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
 ...
        /**
         * 1. 判斷 IApplicationThread 是否為空
         */
        if (caller != null) {
            /**
             * 1.1 得到 Launcher 所在程式
             */
            callerApp = mService.getRecordForAppLocked(caller);
            /**
             * 1.2 獲得 Launcher 程式的 pid , uid
             */
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                        + " (pid=" + callingPid + ") when starting: "
                        + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }
			...

        /**
         * 2. 建立即將要啟動 Activity 的描述類
         */
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
        if (outActivity != null) {
            /**
             * 3. 將建立的 ActivityRecord 賦值給 ActivityRecord 陣列的第一個位置,最後會把 outActivity 傳遞給 startActivity
             */
            outActivity[0] = r;
        }

        if (r.appTimeTracker == null && sourceRecord != null) {
            // If the caller didn't specify an explicit time tracker, we want to continue
            // tracking under any it has.
            r.appTimeTracker = sourceRecord.appTimeTracker;
        }

       ...

        doPendingActivityLaunchesLocked(false);


        /**
         * 4. 繼續呼叫內部的 startActivity  函式
         */
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
    }
複製程式碼

該類函式邏輯比較多,大概以上面註釋總結了幾點小點

  1. 判斷上層傳遞過來的 IApplicationThread 是否為空,因為這裡我們是一路傳遞下來的,所以不為空。
  2. 註釋 1.1 處呼叫 AMS 的 getRecordForAppLocked 函式得到的代表 Launcher 程式的 callerApp 物件,它是 ProcessRecord 型別的, ProcessRecord 用於描述一個應用程式程式。
  3. 建立 ActivityRecord 類,用於描述一個 Activity 所有的資訊。
  4. 將建立出來 ActivityRecord 賦值給 ActivityRecord 陣列的第一個位置
  5. 繼續呼叫內部過載函式 startActivity 把 啟動 Activity 的描述資訊也一併傳遞過去。

接下來我們看註釋 4 的程式碼實現:

//ActivityStarter.java
    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            /**
             * 拿到 WMS
             */
            mService.mWindowManager.deferSurfaceLayout();
            /**
             * 繼續呼叫內部函式 startActivityUnchecked
             */
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } finally {
            ....

        return result;
    }
複製程式碼

接著呼叫 ActivityStarter 內部函式 startActivityUnchecked

//ActivityStarter.java
    /**
     * 主要處理 棧管理相關的邏輯
     * @param r
     * @param sourceRecord
     * @param voiceSession
     * @param voiceInteractor
     * @param startFlags
     * @param doResume
     * @param options
     * @param inTask
     * @param outActivity
     * @return
     */
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {

        ...
          
        /**
         * 1. 判斷條件是否滿足,是否是 新建立的任務棧模式
         */
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            /**
             * 2. 建立新的 TaskRecord ,用來描述 Activity 任務棧
             */
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
        } else if (mSourceRecord != null) {
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            result = setTaskFromInTask();
        } else {
            setTaskToCurrentTopOrCreateNewTask();
        }
        ...
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                ...
                mWindowManager.executeAppTransition();
            } else {
               ...
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                /**
                 * 3. 呼叫 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 函式
                 */
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }
       ...
        return START_SUCCESS;
    }
複製程式碼

startActivityUnchecked 函式主要處理與棧管理相關的邏輯。在註釋 1 處我們得知啟動 Activity 時會將 Intent 的

Flag 設定為 FLAG_ACTIVITY_NEW_TASK 模式,這樣註釋 1 條件滿足,接著執行註釋 2 處的 setTaskFromReuseOrCreateNewTask 函式,其內部會建立一個新的 TaskRecord ,用來描述一個 Activity 的任務棧。在註釋 3 處會呼叫 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 函式,程式碼如下所示:

//ActivityStackSupervisor.java
    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        //需要啟動的目標棧不為空,並且啟動的棧跟需要啟動棧一樣就執行
        if (targetStack != null && isFocusedStack(targetStack)) {
            /**
             * ActivityStack 描述堆疊的
             */
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        /**
         * 1. 獲取需要啟動的 Activity 所在棧的棧頂 不是處於停止狀態的 ActivityRecord
         */
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        /**
         * 2. 如果 ActivityRecord 不為 null,或者要啟動的 Activity 的狀態不是Resumed 狀態
         */
        if (r == null || r.state != RESUMED) {
            /**
             * 3.代表是即將啟動的 Activity
             */
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } else if (r.state == RESUMED) {
            // Kick off any lingering app transitions form the MoveTaskToFront operation.
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }
複製程式碼

這裡主要是獲取正在執行的任務棧,如果獲取到的棧不為空並且不是 Resumed 狀態 ,那麼就代表即將要啟動一個新的 Activity,註釋 3 的程式碼如下:

//ActivityStack.java
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
       ...
        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            /**
             * 1.呼叫內部  resumeTopActivityInnerLocked 函式
             */
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        mStackSupervisor.checkReadyForSleepLocked();

        return result;
    }
複製程式碼

把 mStackSupervisor.inResumeTopActivity 設定為 true ,然後繼續呼叫內部 resumeTopActivityInnerLocked 函式,程式碼如下:

//ActivityStack.java
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
       ...

            /**
             * 1. 呼叫 startSpecificActivityLocked 函式
             */
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }
複製程式碼

該函式邏輯處理比較多,我們只關注註釋 1 的呼叫

//ActivityStackSupervisor.java
    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        /**
         * 1. 獲取即將啟動的 Activity 所在的應用程式程式
         */
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.getStack().setLaunchTime(r);

        /**
         * 2. 判斷要啟動的 Activity 所在的應用程式程式如果已經執行的話,就會呼叫註釋 3
         */
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                   
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                /**
                 * 3. 如果已經正在執行呼叫 realStartActivityLocked 函式
                 */
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
               ...
            }

        }
				//4. 
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
複製程式碼

這裡主要判斷當前啟動 Activity 所在的程式是否已經執行,如果執行呼叫註釋 3 ,如果處於沒有執行的狀態呼叫註釋 4,最後會通知 AMS 與 Zygote 通訊請求建立一個新的程式,這裡我們直接看註釋 3

//ActivityStackSupervisor.java
    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
			
      ...
            
        /*** 
        			這裡的 app.thread 代表的是 IApplicationThread ,呼叫它內部 scheduleLaunchActivity 函								數,
             * 它的實現在 ActivityThread 的內部類 ApplicationThread ,其中 ApplicationThread 繼承了 IApplicationThread.Stub.,
             * app 指的是Activity 所在的應用程式程式。
             */

            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global and
                    // override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);

            ...

        } catch (RemoteException e) {
            ...

        return true;
    }
複製程式碼

這裡只拿出了核心程式碼,注意看上面程式碼,這裡說明一下,app.thread 指的就是 IApplicationThread, 它的實現類在 ActivityThread 的內部類,其中 ApplicationThread 繼承了 IApplicationThread.Stub。app 指的是傳入的要啟動的 Activity 所在應用程式程式,因此,這段程式碼指的就是要在目標應用程式進行啟動 Activity 。當前程式碼邏輯執行在 AMS 所在的 SystemServer 程式中,通過 ApplicationThread 來與應用程式程式進行 Binder 通訊,換句話說,ApplicationThread 是 SystemServer 和應用程式程式通訊的中間人。

KfddeS.png

到這裡下面就該看 ActivityThread 類裡面執行 Activity 任務了,由下一小節詳細講解。

ActivityThread 啟動 Activity 過程

通過上一小節講解的內容,我們知道目前已經執行在了應用程式程式中,先來看一下 ActivityThread 啟動 Activity 的時序圖

Kfwth9.png

接著我們來看 ActivityThread 內部類 ApplicationThread 的 scheduleLaunchActivity 函式,ActivityThread 在應用程式程式建立成功後會執行在當前程式的主執行緒中。scheduleLaunchActivity 程式碼如下:

//ActivityThread.java
public final class ActivityThread {
 ...
   
 private class ApplicationThread extends IApplicationThread.Stub {  
   
 ...
 
 private class ApplicationThread extends IApplicationThread.Stub {
   
 ....
   
         /**
         * Launcher 點選應用圖示啟動對應的應用 .... -> ActivityStackSupervisor . realStartActivityLocked 函式呼叫
         * @param intent
         * @param token
         * @param ident
         * @param info
         * @param curConfig
         * @param overrideConfig
         * @param compatInfo
         * @param referrer
         * @param voiceInteractor
         * @param procState
         * @param state
         * @param persistentState
         * @param pendingResults
         * @param pendingNewIntents
         * @param notResumed
         * @param isForward
         * @param profilerInfo
         */
        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

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

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

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);
            /**
             * 1. 呼叫內部 sendMessage 函式,將啟動 Activity 的資訊封裝成 ActivityClientRecord 物件,然後跟 H.LAUNCH_ACTIVITY 一起傳遞下去
             */
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
   
 ...
 }
   
 ...
}
複製程式碼

上面程式碼中的 ActivityClientRecord 類會把啟動 Activity 所有傳遞過來的引數全部封裝進去,然後呼叫內部 sendMessage 函式(**ps:這裡記住 H.LAUNCH_ACTIVITY **),程式碼如下:

  //ActivityThread.java  
	private void sendMessage(int what, Object obj) {
        /**
         * 繼續呼叫內部過載函式 what = H.LAUNCH_ACTIVITY
         */

        sendMessage(what, obj, 0, 0, false);
    }
複製程式碼

繼續呼叫過載函式

//ActivityThread.java

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        /**
         * 2. 通過 H 的 Handler 將 what = H.LAUNCH_ACTIVITY 訊息 what 傳送出去
         */
        mH.sendMessage(msg);
    }
複製程式碼

mH 是 AcitivtyThread 非靜態內部類,它繼承自 Handler,下面我們看下 H 是實現

//ActivityThread.java
public final class ActivityThread {
  
//應用程式程式 主執行緒 H 
final H mH = new H(); 
  
  ......
    
 private class H extends Handler {
 
  //啟動 Activity 標誌
  public static final int LAUNCH_ACTIVITY         = 100;
    
    public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                /**
                 * 1. 收到傳送過來  LAUNCH_ACTIVITY 標誌的訊息
                 */
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    /**
                     * 1.1 拿到封裝啟動 Activity 資訊的 ActivityClientRecord 類
                     */
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    /**
                     * 1.2 通過 getPackageInfoNoCheck 函式獲得 LoadedApk 型別的物件並賦值給 ActivityClientRecord 的成員變數 packageInfo。
                     *     應用程式程式要啟動 Activity 時,需要將該 Activity 所屬的 APK 載入進來,而 LoadedApk 就是用來描述已載入的 APk 檔案的。
                     */
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    /**
                     * 1.3 呼叫內部 handleLaunchActivity
                     */
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                
                
               ....
  ......
}
複製程式碼

在上一小節我們知道由 mH.sendMessage 將標誌 LAUNCH_ACTIVITY 的訊息傳送到了 H 類,請看上面註釋 1 代表接收傳送過來 LAUNCH_ACTIVITY 的訊息入口,註釋 1.1 代表拿到封裝啟動 Activity 資訊,註釋 1.2 拿到 載入 APK 的描述類 LoadedApk,最後呼叫註釋 3 ,程式碼如下:

//ActivityThread.java
    /**
     *
     *啟動 Activity
     * @param r
     * @param customIntent
     * @param reason
     */
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       ...

        /**
         * 1. 實施啟動 Activity 的例項
         */
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            /**
             * 2. 將 Activity 的狀態設定為 Resume
             */
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

            if (!r.activity.mFinished && r.startsNotResumed) {
               ...
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            }
        } else {
           
            try {
                /**
                 * 如果出現異常,停止 Activity 
                 */
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
複製程式碼

該函式通過 performLaunchActivity 函式啟動了 Activity ,並且將 啟動的 Activity 執行了 onCreate 生命週期函式,註釋 2 代表將啟動的 Activity 設定為可互動的生命週期狀態,當然如果內部執行錯誤,又會以 aidl 的形式通知 AMS 關閉當前 Activity。

我們先看註釋 1 程式碼如下:

//ActivityThread.java


    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

        /**
         * 1. 通過封裝啟動 Activity 資訊類 ActivityClientRecord 來獲取到 ActivityInfo
         */
        ActivityInfo aInfo = r.activityInfo;
        /**
         * 2. 如果 r.packageInfo == null 就獲取 LoadedApk 例項
         */
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        /**
         * 3. 通過封裝啟動 Activity 資訊類 ActivityClientRecord 來獲取啟動 Activity 元件的 ComponentName
         */
        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);
        }
        /**
         * 4. 建立Activity 中的上下文環境
         */
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            /**
             * 拿到當前上下文載入的 ClassLoader 載入器
             */
            java.lang.ClassLoader cl = appContext.getClassLoader();
            /**
             * 5. 呼叫 Instrumentation.newActivity 函式 ,內部通過 ClassLoader 類載入器來建立 Activity 的例項
             */
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            /**
             * 6. 得到 Application 物件
             */
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {

                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
                /**
                 * 7. 將 appContext 等物件依附在 Activity 的 attach 函式中,進行 Activity  attach 初始化
                 */
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                checkAndBlockForNetworkAccess();
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                //是否是持久化
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    /**
                     *  8. 內部呼叫 Activity 的 onCreate 方法
                     */
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
            r.paused = true;

            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }
複製程式碼

根據我的上面註釋可以看出來 ,該函式裡面幾乎每一行程式碼都是核心程式碼,那麼內部主要乾了些什麼了,這裡就簡單說一下,因為上面註釋真的已經很清楚了,拿到啟動 Activity 元件 Component 的資訊,通過 Instrumentation 類的 newActivity 函式,內部是通過 ClassLoader 的 loadClass 例項化了 Activity, 拿到 Application 進行與 Activity 繫結,最後呼叫 Instrumentation 函式的 callActivityOnCreate 執行了 Activity onCreate 生命週期 這裡我就拿 註釋 5,6,8 來看一下原始碼,因為比較典型,註釋 5 程式碼如下

//Instrumentation.java
	public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        //通過 ClassLoader 例項化了  Activity 
        return (Activity)cl.loadClass(className).newInstance();
    }
複製程式碼

註釋 6 ,程式碼如下

//LoadApk.java

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        /**
         * 如果 mApplication 已經建立了就直接返回
         */
        if (mApplication != null) {
            return mApplication;
        }

       ...

        Application app = null;

       ...

        try {
            ...
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            /**
             * 內部通過反射例項化 Application
             */
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
           ...
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        ....

        return app;
    }
複製程式碼

這裡拿到快取 mApplication ,因為在建立應用程式程式的時候 Application 已經被例項化了,有不明白的可以看 Android 8.0 原始碼分析 (三) 應用程式程式建立到應用程式啟動的過程 該文章。

註釋 8 程式碼如下:

//Instrumentation.java
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        ...
        activity.performCreate(icicle);
        ...
    }

    final void performCreate(Bundle icicle) {
      ....
        //呼叫Activity 生命週期 onCreate 函式
        onCreate(icicle);
      ...
     
    }
複製程式碼

到這裡 Launcher 點選應用圖示到啟動應用程式的根 Activity 已經啟動了,啟動根 Activity 中涉及到的程式有 4 個分別為 Zygote 程式、Launcher 桌面程式、SystemServer 程式、應用程式程式。過程比較複雜,涉及知識點比較多,如果想詳細瞭解的,建議可以跟著我的原始碼分析,然後自己跟一遍,這樣效果最好。

應用程式內部 startActivity 呼叫過程

根 Activity 啟動成功了之後,應用程式啟動 Activity 就簡單多了,我這裡簡單說一點,因為剩下邏輯都一樣。

從應用程式中我們自己呼叫 startActivity(Intent intent) 會直接呼叫 Activity 如下程式碼:

//Activity.java
    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }
複製程式碼

執行內部過載 startActivity(intent, null); 函式

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        /**
         * 判斷是否有傳參行為
         */
        if (options != null) {
            /**
             * 1. 呼叫 Activity startActivityForResult 函式,將引數傳遞下去
             */
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }
複製程式碼

看到這裡是否已經有一點影響了,就是我們最開始講過的,在 應用程式根 Activity 啟動過程#Launcher請求 AMS 過程 小節中,後面邏輯就完全一樣了,所以不再將第二遍了。其中自己應用程式涉及到的程式就 2 個,一個是自己的應用程式程式,另一個就是 AMS 所在的 SystemServer 程式,ActivityThread 是跟著當前啟動的元件程式走。

到這裡 Activity 啟動過程就將完了,不知道大家有沒有看明白,不明白了可以跟著我的思路自己跟一下原始碼,如果還是不明白,那麼我的好好反思一下,是不是我描述的有問題了。

下面我就簡單以一張圖來總結下 Launcher 啟動應用程式根 Activity 所經過的程式。

總結

這裡就以一張圖片來簡單概括一下啟動根 Activity 程式間互動的時序圖,相信這張圖會比較容易理解一點。

Kfg29O.png

參考

  • 《Android 進階解密》

相關文章