standard、singleTop、singleTask和singleInstance原理分析

关键函数入口:startActivityUncheckedLocked

  我们知道启动一个Activity有四种方式:standard(标准启动模式)、singleTop、singleTask、singleInstance。先简述一个四种启动方式。standard:进入启动task,每次都创建新的实例进入task顶部;singleTop: 进入启动task,如果已有实例并且在task顶部不创建新实例,调用原实例的onNewIntent(),其它情况都创建新的实例进入task顶部;singleTask:如果某个Activity是singleTask模式,那么Task栈中将会只有一个该Activity的实例。例如:现在栈的情况为:A B C D。B的Launch mode为singleTask,此时D通过Intent跳转到B,则栈的情况变成了:A B。而C和D被弹出销毁了,也就是说位于B之上的实例都被销毁了。singleInstance:进入新的task,并且此task内只存在此一个activity ,不再加入别的activity。 如果task中存在实例,执行实例的onNewIntent()。
  道理我都懂,没有源码还是不安心啊。下面来分析下源码(基于Android5.1)。
  与本章内容相关的方法是ActivityStackSupervisor#startActivityUncheckedLocked。函数比较长,我们分段来进行介绍。
  startActivityUncheckedLocked第一个参数r表示要启动的Activity,第二个参数sourceRecord表示进行启动Activity动作的Activity,即动作发起者。doResume参数表示是否立即启动Activity,options参数与Activity转场动画ActivityOptions有关,inTask指定启动在哪个TaskRecord。通常,doResume参数为true,options参数为null,inTask参数为null,r和sourceRecord参数不为null。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
            ...

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

  这个根据Activity的launchMode决定launchSingleTop,launchSingleInstance和launchSingleTask的值。这些信息由PackageParser#parseActivity解析android:launchMode字段得到。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

        final Intent intent = r.intent;
        ...
        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

  addingToTask表示是启动的Activity是否是添加到一个已经存在的TaskRecord当中去,reuseTask表示复用的TaskRecord。如果发起者sourceRecord表示的Activity的launchMode为singleInstance,则设置FLAG_ACTIVITY_NEW_TASK标志位,所以在singleInstance模式启动的Activity中启动一个新的Activity,是会默认带上FLAG_ACTIVITY_NEW_TASK启动标志位的,这也是我们看到的在singleInstance模式启动的Activity中启动的新的Activity跟发起者Activity不在同一个TaskRecord的原因。但是带上FLAG_ACTIVITY_NEW_TASK启动标志位不意味着一定会新起一个TaskRecord,原因待会介绍。如果要启动的Activity的launchMode如果是singleTask和singleinstance,则带上FLAG_ACTIVITY_NEW_TASK标志位。
  如果发起者Activity处于finish状态,不宜将启动的Activity放在发起者Activity的TaskRecord中,因为那个TaskRecord可能已经是空的(没有非finish的Activity)了,则启动标志位要带上FLAG_ACTIVITY_NEW_TASK。于是,将发起者Activity的ActivityInfo(保存了一些解析AndroidManifest得到的Activity的信息)和发起者Activity所在的Taskrecord的Intent(一般来说是根Activity的Intent)分别保存在newTaskInfo和newTaskIntent,在创建新的TaskRecord时用到。如果发起者Activity不处于finish状态,sourceStack设置为发起者Activity所在的ActivityStack。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

        boolean addingToTask = false;
        TaskRecord reuseTask = null;
        ...
        if (sourceRecord == null && inTask != null && inTask.stack != null) {
        //不走此分支
        ...
        } else {
            inTask = null;
        }
        if (inTask == null) {
            if (sourceRecord == null) {
                // 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 && inTask == null) {
                    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) {
                // The original activity who is starting us is running as a single
                // instance...  this new activity it is starting must go on its
                // own task.
                //如果发起者的Activity的launchMode为singleInstance,则设置FLAG_ACTIVITY_NEW_TASK标志位
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            } else if (launchSingleInstance || launchSingleTask) {
                // The activity being started is a single instance...  it always
                // gets launched into its own task.
                //启动的Activity的launchMode如果是singleTask和singleinstance,则带上FLAG_ACTIVITY_NEW_TASK标志位
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            }
        }
        ActivityInfo newTaskInfo = null;
        Intent newTaskIntent = null;
        ActivityStack sourceStack;
        if (sourceRecord != null) {
            if (sourceRecord.finishing) {
                // If the source is finishing, we can't further count it as our source.  This
                // is because the task it is associated with may now be empty and on its way out,
                // so we don't want to blindly throw it in to that task.  Instead we will take
                // the NEW_TASK flow and try to find a task for it. But save the task information
                // so it can be used when creating the new task.
                if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
                    newTaskInfo = sourceRecord.info;
                    newTaskIntent = sourceRecord.task.intent;
                }
                sourceRecord = null;
                sourceStack = null;
            } else {
                sourceStack = sourceRecord.task.stack;
            }
        } else {
            sourceStack = null;
        }

        boolean movedHome = false;
        ActivityStack targetStack;
        //更新启动的Activity的启动标志位
        intent.setFlags(launchFlags);

  ;尽管使用了FLAG_ACTIVITY_NEW_TASK启动标志位或者singleTask/singleInstance的launchMode,系统还是先检查是否可以使用现有的TaskRecord,而不是立刻创建一个新的TaskRecord。singleTask模式下,使用findTaskLocked来查找一个“符合要求”的Activity;singleInstance模式下,使用findActivityLocked来查找一个“符合要求”的Activity。“符合要求”涉及到taskAffinity等的属性,稍后再分析。如果找到了一个“符合要求”的Activity即代码中的intentActivity,将启动的Activity的TaskRecord设置为intentActivity的TaskRecord,将目标启动的ActivityStack设置为intentActivity的ActivityStack。
  如果我们发现当前resume的Activity的TaskRecord不是我们找到的“符合要求”的Activity所在的TaskRecord时,需要将“符合要求”的Activity所在的TaskRecord转换成前台的TaskRecord。moveTaskToFrontLocked就是将原本处于后台的TaskRecord拿到前台去。
  现在我们找到了“符合要求”的TaskRecord,也把这个TaskRecord拿到前台。剩下就是检查我们要启动的Activity是否在这个TaskRecord中了。performClearTaskLocked用来清理这个TaskRecord中我们要启动的Activity上面的Activity。在以下两种情况performClearTaskLocked会返回null:1.在TaskRecord中找不到要启动的Activity;2.找到了要启动的Activity,但是其launchMode是standard且启动标志位没有FLAG_ACTIVITY_SINGLE_TOP且没有finish。在找到要启动的Activity的情况下,均要将其上面的Activity通过finishActivityLocked清理掉,如果符合上述2的情况下,还要额外清理找到的Activity。在performClearTaskLocked返回null的情况下,addingToTask设为true,表示添加到一个已存在的TaskRecord中,sourceRecord设为“符合要求”的Activity。在performClearTaskLocked不返回null的情况下,addingToTask为false,先调用其的onNewIntent方法,后面会直接调用resumeTopActivityLocked启动一个处于顶部的Activity,也就是寻找到的Activity。如果顶部的Activity不符合上述2的情况,就会造成顶部多个重复实例的情况。所以,对于不符合上述2的情况的Activity,即使它“符合要求”,也要将其去掉,然后重新创建一个实例。
  在singleTask或singleInstance模式或带有FLAG_ACTIVITY_NEW_TASK启动标志位的情况下,对于可以已存在于TaskRecord中无需重新创建实例的Activity,直接用resumeTopActivityLocked启动后返回。如果需要重新创建实例(addingToTask为true),则进入下一步。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

        if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || launchSingleInstance || launchSingleTask) {
            // If bring to front is requested, and no result is requested and we have not
            // been given an explicit task to launch in to, and
            // we can find a task that was started with this same
            // component, then instead of launching bring that one to the front.
            if (inTask == null && r.resultTo == null) {
                // See if there is a task to bring to the front.  If this is
                // a SINGLE_INSTANCE activity, there can be one and only one
                // instance of it in the history, and it is always in its own
                // unique task, so we do a special search.
                //查找“符合要求”的Activity
                ActivityRecord intentActivity = !launchSingleInstance ?
                        findTaskLocked(r) : findActivityLocked(intent, r.info);
                if (intentActivity != null) {
                    if (isLockTaskModeViolation(intentActivity.task)) {
                        showLockTaskToast();
                        Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                        return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
                    }
                    if (r.task == null) {
                        //更新TaskRecod
                        r.task = intentActivity.task;
                    }
                    //目标ActivityStack
                    targetStack = intentActivity.task.stack;
                    targetStack.mLastPausedActivity = null;
                    if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
                            + " from " + intentActivity);
                    targetStack.moveToFront("intentActivityFound");
                    if (intentActivity.task.intent == null) {
                        // This task was started because of movement of
                        // the activity based on affinity...  now that we
                        // are actually launching it, we can assign the
                        // base intent.
                        intentActivity.task.setIntent(r);
                    }
                    // If the target task is not in the front, then we need
                    // to bring it to the front...  except...  well, with
                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
                    // to have the same behavior as if a new instance was
                    // being started, which means not bringing it to the front
                    // if the caller is not itself in the front.
                    final ActivityStack lastStack = getLastStack();
                    ActivityRecord curTop = lastStack == null?
                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);
                    boolean movedToFront = false;
                    if (curTop != null && (curTop.task != intentActivity.task ||
                            curTop.task != lastStack.topTask())) {
                            //非前台TaskRecord,将其变成前台TaskRecord
                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
                                sourceStack.topActivity().task == sourceRecord.task)) {
                            // We really do want to push this one into the
                            // user's face, right now.
                            if (launchTaskBehind && sourceRecord != null) {
                                intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                            }
                            movedHome = true;
                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options,
                                    "bringingFoundTaskToFront");
                            if ((launchFlags &
                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                // Caller wants to appear on home activity.
                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                            }
                            options = null;
                            movedToFront = true;
                        }
                    }
                    // If the caller has requested that the target task be
                    // reset, then do so.
                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
                    }
                    if ((startFlags&ActivityManager.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!  And for paranoia, make
                        // sure we have correctly resumed the top activity.
                        if (doResume) {
                            resumeTopActivitiesLocked(targetStack, null, options);

                            // Make sure to notify Keyguard as well if we are not running an app
                            // transition later.
                            if (!movedToFront) {
                                notifyActivityDrawnForKeyguard();
                            }
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                    }
                    if ((launchFlags &
                            (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
                            == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
                        // The caller has requested to completely replace any
                        // existing task with its new activity.  Well that should
                        // not be too hard...
                        reuseTask = intentActivity.task;
                        reuseTask.performClearTaskLocked();
                        reuseTask.setIntent(r);
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                            || launchSingleInstance || launchSingleTask) {
                        // In this situation we want to remove all activities
                        // from the task up to the one being started.  In most
                        // cases this means we are resetting the task to its
                        // initial state.
                        ActivityRecord top =
                                intentActivity.task.performClearTaskLocked(r, launchFlags);
                        if (top != null) {
                            if (top.frontOfTask) {
                                // Activity aliases may mean we use different
                                // intents for the top activity, so make sure
                                // the task now has the identity of the new
                                // intent.
                                top.task.setIntent(r);
                            }
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                                    r, top.task);
                            top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                        } else {
                            // A special case: we need to
                            // start the activity because it is not currently
                            // running, and the caller has asked to clear the
                            // current task to have this activity at the top.
                            addingToTask = true;
                            // Now pretend like this activity is being started
                            // by the top of its task, so it is put in the
                            // right place.
                            sourceRecord = intentActivity;
                        }
                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
                        // In this case the top activity on the task is the
                        // same as the one being launched, so we take that
                        // as a request to bring the task to the foreground.
                        // If the top activity in the task is the root
                        // activity, deliver this new intent to it if it
                        // desires.
                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
                                && intentActivity.realActivity.equals(r.realActivity)) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                                    intentActivity.task);
                            if (intentActivity.frontOfTask) {
                                intentActivity.task.setIntent(r);
                            }
                            intentActivity.deliverNewIntentLocked(callingUid, r.intent,
                                    r.launchedFromPackage);
                        } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
                            // In this case we are launching the root activity
                            // of the task, but with a different intent.  We
                            // should start a new instance on top.
                            addingToTask = true;
                            sourceRecord = intentActivity;
                        }
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                        // In this case an activity is being launched in to an
                        // existing task, without resetting that task.  This
                        // is typically the situation of launching an activity
                        // from a notification or shortcut.  We want to place
                        // the new activity on top of the current task.
                        addingToTask = true;
                        sourceRecord = intentActivity;
                    } else if (!intentActivity.task.rootWasReset) {
                        // In this case we are launching in to an existing task
                        // that has not yet been started from its front door.
                        // The current task has been brought to the front.
                        // Ideally, we'd probably like to place this new task
                        // at the bottom of its stack, but that's a little hard
                        // to do with the current organization of the code so
                        // for now we'll just drop it.
                        intentActivity.task.setIntent(r);
                    }
                    if (!addingToTask && reuseTask == null) {
                        // We didn't do anything...  but it was needed (a.k.a., client
                        // don't use that intent!)  And for paranoia, make
                        // sure we have correctly resumed the top activity.
                        //所有的TaskRecord都已经调整好,直接启动最顶层的Activity
                        if (doResume) {
                            targetStack.resumeTopActivityLocked(null, options);
                            if (!movedToFront) {
                                // Make sure to notify Keyguard as well if we are not running an app
                                // transition later.
                                notifyActivityDrawnForKeyguard();
                            }
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_TASK_TO_FRONT;
                    }
                }
            }
        }

