Android P ActivityManagerService(五) startActivity的第三小部分

ActivityStarter中的startActivity方法;这是一个有300行长度方法;总体是这样的;

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) {
    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;

    ProcessRecord callerApp = null;
    if (caller != null) {
        callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
            callingPid = callerApp.pid;
            callingUid = callerApp.info.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 = mSupervisor.isInAnyStackLocked(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.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 ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();

    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);

    // 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 (mService.mPermissionReviewRequired && 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);

            final int flags = intent.getFlags();
            Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
            newIntent.setFlags(flags
                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            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) {
                Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
                        true, false) + "} from uid " + callingUid + " on display "
                        + (mSupervisor.mFocusedStack == null
                        ? DEFAULT_DISPLAY : mSupervisor.mFocusedStack.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 = mSupervisor.mFocusedStack;

    // 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")) {
            mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                    sourceRecord, startFlags, stack, callerApp));
            ActivityOptions.abort(checkedOptions);
            return ActivityManager.START_SWITCHES_CANCELED;
        }
    }

    if (mService.mDidAppSwitch) {
        // This is the second allowed switch since we stopped switches,
        // so now just generally allow switches.  Use case: user presses
        // home (switches disabled, switch to home, mDidAppSwitch now true);
        // user taps a home icon (coming from home so allowed, we hit here
        // and now allow anyone to switch again).
        mService.mAppSwitchesAllowedTime = 0;
    } else {
        mService.mDidAppSwitch = true;
    }

    mController.doPendingActivityLaunches(false);

    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity);
}

然后呢;只能分段一点点看了;

1. 定义err并赋值;这个套路大家也都经常用,根据err的情况返回之类的;

int err = ActivityManager.START_SUCCESS;

2. 干掉bundle;具体看注释;

// Pull the optional Ephemeral Installer-only bundle out of the options early.
final Bundle verificationBundle
        = options != null ? options.popAppVerificationBundle() : null;
/**
 * Pop the extra verification bundle for the installer.
 * This removes the bundle from the ActivityOptions to make sure the installer bundle
 * is only available once.
 * @hide
 */
public Bundle popAppVerificationBundle() {
    Bundle out = mAppVerificationBundle;
    mAppVerificationBundle = null;
    return out;
}

3. 获取ProcessRecord;这里的mService就是AMS;这里不做过多的展开;

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

4. 获取userId;

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

5. 打个Log;这个Log只有当成功获取ProcessRecord的时候才会被打出来;

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

6. 给sourceRecord和resultRecord和赋值;

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

ActivityRecord的名词解释;它能表示历史堆栈中的Activity;

/**
 * An entry in the history stack, representing an activity.
 */
public final class ActivityRecord

ActivityStackSupervisor顾名思义是用来管理ActivityStack的;

ActivityStack的名词解释;声明和管理一堆Activity;

/**
 * State and management of a single stack of activities.
 */
class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
        implements StackWindowListener

isInAnyStackLocked方法;这里token是调用startActivity的Activity的token;

ActivityRecord isInAnyStackLocked(IBinder token) {
    int numDisplays = mActivityDisplays.size();
    for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
        final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = display.getChildAt(stackNdx);
            final ActivityRecord r = stack.isInStackLocked(token);
            if (r != null) {
                return r;
            }
        }
    }
    return null;
}
ActivityRecord isInStackLocked(IBinder token) {
    final ActivityRecord r = ActivityRecord.forTokenLocked(token);
    return isInStackLocked(r);
}
public static ActivityRecord forTokenLocked(IBinder token) {
    try {
        return Token.tokenToActivityRecordLocked((Token)token);
    } catch (ClassCastException e) {
        Slog.w(TAG, "Bad activity token: " + token, e);
        return null;
    }
}

7. 对于FLAG_ACTIVITY_FORWARD_RESULT的一些处理;

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

8. 检查Component

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

9. 检查ActivityInfo

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

