ActivityStarter之startActivityUnchecked(()

ActivityStarter封装了一个activity启动的过程(包括上下文环境),不采用情景栈分析法真的很难分析,这里采用情景分析法把该函数分析. 整体代码如下:

 private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {

         //1. 初始化环境和lunchModeFlags   
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor);
        computeLaunchingTaskFlags();
        computeSourceStack();
        mIntent.setFlags(mLaunchFlags);

        //2. 复用activity逻辑
        mReusedActivity = getReusableIntentActivity();
        ......
        if (mReusedActivity != null) {
            ......
            mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
        ......
            setTaskFromIntentActivity(mReusedActivity);

            if (!mAddingToTask && mReuseTask == null) {
                resumeTargetStackIfNeeded();
                return START_TASK_TO_FRONT;
            }
        }
     .......

       //singleTop 或者singleInstance的处理
        if (dontStart) {
            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
            // For paranoia, make sure we have correctly resumed the top activity.
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ......
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
          ......
            return START_DELIVERED_TO_TOP;
        }

        //3. 设置对应task并带到前台
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            setTaskFromReuseOrCreateNewTask(taskToAffiliate);
         ......
        } else if (mSourceRecord != null) {
            ......
            final int result = setTaskFromSourceRecord();
            ......
        } else if (mInTask != null) {
            ......
            final int result = setTaskFromInTask();
            if (result != START_SUCCESS) {
                return result;
            }
        } else {
            setTaskToCurrentTopOrCreateNewTask();
        }
    //  4. 启动Activity
        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);

   //   5. 使Activity可见
        if (mDoResume) {
            if (!mLaunchTaskBehind) {
                mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
            }
            final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
               .... . .
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                mWindowManager.executeAppTransition();
            } else {
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }
        ......
        return START_SUCCESS;
    }

我们先整体介绍下这里activity启动的过程

  1. 计算启动的flags,首先计算flags是因为后面要根据flags选择启动的task,所以这一步是铺垫作用.这里读者可能会问为什么要计算,因为有些flags是冲突的,所以需要计算一下.
  2. 对于找到task的过程其实还包含一些特殊的activity模式和标志的处理,以及对activity复用的逻辑.可以复用的情况包含如下几种 
    1. LaunchSingleInstance
    2. LaunchSingleTask
    3. (singleTop|FLAG_ACTIVITY_SINGLE_TOP) && activity已经在已经在栈顶. 对于在栈顶这一条,如果指定了FLAG_ACTIVITY_NEW_TASK标志或者要启动的activity模式为LaunchSingleInstance或者 LaunchSingleTask的activity,又或者mOptions.getLaunchTaskId()指定了taskId(这个优先级要高于参数中指定的inTask).其实可以先把其他的符合复用条件的task放到栈顶.所以在复用之前还有根据条件将复用的task带到前台的环节. 对于activity复用后这些activity是不用启动的,之需要使他们可见可以返回了,还第5步有着类似的逻辑
  3. 计算在哪个task中启动,这里可定是有四种种情况了
    1. 新创建一个task启动 (指定了FLAG_ACTIVITY_NEW_TASK标志,没有找到复用的task)
    2. 在sourceRecord(也就是调用startActivity的activity),没有指定FLAG_ACTIVITY_NEW_TASK标志,并且sourceRecord不为空
    3. 在指定的task中启动, 一般是用于恢复task
    4. 在当前焦点stack的topTask中启动 , 既没有FLAG_ACTIVITY_NEW_TASK,又没有指定task并且还没有mSourceRecord,这种情况根据注释说不会发生
  4. 在锚定task并把它带到前台之后就可以启动activity了,使用 mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions)
  5. mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
    mOptions) 使activity可见 

下面就围绕这4步对代码进行展开说明