/frameworks/base/services/core/java/com/android/server/am/TaskRecord.java

    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;
            }
            if (r.realActivity.equals(newR.realActivity)) {
                // Here it is!  Now finish everything in front...
                final ActivityRecord ret = r;

                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
                    r = mActivities.get(activityNdx);
                    if (r.finishing) {
                        continue;
                    }
                    ActivityOptions opts = r.takeOptionsLocked();
                    if (opts != null) {
                        ret.updateOptionsLocked(opts);
                    }
                    if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
                            false)) {
                        --activityNdx;
                        --numActivities;
                    }
                }

                // Finally, if this is a normal launch mode (that is, not
                // expecting onNewIntent()), then we will finish the current
                // instance of the activity so a new fresh one can be started.
                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                    if (!ret.finishing) {
                        stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
                                "clear", false);
                        return null;
                    }
                }

                return ret;
            }
        }

        return null;
    }

查找“符合要求”的Activity

  插一下如何找到“符合要求”的Activity的内容。在singleTask模式下,使用findTaskLocked查找Activity;在singleInstance模式下,使用findActivityLocked查找Activity。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    ActivityRecord findTaskLocked(ActivityRecord r) {
        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!r.isApplicationActivity() && !stack.isHomeStack()) {
                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
                    continue;
                }
                if (!stack.mActivityContainer.isEligibleForNewTasks()) {
                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
                            stack);
                    continue;
                }
                final ActivityRecord ar = stack.findTaskLocked(r);
                if (ar != null) {
                    return ar;
                }
            }
        }
        if (DEBUG_TASKS) Slog.d(TAG, "No task found");
        return null;
    }

  findTaskLocked就是遍历每个ActivityStack中的每个TaskRecord,根据TaskRecord和入参ActivityRecord的属性决定TaskRecord中哪一个Activity符合要求。Intent#isDocument检查一个Intent是否带有FLAG_ACTIVITY_NEW_DOCUMENT(在API21以前是FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET),这个标志位启动的Activity所在的TaskRecord从后台被带到前台时,会清掉这个Activity以及其上面的Activiy。
  affinityIntent在FLAG_ACTIVITY_RESET_TASK_IF_NEEDED启动标志位被设置才有机会生效,否则为null。
  在以下几种情况才会视作找到了"符合要求”的Activity:1.启动Activity的标志位和当前遍历到的TaskRecord均没有设置FLAG_ACTIVITY_NEW_DOCUMENT标志位,且TaskRecord的rootAffinity(通常是根Activity的taskAffinity)和启动的Activity的taskAffinity相同;2.TaskRecord的Intent(通常是根Activity的Intent)的Component与启动Activity的Intent的Component相同且TaskRecord的Intent的Data和与启动Activity的Intent的Data相同(两者的Intent的Data可以均为null,视为相同);
