Android activity啟動流程(API 30)

一、Activity啟動流程(基于API30)

這里把Activity 啟動流程分為三個階段
App進程中----(通過binder)---->系統(tǒng)進程中----(通過Binder)----->回到App進程汤求。
最起碼要熟悉 “App進程中” 和 “回到App進程” 的部分躲胳。
下面依次進行梳理潘拱。(只保留關鍵部分)

1. App進程中

1.1 ContextImp startActivity()/Activity startActivity()

這里需要簡單說明一下贪磺,對于開發(fā)者來說拱撵,在代碼中主動啟動activity 的入口有兩重辉川,一個是Activity 的startActivity()系列方法(startActivityForResult 也是可以直接調(diào)用的),一個是其他Context的startActivity()方法拴测,其他Context的startActivity()方法最終實現(xiàn)在ContextImp類內(nèi)乓旗。兩個入口都調(diào)用到了Instrumentation 的execStartActivity()方法。

ContextImpl的startActivity 方法如下集索,可以看到最后會進入到了Instrumentation.execStartActivity方法中屿愚,這個和Activity startActivity()方法是一樣的,后面的分析可以看到务荆。這里還需要注意的是妆距,調(diào)用Instrumentation.execStartActivity方法前有對Intent進行判斷,從主動拋出的異常信息描述可以看出函匕,對Intent 的 flags 是有要求的娱据,一般我們都是給Intent 添加Intent.FLAG_ACTIVITY_NEW_TASK 。這里也是跟調(diào)用Activity 的 startActivity 不一樣的地方盅惜。

public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        final int targetSdkVersion = getApplicationInfo().targetSdkVersion;

        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && (targetSdkVersion < Build.VERSION_CODES.N
                        || targetSdkVersion >= Build.VERSION_CODES.P)
                && (options == null
                        || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                            + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                            + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

在Activity中調(diào)用了startActivity方法后中剩,不管調(diào)用的是哪個重載忌穿,最后都會進入到startActivityForResult(Intent, int, Bundle)中。

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
    ……
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
    ……
    }

然后就進入到了Instrumentation.execStartActivity方法中结啼。

1.2 Instrumentation execStartActivity()

     public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
    ……
            ActivityTaskManager.getService().startActivity(
                        whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
    ……
    }

在這里掠剑,通過ActivityTaskManager.getService()獲取到一個IActivityTaskManager對象。通過其獲取方式:

       // ActivityTaskManager類
    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };

可以看到郊愧,這是一個Binder對象澡腾,用于跨進程調(diào)用系統(tǒng)服務。

注意糕珊!重點动分!
在之前的版本中,Instrumentation都是通過Binder的方式調(diào)用AMS的方法啟動Activity的红选;但是在api29之后澜公,IPC的對象變成了ActivityTaskManagerService(ATMS)。

2. 系統(tǒng)進程中

2.1 ATMS(ActivityTaskManagerService)

ATMS運行在系統(tǒng)服務進程(system_server)之中喇肋。當App通過Instrumentation和ATMS跨進程通信之后坟乾,ATMS就代管了接下來的啟動流程。
ATMS在進行了簡單處理之后蝶防,就會交給ActivityStarter處理甚侣。

    public final int startActivity(...args) {
        return startActivityAsUser(...args);
    }

    public final int startActivityAsUser(args) {
        // ...
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .......
                .execute();
    }

2.2 一些重要的類

接下來的工作,就是一系列的類協(xié)同處理了间学。代碼非常復雜殷费,但是看個大概流程還是不難的,畢竟Android源代碼近億行低葫,不可能全部都仔細讀完详羡。

這部分主要涉及了幾個類:ActivityStarterActivityStackSupervisor嘿悬、ActivityRecord实柠、TaskRecordActivityStack善涨。

ActivityStarter
顧名思義窒盐,ActivityStarter是用來啟動Activity的,同時也在其中判斷了啟動模式的邏輯钢拧;

ActivityStackSupervisor
顧名思義蟹漓,ActivityStackSupervisor則是ActivityStack的管理者。

ActivityRecord
而每次啟動一個Activity娶靡,都有一個對應的ActivityRecord被記錄下來牧牢。這個ActivityRecord是在ActivityStarter.startActivity(IApplicationThread, ...)方法中被創(chuàng)建的,也就是在這里姿锭,Activity的啟動信息完成了從intent到ActivityRecord的蛻變塔鳍。ActivityRecord包含了一個Activity的所有信息,可以看做是Activity的“身份證”呻此。

TaskRecord
任務轮纫。一個TaskRecord就是在四種啟動模式中所說的“棧”焚鲜。一個TaskRecord掌唾,或者說一個Task、任務忿磅,根據(jù)官方說法糯彬,任務是用戶在執(zhí)行某項工作時與之互動的一系列 Activity 的集合。也就是說葱她,一個任務是包含了若干個Activity的撩扒。對于啟動模式為singleInstance的Activity來說,會單獨存在于一個棧中吨些,也就是這個任務中只有一個Activity搓谆;而其他啟動模式的Activity則會在當前棧中進行。具體的參考官網(wǎng)定義啟動模式豪墅。

ActivityStack
ActivityStack顧名思義泉手,也就是Activity棧。通常來講偶器,一個系統(tǒng)里面有兩個ActivityStack斩萌,一個是系統(tǒng)Launcher所在的ActivityStack,一個是用戶App運行的ActivityStack屏轰。通常App所在的棧就是后者术裸。

系統(tǒng)進程中的過程請看
https://blog.csdn.net/zengsidou/article/details/117177399

3.回到App進程

3.1. ApplicationThread / ActivityThread

