当前位置: 首页 > article >正文

Android Activity的启动器ActivityStarter入口

Activity启动器入口

  Android的Activity的启动入口是在ActivityStarter类的execute(),在该方法里面继续调用executeRequest(Request request) ,相应的参数都设置在方法参数request中。代码挺长,分段现在看下它的实现,分段一:

    /**
     * Executing activity start request and starts the journey of starting an activity. Here
     * begins with performing several preliminary checks. The normally activity launch flow will
     * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
     */
    private int executeRequest(Request request) {
        if (TextUtils.isEmpty(request.reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = request.reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord = null;

        final IApplicationThread caller = request.caller;
        Intent intent = request.intent;
        NeededUriGrants intentGrants = request.intentGrants;
        String resolvedType = request.resolvedType;
        ActivityInfo aInfo = request.activityInfo;
        ResolveInfo rInfo = request.resolveInfo;
        final IVoiceInteractionSession voiceSession = request.voiceSession;
        final IBinder resultTo = request.resultTo;
        String resultWho = request.resultWho;
        int requestCode = request.requestCode;
        int callingPid = request.callingPid;
        int callingUid = request.callingUid;
        String callingPackage = request.callingPackage;
        String callingFeatureId = request.callingFeatureId;
        final int realCallingPid = request.realCallingPid;
        final int realCallingUid = request.realCallingUid;
        final int startFlags = request.startFlags;
        final SafeActivityOptions options = request.activityOptions;
        Task inTask = request.inTask;

        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 = mRootWindowContainer.isInAnyTask(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.isInRootTaskLocked()) {
                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;
                callingFeatureId = sourceRecord.launchedFromFeatureId;
            }
        }

        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.getTask().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 Task resultRootTask = resultRecord == null
                ? null : resultRecord.getRootTask();

        if (err != START_SUCCESS) {
            if (resultRecord != null) {
                resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
                        null /* data */, null /* dataGrants */);
            }
            SafeActivityOptions.abort(options);
            return err;
        }

  首先从类Request中取得对应值赋值给变量。
  先将变量err设置为ActivityManager.START_SUCCESS。
  caller是应用进程Java服务代理对象。如果它被设置过,通过mService.getProcessController(caller)得到对应的WindowProcessController对象,mService是ActivityTaskManagerService对象(它里面维护着它们俩的对应关系),如果它不为null,则将局部变量callingPid、callingUid设置为它的对应的值。如果mService中没有找到caller(不为null)对应的WindowProcessController对象,则会将err设置为ActivityManager.START_PERMISSION_DENIED。
  下面通过应用Uid(aInfo.applicationInfo.uid)得到用户id。
  接下来sourceRecord和resultRecord和请求参数resultTo有关。resultTo是对应将启动Activity之后的应答发回到对应的Activity。在需要应答时,还和requestCode有关,需要将它设置为一个非负整数。所以下面通过resultTo得到sourceRecord,然后通过判断requestCode >= 0 && !sourceRecord.finishing之后,才给resultRecord赋值。
  接下来是处理标识Intent.FLAG_ACTIVITY_FORWARD_RESULT的情况。
  在sourceRecord不为null的情况下,如果设置了FLAG_ACTIVITY_FORWARD_RESULT标识,就不能设置requestCode,如果设置了requestCode(为非负数),就直接返回ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT。
  设置了FLAG_ACTIVITY_FORWARD_RESULT标识,是为了将结果转移到启动了sourceRecord的那个Activity。所以将resultRecord设置为sourceRecord.resultTo。如果resultRecord不在根任务的包括层级中,会将resultRecord = null。也会将resultWho、requestCode设置成sourceRecord的对应值。并将sourceRecord.resultTo = null。如果resultRecord != null,则将resultRecord中和sourceRecord、resultWho、requestCode相关的结果删除。如果sourceRecord的启动应用和当前要启动的应用相同,会将callingPackage、callingFeatureId设置为启动sourceRecord的包名和launchedFromFeatureId。
  接下来判断如果intent.getComponent()为null,会将err设置为ActivityManager.START_INTENT_NOT_RESOLVED。代表没有找到对应的启动的类。
  如果aInfo == null,代表也是没找到对应的类,将err设置为ActivityManager.START_CLASS_NOT_FOUND。
  如果现在还没出错(err为ActivityManager.START_SUCCESS ),并且sourceRecord在一个语音交互任务(sourceRecord.getTask().voiceSession != null)中,需要检查新启动的Activity是否能支持。没有FLAG_ACTIVITY_NEW_TASK标识,并且和sourceRecord不在同一个应用进程中,在该种条件先需要去检测。先给intent添加Intent.CATEGORY_VOICE的Category。下面是通过mService.getPackageManager().activitySupportsIntent()来检查的,最终是进入到PackageManagerService中去做检测的,这里主要检查的意思就是,启动的Activity是需要配置Intent.CATEGORY_VOICE的。如果检测没有通过,会将err = ActivityManager.START_NOT_VOICE_COMPATIBLE。
  如果目前需要启动一个语音交互任务,这里也是调用mService.getPackageManager().activitySupportsIntent()来检查的,不过它没有加Intent.CATEGORY_VOICE。这里也就是检查,它能运行。如果没通过检查,同样将err = ActivityManager.START_NOT_VOICE_COMPATIBLE。
  如果resultRecord不为null,会将它的根任务赋值给局部变量resultRootTask。
  如果现在err != START_SUCCESS,则代表出错了,不需要往下执行了。如果此时resultRecord不为null,则调用它的sendResult方法,该方法主要做:如果状态为RESUMED,并且在应用进程中运行,则直接通知它。如果不是会将结果存在resultRecord中(它是ActivityRecord类,存在它的成员results中)。再处理一下options,之后就将错误代码返回。
  继续往下看下分段二:
  

        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
                request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
                resultRootTask);
        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_WINDOW_MANAGER,
                        "shouldAbortBackgroundActivityStart");
                restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
                        callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                        request.originatingPendingIntent, request.allowBackgroundActivityStart,
                        intent);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            }
        }

        // Merge the two options bundles, while realCallerOptions takes precedence.
        ActivityOptions checkedOptions = options != null
                ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
        if (request.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,
                callingFeatureId);
        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;

            // The interception target shouldn't get any permission grants
            // intended for the original destination
            intentGrants = null;
        }

        if (abort) {
            if (resultRecord != null) {
                resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
                        null /* data */, null /* dataGrants */);
            }
            // 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)) {
                final IIntentSender target = mService.getIntentSenderLocked(
                        ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
                        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;

                // The permissions review target shouldn't get any permission
                // grants intended for the original destination
                intentGrants = null;

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

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

                if (DEBUG_PERMISSIONS_REVIEW) {
                    final Task focusedRootTask =
                            mRootWindowContainer.getTopDisplayFocusedRootTask();
                    Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
                            true, false) + "} from uid " + callingUid + " on display "
                            + (focusedRootTask == null ? DEFAULT_DISPLAY
                                    : focusedRootTask.getDisplayId()));
                }
            }
        }

  mSupervisor是ActivityTaskSupervisor对象,它的checkStartAnyActivityPermission方法主要是检查应用进程是否有START_ANY_ACTIVITY权限,如果取得,则返回true。如果没有获取到START_ANY_ACTIVITY权限,还会去检查待启动的Activity所需要的权限(如果存在)是否被应用拒绝、Action对应的权限是否被应用拒绝、如果被限制,则返回false。如果没有限制,也返回true。
  mService.mIntentFirewall是IntentFirewall对象,看名字是Intent防火墙的意思。它的checkStartActivity方法是检查它的一些规则,如果不满足,这里会进行拦截,将abort设置为true。
  mService.getPermissionPolicyInternal()是PermissionPolicyService类中的Internal对象。它主要检测Action为TelecomManager.ACTION_CHANGE_DEFAULT_DIALER和Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT时,如果调用应用的目标SDK大于等于Q时,是拦截,不允许启动的。
  在现在没有出现问题的情况下(abort为false),会调用shouldAbortBackgroundActivityStart方法来检查是否允许背景应用来启动Activity。并且将返回结果存储在变量restrictedBgActivity中。
  接下来就是处理参数选项类options的getOptions()方法,它会检查其中的一些权限,并且它会合并它里面的选项,转为ActivityOptions类对象checkedOptions。
  mService.mController在这里是一个观察者。这里是调用它的activityStarting方法通知它。
  mInterceptor是ActivityStartInterceptor对象,它是一个启动拦截器。它在符合特定条件下,会进行拦截,改变对应的Intent和其他对应值,下面再跳转就是到拦截的界面了。mInterceptor.intercept()在符合拦截的情况下,是返回true的。在这个方法里面,会将mInterceptor对象的相应进行更改,下面就用它里面的对应值设置局部变量intent等。如果用户是在Quiet模式、应用被暂停、锁任务模式下应用不允许启动、启动的应用有有害警告时都会进行拦截。
  接下来,如果abort为true,代表出现问题,需要终止,如果resultRecord不为null,将相应结果(RESULT_CANCELED,取消的结果)设置到里面,返回结果START_ABORTED。
  接下来处理的是如果启动的Activity有review权限,则会启动这个review Activity。它会在review 完成之后,再启动目标Activity。这个权限是目标SDK在Build.VERSION_CODES.M之前才适用,新的权限模式不支持。最后这段代码,就是处理我说的这些。将目标Activity的启动Intent封装成IIntentSender对象,传递给review Activity。之后就是解析出来它的ResolveInfo对象、ActivityInfo对象。
  继续往下看下分段三:

        // 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, request.ephemeralIntent,
                    callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
            resolvedType = null;
            callingUid = realCallingUid;
            callingPid = realCallingPid;

            // The ephemeral installer shouldn't get any permission grants
            // intended for the original destination
            intentGrants = null;

            aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
        }
        // TODO (b/187680964) Correcting the caller/pid/uid when start activity from shortcut
        // Pending intent launched from systemui also depends on caller app
        if (callerApp == null && realCallingPid > 0) {
            final WindowProcessController wpc = mService.mProcessMap.getProcess(realCallingPid);
            if (wpc != null) {
                callerApp = wpc;
            }
        }
        final ActivityRecord r = new ActivityRecord.Builder(mService)
                .setCaller(callerApp)
                .setLaunchedFromPid(callingPid)
                .setLaunchedFromUid(callingUid)
                .setLaunchedFromPackage(callingPackage)
                .setLaunchedFromFeature(callingFeatureId)
                .setIntent(intent)
                .setResolvedType(resolvedType)
                .setActivityInfo(aInfo)
                .setConfiguration(mService.getGlobalConfiguration())
                .setResultTo(resultRecord)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setComponentSpecified(request.componentSpecified)
                .setRootVoiceInteraction(voiceSession != null)
                .setActivityOptions(checkedOptions)
                .setSourceRecord(sourceRecord)
                .build();

        mLastStartActivityRecord = 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;
        }

        // Only allow app switching to be resumed if activity is not a restricted background
        // activity and target app is not home process, otherwise any background activity
        // started in background task can stop home button protection mode.
        // As the targeted app is not a home process and we don't need to wait for the 2nd
        // activity to be started to resume app switching, we can just enable app switching
        // directly.
        WindowProcessController homeProcess = mService.mHomeProcess;
        boolean isHomeProcess = homeProcess != null
                && aInfo.applicationInfo.uid == homeProcess.mUid;
        if (!restrictedBgActivity && !isHomeProcess) {
            mService.resumeAppSwitches();
        }

        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
                restrictedBgActivity, intentGrants);

        if (request.outActivity != null) {
            request.outActivity[0] = mLastStartActivityRecord;
        }

        return mLastStartActivityResult;
    }

  rInfo.auxiliaryInfo是和安装Instant应用有关,如果启动的是Instant应用,则会启动Instant安装者。
  接着下面处理的是从快捷方式启动Activity的情况,这种情况下,callerApp == null,realCallingPid > 0,所以取出realCallingPid对应的应用,赋值给callerApp 。
  接下来就是构建ActivityRecord对象,它是应用端Activity在系统框架层中对应的对象。它的创建是采用了建造者模式。里面用到的变量,前面大多都涉及到了,这里不详细说了。
  创建完之后,将创建的对象赋值给mLastStartActivityRecord。
  r.appTimeTracker是用来跟踪用户使用应用时间,如果没有设置它,则将它设置为sourceRecord对象(它不为null的情况下)的appTimeTracker。
  如果不是背景应用启动Activity并且启动的Activity不是Launcher进程,可以直接使APP切换开关打开。看着注释的解释是,背景应用如果是APP切换开关打开,会停止Home按键的保护模式。启动的Activity如果在Launcher进程中,需要等待Activity启动之后,才能打开APP切换开关。
  再接下来就是调用startActivityUnchecked方法来启动Activity了。并将结果存储在mLastStartActivityResult中。
  request.outActivity不为null,会将它设置为启动的ActivityRecord对象mLastStartActivityRecord。
  最后将结果返回。
  可见该方法主要就是做了一些检查,主要是一些权限和拦截的处理。
  executeRequest(Request request)的代码说完了,Activity启动的代码是在方法startActivityUnchecked方法中,所以,我们继续看它的实现。

