App启动流程【4】ActivityStarter 的 execute 方法执行流程

在介绍启动流程前,先介绍 ActivityManagerService 中涉及的几个类:

  • ActivityRecord
  • Task
  • ActivityStack

他们在 Activity 启动流程和生命周期变化的逻辑中都扮演了重要的角色。

ActivityRecord

ActivityRecord 代表一个 Activity ,是 Activity 历史堆栈中的一个 Item 。它在启动 Activity 时创建,具体位置是 ActivityStarter 执行 execute() 时,内部调用 executeRequest() 中创建的:

    private int executeRequest(Request request) {
        // ...
        
        final ActivityRecord r = new ActivityRecord.Builder(mService)
                .setCaller(callerApp)
                .setLaunchedFromPid(callingPid)
                .setLaunchedFromUid(callingUid)
                .setLaunchedFromPackage(callingPackage)
                .setLaunchedFromFeature(callingFeatureId)
                .setIntent(intent)
                .setResolvedType(resolvedType)
                .setActivityInfo(aInfo)
                .setConfiguration(mService.getGlobalConfiguration())
                .setResultTo(resultRecord)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setComponentSpecified(request.componentSpecified)
                .setRootVoiceInteraction(voiceSession != null)
                .setActivityOptions(checkedOptions)
                .setSourceRecord(sourceRecord)
                .build();

        mLastStartActivityRecord = r;

        // ...

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

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

        return mLastStartActivityResult;
    }

ActivityRecord 内部有一些比较重要的属性:

名称 类型 说明
mAtmService ActivityTaskManagerService
info ActivityInfo AndroidManifest 中开发者提供的 Activity 信息
launchedFromPackage String 启动 Activity 的 package
intent Intent 原始的 Intent
taskAffinity String Activity 的倾向性
task Task 当前 Activity 所在的 Task
resultTo ActivityRecord 启动这个 Activity 的 ActivityRecord,将结果返回给它
launchMode int 启动模式


在这些属性中,最重要的是 Task 。

Task

Task 是用户在执行某项工作时与之互动的一系列 Activity 的集合,即 Activity 的任务栈,虽然 ActivityStack 从名称上更像是 Activity 任务栈,但它并不是我们所理解的 Activity 任务回退堆栈。。Activity 的属性中包含了一个 Task 引用。在老版本中,会通过 TaskRecord 类表示任务的数据结构。而在最新的 Android 版本中,已经删除了 TaskRecord ,通过 Task 和 ActivityTaskManagerService 来管理任务相关的信息。

ActivityStack

ActivityStack 继承自 Task ,一个单独的 Activity 栈的管理和状态:

class ActivityStack extends Task

ActivityStarter 中的启动流程

ActivityStarter#execute

execute 方法中的逻辑将拆成两个部分来说明,下面是 execute 方法的一个整体逻辑:

int execute() {
    try {
        //【PART 1】
        //【PART 2】
    } finally {
        onExecutionComplete(); // 回收 ActivityStarter
    }
}

PART 1

startActivity 的启动流程,最早出现的是 Task ,在 ActivityStarter 的 execute 方法中出现,逐步分析出现在 execute 方法中的逻辑:

// 【PART 1】
final LaunchingState launchingState;
synchronized (mService.mGlobalLock) {
    // 通过 Token 创建了一个 ActivityRecord ,这个 AR 代表的是调用 startActivity 的组件
    final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
    // mSupervisor 的类型是 ActivityStackSupervisor ,在通过 obtain 方法获取 ActivityStarter 时作为构造参数初始化
    // ActivityMetricsLogger 的 notifyActivityLaunching 方法
    launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching( mRequest.intent, caller);
}
// ...

跟进 notifyActivityLaunching 方法,它的注释提示我们它的作用:

如果在一个活跃的 transition 中找到了 caller ,则将其视为连续启动,并合并到 transition 中。

    LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller) {
        return notifyActivityLaunching(intent, caller, Binder.getCallingUid());
    }

在这个方法中继续调用同名不同参的方法:

notifyActivityLaunching 方法会在启动 Activity 时,尽早通知 tracker ,调用者必须确保稍后调用 notifyActivityLaunched 并返回 LaunchingState 。

    private LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller, int callingUid) {
        TransitionInfo existingInfo = null;
        if (callingUid != IGNORE_CALLER) {
            // 如果在已启动 Activity 中找到了 caller,将启动时间关联到 TransitionInfo
            for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
                final TransitionInfo info = mTransitionInfoList.get(i);
                if (caller != null && info.contains(caller)) {
                    existingInfo = info;
                    break;
                }
                if (existingInfo == null && callingUid == info.mLastLaunchedActivity.getUid()) {
                    // 如果调用者不是 Activity,则回退以检查最近匹配的 uid。
                    existingInfo = info;
                }
            }
        }
        // 不存在 existingInfo ,创建一个新的启动事件发送出去
        if (existingInfo == null) {
            // 只是发送一个新的启动事件给观察者
            launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
            final LaunchingState launchingState = new LaunchingState();
            return launchingState;
        }
        return existingInfo.mLaunchingState;
    }

PART 2

//【PART 2】
int res;
synchronized (mService.mGlobalLock) {
    final boolean globalConfigWillChange = mRequest.globalConfig != null && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
    // 当前显示在屏幕上的 Activity 任务栈
    final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
    if (stack != null) {
        // flag 标记为即将改变配置
        stack.mConfigWillChange = globalConfigWillChange;
    }

    // 进程相关的处理逻辑, 如果进程处理失败直接抛出
    res = resolveToHeavyWeightSwitcherIfNeeded();
    if (res != START_SUCCESS) {
        return res;
    }

    // 通过 executeRequest 继续执行启动请求
    res = executeRequest(mRequest);

    // 处理配置变化
    if (globalConfigWillChange) {
        // 如果调用者也想切换到新的配置,那么现在就切换。
        // 这里允许一个迅速的切换,因为我们正在等待当前活动暂停(这样我们就不会销毁它),并且还没有开始下一个活动。
        // ActivityTaskManagerService.ActivityManagerInternal 的 enforceCallingPermission 方法
        mService.mAmInternal.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()");
        if (stack != null) {
            stack.mConfigWillChange = false;
        }
        mService.updateConfigurationLocked(mRequest.globalConfig, nullfalse);
    }

    // 通知 ActivityMetricsLogger, activity 已启动.
    // ActivityMetricsLogger 将会等待 window 绘制完成并且填充 WaitResult.
    mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res, mLastStartActivityRecord);
    return getExternalResult(mRequest.waitResult == null ? res : waitForResult(res, mLastStartActivityRecord));
}

getExternalResult 方法做了一个 START_ABORTED 更新为成功的处理:

    static int getExternalResult(int result) {
        // Aborted results are treated as successes externally, but we must track them internally.
        return result != START_ABORTED ? result : START_SUCCESS;
    }

而当 Request 的 waitResult 为空时,通过 waitForResult 方法,从 res 和最后一次启动的 ActivityRecord 中提取结果:

  // 等待 Activity 启动完成
    private int waitForResult(int res, ActivityRecord r) {
        mRequest.waitResult.result = res;
        switch(res) {
            // Activity 正常成功启动。
            case START_SUCCESS: {
                mSupervisor.mWaitingActivityLaunched.add(mRequest.waitResult);
                // 等待 Task 切换到前台
                do {
                    try {
                        mService.mGlobalLock.wait();
                    } catch (InterruptedException e) {
                    }
                } while (mRequest.waitResult.result != START_TASK_TO_FRONT
                        && !mRequest.waitResult.timeout && mRequest.waitResult.who == null);
                if (mRequest.waitResult.result == START_TASK_TO_FRONT) {
                    res = START_TASK_TO_FRONT;
                }
                break;
            }
            // Activity 并未真正启动,但给定的 Intent 已提供给现有的 Top Activity。
            case START_DELIVERED_TO_TOP: {
                mRequest.waitResult.timeout = false;
                mRequest.waitResult.who = r.mActivityComponent;
                mRequest.waitResult.totalTime = 0;
                break;
            }
            // Activity 并没有真正启动,但只是将一项任务带到了前台。
            case START_TASK_TO_FRONT: {
                // 冷启动 / 热启动
                mRequest.waitResult.launchState = r.attachedToProcess() ? LAUNCH_STATE_HOT : LAUNCH_STATE_COLD;
                // ActivityRecord 可能代表不同的 Activity,但它不应该是 resume 状态
                if (r.nowVisible && r.isState(RESUMED)) {
                    mRequest.waitResult.timeout = false;
                    mRequest.waitResult.who = r.mActivityComponent;
                    mRequest.waitResult.totalTime = 0;
                } else {
                    // 如果不是 resume 状态或不可见的情况下
                    mSupervisor.waitActivityVisible(r.mActivityComponent, mRequest.waitResult);
                    // Note: 超时变量当前未设置。
                    do {
                        try {
                            mService.mGlobalLock.wait();
                        } catch (InterruptedException e) {
                        }
                    } while (!mRequest.waitResult.timeout && mRequest.waitResult.who == null);
                }
                break;
            }
        }
        return res;
    }