ApplicationThread是ActivityThread的內(nèi)部類,繼承自IApplicationThread.Stub亭枷,是一個Binder類袭艺,用于當前應用進程和系統(tǒng)進程之間的跨進程通信。
而ApplicationThread的scheduleTransaction方法其實是調(diào)用了ActivityThread的同名方法叨粘。而ActivityThread自身并沒有定義這個方法猾编,而是繼承自ClientTransactionHandler來的∩茫看下這個方法:

    // ClientTransactionHandler
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }

    // ActivityThread
    private void sendMessage(int what, Object obj) {
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        mH.sendMessage(msg);
    }

所以scheduleTransaction方法其實就是給ActivityThread內(nèi)部HandlermH發(fā)送了一個值為ActivityThread.H.EXECUTE_TRANSACTION的消息答倡,并把事務傳遞了過去。
而mH的處理方式就是把這個事務交給mTransactionExecutor來執(zhí)行驴党。

3.2. TransactionExecutor

    public void execute(ClientTransaction transaction) {
        ...
        executeCallbacks(transaction);
        executeLifecycleState(transaction);
        mPendingActions.clear();
    }

    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        ...
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            item.execute(mTransactionHandler, token, mPendingActions);
        }
    }

    private void executeLifecycleState(ClientTransaction transaction) {
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
        ...
        cycleToPath(r, lifecycleItem.getTargetState(), true, transaction);
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
    }

邏輯很簡單瘪撇,就是分別調(diào)用了這個事務Callback和LifecycleState的execute方法;另外就是調(diào)用了cycleToPath方法,這個方法用于生命周期的過渡倔既。
這里的在Callback和LifecycleState是在之前ActivityStackSupervisor的realStartActivityLocked方法中創(chuàng)建的恕曲,分別對應的是LaunchActivityItem和ResumeActivityItem這兩個類,即啟動和恢復Activity渤涌。
這里按照順序平鋪下來為:LaunchActivityItem.execute() -> cycleToPath() -> ResumeActivityItem.execute()佩谣。

看看這兩個類的execute方法和cycleToPath方法:

    // LaunchActivityItem 的 execute 方法
    public void execute(...args) {
        client.handleLaunchActivity(...args);
    }

    // ResumeActivityItem 的 execute 方法
    public void execute(...args) {
        client.handleResumeActivity(...args);
    }

    // TransactionExecutor.cycleToPath
    private void cycleToPath(...args) {
        ...
        performLifecycleSequence(r, path, transaction);
    }
    private void performLifecycleSequence(...args) {
        ... 
        // 這里的state是ON_START
        switch (state) {
            ...
            case ON_START:
                mTransactionHandler.handleStartActivity(r.token, mPendingActions);
        }
    }

而這里的client參數(shù)和mTransactionHandler是TransactionExecutor對象創(chuàng)建的時候就傳入的,實際上都是是對應應用進程的ActivityThread對象实蓬。
也就是說茸俭,到頭來最終還是分別調(diào)用了ActivityThread的handleLaunchActivity,handleStartActivity和handleResumeActivity方法安皱,分別對應了Activity的onCreate调鬓、onStart、onResume回調(diào)酌伊。

3.3. ActivityThread

handleLaunchActivity的核心是調(diào)用performLaunchActivity方法腾窝。performLaunchActivity大體上依次做了這些事:

通過反射創(chuàng)建Activity實例,這是通過Instrumentation.newActivity方法實現(xiàn)的腺晾;

  • 通過Activity.attach方法燕锥,實例化Window對象;
  • 通過Instrumentation調(diào)用Activity的onCreate回調(diào)悯蝉;

在handleStartActivity方法中:

  • 主要是調(diào)用了對應Activity的performStart方法归形,其中調(diào)用了onStart回調(diào);
  • 通過Instrumentation調(diào)用onRestoreInstanceState回調(diào)鼻由;

與handleLaunchActivity類似的暇榴,handleResumeActivity則是調(diào)用了
performResumeActivity方法。其大體上依次做了:

  • 如果需要蕉世,調(diào)用待Resume Activity的onNewIntent蔼紧、onActivityResult回調(diào);
  • 調(diào)用Activity的performResume方法狠轻,其中調(diào)用了onResume回調(diào)奸例;

四、圖示

image.png
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末向楼,一起剝皮案震驚了整個濱河市查吊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌湖蜕,老刑警劉巖逻卖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異昭抒,居然都是意外死亡评也,警方通過查閱死者的電腦和手機炼杖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盗迟,“玉大人坤邪,你說我怎么就攤上這事≌┢梗” “怎么了罩扇?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵婆芦,是天一觀的道長怕磨。 經(jīng)常有香客問我,道長消约,這世上最難降的妖魔是什么肠鲫? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮或粮,結果婚禮上导饲,老公的妹妹穿的比我還像新娘。我一直安慰自己氯材,他們只是感情好渣锦,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氢哮,像睡著了一般袋毙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冗尤,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天听盖,我揣著相機與錄音,去河邊找鬼裂七。 笑死皆看,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的背零。 我是一名探鬼主播腰吟,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼徙瓶!你這毒婦竟也來了毛雇?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤倍啥,失蹤者是張志新(化名)和其女友劉穎禾乘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虽缕,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡始藕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年蒲稳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伍派。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡江耀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诉植,到底是詐尸還是另有隱情祥国,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布晾腔,位于F島的核電站舌稀,受9級特大地震影響,放射性物質發(fā)生泄漏灼擂。R本人自食惡果不足惜壁查,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剔应。 院中可真熱鬧睡腿,春花似錦、人聲如沸峻贮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纤控。三九已至挂捻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嚼黔,已是汗流浹背细层。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留唬涧,地道東北人疫赎。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像碎节,于是被迫代替她去往敵國和親捧搞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

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