[Android]AMS源码分析(三)AMS中Activity栈管理详解

本文为原创文章,转载请注明出处,原创不易,且转且珍惜

1.前言

Activity栈管理是AMS的另一个重要功能,栈管理又和Activity的启动模式和startActivity时所设置的Flag息息相关,Activity栈管理的主要处理逻辑是在ActivityStarter#startActivityUnchecked方法中,本文也会围绕着这个方法进进出出,反复摩擦,直到脑海中都是它的形状。goolge的工程师起名还是很讲究的,为什么要带Unchecked呢? Unchecked-不确定,是因为在执行这个方法时,我要启动哪个Activity还没决定呢,具体为什么,我想看过这篇文章你就明白了。

2.Activity栈管理相关类

2.1ActivityStackSupervisor

顾名思义,Activity栈的功能提供者和管理者

2.2.ActivityDisplay

表示一个屏幕,Android支持三种屏幕:主屏幕,外接屏幕(HDMI等),虚拟屏幕(投屏)。一般情况下,即只有主屏幕时,ActivityStackSupervisor与ActivityDisplay都是系统唯一

2.3.TaskRecord

ActivityTask记录, Task是我们管理Activity栈的重要单元,它的表现形式与逻辑和Activity启动模式息息相关,也是本文重点要分析的

2.4.ActivityStack

针对ActivityRecord 和 TaskRecord进行管理,记录ActivityRecord的状态和TaskRecord的状态。在Android N之前只有两种ActivityStack:homeStack(launcher和recents Activity)和其他。Android N开始有5种,增加了DockedStack(分屏Activity)、PinnedStack(画中画Activity)、freeformstack(自由模式Activity),虽然它名字叫ActivityStack,但是跟我们熟知的数据结构中的栈基本上没啥关系,这也是有可能会增加一点理解难度的地方

2.5.关系图:

先说一下关系:

  • 一个ActivityDisplay包含多个ActivityStack
  • 一个ActivityStack包含多个TaskRecord
  • 一个TaskRecord包含多个ActivityRecord
image.png

3.启动模式

3.1.standard

标准启动模式,启动Activity时依次向栈顶添加ActivityRecord,返回时依次推出,示例:AActivity打开BActivity打开CActivity

image.png

这是基本的Activity启动模式,需要注意的点不太多

3.1.1.Intent.FLAG_ACTIVITY_CLEAR_TOP

还是刚才的案例,如果依次打开AActivity->BActivity->CActivity->DActivity,此时在DActivity打开AActivity时Intent添加Flag Intent.FLAG_ACTIVITY_CLEAR_TOP,系统会从BActivity开始依次将Task中的Activity依次销毁,直到DActivity,因为DActivity处于活跃状态,因此会先执行onPause,在onPause后,会销毁原来的AActivity,然后打开新的AActivity,最后执行DActivity的onStop和onDestory
流程图如下:

image.png

log:


image.png

3.1.2.源码分析

3.1.2.1.加入TaskRecord

摘抄ActivityStarter#startActivityUnchecked部分代码如下:

if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            // zhangyulong 使用一个旧的Task 或者新建一个
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
        } else if (mSourceRecord != null) {
            // zhangyulong 使用源Activity的task
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            // zhangyulong 使用启动时传递的task
            result = setTaskFromInTask();
        } else {
            // zhangyulong 理论上的可能,不可能走到这里
            setTaskToCurrentTopOrCreateNewTask();
        }
        if (result != START_SUCCESS) {
            return result;
        }

因为我们使用标准模式启动,因此,resultTomSourceRecord均不为空,这段逻辑会执行setTaskFromSourceRecord

private int setTaskFromSourceRecord() {
       ...
        addOrReparentStartingActivity(sourceTask, "setTaskFromSourceRecord");
        return START_SUCCESS;
    }

addOrReparentStartingActivity最终会执行TaskRecord#addActivityAtIndex:

void addActivityAtIndex(int index, ActivityRecord r) {
        ...
        mActivities.add(index, r);
        ...
    }

