Android源码--startActivityUncheckedLocked

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设置进去。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值