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

Android14 - AMS之Activity启动过程(1)-CSDN博客
Android14 - AMS之Activity启动过程(2)-CSDN博客

上篇中我们梳理完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 andResumetrue

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. 服务端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.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);
}

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

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 (== 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.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

回到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.javapublic 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.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;
}

这里最终

  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 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);执行onResumeEventLogTags.writeWmOnResumeCalled记录onResume执行时间

更新服务端状态

回到ActivityTaskSupervisorrealStartActivityLocked()

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VC6环境开发汇编程序和汇编语言调用C库

新建一个Win32控制台类型的空项目&#xff1b; 新建一个源文件&#xff0c;输入文件名时输入后缀.asm&#xff1b;.asm后缀的文件如果不会出现在Source Files文件夹下&#xff0c;可将其拖放到Source Files文件夹下&#xff1b; 输入如下代码&#xff1b;调用C的printf函数输出…

UE5.1 iClone8 正确导入角色骨骼与动作

使用iClone8插件Auto Setup 附录下载链接 里面有两个文件夹,使用Auto Setup C:\Program Files\Reallusion\Shared Plugins 在UE内新建Plugins,把插件复制进去 在工具栏出现这三个人物的图标就安装成功了 iClone选择角色,导入动作 选择导出FBX UE内直接导入 会出现是否启动插件…

Vue 计算属性和监视属性

Vue 计算属性和监视属性 computed computed 计算属性 规则&#xff1a; 用已有的属性计算不存在的属性默认调用一次get()只有值不发生改变的时候才可以使用简写&#xff08;函数&#xff09;&#xff1b;值发生改变 使用对象式写法&#xff0c;才可以配置set()方法底层原理使…

计算机视觉之三维重建(2)---摄像机标定

文章目录 一、回顾线代1.1 线性方程组的解1.2 齐次线性方程组的解 二、透镜摄像机的标定2.1 标定过程2.2 提取摄像机参数2.3 参数总结 三、径向畸变的摄像机标定3.1 建模3.2 求解 四、变换4.1 2D平面上的欧式变换4.2 2D平面上的相似变换和仿射变换4.3 2D平面上的透射变换4.4 3D…

Git Bash命令初始化本地仓库,提交到远程仓库

git init&#xff1a;初始化空仓库 // 初始化一个空仓库或者重新初始化一个存在的仓库 git init git remote // 为当前本地仓库添加一个远程仓库地址 git remote add origin https://gitee.com/xxx/demo.git git pull // 从设置好链接的远程仓库拉去已经存在的数据&#xff0c;…

微信小程序调试、断点调试

1、wxml 查看对应的页面组件 2、console面板可以用来打印信息 3、sources 用来断点调试 4、network面板用来调试接口 5、storage面板 可以查看每个key对应的value内容&#xff0c;这些数据在用户使用小程序时被持久化保存在本地。

Outlook邮件导入Notes竟然有这么多办法

大家好&#xff0c;才是真的好。 以前我们讲过&#xff0c;如何将微软的Outlook里的邮件导入到Notes邮箱中。今天我们来系统地跟大家再回顾下几种方式。 第一种方式就是Notes客户端自带一个迁移工具。名字叫做Exchange迁移&#xff0c;在Notes客户机安装时&#xff0c;可以选…

Flink:使用 Faker 和 DataGen 生成测试数据

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

HarmonyOS定时器与定时任务