向对应的ActivityRecord中的mActivities添加本条记录,完成加入TaskRecord的操作

3.1.2.2.standard + Intent.FLAG_ACTIVITY_CLEAR_TOP

回到ActivityStarter#startActivityUnchecked,摘抄部分逻辑如下:

if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
            // 将ActivityTask目标Actiivty之上的Activity全部清空,返回值top为可以复用的Activity
            ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
            mKeepCurTransition = true;
            // 如果可复用的Activity不为空,直接调用它的onNewIntent方法并将其resume
            if (top != null) {
                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
                deliverNewIntent(top);
                mTargetStack.mLastPausedActivity = null;
                if (mDoResume) {
                    mSupervisor.resumeFocusedStackTopActivityLocked();
                }
                ActivityOptions.abort(mOptions);
                return START_DELIVERED_TO_TOP;
            }
        }

重点看performClearTaskLocked,这里是将目标Activity顶部元素清空的逻辑

/***
* newR: 需要启动的新Activity
* launchFlags: 新Activity的启动模式
*/
final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
        int numActivities = mActivities.size();
        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
            ActivityRecord r = mActivities.get(activityNdx);
            if (r.finishing) {
                continue;
            }
            // 在目标Task中找到了和新Activity相同的记录
            if (r.realActivity.equals(newR.realActivity)) {
                final ActivityRecord ret = r;
                //将在其之上的Activity全部清除
                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
                    r = mActivities.get(activityNdx);
                    if (r.finishing) {
                        continue;
                    }
                    ActivityOptions opts = r.takeOptionsLocked();
                    if (opts != null) {
                        ret.updateOptionsLocked(opts);
                    }
                    // 执行finishActivityLocked,如果Activity已经stop,会直接执行onDestroy,
                    // 如果Activity还在活跃,则会先执行onPause
                    if (mStack != null && mStack.finishActivityLocked(
                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
                        --activityNdx;
                        --numActivities;
                    }
                }

                // ActivityInfo.LAUNCH_MULTIPLE == standrad
                // 如果新Activity的launchMode是standard,且launchFlag没有FLAG_ACTIVITY_SINGLE_TOP,则将之前task
                // 内的activity也结束,以便建立新的
                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
                        && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
                    if (!ret.finishing) {
                        if (mStack != null) {
                            mStack.finishActivityLocked(
                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
                        }
                        // 返回空,说明不执行onNewIntent
                        return null;
                    }
                }

                return ret;
            }
        }
        return null;
    }

看完这部分代码,我想FLAG_ACTIVITY_CLEAR_TOP是怎么工作的大家也就明白了。

3.2.singleTop

singleTop:栈顶唯一,它和standrad的区别在于,如果是standrad模式,在栈顶启动一个相同的Activity,会创建一个新的Activity实例,如果是singleTop模式,在栈顶启动相同的Activity则只会调用原有Activity的onNewIntent,如果原Activity不在栈顶,那么表现形式就和standrad相同

3.2.1.流程图:

3.2.1.1.原Activity不在栈顶
image.png
3.2.1.2.原Activity在栈顶
image.png

3.2.2.singleTop + Intent.FLAG_ACTIVITY_CLEAR_TOP

现在设想一种场景,AActivitylanchMode为singleTop,在AActivity的基础上依次打开了BActivity、CActivity, 在CActivity再次打开AActivity,但打开时设置Intent属性Intent.FLAG_ACTIVITY_CLEAR_TOP,此时的启动流程:

image.png

3.2.3.log

3.2.3.1.原Activity不在栈顶
image.png
3.2.3.2.原Activity在栈顶
image.png
3.2.3.3.原Actiivty在栈顶且设置Intent.FLAG_ACTIVITY_CLEAR_TOP
image.png

3.2.3.源码分析

我们又要进入ActivityStarter#startActivityUnchecked方法了, startActivityUnchecked:你要对我负责555...

摘抄startActivityUnchecked方法中关于singleTop模式的处理如下:

