Android系统开发 Activity启动流程探索

发布时间 2023-07-08 13:03:26作者: 观心静

前言

  此博客基于Android10版本,探索Activitiy的启动流程。Activitiy启动流程相当复杂,这里先看看简单概述的流程图:

  在说Activity启动流程时,我们一般会把这部分功能归于ActivityManagerService,但是系统进程中主要参与Activity的启动的是ActivityTaskManager,而ActivityTaskManager属于ActivityManagerService的一部分。 所以ActivityManagerService这个类只是一个Activity管理的笼统概念,有非常多与之配合的管理类才是真正实现这些功能的关键。

  此外请不要误解ActivityManagerService创建与显示了Activity,在Activity的启动流程中ActivityManagerService都未真正的去创建activity与显示Activity的内容(这部分还是会通过AIDL调用在应用层去实现)ActivityManagerService的主要工作还是记录Activity的堆栈、控制需要顶层显示的Activity、协调切换前后台的Activity流程,支配并且发布应用层activity的生命周期,控制Activity的生命周期全部流程。当然,我上面提了ActivityManagerService只是一个笼统概念,真正去实现这些功能的主要是以下几个类ActivityTaskManager、ActivityStarter、RootActivityContainer 、ActivityStackSupervisor、ActivityStack 。

启动Activity的流程 

第一步  调用Activity的startActivity方法。

注意,这个时候还是应用进程里。

第二步

第三步 调用mInstrumentation.execStartActivity方法

Instrumentation是Android用来自动化测试、性能分享、代码注入等等,用来辅助测试的类,说实话我也很纳闷为什么启动startActivity需要这个类参与,有点职责不清的感觉。

在下面代码中通过的ActivityTaskManager.getService() 获得的是IActivityTaskManager。你看到这个IActivityTaskManager就可以明白这是AIDL生成的接口类。然后通过IActivityTaskManager调用startActivity,通过AIDL将调用方法传递到系统进程,所以从这里继续下去就要跨进程了。

ActivityTaskManager.java

IActivityTaskManager.aidl

第四步 通过AIDL跨进程调用frameworek中ActivityTaskManagerService的startActivity方法

请注意,这一步已经是在系统进程里了

然后,我们看看startActivity方法

首先调用第1016行的startActivity,接下来会调用startActivityAsUser

startActivityAsUser方法

请注意,最后组装会执行execute方法

第五步 通过ActivityStarter活动启动,管理即将启动的Activity的堆栈与生命周期

  ActivityStarter的主要功能是解析和组装Intent、启动模式处理、权限和验证检查是否具有启动指定Activity的权限、是否满足Activity所需的最低API级别等、ActivityStarter会触发一系列系统回调方法,如onCreate()、onStart()、onResume()等,以便目标Activity能够进行必要的初始化和展示用户界面。它还会处理Activity的可见性和焦点事件的分发、ActivityStarter负责协调和监控Activity启动的整个过程。

首先通过ActivityStartController 活动启动控制器获得ActivityStarter

ActivityStarter的execute方法

ActivityStarter类

重载startActivity方法,主要是记录了马上要启动的Activity的启动原因、时间戳、启动结果。

ActivityStarter类

这是上面调用的startActivity方法,这个startActivity主要代码逻辑:

1.检查应用进程,如果进程不存在返回失败结果

2.拦截器这个需要启动的activity(应用退到后台或者用户锁屏了)

3.检查activity启动的权限

4.检查intent携带的flag,处理启动模式

5.创建ActivityRecord,记录信息

