Activity启动流程(二)在ActivityManagerService.java中的第一次执行
发布日期:2021-07-23 22:22:27 浏览次数:2 分类:技术文章

本文共 48832 字,大约阅读时间需要 162 分钟。

打开ActivityManagerService.java这个类,可以看到

public class ActivityManagerService extends IActivityManager.Stub        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback

很明显,继承了IActivityManager.Stub  和前面我们在ActivityManager中看到的是同一个Stub,这个就是ActivityManager

的Service了

 

本文主要涉及两个类 ActivityManagerService以及ActivityStarter

一:构造ActivityStarter

从前一个进程的startactivity我们开始寻找:

@Override    public final int startActivity(IApplicationThread caller, String callingPackage,            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,                resultWho, requestCode, startFlags, profilerInfo, bOptions,                UserHandle.getCallingUserId());    }    @Override    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,                resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,                true /*validateIncomingUser*/);    }    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,            boolean validateIncomingUser) {        enforceNotIsolatedCaller("startActivity");        userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");        // TODO: Switch to user app stacks here.        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")                .setCaller(caller)                .setCallingPackage(callingPackage)                .setResolvedType(resolvedType)                .setResultTo(resultTo)                .setResultWho(resultWho)                .setRequestCode(requestCode)                .setStartFlags(startFlags)                .setProfilerInfo(profilerInfo)                .setActivityOptions(bOptions)                .setMayWait(userId)                .execute();    }

通过一系列的调用,最终构造了一个ActivityStarter并且execute了

二:ActivityStarter的execute方法及startActivityMayWait方法

注意这里set配置的时候调用了这个方法,所以mRequest.mayWait = true

ActivityStarter setMayWait(int userId) {        mRequest.mayWait = true;        mRequest.userId = userId;        return this;    }

看下execute方法