// 要启动的Activity正好是当前在栈顶的Activity
        // 当前聚焦的ActivityStack
        final ActivityStack topStack = mSupervisor.mFocusedStack;
        // 当前聚焦的ActivityStack中的栈顶Actiivty
        final ActivityRecord topFocused = topStack.topActivity();
        // 当前栈顶Activity
        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        // dontStart为true说明可以直接复用栈顶Activity
        if (dontStart) {
            // For paranoia, make sure we have correctly resumed the top activity.
            topStack.mLastPausedActivity = null;
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ActivityOptions.abort(mOptions);
            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don't need to start a new activity, and the client said not to do
                // anything if that is the case, so this is it!
                return START_RETURN_INTENT_TO_CALLER;
            }
            // zhangyulong singleTop  sigleTask onNewIntent 执行
            deliverNewIntent(top);

            return START_DELIVERED_TO_TOP;
        }

需要注意的是,当我们设置目标Activity launchMode是singleTop时,判断条件用的是mLaunchSingleTop,而(mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP是指启动时设置的Intent的Flag属性。这两种方式都能达到singleTop的效果。

3.2.3.1.singleTop + Intent.FLAG_ACTIVITY_CLEAR_TOP

这部分的逻辑处理和standard时差不多,还是performClearTaskLocked方法,这个方法在3.1.2.2章节已经分析过了,这里摘抄部分逻辑如下:

                // ActivityInfo.LAUNCH_MULTIPLE == standrad
                // 如果新Activity的launchMode是standard,且launchFlag没有FLAG_ACTIVITY_SINGLE_TOP,则将之前task
                // 内的activity也结束,以便建立新的
                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
                        && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
                    if (!ret.finishing) {
                        if (mStack != null) {
                            mStack.finishActivityLocked(
                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
                        }
                        // 返回空,说明不执行onNewIntent
                        return null;
                    }
                }

因为我们的launchMode是FLAG_ACTIVITY_SINGLE_TOP,条件不成立,不会销毁命中的原Activity,但原Actiivty上面的记录均已销户,此时它已经是栈顶Activity了,继续执行会执行到startActivityUnchecked方法中3.2.3章节部分,和上面的逻辑就一致了。

3.3 singleTask

singleTask: 栈内唯一,如果Activity设置了launchMode为singleTask,那么在整个ActivityStack中有且仅有一个实例存在。有些朋友看到它名字叫singleTask,就想当然的认为它是Task内唯一的,我们不要被它的名字骗了。需要注意的一点是,singleTask模式启动是默认clearTop的。

3.3.1 启动流程

场景一

假设AActivity的launchMode为singleTask,AActivity后依次启动BActivity和CActivity, CActivity又启动了AActivity,
那么这个过程经历的流程如下:


image.png

log:


image.png

场景二:
假设AActivity和BActivity都是Standard,CActivity为singleTask,CActiivty再次启动CActivity,这个过程的启动流程:

image.png

log:


image.png

场景三:
看完前面两种场景,肯定会有同学不服气,你不是说singleTask是栈内唯一么,这两种场景都是task内的处理啊,那不就应该是task内唯一么,你说栈内唯一拿出证据来啊!别着急,证据马上来。

现在假设AActivity是singleTask, BActivity是standard, BActivity打开CActivity时创建新的Task, 然后CActivity再次打开AActivity
流程如下:
1.AActivity在其自身所在task启动BActivity
2.BActivity在启动CActivity时创建新的Task
3.CActivity启动AActivity时将AActivity所在的Task移到顶部
4.AActivity将BActivity清除并重新启动

流程图:


image.png

看下log是不是这样:


image.png

log也验证了这个说法的正确性,从这个案例中我们看出,虽然AB在一个task, C在另一个task,但C启动A的时候,并没有在其自身的task启动,而是操作AB所在的task。因此,singeTask是栈内唯一的。

3.3.2 singeTask源码分析

再进入一次ActivityStarter#startActivityUnchecked一次,此时startActivityUnchecked内心活动:别进了,再进就怀孕了!!

为什么说singleTask自带clearTop属性呢? 看下startActivityUnchecked的这段逻辑:

            // 如果启动Intent设置了FLAG_ACTIVITY_CLEAR_TOP或者目标Activity启动模式为singleInstance或者singleTask,执行以下逻辑
            if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || isDocumentLaunchesIntoExisting(mLaunchFlags)
                    || mLaunchSingleInstance || mLaunchSingleTask) {
                final TaskRecord task = reusedActivity.getTask();
                // 将与新Actiivty在Task内相同的Activity的顶部元素清空
                final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
                        mLaunchFlags);
               ...
            }