最后这个startActivity方法会调用这行代码继续执行:final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,         true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity); 

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options,
        boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
        TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
        PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
    mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
    int err = ActivityManager.START_SUCCESS;
    // Pull the optional Ephemeral Installer-only bundle out of the options early.
    final Bundle verificationBundle
            = options != null ? options.popAppVerificationBundle() : null;

    WindowProcessController callerApp = null;
    if (caller != null) {
        callerApp = mService.getProcessController(caller);
        if (callerApp != null) {
            callingPid = callerApp.getPid();
            callingUid = callerApp.mInfo.uid;
        } else {
            Slog.w(TAG, "Unable to find app for caller " + caller
                    + " (pid=" + callingPid + ") when starting: "
                    + intent.toString());
            err = ActivityManager.START_PERMISSION_DENIED;
        }
    }

    final int userId = aInfo != null && aInfo.applicationInfo != null
            ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;

    if (err == ActivityManager.START_SUCCESS) {
        Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
                + "} from uid " + callingUid);
    }

    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    if (resultTo != null) {
        sourceRecord = mRootActivityContainer.isInAnyStack(resultTo);
        if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                "Will send result to " + resultTo + " " + sourceRecord);
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    }

    final int launchFlags = intent.getFlags();

    if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
        // Transfer the result target from the source activity to the new
        // one being started, including any failures.
        if (requestCode >= 0) {
            SafeActivityOptions.abort(options);
            return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
        }
        resultRecord = sourceRecord.resultTo;
        if (resultRecord != null && !resultRecord.isInStackLocked()) {
            resultRecord = null;
        }
        resultWho = sourceRecord.resultWho;
        requestCode = sourceRecord.requestCode;
        sourceRecord.resultTo = null;
        if (resultRecord != null) {
            resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
        }
        if (sourceRecord.launchedFromUid == callingUid) {
            // The new activity is being launched from the same uid as the previous
            // activity in the flow, and asking to forward its result back to the
            // previous.  In this case the activity is serving as a trampoline between
            // the two, so we also want to update its launchedFromPackage to be the
            // same as the previous activity.  Note that this is safe, since we know
            // these two packages come from the same uid; the caller could just as
            // well have supplied that same package name itself.  This specifially
            // deals with the case of an intent picker/chooser being launched in the app
            // flow to redirect to an activity picked by the user, where we want the final
            // activity to consider it to have been launched by the previous app activity.
            callingPackage = sourceRecord.launchedFromPackage;
        }
    }

    if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
        // We couldn't find a class that can handle the given Intent.
        // That's the end of that!
        err = ActivityManager.START_INTENT_NOT_RESOLVED;
    }

    if (err == ActivityManager.START_SUCCESS && aInfo == null) {
        // We couldn't find the specific class specified in the Intent.
        // Also the end of the line.
        err = ActivityManager.START_CLASS_NOT_FOUND;
    }

    if (err == ActivityManager.START_SUCCESS && sourceRecord != null
            && sourceRecord.getTaskRecord().voiceSession != null) {
        // If this activity is being launched as part of a voice session, we need
        // to ensure that it is safe to do so.  If the upcoming activity will also
        // be part of the voice session, we can only launch it if it has explicitly
        // said it supports the VOICE category, or it is a part of the calling app.
        if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
                && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
            try {
                intent.addCategory(Intent.CATEGORY_VOICE);
                if (!mService.getPackageManager().activitySupportsIntent(
                        intent.getComponent(), intent, resolvedType)) {
                    Slog.w(TAG,
                            "Activity being started in current voice task does not support voice: "
                                    + intent);
                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failure checking voice capabilities", e);
                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
            }
        }
    }

    if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
        // If the caller is starting a new voice session, just make sure the target
        // is actually allowing it to run this way.
        try {
            if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
                    intent, resolvedType)) {
                Slog.w(TAG,
                        "Activity being started in new voice task does not support: "
                                + intent);
                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Failure checking voice capabilities", e);
            err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
        }
    }

    final ActivityStack resultStack = resultRecord == null
            ? null : resultRecord.getActivityStack();

    if (err != START_SUCCESS) {
        if (resultRecord != null) {
            resultStack.sendActivityResultLocked(
                    -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
        }
        SafeActivityOptions.abort(options);
        return err;
    }

    boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
            requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity,
            inTask != null, callerApp, resultRecord, resultStack);
    abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
            callingPid, resolvedType, aInfo.applicationInfo);
    abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
            callingPackage);

    boolean restrictedBgActivity = false;
    if (!abort) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    "shouldAbortBackgroundActivityStart");
            restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
                    callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                    originatingPendingIntent, allowBackgroundActivityStart, intent);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

    // Merge the two options bundles, while realCallerOptions takes precedence.
    ActivityOptions checkedOptions = options != null
            ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
    if (allowPendingRemoteAnimationRegistryLookup) {
        checkedOptions = mService.getActivityStartController()
                .getPendingRemoteAnimationRegistry()
                .overrideOptionsIfNeeded(callingPackage, checkedOptions);
    }
    if (mService.mController != null) {
        try {
            // The Intent we give to the watcher has the extra data
            // stripped off, since it can contain private information.
            Intent watchIntent = intent.cloneFilter();
            abort |= !mService.mController.activityStarting(watchIntent,
                    aInfo.applicationInfo.packageName);
        } catch (RemoteException e) {
            mService.mController = null;
        }
    }

    mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
    if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
            callingUid, checkedOptions)) {
        // activity start was intercepted, e.g. because the target user is currently in quiet
        // mode (turn off work) or the target application is suspended
        intent = mInterceptor.mIntent;
        rInfo = mInterceptor.mRInfo;
        aInfo = mInterceptor.mAInfo;
        resolvedType = mInterceptor.mResolvedType;
        inTask = mInterceptor.mInTask;
        callingPid = mInterceptor.mCallingPid;
        callingUid = mInterceptor.mCallingUid;
        checkedOptions = mInterceptor.mActivityOptions;
    }

    if (abort) {
        if (resultRecord != null) {
            resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                    RESULT_CANCELED, null);
        }
        // We pretend to the caller that it was really started, but
        // they will just get a cancel result.
        ActivityOptions.abort(checkedOptions);
        return START_ABORTED;
    }

    // If permissions need a review before any of the app components can run, we
    // launch the review activity and pass a pending intent to start the activity
    // we are to launching now after the review is completed.
    if (aInfo != null) {
        if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                aInfo.packageName, userId)) {
            IIntentSender target = mService.getIntentSenderLocked(
                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                    callingUid, userId, null, null, 0, new Intent[]{intent},
                    new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
                            | PendingIntent.FLAG_ONE_SHOT, null);

            Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);

            int flags = intent.getFlags();
            flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;

            /*
             * Prevent reuse of review activity: Each app needs their own review activity. By
             * default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities
             * with the same launch parameters (extras are ignored). Hence to avoid possible
             * reuse force a new activity via the MULTIPLE_TASK flag.
             *
             * Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,
             * hence no need to add the flag in this case.
             */
            if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
                flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
            }
            newIntent.setFlags(flags);

            newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
            newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
            if (resultRecord != null) {
                newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
            }
            intent = newIntent;

            resolvedType = null;
            callingUid = realCallingUid;
            callingPid = realCallingPid;

            rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
                    computeResolveFilterUid(
                            callingUid, realCallingUid, mRequest.filterCallingUid));
            aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
                    null /*profilerInfo*/);

            if (DEBUG_PERMISSIONS_REVIEW) {
                final ActivityStack focusedStack =
                        mRootActivityContainer.getTopDisplayFocusedStack();
                Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
                        true, false) + "} from uid " + callingUid + " on display "
                        + (focusedStack == null ? DEFAULT_DISPLAY : focusedStack.mDisplayId));
            }
        }
    }

    // If we have an ephemeral app, abort the process of launching the resolved intent.
    // Instead, launch the ephemeral installer. Once the installer is finished, it
    // starts either the intent we resolved here [on install error] or the ephemeral
    // app [on install success].
    if (rInfo != null && rInfo.auxiliaryInfo != null) {
        intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
                callingPackage, verificationBundle, resolvedType, userId);
        resolvedType = null;
        callingUid = realCallingUid;
        callingPid = realCallingPid;

        aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
    }

    ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
            callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
            resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
            mSupervisor, checkedOptions, sourceRecord);
    if (outActivity != null) {
        outActivity[0] = r;
    }

    if (r.appTimeTracker == null && sourceRecord != null) {
        // If the caller didn't specify an explicit time tracker, we want to continue
        // tracking under any it has.
        r.appTimeTracker = sourceRecord.appTimeTracker;
    }

    final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();

    // If we are starting an activity that is not from the same uid as the currently resumed
    // one, check whether app switches are allowed.
    if (voiceSession == null && (stack.getResumedActivity() == null
            || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
        if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                realCallingPid, realCallingUid, "Activity start")) {
            if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) {
                mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                        sourceRecord, startFlags, stack, callerApp));
            }
            ActivityOptions.abort(checkedOptions);
            return ActivityManager.START_SWITCHES_CANCELED;
        }
    }

    mService.onStartActivitySetDidAppSwitch();
    mController.doPendingActivityLaunches(false);

    final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
    mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]);
    return res;
}