检查之后的startActivityUnchecked方法

  看一下startActivityUnchecked方法的实现:

    /**
     * Start an activity while most of preliminary checks has been done and caller has been
     * confirmed that holds necessary permissions to do so.
     * Here also ensures that the starting activity is removed if the start wasn't successful.
     */
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        int result = START_CANCELED;
        final Task startedActivityRootTask;

        // Create a transition now to record the original intent of actions taken within
        // startActivityInner. Otherwise, logic in startActivityInner could start a different
        // transition based on a sub-action.
        // Only do the create here (and defer requestStart) since startActivityInner might abort.
        final Transition newTransition = (!mService.getTransitionController().isCollecting()
                && mService.getTransitionController().getTransitionPlayer() != null)
                ? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null;
        IRemoteTransition remoteTransition = r.takeRemoteTransition();
        if (newTransition != null && remoteTransition != null) {
            newTransition.setRemoteTransition(remoteTransition);
        }
        mService.getTransitionController().collect(r);
        try {
            mService.deferWindowLayout();
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            startedActivityRootTask = handleStartResult(r, result);
            mService.continueWindowLayout();
            mSupervisor.mUserLeaving = false;

            // Transition housekeeping
            if (!ActivityManager.isStartResultSuccessful(result)) {
                if (newTransition != null) {
                    newTransition.abort();
                }
            } else {
                if (!mAvoidMoveToFront && mDoResume
                        && mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade(
                            r.launchedFromUid)) {
                    // If the UID launching the activity has a visible window on top of the
                    // notification shade and it's launching an activity that's going to be at the
                    // front, we should move the shade out of the way so the user can see it.
                    // We want to avoid the case where the activity is launched on top of a
                    // background task which is not moved to the front.
                    StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal();
                    if (statusBar != null) {
                        // This results in a async call since the interface is one-way
                        statusBar.collapsePanels();
                    }
                }
                if (result == START_SUCCESS || result == START_TASK_TO_FRONT) {
                    // The activity is started new rather than just brought forward, so record
                    // it as an existence change.
                    mService.getTransitionController().collectExistenceChange(r);
                }
                if (newTransition != null) {
                    mService.getTransitionController().requestStartTransition(newTransition,
                            mTargetTask, remoteTransition);
                } else {
                    // Make the collecting transition wait until this request is ready.
                    mService.getTransitionController().setReady(false);
                }
            }
        }

        postStartActivityProcessing(r, result, startedActivityRootTask);

        return result;
    }

  Transition和Activity的转场动画相关,调用mService.getTransitionController()的collect®方法将ActivityRecord对象收集到转换中。
  接着mService.deferWindowLayout()是延迟窗口布局。
  调用startActivityInner()方法,实现启动Activity。
  handleStartResult(r, result)是处理启动的结果,如果启动成功,会返回它的RootTask。
  mService.continueWindowLayout()是恢复窗口布局。
  mSupervisor.mUserLeaving是一个状态,如果用户没有明确设定FLAG_ACTIVITY_NO_USER_ACTION标识,在前面startActivityInner()方法中,mSupervisor.mUserLeaving会被设置为true,这样会在Activity执行onPause之前,通知用户离开方法onUserLeaveHint()。执行完毕之后,在这里将它设置为false。
  如果启动Activity的结果不是成功的状态,如果前面创建的newTransition不为null,设置它的abort状态。
  如果是启动成功,在不是避免移到前面的条件下,如果启动的应用在通知栏打开的上层有打开窗口,这里将通知栏关闭。
  接下来是处理转场相关。如果返回结果为START_SUCCESS或START_TASK_TO_FRONT的情况下,这里将启动的ActivityRecord对象的改变状态记录下来(Activity打开或关闭)。START_SUCCESS代表正常启动一个Activity,START_TASK_TO_FRONT是一种什么情况呢?它代表Activity已经在任务栈中,并且将任务栈挪到根任务的最前端,包括根任务也会移动到TaskDisplayArea对象的最前端(这里根任务和任务有可能是同一个)。还有一个返回值为START_DELIVERED_TO_TOP,它则是代表在任务栈顶上和被启动的Activity是相同的,不需要再次启动一个新的。
  如果newTransition是在这里新创建的,这里就开始请求开始。如果不是,则是等待,直到请求是准备好。
  最后是调用postStartActivityProcessing方法。它是处理启动Activity之后的工作。

