在介绍启动流程前,先介绍 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, null, false);
}
// 通知 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, null, null, 0, new 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(true, true,
true, false) + "} 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