Android14 - AMS之Activity启动过程(3)

news2024/11/28 9:36:23
Android14 - AMS之Activity启动过程(1)-CSDN博客
Android14 - AMS之Activity启动过程(2)-CSDN博客

上篇中我们梳理完ActivityStarter的startActivityInner,本篇从这里开始:

platform/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

boolean resumeFocusedTasksTopActivities(
		Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
		boolean deferPause) {
	if (!mTaskSupervisor.readyToResume()) {
		return false;
	}

	boolean result = false;
   // targetRootTask不为空,isTopRootTaskInDisplayArea为true
	if (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为true
		if (isLeafTask()) {
        // isFocusableAndVisible为true
			if (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.java

boolean 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.java

boolean hasProcess() {
	return app != null;
}

boolean attachedToProcess() {
	return hasProcess() && app.hasThread();
}

本质判断的是app属性。这个将在后续进程启动后设置。

启动进程

startProcessAsync启动进程:

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

void 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.java

public 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.java

ProcessRecord 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.java

boolean 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.java

boolean 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.java

public 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.java

private 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.java

public 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.java

boolean 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$AttachApplicationHelper

boolean 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 andResumetrue

realStartActivityLocked真正调用客户端Activity

调用客户端Activity

realStartActivityLocked代码

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

boolean 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.java

public 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. 服务端addCallbacksetLifecycleStateRequest

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因此调用ClientLifecycleManagerscheduleTransaction()

platform/frameworks/base/services/core/java/com/android/server/wm/ClientLifecycleManager.java

void 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.java

public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

mClientIApplicationThread也就是客户端所持有的binder服务端因此scheduleTransaction调用客户端ApplicationThreadscheduleTransaction

platform/frameworks/base/core/java/android/app/ActivityThread.java

public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
	ActivityThread.this.scheduleTransaction(transaction);
}

4. 客户端执行scheduleTransaction

ActivityThread这个方法父类执行

platform/frameworks/base/core/java/android/app/ClientTransactionHandler.java

void 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.java

case 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.java

public 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.java

public 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 (== null) {
		// Launch activity request will create an activity record.
= mTransactionHandler.getActivityClient(token);
	}

	if (postExecutionState != UNDEFINED && r != null) {
		// Skip the very last transition and perform it by explicit state request instead.
		final boolean shouldExcludeLastTransition =
== lastCallbackRequestingState && finalState == postExecutionState;
		cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
	}
}
platform/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java

private 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

回到ActivityTaskSupervisorrealStartActivityLocked()

通过ClientTransaction先后执行以下生命周期相关事务:

LaunchActivityItem -- 客户端新建Activity

ResumeActivityItem -- 执行ActivityonResume

新建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调用ClientTransactionHandlerhandleLaunchActivity具体实现ActivityThread

platform/frameworks/base/core/java/android/app/ActivityThread.java

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, int deviceId, Intent customIntent) {
	...
	final Activity a = performLaunchActivity(r, customIntent);
	...
	if (!= 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.java

private 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的onCreate
			if (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;
}

这里最终

  1. 创建appContext:ContextImpl appContext = createBaseContextForActivity(r)
  2. 创建Activityactivity = mInstrumentation.newActivity(...)
  3. activity.attach()
  4. 调用Activity的onCreatemInstrumentation.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 attaching
			if (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) completes
	if (!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);执行onResumeEventLogTags.writeWmOnResumeCalled记录onResume执行时间

更新服务端状态

回到ActivityTaskSupervisorrealStartActivityLocked()

执行clientTransaction调用rootTask.minimalResumeActivityLocked(r);

platform/frameworks/base/services/core/java/com/android/server/wm/Task.java

void 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.java

void 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启动流程梳理完毕。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1530229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux实践 - 命令行解释器 简易版

~~~~ 前言解决的问题为什么shell要以子进程的方式执行我们的命令&#xff1f;为什么直接使用程序名ls&#xff0c;而不是路径/usr/bin/ls&#xff1f; 头文件包含命令行提示符接受用户命令行输入解析用户的输入内建命令&&特殊处理ls 时目录等文件不带高亮颜色cd时目录不…

[OpenCV学习笔记]获取鼠标处图像的坐标和像素值

目录 1、介绍2、效果展示3、代码实现4、源码展示 1、介绍 实现获取鼠标点击处的图像的坐标和像素值&#xff0c;灰度图显示其灰度值&#xff0c;RGB图显示rgb的值。 OpenCV获取灰度值及彩色像素值的方法&#xff1a; //灰度图像&#xff1a; image.at<uchar>(j, i) //j…

学习笔记Day12:初探LInux 2

Linux初探 同一个目录中不允许出现文件及文件夹重名 查看文件 cat &#xff08;Concatenate&#xff09;查看文本文件内容&#xff0c;输出到屏幕&#xff08;标准输出流&#xff09; 常用参数 -A打印所有字符&#xff0c;包括特殊字符&#xff08;换行符、制表符等&#xff…

前端项目,个人笔记(三)【Vue-cli - api封装-axios使用举例】

目录 前言 1、axios配置与测试 1.1、配置 1.2、测试 2、使用axios案例-渲染header 3、Pinia优化重复请求 3.1、为什么&#xff1f; 3.2、使用Pinia优化代码步骤 步骤一&#xff1a;在main.js中创建 Pinia 实例&#xff0c;并将其作为插件添加到 Vue 应用中 步骤二&am…

redis和rabbitmq实现延时队列

redis和rabbitmq实现延时队列 延迟队列使用场景Redis中zset实现延时队列Rabbitmq实现延迟队列 延迟队列使用场景 1. 订单超时处理 延迟队列可以用于处理订单超时问题。当用户下单后&#xff0c;将订单信息放入延迟队列&#xff0c;并设置一定的超时时间。如果在超时时间内用户…

【LabVIEW FPGA入门】使用FPGA实现串行同步接口(SSI)

SSI&#xff08;串行同步接口&#xff09;是连接绝对位置传感器和控制器的广泛应用的串行接口。SSI利用控制器发出一个时钟脉冲序列&#xff0c;初始化传感器的门限输出。 传感器不断更新位置数据&#xff0c;并传送到移位寄存器中。在每一个时钟脉冲序列之间&#xff…

了解常见字符函数

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 点击主页&#xff1a;optimistic_chen和专栏&#xff1a;c语言&#xff0c; 创作不易&#xff0c;大佬们点赞鼓…

.NET 异步编程(异步方法、异步委托、CancellationToken、WhenAll、yield)

文章目录 异步方法异步委托async方法缺点CancellationTokenWhenAllyield 异步方法 “异步方法”&#xff1a;用async关键字修饰的方法 异步方法的返回值一般是Task<T>&#xff0c;T是真正的返回值类型&#xff0c;Task<int>。惯例&#xff1a;异步方法名字以 Asy…

浅析ArcGis中的软件——ArcMap、ArcScene、 ArcGlobe、ArcCatalog

为什么要写这么一篇介绍ArcGis的文章呢&#xff1f;因为大部分人也包括ArcGisdada&#xff0c;在使用ArcMap应用程序创建工程时总以为我们就是使用了ArcGis这个软件的所有。其实不然&#xff0c;在后期的接触和使用中慢慢发现原来ArcMap只是ArcGis这个综合平台的一部分&#xf…

HarmonyOS NEXT应用开发之动态路由

介绍 本示例将介绍如何使用动态路由跳转到模块中的页面&#xff0c;以及如何使用动态import的方式加载模块 使用说明 通过动态import的方式&#xff0c;在需要进入页面时加载对应的模块。配置动态路由&#xff0c;通过WrapBuilder接口&#xff0c;动态创建页面并跳转。动态i…

2024.3.19

思维导图 模拟面试 1.友元的作用 答&#xff1a;通过关键字friend&#xff0c;可以让一些函数或者类&#xff0c;可以访问一个类中的私有数据成员。 2.匿名对象的作用 答&#xff1a;匿名对象就是没有名字的对象&#xff0c;是用来给有名对象进行初始化工作的。 3.常成员函…

【S5PV210】 | GPIO编程

【S5PV210】 | GPIO编程 时间:2024年3月17日22:02:32 目录 文章目录 【`S5PV210`】 | `GPIO`编程目录1.参考2.`DataSheet`2.1.概述2.1.1.特色2.1.2 输入/输出配置2.1.3 `S5PV210` 输入/输出类型2.1.4 IO驱动强度**2.1.4.1 类型A IO驱动强度****2.1.4.2 类型A IO驱动强度****2…

安泰电子:前置微小信号放大器是什么东西

前置微小信号放大器是一种用于放大微弱信号的设备&#xff0c;在电子和通信领域中有广泛的应用。它的主要功能是将输入的微小信号放大到足够的水平&#xff0c;以便后续电路能够准确地测量、处理和分析这些信号。本文将详细介绍前置微小信号放大器的原理、组成部分和应用领域。…

目标检测——PP-PicoDet算法解读

PP-YOLO系列&#xff0c;均是基于百度自研PaddlePaddle深度学习框架发布的算法&#xff0c;2020年基于YOLOv3改进发布PP-YOLO&#xff0c;2021年发布PP-YOLOv2和移动端检测算法PP-PicoDet&#xff0c;2022年发布PP-YOLOE和PP-YOLOE-R。由于均是一个系列&#xff0c;所以放一起解…

AutoSAR配置与实践(深入篇)10.3 CANTP 传输流程和通信示例

AutoSAR配置与实践(深入篇)10.3 CANTP 通信示例 CANTP 通信示例一、诊断传输流程1.1上位机请求流程1.2 ECU反馈流程二、CANTP 通信示例2.1 通信交互详解CANTP 通信示例 ->返回总目录<- 一、诊断传输流程 1.1上位机请求流程 Step 1. Tester(诊断上位机)通过物理总线…

线程,你真的懂了吗?

大家都知道的是线程其实分为的是内核级线程和用户级线程&#xff0c;这几天在看线程的时候&#xff0c;突然有一种感觉不太明白的地方&#xff0c;那就是linux中pthread.h这个库中的线程到底是用户级还是内核级&#xff0c;后来在网上也搜了很多的例子。我自我认为是看不懂的&a…

科技助力高质量发展:新质生产力的崛起与企业数字化转型

引言 随着科技的飞速发展&#xff0c;我们正逐渐步入数字化智能时代&#xff0c;这个时代不仅为企业带来了无限的机遇&#xff0c;也让其面对前所未有的挑战。在这个快速变革的时代&#xff0c;企业必须不断调整自己的经营策略&#xff0c;适应数字化转型的浪潮&#xff0c;以…

阿里云部署MySQL、Redis、RocketMQ、Nacos集群

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容MySQL集群配置云服务器选购CPU选择内存选择云盘选择ESSD AutoPL云盘块存储性能&#xff08;ESSD&#xff09; 镜像选择带宽选择密码配置注意事项 搭建宝塔面板方便管理云服务器云服务器的安全组安装docker和docker-compose…

MyBatis记录

目录 什么是MyBatis MyBatis的优点和缺点 #{}和${}的区别 Mybatis是如何进行分页的&#xff0c;分页插件的原理 Mybatis是如何将sql执行结果封装为目标对象并返回的 MyBatis实现一对一有几种方式 Mybatis设计模式 什么是MyBatis &#xff08;1&#xff09;Mybatis是一个…

Unbuntu20.04 git push和pull相关问题

文章目录 Unbuntu20.04 git push和pull使用&#xff11;&#xff0e;下载[Git工具包](https://git-scm.com/downloads)&#xff12;&#xff0e;建立本地仓库&#xff13;&#xff0e;将本地仓库与github远程仓库关联&#xff14;&#xff0e;将本地仓库文件上传到github远程仓…