一.对启动参数进行初始化,主要是下面三个函数

  1. setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
    voiceInteractor);
    computeLaunchingTaskFlags();
    computeSourceStack();
    mIntent.setFlags(mLaunchFlags);
 private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
            boolean doResume, int startFlags, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {

setInitialState 函数比较简单,主要初始化了如下变量

  • mStartActivity 要启动的Activity的ActivityRecord.
  • mIntent 调用者传递的intent
  • mOptions 调用者传递的额外参数,主要用于动画和task,stack,display等额外信息的传递
  • mCallingUid 调用者uid
  • mSourceRecord 调用者activity
  • mLaunchBounds 打掉主要给PIP模式使用,指定activity的大小
  • mLaunchSingleTop 要启动的activity是否为singleTop模式的activity 
  • mLaunchSingleInstance: singleInstance模式的activity
  • mLaunchSingleTask : singleTask模式的activity
  • mLaunchFlags : 这个值通过adjustLaunchFlagsToDocumentMode计算,主要是通过intent中传递的flags与在AndroidManifest.xml中配置的lunchMode和documentLaunchMode做一些处理,并把DocumentMode转化为lunchModeFlags,操作如下:
 private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
            boolean launchSingleTask, int launchFlags) {
        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                (launchSingleInstance || launchSingleTask)) {
            launchFlags &=
                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
        } else {
            switch (r.info.documentLaunchMode) {
                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
                    launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
                    break;
            }
        }
        return launchFlags;
    }

可以看到launchSingleInstance和launchSingleTask模式的activity是不支持FLAG_ACTIVITY_NEW_DOCUMENT标志的,不允许.所以直接干掉这个表示,使之失效.
另外对于指定了 documentLaunchMode的activity

  1. DOCUMENT_LAUNCH_NONE不用任何操作.
  2. DOCUMENT_LAUNCH_INTO_EXISTING或者DOCUMENT_LAUNCH_ALWAYS 代表activity自动带有FLAG_ACTIVITY_NEW_DOCUMENT标志
  3. DOCUMENT_LAUNCH_NEVER 则会把FLAG_ACTIVITY_MULTIPLE_TASK标志去掉,表示activity永远不主动在新的task中创建
    所以这里我们可以知道对于document模式,都会转化为FLAG_ACTIVITY_MULTIPLE_TASK和FLAG_ACTIVITY_NEW_DOCUMENT标志进行处理
  • mLaunchTaskBehind 不把这个activity启动到前台,是通过Activity的启动参数ActivityOptions传递的,但是以document模式启动的activity才会处理这个参数,所以还要看是否设置了这个标志.
mLaunchTaskBehind = r.mLaunchTaskBehind
                && !mLaunchSingleTask && !mLaunchSingleInstance
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;