ActivityStarter类

这是上面调用的startActivity的方法代码

ActivityStarter类

这是上面代码调用的startActivityUnchecked方法,其中调用的resumeFocusedStacksTopActivities 方法是下一步的关键。 

// Note: This method should only be called from {@link startActivity}.
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity, boolean restrictedBgActivity) {
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
            voiceInteractor, restrictedBgActivity);

    final int preferredWindowingMode = mLaunchParams.mWindowingMode;

    computeLaunchingTaskFlags();

    computeSourceStack();

    mIntent.setFlags(mLaunchFlags);

    ActivityRecord reusedActivity = getReusableIntentActivity();

    mSupervisor.getLaunchParamsController().calculate(
            reusedActivity != null ? reusedActivity.getTaskRecord() : mInTask,
            r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
    mPreferredDisplayId =
            mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
                    : DEFAULT_DISPLAY;

    // Do not start home activity if it cannot be launched on preferred display. We are not
    // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
    // fallback to launch on other displays.
    if (r.isActivityTypeHome() && !mRootActivityContainer.canStartHomeOnDisplay(r.info,
            mPreferredDisplayId, true /* allowInstrumenting */)) {
        Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
        return START_CANCELED;
    }

    if (reusedActivity != null) {
        // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
        // still needs to be a lock task mode violation since the task gets cleared out and
        // the device would otherwise leave the locked task.
        if (mService.getLockTaskController().isLockTaskModeViolation(
                reusedActivity.getTaskRecord(),
                (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
            Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        // True if we are clearing top and resetting of a standard (default) launch mode
        // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
        final boolean clearTopAndResetStandardLaunchMode =
                (mLaunchFlags & (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))
                        == (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
                && mLaunchMode == LAUNCH_MULTIPLE;

        // If mStartActivity does not have a task associated with it, associate it with the
        // reused activity's task. Do not do so if we're clearing top and resetting for a
        // standard launchMode activity.
        if (mStartActivity.getTaskRecord() == null && !clearTopAndResetStandardLaunchMode) {
            mStartActivity.setTask(reusedActivity.getTaskRecord());
        }

        if (reusedActivity.getTaskRecord().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.
            reusedActivity.getTaskRecord().setIntent(mStartActivity);
        } else {
            final boolean taskOnHome =
                    (mStartActivity.intent.getFlags() & FLAG_ACTIVITY_TASK_ON_HOME) != 0;
            if (taskOnHome) {
                reusedActivity.getTaskRecord().intent.addFlags(FLAG_ACTIVITY_TASK_ON_HOME);
            } else {
                reusedActivity.getTaskRecord().intent.removeFlags(FLAG_ACTIVITY_TASK_ON_HOME);
            }
        }

        // This code path leads to delivering a new intent, we want to make sure we schedule it
        // as the first operation, in case the activity will be resumed as a result of later
        // operations.
        if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                || isDocumentLaunchesIntoExisting(mLaunchFlags)
                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
            final TaskRecord task = reusedActivity.getTaskRecord();

            // 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.
            final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
                    mLaunchFlags);

            // The above code can remove {@code reusedActivity} from the task, leading to the
            // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
            // task reference is needed in the call below to
            // {@link setTargetStackAndMoveToFrontIfNeeded}.
            if (reusedActivity.getTaskRecord() == null) {
                reusedActivity.setTask(task);
            }

            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.getTaskRecord().setIntent(mStartActivity);
                }
                deliverNewIntent(top);
            }
        }

        mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded
                (false /* forceSend */, reusedActivity);

        reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);

        final ActivityRecord outResult =
                outActivity != null && outActivity.length > 0 ? outActivity[0] : null;

        // When there is a reused activity and the current result is a trampoline activity,
        // set the reused activity as the result.
        if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
            outActivity[0] = reusedActivity;
        }

        if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
            // We don't need to start a new activity, and the client said not to do anything
            // if that is the case, so this is it!  And for paranoia, make sure we have
            // correctly resumed the top activity.
            resumeTargetStackIfNeeded();
            return START_RETURN_INTENT_TO_CALLER;
        }

        if (reusedActivity != null) {
            setTaskFromIntentActivity(reusedActivity);

            if (!mAddingToTask && mReuseTask == 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.
                resumeTargetStackIfNeeded();
                if (outActivity != null && outActivity.length > 0) {
                    // The reusedActivity could be finishing, for example of starting an
                    // activity with FLAG_ACTIVITY_CLEAR_TOP flag. In that case, return the
                    // top running activity in the task instead.
                    outActivity[0] = reusedActivity.finishing
                            ? reusedActivity.getTaskRecord().getTopActivity() : reusedActivity;
                }

                return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
            }
        }
    }

    if (mStartActivity.packageName == null) {
        final ActivityStack sourceStack = mStartActivity.resultTo != null
                ? mStartActivity.resultTo.getActivityStack() : null;
        if (sourceStack != null) {
            sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
                    mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
                    null /* data */);
        }
        ActivityOptions.abort(mOptions);
        return START_CLASS_NOT_FOUND;
    }

    // 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.
    final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack();
    final ActivityRecord topFocused = topStack.getTopActivity();
    final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
    final boolean dontStart = top != null && mStartActivity.resultTo == null
            && top.mActivityComponent.equals(mStartActivity.mActivityComponent)
            && top.mUserId == mStartActivity.mUserId
            && top.attachedToProcess()
            && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
            || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK))
            // This allows home activity to automatically launch on secondary display when
            // display added, if home was the top activity on default display, instead of
            // sending new intent to the home activity on default display.
            && (!top.isActivityTypeHome() || top.getDisplayId() == mPreferredDisplayId);
    if (dontStart) {
        // For paranoia, make sure we have correctly resumed the top activity.
        topStack.mLastPausedActivity = null;
        if (mDoResume) {
            mRootActivityContainer.resumeFocusedStacksTopActivities();
        }
        ActivityOptions.abort(mOptions);
        if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
            // We don't need to start a new activity, and the client said not to do
            // anything if that is the case, so this is it!
            return START_RETURN_INTENT_TO_CALLER;
        }

        deliverNewIntent(top);

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

        return START_DELIVERED_TO_TOP;
    }

    boolean newTask = false;
    final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
            ? mSourceRecord.getTaskRecord() : null;

    // Should this be considered a new task?
    int result = START_SUCCESS;
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
    } else if (mSourceRecord != null) {
        result = setTaskFromSourceRecord();
    } else if (mInTask != null) {
        result = setTaskFromInTask();
    } 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.
        result = setTaskToCurrentTopOrCreateNewTask();
    }
    if (result != START_SUCCESS) {
        return result;
    }

    mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
            mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
    mService.getPackageManagerInternalLocked().grantEphemeralAccess(
            mStartActivity.mUserId, mIntent, UserHandle.getAppId(mStartActivity.appInfo.uid),
            UserHandle.getAppId(mCallingUid));
    if (newTask) {
        EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
                mStartActivity.getTaskRecord().taskId);
    }
    ActivityStack.logStartActivity(
            EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTaskRecord());
    mTargetStack.mLastPausedActivity = null;

    mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
            false /* forceSend */, mStartActivity);

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

    mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
            preferredWindowingMode, mPreferredDisplayId, mTargetStack);

    return START_SUCCESS;
}