那么task切换到栈顶是在哪里呢,这段逻辑执行完成后,就会执行到Task切换的逻辑了,代码:

            // 将目标Activity所在Task移动到栈顶
            reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);

当前面的逻辑完成后,可复用用的Activity就已经在Task顶部,而Task也已经在Stack顶部,完事俱备,只欠东风,继续执行startActivityUnchecked会执行到3.2.3的内容,和singleTop的处理是一致的,最终回调了目标Activity的onNewIntent。

3.4 singleInstance

singleInstance这个启动模式比sigleTask更NB一些,它不光在栈内唯一,而且还独占一个Task,一看就是那种有独立办公室的老板,跟其他打工人完全不是一个等级的。关于singleInstance的栈管理和切换,你可以把它理解成只有一个singleTask的Activity存在的Task就比较好理解了,上面我们也已经分析过了。

4. Intent.FLAG_ACTIVITY_NEW_TASK、taskAffinity、新Task的创建

先看几个有意思的案例:
现在有两个Activity,分别是AActivity和BActivity,我们先设置A和B均为standard,在A启动B时设置Intent.FLAG_ACTIVITY_NEW_TASK,跳转时Task会新建么?
看一下log:

image.png

从图上我们看到,A和B的TaskId都是305,也就是没有创建新的Task,怎么回事,Intent.FLAG_ACTIVITY_NEW_TASK怎么失效了?

这个时候把B的launchMode设置为singleTask呢?
看一下log:


image.png

依然没有生效!!

这个时候保持B的launchMode为singleTask, 设置B的taskAffinity为".b"试一下:


image.png

生效了!!

这个时候把Intent.FLAG_ACTIVITY_NEW_TASK取消,保持B的launchMode为singleTask, 设置B的taskAffinity为".b"试一下:

image.png

生效了!

这个时候把Intent.FLAG_ACTIVITY_NEW_TASK取消,修改B的launchMode为standard, 设置B的taskAffinity为".b"试一下:


image.png

没生效!

这个时候把B的taskAffinity删掉,设置B为singleInstace试一下:


image.png

又生效了!!

看到这里是不是感觉已经晕了,那到底啥时候生效晒时候失效啊!别着急,看完源码我们再做总结

我们又要进入ActivityStarter#startActivityUnchecked方法了, startActivityUnchecked:不挣扎了,已经有你的形状了...

4.1 Intent.FLAG_ACTIVITY_NEW_TASK的自动设置

startActivityUnchecked前面几行代码执行了一个叫做computeLaunchingTaskFlags的方法,这个方法的作用是根据新Activity的launchMode对launchFlag做处理:

    private void computeLaunchingTaskFlags() {
        ...
        if (mInTask == null) {
            if (mSourceRecord == null) {
                ...
            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
                // 如果源Activity是singleInstance,则新启动Activity时自动添加launchFlag FLAG_ACTIVITY_NEW_TASK
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
                // 如果新Activity的launchMode是singleInstace或者singleTask,则新启动Activity时自动添加launchFlag FLAG_ACTIVITY_NEW_TASK
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            }
        }
    }

也就是说,如果一个Actiivty是singleInstacne的,那么不管是别人启动它还是它启动别人,都会自动添加启动flag FLAG_ACTIVITY_NEW_TASK, 如果是singeTask,则只有别人启动它时才会这样设置

4.2 taskAffinity的识别