代码是这么写的,其实判断mLaunchSingleTask && !mLaunchSingleInstance是没有必要的,因为在前面adjustLaunchFlagsToDocumentMode里面已经处理了.

  • 后面这段逻辑都是对于mLaunchFlags的处理 后面
       首先sendNewTaskResultRequestIfNeeded()函数,如果启动参数带有FLAG_ACTIVITY_NEW_TASK,则要启动一个新的task,这种情况有可能栈顶的task会被切到后台,所以发送给它一个RESULT_CANCELED的结果.所以要获得一个结果请别指定FLAG_ACTIVITY_NEW_TASK
       然后对于指定了FLAG_ACTIVITY_NEW_DOCUMENT启动参数的情况,并且r.resultTo也就是说不接收启动结果的情况添加FLAG_ACTIVITY_NEW_TASK标志,也就是说FLAG_ACTIVITY_NEW_DOCUMENT默认是等效于FLAG_ACTIVITY_NEW_TASK的,只是启动的时候要求接受结果还是以接受结果为准,不把它启动到一个新的task上面.
       经过上面两个步骤对FLAG_ACTIVITY_NEW_TASK的处理,如果documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS或者mLaunchTaskBehind满足的情况下并且设置了FLAG_ACTIVITY_NEW_TASK则要给mLaunchFlags添加FLAG_ACTIVITY_MULTIPLE_TASK标志,为什么这么做呢,因为FLAG_ACTIVITY_MULTIPLE_TASK和FLAG_ACTIVITY_NEW_TASK会产生化学反映,尽量(这里说尽量是由于singleTask和singleInstance优先级要高于FLAG_ACTIVITY_MULTIPLE_TASK)把要启动的activity放到新的的task里面,首先mLaunchTaskBehind为真的情况下要启动的activity不会被启动到前台,但是在多任务下观察要求它在一个单独的放在调用者task的前面,所以它的语义其实就是启动到一个新的task里面. 对于r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS的情况,google source上也有说明是默认添加FLAG_ACTIVITY_MULTIPLE_TASK将docactivity启动到新的task里面.
  • mSupervisor.mUserLeaving 变量表示当用户手动把activity切换出去的时候回调Activity->onUserLeaveHint() 方法,这里如果启动activity指定了FLAG_ACTIVITY_NO_USER_ACTION标志,就不会回调这个函数
  • mDoResume 表示否是要执行resume函数,使activity可见,有些情况是不需要可见的,比如这个要启动的activity不在栈顶. 而且这里还会判断是否要延迟启动,比如activity所在的user还没有启动起来,就会设置ActivityRecord.delayedResume = true. 对于参数ActivityOptions指定了lunchTaskid和明确要求覆盖原有task的情况,要找到指定的task,但是如果task最上面的activity是不可见的,就不需要使要启动的activity显示,并且明确不要移动task到前台.所以可以看到TaskOverlay只是为了把activity放到对应的task上面,并不是为了把这个activity打到用户脸上
  • mNotTop:表示不把当前栈顶的activity作为栈顶task,这是怎么个情况呢,比如说ChooseActivity,用于选择启动哪个应用的,ChooseActivity是由系统启动的,做操作的时候不需要考虑到它,所以这里会设置这个标志.表示做一些操作的时候不考虑topActivity, 那么topActivity是谁呢,就是我们要启动的activity.
  • mInTask  为调用参数中指定的task,后面还对task做了些校验,如果这个task不在inRecents(因为我们选择task的时候是在Recents中的,但是执行到这里之后可能已经不在了),指定一个不太Recents中的task是无用的,所以对于不在Recents里的inTask要设置它为空
  • mStartFlags 多数参数用于启动activity的调试,其中START_FLAG_ONLY_IF_NEEDED标志的作用是检查自己是否在前台,如果在前台则不需要启动,不在才去启动,它的行为类似于Intent#FLAG_ACTIVITY_SINGLE_TOP flags或者
    singleTask 或者 singleTop 但是不执行onNewIntent. 所以这个flags只是为了检查自己是否在前台,所以必须调用者和要启动的activity具有相同的ComponentName,否则标志无效
  •  mNoAnimation  为true表示切换的过程不执行activity切换动画

2 private void computeLaunchingTaskFlags() 计算mLaunchFlags,这里进一步计算关于task的启动参数.

rivate void computeLaunchingTaskFlags() {
        if (mSourceRecord == null && mInTask != null && mInTask.getStack() != null) {
        //1 对于mInTask的处理
            final Intent baseIntent = mInTask.getBaseIntent();
            final ActivityRecord root = mInTask.getRootActivity();
            if (baseIntent == null) {
                ActivityOptions.abort(mOptions);
                throw new IllegalArgumentException("Launching into task without base intent: "
                        + mInTask);
            }
            if (mLaunchSingleInstance || mLaunchSingleTask) { //对于这两种类型的activity要想在新的task中创建(新的rootActivity)必须task 中不包含才能创建新的
            ......
            }
            if (root == null) { //注意mInTask默认的语义就是把要启动的activity作为task的rootActivity
                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
                        | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
                mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
                        | (baseIntent.getFlags() & flagsOfInterest);
                mIntent.setFlags(mLaunchFlags);
                mInTask.setIntent(mStartActivity);
                mAddingToTask = true;
            } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                mAddingToTask = false;
            } else {
                mAddingToTask = true;
            }
            mReuseTask = mInTask;
        } else {
       // 2 sourceRecord的处理
            mInTask = null;
            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null && mSourceRecord.isFreeform())  {
                mAddingToTask = true;
            }
        }
        //3 最后针对需要添加FLAG_ACTIVITY_NEW_TASK的情况处理
        if (mInTask == null) {
            if (mSourceRecord == null) {
                if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                }
            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            }
        }
    }