3.TaskRecord的affinityIntent不为null,affinityIntent的Component和启动Activity的Intent的Component相同且TaskRecord的Intent的Data和与启动Activity的Intent的Data相同(两者的Intent的Data可以均为null,视为相同)。

/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

    ActivityRecord findTaskLocked(ActivityRecord target) {
        Intent intent = target.intent;//Activity启动的Intent
        ActivityInfo info = target.info;//Activity的ActivityInfo
        ComponentName cls = intent.getComponent();//Intent包含的启动组件
        if (info.targetActivity != null) {
           //targetActivity只在android:targetActivity被设置才生效,不走此分支
            cls = new ComponentName(info.packageName, info.targetActivity);
        }
        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
        boolean isDocument = intent != null & intent.isDocument();
        // If documentData is non-null then it must match the existing task data.
        Uri documentData = isDocument ? intent.getData() : null;

        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            //遍历一个ActivityStack中的所有TaskRecord
            final TaskRecord task = mTaskHistory.get(taskNdx);
            if (task.voiceSession != null) {
                // We never match voice sessions; those always run independently.
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
                continue;
            }
            if (task.userId != userId) {
                // Looking for a different task.
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
                continue;
            }
            //得到一个TaskRecord最顶端非finish状态的Activity
            final ActivityRecord r = task.getTopActivity();
            if (r == null || r.finishing || r.userId != userId ||
                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": mismatch root " + r);
                continue;
            }

            final Intent taskIntent = task.intent;//TaskRecord的根Activity的Intent
            final Intent affinityIntent = task.affinityIntent;
            final boolean taskIsDocument;
            final Uri taskDocumentData;
            if (taskIntent != null && taskIntent.isDocument()) {
                taskIsDocument = true;
                taskDocumentData = taskIntent.getData();
            } else if (affinityIntent != null && affinityIntent.isDocument()) {
                taskIsDocument = true;
                taskDocumentData = affinityIntent.getData();
            } else {
                taskIsDocument = false;
                taskDocumentData = null;
            }

            if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls="
                    + taskIntent.getComponent().flattenToShortString()
                    + "/aff=" + r.task.rootAffinity + " to new cls="
                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
            if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
                if (task.rootAffinity.equals(target.taskAffinity)) {
                    if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
                    return r;
                }
            } else if (taskIntent != null && taskIntent.getComponent() != null &&
                    taskIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
                        + r.intent);
                return r;
            } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                    affinityIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
                        + r.intent);
                return r;
            } else if (DEBUG_TASKS) {
                Slog.d(TAG, "Not a match: " + task);
            }
        }

        return null;
    }

  再看看singleInstance模式下使用的findActivityLocked函数。findActivityLocked不会再以Affinity相关属性作为查找依据,而是简单地遍历所有ActivityStack的TaskRecord,直到找到一个不是finish状态且其Intent的Component和启动Activity的Intent的Component相同且其userId和要启动的Activity的userId相同的Activity。也就是说,singleInstance模式下,只有在找到一个已存在的一模一样的Activity才会不新建一个TaskRecord,否则都会创建新的TaskRecord。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
                if (ar != null) {
                    return ar;
                }
            }
        }
        return null;
    }