startActivityInner()方法

  接下来看看startActivityInner()方法:

    /**
     * Start an activity and determine if the activity should be adding to the top of an existing
     * task or delivered new intent to an existing activity. Also manipulating the activity task
     * onto requested or valid root-task/display.
     *
     * Note: This method should only be called from {@link #startActivityUnchecked}.
     */

    // TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
    @VisibleForTesting
    int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor, restrictedBgActivity);

        computeLaunchingTaskFlags();

        computeSourceRootTask();

        mIntent.setFlags(mLaunchFlags);

        final Task reusedTask = getReusableTask();

        // If requested, freeze the task list
        if (mOptions != null && mOptions.freezeRecentTasksReordering()
                && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
                && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
            mFrozeTaskList = true;
            mSupervisor.mRecentTasks.setFreezeTaskListReordering();
        }

        // Compute if there is an existing task that should be used for.
        final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
        final boolean newTask = targetTask == null;
        mTargetTask = targetTask;

        computeLaunchParams(r, sourceRecord, targetTask);

        // Check if starting activity on given task or on a new task is allowed.
        int startResult = isAllowedToStart(r, newTask, targetTask);
        if (startResult != START_SUCCESS) {
            return startResult;
        }

        final ActivityRecord targetTaskTop = newTask
                ? null : targetTask.getTopNonFinishingActivity();
        if (targetTaskTop != null) {
            // Recycle the target task for this launch.
            startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
            if (startResult != START_SUCCESS) {
                return startResult;
            }
        } else {
            mAddingToTask = true;
        }

        // 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 Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
        if (topRootTask != null) {
            startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants);
            if (startResult != START_SUCCESS) {
                return startResult;
            }
        }

        if (mTargetRootTask == null) {
            mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
        }
        if (newTask) {
            final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                    ? mSourceRecord.getTask() : null;
            setNewTask(taskToAffiliate);
        } else if (mAddingToTask) {
            addOrReparentStartingActivity(targetTask, "adding to task");
        }

        if (!mAvoidMoveToFront && mDoResume) {
            mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
            if (mOptions != null) {
                if (mOptions.getTaskAlwaysOnTop()) {
                    mTargetRootTask.setAlwaysOnTop(true);
                }
            }
            if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.mInternal.isDreaming()) {
                // Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
                // -behind transition so the Activity gets created and starts in visible state.
                mLaunchTaskBehind = true;
                r.mLaunchTaskBehind = true;
            }
        }

        mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
                mStartActivity.getUriPermissionsLocked());
        if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
            // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
            final PackageManagerInternal pmInternal =
                    mService.getPackageManagerInternalLocked();
            final int resultToUid = pmInternal.getPackageUid(
                    mStartActivity.resultTo.info.packageName, 0 /* flags */,
                    mStartActivity.mUserId);
            pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
                    UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
                    resultToUid /*visible*/, true /*direct*/);
        }
        if (newTask) {
            EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
                    mStartActivity.getTask().mTaskId);
        }
        mStartActivity.logStartActivity(
                EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());

        mTargetRootTask.mLastPausedActivity = null;

        mRootWindowContainer.startPowerModeLaunchIfNeeded(
                false /* forceSend */, mStartActivity);

        mTargetRootTask.startActivityLocked(mStartActivity,
                topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
                mKeepCurTransition, mOptions, sourceRecord);
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetRootTask.isTopActivityFocusable()
                    || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                    && 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.
                // Passing {@code null} as the start parameter ensures all activities are made
                // visible.
                mTargetRootTask.ensureActivitiesVisible(null /* starting */,
                        0 /* configChanges */, !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.
                mTargetRootTask.mDisplayContent.executeAppTransition();
            } else {
                // If the target root-task was not previously focusable (previous top running
                // activity on that root-task was not visible) then any prior calls to move the
                // root-task to the will not update the focused root-task.  If starting the new
                // activity now allows the task root-task to be focusable, then ensure that we
                // now update the focused root-task accordingly.
                if (mTargetRootTask.isTopActivityFocusable()
                        && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
                    mTargetRootTask.moveToFront("startActivityInner");
                }
                mRootWindowContainer.resumeFocusedTasksTopActivities(
                        mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
            }
        }
        mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);

        // Update the recent tasks list immediately when the activity starts
        mSupervisor.mRecentTasks.add(mStartActivity.getTask());
        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
                mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);

        return START_SUCCESS;
    }

  setInitialState()主要用来初始化ActivityStarter对象的成员变量,
  computeLaunchingTaskFlags()是用来计算启动任务的标识mLaunchFlags。这里注意的一点是,在没指定Task的情况下,如果启动的Activity模式是LAUNCH_SINGLE_INSTANCE或LAUNCH_SINGLE_TASK,会给mLaunchFlags添加FLAG_ACTIVITY_NEW_TASK标识。
  computeSourceRootTask()是用来得到源根任务mSourceRootTask。
  接下来将mLaunchFlags设置到mIntent中。
  getReusableTask()得到新启动Activity应该添加进的Task。主要处理启动标识FLAG_ACTIVITY_NEW_TASK标识,还有启动模式为LAUNCH_SINGLE_INSTANCE、LAUNCH_SINGLE_TASK的情况,这样得到包含对应Activity的Task。
  接下来,如果设置参数里面请求冻结任务链,设置冻结任务链属性。
  targetTask是启动的Activity使用的Task,它可能存在,也可能不存在,需要创建。这里如果上面得到的reusedTask不为null,就使用它;如果他为null,再通过computeTargetTask()计算得到。computeTargetTask()会在有FLAG_ACTIVITY_NEW_TASK标识的情况下,返回null。代表需要新建Task。computeTargetTask()在其他的情况下,如果启动Activity不为null,就返回它的Task。如果指定Task,就使用指定Task。
  如果targetTask为null,则代表需要新建Task。
  给成员变量mTargetTask赋值。
  computeLaunchParams用来计算成员变量mLaunchParams。
  isAllowedToStart()用来判断是否允许启动Activity。它主要用来判断ACTIVITY_TYPE_HOME类型Activity能否在显示屏上启动、后台启动的Activity是否终止、是否违法锁任务模式。如果返回的结果不为START_SUCCESS,则返回对应结果。
  下面如果目标Task不为null,则得到目标Task上面的不为finishing的ActivityRecord targetTaskTop。
  如果目标Task上的不为finishing的ActivityRecord targetTaskTop不为null,则调用recycleTask()处理。注意,这里的targetTaskTop可不见得就是启动的Activity,像SINGLE_TASK模式启动的Activity,它所属的任务栈里在它上面可能存在其他的Activity。recycleTask主要是对于目标Task的重用处理。如果目标Task的根Task不是当前获取焦点的根Task,它会将目标Task的根Task移动到最前面。处理启动的标识,在这里,它可能会将Task里面的Activity给去除(对应启动SingleTask的Activity,它的实现是由complyActivityFlags()实现)。它还决定是在Task顶端添加Activity还是将Task放到最前端。如果是在Task顶端添加Activity,它会将成员变量mAddingToTask设置为true。
  注意,如果recycleTask()返回的结果不为START_SUCCESS,则不会再往下执行,直接返回对应的结果。这里返回START_SUCCESS也即在Task顶端添加Activity。它会继续向下处理。像我们平时启动模式为SingleTask、SingleInstance的Activity,并且已经存在Task的情况下,就不会继续向下执行了。
  如果目标Task上的不为finishing的ActivityRecord targetTaskTop为null,则将变量mAddingToTask = true,代表需要将Activity添加到Task中。
  接下来,是判断启动的Activity是否和当前Task最顶的Activity是不是相同,如果相同,检查是不是需要重新启动一个新的Activity。下面的deliverToCurrentTopIfNeeded(topRootTask, intentGrants)就是做这个事情的。像我们平时启动模式为SingleTop的Activity就是在这里处理的。如果不用新启动Activity,返回START_DELIVERED_TO_TOP。
  再接下来,如果mTargetRootTask为null的话,通过getLaunchRootTask()方法来获得。getLaunchRootTask()如果不能得到目前存在的Task,它会新建一个Task。
  下面继续是新建Task(newTask决定),还是将Activity添加到Task中(mAddingToTask决定)。如果是新建Task,在新建之后,还需要将Activity添加到Task中的最顶端。在这里由于上一步可能通过getLaunchRootTask()新建了RootTask,在这里也可能是使用的上一步新建的RootTask。如果不需要新建Task,只是将Activity加入到Task中,这里是调用addOrReparentStartingActivity(targetTask, “adding to task”)完成的。
  下面,如果mAvoidMoveToFront为false,代表将任务移动到前面。mDoResume为true,代表需要将Activity启动。这里会调用根Task的moveToFront()将任务移动到前面。
  下面是检测Uri权限。
  如果启动Activity之后,返回结果给对应Activity存在(mStartActivity.resultTo != null)。这里获取返回接收者应用对启动应用的可见性。
  下面继续将mTargetRootTask.mLastPausedActivity = null。
  mTargetRootTask.startActivityLocked()主要是将Activity放置到Task的最上端。然后显示应用的StartingWindow。
  mDoResume代表需要恢复Activity。
  得到启动Activity的所在任务的最顶端可以运行的Activity topTaskActivity。
  如果根任务的顶端Activity不是可以取得焦点的或者任务的顶端有一个遮罩并且不是启动的Activity,这样的情况下,也不恢复Activity,只是让它可见。
  除了上面那两种情况下,就需要恢复Activity。还是检查如果根任务不是顶端获取焦点的根任务,需要将它挪到最前端。接着就调用mRootWindowContainer.resumeFocusedTasksTopActivities()来恢复目标Activity的执行。在它里面会执行根Task的resumeTopActivityUncheckedLocked()方法。由于在前面已经将Activity添加到Task的最顶端,所以这里就会将之前的处于Resumed状态的Activity给暂停,然后将新添加的Activity启动,并且将它状态改成Resumed。
  接下来调用mRootWindowContainer.updateUserRootTask()方法来更新对应用户的根Task。
  会将启动的Activity的Task添加到mSupervisor.mRecentTasks中。
  接着调用mSupervisor的handleNonResizableTaskIfNeeded()方法来处理不是可变大小的Task。
  最后返回结果START_SUCCESS。