代码也是分为三个部分处理. 1,2 是两种条件的处理,3是总的处理.
首先对于条件1进行说明,mSourceRecord == null && mInTask != null && mInTask.getStack() != null 这个条件主要是用于处理mInTask, 第一个条件mSourceRecord == null说明使用SourceRecord确定task的优先级要高于参数中指定的mInTask. 如果SourceRecord的task好指定的mInTask都存在,则以mSourceRecord的为准.

  • 1 mInTask的情况,如果要启动的activity是一个singleInstance或者singleTop的activity,因为设置了这种模式的activity只能在一个task中启动,所以要判断指定的task是不是就是他们现在所在的task,如果不是的话则证明指定的task是有问题的,就会抛出异常. 对singleInstance或者singleTop处理之后,说明这个task是可以复用的了,所以首先如果这个task是一个空的task,里面还没有activity,可以把我们要启动的activity作为它的rootTask启动,所以会对这个task做初始化操作. 并且设置变量mAddingToTask,表示明确需要把这个activity放到一个task中去. 如果这个task不是一个空的task,而设置了FLAG_ACTIVITY_NEW_TASK的启动参数,那么只是把这个task带到前台,不去添加新的activity. 这部分我们要参考systemui的实现才能说的清楚,总之不添加要启动的activity到这个task,设置 mAddingToTask = false. 最后一种情况是不满足上述情况的情况,也就是说不是一个空的task,并且也没有设置FLAG_ACTIVITY_NEW_TASK启动参数,所以需要添加一个activity到这个task中,设置 mAddingToTask = true. 如果三种条件能执行完说明用户指定的task是可用的,设置mReuseTask = mInTask
  • 2.对于条件2 满足的情况,说明sourceRecord不为空或者用户没有指定mInTask,这种情况就需要设置mInTask 为null,因为sourceRecord优先级大于mInTask. 这个条件还对特殊情况做了处理,保证要启动的activity尽量放到SourceRecord 之上.
  • 3 对于上述条件判断完成,如果mInTask为空,也就是还没有明确task,就需要对task相关的参数做一些修正. 包括三个条件
    首先sourceRecord为空的情况,无法附加要启动的activity到sourceRecord的task中,所以mLaunchFlags 需要添加FLAG_ACTIVITY_NEW_TASK参数,在新的task上启动activity
    如果sourceRecord存在但是lunchMode为singleInstance的,这种activity只能自己独自在一个task上,所以mLaunchFlags也要添加FLAG_ACTIVITY_NEW_TASK参数,在新的task上启动activity
    最后lunchMode为SingleInstance 或者SingleTask的activity自带FLAG_ACTIVITY_NEW_TASK标志,尽量在原有的task上启动activity,所以mLaunchFlags 需要添加FLAG_ACTIVITY_NEW_TASK参数,在新的task上启动activity
    注意!!! :新的task并非指一个新创建的task,它的语义代表尽量不在SourceRecord的task上启动,说尽量是由于可能使用FLAG_ACTIVITY_NEW_TASK找到的task就是sourceRecord所在的task

3 private void computeSourceStack() 函数用于计算sourceStack, 就是调用者所在的stack

    private void computeSourceStack() {
        if (mSourceRecord == null) {
            mSourceStack = null;
            return;
        }
        if (!mSourceRecord.finishing) {
            mSourceStack = mSourceRecord.getStack();
            return;
        }
        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            mNewTaskInfo = mSourceRecord.info;
            final TaskRecord sourceTask = mSourceRecord.getTask();
            mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
        }
        mSourceRecord = null;
        mSourceStack = null;
    }

代码很简单,首先如果不存在mSourceRecord那么mSourceStack也是不存在的
如果mSourceRecord所代表的activity没有被关闭则直接使用sourceRecord所代表的Activity作为sourceStack
最后的情况则代表mSouorceRecord所代表的activity已经执行的finish方法,那么好了,我们要强行添加FLAG_ACTIVITY_NEW_TASK标志使activity启动到一个新的task中. 并且将原来sourceRecord的信息保存下来主要就是原来的taskinfo信息和intent信息, 最后设置mSourceRecord = null;
mSourceStack = null;保存task的intent信息和taskinfo信息是为了新建task的时候尝试恢复这个task

二 复用activity的情况
1 getReusableIntentActivity()函数,函数的名字很不友好,看似是获取复用的activity实则是获取复用的task

 private ActivityRecord getReusableIntentActivity() {
     boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || mLaunchSingleInstance || mLaunchSingleTask;
        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) {
               intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
            } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
                intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
                        !mLaunchSingleTask);
            } else {
                intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId);
            }
        }
        return intentActivity;
    }

