Activity启动研究

Activity启动研究

前言

在工作项目中,需要研究这一部分的源码。在项目完成后,对这个部分做一个总结。

流程图

在安卓中,我们一般使用intent来启动Activity。比如startActivity(new intent)这样的方式。上层我们使用的时候比较简单,但是,仔细研究,向下挖掘,就会复杂一点。流程图如上。我们重点研究ActivityStarter部分。因为核心内容就在Starter中的execute部分。

ActivityStarter研究

java 复制代码
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
            @Nullable String callingFeatureId, Intent intent, String resolvedType,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
        mAmInternal.addCreatorToken(intent, callingPackage);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final SafeActivityOptions opts = SafeActivityOptions.fromBundle(
                bOptions, callingPid, callingUid);

        assertPackageMatchesCallingUid(callingPackage);
        enforceNotIsolatedCaller("startActivityAsUser");

        if (isSdkSandboxActivityIntent(mContext, intent)) {
            SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
                    SdkSandboxManagerLocal.class);
            sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
                    intent, callingUid, callingPackage
            );
        }

        if (Process.isSdkSandboxUid(callingUid)) {
            SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
                    SdkSandboxManagerLocal.class);
            if (sdkSandboxManagerLocal == null) {
                throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
                        + " an activity from an SDK sandbox uid.");
            }
            sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
        }

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                callingPid, callingUid, "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        // 这里获得ActivityStarter开始启动Activity
        // 很明显,这里设置了许多参数,在execute都能看到这些参数的用途
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setCallingFeatureId(callingFeatureId)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(opts)
                .setUserId(userId)
                .execute();
    }

看到入口,现在开始研究execute函数内部内容。一开始研究的时候,我们只需要关注重点的函数就好,所以我这里省略一些没那么重要的代码。如果全看的话,会造成很大的阅读压力。我强烈建议同学们,在阅读源码的时候,结合一个网络上的分析文档一起看,这样能够抓住主线。

java 复制代码
/**
     * Resolve necessary information according the request parameters provided earlier, and execute
     * the request which begin the journey of starting an activity.
     * @return The starter result.
     */
    int execute() {
        // Required for logging ContentOrFileUriEventReported in the finally block.
        String callerActivityName = null;
        ActivityRecord launchingRecord = null;
        try {
            // 这里在做执行前的一些准备工作,挖下去,其实就是在设置一个状态值
            onExecutionStarted();

           /*
                .......省略
            */

            // If the caller hasn't already resolved the activity, we're willing
            // to do so here. If the caller is already holding the WM lock here,
            // and we need to check dynamic Uri permissions, then we're forced
            // to assume those permissions are denied to avoid deadlocking.
            if (mRequest.activityInfo == null) {

                // 1、这里很重要,这里就开始处理我们传递过来的intent参数了
                mRequest.resolveActivity(mSupervisor);
            }


            /*
               ....省略....
            */

            int res = START_CANCELED;
            synchronized (mService.mGlobalLock) {
                final boolean globalConfigWillChange = mRequest.globalConfig != null
                        && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
                final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
                if (rootTask != null) {
                    rootTask.mConfigWillChange = globalConfigWillChange;
                }
                ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
                        + "will change = %b", globalConfigWillChange);

                final long origId = Binder.clearCallingIdentity();
                try {
                    res = resolveToHeavyWeightSwitcherIfNeeded();
                    if (res != START_SUCCESS) {
                        return res;
                    }
                    // 2.这里是开始执行request,上面启动失败,就会返回。
                    res = executeRequest(mRequest);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                    mRequest.logMessage.append(" result code=").append(res);
                    Slog.i(TAG, mRequest.logMessage.toString());
                    mRequest.logMessage.setLength(0);
                }

                if (globalConfigWillChange) {
                    // 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.mAmInternal.enforceCallingPermission(
                            android.Manifest.permission.CHANGE_CONFIGURATION,
                            "updateConfiguration()");
                    if (rootTask != null) {
                        rootTask.mConfigWillChange = false;
                    }
                    ProtoLog.v(WM_DEBUG_CONFIGURATION,
                                "Updating to new configuration after starting activity.");

                    mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
                }

                // The original options may have additional info about metrics. The mOptions is not
                // used here because it may be cleared in setTargetRootTaskIfNeeded.
                final ActivityOptions originalOptions = mRequest.activityOptions != null
                        ? mRequest.activityOptions.getOriginalOptions() : null;
                // Only track the launch time of activity that will be resumed.
                if (mDoResume || (isStartResultSuccessful(res)
                        && mLastStartActivityRecord.getTask().isVisibleRequested())) {
                    launchingRecord = mLastStartActivityRecord;
                }
                // If the new record is the one that started, a new activity has created.
                final boolean newActivityCreated = mStartActivity == launchingRecord;
                // Notify ActivityMetricsLogger that the activity has launched.
                // ActivityMetricsLogger will then wait for the windows to be drawn and populate
                // WaitResult.
                mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
                        newActivityCreated, launchingRecord, originalOptions);
                if (mRequest.waitResult != null) {
                    mRequest.waitResult.result = res;
                    res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
                            launchingState);
                }

                // 这里返回启动的结果。如果是SUCCESS,就说明启动成功了
                return getExternalResult(res);
            }
        } finally {
              /*
                .....省略.....
                */
            onExecutionComplete();
        }
    }

