美文网首页Android开发经验谈Android开发
中:Android startActivity原理分析(基于An

中:Android startActivity原理分析(基于An

作者: Android征途 | 来源:发表于2019-03-22 17:09 被阅读6次

    继上篇总结------我们继续研读startActivityLocked函数
    https://www.jianshu.com/p/76a98a341bcd上部分:Android startActivity原理分析(基于Android 8.1 AOSP)
    废话少说,直接呈代码!

    int startActivityLocked(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,
                ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
                ActivityRecord[] outActivity, TaskRecord inTask, String reason) {
    
            if (TextUtils.isEmpty(reason)) {
                throw new IllegalArgumentException("Need to specify a reason.");
            }
            //记录时间,然后转发请求
            mLastStartReason = reason;
            mLastStartActivityTimeMs = System.currentTimeMillis();
            mLastStartActivityRecord[0] = null;
    
            //跳入startActivity函数中
            mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                    callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                    inTask);
    
            if (outActivity != null) {
                // mLastStartActivityRecord[0] is set in the call to startActivity above.
                outActivity[0] = mLastStartActivityRecord[0];
            }
    
            // Aborted results are treated as successes externally, but we must track them internally.
            return mLastStartActivityResult != START_ABORTED ? mLastStartActivityResult : START_SUCCESS;
        }
    

    这一站仅仅是记录时间,然后清空mLastStartActivityRecord数组的位置,为即将要启动的Activity腾位置,我们继续向下看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,
                ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
                ActivityRecord[] outActivity, TaskRecord 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;
            //获取我们应用的进程描述类ProcessRecord对象,获取原理是先获取所有进程
            //然后用我们的caller和ProcessRecord下的thread对象做对比,如果是同一个便可以作为返回结果返回出来了
            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;
                }
            }
    
            //又一次获取了userId~~~
            final int userId = aInfo != 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);
            }
            //这个resultTo就是我们的mToken对象,然后isInAnyStackLocked的作用便是获取Token
            //上弱引用的ActivityRecord对象,这样就得到了我们启动者的ActivityRecord对象了,就是//我们例子中的MainActivity的ActivityRecord对象
            //这块是处理startActivityForResult的逻辑,resultRecord是哪个Activity的信息,就会调用哪个Activity的onActivityResult函数,在requestCode大于等于0的情况,它存的是我们的MainActivity
            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();
    
            //FLAG_ACTIVITY_FORWARD_RESULT这个标记允许我们把startActivityForResult的线路
            //拉长,比如A->B->C,然后C可以直接把值传递到A
            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) {
                    ActivityOptions.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 (!AppGlobals.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 (!AppGlobals.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);
                }
                ActivityOptions.abort(options);
                return err;
            }
    
            //校验当前应用是否有开启权限,我们的普通开启肯定是有权限啦,所以可以忽略啦
            boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
                    resultRecord, resultStack, options);
            abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                    callingPid, resolvedType, aInfo.applicationInfo);
    
            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);
            mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid,
                    options);
            intent = mInterceptor.mIntent;
            rInfo = mInterceptor.mRInfo;
            aInfo = mInterceptor.mAInfo;
            resolvedType = mInterceptor.mResolvedType;
            inTask = mInterceptor.mInTask;
            callingPid = mInterceptor.mCallingPid;
            callingUid = mInterceptor.mCallingUid;
            options = 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(options);
                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);
                    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对象,存到传入数组0索引上
            ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                    callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                    resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                    mSupervisor, options, 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 (voiceSession == null && (stack.mResumedActivity == null
                    || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
                if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                        realCallingPid, realCallingUid, "Activity start")) {
                    PendingActivityLaunch pal =  new PendingActivityLaunch(r,
                            sourceRecord, startFlags, stack, callerApp);
                    mPendingActivityLaunches.add(pal);
                    ActivityOptions.abort(options);
                    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;
            }
    
            //检查是否有需要延迟启动的Activity,如果有,则启动
            doPendingActivityLaunchesLocked(false);
    
            //跳转到另外一个startActivity函数中继续执行
            return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                    options, inTask, outActivity);
        }
    

    这个函数就分析完了,写的很长,但是逻辑并不复杂,主要就是处理startActivityForResult的逻辑和校验权限,最后还创建了一个目标activity的ActivityRecord对象就完了。我们继续看下一个重载函数

    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 {
                //阻塞一下Surface
                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.
                if (!ActivityManager.isStartResultSuccessful(result)
                        && mStartActivity.getTask() != null) {
                    mStartActivity.getTask().removeActivity(mStartActivity);
                }
                mService.mWindowManager.continueSurfaceLayout();
            }
    
            postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId,  mSourceRecord,
                    mTargetStack);
    
            return result;
        }
    

    这个函数很简单,也只是通知Wms(WindowManagerService)阻塞一下Surface,然后就转发到了startActivityUnchecked函数中继续处理了,我们接着看startActivityUnchecked的实现吧。

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity) {
    
            //根据启动intent识别启动模式,如果是startActivityForResult并且启动模式是NEW_TASK的话,就会让startActivityForResult的回调失效
            setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                    voiceInteractor);
    
            //判断启动模式,并且在mLaunchFlags上追加对应的标记
            computeLaunchingTaskFlags();
    
            //获取到Activity的启动栈
            computeSourceStack();
    
            //根据上面的计算,应用识别到的flags
            mIntent.setFlags(mLaunchFlags);
    
            ActivityRecord reusedActivity = getReusableIntentActivity();
    
            final int preferredLaunchStackId =
                    (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
            final int preferredLaunchDisplayId =
                    (mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY;
    
            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 (mSupervisor.isLockTaskModeViolation(reusedActivity.getTask(),
                        (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                    mSupervisor.showLockTaskToast();
                    Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
                }
    
                if (mStartActivity.getTask() == null) {
                    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)
                        || mLaunchSingleInstance || mLaunchSingleTask) {
                    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);
                    }
                }
    
                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;
                }
                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 START_TASK_TO_FRONT;
                }
            }
    
            //校验目标页面的包名,很有可能是没有安装该应用
            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.topActivity();
            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
                    || mLaunchSingleTop || mLaunchSingleTask);
            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(), preferredLaunchStackId,
                        preferredLaunchDisplayId, topStack.mStackId);
    
                return START_DELIVERED_TO_TOP;
            }
    
            //接下来判断是否需要新创建一个task出来,比如NEW_TASK
            //如果不需要新建就直接把目标Activity放入到对应的task内,在setTaskFromSourceRecord内执行
            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, preferredLaunchStackId, 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 (mSourceRecord != null) {
                mStartActivity.getTask().setTaskToReturnTo(mSourceRecord);
            }
            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;
    
            //判断是否需要发送警告(PowerManager实现),判断依据是resumedActivity被回收或者是进程被杀死或者是目标Activity的进程和resumedActivity的进程不一致的时候
            sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
    
            //处理新增Task和启动动画的问题
            mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                    mOptions);
            //处理完启动栈任务栈的问题后,准备执行发起者的Resume状态了
            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.
                    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");
                    }
                    //从这开始resume我们的MainActivity
                    mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                            mOptions);
                }
            } else {
                mTargetStack.addRecentActivityLocked(mStartActivity);
            }
            mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
    
            mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
                    preferredLaunchDisplayId, mTargetStack.mStackId);
    
            return START_SUCCESS;
        }
    

    这个startActivityUnchecked做的核心功能就是识别并且处理启动模式,以及关联的启动栈、任务栈,最后选择完合适的任务栈后就准备调用resumeFocusedStackTopActivityLocked继续开启Activity,我们来继续往下看。

    boolean resumeFocusedStackTopActivityLocked(
                ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    
            if (!readyToResume()) {
                return false;
            }
    
            if (targetStack != null && isFocusedStack(targetStack)) {
                return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
            }
    
            final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
            if (r == null || r.state != RESUMED) {
                mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
            } else if (r.state == RESUMED) {
                // Kick off any lingering app transitions form the MoveTaskToFront operation.
                mFocusedStack.executeAppTransition(targetOptions);
            }
    
            return false;
        }
    

    这个resumeFocusedStackTopActivityLocked函数定义在ActivityStackSupervisor类中,从类名上可以看得出来这个是个管理者,不参与具体实现,所以函数也很短,只是做简单的校验就立马转发,很符合企业里领导的身份。我们看紧接着就被转发到了ActivityStack下的resumeTopActivityUncheckedLocked中了,下面这个就是ActivityStack下的resumeTopActivityUncheckedLocked函数了

    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
            if (mStackSupervisor.inResumeTopActivity) {
                // Don't even start recursing.
                return false;
            }
    
            boolean result = false;
            try {
                // Protect against recursion.
                mStackSupervisor.inResumeTopActivity = true;
                result = resumeTopActivityInnerLocked(prev, options);
            } finally {
                mStackSupervisor.inResumeTopActivity = false;
            }
    
            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
            // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
            // any necessary pause logic occurs. In the case where the Activity will be shown regardless
            // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
            // is skipped.
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
    
            return result;
        }
    

    在这里我们可以看一下,他也没做什么业务处理。而是转交给了另外一个函数去处理。因为后面的代码还有一大段,篇幅有限,大家下篇见。

    了解更多Android知识,或者获取相关资料请加入Android技术开发交流2群:935654177。本群可免费获取Gradle,RxJava,小程序,Hybrid,移动架构,NDK,React Native,性能优化等技术教程!

    相关文章

      网友评论

        本文标题:中:Android startActivity原理分析(基于An

        本文链接:https://www.haomeiwen.com/subject/xourvqtx.html