/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
        ComponentName cls = intent.getComponent();
        if (info.targetActivity != null) {
            cls = new ComponentName(info.packageName, info.targetActivity);
        }
        final int userId = UserHandle.getUserId(info.applicationInfo.uid);

        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            TaskRecord task = mTaskHistory.get(taskNdx);
            if (!isCurrentProfileLocked(task.userId)) {
                return null;
            }
            final ArrayList<ActivityRecord> activities = task.mActivities;
            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                ActivityRecord r = activities.get(activityNdx);
                if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) {
                    //Slog.i(TAG, "Found matching class!");
                    //dump();
                    //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
                    return r;
                }
            }
        }

        return null;
    }

taskAffinity属性

  taskAffinity可以通过android:taskAffinity在AndroidManifest.xml的Application标签中指定,表示这个Application内所有的Activity都带上这个taskAffinity;也可以通过在Activity标签中设置android:taskAffinity属性单独为一个Activity指定taskAffinity。
  下面是解析Application标签的过程。

/frameworks/base/core/java/android/content/pm/PackageParser.java

    private boolean parseBaseApplication(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        ...
        if (sa.getBoolean(
              com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
                false)) {
            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
        }
        ...
                if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
            str = sa.getNonConfigurationString(
                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
                    Configuration.NATIVE_CONFIG_VERSION);
        } else {
            // Some older apps have been seen to use a resource reference
            // here that on older builds was ignored (with a warning).  We
            // need to continue to do this for them so they don't break.
            str = sa.getNonResourceString(
                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
        }
        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
                str, outError);

  下面是解析Activity标签的过程。

