Activity 組件的啟動流程

Activity 組件的啟動過程

基于 Android 2.3.1

當(dāng)我們在 Launcher 中點擊一個 app 時,發(fā)生了什么?

1. 參與角色

  • Activity
  • Launcher
  • AMS
  • Instrumentation:監(jiān)控應(yīng)用程序和系統(tǒng)之間的交互操作
  • ActivityThread:ActivityThread 用來描述一個應(yīng)用程序進(jìn)程崔赌,系統(tǒng)每當(dāng)啟動一個應(yīng)用程序進(jìn)程時,都會在該進(jìn)程里加載一個 ActivityThread 實例,并且執(zhí)行 main 方法揣苏,從而開啟主線程 looper 循環(huán)。并且每一個在該進(jìn)程中啟動的 Activity 組件件舵,都會保存這個 ActivityThread 實例在成員變量 mMainThread 中
  • ApplicationThread:看名字會很困惑以為也是一個線程卸察,實則不然,它是一個 Binder 本地對象铅祸,可與 AMS 進(jìn)行 IPC 通信坑质。(繼承 IApplicationThread.Stub)
  • ActivityStack:用來描述一個 Activity 組件堆棧
  • ResolveInfo:PMS.resolveIntent(),解析 intent 得到的一個信息
  • ProcessRecord:在 AMS 中临梗,每一個應(yīng)用程序進(jìn)程都用 ProcessRecord 來描述涡扼,并且保存在 AMS 內(nèi)部
  • TaskRecord:任務(wù)棧的表現(xiàn)形式
  • ActivityRecord:AMS 中的一個 Binder 本地對象,每一個已經(jīng)啟動的 Activity 組件在 AMS 中都有一個對應(yīng)的 ActivityRecord 對象盟庞,用來維護(hù)對應(yīng)的 Activity 組件的運行狀態(tài)和信息吃沪。通常 Activity 中的 mToken 成員變量會指向它,mToken 是一個 Binder 代理對象

2. 啟動流程

2.1 Launcher 發(fā)生的事

當(dāng)我們在 Launcher 中點擊一個 app 圖標(biāo)時什猖,會調(diào)用 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) {
            ......
        }
    }

因此參數(shù) 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 組件降铸。這樣當(dāng)用戶點擊一個快捷圖標(biāo)時,就可以拿到相應(yīng) Activity 組件的信息并啟動起來摇零。

接著上述代碼講推掸,調(diào)用父類的 startActivity(intent),即 Activity.startActivity(intent)遂黍,這里經(jīng)過層層調(diào)用會走到 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.

大意就是它用來監(jiān)控應(yīng)用程序和系統(tǒng)之間的交互操作芯咧。因為 Activity 的啟動最后需要通過 AMS 啟動牙捉,而 AMS 又是運行在系統(tǒng)進(jìn)程 (system 進(jìn)程) 的竹揍,所以算是和系統(tǒng)的交互操作,因此需要交給 Instrumentation 來執(zhí)行邪铲。

execStartActivity 方法里有幾個參數(shù)需要注意:

  • mMainThread.getApplicationThread():Launcher 組件所在的應(yīng)用程序進(jìn)程的 ApplicationThread 的 Binder 本地對象芬位。為了將它傳遞給 AMS,這樣 AMS 接下來就可以通過它來通知 Launcher 組件進(jìn)入 Paused 狀態(tài)带到。
  • mToken:類型為 IBinder昧碉,是一個 Binder 代理對象,指向 AMS 中一個類型為 ActivityRecord 的 Binder 本地對象揽惹。將它傳遞給 AMS 的話被饿,AMS 就可以通過它獲得 Launcher 組件的詳細(xì)信息了。

接下來我們走進(jìn) 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 組件啟動起來搪搏。當(dāng)然中間還有一些過程狭握,無非就是 ActivityManagerProxy 將一些參數(shù)進(jìn)行封裝寫入到 Parcel 對象中,然后通過 mRemote 向 AMS 發(fā)送一個類型為 START_ACTIVITY_TRANSACTION 的進(jìn)程間通信請求疯溺。

2.2 AMS 中做的事

