startActivityUncheckedLocked(ActivityRecord r,ActivityRecord sourceRecord, int startFlags, boolean doResume,Bundle options)
传入的参数为:
ActivityRecord r:要启动的Activity的ActivityRecord
ActivityRecord sourceRecord:调用者Activity的ActivityRecord
int startFlags:0
boolean doResume:true
Bundle options:调用者传入,一般为null
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
final int userId = r.userId;
int launchFlags = intent.getFlags();
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG,
"startActivity() => mUserLeaving=" + mUserLeaving);
// If the caller has asked not to resume at this point, we make note
// of this in the record so that we can skip it when trying to find
// the top running activity.
if (!doResume) {
r.delayedResume = true;
}
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
首先得到要启动的Activity的Intent,然后得到调用者的uid,以及要启动的UID,以及Intent中的LaunchFlags,接着判断launchFlags中是否有FLAG_ACTIVITY_NO_USER_ACTION,如果有的话,那么则得到mUserLeaving为true,此标志位是用来判断是否回调onUserLeaving函数的。
接着判断doResume是否为false,如果为false的话,说明需要延迟resume,则将r.delayedResume设置为true,接着判断launchFlags中是否有FLAG_ACTIVITY_PREVIOUS_IS_TOP,如果有的话,那么则将notTop置为r,否则为null
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = topRunningNonDelayedActivityLocked(notTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
// Caller is not the same as launcher, so always needed.
startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
}
}
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) {
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.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
// The activity being started is a single instance... it always
// gets launched into its own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new
// task... yet the caller has requested a result back. Well, that
// is pretty messed up, so instead immediately send back a cancel
// and let the new task continue launched as normal without a
// dependency on its originator.
Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
}
接着判断startFlags中是否有START_FLAG_ONLY_IF_NEED标志位,那么就会检查调用者的ActivityRecord与要启动的Activity是否是同一个,如果不是同一个的话,那么就将这个START_FLAG_ONLY_IF_NEEDED的标识取消掉。
接着判断sourceRecord是否为空,如果sourceRecord为空的话,那么则会将Intent的launchFlags添加上Intent.FLAG_ACTIVITY_NEW_TASK
如果sourceRecord不为空,那么则判断sourceRecord的LaunchMode是否为SINGLE_INSTANCE,如果是的话,也将launchFlags添上Intent.FLAG_ACTIVITY_NEW_TASK
如果sourceRecord的launchMode不是SINGLE_INSTANCE的话,则判断要启动的Activity是否是SINGLE_INSTANCE或者SINGLE_TASK的,如果是的话,那么将launchFlags添加上Intent.FLAG_ACTIVITY_NEW_TASK
接着判断要启动的Activity的resultTo是否为空,如果不为空而且launchFlags中有Intent.FLAG_ACTIVITY_NEW_TASK的话,那么就将要启动的Activity的resultTo设为null,并且发送取消的消息给调用者的Activity,因为Android不允许两个Task之间通信。
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if (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.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
if (taskTop.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.
taskTop.task.setIntent(intent, r.info);
}
// 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.
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
if (curTop != null && curTop.task != taskTop.task) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
boolean callerAtFront = sourceRecord == null
|| curTop.task == sourceRecord.task;
if (callerAtFront) {
// We really do want to push this one into the
// user's face, right now.
movedHome = true;
moveHomeToFrontFromLaunchLocked(launchFlags);
moveTaskToFrontLocked(taskTop.task, r, options);
options = null;
}
}
// If the caller has requested that the target task be
// reset, then do so.
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
taskTop = resetTaskIfNeededLocked(taskTop, 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) {
resumeTopActivityLocked(null, options);
} 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 = taskTop.task;
performClearTaskLocked(taskTop.task.taskId);
reuseTask.setIntent(r.intent, r.info);
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// 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 = performClearTaskLocked(
taskTop.task.taskId, 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.intent, r.info);
}
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent);
} 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 = taskTop;
}
} else if (r.realActivity.equals(taskTop.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
&& taskTop.realActivity.equals(r.realActivity)) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
if (taskTop.frontOfTask) {
taskTop.task.setIntent(r.intent, r.info);
}
taskTop.deliverNewIntentLocked(callingUid, r.intent);
} else if (!r.intent.filterEquals(taskTop.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 = taskTop;
}
} 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 = taskTop;
} else if (!taskTop.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.
taskTop.task.setIntent(r.intent, r.info);
}
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.
if (doResume) {
resumeTopActivityLocked(null, options);
} else {
ActivityOptions.abort(options);
}
return ActivityManager.START_TASK_TO_FRONT;
}
}
}
}
声明三个变量,addingToTask,moveHome,reuseTask。判断launchFlags中存在的Intent.FLAG_ACTIVITY_NEW_TASK,并且没有Intent.FLAG_ACTIVITY_MULTIPLE_TASK或者要启动的Activity是SINGLE_TASK或者SINGLE_INSTANCE的话,那么就会执行上面的逻辑,否则则不会。
判断r.resultTo是否为空,如果为空的话才执行下面代码,否则不执行。
接着通过r.launchMode来找到当前位于Task顶部的Activty,如果是SINGLE_INSTANCE的话,那么就找到Activity,否则则是找到Task顶部的Activity。接着判断taskTop是否为null,如果为Null的话,说明没有启动过这个Activity或者是没有创建过这个TASK,否则就将intent设置到对应的Task中。
接着得到整个ActivityTask最上面的那个ActivityRecord,如果当前最上面的Activity的task和要启动的Activity的Task不一样的话,那么将launchFlags添加Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT,接着判断sourceRecord是否为null,如果不为null并且sourceRecord与curTop的Task一致的话,那么说明,调用者Activity正在最上层显示,那么此时因为两个Activity的Task不一样,所以就会调用moveTaskToFrontLocked将目标Task整个移动到最上面。
接着判断launchFlag中是否有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,如果有的话,则调用resetTaskIfNeededLocked,然后重新计算出当前Task的顶部Activity,然后赋值给taskTop。
接着判断startFlags是否有START_FLAG_ONLY_IF_NEEDED,判断当前要启动的Activity是否启动新的Activity,如果标志位设成true的话,那么就调用resumeTopActivity(null)启动顶部的Activity,也就是什么都不做。
然后判断:launchFlags是否有FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK,如果有的话,那么就会将reuseTask被赋值成为taskTop.task,也就是说,新运行的这个Activity将重用这个Task,并且调用performClearTaskLocked,然后将Task中的Activity全部清空。否则判断launchFlags中是否有FLAG_ACTIVITY_CLEAR_TOP,或者要启动的Activity的launchMode是否为SINGLE_TASK或者SINGLE_INSTANCE的,如果是的话,那么清掉Task中的Activity,并且找到位于Task中的Activity,如果是一样的话,那么则返回top,也就是说,如果ABCDE,那么从E要启动C,并且C是SINGLE_TASK的话,那么就会清掉DE,然后得到的top就是C了,然后判断top是否为空,如果不为空的话,那么就会调用top.deliverNewIntentLocked回调C的onNewIntent函数,如果不存在的话,那么就将addingToTask设成true,表示要添加到这个Task中,并且将sourceRecord设置成为TaskTop。
否则则判断,launchFlags是否有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,如果有的话那么设置addingTask=true,并且将sourceRecord设置成taskTop。
最后判断,addingTask是否为false,并且reuseTask是否为null,如果addingTask为false,代表不添加到Task中,而reuseTask为null,代表无重用的Task,那么就直接调用resumeTopActivityLocked
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.
ActivityRecord top = 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
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null);
}
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);
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
}
}
} else {
if (r.resultTo != null) {
sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return ActivityManager.START_CLASS_NOT_FOUND;
}
判断要启动的Activity的包名是否为空,如果不为空的话,那么得到mHistory最顶部的ActivityRecord,接着判断当前顶部的Activity与要启动的Activity是否相同,并且Activity的进程以及ApplicationThread不为空,接着如果判断launchFlags为FLAG_ACTIVITY_SINGLE_TOP或者LaunchMode为SINGLE_TOP或者SINGLE_TASK的话,那么就调用resumeTopActivityLocked,并且调用top.deliverNewIntentLocked回调Activity的onNewIntent。否则如果包名为空,那么返回CLASS_NOT_FOUND结果。
boolean newTask = false;
boolean keepCurTransition = false;
// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if (reuseTask == null) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
r.setTask(reuseTask, reuseTask, true);
}
newTask = true;
if (!movedHome) {
moveHomeToFrontFromLaunchLocked(launchFlags);
}
} else if (sourceRecord != null) {
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 = performClearTaskLocked(
sourceRecord.task.taskId, r, launchFlags);
keepCurTransition = true;
if (top != null) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
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.
int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
if (where >= 0) {
ActivityRecord top = moveActivityToFrontLocked(where);
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.updateOptionsLocked(options);
top.deliverNewIntentLocked(callingUid, r.intent);
if (doResume) {
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(sourceRecord.task, sourceRecord.thumbHolder, false);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in existing task " + r.task);
} else {
// 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.
final int N = mHistory.size();
ActivityRecord prev =
N > 0 ? mHistory.get(N-1) : null;
r.setTask(prev != null
? prev.task
: new TaskRecord(mService.mCurTask, r.info, intent), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
创建两个变量,newTask以及keepCurTransition,newTask标识着是否需要创建一个新的Task:
1.判断r.resultTo是否为null,如果为null,并且addingToTask为false,launchFlag被置为FLAG_ACTIVITY_NEW_TASK的话,然后判断reuseTask是否为空,如果为空的话,说明没有可以重用的Task,那么就需要创建一个新的Task,如果reuseTask不为空的话,那么说明有重用的Task,那么就直接设置Task即可。然后判断moveHome,如果moveHome为false的话,那么就会调用moveHomeToFrontLaunchLocked
2.否则判断sourceReocrd是否为空,如果不为空的话,那么判断addingToTask是否为false,并且launchFlags中是否有FLAG_ACTIVITY_CLEAR_TOP,如果存在的话,那么就调用performClearTaskLocked函数,清除掉Task上面的Activity,然后得到Task的顶部的Activity,如果该Activity不为空的话,那么就会调用top.delieverNewIntentLocked,回调onNewIntent
3.否则判断addingToTask是否为false,并且launcFlag是否为FLAG_ACTIVITY_REORDER_TO_FRONT,如果存在该标志位的话,接着通过findActivityInHistoryLocked得到与TaskID还有r相同的ActivityRecord,如果相同的话,那么则返回Activity的Index,如果index大于等于0的话,那么就会将Activity移到History的顶部,然后回调onNewIntent,然后设置它的Task。
4.否则得到mHistory最顶部的Activity,如果Activity是否为null,如果不为null的话,那么就设置r.taskId为Activity的ID,如果为null的话,那么就创建一个新的TaskRecord,然后通过r.setTask设置进去。