上篇中我们梳理完ActivityStarter的startActivityInner,本篇从这里开始:
platform/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.javaboolean resumeFocusedTasksTopActivities(Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,boolean deferPause) {if (!mTaskSupervisor.readyToResume()) {return false;}boolean result = false;// targetRootTask不为空,isTopRootTaskInDisplayArea为trueif (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()|| getTopDisplayFocusedRootTask() == targetRootTask)) {
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);}for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {final DisplayContent display = getChildAt(displayNdx);final boolean curResult = result;boolean[] resumedOnDisplay = new boolean[1];
display.forAllRootTasks(rootTask -> {final ActivityRecord topRunningActivity = rootTask.topRunningActivity();if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) {return;}if (rootTask == targetRootTask) {// Simply update the result for targetRootTask because the targetRootTask// had already resumed in above. We don't want to resume it again,// especially in some cases, it would cause a second launch failure// if app process was dead.
resumedOnDisplay[0] |= curResult;return;}if (topRunningActivity.isState(RESUMED)&& topRunningActivity == rootTask.getDisplayArea().topRunningActivity()) {// Kick off any lingering app transitions form the MoveTaskToFront operation,// but only consider the top activity on that display.
rootTask.executeAppTransition(targetOptions);} else {
resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target);}});
result |= resumedOnDisplay[0];if (!resumedOnDisplay[0]) {// In cases when there are no valid activities (e.g. device just booted or launcher// crashed) it's possible that nothing was resumed on a display. Requesting resume// of top activity in focused root task explicitly will make sure that at least home// activity is started and resumed, and no recursion occurs.final Task focusedRoot = display.getFocusedRootTask();if (focusedRoot != null) {
result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions);} else if (targetRootTask == null) {
result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.getDefaultTaskDisplayArea());}}}return result;
}
通过之前的分析我们知道targetRootTask不为空,isTopRootTaskInDisplayArea为true,因此会走targetRootTask.resumeTopActivityUncheckedLocked
platform/frameworks/base/services/core/java/com/android/server/wm/Task.java/**
* Ensure that the top activity in the root task is resumed.
*
* @param prev The previously resumed activity, for when in the process
* of pausing; can be null to call from elsewhere.
* @param options Activity options.
* @param deferPause When {@code true}, this will not pause back tasks.
*
* @return Returns true if something is being resumed, or false if
* nothing happened.
*
* NOTE: It is not safe to call this method directly as it can cause an activity in a
* non-focused root task to be resumed.
* Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the
* right activity for the current system state.
*/
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,boolean deferPause) {if (mInResumeTopActivity) {// Don't even start recursing.return false;}boolean someActivityResumed = false;try {// Protect against recursion.
mInResumeTopActivity = true;// 本身没有子Task,所以isLeafTask为trueif (isLeafTask()) {// isFocusableAndVisible为trueif (isFocusableAndVisible()) {
someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);}} else {int idx = mChildren.size() - 1;while (idx >= 0) {final Task child = (Task) getChildAt(idx--);if (!child.isTopActivityFocusable()) {continue;}if (child.getVisibility(null /* starting */)!= TASK_FRAGMENT_VISIBILITY_VISIBLE) {if (child.topRunningActivity() == null) {// Skip the task if no running activity and continue resuming next task.continue;}// Otherwise, assuming everything behind this task should also be invisible.break;} someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
deferPause);// Doing so in order to prevent IndexOOB since hierarchy might changes while// resuming activities, for example dismissing split-screen while starting// non-resizeable activity.if (idx >= mChildren.size()) {
idx = mChildren.size() - 1;}}}// 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 ActivityTaskSupervisor#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 ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped.final ActivityRecord next = topRunningActivity(true /* focusableOnly */);if (next == null || !next.canTurnScreenOn()) {checkReadyForSleep();}} finally {
mInResumeTopActivity = false;}return someActivityResumed;
}
继续走到
@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
// Not ready yet!
return false;
}
// topActivity是新建的ActivityRecord
final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
if (topActivity == null) {
// There are no activities left in this task, let's look somewhere else.
return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
} final boolean[] resumed = new boolean[1];
final TaskFragment topFragment = topActivity.getTaskFragment();
resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
forAllLeafTaskFragments(f -> {
if (topFragment == f) {
return;
}
if (!f.canBeResumed(null /* starting */)) {
return;
}
resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
}, true);
return resumed[0];
}
ActivityRecord topActivity = topRunningActivity(true), topActivity返回的是刚进件的ActivityRecord,topActivity.getTaskFragment()返回的是当前Task本身。后续调用topFragment.resumeTopActivity(), 其中参数prev为新建的ActivityRecord。
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
boolean skipPause) {
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
if (next == null || !next.canResumeByCompat()) {
return false;
} next.delayedResume = false; if (!skipPause && !mRootWindowContainer.allPausedActivitiesComplete()) {
// If we aren't skipping pause, then we have to wait for currently pausing activities.
ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: some activity pausing.");
return false;
} final TaskDisplayArea taskDisplayArea = getDisplayArea();
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// Ensure the visibility gets updated before execute app transition.
taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options); // In a multi-resumed environment, like in a freeform device, the top
// activity can be resumed, but it might not be the focused app.
// Set focused app when top activity is resumed
if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null
&& taskDisplayArea.mDisplayContent.mFocusedApp != next) {
taskDisplayArea.mDisplayContent.setFocusedApp(next);
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
+ "resumed %s", next);
return false;
} // If we are sleeping, and there is no resumed activity, and the top activity is paused,
// well that is the state we want.
if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and"
+ " all paused");
return false;
} // Make sure that the user who owns this activity is started. If not,
// we will just leave it as is because someone should be bringing
// another user's activities to the top of the stack.
if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
Slog.w(TAG, "Skipping resume of top activity " + next
+ ": user " + next.mUserId + " is stopped");
return false;
} // The activity may be waiting for stop, but that is no longer
// appropriate for it.
mTaskSupervisor.mStoppingActivities.remove(next); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); // 记录当前新建的ActivityRecord的uid mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid); ActivityRecord lastResumed = null;
final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) {
// So, why aren't we using prev here??? See the param comment on the method. prev
// doesn't represent the last resumed activity. However, the last focus stack does if
// it isn't null.
lastResumed = lastFocusedRootTask.getTopResumedActivity();
} boolean pausing = !skipPause && taskDisplayArea.pauseBackTasks(next);
// 位置2
if (mResumedActivity != null) {
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
next, "resumeTopActivity");
}
// 位置1
if (pausing) {
ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
+ " start pausing");
// 此时还没有启动进程attachedToProcess为false
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */,
false /* addPendingTopUid */);
} else if (!next.isProcessRunning()) {
// Since the start-process is asynchronous, if we already know the process of next
// activity isn't running, we can start the process earlier to save the time to wait
// for the current activity to be paused.
final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
// 启动进程
mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);
}
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
}
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed "
+ "(dontWaitForPause) %s", next);
return true;
} // If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
if (shouldSleepActivities()) {
mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
} if (prev != null && prev != next && next.nowVisible) {
// The next activity is already visible, so hide the previous
// activity's windows right now so we can show the new one ASAP.
// We only do this if the previous is finishing, which should mean
// it is on top of the one being resumed so hiding it quickly
// is good. Otherwise, we want to do the normal route of allowing
// the resumed activity to be shown so we can decide if the
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
prev.setVisibility(false);
if (DEBUG_SWITCH) {
Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev
+ ", nowVisible=" + next.nowVisible);
}
} else {
if (DEBUG_SWITCH) {
Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev
+ ", nowVisible=" + next.nowVisible);
}
}
} // Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
mTaskSupervisor.getActivityMetricsLogger()
.notifyBeforePackageUnstopped(next.packageName);
mAtmService.getPackageManager().setPackageStoppedState(
next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ next.packageName + ": " + e);
} // We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
final DisplayContent dc = taskDisplayArea.mDisplayContent;
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) {
Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev);
}
if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
anim = false;
dc.prepareAppTransition(TRANSIT_NONE);
} else {
dc.prepareAppTransition(TRANSIT_CLOSE);
}
prev.setVisibility(false);
} else {
if (DEBUG_TRANSITION) {
Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev);
}
if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
dc.prepareAppTransition(TRANSIT_NONE);
} else {
dc.prepareAppTransition(TRANSIT_OPEN,
next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
}
}
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
dc.prepareAppTransition(TRANSIT_NONE);
} else {
dc.prepareAppTransition(TRANSIT_OPEN);
}
} if (anim) {
next.applyOptionsAnimation();
} else {
next.abortAndClearOptionsAnimation();
} mTaskSupervisor.mNoAnimActivities.clear(); if (next.attachedToProcess()) {
if (DEBUG_SWITCH) {
Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.mAppStopped
+ " visibleRequested=" + next.isVisibleRequested());
} // If the previous activity is translucent, force a visibility update of
// the next activity, so that it's added to WM's opening app list, and
// transition animation can be set up properly.
// For example, pressing Home button with a translucent activity in focus.
// Launcher is already visible in this case. If we don't add it to opening
// apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
// TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
final boolean lastActivityTranslucent = inMultiWindowMode()
|| mLastPausedActivity != null && !mLastPausedActivity.occludesParent(); // This activity is now becoming visible.
if (!next.isVisibleRequested() || next.mAppStopped || lastActivityTranslucent) {
next.app.addToPendingTop();
next.setVisibility(true);
} // schedule launch ticks to collect information about slow apps.
next.startLaunchTickingLocked(); ActivityRecord lastResumedActivity =
lastFocusedRootTask == null ? null
: lastFocusedRootTask.getTopResumedActivity();
final ActivityRecord.State lastState = next.getState(); mAtmService.updateCpuStats(); ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next); next.setState(RESUMED, "resumeTopActivity"); // Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean notUpdated = true; // Activity should also be visible if set mLaunchTaskBehind to true (see
// ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
if (shouldBeVisible(next)) {
// We have special rotation behavior when here is some active activity that
// requests specific orientation or Keyguard is locked. Make sure all activity
// visibilities are set correctly as well as the transition is updated if needed
// to get the correct rotation behavior. Otherwise the following call to update
// the orientation may cause incorrect configurations delivered to client as a
// result of invisible window resize.
// TODO: Remove this once visibilities are set correctly immediately when
// starting an activity.
notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
true /* markFrozenIfConfigChanged */, false /* deferResume */);
} if (notUpdated) {
// The configuration update wasn't able to keep the existing
// instance of the activity, and instead started a new one.
// We should be all done, but let's just make sure our activity
// is still at the top and schedule another run if something
// weird happened.
ActivityRecord nextNext = topRunningActivity();
ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
+ "%s, new next: %s", next, nextNext);
if (nextNext != next) {
// Do over!
mTaskSupervisor.scheduleResumeTopActivities();
}
if (!next.isVisibleRequested() || next.mAppStopped) {
next.setVisibility(true);
}
next.completeResumeLocked();
return true;
} try {
final ClientTransaction transaction =
ClientTransaction.obtain(next.app.getThread(), next.token);
// Deliver all pending results.
ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int size = a.size();
if (!next.finishing && size > 0) {
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
}
transaction.addCallback(ActivityResultItem.obtain(a));
}
} if (next.newIntents != null) {
transaction.addCallback(
NewIntentItem.obtain(next.newIntents, true /* resume */));
} // Well the app will no longer be stopped.
// Clear app token stopped state in window manager if needed.
next.notifyAppResumed(); EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
next.getTask().mTaskId, next.shortComponentName); mAtmService.getAppWarningsLocked().onResumeActivity(next);
next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
next.abortAndClearOptionsAnimation();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus()));
mAtmService.getLifecycleManager().scheduleTransaction(transaction); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
} catch (Exception e) {
// Whoops, need to restart this activity!
ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
+ "%s", lastState, next);
next.setState(lastState, "resumeTopActivityInnerLocked"); // lastResumedActivity being non-null implies there is a lastStack present.
if (lastResumedActivity != null) {
lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
} Slog.i(TAG, "Restarting because process died: " + next);
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
&& lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
next.showStartingWindow(false /* taskSwitch */);
}
mTaskSupervisor.startSpecificActivity(next, true, false);
return true;
} // From this point on, if something goes wrong there is no way
// to recover the activity.
try {
next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
next.finishIfPossible("resume-exception", true /* oomAdj */);
return true;
}
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(false /* taskSwich */);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
mTaskSupervisor.startSpecificActivity(next, true, true);
} return true;
}
暂停前一个Activity
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
next是当前顶部activity,等于prev。
mResumedActivity、mLastPausedActivity此时都为空。taskDisplayArea.pauseBackTasks(next);来pause前一个activity
platform/frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.javaboolean pauseBackTasks(ActivityRecord resuming) {
final int[] someActivityPaused = {0};
forAllLeafTasks(leafTask -> {
// Check if the direct child resumed activity in the leaf task needed to be paused if
// the leaf task is not a leaf task fragment.
if (!leafTask.isLeafTaskFragment()) {
final ActivityRecord top = topRunningActivity();
final ActivityRecord resumedActivity = leafTask.getResumedActivity();
if (resumedActivity != null && top.getTaskFragment() != leafTask) {
// Pausing the resumed activity because it is occluded by other task fragment.
if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
}
} leafTask.forAllLeafTaskFragments((taskFrag) -> {
final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
}
}, true /* traverseTopToBottom */);
}, true /* traverseTopToBottom */);
return someActivityPaused[0] > 0;
}
这里遍历TaskDisplayArea下所有Task,如果有已经Resumed的Activity,则会执行pausing流程先暂停:
boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
String reason) { ActivityRecord prev = mResumedActivity;
... mPausingActivity = prev;
mLastPausedActivity = prev;
if (!prev.finishing && prev.isNoHistory()
&& !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
mTaskSupervisor.mNoHistoryActivities.add(prev);
}
prev.setState(PAUSING, "startPausingLocked");
prev.getTask().touchActiveTime(); mAtmService.updateCpuStats();
..
if (resuming != null) {
// We do not want to trigger auto-PiP upon launch of a translucent activity.
final boolean resumingOccludesParent = resuming.occludesParent();
// Resuming the new resume activity only if the previous activity can't go into Pip
// since we want to give Pip activities a chance to enter Pip before resuming the
// next activity.
final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
"shouldAutoPipWhilePausing", userLeaving);
if (userLeaving && resumingOccludesParent && lastResumedCanPip
&& prev.pictureInPictureArgs.isAutoEnterEnabled()) {
shouldAutoPip = true;
} else if (!lastResumedCanPip) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
// activity to be paused.
pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
} else {
// The previous activity may still enter PIP even though it did not allow auto-PIP.
}
}
...
if (prev.attachedToProcess()) {
if (shouldAutoPip) {
prev.mPauseSchedulePendingForPip = true;
boolean didAutoPip = mAtmService.enterPictureInPictureMode(
prev, prev.pictureInPictureArgs, false /* fromClient */);
ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
+ "directly: %s, didAutoPip: %b", prev, didAutoPip);
} else {
schedulePauseActivity(prev, userLeaving, pauseImmediately,
false /* autoEnteringPip */, reason);
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mTaskSupervisor.mNoHistoryActivities.remove(prev);
}
...
// If already entered PIP mode, no need to keep pausing.
if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
// the screen is being turned off and the UI is sleeping, don't interrupt
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
} else {
ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
} if (pauseImmediately) {
// If the caller said they don't want to wait for the pause, then complete
// the pause now.
completePause(false, resuming);
return false; } else {
prev.schedulePauseTimeout();
// All activities will be stopped when sleeping, don't need to wait for pause.
if (!uiSleeping) {
// Unset readiness since we now need to wait until this pause is complete.
mTransitionController.setReady(this, false /* ready */);
}
return true;
} } else {
// This activity either failed to schedule the pause or it entered PIP mode,
// so just treat it as being paused now.
ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next.");
if (resuming == null) {
mRootWindowContainer.resumeFocusedTasksTopActivities();
}
return false;
}
}
首先会更新前一个Task几个成员的状态:
mPausingActivity = prev;
mLastPausedActivity = prev;
prev.setState(PAUSING, "startPausingLocked");
然后会执行schedulePauseActivity(prev, ...) 暂停前一个Task里的mResumedActivity
其中,如果正在resuming的,也就是新启动的activity设置了info.flags & FLAG_RESUME_WHILE_PAUSING, 那么回立即执行completePause(false, resuming);并且startPausing()返回false, 否则返回true。
本场景下没有设置flags,startPausing返回true。因此resumeTopActivity()的“位置1”处,pausing为true。
接下来,因为新activity对应的进程还没有启动,next.attachedToProcess()是false。接下来会走mAtmService.startProcessAsync()启动进程。
我们先看看attachedToProcess是怎么判断的。
platform/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.javaboolean hasProcess() {
return app != null;
}boolean attachedToProcess() {
return hasProcess() && app.hasThread();
}
本质判断的是app属性。这个将在后续进程启动后设置。
启动进程
startProcessAsync启动进程:
platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.javavoid startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
String hostingType) {
try {
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"
+ activity.processName);
}
// Post message to start process to avoid possible deadlock of calling into AMS with the
// ATMS lock held.
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
这里通过向mH发送异步消息,执行ActivityManagerInternal::startProcess来启动进程:
ActivityManagerInternal的实现类是ActivityManagerService
platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
boolean isTop, String hostingType, ComponentName hostingName) {
try {
...
synchronized (ActivityManagerService.this) {
// If the process is known as top app, set a hint so when the process is
// started, the top priority can be applied immediately to avoid cpu being
// preempted by other processes before attaching the process of top app.
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
new HostingRecord(hostingType, hostingName, isTop),
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
null /* sdkSandboxClientAppPackage */,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
通过ProcessList.startProcessLocked()启动进程:
platform/frameworks/base/services/core/java/com/android/server/am/ProcessList.javaProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { ...
app = newProcessRecordLocked(info, processName, isolated, isolatedUid, isSdkSandbox,
sdkSandboxUid, sdkSandboxClientAppPackage, hostingRecord);
...
final boolean success =
startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
...
}
newProcessRecordLocked() :这里new了ProcessRecord。
startProcessLocked():继续往下启动进程
platform/frameworks/base/services/core/java/com/android/server/am/ProcessList.javaboolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
String abiOverride) {
...
String useAppImageCache = SystemProperties.get(
PROPERTY_USE_APP_IMAGE_STARTUP_CACHE, "");
// Property defaults to true currently.
if (!TextUtils.isEmpty(useAppImageCache) && !useAppImageCache.equals("false")) {
runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;
}
...
app.setGids(gids);
app.setRequiredAbi(requiredAbi);
app.setInstructionSet(instructionSet);
...
return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,instructionSet, invokeWith, startUptime, startElapsedTime);
}
设置了一系列参数后,调用startProcessLocked()
platform/frameworks/base/services/core/java/com/android/server/am/ProcessList.javaboolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startUptime, long startElapsedTime) {
...
app.setStartSeq(startSeq);
app.setStartParams(uid, hostingRecord, seInfo, startUptime, startElapsedTime);
app.setUsingWrapper(invokeWith != null
|| Zygote.getWrapProperty(app.processName) != null);
mPendingStarts.put(startSeq, app);
...
if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
"Posting procStart msg for " + app.toShortString());
mService.mProcStartHandler.post(() -> handleProcessStart(
app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,
requiredAbi, instructionSet, invokeWith, startSeq));
return true;
} else {
try {
final Process.ProcessStartResult startResult = startProcess(hostingRecord,
entryPoint, app,
uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
requiredAbi, instructionSet, invokeWith, startUptime);
handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
startSeq, false);
} catch (RuntimeException e) {
Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ app.processName, e);
app.setPendingStart(false);
mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false, app.userId, "start failure");
}
return app.getPid() > 0;
}
}
合理首先记录了mPendingStarts.put(startSeq, app);用来启动进程后从客户端回来能找到刚刚启动的这个进程。随后通过启动startProcess启动进程。
客户端进程具体启动过程不详述。在通过zygote孵化出进程后,客户端会回调ActivityManagerService的attachApplication。
platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic final void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}private void attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
if (app.getIsolatedEntryPoint() != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
} else {
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList, null, profilerInfo, null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
...
if (!mConstants.mEnableWaitForFinishAttachApplication) {
finishAttachApplicationInner(startSeq, callingUid, pid);
}
}
thread.bindApplication() 是调用客户端,最终触发Application的onCreate等方法。
finishAttachApplicationInner()则继续完成之前的Activity启动过程。
platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaprivate void finishAttachApplicationInner(long startSeq, int uid, int pid) {
...
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
} // Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "finishAttachApplicationInner: "
+ "after mServices.attachApplicationLocked");
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
} // Check if a next-broadcast receiver is in this process...
if (!badApp) {
try {
for (BroadcastQueue queue : mBroadcastQueues) {
didSomething |= queue.onApplicationAttachedLocked(app);
}
checkTime(startTime, "finishAttachApplicationInner: "
+ "after dispatching broadcasts");
} catch (BroadcastDeliveryFailedException e) {
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
}
}
...
}
依次检查是否有未完成的Activity、Service、Broadcast的启动流程。本场景只关注Activity的启动 mAtmInternal.attachApplication(),其具体实现在ActivityTaskManagerService
platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.javapublic boolean attachApplication(WindowProcessController wpc) throws RemoteException {
synchronized (mGlobalLockWithoutBoost) {
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);
}
try {
return mRootWindowContainer.attachApplication(wpc);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
platform/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.javaboolean attachApplication(WindowProcessController app) throws RemoteException {
try {
return mAttachApplicationHelper.process(app);
} finally {
mAttachApplicationHelper.reset();
}
}platform/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java$AttachApplicationHelperboolean process(WindowProcessController app) throws RemoteException {
mApp = app;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
// 递归RootWindowContainer下的所有Child的forAllRootTasks,最终调用到Task的forAllRootTasks,执行了本类的test方法。
getChildAt(displayNdx).forAllRootTasks(this);
if (mRemoteException != null) {
throw mRemoteException;
}
}
if (!mHasActivityStarted) {
ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */);
}
return mHasActivityStarted;
}public void accept(Task rootTask) {
if (mRemoteException != null) {
return;
}
if (rootTask.getVisibility(null /* starting */)
== TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
return;
}
mTop = rootTask.topRunningActivity();
rootTask.forAllActivities(this);
}@Override
public boolean test(ActivityRecord r) {
if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard
|| r.app != null || mApp.mUid != r.info.applicationInfo.uid
|| !mApp.mName.equals(r.processName)) {
return false;
} try {
if (mTaskSupervisor.realStartActivityLocked(r, mApp,
mTop == r && r.getTask().canBeResumed(r) /* andResume */,
true /* checkConfig */)) {
mHasActivityStarted = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity " + mTop, e);
mRemoteException = e;
return true;
}
return false;
}
注意这里的process方法首先记录了下mApp, 随后getChildAt(displayNdx).forAllRootTasks(this);这里的this指AttachApplicationHelper自身作为一个callback传入。
由于基类WindowContainer对该方法的定义是遍历递归所有child的forAllRootTasks,而作为Child的Task类对其的实现是调用callback的accept
platform/frameworks/base/services/core/java/com/android/server/wm/Task.java@Override
void forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
if (isRootTask()) {
callback.accept(this);
}
}
AttachApplicationHelper中, accept方法获取到该Task的最顶部Activity,随后调用的rootTask.forAllActivities(this);也来自WindowContainer,最终会递归到最底层Child ActivityRecord,传入的参数是ActivityRecord自身。
platform/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java@Override
boolean forAllActivities(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {
return callback.test(this);
}
因此最终会调用AttachApplicationHelper的test方法,并调用mTaskSupervisor.realStartActivityLocked()
经过了accept和test方法的筛选后,只针对刚启动的这个app,并且是其顶部activity执行realStartActivityLocked,也就是说第一个r参数是我们之前要启动的Activity。
即realStartActivityLocked的参数r为待启动activity,proc为刚启动的app, andResume为true。
realStartActivityLocked将真正调用客户端的Activity。
调用客户端Activity
realStartActivityLocked代码:
platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.javaboolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException { ... try {
r.startFreezingScreenLocked(proc, 0); // schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
r.lastLaunchTime = SystemClock.uptimeMillis();
r.setProcess(proc); // Ensure activity is allowed to be resumed after process has set.
if (andResume && !r.canResumeByCompat()) {
andResume = false;
}
... // 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);
} 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;
}
... // Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.token); final boolean isTransitionForward = r.isTransitionForward();
final IBinder fragmentToken = r.getTaskFragment().getFragmentToken(); final int deviceId = getDeviceIdForDisplayId(r.getDisplayId());
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(), deviceId,
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;
}
这里以ClientTransaction的形式与客户端通信。
ClientTransaction
ClientTransaction用于AMS服务端调用客户端生命周期相关事务的通道。
1. 服务端obtain一个ClientTransaction
platform/frameworks/base/core/java/android/app/servertransaction/ClientTransaction.javapublic static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);if (instance == null) {
instance = new ClientTransaction();}
instance.mClient = client;
instance.mActivityToken = activityToken;return instance;}
2. 服务端addCallback、setLifecycleStateRequest
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
...
lifecycleItem = ResumeActivityItem.obtain(isTransitionForward,
r.shouldSendCompatFakeFocus());
clientTransaction.setLifecycleStateRequest(lifecycleItem);
3. mService.getLifecycleManager().scheduleTransaction(clientTransaction);
getLifecycleManager()为ActivityTaskManagerService的ClientLifecycleManager,因此会调用ClientLifecycleManager的scheduleTransaction()
platform/frameworks/base/services/core/java/com/android/server/wm/ClientLifecycleManager.javavoid scheduleTransaction(ClientTransaction transaction) throws RemoteException {final IApplicationThread client = transaction.getClient();
transaction.schedule();if (!(client instanceof Binder)) {// If client is not an instance of Binder - it's a remote call and at this point it is// safe to recycle the object. All objects used for local calls will be recycled after// the transaction is executed on client in ActivityThread.
transaction.recycle();}
}
platform/frameworks/base/core/java/android/app/servertransaction/ClientTransaction.javapublic void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
mClient为IApplicationThread,也就是客户端所持有的binder服务端。因此scheduleTransaction会调用到客户端的ApplicationThread的scheduleTransaction
platform/frameworks/base/core/java/android/app/ActivityThread.javapublic void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
4. 客户端执行scheduleTransaction
ActivityThread的这个方法是在父类执行的:
platform/frameworks/base/core/java/android/app/ClientTransactionHandler.javavoid scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
先执行transaction.preExecute(this);再执行主任务EXECUTE_TRANSACTION
platform/frameworks/base/core/java/android/app/ActivityThread.javacase EXECUTE_TRANSACTION:final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);if (isSystem()) {// Client transactions inside system process are recycled on the client side// instead of ClientLifecycleManager to avoid being cleared before this// message is handled.
transaction.recycle();}// TODO(lifecycler): Recycle locally scheduled transactions.break;
platform/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.javapublic void execute(ClientTransaction transaction) {if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");final IBinder token = transaction.getActivityToken();if (token != null) {final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =
mTransactionHandler.getActivitiesToBeDestroyed();final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);if (destroyItem != null) {if (transaction.getLifecycleStateRequest() == destroyItem) {// It is going to execute the transaction that will destroy activity with the// token, so the corresponding to-be-destroyed record can be removed.
activitiesToBeDestroyed.remove(token);}if (mTransactionHandler.getActivityClient(token) == null) {// The activity has not been created but has been requested to destroy, so all// transactions for the token are just like being cancelled.
Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"+ transactionToString(transaction, mTransactionHandler));return;}}}if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler));executeCallbacks(transaction);executeLifecycleState(transaction);
mPendingActions.clear();if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}
先后执行两个方法:
executeCallbacks()
executeLifecycleState()
platform/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.javapublic void executeCallbacks(ClientTransaction transaction) {final int size = callbacks.size();
for (int i = 0; i < size; ++i) {final ClientTransactionItem item = callbacks.get(i);if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);final int postExecutionState = item.getPostExecutionState();if (item.shouldHaveDefinedPreExecutionState()) {final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
item.getPostExecutionState());if (closestPreExecutionState != UNDEFINED) {cycleToPath(r, closestPreExecutionState, transaction);}} item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);if (r == null) {// Launch activity request will create an activity record.
r = mTransactionHandler.getActivityClient(token);}if (postExecutionState != UNDEFINED && r != null) {// Skip the very last transition and perform it by explicit state request instead.final boolean shouldExcludeLastTransition =
i == lastCallbackRequestingState && finalState == postExecutionState;cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);}
}
platform/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.javaprivate void executeLifecycleState(ClientTransaction transaction) {final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();...// Execute the final transition with proper parameters.
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
调用客户端Activity
回到ActivityTaskSupervisor的realStartActivityLocked()
通过ClientTransaction,会先后执行以下生命周期相关事务:
LaunchActivityItem -- 客户端新建Activity
ResumeActivityItem -- 执行Activity的onResume
新建Activity:
platform/frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
mTaskFragmentToken);
client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
这里构建了ActivityClientRecord后调用ClientTransactionHandler的handleLaunchActivity,具体实现在ActivityThread。
platform/frameworks/base/core/java/android/app/ActivityThread.javapublic Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, int deviceId, Intent customIntent) {...final Activity a = performLaunchActivity(r, customIntent);...if (a != null) {
r.createdConfig = new Configuration(mConfigurationController.getConfiguration());reportSizeConfigurations(r);if (!r.activity.mFinished && pendingActions != null) {
pendingActions.setOldState(r.state);
pendingActions.setRestoreInstanceState(true);
pendingActions.setCallOnPostCreate(true);}} else {// If there was an error, for any reason, tell the activity manager to stop us.
ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED,
null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY);}
}
platform/frameworks/base/core/java/android/app/ActivityThread.javaprivate Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, mCompatibilityInfo,
Context.CONTEXT_INCLUDE_CODE);} ComponentName component = r.intent.getComponent();if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);}if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);}// 创建Context
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;try {// 创建Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
appContext.getAttributionSource());if (r.state != null) {
r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}try {
Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(
TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());// updatePendingActivityConfiguration() reads from mActivities to update// ActivityClientRecord which runs in a different thread. Protect modifications to// mActivities to avoid race.synchronized (mResourcesManager) {
mActivities.put(r.token, r);}if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config =new Configuration(mConfigurationController.getCompatConfiguration());if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);}if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);
Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;}// Activity resources must be initialized with the same loaders as the// application context.
appContext.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0])); appContext.setOuterContext(activity);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
r.assistToken, r.shareableActivityToken);if (customIntent != null) {
activity.mIntent = customIntent;}
r.lastNonConfigurationInstances = null;checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();if (theme != 0) {
activity.setTheme(theme);}if (r.mActivityOptions != null) {
activity.mPendingOptions = r.mActivityOptions;
r.mActivityOptions = null;}
activity.mLaunchedFromBubble = r.mLaunchedFromBubble;
activity.mCalled = false;// Assigning the activity to the record before calling onCreate() allows// ActivityThread#getActivity() lookup for the callbacks triggered from// ActivityLifecycleCallbacks#onActivityCreated() or// ActivityLifecycleCallback#onActivityPostCreated().
r.activity = activity;// 调用Activity的onCreateif (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {
mInstrumentation.callActivityOnCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}
r.mLastReportedWindowingMode = config.windowConfiguration.getWindowingMode();}
r.setState(ON_CREATE);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;
}
这里最终要的:
- 创建appContext:ContextImpl appContext = createBaseContextForActivity(r)
- 创建Activity:activity = mInstrumentation.newActivity(...)
- activity.attach()
- 调用Activity的onCreate:mInstrumentation.callActivityOnCreate(...)
onResume
platform/frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java@Override
public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
mShouldSendCompatFakeFocus, "RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
同样,具体实现在ActivityThread
D:\AndroidSource\Android11\platform\frameworks\base\core\java\android\app\ActivityThread.java@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();
mSomeActivitiesChanged = true;// TODO Push resumeArgs into the activity for consideration// skip below steps for double-resume and r.mFinish = true case.if (!performResumeActivity(r, finalStateRequest, reason)) {return;}if (mActivitiesToBeDestroyed.containsKey(r.token)) {// Although the activity is resumed, it is going to be destroyed. So the following// UI operations are unnecessary and also prevents exception because its token may// be gone that window manager cannot recognize it. All necessary cleanup actions// performed below will be done while handling destruction.return;}final Activity a = r.activity;if (localLOGV) {
Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity+ ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);}final int forwardBit = isForward? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;// If the window hasn't yet been added to the window manager,// and this guy didn't finish itself or start another activity,// then go ahead and add the window.boolean willBeVisible = !a.mStartedActivity;if (!willBeVisible) {
willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
a.getActivityToken());}if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;// Normally the ViewRoot sets up callbacks with the Activity// in addView->ViewRootImpl#setView. If we are instead reusing// the decor view we have to notify the view root that the// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();if (impl != null) {
impl.notifyChildRebuilt();}}if (a.mVisibleFromClient) {if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);} else {// The activity will get a callback for this {@link LayoutParams} change// earlier. However, at that time the decor will not be set (this is set// in this method), so no action will be taken. This call ensures the// callback occurs with the decor set.
a.onWindowAttributesChanged(l);}}// If the window has already been added, but during resume// we started another activity, then don't yet make the// window visible.} else if (!willBeVisible) {if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;}// Get rid of anything left hanging around.cleanUpPendingRemoveWindows(r, false /* force */);// The window is now visible if it has been added, we are not// simply finishing, and we are not starting another activity.if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
WindowManager.LayoutParams l = impl != null? impl.mWindowAttributes : r.window.getAttributes();if ((l.softInputMode& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)!= forwardBit) {
l.softInputMode = (l.softInputMode& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))| forwardBit;if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);}} r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();}if (shouldSendCompatFakeFocus) {// Attaching to a window is asynchronous with the activity being resumed,// so it's possible we will need to send a fake focus event after attachingif (impl != null) {
impl.dispatchCompatFakeFocus();} else {
r.window.getDecorView().fakeFocusAfterAttachingToWindow();}}} mNewActivities.add(r);if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
这里主要关注performResumeActivity
D:\AndroidSource\Android11\platform\frameworks\base\core\java\android\app\ActivityThread.java@VisibleForTesting
public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
String reason) {if (localLOGV) {
Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);}if (r.activity.mFinished) {return false;}if (r.getLifecycleState() == ON_RESUME) {if (!finalStateRequest) {final RuntimeException e = new IllegalStateException("Trying to resume activity which is already resumed");
Slog.e(TAG, e.getMessage(), e);
Slog.e(TAG, r.getStateString());// TODO(lifecycler): A double resume request is possible when an activity// receives two consequent transactions with relaunch requests and "resumed"// final state requests and the second relaunch is omitted. We still try to// handle two resume requests for the final state. For cases other than this// one, we don't expect it to happen.}return false;}if (finalStateRequest) {
r.hideForNow = false;
r.activity.mStartedActivity = false;}try {
r.activity.onStateNotSaved();
r.activity.mFragments.noteStateNotSaved();checkAndBlockForNetworkAccess();if (r.pendingIntents != null) {deliverNewIntents(r, r.pendingIntents);
r.pendingIntents = null;}if (r.pendingResults != null) {deliverResults(r, r.pendingResults, reason);
r.pendingResults = null;}
r.activity.performResume(r.startsNotResumed, reason); r.state = null;
r.persistentState = null;
r.setState(ON_RESUME);reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to resume activity "+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);}}return true;
}
r.activity.performResume(r.startsNotResumed, reason);
final void performResume(boolean followedByPause, String reason) {if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performResume:"+ mComponent.getClassName());}dispatchActivityPreResumed(); mFragments.execPendingActions(); mLastNonConfigurationInstances = null;getAutofillClientController().onActivityPerformResume(followedByPause); mCalled = false;final long startTime = SystemClock.uptimeMillis();// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);final long duration = SystemClock.uptimeMillis() - startTime;
EventLogTags.writeWmOnResumeCalled(mIdent, getComponentName().getClassName(), reason,
duration);if (!mCalled) {throw new SuperNotCalledException("Activity " + mComponent.toShortString() +" did not call through to super.onResume()");}// invisible activities must be finished before onResume) completesif (!mVisibleFromClient && !mFinished) {
Log.w(TAG, "An activity without a UI must call finish() before onResume() completes");if (getApplicationInfo().targetSdkVersion> android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {throw new IllegalStateException("Activity " + mComponent.toShortString() +" did not call finish() prior to onResume() completing");}}// Now really resume, and install the current status bar and menu.
mCalled = false; mFragments.dispatchResume();
mFragments.execPendingActions();onPostResume();if (!mCalled) {throw new SuperNotCalledException("Activity " + mComponent.toShortString() +" did not call through to super.onPostResume()");}dispatchActivityPostResumed();
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
mInstrumentation.callActivityOnResume(this);执行onResume,EventLogTags.writeWmOnResumeCalled记录了onResume执行的时间。
更新服务端状态
回到ActivityTaskSupervisor的realStartActivityLocked()
在执行完clientTransaction后,调用rootTask.minimalResumeActivityLocked(r);
platform/frameworks/base/services/core/java/com/android/server/wm/Task.javavoid minimalResumeActivityLocked(ActivityRecord r) {
ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (starting new instance) "+ "callers=%s", r, Debug.getCallers(5));
r.setState(RESUMED, "minimalResumeActivityLocked");
r.completeResumeLocked();
}
这里将ActivityRecord状态设置成了RESUMED
platform/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.javavoid completeResumeLocked() {final boolean wasVisible = mVisibleRequested;setVisibility(true);if (!wasVisible) {// Visibility has changed, so take a note of it so we call the TaskStackChangedListener
mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;}
idle = false;
results = null;if (newIntents != null && newIntents.size() > 0) {
mLastNewIntent = newIntents.get(newIntents.size() - 1);}
newIntents = null;if (isActivityTypeHome()) {
mTaskSupervisor.updateHomeProcess(task.getBottomMostActivity().app);}if (nowVisible) {
mTaskSupervisor.stopWaitingForActivityVisible(this);}// Schedule an idle timeout in case the app doesn't do it for us.
mTaskSupervisor.scheduleIdleTimeout(this); mTaskSupervisor.reportResumedActivityLocked(this);resumeKeyDispatchingLocked();final Task rootTask = getRootTask();
mTaskSupervisor.mNoAnimActivities.clear();
returningOptions = null;if (canTurnScreenOn()) {
mTaskSupervisor.wakeUp("turnScreenOnFlag");} else {// If the screen is going to turn on because the caller explicitly requested it and// the keyguard is not showing don't attempt to sleep. Otherwise the Activity will// pause and then resume again later, which will result in a double life-cycle event.
rootTask.checkReadyForSleep();}
}
此处调用setVisibility(true);等相关方法,更新状态。
至此,Activity启动流程梳理完毕。