1.resolveActivity

java 复制代码
/**
         * Resolve activity from the given intent for this launch.
         */
        void resolveActivity(ActivityTaskSupervisor supervisor) {
            /*
                这里重点看这个resolveIntent
                调用到ResolveIntentHelper.java中的resolveIntentInternal函数,在该函数中,会
使用PackageManagerService来检索对应用户下能够处理这个intent的resolve,这里先不介绍。
            */

            resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,
                    0 /* matchFlags */,
                    computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid),
                    realCallingPid);
            if (resolveInfo == null) {
                // Special case for profiles: If attempting to launch non-crypto aware app in a
                // locked profile or launch an app in a profile that is stopped by quiet mode from
                // an unlocked parent, allow it to resolve as user will be sent via confirm
                // credentials to unlock the profile.
                resolveInfo = resolveIntentForLockedOrStoppedProfiles(supervisor);
            }

            // Collect information about the target of the Intent.
            // 用上面获得的resolveinfo来获取对应的Activity,其实返回就是resolvceinfo中的activityInfo
            activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,
                    profilerInfo);
           /*
            ....省略....
            */
        }

2.executeRequest

java 复制代码
 /**
     * Executing activity start request and starts the journey of starting an activity. Here
     * begins with performing several preliminary checks. The normally activity launch flow will
     * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
     */
    private int executeRequest(Request request) {
        /*
         ....省略....
         */

        final int userId = aInfo != null && aInfo.applicationInfo != null
                ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
        final int launchMode = aInfo != null ? aInfo.launchMode : 0;
        if (err == ActivityManager.START_SUCCESS) {
         /*
             以后想要排查activity启动的问题,就可以debug这里这个字段,看看是不是走在这里
         */
            request.logMessage.append("START u").append(userId).append(" {")
                    .append(intent.toShortString(true, true, true, false))
                    .append("} with ").append(launchModeToString(launchMode))
                    .append(" from uid ").append(callingUid);
            if (callingUid != realCallingUid
                    && realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
                request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
            }
        }
 
         /*
         省略
         */
        // Only do the create here since startActivityInner can abort. If it doesn't abort,
        // the requestStart will be sent in handleStartRequest.
        final Transition newTransition = r.mTransitionController.isShellTransitionsEnabled()
                ? r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
        // Because startActivity must run immediately, it can get combined with another
        // transition meaning it is no-longer independent. This is NOT desirable, but is the
        // only option for the time being.
        final boolean isIndependent = newTransition != null;
        final Transition transition = isIndependent ? newTransition
                : mService.getTransitionController().getCollectingTransition();
        // 这个函数,内部调用startActivityInner函数
 /*官方对startActivityInner的解释
     * Start an activity and determine if the activity should be adding to the top of an existing
     * task or delivered new intent to an existing activity. Also manipulating the activity task
     * onto requested or valid root-task/display.
     **/
        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                request.voiceInteractor, startFlags, checkedOptions,
                inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, transition,
                isIndependent);

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

        return mLastStartActivityResult;
    }

写到这里,基本上这个流程就结束了。这些重要函数的内部细节还有很多需要研究的地方。AMS是一个很大服务。梳理好这个流程至少能够让我们思路清晰点。

相关推荐
前端进阶者3 分钟前
天地图监听圆是否改变
前端
自己记录_理解更深刻4 分钟前
array.reduce()的理解和使用记录
前端
盛夏绽放10 分钟前
Vuex 核心知识详解:Vue2Vue3 状态管理指南
前端·javascript·vue.js
蓝易云23 分钟前
MyBatis注解的运用于条件搜索实践
前端
多啦C梦a27 分钟前
「React事件机制」揭秘:你以为点了按钮,其实点进了事件池!
前端·javascript·react.js
jackyChan28 分钟前
MutationObserver是怎么解决实时性问题
前端
mwq3012331 分钟前
🌈 Vibe Coding - Cursor AI Code Editor 入门指南:AI编程的新范式
前端·人工智能
程序员嘉逸44 分钟前
CSS高级特性全解析
前端
耀耀切克闹灬1 小时前
web前端基础知识梳理(三)
前端
程序员嘉逸1 小时前
🏗️ CSS布局完全指南:Flex、Grid与Float的终极对决
前端