10. 检查voice session;和下面不一样,这里是一个老的voice session的一部分;

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

11. 检查voice session;和上面不一样,这里是一个新的voice session;

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

12. 获取ActivityStack resultStack;

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

13. 判断当前是否已经出错,如果出错就直接返回,并且发送result;

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

14. 检查权限;

boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
        requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity,
        inTask != null, callerApp, resultRecord, resultStack);

15. 检查Activity intent启动是否被允许;

abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
        callingPid, resolvedType, aInfo.applicationInfo);
/**
 * This is called from ActivityManager to check if a start activity intent should be allowed.
 * It is assumed the caller is already holding the global ActivityManagerService lock.
 */
public boolean checkStartActivity(Intent intent, int callerUid, int callerPid,
        String resolvedType, ApplicationInfo resolvedApp) {
    return checkIntent(mActivityResolver, intent.getComponent(), TYPE_ACTIVITY, intent,
            callerUid, callerPid, resolvedType, resolvedApp.uid);
}

16. 合并options

// 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);
}

17. 告知测试接口正在启动Activity;这里的mService.mController是一个IActivityController接口,不是ActivityStartController,它的作用是测试,具体可以看下方的名词解释;

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;
    }
}
/**
 * Testing interface to monitor what is happening in the activity manager
 * while tests are running.  Not for normal application development.
 * {@hide}
 */
interface IActivityController

18. 设置拦截状态并尝试拦截;mInterceptor是ActivityStartInterceptor对象,名词解释如下;

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;
}
/**
 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
 * It's initialized via setStates and interception occurs via the intercept method.
 *
 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
 * is no guarantee that other system services are already present.
 */
class ActivityStartInterceptor

19. 判断是否需要退出;如果是,直接return;当然,如果需要result的话,还是得发个result;

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

20. 权限审核处理;

// 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 (mService.mPermissionReviewRequired && 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);

        final int flags = intent.getFlags();
        Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
        newIntent.setFlags(flags
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        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) {
            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
                    true, false) + "} from uid " + callingUid + " on display "
                    + (mSupervisor.mFocusedStack == null
                    ? DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId));
        }
    }
}

21. 处理ephemeral;还不清楚是什么情况下的case;应用安装???

// 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*/);
}

22. 创建ActivityRecord;刚说过,它表示这着一个Activity;这里算是完成了从Intent到ActivityRecord的蜕变;

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

23. TimeTracker设置;

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

24. 拿到mFocusedStack;

final ActivityStack stack = mSupervisor.mFocusedStack;

25. 检查是否允许切换;

// 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")) {
        mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                sourceRecord, startFlags, stack, callerApp));
        ActivityOptions.abort(checkedOptions);
        return ActivityManager.START_SWITCHES_CANCELED;
    }
}

26. 针对HOME的切换处理;

if (mService.mDidAppSwitch) {
    // This is the second allowed switch since we stopped switches,
    // so now just generally allow switches.  Use case: user presses
    // home (switches disabled, switch to home, mDidAppSwitch now true);
    // user taps a home icon (coming from home so allowed, we hit here
    // and now allow anyone to switch again).
    mService.mAppSwitchesAllowedTime = 0;
} else {
    mService.mDidAppSwitch = true;
}

27. 设置为不启动Pending的Activity,为下面的启动Activity做铺垫;

mController.doPendingActivityLaunches(false);

28. 启动Activity;搞了半天,这里还是没有涉及到正在的启动;300行代码只是做个铺垫;新的startActivity参数明显少了;毕竟已经有了ActivityRecord对象了;

return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
        true /* doResume */, checkedOptions, inTask, outActivity);

小结

这段代码大部分都是做在各种检查;经过层层安检后,会创建ActivityRecord对象;并调用下一步的startActivity方法;

猜你喜欢

转载自blog.csdn.net/weixin_39821531/article/details/89450444