Activity启动流程?基于Api30的Activity启动流程分析

前文:api 29版本Activity启动流程分析

本文将根据Api 30(Android 11)的源码来分析Activity的启动流程。

我个人把Activity的启动流程依次分为三个阶段:
App进程中 ——[通过Binder]——> 系统进程中 ——[通过Binder]——> 回到App进程中

下面按顺序进行梳理,主要整理大体脉络,不会大量贴出源码,只展示关键代码。

一、App进程中

第一阶段在用户进程中进行,比较简单。

1. Activity

一般通过Activity.startActivity(Intent)来启动Activity。通过一系列的处理和传递,最终会走到startActivityForResult(Intent, Int, Bundle)方法。在这里,会调用Instrumentation.execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)方法。

2. Instrumentation

在Instrumentation的execStartActivity方法中,有这么一句:

    // Instrumentation类
    int result = ActivityTaskManager.getService().startActivity(...args);

在这里,通过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对象,用于跨进程调用系统服务。

回到Instrumentation的代码中,这里是跨进程调用了系统服务ActivityTaskManagerService(ATMS)的startActivity方法。

    // Instrumentation类
    int result = ActivityTaskManager.getService().startActivity(...args);

二、系统进程中

1. ActivityTaskManagerService(ATMS)

ActivityTaskManagerService是系统服务,用途是管理Activity及其容器类,如Task/Stack/Display等。ATMS是新版本加入分担AMS部分职责的类。

在ActivityTaskManagerService中,会依次调用startActivity -> startActivityAsUser。
在startActivityAsUser方法中,会通过Starter池获取到一个ActivityStarter对象,然后设置一些参数,最后调用execute方法执行Activity的启动。

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

    private int startActivityAsUser(...args) {
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                ....
                .execute();
    }

2. ActivityStarter

顾名思义,ActivityStarter类就是为了启动Activity的。
execute方法中,会调用executeRequest方法,这里会处理启动Activity的请求,并开始一个Activity启动的旅程(代码注释原话)。
executeRequest方法会进行初步的检查并且确认权限,并且在这里组装对应Activity的ActivityRecord,其包含了对应Activity的所有信息,并储存在任务栈帧TaskRecord中。在Activity的启动过程中,Activity都是通过ActivityRecord来表示的。然后,会调用startActivityUnchecked方法,接着startActivityUnchecked方法会调用startActivityInner方法。

startActivityInner中,主要的一件事就是就是处理了Activity的启动模式,并且在ActivityStack中处理对应Activity在任务栈中的相关事宜,包括但不仅限于将对应的ActivityRecord添加到TaskRecord中、将对应的ActivityRecord提到栈中最顶部。

最后,会调用RootWindowContainer的resumeFocusedStacksTopActivities方法。

3. RootWindowContainer

RootWindowContainer是窗口容器(WindowContainer)的根容器,管理了所有窗口容器,设备上所有的窗口(Window)、显示(Display)都是由它来管理的。

顾名思义,resumeFocusedStacksTopActivities会恢复对应任务栈顶部的Activity。这个方法会检查一些可见性相关的属性,然后转交给ActivityStack.resumeTopActivityUncheckedLocked方法来继续流程。

4. ActivityStack

一个ActivityStack包含了若干个TaskRecord,每个TaskRecord又包含了若干个ActivityRecord,每个ActivityRecord对应了一个Activity。在这里,TaskRecord相当于在启动模式中的“任务栈”,根据启动模式的不同,在启动Activity的时候,会对TaskRecord进行不同的操作。

由于之前已经将对应Activity的ActivityRecord添加到了栈顶,所以resumeTopActivityUncheckedLocked恢复的就是将启动的Activity。这个方法只是做一些判断,最后调用resumeTopActivityInnerLocked实现具体功能。

resumeTopActivityInnerLocked方法中,做了一系列的判断,确保待启动的Activity可见性,预定Activity的切换动画等。

        if (next.attachedToProcess()) {
            ...
        } else {
            ...
            mStackSupervisor.startSpecificActivity(next, true, true);
        }

对于尚未启动的Activity来说,由于对应的Activity还没有添加到应用中,这里attachedToProcess会返回false。所以接下来执行mStackSupervisor.startSpecificActivity方法。

5. ActivityStackSupervisor

mStackSupervisor是ActivityStackSupervisor类型的对象,主要作用是进行对ActivityStack的管理。根据注释所言,这个类在不久后将会被移除,虽然这个注释以及持续很多个版本了。

