有两处可能触发 attach 和 pauseCompleted。 realStartActivity 需要两个条件触发。
- 进程已经创建好了。
- 其他 Activity 都 Paused 完了。
所以两者谁进行完之后,都可以对另一项进行检查,通过了就可以进行 realStartActivity。
场景 1:先 pause 完成
- 栈顶 Activity 已经 pause 完成(
activityPaused()
→activityPauseComplete()
) - 此时目标 Activity 对应的进程可能还没 attach,系统会等待 attach 发生
- 一旦
attachApplicationLocked()
发生,就进入 resume 流程,调用realStartActivityLocked()
场景 2:先 attach 完成
- 系统收到 App attach(
attachApplicationLocked()
→mAtmInternal.attachApplication()
- 系统检测到目标 Activity 栈顶尚未 resumed
- 如果之前已经 pause 完成,就可以立刻 resume →
realStartActivityLocked()
以下为场景2过程: 可以看到在调用 startActivity 时会先让 activity Pause。
java
schedulePauseActivity:1764, TaskFragment (com.android.server.wm)
startPausing:1708, TaskFragment (com.android.server.wm)
startPausing:1616, TaskFragment (com.android.server.wm)
lambda$pauseBackTasks$5:1286, TaskDisplayArea (com.android.server.wm)
$r8$lambda$m5XHJk9c1RGMj6XWeVM475WcQIg:-1, TaskDisplayArea (com.android.server.wm)
accept:-1, TaskDisplayArea$$ExternalSyntheticLambda9 (com.android.server.wm)
forAllLeafTaskFragments:1943, TaskFragment (com.android.server.wm)
lambda$pauseBackTasks$6:1283, TaskDisplayArea (com.android.server.wm)
$r8$lambda$Bbr_9JIpdvMngBiuBSXkHUu4nwk:-1, TaskDisplayArea (com.android.server.wm)
accept:-1, TaskDisplayArea$$ExternalSyntheticLambda6 (com.android.server.wm)
forAllLeafTasks:3170, Task (com.android.server.wm)
forAllLeafTasks:3158, Task (com.android.server.wm)
forAllLeafTasks:2033, WindowContainer (com.android.server.wm)
pauseBackTasks:1269, TaskDisplayArea (com.android.server.wm)
resumeTopActivity:1293, TaskFragment (com.android.server.wm)
resumeTopActivityInnerLocked:5017, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4947, Task (com.android.server.wm)
resumeFocusedTasksTopActivities:2264, RootWindowContainer (com.android.server.wm)
startActivityInner:1971, ActivityStarter (com.android.server.wm)
startActivityUnchecked:1671, ActivityStarter (com.android.server.wm)
executeRequest:1224, ActivityStarter (com.android.server.wm)
execute:710, ActivityStarter (com.android.server.wm)
startActivityAsUser:1292, ActivityTaskManagerService (com.android.server.wm)
startActivityAsUser:1233, ActivityTaskManagerService (com.android.server.wm)
startActivity:1208, ActivityTaskManagerService (com.android.server.wm)
onTransact:896, IActivityTaskManager$Stub (android.app)
onTransact:5323, ActivityTaskManagerService (com.android.server.wm)
execTransactInternal:1280, Binder (android.os)
execTransact:1244, Binder (android.os)
上一个 Activity Paused 之后,回来到 startSpecificActivity 会判断线程是否存在。存在就热启动,直接寻找 Activity 打开。不存在就冷启动,fork 线程。 Is this activity's application already running?
java
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application. knownToBeDead = true;
// Remove the process record so it won't be considered as alive.
mService.mProcessNames.remove(wpc.mName, wpc.mUid);
mService.mProcessMap.remove(wpc.getPid());
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
mService.startProcessAsync(r, knownToBeDead, isTop,
isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_ACTIVITY);
}
java
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
启动新的进程。
java
startSpecificActivity:1065, ActivityTaskSupervisor (com.android.server.wm)
resumeTopActivity:1581, TaskFragment (com.android.server.wm)
resumeTopActivityInnerLocked:5017, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4947, Task (com.android.server.wm)
resumeFocusedTasksTopActivities:2264, RootWindowContainer (com.android.server.wm)
resumeFocusedTasksTopActivities:2250, RootWindowContainer (com.android.server.wm)
completePause:1839, TaskFragment (com.android.server.wm)
activityPaused:6197, ActivityRecord (com.android.server.wm)
activityPaused:190, ActivityClientController (com.android.server.wm)
onTransact:609, IActivityClientController$Stub (android.app)
onTransact:127, ActivityClientController (com.android.server.wm)
execTransactInternal:1280, Binder (android.os)
execTransact:1244, Binder (android.os)
首次启动的 realStartActivity。FallbackHome Paused 到 launcher Launch 。 下面是线程存在的情况。
java
realStartActivityLocked:929, ActivityTaskSupervisor (com.android.server.wm)
startSpecificActivity:1047, ActivityTaskSupervisor (com.android.server.wm)
resumeTopActivity:1581, TaskFragment (com.android.server.wm)
resumeTopActivityInnerLocked:5017, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4947, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4966, Task (com.android.server.wm)
resumeFocusedTasksTopActivities:2264, RootWindowContainer (com.android.server.wm)
resumeFocusedTasksTopActivities:2250, RootWindowContainer (com.android.server.wm)
completePause:1839, TaskFragment (com.android.server.wm)
activityPaused:6197, ActivityRecord (com.android.server.wm)
activityPaused:190, ActivityClientController (com.android.server.wm) //ActivityRecord{cc65ede u0 com.android.settings/.FallbackHome} t5 f}}
onTransact:609, IActivityClientController$Stub (android.app)
onTransact:127, ActivityClientController (com.android.server.wm)
execTransactInternal:1280, Binder (android.os)
execTransact:1244, Binder (android.os)
LaunchActivityItem,ResumeActivityItem 都在这个方法中创建。
![[RealStartActivity 中创建 TranslationItem 的过程.png]]
java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!mRootWindowContainer.allPausedActivitiesComplete()) {
// While there are activities pausing we skipping starting any new activities until
// pauses are complete. NOTE: that we also do this for activities that are starting in // the paused state because they will first be resumed then paused on the client side. ProtoLog.v(WM_DEBUG_STATES,
"realStartActivityLocked: Skipping start of r=%s some activities pausing...",
r);
return false;
}
final Task task = r.getTask();
final Task rootTask = task.getRootTask();
beginDeferResume();
// The LaunchActivityItem also contains process configuration, so the configuration change
// from WindowProcessController#setProcess can be deferred. The major reason is that if // the activity has FixedRotationAdjustments, it needs to be applied with configuration. // In general, this reduces a binder transaction if process configuration is changed. proc.pauseConfigurationDispatch();
try {
r.startFreezingScreenLocked(proc, 0);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
r.setProcess(proc);
// Ensure activity is allowed to be resumed after process has set.
if (andResume && !r.canResumeByCompat()) {
andResume = false;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
// Have the window manager re-evaluate the orientation of the screen based on the new
// activity order. Note that as a result of this, it can call back into the activity // manager with a new orientation. We don't care about that, because the activity is // not currently running so we are just restarting it anyway. if (checkConfig) {
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring // configurations and trying to resume top activity of focused root task. mRootWindowContainer.ensureVisibilityAndConfig(r, r.getDisplayId(),
false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
if (mKeyguardController.checkKeyguardVisibility(r) && r.allowMoveToFront()) {
// We only set the visibility to true if the activity is not being launched in
// background, and is allowed to be visible based on keyguard state. This avoids // setting this into motion in window manager that is later cancelled due to later // calls to ensure visible activities that set visibility back to false. r.setVisibility(true);
}
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
if ((r.mUserId != proc.mUserId) || (r.info.applicationInfo.uid != applicationInfoUid)) {
Slog.wtf(TAG,
"User ID for activity changing for " + r
+ " appInfo.uid=" + r.info.applicationInfo.uid
+ " info.ai.uid=" + applicationInfoUid
+ " old=" + r.app + " new=" + proc);
}
// Send the controller to client if the process is the first time to launch activity.
// So the client can save binder transactions of getting the controller from activity // task manager service. final IActivityClientController activityClientController =
proc.hasEverLaunchedActivity() ? null : mService.mActivityClientController;
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
proc.setLastActivityLaunchTime(r.lastLaunchTime);
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
final LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
|| (task.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED
&& lockTaskController.getLockTaskModeState()
== LOCK_TASK_MODE_LOCKED)) {
lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
}
try {
if (!proc.hasThread()) {
throw new RemoteException();
}
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
// We don't need to deliver new intents and/or set results if activity is going
// to pause immediately after launch. results = r.results;
newIntents = r.newIntents;
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Launching: " + r + " savedState=" + r.getSavedState()
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
task.mTaskId, r.shortComponentName);
if (r.isActivityTypeHome()) {
// Home process is the root process of the task.
updateHomeProcess(task.getBottomMostActivity().app);
}
mService.getPackageManagerInternalLocked().notifyPackageUse(
r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY);
r.forceNewConfig = false;
mService.getAppWarningsLocked().onStartActivity(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
// Because we could be starting an Activity in the system process this may not go
// across a Binder interface which would create a new Configuration. Consequently // we have to always create a new Configuration here. final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity();
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
procConfig, r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.getSavedState());
final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
if (organizedTaskFragment != null) {
// Sending TaskFragmentInfo to client to ensure the info is updated before
// the activity creation. mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent(
organizedTaskFragment);
}
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.token);
final boolean isTransitionForward = r.isTransitionForward();
final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(isTransitionForward,
r.shouldSendCompatFakeFocus());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) {
// If the seq is increased, there should be something changed (e.g. registered
// activity configuration). proc.setLastReportedConfiguration(procConfig);
}
if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
&& mService.mHasHeavyWeightFeature) {
// This may be a heavy-weight process! Note that the package manager will ensure
// that only activity can run in the main process of the .apk, which is the only // thing that will be considered heavy-weight. if (proc.mName.equals(proc.mInfo.packageName)) {
if (mService.mHeavyWeightProcess != null
&& mService.mHeavyWeightProcess != proc) {
Slog.w(TAG, "Starting new heavy weight process " + proc
+ " when already running "
+ mService.mHeavyWeightProcess);
}
mService.setHeavyWeightProcess(r);
}
}
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity and give up.
Slog.e(TAG, "Second failure launching "
+ r.intent.getComponent().flattenToShortString() + ", giving up", e);
proc.appDied("2nd-crash");
r.finishIfPossible("2nd-crash", false /* oomAdj */);
return false;
}
// This is the first time we failed -- restart process and
// retry. r.launchFailed = true;
r.detachFromProcess();
throw e;
}
} finally {
endDeferResume();
proc.resumeConfigurationDispatch();
}
r.launchFailed = false;
// TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
// so updating the state should be done accordingly.
if (andResume && readyToResume()) {
// As part of the process of launching, ActivityThread also performs
// a resume. rootTask.minimalResumeActivityLocked(r);
} else {
// This activity is not starting in the resumed state... which should look like we asked
// it to pause+stop (but remain visible), and it has done so and reported back the // current icicle and other state. ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s "
+ "(starting in paused state)", r);
r.setState(PAUSED, "realStartActivityLocked");
mRootWindowContainer.executeAppTransitionForAllDisplay();
}
// Perform OOM scoring after the activity state is set, so the process can be updated with
// the latest state. proc.onStartActivity(mService.mTopProcessState, r.info);
// Launch the new version setup screen if needed. We do this -after-
// launching the initial activity (that is, home), so that it can have // a chance to initialize itself while in the background, making the // switch back to it faster and look better. if (mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask)) {
mService.getActivityStartController().startSetupActivity();
}
// Update any services we are bound to that might care about whether
// their client may have activities. if (r.app != null) {
r.app.updateServiceConnectionActivities();
}
return true;
}