这里罗列了一些可以复用task的情况,主要包括设置了FLAG_ACTIVITY_NEW_TASK标志并且没有设置FLAG_ACTIVITY_MULTIPLE_TASK的情况,如果设置了FLAG_ACTIVITY_MULTIPLE_TASK标志需要另外起一个task盛放要启动的activity. 以及lunchMode为singleTask或者singleInstance的情况和明确在AppOptions中指定的使用的task的情况。 对于明确指定的情况肯定要复用task,前两种情况呢,还要在不使用inTask的情况和mStartActivity.resultTo不为空的情况。 指定了InTask参数和mStartActivity.resultTo不为空的情况都会单独处理。
还要说明的是对于singleInstance的情况要找到task中包含要启动activity的task进行复用,寻找到过程使用mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false)函数,其中第三个参数为false表示不需要匹配intent,因为lunchMode为singleInstance的时候,它所在的task只能放一个activity. 如果存在这样的task那就必然使我们要找的task了。对于指定了FLAG_ACTIVITY_LAUNCH_ADJACENT的情况也是要找到与启动activity相同的task。 最后如果并非是singleInstance或者FLAG_ACTIVITY_LAUNCH_ADJACENT方式启动activity,意味着使用mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId),这种情况只是找到合适的task,并不要求task中包含对应的activity。 
- 获取到可复用的task和这个task上的activity(或许是与我们要启动的activity相同compoentname的activity或是可复用task栈顶的activity) ,整体流程如下

 if (reusedActivity != null) {
           ......
            if (mStartActivity.getTask() == null) {
                mStartActivity.setTask(reusedActivity.getTask());
            }
            if (reusedActivity.getTask().intent == null) {
                reusedActivity.getTask().setIntent(mStartActivity);
            }
            //清除task中复用的activity上面的activity
            if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || isDocumentLaunchesIntoExisting(mLaunchFlags)
                    || mLaunchSingleInstance || mLaunchSingleTask) {
                final TaskRecord task = reusedActivity.getTask();
                final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
                        mLaunchFlags);
                if (reusedActivity.getTask() == null) {
                    reusedActivity.setTask(task);
                }
                if (top != null) {
                    if (top.frontOfTask) {
                        top.getTask().setIntent(mStartActivity);
                    }
                    //执行newIntent
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                            mStartActivity.launchedFromPackage);
                }
            }
            sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
            //将复用的task拿到前台
            reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
            final ActivityRecord outResult =
                    outActivity != null && outActivity.length > 0 ? outActivity[0] : null;    
            if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
                outActivity[0] = reusedActivity;
            }
            //把task拿到前台就可以了不需要重启
            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                resumeTargetStackIfNeeded();
                return START_RETURN_INTENT_TO_CALLER;
            }
            //根据复用情况设置task
            setTaskFromIntentActivity(reusedActivity);

            if (!mAddingToTask && mReuseTask == null) {
                resumeTargetStackIfNeeded();
                if (outActivity != null && outActivity.length > 0) {
                    outActivity[0] = reusedActivity;
                }
                return START_TASK_TO_FRONT;
            }
        }