等待启动结果时,会再通过 waitResult 方法处理等待处理后的最终结果,分为三种情况:

  • Activity 正常启动,仍需等待所在的 Task 切换到前台
  • Activity 并未真正启动,但给定的 Intent 已提供给现有的 Top Activity,栈顶复用的情况。
  • Activity 并未真正启动,只是将其他 Task 切换到前台,此时要等待 Activity 进入可见状态或 Resume 。

ActivityStarter#executeRequest(Request)

在 execute 方法中,最重要的一步是 executeRequest 方法。executeRequest 中的逻辑也很复杂,需要拆分进行分析。

PART 1 设置接收结果的 Activity

    // 【PART 1】设置接收结果的 Activity
    // 原始的 Activity 
    ActivityRecord sourceRecord = null;
    // 接收启动 Result 的 Activity
    ActivityRecord resultRecord = null;
    
    if (resultTo != null) {
        sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);
        if (DEBUG_RESULTS) {
            Slog.v(TAG_RESULTS, "将会把 Result 发送给 " + resultTo + " " + sourceRecord);
        }
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    }
    final int launchFlags = intent.getFlags();
    // FLAG_ACTIVITY_FORWARD_RESULT: 如果设置并且此 Intent 用于从现有 Activity 启动新 Activity ,则现有 Activity 的 reply 目标将转移到新 Activity 。 
    // 这样,新 Activity 可以调用 android.app.Activity.setResult 并将结果发送回原始 Activity 的回复目标。
    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); // option 中止, sendResult(null)
            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) {
            callingPackage = sourceRecord.launchedFromPackage;
            callingFeatureId = sourceRecord.launchedFromFeatureId;
        }
    }

PART 2 启动状态检查

    // 【PART 2】 启动状态检查
    if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
        // 找不到 class 能够处理 intent。
        err = ActivityManager.START_INTENT_NOT_RESOLVED;
    }

    if (err == ActivityManager.START_SUCCESS && aInfo == null) {
        // 找不到 Intent 请求的类型
        err = ActivityManager.START_CLASS_NOT_FOUND;
    }

    // 这里省略语音会话相关逻辑

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

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

PART 3 检查是否中止

    // 【PART 3】检查是否中止
    boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho, requestCode, callingPid, callingUid, callingPackage, callingFeatureId, request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);
    abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo);
    abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid, callingPackage);
    boolean restrictedBgActivity = false;
    // 不中止启动
    if (!abort) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "shouldAbortBackgroundActivityStart");
            restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
                    callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                    request.originatingPendingIntent, request.allowBackgroundActivityStart,
                    intent);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
        }
    }
    // 合并两个 option bundle,而 realCallerOptions 优先。
    ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
    if (request.allowPendingRemoteAnimationRegistryLookup) {
        checkedOptions = mService.getActivityStartController()
                .getPendingRemoteAnimationRegistry()
                .overrideOptionsIfNeeded(callingPackage, checkedOptions);
    }
    if (mService.mController != null) {
        try {
            // 我们提供给观察者的 Intent 已经剥离了额外的数据,因为它可能包含私人信息。
            Intent watchIntent = intent.cloneFilter();
            abort |= !mService.mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName);
        } catch (RemoteException e) {
            mService.mController = null;
        }
    }

    mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage, callingFeatureId);
    if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid, checkedOptions)) {
        // Activity 启动被拦截,例如 因为目标用户当前处于安静模式(关闭工作)或目标应用程序被挂起
        intent = mInterceptor.mIntent;
        rInfo = mInterceptor.mRInfo;
        aInfo = mInterceptor.mAInfo;
        resolvedType = mInterceptor.mResolvedType;
        inTask = mInterceptor.mInTask;
        callingPid = mInterceptor.mCallingPid;
        callingUid = mInterceptor.mCallingUid;
        checkedOptions = mInterceptor.mActivityOptions;

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

    if (abort) {
        if (resultRecord != null) {
            resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
                    null /* data */null /* dataGrants */);
        }
        // 我们向调用者假装它真的开始了,但他们只会得到一个取消结果。
        ActivityOptions.abort(checkedOptions);
        return START_ABORTED;
    }