在ActivityStackSupervisor的startSpecificActivity方法中,对于已经启动进程的Activity,会调用realStartActivityLocked方法,看名字就知道这是真正的启动Activity了(若对应Activity的进程尚未启动,则会通过ATMS的startProcessAsync方法启动进程,这就是另一个流程了)。

realStartActivityLocked流程的核心代码如下:

        final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.appToken);
        clientTransaction.addCallback(LaunchActivityItem.obtain(...));
        clientTransaction.setLifecycleStateRequest(ResumeActivityItem.obtain(...));
        mService.getLifecycleManager().scheduleTransaction(clientTransaction);

在这里,mAtmService对应的就是ActivityTaskManagerService,即ATMS;而getLifecycleManager对应的类是ClientLifecycleManager,通过其scheduleTransaction方法将对应事务发送到App进程。
在这里,obtain方法传入的proc.getThread(),即是联系待启动Activity进程的Binder对象,之后会于系统服务进程和App进程的跨进程通信。

5. ClientLifecycleManager和Transaction

在开发中,transaction一般被翻译成“事务”,表示将要或正在进行的任务。在realStartActivityLocked方法中,建立了一个事务,并将其递交给LifecycleManager。LivecycleManager和事务对应的类分别是ClientLifecycleManagerClientTransaction,顾名思义就是用来管理客户端,即App进程的生命周期的。

看看ClientLifecycleManager的scheduleTransaction方法和ClientTransaction的schedule方法:

    // ClientLifecycleManager.scheduleTransaction
    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        transaction.schedule();
    }
    
    // ClientTransaction.schedule
    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }

可以看到,最终调用了ClientTransaction成员mClientscheduleTransaction方法。这个mClient即是上一小节最后obtain方法传入的Binder。
也就是说,在这里,通过mClient.scheduleTransaction方法,系统服务进程将事务转发给了App进程。

三、回到App进程

1. ApplicationThread / ActivityThread

前面说到的mClient对应的类是ActivityThread.ApplicationThread。ActivityThread可以理解为一个应用的主线程(虽然它不是一个线程),应用的main方法就是在这个类里面的,并通过Looper维持了应用的运行状态,这点在这篇文章中做了分析。

ApplicationThread是ActivityThread的内部类,继承自IApplicationThread.Stub,是一个Binder类,用于当前应用进程和系统进程之间的跨进程通信。
而ApplicationThread的scheduleTransaction方法其实是调用了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内部HandlermH发送了一个值为ActivityThread.H.EXECUTE_TRANSACTION的消息,并把事务传递了过去。
而mH的处理方式就是把这个事务交给mTransactionExecutor来执行。

2. TransactionExecutor

mTransactionExecutor是一个TransactionExecutor类型的对象,看名字就知道是专门用于处理事务的类。看看它的execute方法:

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

    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        ...
        final int size = callbacks.size();
        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);
    }

逻辑很简单,就是分别调用了这个事务Callback和LifecycleState的execute方法;另外就是调用了cycleToPath方法,这个方法用于生命周期的过渡。
这里的在Callback和LifecycleState是在ActivityStackSupervisor的realStartActivityLocked流程创建的,分别对应的是LaunchActivityItemResumeActivityItem
看看这两个类的execute方法:

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

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

    // 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参数和mTransactionHandler是TransactionExecutor对象创建的时候就传入的,实际上都是是对应应用进程的ActivityThread对象。
也就是说,到头来最终还是分别调用了ActivityThread的handleLaunchActivityhandleStartActivityhandleResumeActivity方法。

3. ActivityThread

handleLaunchActivity的核心是调用performLaunchActivity方法。performLaunchActivity大体上依次做了这些事:

  • 通过反射创建Activity实例,这是通过Instrumentation.newActivity方法实现的;
  • 通过Activity.attach方法,实例化Window对象;
  • 调用Activity的onCreate回调;

handleStartActivity方法中,主要是通过Instrumentation调用了对应Activity的onStart和onRestoreInstanceState回调,并将状态设置为ON_START

与handleLaunchActivity类似的,handleResumeActivity则是调用了performResumeActivity方法。其大体上依次做了:

  • 如果需要,调用待Resume Activity的onNewIntent、onActivityResult回调;
  • 调用Activity的performResume方法,其中调用了onResume回调;

四、图示

点击查看原图

Activity启动流程.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344