第六步 调用RootActivityContainer类resumeFocusedStacksTopActivities 方法

RootActivityContainer 这个类是临时的(可能是从Android10版本后新增的),用于将一部分功能从ActivityStackSupervisor.java中分离出来,所以RootActivityContainer是ActivityStackSupervisor的部分功能的承接者,负责记录和管理活动的导航栈,也就是用户在应用程序中浏览活动的顺序和层次关系。它可以跟踪用户打开和关闭活动的操作,并确保正确的活动出现在屏幕上。

第七步 调用ActivityStack类的resumeTopActivityUncheckedLocked方法

这里介绍一下ActivityStack,ActivityStack是一个具体的活动栈实例,代表了一个任务(Task)中的一组活动。每个任务对应一个活动栈,其中包含了按照启动顺序排列的活动实例。ActivityStack的主要功能是管理和维护活动实例的生命周期,以及处理用户界面的导航和交互。内部有TaskRecord的集合mTaskHistory全局变量 与 ActivityRecord的集合mLRUActivities全局变量。mTaskHistory负责保存所有以前(可能仍在运行)活动的后台历史记录, mLRUActivities用来按最近的使用情况排序。

resumeTopActivityUncheckedLocked方法是ActivityStack类中的一个重要方法,用于恢复位于栈顶的Activity。