PART 4 权限检查相关逻辑

    // 检查权限,通过启动一个权限检查页面 Activity 并传递 Intent 进行处理,处理后继续启动目标 Activity
    if (aInfo != null) {
        if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                aInfo.packageName, userId)) {
            final IIntentSender target = mService.getIntentSenderLocked(
                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
                    callingUid, userId, nullnull0new Intent[]{intent},
                    new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
                            | PendingIntent.FLAG_ONE_SHOT, null);

            Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);

            int flags = intent.getFlags();
            flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;

            /*
             * 防止 review activity 复用,每个 App 都需要自己的 review activity . 默认情况下,使用 NEW_TASK 或 NEW_DOCUMENT 启动的活动尝试重用具有相同启动参数的活动(忽略附加内容)。 因此,为了避免可能的重用,通过 MULTIPLE_TASK 标志强制执行新活动。
             * 未使用 NEW_TASK 或 NEW_DOCUMENT 启动的活动不会被重用,因此在这种情况下无需添加标志。
             */

            if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
                flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
            }
            newIntent.setFlags(flags);

            newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
            newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
            if (resultRecord != null) {
                newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
            }
            intent = newIntent;
            intentGrants = null;
            resolvedType = null;
            callingUid = realCallingUid;
            callingPid = realCallingPid;

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

            if (DEBUG_PERMISSIONS_REVIEW) {
                final ActivityStack focusedStack =
                        mRootWindowContainer.getTopDisplayFocusedStack();
                Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(truetrue,
                        truefalse) + "} from uid " + callingUid + " on display "
                        + (focusedStack == null ? DEFAULT_DISPLAY
                                : focusedStack.getDisplayId()));
            }
        }
    }

PART 5 临时应用程序的处理逻辑

    // 【PART 5】临时应用程序的处理逻辑
    // 如果我们有一个临时应用程序,请中止启动解析 intent 的过程。
    // 相反,启动临时安装程序。 安装程序完成后,它会开始在此处解析 intent [on install error] 或临时应用程序 [on install success]。
    if (rInfo != null && rInfo.auxiliaryInfo != null) {
        intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
                callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
        resolvedType = null;
        callingUid = realCallingUid;
        callingPid = realCallingPid;

        intentGrants = null;

        aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
    }

PART 6 检查 UID

    final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();

    // 如果我们正在启动一个与当前 resume 的 uid 不同的 activity ,请检查是否允许应用切换。
    if (voiceSession == null && stack != null && (stack.getResumedActivity() == null
            || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
        if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                realCallingPid, realCallingUid, "Activity start")) {
            if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) {
                mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                        sourceRecord, startFlags, stack, callerApp, intentGrants));
            }
            ActivityOptions.abort(checkedOptions);
            return ActivityManager.START_SWITCHES_CANCELED;
        }
    }

PART 7 开始启动 Activity

    final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
            callingPackage, callingFeatureId, intent, resolvedType, aInfo,
            mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
            request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
            sourceRecord);
    mLastStartActivityRecord = r;

    mService.onStartActivitySetDidAppSwitch();
    mController.doPendingActivityLaunches(false);

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

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

    return mLastStartActivityResult;

在这一步,通过 startActivityUnchecked 去启动 Activity ,并更新了一些配置,execute 中的逻辑也就全部分析完了,下一篇继续详细分析 startActivityUnchecked 的细节。


原文始发于微信公众号(八千里路山与海):App启动流程【4】ActivityStarter 的 execute 方法执行流程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/85050.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!