/frameworks/base/core/java/android/content/pm/PackageParser.java

    private Activity parseActivity(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {
            ...
                str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
                Configuration.NATIVE_CONFIG_VERSION);
        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
                owner.applicationInfo.taskAffinity, str, outError);
                ...
                if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
        }

  通过buildTaskAffinityName来构造一个合适的taskAffinity。调用parseBaseApplication时,第一个参数为应用的包名,第二个参数为默认的taskAffinity,第三个参数为通过android:taskAffinity指定的值。
  parseBaseApplication中buildTaskAffinityName的第一和第二个参数均是应用包名,若没有指定android:taskAffinity或者android:taskAffinity为空字符串,直接将应用包名作为taskAffinity。若指定了android:taskAffinity,则通过buildCompoundName构造一个合适的taskAffinity:1.若android:taskAffinity的值以“:”开头,则taskAffinity为应用包名和android:taskAffinity的值去掉“:”后连接起来的字符串。2.若android:taskAffinity的值不以“:”开头,则taskAffinity就是android:taskAffinity的值。
  parseActivity中buildTaskAffinityName的第一个参数是应用包名,第二个参数是在parseBaseApplication中获得的taskAffinity值,第三个参数是android:taskAffinity指定的值。依样画葫芦,可以知道:taskAffinity的获取首先是看Activity标签指定的android:taskAffinity的值,再看Application标签指定的android:taskAffinity的值,最后再以包名作为taskAffinity的值,优先级从高到低。