总结

  这里是启动Activity的实现。
  首先是需要执行一系列检查,主要是权限和拦截的处理。
  接着处理主要分可以重用的Task,还是新建Task。对于可以重用的Task,还是要区分里面是否已经存在Activity实例(SingleTask、SingleInstance、SingleTop模式的Activity)进行处理。
  最后会将满足条件的Activty启动起来。


http://www.kler.cn/a/578486.html

相关文章:

  • 使用 Java 在后端 为 PDF 添加水印
  • 跟着 Lua 5.1 官方参考文档学习 Lua (11)
  • AtCoder ABC E - Min of Restricted Sum 题解
  • Etcd的安装与使用
  • Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
  • 通过定制initramfs实现从单系统分区到双系统的无缝升级
  • 手抖护理全攻略:从生活点滴改善症状
  • AI 智能:开拓未知疆域的科技先锋
  • 11-Agent中配置自己的插件
  • 芋道源码 —— Spring Boot 缓存 Cache 入门
  • 搭建农产品管理可视化,助力农业智能化
  • scala函数的至简原则
  • Android Retrofit + RxJava + OkHttp 网络请求高效封装方案
  • 线性表相关代码(顺序表+单链表)
  • C++蓝桥杯基础篇(九)
  • UE4 World, Level, LevelStreaming从入门到深入
  • 【Linux系统编程】初识系统编程
  • RMAN备份bug-审计日志暴涨(select action from gv$session)
  • ECC升级到S/4 HANA的功能差异 物料、采购、库存管理对比指南
  • 软件网络安全测试用例