ActivityStack类resumeTopActivityInnerLocked方法

这里介绍下resumeTopActivityInnerLocked方法,此方法主要功能是在启动Activity的过程中将要启动的Activity设置为顶层可见。

下面的图片还是在resumeTopActivityInnerLocked方法里,在上面取得了next后,这部分代码里调用了startSpecificActivityLocked方法去执行下一步。(请注意它携带的next参数)

下面图片中调用了ActivityStackSupervisor类realStartActivityLocked方法,去执行下一步。

ActivityStackSupervisor是一个活动堆栈的全局的管理者,负责协调和管理整个应用程序中的所有活动栈。它是ActivityManagerService中的一部分,负责跟踪和管理不同任务的活动栈,并处理活动的启动、切换和销毁。

ActivityStackSupervisor通过创建和管理多个ActivityStack实例来实现对整个应用程序的活动栈的管理(所以ActivityStackSupervisor是作为ActivityStack管理者)。它通过ActivityStack的方法来操作和管理ActivityStack中的活动实例。ActivityStackSupervisor可以通过跟踪活动栈的状态和任务之间的关系,进行任务的切换和活动的启动。

在realStartActivityLocked方法中

这里创建了ClientTransaction类它客户端事务类,它会携带一些应用进程信息、Activity生命周期信息、ActivityToken。它是需要被传递到应用层的关键信息。提供应用层创建Activity的进程信息与Activity的生命周期信息。