/frameworks/base/core/java/android/content/pm/PackageParser.java

    private static String buildTaskAffinityName(String pkg, String defProc,
            CharSequence procSeq, String[] outError) {
        if (procSeq == null) {
            return defProc;
        }
        if (procSeq.length() <= 0) {
            return null;
        }
        return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
    }

/frameworks/base/core/java/android/content/pm/PackageParser.java

    private static String buildCompoundName(String pkg,
            CharSequence procSeq, String type, String[] outError) {
        String proc = procSeq.toString();
        char c = proc.charAt(0);
        if (pkg != null && c == ':') {
            if (proc.length() < 2) {
                outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
                        + ": must be at least two characters";
                return null;
            }
            String subName = proc.substring(1);
            String nameError = validateName(subName, false);
            if (nameError != null) {
                outError[0] = "Invalid " + type + " name " + proc + " in package "
                        + pkg + ": " + nameError;
                return null;
            }
            return (pkg + proc).intern();
        }
        String nameError = validateName(proc, true);
        if (nameError != null && !"system".equals(proc)) {
            outError[0] = "Invalid " + type + " name " + proc + " in package "
                    + pkg + ": " + nameError;
            return null;
        }
        return proc.intern();
    

启动过程

  下面这部分是处理singleTop模式或者带有FLAG_ACTIVITY_SINGLE_TOP启动标志位的情况。如果当前最顶端的TaskRecord的最顶端的Activity的组件名和要启动的Activity的组件名和userId相同,则使用resumeTopActivitiesLocked来resume这个已存在的Activity,然后调用Activity的onNewIntent方法后返回。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

        if (r.packageName != null) {
            // If the activity being launched is the same as the one currently
            // at the top, then we need to check if it should only be launched
            // once.
            ActivityStack topStack = getFocusedStack();
            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
            if (top != null && r.resultTo == null) {
                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                    if (top.app != null && top.app.thread != null) {
                        if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || launchSingleTop || launchSingleTask) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
                                    top.task);
                            // For paranoia, make sure we have correctly
                            // resumed the top activity.
                            topStack.mLastPausedActivity = null;
                            if (doResume) {
                                resumeTopActivitiesLocked();
                            }
                            ActivityOptions.abort(options);
                            if ((startFlags&ActivityManager.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 ActivityManager.START_RETURN_INTENT_TO_CALLER;
                            }
                            top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                            return ActivityManager.START_DELIVERED_TO_TOP;
                        }
                    }
                }
            }

        } else {
            if (r.resultTo != null) {
                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
                        r.requestCode, Activity.RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            return ActivityManager.START_CLASS_NOT_FOUND;
        }

  下面是创建一个新的TaskRecord的流程。当启动的Activity不需要返回结果给启动发起者(resultTo为null)且没有指定启动的TaskRecord(inTask为null)且不需要在已存在的TaskRecord添加要启动的Activity(addingToTask为false)且启动标志位带有FLAG_ACTIVITY_NEW_TASK时,进入此流程。
  adjustStackFocus用来获取一个合适的ActivityStack。reuseTask表示是否复用一个清空过的TaskRecord(与FLAG_ACTIVITY_CLEAR_TASK标志位有关,此处权当为null)。createTaskRecord用来创建一个新的TaskRecord。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

        // Should this be considered a new task?
        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            if (isLockTaskModeViolation(reuseTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            newTask = true;
            targetStack = adjustStackFocus(r, newTask);
            if (!launchTaskBehind) {
                targetStack.moveToFront("startingNewTask");
            }
            if (reuseTask == null) {
                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                        newTaskInfo != null ? newTaskInfo : r.info,
                        newTaskIntent != null ? newTaskIntent : intent,
                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                        taskToAffiliate);
                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                        r.task);
            } else {
                r.setTask(reuseTask, taskToAffiliate);
            }
            if (!movedHome) {
                if ((launchFlags &
                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                    // Caller wants to appear on home activity, so before starting
                    // their own activity we will bring home to the front.
                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                }
            }
        }

  下面是默认(standard模式)的启动流程。省去其他细节,就是把启动的Activity的TaskRecord设为启动发起者Activity所在的TaskRecord。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

        } else if (sourceRecord != null) {
            final TaskRecord sourceTask = sourceRecord.task;
            if (isLockTaskModeViolation(sourceTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            targetStack = sourceTask.stack;
            targetStack.moveToFront("sourceStackToFront");
            final TaskRecord topTask = targetStack.topTask();
            if (topTask != sourceTask) {
                targetStack.moveTaskToFrontLocked(sourceTask, r, options, "sourceTaskToFront");
            }
            if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                // In this case, we are adding the activity to an existing
                // task, but the caller has asked to clear that task if the
                // activity is already running.
                ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
                keepCurTransition = true;
                if (top != null) {
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                    // For paranoia, make sure we have correctly
                    // resumed the top activity.
                    targetStack.mLastPausedActivity = null;
                    if (doResume) {
                        targetStack.resumeTopActivityLocked(null);
                    }
                    ActivityOptions.abort(options);
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
            } else if (!addingToTask &&
                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
                // In this case, we are launching an activity in our own task
                // that may already be running somewhere in the history, and
                // we want to shuffle it to the front of the stack if so.
                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
                if (top != null) {
                    final TaskRecord task = top.task;
                    task.moveActivityToFrontLocked(top);
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
                    top.updateOptionsLocked(options);
                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                    targetStack.mLastPausedActivity = null;
                    if (doResume) {
                        targetStack.resumeTopActivityLocked(null);
                    }
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
            }
            // An existing activity is starting this new activity, so we want
            // to keep the new one in the same task as the one that is starting
            // it.
            r.setTask(sourceTask, null);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in existing task " + r.task + " from source " + sourceRecord);

        

  在末尾,通过ActivityStack#startActivityLocked来继续下一步的启动流程。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);

TaskRecord和ActivityStack的创建流程

  在上面的流程中,我们使用了createTaskRecord和adjustStackFocus分别创建TaskRecord和获取ActivityStack。
  createTaskRecord就是new了一个TaskRecord,然后根据toTop参数决定把TaskRecord放在顶部还是底部。toTop为true的话,就放在顶部。上文的启动流程就是放在顶部的。

/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

    TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            boolean toTop) {
        TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
                voiceInteractor);
        addTask(task, toTop, false);
        return task;
    }

  TaskRecord构造函数就是初始化一些变量。尤其在setIntent中初始化的成员变量,包括affinity,rootAffinity,intent,realActivity等,分别被初始化为根Activity的taskAffinity,根Activity的taskAffinity,根Activity的intent,根Activity的组件。

/frameworks/base/services/core/java/com/android/server/am/TaskRecord.java

    TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
        mService = service;
        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                TaskPersister.IMAGE_EXTENSION;
        mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
        taskId = _taskId;
        mAffiliatedTaskId = _taskId;
        voiceSession = _voiceSession;
        voiceInteractor = _voiceInteractor;
        isAvailable = true;
        mActivities = new ArrayList<ActivityRecord>();
        setIntent(_intent, info);
    }

  adjustStackFocus用来分配一个合适的ActivityStack。当mLeanbackOnlyDevice为false且以下条件有一个成立:启动的Activity是普通app的Activity(除了Launcher和com.android.systemui.recents外的Activity)或者启动的Activity所在的TaskRecord是一个普通的TaskRecord(根Activity是普通app的Activity),才会有额外分配ActivityStack的可能。mLeanbackOnlyDevice标志当前的设备是否是TV设备,通过android.software.leanback_only的feature值指定,若是TV设备,则所有的Activity都启动在HomeStack中,一个承载Launcher且id为0的ActivityStack。
  1.若启动的Activity已经有所在的TaskRecord了,则直接返回这个TaskRecord所在的ActivityStack。考虑到需要创建TaskRecord的情况,这个时候启动的Activity不一定有自己的TaskRecord。2.若当前focus的ActivityStack不是HomeStack,则直接返回当前focus的ActivityStack。3.如果当前focus的ActivityStack是HomeStack,则从HomeStack的mStacks成员拿一个最顶部的非HomeStack的ActivityStack返回。4.最后才会createStackOnDisplay创建一个ActivityStack。在以上4步中,只要拿到一个合适的ActivityStack,都会更新mFocusedStack为这个合适的ActivityStack。

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
        final TaskRecord task = r.task;

        // On leanback only devices we should keep all activities in the same stack.
        if (!mLeanbackOnlyDevice &&
                (r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
            if (task != null) {
                final ActivityStack taskStack = task.stack;
                if (taskStack.isOnHomeDisplay()) {
                    if (mFocusedStack != taskStack) {
                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
                                "focused stack to r=" + r + " task=" + task);
                        mFocusedStack = taskStack;
                    } else {
                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                            "adjustStackFocus: Focused stack already=" + mFocusedStack);
                    }
                }
                return taskStack;
            }

            final ActivityContainer container = r.mInitialActivityContainer;
            if (container != null) {
                // The first time put it on the desired stack, after this put on task stack.
                r.mInitialActivityContainer = null;
                return container.mStack;
            }

            if (mFocusedStack != mHomeStack && (!newTask ||
                    mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
                return mFocusedStack;
            }

            final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
            for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = homeDisplayStacks.get(stackNdx);
                if (!stack.isHomeStack()) {
                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                            "adjustStackFocus: Setting focused stack=" + stack);
                    mFocusedStack = stack;
                    return mFocusedStack;
                }
            }

            // Need to create an app stack for this user.
            int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
                    " stackId=" + stackId);
            mFocusedStack = getStack(stackId);
            return mFocusedStack;
        }
        return mHomeStack;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Invoker123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值