接著上述來论颅,Launcher 通過 Instrumentation 發(fā)起了一個 START_ACTIVITY_TRANSACTION 的進(jìn)程間通信,因此會回調(diào)到 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,那我們進(jìn)到 ActivityStack 中的 startActivityMayWait 方法看看损俭,這個方法挺長蛙奖,所以分析就在注釋里了:

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

/**
* caller: mMainThread.getApplicationThread(), Launcher 組件所在的應(yīng)用程序進(jìn)程ApplicationThread 的 Binder 本地對象。
* intent: 前面所構(gòu)造的 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 對象雁仲,目測是用來整合前面?zhèn)鬟M(jìn)來的 Intent 中所描述的信息
        ActivityInfo aInfo;
        try {
            // 這里通過 PMS 去解析參數(shù) intent 的內(nèi)容,以便可以獲得即將啟動的 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;
        }
    }

其實總結(jié)下來無非就是通過 PMS 將 Intent 中的參數(shù)解析出來琐脏,并獲取到即將啟動的 Activity 組件的更多信息攒砖,也就是 com.yjnull.demo.activity.MainActivity 的更多信息。

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

/**
* ...... 同上
* aInfo: 通過 PMS 去解析參數(shù) intent 的內(nèi)容日裙,得到 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 組件所在的應(yīng)用程序進(jìn)程信息昂拂。
            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 進(jìn)程中 Instrumentation 傳遞的 mToken 參數(shù)。
            int index = indexOfTokenLocked(resultTo);
            ......
            if (index >= 0) {
                sourceRecord = (ActivityRecord)mHistory.get(index);
                ......
            }
        }

        ......
        // 這里創(chuàng)建一個 ActivityRecord 用來描述即將啟動的 Activity 組件格侯,即 MainActivity 組件鼻听,可以注意财著,前面我們說過 mToken 就是指向 ActivityRecord 的,所以可以關(guān)注這個 ActivityRecord 對象撑碴,看看它是怎么傳遞給 Activity 類的成員變量
        // 這里的幾個參數(shù)如下:AMS; ActivityStack; 描述 Launcher 的 ProcessRecord; Launcher 進(jìn)程的 uid; intent; null; ActivityInfo 即將要啟動的 Activity 相關(guān)信息; 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 參數(shù)撑教,在 Activity 堆棧中拿到 Launcher 這個 Activity 的相關(guān)信息并保存在 sourceRecod 中,然后創(chuàng)建一個新的 ActivityRecord 用來描述即將要啟動的 Activity 的相關(guān)信息醉拓,并保存在變量 r 中伟姐。 接著調(diào)用 startActivityUncheckedLocked 函數(shù)進(jìn)行下一步操作。

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 的標(biāo)志位
        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玫镐,所以不看里面的內(nèi)容
        if (onlyIfNeeded) {
            ......
        }

        if (sourceRecord == null) {
            // 原文注釋以及 Slog 打印的內(nèi)容說的很清楚了,這正好是當(dāng)我們以 ApplicationContext 啟動一個 Activity 的情況怠噪,這種情況下,launchFlags 必須設(shè)置 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 就是上面構(gòu)造函數(shù)中的 resultRecord葛闷,可知是為 null 的憋槐,表示 Launcher 不需要等這個即將要啟動的 MainActivity 的執(zhí)行結(jié)果
            if (r.resultTo == null) {
                // 這里 r.launchMode 是不等于 SINGLE_INSTANCE 的,所以通過 findTaskLocked 來查找是否有 Task 可以用來執(zhí)行這個將要啟動的 Activity 組件淑趾。我們的場景是在 Launcher 中第一次啟動一個 app阳仔,因此這里返回的 null,即 taskTop == null扣泊,因此需要創(chuàng)建一個新的 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) {
            // 當(dāng)前在堆棧頂端的 Activity 是否就是即將要啟動的 Activity近范,因為有些情況下,如果即將要啟動的 Activity 就在堆棧的頂端延蟹,那么就不會重新啟動這個 Activity 的另一個實例了评矩。我們的場景下,當(dāng)前處在堆棧頂端的 Activity 是 Launcher阱飘,因此不繼續(xù)往下看
            ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);    
            if (top != null && r.resultTo == null) {
                if (top.realActivity.equals(r.realActivity)) {
                    ......
                }
            }

        } else {
            ......
        }

        boolean newTask = false;

        // 首先 addingToTask 在我們的場景下斥杜,現(xiàn)在是 false
        // 執(zhí)行到這里,其實就是要在一個新的 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;
    }

這一段主要是結(jié)合 Launcher 的 launchMode 以及將要啟動的 MainActivity 的 launchMode 來判斷是否需要在一個新的 Task 中啟動這個 MainActivity蔗喂,如果需要就 new 一個新的 TaskRecord,保存在 r.task 中高帖,并添加到 AMS中缰儿,然后進(jìn)入 startActivityLocked(r, newTask, doResume) 進(jìn)一步處理。

總結(jié)這一段就是判斷你的 LaunchMode散址,然后決定要不要新建 Task返弹。

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

/**
* r: 上面的 ActivityRecord锈玉,現(xiàn)在 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 已經(jīng)跑起來了拉背。
        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.
            // 這一段是當(dāng)切換新任務(wù)時,要做一些任務(wù)切換的界面操作默终,主要是操作 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 中椅棺,并做一些界面切換的操作,然后調(diào)用 resumeTopActivityLocked 進(jìn)一步操作

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
        // 這段主要是查看當(dāng)前要啟動的 Activity 是否就是當(dāng)前處于 Resume 狀態(tài)的 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;
        }

        // 這里是處理休眠狀態(tài)時的情況,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;
        }
        ......
          
        // 在我們的情景中含滴,上面兩個情況肯定都不滿足诱渤,因此執(zhí)行到這里
        // 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;
    }

這一段主要做的事情是將當(dāng)前處于 Resume 狀態(tài)的 Activity 推入 Paused 狀態(tài)去。這個過程也反映了當(dāng)啟動一個新的 Activity 時谈况,舊 Activity 是先進(jìn)入 Paused 狀態(tài)勺美,新 Activity 才 create 的。

到這里可以分個小階段碑韵,因為我們要啟動的 Activity 的信息保存下來了赡茸,Task 也建立起來了。接下來還是轉(zhuǎn)場給 Launcher 這個應(yīng)用程序進(jìn)程了祝闻,得讓它進(jìn)入 Paused 狀態(tài)占卧。


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 小節(jié)有用
        mPausingActivity = prev;
        mLastPausedActivity = prev;
        prev.state = ActivityState.PAUSING;
        prev.task.touchActiveTime();

        mService.updateCpuStats();
        
        if (prev.app != null && prev.app.thread != null) {
            ......
            try {
                ......
                // 這里其實就是通過 Launcher 進(jìn)程中的 ApplicationThread 來通知 Launcher 進(jìn)入 Paused 狀態(tài)。其中參數(shù) prev.finishing 代表當(dāng)前 Activity 是否正在等待結(jié)束的 Activity 列表中联喘,由于 Launcher 正在運行华蜒,所以這里為 false
                prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving, prev.configChangeFlags);
                ......
            } catch (Exception e) {
                ......
            }
        } else {
            ......
        }
        ......
    }

這里其實就是通過 ApplicationThread 發(fā)起一個 IPC,通知 Launcher 進(jìn)程進(jìn)入 paused 狀態(tài)豁遭。

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 進(jìn)入到 ApplicationThread.schedulePauseActivity 方法。

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

/*
* token: Launcher 的 ActivityRecord堤框。
* finished: false
* userLeaving: true
* configChanges: 暫不關(guān)心
!!! 到這里是否可以猜測 mToken 是怎么賦值的了域滥,前面我們知道給將要啟動的 MainActivity 新建了一個 ActivityRecord 并且存在了 mHistory 中,想必接下來在給那個將要啟動的 MainActivity 發(fā)送 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 將消息發(fā)送出去了,最后是由 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 的。
                // 執(zhí)行這個方法會回調(diào) Activity 的 onUserLeaveHint 通知 Activity着倾,用戶要離開它了
                performUserLeavingActivity(r);
            }

            r.activity.mConfigChangeFlags |= configChanges;
            // 回調(diào) Activity 的生命周期拾酝,進(jìn)入 onPause()
            Bundle state = performPauseActivity(token, finished, true);
            
            ......
            
            // 告訴 AMS 我們已經(jīng)進(jìn)入 Paused 了
            try {
                ActivityManagerNative.getDefault().activityPaused(token, state);
            } catch (RemoteException ex) {
            }
        }
    }

這里又可以告一段落了,Launcher 已經(jīng)進(jìn)入 onPause 了卡者,并且去通知 AMS蒿囤,AMS 接到這個通知就可以繼續(xù)完成未完成的事情了,即啟動 MainActivity崇决。


2.4 Launcher 通知 AMS 我暫停好了材诽,你繼續(xù)做你接下來要做的事吧

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

這里可以看到再次進(jìn)入到 ActivityStack 類中,去執(zhí)行 activityPaused 函數(shù)恒傻。

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

/*
* token: 是 Launcher 的 ActivityRecord
* icicle: 不關(guān)心
* 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 小節(jié)中脸侥,我們讓 Launcher 進(jìn)入 Paused 狀態(tài)時,把 Launcher 賦值給了 mPausingActivity盈厘,因此下面這個判斷是相等的
                if (mPausingActivity == r) {
                    r.state = ActivityState.PAUSED;
                    completePauseLocked();
                } else {
                    ......
                }
            }
        }
    }

這一段主要是判斷 mPausingActivity 是否等于 token 代表的 Activity睁枕,如果是相等就代表完成了 Pause,進(jìn)入 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 置空外遇,因為已經(jīng)不需要了
            mPausingActivity = null;
        }

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

這里 AMS 肯定還沒有在睡眠也沒有 shutdown,因此進(jìn)入 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 狀態(tài)的 Activity 是 Launcher,現(xiàn)在它已經(jīng)處于 Paused 狀態(tài)了滩援。
        if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
            ......
            return false;
        }

        // 這里是處理休眠狀態(tài)時的情況栅隐,這里 mLastPausedActivity 是 Launcher
        if ((mService.mSleeping || mService.mShuttingDown)
                && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
            ......
            return false;
        }
        ......
          
        // 在 Step 5 的時候,這里是滿足情況的玩徊,會去執(zhí)行 startPausingLocked租悄,但是現(xiàn)在不滿足了,mResumedActivity 已經(jīng)為 null 了
        if (mResumedActivity != null) {
            ......
            startPausingLocked(userLeaving, false);
            return true;
        }
        ......
          
        // next 是將要啟動的 MainActivity恩袱,前面我們只是為它創(chuàng)建了 ActivityRecord泣棋,然后就讓 Launcher 去 Pause 了,因此這里的 app 域還是為 null 的畔塔。也很容易理解潭辈,我們還沒啟動起來呢,怎么可能不為 null
        if (next.app != null && next.app.thread != null) {
            ......
        } else {
            ......
            // 調(diào)用這個去啟動 Activity
            startSpecificActivityLocked(next, true, true);
        }
  
        return true;
    }

這里在 Step 5 的時候分析過澈吨,那個時候 prev 是為 null 的把敢,現(xiàn)在有值了,是 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) {
        // 這里我們的是第一次啟動應(yīng)用程序的 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 命名的進(jìn)程是否存在桑阶,取到的 app 還是等于 null
        ProcessRecord app = getProcessRecordLocked(processName, info.uid);
        ......
          
        // 這里的 hostingNameStr = com.yjnull.demo/.activity.MainActivity
        String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;
        
        ......
        
        if (app == null) {
            // 創(chuàng)建一個 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);
        }

        ......
        // 這里應(yīng)該是去真正創(chuàng)建一個新的進(jìn)程了
        startProcessLocked(app, hostingType, hostingNameStr);
        return (app.pid != 0) ? app : null;
}

// --- 接著看 startProcessLocked 方法 ---------------------------------------------

/*
* app: 上面新創(chuàng)建的 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 來創(chuàng)建一個新的進(jìn)程柏副,新的進(jìn)程會導(dǎo)入 android.app.ActivityThread 類勾邦,并執(zhí)行它的 main 函數(shù)
            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 創(chuàng)建新進(jìn)程去了

創(chuàng)建新進(jìn)程的主要過程:

  • 把一些參數(shù)拼接好,通過 socket 發(fā)出去割择。ZygoteInit 類在 runSelectLoopMode 函數(shù)會一直偵聽是否有請求眷篇,當(dāng)偵聽到有請求來臨時,會交給 ZygoteConnection 的 runOnce 函數(shù)去處理锨推。這里面會通過 Zygote.forkAndSpecialize 真正創(chuàng)建進(jìn)程铅歼。
  • Zygote.forkAndSpecialize 創(chuàng)建一個進(jìn)程后,會有兩個返回值换可,一個是在當(dāng)前進(jìn)程中返回的椎椰,一個是在新創(chuàng)建的進(jìn)程中返回的。在當(dāng)前進(jìn)程中返回的是新創(chuàng)建進(jìn)程的 pid沾鳄,而在新創(chuàng)建進(jìn)程中返回的是 0慨飘。 當(dāng) pid 不等于 0 時,會調(diào)用 handleParentProc 译荞,這里面會通過 mSocketOutStream.writeInt(pid); 將 pid 發(fā)送回去瓤的。這樣上面所講的 AMS 去啟動一個新進(jìn)程的流程就結(jié)束了,AMS 拿到了 pid吞歼,并賦給了 ProcessRecord圈膏。然鵝,新進(jìn)程開始繼續(xù)運行了呢篙骡。
  • 創(chuàng)建好新進(jìn)程后稽坤,肯定還需要一些處理,前面我們有拼接過一些參數(shù)糯俗,那些參數(shù)里有一個 --runtime-init 尿褪,因此新進(jìn)程通過這個參數(shù)就知道要去初始化運行時庫,于是繼續(xù)執(zhí)行 RuntimeInit.zygoteInit 進(jìn)一步處理得湘。這里面主要做了兩件事杖玲,一個 zygoteInitNative(),一個 invokeStaticMain()淘正。前者是執(zhí)行 Binder 驅(qū)動程序初始化相關(guān)的工作摆马。后者就是執(zhí)行進(jìn)程的入口函數(shù),在這個場景下就是 android.app.ActivityThread 的 main 函數(shù)鸿吆。
  • 這樣新進(jìn)程就進(jìn)入到 ActivityThread 的 main 函數(shù)了今膊,在 main 里面,我們會創(chuàng)建一個 ActivityThread 實例伞剑,然后調(diào)用它的 attach 函數(shù)斑唬,接著就通過 Looper 進(jìn)入消息循環(huán)了,直到最后進(jìn)程退出。

在創(chuàng)建新進(jìn)程這里我們好像斷流程了恕刘。 AMS 在拿到 pid 后就結(jié)束了缤谎。

為什么會覺得斷流程了,因為 MainActivity 還是沒啟動起來褐着。但是仔細(xì)想想坷澡,我們運行 MainActivity 的進(jìn)程已經(jīng)啟動起來了,并且調(diào)用了 attach 函數(shù)含蓉,那么我們新的流程就從 attach 開始分析频敛。

2.6 新進(jìn)程調(diào)用 ActivityThread.attach(),向 AMS 發(fā)送消息馅扣,在 AMS 中繼續(xù)處理

函數(shù) attach 最終會調(diào)用 AMS 的 attachApplication 函數(shù)斟赚,傳入的參數(shù)是 mAppThread。

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

/*
* thread: 新進(jìn)程的 ApplicationThread
* pid: 新進(jìn)程的 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 創(chuàng)建一個新進(jìn)程獲得 pid 時差油,將 ProcessRecord put 進(jìn) 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;
        }

        ......
        // 主要進(jìn)行一些初始化,把 thread 設(shè)置為 ApplicationThread 是關(guān)鍵蓄喇,這樣发侵,AMS 就可以通過這個 thread 與新創(chuàng)建的應(yīng)用程序進(jìn)程通信了
        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...
        // 這里取棧頂?shù)?ActivityRecord,其實就是對應(yīng)的 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 找到之前創(chuàng)建的 ProcessRecord妆偏,然后初始化一些值刃鳄,主要是把 ApplicationThread 設(shè)置進(jìn)去。最后交給 realStartActivityLocked 進(jìn)一步處理钱骂。

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

/**
* r: MainActivity 代表的 ActivityRecord
* app: 新創(chuàng)建的進(jìn)程叔锐,即 MainActivity 將要運行在的進(jìn)程
* 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 的任務(wù)交給了應(yīng)用程序進(jìn)程的 ApplicationThread 中去了。

到這里我們想想罐柳,前面創(chuàng)建了一個新進(jìn)程后掌腰,新進(jìn)程已經(jīng)進(jìn)入了 looper 消息循環(huán)狰住,一直在等待消息來處理张吉,此時這個新進(jìn)程還沒有任何 Activity 啟動起來。但是 AMS 已經(jīng)有了 MainActivity 的記錄 ActivityRecord催植,也有了這個新進(jìn)程的記錄 ProcessRecord肮蛹。因此 AMS 通過 ApplicationThread 向新進(jìn)程發(fā)了一個 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 的消息通信。所以后面我們就轉(zhuǎn)場到 新進(jìn)程 中去分析创南。

2.7 回到新進(jìn)程中處理 啟動 Activity 的請求

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

/**
* intent: 就是最初的 intent
* token: MainActivity 在 AMS 中的表現(xiàn)形式 [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();
                  // 到這里我們應(yīng)該知道 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 發(fā)送一個 LAUNCH_ACTIVITY 的消息。

H 收到這個消息稿辙,會分發(fā)給 handleLaunchActivity 處理昆码。

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

/**
* r: MainActivity 組件信息
* customIntent: null
*/
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        // 執(zhí)行啟動 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 {
            // 這里會根據(jù) Manifest 文件中解析出來的 ApplicationInfo 去生成 Application。并且完成 Application 的 attach 、onCreate 生命周期
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            ......

            if (activity != null) {
                // 創(chuàng)建 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, 終于回調(diào)到 onCreate 了
                mInstrumentation.callActivityOnCreate(activity, r.state);
                ......
            }
            ......

            mActivities.put(r.token, r);

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

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

        return activity;
    }