第八步 通过ClientLifecycleManager进行AIDL跨进程

下面会调用ClientLifecycleManager类scheduleTransaction方法。

ClientTransaction类是客户端事务类在上面被创建后传递到这里,它会携带一些应用进程信息、Activity生命周期信息、ActivityToken。它是需要被传递到应用层的关键信息。提供应用层创建Activity的进程信息与Activity的生命周期信息。

通过ClientTransaction类的schedule方法。在这里会通过mClient(这是IApplicationThread的实例)调用scheduleTransaction方法将ClientTransaction自己传递到应用层,最终通过AIDL这个调用会被应用层的ActivityThread.ApplicationThread中的scheduleTransaction方法接收。 

第九步 回调到应用进程中

在ActivityThread的scheduleTransaction会接收消息,从

第十步 发送Handler消息

在上面我们可以看到ActivityThread的scheduleTransaction里又自己调用了scheduleTransaction方法,所以这里的关键是ActivityThread继承的ClientTransactionHandler类,看看它实现的scheduleTransaction方法做了什么。在下面的图片中我们可以看到它发送了一个Handler消息。 这个sendMessage是抽象方法,它的具体实现要回到ActivityThread类中查看。

这里补充一下上面发送sendMessage的ActivityThread的Handler,这很关键,因为大部分工作都通过了ActivityThread的内部类H(H类继承了Handler类),通过这个H类异步调度大量工作,包括了绑定应用、申请退出应用、广播、启动服务、停止服务、绑定服务、解绑服务、创建Activity等等。

在ActivityThread类中的H内部类里,处理发送过来的消息

第十一步 执行启动activity

TransactionExecutor类的execute方法

TransactionExecutor类的executeCallbacks方法

LaunchActivityItem类的execute方法

ActivityThread类的handlerLaunchActivity方法

最后一步,创建新的Activity

ActivityThread类的performLaunchActivity方法

下图最终new了一个activity

end