4.1部分的逻辑执行后,startActivityUnchecked会执行getReusableIntentActivity方法,这个方法主要是寻找ActivityStack中是否有可复用的Task, 返回值会可复用Task的顶部元素:

    private ActivityRecord getReusableIntentActivity() {

        // 设置了launchFlag为FLAG_ACTIVITY_NEW_TASK或者 launchMode为singleInstance或singleTask
        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || mLaunchSingleInstance || mLaunchSingleTask;

        // inTask为null 且requestCode小于0(即resultTo ==  null)
        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
        ActivityRecord intentActivity = null;
        if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
            final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
            intentActivity = task != null ? task.getTopActivity() : null;
        } else if (putIntoExistingTask) {
            if (mLaunchSingleInstance) {
                // 如果launchMode为singleInstance,只要当前状态下Stack中有和要启动的Activity相同的记录,就说明可以复用
               intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
                       mStartActivity.isHomeActivity());
            } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
                // 没研究
                intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
                        !mLaunchSingleTask);
            } else {
                // 其他情况查找Stack中是否有适用的Task和可复用的Actiivty
                intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId);
            }
        }
        return intentActivity;
    }

findActivityLocked逻辑比较简单,就是在整个Stack中遍历Activity作对比,重点看ActivitySuperVisor#findTaskLocked,ActivitySuperVisor#findTaskLocked中调用了ActivityStack#findTaskLocked,看一下重要逻辑:

void findTaskLocked(ActivityRecord target, FindTaskResult result) {
            ...
            } else if (!isDocument && !taskIsDocument
                    && result.r == null && task.rootAffinity != null) {
                // 如果Task的rootAffinity和新Activity的taskAffinity匹配,则说明有可复用的栈
                // ,task的rootAffinity一般由底部Actiivty决定,不特意设置的话,一般使用包名
                if (task.rootAffinity.equals(target.taskAffinity)) {
                    result.r = r;
                    result.matchedByRootAffinity = true;
                }
            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
        }
    }

这里就是匹配taskAffinity的地方。回到getReusableIntentActivity方法,说一下它的返回值逻辑:

  • 如果launchMode是singleInstance,则判断当前stack中是否有相同Actiivty,如果有则返回对应Actiivty,否则是null
  • 如果launchMode是其他,则判断当前stack中是否有可以匹配其affinity的Task,如果有则返回对应Task顶部Activity,否则是null

4.3 是否创建新task的识别

如果getReusableIntentActivity方法返回值不为null,startActivityUncheck后面的逻辑会执行setTaskFromReuseOrCreateNewTask方法:

private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
        if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
            final TaskRecord task = intentActivity.getTask();
            task.performClearTaskLocked();
            // 设置启动新Actiivty时所使用的task
            mReuseTask = task;
            mReuseTask.setIntent(mStartActivity);
        }
        ...
    }

注意,这个方法执行的必要条件是getReusableIntentActivity方法返回值不为null,入参intentActivity即是getReusableIntentActivity方法的返回值。
因此,假如mReuseTask 为null,则启动Actiivty时会创建新的task,否则向mReuseTask 中添加,逻辑如下:

    private int setTaskFromReuseOrCreateNewTask(
            TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
        mTargetStack = computeStackFocus(
                mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
        if (mReuseTask == null) {
            // 创建新的Task
            final TaskRecord task = mTargetStack.createTaskRecord(
                    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
                    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                    mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                    mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
            // 向新Task中添加
            addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
            ...
        } else {
            // 向旧task中添加
            addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
        }

        ...
        return START_SUCCESS;
    }

4.4 总结

通过上面的代码分析,我们可以总结出在Activity启动过程中创建新Task的条件:

  1. standard、singleTop模式 Intent.FLAG_ACTIVITY_NEW_TASK 和taskAffinity必须同时设置
  2. sinlgeTask模式 只需设置taskAffinity,Intent.FLAG_ACTIVITY_NEW_TASK 可有可无
  3. singeInstance Intent.FLAG_ACTIVITY_NEW_TASK 和taskAffinity均可有可无

你可能感兴趣的:([Android]AMS源码分析(三)AMS中Activity栈管理详解)