無 f**k 說

問題

  1. mToken 是怎么初始化的旧噪。

參考

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脓匿,隨后出現(xiàn)的幾起案子淘钟,更是在濱河造成了極大的恐慌,老刑警劉巖陪毡,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件米母,死亡現(xiàn)場離奇詭異,居然都是意外死亡毡琉,警方通過查閱死者的電腦和手機铁瞒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绊起,“玉大人精拟,你說我怎么就攤上這事∈幔” “怎么了蜂绎?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長笋鄙。 經(jīng)常有香客問我师枣,道長,這世上最難降的妖魔是什么萧落? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任践美,我火速辦了婚禮,結(jié)果婚禮上找岖,老公的妹妹穿的比我還像新娘陨倡。我一直安慰自己,他們只是感情好许布,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布兴革。 她就那樣靜靜地躺著,像睡著了一般蜜唾。 火紅的嫁衣襯著肌膚如雪杂曲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天袁余,我揣著相機與錄音擎勘,去河邊找鬼。 笑死颖榜,一個胖子當(dāng)著我的面吹牛棚饵,可吹牛的內(nèi)容都是我干的煤裙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼噪漾,長吁一口氣:“原來是場噩夢啊……” “哼积暖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怪与,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤夺刑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后分别,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遍愿,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年耘斩,在試婚紗的時候發(fā)現(xiàn)自己被綠了沼填。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡括授,死狀恐怖坞笙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荚虚,我是刑警寧澤薛夜,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站版述,受9級特大地震影響梯澜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渴析,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一晚伙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俭茧,春花似錦咆疗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至场斑,卻和暖如春漓踢,著一層夾襖步出監(jiān)牢的瞬間牵署,已是汗流浹背漏隐。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奴迅,地道東北人青责。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓挺据,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脖隶。 傳聞我的和親對象是個殘疾皇子扁耐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容