HarmonyOS 的 ArkTS 说白了 就是 TS和JS混合 加了一些新特性的语言 定时任务 就还是用 js代码就OK了 我们代码这样写 Entry Component struct Twox {build() {Row() {Column(){Button("触发定时任务").onClick(()>{setTimeout(()> {console.log(执行)},2000…

如何将Excel两列数据转换为统计图、曲线图、折线图?如何自定义某一列作为Excel的统计图横纵坐标?

这样&#xff0c;横坐标就更换为指定选中的数据了 我们还可以修改统计图的样式 也可以修改统计图的类型

GAMES104-现代游戏引擎 1

主要学习重点还是面向就业&#xff0c;重点复习八股和算法 每天早上八点到九点用来学习这个课程 持续更新中... 第一节 游戏引擎导论 第二节 引擎架构分层 引擎是分层架构的 编辑器功能层资源层核心层平台层 越底层的代码越稳定越坚固&#xff0c;越上层的代码越灵活越开…

蓝桥杯练习03个人博客

个人博客 介绍 很多人都有自己的博客&#xff0c;在博客上面用自己的方式去书写文章&#xff0c;用来记录生活&#xff0c;分享技术等。下面是蓝桥云课的博客&#xff0c;但是上面还缺少一些样式&#xff0c;需要大家去完善。 准备 开始答题前&#xff0c;需要先打开本题的…

【重温设计模式】策略模式及其Java示例

策略模式的基本概念 策略模式&#xff0c;是一种常见的行为设计模式&#xff0c;主要用于处理程序中的一些相同行为&#xff0c;但具有不同实现方式的问题。在策略模式中&#xff0c;我们将每一种行为封装为一个个策略类&#xff0c;通过策略类的组合和切换&#xff0c;可以灵…

Qt QTableWidget 实现行选中及行悬浮高亮

表格整行的 selected、hover 高亮需求很常见&#xff0c;但使用 Qt 提供的开箱即用的方法根本无法实现这个需求&#xff08;至少在当前的时间节点是不行的&#xff09;&#xff1b;想要实现这个效果必须要费一点点力气&#xff0c;我们尽量选择较为简单的方法。 话不多说&…

【运维】StarRocks数据迁移到新集群(针对于集群互通、不互通的情况)

文章目录 一. 迁移整体思路1. 对于新旧集群互通的情况2. 对于新旧集群不互通的情况二、迁移过程(两个集群互通的情况)1. 备份过程1.1. 通过mysqlclient与starrocks进行关联1.2. 创建仓库与minio建立联系1.3. 备份数据到minio2. 迁移过程2.1. 通过mysqlclient与starrocks进行关…

【C语言】—— 指针三 : 参透数组传参的本质

【C语言】—— 指针三 &#xff1a; 参透数组传参的本质 一、数组名的理解二、使用指针访问数组2.1、指针访问数组2.2、[ ] 的深入理解2.3、数组与指针的区别 三、一维数组的传参本质四、数组指针变量4.1、数组指针变量是什么4.2、 数组指针的初始化 五、二维数组传参的本质 一…

spring整合Sentinel

安装sentinel&#xff1a; 执行命令; java -jar sentinel-dashboard-1.8.6.jar 注:sentinel的默认端口为8080&#xff0c;容易出现tomcat的冲突。 当端口冲突&#xff0c;可以使用该指令修改sentinel的端口 默认账号和密码都为sentinel Springcloud整合sentinel&#xff1a;…

深入理解Java中的TCP连接:三次握手和四次挥手

欢迎来到我的博客&#xff01;今天我们将一起探索网络通信的奥秘。在Java编程中&#xff0c;我们经常会涉及到网络通信&#xff0c;而TCP协议是实现可靠数据传输的重要协议之一。在建立TCP连接和断开连接的过程中&#xff0c;三次握手和四次挥手是至关重要的步骤。本文将深入探…

人工智能数据分析Python常用库 01 time、random、collections、itertools库

文章目录 一、time库1、获取现在时间2、时间戳与计时器3、格式化4、睡眠 二、random库1、随机种子2、产生随机整数3、产生随机浮点数4、随机序列5、概率分布——以高斯分布为例 三、collections库——容器数据类型1、namedtuple——具名元组&#xff08;1&#xff09;定义方法&…

YOLO_you only look once

前言 计算机图形学的课程即将结束&#xff0c;我需要提交一份关于YOLO模型的学习报告。在这段时间里&#xff0c;我对YOLO进行了深入的学习和研究&#xff0c;并记录下了我的学习过程和心得体会。本文将详细介绍YOLO模型的原理、优缺点以及应用领域&#xff0c;希望能够为后续…