这段代码还是比较不容易弄懂的,注意我们这里的mStartActivity和reusedActivity的含义,mStartActivity才是我们要启动的activity.,而reusedActivity只不过是我们要复用的task上的一个activity,有可能是我们要复用的activity,也可能只是这个task最上面的activity.
这段代码首先如果要启动的activity还没有设置task,就设置成复用的task,另外如果复用的task还没有mStartActivity则根据activity设置baseintent.
后面一段清除task中复用的activity上面的activity的逻辑,主要是对于FLAG_ACTIVITY_CLEAR_TOP(含义就是清除与mStartActivity相同的activity上面的activity). 另外对于isDocumentLaunchesIntoExisting(mLaunchFlags)
|| mLaunchSingleInstance || mLaunchSingleTask 这三种模式的也需要清除StartActivity相同的activity上面的activity。函数体使用 final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);函数进行task的清除,值得注意的一点是performClearTaskLocked(ActivityRecord newR, int launchFlags)函数内部如果和mStartActivity相同compoentname的activity的启动模式是默认的ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE,则也会将这个activity销毁。对于SingleInstance || SingleTask|| singleTop启动模式的则不会被销毁。所以task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags)返回后对于要启动的activity的启动模式为LAUNCH_MULTIPLE的,返回值top肯定是空的。所以不会发送newIntent的请求给客户端。
后面setTargetStackAndMoveToFrontIfNeeded(reusedActivity)函数是把复用的task所在的stack设置为fourceStack并且把复用的task拿到栈顶。 请参考https://blog.csdn.net/woai110120130/article/details/79720840
执行完setTargetStackAndMoveToFrontIfNeeded函数后就可以设置返回结果了,为什么这里就可以设置了呢,注意判断条件
后面对startFlags参数的START_FLAG_ONLY_IF_NEEDED标志处理,这种情况不需要去真的启动activity,只需要使task放到前台就可以了,这种情况多是从桌面点击图标恢复task的情况。
后面 setTaskFromIntentActivity(reusedActivity)也是比较关键的函数,我在代码上进行注释,具体细节就不在讲解,最后对于复用的情况,到这里就处理完了,只是把task带到了前台,所以返回START_TASK_TO_FRONT。

private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
        if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) { //条件1 清空task
            final TaskRecord task = intentActivity.getTask();
            task.performClearTaskLocked();
            mReuseTask = task;
            mReuseTask.setIntent(mStartActivity);
            mMovedOtherTask = true;
        } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                || mLaunchSingleInstance || mLaunchSingleTask) { //2 clear top 
            ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
                    mLaunchFlags);
            if (top == null) {
                mAddingToTask = true;

                mStartActivity.setTask(null);
                mSourceRecord = intentActivity;
                final TaskRecord task = mSourceRecord.getTask();
                if (task != null && task.getStack() == null) {
                    mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
                            null /* bounds */, mLaunchFlags, mOptions);
                    mTargetStack.addTask(task,
                            !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
                }
            }
        } else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
        //3 singleTop 
            if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
                    && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
                        intentActivity.getTask());
                if (intentActivity.frontOfTask) {
                    intentActivity.getTask().setIntent(mStartActivity);
                }
                intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                        mStartActivity.launchedFromPackage);
            } else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
                mAddingToTask = true;
                mSourceRecord = intentActivity;
            }
        } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) { //4 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
            mAddingToTask = true;
            mSourceRecord = intentActivity;
        } else if (!intentActivity.getTask().rootWasReset) { //5 rootWasReset
            intentActivity.getTask().setIntent(mStartActivity);
        }
    }

setTaskFromIntentActivity 从函数的名字来看是根据intentActivity设置task, 参数是ActivityStarter->startActivityUnchecked()中的reusedActivity,函数主要分为五中情况处理

  • 1 首先对FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK的处理,这种情况要清除task. 所以后面的处理就是清空task的操作和对task的重新设置
  • 2 这个条件其实外面已经处理过,但是这里更侧重的是对条件提top == null的情况做处理(主要是那种非lunchMode为singleInstance 或者singleTask的情况)。 这里会把activity的task设置为null,因为后面会重新计算(不使用NEW_TASK找到的task,但是要尽量放到intentActivity所在的task,所以这里先把targetStack设置为intentActivity所在的stack上)
  • 3 第三种情况其实很简单,常见的情况就是从桌面进入一个task的情况,如打开了日历应用,到了创建日程的界面,然后按home键返回,再次点击桌面日历图标,这时候条件3就会满足。 函数体内首先对FLAG_ACTIVITY_SINGLE_TOP和lunchMode为SingleTop,并且task中只有一个activity的情况,那么要发送给这个activity一个newIntent事件更新页面。
      另外条件体里面的另一个分支所处理情况为task的baseIntent的intent和启动的activity intent不同的情况,说明并不是从桌面启动的,也不能直接使用这个task,需要新创建一个activity.  注意函数里面很多设置mAddingToTask为真的表示不能复用activity,需要创建新的放到task里面
  • 4 条件四是对FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标志出处理 ,这个主要用于快捷图标和或者从通知启动,这种情况需要替换task最上面的activity,所以需要添加activity到task中,设置mSourceRecord为intentActivity方便后面将activity启动到intentActivity所在的task中。
  • 5 所说的情况是希望把要启动的activity放到task的最底部,但是现在的代码结构做不到,只是把task更新为mStartActivity为baseIntent
    到这里setTaskFromIntentActivity分析完了,我们来总结下这里设置的几个变量

  • mReuseTask 复用task, 这里有两种情况会设置,第一种是inUseTask可用的时候,第二种情况是FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK情况

  • mMovedOtherTask 表示task已经被移动到顶端,不需要更新task的returnType

  • mAddingToTask 表示要新创建activity,不能复用

    回到二(Activity复用的情况下,只剩下一段代码)如下

