关键函数入口: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;
}