/**     * Starts an activity based on the request parameters provided earlier.     * @return The starter result.     */    int execute() {        try {            // TODO(b/64750076): Look into passing request directly to these methods to allow            // for transactional diffs and preprocessing.            if (mRequest.mayWait) {                return startActivityMayWait(mRequest.caller, mRequest.callingUid,                        mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,                        mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,                        mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,                        mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,                        mRequest.inTask, mRequest.reason,                        mRequest.allowPendingRemoteAnimationRegistryLookup);            } else {                return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,                        mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,                        mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,                        mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,                        mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,                        mRequest.ignoreTargetSecurity, mRequest.componentSpecified,                        mRequest.outActivity, mRequest.inTask, mRequest.reason,                        mRequest.allowPendingRemoteAnimationRegistryLookup);            }        } finally {            onExecutionComplete();        }    }

staratActivityMayWait  这个方法超级长

private int startActivityMayWait(IApplicationThread caller, int callingUid,            String callingPackage, Intent intent, String resolvedType,            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,            IBinder resultTo, String resultWho, int requestCode, int startFlags,            ProfilerInfo profilerInfo, WaitResult outResult,            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,            int userId, TaskRecord inTask, String reason,            boolean allowPendingRemoteAnimationRegistryLookup) {        // Refuse possible leaked file descriptors        if (intent != null && intent.hasFileDescriptors()) {            throw new IllegalArgumentException("File descriptors passed in Intent");        }        mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();        boolean componentSpecified = intent.getComponent() != null;        final int realCallingPid = Binder.getCallingPid();        final int realCallingUid = Binder.getCallingUid();        int callingPid;        if (callingUid >= 0) {            callingPid = -1;        } else if (caller == null) {            callingPid = realCallingPid;            callingUid = realCallingUid;        } else {            callingPid = callingUid = -1;        }        // Save a copy in case ephemeral needs it        final Intent ephemeralIntent = new Intent(intent);        // Don't modify the client's object!        intent = new Intent(intent);        if (componentSpecified                && !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)                && !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())                && !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())                && mService.getPackageManagerInternalLocked()                        .isInstantAppInstallerComponent(intent.getComponent())) {            // intercept intents targeted directly to the ephemeral installer the            // ephemeral installer should never be started with a raw Intent; instead            // adjust the intent so it looks like a "normal" instant app launch            intent.setComponent(null /*component*/);            componentSpecified = false;        }        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,                0 /* matchFlags */,                        computeResolveFilterUid(                                callingUid, realCallingUid, mRequest.filterCallingUid));        if (rInfo == null) {            UserInfo userInfo = mSupervisor.getUserInfo(userId);            if (userInfo != null && userInfo.isManagedProfile()) {                // Special case for managed profiles, if attempting to launch non-cryto aware                // app in a locked managed profile from an unlocked parent allow it to resolve                // as user will be sent via confirm credentials to unlock the profile.                UserManager userManager = UserManager.get(mService.mContext);                boolean profileLockedAndParentUnlockingOrUnlocked = false;                long token = Binder.clearCallingIdentity();                try {                    UserInfo parent = userManager.getProfileParent(userId);                    profileLockedAndParentUnlockingOrUnlocked = (parent != null)                            && userManager.isUserUnlockingOrUnlocked(parent.id)                            && !userManager.isUserUnlockingOrUnlocked(userId);                } finally {                    Binder.restoreCallingIdentity(token);                }                if (profileLockedAndParentUnlockingOrUnlocked) {                    rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,                            PackageManager.MATCH_DIRECT_BOOT_AWARE                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,                            computeResolveFilterUid(                                    callingUid, realCallingUid, mRequest.filterCallingUid));                }            }        }        // Collect information about the target of the Intent.        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);        synchronized (mService) {            final ActivityStack stack = mSupervisor.mFocusedStack;            stack.mConfigWillChange = globalConfig != null                    && mService.getGlobalConfiguration().diff(globalConfig) != 0;            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,                    "Starting activity when config will change = " + stack.mConfigWillChange);            final long origId = Binder.clearCallingIdentity();            if (aInfo != null &&                    (aInfo.applicationInfo.privateFlags                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 &&                    mService.mHasHeavyWeightFeature) {                // This may be a heavy-weight process!  Check to see if we already                // have another, different heavy-weight process running.                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {                    final ProcessRecord heavy = mService.mHeavyWeightProcess;                    if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid                            || !heavy.processName.equals(aInfo.processName))) {                        int appCallingUid = callingUid;                        if (caller != null) {                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);                            if (callerApp != null) {                                appCallingUid = callerApp.info.uid;                            } else {                                Slog.w(TAG, "Unable to find app for caller " + caller                                        + " (pid=" + callingPid + ") when starting: "                                        + intent.toString());                                SafeActivityOptions.abort(options);                                return ActivityManager.START_PERMISSION_DENIED;                            }                        }                        IIntentSender target = mService.getIntentSenderLocked(                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",                                appCallingUid, userId, null, null, 0, new Intent[] { intent },                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT                                        | PendingIntent.FLAG_ONE_SHOT, null);                        Intent newIntent = new Intent();                        if (requestCode >= 0) {                            // Caller is requesting a result.                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);                        }                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,                                new IntentSender(target));                        if (heavy.activities.size() > 0) {                            ActivityRecord hist = heavy.activities.get(0);                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,                                    hist.packageName);                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,                                    hist.getTask().taskId);                        }                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,                                aInfo.packageName);                        newIntent.setFlags(intent.getFlags());                        newIntent.setClassName("android",                                HeavyWeightSwitcherActivity.class.getName());                        intent = newIntent;                        resolvedType = null;                        caller = null;                        callingUid = Binder.getCallingUid();                        callingPid = Binder.getCallingPid();                        componentSpecified = true;                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,                                0 /* matchFlags */, computeResolveFilterUid(                                        callingUid, realCallingUid, mRequest.filterCallingUid));                        aInfo = rInfo != null ? rInfo.activityInfo : null;                        if (aInfo != null) {                            aInfo = mService.getActivityInfoForUser(aInfo, userId);                        }                    }                }            }            final ActivityRecord[] outRecord = new ActivityRecord[1];            int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,                    voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,                    ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,                    allowPendingRemoteAnimationRegistryLookup);            Binder.restoreCallingIdentity(origId);            if (stack.mConfigWillChange) {                // If the caller also wants to switch to a new configuration,                // do so now.  This allows a clean switch, as we are waiting                // for the current activity to pause (so we will not destroy                // it), and have not yet started the next activity.                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,                        "updateConfiguration()");                stack.mConfigWillChange = false;                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,                        "Updating to new configuration after starting activity.");                mService.updateConfigurationLocked(globalConfig, null, false);            }            if (outResult != null) {                outResult.result = res;                final ActivityRecord r = outRecord[0];                switch(res) {                    case START_SUCCESS: {                        mSupervisor.mWaitingActivityLaunched.add(outResult);                        do {                            try {                                mService.wait();                            } catch (InterruptedException e) {                            }                        } while (outResult.result != START_TASK_TO_FRONT                                && !outResult.timeout && outResult.who == null);                        if (outResult.result == START_TASK_TO_FRONT) {                            res = START_TASK_TO_FRONT;                        }                        break;                    }                    case START_DELIVERED_TO_TOP: {                        outResult.timeout = false;                        outResult.who = r.realActivity;                        outResult.totalTime = 0;                        outResult.thisTime = 0;                        break;                    }                    case START_TASK_TO_FRONT: {                        // ActivityRecord may represent a different activity, but it should not be                        // in the resumed state.                        if (r.nowVisible && r.isState(RESUMED)) {                            outResult.timeout = false;                            outResult.who = r.realActivity;                            outResult.totalTime = 0;                            outResult.thisTime = 0;                        } else {                            outResult.thisTime = SystemClock.uptimeMillis();                            mSupervisor.waitActivityVisible(r.realActivity, outResult);                            // Note: the timeout variable is not currently not ever set.                            do {                                try {                                    mService.wait();                                } catch (InterruptedException e) {                                }                            } while (!outResult.timeout && outResult.who == null);                        }                        break;                    }                }            }            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);            return res;        }    }

三,从mayWait到startActivityUnchecked

这个方法关键的一句调用了startActivity方法

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, String reason,            boolean allowPendingRemoteAnimationRegistryLookup) {        if (TextUtils.isEmpty(reason)) {            throw new IllegalArgumentException("Need to specify a reason.");        }        mLastStartReason = reason;        mLastStartActivityTimeMs = System.currentTimeMillis();        mLastStartActivityRecord[0] = null;        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,                inTask, allowPendingRemoteAnimationRegistryLookup);        if (outActivity != null) {            // mLastStartActivityRecord[0] is set in the call to startActivity above.            outActivity[0] = mLastStartActivityRecord[0];        }        return getExternalResult(mLastStartActivityResult);    }

继续startActivity

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

再次startActivity

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,                ActivityRecord[] outActivity) {        int result = START_CANCELED;        try {            mService.mWindowManager.deferSurfaceLayout();            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,                    startFlags, doResume, options, inTask, outActivity);        } finally {            // If we are not able to proceed, disassociate the activity from the task. Leaving an            // activity in an incomplete state can lead to issues, such as performing operations            // without a window container.            final ActivityStack stack = mStartActivity.getStack();            if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {                stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,                        null /* intentResultData */, "startActivity", true /* oomAdj */);            }            mService.mWindowManager.continueSurfaceLayout();        }        postStartActivityProcessing(r, result, mTargetStack);        return result;    }

startActivityUnchecked,这个方法也超级长。。。。

// 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) {        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,                voiceInteractor);        computeLaunchingTaskFlags();        computeSourceStack();        mIntent.setFlags(mLaunchFlags);        ActivityRecord reusedActivity = getReusableIntentActivity();        int preferredWindowingMode = WINDOWING_MODE_UNDEFINED;        int preferredLaunchDisplayId = DEFAULT_DISPLAY;        if (mOptions != null) {            preferredWindowingMode = mOptions.getLaunchWindowingMode();            preferredLaunchDisplayId = mOptions.getLaunchDisplayId();        }        // windowing mode and preferred launch display values from {@link LaunchParams} take        // priority over those specified in {@link ActivityOptions}.        if (!mLaunchParams.isEmpty()) {            if (mLaunchParams.hasPreferredDisplay()) {                preferredLaunchDisplayId = mLaunchParams.mPreferredDisplayId;            }            if (mLaunchParams.hasWindowingMode()) {                preferredWindowingMode = mLaunchParams.mWindowingMode;            }        }        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.getTask(),                    (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.getTask() == null && !clearTopAndResetStandardLaunchMode) {                mStartActivity.setTask(reusedActivity.getTask());            }            if (reusedActivity.getTask().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.getTask().setIntent(mStartActivity);            }            // 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.getTask();                // 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.getTask() == 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.getTask().setIntent(mStartActivity);                    }                    deliverNewIntent(top);                }            }            mSupervisor.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) {                        outActivity[0] = reusedActivity;                    }                    return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;                }            }        }        if (mStartActivity.packageName == null) {            final ActivityStack sourceStack = mStartActivity.resultTo != null                    ? mStartActivity.resultTo.getStack() : 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 = mSupervisor.mFocusedStack;        final ActivityRecord topFocused = topStack.getTopActivity();        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);        final boolean dontStart = top != null && mStartActivity.resultTo == null                && top.realActivity.equals(mStartActivity.realActivity)                && top.userId == mStartActivity.userId                && top.app != null && top.app.thread != null                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0                || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));        if (dontStart) {            // For paranoia, make sure we have correctly resumed the top activity.            topStack.mLastPausedActivity = null;            if (mDoResume) {                mSupervisor.resumeFocusedStackTopActivityLocked();            }            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.getTask(), preferredWindowingMode,                    preferredLaunchDisplayId, topStack);            return START_DELIVERED_TO_TOP;        }        boolean newTask = false;        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)                ? mSourceRecord.getTask() : 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, topStack);        } 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.            setTaskToCurrentTopOrCreateNewTask();        }        if (result != START_SUCCESS) {            return result;        }        mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);        mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,                mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));        if (newTask) {            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.userId,                    mStartActivity.getTask().taskId);        }        ActivityStack.logStartActivity(                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());        mTargetStack.mLastPausedActivity = null;        mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,                mOptions);        if (mDoResume) {            final ActivityRecord topTaskActivity =                    mStartActivity.getTask().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(null, 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.                mService.mWindowManager.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() && !mSupervisor.isFocusedStack(mTargetStack)) {                    mTargetStack.moveToFront("startActivityUnchecked");                }                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,                        mOptions);            }        } else if (mStartActivity != null) {            mSupervisor.mRecentTasks.add(mStartActivity.getTask());        }        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,                preferredLaunchDisplayId, mTargetStack);        return START_SUCCESS;    }

此,我们走到了ActivityStarter的startActivityUnchecked方法。后面继续分析。

转载地址:https://blog.csdn.net/perfectnihil/article/details/90919240 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Activity启动流程(三)从远端回到本地进程(mClient.scheduleTransaction(this);)
下一篇:关于android.os.ServiceManager 这个类及源码中的问题

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月15日 02时59分01秒