if (!mAddingToTask && mReuseTask == null) {
               resumeTargetStackIfNeeded();
               if (outActivity != null && outActivity.length > 0) {
                   outActivity[0] = reusedActivity;
               }
               return START_TASK_TO_FRONT;
           }

这里mAddingToTask为假表示可以复用activity,mReuseTask不为空说明task被清除了,所以这两个条件满足可以复用activity并且task没有被清空就可以设置栈顶activity可见并返回START_TASK_TO_FRONT,到这里activity的复用逻辑就快要执行完成了

跳出reusedActivity不为空的情况,因为获取resuedActivity的时候并没有处理所有情况,如mInTask == null 或者mStartActivity.resultTo == null的情况,这里检查topActivity是否为我们要启动的activity. 代码如下

   final ActivityStack topStack = mSupervisor.mFocusedStack;
        final ActivityRecord topFocused = topStack.topActivity();
        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);
        if (dontStart) {
            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
            // 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;
            }
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);

            // Don't use mStartActivity.task to show the toast. We're not starting a new activity
            // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
            mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId,
                    preferredLaunchDisplayId, topStack.mStackId);

            return START_DELIVERED_TO_TOP;
        }

主要就是对FLAG_ACTIVITY_SINGLE_TOP和singleTask,singleTop, singleTask的处理,代码很简单就不解释了。
到这里activity的复用逻辑就介绍完了

三 第三部分的操作主要就是task的创建或者复用,并且拿到前台。 

 if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { //1创建新的或者重用mReuseTask
            newTask = true;   
            String packageName= mService.mContext.getPackageName();
            if (mPerf != null) {
                mStartActivity.perfActivityBoostHandler =
                    mPerf.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, packageName, -1, BoostFramework.Launch.BOOST_V1);
            }
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
        } else if (mSourceRecord != null) { //2 从mSourceRecord获取task
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) { //3 使用mInTask
            result = setTaskFromInTask();
        } else {  //4 其他情况
            // This not being started from an existing activity, and not part of a new task...
            // just put it in the top task, though these days this case should never happen.
            setTaskToCurrentTopOrCreateNewTask();
        }

代码也是分为四中情况 ,代码注释中写的很清楚,函数的名字也比较清晰,就不分析了,我们在分析stack管理的时候再进行分析。

四. 最后这段代码主要的逻辑就是activity的情动和显示的逻辑,也很简单

  mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
        mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
                mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
        if (mSourceRecord != null) {
            mStartActivity.getTask().setTaskToReturnTo(mSourceRecord);
        }
        if (newTask) {
            EventLog.writeEvent(
                    EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
                    mStartActivity.getTask().taskId);
        }
        ActivityStack.logStartActivity(
                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
        mTargetStack.mLastPausedActivity = null;

        sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);

        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                mOptions);
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                // If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                // Go ahead and tell window manager to execute app transition for this activity
                // since the app transition will not be triggered through the resume channel.
                mWindowManager.executeAppTransition();
            } else {
                // If the target stack was not previously focusable (previous top running activity
                // on that stack was not visible) then any prior calls to move the stack to the
                // will not update the focused stack.  If starting the new activity now allows the
                // task stack to be focusable, then ensure that we now update the focused stack
                // accordingly.
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }
        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
                preferredLaunchDisplayId, mTargetStack.mStackId);
        return START_SUCCESS;

也没有什么好解释的,具体启动和显示的过程我们单独写一片文章分析

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值